From 9a26ab44fbe02d5211789f28c36d6aa277c9bd2d Mon Sep 17 00:00:00 2001 From: Jacob Siverskog Date: Tue, 6 Jun 2023 16:10:37 +0200 Subject: [PATCH 0001/2042] drivers: dma_mcux_lpc: Fix potential NULL pointer dereferences Dereference variables after NULL checking. Signed-off-by: Jacob Siverskog --- drivers/dma/dma_mcux_lpc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 778fe1294d6d..65716cc5262a 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -259,25 +259,31 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, struct dma_config *config) { - const struct dma_mcux_lpc_config *dev_config = dev->config; + const struct dma_mcux_lpc_config *dev_config; dma_handle_t *p_handle; uint32_t xfer_config = 0U; struct channel_data *data; - struct dma_mcux_lpc_dma_data *dma_data = dev->data; - struct dma_block_config *block_config = config->head_block; + struct dma_mcux_lpc_dma_data *dma_data; + struct dma_block_config *block_config; uint32_t virtual_channel; uint32_t total_dma_channels; uint8_t otrig_index; uint8_t src_inc, dst_inc; bool is_periph = true; - uint8_t width = MIN(config->source_data_size, config->dest_data_size); - uint32_t max_xfer = NXP_LPC_DMA_MAX_XFER * width; + uint8_t width; + uint32_t max_xfer; uint8_t reload = 0; if (NULL == dev || NULL == config) { return -EINVAL; } + dev_config = dev->config; + dma_data = dev->data; + block_config = config->head_block; + width = MIN(config->source_data_size, config->dest_data_size); + max_xfer = NXP_LPC_DMA_MAX_XFER * width; + /* * Check if circular mode is requested. */ From e0e7f5888f63555fbfa028331dfaf450d004d965 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 7 Jun 2023 14:31:57 +0000 Subject: [PATCH 0002/2042] fs/littlefs/sample: Increase stack size Increase stack size to prevent sample crashes. Fixes #57525 Signed-off-by: Dominik Ermel --- samples/subsys/fs/littlefs/prj.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/subsys/fs/littlefs/prj.conf b/samples/subsys/fs/littlefs/prj.conf index baaa677e7987..673735fb0fd8 100644 --- a/samples/subsys/fs/littlefs/prj.conf +++ b/samples/subsys/fs/littlefs/prj.conf @@ -8,7 +8,7 @@ #CONFIG_APP_WIPE_STORAGE=y # fs_dirent structures are big. -CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_MAIN_STACK_SIZE=4096 # Let __ASSERT do its job CONFIG_DEBUG=y From e9ee3e0af08c91807fdbdbb9bca2c79062afa263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 7 Jun 2023 07:52:31 +0200 Subject: [PATCH 0003/2042] Bluetooth: Samples: Remove usage of `BT_DEBUG_LOG` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove usage of Kconfig symbol `CONFIG_BT_DEBUG_LOG` from samples. It has been deprecated since this PR: https://github.com/zephyrproject-rtos/zephyr/pull/56183 The Kconfig symbols has been replaced by `CONFIG_LOG=y` on most of the cases. Or it has been removed when not needed anymore. Signed-off-by: Théo Battrel --- samples/bluetooth/beacon/prj-coex.conf | 2 +- samples/bluetooth/beacon/prj.conf | 2 +- samples/bluetooth/broadcast_audio_sink/prj.conf | 2 +- samples/bluetooth/broadcast_audio_source/prj.conf | 2 +- samples/bluetooth/broadcaster_multiple/prj.conf | 2 +- samples/bluetooth/central_gatt_write/prj.conf | 2 +- samples/bluetooth/central_hr/prj.conf | 2 +- samples/bluetooth/central_ht/prj.conf | 2 +- samples/bluetooth/central_iso/prj.conf | 2 +- samples/bluetooth/central_past/prj.conf | 2 +- samples/bluetooth/direct_adv/prj.conf | 2 +- samples/bluetooth/direction_finding_central/prj.conf | 2 +- samples/bluetooth/direction_finding_peripheral/prj.conf | 2 +- samples/bluetooth/eddystone/prj.conf | 2 +- samples/bluetooth/hap_ha/prj.conf | 2 +- samples/bluetooth/hci_pwr_ctrl/prj.conf | 2 +- samples/bluetooth/hci_uart/debug.conf | 2 +- samples/bluetooth/ibeacon/prj.conf | 2 +- samples/bluetooth/ipsp/prj.conf | 2 +- samples/bluetooth/ipsp/prj_dbg.conf | 2 +- samples/bluetooth/ipsp/prj_zep1656.conf | 2 +- samples/bluetooth/iso_broadcast/prj.conf | 2 +- samples/bluetooth/iso_receive/prj.conf | 2 +- samples/bluetooth/periodic_adv/prj.conf | 2 +- samples/bluetooth/periodic_sync/prj.conf | 2 +- samples/bluetooth/peripheral/prj.conf | 2 +- samples/bluetooth/peripheral_accept_list/prj.conf | 2 +- samples/bluetooth/peripheral_gatt_write/prj.conf | 2 +- samples/bluetooth/peripheral_hids/prj.conf | 2 +- samples/bluetooth/peripheral_hr/prj.conf | 2 +- samples/bluetooth/peripheral_hr/prj_minimal.conf | 1 - samples/bluetooth/peripheral_ht/prj.conf | 2 +- samples/bluetooth/peripheral_iso/prj.conf | 2 +- samples/bluetooth/peripheral_past/prj.conf | 2 +- samples/bluetooth/peripheral_sc_only/prj.conf | 2 +- samples/bluetooth/scan_adv/prj.conf | 2 +- samples/bluetooth/st_ble_sensor/prj.conf | 1 - samples/bluetooth/tmap_central/prj.conf | 2 +- samples/bluetooth/tmap_peripheral/prj.conf | 2 +- samples/bluetooth/unicast_audio_client/prj.conf | 2 +- samples/bluetooth/unicast_audio_server/prj.conf | 2 +- samples/boards/nrf/mesh/onoff-app/prj.conf | 2 +- samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/prj.conf | 2 +- samples/boards/reel_board/mesh_badge/prj.conf | 2 +- samples/net/lwm2m_client/overlay-bt.conf | 2 +- samples/net/mdns_responder/overlay-bt.conf | 2 +- samples/net/mqtt_publisher/overlay-bt.conf | 2 +- samples/net/sockets/echo_client/overlay-bt.conf | 2 +- samples/net/sockets/echo_server/overlay-bt.conf | 2 +- samples/net/telnet/overlay-bt.conf | 2 +- samples/net/zperf/overlay-bt.conf | 2 +- 51 files changed, 49 insertions(+), 51 deletions(-) diff --git a/samples/bluetooth/beacon/prj-coex.conf b/samples/bluetooth/beacon/prj-coex.conf index 6dafb5b261be..b16487f3999b 100644 --- a/samples/bluetooth/beacon/prj-coex.conf +++ b/samples/bluetooth/beacon/prj-coex.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test beacon" CONFIG_BT_LL_SW_SPLIT=y diff --git a/samples/bluetooth/beacon/prj.conf b/samples/bluetooth/beacon/prj.conf index 1d6745c7942b..045c5c5f61d8 100644 --- a/samples/bluetooth/beacon/prj.conf +++ b/samples/bluetooth/beacon/prj.conf @@ -1,3 +1,3 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test beacon" diff --git a/samples/bluetooth/broadcast_audio_sink/prj.conf b/samples/bluetooth/broadcast_audio_sink/prj.conf index 4e750c19e6e5..11e0971638a0 100644 --- a/samples/bluetooth/broadcast_audio_sink/prj.conf +++ b/samples/bluetooth/broadcast_audio_sink/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_AUDIO=y CONFIG_BT_SMP=y CONFIG_BT_PAC_SNK=y diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index edbb192f7fa4..89210995535e 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -1,7 +1,7 @@ CONFIG_MAIN_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_BROADCAST_SOURCE=y diff --git a/samples/bluetooth/broadcaster_multiple/prj.conf b/samples/bluetooth/broadcaster_multiple/prj.conf index efce4351c113..65248db31911 100644 --- a/samples/bluetooth/broadcaster_multiple/prj.conf +++ b/samples/bluetooth/broadcaster_multiple/prj.conf @@ -4,7 +4,7 @@ CONFIG_BT_EXT_ADV=y CONFIG_BT_EXT_ADV_MAX_ADV_SET=2 CONFIG_BT_DEVICE_NAME="Broadcaster Multiple" -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y # Zephyr Bluetooth LE Controller will need to use chain PDUs when AD data # length > 191 bytes diff --git a/samples/bluetooth/central_gatt_write/prj.conf b/samples/bluetooth/central_gatt_write/prj.conf index 3014d05dfe3f..e92eecda0f65 100644 --- a/samples/bluetooth/central_gatt_write/prj.conf +++ b/samples/bluetooth/central_gatt_write/prj.conf @@ -10,4 +10,4 @@ CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 CONFIG_BT_L2CAP_TX_MTU=247 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/samples/bluetooth/central_hr/prj.conf b/samples/bluetooth/central_hr/prj.conf index e937bf405d34..d7e8c7128d46 100644 --- a/samples/bluetooth/central_hr/prj.conf +++ b/samples/bluetooth/central_hr/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_SMP=y CONFIG_BT_GATT_CLIENT=y diff --git a/samples/bluetooth/central_ht/prj.conf b/samples/bluetooth/central_ht/prj.conf index ee1497430b77..8e1998d625ae 100644 --- a/samples/bluetooth/central_ht/prj.conf +++ b/samples/bluetooth/central_ht/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_SMP=y CONFIG_BT_GATT_CLIENT=y diff --git a/samples/bluetooth/central_iso/prj.conf b/samples/bluetooth/central_iso/prj.conf index 44d8adf0e1fa..ab5a202401f5 100644 --- a/samples/bluetooth/central_iso/prj.conf +++ b/samples/bluetooth/central_iso/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ISO_CENTRAL=y CONFIG_BT_SMP=y diff --git a/samples/bluetooth/central_past/prj.conf b/samples/bluetooth/central_past/prj.conf index 79c3d1a9d590..09ef795f3b82 100644 --- a/samples/bluetooth/central_past/prj.conf +++ b/samples/bluetooth/central_past/prj.conf @@ -2,6 +2,6 @@ CONFIG_BT=y CONFIG_BT_CENTRAL=y CONFIG_BT_EXT_ADV=y CONFIG_BT_PER_ADV_SYNC=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test Central Periodic Advertising Sync Transfer" CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y diff --git a/samples/bluetooth/direct_adv/prj.conf b/samples/bluetooth/direct_adv/prj.conf index a3905e5207cc..6a633da19238 100644 --- a/samples/bluetooth/direct_adv/prj.conf +++ b/samples/bluetooth/direct_adv/prj.conf @@ -2,7 +2,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_SIGNING=y CONFIG_BT_PERIPHERAL=y diff --git a/samples/bluetooth/direction_finding_central/prj.conf b/samples/bluetooth/direction_finding_central/prj.conf index 03ef424c1b89..f296baca1c06 100644 --- a/samples/bluetooth/direction_finding_central/prj.conf +++ b/samples/bluetooth/direction_finding_central/prj.conf @@ -5,7 +5,7 @@ # CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Direction Finding Central" CONFIG_BT_CENTRAL=y diff --git a/samples/bluetooth/direction_finding_peripheral/prj.conf b/samples/bluetooth/direction_finding_peripheral/prj.conf index b94ff0a47326..906a1577ea9c 100644 --- a/samples/bluetooth/direction_finding_peripheral/prj.conf +++ b/samples/bluetooth/direction_finding_peripheral/prj.conf @@ -5,7 +5,7 @@ # CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="DF Conn App" CONFIG_BT_SMP=y diff --git a/samples/bluetooth/eddystone/prj.conf b/samples/bluetooth/eddystone/prj.conf index 2ae4f32a0f20..58ac343e0751 100644 --- a/samples/bluetooth/eddystone/prj.conf +++ b/samples/bluetooth/eddystone/prj.conf @@ -1,4 +1,4 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="Zephyr Eddystone" diff --git a/samples/bluetooth/hap_ha/prj.conf b/samples/bluetooth/hap_ha/prj.conf index eda99512ca8a..53240f86c614 100644 --- a/samples/bluetooth/hap_ha/prj.conf +++ b/samples/bluetooth/hap_ha/prj.conf @@ -61,4 +61,4 @@ CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=0 CONFIG_BT_TBS_CLIENT_CCID=y CONFIG_BT_TBS_CLIENT_STATUS_FLAGS=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/samples/bluetooth/hci_pwr_ctrl/prj.conf b/samples/bluetooth/hci_pwr_ctrl/prj.conf index 7210cd74caf6..8d76025b3ab1 100644 --- a/samples/bluetooth/hci_pwr_ctrl/prj.conf +++ b/samples/bluetooth/hci_pwr_ctrl/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_HRS=y CONFIG_BT_DEVICE_APPEARANCE=833 diff --git a/samples/bluetooth/hci_uart/debug.conf b/samples/bluetooth/hci_uart/debug.conf index bd43b724f9eb..7d0c43dab62f 100644 --- a/samples/bluetooth/hci_uart/debug.conf +++ b/samples/bluetooth/hci_uart/debug.conf @@ -8,7 +8,7 @@ CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y CONFIG_HW_STACK_PROTECTION=y CONFIG_CONSOLE=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=4096 CONFIG_RTT_CONSOLE=y CONFIG_LOG_BACKEND_RTT=y diff --git a/samples/bluetooth/ibeacon/prj.conf b/samples/bluetooth/ibeacon/prj.conf index 44a041269ef4..06dec403bd83 100644 --- a/samples/bluetooth/ibeacon/prj.conf +++ b/samples/bluetooth/ibeacon/prj.conf @@ -1,2 +1,2 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/samples/bluetooth/ipsp/prj.conf b/samples/bluetooth/ipsp/prj.conf index 5dc407b3ad19..8ba24abb30c9 100644 --- a/samples/bluetooth/ipsp/prj.conf +++ b/samples/bluetooth/ipsp/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/bluetooth/ipsp/prj_dbg.conf b/samples/bluetooth/ipsp/prj_dbg.conf index 40474ed00b27..10f258092a0c 100644 --- a/samples/bluetooth/ipsp/prj_dbg.conf +++ b/samples/bluetooth/ipsp/prj_dbg.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/bluetooth/ipsp/prj_zep1656.conf b/samples/bluetooth/ipsp/prj_zep1656.conf index 992bf35866d6..d0a6f6661700 100644 --- a/samples/bluetooth/ipsp/prj_zep1656.conf +++ b/samples/bluetooth/ipsp/prj_zep1656.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/bluetooth/iso_broadcast/prj.conf b/samples/bluetooth/iso_broadcast/prj.conf index 8b403e885204..8a9a5f196918 100644 --- a/samples/bluetooth/iso_broadcast/prj.conf +++ b/samples/bluetooth/iso_broadcast/prj.conf @@ -1,6 +1,6 @@ CONFIG_BT=y CONFIG_BT_ISO_BROADCASTER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test ISO Broadcaster" CONFIG_BT_ISO_MAX_CHAN=2 diff --git a/samples/bluetooth/iso_receive/prj.conf b/samples/bluetooth/iso_receive/prj.conf index aed850817e31..093695a54396 100644 --- a/samples/bluetooth/iso_receive/prj.conf +++ b/samples/bluetooth/iso_receive/prj.conf @@ -1,6 +1,6 @@ CONFIG_BT=y CONFIG_BT_ISO_SYNC_RECEIVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test ISO Receive" CONFIG_BT_ISO_MAX_CHAN=2 diff --git a/samples/bluetooth/periodic_adv/prj.conf b/samples/bluetooth/periodic_adv/prj.conf index 71047b7cb47b..0fcc6e0efd59 100644 --- a/samples/bluetooth/periodic_adv/prj.conf +++ b/samples/bluetooth/periodic_adv/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y CONFIG_BT_EXT_ADV=y CONFIG_BT_PER_ADV=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test Periodic Advertising" diff --git a/samples/bluetooth/periodic_sync/prj.conf b/samples/bluetooth/periodic_sync/prj.conf index e19a567cffb5..5ae7d77144f3 100644 --- a/samples/bluetooth/periodic_sync/prj.conf +++ b/samples/bluetooth/periodic_sync/prj.conf @@ -2,5 +2,5 @@ CONFIG_BT=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y CONFIG_BT_PER_ADV_SYNC=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test Periodic Advertising Sync" diff --git a/samples/bluetooth/peripheral/prj.conf b/samples/bluetooth/peripheral/prj.conf index 549a30da79f8..9946a3107bca 100644 --- a/samples/bluetooth/peripheral/prj.conf +++ b/samples/bluetooth/peripheral/prj.conf @@ -2,7 +2,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_SIGNING=y CONFIG_BT_PERIPHERAL=y diff --git a/samples/bluetooth/peripheral_accept_list/prj.conf b/samples/bluetooth/peripheral_accept_list/prj.conf index 3ec067551193..3395353388a5 100644 --- a/samples/bluetooth/peripheral_accept_list/prj.conf +++ b/samples/bluetooth/peripheral_accept_list/prj.conf @@ -2,7 +2,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_SIGNING=y CONFIG_BT_PERIPHERAL=y diff --git a/samples/bluetooth/peripheral_gatt_write/prj.conf b/samples/bluetooth/peripheral_gatt_write/prj.conf index e01892000a14..eac63333f75b 100644 --- a/samples/bluetooth/peripheral_gatt_write/prj.conf +++ b/samples/bluetooth/peripheral_gatt_write/prj.conf @@ -11,4 +11,4 @@ CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 CONFIG_BT_L2CAP_TX_MTU=247 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/samples/bluetooth/peripheral_hids/prj.conf b/samples/bluetooth/peripheral_hids/prj.conf index f66e142c3254..dd21313836cc 100644 --- a/samples/bluetooth/peripheral_hids/prj.conf +++ b/samples/bluetooth/peripheral_hids/prj.conf @@ -2,7 +2,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DIS=y diff --git a/samples/bluetooth/peripheral_hr/prj.conf b/samples/bluetooth/peripheral_hr/prj.conf index 18815731973a..c24dc7c59673 100644 --- a/samples/bluetooth/peripheral_hr/prj.conf +++ b/samples/bluetooth/peripheral_hr/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DIS=y diff --git a/samples/bluetooth/peripheral_hr/prj_minimal.conf b/samples/bluetooth/peripheral_hr/prj_minimal.conf index 696114ff0154..888c75d8a5d5 100644 --- a/samples/bluetooth/peripheral_hr/prj_minimal.conf +++ b/samples/bluetooth/peripheral_hr/prj_minimal.conf @@ -1,5 +1,4 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=n CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DIS=y diff --git a/samples/bluetooth/peripheral_ht/prj.conf b/samples/bluetooth/peripheral_ht/prj.conf index 59360b0a0134..d25259ec6602 100644 --- a/samples/bluetooth/peripheral_ht/prj.conf +++ b/samples/bluetooth/peripheral_ht/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DIS=y diff --git a/samples/bluetooth/peripheral_iso/prj.conf b/samples/bluetooth/peripheral_iso/prj.conf index f44bf1c959df..a605030ca01c 100644 --- a/samples/bluetooth/peripheral_iso/prj.conf +++ b/samples/bluetooth/peripheral_iso/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Zephyr ISO server" CONFIG_BT_ISO_PERIPHERAL=y CONFIG_BT_SMP=y diff --git a/samples/bluetooth/peripheral_past/prj.conf b/samples/bluetooth/peripheral_past/prj.conf index 3d170fc94013..41a352ba08ac 100644 --- a/samples/bluetooth/peripheral_past/prj.conf +++ b/samples/bluetooth/peripheral_past/prj.conf @@ -3,6 +3,6 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y CONFIG_BT_PER_ADV_SYNC=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Peripheral PAST" CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y diff --git a/samples/bluetooth/peripheral_sc_only/prj.conf b/samples/bluetooth/peripheral_sc_only/prj.conf index 166454b23f21..c43abee996dc 100644 --- a/samples/bluetooth/peripheral_sc_only/prj.conf +++ b/samples/bluetooth/peripheral_sc_only/prj.conf @@ -3,7 +3,7 @@ #CONFIG_THREAD_STACK_INFO=y CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_SMP=y CONFIG_BT_SMP_SC_ONLY=y diff --git a/samples/bluetooth/scan_adv/prj.conf b/samples/bluetooth/scan_adv/prj.conf index 26db96e63345..59bff9fe1835 100644 --- a/samples/bluetooth/scan_adv/prj.conf +++ b/samples/bluetooth/scan_adv/prj.conf @@ -1,4 +1,4 @@ CONFIG_BT=y CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/samples/bluetooth/st_ble_sensor/prj.conf b/samples/bluetooth/st_ble_sensor/prj.conf index 86f773244902..eb6dae37fbec 100644 --- a/samples/bluetooth/st_ble_sensor/prj.conf +++ b/samples/bluetooth/st_ble_sensor/prj.conf @@ -1,5 +1,4 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="P2PSRV1" CONFIG_BT_GATT_CLIENT=y diff --git a/samples/bluetooth/tmap_central/prj.conf b/samples/bluetooth/tmap_central/prj.conf index 754023b82090..b73458e5dad5 100644 --- a/samples/bluetooth/tmap_central/prj.conf +++ b/samples/bluetooth/tmap_central/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_AUDIO=y diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index b821ba072a32..d742e1f2c442 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y CONFIG_BT_AUDIO=y diff --git a/samples/bluetooth/unicast_audio_client/prj.conf b/samples/bluetooth/unicast_audio_client/prj.conf index 12b619a23eda..c637a40b6902 100644 --- a/samples/bluetooth/unicast_audio_client/prj.conf +++ b/samples/bluetooth/unicast_audio_client/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_CLIENT=y diff --git a/samples/bluetooth/unicast_audio_server/prj.conf b/samples/bluetooth/unicast_audio_server/prj.conf index 7963da2b157b..37a0a5f4c6ae 100644 --- a/samples/bluetooth/unicast_audio_server/prj.conf +++ b/samples/bluetooth/unicast_audio_server/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y diff --git a/samples/boards/nrf/mesh/onoff-app/prj.conf b/samples/boards/nrf/mesh/onoff-app/prj.conf index 4f7a46499954..6c3a08f44eac 100644 --- a/samples/boards/nrf/mesh/onoff-app/prj.conf +++ b/samples/boards/nrf/mesh/onoff-app/prj.conf @@ -64,7 +64,7 @@ CONFIG_UART_CONSOLE=y # this outputs btmon formatted data to the serial port #CONFIG_BT_DEBUG_MONITOR_UART=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_LOG_LEVEL_DBG=y diff --git a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/prj.conf b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/prj.conf index 832a600af84c..e617afed89f4 100644 --- a/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/prj.conf +++ b/samples/boards/nrf/mesh/onoff_level_lighting_vnd_app/prj.conf @@ -59,7 +59,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 #CONFIG_UART_CONSOLE=n #CONFIG_BT_DEBUG_MONITOR_UART=y -#CONFIG_BT_DEBUG_LOG=y +#CONFIG_LOG=y ##CONFIG_BT_MESH_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_LOG_LEVEL_DBG=y diff --git a/samples/boards/reel_board/mesh_badge/prj.conf b/samples/boards/reel_board/mesh_badge/prj.conf index 5d470fa0f0d6..833ca55da342 100644 --- a/samples/boards/reel_board/mesh_badge/prj.conf +++ b/samples/boards/reel_board/mesh_badge/prj.conf @@ -12,7 +12,7 @@ CONFIG_BT_PRIVACY=y CONFIG_BT_DEVICE_NAME="reel board" CONFIG_BT_DEVICE_NAME_MAX=32 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y #CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_ADV_LOG_LEVEL_DBG=y diff --git a/samples/net/lwm2m_client/overlay-bt.conf b/samples/net/lwm2m_client/overlay-bt.conf index 746c3912f8c1..01c59b599eb6 100644 --- a/samples/net/lwm2m_client/overlay-bt.conf +++ b/samples/net/lwm2m_client/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/mdns_responder/overlay-bt.conf b/samples/net/mdns_responder/overlay-bt.conf index 7e65c3e613ba..ad6ca65e38e2 100644 --- a/samples/net/mdns_responder/overlay-bt.conf +++ b/samples/net/mdns_responder/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/mqtt_publisher/overlay-bt.conf b/samples/net/mqtt_publisher/overlay-bt.conf index 1874b663c8f0..9151d577057b 100644 --- a/samples/net/mqtt_publisher/overlay-bt.conf +++ b/samples/net/mqtt_publisher/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/sockets/echo_client/overlay-bt.conf b/samples/net/sockets/echo_client/overlay-bt.conf index c7fb54cc9af1..2902c7300259 100644 --- a/samples/net/sockets/echo_client/overlay-bt.conf +++ b/samples/net/sockets/echo_client/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/sockets/echo_server/overlay-bt.conf b/samples/net/sockets/echo_server/overlay-bt.conf index e4ba34cb5237..66b316c06c80 100644 --- a/samples/net/sockets/echo_server/overlay-bt.conf +++ b/samples/net/sockets/echo_server/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/telnet/overlay-bt.conf b/samples/net/telnet/overlay-bt.conf index 84a5339be9af..3b7eaaffbea2 100644 --- a/samples/net/telnet/overlay-bt.conf +++ b/samples/net/telnet/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/samples/net/zperf/overlay-bt.conf b/samples/net/zperf/overlay-bt.conf index db4708981e94..43378326544e 100644 --- a/samples/net/zperf/overlay-bt.conf +++ b/samples/net/zperf/overlay-bt.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_SMP=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y From f5ff8862603256eb14e405539f8b478ab5757b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 7 Jun 2023 08:10:39 +0200 Subject: [PATCH 0004/2042] Bluetooth: Tests: Remove usage of `BT_DEBUG_LOG` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove usage of Kconfig symbol `CONFIG_BT_DEBUG_LOG` from tests. It has been deprecated since this PR: https://github.com/zephyrproject-rtos/zephyr/pull/56183 The Kconfig symbols has been replaced by `CONFIG_LOG=y` on most of the cases. Or it has been removed when not needed anymore. Signed-off-by: Théo Battrel --- tests/bluetooth/adv/prj.conf | 2 +- tests/bluetooth/audio/ascs/prj.conf | 2 +- tests/bluetooth/bluetooth/prj.conf | 2 +- tests/bluetooth/gatt/prj.conf | 2 +- tests/bluetooth/hci_prop_evt/prj.conf | 2 +- tests/bluetooth/host/keys/bt_keys_add_type/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_clear/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_find/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_find_addr/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_find_irk/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_foreach_bond/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_foreach_type/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_get_type/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_store/prj.conf | 1 - tests/bluetooth/host/keys/bt_keys_update_usage/prj.conf | 1 - tests/bluetooth/host_long_adv_recv/prj.conf | 2 +- tests/bluetooth/init/prj.conf | 2 +- tests/bluetooth/init/prj_17.conf | 2 +- tests/bluetooth/init/prj_h5_dbg.conf | 2 +- tests/bluetooth/l2cap/prj.conf | 2 +- tests/bluetooth/mesh/basic/dbg.conf | 2 +- tests/bluetooth/mesh/basic/ext_adv.conf | 2 +- tests/bluetooth/mesh/basic/lpn.conf | 2 +- tests/bluetooth/mesh/basic/multi_ext_adv.conf | 2 +- tests/bluetooth/mesh/basic/prj.conf | 2 +- tests/bluetooth/mesh_shell/prj.conf | 2 +- tests/bluetooth/shell/audio.conf | 3 +-- tests/bluetooth/shell/log.conf | 2 +- tests/bluetooth/shell/mesh.conf | 2 +- tests/bluetooth/shell/prj.conf | 2 +- tests/bluetooth/shell/prj_br.conf | 2 +- tests/bluetooth/tester/boards/nrf52840dk_nrf52840.conf | 2 +- tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf | 2 +- tests/bluetooth/tester/boards/qemu_cortex_m3.conf | 2 +- tests/bsim/bluetooth/audio/prj.conf | 2 +- tests/bsim/bluetooth/host/adv/resume/prj.conf | 2 +- tests/bsim/bluetooth/host/adv/resume/prj_2.conf | 2 +- tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf | 2 +- tests/bsim/bluetooth/host/att/eatt/prj_collision.conf | 2 +- tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf | 2 +- tests/bsim/bluetooth/host/att/read_fill_buf/client/prj.conf | 2 +- tests/bsim/bluetooth/host/att/read_fill_buf/server/prj.conf | 2 +- tests/bsim/bluetooth/host/gatt/notify/prj.conf | 2 +- tests/bsim/bluetooth/host/gatt/notify_multiple/prj.conf | 2 +- tests/bsim/bluetooth/host/l2cap/split/dut/prj.conf | 2 +- tests/bsim/bluetooth/host/l2cap/stress/prj.conf | 1 - .../bluetooth/host/security/bond_overwrite_allowed/prj.conf | 2 +- .../bluetooth/host/security/bond_overwrite_denied/prj.conf | 2 +- tests/bsim/bluetooth/ll/cis/prj.conf | 2 +- tests/bsim/bluetooth/ll/conn/prj_split.conf | 2 +- tests/bsim/bluetooth/ll/conn/prj_split_low_lat.conf | 2 +- tests/bsim/bluetooth/ll/conn/prj_split_privacy.conf | 2 +- tests/bsim/bluetooth/ll/conn/prj_split_single_timer.conf | 2 +- tests/bsim/bluetooth/ll/edtt/gatt_test_app/prj_llcp.conf | 2 +- tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_dut_llcp.conf | 2 +- tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_tst_llcp.conf | 2 +- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- 59 files changed, 47 insertions(+), 60 deletions(-) diff --git a/tests/bluetooth/adv/prj.conf b/tests/bluetooth/adv/prj.conf index 19e7c1b8f21d..e6fddd337d04 100644 --- a/tests/bluetooth/adv/prj.conf +++ b/tests/bluetooth/adv/prj.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_DEVICE_NAME="Test Adv Data" CONFIG_ASSERT=y CONFIG_ZTEST=y diff --git a/tests/bluetooth/audio/ascs/prj.conf b/tests/bluetooth/audio/ascs/prj.conf index d7a8a6e18d6d..9376de2355b2 100644 --- a/tests/bluetooth/audio/ascs/prj.conf +++ b/tests/bluetooth/audio/ascs/prj.conf @@ -15,7 +15,7 @@ CONFIG_BT_ISO_MAX_CHAN=2 # Mandatory to support at least 1 for ASCS CONFIG_BT_ATT_PREPARE_COUNT=1 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ASCS_LOG_LEVEL_DBG=y CONFIG_BT_BAP_ISO_LOG_LEVEL_DBG=y CONFIG_BT_BAP_STREAM_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/bluetooth/prj.conf b/tests/bluetooth/bluetooth/prj.conf index 2db2bc239404..c150a19272d0 100644 --- a/tests/bluetooth/bluetooth/prj.conf +++ b/tests/bluetooth/bluetooth/prj.conf @@ -1,7 +1,7 @@ CONFIG_BT=y CONFIG_BT_CTLR=n CONFIG_BT_NO_DRIVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_UART_INTERRUPT_DRIVEN=n CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y diff --git a/tests/bluetooth/gatt/prj.conf b/tests/bluetooth/gatt/prj.conf index 540f6ddf4a9e..796b840d6815 100644 --- a/tests/bluetooth/gatt/prj.conf +++ b/tests/bluetooth/gatt/prj.conf @@ -6,6 +6,6 @@ CONFIG_BT=y CONFIG_BT_CTLR=n CONFIG_BT_NO_DRIVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_GATT_DYNAMIC_DB=y diff --git a/tests/bluetooth/hci_prop_evt/prj.conf b/tests/bluetooth/hci_prop_evt/prj.conf index 7bc1a2cad714..242ff1e19540 100644 --- a/tests/bluetooth/hci_prop_evt/prj.conf +++ b/tests/bluetooth/hci_prop_evt/prj.conf @@ -9,7 +9,7 @@ CONFIG_BT_RECV_BLOCKING=y CONFIG_BT_HCI_VS_EVT_USER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=y CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/host/keys/bt_keys_add_type/prj.conf b/tests/bluetooth/host/keys/bt_keys_add_type/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_add_type/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_add_type/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_clear/prj.conf b/tests/bluetooth/host/keys/bt_keys_clear/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_clear/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_clear/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_find/prj.conf b/tests/bluetooth/host/keys/bt_keys_find/prj.conf index f32133f11882..4f07ff598174 100644 --- a/tests/bluetooth/host/keys/bt_keys_find/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_find/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_find_addr/prj.conf b/tests/bluetooth/host/keys/bt_keys_find_addr/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_find_addr/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_find_addr/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_find_irk/prj.conf b/tests/bluetooth/host/keys/bt_keys_find_irk/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_find_irk/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_find_irk/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_foreach_bond/prj.conf b/tests/bluetooth/host/keys/bt_keys_foreach_bond/prj.conf index 5a575943b324..f974a1868bb8 100644 --- a/tests/bluetooth/host/keys/bt_keys_foreach_bond/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_foreach_bond/prj.conf @@ -7,5 +7,4 @@ CONFIG_ASSERT=y CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_foreach_type/prj.conf b/tests/bluetooth/host/keys/bt_keys_foreach_type/prj.conf index c41ea9eec9da..e45b77e8764d 100644 --- a/tests/bluetooth/host/keys/bt_keys_foreach_type/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_foreach_type/prj.conf @@ -7,5 +7,4 @@ CONFIG_ASSERT=y CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf b/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf index 5a575943b324..f974a1868bb8 100644 --- a/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_get_addr/prj.conf @@ -7,5 +7,4 @@ CONFIG_ASSERT=y CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_get_type/prj.conf b/tests/bluetooth/host/keys/bt_keys_get_type/prj.conf index f32133f11882..4f07ff598174 100644 --- a/tests/bluetooth/host/keys/bt_keys_get_type/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_get_type/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_store/prj.conf b/tests/bluetooth/host/keys/bt_keys_store/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_store/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_store/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host/keys/bt_keys_update_usage/prj.conf b/tests/bluetooth/host/keys/bt_keys_update_usage/prj.conf index 0d8659cbf89b..2d9af947d943 100644 --- a/tests/bluetooth/host/keys/bt_keys_update_usage/prj.conf +++ b/tests/bluetooth/host/keys/bt_keys_update_usage/prj.conf @@ -8,5 +8,4 @@ CONFIG_ASSERT_LEVEL=2 CONFIG_ASSERT_VERBOSE=y CONFIG_LOG=n -CONFIG_BT_DEBUG_LOG=n CONFIG_TEST_LOGGING_DEFAULTS=n diff --git a/tests/bluetooth/host_long_adv_recv/prj.conf b/tests/bluetooth/host_long_adv_recv/prj.conf index e58a5236e279..68a16e685017 100644 --- a/tests/bluetooth/host_long_adv_recv/prj.conf +++ b/tests/bluetooth/host_long_adv_recv/prj.conf @@ -11,7 +11,7 @@ CONFIG_BT_NO_DRIVER=y CONFIG_BT_RECV_BLOCKING=y CONFIG_BT_EXT_ADV=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=n CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=n CONFIG_BT_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/init/prj.conf b/tests/bluetooth/init/prj.conf index 481ee77a89f8..2103829ea4e2 100644 --- a/tests/bluetooth/init/prj.conf +++ b/tests/bluetooth/init/prj.conf @@ -1,4 +1,4 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y diff --git a/tests/bluetooth/init/prj_17.conf b/tests/bluetooth/init/prj_17.conf index d1fd95b5cdf5..9c2b3689f3aa 100644 --- a/tests/bluetooth/init/prj_17.conf +++ b/tests/bluetooth/init/prj_17.conf @@ -8,7 +8,7 @@ CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_USE_DEBUG_KEYS=y CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y CONFIG_BT_GATT_CLIENT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=y CONFIG_BT_CONN_LOG_LEVEL_DBG=y CONFIG_BT_KEYS_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/init/prj_h5_dbg.conf b/tests/bluetooth/init/prj_h5_dbg.conf index f8733eb2ee27..28ef86d3e09f 100644 --- a/tests/bluetooth/init/prj_h5_dbg.conf +++ b/tests/bluetooth/init/prj_h5_dbg.conf @@ -1,6 +1,6 @@ CONFIG_BT=y CONFIG_BT_H5=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_HCI_DRIVER_LOG_LEVEL_DBG=y CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y diff --git a/tests/bluetooth/l2cap/prj.conf b/tests/bluetooth/l2cap/prj.conf index 4b037492d438..3a7449d2618c 100644 --- a/tests/bluetooth/l2cap/prj.conf +++ b/tests/bluetooth/l2cap/prj.conf @@ -6,7 +6,7 @@ CONFIG_BT=y CONFIG_BT_CTLR=n CONFIG_BT_NO_DRIVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_SMP=y CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y diff --git a/tests/bluetooth/mesh/basic/dbg.conf b/tests/bluetooth/mesh/basic/dbg.conf index 6ce4b719f598..6a7af5638281 100644 --- a/tests/bluetooth/mesh/basic/dbg.conf +++ b/tests/bluetooth/mesh/basic/dbg.conf @@ -42,7 +42,7 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y #CONFIG_UART_CONSOLE=n #CONFIG_BT_DEBUG_MONITOR_UART=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_PROV_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/mesh/basic/ext_adv.conf b/tests/bluetooth/mesh/basic/ext_adv.conf index 7760f74202d6..db03b4446083 100644 --- a/tests/bluetooth/mesh/basic/ext_adv.conf +++ b/tests/bluetooth/mesh/basic/ext_adv.conf @@ -42,7 +42,7 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y #CONFIG_UART_CONSOLE=n #CONFIG_BT_DEBUG_MONITOR_UART=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_PROV_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/mesh/basic/lpn.conf b/tests/bluetooth/mesh/basic/lpn.conf index 2fddf6aa0c43..cb40ce345134 100644 --- a/tests/bluetooth/mesh/basic/lpn.conf +++ b/tests/bluetooth/mesh/basic/lpn.conf @@ -42,7 +42,7 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y #CONFIG_UART_CONSOLE=n #CONFIG_BT_DEBUG_MONITOR_UART=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y #CONFIG_BT_MESH_PROV_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/mesh/basic/multi_ext_adv.conf b/tests/bluetooth/mesh/basic/multi_ext_adv.conf index 19eaee8e3a64..610318f847b6 100644 --- a/tests/bluetooth/mesh/basic/multi_ext_adv.conf +++ b/tests/bluetooth/mesh/basic/multi_ext_adv.conf @@ -40,7 +40,7 @@ CONFIG_BT_MESH_LABEL_COUNT=3 CONFIG_BT_MESH_IV_UPDATE_TEST=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_PROV_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/mesh/basic/prj.conf b/tests/bluetooth/mesh/basic/prj.conf index abff7c67bdf7..93b99d2f3731 100644 --- a/tests/bluetooth/mesh/basic/prj.conf +++ b/tests/bluetooth/mesh/basic/prj.conf @@ -44,7 +44,7 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y #CONFIG_UART_CONSOLE=n #CONFIG_BT_DEBUG_MONITOR_UART=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_PROV_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/mesh_shell/prj.conf b/tests/bluetooth/mesh_shell/prj.conf index 760c8de47f33..0672ec6cbb31 100644 --- a/tests/bluetooth/mesh_shell/prj.conf +++ b/tests/bluetooth/mesh_shell/prj.conf @@ -70,7 +70,7 @@ CONFIG_BT_MESH_MODEL_KEY_COUNT=3 CONFIG_BT_MESH_MODEL_GROUP_COUNT=2 CONFIG_BT_MESH_LABEL_COUNT=1 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=4000 CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=250 diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 4da572680632..32d8315b0b40 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -7,7 +7,6 @@ CONFIG_BT_RX_STACK_SIZE=4096 CONFIG_TEST=y CONFIG_TEST_LOGGING_DEFAULTS=n CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y CONFIG_BT_TESTING=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y @@ -144,7 +143,7 @@ CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y CONFIG_BT_CAP_INITIATOR=y # DEBUGGING -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_MPL_LOG_LEVEL_DBG=y CONFIG_BT_MCS_LOG_LEVEL_DBG=y CONFIG_BT_MCC_LOG_LEVEL_DBG=y diff --git a/tests/bluetooth/shell/log.conf b/tests/bluetooth/shell/log.conf index 9724a6f9bd31..6c278246e33a 100644 --- a/tests/bluetooth/shell/log.conf +++ b/tests/bluetooth/shell/log.conf @@ -30,7 +30,7 @@ CONFIG_BT_REMOTE_VERSION=y CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y # Disable BT logging and enable general logging -CONFIG_BT_DEBUG_LOG=n +CONFIG_BT_LOG_LEVEL_OFF=y CONFIG_LOG=y CONFIG_BT_SETTINGS=y diff --git a/tests/bluetooth/shell/mesh.conf b/tests/bluetooth/shell/mesh.conf index c67416775e61..a8079eb7b28b 100644 --- a/tests/bluetooth/shell/mesh.conf +++ b/tests/bluetooth/shell/mesh.conf @@ -4,7 +4,7 @@ CONFIG_TEST_LOGGING_DEFAULTS=n CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bluetooth/shell/prj.conf b/tests/bluetooth/shell/prj.conf index e7657ddc8b87..168ccf62a7f9 100644 --- a/tests/bluetooth/shell/prj.conf +++ b/tests/bluetooth/shell/prj.conf @@ -4,7 +4,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_TEST=y CONFIG_TEST_LOGGING_DEFAULTS=n CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bluetooth/shell/prj_br.conf b/tests/bluetooth/shell/prj_br.conf index ddd92ed064f6..11cad5cfd92c 100644 --- a/tests/bluetooth/shell/prj_br.conf +++ b/tests/bluetooth/shell/prj_br.conf @@ -3,7 +3,7 @@ CONFIG_BT=y CONFIG_BT_BREDR=y CONFIG_BT_RFCOMM=y CONFIG_BT_SHELL=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bluetooth/tester/boards/nrf52840dk_nrf52840.conf b/tests/bluetooth/tester/boards/nrf52840dk_nrf52840.conf index 22321dfddd4b..29139393b46a 100644 --- a/tests/bluetooth/tester/boards/nrf52840dk_nrf52840.conf +++ b/tests/bluetooth/tester/boards/nrf52840dk_nrf52840.conf @@ -7,7 +7,7 @@ CONFIG_ASSERT=y CONFIG_THREAD_NAME=y CONFIG_HW_STACK_PROTECTION=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=4096 CONFIG_RTT_CONSOLE=y CONFIG_LOG_BACKEND_RTT=y diff --git a/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf b/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf index 22321dfddd4b..29139393b46a 100644 --- a/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/tests/bluetooth/tester/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -7,7 +7,7 @@ CONFIG_ASSERT=y CONFIG_THREAD_NAME=y CONFIG_HW_STACK_PROTECTION=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=4096 CONFIG_RTT_CONSOLE=y CONFIG_LOG_BACKEND_RTT=y diff --git a/tests/bluetooth/tester/boards/qemu_cortex_m3.conf b/tests/bluetooth/tester/boards/qemu_cortex_m3.conf index c44cb7434443..c1f9aa465c43 100644 --- a/tests/bluetooth/tester/boards/qemu_cortex_m3.conf +++ b/tests/bluetooth/tester/boards/qemu_cortex_m3.conf @@ -1,6 +1,6 @@ CONFIG_INIT_STACKS=y CONFIG_PRINTK=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_HCI_CORE_LOG_LEVEL_DBG=y CONFIG_BT_CONN_LOG_LEVEL_DBG=y CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 54b69aef8add..e33905562a25 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -119,7 +119,7 @@ CONFIG_BT_CAP_INITIATOR=y CONFIG_BT_TMAP=y # DEBUGGING -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL_DBG=y CONFIG_BT_AICS_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/adv/resume/prj.conf b/tests/bsim/bluetooth/host/adv/resume/prj.conf index ec138585fd77..1d6ee14d0bb3 100644 --- a/tests/bsim/bluetooth/host/adv/resume/prj.conf +++ b/tests/bsim/bluetooth/host/adv/resume/prj.conf @@ -4,7 +4,7 @@ CONFIG_BT_CENTRAL=y CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_EXT_ADV=n CONFIG_BT_PRIVACY=n diff --git a/tests/bsim/bluetooth/host/adv/resume/prj_2.conf b/tests/bsim/bluetooth/host/adv/resume/prj_2.conf index 8b229c2b398d..444ba8499e43 100644 --- a/tests/bsim/bluetooth/host/adv/resume/prj_2.conf +++ b/tests/bsim/bluetooth/host/adv/resume/prj_2.conf @@ -3,7 +3,7 @@ CONFIG_BT_PERIPHERAL=y CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_EXT_ADV=y CONFIG_BT_PRIVACY=n diff --git a/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf b/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf index 68a6d7445e02..39caef2b6302 100644 --- a/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf +++ b/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf @@ -10,7 +10,7 @@ CONFIG_BT_EATT_MAX=5 CONFIG_BT_MAX_CONN=1 CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_ASSERT=y CONFIG_BT_L2CAP_TX_MTU=200 diff --git a/tests/bsim/bluetooth/host/att/eatt/prj_collision.conf b/tests/bsim/bluetooth/host/att/eatt/prj_collision.conf index 7b82b4748989..0b27819bba74 100644 --- a/tests/bsim/bluetooth/host/att/eatt/prj_collision.conf +++ b/tests/bsim/bluetooth/host/att/eatt/prj_collision.conf @@ -11,5 +11,5 @@ CONFIG_BT_MAX_CONN=1 CONFIG_BT_EATT_AUTO_CONNECT=n CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf b/tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf index cd05f4602c59..b746172ba23e 100644 --- a/tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf +++ b/tests/bsim/bluetooth/host/att/eatt/prj_multiple_conn.conf @@ -11,5 +11,5 @@ CONFIG_BT_MAX_CONN=2 CONFIG_BT_EATT_AUTO_CONNECT=n CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/att/read_fill_buf/client/prj.conf b/tests/bsim/bluetooth/host/att/read_fill_buf/client/prj.conf index 848e0dff2c45..ee1c40f43009 100644 --- a/tests/bsim/bluetooth/host/att/read_fill_buf/client/prj.conf +++ b/tests/bsim/bluetooth/host/att/read_fill_buf/client/prj.conf @@ -14,5 +14,5 @@ CONFIG_BT_GATT_CLIENT=y CONFIG_BT_L2CAP_TX_MTU=200 CONFIG_BT_BUF_ACL_RX_SIZE=204 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ATT_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/att/read_fill_buf/server/prj.conf b/tests/bsim/bluetooth/host/att/read_fill_buf/server/prj.conf index 01a7857243f0..14e44e667273 100644 --- a/tests/bsim/bluetooth/host/att/read_fill_buf/server/prj.conf +++ b/tests/bsim/bluetooth/host/att/read_fill_buf/server/prj.conf @@ -13,5 +13,5 @@ CONFIG_BT_EATT=y CONFIG_BT_EXT_ADV=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ATT_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/gatt/notify/prj.conf b/tests/bsim/bluetooth/host/gatt/notify/prj.conf index 3040eee6aca7..823a6ae88455 100644 --- a/tests/bsim/bluetooth/host/gatt/notify/prj.conf +++ b/tests/bsim/bluetooth/host/gatt/notify/prj.conf @@ -14,4 +14,4 @@ CONFIG_BT_EATT_MAX=5 CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/tests/bsim/bluetooth/host/gatt/notify_multiple/prj.conf b/tests/bsim/bluetooth/host/gatt/notify_multiple/prj.conf index 4fd7e8952fcf..0f0e7b960aa9 100644 --- a/tests/bsim/bluetooth/host/gatt/notify_multiple/prj.conf +++ b/tests/bsim/bluetooth/host/gatt/notify_multiple/prj.conf @@ -15,4 +15,4 @@ CONFIG_BT_GATT_NOTIFY_MULTIPLE=y CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y diff --git a/tests/bsim/bluetooth/host/l2cap/split/dut/prj.conf b/tests/bsim/bluetooth/host/l2cap/split/dut/prj.conf index 847c8505e254..253149a961ff 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/dut/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/split/dut/prj.conf @@ -1,7 +1,7 @@ CONFIG_LOG=y CONFIG_ASSERT=y CONFIG_NET_BUF_POOL_USAGE=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT=y CONFIG_BT_CENTRAL=y diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf index fcb08ee2217c..3560a1b1f4be 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf @@ -45,5 +45,4 @@ CONFIG_BT_MAX_CONN=10 CONFIG_LOG=y CONFIG_ASSERT=y -CONFIG_BT_DEBUG_LOG=y CONFIG_NET_BUF_POOL_USAGE=y diff --git a/tests/bsim/bluetooth/host/security/bond_overwrite_allowed/prj.conf b/tests/bsim/bluetooth/host/security/bond_overwrite_allowed/prj.conf index b8851a8165c3..ae897174d23e 100644 --- a/tests/bsim/bluetooth/host/security/bond_overwrite_allowed/prj.conf +++ b/tests/bsim/bluetooth/host/security/bond_overwrite_allowed/prj.conf @@ -6,7 +6,7 @@ CONFIG_BT_SMP=y CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ID_MAX=3 CONFIG_BT_MAX_PAIRED=2 diff --git a/tests/bsim/bluetooth/host/security/bond_overwrite_denied/prj.conf b/tests/bsim/bluetooth/host/security/bond_overwrite_denied/prj.conf index 96fd6dc2f4f1..58b9fb8cb73c 100644 --- a/tests/bsim/bluetooth/host/security/bond_overwrite_denied/prj.conf +++ b/tests/bsim/bluetooth/host/security/bond_overwrite_denied/prj.conf @@ -6,7 +6,7 @@ CONFIG_BT_SMP=y CONFIG_ASSERT=y CONFIG_BT_TESTING=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ID_MAX=3 CONFIG_BT_MAX_PAIRED=2 diff --git a/tests/bsim/bluetooth/ll/cis/prj.conf b/tests/bsim/bluetooth/ll/cis/prj.conf index 7e032017ca66..f7aa0bd7ed7b 100644 --- a/tests/bsim/bluetooth/ll/cis/prj.conf +++ b/tests/bsim/bluetooth/ll/cis/prj.conf @@ -21,7 +21,7 @@ CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_USE_DEBUG_KEYS=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y # Controller Settings CONFIG_BT_LL_SW_SPLIT=y diff --git a/tests/bsim/bluetooth/ll/conn/prj_split.conf b/tests/bsim/bluetooth/ll/conn/prj_split.conf index 84bdc1da484b..94eae38bf62e 100644 --- a/tests/bsim/bluetooth/ll/conn/prj_split.conf +++ b/tests/bsim/bluetooth/ll/conn/prj_split.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bsim/bluetooth/ll/conn/prj_split_low_lat.conf b/tests/bsim/bluetooth/ll/conn/prj_split_low_lat.conf index a6246ea52c2b..b00b6c74b934 100644 --- a/tests/bsim/bluetooth/ll/conn/prj_split_low_lat.conf +++ b/tests/bsim/bluetooth/ll/conn/prj_split_low_lat.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bsim/bluetooth/ll/conn/prj_split_privacy.conf b/tests/bsim/bluetooth/ll/conn/prj_split_privacy.conf index d728cdc36849..7c490964fbed 100644 --- a/tests/bsim/bluetooth/ll/conn/prj_split_privacy.conf +++ b/tests/bsim/bluetooth/ll/conn/prj_split_privacy.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bsim/bluetooth/ll/conn/prj_split_single_timer.conf b/tests/bsim/bluetooth/ll/conn/prj_split_single_timer.conf index f76368524b7d..9d446e0149f8 100644 --- a/tests/bsim/bluetooth/ll/conn/prj_split_single_timer.conf +++ b/tests/bsim/bluetooth/ll/conn/prj_split_single_timer.conf @@ -1,5 +1,5 @@ CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_PRIVACY=y diff --git a/tests/bsim/bluetooth/ll/edtt/gatt_test_app/prj_llcp.conf b/tests/bsim/bluetooth/ll/edtt/gatt_test_app/prj_llcp.conf index e9109de95b95..1fdcd1a770f6 100644 --- a/tests/bsim/bluetooth/ll/edtt/gatt_test_app/prj_llcp.conf +++ b/tests/bsim/bluetooth/ll/edtt/gatt_test_app/prj_llcp.conf @@ -16,7 +16,7 @@ CONFIG_BT_CTLR=y CONFIG_BT_HCI_ACL_FLOW_CONTROL=y CONFIG_BT_BUF_ACL_RX_SIZE=516 CONFIG_BT_L2CAP_TX_MTU=512 -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y # NOTE: In order to get ACL_FLOW_CONTROL to work it is imperative that # BT_CTRL_RX_BUFFERS is increased from its default value of 1. diff --git a/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_dut_llcp.conf b/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_dut_llcp.conf index e2424dcc5ba5..b734a6cbbc34 100644 --- a/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_dut_llcp.conf +++ b/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_dut_llcp.conf @@ -6,7 +6,7 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_BROADCASTER=y CONFIG_BT_CENTRAL=y CONFIG_BT_OBSERVER=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ECC=y # BUF_CMD_TX_SIZE must be 255 because of HCI/GEV/BV-01-C diff --git a/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_tst_llcp.conf b/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_tst_llcp.conf index ba8ee7c934bf..e904af2a277f 100644 --- a/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_tst_llcp.conf +++ b/tests/bsim/bluetooth/ll/edtt/hci_test_app/prj_tst_llcp.conf @@ -4,7 +4,7 @@ CONFIG_BT=y CONFIG_BT_HCI_RAW=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_ECC=y # BUF_CMD_TX_SIZE must be 255 because of HCI/GEV/BV-01-C diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index 84dfa186dcbc..ab15e1a136c7 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -4,7 +4,7 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=32768 # Bluetooth configuration CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PRIVACY=n CONFIG_BT_COMPANY_ID=0x0059 CONFIG_BT_DEVICE_NAME="Mesh test" diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index 7d6738f73324..769848ad634b 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -4,7 +4,7 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=32768 # Bluetooth configuration CONFIG_BT=y -CONFIG_BT_DEBUG_LOG=y +CONFIG_LOG=y CONFIG_BT_PRIVACY=n CONFIG_BT_COMPANY_ID=0x0059 CONFIG_BT_DEVICE_NAME="Mesh test" From b90fc34759b245ed367c0d5eb364c6e2f0c7d36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 7 Jun 2023 12:09:34 +0200 Subject: [PATCH 0005/2042] Bluetooth: Documentation: Remove reference to `BT_DEBUG_LOG` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove reference to deprecated Kconfig symbol `CONFIG_BT_DEBUG_LOG` in the documentation. Signed-off-by: Théo Battrel --- doc/connectivity/bluetooth/bluetooth-dev.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/connectivity/bluetooth/bluetooth-dev.rst b/doc/connectivity/bluetooth/bluetooth-dev.rst index abe8b3a5e0fd..3925e3de1b46 100644 --- a/doc/connectivity/bluetooth/bluetooth-dev.rst +++ b/doc/connectivity/bluetooth/bluetooth-dev.rst @@ -106,7 +106,7 @@ which is comprised of the following devices: bt_hci_core: opcode 0x0c33 status 0x12 when booting your sample of choice (make sure you have enabled - :kconfig:option:`CONFIG_BT_DEBUG_LOG` in your :file:`prj.conf` before running the + :kconfig:option:`CONFIG_LOG` in your :file:`prj.conf` before running the sample), or if there is no data flowing from the Controller to the Host, then you need to disable Host to Controller flow control. To do so, set ``CONFIG_BT_HCI_ACL_FLOW_CONTROL=n`` in your :file:`prj.conf`. From 2602b7260fe9031c3ac0cbb1c34fea16e83fc4ee Mon Sep 17 00:00:00 2001 From: Jose Alberto Meza Date: Wed, 7 Jun 2023 10:34:35 -0700 Subject: [PATCH 0006/2042] samples: drivers: peci: Exclude MEC172x EVB from test PECI bus sample requires a controller and a target Intel system(PECI controller) + Embedded controller(PECI target), where EC HW can be add-on card (mec172xmodular) or onboard EC. MEC172x EVB is not intended to be connected hence excluding the platform. Signed-off-by: Jose Alberto Meza --- samples/drivers/peci/sample.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/drivers/peci/sample.yaml b/samples/drivers/peci/sample.yaml index d036c27ff218..50d1def24e0b 100644 --- a/samples/drivers/peci/sample.yaml +++ b/samples/drivers/peci/sample.yaml @@ -4,7 +4,9 @@ tests: sample.drivers.peci: # theoretically EVB can be connected to Intel RVP as well, # but HW setup is not documented, hence qualifying as unsupported. - platform_exclude: mec15xxevb_assy6853 + platform_exclude: + - mec15xxevb_assy6853 + - mec172xevb_assy6906 integration_platforms: - npcx9m6f_evb filter: dt_alias_exists("peci-0") From d281b8db73a113455733708707ab25f23948e132 Mon Sep 17 00:00:00 2001 From: Jose Alberto Meza Date: Tue, 13 Sep 2022 12:19:49 +0530 Subject: [PATCH 0007/2042] boards: mec172xmodular_assy6930: Correct EC bootloader settings Changing the EC ROM bootloader mode to Quad from Dual and SPI drivestrength to 8mA This changes are required because of the different SPI flash used which doesn't support Dual mode. Signed-off-by: Jose Alberto Meza --- .../arm/mec172xmodular_assy6930/support/spi_cfg_4MBit.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/arm/mec172xmodular_assy6930/support/spi_cfg_4MBit.txt b/boards/arm/mec172xmodular_assy6930/support/spi_cfg_4MBit.txt index 809e67b356ed..3ff5528da906 100644 --- a/boards/arm/mec172xmodular_assy6930/support/spi_cfg_4MBit.txt +++ b/boards/arm/mec172xmodular_assy6930/support/spi_cfg_4MBit.txt @@ -14,10 +14,10 @@ TagAddr1 = 0 BoardID = 0 [IMAGE "0"] -ImageLocation = 0x1000 +ImageLocation = 0x100 SpiFreqMHz = 24 -SpiReadCommand = Dual -SpiDriveStrength = 4 +SpiReadCommand = Quad +SpiDriveStrength = 8 SpiSlewFast = false SpiSignalControl = 0x00 FwBinFile = zephyr.bin From 57ab4f4cf41797873f689b43e1166361e02ea6e4 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Wed, 7 Jun 2023 13:05:07 +0200 Subject: [PATCH 0008/2042] Bluetooth: samples: ISO: Check validity of incoming data Only print incoming data when the data is valid. Otherwise we also print incoming data when no data was received. Signed-off-by: Rubin Gerritsen --- samples/bluetooth/peripheral_iso/src/main.c | 6 ++++-- samples/bluetooth/unicast_audio_client/src/main.c | 4 +++- samples/bluetooth/unicast_audio_server/src/main.c | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/bluetooth/peripheral_iso/src/main.c b/samples/bluetooth/peripheral_iso/src/main.c index 9d3a1d361b57..95f415e95038 100644 --- a/samples/bluetooth/peripheral_iso/src/main.c +++ b/samples/bluetooth/peripheral_iso/src/main.c @@ -91,8 +91,10 @@ static void iso_print_data(uint8_t *data, size_t data_len) static void iso_recv(struct bt_iso_chan *chan, const struct bt_iso_recv_info *info, struct net_buf *buf) { - printk("Incoming data channel %p len %u\n", chan, buf->len); - iso_print_data(buf->data, buf->len); + if (info->flags & BT_ISO_FLAGS_VALID) { + printk("Incoming data channel %p len %u\n", chan, buf->len); + iso_print_data(buf->data, buf->len); + } } static void iso_connected(struct bt_iso_chan *chan) diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 275ece02a8a2..111eac2185a8 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -535,7 +535,9 @@ static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - printk("Incoming audio on stream %p len %u\n", stream, buf->len); + if (info->flags & BT_ISO_FLAGS_VALID) { + printk("Incoming audio on stream %p len %u\n", stream, buf->len); + } } static struct bt_bap_stream_ops stream_ops = { diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 925bdf0f34c9..ff54923eab22 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -545,7 +545,9 @@ static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - printk("Incoming audio on stream %p len %u\n", stream, buf->len); + if (info->flags & BT_ISO_FLAGS_VALID) { + printk("Incoming audio on stream %p len %u\n", stream, buf->len); + } } #endif From 58cc10b333f392b80ba03f9162c4deb707854fe2 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Wed, 7 Jun 2023 13:06:43 +0200 Subject: [PATCH 0009/2042] Bluetooth: samples: central_iso: Unref if send fails Fixes a resource leak. Signed-off-by: Rubin Gerritsen --- samples/bluetooth/central_iso/src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/bluetooth/central_iso/src/main.c b/samples/bluetooth/central_iso/src/main.c index f3d4359414cb..c5da26373b1d 100644 --- a/samples/bluetooth/central_iso/src/main.c +++ b/samples/bluetooth/central_iso/src/main.c @@ -67,6 +67,7 @@ static void iso_timer_timeout(struct k_work *work) if (ret < 0) { printk("Failed to send ISO data (%d)\n", ret); + net_buf_unref(buf); } k_work_schedule(&iso_send_work, K_USEC(interval_us)); From 8acfdaefe48cc78317a2d80ace4ca32bd6e80af2 Mon Sep 17 00:00:00 2001 From: Jose Alberto Meza Date: Wed, 7 Jun 2023 11:07:27 -0700 Subject: [PATCH 0010/2042] include: zephyr: drivers: ps2: Add missing err codes header Fix compilation error when enabling PS2 driver and userspace. Signed-off-by: Jose Alberto Meza --- include/zephyr/drivers/ps2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/zephyr/drivers/ps2.h b/include/zephyr/drivers/ps2.h index a48195020c83..80351c446618 100644 --- a/include/zephyr/drivers/ps2.h +++ b/include/zephyr/drivers/ps2.h @@ -14,6 +14,7 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PS2_H_ #define ZEPHYR_INCLUDE_DRIVERS_PS2_H_ +#include #include #include #include From 22b889e3b49def0a6423203581596076d2ef9c38 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 7 Jun 2023 15:42:06 +0200 Subject: [PATCH 0011/2042] net: context: Fix ambigous pointer check in net_context_connect() Coverity reported, that laddr pointer used in net_context_connect() could be passed as NULL to net_tcp_connect() where it could be dereferenced. This is because the actual setting of laddr to a valid address structure was only done after net_sin/sin6_ptr(&context->local)->sin/sin6_addr verification. In practice though, the aforementioned pointer verification would always pass, as the bind_default() guarantee that the context->local address is set to an unspecified address (if it hasn't been set earlier). Therefore refactor the code a bit: replace the pointer verification with NET_ASSERT - only to assure that we can catch regression in case for any reason the behavior of bind_default() changes. This should also ensure that Coverity no longer reports that laddr is NULL when reaching net_tcp_connect(). Signed-off-by: Robert Lubos --- subsys/net/ip/net_context.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index d3b44d33ea48..91a98a9a44ae 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1032,17 +1032,16 @@ int net_context_connect(struct net_context *context, goto unlock; } + NET_ASSERT(net_sin6_ptr(&context->local)->sin6_addr != NULL); + net_sin6_ptr(&context->local)->sin6_family = AF_INET6; net_sin6(&local_addr)->sin6_family = AF_INET6; net_sin6(&local_addr)->sin6_port = lport = net_sin6((struct sockaddr *)&context->local)->sin6_port; + net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr, + net_sin6_ptr(&context->local)->sin6_addr); - if (net_sin6_ptr(&context->local)->sin6_addr) { - net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr, - net_sin6_ptr(&context->local)->sin6_addr); - - laddr = &local_addr; - } + laddr = &local_addr; } else if (IS_ENABLED(CONFIG_NET_IPV4) && net_context_get_family(context) == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in *) @@ -1074,17 +1073,16 @@ int net_context_connect(struct net_context *context, goto unlock; } + NET_ASSERT(net_sin_ptr(&context->local)->sin_addr != NULL); + net_sin_ptr(&context->local)->sin_family = AF_INET; net_sin(&local_addr)->sin_family = AF_INET; net_sin(&local_addr)->sin_port = lport = net_sin((struct sockaddr *)&context->local)->sin_port; + net_ipaddr_copy(&net_sin(&local_addr)->sin_addr, + net_sin_ptr(&context->local)->sin_addr); - if (net_sin_ptr(&context->local)->sin_addr) { - net_ipaddr_copy(&net_sin(&local_addr)->sin_addr, - net_sin_ptr(&context->local)->sin_addr); - - laddr = &local_addr; - } + laddr = &local_addr; } else { ret = -EINVAL; /* Not IPv4 or IPv6 */ goto unlock; From b6fc47477711a7bfe1ed9173cfd4f448f731c34c Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 6 Jun 2023 10:09:16 +0800 Subject: [PATCH 0012/2042] Bluetooth: Mesh: Fix unable sent mesh message In PR (#58723) has introduce another bug, that, the flag ADV_FLAG_PROXY set before actually enabled. When ctx:: BT RX call schedule_send will atomic_test_and_clear ADV_FLAG_PROXY, but at this time, the proxy advertising will not at advertising state, maybe in update params or set adverting data phase, so that, call bt_le_ext_adv_stop will nothing, and then call k_work_reschedule --> send_pending_adv(at this time, the proxy advertising actually enabled, but the upper layer clear proxy flags), cause latest advertising unable start, because unable in advertising state to update params(-EINVAL). Fixes: #58721 Signed-off-by: Lingao Meng --- subsys/bluetooth/mesh/adv_ext.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 42642d0e0ef7..88c631a5867f 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -41,6 +41,8 @@ enum { ADV_FLAG_SENT, /** Currently performing proxy advertising */ ADV_FLAG_PROXY, + /** The proxy has been start, but maybe pending. */ + ADV_FLAG_PROXY_START, /** The send-call has been scheduled. */ ADV_FLAG_SCHEDULED, /** The send-call has been pending. */ @@ -267,6 +269,7 @@ static void send_pending_adv(struct k_work *work) 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 (adv->buf) { net_buf_unref(adv->buf); @@ -307,10 +310,10 @@ static void send_pending_adv(struct k_work *work) return; } - atomic_set_bit(adv->flags, ADV_FLAG_PROXY); + atomic_set_bit(adv->flags, ADV_FLAG_PROXY_START); - if (bt_mesh_adv_gatt_send()) { - atomic_clear_bit(adv->flags, ADV_FLAG_PROXY); + if (!bt_mesh_adv_gatt_send()) { + atomic_set_bit(adv->flags, ADV_FLAG_PROXY); } if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING)) { @@ -326,7 +329,9 @@ static bool schedule_send(struct bt_mesh_ext_adv *adv) timestamp = 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); + atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); } @@ -438,7 +443,7 @@ static void connected(struct bt_le_ext_adv *instance, { struct bt_mesh_ext_adv *adv = gatt_adv_get(); - if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY)) { + if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_PROXY_START)) { atomic_clear_bit(adv->flags, ADV_FLAG_ACTIVE); (void)schedule_send(adv); } From b05842eb6d32bb99d70cfb71573339872f6599ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 7 Jun 2023 14:39:48 +0200 Subject: [PATCH 0013/2042] doc: api: Update status for auxdisplay API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit auxdisplay API was introduced in 3.4, not 3.3. Also update to "experimental" status to better reflect that the API is new. Signed-off-by: Benjamin Cabé --- doc/develop/api/overview.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/api/overview.rst b/doc/develop/api/overview.rst index 4b65cdd10f93..c212550e69a0 100644 --- a/doc/develop/api/overview.rst +++ b/doc/develop/api/overview.rst @@ -30,8 +30,8 @@ between major releases are available in the :ref:`zephyr_release_notes`. - 1.13 * - :ref:`auxdisplay_api` - - Unstable - - 3.3 + - Experimental + - 3.4 * - :ref:`barriers_api` - Experimental From 24ea25827c7b2ea7d7088417bbe575153296021c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Tue, 4 Apr 2023 07:34:31 +0200 Subject: [PATCH 0014/2042] Bluetooth: Tests: Check CCC Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that if a bonded peer subscribed to a CCC, a non-bonded peer with the same address cannot update the CCC. Signed-off-by: Théo Battrel --- tests/bsim/bluetooth/host/compile.sh | 2 + .../host/security/ccc_update/CMakeLists.txt | 28 ++ .../host/security/ccc_update/prj.conf | 24 ++ .../host/security/ccc_update/prj_2.conf | 26 ++ .../host/security/ccc_update/src/central.c | 391 ++++++++++++++++++ .../host/security/ccc_update/src/common.c | 38 ++ .../host/security/ccc_update/src/common.h | 56 +++ .../host/security/ccc_update/src/main.c | 100 +++++ .../host/security/ccc_update/src/peripheral.c | 330 +++++++++++++++ .../ccc_update/test_scripts/_compile.sh | 14 + .../security/ccc_update/test_scripts/_env.sh | 16 + .../ccc_update/test_scripts/ccc_update.sh | 54 +++ .../ccc_update/test_scripts/ccc_update_2.sh | 54 +++ 13 files changed, 1133 insertions(+) create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/prj.conf create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/prj_2.conf create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/src/central.c create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/src/common.c create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/src/common.h create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/src/main.c create mode 100644 tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c create mode 100755 tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_env.sh create mode 100755 tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update.sh create mode 100755 tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update_2.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index c2bdb00aca87..6903a24beea8 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -62,5 +62,7 @@ app=tests/bsim/bluetooth/host/privacy/device compile app=tests/bsim/bluetooth/host/security/bond_overwrite_allowed compile app=tests/bsim/bluetooth/host/security/bond_overwrite_denied compile +app=tests/bsim/bluetooth/host/security/ccc_update compile +app=tests/bsim/bluetooth/host/security/ccc_update conf_file=prj_2.conf compile wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/security/ccc_update/CMakeLists.txt b/tests/bsim/bluetooth/host/security/ccc_update/CMakeLists.txt new file mode 100644 index 000000000000..90a9de7f62e9 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +if (NOT DEFINED ENV{BSIM_COMPONENTS_PATH}) + message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set \ + the environment variable BSIM_COMPONENTS_PATH to point to its \ + components folder. More information can be found in \ + https://babblesim.github.io/folder_structure_and_env.html") +endif() + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_ccc_update) + +target_sources(app PRIVATE + src/main.c + src/common.c + + src/central.c + src/peripheral.c +) + +zephyr_include_directories( + $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/ + $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + + $ENV{ZEPHYR_BASE}/subsys/bluetooth/host/ +) diff --git a/tests/bsim/bluetooth/host/security/ccc_update/prj.conf b/tests/bsim/bluetooth/host/security/ccc_update/prj.conf new file mode 100644 index 000000000000..3d727bf31de3 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/prj.conf @@ -0,0 +1,24 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="CCC Update Test" + +CONFIG_LOG=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_MAX_CONN=3 +CONFIG_BT_GATT_CLIENT=y + +CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=y + +CONFIG_BT_SMP=y + +CONFIG_SETTINGS=y +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_NVS=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS_NVS=y + +CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/security/ccc_update/prj_2.conf b/tests/bsim/bluetooth/host/security/ccc_update/prj_2.conf new file mode 100644 index 000000000000..ce1300a74396 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/prj_2.conf @@ -0,0 +1,26 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="CCC Update Test" + +CONFIG_LOG=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_MAX_CONN=3 +CONFIG_BT_GATT_CLIENT=y + +# Disable CCC lazy loading, this cause the CCC config to not be cleared at +# disconnection +CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=n + +CONFIG_BT_SMP=y + +CONFIG_SETTINGS=y +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_NVS=y +CONFIG_FLASH_MAP=y +CONFIG_SETTINGS_NVS=y + +CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/central.c b/tests/bsim/bluetooth/host/security/ccc_update/src/central.c new file mode 100644 index 000000000000..5b4e851a5752 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/central.c @@ -0,0 +1,391 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "common.h" +#include "settings.h" + +#include "argparse.h" +#include "bs_pc_backchannel.h" + +#define CLIENT_CLIENT_CHAN 0 +#define SERVER_CLIENT_CHAN 1 + +CREATE_FLAG(connected_flag); +CREATE_FLAG(disconnected_flag); +CREATE_FLAG(security_updated_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) + +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; + +static void gatt_write_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_write_params *params) +{ + gatt_write_att_err = att_err; + + if (att_err) { + FAIL("GATT write ATT error (err %d)\n", att_err); + } + + SET_FLAG(gatt_write_flag); +} + +static int gatt_write(struct bt_conn *conn, uint16_t handle, const uint8_t *write_buf, + size_t write_size) +{ + 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); + } + + WAIT_FOR_FLAG(gatt_write_flag); + + return gatt_write_att_err; +} + +static void ccc_subscribe(void) +{ + int err; + uint8_t buf = 1; + + err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf)); + if (err) { + FAIL("Failed to subscribe (att err %d)", err); + } +} + +static void ccc_unsubscribe(void) +{ + int err; + uint8_t buf = 0; + + err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf)); + if (err) { + FAIL("Failed to unsubscribe (att err %d)", err); + } +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + int err; + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi); + + err = bt_le_scan_stop(); + if (err) { + FAIL("Failed to stop scanner (err %d)\n", err); + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, + &default_conn); + if (err) { + FAIL("Could not connect to peer: %s (err %d)\n", addr_str, err); + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + const bt_addr_le_t *addr; + char addr_str[BT_ADDR_LE_STR_LEN]; + + addr = bt_conn_get_dst(conn); + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + if (err) { + FAIL("Failed to connect to %s (err %d)\n", addr_str, err); + } + + LOG_DBG("Connected: %s", addr_str); + + if (conn == default_conn) { + SET_FLAG(connected_flag); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason); + + SET_FLAG(disconnected_flag); + + if (default_conn != conn) { + return; + } + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + if (!err) { + LOG_DBG("Security changed: %s level %u", addr_str, level); + SET_FLAG(security_updated_flag); + } else { + LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err); + } +} + +static void start_scan(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + FAIL("Scanning failed to start (err %d)\n", err); + } + + LOG_DBG("Scanning successfully started"); +} + +static void disconnect(void) +{ + int err; + + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + FAIL("Disconnection failed (err %d)\n", err); + } + + WAIT_FOR_FLAG(disconnected_flag); + UNSET_FLAG(disconnected_flag); +} + +/* Test steps */ + +static void connect_pair_subscribe(void) +{ + int err; + + start_scan(); + + WAIT_FOR_FLAG(connected_flag); + UNSET_FLAG(connected_flag); + + err = bt_conn_set_security(default_conn, BT_SECURITY_L2); + if (err != 0) { + FAIL("Failed to set security (err %d)\n", err); + } + + WAIT_FOR_FLAG(security_updated_flag); + UNSET_FLAG(security_updated_flag); + + /* subscribe while being paired */ + ccc_subscribe(); + + /* confirm to server that we subscribed */ + backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID); + /* wait for server to check that the subscribtion is well registered */ + backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID); +} + +static void connect_unsubscribe(void) +{ + start_scan(); + + WAIT_FOR_FLAG(connected_flag); + UNSET_FLAG(connected_flag); + + /* wait for server to check that the subscribtion has not been restored */ + backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID); + + LOG_DBG("Trying to unsubscribe without being paired..."); + /* try to unsubscribe */ + ccc_unsubscribe(); + + /* confirm to server that we send unsubscribtion request */ + backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID); + /* wait for server to check that the unsubscribtion is ignored */ + backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID); +} + +static void connect_restore_sec_unsubscribe(void) +{ + int err; + + start_scan(); + + WAIT_FOR_FLAG(connected_flag); + UNSET_FLAG(connected_flag); + + err = bt_conn_set_security(default_conn, BT_SECURITY_L2); + if (err != 0) { + FAIL("Failed to set security (err %d)\n", err); + } + + WAIT_FOR_FLAG(security_updated_flag); + UNSET_FLAG(security_updated_flag); + + /* notify the end of security update to server */ + backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID); + /* wait for server to check that the subscribtion has been restored */ + backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID); + + /* send unsubscribtion request */ + ccc_unsubscribe(); + + /* wait for server to check that the unsubscribtion has been well registered */ + backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID); +} + +/* Util functions */ + +void central_backchannel_init(void) +{ + uint device_number = get_device_nbr(); + uint channel_numbers[2] = { + 0, + 0, + }; + uint device_numbers[2]; + uint num_ch = 2; + uint *ch; + + device_numbers[0] = (device_number == GOOD_CLIENT_ID) ? BAD_CLIENT_ID : GOOD_CLIENT_ID; + device_numbers[1] = SERVER_ID; + + LOG_DBG("Opening back channels for device %d", device_number); + ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch); + if (!ch) { + FAIL("Unable to open backchannel\n"); + } + LOG_DBG("Back channels for device %d opened", device_number); +} + +static void set_public_addr(void) +{ + bt_addr_le_t addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}}; + + bt_id_create(&addr, NULL); +} + +/* Main functions */ + +void run_central(void) +{ + int err; + + central_cb.connected = connected; + central_cb.disconnected = disconnected; + central_cb.security_changed = security_changed; + + central_backchannel_init(); + set_public_addr(); + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth init failed (err %d)\n", err); + } + + LOG_DBG("Bluetooth initialized"); + + bt_conn_cb_register(¢ral_cb); + + err = settings_load(); + if (err) { + FAIL("Settings load failed (err %d)\n", err); + } + + err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY); + if (err) { + FAIL("Unpairing failed (err %d)\n", err); + } + + connect_pair_subscribe(); + disconnect(); + + /* tell the bad client that we disconnected and wait for him to disconnect */ + backchannel_sync_send(CLIENT_CLIENT_CHAN, BAD_CLIENT_ID); + backchannel_sync_wait(CLIENT_CLIENT_CHAN, BAD_CLIENT_ID); + + connect_restore_sec_unsubscribe(); + disconnect(); + + PASS("Central test passed\n"); +} + +void run_bad_central(void) +{ + int err; + + central_cb.connected = connected; + central_cb.disconnected = disconnected; + central_cb.security_changed = security_changed; + + central_backchannel_init(); + set_public_addr(); + + /* wait for good central to disconnect from server */ + backchannel_sync_wait(CLIENT_CLIENT_CHAN, GOOD_CLIENT_ID); + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth init failed (err %d)\n"); + } + + LOG_DBG("Bluetooth initialized"); + + bt_conn_cb_register(¢ral_cb); + + err = settings_load(); + if (err) { + FAIL("Settings load failed (err %d)\n"); + } + + connect_unsubscribe(); + disconnect(); + + PASS("Bad Central test passed\n"); + + /* tell the good client that we disconnected from the server */ + backchannel_sync_send(CLIENT_CLIENT_CHAN, GOOD_CLIENT_ID); +} diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/common.c b/tests/bsim/bluetooth/host/security/ccc_update/src/common.c new file mode 100644 index 000000000000..7c9c898bc551 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/common.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "common.h" + +#include "argparse.h" +#include "bs_pc_backchannel.h" + +void backchannel_sync_send(uint channel, uint device_nbr) +{ + uint8_t sync_msg[BC_MSG_SIZE] = {get_device_nbr(), device_nbr}; /* src, dst */ + + bs_bc_send_msg(channel, sync_msg, ARRAY_SIZE(sync_msg)); +} + +void backchannel_sync_wait(uint channel, uint device_nbr) +{ + uint8_t sync_msg[BC_MSG_SIZE]; + + LOG_DBG("Wait for %d on channel %d", device_nbr, channel); + + while (true) { + if (bs_bc_is_msg_received(channel) > 0) { + bs_bc_receive_msg(channel, sync_msg, ARRAY_SIZE(sync_msg)); + + if (sync_msg[0] == device_nbr && sync_msg[1] == get_device_nbr()) { + break; + } + } + + k_msleep(1); + } + + LOG_DBG("Sync received"); +} diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/common.h b/tests/bsim/bluetooth/host/security/ccc_update/src/common.h new file mode 100644 index 000000000000..4166fa2b6aa0 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/common.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include + +#include "bs_tracing.h" +#include "bstests.h" + +#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) + +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 GET_FLAG(flag) (bool)atomic_get(&flag) +#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)); \ + } + +LOG_MODULE_DECLARE(bt_bsim_ccc_update, LOG_LEVEL_DBG); + +#define DUMMY_SERVICE_TYPE BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f0) +#define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE) + +#define DUMMY_SERVICE_NOTIFY_TYPE \ + BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f3) +#define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE) + +#define CCC_HANDLE 19 + +#define BC_MSG_SIZE 2 + +#define GOOD_CLIENT_ID 0 +#define BAD_CLIENT_ID 1 +#define SERVER_ID 2 + +void backchannel_sync_send(uint channel, uint device_nbr); +void backchannel_sync_wait(uint channel, uint device_nbr); diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/main.c b/tests/bsim/bluetooth/host/security/ccc_update/src/main.c new file mode 100644 index 000000000000..6fa3dcdf60a2 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/main.c @@ -0,0 +1,100 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" +#include + +#include + +LOG_MODULE_REGISTER(bt_bsim_ccc_update, LOG_LEVEL_DBG); + +#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) + +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); +extern void run_bad_central(void); + +static void central_main(void) +{ + run_central(); +} + +static void bad_central_main(void) +{ + run_bad_central(); +} + +static void peripheral_main(void) +{ + run_peripheral(); +} + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + bst_result = Failed; + bs_trace_error_time_line("Test failed (not passed after %d seconds)\n", + WAIT_TIME_S); + } +} + +static void test_ccc_update_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "central", + .test_descr = "Central device", + .test_post_init_f = test_ccc_update_init, + .test_tick_f = test_tick, + .test_main_f = central_main, + }, + { + .test_id = "bad_central", + .test_descr = "Bad Central device", + .test_post_init_f = test_ccc_update_init, + .test_tick_f = test_tick, + .test_main_f = bad_central_main, + }, + { + .test_id = "peripheral", + .test_descr = "Peripheral device", + .test_post_init_f = test_ccc_update_init, + .test_tick_f = test_tick, + .test_main_f = peripheral_main, + }, + BSTEST_END_MARKER}; + +struct bst_test_list *test_ccc_update_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +bst_test_install_t test_installers[] = {test_ccc_update_install, NULL}; + +void main(void) +{ + bst_main(); +} diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c new file mode 100644 index 000000000000..b9070361577f --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c @@ -0,0 +1,330 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "common.h" +#include "settings.h" + +#include "argparse.h" +#include "bs_pc_backchannel.h" + +#define GOOD_CLIENT_CHAN 0 +#define BAD_CLIENT_CHAN 1 + +CREATE_FLAG(connected_flag); +CREATE_FLAG(disconnected_flag); +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 struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(DUMMY_SERVICE_NOTIFY_TYPE); + +static struct bt_conn *default_conn; + +static struct bt_conn_cb peripheral_cb; + +static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + ARG_UNUSED(attr); + + bool notif_enabled = (value == BT_GATT_CCC_NOTIFY); + + LOG_INF("CCC Update: notification %s", notif_enabled ? "enabled" : "disabled"); + + SET_FLAG(ccc_cfg_changed_flag); +} + +BT_GATT_SERVICE_DEFINE(dummy_svc, BT_GATT_PRIMARY_SERVICE(&dummy_service), + BT_GATT_CHARACTERISTIC(¬ify_characteristic_uuid.uuid, BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_NONE, NULL, NULL, NULL), + BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)); + +static void create_adv(struct bt_le_ext_adv **adv) +{ + int err; + struct bt_le_adv_param params; + + memset(¶ms, 0, sizeof(struct bt_le_adv_param)); + + params.options |= BT_LE_ADV_OPT_CONNECTABLE; + + params.id = BT_ID_DEFAULT; + params.sid = 0; + params.interval_min = BT_GAP_ADV_FAST_INT_MIN_2; + params.interval_max = BT_GAP_ADV_FAST_INT_MAX_2; + + err = bt_le_ext_adv_create(¶ms, NULL, adv); + if (err) { + FAIL("Failed to create advertiser (%d)\n", err); + } +} + +static void start_adv(struct bt_le_ext_adv *adv) +{ + int err; + int32_t timeout = 0; + int8_t num_events = 0; + + struct bt_le_ext_adv_start_param start_params; + + start_params.timeout = timeout; + start_params.num_events = num_events; + + err = bt_le_ext_adv_start(adv, &start_params); + if (err) { + FAIL("Failed to start advertiser (err %d)\n", err); + } + + LOG_DBG("Advertiser started"); +} + +static void stop_adv(struct bt_le_ext_adv *adv) +{ + int err; + + err = bt_le_ext_adv_stop(adv); + if (err) { + FAIL("Failed to stop advertiser (err %d)\n", err); + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + if (err) { + FAIL("Failed to connect to %s (err %d)\n", addr_str, err); + } + + LOG_DBG("Connected: %s", addr_str); + + default_conn = bt_conn_ref(conn); + + SET_FLAG(connected_flag); + UNSET_FLAG(disconnected_flag); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason); + + bt_conn_unref(conn); + default_conn = NULL; + + SET_FLAG(disconnected_flag); + UNSET_FLAG(connected_flag); +} + +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str)); + + if (!err) { + LOG_DBG("Security changed: %s level %u", addr_str, level); + SET_FLAG(security_updated_flag); + } else { + LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err); + } +} + +static bool is_peer_subscribed(struct bt_conn *conn) +{ + struct bt_gatt_attr *attr = bt_gatt_find_by_uuid(NULL, 0, BT_UUID_DUMMY_SERVICE_NOTIFY); + bool is_subscribed = bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY); + + return is_subscribed; +} + +/* Test steps */ + +static void connect_pair_check_subscribtion(struct bt_le_ext_adv *adv) +{ + start_adv(adv); + + WAIT_FOR_FLAG(connected_flag); + + WAIT_FOR_FLAG(security_updated_flag); + UNSET_FLAG(security_updated_flag); + + /* wait for confirmation of subscribtion from good client */ + backchannel_sync_wait(GOOD_CLIENT_CHAN, GOOD_CLIENT_ID); + + /* check that subscribtion request did not fail */ + if (!is_peer_subscribed(default_conn)) { + FAIL("Good client did not subscribed\n"); + } + + stop_adv(adv); + + /* confirm to good client that the subscribtion has been well registered */ + backchannel_sync_send(GOOD_CLIENT_CHAN, GOOD_CLIENT_ID); +} + +static void connect_wait_unsubscribtion(struct bt_le_ext_adv *adv) +{ + UNSET_FLAG(ccc_cfg_changed_flag); + + start_adv(adv); + + WAIT_FOR_FLAG(connected_flag); + + stop_adv(adv); + + /* check that subscribtion is not restored for bad client */ + if (is_peer_subscribed(default_conn)) { + FAIL("Subscribtion has been restored for bad client\n"); + } + + /* confirm to bad client that the subscribtion had not been restored */ + backchannel_sync_send(BAD_CLIENT_CHAN, BAD_CLIENT_ID); + /* wait for confirmation that bad client requested unsubscribtion */ + backchannel_sync_wait(BAD_CLIENT_CHAN, BAD_CLIENT_ID); + + /* check that unsubscribtion request failed */ + if (GET_FLAG(ccc_cfg_changed_flag)) { + FAIL("Bad client updated CCC config\n"); + } + + /* confirm to bad client that unsubscribtion request has been ignored */ + backchannel_sync_send(BAD_CLIENT_CHAN, BAD_CLIENT_ID); +} + +static void connect_restore_sec_check_subscribtion(struct bt_le_ext_adv *adv) +{ + start_adv(adv); + + WAIT_FOR_FLAG(connected_flag); + + WAIT_FOR_FLAG(security_updated_flag); + UNSET_FLAG(security_updated_flag); + + /* wait for good client end of security update */ + backchannel_sync_wait(GOOD_CLIENT_CHAN, GOOD_CLIENT_ID); + + /* check that subscribtion has been restored */ + if (!is_peer_subscribed(default_conn)) { + FAIL("Good client is not subscribed\n"); + } + + /* confirm to good client that the subscribtion has been well restored */ + backchannel_sync_send(GOOD_CLIENT_CHAN, GOOD_CLIENT_ID); + /* wait for confimation of unsubscribtion from good client */ + backchannel_sync_wait(GOOD_CLIENT_CHAN, GOOD_CLIENT_ID); + + /* check that unsubscribtion request from good client has been registered */ + if (is_peer_subscribed(default_conn)) { + FAIL("Good client did not unsubscribe\n"); + } +} + +/* Util functions */ + +void peripheral_backchannel_init(void) +{ + uint device_number = get_device_nbr(); + uint channel_numbers[2] = { + 0, + 0, + }; + uint device_numbers[2] = { + GOOD_CLIENT_ID, + BAD_CLIENT_ID, + }; + uint num_ch = 2; + uint *ch; + + LOG_DBG("Opening back channels for device %d", device_number); + ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch); + if (!ch) { + FAIL("Unable to open backchannel\n"); + } +} + +static void check_ccc_handle(void) +{ + struct bt_gatt_attr *service_notify_attr = + bt_gatt_find_by_uuid(NULL, 0, ¬ify_characteristic_uuid.uuid); + + 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)}}; + + 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); + + __ASSERT(actual_ccc_handle == CCC_HANDLE, + "Please update the CCC_HANDLE define (actual_ccc_handle=%d)", actual_ccc_handle); +} + +/* Main function */ + +void run_peripheral(void) +{ + int err; + struct bt_le_ext_adv *adv = NULL; + + peripheral_cb.connected = connected; + peripheral_cb.disconnected = disconnected; + peripheral_cb.security_changed = security_changed; + + peripheral_backchannel_init(); + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth init failed (err %d)\n", err); + } + + LOG_DBG("Bluetooth initialized"); + + check_ccc_handle(); + + bt_conn_cb_register(&peripheral_cb); + + err = settings_load(); + if (err) { + FAIL("Settings load failed (err %d)\n", err); + } + + err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY); + if (err) { + FAIL("Unpairing failed (err %d)\n", err); + } + + create_adv(&adv); + + connect_pair_check_subscribtion(adv); + WAIT_FOR_FLAG(disconnected_flag); + + connect_wait_unsubscribtion(adv); + WAIT_FOR_FLAG(disconnected_flag); + + connect_restore_sec_check_subscribtion(adv); + WAIT_FOR_FLAG(disconnected_flag); + + PASS("Peripheral test passed\n"); +} diff --git a/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_compile.sh new file mode 100755 index 000000000000..bf28e0cb9361 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_compile.sh @@ -0,0 +1,14 @@ +#!/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +source "${bash_source_dir}/_env.sh" + +west build -b nrf52_bsim -d build_test && \ + cp -v build_test/zephyr/zephyr.exe "${test_exe}" + +west build -b nrf52_bsim -d build_test_2 -- -DCONF_FILE=prj_2.conf && \ + cp -v build_test_2/zephyr/zephyr.exe "${test_exe_2}" diff --git a/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_env.sh b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_env.sh new file mode 100755 index 000000000000..701b4b5d2d68 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/_env.sh @@ -0,0 +1,16 @@ +#!/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" + +test_name="$(basename "$(realpath "$bash_source_dir/..")")" +bsim_bin="${BSIM_OUT_PATH}/bin" +verbosity_level=2 +BOARD="${BOARD:-nrf52_bsim}" +simulation_id="$test_name" +test_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_security_ccc_update_prj_conf" +test_exe_2="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_security_ccc_update_prj_2_conf" diff --git a/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update.sh b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update.sh new file mode 100755 index 000000000000..aaf3c7899f31 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update.sh @@ -0,0 +1,54 @@ +#!/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name='ccc_update' +test_exe="bs_${BOARD}_tests_bsim_bluetooth_host_security_${test_name}_prj_conf" +simulation_id="${test_name}" +verbosity_level=2 +EXECUTE_TIMEOUT=30 + +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 +fi + +if [ "${1}" != 'debug1' ]; then + Execute "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=bad_central \ + -flash="${simulation_id}_bad_client.log.bin" -flash_rm +fi + +if [ "${1}" != 'debug2' ]; then + Execute "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral \ + -flash="${simulation_id}_server.log.bin" -flash_rm +fi + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=3 -sim_length=60e6 + +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 +fi + +if [ "${1}" == 'debug1' ]; then + gdb --args "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=bad_central \ + -flash="${simulation_id}_bad_client.log.bin" -flash_rm +fi + +if [ "${1}" == 'debug2' ]; then + gdb --args "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral \ + -flash="${simulation_id}_server.log.bin" -flash_rm +fi + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update_2.sh b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update_2.sh new file mode 100755 index 000000000000..ab9097d9d5e2 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/ccc_update/test_scripts/ccc_update_2.sh @@ -0,0 +1,54 @@ +#!/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name='ccc_update' +test_exe="bs_${BOARD}_tests_bsim_bluetooth_host_security_${test_name}_prj_2_conf" +simulation_id="${test_name}_2" +verbosity_level=2 +EXECUTE_TIMEOUT=30 + +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 +fi + +if [ "${1}" != 'debug1' ]; then + Execute "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=bad_central \ + -flash="${simulation_id}_bad_client.log.bin" -flash_rm +fi + +if [ "${1}" != 'debug2' ]; then + Execute "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral \ + -flash="${simulation_id}_server.log.bin" -flash_rm +fi + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=3 -sim_length=60e6 + +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 +fi + +if [ "${1}" == 'debug1' ]; then + gdb --args "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=bad_central \ + -flash="${simulation_id}_bad_client.log.bin" -flash_rm +fi + +if [ "${1}" == 'debug2' ]; then + gdb --args "./${test_exe}" \ + -v=${verbosity_level} -s=${simulation_id} -d=2 -testid=peripheral \ + -flash="${simulation_id}_server.log.bin" -flash_rm +fi + +wait_for_background_jobs From cfd368fef1b72e9468626ee03ed1992ceb1e8965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Tue, 18 Apr 2023 12:27:16 +0200 Subject: [PATCH 0015/2042] Bluetooth: Host: Fix GATT server handling of CCC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GATT server was not doing enough check before udpating the CCC. For example, a non-bonded client could update the CCC of a bonded client by spoofing his address. This fix the issue by dissociating the CCC configuration of a bonded and a non-bonded peer. To do that, a new field is added to the CCC config: `link_encrypted`. Signed-off-by: Théo Battrel --- include/zephyr/bluetooth/gatt.h | 5 +++++ subsys/bluetooth/host/gatt.c | 40 +++++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 940416cceb65..8e626e97570e 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -736,6 +736,11 @@ struct bt_gatt_ccc_cfg { uint8_t id; /** Remote peer address. */ bt_addr_le_t peer; + /** + * Separate storage for encrypted and unencrypted context. This + * indicate that the link was encrypted when the CCC was written. + */ + bool link_encrypted; /** Configuration value. */ uint16_t value; }; diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 61b7b12e57f5..5539c4997f3b 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -1356,6 +1356,7 @@ static void clear_ccc_cfg(struct bt_gatt_ccc_cfg *cfg) bt_addr_le_copy(&cfg->peer, BT_ADDR_LE_ANY); cfg->id = 0U; cfg->value = 0U; + cfg->link_encrypted = false; } static void gatt_store_ccc_cf(uint8_t id, const bt_addr_le_t *peer_addr); @@ -2087,6 +2088,31 @@ struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr) return next; } +static bool bt_gatt_ccc_cfg_is_matching_conn(const struct bt_conn *conn, + const struct bt_gatt_ccc_cfg *cfg) +{ + bool conn_encrypted = bt_conn_get_security(conn) >= BT_SECURITY_L2; + + if (cfg->link_encrypted && !conn_encrypted) { + return false; + } + + return bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer); +} + +static struct bt_conn *bt_gatt_ccc_cfg_conn_lookup(const struct bt_gatt_ccc_cfg *cfg) +{ + struct bt_conn *conn; + + conn = bt_conn_lookup_addr_le(cfg->id, &cfg->peer); + + if (bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { + return conn; + } + + return NULL; +} + static struct bt_gatt_ccc_cfg *find_ccc_cfg(const struct bt_conn *conn, struct _bt_gatt_ccc *ccc) { @@ -2094,8 +2120,7 @@ static struct bt_gatt_ccc_cfg *find_ccc_cfg(const struct bt_conn *conn, struct bt_gatt_ccc_cfg *cfg = &ccc->cfg[i]; if (conn) { - if (bt_conn_is_peer_addr_le(conn, cfg->id, - &cfg->peer)) { + if (bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { return cfg; } } else if (bt_addr_le_eq(&cfg->peer, BT_ADDR_LE_ANY)) { @@ -2189,6 +2214,7 @@ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, bt_addr_le_copy(&cfg->peer, &conn->le.dst); cfg->id = conn->id; + cfg->link_encrypted = (bt_conn_get_security(conn) >= BT_SECURITY_L2); } /* Confirm write if cfg is managed by application */ @@ -3268,8 +3294,7 @@ static uint8_t update_ccc(const struct bt_gatt_attr *attr, uint16_t handle, struct bt_gatt_ccc_cfg *cfg = &ccc->cfg[i]; /* Ignore configuration for different peer or not active */ - if (!cfg->value || - !bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer)) { + if (!cfg->value || !bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { continue; } @@ -3343,11 +3368,11 @@ static uint8_t disconnected_cb(const struct bt_gatt_attr *attr, uint16_t handle, continue; } - if (!bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer)) { + if (!bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { struct bt_conn *tmp; /* Skip if there is another peer connected */ - tmp = bt_conn_lookup_addr_le(cfg->id, &cfg->peer); + tmp = bt_gatt_ccc_cfg_conn_lookup(cfg); if (tmp) { if (tmp->state == BT_CONN_CONNECTED) { value_used = true; @@ -3437,7 +3462,7 @@ bool bt_gatt_is_subscribed(struct bt_conn *conn, for (size_t i = 0; i < BT_GATT_CCC_MAX; i++) { const struct bt_gatt_ccc_cfg *cfg = &ccc->cfg[i]; - if (bt_conn_is_peer_addr_le(conn, cfg->id, &cfg->peer) && + if (bt_gatt_ccc_cfg_is_matching_conn(conn, cfg) && (ccc_type & ccc->cfg[i].value)) { return true; } @@ -5588,6 +5613,7 @@ static uint8_t ccc_load(const struct bt_gatt_attr *attr, uint16_t handle, } bt_addr_le_copy(&cfg->peer, load->addr_with_id.addr); cfg->id = load->addr_with_id.id; + cfg->link_encrypted = true; } cfg->value = load->entry->value; From 242c8f1c7727b74af758ecbe235aecf161594f48 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 7 Jun 2023 16:40:40 +0200 Subject: [PATCH 0016/2042] Bluetooth: Mesh: Avoid undefined behavior in bit shift in blob_cli.c block_size_log can be 0x20 which will shift 1 by 32 bits which will cause undefined behavior. Adding ULL to 1 is an option but this will add little bit more code when debug option is enabled. So simply print the logarithmic value. Coverity-ID: 316387 Fixes #58951 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/blob_cli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/mesh/blob_cli.c b/subsys/bluetooth/mesh/blob_cli.c index 45ffcf5d2daf..e2b0fc68a70c 100644 --- a/subsys/bluetooth/mesh/blob_cli.c +++ b/subsys/bluetooth/mesh/blob_cli.c @@ -1550,9 +1550,9 @@ int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, return -ENODEV; } - LOG_DBG("\n\tblock size: %u\n\tchunk size: %u\n" + LOG_DBG("\n\tblock size log: %u\n\tchunk size: %u\n" "\tblob size: %u\n\tmode: %x", - (1 << cli->xfer->block_size_log), cli->xfer->chunk_size, + cli->xfer->block_size_log, cli->xfer->chunk_size, cli->xfer->size, cli->xfer->mode); return xfer_start(cli); From 54aa6f1075b3030ffc2792353703a2d76eed121a Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 3 Jun 2023 07:32:52 +0530 Subject: [PATCH 0017/2042] Bluetooth: Controller: Fix ISOAL sink create role for ISO Receiver Fix ISOAL sink create role for ISO Receiver. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/isoal.c | 6 +- subsys/bluetooth/controller/ll_sw/isoal.h | 5 +- subsys/bluetooth/controller/ll_sw/ull_iso.c | 4 +- .../ctrl_isoal/src/isoal_test_common.h | 8 +- .../ctrl_isoal/src/sub_sets/isoal_test_rx.c | 114 +++++++++--------- .../ctrl_isoal/src/sub_sets/isoal_test_tx.c | 58 ++++----- 6 files changed, 100 insertions(+), 95 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index fba78369c9c1..93cee474222f 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -315,7 +315,7 @@ isoal_status_t isoal_sink_create( * BIG reference anchor point + * BIG_Sync_Delay + SDU_interval + ISO_Interval - Time_Offset. */ - if (role == BT_CONN_ROLE_PERIPHERAL) { + if (role == ISOAL_ROLE_PERIPHERAL) { if (framed) { session->sdu_sync_const = stream_sync_delay + sdu_interval + (flush_timeout * iso_interval_us); @@ -323,7 +323,7 @@ isoal_status_t isoal_sink_create( session->sdu_sync_const = stream_sync_delay + ((flush_timeout - 1UL) * iso_interval_us); } - } else if (role == BT_CONN_ROLE_CENTRAL) { + } else if (role == ISOAL_ROLE_CENTRAL) { if (framed) { session->sdu_sync_const = stream_sync_delay - group_sync_delay; } else { @@ -331,7 +331,7 @@ isoal_status_t isoal_sink_create( (((iso_interval_us / sdu_interval) - 1UL) * iso_interval_us); } - } else if (role == BT_ROLE_BROADCAST) { + } else if (role == ISOAL_ROLE_BROADCAST_SINK) { if (framed) { session->sdu_sync_const = group_sync_delay + sdu_interval + iso_interval_us; } else { diff --git a/subsys/bluetooth/controller/ll_sw/isoal.h b/subsys/bluetooth/controller/ll_sw/isoal.h index 304a54f77d40..2bceebe7de74 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.h +++ b/subsys/bluetooth/controller/ll_sw/isoal.h @@ -24,7 +24,10 @@ typedef uint8_t isoal_status_t; #define ISOAL_STATUS_ERR_PDU_EMIT ((isoal_status_t) 0x20) /* PDU emission */ #define ISOAL_STATUS_ERR_UNSPECIFIED ((isoal_status_t) 0x80) /* Unspecified error */ -#define BT_ROLE_BROADCAST (BT_CONN_ROLE_PERIPHERAL + 1) +#define ISOAL_ROLE_CENTRAL (BT_CONN_ROLE_CENTRAL) +#define ISOAL_ROLE_PERIPHERAL (BT_CONN_ROLE_PERIPHERAL) +#define ISOAL_ROLE_BROADCAST_SOURCE (BT_CONN_ROLE_PERIPHERAL + 1U) +#define ISOAL_ROLE_BROADCAST_SINK (BT_CONN_ROLE_PERIPHERAL + 2U) /** Handle to a registered ISO Sub-System sink */ typedef uint8_t isoal_sink_handle_t; diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index e04d29cc1ec5..b52f9c31b4b9 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -303,7 +303,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, adv_iso = ull_adv_iso_by_stream_get(stream_handle); lll_iso = &adv_iso->lll; - role = 0U; /* FIXME: Set role from LLL struct */ + role = ISOAL_ROLE_BROADCAST_SOURCE; iso_interval = lll_iso->iso_interval; sdu_interval = lll_iso->sdu_interval; burst_number = lll_iso->bn; @@ -329,7 +329,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, sync_iso = ull_sync_iso_by_stream_get(stream_handle); lll_iso = &sync_iso->lll; - role = 1U; /* FIXME: Is this correct role value? */ + role = ISOAL_ROLE_BROADCAST_SINK; iso_interval = lll_iso->iso_interval; sdu_interval = lll_iso->sdu_interval; burst_number = lll_iso->bn; diff --git a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h index aa38109112a2..730cb2e6f40a 100644 --- a/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h +++ b/tests/bluetooth/ctrl_isoal/src/isoal_test_common.h @@ -37,9 +37,11 @@ (s == BT_ISO_CONT ? "CONT" : \ (s == BT_ISO_END ? "END" : "???")))) -#define ROLE_TO_STR(s) (s == BT_ROLE_BROADCAST ? "Broadcast" : \ - (role == BT_CONN_ROLE_PERIPHERAL ? "Peripheral" : \ - (role == BT_CONN_ROLE_CENTRAL ? "Central" : "Undefined"))) +#define ROLE_TO_STR(s) \ + ((s) == ISOAL_ROLE_BROADCAST_SOURCE ? "Broadcast Source" : \ + ((s) == ISOAL_ROLE_BROADCAST_SINK ? "Broadcast Sink" : \ + ((s) == ISOAL_ROLE_PERIPHERAL ? "Peripheral" : \ + ((s) == ISOAL_ROLE_CENTRAL ? "Central" : "Undefined")))) #define FSM_TO_STR(s) (s == ISOAL_START ? "START" : \ (s == ISOAL_CONTINUE ? "CONTINUE" : \ 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 c0074405bded..2ce8862e1d48 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 @@ -281,7 +281,7 @@ static int32_t calc_rx_latency_by_role(uint8_t role, iso_interval = iso_interval_int * ISO_INT_UNIT_US; switch (role) { - case BT_CONN_ROLE_PERIPHERAL: + case ISOAL_ROLE_PERIPHERAL: if (framed) { latency = stream_sync_delay + sdu_interval + (flush_timeout * iso_interval); } else { @@ -289,7 +289,7 @@ static int32_t calc_rx_latency_by_role(uint8_t role, } break; - case BT_CONN_ROLE_CENTRAL: + case ISOAL_ROLE_CENTRAL: if (framed) { latency = stream_sync_delay - group_sync_delay; } else { @@ -298,7 +298,7 @@ static int32_t calc_rx_latency_by_role(uint8_t role, } break; - case BT_ROLE_BROADCAST: + case ISOAL_ROLE_BROADCAST_SINK: if (framed) { latency = group_sync_delay + sdu_interval + iso_interval; } else { @@ -496,9 +496,9 @@ ZTEST(test_rx_basics, test_sink_isoal_test_create_destroy) pdus_per_sdu = (burst_number * sdu_interval) / iso_interval; switch (role) { - case BT_CONN_ROLE_PERIPHERAL: - case BT_CONN_ROLE_CENTRAL: - case BT_ROLE_BROADCAST: + case ISOAL_ROLE_PERIPHERAL: + case ISOAL_ROLE_CENTRAL: + case ISOAL_ROLE_BROADCAST_SINK: latency = calc_rx_latency_by_role(role, framed, flush_timeout, @@ -625,7 +625,7 @@ ZTEST(test_rx_basics, test_sink_isoal_test_create_err) bool framed; handle = 0x8000; - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; burst_number = 1; flush_timeout = 1; framed = false; @@ -711,7 +711,7 @@ ZTEST(test_rx_basics, test_sink_disable) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -812,7 +812,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -979,7 +979,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu_ts_wrap1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -1114,7 +1114,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu_ts_wrap2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_CENTRAL; + role = ISOAL_ROLE_CENTRAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -1250,7 +1250,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 2; @@ -1433,7 +1433,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_split) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US / 2; BN = 4; @@ -1774,7 +1774,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 5; @@ -2078,7 +2078,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_multi_split_on_border) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 5; @@ -2403,7 +2403,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_long_pdu_short_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -2558,7 +2558,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_prem) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -2740,7 +2740,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_single_pdu_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -2924,7 +2924,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -3153,7 +3153,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -3435,7 +3435,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_pdu_err2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -3734,7 +3734,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 4; @@ -3962,7 +3962,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_no_end) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -4542,7 +4542,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -4729,7 +4729,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -4917,7 +4917,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_padding_error3) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -5111,7 +5111,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_zero_len_packet) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 1; @@ -5231,7 +5231,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_seq_err_zero_length) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 3; @@ -5467,7 +5467,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_no_end) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 2; @@ -5628,7 +5628,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_invalid_llid1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 2; @@ -5718,7 +5718,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_invalid_llid2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 2; @@ -5854,7 +5854,7 @@ ZTEST(test_rx_unframed, test_rx_unframed_dbl_pdu_invalid_llid2_pdu_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ISO_INT_UNIT_US; BN = 2; @@ -6019,7 +6019,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -6150,7 +6150,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu_ts_wrap1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -6282,7 +6282,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_pdu_single_sdu_ts_wrap2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_CENTRAL; + role = ISOAL_ROLE_CENTRAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -6413,7 +6413,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -6626,7 +6626,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = (iso_interval_int * ISO_INT_UNIT_US); sdu_interval = (iso_interval_us / 3) + 5; @@ -6889,7 +6889,7 @@ ZTEST(test_rx_framed, test_rx_framed_zero_length_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -7195,7 +7195,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -8163,7 +8163,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -8360,7 +8360,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -8562,7 +8562,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_pdu_err3) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -8754,7 +8754,7 @@ ZTEST(test_rx_framed, test_rx_framed_dbl_pdu_dbl_sdu_seq_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -8998,7 +8998,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = iso_interval_us + 5; @@ -9263,7 +9263,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -9532,7 +9532,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_err3) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -9810,7 +9810,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_seq_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -10055,7 +10055,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_single_sdu_pdu_seq_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -10300,7 +10300,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -10674,7 +10674,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -11044,7 +11044,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_err3) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -11423,7 +11423,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seq_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -11770,7 +11770,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_pdu_seq_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -12095,7 +12095,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -12256,7 +12256,7 @@ ZTEST(test_rx_framed, test_rx_framed_single_invalid_pdu_single_sdu_hdr_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = ((iso_interval_int * ISO_INT_UNIT_US) / 3) + 5; BN = 3; @@ -12459,7 +12459,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; @@ -12742,7 +12742,7 @@ ZTEST(test_rx_framed, test_rx_framed_trppl_pdu_dbl_sdu_seg_err2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; iso_interval_us = iso_interval_int * ISO_INT_UNIT_US; sdu_interval = (iso_interval_us / 3) + 5; 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 42fc0af89a8f..fe375b7accd9 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 @@ -648,7 +648,7 @@ ZTEST(test_tx_basics, test_source_isoal_test_create_err) bool framed; handle = 0x8000; - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; burst_number = 1; max_octets = 40; flush_timeout = 1; @@ -745,7 +745,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_1_frag_1_pdu_maxPDU) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -873,7 +873,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_1_frag_1_pdu_bufSize) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -991,7 +991,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_1_frag_3_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -1150,7 +1150,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_3_frag_1_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -1355,7 +1355,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_3_frag_2_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -1687,7 +1687,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_2_sdu_1_frag_2_pdu_ts_wrap1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -1868,7 +1868,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_2_sdu_3_frag_4_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 2; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -2262,7 +2262,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_2_sdu_3_frag_4_pdu_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 2; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -2737,7 +2737,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_zero_sdu_1_frag_1_pdu_maxPDU_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -2905,7 +2905,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_1_frag_pdu_alloc_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -3022,7 +3022,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_1_sdu_1_frag_pdu_emit_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -3151,7 +3151,7 @@ ZTEST(test_tx_unframed, test_tx_unframed_4_sdu_1_frag_4_pdu_stream_loc) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US / 2; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -3488,7 +3488,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_1_pdu_maxPDU) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -3643,7 +3643,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_1_pdu_bufSize) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -3789,7 +3789,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_3_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -4020,7 +4020,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_3_frag_1_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -4279,7 +4279,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_3_frag_2_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -4581,7 +4581,7 @@ ZTEST(test_tx_framed, test_tx_framed_2_sdu_3_frag_4_pdu) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 2; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -5113,7 +5113,7 @@ ZTEST(test_tx_framed, test_tx_framed_2_sdu_3_frag_4_pdu_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 2; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -5659,7 +5659,7 @@ ZTEST(test_tx_framed, test_tx_framed_2_sdu_1_frag_2_pdu_refPoint2) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -5888,7 +5888,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_1_pdu_refPoint3) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -6044,7 +6044,7 @@ ZTEST(test_tx_framed, test_tx_framed_2_sdu_1_frag_2_pdu_ts_wrap1) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -6268,7 +6268,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_zero_sdu_1_frag_1_pdu_maxPDU) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -6411,7 +6411,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_zero_sdu_1_frag_1_pdu_padding) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -6596,7 +6596,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_pdu_alloc_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -6724,7 +6724,7 @@ ZTEST(test_tx_framed, test_tx_framed_1_sdu_1_frag_pdu_emit_err) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 1; sdu_interval = CONN_INT_UNIT_US + 50; max_octets = TEST_TX_PDU_PAYLOAD_MAX - 5; @@ -6873,7 +6873,7 @@ ZTEST(test_tx_framed, test_tx_framed_2_sdu_1_frag_pdu_timeout) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 800; sdu_interval = 500000; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; @@ -7167,7 +7167,7 @@ ZTEST(test_tx_framed_ebq, test_tx_framed_cis_fra_per_bv07c) uint8_t FT; /* Settings */ - role = BT_CONN_ROLE_PERIPHERAL; + role = ISOAL_ROLE_PERIPHERAL; iso_interval_int = 800; sdu_interval = 500000; max_octets = TEST_TX_PDU_PAYLOAD_MAX + 5; From 124e0f57bff872b782aa499f3a6e191d20f18bd6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 8 Jun 2023 12:25:54 +0300 Subject: [PATCH 0018/2042] doc: api: Promote EDAC API as Unstable Promote Error Detection And Correction (EDAC) API as Unstable. Fixes: #58487 Signed-off-by: Andrei Emeltchenko --- 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 c212550e69a0..381252325ae6 100644 --- a/doc/develop/api/overview.rst +++ b/doc/develop/api/overview.rst @@ -94,7 +94,7 @@ between major releases are available in the :ref:`zephyr_release_notes`. - 2.4 * - :ref:`edac_api` - - Experimental + - Unstable - 2.5 * - :ref:`eeprom_api` From f992029f26672fa671c922ba78203c91bf69ce08 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 1 Jun 2023 06:57:08 +0530 Subject: [PATCH 0019/2042] samples: Bluetooth: unicast audio client and server overlay config Add Zephyr Bluetooth Low Energy Controller overlay config for the unicast audio client and server samples. Signed-off-by: Vinayak Kariappa Chettimada --- samples/bluetooth/unicast_audio_client/README.rst | 2 ++ .../unicast_audio_client/overlay-bt_ll_sw_split.conf | 8 ++++++++ samples/bluetooth/unicast_audio_client/sample.yaml | 11 +++++++++++ samples/bluetooth/unicast_audio_server/README.rst | 2 ++ .../unicast_audio_server/overlay-bt_ll_sw_split.conf | 6 ++++++ samples/bluetooth/unicast_audio_server/prj.conf | 1 + samples/bluetooth/unicast_audio_server/sample.yaml | 11 +++++++++++ 7 files changed, 41 insertions(+) create mode 100644 samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf create mode 100644 samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/unicast_audio_client/README.rst b/samples/bluetooth/unicast_audio_client/README.rst index b9acf06d0236..dc3b336d9a3f 100644 --- a/samples/bluetooth/unicast_audio_client/README.rst +++ b/samples/bluetooth/unicast_audio_client/README.rst @@ -20,5 +20,7 @@ Building and Running ******************** This sample can be found under :zephyr_file:`samples/bluetooth/unicast_audio_client` in the Zephyr tree. +Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO +feature support in Zephyr Bluetooth Controller on supported boards. See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf new file mode 100644 index 000000000000..cecb923bd35f --- /dev/null +++ b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf @@ -0,0 +1,8 @@ +CONFIG_BT_LL_SW_SPLIT=y +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=1650 +CONFIG_BT_CTLR_ISO_TX_BUFFERS=4 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 +CONFIG_BT_CTLR_ISOAL_SOURCES=2 +CONFIG_BT_CTLR_ISOAL_SINKS=1 +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y diff --git a/samples/bluetooth/unicast_audio_client/sample.yaml b/samples/bluetooth/unicast_audio_client/sample.yaml index 1e9998c9770a..9ca15182f523 100644 --- a/samples/bluetooth/unicast_audio_client/sample.yaml +++ b/samples/bluetooth/unicast_audio_client/sample.yaml @@ -10,3 +10,14 @@ tests: tags: bluetooth integration_platforms: - qemu_cortex_m3 + sample.bluetooth.audio_unicast_client.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf52_bsim + - nrf52dk_nrf52832 + integration_platforms: + - nrf52dk_nrf52832 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/unicast_audio_server/README.rst b/samples/bluetooth/unicast_audio_server/README.rst index a94dc05f0ce4..ce7151e5fb78 100644 --- a/samples/bluetooth/unicast_audio_server/README.rst +++ b/samples/bluetooth/unicast_audio_server/README.rst @@ -19,5 +19,7 @@ Building and Running ******************** This sample can be found under :zephyr_file:`samples/bluetooth/unicast_audio_server` in the Zephyr tree. +Use `-DEXTRA_CONF_FILE=overlay-bt_ll_sw_split.conf` to enable required ISO +feature support in Zephyr Bluetooth Controller on supported boards. See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf new file mode 100644 index 000000000000..a6b48df9c793 --- /dev/null +++ b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf @@ -0,0 +1,6 @@ +CONFIG_BT_LL_SW_SPLIT=y +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 +CONFIG_BT_CTLR_ISO_TX_BUFFERS=2 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 +CONFIG_BT_CTLR_ISOAL_SOURCES=1 +CONFIG_BT_CTLR_ISOAL_SINKS=2 diff --git a/samples/bluetooth/unicast_audio_server/prj.conf b/samples/bluetooth/unicast_audio_server/prj.conf index 37a0a5f4c6ae..3aec74ddbcc6 100644 --- a/samples/bluetooth/unicast_audio_server/prj.conf +++ b/samples/bluetooth/unicast_audio_server/prj.conf @@ -5,6 +5,7 @@ CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=1 +CONFIG_BT_ISO_TX_BUF_COUNT=2 # Support an ISO channel per ASE CONFIG_BT_ISO_MAX_CHAN=4 diff --git a/samples/bluetooth/unicast_audio_server/sample.yaml b/samples/bluetooth/unicast_audio_server/sample.yaml index 477398a93f7f..afb93362d1eb 100644 --- a/samples/bluetooth/unicast_audio_server/sample.yaml +++ b/samples/bluetooth/unicast_audio_server/sample.yaml @@ -10,3 +10,14 @@ tests: tags: bluetooth integration_platforms: - qemu_cortex_m3 + sample.bluetooth.audio_unicast_server.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf52_bsim + - nrf52dk_nrf52832 + integration_platforms: + - nrf52dk_nrf52832 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth From 5f38c4ba710dcdf240903f0ef38954e6fcfccbf4 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 1 Jun 2023 07:15:44 +0530 Subject: [PATCH 0020/2042] Bluetooth: Controller: Fix Tx ISO SDUs dropped due to strict SN check Introduce a Kconfig BT_CTLR_ISOAL_SN_STRICT to relax the Tx ISO Data SDUs being dropped due to strict check of sequence numbers in ISOAL, i.e. dropped when ISO Data SDUs are delayed from upper layer with respect to the current payload number in the ISO radio events. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig.ll_sw_split | 13 +++++++++++++ subsys/bluetooth/controller/ll_sw/isoal.c | 3 ++- tests/bluetooth/ctrl_isoal/Kconfig | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index a257d9a5b5f1..6a7626036ede 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -377,6 +377,19 @@ config BT_CTLR_SCAN_ENABLE_STRICT Enforce returning HCI Error Command Disallowed on enabling/disabling already enabled/disabled scanning. +config BT_CTLR_ISOAL_SN_STRICT + bool "Enforce Strict Tx ISO Data Sequence Number use" + depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO + default y + help + Enforce dropping stale Tx ISO Data SDUs from upper layer by checking + the next expected Sequence Number maintained in ISOAL. + + This option may be used to relax the Tx ISO Data SDUs being dropped + due to strict check of sequence numbers in ISOAL, i.e. dropped when + HCI ISO Data packets are delayed from upper layer with respect to the + current payload number in the ISO radio events. + config BT_CTLR_ZLI bool "Use Zero Latency IRQs" depends on ZERO_LATENCY_IRQS diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 93cee474222f..7a7e9d48094d 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -1749,8 +1749,9 @@ uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_ /* Start of a new SDU */ time_diff_valid = false; time_diff = 0; + /* Adjust payload number */ - if (session->sn) { + if (IS_ENABLED(CONFIG_BT_CTLR_ISOAL_SN_STRICT) && session->sn) { /* Not the first SDU in this session, so reference * information should be valid. At this point, the * current payload number should be at the first PDU of diff --git a/tests/bluetooth/ctrl_isoal/Kconfig b/tests/bluetooth/ctrl_isoal/Kconfig index 39004539869f..b7c10723b93c 100644 --- a/tests/bluetooth/ctrl_isoal/Kconfig +++ b/tests/bluetooth/ctrl_isoal/Kconfig @@ -40,4 +40,9 @@ config BT_CTLR_ISO_TX_SEG_PLAYLOAD_MIN Minimum number of payload bytes that would make inserting a new segment into a PDU worthwhile. +config BT_CTLR_ISOAL_SN_STRICT + bool "Enforce Strict Tx ISO Data Sequence Number use" + depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO + default y + source "Kconfig.zephyr" From 7d7d1cbf53fdb0e2fef0f56a0b5f4ae35f0f7620 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 1 Jun 2023 07:22:39 +0530 Subject: [PATCH 0021/2042] samples: Bluetooth: Relax Tx ISO SDUs dropped in unicast audio samples Relax Tx ISO SDUs being dropped in unicast audio client and server samples when using the Zephyr Bluetooth Low Energy Controller, i.e. Tx ISO SDUs dropped due to delayed ISO data send calls in upper layer with respect to payload number in the current ISO radio events in the Controller. This option is disabled in the sample and users can use it when need be. Signed-off-by: Vinayak Kariappa Chettimada --- .../unicast_audio_client/overlay-bt_ll_sw_split.conf | 3 +++ .../unicast_audio_server/overlay-bt_ll_sw_split.conf | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf index cecb923bd35f..1c29b28e2dda 100644 --- a/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/unicast_audio_client/overlay-bt_ll_sw_split.conf @@ -6,3 +6,6 @@ CONFIG_BT_CTLR_ISOAL_SOURCES=2 CONFIG_BT_CTLR_ISOAL_SINKS=1 CONFIG_BT_CTLR_ADVANCED_FEATURES=y CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y + +# Use the below if the sample is sending stale packet sequence number +# CONFIG_BT_CTLR_ISOAL_SN_STRICT=n diff --git a/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf index a6b48df9c793..1499e379d4e2 100644 --- a/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf +++ b/samples/bluetooth/unicast_audio_server/overlay-bt_ll_sw_split.conf @@ -4,3 +4,7 @@ CONFIG_BT_CTLR_ISO_TX_BUFFERS=2 CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 CONFIG_BT_CTLR_ISOAL_SOURCES=1 CONFIG_BT_CTLR_ISOAL_SINKS=2 + +# Use the below if the sample is sending stale packet sequence number +# CONFIG_BT_CTLR_ADVANCED_FEATURES=y +# CONFIG_BT_CTLR_ISOAL_SN_STRICT=n From b7c2ca4bdf6c245aced25afb10208d3c8e4c7aa4 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 2 Jun 2023 06:46:29 +0530 Subject: [PATCH 0022/2042] samples: Bluetooth: Fix Tx ISO Data packet sequence number Fix Tx ISO Data packet sequence number increment based on the send timer timeout value. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/unicast_audio_client/src/main.c | 17 ++++++++++++-- .../bluetooth/unicast_audio_server/src/main.c | 22 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 111eac2185a8..63fffe8834e7 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -58,11 +58,24 @@ static K_SEM_DEFINE(sem_stream_qos, 0, ARRAY_SIZE(sinks) + ARRAY_SIZE(sources)); static K_SEM_DEFINE(sem_stream_enabled, 0, 1); static K_SEM_DEFINE(sem_stream_started, 0, 1); +#define AUDIO_DATA_TIMEOUT_US 1000000UL /* Send data every 1 second */ + static uint16_t get_and_incr_seq_num(const struct bt_bap_stream *stream) { for (size_t i = 0U; i < configured_sink_stream_count; i++) { if (stream->ep == sinks[i].ep) { - return sinks[i].seq_num++; + uint16_t seq_num; + + seq_num = sinks[i].seq_num; + + if (IS_ENABLED(CONFIG_LIBLC3)) { + sinks[i].seq_num++; + } else { + sinks[i].seq_num += (AUDIO_DATA_TIMEOUT_US / + codec_configuration.qos.interval); + } + + return seq_num; } } @@ -322,7 +335,7 @@ static void audio_timer_timeout(struct k_work *work) } } - k_work_schedule(&audio_send_work, K_MSEC(1000)); + k_work_schedule(&audio_send_work, K_USEC(AUDIO_DATA_TIMEOUT_US)); len_to_send++; if (len_to_send > codec_configuration.qos.sdu) { diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index ff54923eab22..8197a9f5e314 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -69,11 +69,25 @@ static const struct bt_data ad[] = { BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)), }; +#define AUDIO_DATA_TIMEOUT_US 1000000UL /* Send data every 1 second */ +#define SDU_INTERVAL_US 10000UL /* 10 ms SDU interval */ + static uint16_t get_and_incr_seq_num(const struct bt_bap_stream *stream) { for (size_t i = 0U; i < configured_source_stream_count; i++) { if (stream == &source_streams[i].stream) { - return source_streams[i].seq_num++; + uint16_t seq_num; + + seq_num = source_streams[i].seq_num; + + if (IS_ENABLED(CONFIG_LIBLC3)) { + source_streams[i].seq_num++; + } else { + source_streams[i].seq_num += (AUDIO_DATA_TIMEOUT_US / + SDU_INTERVAL_US); + } + + return seq_num; } } @@ -214,7 +228,11 @@ static void audio_timer_timeout(struct k_work *work) } } - k_work_schedule(&audio_send_work, K_MSEC(1000U)); +#if defined(CONFIG_LIBLC3) + k_work_schedule(&audio_send_work, K_USEC(MAX_FRAME_DURATION_US)); +#else + k_work_schedule(&audio_send_work, K_USEC(AUDIO_DATA_TIMEOUT_US)); +#endif } static enum bt_audio_dir stream_dir(const struct bt_bap_stream *stream) From 52c5ce97d410782824a20f1a04f348752b2f5875 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 2 Jun 2023 07:15:03 +0530 Subject: [PATCH 0023/2042] Bluetooth: Controller: Update BT_CTLR_ISOAL_SN_STRICT help text Update BT_CTLR_ISOAL_SN_STRICT help text. Co-authored-by: Nirosharn Amarasinghe Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/Kconfig.ll_sw_split | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 6a7626036ede..0342889e3e14 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -382,13 +382,20 @@ config BT_CTLR_ISOAL_SN_STRICT depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO default y help - Enforce dropping stale Tx ISO Data SDUs from upper layer by checking - the next expected Sequence Number maintained in ISOAL. - - This option may be used to relax the Tx ISO Data SDUs being dropped - due to strict check of sequence numbers in ISOAL, i.e. dropped when - HCI ISO Data packets are delayed from upper layer with respect to the - current payload number in the ISO radio events. + Enforce strict sequencing of released payloads based on the TX SDU's + packet sequence number. This will be effective when fragmenting an + SDU into unframed PDUs. + + When enabled, this could result in an SDU being fragmented into + payload numbers that are expired (will be dropped), if the TX SDU + packet sequence numbers do not increment according to the SDU interval + and delivery of SDUs to the ISO-AL do not strictly follow the SDU + interval. + + When disabled, TX SDUs could be shifted from their stream aligned + position and fragmented into payloads that are less likely to be + dropped. This will result in better delivery of data to the receiver + but at the cost of creating skews in the received stream of SDUs. config BT_CTLR_ZLI bool "Use Zero Latency IRQs" From 273e233d607b4a69d8bf5e78577e4170f302521b Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 7 Jun 2023 10:48:40 +0530 Subject: [PATCH 0024/2042] tests: bsim: Bluetooth: Fix BIS test ISO Tx Buffers in Controller Fix BIS test for ISO Tx Buffers in Controller to be 2 for ISO TX MTU size of 502 bytes. Signed-off-by: Vinayak Kariappa Chettimada --- tests/bsim/bluetooth/ll/bis/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bsim/bluetooth/ll/bis/prj.conf b/tests/bsim/bluetooth/ll/bis/prj.conf index 54a83d9f3167..893cedcbff6a 100644 --- a/tests/bsim/bluetooth/ll/bis/prj.conf +++ b/tests/bsim/bluetooth/ll/bis/prj.conf @@ -15,6 +15,7 @@ CONFIG_BT_CTLR_ADV_EXT=y CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y +CONFIG_BT_CTLR_ISO_TX_BUFFERS=2 CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=251 CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=251 From 48f6411416d0a64fe614a3971ebd226bd22937cb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 7 Jun 2023 09:03:37 +0530 Subject: [PATCH 0025/2042] Bluetooth: Controller: Fix Broadcast ISO interval unit Fix incorrectly stored Broadcast ISO interval in microseconds instead of storing in 1.25 ms units. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_adv_iso.c | 2 +- 1 file changed, 1 insertion(+), 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 58fd0c477b38..7cbcab1bbf34 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -252,7 +252,7 @@ uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, */ iso_interval_us = ((sdu_interval * lll_adv_iso->bn * sdu_per_event) / (bn * PERIODIC_INT_UNIT_US)) * PERIODIC_INT_UNIT_US; - lll_adv_iso->iso_interval = iso_interval_us; + lll_adv_iso->iso_interval = iso_interval_us / PERIODIC_INT_UNIT_US; /* Immediate Repetition Count (IRC), Mandatory IRC = 1 */ lll_adv_iso->irc = rtn + 1U; From 4195ba5870ad86803f5740ef5254f9e930265ef6 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 2 Jun 2023 09:12:04 +0530 Subject: [PATCH 0026/2042] Bluetooth: Controller: Fix read ISO Tx Sync for Broadcast ISO Fix missing read ISO Tx Sync for Broadcast ISO feature. Co-authored-by: Nirosharn Amarasinghe Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 53 ++++++++++--------- subsys/bluetooth/controller/ll_sw/isoal.c | 45 ++++++++++++++-- .../bluetooth/controller/ll_sw/ull_adv_iso.c | 9 ++++ .../controller/ll_sw/ull_adv_types.h | 5 ++ subsys/bluetooth/controller/ll_sw/ull_iso.c | 13 ++++- 5 files changed, 95 insertions(+), 30 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 4ff60523a43d..d17d00de02c1 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -5792,6 +5792,8 @@ 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; + uint8_t target_event; + uint8_t event_offset; uint16_t slen; /* FIXME: Code only expects header present */ @@ -5817,33 +5819,34 @@ int hci_iso_handle(struct net_buf *buf, struct net_buf **evt) return -EINVAL; } - /* FIXME: convey group start */ - sdu_frag_tx.grp_ref_point = 0; - - /* FIXME: temporary interface to enable ISOAL data Tx - * Create provide proper interface between client - * (using ISOAL target_event) and ISOAL, preferably - * without dependence on peeking at LL data. - * Problem is that client must specify a value greater - * than LL bisPayloadCounter or no data is sent. + /* Determine the target event and the first event offset after + * datapath setup. + * event_offset mitigates the possibility of first SDU being + * late on the datapath and avoid all subsequent SDUs being + * dropped for a said SDU interval. i.e. upper layer is not + * drifting, say first SDU dropped, hence subsequent SDUs all + * dropped, is mitigated by offsetting the grp_ref_point. + * + * It is ok to do the below for every received ISO data, ISOAL + * will not consider subsequent skewed target_event after the + * first use of target_event value. + * + * In BIG implementation in LLL, payload_count corresponds to + * the next BIG event, hence calculate grp_ref_point for next + * BIG event by incrementing the previous elapsed big_ref_point + * by one additional ISO interval. */ lll_iso = &adv_iso->lll; - - /* FIXME: Remove the below temporary hack to buffer up ISO data - * if the SDU interval and ISO interval misalign. - */ - uint64_t pkt_seq_num = lll_iso->payload_count / lll_iso->bn; - - if (((pkt_seq_num - stream->pkt_seq_num) & BIT64_MASK(39)) <= - BIT64_MASK(38)) { - stream->pkt_seq_num = pkt_seq_num; - } else { - pkt_seq_num = stream->pkt_seq_num; - } - - sdu_frag_tx.target_event = pkt_seq_num; - - stream->pkt_seq_num++; + target_event = lll_iso->payload_count / lll_iso->bn; + event_offset = ull_ref_get(&adv_iso->ull) ? 0U : 1U; + event_offset += lll_iso->latency_prepare; + + sdu_frag_tx.target_event = target_event + event_offset; + sdu_frag_tx.grp_ref_point = + isoal_get_wrapped_time_us(adv_iso->big_ref_point, + ((event_offset + 1U) * + lll_iso->iso_interval * + ISO_INT_UNIT_US)); /* Start Fragmentation */ /* FIXME: need to ensure ISO-AL returns proper isoal_status. diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 7a7e9d48094d..ceb82e28de2a 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -1806,6 +1806,44 @@ uint16_t isoal_tx_unframed_get_next_payload_number(isoal_source_handle_t source_ return sdus_skipped; } +/* NOTE: Use of target_event and grp_ref_point as input from upper layer. + * + * For unframed: + * Before the modification to use the PSN to decide the position of an SDU in a + * stream of SDU, the target event was what was used in deciding the event for + * each SDU. This meant that there would possibly have been skews on the + * receiver for each SDU and we had trouble with LL/CIS/PER/BV-39-C which + * expects clustering within an event. + * + * After the change, the PSN is used to decide the position of an SDU in the + * stream anchored at the first PSN received. However for the first SDU + * (assume that PSN=0), it will be the target event that decides which event + * will be used for the fragmented payloads. Although the same interface from + * the original is retained, the target event and group reference point only + * impacts the event chosen for the first SDU and all subsequent SDUs will be + * decided relative to the first. + * + * The target event and related group reference point is still used to provide + * the ISO-AL with a notion of time, for example when storing information + * required for the TX Sync command. For example if for PSN 4, target event is + * 8 but event 7 is chosen as the correct position for the SDU with PSN 4, the + * group reference point stored is obtained by subtracting an ISO interval from + * the group reference provided with target event 8 to get the BIG/CIG reference + * for event 7. It is also expected that this value is the latest reference and + * is drift compensated. + * + * The PSN alone is not sufficient for this because as far as I am aware, host + * and controller have no common reference time for when CIG/BIG event 0 starts. + * Therefore I would expect it is possible to receive PSN 0 in event 2 for + * example. If the target event provided is event 3, then PSN 0 will be + * fragmented into payloads for event 3 and that will serve as the anchor for + * the stream and subsequent SDUs. If for example target event provided was + * event 2 instead, then it could very well be that PSN 0 might not be + * transmitted as is was received midway through event 2 and the payloads + * expired. If this happens then subsequent SDUs might also all be late for + * their transmission slots as they are positioned relative to PSN 0. + */ + /** * @brief Fragment received SDU and produce unframed PDUs * @details Destination source may have an already partially built PDU @@ -1889,9 +1927,10 @@ static isoal_status_t isoal_tx_unframed_produce(isoal_source_handle_t source_hdl * this seems to be the best candidate. */ if (actual_event != tx_sdu->target_event) { - actual_grp_ref_point = isoal_get_wrapped_time_us(tx_sdu->grp_ref_point, - ((actual_event - tx_sdu->target_event) * session->iso_interval * - ISO_INT_UNIT_US)); + actual_grp_ref_point = + isoal_get_wrapped_time_us(tx_sdu->grp_ref_point, + (actual_event - tx_sdu->target_event) * + session->iso_interval * ISO_INT_UNIT_US); } /* Store timing info for TX Sync command */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 7cbcab1bbf34..689129ee0cdd 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -1269,6 +1269,7 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, { static struct lll_prepare_param p; struct ll_adv_iso_set *adv_iso = param; + uint32_t remainder_us; uint32_t ret; uint8_t ref; @@ -1291,6 +1292,14 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, &mfy_lll_prepare); LL_ASSERT(!ret); + /* Calculate the BIG reference point of current BIG event */ + remainder_us = remainder; + hal_ticker_remove_jitter(&ticks_at_expire, &remainder_us); + ticks_at_expire &= HAL_TICKER_CNTR_MASK; + adv_iso->big_ref_point = isoal_get_wrapped_time_us(HAL_TICKER_TICKS_TO_US(ticks_at_expire), + (remainder_us + + EVENT_OVERHEAD_START_US)); + DEBUG_RADIO_PREPARE_A(1); } diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h index 646d70178c58..de0e4908b6f0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_types.h @@ -101,6 +101,11 @@ struct ll_adv_iso_set { struct ull_hdr ull; struct lll_adv_iso lll; + uint32_t big_ref_point; /* Previously elapsed BIG reference point in + * microseconds of the free running Controller + * clock. + */ + struct { struct node_rx_hdr hdr; } node_rx_complete; diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index b52f9c31b4b9..a19bcc5df6e3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -176,9 +176,18 @@ uint8_t ll_read_iso_tx_sync(uint16_t handle, uint16_t *seq, return BT_HCI_ERR_CMD_DISALLOWED; } else if (IS_ADV_ISO_HANDLE(handle)) { - /* FIXME: Do something similar to connected */ + const struct lll_adv_iso_stream *adv_stream; + uint16_t stream_handle; - return BT_HCI_ERR_CMD_DISALLOWED; + stream_handle = LL_BIS_ADV_IDX_FROM_HANDLE(handle); + adv_stream = ull_adv_iso_stream_get(stream_handle); + if (!adv_stream || !adv_stream->dp || + isoal_tx_get_sync_info(adv_stream->dp->source_hdl, seq, + timestamp, offset) != ISOAL_STATUS_OK) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + return BT_HCI_ERR_SUCCESS; } return BT_HCI_ERR_UNKNOWN_CONN_ID; From 782a0515ed2d09723d8d41938ff142c860f0a253 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Thu, 13 Apr 2023 12:20:01 +0200 Subject: [PATCH 0027/2042] sysbuild: ensure warning is only printed when VAR is not used When calling `sysbuild_get( VAR ...)` user specifically specify the output variable and in such cases the overwrite warning should not be printed, because such invocation is similar to a regular `set( )` CMake call. Only the invocation where the same variable name is used for lookup and return variable, then the warning must be printed to avoid unintentional overwriting of existing variables. Signed-off-by: Torsten Rasmussen --- share/sysbuild/cmake/modules/sysbuild_extensions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 70c7aad3e58a..5960c63c31e9 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -75,7 +75,7 @@ function(sysbuild_get variable) message(FATAL_ERROR "sysbuild_get(...) requires IMAGE.") endif() - if(DEFINED ${variable}) + if(DEFINED ${variable} AND NOT DEFINED GET_VAR_VAR) message(WARNING "Return variable ${variable} already defined with a value. " "sysbuild_get(${variable} ...) may overwrite existing value. " "Please use sysbuild_get( ... VAR ) " From 98ba1175fdc4d67f084153c868555712566b58d7 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Thu, 8 Jun 2023 09:14:38 +0200 Subject: [PATCH 0028/2042] tests: drivers: can: api: fix test_set_timing_data_while_started test Change the test_set_timing_data_while_started test to actually attempt to set the data phase timing parameters instead of attempting to set the nominal/arbitration timing parameters. Update test descriptions to explicitly mention data phase timing. Fixes: #59046 Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/api/src/canfd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/drivers/can/api/src/canfd.c b/tests/drivers/can/api/src/canfd.c index 446741815884..852d1fad7e17 100644 --- a/tests/drivers/can/api/src/canfd.c +++ b/tests/drivers/can/api/src/canfd.c @@ -373,7 +373,7 @@ ZTEST_USER(canfd, test_filters_preserved_through_fd_to_classic_mode_change) } /** - * @brief Test setting bitrate is not allowed while started. + * @brief Test setting data phase bitrate is not allowed while started. */ ZTEST_USER(canfd, test_set_bitrate_data_while_started) { @@ -385,7 +385,7 @@ ZTEST_USER(canfd, test_set_bitrate_data_while_started) } /** - * @brief Test setting timing is not allowed while started. + * @brief Test setting data phase timing is not allowed while started. */ ZTEST_USER(canfd, test_set_timing_data_while_started) { @@ -397,7 +397,7 @@ ZTEST_USER(canfd, test_set_timing_data_while_started) err = can_calc_timing_data(can_dev, &timing, TEST_BITRATE_3, TEST_SAMPLE_POINT); zassert_ok(err, "failed to calculate data timing (err %d)", err); - err = can_set_timing(can_dev, &timing); + err = can_set_timing_data(can_dev, &timing); zassert_not_equal(err, 0, "changed data timing while started"); zassert_equal(err, -EBUSY, "wrong error return code (err %d)", err); } From 466f3e8e709141e8b3220e4af70d23f696115e33 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 7 Jun 2023 15:53:20 +0530 Subject: [PATCH 0029/2042] Bluetooth: Controller: Fix cis_offset_min to have additional margin As the coarse tick of ACL prepare and CIG prepare jitter by +/- 1 tick, hence when initially scheduling the CIG place it with enough margin so that cis_offset_min calculated when there already exists a CIG can be larger than peer's cis_offset_min being negotiated. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index e78b5c3955ea..cc71a48cba60 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -907,13 +907,13 @@ static void mfy_cig_offset_get(void *param) LL_ASSERT(!err); offset_min_us = HAL_TICKER_TICKS_TO_US(ticks_to_expire) + - (EVENT_TICKER_RES_MARGIN_US << 1U); + (EVENT_TICKER_RES_MARGIN_US << 2U); offset_min_us += cig->sync_delay - cis->sync_delay; conn = ll_conn_get(cis->lll.acl_handle); conn_interval_us = (uint32_t)conn->lll.interval * CONN_INT_UNIT_US; - while (offset_min_us > conn_interval_us) { + while (offset_min_us > (conn_interval_us + PDU_CIS_OFFSET_MIN_US)) { offset_min_us -= conn_interval_us; } From 833a228db45c70abb30a2a03635e876a7e531b37 Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Tue, 30 May 2023 10:11:45 +0200 Subject: [PATCH 0030/2042] tracing: sysview: implement RTT channel selection through KConfig Implement Kconfig value for selecting the RTT channel to be used by Segger SystemView Signed-off-by: Nathan Olff --- modules/segger/SEGGER_SYSVIEW_Conf.h | 1 + subsys/tracing/sysview/Kconfig | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/modules/segger/SEGGER_SYSVIEW_Conf.h b/modules/segger/SEGGER_SYSVIEW_Conf.h index e8d66ad64c35..b93e93763a67 100644 --- a/modules/segger/SEGGER_SYSVIEW_Conf.h +++ b/modules/segger/SEGGER_SYSVIEW_Conf.h @@ -17,6 +17,7 @@ uint32_t sysview_get_interrupt(void); #define SEGGER_SYSVIEW_RTT_BUFFER_SIZE CONFIG_SEGGER_SYSVIEW_RTT_BUFFER_SIZE #define SEGGER_SYSVIEW_POST_MORTEM_MODE CONFIG_SEGGER_SYSVIEW_POST_MORTEM_MODE +#define SEGGER_SYSVIEW_RTT_CHANNEL CONFIG_SEGGER_SYSVIEW_RTT_CHANNEL #if defined(CONFIG_SEGGER_SYSVIEW_SECTION_DTCM) #define SEGGER_SYSVIEW_SECTION ".dtcm_data" diff --git a/subsys/tracing/sysview/Kconfig b/subsys/tracing/sysview/Kconfig index c411a75aed79..708fc0aa2a8c 100644 --- a/subsys/tracing/sysview/Kconfig +++ b/subsys/tracing/sysview/Kconfig @@ -12,6 +12,11 @@ config SEGGER_SYSVIEW_RTT_BUFFER_SIZE depends on SEGGER_SYSTEMVIEW default 4096 +config SEGGER_SYSVIEW_RTT_CHANNEL + int "RTT channel for SystemView" + depends on SEGGER_SYSTEMVIEW + default 0 + config SEGGER_SYSVIEW_POST_MORTEM_MODE bool "Post-mortem mode for SystemView" depends on SEGGER_SYSTEMVIEW From 685476d7e099fb5b7e36f9a1a935386300d6ed9c Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Tue, 30 May 2023 12:14:21 +0200 Subject: [PATCH 0031/2042] tracing: sysview: implement SEGGER_SYSVIEW_APP_NAME Implement APP_NAME define in Kconfig for Segger SystemView module. Use APP_NAME in Systemview initialization function Signed-off-by: Nathan Olff --- subsys/tracing/sysview/Kconfig | 5 +++++ subsys/tracing/sysview/sysview_config.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/subsys/tracing/sysview/Kconfig b/subsys/tracing/sysview/Kconfig index 708fc0aa2a8c..972fb1aec31d 100644 --- a/subsys/tracing/sysview/Kconfig +++ b/subsys/tracing/sysview/Kconfig @@ -17,6 +17,11 @@ config SEGGER_SYSVIEW_RTT_CHANNEL depends on SEGGER_SYSTEMVIEW default 0 +config SEGGER_SYSVIEW_APP_NAME + string "Application name to be displayed in SystemView" + depends on SEGGER_SYSTEMVIEW + default "ZephyrSysView" + config SEGGER_SYSVIEW_POST_MORTEM_MODE bool "Post-mortem mode for SystemView" depends on SEGGER_SYSTEMVIEW diff --git a/subsys/tracing/sysview/sysview_config.c b/subsys/tracing/sysview/sysview_config.c index b430c78d2e00..e68cb4f8a79e 100644 --- a/subsys/tracing/sysview/sysview_config.c +++ b/subsys/tracing/sysview/sysview_config.c @@ -49,7 +49,7 @@ void sys_trace_thread_info(struct k_thread *thread) static void cbSendSystemDesc(void) { - SEGGER_SYSVIEW_SendSysDesc("N=ZephyrSysView"); + SEGGER_SYSVIEW_SendSysDesc("N=" CONFIG_SEGGER_SYSVIEW_APP_NAME); SEGGER_SYSVIEW_SendSysDesc("D=" CONFIG_BOARD " " CONFIG_SOC_SERIES " " CONFIG_ARCH); SEGGER_SYSVIEW_SendSysDesc("O=Zephyr"); From 65c9058ed4769cbb4957c4d111e96252b29ffb33 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 8 Jun 2023 09:35:08 +0100 Subject: [PATCH 0032/2042] sysbuild: Fix value propagation of signature type to MCUboot Fixes an issue whereby the type of the signature was not passed to MCUboot. Signed-off-by: Jamie McCrae --- scripts/ci/check_compliance.py | 6 +++++- share/sysbuild/image_config.cmake | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 45a4827c6b43..25d7f9df37ee 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -608,7 +608,11 @@ def check_no_undef_outside_kconfig(self, kconf): "BOOT_SERIAL_CDC_ACM", # Used in (sysbuild-based) test "BOOT_SERIAL_ENTRANCE_GPIO", # Used in (sysbuild-based) test "BOOT_SERIAL_IMG_GRP_HASH", # Used in documentation - "BOOT_SIGNATURE_KEY_FILE", # MCUboot idefined setting used by sysbuild. + "BOOT_SIGNATURE_KEY_FILE", # MCUboot setting used by sysbuild + "BOOT_SIGNATURE_TYPE_ECDSA_P256", # MCUboot setting used by sysbuild + "BOOT_SIGNATURE_TYPE_ED25519", # MCUboot setting used by sysbuild + "BOOT_SIGNATURE_TYPE_NONE", # MCUboot setting used by sysbuild + "BOOT_SIGNATURE_TYPE_RSA", # MCUboot setting used by sysbuild "BOOT_VALIDATE_SLOT0", # Used in (sysbuild-based) test "BOOT_WATCHDOG_FEED", # Used in (sysbuild-based) test "BTTESTER_LOG_LEVEL", # Used in tests/bluetooth/tester diff --git a/share/sysbuild/image_config.cmake b/share/sysbuild/image_config.cmake index 2ee395618862..0d44f379789c 100644 --- a/share/sysbuild/image_config.cmake +++ b/share/sysbuild/image_config.cmake @@ -13,6 +13,29 @@ if((NOT image_board) OR ("${image_BOARD}" STREQUAL "${BOARD}")) set_config_string(${image} CONFIG_MCUBOOT_SIGNATURE_KEY_FILE "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}" ) + else() + set(keytypes CONFIG_BOOT_SIGNATURE_TYPE_NONE + CONFIG_BOOT_SIGNATURE_TYPE_RSA + CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 + CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + + if(SB_CONFIG_BOOT_SIGNATURE_TYPE_NONE) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_NONE) + elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_RSA) + elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256) + elseif(SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + set(keytype CONFIG_BOOT_SIGNATURE_TYPE_ED25519) + endif() + + foreach(loopkeytype ${keytypes}) + if("${loopkeytype}" STREQUAL "${keytype}") + set_config_bool(${image} ${loopkeytype} y) + else() + set_config_bool(${image} ${loopkeytype} n) + endif() + endforeach() endif() if(SB_CONFIG_BOOTLOADER_MCUBOOT) From c1e40bb3d53dc0ec7280d838f967e7d2a93a2c04 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 8 Jun 2023 10:17:25 +0000 Subject: [PATCH 0033/2042] templates: change template file namaes for proper sorting prefix with numbers to get sorting based on usage. Most common files issue types should come first, with bugs being at the top. Signed-off-by: Anas Nashif --- .github/ISSUE_TEMPLATE/{bug_report.md => 001_bug_report.md} | 0 .github/ISSUE_TEMPLATE/{enhancement.md => 002_enhancement.md} | 0 .github/ISSUE_TEMPLATE/{rfc-proposal.md => 003_rfc-proposal.md} | 0 .../{feature_request.md => 004_feature_request.md} | 0 .../{hardware_support.md => 005_hardware_support.md} | 0 .github/ISSUE_TEMPLATE/{nomination.md => 006_nomination.md} | 0 .github/ISSUE_TEMPLATE/{ext-source.md => 007_ext-source.md} | 0 .github/ISSUE_TEMPLATE/{bin-blobs.md => 008_bin-blobs.md} | 0 doc/contribute/bin_blobs.rst | 2 +- doc/contribute/external.rst | 2 +- doc/contribute/guidelines.rst | 2 +- doc/contribute/proposals_and_rfcs.rst | 2 +- doc/project/project_roles.rst | 2 +- 13 files changed, 5 insertions(+), 5 deletions(-) rename .github/ISSUE_TEMPLATE/{bug_report.md => 001_bug_report.md} (100%) rename .github/ISSUE_TEMPLATE/{enhancement.md => 002_enhancement.md} (100%) rename .github/ISSUE_TEMPLATE/{rfc-proposal.md => 003_rfc-proposal.md} (100%) rename .github/ISSUE_TEMPLATE/{feature_request.md => 004_feature_request.md} (100%) rename .github/ISSUE_TEMPLATE/{hardware_support.md => 005_hardware_support.md} (100%) rename .github/ISSUE_TEMPLATE/{nomination.md => 006_nomination.md} (100%) rename .github/ISSUE_TEMPLATE/{ext-source.md => 007_ext-source.md} (100%) rename .github/ISSUE_TEMPLATE/{bin-blobs.md => 008_bin-blobs.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/001_bug_report.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/001_bug_report.md diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/002_enhancement.md similarity index 100% rename from .github/ISSUE_TEMPLATE/enhancement.md rename to .github/ISSUE_TEMPLATE/002_enhancement.md diff --git a/.github/ISSUE_TEMPLATE/rfc-proposal.md b/.github/ISSUE_TEMPLATE/003_rfc-proposal.md similarity index 100% rename from .github/ISSUE_TEMPLATE/rfc-proposal.md rename to .github/ISSUE_TEMPLATE/003_rfc-proposal.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/004_feature_request.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/004_feature_request.md diff --git a/.github/ISSUE_TEMPLATE/hardware_support.md b/.github/ISSUE_TEMPLATE/005_hardware_support.md similarity index 100% rename from .github/ISSUE_TEMPLATE/hardware_support.md rename to .github/ISSUE_TEMPLATE/005_hardware_support.md diff --git a/.github/ISSUE_TEMPLATE/nomination.md b/.github/ISSUE_TEMPLATE/006_nomination.md similarity index 100% rename from .github/ISSUE_TEMPLATE/nomination.md rename to .github/ISSUE_TEMPLATE/006_nomination.md diff --git a/.github/ISSUE_TEMPLATE/ext-source.md b/.github/ISSUE_TEMPLATE/007_ext-source.md similarity index 100% rename from .github/ISSUE_TEMPLATE/ext-source.md rename to .github/ISSUE_TEMPLATE/007_ext-source.md diff --git a/.github/ISSUE_TEMPLATE/bin-blobs.md b/.github/ISSUE_TEMPLATE/008_bin-blobs.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bin-blobs.md rename to .github/ISSUE_TEMPLATE/008_bin-blobs.md diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index 0f7819452f7a..f821cac1d254 100644 --- a/doc/contribute/bin_blobs.rst +++ b/doc/contribute/bin_blobs.rst @@ -237,7 +237,7 @@ Follow the steps below to begin the submission process: detail, so that you are informed of the criteria used by the TSC in order to approve or reject a request #. Use the :github:`New Binary Blobs Issue - ` to open an issue + ` to open an issue #. Fill out all required sections, making sure you provide enough detail for the TSC to assess the merit of the request. Additionally you must also create a Pull Request that demonstrates the integration of the binary blobs and then diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index 3d34710d66f7..8d0bf379a2cc 100644 --- a/doc/contribute/external.rst +++ b/doc/contribute/external.rst @@ -131,7 +131,7 @@ Follow the steps below to begin the submission process: detail, so that you are informed of the criteria used by the TSC and board in order to approve or reject a request #. Use the :github:`New External Source Code Issue - ` to open an issue + ` to open an issue #. Fill out all required sections, making sure you provide enough detail for the TSC to assess the merit of the request. Optionally you can also create a Pull Request that demonstrates the integration of the external source code and diff --git a/doc/contribute/guidelines.rst b/doc/contribute/guidelines.rst index 62386359efc8..ee8d01094262 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -994,7 +994,7 @@ Requirements for Treewide Changes pull requests that are treewide changes - The person proposing a treewide change must create an `RFC issue - `_ + `_ describing the change, its rationale and impact, etc. before any pull requests related to the change can be merged diff --git a/doc/contribute/proposals_and_rfcs.rst b/doc/contribute/proposals_and_rfcs.rst index d1812611dd1f..6333ecf05c79 100644 --- a/doc/contribute/proposals_and_rfcs.rst +++ b/doc/contribute/proposals_and_rfcs.rst @@ -51,5 +51,5 @@ either disagreement or not enough voiced opinions in order to proceed. Make sure to either label it appropriately or include it in the corresponding GitHub project in order for it to be examined during the next meeting. -.. _`RFC template`: https://github.com/zephyrproject-rtos/zephyr/blob/main/.github/ISSUE_TEMPLATE/rfc-proposal.md +.. _`RFC template`: https://github.com/zephyrproject-rtos/zephyr/blob/main/.github/ISSUE_TEMPLATE/003_rfc-proposal.md .. _`Zephyr meetings`: https://github.com/zephyrproject-rtos/zephyr/wiki/Zephyr-Committee-and-Working-Group-Meetings diff --git a/doc/project/project_roles.rst b/doc/project/project_roles.rst index 4e2eeb803213..95d38da438c3 100644 --- a/doc/project/project_roles.rst +++ b/doc/project/project_roles.rst @@ -63,7 +63,7 @@ level to the Zephyr GitHub repository. You may nominate yourself, or another GitHub user, for promotion to the Triage permission level by creating a GitHub issue, using the :github:`nomination -template `. +template `. Contributors granted the Triage permission level are permitted to add reviewers to a pull request and can be added as a reviewer by other GitHub users. From 7f0aff9045bc70dffae7299d268e3dcb4b904271 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 7 Jun 2023 11:52:01 +0000 Subject: [PATCH 0034/2042] ci: testplan: do not start more runners than needed We have been launching 10 runners up a certain number of tests, although we only neeed half of that for some scenarios. Too many runners started that have to execute just a small number of tests wastes times on setup and blocks the queue. Just start the number of nodes needed based on initial calculation. Signed-off-by: Anas Nashif --- scripts/ci/test_plan.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/ci/test_plan.py b/scripts/ci/test_plan.py index 6d8fc91325cd..5b38e9f2c701 100755 --- a/scripts/ci/test_plan.py +++ b/scripts/ci/test_plan.py @@ -359,12 +359,6 @@ def parse_args(): else: nodes = round(total_tests / args.tests_per_builder) - if total_tests % args.tests_per_builder != total_tests: - nodes = nodes + 1 - - if args.default_matrix > nodes > 5: - nodes = args.default_matrix - tp.write(f"TWISTER_TESTS={total_tests}\n") tp.write(f"TWISTER_NODES={nodes}\n") tp.write(f"TWISTER_FULL={f.full_twister}\n") From c908aead776d19a9a60abfe2a1b772fd73ff467b Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 7 Jun 2023 09:31:44 +0200 Subject: [PATCH 0035/2042] tests: drivers: dac channel structure has a buffered parameter boolean Add the '.buffered' field to the dac_channel_cfg structure when testing the DAC. This boolean parameter is initialised to 'true' to PASS the test. It follows the https://github.com/zephyrproject-rtos/zephyr/pull/57730 Also changed for the samples/drivers/dac Signed-off-by: Francois Ramu --- samples/drivers/dac/src/main.c | 3 ++- tests/drivers/dac/dac_api/src/test_dac.c | 3 ++- tests/drivers/dac/dac_loopback/src/test_dac.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/samples/drivers/dac/src/main.c b/samples/drivers/dac/src/main.c index 34eb1330b974..308777928b12 100644 --- a/samples/drivers/dac/src/main.c +++ b/samples/drivers/dac/src/main.c @@ -27,7 +27,8 @@ static const struct device *const dac_dev = DEVICE_DT_GET(DAC_NODE); static const struct dac_channel_cfg dac_ch_cfg = { .channel_id = DAC_CHANNEL_ID, - .resolution = DAC_RESOLUTION + .resolution = DAC_RESOLUTION, + .buffered = true }; int main(void) diff --git a/tests/drivers/dac/dac_api/src/test_dac.c b/tests/drivers/dac/dac_api/src/test_dac.c index 44277d7c7fbe..ae03ee582645 100644 --- a/tests/drivers/dac/dac_api/src/test_dac.c +++ b/tests/drivers/dac/dac_api/src/test_dac.c @@ -87,7 +87,8 @@ static const struct dac_channel_cfg dac_ch_cfg = { .channel_id = DAC_CHANNEL_ID, - .resolution = DAC_RESOLUTION + .resolution = DAC_RESOLUTION, + .buffered = true }; const struct device *get_dac_device(void) diff --git a/tests/drivers/dac/dac_loopback/src/test_dac.c b/tests/drivers/dac/dac_loopback/src/test_dac.c index 122218c36457..13b53180e5d3 100644 --- a/tests/drivers/dac/dac_loopback/src/test_dac.c +++ b/tests/drivers/dac/dac_loopback/src/test_dac.c @@ -148,7 +148,8 @@ static const struct dac_channel_cfg dac_ch_cfg = { .channel_id = DAC_CHANNEL_ID, - .resolution = DAC_RESOLUTION + .resolution = DAC_RESOLUTION, + .buffered = true }; static const struct adc_channel_cfg adc_ch_cfg = { From c0c2c6e35cbed37ca4b7de642477764d40366829 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 8 Jun 2023 14:02:19 +0200 Subject: [PATCH 0036/2042] Bluetooth: Host: Set valid default for secondary adv phy Set the secondary advertising PHY to a valid value when using legacy advertising through the LE Set Extended Advertising Parameters command. Fixes #57885. Signed-off-by: Carles Cufi --- subsys/bluetooth/host/adv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 771709bce74b..614220ae5af4 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -1156,12 +1156,11 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, adv->options = param->options; cp->prim_adv_phy = BT_HCI_LE_PHY_1M; - if (param->options & BT_LE_ADV_OPT_EXT_ADV) { - if (param->options & BT_LE_ADV_OPT_NO_2M) { - cp->sec_adv_phy = BT_HCI_LE_PHY_1M; - } else { - cp->sec_adv_phy = BT_HCI_LE_PHY_2M; - } + if ((param->options & BT_LE_ADV_OPT_EXT_ADV) && + !(param->options & BT_LE_ADV_OPT_NO_2M)) { + cp->sec_adv_phy = BT_HCI_LE_PHY_2M; + } else { + cp->sec_adv_phy = BT_HCI_LE_PHY_1M; } if (param->options & BT_LE_ADV_OPT_CODED) { From bcd0e8c1758b90177ac65c95fb5315ffe49afe1b Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 8 Jun 2023 14:11:46 +0200 Subject: [PATCH 0037/2042] tests: bluetooth: tester: Fix ATT max attr size assert ATT attributes can be up to 512 bytes long, so the comparisong needed fixing. See spec v5.4, Vol 3, Part F, 3.2.9. Fixes #57930. Signed-off-by: Carles Cufi --- tests/bluetooth/tester/src/btp_gatt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp_gatt.c b/tests/bluetooth/tester/src/btp_gatt.c index aa8367b6fb90..add74f2fd2f3 100644 --- a/tests/bluetooth/tester/src/btp_gatt.c +++ b/tests/bluetooth/tester/src/btp_gatt.c @@ -415,7 +415,7 @@ static ssize_t write_value(struct bt_conn *conn, value->len = len; /* Maximum attribute value size is 512 bytes */ - __ASSERT_NO_MSG(value->len < 512); + __ASSERT_NO_MSG(value->len <= 512); attr_value_changed_ev(attr->handle, value->data, value->len); From c8a9634a3099436e026ec534164ddf519da61167 Mon Sep 17 00:00:00 2001 From: Luca Fancellu Date: Mon, 5 Jun 2023 10:48:04 +0100 Subject: [PATCH 0038/2042] arch: arm64: Use atomic for fpu_owner pointer Currently the lazy fpu saving algorithm in arm64 is using the fpu_owner pointer from the cpu structure to understand the owner of the context in the cpu and save it in case someone different from the owner is accessing the fpu. The semantics for memory consistency across smp systems is quite prone to errors and reworks on the current code might miss some barriers that could lead to inconsistent state across cores, so to overcome the issue, use atomics to hide the complexity and be sure that the code will behave as intended. While there, add some isb barriers after writes to cpacr_el1, following the guidance of ARM ARM specs about writes on system registers. Signed-off-by: Luca Fancellu --- arch/arm64/core/fpu.c | 21 ++++++++++++--------- include/zephyr/arch/arm64/structs.h | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/arm64/core/fpu.c b/arch/arm64/core/fpu.c index 7b25a38d48c2..74a32b8009c8 100644 --- a/arch/arm64/core/fpu.c +++ b/arch/arm64/core/fpu.c @@ -10,6 +10,7 @@ #include #include #include +#include /* to be found in fpu.S */ extern void z_arm64_fpu_save(struct z_arm64_fp_context *saved_fp_context); @@ -67,7 +68,7 @@ void z_arm64_flush_local_fpu(void) { __ASSERT(read_daif() & DAIF_IRQ_BIT, "must be called with IRQs disabled"); - struct k_thread *owner = _current_cpu->arch.fpu_owner; + struct k_thread *owner = atomic_ptr_get(&_current_cpu->arch.fpu_owner); if (owner != NULL) { uint64_t cpacr = read_cpacr_el1(); @@ -81,11 +82,12 @@ void z_arm64_flush_local_fpu(void) /* make sure content made it to memory before releasing */ barrier_dsync_fence_full(); /* release ownership */ - _current_cpu->arch.fpu_owner = NULL; + atomic_ptr_clear(&_current_cpu->arch.fpu_owner); DBG("disable", owner); /* disable FPU access */ write_cpacr_el1(cpacr & ~CPACR_EL1_FPEN_NOTRAP); + barrier_isync_fence_full(); } } @@ -100,7 +102,7 @@ static void flush_owned_fpu(struct k_thread *thread) unsigned int num_cpus = arch_num_cpus(); for (i = 0; i < num_cpus; i++) { - if (_kernel.cpus[i].arch.fpu_owner != thread) { + if (atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner) != thread) { continue; } /* we found it live on CPU i */ @@ -125,7 +127,7 @@ static void flush_owned_fpu(struct k_thread *thread) */ if (thread == _current) { z_arm64_flush_local_fpu(); - while (_kernel.cpus[i].arch.fpu_owner == thread) { + while (atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner) == thread) { barrier_dsync_fence_full(); } } @@ -233,12 +235,12 @@ void z_arm64_fpu_trap(z_arch_esf_t *esf) barrier_isync_fence_full(); /* save current owner's content if any */ - struct k_thread *owner = _current_cpu->arch.fpu_owner; + struct k_thread *owner = atomic_ptr_get(&_current_cpu->arch.fpu_owner); if (owner) { z_arm64_fpu_save(&owner->arch.saved_fp_context); barrier_dsync_fence_full(); - _current_cpu->arch.fpu_owner = NULL; + atomic_ptr_clear(&_current_cpu->arch.fpu_owner); DBG("save", owner); } @@ -262,7 +264,7 @@ void z_arm64_fpu_trap(z_arch_esf_t *esf) #endif /* become new owner */ - _current_cpu->arch.fpu_owner = _current; + atomic_ptr_set(&_current_cpu->arch.fpu_owner, _current); /* restore our content */ z_arm64_fpu_restore(&_current->arch.saved_fp_context); @@ -285,7 +287,7 @@ static void fpu_access_update(unsigned int exc_update_level) if (arch_exception_depth() == exc_update_level) { /* We're about to execute non-exception code */ - if (_current_cpu->arch.fpu_owner == _current) { + if (atomic_ptr_get(&_current_cpu->arch.fpu_owner) == _current) { /* turn on FPU access */ write_cpacr_el1(cpacr | CPACR_EL1_FPEN_NOTRAP); } else { @@ -300,6 +302,7 @@ static void fpu_access_update(unsigned int exc_update_level) */ write_cpacr_el1(cpacr & ~CPACR_EL1_FPEN_NOTRAP); } + barrier_isync_fence_full(); } /* @@ -330,7 +333,7 @@ int arch_float_disable(struct k_thread *thread) #ifdef CONFIG_SMP flush_owned_fpu(thread); #else - if (thread == _current_cpu->arch.fpu_owner) { + if (thread == atomic_ptr_get(&_current_cpu->arch.fpu_owner)) { z_arm64_flush_local_fpu(); } #endif diff --git a/include/zephyr/arch/arm64/structs.h b/include/zephyr/arch/arm64/structs.h index 88068c837ce9..ea049301dcd8 100644 --- a/include/zephyr/arch/arm64/structs.h +++ b/include/zephyr/arch/arm64/structs.h @@ -10,7 +10,7 @@ /* Per CPU architecture specifics */ struct _cpu_arch { #ifdef CONFIG_FPU_SHARING - struct k_thread *fpu_owner; + atomic_ptr_val_t fpu_owner; #endif #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK uint64_t safe_exception_stack; From 433114edcade9e9ee2cc28e304014fe04aee282f Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 7 Jun 2023 10:55:52 +0200 Subject: [PATCH 0039/2042] tests: drivers: dac loopback on stm32 boards fix pinout Change the pinout for ADC/DAC loopback testing on the stm32 boards nucleo_l073rz: adc_in0_pa0/dac_out1_pa4 --> A0 to A2 on arduino CN8 nucleo_g071rb: adc1_in0_pa0/dac1_out1_pa4 --> A0 to A2 on arduino CN8 stm32l562e_dk: adc1_in13_pc4/dac1_out1_pa4 --> A2 to A4 on arduino CN19 Adjust the ACQuisition time to the MAX value because the default (=0) is too low for several boards. Signed-off-by: Francois Ramu --- tests/drivers/dac/dac_loopback/src/test_dac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/drivers/dac/dac_loopback/src/test_dac.c b/tests/drivers/dac/dac_loopback/src/test_dac.c index 13b53180e5d3..dff32bbfba2c 100644 --- a/tests/drivers/dac/dac_loopback/src/test_dac.c +++ b/tests/drivers/dac/dac_loopback/src/test_dac.c @@ -26,8 +26,7 @@ * point is at half of the full scale voltage. */ -#if defined(CONFIG_BOARD_NUCLEO_L073RZ) || \ - defined(CONFIG_BOARD_NUCLEO_L152RE) || \ +#if defined(CONFIG_BOARD_NUCLEO_L152RE) || \ defined(CONFIG_BOARD_STM32F3_DISCO) || \ defined(CONFIG_BOARD_STM32L562E_DK) || \ defined(CONFIG_BOARD_NUCLEO_L552ZE_Q) || \ @@ -44,13 +43,20 @@ #define DAC_RESOLUTION 12 #define ADC_DEVICE_NODE DT_NODELABEL(adc1) +#if defined(CONFIG_BOARD_STM32L562E_DK) +#define ADC_CHANNEL_ID 13 +#else #define ADC_CHANNEL_ID 1 +#endif /* CONFIG_BOARD_STM32L562E_DK */ #define ADC_RESOLUTION 12 #define ADC_GAIN ADC_GAIN_1 #define ADC_REFERENCE ADC_REF_INTERNAL -#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +/* The STM32L562E_DK does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */ +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX -#elif defined(CONFIG_BOARD_NUCLEO_F207ZG) || \ + +#elif defined(CONFIG_BOARD_NUCLEO_L073RZ) || \ + defined(CONFIG_BOARD_NUCLEO_F207ZG) || \ defined(CONFIG_BOARD_NUCLEO_F429ZI) || \ defined(CONFIG_BOARD_NUCLEO_F746ZG) || \ defined(CONFIG_BOARD_NUCLEO_G071RB) @@ -68,7 +74,8 @@ #define ADC_RESOLUTION 12 #define ADC_GAIN ADC_GAIN_1 #define ADC_REFERENCE ADC_REF_INTERNAL -#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +/* The NUCLEO_G071RB does not accept ADC_ACQ_TIME_DEFAULT (=0) but the MAX one */ +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_MAX #elif defined(CONFIG_BOARD_TWR_KE18F) From 9ce0d416f513b9108c13f07e4927c2400d2b6c72 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 16:33:18 +0200 Subject: [PATCH 0040/2042] manifest: bsim: Do not import but replicate in main manifest Due to a limitation in the west import feature, a project cannot both have an import and be part of a group. Moreover, when a project has an import and is not filtered out, it is required for that project to be present for most west commands to work. As the bsim project is not filtered by default, it causes trouble for users who never run a west update but try to use west further. To work around this issue, let's disable the import in the bsim project, and instead replicate its content inside Zephyr's main manifest. Having a replica of the babblesim manifest content is likely to cause some confusion in users, wrt to which version of components they are using. So whenever west supports both imports and groups, or another simple and nicer way of working around this, it should be used. Signed-off-by: Alberto Escolar Piedras --- west.yml | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/west.yml b/west.yml index ca33049f8182..abe9772498ea 100644 --- a/west.yml +++ b/west.yml @@ -21,6 +21,8 @@ manifest: remotes: - name: upstream url-base: https://github.com/zephyrproject-rtos + - name: babblesim + url-base: https://github.com/BabbleSim group-filter: [-babblesim] @@ -30,8 +32,86 @@ manifest: - name: bsim repo-path: babblesim-manifest revision: 908ffde6298a937c6549dbfa843a62caab26bfc5 - import: - path-prefix: tools + path: tools/bsim + groups: + - babblesim + - name: babblesim_base + remote: babblesim + repo-path: base.git + path: tools/bsim/components + revision: 02838ca04c4562e68dc876196828d8121679e537 + groups: + - babblesim + - name: babblesim_ext_2G4_libPhyComv1 + remote: babblesim + repo-path: ext_2G4_libPhyComv1.git + path: tools/bsim/components/ext_2G4_libPhyComv1 + revision: 9018113a362fa6c9e8f4b9cab9e5a8f12cc46b94 + groups: + - babblesim + - name: babblesim_ext_2G4_phy_v1 + remote: babblesim + repo-path: ext_2G4_phy_v1.git + path: tools/bsim/components/ext_2G4_phy_v1 + revision: cf2d86e736efac4f12fad5093ed2da2c5b406156 + groups: + - babblesim + - name: babblesim_ext_2G4_channel_NtNcable + remote: babblesim + repo-path: ext_2G4_channel_NtNcable.git + path: tools/bsim/components/ext_2G4_channel_NtNcable + revision: 20a38c997f507b0aa53817aab3d73a462fff7af1 + groups: + - babblesim + - name: babblesim_ext_2G4_channel_multiatt + remote: babblesim + repo-path: ext_2G4_channel_multiatt.git + path: tools/bsim/components/ext_2G4_channel_multiatt + revision: e09bc2d14b1975f969ad19c6ed23eb20e5dc3d09 + groups: + - babblesim + - name: babblesim_ext_2G4_modem_magic + remote: babblesim + repo-path: ext_2G4_modem_magic.git + path: tools/bsim/components/ext_2G4_modem_magic + revision: cb70771794f0bf6f262aa474848611c68ae8f1ed + groups: + - babblesim + - name: babblesim_ext_2G4_modem_BLE_simple + remote: babblesim + repo-path: ext_2G4_modem_BLE_simple.git + path: tools/bsim/components/ext_2G4_modem_BLE_simple + revision: ce975a3259fd0dd761d371b60435242d54794bad + groups: + - babblesim + - name: babblesim_ext_2G4_device_burst_interferer + remote: babblesim + repo-path: ext_2G4_device_burst_interferer.git + path: tools/bsim/components/ext_2G4_device_burst_interferer + revision: 5b5339351d6e6a2368c686c734dc8b2fc65698fc + groups: + - babblesim + - name: babblesim_ext_2G4_device_WLAN_actmod + remote: babblesim + repo-path: ext_2G4_device_WLAN_actmod.git + path: tools/bsim/components/ext_2G4_device_WLAN_actmod + revision: 9cb6d8e72695f6b785e57443f0629a18069d6ce4 + groups: + - babblesim + - name: babblesim_ext_2G4_device_playback + remote: babblesim + repo-path: ext_2G4_device_playback.git + path: tools/bsim/components/ext_2G4_device_playback + revision: 85c645929cf1ce995d8537107d9dcbd12ed64036 + groups: + - babblesim + - name: babblesim_ext_libCryptov1 + remote: babblesim + repo-path: ext_libCryptov1.git + path: tools/bsim/components/ext_libCryptov1 + revision: eed6d7038e839153e340bd333bc43541cb90ba64 + groups: + - babblesim - name: canopennode revision: dec12fa3f0d790cafa8414a4c2930ea71ab72ffd path: modules/lib/canopennode From 1c165296e8a89580adc417f6bcd1c5eb0d454f7a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 28 Apr 2023 08:10:58 +0200 Subject: [PATCH 0041/2042] Revert "ci: doc-build: Pull 'bsim' west project" This reverts commit 00130b72ceb8a68aee2faa564e7107a5fc56deb2. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/doc-build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 1455de66c63b..466f9c8afbda 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -69,7 +69,6 @@ jobs: - name: west setup run: | west init -l . - west update bsim - name: build-docs run: | @@ -155,7 +154,6 @@ jobs: - name: west setup run: | west init -l . - west update bsim - name: build-docs run: | From 9af9a812b606344a99fa98c0cdd7ca218edf672c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 16:53:24 +0200 Subject: [PATCH 0042/2042] CI: bsim workflow: Fix getting bsim revision As the bsim repo is disabled by default, west list bsim -f {sha} fails. Instead get the revision field which works. Signed-off-by: Alberto Escolar Piedras --- .github/workflows/bsim-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index 13aff26f8cdc..16d3b7a1f4ac 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -116,7 +116,7 @@ jobs: || steps.check-networking-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' run: | - export BSIM_VERSION=$( west list bsim -f {sha} ) + export BSIM_VERSION=$( west list bsim -f {revision} ) echo "Manifest points to bsim sha $BSIM_VERSION" cd /opt/bsim_west/bsim git fetch -n origin ${BSIM_VERSION} From f282ce90ccf18c085fe6f825af50db3de34e5d19 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 2 Jun 2023 12:11:47 +0200 Subject: [PATCH 0043/2042] Bluetooth: MPL: Modify parse_search to use bt_data_parse Modify the implementation of parse_search to use a net_buf_simple and bt_data_parse to parse the LTV search structure. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/mpl.c | 52 +++++++++++++++++------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index a1c9a321da00..0863db31e2f8 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -2622,43 +2622,41 @@ uint32_t get_commands_supported(void) } #ifdef CONFIG_BT_MPL_OBJECTS + +static bool parse_sci(struct bt_data *data, void *user_data) +{ + LOG_DBG("type: %u len %u", data->type, data->data_len); + LOG_HEXDUMP_DBG(data->data, data->data_len, "param:"); + + if (data->type < MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME || + data->type > MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS) { + LOG_DBG("Invalid search type: %u", data->type); + return false; + } + + return true; +} + static void parse_search(const struct mpl_search *search) { - uint8_t index = 0; - struct mpl_sci sci; - uint8_t sci_num = 0; bool search_failed = false; if (search->len > SEARCH_LEN_MAX) { LOG_WRN("Search too long (%d) - aborting", search->len); search_failed = true; } else { - LOG_DBG("Parsing %d octets search", search->len); + uint8_t search_ltv[SEARCH_LEN_MAX]; + struct net_buf_simple buf; - while (search->len - index > 0) { - sci.len = (uint8_t)search->search[index++]; - if (sci.len < SEARCH_SCI_LEN_MIN) { - LOG_WRN("Invalid length field - too small"); - search_failed = true; - break; - } - if (sci.len > (search->len - index)) { - LOG_WRN("Incomplete search control item"); - search_failed = true; - break; - } - sci.type = (uint8_t)search->search[index++]; - if (sci.type < MEDIA_PROXY_SEARCH_TYPE_TRACK_NAME || - sci.type > MEDIA_PROXY_SEARCH_TYPE_ONLY_GROUPS) { - search_failed = true; - break; - } - (void)memcpy(&sci.param, &search->search[index], sci.len - 1); - index += sci.len - 1; + /* Copy so that we can parse it using the net_buf_simple when search is const */ + memcpy(search_ltv, search->search, search->len); + + net_buf_simple_init_with_data(&buf, search_ltv, search->len); + + bt_data_parse(&buf, parse_sci, NULL); - LOG_DBG("SCI # %d: type: %d", sci_num, sci.type); - LOG_HEXDUMP_DBG(sci.param, sci.len - 1, "param:"); - sci_num++; + if (buf.len != 0U) { + search_failed = true; } } From 028e0a3c8d75fc5e2027f54dbb5a55aadbb1c490 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 8 Jun 2023 11:42:44 +0200 Subject: [PATCH 0044/2042] Bluetooth: Shell: On disconnect set new default_conn When a device disconnects we previously just unref'ed it and set default_conn = NULL. However, if we are connected to mulitple devices, it makes sense to set the default_conn to one of the other connections. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 89cb1aaf17fc..bc62751dd9dd 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -515,6 +515,30 @@ static void connected(struct bt_conn *conn, uint8_t err) } } +static void disconencted_set_new_default_conn_cb(struct bt_conn *conn, void *user_data) +{ + struct bt_conn_info info; + + if (default_conn != NULL) { + /* nop */ + return; + } + + if (bt_conn_get_info(conn, &info) != 0) { + shell_error(ctx_shell, "Unable to get info: conn %p", conn); + return; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + char addr_str[BT_ADDR_LE_STR_LEN]; + + default_conn = bt_conn_ref(conn); + + bt_addr_le_to_str(info.le.dst, addr_str, sizeof(addr_str)); + shell_print(ctx_shell, "Selected conn is now: %s", addr_str); + } +} + static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; @@ -525,6 +549,9 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) if (default_conn == conn) { bt_conn_unref(default_conn); default_conn = NULL; + + /* If we are connected to other devices, set one of them as default */ + bt_conn_foreach(BT_CONN_TYPE_LE, disconencted_set_new_default_conn_cb, NULL); } } @@ -2623,6 +2650,7 @@ static int cmd_disconnect(const struct shell *sh, size_t argc, char *argv[]) static int cmd_select(const struct shell *sh, size_t argc, char *argv[]) { + char addr_str[BT_ADDR_LE_STR_LEN]; struct bt_conn *conn; bt_addr_le_t addr; int err; @@ -2645,6 +2673,9 @@ static int cmd_select(const struct shell *sh, size_t argc, char *argv[]) default_conn = conn; + bt_addr_le_to_str(&addr, addr_str, sizeof(addr_str)); + shell_print(sh, "Selected conn is now: %s", addr_str); + return 0; } From 9d6ced38226146071369ebc4bca9e78b8aa4786f Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Tue, 6 Jun 2023 13:11:06 +0100 Subject: [PATCH 0045/2042] ARC: SMP: fix livelock in thread abort due to exception We are missing setting of switch_handle for the thread which is aborting due to exception (i.e. in case of k_panic or __ASSERT triggered). This may cause livelock in SMP code after a08e23f68e03 commit ("kernel/sched: Fix SMP must-wait-for-switch conditions in abort/join"). Fix that. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- arch/arc/core/fault_s.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arc/core/fault_s.S b/arch/arc/core/fault_s.S index d9019becb495..d89f3fe6a820 100644 --- a/arch/arc/core/fault_s.S +++ b/arch/arc/core/fault_s.S @@ -118,6 +118,11 @@ _exc_return: BREQR r0, 0, _exc_return_from_exc + /* Save old thread into switch handle which is required by z_sched_switch_spin which + * will be called during old thread abort. + */ + STR r2, r2, ___thread_t_switch_handle_OFFSET + MOVR r2, r0 #ifdef CONFIG_ARC_SECURE_FIRMWARE From a8ed28ab6fc868ac73eed56fc3b46c23df52adde Mon Sep 17 00:00:00 2001 From: Cyril Fougeray Date: Thu, 8 Jun 2023 14:51:45 +0200 Subject: [PATCH 0046/2042] stm32g4: adc345: set resolutions & sampling-times in dtsi bring back adc3/4/5 with latest "st,stm32-adc" required properties: resolutions & sampling-times Signed-off-by: Cyril Fougeray --- dts/arm/st/g4/stm32g473.dtsi | 10 ++++++++++ dts/arm/st/g4/stm32g491.dtsi | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/dts/arm/st/g4/stm32g473.dtsi b/dts/arm/st/g4/stm32g473.dtsi index 7398c541f9ff..d47f288b8172 100644 --- a/dts/arm/st/g4/stm32g473.dtsi +++ b/dts/arm/st/g4/stm32g473.dtsi @@ -34,6 +34,11 @@ interrupts = <61 0>; status = "disabled"; #io-channel-cells = <1>; + resolutions = ; + sampling-times = <3 7 13 25 48 93 248 641>; }; adc5: adc@50000600 { @@ -44,6 +49,11 @@ status = "disabled"; #io-channel-cells = <1>; temp-channel = <4>; + resolutions = ; + sampling-times = <3 7 13 25 48 93 248 641>; }; spi4: spi@40013c00 { diff --git a/dts/arm/st/g4/stm32g491.dtsi b/dts/arm/st/g4/stm32g491.dtsi index b01d91b5a594..44ec13a395ea 100644 --- a/dts/arm/st/g4/stm32g491.dtsi +++ b/dts/arm/st/g4/stm32g491.dtsi @@ -65,6 +65,11 @@ status = "disabled"; #io-channel-cells = <1>; vref-channel = <18>; + resolutions = ; + sampling-times = <3 7 13 25 48 93 248 641>; }; uart5: serial@40005000 { From 8eaeb737532bf3ca471c58a74c4a019f80ed5d5a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 8 Jun 2023 12:00:49 +0200 Subject: [PATCH 0047/2042] tests: Bluetooth: Split CAP initiator tests to unicast and broadcast Split the cap_initiator_test.c to two new files cap_initiator_broadcast_test.c and cap_initiator_unicast_test.c as the two barely had any common functionality, and the file was getting too large. Signed-off-by: Emil Gydesen --- .../audio/src/cap_initiator_broadcast_test.c | 585 ++++++++ .../bluetooth/audio/src/cap_initiator_test.c | 1235 ----------------- .../audio/src/cap_initiator_unicast_test.c | 677 +++++++++ tests/bsim/bluetooth/audio/src/main.c | 8 +- 4 files changed, 1267 insertions(+), 1238 deletions(-) create mode 100644 tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c delete mode 100644 tests/bsim/bluetooth/audio/src/cap_initiator_test.c create mode 100644 tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c new file mode 100644 index 000000000000..d28bd4a88261 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + +#include +#include +#include +#include +#include +#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) + +BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, + "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " + "BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT"); + +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 struct bt_cap_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 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); + k_sem_give(&sem_broadcast_started); +} + +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); +} + +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_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); + return; + } + + if (TEST_FLAG(flag_broadcast_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, broadcast_preset_16_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. */ + printk("Unable to broadcast data on %p: %d\n", stream, ret); + 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 void init(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth enable failed (err %d)\n", err); + return; + } + + (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]; + bt_cap_stream_ops_register(broadcast_streams[i], &broadcast_stream_ops); + } +} + +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 + sizeof(ext_ad.type); + 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 test_broadcast_audio_create_inval(void) +{ + struct bt_codec_data bis_codec_data = + BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); + struct bt_cap_initiator_broadcast_stream_param + stream_params[ARRAY_SIZE(broadcast_source_streams)]; + 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_codec invalid_codec = + BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + int err; + + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { + stream_params[i].stream = &broadcast_source_streams[i]; + stream_params[i].data_count = 1U; + stream_params[i].data = &bis_codec_data; + } + + subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); + subgroup_param.stream_params = stream_params; + subgroup_param.codec = &broadcast_preset_16_2_1.codec; + + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_16_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + /* Test NULL parameters */ + err = bt_cap_initiator_broadcast_audio_create(NULL, &broadcast_source); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_create with NULL param did not fail\n"); + return; + } + + err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_create with NULL broadcast source did not " + "fail\n"); + return; + } + + /* Clear metadata so that it does not contain the mandatory stream context */ + memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); + subgroup_param.codec = &invalid_codec; + err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_create with invalid metadata did not " + "fail\n"); + return; + } + + /* Since we are just casting the CAP parameters to BAP parameters, + * we can rely on the BAP tests to verify the values + */ +} + +static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadcast_source) +{ + struct bt_codec_data bis_codec_data = + BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); + struct bt_cap_initiator_broadcast_stream_param + stream_params[ARRAY_SIZE(broadcast_source_streams)]; + struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; + struct bt_cap_initiator_broadcast_create_param create_param; + int err; + + for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { + stream_params[i].stream = &broadcast_source_streams[i]; + stream_params[i].data_count = 1U; + stream_params[i].data = &bis_codec_data; + } + + subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); + subgroup_param.stream_params = stream_params; + subgroup_param.codec = &broadcast_preset_16_2_1.codec; + + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_16_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + printk("Creating broadcast source with %zu broadcast_streams\n", + ARRAY_SIZE(broadcast_streams)); + + err = bt_cap_initiator_broadcast_audio_create(&create_param, broadcast_source); + if (err != 0) { + FAIL("Unable to start broadcast source: %d\n", err); + return; + } + + printk("Broadcast source created with %zu broadcast_streams\n", + ARRAY_SIZE(broadcast_streams)); +} + +static void test_broadcast_audio_start_inval(struct bt_cap_broadcast_source *broadcast_source, + struct bt_le_ext_adv *adv) +{ + int err; + + /* Test NULL parameters */ + err = bt_cap_initiator_broadcast_audio_start(NULL, adv); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_start with NULL broadcast source did not " + "fail\n"); + return; + } + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, NULL); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_start with NULL adv did not fail\n"); + return; + } +} + +static void test_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 with %zu broadcast_streams\n", + ARRAY_SIZE(broadcast_streams)); +} + +static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source) +{ + const uint16_t mock_ccid = 0x1234; + const struct bt_codec_data new_metadata[] = { + BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), + ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), + BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), + ((mock_ccid >> 8) & 0xFFU)), + }; + const struct bt_codec_data invalid_metadata[] = { + BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), + ((mock_ccid >> 8) & 0xFFU)), + }; + int err; + + /* Test NULL parameters */ + err = bt_cap_initiator_broadcast_audio_update(NULL, new_metadata, ARRAY_SIZE(new_metadata)); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_update with NULL broadcast source did not " + "fail\n"); + return; + } + + err = bt_cap_initiator_broadcast_audio_update(broadcast_source, NULL, + ARRAY_SIZE(new_metadata)); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_update with NULL metadata did not fail\n"); + return; + } + + err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata, 0); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_update with 0 metadata count did not " + "fail\n"); + return; + } + + /* Test with metadata without streaming context */ + err = bt_cap_initiator_broadcast_audio_update(broadcast_source, invalid_metadata, + ARRAY_SIZE(invalid_metadata)); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_update with invalid metadata did not " + "fail\n"); + return; + } + + printk("Broadcast metadata updated\n"); +} + +static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source) +{ + const uint16_t mock_ccid = 0x1234; + const struct bt_codec_data new_metadata[] = { + BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), + BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, BT_BYTES_LIST_LE16(mock_ccid)), + }; + int err; + + printk("Updating broadcast metadata\n"); + + err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata, + ARRAY_SIZE(new_metadata)); + if (err != 0) { + FAIL("Failed to update broadcast source metadata: %d\n", err); + return; + } + + printk("Broadcast metadata updated\n"); +} + +static void test_broadcast_audio_stop_inval(void) +{ + int err; + + /* Test NULL parameters */ + err = bt_cap_initiator_broadcast_audio_stop(NULL); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_stop with NULL broadcast source did not " + "fail\n"); + return; + } +} + +static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source) +{ + int err; + + printk("Stopping broadcast metadata\n"); + + 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 < ARRAY_SIZE(broadcast_streams); i++) { + k_sem_take(&sem_broadcast_stopped, K_FOREVER); + } + + printk("Broadcast metadata stopped\n"); + + /* Verify that it cannot be stopped twice */ + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_stop with already-stopped broadcast source " + "did not fail\n"); + return; + } +} + +static void test_broadcast_audio_delete_inval(void) +{ + int err; + + /* Test NULL parameters */ + err = bt_cap_initiator_broadcast_audio_delete(NULL); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_delete with NULL broadcast source did not " + "fail\n"); + return; + } +} + +static void test_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source) +{ + int err; + + printk("Stopping broadcast metadata\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 metadata stopped\n"); + + /* Verify that it cannot be deleted twice */ + err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err == 0) { + FAIL("bt_cap_initiator_broadcast_audio_delete with already-deleted broadcast " + "source did not fail\n"); + return; + } +} + +static void test_main_cap_initiator_broadcast(void) +{ + struct bt_cap_broadcast_source *broadcast_source; + struct bt_le_ext_adv *adv; + + (void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams)); + + init(); + + setup_extended_adv(&adv); + + test_broadcast_audio_create_inval(); + test_broadcast_audio_create(&broadcast_source); + + test_broadcast_audio_start_inval(broadcast_source, adv); + 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 < ARRAY_SIZE(broadcast_streams); 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++) { + broadcast_sent_cb(&broadcast_streams[i]->bap_stream); + } + } + + /* Keeping running for a little while */ + k_sleep(K_SECONDS(5)); + + test_broadcast_audio_update_inval(broadcast_source); + test_broadcast_audio_update(broadcast_source); + + /* Keeping running for a little while */ + k_sleep(K_SECONDS(5)); + + test_broadcast_audio_stop_inval(); + test_broadcast_audio_stop(broadcast_source); + + test_broadcast_audio_delete_inval(); + test_broadcast_audio_delete(broadcast_source); + broadcast_source = NULL; + + stop_and_delete_extended_adv(adv); + adv = NULL; + + PASS("CAP initiator broadcast passed\n"); +} + +static const struct bst_test_instance test_cap_initiator_broadcast[] = { + { + .test_id = "cap_initiator_broadcast", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_cap_initiator_broadcast, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_cap_initiator_broadcast); +} + +#else /* !(defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE)) */ + +struct bst_test_list *test_cap_initiator_broadcast_install(struct bst_test_list *tests) +{ + return tests; +} + +#endif /* defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_BROADCAST_SOURCE) */ diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_test.c deleted file mode 100644 index 342e515805da..000000000000 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_test.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * Copyright (c) 2022-2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if defined(CONFIG_BT_CAP_INITIATOR) - -#include -#include -#include -#include -#include -#include "common.h" -#include "bap_unicast_common.h" - - -#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) -#define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT -#else -#define BROADCAST_STREMT_CNT 0 -#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ -/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that - * the controller is never idle - */ -#define BROADCAST_ENQUEUE_COUNT 2U -#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT) - -BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, - "CONFIG_BT_ISO_TX_BUF_COUNT should be at least " - "BROADCAST_ENQUEUE_COUNT * BROADCAST_STREMT_CNT"); - -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 struct bt_cap_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 unicast_preset_16_2_1 = - BT_BAP_LC3_UNICAST_PRESET_16_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); - -static struct bt_cap_stream unicast_client_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; -static struct bt_bap_ep *unicast_sink_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_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)); - -CREATE_FLAG(flag_discovered); -CREATE_FLAG(flag_codec_found); -CREATE_FLAG(flag_endpoint_found); -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_broadcast_stopping); - -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) -{ - 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_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); - return; - } - - if (TEST_FLAG(flag_broadcast_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, broadcast_preset_16_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. */ - printk("Unable to broadcast data on %p: %d\n", stream, ret); - 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 void unicast_stream_configured(struct bt_bap_stream *stream, - const struct bt_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 unicast_stream_qos_set(struct bt_bap_stream *stream) -{ - printk("QoS set stream %p\n", stream); -} - -static void unicast_stream_enabled(struct bt_bap_stream *stream) -{ - printk("Enabled stream %p\n", stream); -} - -static void unicast_stream_started(struct bt_bap_stream *stream) -{ - printk("Started stream %p\n", stream); -} - -static void unicast_stream_metadata_updated(struct bt_bap_stream *stream) -{ - printk("Metadata updated stream %p\n", stream); -} - -static void unicast_stream_disabled(struct bt_bap_stream *stream) -{ - printk("Disabled stream %p\n", stream); -} - -static void unicast_stream_stopped(struct bt_bap_stream *stream, uint8_t reason) -{ - printk("Stopped stream with reason 0x%02X%p\n", stream, reason); -} - -static void unicast_stream_released(struct bt_bap_stream *stream) -{ - printk("Released stream %p\n", stream); -} - -static struct bt_bap_stream_ops unicast_stream_ops = { - .configured = unicast_stream_configured, - .qos_set = unicast_stream_qos_set, - .enabled = unicast_stream_enabled, - .started = unicast_stream_started, - .metadata_updated = unicast_stream_metadata_updated, - .disabled = unicast_stream_disabled, - .stopped = unicast_stream_stopped, - .released = unicast_stream_released, -}; - -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 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", 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", 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", 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(struct bt_bap_ep *ep) -{ - for (size_t i = 0U; i < ARRAY_SIZE(unicast_sink_eps); i++) { - if (unicast_sink_eps[i] == NULL) { - printk("Sink #%zu: ep %p\n", i, ep); - unicast_sink_eps[i] = ep; - return; - } - } - - FAIL("Could not add source ep\n"); -} - -static void print_remote_codec(const struct bt_codec *codec, enum bt_audio_dir dir) -{ - printk("codec %p dir 0x%02x\n", codec, dir); - - print_codec(codec); -} - -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) -{ - print_remote_codec(codec, dir); - SET_FLAG(flag_codec_found); -} - -static void discover_sink_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) -{ - if (err != 0) { - FAIL("Discovery failed: %d\n", err); - return; - } - - printk("Sink discover complete\n"); - - SET_FLAG(flag_sink_discovered); -} - -static void 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); - SET_FLAG(flag_endpoint_found); - } else { - FAIL("Invalid param dir: %u\n", dir); - } -} - -static const struct bt_bap_unicast_client_cb unicast_client_cbs = { - .discover = discover_sink_cb, - .pac_record = pac_record_cb, - .endpoint = endpoint_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; - } - - if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) { - bt_gatt_cb_register(&gatt_callbacks); - - err = bt_bap_unicast_client_register_cb(&unicast_client_cbs); - if (err != 0) { - FAIL("Failed to register BAP unicast client 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(broadcast_streams); i++) { - bt_cap_stream_ops_register(&unicast_client_streams[i], - &unicast_stream_ops); - } - } - - if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE)) { - (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]; - bt_cap_stream_ops_register(broadcast_streams[i], - &broadcast_stream_ops); - } - } -} - -static void scan_and_connect(void) -{ - int err; - - err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, 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); -} - -static void discover_sink(void) -{ - int err; - - UNSET_FLAG(flag_sink_discovered); - UNSET_FLAG(flag_codec_found); - UNSET_FLAG(flag_endpoint_found); - - err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK); - if (err != 0) { - printk("Failed to discover sink: %d\n", err); - return; - } - - memset(unicast_sink_eps, 0, sizeof(unicast_sink_eps)); - - WAIT_FOR_FLAG(flag_sink_discovered); - WAIT_FOR_FLAG(flag_endpoint_found); - WAIT_FOR_FLAG(flag_codec_found); -} - -static void discover_cas_inval(void) -{ - int err; - - err = bt_cap_initiator_unicast_discover(NULL); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_discover with NULL conn did not fail\n"); - return; - } - - /* Test if it handles concurrent request for same connection */ - UNSET_FLAG(flag_discovered); - - err = bt_cap_initiator_unicast_discover(default_conn); - if (err != 0) { - printk("Failed to discover CAS: %d\n", err); - return; - } - - err = bt_cap_initiator_unicast_discover(default_conn); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_discover while previous discovery has not completed " - "did not fail\n"); - return; - } - - WAIT_FOR_FLAG(flag_discovered); -} - -static void discover_cas(void) -{ - int err; - - UNSET_FLAG(flag_discovered); - - err = bt_cap_initiator_unicast_discover(default_conn); - if (err != 0) { - printk("Failed to discover CAS: %d\n", err); - return; - } - - WAIT_FOR_FLAG(flag_discovered); -} - -static void unicast_group_create(struct bt_bap_unicast_group **out_unicast_group) -{ - struct bt_bap_unicast_group_stream_param group_stream_params; - struct bt_bap_unicast_group_stream_pair_param pair_params; - struct bt_bap_unicast_group_param group_param; - int err; - - group_stream_params.qos = &unicast_preset_16_2_1.qos; - group_stream_params.stream = &unicast_client_streams[0].bap_stream; - pair_params.tx_param = &group_stream_params; - pair_params.rx_param = NULL; - - group_param.packing = BT_ISO_PACKING_SEQUENTIAL; - group_param.params_count = 1; - group_param.params = &pair_params; - - err = bt_bap_unicast_group_create(&group_param, out_unicast_group); - if (err != 0) { - FAIL("Failed to create group: %d\n", err); - return; - } -} - -static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group) -{ - struct bt_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); - struct bt_cap_unicast_audio_start_stream_param invalid_stream_param; - struct bt_cap_unicast_audio_start_stream_param valid_stream_param; - struct bt_cap_unicast_audio_start_param invalid_start_param; - struct bt_cap_unicast_audio_start_param valid_start_param; - int err; - - valid_start_param.type = BT_CAP_SET_TYPE_AD_HOC; - valid_start_param.count = 1u; - valid_start_param.stream_params = &valid_stream_param; - - valid_stream_param.member.member = default_conn; - valid_stream_param.stream = &unicast_client_streams[0]; - valid_stream_param.ep = unicast_sink_eps[0]; - valid_stream_param.codec = &unicast_preset_16_2_1.codec; - valid_stream_param.qos = &unicast_preset_16_2_1.qos; - - /* Test NULL parameters */ - err = bt_cap_initiator_unicast_audio_start(NULL, unicast_group); - 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)); - invalid_start_param.stream_params = &invalid_stream_param; - - /* Test invalid stream_start parameters */ - invalid_start_param.count = 0U; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with 0 count did not fail\n"); - return; - } - - memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param)); - 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); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params did not fail\n"); - return; - } - - memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param)); - invalid_start_param.stream_params = &invalid_stream_param; - - /* Test invalid stream_param parameters */ - invalid_stream_param.member.member = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params member did not " - "fail\n"); - return; - } - - 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); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params stream did not " - "fail\n"); - return; - } - - 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); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params ep did not " - "fail\n"); - return; - } - - memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); - - invalid_stream_param.codec = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params codec did not " - "fail\n"); - return; - } - - memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); - - invalid_stream_param.qos = NULL; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params qos did not " - "fail\n"); - return; - } - - /* Clear metadata so that it does not contain the mandatory stream context */ - memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); - memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - - invalid_stream_param.codec = &invalid_codec; - err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_start with invalid Codec metadata did not " - "fail\n"); - return; - } -} - -static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group) -{ - struct bt_cap_unicast_audio_start_stream_param stream_param[1]; - struct bt_cap_unicast_audio_start_param param; - int err; - - param.type = BT_CAP_SET_TYPE_AD_HOC; - param.count = 1u; - param.stream_params = stream_param; - stream_param[0].member.member = default_conn; - stream_param[0].stream = &unicast_client_streams[0]; - stream_param[0].ep = unicast_sink_eps[0]; - stream_param[0].codec = &unicast_preset_16_2_1.codec; - stream_param[0].qos = &unicast_preset_16_2_1.qos; - - UNSET_FLAG(flag_started); - - err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); - if (err != 0) { - FAIL("Failed to start unicast audio: %d\n", err); - return; - } - - WAIT_FOR_FLAG(flag_started); -} - -static void unicast_audio_update_inval(void) -{ - struct bt_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); - struct bt_cap_unicast_audio_update_param param; - int err; - - param.stream = &unicast_client_streams[0]; - param.meta = unicast_preset_16_2_1.codec.meta; - param.meta_count = unicast_preset_16_2_1.codec.meta_count; - - err = bt_cap_initiator_unicast_audio_update(NULL, 1); - 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); - 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 */ - memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - param.meta = invalid_codec.meta; - - err = bt_cap_initiator_unicast_audio_update(¶m, 1); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_update with invalid Codec metadata did not " - "fail\n"); - return; - } -} - -static void unicast_audio_update(void) -{ - struct bt_cap_unicast_audio_update_param param; - int err; - - param.stream = &unicast_client_streams[0]; - param.meta = unicast_preset_16_2_1.codec.meta; - param.meta_count = unicast_preset_16_2_1.codec.meta_count; - - UNSET_FLAG(flag_updated); - - err = bt_cap_initiator_unicast_audio_update(¶m, 1); - if (err != 0) { - FAIL("Failed to update unicast audio: %d\n", err); - return; - } - - WAIT_FOR_FLAG(flag_updated); -} - -static void unicast_audio_stop_inval(void) -{ - int err; - - 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"); - return; - } -} - -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); - - /* Verify that it cannot be stopped twice */ - err = bt_cap_initiator_unicast_audio_stop(unicast_group); - if (err == 0) { - FAIL("bt_cap_initiator_unicast_audio_stop with already-stopped unicast group did " - "not fail\n"); - return; - } -} - -static void unicast_group_delete_inval(void) -{ - int err; - - err = bt_bap_unicast_group_delete(NULL); - if (err == 0) { - FAIL("bt_bap_unicast_group_delete with NULL group did not fail\n"); - return; - } -} - -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; - } - - /* Verify that it cannot be deleted twice */ - err = bt_bap_unicast_group_delete(unicast_group); - if (err == 0) { - FAIL("bt_bap_unicast_group_delete with already-deleted unicast group did not " - "fail\n"); - return; - } -} - -static void test_cap_initiator_unicast(void) -{ - struct bt_bap_unicast_group *unicast_group; - const size_t iterations = 2; - - init(); - - scan_and_connect(); - - WAIT_FOR_FLAG(flag_mtu_exchanged); - - discover_cas_inval(); - discover_cas(); - - discover_sink(); - - for (size_t i = 0U; i < iterations; i++) { - unicast_group_create(&unicast_group); - - for (size_t j = 0U; j < iterations; j++) { - unicast_audio_start_inval(unicast_group); - unicast_audio_start(unicast_group); - - unicast_audio_update_inval(); - unicast_audio_update(); - - unicast_audio_stop_inval(); - unicast_audio_stop(unicast_group); - } - - unicast_group_delete_inval(); - unicast_group_delete(unicast_group); - unicast_group = NULL; - } - - PASS("CAP initiator unicast passed\n"); -} - -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 + sizeof(ext_ad.type); - 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 test_broadcast_audio_create_inval(void) -{ - struct bt_codec_data bis_codec_data = - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); - struct bt_cap_initiator_broadcast_stream_param - stream_params[ARRAY_SIZE(broadcast_source_streams)]; - 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_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); - int err; - - for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { - stream_params[i].stream = &broadcast_source_streams[i]; - stream_params[i].data_count = 1U; - stream_params[i].data = &bis_codec_data; - } - - subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); - subgroup_param.stream_params = stream_params; - subgroup_param.codec = &broadcast_preset_16_2_1.codec; - - create_param.subgroup_count = 1U; - create_param.subgroup_params = &subgroup_param; - create_param.qos = &broadcast_preset_16_2_1.qos; - create_param.packing = BT_ISO_PACKING_SEQUENTIAL; - create_param.encryption = false; - - /* Test NULL parameters */ - err = bt_cap_initiator_broadcast_audio_create(NULL, &broadcast_source); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_create with NULL param did not fail\n"); - return; - } - - err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_create with NULL broadcast source did not " - "fail\n"); - return; - } - - /* Clear metadata so that it does not contain the mandatory stream context */ - memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - subgroup_param.codec = &invalid_codec; - err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_create with invalid metadata did not " - "fail\n"); - return; - } - - /* Since we are just casting the CAP parameters to BAP parameters, - * we can rely on the BAP tests to verify the values - */ -} - -static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadcast_source) -{ - struct bt_codec_data bis_codec_data = - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); - struct bt_cap_initiator_broadcast_stream_param - stream_params[ARRAY_SIZE(broadcast_source_streams)]; - struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; - struct bt_cap_initiator_broadcast_create_param create_param; - int err; - - for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) { - stream_params[i].stream = &broadcast_source_streams[i]; - stream_params[i].data_count = 1U; - stream_params[i].data = &bis_codec_data; - } - - subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); - subgroup_param.stream_params = stream_params; - subgroup_param.codec = &broadcast_preset_16_2_1.codec; - - create_param.subgroup_count = 1U; - create_param.subgroup_params = &subgroup_param; - create_param.qos = &broadcast_preset_16_2_1.qos; - create_param.packing = BT_ISO_PACKING_SEQUENTIAL; - create_param.encryption = false; - - printk("Creating broadcast source with %zu broadcast_streams\n", - ARRAY_SIZE(broadcast_streams)); - - err = bt_cap_initiator_broadcast_audio_create(&create_param, broadcast_source); - if (err != 0) { - FAIL("Unable to start broadcast source: %d\n", err); - return; - } - - printk("Broadcast source created with %zu broadcast_streams\n", - ARRAY_SIZE(broadcast_streams)); -} - -static void test_broadcast_audio_start_inval(struct bt_cap_broadcast_source *broadcast_source, - struct bt_le_ext_adv *adv) -{ - int err; - - /* Test NULL parameters */ - err = bt_cap_initiator_broadcast_audio_start(NULL, adv); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_start with NULL broadcast source did not " - "fail\n"); - return; - } - - err = bt_cap_initiator_broadcast_audio_start(broadcast_source, NULL); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_start with NULL adv did not fail\n"); - return; - } -} - -static void test_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 with %zu broadcast_streams\n", - ARRAY_SIZE(broadcast_streams)); -} - -static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source) -{ - const uint16_t mock_ccid = 0x1234; - const struct bt_codec_data new_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), - ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), - ((mock_ccid >> 8) & 0xFFU)), - }; - const struct bt_codec_data invalid_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), - ((mock_ccid >> 8) & 0xFFU)), - }; - int err; - - /* Test NULL parameters */ - err = bt_cap_initiator_broadcast_audio_update(NULL, new_metadata, ARRAY_SIZE(new_metadata)); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_update with NULL broadcast source did not " - "fail\n"); - return; - } - - err = bt_cap_initiator_broadcast_audio_update(broadcast_source, NULL, - ARRAY_SIZE(new_metadata)); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_update with NULL metadata did not fail\n"); - return; - } - - err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata, 0); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_update with 0 metadata count did not " - "fail\n"); - return; - } - - /* Test with metadata without streaming context */ - err = bt_cap_initiator_broadcast_audio_update(broadcast_source, invalid_metadata, - ARRAY_SIZE(invalid_metadata)); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_update with invalid metadata did not " - "fail\n"); - return; - } - - printk("Broadcast metadata updated\n"); -} - -static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source) -{ - const uint16_t mock_ccid = 0x1234; - const struct bt_codec_data new_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, - BT_BYTES_LIST_LE16(mock_ccid)), - }; - int err; - - printk("Updating broadcast metadata\n"); - - err = bt_cap_initiator_broadcast_audio_update(broadcast_source, new_metadata, - ARRAY_SIZE(new_metadata)); - if (err != 0) { - FAIL("Failed to update broadcast source metadata: %d\n", err); - return; - } - - printk("Broadcast metadata updated\n"); -} - -static void test_broadcast_audio_stop_inval(void) -{ - int err; - - /* Test NULL parameters */ - err = bt_cap_initiator_broadcast_audio_stop(NULL); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_stop with NULL broadcast source did not " - "fail\n"); - return; - } -} - -static void test_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source) -{ - int err; - - printk("Stopping broadcast metadata\n"); - - 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 < ARRAY_SIZE(broadcast_streams); i++) { - k_sem_take(&sem_broadcast_stopped, K_FOREVER); - } - - printk("Broadcast metadata stopped\n"); - - /* Verify that it cannot be stopped twice */ - err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_stop with already-stopped broadcast source " - "did not fail\n"); - return; - } -} - -static void test_broadcast_audio_delete_inval(void) -{ - int err; - - /* Test NULL parameters */ - err = bt_cap_initiator_broadcast_audio_delete(NULL); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_delete with NULL broadcast source did not " - "fail\n"); - return; - } -} - -static void test_broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source) -{ - int err; - - printk("Stopping broadcast metadata\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 metadata stopped\n"); - - /* Verify that it cannot be deleted twice */ - err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); - if (err == 0) { - FAIL("bt_cap_initiator_broadcast_audio_delete with already-deleted broadcast " - "source did not fail\n"); - return; - } -} - -static void test_cap_initiator_broadcast(void) -{ - struct bt_cap_broadcast_source *broadcast_source; - struct bt_le_ext_adv *adv; - - (void)memset(broadcast_source_streams, 0, sizeof(broadcast_source_streams)); - - init(); - - setup_extended_adv(&adv); - - test_broadcast_audio_create_inval(); - test_broadcast_audio_create(&broadcast_source); - - test_broadcast_audio_start_inval(broadcast_source, adv); - 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 < ARRAY_SIZE(broadcast_streams); 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++) { - broadcast_sent_cb(&broadcast_streams[i]->bap_stream); - } - } - - /* Keeping running for a little while */ - k_sleep(K_SECONDS(5)); - - test_broadcast_audio_update_inval(broadcast_source); - test_broadcast_audio_update(broadcast_source); - - /* Keeping running for a little while */ - k_sleep(K_SECONDS(5)); - - test_broadcast_audio_stop_inval(); - test_broadcast_audio_stop(broadcast_source); - - test_broadcast_audio_delete_inval(); - test_broadcast_audio_delete(broadcast_source); - broadcast_source = NULL; - - stop_and_delete_extended_adv(adv); - adv = NULL; - - PASS("CAP initiator broadcast passed\n"); -} - -static const struct bst_test_instance test_cap_initiator[] = { -#if defined(CONFIG_BT_BAP_UNICAST_CLIENT) - {.test_id = "cap_initiator_unicast", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_cap_initiator_unicast}, -#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ -#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) - {.test_id = "cap_initiator_broadcast", - .test_post_init_f = test_init, - .test_tick_f = test_tick, - .test_main_f = test_cap_initiator_broadcast}, -#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ - BSTEST_END_MARKER}; - -struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests) -{ - return bst_add_tests(tests, test_cap_initiator); -} - -#else /* !(CONFIG_BT_CAP_INITIATOR) */ - -struct bst_test_list *test_cap_initiator_install(struct bst_test_list *tests) -{ - return tests; -} - -#endif /* CONFIG_BT_CAP_INITIATOR */ diff --git a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c new file mode 100644 index 000000000000..251f91bb4114 --- /dev/null +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT) + +#include +#include +#include +#include +#include +#include "common.h" +#include "bap_unicast_common.h" + +extern enum bst_result_t bst_result; + +static struct bt_bap_lc3_preset unicast_preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + +static struct bt_cap_stream unicast_client_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct bt_bap_ep *unicast_sink_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; + +CREATE_FLAG(flag_discovered); +CREATE_FLAG(flag_codec_found); +CREATE_FLAG(flag_endpoint_found); +CREATE_FLAG(flag_started); +CREATE_FLAG(flag_updated); +CREATE_FLAG(flag_stopped); +CREATE_FLAG(flag_mtu_exchanged); +CREATE_FLAG(flag_sink_discovered); + +static void unicast_stream_configured(struct bt_bap_stream *stream, + const struct bt_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 unicast_stream_qos_set(struct bt_bap_stream *stream) +{ + printk("QoS set stream %p\n", stream); +} + +static void unicast_stream_enabled(struct bt_bap_stream *stream) +{ + printk("Enabled stream %p\n", stream); +} + +static void unicast_stream_started(struct bt_bap_stream *stream) +{ + printk("Started stream %p\n", stream); +} + +static void unicast_stream_metadata_updated(struct bt_bap_stream *stream) +{ + printk("Metadata updated stream %p\n", stream); +} + +static void unicast_stream_disabled(struct bt_bap_stream *stream) +{ + printk("Disabled stream %p\n", stream); +} + +static void unicast_stream_stopped(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stopped stream with reason 0x%02X%p\n", stream, reason); +} + +static void unicast_stream_released(struct bt_bap_stream *stream) +{ + printk("Released stream %p\n", stream); +} + +static struct bt_bap_stream_ops unicast_stream_ops = { + .configured = unicast_stream_configured, + .qos_set = unicast_stream_qos_set, + .enabled = unicast_stream_enabled, + .started = unicast_stream_started, + .metadata_updated = unicast_stream_metadata_updated, + .disabled = unicast_stream_disabled, + .stopped = unicast_stream_stopped, + .released = unicast_stream_released, +}; + +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 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", 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", 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", 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(struct bt_bap_ep *ep) +{ + for (size_t i = 0U; i < ARRAY_SIZE(unicast_sink_eps); i++) { + if (unicast_sink_eps[i] == NULL) { + printk("Sink #%zu: ep %p\n", i, ep); + unicast_sink_eps[i] = ep; + return; + } + } + + FAIL("Could not add source ep\n"); +} + +static void print_remote_codec(const struct bt_codec *codec, enum bt_audio_dir dir) +{ + printk("codec %p dir 0x%02x\n", codec, dir); + + print_codec(codec); +} + +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +{ + print_remote_codec(codec, dir); + SET_FLAG(flag_codec_found); +} + +static void discover_sink_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) +{ + if (err != 0) { + FAIL("Discovery failed: %d\n", err); + return; + } + + printk("Sink discover complete\n"); + + SET_FLAG(flag_sink_discovered); +} + +static void 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); + SET_FLAG(flag_endpoint_found); + } else { + FAIL("Invalid param dir: %u\n", dir); + } +} + +static const struct bt_bap_unicast_client_cb unicast_client_cbs = { + .discover = discover_sink_cb, + .pac_record = pac_record_cb, + .endpoint = endpoint_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_bap_unicast_client_register_cb(&unicast_client_cbs); + if (err != 0) { + FAIL("Failed to register BAP unicast client 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_client_streams); i++) { + bt_cap_stream_ops_register(&unicast_client_streams[i], &unicast_stream_ops); + } +} + +static void scan_and_connect(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, 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); +} + +static void discover_sink(void) +{ + int err; + + UNSET_FLAG(flag_sink_discovered); + UNSET_FLAG(flag_codec_found); + UNSET_FLAG(flag_endpoint_found); + + err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK); + if (err != 0) { + printk("Failed to discover sink: %d\n", err); + return; + } + + memset(unicast_sink_eps, 0, sizeof(unicast_sink_eps)); + + WAIT_FOR_FLAG(flag_sink_discovered); + WAIT_FOR_FLAG(flag_endpoint_found); + WAIT_FOR_FLAG(flag_codec_found); +} + +static void discover_cas_inval(void) +{ + int err; + + err = bt_cap_initiator_unicast_discover(NULL); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_discover with NULL conn did not fail\n"); + return; + } + + /* Test if it handles concurrent request for same connection */ + UNSET_FLAG(flag_discovered); + + err = bt_cap_initiator_unicast_discover(default_conn); + if (err != 0) { + printk("Failed to discover CAS: %d\n", err); + return; + } + + err = bt_cap_initiator_unicast_discover(default_conn); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_discover while previous discovery has not completed " + "did not fail\n"); + return; + } + + WAIT_FOR_FLAG(flag_discovered); +} + +static void discover_cas(void) +{ + int err; + + UNSET_FLAG(flag_discovered); + + err = bt_cap_initiator_unicast_discover(default_conn); + if (err != 0) { + printk("Failed to discover CAS: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_discovered); +} + +static void unicast_group_create(struct bt_bap_unicast_group **out_unicast_group) +{ + struct bt_bap_unicast_group_stream_param group_stream_params; + struct bt_bap_unicast_group_stream_pair_param pair_params; + struct bt_bap_unicast_group_param group_param; + int err; + + group_stream_params.qos = &unicast_preset_16_2_1.qos; + group_stream_params.stream = &unicast_client_streams[0].bap_stream; + pair_params.tx_param = &group_stream_params; + pair_params.rx_param = NULL; + + group_param.packing = BT_ISO_PACKING_SEQUENTIAL; + group_param.params_count = 1; + group_param.params = &pair_params; + + err = bt_bap_unicast_group_create(&group_param, out_unicast_group); + if (err != 0) { + FAIL("Failed to create group: %d\n", err); + return; + } +} + +static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group) +{ + struct bt_codec invalid_codec = + BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + struct bt_cap_unicast_audio_start_stream_param invalid_stream_param; + struct bt_cap_unicast_audio_start_stream_param valid_stream_param; + struct bt_cap_unicast_audio_start_param invalid_start_param; + struct bt_cap_unicast_audio_start_param valid_start_param; + int err; + + valid_start_param.type = BT_CAP_SET_TYPE_AD_HOC; + valid_start_param.count = 1u; + valid_start_param.stream_params = &valid_stream_param; + + valid_stream_param.member.member = default_conn; + valid_stream_param.stream = &unicast_client_streams[0]; + valid_stream_param.ep = unicast_sink_eps[0]; + valid_stream_param.codec = &unicast_preset_16_2_1.codec; + valid_stream_param.qos = &unicast_preset_16_2_1.qos; + + /* Test NULL parameters */ + err = bt_cap_initiator_unicast_audio_start(NULL, unicast_group); + 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)); + invalid_start_param.stream_params = &invalid_stream_param; + + /* Test invalid stream_start parameters */ + invalid_start_param.count = 0U; + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with 0 count did not fail\n"); + return; + } + + memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param)); + 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); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params did not fail\n"); + return; + } + + memcpy(&invalid_start_param, &valid_start_param, sizeof(valid_start_param)); + invalid_start_param.stream_params = &invalid_stream_param; + + /* Test invalid stream_param parameters */ + invalid_stream_param.member.member = NULL; + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params member did not " + "fail\n"); + return; + } + + 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); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params stream did not " + "fail\n"); + return; + } + + 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); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params ep did not " + "fail\n"); + return; + } + + memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); + + invalid_stream_param.codec = NULL; + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params codec did not " + "fail\n"); + return; + } + + memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); + + invalid_stream_param.qos = NULL; + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params qos did not " + "fail\n"); + return; + } + + /* Clear metadata so that it does not contain the mandatory stream context */ + memcpy(&invalid_stream_param, &valid_stream_param, sizeof(valid_stream_param)); + memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); + + invalid_stream_param.codec = &invalid_codec; + err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_start with invalid Codec metadata did not " + "fail\n"); + return; + } +} + +static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group) +{ + struct bt_cap_unicast_audio_start_stream_param stream_param[1]; + struct bt_cap_unicast_audio_start_param param; + int err; + + param.type = BT_CAP_SET_TYPE_AD_HOC; + param.count = 1u; + param.stream_params = stream_param; + stream_param[0].member.member = default_conn; + stream_param[0].stream = &unicast_client_streams[0]; + stream_param[0].ep = unicast_sink_eps[0]; + stream_param[0].codec = &unicast_preset_16_2_1.codec; + stream_param[0].qos = &unicast_preset_16_2_1.qos; + + UNSET_FLAG(flag_started); + + err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); + if (err != 0) { + FAIL("Failed to start unicast audio: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_started); +} + +static void unicast_audio_update_inval(void) +{ + struct bt_codec invalid_codec = + BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + struct bt_cap_unicast_audio_update_param param; + int err; + + param.stream = &unicast_client_streams[0]; + param.meta = unicast_preset_16_2_1.codec.meta; + param.meta_count = unicast_preset_16_2_1.codec.meta_count; + + err = bt_cap_initiator_unicast_audio_update(NULL, 1); + 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); + 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 */ + memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); + param.meta = invalid_codec.meta; + + err = bt_cap_initiator_unicast_audio_update(¶m, 1); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_update with invalid Codec metadata did not " + "fail\n"); + return; + } +} + +static void unicast_audio_update(void) +{ + struct bt_cap_unicast_audio_update_param param; + int err; + + param.stream = &unicast_client_streams[0]; + param.meta = unicast_preset_16_2_1.codec.meta; + param.meta_count = unicast_preset_16_2_1.codec.meta_count; + + UNSET_FLAG(flag_updated); + + err = bt_cap_initiator_unicast_audio_update(¶m, 1); + if (err != 0) { + FAIL("Failed to update unicast audio: %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_updated); +} + +static void unicast_audio_stop_inval(void) +{ + int err; + + 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"); + return; + } +} + +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); + + /* Verify that it cannot be stopped twice */ + err = bt_cap_initiator_unicast_audio_stop(unicast_group); + if (err == 0) { + FAIL("bt_cap_initiator_unicast_audio_stop with already-stopped unicast group did " + "not fail\n"); + return; + } +} + +static void unicast_group_delete_inval(void) +{ + int err; + + err = bt_bap_unicast_group_delete(NULL); + if (err == 0) { + FAIL("bt_bap_unicast_group_delete with NULL group did not fail\n"); + return; + } +} + +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; + } + + /* Verify that it cannot be deleted twice */ + err = bt_bap_unicast_group_delete(unicast_group); + if (err == 0) { + FAIL("bt_bap_unicast_group_delete with already-deleted unicast group did not " + "fail\n"); + return; + } +} + +static void test_main_cap_initiator_unicast(void) +{ + struct bt_bap_unicast_group *unicast_group; + const size_t iterations = 2; + + init(); + + scan_and_connect(); + + WAIT_FOR_FLAG(flag_mtu_exchanged); + + discover_cas_inval(); + discover_cas(); + + discover_sink(); + + for (size_t i = 0U; i < iterations; i++) { + unicast_group_create(&unicast_group); + + for (size_t j = 0U; j < iterations; j++) { + unicast_audio_start_inval(unicast_group); + unicast_audio_start(unicast_group); + + unicast_audio_update_inval(); + unicast_audio_update(); + + unicast_audio_stop_inval(); + unicast_audio_stop(unicast_group); + } + + unicast_group_delete_inval(); + unicast_group_delete(unicast_group); + unicast_group = NULL; + } + + PASS("CAP initiator unicast passed\n"); +} + +static const struct bst_test_instance test_cap_initiator_unicast[] = { + { + .test_id = "cap_initiator_unicast", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_cap_initiator_unicast, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_cap_initiator_unicast_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_cap_initiator_unicast); +} + +#else /* !(defined(CONFIG_BT_CAP_INITIATOR) && defined(CONFIG_BT_BAP_UNICAST_CLIENT)) */ + +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) */ diff --git a/tests/bsim/bluetooth/audio/src/main.c b/tests/bsim/bluetooth/audio/src/main.c index f939754875cb..40e0c116a655 100644 --- a/tests/bsim/bluetooth/audio/src/main.c +++ b/tests/bsim/bluetooth/audio/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2022 Nordic Semiconductor ASA + * Copyright (c) 2020-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,7 +25,8 @@ 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_initiator_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); extern struct bst_test_list *test_has_client_install(struct bst_test_list *tests); extern struct bst_test_list *test_ias_install(struct bst_test_list *tests); @@ -53,7 +54,8 @@ bst_test_install_t test_installers[] = { test_bap_broadcast_assistant_install, test_bass_broadcaster_install, test_cap_acceptor_install, - test_cap_initiator_install, + test_cap_initiator_broadcast_install, + test_cap_initiator_unicast_install, test_has_install, test_has_client_install, test_ias_install, From 5eb17bca217ca03bc809c4fa27e706c8bf3ae78c Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 9 Jun 2023 07:34:49 +0530 Subject: [PATCH 0048/2042] samples: Bluetooth: hci_usb: Disable USB_CDC_ACM BlueZ btusb does not recognize hci_usb sample as Bluetooth Controller when CDC ACM is enabled in the sample. Refer to https://github.com/zephyrproject-rtos/zephyr/issues/29107 Signed-off-by: Vinayak Kariappa Chettimada --- .../adafruit_itsybitsy_nrf52840/Kconfig.defconfig | 4 ++-- boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig | 4 ++-- samples/bluetooth/hci_usb/prj.conf | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/boards/arm/adafruit_itsybitsy_nrf52840/Kconfig.defconfig b/boards/arm/adafruit_itsybitsy_nrf52840/Kconfig.defconfig index e8e316f3a177..a31f72aa40d9 100644 --- a/boards/arm/adafruit_itsybitsy_nrf52840/Kconfig.defconfig +++ b/boards/arm/adafruit_itsybitsy_nrf52840/Kconfig.defconfig @@ -17,13 +17,13 @@ config USB_DEVICE_STACK default y config USB_CDC_ACM - default y + default SERIAL config UART_CONSOLE default CONSOLE config USB_DEVICE_INITIALIZE_AT_BOOT - default y + default y if CONSOLE config SHELL_BACKEND_SERIAL_CHECK_DTR default SHELL diff --git a/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig b/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig index 3dc18d894bb1..75a76b332937 100644 --- a/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig +++ b/boards/arm/nrf52840dongle_nrf52840/Kconfig.defconfig @@ -31,13 +31,13 @@ config USB_DEVICE_STACK default y config USB_CDC_ACM - default y + default SERIAL config UART_CONSOLE default CONSOLE config USB_DEVICE_INITIALIZE_AT_BOOT - default y if !MCUBOOT + default y if !MCUBOOT && CONSOLE config SHELL_BACKEND_SERIAL_CHECK_DTR default SHELL diff --git a/samples/bluetooth/hci_usb/prj.conf b/samples/bluetooth/hci_usb/prj.conf index 110cea092d1c..0f809e424d6d 100644 --- a/samples/bluetooth/hci_usb/prj.conf +++ b/samples/bluetooth/hci_usb/prj.conf @@ -1,9 +1,3 @@ -CONFIG_STDOUT_CONSOLE=y -CONFIG_GPIO=y -CONFIG_SERIAL=y -CONFIG_UART_INTERRUPT_DRIVEN=y -CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n - CONFIG_BT=y CONFIG_BT_HCI_RAW=y @@ -11,6 +5,12 @@ CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PID=0x000B CONFIG_USB_DEVICE_BLUETOOTH=y CONFIG_USB_DEVICE_BLUETOOTH_VS_H4=n +CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n + +# We dont want any console or CDC ACM that may cause BlueZ to not detect hci_usb +CONFIG_SERIAL=n +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n # Workaround: Unable to allocate command buffer when using K_NO_WAIT since # Host number of completed commands does not follow normal flow control. From fb408077df3d78eb926cf1cad2dcc6eedc2f4122 Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Fri, 9 Jun 2023 10:29:13 +0200 Subject: [PATCH 0049/2042] shell: Fix shell_vfprintf when vt100 is disabled Without this fix, for every call to shell_vfprintf, a prompt string and vt100 codes are printed too, resulting in mangled log output. Signed-off-by: Lars Knudsen --- subsys/shell/shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index e1f6424dbb3b..2d9e0883e229 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -1503,11 +1503,11 @@ void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color, } k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER); - if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass) { + if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) { z_shell_cmd_line_erase(sh); } z_shell_vfprintf(sh, color, fmt, args); - if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass) { + if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) { z_shell_print_prompt_and_cmd(sh); } z_transport_buffer_flush(sh); From 3b14268e4130d506243d27d1b05a12bfffb1a3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Wed, 7 Jun 2023 14:43:33 +0200 Subject: [PATCH 0050/2042] drivers: usb_dc_native_posix: Check data length before copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fail requests if the data does not fit inside buffer. This commit only adds missing sanity checks but the native posix driver remains broken at the design level. The amount of work to fix the native posix driver in legacy USB stack is deemed too great to be worth it. Coverity-CID: 195841, GitHub issue #58564 Coverity-CID: 240244, GitHub issue #58570 Signed-off-by: Tomasz Moń --- drivers/usb/device/usb_dc_native_posix.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/usb/device/usb_dc_native_posix.c b/drivers/usb/device/usb_dc_native_posix.c index 691c11dbbf48..70410db24403 100644 --- a/drivers/usb/device/usb_dc_native_posix.c +++ b/drivers/usb/device/usb_dc_native_posix.c @@ -356,6 +356,10 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, uint8_t ep_idx = USB_EP_GET_IDX(ep); struct usb_ep_ctrl_prv *ctrl = &usbip_ctrl.in_ep_ctrl[ep_idx]; + if (data_len > ARRAY_SIZE(ctrl->buf)) { + return -EINVAL; + } + memcpy(ctrl->buf, data, data_len); ctrl->buf_len = data_len; } @@ -525,8 +529,15 @@ int handle_usb_control(struct usbip_header *hdr) ep_ctrl->cb(ep_idx, USB_DC_EP_SETUP); if (ntohl(hdr->common.direction) == USBIP_DIR_OUT) { + uint32_t data_len = ntohl(hdr->u.submit.transfer_buffer_length); + /* Data OUT stage availably */ - ep_ctrl->data_len = ntohl(hdr->u.submit.transfer_buffer_length); + if (data_len > ARRAY_SIZE(ep_ctrl->buf)) { + return -EIO; + } + + ep_ctrl->data_len = data_len; + if (usbip_recv(ep_ctrl->buf, ep_ctrl->data_len) < 0) { return -EIO; } @@ -546,13 +557,22 @@ int handle_usb_data(struct usbip_header *hdr) uint8_t ep; if (ntohl(hdr->common.direction) == USBIP_DIR_OUT) { + uint32_t data_len; + if (ep_idx >= USBIP_OUT_EP_NUM) { return -EINVAL; } ep_ctrl = &usbip_ctrl.out_ep_ctrl[ep_idx]; ep = ep_idx | USB_EP_DIR_OUT; - ep_ctrl->data_len = ntohl(hdr->u.submit.transfer_buffer_length); + data_len = ntohl(hdr->u.submit.transfer_buffer_length); + + if (data_len > ARRAY_SIZE(ep_ctrl->buf)) { + return -EIO; + } + + ep_ctrl->data_len = data_len; + if (usbip_recv(ep_ctrl->buf, ep_ctrl->data_len) < 0) { return -EIO; } From e94b6f901b430835197d6060214d7651e30e1e0a Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Wed, 7 Jun 2023 13:46:02 -0500 Subject: [PATCH 0051/2042] drivers: usb_mcux: Fix disable and reset functions 1. Fix the reset function to reset correctly. 2. Ensure the controller handle is initialized before calling the SDK functions. Signed-off-by: Mahesh Mahadevan --- drivers/usb/device/usb_dc_mcux.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/usb/device/usb_dc_mcux.c b/drivers/usb/device/usb_dc_mcux.c index c2367efa28b2..de2d48ca0e73 100644 --- a/drivers/usb/device/usb_dc_mcux.c +++ b/drivers/usb/device/usb_dc_mcux.c @@ -140,10 +140,7 @@ int usb_dc_reset(void) if (dev_state.dev_struct.controllerHandle != NULL) { dev_state.dev_struct.controllerInterface->deviceControl( dev_state.dev_struct.controllerHandle, - kUSB_DeviceControlStop, NULL); - dev_state.dev_struct.controllerInterface->deviceDeinit( - dev_state.dev_struct.controllerHandle); - dev_state.dev_struct.controllerHandle = NULL; + kUSB_DeviceControlSetDefaultStatus, NULL); } return 0; @@ -470,12 +467,14 @@ int usb_dc_ep_disable(const uint8_t ep) return -EINVAL; } - status = dev_state.dev_struct.controllerInterface->deviceCancel( - dev_state.dev_struct.controllerHandle, - ep); - if (kStatus_USB_Success != status) { - LOG_ERR("Failed to disable ep 0x%02x", ep); - return -EIO; + if (dev_state.dev_struct.controllerHandle != NULL) { + status = dev_state.dev_struct.controllerInterface->deviceCancel( + dev_state.dev_struct.controllerHandle, + ep); + if (kStatus_USB_Success != status) { + LOG_ERR("Failed to disable ep 0x%02x", ep); + return -EIO; + } } dev_state.eps[ep_abs_idx].ep_enabled = false; From edd343782643b26e345cf1e460a8f77fd9bcd496 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 9 Jun 2023 10:36:55 +0200 Subject: [PATCH 0052/2042] riscv: Rename Kconfig symbol to *_PRIVILEGED Rename SOC_FAMILY_RISCV_PRIVILEGE to SOC_FAMILY_RISCV_PRIVILEGED because the spec is "privileged". Signed-off-by: Carlo Caione --- arch/riscv/Kconfig | 2 +- drivers/interrupt_controller/intc_plic.c | 4 ++-- include/zephyr/arch/riscv/arch.h | 2 +- .../zephyr/arch/riscv/riscv-privilege/asm_inline.h | 6 +++--- .../arch/riscv/riscv-privilege/asm_inline_gcc.h | 6 +++--- soc/riscv/riscv-privilege/Kconfig | 12 ++++++++---- soc/riscv/riscv-privilege/andes_v5/Kconfig.series | 2 +- soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h | 6 +++--- soc/riscv/riscv-privilege/gd32vf103/Kconfig.series | 2 +- soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h | 6 +++--- soc/riscv/riscv-privilege/miv/Kconfig.series | 2 +- soc/riscv/riscv-privilege/mpfs/Kconfig.series | 2 +- soc/riscv/riscv-privilege/neorv32/Kconfig.series | 2 +- soc/riscv/riscv-privilege/niosv/Kconfig.series | 2 +- soc/riscv/riscv-privilege/opentitan/Kconfig.series | 2 +- .../riscv-privilege/sifive-freedom/Kconfig.series | 2 +- .../riscv-privilege/sifive-freedom/pinctrl_soc.h | 6 +++--- .../riscv-privilege/starfive_jh71xx/Kconfig.series | 2 +- soc/riscv/riscv-privilege/telink_b91/Kconfig.series | 2 +- soc/riscv/riscv-privilege/virt/Kconfig.series | 2 +- tests/kernel/gen_isr_table/testcase.yaml | 4 ++-- 21 files changed, 40 insertions(+), 36 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 17948c6b6851..7e3eb9679570 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -280,7 +280,7 @@ config ARCH_IRQ_VECTOR_TABLE_ALIGN default 256 config GEN_IRQ_VECTOR_TABLE - select RISCV_MTVEC_VECTORED_MODE if SOC_FAMILY_RISCV_PRIVILEGE + select RISCV_MTVEC_VECTORED_MODE if SOC_FAMILY_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 9fdd1fd27337..d7958ad9b4a1 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -40,7 +40,7 @@ static int save_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_PRIVILEGE + * 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. * @@ -61,7 +61,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_PRIVILEGE + * riscv_plic_irq_disable is called by SOC_FAMILY_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 4adbd5957392..7bc1d8bc49a9 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_PRIVILEGE) +#if defined(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED) #include #endif diff --git a/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h b/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h index 874d5b4a43eb..106054b649a4 100644 --- a/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h +++ b/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_H_ -#define ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_H_ +#define ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_H_ /* * The file must not be included directly @@ -19,4 +19,4 @@ #error "Supports only GNU C compiler" #endif -#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_H_ */ diff --git a/include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h b/include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h index 0bd2a78e433e..49a036fa7b12 100644 --- a/include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h +++ b/include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_GCC_H_ -#define ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_GCC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_GCC_H_ +#define ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_GCC_H_ /* * The file must not be included directly @@ -19,4 +19,4 @@ #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGE_ASM_INLINE_GCC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_RISCV_PRIVILEGED_ASM_INLINE_GCC_H_ */ diff --git a/soc/riscv/riscv-privilege/Kconfig b/soc/riscv/riscv-privilege/Kconfig index dcab063b1707..151b9690e3d3 100644 --- a/soc/riscv/riscv-privilege/Kconfig +++ b/soc/riscv/riscv-privilege/Kconfig @@ -6,27 +6,31 @@ config SOC_FAMILY_RISCV_PRIVILEGE bool + select DEPRECATED + +config SOC_FAMILY_RISCV_PRIVILEGED + bool config SOC_FAMILY string default "riscv-privilege" - depends on SOC_FAMILY_RISCV_PRIVILEGE + 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_PRIVILEGE + 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_PRIVILEGE + depends on SOC_FAMILY_RISCV_PRIVILEGED help Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). config RISCV_MTVEC_VECTORED_MODE bool "Should the SOC use mtvec in vectored mode" - depends on SOC_FAMILY_RISCV_PRIVILEGE + depends on SOC_FAMILY_RISCV_PRIVILEGED help Should the SOC use mtvec in vectored mode diff --git a/soc/riscv/riscv-privilege/andes_v5/Kconfig.series b/soc/riscv/riscv-privilege/andes_v5/Kconfig.series index 15d811fc6d8f..9a99711b04c6 100644 --- a/soc/riscv/riscv-privilege/andes_v5/Kconfig.series +++ b/soc/riscv/riscv-privilege/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_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for Andes V5 SoC Series diff --git a/soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h b/soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h index edf10a4d92d1..4bc1f496fabe 100644 --- a/soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h +++ b/soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h @@ -13,8 +13,8 @@ * Use arch/riscv/csr.h for RISC-V standard CSR and definitions. */ -#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_COMMON_NUCLEI_NUCLEI_CSR_H_ -#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_COMMON_NUCLEI_NUCLEI_CSR_H_ +#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_COMMON_NUCLEI_NUCLEI_CSR_H_ +#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_COMMON_NUCLEI_NUCLEI_CSR_H_ #include @@ -239,4 +239,4 @@ extern "C" { } #endif -#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_COMMON_NUCLEI_NUCLEI_CSR_H_ */ +#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_COMMON_NUCLEI_NUCLEI_CSR_H_ */ diff --git a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.series b/soc/riscv/riscv-privilege/gd32vf103/Kconfig.series index 2e2a95c66b24..3922bf19bdda 100644 --- a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.series +++ b/soc/riscv/riscv-privilege/gd32vf103/Kconfig.series @@ -6,7 +6,7 @@ config SOC_SERIES_GD32VF103 bool "GigaDevice GD32VF103 series SoC implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED select ATOMIC_OPERATIONS_C select INCLUDE_RESET_VECTOR select BUILD_OUTPUT_HEX diff --git a/soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h b/soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h index fd566891bc88..7d703caa97aa 100644 --- a/soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h +++ b/soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h @@ -9,9 +9,9 @@ * Gigadevice SoC specific helpers for pinctrl driver */ -#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ -#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ +#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ #include -#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ */ +#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_NUCLEI_GD32VF103_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/riscv/riscv-privilege/miv/Kconfig.series b/soc/riscv/riscv-privilege/miv/Kconfig.series index dc69e90517d0..00a6f129f9fa 100644 --- a/soc/riscv/riscv-privilege/miv/Kconfig.series +++ b/soc/riscv/riscv-privilege/miv/Kconfig.series @@ -6,6 +6,6 @@ config SOC_SERIES_RISCV32_MIV bool "Microchip Mi-V implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for Microchip Mi-V diff --git a/soc/riscv/riscv-privilege/mpfs/Kconfig.series b/soc/riscv/riscv-privilege/mpfs/Kconfig.series index d31be61fc903..ca37731f1925 100644 --- a/soc/riscv/riscv-privilege/mpfs/Kconfig.series +++ b/soc/riscv/riscv-privilege/mpfs/Kconfig.series @@ -6,6 +6,6 @@ config SOC_SERIES_RISCV64_MIV bool "Microchip RV64 implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/riscv-privilege/neorv32/Kconfig.series b/soc/riscv/riscv-privilege/neorv32/Kconfig.series index 7d80aba1f45d..98c7f34024d2 100644 --- a/soc/riscv/riscv-privilege/neorv32/Kconfig.series +++ b/soc/riscv/riscv-privilege/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_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for the NEORV32 Processor (SoC). diff --git a/soc/riscv/riscv-privilege/niosv/Kconfig.series b/soc/riscv/riscv-privilege/niosv/Kconfig.series index 45673fd8721e..7de17cf2db09 100644 --- a/soc/riscv/riscv-privilege/niosv/Kconfig.series +++ b/soc/riscv/riscv-privilege/niosv/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_NIOSV bool "INTEL FPGA NIOSV" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/riscv-privilege/opentitan/Kconfig.series b/soc/riscv/riscv-privilege/opentitan/Kconfig.series index f45d74fc4e9a..f9cdf3bea479 100644 --- a/soc/riscv/riscv-privilege/opentitan/Kconfig.series +++ b/soc/riscv/riscv-privilege/opentitan/Kconfig.series @@ -4,7 +4,7 @@ config SOC_SERIES_RISCV_OPENTITAN bool "OpenTitan implementation" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. select RISCV_MTVEC_VECTORED_MODE select GEN_IRQ_VECTOR_TABLE diff --git a/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.series b/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.series index 07cd3bf82e1c..523f6a4ffe97 100644 --- a/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.series +++ b/soc/riscv/riscv-privilege/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_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for SiFive Freedom SOC diff --git a/soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h b/soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h index ed534237da1a..769a68684a78 100644 --- a/soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h +++ b/soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_SIFIVE_FREEDOM_PINCTRL_H_ -#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_SIFIVE_FREEDOM_PINCTRL_H_ +#ifndef ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_SIFIVE_FREEDOM_PINCTRL_H_ +#define ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_SIFIVE_FREEDOM_PINCTRL_H_ #include @@ -26,4 +26,4 @@ typedef struct pinctrl_soc_pin_t { #define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } -#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGE_SIFIVE_FREEDOM_PINCTRL_H_ */ +#endif /* ZEPHYR_SOC_RISCV_RISCV_PRIVILEGED_SIFIVE_FREEDOM_PINCTRL_H_ */ diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series b/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series index b573684e0ac8..b360f78b77b4 100644 --- a/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series +++ b/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series @@ -4,6 +4,6 @@ config SOC_SERIES_STARFIVE_JH71XX bool "Starfive JH71XX series" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED help Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.series b/soc/riscv/riscv-privilege/telink_b91/Kconfig.series index b1f30e73fb43..a966dfe447bd 100644 --- a/soc/riscv/riscv-privilege/telink_b91/Kconfig.series +++ b/soc/riscv/riscv-privilege/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_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED select HAS_TELINK_DRIVERS help Enable support for Telink B91 SoC diff --git a/soc/riscv/riscv-privilege/virt/Kconfig.series b/soc/riscv/riscv-privilege/virt/Kconfig.series index 4f105a26641e..e9846764f6ba 100644 --- a/soc/riscv/riscv-privilege/virt/Kconfig.series +++ b/soc/riscv/riscv-privilege/virt/Kconfig.series @@ -4,4 +4,4 @@ config SOC_SERIES_RISCV_VIRT bool "QEMU RISC-V VirtIO Board" select RISCV - select SOC_FAMILY_RISCV_PRIVILEGE + select SOC_FAMILY_RISCV_PRIVILEGED diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index 250d5aca9cc8..63735a6993f6 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -51,7 +51,7 @@ tests: - riscv32 - riscv64 platform_exclude: m2gl025_miv - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGE + filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=y arch.interrupt.gen_isr_table.riscv_no_direct: @@ -59,6 +59,6 @@ tests: arch_allow: - riscv32 - riscv64 - filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGE + filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=n From 8eeb5c992e832e7b0db041ad338588649ab06741 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 9 Jun 2023 10:40:43 +0200 Subject: [PATCH 0053/2042] riscv: Move directory to *-privileged Because the spec is "privileged" not "privilege". Signed-off-by: Carlo Caione --- CODEOWNERS | 8 ++++---- MAINTAINERS.yml | 2 +- include/zephyr/arch/riscv/arch.h | 2 +- .../{riscv-privilege => riscv-privileged}/asm_inline.h | 2 +- .../asm_inline_gcc.h | 0 soc/riscv/litex-vexriscv/CMakeLists.txt | 4 ++-- soc/riscv/litex-vexriscv/soc.h | 2 +- .../{riscv-privilege => riscv-privileged}/CMakeLists.txt | 0 soc/riscv/{riscv-privilege => riscv-privileged}/Kconfig | 4 ++-- .../Kconfig.defconfig | 2 +- .../{riscv-privilege => riscv-privileged}/Kconfig.soc | 2 +- .../andes_v5/CMakeLists.txt | 0 .../andes_v5/Kconfig.defconfig.ae350 | 0 .../andes_v5/Kconfig.defconfig.series | 2 +- .../andes_v5/Kconfig.series | 0 .../andes_v5/Kconfig.soc | 0 .../andes_v5/ae350/linker.ld | 0 .../andes_v5/ae350/soc.h | 0 .../andes_v5/l2_cache.c | 0 .../andes_v5/linker.ld | 0 .../{riscv-privilege => riscv-privileged}/andes_v5/pma.c | 0 .../andes_v5/soc_context.h | 0 .../andes_v5/soc_irq.S | 0 .../andes_v5/soc_offsets.h | 0 .../andes_v5/soc_v5.h | 0 .../andes_v5/start.S | 0 .../common/CMakeLists.txt | 0 .../{riscv-privilege => riscv-privileged}/common/idle.c | 0 .../common/nuclei/nuclei_csr.h | 0 .../common/soc_common.h | 0 .../common/soc_common_irq.c | 0 .../common/soc_irq.S | 0 .../{riscv-privilege => riscv-privileged}/common/vector.S | 0 .../gd32vf103/CMakeLists.txt | 0 .../gd32vf103/Kconfig.defconfig.gd32vf103 | 0 .../gd32vf103/Kconfig.defconfig.series | 2 +- .../gd32vf103/Kconfig.series | 0 .../gd32vf103/Kconfig.soc | 0 .../gd32vf103/entry.S | 0 .../gd32vf103/gd32_regs.h | 0 .../gd32vf103/linker.ld | 0 .../gd32vf103/pinctrl_soc.h | 0 .../{riscv-privilege => riscv-privileged}/gd32vf103/soc.c | 0 .../{riscv-privilege => riscv-privileged}/gd32vf103/soc.h | 0 .../miv/CMakeLists.txt | 0 .../miv/Kconfig.defconfig.series | 0 .../miv/Kconfig.series | 0 .../{riscv-privilege => riscv-privileged}/miv/Kconfig.soc | 0 .../{riscv-privilege => riscv-privileged}/miv/linker.ld | 0 soc/riscv/{riscv-privilege => riscv-privileged}/miv/soc.h | 0 .../mpfs/CMakeLists.txt | 0 .../mpfs/Kconfig.defconfig.series | 0 .../mpfs/Kconfig.series | 0 .../mpfs/Kconfig.soc | 0 .../{riscv-privilege => riscv-privileged}/mpfs/linker.ld | 0 .../{riscv-privilege => riscv-privileged}/mpfs/soc.h | 0 .../neorv32/CMakeLists.txt | 0 .../neorv32/Kconfig.defconfig.series | 0 .../neorv32/Kconfig.series | 0 .../neorv32/Kconfig.soc | 0 .../neorv32/linker.ld | 0 .../{riscv-privilege => riscv-privileged}/neorv32/reset.S | 0 .../{riscv-privilege => riscv-privileged}/neorv32/soc.c | 0 .../{riscv-privilege => riscv-privileged}/neorv32/soc.h | 0 .../neorv32/soc_irq.S | 0 .../niosv/CMakeLists.txt | 0 .../niosv/Kconfig.defconfig.series | 0 .../niosv/Kconfig.series | 0 .../niosv/Kconfig.soc | 0 .../{riscv-privilege => riscv-privileged}/niosv/linker.ld | 0 .../{riscv-privilege => riscv-privileged}/niosv/soc.h | 0 .../opentitan/CMakeLists.txt | 0 .../opentitan/Kconfig.defconfig.series | 0 .../opentitan/Kconfig.series | 0 .../opentitan/Kconfig.soc | 0 .../opentitan/linker.ld | 0 .../opentitan/rom_header.S | 0 .../opentitan/rom_header.ld | 0 .../{riscv-privilege => riscv-privileged}/opentitan/soc.c | 0 .../{riscv-privilege => riscv-privileged}/opentitan/soc.h | 0 .../sifive-freedom/CMakeLists.txt | 0 .../sifive-freedom/Kconfig.defconfig.series | 0 .../sifive-freedom/Kconfig.series | 0 .../sifive-freedom/Kconfig.soc | 0 .../sifive-freedom/fe310_clock.c | 0 .../sifive-freedom/fe310_prci.h | 0 .../sifive-freedom/fu540_clock.c | 0 .../sifive-freedom/fu540_prci.h | 0 .../sifive-freedom/fu740_clock.c | 0 .../sifive-freedom/fu740_prci.h | 0 .../sifive-freedom/linker.ld | 0 .../sifive-freedom/pinctrl_soc.h | 0 .../sifive-freedom/soc.h | 0 .../starfive_jh71xx/CMakeLists.txt | 0 .../starfive_jh71xx/Kconfig.defconfig.series | 0 .../starfive_jh71xx/Kconfig.series | 0 .../starfive_jh71xx/Kconfig.soc | 0 .../starfive_jh71xx/linker.ld | 0 .../starfive_jh71xx/soc.h | 0 .../telink_b91/CMakeLists.txt | 0 .../telink_b91/Kconfig.defconfig.series | 0 .../telink_b91/Kconfig.series | 0 .../telink_b91/Kconfig.soc | 0 .../telink_b91/init.ld | 0 .../telink_b91/linker.ld | 0 .../telink_b91/pinctrl_soc.h | 0 .../telink_b91/soc.c | 0 .../telink_b91/soc.h | 0 .../telink_b91/soc_context.h | 0 .../telink_b91/soc_irq.S | 0 .../telink_b91/soc_offsets.h | 0 .../telink_b91/start.S | 0 .../virt/CMakeLists.txt | 0 .../virt/Kconfig.defconfig.series | 0 .../virt/Kconfig.series | 0 .../virt/Kconfig.soc | 0 .../{riscv-privilege => riscv-privileged}/virt/linker.ld | 0 .../{riscv-privilege => riscv-privileged}/virt/soc.c | 0 .../{riscv-privilege => riscv-privileged}/virt/soc.h | 0 119 files changed, 16 insertions(+), 16 deletions(-) rename include/zephyr/arch/riscv/{riscv-privilege => riscv-privileged}/asm_inline.h (89%) rename include/zephyr/arch/riscv/{riscv-privilege => riscv-privileged}/asm_inline_gcc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/Kconfig (92%) rename soc/riscv/{riscv-privilege => riscv-privileged}/Kconfig.defconfig (73%) rename soc/riscv/{riscv-privilege => riscv-privileged}/Kconfig.soc (76%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/Kconfig.defconfig.ae350 (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/Kconfig.defconfig.series (92%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/ae350/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/ae350/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/l2_cache.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/pma.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/soc_context.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/soc_irq.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/soc_offsets.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/soc_v5.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/andes_v5/start.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/idle.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/nuclei/nuclei_csr.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/soc_common.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/soc_common_irq.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/soc_irq.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/common/vector.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/Kconfig.defconfig.gd32vf103 (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/Kconfig.defconfig.series (72%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/entry.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/gd32_regs.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/pinctrl_soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/soc.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/gd32vf103/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/miv/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/mpfs/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/reset.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/soc.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/neorv32/soc_irq.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/niosv/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/rom_header.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/rom_header.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/soc.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/opentitan/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fe310_clock.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fe310_prci.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fu540_clock.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fu540_prci.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fu740_clock.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/fu740_prci.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/pinctrl_soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/sifive-freedom/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/starfive_jh71xx/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/init.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/pinctrl_soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/soc.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/soc.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/soc_context.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/soc_irq.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/soc_offsets.h (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/telink_b91/start.S (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/CMakeLists.txt (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/Kconfig.defconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/Kconfig.series (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/Kconfig.soc (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/linker.ld (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/soc.c (100%) rename soc/riscv/{riscv-privilege => riscv-privileged}/virt/soc.h (100%) diff --git a/CODEOWNERS b/CODEOWNERS index 7da0fe19cdc6..2cc376dc5f03 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -80,10 +80,10 @@ /soc/posix/ @aescolar @daor-oti /soc/riscv/ @kgugala @pgielda /soc/riscv/openisa*/ @dleach02 -/soc/riscv/riscv-privilege/andes_v5/ @cwshu @kevinwang821020 @jimmyzhe -/soc/riscv/riscv-privilege/neorv32/ @henrikbrixandersen -/soc/riscv/riscv-privilege/gd32vf103/ @soburi -/soc/riscv/riscv-privilege/niosv/ @sweeaun +/soc/riscv/riscv-privileged/andes_v5/ @cwshu @kevinwang821020 @jimmyzhe +/soc/riscv/riscv-privileged/neorv32/ @henrikbrixandersen +/soc/riscv/riscv-privileged/gd32vf103/ @soburi +/soc/riscv/riscv-privileged/niosv/ @sweeaun /soc/x86/ @dcpleung @nashif @aasthagr /arch/xtensa/ @dcpleung @andyross @nashif /soc/xtensa/ @dcpleung @andyross @nashif diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index bb68a4cc3ab2..254908afffbd 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2106,7 +2106,7 @@ GD32 Platforms: - dts/*/gigadevice/ - dts/bindings/*/*gd32* - soc/arm/gigadevice/ - - soc/riscv/riscv-privilege/gd32vf103/ + - soc/riscv/riscv-privileged/gd32vf103/ - scripts/west_commands/*/*gd32* labels: - "platform: GD32" diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 7bc1d8bc49a9..29f854f3ff88 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -301,7 +301,7 @@ static inline uint64_t arch_k_cycle_get_64(void) #endif /*_ASMLANGUAGE */ #if defined(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED) -#include +#include #endif diff --git a/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h b/include/zephyr/arch/riscv/riscv-privileged/asm_inline.h similarity index 89% rename from include/zephyr/arch/riscv/riscv-privilege/asm_inline.h rename to include/zephyr/arch/riscv/riscv-privileged/asm_inline.h index 106054b649a4..6ba9f9fb966e 100644 --- a/include/zephyr/arch/riscv/riscv-privilege/asm_inline.h +++ b/include/zephyr/arch/riscv/riscv-privileged/asm_inline.h @@ -14,7 +14,7 @@ */ #if defined(__GNUC__) -#include +#include #else #error "Supports only GNU C compiler" #endif diff --git a/include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h b/include/zephyr/arch/riscv/riscv-privileged/asm_inline_gcc.h similarity index 100% rename from include/zephyr/arch/riscv/riscv-privilege/asm_inline_gcc.h rename to include/zephyr/arch/riscv/riscv-privileged/asm_inline_gcc.h diff --git a/soc/riscv/litex-vexriscv/CMakeLists.txt b/soc/riscv/litex-vexriscv/CMakeLists.txt index 3be6a867a674..34d6046ab684 100644 --- a/soc/riscv/litex-vexriscv/CMakeLists.txt +++ b/soc/riscv/litex-vexriscv/CMakeLists.txt @@ -5,6 +5,6 @@ # zephyr_sources( - ../riscv-privilege/common/soc_irq.S - ../riscv-privilege/common/vector.S + ../riscv-privileged/common/soc_irq.S + ../riscv-privileged/common/vector.S ) diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex-vexriscv/soc.h index 6f80ba07f8a4..d9b1f19c46f4 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-privilege/common/soc_common.h" +#include "../riscv-privileged/common/soc_common.h" #include #include diff --git a/soc/riscv/riscv-privilege/CMakeLists.txt b/soc/riscv/riscv-privileged/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/CMakeLists.txt rename to soc/riscv/riscv-privileged/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/Kconfig b/soc/riscv/riscv-privileged/Kconfig similarity index 92% rename from soc/riscv/riscv-privilege/Kconfig rename to soc/riscv/riscv-privileged/Kconfig index 151b9690e3d3..9d3b9f4a3567 100644 --- a/soc/riscv/riscv-privilege/Kconfig +++ b/soc/riscv/riscv-privileged/Kconfig @@ -13,7 +13,7 @@ config SOC_FAMILY_RISCV_PRIVILEGED config SOC_FAMILY string - default "riscv-privilege" + default "riscv-privileged" depends on SOC_FAMILY_RISCV_PRIVILEGED config RISCV_HAS_PLIC @@ -34,4 +34,4 @@ config RISCV_MTVEC_VECTORED_MODE help Should the SOC use mtvec in vectored mode -source "soc/riscv/riscv-privilege/*/Kconfig.soc" +source "soc/riscv/riscv-privileged/*/Kconfig.soc" diff --git a/soc/riscv/riscv-privilege/Kconfig.defconfig b/soc/riscv/riscv-privileged/Kconfig.defconfig similarity index 73% rename from soc/riscv/riscv-privilege/Kconfig.defconfig rename to soc/riscv/riscv-privileged/Kconfig.defconfig index d8815302bef9..6793d72a385b 100644 --- a/soc/riscv/riscv-privilege/Kconfig.defconfig +++ b/soc/riscv/riscv-privileged/Kconfig.defconfig @@ -3,4 +3,4 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -source "soc/riscv/riscv-privilege/*/Kconfig.defconfig.series" +source "soc/riscv/riscv-privileged/*/Kconfig.defconfig.series" diff --git a/soc/riscv/riscv-privilege/Kconfig.soc b/soc/riscv/riscv-privileged/Kconfig.soc similarity index 76% rename from soc/riscv/riscv-privilege/Kconfig.soc rename to soc/riscv/riscv-privileged/Kconfig.soc index 5d0bad94b6a9..14d141223e0a 100644 --- a/soc/riscv/riscv-privilege/Kconfig.soc +++ b/soc/riscv/riscv-privileged/Kconfig.soc @@ -3,4 +3,4 @@ # Copyright (c) 2017 Jean-Paul Etienne # SPDX-License-Identifier: Apache-2.0 -source "soc/riscv/riscv-privilege/*/Kconfig.series" +source "soc/riscv/riscv-privileged/*/Kconfig.series" diff --git a/soc/riscv/riscv-privilege/andes_v5/CMakeLists.txt b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/CMakeLists.txt rename to soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/Kconfig.defconfig.ae350 rename to soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 diff --git a/soc/riscv/riscv-privilege/andes_v5/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series similarity index 92% rename from soc/riscv/riscv-privilege/andes_v5/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series index 043f008320b3..c6436807825f 100644 --- a/soc/riscv/riscv-privilege/andes_v5/Kconfig.defconfig.series +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series @@ -6,7 +6,7 @@ if SOC_SERIES_RISCV_ANDES_V5 # 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-privilege/andes_v5/Kconfig.defconfig.ae*" +source "soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae*" config SOC_SERIES default "andes_v5" diff --git a/soc/riscv/riscv-privilege/andes_v5/Kconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/Kconfig.series rename to soc/riscv/riscv-privileged/andes_v5/Kconfig.series diff --git a/soc/riscv/riscv-privilege/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/Kconfig.soc rename to soc/riscv/riscv-privileged/andes_v5/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/ae350/linker.ld rename to soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld diff --git a/soc/riscv/riscv-privilege/andes_v5/ae350/soc.h b/soc/riscv/riscv-privileged/andes_v5/ae350/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/ae350/soc.h rename to soc/riscv/riscv-privileged/andes_v5/ae350/soc.h diff --git a/soc/riscv/riscv-privilege/andes_v5/l2_cache.c b/soc/riscv/riscv-privileged/andes_v5/l2_cache.c similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/l2_cache.c rename to soc/riscv/riscv-privileged/andes_v5/l2_cache.c diff --git a/soc/riscv/riscv-privilege/andes_v5/linker.ld b/soc/riscv/riscv-privileged/andes_v5/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/linker.ld rename to soc/riscv/riscv-privileged/andes_v5/linker.ld diff --git a/soc/riscv/riscv-privilege/andes_v5/pma.c b/soc/riscv/riscv-privileged/andes_v5/pma.c similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/pma.c rename to soc/riscv/riscv-privileged/andes_v5/pma.c diff --git a/soc/riscv/riscv-privilege/andes_v5/soc_context.h b/soc/riscv/riscv-privileged/andes_v5/soc_context.h similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/soc_context.h rename to soc/riscv/riscv-privileged/andes_v5/soc_context.h diff --git a/soc/riscv/riscv-privilege/andes_v5/soc_irq.S b/soc/riscv/riscv-privileged/andes_v5/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/soc_irq.S rename to soc/riscv/riscv-privileged/andes_v5/soc_irq.S diff --git a/soc/riscv/riscv-privilege/andes_v5/soc_offsets.h b/soc/riscv/riscv-privileged/andes_v5/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/soc_offsets.h rename to soc/riscv/riscv-privileged/andes_v5/soc_offsets.h diff --git a/soc/riscv/riscv-privilege/andes_v5/soc_v5.h b/soc/riscv/riscv-privileged/andes_v5/soc_v5.h similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/soc_v5.h rename to soc/riscv/riscv-privileged/andes_v5/soc_v5.h diff --git a/soc/riscv/riscv-privilege/andes_v5/start.S b/soc/riscv/riscv-privileged/andes_v5/start.S similarity index 100% rename from soc/riscv/riscv-privilege/andes_v5/start.S rename to soc/riscv/riscv-privileged/andes_v5/start.S diff --git a/soc/riscv/riscv-privilege/common/CMakeLists.txt b/soc/riscv/riscv-privileged/common/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/common/CMakeLists.txt rename to soc/riscv/riscv-privileged/common/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/common/idle.c b/soc/riscv/riscv-privileged/common/idle.c similarity index 100% rename from soc/riscv/riscv-privilege/common/idle.c rename to soc/riscv/riscv-privileged/common/idle.c diff --git a/soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h b/soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h similarity index 100% rename from soc/riscv/riscv-privilege/common/nuclei/nuclei_csr.h rename to soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h diff --git a/soc/riscv/riscv-privilege/common/soc_common.h b/soc/riscv/riscv-privileged/common/soc_common.h similarity index 100% rename from soc/riscv/riscv-privilege/common/soc_common.h rename to soc/riscv/riscv-privileged/common/soc_common.h diff --git a/soc/riscv/riscv-privilege/common/soc_common_irq.c b/soc/riscv/riscv-privileged/common/soc_common_irq.c similarity index 100% rename from soc/riscv/riscv-privilege/common/soc_common_irq.c rename to soc/riscv/riscv-privileged/common/soc_common_irq.c diff --git a/soc/riscv/riscv-privilege/common/soc_irq.S b/soc/riscv/riscv-privileged/common/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privilege/common/soc_irq.S rename to soc/riscv/riscv-privileged/common/soc_irq.S diff --git a/soc/riscv/riscv-privilege/common/vector.S b/soc/riscv/riscv-privileged/common/vector.S similarity index 100% rename from soc/riscv/riscv-privilege/common/vector.S rename to soc/riscv/riscv-privileged/common/vector.S diff --git a/soc/riscv/riscv-privilege/gd32vf103/CMakeLists.txt b/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/CMakeLists.txt rename to soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.gd32vf103 rename to soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 diff --git a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series similarity index 72% rename from soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series index 309b7ecc0e1f..061b53b2514e 100644 --- a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.series +++ b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series @@ -3,7 +3,7 @@ if SOC_SERIES_GD32VF103 -source "soc/riscv/riscv-privilege/gd32vf103/Kconfig.defconfig.gd32vf103*" +source "soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103*" config SOC_SERIES default "gd32vf103" diff --git a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.series b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/Kconfig.series rename to soc/riscv/riscv-privileged/gd32vf103/Kconfig.series diff --git a/soc/riscv/riscv-privilege/gd32vf103/Kconfig.soc b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/Kconfig.soc rename to soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/gd32vf103/entry.S b/soc/riscv/riscv-privileged/gd32vf103/entry.S similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/entry.S rename to soc/riscv/riscv-privileged/gd32vf103/entry.S diff --git a/soc/riscv/riscv-privilege/gd32vf103/gd32_regs.h b/soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/gd32_regs.h rename to soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h diff --git a/soc/riscv/riscv-privilege/gd32vf103/linker.ld b/soc/riscv/riscv-privileged/gd32vf103/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/linker.ld rename to soc/riscv/riscv-privileged/gd32vf103/linker.ld diff --git a/soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h b/soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/pinctrl_soc.h rename to soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h diff --git a/soc/riscv/riscv-privilege/gd32vf103/soc.c b/soc/riscv/riscv-privileged/gd32vf103/soc.c similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/soc.c rename to soc/riscv/riscv-privileged/gd32vf103/soc.c diff --git a/soc/riscv/riscv-privilege/gd32vf103/soc.h b/soc/riscv/riscv-privileged/gd32vf103/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/gd32vf103/soc.h rename to soc/riscv/riscv-privileged/gd32vf103/soc.h diff --git a/soc/riscv/riscv-privilege/miv/CMakeLists.txt b/soc/riscv/riscv-privileged/miv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/miv/CMakeLists.txt rename to soc/riscv/riscv-privileged/miv/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/miv/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/miv/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/miv/Kconfig.series b/soc/riscv/riscv-privileged/miv/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/miv/Kconfig.series rename to soc/riscv/riscv-privileged/miv/Kconfig.series diff --git a/soc/riscv/riscv-privilege/miv/Kconfig.soc b/soc/riscv/riscv-privileged/miv/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/miv/Kconfig.soc rename to soc/riscv/riscv-privileged/miv/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/miv/linker.ld b/soc/riscv/riscv-privileged/miv/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/miv/linker.ld rename to soc/riscv/riscv-privileged/miv/linker.ld diff --git a/soc/riscv/riscv-privilege/miv/soc.h b/soc/riscv/riscv-privileged/miv/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/miv/soc.h rename to soc/riscv/riscv-privileged/miv/soc.h diff --git a/soc/riscv/riscv-privilege/mpfs/CMakeLists.txt b/soc/riscv/riscv-privileged/mpfs/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/CMakeLists.txt rename to soc/riscv/riscv-privileged/mpfs/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/mpfs/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/mpfs/Kconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/Kconfig.series rename to soc/riscv/riscv-privileged/mpfs/Kconfig.series diff --git a/soc/riscv/riscv-privilege/mpfs/Kconfig.soc b/soc/riscv/riscv-privileged/mpfs/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/Kconfig.soc rename to soc/riscv/riscv-privileged/mpfs/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/mpfs/linker.ld b/soc/riscv/riscv-privileged/mpfs/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/linker.ld rename to soc/riscv/riscv-privileged/mpfs/linker.ld diff --git a/soc/riscv/riscv-privilege/mpfs/soc.h b/soc/riscv/riscv-privileged/mpfs/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/mpfs/soc.h rename to soc/riscv/riscv-privileged/mpfs/soc.h diff --git a/soc/riscv/riscv-privilege/neorv32/CMakeLists.txt b/soc/riscv/riscv-privileged/neorv32/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/CMakeLists.txt rename to soc/riscv/riscv-privileged/neorv32/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/neorv32/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/neorv32/Kconfig.series b/soc/riscv/riscv-privileged/neorv32/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/Kconfig.series rename to soc/riscv/riscv-privileged/neorv32/Kconfig.series diff --git a/soc/riscv/riscv-privilege/neorv32/Kconfig.soc b/soc/riscv/riscv-privileged/neorv32/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/Kconfig.soc rename to soc/riscv/riscv-privileged/neorv32/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/neorv32/linker.ld b/soc/riscv/riscv-privileged/neorv32/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/linker.ld rename to soc/riscv/riscv-privileged/neorv32/linker.ld diff --git a/soc/riscv/riscv-privilege/neorv32/reset.S b/soc/riscv/riscv-privileged/neorv32/reset.S similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/reset.S rename to soc/riscv/riscv-privileged/neorv32/reset.S diff --git a/soc/riscv/riscv-privilege/neorv32/soc.c b/soc/riscv/riscv-privileged/neorv32/soc.c similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/soc.c rename to soc/riscv/riscv-privileged/neorv32/soc.c diff --git a/soc/riscv/riscv-privilege/neorv32/soc.h b/soc/riscv/riscv-privileged/neorv32/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/soc.h rename to soc/riscv/riscv-privileged/neorv32/soc.h diff --git a/soc/riscv/riscv-privilege/neorv32/soc_irq.S b/soc/riscv/riscv-privileged/neorv32/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privilege/neorv32/soc_irq.S rename to soc/riscv/riscv-privileged/neorv32/soc_irq.S diff --git a/soc/riscv/riscv-privilege/niosv/CMakeLists.txt b/soc/riscv/riscv-privileged/niosv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/niosv/CMakeLists.txt rename to soc/riscv/riscv-privileged/niosv/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/niosv/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/niosv/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/niosv/Kconfig.series b/soc/riscv/riscv-privileged/niosv/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/niosv/Kconfig.series rename to soc/riscv/riscv-privileged/niosv/Kconfig.series diff --git a/soc/riscv/riscv-privilege/niosv/Kconfig.soc b/soc/riscv/riscv-privileged/niosv/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/niosv/Kconfig.soc rename to soc/riscv/riscv-privileged/niosv/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/niosv/linker.ld b/soc/riscv/riscv-privileged/niosv/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/niosv/linker.ld rename to soc/riscv/riscv-privileged/niosv/linker.ld diff --git a/soc/riscv/riscv-privilege/niosv/soc.h b/soc/riscv/riscv-privileged/niosv/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/niosv/soc.h rename to soc/riscv/riscv-privileged/niosv/soc.h diff --git a/soc/riscv/riscv-privilege/opentitan/CMakeLists.txt b/soc/riscv/riscv-privileged/opentitan/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/CMakeLists.txt rename to soc/riscv/riscv-privileged/opentitan/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/opentitan/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/opentitan/Kconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/Kconfig.series rename to soc/riscv/riscv-privileged/opentitan/Kconfig.series diff --git a/soc/riscv/riscv-privilege/opentitan/Kconfig.soc b/soc/riscv/riscv-privileged/opentitan/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/Kconfig.soc rename to soc/riscv/riscv-privileged/opentitan/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/opentitan/linker.ld b/soc/riscv/riscv-privileged/opentitan/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/linker.ld rename to soc/riscv/riscv-privileged/opentitan/linker.ld diff --git a/soc/riscv/riscv-privilege/opentitan/rom_header.S b/soc/riscv/riscv-privileged/opentitan/rom_header.S similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/rom_header.S rename to soc/riscv/riscv-privileged/opentitan/rom_header.S diff --git a/soc/riscv/riscv-privilege/opentitan/rom_header.ld b/soc/riscv/riscv-privileged/opentitan/rom_header.ld similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/rom_header.ld rename to soc/riscv/riscv-privileged/opentitan/rom_header.ld diff --git a/soc/riscv/riscv-privilege/opentitan/soc.c b/soc/riscv/riscv-privileged/opentitan/soc.c similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/soc.c rename to soc/riscv/riscv-privileged/opentitan/soc.c diff --git a/soc/riscv/riscv-privilege/opentitan/soc.h b/soc/riscv/riscv-privileged/opentitan/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/opentitan/soc.h rename to soc/riscv/riscv-privileged/opentitan/soc.h diff --git a/soc/riscv/riscv-privilege/sifive-freedom/CMakeLists.txt b/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/CMakeLists.txt rename to soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/Kconfig.series rename to soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series diff --git a/soc/riscv/riscv-privilege/sifive-freedom/Kconfig.soc b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/Kconfig.soc rename to soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fe310_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fe310_clock.c rename to soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fe310_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fe310_prci.h rename to soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fu540_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fu540_clock.c rename to soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fu540_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fu540_prci.h rename to soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fu740_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fu740_clock.c rename to soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c diff --git a/soc/riscv/riscv-privilege/sifive-freedom/fu740_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/fu740_prci.h rename to soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h diff --git a/soc/riscv/riscv-privilege/sifive-freedom/linker.ld b/soc/riscv/riscv-privileged/sifive-freedom/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/linker.ld rename to soc/riscv/riscv-privileged/sifive-freedom/linker.ld diff --git a/soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h b/soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/pinctrl_soc.h rename to soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h diff --git a/soc/riscv/riscv-privilege/sifive-freedom/soc.h b/soc/riscv/riscv-privileged/sifive-freedom/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/sifive-freedom/soc.h rename to soc/riscv/riscv-privileged/sifive-freedom/soc.h diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/CMakeLists.txt b/soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/CMakeLists.txt rename to soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.series rename to soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.soc b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/Kconfig.soc rename to soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/linker.ld b/soc/riscv/riscv-privileged/starfive_jh71xx/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/linker.ld rename to soc/riscv/riscv-privileged/starfive_jh71xx/linker.ld diff --git a/soc/riscv/riscv-privilege/starfive_jh71xx/soc.h b/soc/riscv/riscv-privileged/starfive_jh71xx/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/starfive_jh71xx/soc.h rename to soc/riscv/riscv-privileged/starfive_jh71xx/soc.h diff --git a/soc/riscv/riscv-privilege/telink_b91/CMakeLists.txt b/soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/CMakeLists.txt rename to soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.series b/soc/riscv/riscv-privileged/telink_b91/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/Kconfig.series rename to soc/riscv/riscv-privileged/telink_b91/Kconfig.series diff --git a/soc/riscv/riscv-privilege/telink_b91/Kconfig.soc b/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/Kconfig.soc rename to soc/riscv/riscv-privileged/telink_b91/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/telink_b91/init.ld b/soc/riscv/riscv-privileged/telink_b91/init.ld similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/init.ld rename to soc/riscv/riscv-privileged/telink_b91/init.ld diff --git a/soc/riscv/riscv-privilege/telink_b91/linker.ld b/soc/riscv/riscv-privileged/telink_b91/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/linker.ld rename to soc/riscv/riscv-privileged/telink_b91/linker.ld diff --git a/soc/riscv/riscv-privilege/telink_b91/pinctrl_soc.h b/soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/pinctrl_soc.h rename to soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h diff --git a/soc/riscv/riscv-privilege/telink_b91/soc.c b/soc/riscv/riscv-privileged/telink_b91/soc.c similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/soc.c rename to soc/riscv/riscv-privileged/telink_b91/soc.c diff --git a/soc/riscv/riscv-privilege/telink_b91/soc.h b/soc/riscv/riscv-privileged/telink_b91/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/soc.h rename to soc/riscv/riscv-privileged/telink_b91/soc.h diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_context.h b/soc/riscv/riscv-privileged/telink_b91/soc_context.h similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/soc_context.h rename to soc/riscv/riscv-privileged/telink_b91/soc_context.h diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_irq.S b/soc/riscv/riscv-privileged/telink_b91/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/soc_irq.S rename to soc/riscv/riscv-privileged/telink_b91/soc_irq.S diff --git a/soc/riscv/riscv-privilege/telink_b91/soc_offsets.h b/soc/riscv/riscv-privileged/telink_b91/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/soc_offsets.h rename to soc/riscv/riscv-privileged/telink_b91/soc_offsets.h diff --git a/soc/riscv/riscv-privilege/telink_b91/start.S b/soc/riscv/riscv-privileged/telink_b91/start.S similarity index 100% rename from soc/riscv/riscv-privilege/telink_b91/start.S rename to soc/riscv/riscv-privileged/telink_b91/start.S diff --git a/soc/riscv/riscv-privilege/virt/CMakeLists.txt b/soc/riscv/riscv-privileged/virt/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privilege/virt/CMakeLists.txt rename to soc/riscv/riscv-privileged/virt/CMakeLists.txt diff --git a/soc/riscv/riscv-privilege/virt/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/virt/Kconfig.defconfig.series rename to soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series diff --git a/soc/riscv/riscv-privilege/virt/Kconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.series similarity index 100% rename from soc/riscv/riscv-privilege/virt/Kconfig.series rename to soc/riscv/riscv-privileged/virt/Kconfig.series diff --git a/soc/riscv/riscv-privilege/virt/Kconfig.soc b/soc/riscv/riscv-privileged/virt/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privilege/virt/Kconfig.soc rename to soc/riscv/riscv-privileged/virt/Kconfig.soc diff --git a/soc/riscv/riscv-privilege/virt/linker.ld b/soc/riscv/riscv-privileged/virt/linker.ld similarity index 100% rename from soc/riscv/riscv-privilege/virt/linker.ld rename to soc/riscv/riscv-privileged/virt/linker.ld diff --git a/soc/riscv/riscv-privilege/virt/soc.c b/soc/riscv/riscv-privileged/virt/soc.c similarity index 100% rename from soc/riscv/riscv-privilege/virt/soc.c rename to soc/riscv/riscv-privileged/virt/soc.c diff --git a/soc/riscv/riscv-privilege/virt/soc.h b/soc/riscv/riscv-privileged/virt/soc.h similarity index 100% rename from soc/riscv/riscv-privilege/virt/soc.h rename to soc/riscv/riscv-privileged/virt/soc.h From f35fb33b94e80b8f2766ad9c9b4dcc19a8795eed Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 4 Jun 2023 09:19:46 -0400 Subject: [PATCH 0054/2042] posix: pthread: reimplement pthread_barrier using zephyr objects Previously pthread_barrier_t was implemented in terms of wait queues and internal scheduler functions. This introduced some obstacles and inconsistency. In order to be more consistent, rely only on Zephyr's public API and reuse as many concepts as possible. Deprecate `PTHREAD_BARRIER_DEFINE()` since it's non-standard. Signed-off-by: Christopher Friedt --- include/zephyr/posix/posix_types.h | 6 +- include/zephyr/posix/pthread.h | 29 +---- lib/posix/Kconfig | 7 ++ lib/posix/pthread_barrier.c | 171 ++++++++++++++++++++++++++--- tests/posix/common/src/pthread.c | 8 +- 5 files changed, 177 insertions(+), 44 deletions(-) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index bbac6b0bbec8..d34102a06de1 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -80,11 +80,7 @@ typedef struct pthread_condattr pthread_condattr_t; BUILD_ASSERT(sizeof(pthread_condattr_t) >= sizeof(struct pthread_condattr)); /* Barrier */ -typedef struct pthread_barrier { - _wait_q_t wait_q; - int max; - int count; -} pthread_barrier_t; +typedef uint32_t pthread_barrier_t; typedef struct pthread_barrierattr { } pthread_barrierattr_t; diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 083be9b7ca59..0004aa94e079 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -8,7 +8,6 @@ #define ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ #include -#include #include #include #include "posix_types.h" @@ -287,12 +286,9 @@ static inline int pthread_mutexattr_destroy(pthread_mutexattr_t *m) * @param name Symbol name of the barrier * @param count Thread count, same as the "count" argument to * pthread_barrier_init() + * @deprecated Use @ref pthread_barrier_init instead. */ -#define PTHREAD_BARRIER_DEFINE(name, count) \ - struct pthread_barrier name = { \ - .wait_q = Z_WAIT_Q_INIT(&name.wait_q), \ - .max = count, \ - } +#define PTHREAD_BARRIER_DEFINE(name, count) pthread_barrier_t name = -1 __DEPRECATED_MACRO #define PTHREAD_BARRIER_SERIAL_THREAD 1 @@ -308,30 +304,15 @@ int pthread_barrier_wait(pthread_barrier_t *b); * * See IEEE 1003.1 */ -static inline int pthread_barrier_init(pthread_barrier_t *b, - const pthread_barrierattr_t *attr, - unsigned int count) -{ - ARG_UNUSED(attr); - - b->max = count; - b->count = 0; - z_waitq_init(&b->wait_q); - - return 0; -} +int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *attr, + unsigned int count); /** * @brief POSIX threading compatibility API * * See IEEE 1003.1 */ -static inline int pthread_barrier_destroy(pthread_barrier_t *b) -{ - ARG_UNUSED(b); - - return 0; -} +int pthread_barrier_destroy(pthread_barrier_t *b); /** * @brief POSIX threading compatibility API diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 5c2592cb4f9f..30085e5abc60 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -56,6 +56,13 @@ config MAX_PTHREAD_KEY_COUNT help Maximum number of simultaneously active keys in a POSIX application. +config MAX_PTHREAD_BARRIER_COUNT + int "Maximum simultaneously active barriers in a POSIX application" + default 5 + range 0 255 + help + Maximum number of simultaneously active keys in a POSIX application. + config SEM_VALUE_MAX int "Maximum semaphore limit" default 32767 diff --git a/lib/posix/pthread_barrier.c b/lib/posix/pthread_barrier.c index 5c52fd30fdd1..ead8d60c429b 100644 --- a/lib/posix/pthread_barrier.c +++ b/lib/posix/pthread_barrier.c @@ -4,31 +4,174 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include -#include -#include +#include -extern struct k_spinlock z_pthread_spinlock; +#include "posix_internal.h" + +struct posix_barrier { + struct k_mutex mutex; + struct k_condvar cond; + uint32_t max; + uint32_t count; +}; + +static struct posix_barrier posix_barrier_pool[CONFIG_MAX_PTHREAD_BARRIER_COUNT]; +SYS_BITARRAY_DEFINE_STATIC(posix_barrier_bitarray, CONFIG_MAX_PTHREAD_BARRIER_COUNT); + +/* + * We reserve the MSB to mark a pthread_barrier_t as initialized (from the + * perspective of the application). With a linear space, this means that + * the theoretical pthread_barrier_t range is [0,2147483647]. + */ +BUILD_ASSERT(CONFIG_MAX_PTHREAD_BARRIER_COUNT < PTHREAD_OBJ_MASK_INIT, + "CONFIG_MAX_PTHREAD_BARRIER_COUNT is too high"); + +static inline size_t posix_barrier_to_offset(struct posix_barrier *bar) +{ + return bar - posix_barrier_pool; +} + +static inline size_t to_posix_barrier_idx(pthread_barrier_t b) +{ + return mark_pthread_obj_uninitialized(b); +} + +struct posix_barrier *get_posix_barrier(pthread_barrier_t b) +{ + int actually_initialized; + size_t bit = to_posix_barrier_idx(b); + + /* if the provided barrier does not claim to be initialized, its invalid */ + if (!is_pthread_obj_initialized(b)) { + return NULL; + } + + /* Mask off the MSB to get the actual bit index */ + if (sys_bitarray_test_bit(&posix_barrier_bitarray, bit, &actually_initialized) < 0) { + return NULL; + } + + if (actually_initialized == 0) { + /* The barrier claims to be initialized but is actually not */ + return NULL; + } + + return &posix_barrier_pool[bit]; +} int pthread_barrier_wait(pthread_barrier_t *b) { - k_spinlock_key_t key = k_spin_lock(&z_pthread_spinlock); - int ret = 0; + int ret; + int err; + pthread_barrier_t bb = *b; + struct posix_barrier *bar; - b->count++; + bar = get_posix_barrier(bb); + if (bar == NULL) { + return EINVAL; + } + + err = k_mutex_lock(&bar->mutex, K_FOREVER); + __ASSERT_NO_MSG(err == 0); - if (b->count >= b->max) { - b->count = 0; + ++bar->count; - while (z_waitq_head(&b->wait_q)) { - _ready_one_thread(&b->wait_q); - } - z_reschedule(&z_pthread_spinlock, key); + if (bar->count == bar->max) { + bar->count = 0; ret = PTHREAD_BARRIER_SERIAL_THREAD; - } else { - (void) z_pend_curr(&z_pthread_spinlock, key, &b->wait_q, K_FOREVER); + + goto unlock; } + while (bar->count != 0) { + err = k_condvar_wait(&bar->cond, &bar->mutex, K_FOREVER); + __ASSERT_NO_MSG(err == 0); + /* Note: count is reset to zero by the serialized thread */ + } + + ret = 0; + +unlock: + err = k_condvar_signal(&bar->cond); + __ASSERT_NO_MSG(err == 0); + err = k_mutex_unlock(&bar->mutex); + __ASSERT_NO_MSG(err == 0); + return ret; } + +int pthread_barrier_init(pthread_barrier_t *b, const pthread_barrierattr_t *attr, + unsigned int count) +{ + size_t bit; + struct posix_barrier *bar; + + if (count == 0) { + return EINVAL; + } + + if (sys_bitarray_alloc(&posix_barrier_bitarray, 1, &bit) < 0) { + return ENOMEM; + } + + bar = &posix_barrier_pool[bit]; + bar->max = count; + bar->count = 0; + + *b = mark_pthread_obj_initialized(bit); + + return 0; +} + +int pthread_barrier_destroy(pthread_barrier_t *b) +{ + int err; + size_t bit; + struct posix_barrier *bar; + + bar = get_posix_barrier(*b); + if (bar == NULL) { + return EINVAL; + } + + err = k_mutex_lock(&bar->mutex, K_FOREVER); + if (err < 0) { + return -err; + } + __ASSERT_NO_MSG(err == 0); + + /* An implementation may use this function to set barrier to an invalid value */ + bar->max = 0; + bar->count = 0; + + bit = posix_barrier_to_offset(bar); + err = sys_bitarray_free(&posix_barrier_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); + + err = k_condvar_broadcast(&bar->cond); + __ASSERT_NO_MSG(err == 0); + + err = k_mutex_unlock(&bar->mutex); + __ASSERT_NO_MSG(err == 0); + + return 0; +} + +static int pthread_barrier_pool_init(void) +{ + int err; + size_t i; + + for (i = 0; i < CONFIG_MAX_PTHREAD_BARRIER_COUNT; ++i) { + err = k_mutex_init(&posix_barrier_pool[i].mutex); + __ASSERT_NO_MSG(err == 0); + err = k_condvar_init(&posix_barrier_pool[i].cond); + __ASSERT_NO_MSG(err == 0); + } + + return 0; +} +SYS_INIT(pthread_barrier_pool_init, PRE_KERNEL_1, 0); diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 5e506c4d3953..50c1233bada0 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -40,7 +40,7 @@ PTHREAD_COND_DEFINE(cvar0); PTHREAD_COND_DEFINE(cvar1); -PTHREAD_BARRIER_DEFINE(barrier, N_THR_E); +static pthread_barrier_t barrier; sem_t main_sem; @@ -244,6 +244,12 @@ ZTEST(posix_apis, test_posix_pthread_execution) static const char thr_name[] = "thread name"; char thr_name_buf[CONFIG_THREAD_MAX_NAME_LEN]; + /* + * initialize barriers the standard way after deprecating + * PTHREAD_BARRIER_DEFINE(). + */ + 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); From 0d7ef2297b58d5d12c87c26eb6cd45447eb70e3d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 3 Jun 2023 15:49:04 -0400 Subject: [PATCH 0055/2042] posix: mutex: use k_mutex instead of posix_mutex The internal representation of `pthread_mutex_t`, `struct posix_mutex`, is basically a clone of `struct k_mutex` but without the benefit of being able to use all of the existing `k_mutex_*()` suite of functions. The first step in the right direction was switching the external representation of `pthread_mutex_t` to a simple `int`. Let's take the next step in the right direction, which is getting rid of `struct posix_mutex`. The only significant difference between `struct k_mutex` and `struct posix_mutex` is that the latter needs a `type` field. Since there were a fixed number of `struct posix_mutex`, we can just externalize the `type` field and reuse `struct k_mutex` as-is. For now, let's keep this change as a simple type substitution. Eventually, we should be able to fully switch to Zephyr API internally. Signed-off-by: Christopher Friedt --- lib/posix/posix_internal.h | 11 ++------- lib/posix/pthread_cond.c | 2 +- lib/posix/pthread_mutex.c | 50 +++++++++++++++++++++++++++++--------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 48999c5694ce..b69c4d500c19 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -15,13 +15,6 @@ */ #define PTHREAD_OBJ_MASK_INIT 0x80000000 -struct posix_mutex { - k_tid_t owner; - uint16_t lock_count; - int type; - _wait_q_t wait_q; -}; - struct posix_cond { _wait_q_t wait_q; }; @@ -98,10 +91,10 @@ static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj) struct posix_thread *to_posix_thread(pthread_t pthread); /* get and possibly initialize a posix_mutex */ -struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu); +struct k_mutex *to_posix_mutex(pthread_mutex_t *mu); /* get a previously initialized posix_mutex */ -struct posix_mutex *get_posix_mutex(pthread_mutex_t mut); +struct k_mutex *get_posix_mutex(pthread_mutex_t mut); /* get and possibly initialize a posix_cond */ struct posix_cond *to_posix_cond(pthread_cond_t *cvar); diff --git a/lib/posix/pthread_cond.c b/lib/posix/pthread_cond.c index 7e21244d1d3c..5c038b69170a 100644 --- a/lib/posix/pthread_cond.c +++ b/lib/posix/pthread_cond.c @@ -90,7 +90,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time int ret; k_spinlock_key_t key; struct posix_cond *cv; - struct posix_mutex *m; + struct k_mutex *m; key = k_spin_lock(&z_pthread_spinlock); m = to_posix_mutex(mu); diff --git a/lib/posix/pthread_mutex.c b/lib/posix/pthread_mutex.c index 2d514b6886c5..a9b1984e1ac9 100644 --- a/lib/posix/pthread_mutex.c +++ b/lib/posix/pthread_mutex.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -25,7 +26,8 @@ static const struct pthread_mutexattr def_attr = { .type = PTHREAD_MUTEX_DEFAULT, }; -static struct posix_mutex posix_mutex_pool[CONFIG_MAX_PTHREAD_MUTEX_COUNT]; +static struct k_mutex posix_mutex_pool[CONFIG_MAX_PTHREAD_MUTEX_COUNT]; +static uint8_t posix_mutex_type[CONFIG_MAX_PTHREAD_MUTEX_COUNT]; SYS_BITARRAY_DEFINE_STATIC(posix_mutex_bitarray, CONFIG_MAX_PTHREAD_MUTEX_COUNT); /* @@ -36,7 +38,7 @@ SYS_BITARRAY_DEFINE_STATIC(posix_mutex_bitarray, CONFIG_MAX_PTHREAD_MUTEX_COUNT) BUILD_ASSERT(CONFIG_MAX_PTHREAD_MUTEX_COUNT < PTHREAD_OBJ_MASK_INIT, "CONFIG_MAX_PTHREAD_MUTEX_COUNT is too high"); -static inline size_t posix_mutex_to_offset(struct posix_mutex *m) +static inline size_t posix_mutex_to_offset(struct k_mutex *m) { return m - posix_mutex_pool; } @@ -46,7 +48,7 @@ static inline size_t to_posix_mutex_idx(pthread_mutex_t mut) return mark_pthread_obj_uninitialized(mut); } -struct posix_mutex *get_posix_mutex(pthread_mutex_t mu) +struct k_mutex *get_posix_mutex(pthread_mutex_t mu) { int actually_initialized; size_t bit = to_posix_mutex_idx(mu); @@ -69,10 +71,10 @@ struct posix_mutex *get_posix_mutex(pthread_mutex_t mu) return &posix_mutex_pool[bit]; } -struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu) +struct k_mutex *to_posix_mutex(pthread_mutex_t *mu) { size_t bit; - struct posix_mutex *m; + struct k_mutex *m; if (*mu != PTHREAD_MUTEX_INITIALIZER) { return get_posix_mutex(*mu); @@ -100,9 +102,11 @@ struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu) static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout) { + int type; int rc = 0; + size_t bit; k_spinlock_key_t key; - struct posix_mutex *m; + struct k_mutex *m; key = k_spin_lock(&z_pthread_spinlock); @@ -112,6 +116,7 @@ static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout) return EINVAL; } + bit = posix_mutex_to_offset(m); if (m->lock_count == 0U && m->owner == NULL) { m->lock_count++; m->owner = k_current_get(); @@ -119,11 +124,12 @@ static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout) k_spin_unlock(&z_pthread_spinlock, key); return 0; } else if (m->owner == k_current_get()) { - if (m->type == PTHREAD_MUTEX_RECURSIVE && + type = posix_mutex_type[bit]; + if (type == PTHREAD_MUTEX_RECURSIVE && m->lock_count < MUTEX_MAX_REC_LOCK) { m->lock_count++; rc = 0; - } else if (m->type == PTHREAD_MUTEX_ERRORCHECK) { + } else if (type == PTHREAD_MUTEX_ERRORCHECK) { rc = EDEADLK; } else { rc = EINVAL; @@ -176,8 +182,9 @@ int pthread_mutex_timedlock(pthread_mutex_t *m, */ int pthread_mutex_init(pthread_mutex_t *mu, const pthread_mutexattr_t *_attr) { + size_t bit; + struct k_mutex *m; k_spinlock_key_t key; - struct posix_mutex *m; const struct pthread_mutexattr *attr = (const struct pthread_mutexattr *)_attr; *mu = PTHREAD_MUTEX_INITIALIZER; @@ -189,7 +196,12 @@ int pthread_mutex_init(pthread_mutex_t *mu, const pthread_mutexattr_t *_attr) return ENOMEM; } - m->type = (attr == NULL) ? def_attr.type : attr->type; + bit = posix_mutex_to_offset(m); + if (attr == NULL) { + posix_mutex_type[bit] = def_attr.type; + } else { + posix_mutex_type[bit] = attr->type; + } k_spin_unlock(&z_pthread_spinlock, key); @@ -216,7 +228,7 @@ int pthread_mutex_unlock(pthread_mutex_t *mu) { k_tid_t thread; k_spinlock_key_t key; - struct posix_mutex *m; + struct k_mutex *m; pthread_mutex_t mut = *mu; key = k_spin_lock(&z_pthread_spinlock); @@ -265,7 +277,7 @@ int pthread_mutex_destroy(pthread_mutex_t *mu) { __unused int rc; k_spinlock_key_t key; - struct posix_mutex *m; + struct k_mutex *m; pthread_mutex_t mut = *mu; size_t bit = to_posix_mutex_idx(mut); @@ -327,3 +339,17 @@ int pthread_mutexattr_settype(pthread_mutexattr_t *_attr, int type) return retc; } + +static int pthread_mutex_pool_init(void) +{ + int err; + size_t i; + + for (i = 0; i < CONFIG_MAX_PTHREAD_MUTEX_COUNT; ++i) { + err = k_mutex_init(&posix_mutex_pool[i]); + __ASSERT_NO_MSG(err == 0); + } + + return 0; +} +SYS_INIT(pthread_mutex_pool_init, PRE_KERNEL_1, 0); From 08ba17683b5da2c016a7515f3ae58231e176fed1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 3 Jun 2023 16:00:44 -0400 Subject: [PATCH 0056/2042] posix: cond: use k_condvar instead of posix_cond The internal representation of `pthread_cond_t`, `struct posix_cond`, is an identical clone of `struct k_condvar` but without the benefit of being able to use all of the existing `k_condvar_*()` suite of functions. The first step in the right direction was switching the external representation of `pthread_cond_t` to a simple `int`. Let's take the next step in the right direction, which is getting rid of `struct posix_cond`. For now, let's keep this change as a simple type substitution. Eventually, we should be able to fully switch to Zephyr API internally. Signed-off-by: Christopher Friedt --- lib/posix/posix_internal.h | 8 ++------ lib/posix/pthread_cond.c | 37 +++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index b69c4d500c19..3d22000788a4 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -15,10 +15,6 @@ */ #define PTHREAD_OBJ_MASK_INIT 0x80000000 -struct posix_cond { - _wait_q_t wait_q; -}; - enum pthread_state { /* The thread is running and detached. */ PTHREAD_DETACHED = PTHREAD_CREATE_DETACHED, @@ -97,10 +93,10 @@ struct k_mutex *to_posix_mutex(pthread_mutex_t *mu); struct k_mutex *get_posix_mutex(pthread_mutex_t mut); /* get and possibly initialize a posix_cond */ -struct posix_cond *to_posix_cond(pthread_cond_t *cvar); +struct k_condvar *to_posix_cond(pthread_cond_t *cvar); /* get a previously initialized posix_cond */ -struct posix_cond *get_posix_cond(pthread_cond_t cond); +struct k_condvar *get_posix_cond(pthread_cond_t cond); /* get and possibly initialize a posix_key */ pthread_key_obj *to_posix_key(pthread_key_t *keyp); diff --git a/lib/posix/pthread_cond.c b/lib/posix/pthread_cond.c index 5c038b69170a..0332f99763f0 100644 --- a/lib/posix/pthread_cond.c +++ b/lib/posix/pthread_cond.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -12,11 +13,9 @@ #include "posix_internal.h" -extern struct k_spinlock z_pthread_spinlock; - int64_t timespec_to_timeoutms(const struct timespec *abstime); -static struct posix_cond posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; +static struct k_condvar posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT); /* @@ -27,7 +26,7 @@ SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT); BUILD_ASSERT(CONFIG_MAX_PTHREAD_COND_COUNT < PTHREAD_OBJ_MASK_INIT, "CONFIG_MAX_PTHREAD_COND_COUNT is too high"); -static inline size_t posix_cond_to_offset(struct posix_cond *cv) +static inline size_t posix_cond_to_offset(struct k_condvar *cv) { return cv - posix_cond_pool; } @@ -37,7 +36,7 @@ static inline size_t to_posix_cond_idx(pthread_cond_t cond) return mark_pthread_obj_uninitialized(cond); } -struct posix_cond *get_posix_cond(pthread_cond_t cond) +struct k_condvar *get_posix_cond(pthread_cond_t cond) { int actually_initialized; size_t bit = to_posix_cond_idx(cond); @@ -60,10 +59,10 @@ struct posix_cond *get_posix_cond(pthread_cond_t cond) return &posix_cond_pool[bit]; } -struct posix_cond *to_posix_cond(pthread_cond_t *cvar) +struct k_condvar *to_posix_cond(pthread_cond_t *cvar) { size_t bit; - struct posix_cond *cv; + struct k_condvar *cv; if (*cvar != PTHREAD_COND_INITIALIZER) { return get_posix_cond(*cvar); @@ -89,7 +88,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time { int ret; k_spinlock_key_t key; - struct posix_cond *cv; + struct k_condvar *cv; struct k_mutex *m; key = k_spin_lock(&z_pthread_spinlock); @@ -127,7 +126,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time int pthread_cond_signal(pthread_cond_t *cvar) { k_spinlock_key_t key; - struct posix_cond *cv; + struct k_condvar *cv; key = k_spin_lock(&z_pthread_spinlock); @@ -147,7 +146,7 @@ int pthread_cond_signal(pthread_cond_t *cvar) int pthread_cond_broadcast(pthread_cond_t *cvar) { k_spinlock_key_t key; - struct posix_cond *cv; + struct k_condvar *cv; key = k_spin_lock(&z_pthread_spinlock); @@ -177,7 +176,7 @@ int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struc int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) { k_spinlock_key_t key; - struct posix_cond *cv; + struct k_condvar *cv; ARG_UNUSED(att); *cvar = PTHREAD_COND_INITIALIZER; @@ -199,7 +198,7 @@ int pthread_cond_destroy(pthread_cond_t *cvar) { __unused int rc; k_spinlock_key_t key; - struct posix_cond *cv; + struct k_condvar *cv; pthread_cond_t c = *cvar; size_t bit = to_posix_cond_idx(c); @@ -218,3 +217,17 @@ int pthread_cond_destroy(pthread_cond_t *cvar) return 0; } + +static int pthread_cond_pool_init(void) +{ + int err; + size_t i; + + for (i = 0; i < CONFIG_MAX_PTHREAD_COND_COUNT; ++i) { + err = k_condvar_init(&posix_cond_pool[i]); + __ASSERT_NO_MSG(err == 0); + } + + return 0; +} +SYS_INIT(pthread_cond_pool_init, PRE_KERNEL_1, 0); From 85e18746b83b908d6d8432719b3108048f23df9e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 6 Jun 2023 07:40:50 -0400 Subject: [PATCH 0057/2042] posix: pthread: rework pthreads to use zephyr api Previously, pthreads suffered from some race conditions. This was almost inevitable given that it was maintained in parallel to Zephyr's threading and synchronization API. The unfortunate side-effect of with that is that it did not receive the reliability and other improvements that `k_thread`s did. Here, we perform a significant update of pthread code so that it depends directly on public Zephyr API. With that, we reuse as many concepts as possible and pthreads benefits for free from any improvement made to Zephyr's threading and synchronization APIs. Included with this change, we * implement state with `ready_q`, `run_q`, and `done_q` * use `pthread_barrier_wait()` to sync `pthread_create()` * synchronize internal state with a spinlock These pthreads are considerably more reliable than before. Signed-off-by: Christopher Friedt --- lib/posix/posix_internal.h | 38 ++- lib/posix/pthread.c | 464 ++++++++++++++++++++++--------------- lib/posix/pthread_cond.c | 97 +++----- lib/posix/pthread_mutex.c | 142 +++++------- 4 files changed, 384 insertions(+), 357 deletions(-) diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 3d22000788a4..4ce90a50d686 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -7,7 +7,13 @@ #ifndef ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ #define ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ +#include +#include + #include +#include +#include +#include /* * Bit used to mark a pthread object as initialized. Initialization status is @@ -15,20 +21,12 @@ */ #define PTHREAD_OBJ_MASK_INIT 0x80000000 -enum pthread_state { - /* The thread is running and detached. */ - PTHREAD_DETACHED = PTHREAD_CREATE_DETACHED, - /* The thread is running and joinable. */ - PTHREAD_JOINABLE = PTHREAD_CREATE_JOINABLE, - /* The thread structure is unallocated and available for reuse. */ - PTHREAD_TERMINATED, - /* A joinable thread exited and its return code is available. */ - PTHREAD_EXITED -}; - struct posix_thread { struct k_thread thread; + /* List node for ready_q, run_q, or done_q */ + sys_dnode_t q_node; + /* List of keys that thread has called pthread_setspecific() on */ sys_slist_t key_list; @@ -36,14 +34,14 @@ struct posix_thread { void *retval; /* Pthread cancellation */ - int cancel_state; - int cancel_pending; - struct k_spinlock cancel_lock; - - /* Pthread State */ - enum pthread_state state; - pthread_mutex_t state_lock; - pthread_cond_t state_cond; + uint8_t cancel_state; + bool cancel_pending; + + /* Detach state */ + uint8_t detachstate; + + /* Queue ID (internal-only) */ + uint8_t qid; }; typedef struct pthread_key_obj { @@ -84,7 +82,7 @@ static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj) return obj & ~PTHREAD_OBJ_MASK_INIT; } -struct posix_thread *to_posix_thread(pthread_t pthread); +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); diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index ab28b22e1ef7..407e8ecbd8c8 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -16,10 +16,31 @@ #include "posix_internal.h" #include "pthread_sched.h" -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *) -1) +#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +#define PTHREAD_CANCELED ((void *)-1) + +enum posix_thread_qid { + /* ready to be started via pthread_create() */ + POSIX_THREAD_READY_Q, + /* running */ + POSIX_THREAD_RUN_Q, + /* exited (either joinable or detached) */ + POSIX_THREAD_DONE_Q, +}; + +BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && + (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1)); + +BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) && + (PTHREAD_CANCEL_ENABLE == 1 || PTHREAD_CANCEL_DISABLE == 1)); + +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 struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; +static struct k_spinlock pthread_pool_lock; -K_MUTEX_DEFINE(pthread_once_lock); +static K_MUTEX_DEFINE(pthread_once_lock); static const struct pthread_attr init_pthread_attrs = { .priority = 0, @@ -36,23 +57,70 @@ static const struct pthread_attr init_pthread_attrs = { .initialized = true, }; -static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; -static struct k_spinlock pthread_pool_lock; +/* + * We reserve the MSB to mark a pthread_t as initialized (from the + * perspective of the application). With a linear space, this means that + * the theoretical pthread_t range is [0,2147483647]. + */ +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT < PTHREAD_OBJ_MASK_INIT, + "CONFIG_MAX_PTHREAD_COUNT is too high"); -pthread_t pthread_self(void) +static inline size_t posix_thread_to_offset(struct posix_thread *t) { - return (struct posix_thread *) - CONTAINER_OF(k_current_get(), struct posix_thread, thread) - - posix_thread_pool; + return t - posix_thread_pool; +} + +static inline size_t get_posix_thread_idx(pthread_t pth) +{ + return mark_pthread_obj_uninitialized(pth); } struct posix_thread *to_posix_thread(pthread_t pthread) { - if (pthread >= CONFIG_MAX_PTHREAD_COUNT) { + k_spinlock_key_t key; + struct posix_thread *t; + bool actually_initialized; + size_t bit = get_posix_thread_idx(pthread); + + /* if the provided thread does not claim to be initialized, its invalid */ + if (!is_pthread_obj_initialized(pthread)) { + return NULL; + } + + if (bit >= CONFIG_MAX_PTHREAD_COUNT) { return NULL; } - return &posix_thread_pool[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 + * 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)); + k_spin_unlock(&pthread_pool_lock, key); + + if (!actually_initialized) { + /* The thread claims to be initialized but is actually not */ + return NULL; + } + + return &posix_thread_pool[bit]; +} + +pthread_t pthread_self(void) +{ + size_t bit; + struct posix_thread *t; + + t = (struct posix_thread *)CONTAINER_OF(k_current_get(), struct posix_thread, thread); + bit = posix_thread_to_offset(t); + + return mark_pthread_obj_initialized(bit); } static bool is_posix_policy_prio_valid(uint32_t priority, int policy) @@ -89,7 +157,7 @@ static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) if (policy == SCHED_FIFO) { /* Zephyr COOP priority starts from -1 */ __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); - prio = -1 * (priority + 1); + prio = -1 * (priority + 1); } else { __ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES); prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1); @@ -135,12 +203,75 @@ 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) +{ + /* + * FIXME: Pthread attribute must be non-null and it provides stack + * pointer and stack size. So even though POSIX 1003.1 spec accepts + * attrib as NULL but zephyr needs it initialized with valid stack. + */ + if (attr == NULL || attr->initialized == 0U || attr->stack == NULL || + attr->stacksize == 0) { + return false; + } + + /* require a valid scheduler policy */ + if (!valid_posix_policy(attr->schedpolicy)) { + return false; + } + + /* require a valid detachstate */ + if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE || + attr->detachstate == PTHREAD_CREATE_DETACHED)) { + return false; + } + + /* we cannot create an essential thread (i.e. one that may not abort) */ + if ((attr->flags & K_ESSENTIAL) != 0) { + return false; + } + + return true; +} + +static void posix_thread_finalize(struct posix_thread *t, void *retval) +{ + sys_snode_t *node_l; + k_spinlock_key_t key; + pthread_key_obj *key_obj; + pthread_thread_data *thread_spec_data; + + SYS_SLIST_FOR_EACH_NODE(&t->key_list, node_l) { + thread_spec_data = (pthread_thread_data *)node_l; + if (thread_spec_data != NULL) { + key_obj = thread_spec_data->key; + if (key_obj->destructor != NULL) { + (key_obj->destructor)(thread_spec_data->spec_data); + } + } + } + + /* 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; + t->retval = retval; + k_spin_unlock(&pthread_pool_lock, key); + + /* abort the underlying k_thread */ + k_thread_abort(&t->thread); +} + +FUNC_NORETURN static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) { - void * (*fun_ptr)(void *) = arg3; + void *(*fun_ptr)(void *arg) = arg2; + struct posix_thread *t = CONTAINER_OF(k_current_get(), struct posix_thread, thread); + + posix_thread_finalize(t, fun_ptr(arg1)); - fun_ptr(arg1); - pthread_exit(NULL); + CODE_UNREACHABLE; } /** @@ -151,73 +282,65 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) * * See IEEE 1003.1 */ -int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr, - void *(*threadroutine)(void *), void *arg) +int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadroutine)(void *), + void *arg) { - int rv; - int32_t prio; k_spinlock_key_t key; - uint32_t pthread_num; - k_spinlock_key_t cancel_key; - pthread_condattr_t cond_attr; - struct posix_thread *thread; + struct posix_thread *safe_t; + struct posix_thread *t = NULL; const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - /* - * FIXME: Pthread attribute must be non-null and it provides stack - * pointer and stack size. So even though POSIX 1003.1 spec accepts - * attrib as NULL but zephyr needs it initialized with valid stack. - */ - if ((attr == NULL) || (attr->initialized == 0U) - || (attr->stack == NULL) || (attr->stacksize == 0)) { + if (!pthread_attr_is_valid(attr)) { return EINVAL; } key = k_spin_lock(&pthread_pool_lock); - for (pthread_num = 0; - pthread_num < CONFIG_MAX_PTHREAD_COUNT; pthread_num++) { - thread = &posix_thread_pool[pthread_num]; - if (thread->state == PTHREAD_EXITED || thread->state == PTHREAD_TERMINATED) { - thread->state = PTHREAD_JOINABLE; + if (!sys_dlist_is_empty(&ready_q)) { + /* spawn thread 't' directly from ready_q */ + t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); + } else { + SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&done_q, t, safe_t, q_node) { + if (t->detachstate == PTHREAD_CREATE_JOINABLE) { + /* thread has not been joined yet */ + continue; + } + + /* spawn thread 't' from done_q */ + sys_dlist_remove(&t->q_node); break; } } - k_spin_unlock(&pthread_pool_lock, key); - if (pthread_num >= CONFIG_MAX_PTHREAD_COUNT) { - return EAGAIN; + if (t != NULL) { + /* initialize thread state */ + 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_pending = false; + sys_slist_init(&t->key_list); } + k_spin_unlock(&pthread_pool_lock, key); - rv = pthread_mutex_init(&thread->state_lock, NULL); - if (rv != 0) { - key = k_spin_lock(&pthread_pool_lock); - thread->state = PTHREAD_EXITED; - k_spin_unlock(&pthread_pool_lock, key); - return rv; + if (t == NULL) { + /* no threads are ready */ + return EAGAIN; } - prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy); - - cancel_key = k_spin_lock(&thread->cancel_lock); - thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags; - thread->cancel_pending = 0; - k_spin_unlock(&thread->cancel_lock, cancel_key); - - pthread_mutex_lock(&thread->state_lock); - thread->state = attr->detachstate; - pthread_mutex_unlock(&thread->state_lock); + /* spawn the thread */ + k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, + (void *)arg, threadroutine, NULL, + posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags, + K_MSEC(attr->delayedstart)); - pthread_cond_init(&thread->state_cond, &cond_attr); - sys_slist_init(&thread->key_list); + /* finally provide the initialized thread to the caller */ + *th = mark_pthread_obj_initialized(posix_thread_to_offset(t)); - *newthread = pthread_num; - k_thread_create(&thread->thread, attr->stack, attr->stacksize, - (k_thread_entry_t)zephyr_thread_wrapper, (void *)arg, NULL, threadroutine, - prio, (~K_ESSENTIAL & attr->flags), K_MSEC(attr->delayedstart)); return 0; } - /** * @brief Set cancelability State. * @@ -226,22 +349,26 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *_attr, int pthread_setcancelstate(int state, int *oldstate) { bool cancel_pending; - k_spinlock_key_t cancel_key; - struct posix_thread *pthread = to_posix_thread(pthread_self()); + k_spinlock_key_t key; + struct posix_thread *t; + + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) { + return EINVAL; + } - if (state != PTHREAD_CANCEL_ENABLE && - state != PTHREAD_CANCEL_DISABLE) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { return EINVAL; } - cancel_key = k_spin_lock(&pthread->cancel_lock); - *oldstate = pthread->cancel_state; - pthread->cancel_state = state; - cancel_pending = pthread->cancel_pending; - k_spin_unlock(&pthread->cancel_lock, cancel_key); + key = k_spin_lock(&pthread_pool_lock); + *oldstate = t->cancel_state; + t->cancel_state = state; + cancel_pending = t->cancel_pending; + k_spin_unlock(&pthread_pool_lock, key); if (state == PTHREAD_CANCEL_ENABLE && cancel_pending) { - pthread_exit((void *)PTHREAD_CANCELED); + posix_thread_finalize(t, PTHREAD_CANCELED); } return 0; @@ -254,31 +381,22 @@ int pthread_setcancelstate(int state, int *oldstate) */ int pthread_cancel(pthread_t pthread) { - struct posix_thread *thread = to_posix_thread(pthread); int cancel_state; - k_spinlock_key_t cancel_key; + k_spinlock_key_t key; + struct posix_thread *t; - if ((thread == NULL) || (thread->state == PTHREAD_TERMINATED)) { + t = to_posix_thread(pthread); + if (t == NULL) { return ESRCH; } - cancel_key = k_spin_lock(&thread->cancel_lock); - thread->cancel_pending = 1; - cancel_state = thread->cancel_state; - k_spin_unlock(&thread->cancel_lock, cancel_key); + key = k_spin_lock(&pthread_pool_lock); + t->cancel_pending = true; + cancel_state = t->cancel_state; + k_spin_unlock(&pthread_pool_lock, key); if (cancel_state == PTHREAD_CANCEL_ENABLE) { - pthread_mutex_lock(&thread->state_lock); - if (thread->state == PTHREAD_DETACHED) { - thread->state = PTHREAD_TERMINATED; - } else { - thread->retval = PTHREAD_CANCELED; - thread->state = PTHREAD_EXITED; - pthread_cond_broadcast(&thread->state_cond); - } - pthread_mutex_unlock(&thread->state_lock); - - k_thread_abort(&thread->thread); + posix_thread_finalize(t, PTHREAD_CANCELED); } return 0; @@ -289,13 +407,12 @@ int pthread_cancel(pthread_t pthread) * * See IEEE 1003.1 */ -int pthread_setschedparam(pthread_t pthread, int policy, - const struct sched_param *param) +int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) { - struct posix_thread *thread = to_posix_thread(pthread); + struct posix_thread *t = to_posix_thread(pthread); int new_prio; - if (thread == NULL) { + if (t == NULL) { return ESRCH; } @@ -309,7 +426,7 @@ int pthread_setschedparam(pthread_t pthread, int policy, new_prio = posix_to_zephyr_priority(param->sched_priority, policy); - k_thread_priority_set(&thread->thread, new_prio); + k_thread_priority_set(&t->thread, new_prio); return 0; } @@ -335,17 +452,17 @@ int pthread_attr_init(pthread_attr_t *attr) * * See IEEE 1003.1 */ -int pthread_getschedparam(pthread_t pthread, int *policy, - struct sched_param *param) +int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) { - struct posix_thread *thread = to_posix_thread(pthread); uint32_t priority; + struct posix_thread *t; - if ((thread == NULL) || (thread->state == PTHREAD_TERMINATED)) { + t = to_posix_thread(pthread); + if (t == NULL) { return ESRCH; } - priority = k_thread_priority_get(&thread->thread); + priority = k_thread_priority_get(&t->thread); param->sched_priority = zephyr_to_posix_priority(priority, policy); return 0; @@ -375,47 +492,26 @@ int pthread_once(pthread_once_t *once, void (*init_func)(void)) * * See IEEE 1003.1 */ +FUNC_NORETURN void pthread_exit(void *retval) { - k_spinlock_key_t cancel_key; - struct posix_thread *self = to_posix_thread(pthread_self()); - pthread_key_obj *key_obj; - pthread_thread_data *thread_spec_data; - sys_snode_t *node_l; - - /* Make a thread as cancelable before exiting */ - cancel_key = k_spin_lock(&self->cancel_lock); - if (self->cancel_state == PTHREAD_CANCEL_DISABLE) { - self->cancel_state = PTHREAD_CANCEL_ENABLE; - } - - k_spin_unlock(&self->cancel_lock, cancel_key); - - pthread_mutex_lock(&self->state_lock); - if (self->state == PTHREAD_JOINABLE) { - self->state = PTHREAD_EXITED; - self->retval = retval; - pthread_cond_broadcast(&self->state_cond); - } else { - self->state = PTHREAD_TERMINATED; - } + k_spinlock_key_t key; + struct posix_thread *self; - SYS_SLIST_FOR_EACH_NODE(&self->key_list, node_l) { - thread_spec_data = (pthread_thread_data *)node_l; - if (thread_spec_data != NULL) { - key_obj = thread_spec_data->key; - if (key_obj->destructor != NULL) { - (key_obj->destructor)(thread_spec_data->spec_data); - } - } + self = to_posix_thread(pthread_self()); + if (self == NULL) { + /* not a valid posix_thread */ + __ASSERT_NO_MSG(self != NULL); + k_thread_abort(k_current_get()); } - pthread_mutex_unlock(&self->state_lock); - pthread_mutex_destroy(&self->state_lock); - - pthread_cond_destroy(&self->state_cond); + /* Make a thread as cancelable before exiting */ + key = k_spin_lock(&pthread_pool_lock); + self->cancel_state = PTHREAD_CANCEL_ENABLE; + k_spin_unlock(&pthread_pool_lock, key); - k_thread_abort((k_tid_t)self); + posix_thread_finalize(self, retval); + CODE_UNREACHABLE; } /** @@ -423,41 +519,46 @@ void pthread_exit(void *retval) * * See IEEE 1003.1 */ -int pthread_join(pthread_t thread, void **status) +int pthread_join(pthread_t pthread, void **status) { - struct posix_thread *pthread = to_posix_thread(thread); - int ret = 0; + int err; + int ret; + k_spinlock_key_t key; + struct posix_thread *t; - if (thread == pthread_self()) { + if (pthread == pthread_self()) { return EDEADLK; } - if (pthread == NULL) { + t = to_posix_thread(pthread); + if (t == NULL) { return ESRCH; } - pthread_mutex_lock(&pthread->state_lock); - - if (pthread->state == PTHREAD_JOINABLE) { - pthread_cond_wait(&pthread->state_cond, &pthread->state_lock); - } - - if (pthread->state == PTHREAD_EXITED) { - if (status != NULL) { - *status = pthread->retval; - } - } else if (pthread->state == PTHREAD_DETACHED) { + ret = 0; + key = k_spin_lock(&pthread_pool_lock); + if (t->detachstate != PTHREAD_CREATE_JOINABLE) { ret = EINVAL; - } else { + } else if (t->qid == POSIX_THREAD_READY_Q) { + /* marginal chance thread has moved to ready_q between to_posix_thread() and here */ ret = ESRCH; + } else { + /* + * 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; + ret = 0; } + k_spin_unlock(&pthread_pool_lock, key); - pthread_mutex_unlock(&pthread->state_lock); - if (pthread->state == PTHREAD_EXITED) { - pthread_mutex_destroy(&pthread->state_lock); + if (ret == 0) { + err = k_thread_join(&t->thread, K_FOREVER); + /* other possibilities? */ + __ASSERT_NO_MSG(err == 0); } - return ret; + return 0; } /** @@ -465,40 +566,28 @@ int pthread_join(pthread_t thread, void **status) * * See IEEE 1003.1 */ -int pthread_detach(pthread_t thread) +int pthread_detach(pthread_t pthread) { - struct posix_thread *pthread = to_posix_thread(thread); - int ret = 0; + int ret; + k_spinlock_key_t key; + struct posix_thread *t; + enum posix_thread_qid qid; - if (pthread == NULL) { + t = to_posix_thread(pthread); + if (t == NULL) { return ESRCH; } - pthread_mutex_lock(&pthread->state_lock); - - switch (pthread->state) { - case PTHREAD_JOINABLE: - pthread->state = PTHREAD_DETACHED; - /* Broadcast the condition. - * This will make threads waiting to join this thread continue. - */ - pthread_cond_broadcast(&pthread->state_cond); - break; - case PTHREAD_EXITED: - pthread->state = PTHREAD_TERMINATED; - /* THREAD has already exited. - * Pthread remained to provide exit status. - */ - break; - case PTHREAD_TERMINATED: - ret = ESRCH; - break; - default: + key = k_spin_lock(&pthread_pool_lock); + qid = t->qid; + if (qid == POSIX_THREAD_READY_Q || t->detachstate != PTHREAD_CREATE_JOINABLE) { ret = EINVAL; - break; + } else { + ret = 0; + t->detachstate = PTHREAD_CREATE_DETACHED; } + k_spin_unlock(&pthread_pool_lock, key); - pthread_mutex_unlock(&pthread->state_lock); return ret; } @@ -529,8 +618,7 @@ 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)) { + (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) { return EINVAL; } @@ -538,7 +626,6 @@ int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) return 0; } - /** * @brief Get scheduling policy attribute in Thread attributes. * @@ -556,7 +643,6 @@ int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) return 0; } - /** * @brief Set scheduling policy attribute in Thread attributes object. * @@ -589,7 +675,6 @@ int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) *stacksize = attr->stacksize; return 0; - } /** @@ -670,6 +755,7 @@ int pthread_setname_np(pthread_t thread, const char *name) #ifdef CONFIG_THREAD_NAME k_tid_t kthread; + thread = get_posix_thread_idx(thread); if (thread >= CONFIG_MAX_PTHREAD_COUNT) { return ESRCH; } @@ -693,6 +779,7 @@ int pthread_getname_np(pthread_t thread, char *name, size_t len) #ifdef CONFIG_THREAD_NAME k_tid_t kthread; + thread = get_posix_thread_idx(thread); if (thread >= CONFIG_MAX_PTHREAD_COUNT) { return ESRCH; } @@ -703,7 +790,7 @@ int pthread_getname_np(pthread_t thread, char *name, size_t len) memset(name, '\0', len); kthread = &posix_thread_pool[thread].thread; - return k_thread_name_copy(kthread, name, len-1); + return k_thread_name_copy(kthread, name, len - 1); #else ARG_UNUSED(thread); ARG_UNUSED(name); @@ -716,9 +803,8 @@ static int posix_thread_pool_init(void) { size_t i; - for (i = 0; i < CONFIG_MAX_PTHREAD_COUNT; ++i) { - posix_thread_pool[i].state = PTHREAD_EXITED; + sys_dlist_append(&ready_q, &posix_thread_pool[i].q_node); } return 0; diff --git a/lib/posix/pthread_cond.c b/lib/posix/pthread_cond.c index 0332f99763f0..9f808b9e97d2 100644 --- a/lib/posix/pthread_cond.c +++ b/lib/posix/pthread_cond.c @@ -78,87 +78,70 @@ struct k_condvar *to_posix_cond(pthread_cond_t *cvar) *cvar = mark_pthread_obj_initialized(bit); cv = &posix_cond_pool[bit]; - /* Initialize the condition variable here */ - z_waitq_init(&cv->wait_q); - return cv; } static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t timeout) { int ret; - k_spinlock_key_t key; - struct k_condvar *cv; struct k_mutex *m; + struct k_condvar *cv; - key = k_spin_lock(&z_pthread_spinlock); m = to_posix_mutex(mu); - if (m == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); + cv = to_posix_cond(cond); + if (cv == NULL || m == NULL) { return EINVAL; } - cv = to_posix_cond(cond); - if (cv == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); - return EINVAL; + ret = k_condvar_wait(cv, m, timeout); + if (ret == -EAGAIN) { + ret = ETIMEDOUT; + } else if (ret < 0) { + ret = -ret; + } else { + __ASSERT_NO_MSG(ret == 0); } - __ASSERT_NO_MSG(m->lock_count == 1U); - m->lock_count = 0U; - m->owner = NULL; - _ready_one_thread(&m->wait_q); - ret = z_sched_wait(&z_pthread_spinlock, key, &cv->wait_q, timeout, NULL); - - /* FIXME: this extra lock (and the potential context switch it - * can cause) could be optimized out. At the point of the - * signal/broadcast, it's possible to detect whether or not we - * will be swapping back to this particular thread and lock it - * (i.e. leave the lock variable unchanged) on our behalf. - * But that requires putting scheduler intelligence into this - * higher level abstraction and is probably not worth it. - */ - pthread_mutex_lock(mu); - - return ret == -EAGAIN ? ETIMEDOUT : ret; + return ret; } int pthread_cond_signal(pthread_cond_t *cvar) { - k_spinlock_key_t key; + int ret; struct k_condvar *cv; - key = k_spin_lock(&z_pthread_spinlock); - cv = to_posix_cond(cvar); if (cv == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } - k_spin_unlock(&z_pthread_spinlock, key); + ret = k_condvar_signal(cv); + if (ret < 0) { + return -ret; + } - z_sched_wake(&cv->wait_q, 0, NULL); + __ASSERT_NO_MSG(ret == 0); return 0; } int pthread_cond_broadcast(pthread_cond_t *cvar) { - k_spinlock_key_t key; + int ret; struct k_condvar *cv; - key = k_spin_lock(&z_pthread_spinlock); - - cv = to_posix_cond(cvar); + cv = get_posix_cond(*cvar); if (cv == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } - k_spin_unlock(&z_pthread_spinlock, key); + ret = k_condvar_broadcast(cv); + if (ret < 0) { + return -ret; + } + + __ASSERT_NO_MSG(ret >= 0); - z_sched_wake_all(&cv->wait_q, 0, NULL); return 0; } @@ -169,51 +152,41 @@ int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut) int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime) { - int32_t timeout = (int32_t)timespec_to_timeoutms(abstime); - return cond_wait(cv, mut, K_MSEC(timeout)); + return cond_wait(cv, mut, K_MSEC((int32_t)timespec_to_timeoutms(abstime))); } int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) { - k_spinlock_key_t key; struct k_condvar *cv; ARG_UNUSED(att); *cvar = PTHREAD_COND_INITIALIZER; - key = k_spin_lock(&z_pthread_spinlock); - + /* calls k_condvar_init() */ cv = to_posix_cond(cvar); if (cv == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); - return EINVAL; + return ENOMEM; } - k_spin_unlock(&z_pthread_spinlock, key); - return 0; } int pthread_cond_destroy(pthread_cond_t *cvar) { - __unused int rc; - k_spinlock_key_t key; + int err; + size_t bit; struct k_condvar *cv; - pthread_cond_t c = *cvar; - size_t bit = to_posix_cond_idx(c); - - key = k_spin_lock(&z_pthread_spinlock); - cv = get_posix_cond(c); + cv = get_posix_cond(*cvar); if (cv == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } - rc = sys_bitarray_free(&posix_cond_bitarray, 1, bit); - __ASSERT(rc == 0, "failed to free bit %zu", bit); + bit = posix_cond_to_offset(cv); + err = sys_bitarray_free(&posix_cond_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); - k_spin_unlock(&z_pthread_spinlock, key); + *cvar = -1; return 0; } diff --git a/lib/posix/pthread_mutex.c b/lib/posix/pthread_mutex.c index a9b1984e1ac9..182a237589d1 100644 --- a/lib/posix/pthread_mutex.c +++ b/lib/posix/pthread_mutex.c @@ -4,16 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_internal.h" + #include #include -#include -#include #include #include -#include "posix_internal.h" - -struct k_spinlock z_pthread_spinlock; +static struct k_spinlock pthread_mutex_spinlock; int64_t timespec_to_timeoutms(const struct timespec *abstime); @@ -73,6 +71,7 @@ struct k_mutex *get_posix_mutex(pthread_mutex_t mu) struct k_mutex *to_posix_mutex(pthread_mutex_t *mu) { + int err; size_t bit; struct k_mutex *m; @@ -92,10 +91,8 @@ struct k_mutex *to_posix_mutex(pthread_mutex_t *mu) /* Initialize the posix_mutex */ m = &posix_mutex_pool[bit]; - m->owner = NULL; - m->lock_count = 0U; - - z_waitq_init(&m->wait_q); + err = k_mutex_init(m); + __ASSERT_NO_MSG(err == 0); return m; } @@ -103,53 +100,59 @@ struct k_mutex *to_posix_mutex(pthread_mutex_t *mu) static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout) { int type; - int rc = 0; size_t bit; - k_spinlock_key_t key; + int ret = 0; struct k_mutex *m; - - key = k_spin_lock(&z_pthread_spinlock); + k_spinlock_key_t key; m = to_posix_mutex(mu); if (m == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } bit = posix_mutex_to_offset(m); - if (m->lock_count == 0U && m->owner == NULL) { - m->lock_count++; - m->owner = k_current_get(); - - k_spin_unlock(&z_pthread_spinlock, key); - return 0; - } else if (m->owner == k_current_get()) { - type = posix_mutex_type[bit]; - if (type == PTHREAD_MUTEX_RECURSIVE && - m->lock_count < MUTEX_MAX_REC_LOCK) { - m->lock_count++; - rc = 0; - } else if (type == PTHREAD_MUTEX_ERRORCHECK) { - rc = EDEADLK; - } else { - rc = EINVAL; + type = posix_mutex_type[bit]; + + key = k_spin_lock(&pthread_mutex_spinlock); + if (m->owner == k_current_get()) { + switch (type) { + case PTHREAD_MUTEX_NORMAL: + if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { + ret = EBUSY; + break; + } + /* On most POSIX systems, this usually results in an infinite loop */ + k_spin_unlock(&pthread_mutex_spinlock, key); + do { + (void)k_sleep(K_FOREVER); + } while (true); + CODE_UNREACHABLE; + break; + case PTHREAD_MUTEX_RECURSIVE: + if (m->lock_count >= MUTEX_MAX_REC_LOCK) { + ret = EAGAIN; + } + break; + case PTHREAD_MUTEX_ERRORCHECK: + ret = EDEADLK; + break; + default: + __ASSERT(false, "invalid pthread type %d", type); + ret = EINVAL; + break; } - - k_spin_unlock(&z_pthread_spinlock, key); - return rc; } + k_spin_unlock(&pthread_mutex_spinlock, key); - if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - k_spin_unlock(&z_pthread_spinlock, key); - return EINVAL; + if (ret == 0) { + ret = k_mutex_lock(m, timeout); } - rc = z_pend_curr(&z_pthread_spinlock, key, &m->wait_q, timeout); - if (rc != 0) { - rc = ETIMEDOUT; + if (ret < 0) { + ret = -ret; } - return rc; + return ret; } /** @@ -184,15 +187,12 @@ int pthread_mutex_init(pthread_mutex_t *mu, const pthread_mutexattr_t *_attr) { size_t bit; struct k_mutex *m; - k_spinlock_key_t key; const struct pthread_mutexattr *attr = (const struct pthread_mutexattr *)_attr; *mu = PTHREAD_MUTEX_INITIALIZER; - key = k_spin_lock(&z_pthread_spinlock); m = to_posix_mutex(mu); if (m == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return ENOMEM; } @@ -203,8 +203,6 @@ int pthread_mutex_init(pthread_mutex_t *mu, const pthread_mutexattr_t *_attr) posix_mutex_type[bit] = attr->type; } - k_spin_unlock(&z_pthread_spinlock, key); - return 0; } @@ -226,45 +224,21 @@ int pthread_mutex_lock(pthread_mutex_t *m) */ int pthread_mutex_unlock(pthread_mutex_t *mu) { - k_tid_t thread; - k_spinlock_key_t key; + int ret; struct k_mutex *m; - pthread_mutex_t mut = *mu; - - key = k_spin_lock(&z_pthread_spinlock); - m = get_posix_mutex(mut); + m = get_posix_mutex(*mu); if (m == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } - if (m->owner != k_current_get()) { - k_spin_unlock(&z_pthread_spinlock, key); - return EPERM; - } - - if (m->lock_count == 0U) { - k_spin_unlock(&z_pthread_spinlock, key); - return EINVAL; + ret = k_mutex_unlock(m); + if (ret < 0) { + return -ret; } - m->lock_count--; - - if (m->lock_count == 0U) { - thread = z_unpend_first_thread(&m->wait_q); - if (thread) { - m->owner = thread; - m->lock_count++; - arch_thread_return_value_set(thread, 0); - z_ready_thread(thread); - z_reschedule(&z_pthread_spinlock, key); - return 0; - } - m->owner = NULL; + __ASSERT_NO_MSG(ret == 0); - } - k_spin_unlock(&z_pthread_spinlock, key); return 0; } @@ -275,23 +249,18 @@ int pthread_mutex_unlock(pthread_mutex_t *mu) */ int pthread_mutex_destroy(pthread_mutex_t *mu) { - __unused int rc; - k_spinlock_key_t key; + int err; + size_t bit; struct k_mutex *m; - pthread_mutex_t mut = *mu; - size_t bit = to_posix_mutex_idx(mut); - key = k_spin_lock(&z_pthread_spinlock); - m = get_posix_mutex(mut); + m = get_posix_mutex(*mu); if (m == NULL) { - k_spin_unlock(&z_pthread_spinlock, key); return EINVAL; } - rc = sys_bitarray_free(&posix_mutex_bitarray, 1, bit); - __ASSERT(rc == 0, "failed to free bit %zu", bit); - - k_spin_unlock(&z_pthread_spinlock, key); + bit = to_posix_mutex_idx(*mu); + err = sys_bitarray_free(&posix_mutex_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); return 0; } @@ -316,6 +285,7 @@ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int pthread_mutexattr_gettype(const pthread_mutexattr_t *_attr, int *type) { const struct pthread_mutexattr *attr = (const struct pthread_mutexattr *)_attr; + *type = attr->type; return 0; } From e1f8ea1ad7b66f9a112561a2e794f83ce27b47c8 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 8 Jun 2023 19:15:11 -0400 Subject: [PATCH 0058/2042] posix: pthread: add option for pthread_create() barrier To enable testing, introduce `CONFIG_PTHREAD_CREATE_BARRIER`. Some observations were made that running several Qemu SMP targets concurrently could lead to synchronization problems. On such targets, it was found that the synchronization issues were mitigated by introducing a `pthread_barrier_t` shared between `pthread_create()` and the spawned thread. It is suggested to enable the option when running many SMP tests concurrently in several parallel Qemu processes, e.g. with `twister`. Signed-off-by: Christopher Friedt --- lib/posix/Kconfig | 11 +++++++++++ lib/posix/pthread.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 30085e5abc60..f857a49462a2 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -35,6 +35,17 @@ config MAX_PTHREAD_COUNT help Maximum number of simultaneously active threads in a POSIX application. +config PTHREAD_CREATE_BARRIER + bool "Use a pthread_barrier_t to serialize pthread_create()" + help + When running several SMP applications in parallel instances of Qemu, + e.g. via twister, explicit serialization may be required between + pthread_create() and zephyr_thread_wrapper() when spawning and joining + many pthreads concurrently. + + On such systems, say Y here to introduce explicit serialization + via pthread_barrier_wait(). + config MAX_PTHREAD_MUTEX_COUNT int "Maximum simultaneously active mutex count in POSIX application" default 5 diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 407e8ecbd8c8..5a9d401bace5 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -266,9 +266,18 @@ static void posix_thread_finalize(struct posix_thread *t, void *retval) FUNC_NORETURN static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) { + int err; + int barrier; void *(*fun_ptr)(void *arg) = arg2; struct posix_thread *t = CONTAINER_OF(k_current_get(), struct posix_thread, thread); + if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + /* cross the barrier so that pthread_create() can continue */ + barrier = POINTER_TO_UINT(arg3); + err = pthread_barrier_wait(&barrier); + __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); + } + posix_thread_finalize(t, fun_ptr(arg1)); CODE_UNREACHABLE; @@ -285,7 +294,9 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadroutine)(void *), void *arg) { + int err; k_spinlock_key_t key; + pthread_barrier_t barrier; struct posix_thread *safe_t; struct posix_thread *t = NULL; const struct pthread_attr *attr = (const struct pthread_attr *)_attr; @@ -324,6 +335,19 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou } k_spin_unlock(&pthread_pool_lock, key); + if (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 */ + 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; + } + } + if (t == NULL) { /* no threads are ready */ return EAGAIN; @@ -331,10 +355,20 @@ 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, NULL, + (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)); + if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + /* wait for the spawned thread to cross our barrier */ + err = pthread_barrier_wait(&barrier); + __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); + err = pthread_barrier_destroy(&barrier); + __ASSERT_NO_MSG(err == 0); + } + /* finally provide the initialized thread to the caller */ *th = mark_pthread_obj_initialized(posix_thread_to_offset(t)); From d9bae7ce65ff8ecfe3bb6c1331001ff9821511a7 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 6 Jun 2023 20:23:08 -0400 Subject: [PATCH 0059/2042] tests: posix: improvements to pthread_pressure test * allow `qemu_cortex_a53` * disallow `qemu_leon3 * remove `TEST_DURATION_S` range * additional report formatting Signed-off-by: Christopher Friedt --- tests/posix/common/prj.conf | 2 -- tests/posix/pthread_pressure/Kconfig | 17 ++++------------- tests/posix/pthread_pressure/prj.conf | 8 ++++++++ tests/posix/pthread_pressure/src/main.c | 9 +++++++-- tests/posix/pthread_pressure/testcase.yaml | 3 +-- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tests/posix/common/prj.conf b/tests/posix/common/prj.conf index 109f72cef4a4..f72676270156 100644 --- a/tests/posix/common/prj.conf +++ b/tests/posix/common/prj.conf @@ -8,5 +8,3 @@ CONFIG_POSIX_MQUEUE=y CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_MAX_THREAD_BYTES=4 CONFIG_THREAD_NAME=y - -CONFIG_SMP=n diff --git a/tests/posix/pthread_pressure/Kconfig b/tests/posix/pthread_pressure/Kconfig index 536714064ed9..a26cea5cd7ca 100644 --- a/tests/posix/pthread_pressure/Kconfig +++ b/tests/posix/pthread_pressure/Kconfig @@ -9,21 +9,13 @@ config TEST_NUM_CPUS range 1 MP_NUM_CPUS default MP_NUM_CPUS help - The number of parallel threads to run during the test. The test - thread itself yields so that all cores have some probability of - causing racey behaviour. + The number of parallel threads to run during the test. config TEST_DURATION_S int "Number of seconds to run the test" - range 1 21600 default 5 help - Duration for the test, in seconds. The range has a reblatively high - upper bound because we should expect that pthread_create() and - pthread_join() are stable enough to run for an arbitrarily long - period of time without encountering any race conditions. - - Some exceptions apply, notably Qemu SMP targets. + Duration for the test, in seconds. config TEST_DELAY_US int "Microseconds to delay between pthread join and create" @@ -37,7 +29,7 @@ config TEST_STACK_SIZE default 512 if !64_BIT default 1024 if 64_BIT help - The minimal stack size required to run a no-op thread. + The minimal stack size required to run a minimal thread. config TEST_KTHREADS bool "Test k_threads" @@ -55,5 +47,4 @@ config TEST_EXTRA_ASSERTIONS bool "Add extra assertions into the hot path" default y help - On Qemu SMP targets, this can potentially lead to "scheduler noise" - leaking in from the host system, which can cause the test to fail. + This can be disabled for benchmarking. diff --git a/tests/posix/pthread_pressure/prj.conf b/tests/posix/pthread_pressure/prj.conf index d189ad86a680..9499b191c2df 100644 --- a/tests/posix/pthread_pressure/prj.conf +++ b/tests/posix/pthread_pressure/prj.conf @@ -1,3 +1,11 @@ CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_POSIX_API=y + +## Note: for benchmarking purposes, uncomment the Kconfig below +# CONFIG_TEST_DURATION_S=60 +# CONFIG_TEST_EXTRA_ASSERTIONS=n +# CONFIG_ASSERT=n + +## Optionally, uncomment this to only test pthreads: +# CONFIG_TEST_KTHREADS=n diff --git a/tests/posix/pthread_pressure/src/main.c b/tests/posix/pthread_pressure/src/main.c index f876d4bb29f7..adab1ba7ff7a 100644 --- a/tests/posix/pthread_pressure/src/main.c +++ b/tests/posix/pthread_pressure/src/main.c @@ -36,13 +36,16 @@ static bool alive[NUM_THREADS]; static K_THREAD_STACK_ARRAY_DEFINE(thread_stacks, NUM_THREADS, STACK_SIZE); static struct k_thread k_threads[NUM_THREADS]; -static size_t counters[NUM_THREADS]; +static uint64_t counters[NUM_THREADS]; +static uint64_t prev_counters[NUM_THREADS]; static void print_stats(uint64_t now, uint64_t end) { printk("now (ms): %llu end (ms): %llu\n", now, end); for (int i = 0; i < NUM_THREADS; ++i) { - printk("Thread %d created and joined %zu times\n", i, counters[i]); + printk("Thread %d created and joined %llu times (%llu joins/s)\n", i, counters[i], + (counters[i] - prev_counters[i]) / UPDATE_INTERVAL_S); + prev_counters[i] = counters[i]; } } @@ -55,6 +58,7 @@ static void test_create_join_common(const char *tag, create_fn create, join_fn j uint64_t update_ms = now_ms + MSEC_PER_SEC * UPDATE_INTERVAL_S; printk("BOARD: %s\n", CONFIG_BOARD); + printk("CONFIG_SMP: %s\n", IS_ENABLED(CONFIG_SMP) ? "y" : "n"); printk("NUM_THREADS: %u\n", NUM_THREADS); printk("TEST_NUM_CPUS: %u\n", CONFIG_TEST_NUM_CPUS); printk("TEST_DURATION_S: %u\n", CONFIG_TEST_DURATION_S); @@ -62,6 +66,7 @@ static void test_create_join_common(const char *tag, create_fn create, join_fn j for (i = 0; i < NUM_THREADS; ++i) { /* spawn thread i */ + prev_counters[i] = 0; ret = create(i); if (IS_ENABLED(CONFIG_TEST_EXTRA_ASSERTIONS)) { zassert_ok(ret, "%s_create(%d)[%zu] failed: %d", tag, i, counters[i], ret); diff --git a/tests/posix/pthread_pressure/testcase.yaml b/tests/posix/pthread_pressure/testcase.yaml index cca77f9179a3..ff0c2c32a2fb 100644 --- a/tests/posix/pthread_pressure/testcase.yaml +++ b/tests/posix/pthread_pressure/testcase.yaml @@ -6,7 +6,6 @@ common: integration_platforms: - qemu_riscv64_smp platform_exclude: - - qemu_cortex_a53 - - qemu_cortex_a53_smp + - qemu_leon3 tests: portability.posix.pthread_pressure: {} From 89cf4cea564966d3ae7fe87bb408196dc5426d80 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 3 Jun 2023 20:52:11 -0400 Subject: [PATCH 0060/2042] posix: pthread: mitigate include order sensitivity Previously, the `posix_internal.h` header needed to be exposed to the application because we had non-trivial details for most posix types (pthread, mutex, cond, ...). Since most of those have been simplified to a typedef'ed integer, we no longer need to expose that header to the applicaiton. Additionally, it means that we can adopt normalized header order in posix. Additionally, keep more implementation details hidden and prefer the static keyword on internal symbols where possible. Signed-off-by: Christopher Friedt --- include/zephyr/posix/pthread.h | 9 +++++---- include/zephyr/posix/pthread_key.h | 10 +++++----- lib/posix/posix_internal.h | 20 -------------------- lib/posix/pthread.c | 15 +++++++-------- lib/posix/pthread_barrier.c | 4 ++-- lib/posix/pthread_cond.c | 10 ++++------ lib/posix/pthread_key.c | 19 ++++++++++++------- lib/posix/pthread_mutex.c | 2 +- 8 files changed, 36 insertions(+), 53 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 0004aa94e079..e0822307083f 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -7,14 +7,15 @@ #ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ #define ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ +#include "pthread_key.h" + +#include +#include + #include #include #include -#include "posix_types.h" #include -#include "pthread_key.h" -#include -#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/posix/pthread_key.h b/include/zephyr/posix/pthread_key.h index 92f2ddaff3bd..025f29c6d33e 100644 --- a/include/zephyr/posix/pthread_key.h +++ b/include/zephyr/posix/pthread_key.h @@ -7,14 +7,14 @@ #ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ #define ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ -#ifdef CONFIG_PTHREAD_IPC -#include -#include +#include #ifdef __cplusplus extern "C" { #endif +#ifdef CONFIG_PTHREAD_IPC + #if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) typedef struct { int is_initialized; @@ -25,10 +25,10 @@ typedef struct { /* pthread_key */ typedef uint32_t pthread_key_t; +#endif /* CONFIG_PTHREAD_IPC */ + #ifdef __cplusplus } #endif -#endif /* CONFIG_PTHREAD_IPC */ - #endif /* ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_*/ diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index 4ce90a50d686..e3c2b2817125 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -62,11 +62,6 @@ typedef struct pthread_thread_data { void *spec_data; } pthread_thread_data; -typedef struct pthread_key_data { - sys_snode_t node; - pthread_thread_data thread_data; -} pthread_key_data; - static inline bool is_pthread_obj_initialized(uint32_t obj) { return (obj & PTHREAD_OBJ_MASK_INIT) != 0; @@ -87,19 +82,4 @@ 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); -/* get a previously initialized posix_mutex */ -struct k_mutex *get_posix_mutex(pthread_mutex_t mut); - -/* get and possibly initialize a posix_cond */ -struct k_condvar *to_posix_cond(pthread_cond_t *cvar); - -/* get a previously initialized posix_cond */ -struct k_condvar *get_posix_cond(pthread_cond_t cond); - -/* get and possibly initialize a posix_key */ -pthread_key_obj *to_posix_key(pthread_key_t *keyp); - -/* get a previously initialized posix_key */ -pthread_key_obj *get_posix_key(pthread_key_t key); - #endif diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 5a9d401bace5..30044420f1de 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -4,20 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_internal.h" +#include "pthread_sched.h" + +#include + #include #include -#include #include -#include -#include #include #include -#include "posix_internal.h" -#include "pthread_sched.h" - -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *)-1) +#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE +#define PTHREAD_CANCELED ((void *) -1) enum posix_thread_qid { /* ready to be started via pthread_create() */ diff --git a/lib/posix/pthread_barrier.c b/lib/posix/pthread_barrier.c index ead8d60c429b..2605efa2fb94 100644 --- a/lib/posix/pthread_barrier.c +++ b/lib/posix/pthread_barrier.c @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_internal.h" + #include #include #include #include -#include "posix_internal.h" - struct posix_barrier { struct k_mutex mutex; struct k_condvar cond; diff --git a/lib/posix/pthread_cond.c b/lib/posix/pthread_cond.c index 9f808b9e97d2..917900e2e98e 100644 --- a/lib/posix/pthread_cond.c +++ b/lib/posix/pthread_cond.c @@ -4,15 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_internal.h" + #include #include -#include -#include #include #include -#include "posix_internal.h" - int64_t timespec_to_timeoutms(const struct timespec *abstime); static struct k_condvar posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; @@ -36,7 +34,7 @@ static inline size_t to_posix_cond_idx(pthread_cond_t cond) return mark_pthread_obj_uninitialized(cond); } -struct k_condvar *get_posix_cond(pthread_cond_t cond) +static struct k_condvar *get_posix_cond(pthread_cond_t cond) { int actually_initialized; size_t bit = to_posix_cond_idx(cond); @@ -59,7 +57,7 @@ struct k_condvar *get_posix_cond(pthread_cond_t cond) return &posix_cond_pool[bit]; } -struct k_condvar *to_posix_cond(pthread_cond_t *cvar) +static struct k_condvar *to_posix_cond(pthread_cond_t *cvar) { size_t bit; struct k_condvar *cv; diff --git a/lib/posix/pthread_key.c b/lib/posix/pthread_key.c index 26ce4d8d4538..c181e69d8356 100644 --- a/lib/posix/pthread_key.c +++ b/lib/posix/pthread_key.c @@ -3,12 +3,17 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_internal.h" + #include #include #include #include -#include "posix_internal.h" +struct pthread_key_data { + sys_snode_t node; + pthread_thread_data thread_data; +}; static struct k_spinlock pthread_key_lock; @@ -36,7 +41,7 @@ static inline size_t to_posix_key_idx(pthread_key_t key) return mark_pthread_obj_uninitialized(key); } -pthread_key_obj *get_posix_key(pthread_key_t key) +static pthread_key_obj *get_posix_key(pthread_key_t key) { int actually_initialized; size_t bit = to_posix_key_idx(key); @@ -59,7 +64,7 @@ pthread_key_obj *get_posix_key(pthread_key_t key) return &posix_key_pool[bit]; } -pthread_key_obj *to_posix_key(pthread_key_t *key) +static pthread_key_obj *to_posix_key(pthread_key_t *key) { size_t bit; pthread_key_obj *k; @@ -115,7 +120,7 @@ int pthread_key_create(pthread_key_t *key, int pthread_key_delete(pthread_key_t key) { pthread_key_obj *key_obj; - pthread_key_data *key_data; + struct pthread_key_data *key_data; sys_snode_t *node_l, *next_node_l; k_spinlock_key_t key_key; @@ -132,7 +137,7 @@ int pthread_key_delete(pthread_key_t key) node_l, next_node_l) { /* Remove the object from the list key_data_l */ - key_data = (pthread_key_data *) + key_data = (struct pthread_key_data *) sys_slist_get(&(key_obj->key_data_l)); /* Deallocate the object's memory */ @@ -155,7 +160,7 @@ int pthread_setspecific(pthread_key_t key, const void *value) { pthread_key_obj *key_obj; struct posix_thread *thread = to_posix_thread(pthread_self()); - pthread_key_data *key_data; + struct pthread_key_data *key_data; pthread_thread_data *thread_spec_data; k_spinlock_key_t key_key; sys_snode_t *node_l; @@ -188,7 +193,7 @@ int pthread_setspecific(pthread_key_t key, const void *value) } if (node_l == NULL) { - key_data = k_malloc(sizeof(pthread_key_data)); + key_data = k_malloc(sizeof(struct pthread_key_data)); if (key_data == NULL) { retval = ENOMEM; diff --git a/lib/posix/pthread_mutex.c b/lib/posix/pthread_mutex.c index 182a237589d1..5264c39ebbe7 100644 --- a/lib/posix/pthread_mutex.c +++ b/lib/posix/pthread_mutex.c @@ -46,7 +46,7 @@ static inline size_t to_posix_mutex_idx(pthread_mutex_t mut) return mark_pthread_obj_uninitialized(mut); } -struct k_mutex *get_posix_mutex(pthread_mutex_t mu) +static struct k_mutex *get_posix_mutex(pthread_mutex_t mu) { int actually_initialized; size_t bit = to_posix_mutex_idx(mu); From 1d71fb765fd72f27c245e91d647703b17e7071b1 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 7 Jun 2023 11:26:33 -0400 Subject: [PATCH 0061/2042] doc: release: 3.4: add posix api release notes Add POSIX API release notes for v3.4.0. Signed-off-by: Christopher Friedt --- doc/releases/release-notes-3.4.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index c185710b5bde..7a6acd71de80 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -741,6 +741,21 @@ Libraries / Subsystems fs_mgmt, :kconfig:option:`CONFIG_FLASH` and :kconfig:option:`CONFIG_IMG_MANAGER` are needed to enable MCUmgr img_mgmt. +* POSIX API + + * Improved the locking strategy for :c:func:`eventfd_read()` and + :c:func:`eventfd_write()`. This eliminated a deadlock scenario that was + present since the initial contribution and increased performance by a + factor of 10x. + + * Reimplemented :ref:`POSIX ` threads, mutexes, condition + variables, and barriers using native Zephyr counterparts. POSIX + synchronization primitives in Zephyr were originally implemented + separately and received less maintenance as a result. Unfortunately, this + opened POSIX up to unique bugs and race conditions. Going forward, POSIX + will benefit from all improvements to Zephyr's synchronization and + threading API and race conditions have been mitigated. + * Retention * Retention subsystem has been added which adds enhanced features over From fb74e5ecc5e9eaff4bc4f78c916059df014772bc Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Fri, 9 Jun 2023 17:04:33 +0200 Subject: [PATCH 0062/2042] doc: release: 3.4: Add notes about Atmel Add 3.4.0 release notes for Atmel. Signed-off-by: Gerson Fernando Budke --- doc/releases/release-notes-3.4.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 7a6acd71de80..dd62fb60dcad 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -343,6 +343,8 @@ Boards & SoC Support * Made these changes for ARM boards: + * ``atsamc21n_xpro``: Enable support to CAN. + * ``atsame54_xpro``: Read Ethernet MAC from I2C. * Changed the default board revision to 0.14.0 for the Nordic boards ``nrf9160dk_nrf9160`` and ``nrf9160dk_nrf52840``. To build for an older revision of the nRF9160 DK without external flash, specify that @@ -509,6 +511,9 @@ Drivers and Sensors * Clock control + * Atmel SAM/SAM0: Introduce peripheral clock control. + * Atmel SAM0: Improved ``samd20``/``samd21``/``samr21`` clocking mechanism. + * Counter * Crypto From f220e26703c0fe516d433035eb5c2ff72ecf036e Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Fri, 9 Jun 2023 17:12:04 +0200 Subject: [PATCH 0063/2042] doc: release: 3.4: Add notes about Gigadevices Add 3.4.0 release notes for Gigadevices Signed-off-by: Gerson Fernando Budke --- doc/releases/release-notes-3.4.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index dd62fb60dcad..7ae08b4a2d14 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -359,6 +359,8 @@ Boards & SoC Support * Made these changes for RISC-V boards: + * ``gd32vf103``: No longer requires special OpenOCD version. + * Made these changes for X86 boards: * Made these changes for Xtensa boards: @@ -631,6 +633,8 @@ Drivers and Sensors * Serial + * Add UART3 and UART4 configuration for ``gd32vf103`` SoCs. + * SPI * Timer From f307e200c21e80928b6872c85cb7273faf5285e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 8 Jun 2023 19:50:26 +0200 Subject: [PATCH 0064/2042] drivers: auxdisplay: Fix jhd1313 compilation issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added several missing undeclared config variables causing the driver to not compile properly. Fixes #59078. Signed-off-by: Benjamin Cabé --- drivers/auxdisplay/auxdisplay_jhd1313.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/auxdisplay/auxdisplay_jhd1313.c b/drivers/auxdisplay/auxdisplay_jhd1313.c index 8d304851311e..e17c190d31ce 100644 --- a/drivers/auxdisplay/auxdisplay_jhd1313.c +++ b/drivers/auxdisplay/auxdisplay_jhd1313.c @@ -110,6 +110,7 @@ static int auxdisplay_jhd1313_cursor_position_set(const struct device *dev, enum auxdisplay_position type, int16_t x, int16_t y) { + const struct auxdisplay_jhd1313_config *config = dev->config; unsigned char data[2]; if (type != AUXDISPLAY_POSITION_ABSOLUTE) { @@ -306,6 +307,7 @@ static int auxdisplay_jhd1313_initialize(const struct device *dev) static int auxdisplay_jhd1313_display_on(const struct device *dev) { + const struct auxdisplay_jhd1313_config *config = dev->config; struct auxdisplay_jhd1313_data *data = dev->data; data->power = true; @@ -314,6 +316,7 @@ static int auxdisplay_jhd1313_display_on(const struct device *dev) static int auxdisplay_jhd1313_display_off(const struct device *dev) { + const struct auxdisplay_jhd1313_config *config = dev->config; struct auxdisplay_jhd1313_data *data = dev->data; data->power = false; From 3b181641d2605c56f9f61b00e159dff3933e5779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 8 Jun 2023 20:10:19 +0200 Subject: [PATCH 0065/2042] drivers: auxdisplay: Fix text direction handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Input Set handling. Flag had misleading names: whether "entry" happens to the left or to the right is dependent on whether increment mode is active or not), so switched to just using a "SHIFT" y/n flag instead. It also reflects better the contents of the datasheet). Updated romance text direction accordingly ("increment, no shift"). Signed-off-by: Benjamin Cabé --- drivers/auxdisplay/auxdisplay_jhd1313.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/auxdisplay/auxdisplay_jhd1313.c b/drivers/auxdisplay/auxdisplay_jhd1313.c index e17c190d31ce..59b378e6e4e3 100644 --- a/drivers/auxdisplay/auxdisplay_jhd1313.c +++ b/drivers/auxdisplay/auxdisplay_jhd1313.c @@ -26,10 +26,9 @@ LOG_MODULE_REGISTER(auxdisplay_jhd1313, CONFIG_AUXDISPLAY_LOG_LEVEL); #define JHD1313_CS_RIGHT_SHIFT (1 << 2) /* Defines for the JHD1313_CMD_INPUT_SET to change text direction */ -#define JHD1313_IS_SHIFT_INCREMENT (1 << 1) -#define JHD1313_IS_SHIFT_DECREMENT (0 << 1) -#define JHD1313_IS_ENTRY_LEFT (1 << 0) -#define JHD1313_IS_ENTRY_RIGHT (0 << 0) +#define JHD1313_IS_INCREMENT (1 << 1) +#define JHD1313_IS_DECREMENT (0 << 1) +#define JHD1313_IS_SHIFT (1 << 0) /* Defines for the JHD1313_CMD_FUNCTION_SET */ #define JHD1313_FS_8BIT_MODE (1 << 4) @@ -287,8 +286,11 @@ static int auxdisplay_jhd1313_initialize(const struct device *dev) /* Clear the screen */ auxdisplay_jhd1313_clear(dev); - /* Initialize to the default text direction for romance languages */ - cmd = JHD1313_IS_ENTRY_LEFT | JHD1313_IS_SHIFT_DECREMENT; + /* + * Initialize to the default text direction for romance languages + * (increment, no shift) + */ + cmd = JHD1313_IS_INCREMENT; auxdisplay_jhd1313_input_state_set(dev, cmd); From 0445c7e7d50802ba2f15a28b4f9415db25004f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 8 Jun 2023 20:12:27 +0200 Subject: [PATCH 0066/2042] drivers: auxdisplay: Set background to white MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed inconsistency between code & comments and actually set background to black Signed-off-by: Benjamin Cabé --- drivers/auxdisplay/auxdisplay_jhd1313.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/auxdisplay/auxdisplay_jhd1313.c b/drivers/auxdisplay/auxdisplay_jhd1313.c index 59b378e6e4e3..10277a2bd456 100644 --- a/drivers/auxdisplay/auxdisplay_jhd1313.c +++ b/drivers/auxdisplay/auxdisplay_jhd1313.c @@ -300,7 +300,7 @@ static int auxdisplay_jhd1313_initialize(const struct device *dev) auxdisplay_jhd1313_reg_set(config->bus.bus, 0x01, 0x05); auxdisplay_jhd1313_reg_set(config->bus.bus, 0x08, 0xAA); - /* Now set the background colour to white */ + /* Now set the background colour to black */ LOG_DBG("Background set to off"); auxdisplay_jhd1313_backlight_set(dev, 0); From 7ebe4889f3218efb4865fdb85298e5818612b42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 9 Jun 2023 10:00:59 +0200 Subject: [PATCH 0067/2042] drivers: auxdisplay: Fix rows/columns inversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JHD1313 is 16 columns x 2 rows. Signed-off-by: Benjamin Cabé --- drivers/auxdisplay/auxdisplay_jhd1313.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/auxdisplay/auxdisplay_jhd1313.c b/drivers/auxdisplay/auxdisplay_jhd1313.c index 10277a2bd456..9b4ef08e88b9 100644 --- a/drivers/auxdisplay/auxdisplay_jhd1313.c +++ b/drivers/auxdisplay/auxdisplay_jhd1313.c @@ -351,8 +351,8 @@ static const struct auxdisplay_driver_api auxdisplay_jhd1313_auxdisplay_api = { #define AUXDISPLAY_JHD1313_DEVICE(inst) \ static const struct auxdisplay_jhd1313_config auxdisplay_jhd1313_config_##inst = { \ .capabilities = { \ - .columns = 2, \ - .rows = 16, \ + .columns = 16, \ + .rows = 2, \ .mode = 0, \ .brightness.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ .brightness.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ From 1a3fd597a871b1ac36e193492826476f3b8d7ebb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 9 Jun 2023 13:42:44 +0200 Subject: [PATCH 0068/2042] Bluetooth: ISO: Log status as hex instead of decimal Log status values in events as hex instead of decimal to make it easier to compare to the spec and hci_err.h Signed-off-by: Emil Gydesen --- subsys/bluetooth/host/iso.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index c3cb52913bc2..6e9976fa8154 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -979,7 +979,7 @@ void hci_le_cis_established(struct net_buf *buf) uint16_t handle = sys_le16_to_cpu(evt->conn_handle); struct bt_conn *iso; - LOG_DBG("status %u handle %u", evt->status, handle); + LOG_DBG("status 0x%02x handle %u", evt->status, handle); /* ISO connection handles are already assigned at this point */ iso = bt_conn_lookup_handle(handle); @@ -2473,7 +2473,7 @@ void hci_le_big_complete(struct net_buf *buf) big = lookup_big_by_handle(evt->big_handle); atomic_clear_bit(big->flags, BT_BIG_PENDING); - LOG_DBG("BIG[%u] %p completed, status %u", big->handle, big, evt->status); + LOG_DBG("BIG[%u] %p completed, status 0x%02x", big->handle, big, evt->status); if (evt->status || evt->num_bis != big->num_bis) { if (evt->status == BT_HCI_ERR_SUCCESS && evt->num_bis != big->num_bis) { @@ -2647,7 +2647,7 @@ void hci_le_big_sync_established(struct net_buf *buf) big = lookup_big_by_handle(evt->big_handle); atomic_clear_bit(big->flags, BT_BIG_SYNCING); - LOG_DBG("BIG[%u] %p sync established, status %u", big->handle, big, evt->status); + LOG_DBG("BIG[%u] %p sync established, status 0x%02x", big->handle, big, evt->status); if (evt->status || evt->num_bis != big->num_bis) { if (evt->status == BT_HCI_ERR_SUCCESS && evt->num_bis != big->num_bis) { From faecdff7a2679b863fb068a19d0980dbf96ba203 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Fri, 9 Jun 2023 09:59:34 +0200 Subject: [PATCH 0069/2042] Samples: iso_connected_benchmark: Use BT_LE_ADV_OPT_ONE_TIME It is not intentional to continue advertising once a connection has been established for two reasons: 1. We do not configure enough connection contexts for this 2. We don't want to generate controller scheduling conflicts that can possibly reduce performance. Signed-off-by: Rubin Gerritsen --- samples/bluetooth/iso_connected_benchmark/src/main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index 6bcdb336d5d5..d4db26878644 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -1012,7 +1012,12 @@ static int run_peripheral(void) } LOG_INF("Starting advertising"); - err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, NULL, 0, NULL, 0); + err = bt_le_adv_start( + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_CONNECTABLE | + BT_LE_ADV_OPT_USE_NAME | + BT_LE_ADV_OPT_FORCE_NAME_IN_AD, + BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL), + NULL, 0, NULL, 0); if (err != 0) { LOG_ERR("Advertising failed to start: %d", err); return err; From 9cb339166e1da435ecd6253f2cbb108f6322e061 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Fri, 9 Jun 2023 10:01:40 +0200 Subject: [PATCH 0070/2042] Samples: iso_connected_benchmark: Fix invalid latency The default transport latency was not valid. Set it to a value that is large enough. The minimum possible transport latency is 16580 us, but this assumes the controller ignores the RTN=2. If the controller uses the RTN=2, the transport latency will be slightly larger than 30 ms depending on how the controller chooses to setup the ISO link. Therefore, we set it to 40 ms to ensure the default configuration is valid. How these numbers were found: For unframed PDUs this is defined in Core_v5.4, Vol 6, Part G, Section 3.2.2: Transport_Latency = CIG_Sync_Delay + FT * ISO_Interval - SDU_Interval Because unframed PDUs are being used, the ISO interval needs to be a multiple of SDU interval. If MaxPDU = MaxSDU and the PHY is 2M, this results in that the maximum subevent size is: 2120 * 2 + 2 * 150 = 4540. For 2 CISes this is 9080 us > 7500 Therefore, the controller has to set the ISO interval to a minimum of 15000 us in order to fit the packets. Based upon this info, the controller has the freedom to ignore or use the requested RTN=2. 1. Ignore -> NSE is 2: Minimum ISO interval is 15000 us 2. RTN = 2, Increase NSE: 4 * 4540 = 18160 -> ISO_Interval = 22500 us 3. RTN = 2, Increase the FT to 2, NSE = 2 -> ISO_Interval = 15000 us For (1): Transport_Latency = CIG_Sync_Delay + 15000 - 7500 = CIG_Sync_Delay + 7500 For (2): Transport_Latency = CIG_Sync_Delay + 22500 - 7500 = CIG_Sync_Delay + 15000 For (3): Transport_Latency = CIG_Sync_Delay + 2 * 15000 - 7500 = CIG_Sync_Delay + 22500 As shown in Core_v5.4, Vol 6, Part B, Section 4.5.14, CIG_Sync_Delay needs to be larger than or equal to the length of all ISO events. That is, the sum of the subevents: For (1): CIG_Sync_Delay = 2 * 4540 = 9080 For (2): CIG_Sync_Delay = 4 * 4540 = 18160 For (3): CIG_Sync_Delay = 2 * 4540 = 9080 This results in the following transport latencies: For (1): Transport_Latency = 9080 + 7500 = 16580 For (2): Transport_Latency = 18160 + 15000 = 33160 For (3): Transport_Latency = 9080 + 22500 = 31580 Signed-off-by: Rubin Gerritsen --- samples/bluetooth/iso_connected_benchmark/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index d4db26878644..ed2bd0f3b28b 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -30,7 +30,7 @@ enum benchmark_role { #define DEFAULT_CIS_RTN 2 #define DEFAULT_CIS_INTERVAL_US 7500 -#define DEFAULT_CIS_LATENCY_MS 10 +#define DEFAULT_CIS_LATENCY_MS 40 #define DEFAULT_CIS_PHY BT_GAP_LE_PHY_2M #define DEFAULT_CIS_SDU_SIZE CONFIG_BT_ISO_TX_MTU #define DEFAULT_CIS_PACKING 0 From f8f8fa2e24863facf9efb63d3f093d8e14a97f0b Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Fri, 9 Jun 2023 10:30:54 +0200 Subject: [PATCH 0071/2042] doc: release notes: add 1-wire release notes for 3.4.0 Add 1-Wire related release notes for Zephyr v3.4.0. Signed-off-by: Thomas Stranger --- doc/releases/release-notes-3.4.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 7ae08b4a2d14..e412fbab58dd 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -646,6 +646,11 @@ Drivers and Sensors * W1 + * Added DS2482-800 1-Wire master driver. See the :dtcompatible:`maxim,ds2482-800` + devicetree binding for more information. + * Added :kconfig:option:`CONFIG_W1_NET_FORCE_MULTIDROP_ADDRESSING` which can be + enabled force the 1-Wire network layer to use multidrop addressing. + * Watchdog * WiFi From 6e940c513cb665a70fb57c2dd409d0bbdba734f2 Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Wed, 7 Jun 2023 15:02:39 +0400 Subject: [PATCH 0072/2042] ARC: Fix portability.posix.common.arcmwdtlib test portability.posix.common.arcmwdtlib test fails with ARCMWDT libc. This path fixes the test. STDIN_FILENO and others macroses are used in libc-hooks.c only. So they defined localy. Signed-off-by: Nikolay Agishev --- include/zephyr/posix/posix_types.h | 10 +++++++--- include/zephyr/posix/pthread_key.h | 4 +++- include/zephyr/posix/sched.h | 3 ++- lib/libc/arcmwdt/include/sys/cdefs.h | 7 +++++++ lib/libc/arcmwdt/include/sys/types.h | 18 ++++++++++++++++++ lib/libc/arcmwdt/libc-hooks.c | 12 ++++++++++++ 6 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 lib/libc/arcmwdt/include/sys/cdefs.h create mode 100644 lib/libc/arcmwdt/include/sys/types.h diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index d34102a06de1..511697cfab95 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -47,9 +47,11 @@ struct pthread_attr { int32_t detachstate; uint32_t initialized; }; -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) typedef struct pthread_attr pthread_attr_t; #endif + BUILD_ASSERT(sizeof(pthread_attr_t) >= sizeof(struct pthread_attr)); typedef uint32_t pthread_t; @@ -63,7 +65,8 @@ typedef uint32_t pthread_mutex_t; struct pthread_mutexattr { int type; }; -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) typedef struct pthread_mutexattr pthread_mutexattr_t; #endif BUILD_ASSERT(sizeof(pthread_mutexattr_t) >= sizeof(struct pthread_mutexattr)); @@ -74,7 +77,8 @@ typedef uint32_t pthread_cond_t; struct pthread_condattr { }; -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) typedef struct pthread_condattr pthread_condattr_t; #endif BUILD_ASSERT(sizeof(pthread_condattr_t) >= sizeof(struct pthread_condattr)); diff --git a/include/zephyr/posix/pthread_key.h b/include/zephyr/posix/pthread_key.h index 025f29c6d33e..6b89c8f9818e 100644 --- a/include/zephyr/posix/pthread_key.h +++ b/include/zephyr/posix/pthread_key.h @@ -13,9 +13,11 @@ extern "C" { #endif +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) + #ifdef CONFIG_PTHREAD_IPC -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) typedef struct { int is_initialized; int init_executed; diff --git a/include/zephyr/posix/sched.h b/include/zephyr/posix/sched.h index 6a376fb4958d..10cfc666c66d 100644 --- a/include/zephyr/posix/sched.h +++ b/include/zephyr/posix/sched.h @@ -25,7 +25,8 @@ extern "C" { /* Priority based preemptive scheduling policy */ #define SCHED_RR 2 -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) struct sched_param { int sched_priority; }; diff --git a/lib/libc/arcmwdt/include/sys/cdefs.h b/lib/libc/arcmwdt/include/sys/cdefs.h new file mode 100644 index 000000000000..ff8eecfb1c1c --- /dev/null +++ b/lib/libc/arcmwdt/include/sys/cdefs.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Synopsys. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* MWDT has no it's own cdefs. Add this one for satisfy dependencies */ diff --git a/lib/libc/arcmwdt/include/sys/types.h b/lib/libc/arcmwdt/include/sys/types.h new file mode 100644 index 000000000000..1024f22834c9 --- /dev/null +++ b/lib/libc/arcmwdt/include/sys/types.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Synopsys. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIB_LIBC_ARCMWDT_INCLUDE_SYS_TYPES_H_ +#define LIB_LIBC_ARCMWDT_INCLUDE_SYS_TYPES_H_ + +#include_next "sys/types.h" + +#define _DEV_T_DECLARED +#define _INO_T_DECLARED +#define _NLINK_T_DECLARED +#define _UID_T_DECLARED +#define _GID_T_DECLARED + +#endif /* LIB_LIBC_ARCMWDT_INCLUDE_SYS_TYPES_H_ */ diff --git a/lib/libc/arcmwdt/libc-hooks.c b/lib/libc/arcmwdt/libc-hooks.c index 1ffb607dfe79..b7ee5f90a81b 100644 --- a/lib/libc/arcmwdt/libc-hooks.c +++ b/lib/libc/arcmwdt/libc-hooks.c @@ -13,6 +13,18 @@ #include #include +#ifndef STDIN_FILENO + #define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO + #define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO + #define STDERR_FILENO 2 +#endif + static int _stdout_hook_default(int c) { ARG_UNUSED(c); From bc89eabfdd21d510267845e52c647f817022d2bb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 9 Jun 2023 17:16:41 +0200 Subject: [PATCH 0073/2042] Bluetooth: BAP: Remove bad log error from bt_audio_valid_codec There was a LOG_ERR from debugging. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index c6a1fbba25e9..11f3afdc4970 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -221,7 +221,6 @@ bool bt_audio_valid_codec(const struct bt_codec *codec) } for (size_t i = 0U; i < codec->meta_count; i++) { - LOG_ERR("META %zu", i); if (!bt_audio_valid_codec_data(&codec->meta[i])) { LOG_DBG("codec->meta[%zu] invalid", i); return false; From f3f838029663cf87277123b4a7d77321c59ca630 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 1 Jun 2023 16:01:10 +0200 Subject: [PATCH 0074/2042] Bluetooth: BAP: modify when ASCS disconnects the CIS When an audio stream in a bidirectional CIS is released, it should not disconnect the CIS if there is still a stream for the opposite direction streaming. Only if both streams are not in a streaming state, should ASCS attempt to disconnect the CIS. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 11 ++--- subsys/bluetooth/audio/bap_stream.c | 39 +++++++++++++++ subsys/bluetooth/audio/bap_stream.h | 2 +- subsys/bluetooth/audio/bap_unicast_client.c | 53 +++++---------------- 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index ea74154f2e56..b9054d50c12e 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -436,10 +436,7 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) ep->receiver_ready = false; - if (ep->iso == NULL || - ep->iso->chan.state == BT_ISO_STATE_DISCONNECTED) { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_IDLE); - } else { + if (bt_bap_stream_can_disconnect(stream)) { /* Either the client or the server may disconnect the * CISes when entering the releasing state. */ @@ -449,6 +446,8 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) LOG_ERR("Failed to disconnect stream %p: %d", stream, err); } + } else { + ascs_ep_set_state(ep, BT_BAP_EP_STATE_IDLE); } break; @@ -2480,9 +2479,7 @@ static void ase_stop(struct bt_ascs_ase *ase) * for that ASE by following the Connected Isochronous Stream Terminate * procedure defined in Volume 3, Part C, Section 9.3.15. */ - if (ep->iso != NULL && - ep->iso->chan.state != BT_ISO_STATE_DISCONNECTED && - ep->iso->chan.state != BT_ISO_STATE_DISCONNECTING) { + if (bt_bap_stream_can_disconnect(stream)) { err = ascs_disconnect_stream(stream); if (err < 0) { LOG_ERR("Failed to disconnect stream %p: %d", stream, err); diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 11f3afdc4970..5df9731d081e 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -257,6 +257,45 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, #endif /* CONFIG_BT_AUDIO_TX */ #if defined(CONFIG_BT_BAP_UNICAST) + +/** Checks if the stream can terminate the CIS + * + * If the CIS is used for another stream, or if the CIS is not in the connected + * state it will return false. + */ +bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream) +{ + const struct bt_bap_ep *stream_ep; + enum bt_iso_state iso_state; + + if (stream == NULL) { + return false; + } + + stream_ep = stream->ep; + + if (stream_ep == NULL || stream_ep->iso == NULL) { + return false; + } + + iso_state = stream_ep->iso->chan.state; + + if (iso_state == BT_ISO_STATE_CONNECTED || iso_state == BT_ISO_STATE_CONNECTING) { + const struct bt_bap_ep *pair_ep; + + pair_ep = bt_bap_iso_get_paired_ep(stream_ep); + + /* If there are no paired endpoint, or the paired endpoint is + * not in the streaming state, we can disconnect the CIS + */ + if (pair_ep == NULL || pair_ep->status.state != BT_BAP_EP_STATE_STREAMING) { + return true; + } + } + + return false; +} + static bool bt_bap_stream_is_broadcast(const struct bt_bap_stream *stream) { return (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) && diff --git a/subsys/bluetooth/audio/bap_stream.h b/subsys/bluetooth/audio/bap_stream.h index f2074932f162..e7777f8d5a0b 100644 --- a/subsys/bluetooth/audio/bap_stream.h +++ b/subsys/bluetooth/audio/bap_stream.h @@ -27,7 +27,7 @@ void bt_bap_stream_detach(struct bt_bap_stream *stream); enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos); bool bt_audio_valid_codec_data(const struct bt_codec_data *data); bool bt_audio_valid_codec(const struct bt_codec *codec); - +bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream); enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream, const struct bt_codec_qos *qos); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index c4d844147b84..6baf39d0b4b5 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -40,7 +40,6 @@ BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 || LOG_MODULE_REGISTER(bt_bap_unicast_client, CONFIG_BT_BAP_UNICAST_CLIENT_LOG_LEVEL); #define PAC_DIR_UNUSED(dir) ((dir) != BT_AUDIO_DIR_SINK && (dir) != BT_AUDIO_DIR_SOURCE) - struct bt_bap_unicast_client_ep { uint16_t handle; uint16_t cp_handle; @@ -162,44 +161,6 @@ static int unicast_client_send_start(struct bt_bap_ep *ep) static int unicast_client_ep_idle_state(struct bt_bap_ep *ep); -/** Checks if the stream can terminate the CIS - * - * If the CIS is used for another stream, or if the CIS is not in the connected - * state it will return false. - */ -static bool unicast_client_can_disconnect_stream(const struct bt_bap_stream *stream) -{ - const struct bt_bap_ep *stream_ep; - enum bt_iso_state iso_state; - - if (stream == NULL) { - return false; - } - - stream_ep = stream->ep; - - if (stream_ep == NULL || stream_ep->iso == NULL) { - return false; - } - - iso_state = stream_ep->iso->chan.state; - - if (iso_state == BT_ISO_STATE_CONNECTED || iso_state == BT_ISO_STATE_CONNECTING) { - const struct bt_bap_ep *pair_ep; - - pair_ep = bt_bap_iso_get_paired_ep(stream_ep); - - /* If there are no paired endpoint, or the paired endpoint is - * not in the streaming state, we can disconnect the CIS - */ - if (pair_ep == NULL || pair_ep->status.state != BT_BAP_EP_STATE_STREAMING) { - return true; - } - } - - return false; -} - static struct bt_bap_stream *audio_stream_by_ep_id(const struct bt_conn *conn, uint8_t id) { @@ -581,7 +542,7 @@ static int unicast_client_ep_idle_state(struct bt_bap_ep *ep) } /* If CIS is connected, disconnect and wait for CIS disconnection */ - if (unicast_client_can_disconnect_stream(stream)) { + if (bt_bap_stream_can_disconnect(stream)) { int err; LOG_DBG("Disconnecting stream"); @@ -652,11 +613,19 @@ static void unicast_client_ep_qos_update(struct bt_bap_ep *ep, static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_simple *buf) { + struct bt_bap_unicast_client_ep *client_ep = + CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep); struct bt_ascs_ase_status_config *cfg; struct bt_codec_qos_pref *pref; struct bt_bap_stream *stream; void *cc; + if (client_ep->release_requested) { + LOG_DBG("Released was requested, change local state to idle"); + ep->status.state = BT_BAP_EP_STATE_IDLE; + unicast_client_ep_idle_state(ep); + } + if (buf->len < sizeof(*cfg)) { LOG_ERR("Config status too short"); return; @@ -768,7 +737,7 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim stream->qos->latency, stream->qos->pd); /* Disconnect ISO if connected */ - if (unicast_client_can_disconnect_stream(stream)) { + if (bt_bap_stream_can_disconnect(stream)) { const int err = bt_bap_stream_disconnect(stream); if (err != 0) { @@ -931,7 +900,7 @@ static void unicast_client_ep_releasing_state(struct bt_bap_ep *ep, struct net_b LOG_DBG("dir %s", bt_audio_dir_str(ep->dir)); - if (unicast_client_can_disconnect_stream(stream)) { + if (bt_bap_stream_can_disconnect(stream)) { /* The Unicast Client shall terminate any CIS established for * that ASE by following the Connected Isochronous Stream * Terminate procedure defined in Volume 3, Part C, From 65c2f8ef37d48f86857ddfefc6c618a969534901 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 1 Jun 2023 16:02:39 +0200 Subject: [PATCH 0075/2042] Bluetooth: BAP: Release stream on codec config if requested An ASCS endpoint may go into either the idle or codec configured state when a stream is released. However since we have such a high coupling between audio streams and endpoints, we need to consider the endpoint as having been released (i.e. gone to the IDLE state). This is handled by a boolean state variable for now, but we may want to consider a more generic approach where streams and endpoints may be less coupled. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_unicast_client.c | 50 ++++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 6baf39d0b4b5..7f769c1edaff 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -50,6 +50,7 @@ struct bt_bap_unicast_client_ep { /* Bool to help handle different order of CP and ASE notification when releasing */ bool release_requested; + bool cp_ntf_pending; }; static const struct bt_uuid *snk_uuid = BT_UUID_PACS_SNK; @@ -562,15 +563,19 @@ static int unicast_client_ep_idle_state(struct bt_bap_ep *ep) /* Notify upper layer */ if (client_ep->release_requested) { - /* In case that we get the idle state notification before the CP notification we - * trigger the CP callback now, as after this we won't be able to find the stream - * by the ASE ID - */ client_ep->release_requested = false; - if (unicast_client_cbs != NULL && unicast_client_cbs->release != NULL) { - unicast_client_cbs->release(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); + if (client_ep->cp_ntf_pending) { + /* In case that we get the idle state notification before the CP + * notification we trigger the CP callback now, as after this we won't be + * able to find the stream by the ASE ID + */ + client_ep->cp_ntf_pending = false; + + if (unicast_client_cbs != NULL && unicast_client_cbs->release != NULL) { + unicast_client_cbs->release(stream, BT_BAP_ASCS_RSP_CODE_SUCCESS, + BT_BAP_ASCS_REASON_NONE); + } } } @@ -1307,7 +1312,7 @@ static uint8_t unicast_client_cp_notify(struct bt_conn *conn, } for (uint8_t i = 0U; i < rsp->num_ase; i++) { - struct bt_bap_unicast_client_ep *client_ep; + struct bt_bap_unicast_client_ep *client_ep = NULL; struct bt_ascs_cp_ase_rsp *ase_rsp; struct bt_bap_stream *stream; @@ -1331,6 +1336,9 @@ static uint8_t unicast_client_cp_notify(struct bt_conn *conn, stream = audio_stream_by_ep_id(conn, ase_rsp->id); if (stream == NULL) { LOG_DBG("Could not find stream by id %u", ase_rsp->id); + } else { + client_ep = CONTAINER_OF(stream->ep, struct bt_bap_unicast_client_ep, ep); + client_ep->cp_ntf_pending = false; } switch (rsp->op) { @@ -1371,18 +1379,20 @@ static uint8_t unicast_client_cp_notify(struct bt_conn *conn, } break; case BT_ASCS_RELEASE_OP: - if (stream != NULL) { - client_ep = CONTAINER_OF(stream->ep, - struct bt_bap_unicast_client_ep, ep); - - if (client_ep->release_requested) { - /* Set to false to only handle the callback here */ + /* client_ep->release_requested is set to false if handled by the + * endpoint notification handler + */ + if (client_ep != NULL && client_ep->release_requested) { + /* If request was reject, do not expect endpoint notifications */ + if (ase_rsp->code != BT_BAP_ASCS_RSP_CODE_SUCCESS) { + client_ep->cp_ntf_pending = false; client_ep->release_requested = false; } - } - if (unicast_client_cbs->release != NULL) { - unicast_client_cbs->release(stream, ase_rsp->code, ase_rsp->reason); + if (unicast_client_cbs->release != NULL) { + unicast_client_cbs->release(stream, ase_rsp->code, + ase_rsp->reason); + } } break; default: @@ -2012,6 +2022,10 @@ int bt_bap_unicast_client_ep_send(struct bt_conn *conn, struct bt_bap_ep *ep, reset_att_buf(client); } + if (err == 0) { + client_ep->cp_ntf_pending = true; + } + return err; } @@ -2041,6 +2055,8 @@ static void unicast_client_reset(struct bt_bap_ep *ep) client_ep->cp_handle = 0U; client_ep->handle = 0U; (void)memset(&client_ep->discover, 0, sizeof(client_ep->discover)); + client_ep->release_requested = false; + client_ep->cp_ntf_pending = false; /* Need to keep the subscribe params intact for the callback */ } From e9c1be88ca4085ece9c7af0d38752ad6f0b64b7b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 31 May 2023 14:47:51 +0200 Subject: [PATCH 0076/2042] Bluetooth: CAP: Add Initiator cancel procedure Add function to cancel any current proecedure. This is useful in cases where the connection to one or more acceptors is lost or if some acceptor does not respond to our requests for whatever reason. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/cap.h | 48 ++++++++-- subsys/bluetooth/audio/cap_initiator.c | 116 ++++++++++++++----------- 2 files changed, 104 insertions(+), 60 deletions(-) diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 86f0e88a70d8..1436b96ca874 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -78,10 +78,12 @@ struct bt_cap_initiator_cb { * * @param unicast_group The unicast group pointer supplied to * bt_cap_initiator_unicast_audio_start(). - * @param err 0 if success, else BT_GATT_ERR() with a - * specific ATT (BT_ATT_ERR_*) error code. + * @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(). * @param conn Pointer to the connection where the error - * occurred. NULL if @p err is 0. + * 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); @@ -89,10 +91,12 @@ struct bt_cap_initiator_cb { /** * @brief Callback for bt_cap_initiator_unicast_audio_update(). * - * @param err 0 if success, else BT_GATT_ERR() with a - * specific ATT (BT_ATT_ERR_*) error code. + * @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(). * @param conn Pointer to the connection where the error - * occurred. NULL if @p err is 0. + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() */ void (*unicast_update_complete)(int err, struct bt_conn *conn); @@ -107,10 +111,12 @@ struct bt_cap_initiator_cb { * * @param unicast_group The unicast group pointer supplied to * bt_cap_initiator_unicast_audio_stop(). - * @param err 0 if success, else BT_GATT_ERR() with a - * specific ATT (BT_ATT_ERR_*) error code. + * @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(). * @param conn Pointer to the connection where the error - * occurred. NULL if @p err is 0. + * 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); @@ -269,6 +275,30 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda */ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group); +/** @brief Cancel any current Common Audio Profile 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 take 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 0 and the err value set to -ECANCELED. + * + * @retval 0 on success + * @retval -EALREADY if no procedure is active + */ +int bt_cap_initiator_unicast_audio_cancel(void); + struct bt_cap_initiator_broadcast_stream_param { /** Audio stream */ struct bt_cap_stream *stream; diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 5f321dd3ed11..d877f99b80b3 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -293,6 +293,13 @@ enum { 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, @@ -311,6 +318,7 @@ struct cap_unicast_proc { 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; @@ -809,22 +817,42 @@ static int cap_initiator_unicast_audio_configure( return 0; } -static void cap_initiator_unicast_audio_start_complete(void) +static void cap_initiator_unicast_audio_proc_complete(void) { struct bt_bap_unicast_group *unicast_group; + enum cap_unicast_proc_type proc_type; struct bt_conn *failed_conn; int err; - /* All streams in the procedure share the same unicast group, so we just - * use the reference from the first stream - */ - unicast_group = (struct bt_bap_unicast_group *)active_proc.streams[0]->bap_stream.group; + 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)); - if (cap_cb != NULL && cap_cb->unicast_start_complete != NULL) { - cap_cb->unicast_start_complete(unicast_group, err, failed_conn); + + if (cap_cb == NULL) { + return; + } + + switch (proc_type) { + case CAP_UNICAST_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: + if (cap_cb->unicast_update_complete != NULL) { + cap_cb->unicast_update_complete(err, failed_conn); + } + break; + case CAP_UNICAST_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: + default: + __ASSERT(false, "Invalid proc_type: %u", proc_type); } } @@ -847,6 +875,7 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start } active_proc.unicast_group = unicast_group; + active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START; return cap_initiator_unicast_audio_configure(param); } @@ -886,7 +915,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) if (cap_proc_is_aborted()) { if (cap_proc_all_streams_handled()) { - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; @@ -944,7 +973,7 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) */ cap_abort_proc(conns[i], err); if (i == 0U) { - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; @@ -979,7 +1008,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) if (cap_proc_is_aborted()) { if (cap_proc_all_streams_handled()) { - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; @@ -1006,7 +1035,7 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) */ cap_abort_proc(bap_stream->conn, err); if (i == 0U) { - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; @@ -1042,7 +1071,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) if (cap_proc_is_aborted()) { if (cap_proc_all_streams_handled()) { - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; @@ -1065,7 +1094,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) * once all sent requests has completed */ cap_abort_proc(bap_stream->conn, err); - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); return; } @@ -1108,24 +1137,10 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream) * once all sent requests has completed */ cap_abort_proc(bap_stream->conn, err); - cap_initiator_unicast_audio_start_complete(); + cap_initiator_unicast_audio_proc_complete(); } } else { - cap_initiator_unicast_audio_start_complete(); - } -} - -static void cap_initiator_unicast_audio_update_complete(void) -{ - struct bt_conn *failed_conn; - int err; - - failed_conn = active_proc.failed_conn; - err = active_proc.err; - - (void)memset(&active_proc, 0, sizeof(active_proc)); - if (cap_cb != NULL && cap_cb->unicast_update_complete != NULL) { - cap_cb->unicast_update_complete(err, failed_conn); + cap_initiator_unicast_audio_proc_complete(); } } @@ -1208,6 +1223,7 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); active_proc.stream_cnt = count; + active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE; cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_META_UPDATE); @@ -1242,6 +1258,20 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda return 0; } +int bt_cap_initiator_unicast_audio_cancel(void) +{ + if (!cap_proc_is_active() && !cap_proc_is_aborted()) { + LOG_DBG("No CAP procedure is in progress"); + + return -EALREADY; + } + + cap_abort_proc(NULL, -ECANCELED); + cap_initiator_unicast_audio_proc_complete(); + + return 0; +} + void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) { if (!cap_stream_in_active_proc(cap_stream)) { @@ -1265,30 +1295,13 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) return; } else if (cap_proc_is_aborted()) { if (cap_proc_all_streams_handled()) { - cap_initiator_unicast_audio_update_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; } - cap_initiator_unicast_audio_update_complete(); -} - -static void cap_initiator_unicast_audio_stop_complete(void) -{ - struct bt_bap_unicast_group *unicast_group; - struct bt_conn *failed_conn; - int err; - - unicast_group = active_proc.unicast_group; - failed_conn = active_proc.failed_conn; - err = active_proc.err; - - (void)memset(&active_proc, 0, sizeof(active_proc)); - - if (cap_cb != NULL && cap_cb->unicast_stop_complete != NULL) { - cap_cb->unicast_stop_complete(unicast_group, err, failed_conn); - } + cap_initiator_unicast_audio_proc_complete(); } static bool can_release(const struct bt_bap_stream *bap_stream) @@ -1343,6 +1356,7 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro 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; cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_RELEASE); @@ -1404,13 +1418,13 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) return; } else if (cap_proc_is_aborted()) { if (cap_proc_all_streams_handled()) { - cap_initiator_unicast_audio_stop_complete(); + cap_initiator_unicast_audio_proc_complete(); } return; } - cap_initiator_unicast_audio_stop_complete(); + cap_initiator_unicast_audio_proc_complete(); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ From 7712f811712f1b532691b6ad3812c18b02bdcb26 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 31 May 2023 14:49:16 +0200 Subject: [PATCH 0077/2042] Bluetooth: CAP: Shell: Add cmd_cap_initiator_unicast_cancel Add cmd_cap_initiator_unicast_cancel to call the cancel function. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/cap_initiator.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 3a2a36459e2a..54de29c130b8 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -469,6 +469,19 @@ static int cmd_cap_initiator_unicast_stop(const struct shell *sh, size_t argc, return err; } +static int cmd_cap_initiator_unicast_cancel(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + err = bt_cap_initiator_unicast_audio_cancel(); + if (err != 0) { + shell_print(sh, "Failed to cancel unicast audio procedure: %d", err); + + return -ENOEXEC; + } + + return 0; +} #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ static int cmd_cap_initiator(const struct shell *sh, size_t argc, char **argv) @@ -499,6 +512,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(cap_initiator_cmds, CAP_UNICAST_CLIENT_STREAM_COUNT), SHELL_CMD_ARG(unicast-stop, NULL, "Unicast stop all streams", cmd_cap_initiator_unicast_stop, 1, 0), + SHELL_CMD_ARG(unicast-cancel, NULL, "Unicast cancel current procedure", + cmd_cap_initiator_unicast_cancel, 1, 0), #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ SHELL_SUBCMD_SET_END ); From b635a47c7031a2ab75e26c9e0b271fa1d312f8fd Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 1 Jun 2023 11:58:27 +0200 Subject: [PATCH 0078/2042] tests: Bluetooth: CAP: Add bsim test for unicast_audio_cancel Add test of the unicast audio cancel that can cancel any pending procedures. This is done by adding a new blocking behavior in the cap acceptor. Signed-off-by: Emil Gydesen --- .../bluetooth/audio/src/cap_acceptor_test.c | 35 +++++++-- .../audio/src/cap_initiator_unicast_test.c | 75 +++++++++++++++++-- .../audio/test_scripts/cap_unicast_timeout.sh | 27 +++++++ 3 files changed, 123 insertions(+), 14 deletions(-) create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 1e840cd31449..eae27963e580 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -39,6 +39,7 @@ static struct bt_bap_lc3_preset broadcast_preset_16_2_1 = static const struct bt_codec_qos_pref unicast_qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u); +static bool auto_start_sink_streams; static K_SEM_DEFINE(sem_broadcast_started, 0U, ARRAY_SIZE(broadcast_sink_streams)); static K_SEM_DEFINE(sem_broadcast_stopped, 0U, ARRAY_SIZE(broadcast_sink_streams)); @@ -210,7 +211,8 @@ 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); + printk("Enabled: stream %p (auto_start_sink_streams %d)\n", stream, + auto_start_sink_streams); err = bt_bap_ep_get_info(stream->ep, &ep_info); if (err != 0) { @@ -218,7 +220,7 @@ static void unicast_stream_enabled_cb(struct bt_bap_stream *stream) return; } - if (ep_info.dir == BT_AUDIO_DIR_SINK) { + if (auto_start_sink_streams && ep_info.dir == BT_AUDIO_DIR_SINK) { /* Automatically do the receiver start ready operation */ err = bt_bap_stream_start(stream); @@ -589,7 +591,22 @@ static void test_cap_acceptor_unicast(void) { init(); - /* TODO: When babblesim supports ISO, wait for audio stream to pass */ + auto_start_sink_streams = true; + + /* TODO: wait for audio stream to pass */ + + WAIT_FOR_FLAG(flag_connected); + + PASS("CAP acceptor unicast passed\n"); +} + +static void test_cap_acceptor_unicast_timeout(void) +{ + init(); + + auto_start_sink_streams = false; /* Cause unicast_audio_start timeout */ + + /* TODO: wait for audio stream to pass */ WAIT_FOR_FLAG(flag_connected); @@ -660,15 +677,21 @@ static const struct bst_test_instance test_cap_acceptor[] = { .test_id = "cap_acceptor_unicast", .test_post_init_f = test_init, .test_tick_f = test_tick, - .test_main_f = test_cap_acceptor_unicast + .test_main_f = test_cap_acceptor_unicast, + }, + { + .test_id = "cap_acceptor_unicast_timeout", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_acceptor_unicast_timeout, }, { .test_id = "cap_acceptor_broadcast", .test_post_init_f = test_init, .test_tick_f = test_tick, - .test_main_f = test_cap_acceptor_broadcast + .test_main_f = test_cap_acceptor_broadcast, }, - BSTEST_END_MARKER + BSTEST_END_MARKER, }; struct bst_test_list *test_cap_acceptor_install(struct bst_test_list *tests) 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 251f91bb4114..39ae4d672b22 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -26,6 +26,7 @@ CREATE_FLAG(flag_discovered); CREATE_FLAG(flag_codec_found); CREATE_FLAG(flag_endpoint_found); CREATE_FLAG(flag_started); +CREATE_FLAG(flag_start_timeout); CREATE_FLAG(flag_updated); CREATE_FLAG(flag_stopped); CREATE_FLAG(flag_mtu_exchanged); @@ -114,13 +115,13 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, struct bt_conn *conn) { - if (err != 0) { + if (err == -ECANCELED) { + SET_FLAG(flag_start_timeout); + } else if (err != 0) { FAIL("Failed to start (failing conn %p): %d", conn, err); - - return; + } else { + SET_FLAG(flag_started); } - - SET_FLAG(flag_started); } static void unicast_update_complete_cb(int err, struct bt_conn *conn) @@ -469,7 +470,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group } } -static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group) +static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group, bool wait) { struct bt_cap_unicast_audio_start_stream_param stream_param[1]; struct bt_cap_unicast_audio_start_param param; @@ -492,7 +493,9 @@ static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group) return; } - WAIT_FOR_FLAG(flag_started); + if (wait) { + WAIT_FOR_FLAG(flag_started); + } } static void unicast_audio_update_inval(void) @@ -584,6 +587,17 @@ static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) } } +static void unicast_audio_cancel(void) +{ + int err; + + err = bt_cap_initiator_unicast_audio_cancel(); + if (err != 0) { + FAIL("Failed to cancel unicast audio: %d\n", err); + return; + } +} + static void unicast_group_delete_inval(void) { int err; @@ -635,7 +649,7 @@ static void test_main_cap_initiator_unicast(void) for (size_t j = 0U; j < iterations; j++) { unicast_audio_start_inval(unicast_group); - unicast_audio_start(unicast_group); + unicast_audio_start(unicast_group, true); unicast_audio_update_inval(); unicast_audio_update(); @@ -652,6 +666,45 @@ static void test_main_cap_initiator_unicast(void) PASS("CAP initiator unicast passed\n"); } +static void test_cap_initiator_unicast_timeout(void) +{ + struct bt_bap_unicast_group *unicast_group; + const k_timeout_t timeout = K_SECONDS(1); + const size_t iterations = 2; + + init(); + + scan_and_connect(); + + WAIT_FOR_FLAG(flag_mtu_exchanged); + + discover_cas(); + + discover_sink(); + + unicast_group_create(&unicast_group); + + for (size_t j = 0U; j < iterations; j++) { + unicast_audio_start(unicast_group, false); + + k_sleep(timeout); + if ((bool)atomic_get(&flag_started)) { + FAIL("Unexpected start complete\n"); + } else { + unicast_audio_cancel(); + } + + WAIT_FOR_FLAG(flag_start_timeout); + + unicast_audio_stop(unicast_group); + } + + unicast_group_delete(unicast_group); + unicast_group = NULL; + + PASS("CAP initiator unicast passed\n"); +} + static const struct bst_test_instance test_cap_initiator_unicast[] = { { .test_id = "cap_initiator_unicast", @@ -659,6 +712,12 @@ static const struct bst_test_instance test_cap_initiator_unicast[] = { .test_tick_f = test_tick, .test_main_f = test_main_cap_initiator_unicast, }, + { + .test_id = "cap_initiator_unicast_timeout", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_unicast_timeout, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh new file mode 100755 index 000000000000..a45f93ce808b --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_timeout" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=20 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n======== Running CAP unicast timeout test =========\n\n" + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_unicast_timeout -rs=23 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_unicast_timeout -rs=46 + +# 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 $@ + +wait_for_background_jobs From 9ed72eb0e639ca79ab05214c58910a56c1873841 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 1 Jun 2023 12:00:13 +0200 Subject: [PATCH 0079/2042] tests: Bluetooth: CAP: BSIM: Set initiator as d=0 and acceptor as d=1 Typically the client is the first device in our babblesim tests, so reordered the initiator and acceptor for the CAP tests to conform to that. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh | 6 +++--- tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh | 6 +++--- .../bluetooth/audio/test_scripts/cap_unicast_timeout.sh | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh index a18573e2192d..cf4f95a49e09 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_broadcast.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2022 Nordic Semiconductor ASA +# Copyright (c) 2022-2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -15,10 +15,10 @@ cd ${BSIM_OUT_PATH}/bin printf "\n\n======== Running CAP broadcast test =========\n\n" Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_broadcast -rs=23 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_broadcast -rs=46 Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_broadcast -rs=46 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_broadcast -rs=23 # Simulation time should be larger than the WAIT_TIME in common.h Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh index e657ac958eed..7a888e1ff0e8 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2022 Nordic Semiconductor ASA +# Copyright (c) 2022-2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 @@ -15,10 +15,10 @@ cd ${BSIM_OUT_PATH}/bin printf "\n\n======== Running CAP unicast test =========\n\n" Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_unicast -rs=23 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_unicast -rs=46 Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_unicast -rs=46 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast -rs=23 # Simulation time should be larger than the WAIT_TIME in common.h Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh index a45f93ce808b..8b806d409590 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_timeout.sh @@ -15,10 +15,10 @@ cd ${BSIM_OUT_PATH}/bin printf "\n\n======== Running CAP unicast timeout test =========\n\n" Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_acceptor_unicast_timeout -rs=23 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_unicast_timeout -rs=46 Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ - -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_initiator_unicast_timeout -rs=46 + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast_timeout -rs=23 # Simulation time should be larger than the WAIT_TIME in common.h Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \ From b0d64376535102aed122cf3a2475827280d97395 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 6 Jun 2023 14:23:27 +0200 Subject: [PATCH 0080/2042] Bluetooth: Audio: Shell: Increase number of streams for unicast client Increase CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT to match CONFIG_BT_ISO_MAX_CHAN. Signed-off-by: Emil Gydesen --- tests/bluetooth/shell/audio.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 32d8315b0b40..c5a4e56d7e42 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -53,6 +53,7 @@ CONFIG_BT_ASCS_ASE_SRC_COUNT=2 CONFIG_BT_ISO_MAX_CHAN=8 CONFIG_BT_ISO_TX_BUF_COUNT=10 CONFIG_BT_ISO_RX_BUF_COUNT=10 +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=8 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_ASCS_ASE_SNK_COUNT=2 From 533c1985dc18177d8986fea86f00d39c132cda5e Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 10 Jun 2023 07:45:38 -0400 Subject: [PATCH 0081/2042] doc: services: posix: update posix supported items Several items needed to be updated in POSIX documentation. * add `_POSIX_BARRIERS` top Option Requirements * update `_POSIX_THREAD_ATTR_STACK*` in Option Requirements * add `pthread_barrier_*()` to `POSIX_THREADS_BASE` * update `pthread_cond_destroy()` and `pthread_setcancelstate()` Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index cc69c67f012f..38a4e3926f1a 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -83,6 +83,7 @@ Zephyr. :header: Requirements, Supported :widths: 50,10 + _POSIX_BARRIERS,yes _POSIX_CLOCK_SELECTION, _POSIX_FSYNC, _POSIX_MEMLOCK, @@ -93,8 +94,8 @@ Zephyr. _POSIX_SEMAPHORES,yes _POSIX_SHARED_MEMORY_OBJECTS, _POSIX_SYNCHRONIZED_IO, - _POSIX_THREAD_ATTR_STACKADDR, - _POSIX_THREAD_ATTR_STACKSIZE, + _POSIX_THREAD_ATTR_STACKADDR,yes + _POSIX_THREAD_ATTR_STACKSIZE,yes _POSIX_THREAD_CPUTIME, _POSIX_THREAD_PRIO_INHERIT,yes _POSIX_THREAD_PRIO_PROTECT, @@ -134,11 +135,18 @@ multiple processes. pthread_attr_init(),yes pthread_attr_setdetachstate(),yes pthread_attr_setschedparam(),yes + pthread_barrier_destroy(),yes + pthread_barrier_init(),yes + pthread_barrier_wait(),yes + pthread_barrierattr_destroy(), + pthread_barrierattr_getpshared(), + pthread_barrierattr_init(), + pthread_barrierattr_setpshared(), pthread_cancel(),yes pthread_cleanup_pop(), pthread_cleanup_push(), pthread_cond_broadcast(),yes - pthread_cond_destroy(), + pthread_cond_destroy(),yes pthread_cond_init(),yes pthread_cond_signal(),yes pthread_cond_timedwait(),yes @@ -163,7 +171,7 @@ multiple processes. pthread_mutexattr_init(), pthread_once(),yes pthread_self(),yes - pthread_setcalcelstate(), + pthread_setcancelstate(),yes pthread_setcanceltype(), pthread_setspecific(),yes pthread_sigmask(), From a7254b85e11f7a3f4500cf17b969b071195d37f7 Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Wed, 7 Jun 2023 11:54:16 +0200 Subject: [PATCH 0082/2042] shell: Fix BT verbose scan logging Fix endianness printout of values. Handle service data output with initial UUID. Signed-off-by: Lars Knudsen --- subsys/bluetooth/shell/bt.c | 117 +++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 23 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index bc62751dd9dd..a4083fad27ef 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -65,6 +65,8 @@ static struct bt_conn_auth_info_cb auth_info_cb; #define KEY_STR_LEN 33 +#define ADV_DATA_DELIMITER ", " + /* * Based on the maximum number of parameters for HCI_LE_Generate_DHKey * See BT Core Spec V5.2 Vol. 4, Part E, section 7.8.37 @@ -193,65 +195,134 @@ static bool data_cb(struct bt_data *data, void *user_data) } } -static void print_data_set(uint8_t type, uint8_t set_value_len, +static void print_data_hex(const uint8_t *data, uint8_t len, enum shell_vt100_color color) +{ + if (len == 0) + return; + + shell_fprintf(ctx_shell, color, "0x"); + /* Reverse the byte order when printing as advertising data is LE + * and the MSB should be first in the printed output. + */ + for (int16_t i = len - 1; i >= 0; i--) { + shell_fprintf(ctx_shell, color, "%02x", data[i]); + } +} + +static void print_data_set(uint8_t set_value_len, const uint8_t *scan_data, uint8_t scan_data_len) { - uint8_t min_value_len = MIN(set_value_len, scan_data_len); + uint8_t idx = 0; - shell_fprintf(ctx_shell, SHELL_INFO, "%*sType 0x%02x: ", - strlen(scan_response_label), "", - type); - for (uint8_t i = 0U; i < (scan_data_len / min_value_len); i++) { - if (i > 0L) { - shell_fprintf(ctx_shell, SHELL_INFO, ", "); - } + if (scan_data_len == 0 || set_value_len > scan_data_len) { + return; + } - shell_fprintf(ctx_shell, SHELL_INFO, "0x"); - for (uint8_t j = 0U; j < min_value_len; j++) { - shell_fprintf(ctx_shell, SHELL_INFO, "%02x", - scan_data[i * min_value_len + j]); + do { + if (idx > 0) { + shell_fprintf(ctx_shell, SHELL_INFO, ADV_DATA_DELIMITER); } - } - shell_fprintf(ctx_shell, SHELL_INFO, "\n"); + print_data_hex(&scan_data[idx], set_value_len, SHELL_INFO); + idx += set_value_len; + } while (idx + set_value_len <= scan_data_len); + + if (idx < scan_data_len) { + shell_fprintf(ctx_shell, SHELL_WARNING, " Excess data: "); + print_data_hex(&scan_data[idx], scan_data_len - idx, SHELL_WARNING); + } } static bool data_verbose_cb(struct bt_data *data, void *user_data) { + shell_fprintf(ctx_shell, SHELL_INFO, "%*sType 0x%02x: ", + strlen(scan_response_label), "", data->type); + switch (data->type) { case BT_DATA_UUID16_SOME: case BT_DATA_UUID16_ALL: case BT_DATA_SOLICIT16: + print_data_set(BT_UUID_SIZE_16, data->data, data->data_len); + break; case BT_DATA_SVC_DATA16: - print_data_set(data->type, 2, data->data, data->data_len); + /* Data starts with a UUID16 (2 bytes), + * the rest is unknown and printed as single bytes + */ + if (data->data_len < BT_UUID_SIZE_16) { + shell_fprintf(ctx_shell, SHELL_WARNING, + "BT_DATA_SVC_DATA16 data length too short (%u)", + data->data_len); + break; + } + print_data_set(BT_UUID_SIZE_16, data->data, BT_UUID_SIZE_16); + if (data->data_len > BT_UUID_SIZE_16) { + shell_fprintf(ctx_shell, SHELL_INFO, ADV_DATA_DELIMITER); + print_data_set(1, data->data + BT_UUID_SIZE_16, + data->data_len - BT_UUID_SIZE_16); + } break; case BT_DATA_UUID32_SOME: case BT_DATA_UUID32_ALL: + print_data_set(BT_UUID_SIZE_32, data->data, data->data_len); + break; case BT_DATA_SVC_DATA32: - print_data_set(data->type, 4, data->data, data->data_len); + /* Data starts with a UUID32 (4 bytes), + * the rest is unknown and printed as single bytes + */ + if (data->data_len < BT_UUID_SIZE_32) { + shell_fprintf(ctx_shell, SHELL_WARNING, + "BT_DATA_SVC_DATA32 data length too short (%u)", + data->data_len); + break; + } + print_data_set(BT_UUID_SIZE_32, data->data, BT_UUID_SIZE_32); + if (data->data_len > BT_UUID_SIZE_32) { + shell_fprintf(ctx_shell, SHELL_INFO, ADV_DATA_DELIMITER); + print_data_set(1, data->data + BT_UUID_SIZE_32, + data->data_len - BT_UUID_SIZE_32); + } break; case BT_DATA_UUID128_SOME: case BT_DATA_UUID128_ALL: case BT_DATA_SOLICIT128: + print_data_set(BT_UUID_SIZE_128, data->data, data->data_len); + break; case BT_DATA_SVC_DATA128: - print_data_set(data->type, 16, data->data, data->data_len); + /* Data starts with a UUID128 (16 bytes), + * the rest is unknown and printed as single bytes + */ + if (data->data_len < BT_UUID_SIZE_128) { + shell_fprintf(ctx_shell, SHELL_WARNING, + "BT_DATA_SVC_DATA128 data length too short (%u)", + data->data_len); + break; + } + print_data_set(BT_UUID_SIZE_128, data->data, BT_UUID_SIZE_128); + if (data->data_len > BT_UUID_SIZE_128) { + shell_fprintf(ctx_shell, SHELL_INFO, ADV_DATA_DELIMITER); + print_data_set(1, data->data + BT_UUID_SIZE_128, + data->data_len - BT_UUID_SIZE_128); + } break; case BT_DATA_NAME_SHORTENED: case BT_DATA_NAME_COMPLETE: case BT_DATA_BROADCAST_NAME: - shell_info(ctx_shell, "%*sType 0x%02x: %.*s", - strlen(scan_response_label), "", - data->type, data->data_len, data->data); + shell_fprintf(ctx_shell, SHELL_INFO, "%.*s", data->data_len, data->data); break; case BT_DATA_PUB_TARGET_ADDR: case BT_DATA_RAND_TARGET_ADDR: case BT_DATA_LE_BT_DEVICE_ADDRESS: - print_data_set(data->type, BT_ADDR_SIZE, data->data, data->data_len); + print_data_set(BT_ADDR_SIZE, data->data, data->data_len); + break; + case BT_DATA_CSIS_RSI: + print_data_set(3, data->data, data->data_len); break; default: - print_data_set(data->type, 1, data->data, data->data_len); + print_data_set(1, data->data, data->data_len); } + shell_fprintf(ctx_shell, SHELL_INFO, "\n"); + return true; } From efe9111b215f81ee3dbb48b3825a0b0f91cb6083 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 10 Jun 2023 10:51:29 -0400 Subject: [PATCH 0083/2042] doc: services: posix: update c-lang support section Several C language items have gained support in Zephyr over time. Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 38a4e3926f1a..45d3496dc4d5 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -262,7 +262,7 @@ This is implemented as part of the minimal C library available in Zephyr. isalnum(),yes isalpha(),yes isblank(), - iscntrl(), + iscntrl(),yes isdigit(),yes isgraph(),yes islower(), @@ -285,9 +285,9 @@ This is implemented as part of the minimal C library available in Zephyr. memmove(),yes memset(),yes mktime(),yes - qsort(), + qsort(),yes rand(),yes - rand_r(), + rand_r(),yes realloc(),yes setlocale(), snprintf(),yes @@ -299,7 +299,7 @@ This is implemented as part of the minimal C library available in Zephyr. strcmp(),yes strcoll(), strcpy(),yes - strcspn(), + strcspn(),yes strerror(),yes strerror_r(),yes strftime(), @@ -309,12 +309,12 @@ This is implemented as part of the minimal C library available in Zephyr. strncpy(),yes strpbrk(), strrchr(),yes - strspn(), + strspn(),yes strstr(),yes strtod(), strtof(), strtoimax(), - strtok(), + strtok(),yes strtok_r(),yes strtol(),yes strtold(), @@ -328,10 +328,10 @@ This is implemented as part of the minimal C library available in Zephyr. toupper(),yes tzname(), tzset(), - va_arg(), - va_copy(), - va_end(), - va_start(), + va_arg(),yes + va_copy(),yes + va_end(),yes + va_start(),yes vsnprintf(),yes vsprintf(),yes vsscanf(), @@ -349,7 +349,7 @@ process applications. confstr(), environ, - errno, + errno,yes getenv(), setenv(), sysconf(), @@ -397,11 +397,11 @@ POSIX_DEVICE_IO ftrylockfile(), funlockfile(), getc_unlocked(), - getchar_unlocked(), + getchar_unlocked(),yes putc_unlocked(), putchar_unlocked() clearerr(), - close(), + close(),yes fclose(), fdopen(), feof(), @@ -425,18 +425,18 @@ POSIX_DEVICE_IO perror(),yes printf(),yes putc(),yes - putchar(), + putchar(),yes puts(),yes read(),yes scanf(), setbuf(), etvbuf(), - stderr, - stdin, - stdout, + stderr,yes + stdin,yes + stdout,yes ungetc(), vfprintf(),yes vfscanf(), vprintf(),yes vscanf(), - write(), + write(),yes From d14519cb24a1162ae403ccb4859d411eb8478c6c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sun, 11 Jun 2023 11:59:20 +0000 Subject: [PATCH 0084/2042] release: bump release to 3.4.0-rc3 Bump release to 3.4.0-rc3. Signed-off-by: Anas Nashif --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e0314fa964c4..ccf2ed32034c 100644 --- a/VERSION +++ b/VERSION @@ -2,4 +2,4 @@ VERSION_MAJOR = 3 VERSION_MINOR = 4 PATCHLEVEL = 0 VERSION_TWEAK = 0 -EXTRAVERSION = rc2 +EXTRAVERSION = rc3 From a17fc4ff2b71cc833ae479c2aaf87d014fd87a5b Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 10 Jun 2023 10:22:24 -0400 Subject: [PATCH 0085/2042] doc: release: 3.4: add posix api deprecations Add POSIX API deprecations to v3.4 release notes. Signed-off-by: Christopher Friedt --- doc/releases/release-notes-3.4.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index e412fbab58dd..86dd7149a14e 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -202,6 +202,9 @@ Deprecated in this release functionality, enable :kconfig:option:`CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET`. +* Deprecated :c:macro:`PTHREAD_BARRIER_DEFINE` in favor of the standardized + :c:func:`pthread_barrier_init` + Stable API changes in this release ================================== From 22f73992b24a01b820c2abc20bcbaea57e8e62f5 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Fri, 9 Jun 2023 13:33:53 +0200 Subject: [PATCH 0086/2042] Bluetooth: Rework the HCI header set In order to have clean, self-contained HCI headers that do not have any dependencies towards the Host or any other part of the system (except types), reorganize the headers in the following way: - Split out the macros and structs from hci.h to a new hci_types.h - Merge the existing hci_err.h into the new hci_types.h Fixes #58214. Signed-off-by: Carles Cufi --- doc/releases/release-notes-3.4.rst | 5 + include/zephyr/bluetooth/conn.h | 2 +- include/zephyr/bluetooth/hci.h | 2981 +--------------- include/zephyr/bluetooth/hci_err.h | 90 - include/zephyr/bluetooth/hci_types.h | 3073 +++++++++++++++++ .../bluetooth/controller/coex/coex_ticker.c | 2 +- .../controller/flash/soc_flash_nrf_ticker.c | 2 +- subsys/bluetooth/controller/hci/hci.c | 2 +- subsys/bluetooth/controller/hci/hci_driver.c | 2 +- subsys/bluetooth/controller/include/ll.h | 5 + subsys/bluetooth/controller/ll_sw/isoal.c | 2 +- subsys/bluetooth/controller/ll_sw/ll_addr.c | 2 +- subsys/bluetooth/controller/ll_sw/ll_feat.c | 2 +- subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c | 2 +- .../controller/ll_sw/nordic/lll/lll_adv.c | 2 +- .../controller/ll_sw/nordic/lll/lll_adv_aux.c | 2 +- .../controller/ll_sw/nordic/lll/lll_conn.c | 2 +- .../controller/ll_sw/nordic/lll/lll_df.c | 2 +- .../controller/ll_sw/nordic/lll/lll_scan.c | 2 +- .../ll_sw/nordic/lll/lll_scan_aux.c | 2 +- .../controller/ll_sw/nordic/lll/lll_sync.c | 2 +- .../controller/ll_sw/nordic/lll/lll_test.c | 2 +- .../ll_sw/nordic/ull/ull_iso_vendor.c | 2 +- .../controller/ll_sw/openisa/hal/RV32M1/ecb.c | 2 +- .../controller/ll_sw/openisa/lll/lll_adv.c | 2 +- .../controller/ll_sw/openisa/lll/lll_scan.c | 2 +- subsys/bluetooth/controller/ll_sw/ull.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_adv.c | 2 +- .../bluetooth/controller/ll_sw/ull_adv_aux.c | 2 +- .../bluetooth/controller/ll_sw/ull_adv_iso.c | 2 +- .../bluetooth/controller/ll_sw/ull_adv_sync.c | 2 +- .../bluetooth/controller/ll_sw/ull_central.c | 2 +- .../controller/ll_sw/ull_central_iso.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_conn.c | 2 +- .../bluetooth/controller/ll_sw/ull_conn_iso.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_df.c | 2 +- .../bluetooth/controller/ll_sw/ull_filter.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_iso.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_llcp.c | 2 +- .../bluetooth/controller/ll_sw/ull_llcp_cc.c | 2 +- .../controller/ll_sw/ull_llcp_chmu.c | 2 +- .../controller/ll_sw/ull_llcp_common.c | 2 +- .../controller/ll_sw/ull_llcp_conn_upd.c | 2 +- .../bluetooth/controller/ll_sw/ull_llcp_enc.c | 2 +- .../controller/ll_sw/ull_llcp_local.c | 2 +- .../bluetooth/controller/ll_sw/ull_llcp_pdu.c | 2 +- .../bluetooth/controller/ll_sw/ull_llcp_phy.c | 2 +- .../controller/ll_sw/ull_llcp_remote.c | 2 +- .../controller/ll_sw/ull_peripheral.c | 2 +- .../controller/ll_sw/ull_peripheral_iso.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_scan.c | 2 +- .../bluetooth/controller/ll_sw/ull_scan_aux.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_sched.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_sync.c | 2 +- .../bluetooth/controller/ll_sw/ull_sync_iso.c | 2 +- tests/bluetooth/audio/ascs/src/main.c | 2 +- .../controller/mock_ctrl/src/ull_scan.c | 3 +- .../host/gatt/ccc_store/src/central.c | 2 +- .../host/security/ccc_update/src/central.c | 2 +- 59 files changed, 3139 insertions(+), 3124 deletions(-) delete mode 100644 include/zephyr/bluetooth/hci_err.h create mode 100644 include/zephyr/bluetooth/hci_types.h diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 86dd7149a14e..b7b54896061d 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -179,6 +179,11 @@ Changes in this release * Cache API functions are now fully inlined by compilers. +* The Bluetooth HCI headers have been reworked, with ``hci.h`` now containing + only the function prototypes and the new ``hci_types.h`` defining all + HCI-related macros and structs. The previous ``hci_err.h`` has been merged + into ``hci_types.h``. + Removed APIs in this release ============================ diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index e7258fbcf77a..a6c6d3b0366c 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/zephyr/bluetooth/hci.h b/include/zephyr/bluetooth/hci.h index 57842b834861..8dd7434e4458 100644 --- a/include/zephyr/bluetooth/hci.h +++ b/include/zephyr/bluetooth/hci.h @@ -10,2995 +10,16 @@ #include #include -#include -#include -#include -#include #include #include -#include #include +#include #ifdef __cplusplus extern "C" { #endif -/* Special own address types for LL privacy (used in adv & scan parameters) */ -#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 -#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 -#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 - -#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe -#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff - -#define BT_ENC_KEY_SIZE_MIN 0x07 -#define BT_ENC_KEY_SIZE_MAX 0x10 - -#define BT_HCI_ADV_HANDLE_INVALID 0xff -#define BT_HCI_SYNC_HANDLE_INVALID 0xffff -#define BT_HCI_PAWR_SUBEVENT_MAX 128 - -struct bt_hci_evt_hdr { - uint8_t evt; - uint8_t len; -} __packed; -#define BT_HCI_EVT_HDR_SIZE 2 - -#define BT_ACL_START_NO_FLUSH 0x00 -#define BT_ACL_CONT 0x01 -#define BT_ACL_START 0x02 -#define BT_ACL_COMPLETE 0x03 - -#define BT_ACL_POINT_TO_POINT 0x00 -#define BT_ACL_BROADCAST 0x01 - -#define BT_ACL_HANDLE_MASK BIT_MASK(12) - -#define bt_acl_handle(h) ((h) & BT_ACL_HANDLE_MASK) -#define bt_acl_flags(h) ((h) >> 12) -#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) -#define bt_acl_flags_bc(f) ((f) >> 2) -#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) - -struct bt_hci_acl_hdr { - uint16_t handle; - uint16_t len; -} __packed; -#define BT_HCI_ACL_HDR_SIZE 4 - -#define BT_ISO_START 0x00 -#define BT_ISO_CONT 0x01 -#define BT_ISO_SINGLE 0x02 -#define BT_ISO_END 0x03 - -#define bt_iso_handle(h) ((h) & 0x0fff) -#define bt_iso_flags(h) ((h) >> 12) -#define bt_iso_flags_pb(f) ((f) & 0x0003) -#define bt_iso_flags_ts(f) (((f) >> 2) & 0x0001) -#define bt_iso_pack_flags(pb, ts) \ - (((pb) & 0x0003) | (((ts) & 0x0001) << 2)) -#define bt_iso_handle_pack(h, pb, ts) \ - ((h) | (bt_iso_pack_flags(pb, ts) << 12)) -#define bt_iso_hdr_len(h) ((h) & BIT_MASK(14)) - -#define BT_ISO_DATA_VALID 0x00 -#define BT_ISO_DATA_INVALID 0x01 -#define BT_ISO_DATA_NOP 0x02 - -#define bt_iso_pkt_len(h) ((h) & 0x3fff) -#define bt_iso_pkt_flags(h) ((h) >> 14) -#define bt_iso_pkt_len_pack(h, f) ((h) | ((f) << 14)) - -struct bt_hci_iso_data_hdr { - uint16_t sn; - uint16_t slen; -} __packed; -#define BT_HCI_ISO_DATA_HDR_SIZE 4 - -struct bt_hci_iso_ts_data_hdr { - uint32_t ts; - struct bt_hci_iso_data_hdr data; -} __packed; -#define BT_HCI_ISO_TS_DATA_HDR_SIZE 8 - -struct bt_hci_iso_hdr { - uint16_t handle; /* 12 bit handle, 2 bit PB flags, 1 bit TS_Flag, 1 bit RFU */ - uint16_t len; /* 14 bits, 2 bits RFU */ -} __packed; -#define BT_HCI_ISO_HDR_SIZE 4 - -struct bt_hci_cmd_hdr { - uint16_t opcode; - uint8_t param_len; -} __packed; -#define BT_HCI_CMD_HDR_SIZE 3 - -/* Supported Commands */ -#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) -#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) - -#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) - -#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) -#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) -#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) -#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) -#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) - -#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) -#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) -#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) -#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) -#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) -#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) -#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) -#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) - -/* LE features */ -#define BT_LE_FEAT_BIT_ENC 0 -#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 -#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 -#define BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG 3 -#define BT_LE_FEAT_BIT_PING 4 -#define BT_LE_FEAT_BIT_DLE 5 -#define BT_LE_FEAT_BIT_PRIVACY 6 -#define BT_LE_FEAT_BIT_EXT_SCAN 7 -#define BT_LE_FEAT_BIT_PHY_2M 8 -#define BT_LE_FEAT_BIT_SMI_TX 9 -#define BT_LE_FEAT_BIT_SMI_RX 10 -#define BT_LE_FEAT_BIT_PHY_CODED 11 -#define BT_LE_FEAT_BIT_EXT_ADV 12 -#define BT_LE_FEAT_BIT_PER_ADV 13 -#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 -#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 -#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 -#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 -#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 -#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 -#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 -#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 -#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 -#define BT_LE_FEAT_BIT_RX_CTE 23 -#define BT_LE_FEAT_BIT_PAST_SEND 24 -#define BT_LE_FEAT_BIT_PAST_RECV 25 -#define BT_LE_FEAT_BIT_SCA_UPDATE 26 -#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 -#define BT_LE_FEAT_BIT_CIS_CENTRAL 28 -#define BT_LE_FEAT_BIT_CIS_PERIPHERAL 29 -#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 -#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 -#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 -#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 -#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 -#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 -#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 -#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 -#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 -#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 - -#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 -#define BT_LE_FEAT_BIT_PAWR_SCANNER 44 - -#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ - BIT((n) & 7)) - -#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ENC) -#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_PARAM_REQ) -#define BT_FEAT_LE_PER_INIT_FEAT_XCHG(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG) -#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_DLE) -#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PHY_2M) -#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PHY_CODED) -#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PRIVACY) -#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_EXT_ADV) -#define BT_FEAT_LE_EXT_PER_ADV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_ADV) -#define BT_FEAT_LE_CONNECTION_CTE_REQ(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_CTE_REQ) -#define BT_FEAT_LE_CONNECTION_CTE_RESP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_CTE_RESP) -#define BT_FEAT_LE_CONNECTIONLESS_CTE_TX(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX) -#define BT_FEAT_LE_CONNECTIONLESS_CTE_RX(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX) -#define BT_FEAT_LE_ANT_SWITCH_TX_AOD(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD) -#define BT_FEAT_LE_ANT_SWITCH_RX_AOA(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA) -#define BT_FEAT_LE_RX_CTE(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_RX_CTE) -#define BT_FEAT_LE_PAST_SEND(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAST_SEND) -#define BT_FEAT_LE_PAST_RECV(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAST_RECV) -#define BT_FEAT_LE_CIS_CENTRAL(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CIS_CENTRAL) -#define BT_FEAT_LE_CIS_PERIPHERAL(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CIS_PERIPHERAL) -#define BT_FEAT_LE_ISO_BROADCASTER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ISO_BROADCASTER) -#define BT_FEAT_LE_SYNC_RECEIVER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_SYNC_RECEIVER) -#define BT_FEAT_LE_ISO_CHANNELS(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_ISO_CHANNELS) -#define BT_FEAT_LE_PWR_CTRL_REQ(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PWR_CTRL_REQ) -#define BT_FEAT_LE_PWR_CHG_IND(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PWR_CHG_IND) -#define BT_FEAT_LE_PATH_LOSS_MONITOR(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PATH_LOSS_MONITOR) -#define BT_FEAT_LE_PER_ADV_ADI_SUPP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) -#define BT_FEAT_LE_CONN_SUBRATING(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_SUBRATING) -#define BT_FEAT_LE_CONN_SUBRATING_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) -#define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) -#define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAWR_ADVERTISER) -#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ - BT_LE_FEAT_BIT_PAWR_SCANNER) - -#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ - BT_FEAT_LE_CIS_PERIPHERAL(feat)) -#define BT_FEAT_LE_BIS(feat) (BT_FEAT_LE_ISO_BROADCASTER(feat) | \ - BT_FEAT_LE_SYNC_RECEIVER(feat)) -#define BT_FEAT_LE_ISO(feat) (BT_FEAT_LE_CIS(feat) | \ - BT_FEAT_LE_BIS(feat)) - -/* LE States */ -#define BT_LE_STATES_PER_CONN_ADV(states) (states & 0x0000004000000000) - -/* Bonding/authentication types */ -#define BT_HCI_NO_BONDING 0x00 -#define BT_HCI_NO_BONDING_MITM 0x01 -#define BT_HCI_DEDICATED_BONDING 0x02 -#define BT_HCI_DEDICATED_BONDING_MITM 0x03 -#define BT_HCI_GENERAL_BONDING 0x04 -#define BT_HCI_GENERAL_BONDING_MITM 0x05 - -/* - * MITM protection is enabled in SSP authentication requirements octet when - * LSB bit is set. - */ -#define BT_MITM 0x01 - -/* I/O capabilities */ -#define BT_IO_DISPLAY_ONLY 0x00 -#define BT_IO_DISPLAY_YESNO 0x01 -#define BT_IO_KEYBOARD_ONLY 0x02 -#define BT_IO_NO_INPUT_OUTPUT 0x03 - -/* SCO packet types */ -#define HCI_PKT_TYPE_HV1 0x0020 -#define HCI_PKT_TYPE_HV2 0x0040 -#define HCI_PKT_TYPE_HV3 0x0080 - -/* eSCO packet types */ -#define HCI_PKT_TYPE_ESCO_HV1 0x0001 -#define HCI_PKT_TYPE_ESCO_HV2 0x0002 -#define HCI_PKT_TYPE_ESCO_HV3 0x0004 -#define HCI_PKT_TYPE_ESCO_EV3 0x0008 -#define HCI_PKT_TYPE_ESCO_EV4 0x0010 -#define HCI_PKT_TYPE_ESCO_EV5 0x0020 -#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 -#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 -#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 -#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 - - -#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ - HCI_PKT_TYPE_ESCO_HV2 | \ - HCI_PKT_TYPE_ESCO_HV3) -#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ - HCI_PKT_TYPE_HV2 | \ - HCI_PKT_TYPE_HV3) -#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ - HCI_PKT_TYPE_ESCO_3EV3 | \ - HCI_PKT_TYPE_ESCO_2EV5 | \ - HCI_PKT_TYPE_ESCO_3EV5) - -/* HCI BR/EDR link types */ -#define BT_HCI_SCO 0x00 -#define BT_HCI_ACL 0x01 -#define BT_HCI_ESCO 0x02 - -/* OpCode Group Fields */ -#define BT_OGF_LINK_CTRL 0x01 -#define BT_OGF_BASEBAND 0x03 -#define BT_OGF_INFO 0x04 -#define BT_OGF_STATUS 0x05 -#define BT_OGF_LE 0x08 -#define BT_OGF_VS 0x3f - -/* Construct OpCode from OGF and OCF */ -#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) - -/* Invalid opcode */ -#define BT_OP_NOP 0x0000 - -/* Obtain OGF from OpCode */ -#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) -/* Obtain OCF from OpCode */ -#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) - -#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) -struct bt_hci_op_inquiry { - uint8_t lap[3]; - uint8_t length; - uint8_t num_rsp; -} __packed; - -#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) - -#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) -struct bt_hci_cp_connect { - bt_addr_t bdaddr; - uint16_t packet_type; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint16_t clock_offset; - uint8_t allow_role_switch; -} __packed; - -#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) -struct bt_hci_cp_disconnect { - uint16_t handle; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) -struct bt_hci_cp_connect_cancel { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_connect_cancel { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) -struct bt_hci_cp_accept_conn_req { - bt_addr_t bdaddr; - uint8_t role; -} __packed; - -#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) -struct bt_hci_cp_setup_sync_conn { - uint16_t handle; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t content_format; - uint8_t retrans_effort; - uint16_t pkt_type; -} __packed; - -#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) -struct bt_hci_cp_accept_sync_conn_req { - bt_addr_t bdaddr; - uint32_t tx_bandwidth; - uint32_t rx_bandwidth; - uint16_t max_latency; - uint16_t content_format; - uint8_t retrans_effort; - uint16_t pkt_type; -} __packed; - -#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) -struct bt_hci_cp_reject_conn_req { - bt_addr_t bdaddr; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) -struct bt_hci_cp_link_key_reply { - bt_addr_t bdaddr; - uint8_t link_key[16]; -} __packed; - -#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) -struct bt_hci_cp_link_key_neg_reply { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) -struct bt_hci_cp_pin_code_reply { - bt_addr_t bdaddr; - uint8_t pin_len; - uint8_t pin_code[16]; -} __packed; -struct bt_hci_rp_pin_code_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) -struct bt_hci_cp_pin_code_neg_reply { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_pin_code_neg_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) -struct bt_hci_cp_auth_requested { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) -struct bt_hci_cp_set_conn_encrypt { - uint16_t handle; - uint8_t encrypt; -} __packed; - -#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) -struct bt_hci_cp_remote_name_request { - bt_addr_t bdaddr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint16_t clock_offset; -} __packed; - -#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) -struct bt_hci_cp_remote_name_cancel { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_remote_name_cancel { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) -struct bt_hci_cp_read_remote_features { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) -struct bt_hci_cp_read_remote_ext_features { - uint16_t handle; - uint8_t page; -} __packed; - -#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) -struct bt_hci_cp_read_remote_version_info { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) -struct bt_hci_cp_io_capability_reply { - bt_addr_t bdaddr; - uint8_t capability; - uint8_t oob_data; - uint8_t authentication; -} __packed; - -#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) -#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) -struct bt_hci_cp_user_confirm_reply { - bt_addr_t bdaddr; -} __packed; -struct bt_hci_rp_user_confirm_reply { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) -struct bt_hci_cp_user_passkey_reply { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) -struct bt_hci_cp_user_passkey_neg_reply { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) -struct bt_hci_cp_io_capability_neg_reply { - bt_addr_t bdaddr; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) -struct bt_hci_cp_set_event_mask { - uint8_t events[8]; -} __packed; - -#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) - -#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) -struct bt_hci_write_local_name { - uint8_t local_name[248]; -} __packed; - -#define BT_HCI_OP_READ_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0015) -struct bt_hci_rp_read_conn_accept_timeout { - uint8_t status; - uint16_t conn_accept_timeout; -} __packed; - -#define BT_HCI_OP_WRITE_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0016) -struct bt_hci_cp_write_conn_accept_timeout { - uint16_t conn_accept_timeout; -} __packed; - -struct bt_hci_rp_write_conn_accept_timeout { - uint8_t status; -} __packed; - -#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) - -#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) -#define BT_BREDR_SCAN_DISABLED 0x00 -#define BT_BREDR_SCAN_INQUIRY 0x01 -#define BT_BREDR_SCAN_PAGE 0x02 - -#define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) -struct bt_hci_cp_write_class_of_device { - uint8_t class_of_device[3]; -} __packed; - -#define BT_TX_POWER_LEVEL_CURRENT 0x00 -#define BT_TX_POWER_LEVEL_MAX 0x01 -#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) -struct bt_hci_cp_read_tx_power_level { - uint16_t handle; - uint8_t type; -} __packed; - -struct bt_hci_rp_read_tx_power_level { - uint8_t status; - uint16_t handle; - int8_t tx_power_level; -} __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) -struct bt_hci_cp_set_ctl_to_host_flow { - uint8_t flow_enable; -} __packed; - -#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) -struct bt_hci_cp_host_buffer_size { - uint16_t acl_mtu; - uint8_t sco_mtu; - uint16_t acl_pkts; - uint16_t sco_pkts; -} __packed; - -struct bt_hci_handle_count { - uint16_t handle; - uint16_t count; -} __packed; - -#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) -struct bt_hci_cp_host_num_completed_packets { - uint8_t num_handles; - struct bt_hci_handle_count h[0]; -} __packed; - -#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) -struct bt_hci_cp_write_inquiry_mode { - uint8_t mode; -} __packed; - -#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) -struct bt_hci_cp_write_ssp_mode { - uint8_t mode; -} __packed; - -#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) -struct bt_hci_cp_set_event_mask_page_2 { - uint8_t events_page_2[8]; -} __packed; - -#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) -struct bt_hci_cp_write_le_host_supp { - uint8_t le; - uint8_t simul; -} __packed; - -#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) -struct bt_hci_cp_write_sc_host_supp { - uint8_t sc_support; -} __packed; - -#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) -struct bt_hci_cp_read_auth_payload_timeout { - uint16_t handle; -} __packed; - -struct bt_hci_rp_read_auth_payload_timeout { - uint8_t status; - uint16_t handle; - uint16_t auth_payload_timeout; -} __packed; - -#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) -struct bt_hci_cp_write_auth_payload_timeout { - uint16_t handle; - uint16_t auth_payload_timeout; -} __packed; - -struct bt_hci_rp_write_auth_payload_timeout { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_CONFIGURE_DATA_PATH BT_OP(BT_OGF_BASEBAND, 0x0083) -struct bt_hci_cp_configure_data_path { - uint8_t data_path_dir; - uint8_t data_path_id; - uint8_t vs_config_len; - uint8_t vs_config[0]; -} __packed; - -struct bt_hci_rp_configure_data_path { - uint8_t status; -} __packed; - -/* HCI version from Assigned Numbers */ -#define BT_HCI_VERSION_1_0B 0 -#define BT_HCI_VERSION_1_1 1 -#define BT_HCI_VERSION_1_2 2 -#define BT_HCI_VERSION_2_0 3 -#define BT_HCI_VERSION_2_1 4 -#define BT_HCI_VERSION_3_0 5 -#define BT_HCI_VERSION_4_0 6 -#define BT_HCI_VERSION_4_1 7 -#define BT_HCI_VERSION_4_2 8 -#define BT_HCI_VERSION_5_0 9 -#define BT_HCI_VERSION_5_1 10 -#define BT_HCI_VERSION_5_2 11 -#define BT_HCI_VERSION_5_3 12 -#define BT_HCI_VERSION_5_4 13 - -#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) -struct bt_hci_rp_read_local_version_info { - uint8_t status; - uint8_t hci_version; - uint16_t hci_revision; - uint8_t lmp_version; - uint16_t manufacturer; - uint16_t lmp_subversion; -} __packed; - -#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) -struct bt_hci_rp_read_supported_commands { - uint8_t status; - uint8_t commands[64]; -} __packed; - -#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) -struct bt_hci_cp_read_local_ext_features { - uint8_t page; -}; -struct bt_hci_rp_read_local_ext_features { - uint8_t status; - uint8_t page; - uint8_t max_page; - uint8_t ext_features[8]; -} __packed; - -#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) -struct bt_hci_rp_read_local_features { - uint8_t status; - uint8_t features[8]; -} __packed; - -#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) -struct bt_hci_rp_read_buffer_size { - uint8_t status; - uint16_t acl_max_len; - uint8_t sco_max_len; - uint16_t acl_max_num; - uint16_t sco_max_num; -} __packed; - -#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) -struct bt_hci_rp_read_bd_addr { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -/* logic transport type bits as returned when reading supported codecs */ -#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_ACL BIT(0) -#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_SCO BIT(1) -#define BT_HCI_CODEC_TRANSPORT_MASK_LE_CIS BIT(2) -#define BT_HCI_CODEC_TRANSPORT_MASK_LE_BIS BIT(3) - -/* logic transport types for reading codec capabilities and controller delays */ -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_ACL 0x00 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_SCO 0x01 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_CIS 0x02 -#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_BIS 0x03 - -/* audio datapath directions */ -#define BT_HCI_DATAPATH_DIR_HOST_TO_CTLR 0x00 -#define BT_HCI_DATAPATH_DIR_CTLR_TO_HOST 0x01 - -/* audio datapath IDs */ -#define BT_HCI_DATAPATH_ID_HCI 0x00 -#define BT_HCI_DATAPATH_ID_VS 0x01 -#define BT_HCI_DATAPATH_ID_VS_END 0xfe - -/* coding format assigned numbers, used for codec IDs */ -#define BT_HCI_CODING_FORMAT_ULAW_LOG 0x00 -#define BT_HCI_CODING_FORMAT_ALAW_LOG 0x01 -#define BT_HCI_CODING_FORMAT_CVSD 0x02 -#define BT_HCI_CODING_FORMAT_TRANSPARENT 0x03 -#define BT_HCI_CODING_FORMAT_LINEAR_PCM 0x04 -#define BT_HCI_CODING_FORMAT_MSBC 0x05 -#define BT_HCI_CODING_FORMAT_VS 0xFF - - -#define BT_HCI_OP_READ_CODECS BT_OP(BT_OGF_INFO, 0x000b) -struct bt_hci_std_codec_info { - uint8_t codec_id; -} __packed; -struct bt_hci_std_codecs { - uint8_t num_codecs; - struct bt_hci_std_codec_info codec_info[0]; -} __packed; -struct bt_hci_vs_codec_info { - uint16_t company_id; - uint16_t codec_id; -} __packed; -struct bt_hci_vs_codecs { - uint8_t num_codecs; - struct bt_hci_vs_codec_info codec_info[0]; -} __packed; -struct bt_hci_rp_read_codecs { - uint8_t status; - /* other fields filled in dynamically */ - uint8_t codecs[0]; -} __packed; - -#define BT_HCI_OP_READ_CODECS_V2 BT_OP(BT_OGF_INFO, 0x000d) -struct bt_hci_std_codec_info_v2 { - uint8_t codec_id; - uint8_t transports; /* bitmap */ -} __packed; -struct bt_hci_std_codecs_v2 { - uint8_t num_codecs; - struct bt_hci_std_codec_info_v2 codec_info[0]; -} __packed; -struct bt_hci_vs_codec_info_v2 { - uint16_t company_id; - uint16_t codec_id; - uint8_t transports; /* bitmap */ -} __packed; -struct bt_hci_vs_codecs_v2 { - uint8_t num_codecs; - struct bt_hci_vs_codec_info_v2 codec_info[0]; -} __packed; -struct bt_hci_rp_read_codecs_v2 { - uint8_t status; - /* other fields filled in dynamically */ - uint8_t codecs[0]; -} __packed; - -struct bt_hci_cp_codec_id { - uint8_t coding_format; - uint16_t company_id; - uint16_t vs_codec_id; -} __packed; - -#define BT_HCI_OP_READ_CODEC_CAPABILITIES BT_OP(BT_OGF_INFO, 0x000e) -struct bt_hci_cp_read_codec_capabilities { - struct bt_hci_cp_codec_id codec_id; - uint8_t transport; - uint8_t direction; -} __packed; -struct bt_hci_codec_capability_info { - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_rp_read_codec_capabilities { - uint8_t status; - uint8_t num_capabilities; - /* other fields filled in dynamically */ - uint8_t capabilities[0]; -} __packed; - -#define BT_HCI_OP_READ_CTLR_DELAY BT_OP(BT_OGF_INFO, 0x000f) -struct bt_hci_cp_read_ctlr_delay { - struct bt_hci_cp_codec_id codec_id; - uint8_t transport; - uint8_t direction; - uint8_t codec_config_len; - uint8_t codec_config[0]; -} __packed; -struct bt_hci_rp_read_ctlr_delay { - uint8_t status; - uint8_t min_ctlr_delay[3]; - uint8_t max_ctlr_delay[3]; -} __packed; - -#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) -struct bt_hci_cp_read_rssi { - uint16_t handle; -} __packed; -struct bt_hci_rp_read_rssi { - uint8_t status; - uint16_t handle; - int8_t rssi; -} __packed; - -#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 -#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 - -#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) -struct bt_hci_cp_read_encryption_key_size { - uint16_t handle; -} __packed; -struct bt_hci_rp_read_encryption_key_size { - uint8_t status; - uint16_t handle; - uint8_t key_size; -} __packed; - -/* BLE */ - -#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) -struct bt_hci_cp_le_set_event_mask { - uint8_t events[8]; -} __packed; - -#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) -struct bt_hci_rp_le_read_buffer_size { - uint8_t status; - uint16_t le_max_len; - uint8_t le_max_num; -} __packed; - -#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) -struct bt_hci_rp_le_read_local_features { - uint8_t status; - uint8_t features[8]; -} __packed; - -#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) -struct bt_hci_cp_le_set_random_address { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_ADV_IND 0x00 -#define BT_HCI_ADV_DIRECT_IND 0x01 -#define BT_HCI_ADV_SCAN_IND 0x02 -#define BT_HCI_ADV_NONCONN_IND 0x03 -#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 -#define BT_HCI_ADV_SCAN_RSP 0x04 - -#define BT_LE_ADV_INTERVAL_MIN 0x0020 -#define BT_LE_ADV_INTERVAL_MAX 0x4000 -#define BT_LE_ADV_INTERVAL_DEFAULT 0x0800 - -#define BT_LE_ADV_CHAN_MAP_CHAN_37 0x01 -#define BT_LE_ADV_CHAN_MAP_CHAN_38 0x02 -#define BT_LE_ADV_CHAN_MAP_CHAN_39 0x04 -#define BT_LE_ADV_CHAN_MAP_ALL 0x07 - -#define BT_LE_ADV_FP_NO_FILTER 0x00 -#define BT_LE_ADV_FP_FILTER_SCAN_REQ 0x01 -#define BT_LE_ADV_FP_FILTER_CONN_IND 0x02 -#define BT_LE_ADV_FP_FILTER_BOTH 0x03 - -#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) -struct bt_hci_cp_le_set_adv_param { - uint16_t min_interval; - uint16_t max_interval; - uint8_t type; - uint8_t own_addr_type; - bt_addr_le_t direct_addr; - uint8_t channel_map; - uint8_t filter_policy; -} __packed; - -#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) -struct bt_hci_rp_le_read_chan_tx_power { - uint8_t status; - int8_t tx_power_level; -} __packed; - -#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) -struct bt_hci_cp_le_set_adv_data { - uint8_t len; - uint8_t data[31]; -} __packed; - -#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) -struct bt_hci_cp_le_set_scan_rsp_data { - uint8_t len; - uint8_t data[31]; -} __packed; - -#define BT_HCI_LE_ADV_DISABLE 0x00 -#define BT_HCI_LE_ADV_ENABLE 0x01 - -#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) -struct bt_hci_cp_le_set_adv_enable { - uint8_t enable; -} __packed; - -/* Scan types */ -#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) -#define BT_HCI_LE_SCAN_PASSIVE 0x00 -#define BT_HCI_LE_SCAN_ACTIVE 0x01 - -#define BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER 0x00 -#define BT_HCI_LE_SCAN_FP_BASIC_FILTER 0x01 -#define BT_HCI_LE_SCAN_FP_EXT_NO_FILTER 0x02 -#define BT_HCI_LE_SCAN_FP_EXT_FILTER 0x03 - -struct bt_hci_cp_le_set_scan_param { - uint8_t scan_type; - uint16_t interval; - uint16_t window; - uint8_t addr_type; - uint8_t filter_policy; -} __packed; - -#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) - -#define BT_HCI_LE_SCAN_DISABLE 0x00 -#define BT_HCI_LE_SCAN_ENABLE 0x01 - -#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 -#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 - -struct bt_hci_cp_le_set_scan_enable { - uint8_t enable; - uint8_t filter_dup; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) - -#define BT_HCI_LE_CREATE_CONN_FP_NO_FILTER 0x00 -#define BT_HCI_LE_CREATE_CONN_FP_FILTER 0x01 - -struct bt_hci_cp_le_create_conn { - uint16_t scan_interval; - uint16_t scan_window; - uint8_t filter_policy; - bt_addr_le_t peer_addr; - uint8_t own_addr_type; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) - -#define BT_HCI_OP_LE_READ_FAL_SIZE BT_OP(BT_OGF_LE, 0x000f) -struct bt_hci_rp_le_read_fal_size { - uint8_t status; - uint8_t fal_size; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_FAL BT_OP(BT_OGF_LE, 0x0010) - -#define BT_HCI_OP_LE_ADD_DEV_TO_FAL BT_OP(BT_OGF_LE, 0x0011) -struct bt_hci_cp_le_add_dev_to_fal { - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_FAL BT_OP(BT_OGF_LE, 0x0012) -struct bt_hci_cp_le_rem_dev_from_fal { - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) -struct hci_cp_le_conn_update { - uint16_t handle; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) -struct bt_hci_cp_le_set_host_chan_classif { - uint8_t ch_map[5]; -} __packed; - -#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) -struct bt_hci_cp_le_read_chan_map { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_read_chan_map { - uint8_t status; - uint16_t handle; - uint8_t ch_map[5]; -} __packed; - -#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) -struct bt_hci_cp_le_read_remote_features { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) -struct bt_hci_cp_le_encrypt { - uint8_t key[16]; - uint8_t plaintext[16]; -} __packed; -struct bt_hci_rp_le_encrypt { - uint8_t status; - uint8_t enc_data[16]; -} __packed; - -#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) -struct bt_hci_rp_le_rand { - uint8_t status; - uint8_t rand[8]; -} __packed; - -#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) -struct bt_hci_cp_le_start_encryption { - uint16_t handle; - uint64_t rand; - uint16_t ediv; - uint8_t ltk[16]; -} __packed; - -#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) -struct bt_hci_cp_le_ltk_req_reply { - uint16_t handle; - uint8_t ltk[16]; -} __packed; -struct bt_hci_rp_le_ltk_req_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) -struct bt_hci_cp_le_ltk_req_neg_reply { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_ltk_req_neg_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) -struct bt_hci_rp_le_read_supp_states { - uint8_t status; - uint8_t le_states[8]; -} __packed; - -#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) -struct bt_hci_cp_le_rx_test { - uint8_t rx_ch; -} __packed; - -#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00 -#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01 -#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02 -#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03 -#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04 -#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05 -#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06 -#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07 - -#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) -struct bt_hci_cp_le_tx_test { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; -} __packed; - -#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) -struct bt_hci_rp_le_test_end { - uint8_t status; - uint16_t rx_pkt_count; -} __packed; - -#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) -struct bt_hci_cp_le_conn_param_req_reply { - uint16_t handle; - uint16_t interval_min; - uint16_t interval_max; - uint16_t latency; - uint16_t timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; -struct bt_hci_rp_le_conn_param_req_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) -struct bt_hci_cp_le_conn_param_req_neg_reply { - uint16_t handle; - uint8_t reason; -} __packed; -struct bt_hci_rp_le_conn_param_req_neg_reply { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) -struct bt_hci_cp_le_set_data_len { - uint16_t handle; - uint16_t tx_octets; - uint16_t tx_time; -} __packed; -struct bt_hci_rp_le_set_data_len { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) -struct bt_hci_rp_le_read_default_data_len { - uint8_t status; - uint16_t max_tx_octets; - uint16_t max_tx_time; -} __packed; - -#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) -struct bt_hci_cp_le_write_default_data_len { - uint16_t max_tx_octets; - uint16_t max_tx_time; -} __packed; - -#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) - -#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) -struct bt_hci_cp_le_generate_dhkey { - uint8_t key[64]; -} __packed; - - -#define BT_HCI_OP_LE_GENERATE_DHKEY_V2 BT_OP(BT_OGF_LE, 0x005e) - -#define BT_HCI_LE_KEY_TYPE_GENERATED 0x00 -#define BT_HCI_LE_KEY_TYPE_DEBUG 0x01 - -struct bt_hci_cp_le_generate_dhkey_v2 { - uint8_t key[64]; - uint8_t key_type; -} __packed; - - -#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) -struct bt_hci_cp_le_add_dev_to_rl { - bt_addr_le_t peer_id_addr; - uint8_t peer_irk[16]; - uint8_t local_irk[16]; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) -struct bt_hci_cp_le_rem_dev_from_rl { - bt_addr_le_t peer_id_addr; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) - -#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) -struct bt_hci_rp_le_read_rl_size { - uint8_t status; - uint8_t rl_size; -} __packed; - -#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) -struct bt_hci_cp_le_read_peer_rpa { - bt_addr_le_t peer_id_addr; -} __packed; -struct bt_hci_rp_le_read_peer_rpa { - uint8_t status; - bt_addr_t peer_rpa; -} __packed; - -#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) -struct bt_hci_cp_le_read_local_rpa { - bt_addr_le_t peer_id_addr; -} __packed; -struct bt_hci_rp_le_read_local_rpa { - uint8_t status; - bt_addr_t local_rpa; -} __packed; - -#define BT_HCI_ADDR_RES_DISABLE 0x00 -#define BT_HCI_ADDR_RES_ENABLE 0x01 - -#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) -struct bt_hci_cp_le_set_addr_res_enable { - uint8_t enable; -} __packed; - -#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) -struct bt_hci_cp_le_set_rpa_timeout { - uint16_t rpa_timeout; -} __packed; - -#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) -struct bt_hci_rp_le_read_max_data_len { - uint8_t status; - uint16_t max_tx_octets; - uint16_t max_tx_time; - uint16_t max_rx_octets; - uint16_t max_rx_time; -} __packed; - -#define BT_HCI_LE_PHY_1M 0x01 -#define BT_HCI_LE_PHY_2M 0x02 -#define BT_HCI_LE_PHY_CODED 0x03 - -#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) -struct bt_hci_cp_le_read_phy { - uint16_t handle; -} __packed; -struct bt_hci_rp_le_read_phy { - uint8_t status; - uint16_t handle; - uint8_t tx_phy; - uint8_t rx_phy; -} __packed; - -#define BT_HCI_LE_PHY_TX_ANY BIT(0) -#define BT_HCI_LE_PHY_RX_ANY BIT(1) - -#define BT_HCI_LE_PHY_PREFER_1M BIT(0) -#define BT_HCI_LE_PHY_PREFER_2M BIT(1) -#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) - -#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) -struct bt_hci_cp_le_set_default_phy { - uint8_t all_phys; - uint8_t tx_phys; - uint8_t rx_phys; -} __packed; - -#define BT_HCI_LE_PHY_CODED_ANY 0x00 -#define BT_HCI_LE_PHY_CODED_S2 0x01 -#define BT_HCI_LE_PHY_CODED_S8 0x02 - -#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) -struct bt_hci_cp_le_set_phy { - uint16_t handle; - uint8_t all_phys; - uint8_t tx_phys; - uint8_t rx_phys; - uint16_t phy_opts; -} __packed; - -#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 -#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 - -#define BT_HCI_LE_RX_PHY_1M 0x01 -#define BT_HCI_LE_RX_PHY_2M 0x02 -#define BT_HCI_LE_RX_PHY_CODED 0x03 - -#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) -struct bt_hci_cp_le_enh_rx_test { - uint8_t rx_ch; - uint8_t phy; - uint8_t mod_index; -} __packed; - -#define BT_HCI_LE_TX_PHY_1M 0x01 -#define BT_HCI_LE_TX_PHY_2M 0x02 -#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 -#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 - -#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) -struct bt_hci_cp_le_enh_tx_test { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; -} __packed; - -#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) -struct bt_hci_cp_le_set_adv_set_random_addr { - uint8_t handle; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_LE_ADV_PROP_CONN BIT(0) -#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) -#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) -#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) -#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) -#define BT_HCI_LE_ADV_PROP_ANON BIT(5) -#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) - -#define BT_HCI_LE_PRIM_ADV_INTERVAL_MIN 0x000020 -#define BT_HCI_LE_PRIM_ADV_INTERVAL_MAX 0xFFFFFF - -#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 -#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 - -#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F - -#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF - -#define BT_HCI_LE_EXT_ADV_SID_INVALID 0xFF - -#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) -struct bt_hci_cp_le_set_ext_adv_param { - uint8_t handle; - uint16_t props; - uint8_t prim_min_interval[3]; - uint8_t prim_max_interval[3]; - uint8_t prim_channel_map; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t filter_policy; - int8_t tx_power; - uint8_t prim_adv_phy; - uint8_t sec_adv_max_skip; - uint8_t sec_adv_phy; - uint8_t sid; - uint8_t scan_req_notify_enable; -} __packed; -struct bt_hci_rp_le_set_ext_adv_param { - uint8_t status; - int8_t tx_power; -} __packed; - -#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 -#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 -#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 -#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 -#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 - -#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 -#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 - -#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 - -#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) -struct bt_hci_cp_le_set_ext_adv_data { - uint8_t handle; - uint8_t op; - uint8_t frag_pref; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) -struct bt_hci_cp_le_set_ext_scan_rsp_data { - uint8_t handle; - uint8_t op; - uint8_t frag_pref; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) -struct bt_hci_ext_adv_set { - uint8_t handle; - uint16_t duration; - uint8_t max_ext_adv_evts; -} __packed; - -struct bt_hci_cp_le_set_ext_adv_enable { - uint8_t enable; - uint8_t set_num; - struct bt_hci_ext_adv_set s[0]; -} __packed; - -#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) -struct bt_hci_rp_le_read_max_adv_data_len { - uint8_t status; - uint16_t max_adv_data_len; -} __packed; - -#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) -struct bt_hci_rp_le_read_num_adv_sets { - uint8_t status; - uint8_t num_sets; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) -struct bt_hci_cp_le_remove_adv_set { - uint8_t handle; -} __packed; - -#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) - -#define BT_HCI_LE_PER_ADV_INTERVAL_MIN 0x0006 -#define BT_HCI_LE_PER_ADV_INTERVAL_MAX 0xFFFF - -#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) -struct bt_hci_cp_le_set_per_adv_param { - uint8_t handle; - uint16_t min_interval; - uint16_t max_interval; - uint16_t props; -} __packed; - -#define BT_HCI_LE_PER_ADV_OP_INTERM_FRAG 0x00 -#define BT_HCI_LE_PER_ADV_OP_FIRST_FRAG 0x01 -#define BT_HCI_LE_PER_ADV_OP_LAST_FRAG 0x02 -#define BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA 0x03 - -#define BT_HCI_LE_PER_ADV_FRAG_MAX_LEN 252 - -#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) -struct bt_hci_cp_le_set_per_adv_data { - uint8_t handle; - uint8_t op; - uint8_t len; - uint8_t data[0]; -} __packed; - -#define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) -#define BT_HCI_LE_SET_PER_ADV_ENABLE_ADI BIT(1) - -#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) -struct bt_hci_cp_le_set_per_adv_enable { - uint8_t enable; - uint8_t handle; -} __packed; - -#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) -struct bt_hci_ext_scan_phy { - uint8_t type; - uint16_t interval; - uint16_t window; -} __packed; - -#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) -#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) -#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) - -struct bt_hci_cp_le_set_ext_scan_param { - uint8_t own_addr_type; - uint8_t filter_policy; - uint8_t phys; - struct bt_hci_ext_scan_phy p[0]; -} __packed; - -/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ -#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 - -#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) -struct bt_hci_cp_le_set_ext_scan_enable { - uint8_t enable; - uint8_t filter_dup; - uint16_t duration; - uint16_t period; -} __packed; - -#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) -#define BT_HCI_OP_LE_EXT_CREATE_CONN_V2 BT_OP(BT_OGF_LE, 0x0085) -struct bt_hci_ext_conn_phy { - uint16_t scan_interval; - uint16_t scan_window; - uint16_t conn_interval_min; - uint16_t conn_interval_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; -} __packed; - -struct bt_hci_cp_le_ext_create_conn { - uint8_t filter_policy; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t phys; - struct bt_hci_ext_conn_phy p[0]; -} __packed; - -struct bt_hci_cp_le_ext_create_conn_v2 { - uint8_t adv_handle; - uint8_t subevent; - uint8_t filter_policy; - uint8_t own_addr_type; - bt_addr_le_t peer_addr; - uint8_t phys; - struct bt_hci_ext_conn_phy p[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_PER_ADV_SUBEVENT_DATA BT_OP(BT_OGF_LE, 0x0082) -struct bt_hci_cp_le_set_pawr_subevent_data_element { - uint8_t subevent; - uint8_t response_slot_start; - uint8_t response_slot_count; - uint8_t subevent_data_length; - uint8_t subevent_data[0]; -} __packed; - -struct bt_hci_cp_le_set_pawr_subevent_data { - uint8_t adv_handle; - uint8_t num_subevents; - struct bt_hci_cp_le_set_pawr_subevent_data_element subevents[0]; -} __packed; - - -#define BT_HCI_OP_LE_SET_PER_ADV_RESPONSE_DATA BT_OP(BT_OGF_LE, 0x0083) -struct bt_hci_cp_le_set_pawr_response_data { - uint16_t sync_handle; - uint16_t request_event; - uint8_t request_subevent; - uint8_t response_subevent; - uint8_t response_slot; - uint8_t response_data_length; - uint8_t response_data[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_PER_ADV_SYNC_SUBEVENT BT_OP(BT_OGF_LE, 0x0084) -struct bt_hci_cp_le_set_pawr_sync_subevent { - uint16_t sync_handle; - uint16_t periodic_adv_properties; - uint8_t num_subevents; - uint8_t subevents[0]; -} __packed; - - -#define BT_HCI_OP_LE_SET_PER_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x0086) -struct bt_hci_cp_le_set_per_adv_param_v2 { - uint8_t handle; - uint16_t min_interval; - uint16_t max_interval; - uint16_t props; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; - uint8_t num_response_slots; -} __packed; - - -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2) - -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US BIT(1) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US BIT(2) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE BIT(3) -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE BIT(4) -/* Constants to check correctness of CTE type */ -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS 5 -#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_INVALID_VALUE \ - (~BIT_MASK(BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS)) - -#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) -struct bt_hci_cp_le_per_adv_create_sync { - uint8_t options; - uint8_t sid; - bt_addr_le_t addr; - uint16_t skip; - uint16_t sync_timeout; - uint8_t cte_type; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) - -#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) -struct bt_hci_cp_le_per_adv_terminate_sync { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) -struct bt_hci_cp_le_add_dev_to_per_adv_list { - bt_addr_le_t addr; - uint8_t sid; -} __packed; - -#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) -struct bt_hci_cp_le_rem_dev_from_per_adv_list { - bt_addr_le_t addr; - uint8_t sid; -} __packed; - -#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) - -#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) -struct bt_hci_rp_le_read_per_adv_list_size { - uint8_t status; - uint8_t list_size; -} __packed; - -#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) -struct bt_hci_rp_le_read_tx_power { - uint8_t status; - int8_t min_tx_power; - int8_t max_tx_power; -} __packed; - -#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) -struct bt_hci_rp_le_read_rf_path_comp { - uint8_t status; - int16_t tx_path_comp; - int16_t rx_path_comp; -} __packed; - -#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) -struct bt_hci_cp_le_write_rf_path_comp { - int16_t tx_path_comp; - int16_t rx_path_comp; -} __packed; - -#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 -#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 - -#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) -struct bt_hci_cp_le_set_privacy_mode { - bt_addr_le_t id_addr; - uint8_t mode; -} __packed; - -#define BT_HCI_LE_TEST_CTE_DISABLED 0x00 -#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00 -#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00 -#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00 - -#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f) -struct bt_hci_cp_le_rx_test_v3 { - uint8_t rx_ch; - uint8_t phy; - uint8_t mod_index; - uint8_t expected_cte_len; - uint8_t expected_cte_type; - uint8_t slot_durations; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050) - -struct bt_hci_cp_le_tx_test_v3 { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; - uint8_t cte_len; - uint8_t cte_type; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -/* Min and max Constant Tone Extension length in 8us units */ -#define BT_HCI_LE_CTE_LEN_MIN 0x2 -#define BT_HCI_LE_CTE_LEN_MAX 0x14 - -#define BT_HCI_LE_AOA_CTE 0x0 -#define BT_HCI_LE_AOD_CTE_1US 0x1 -#define BT_HCI_LE_AOD_CTE_2US 0x2 -#define BT_HCI_LE_NO_CTE 0xFF - -#define BT_HCI_LE_CTE_COUNT_MIN 0x1 -#define BT_HCI_LE_CTE_COUNT_MAX 0x10 - -#define BT_HCI_OP_LE_SET_CL_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0051) -struct bt_hci_cp_le_set_cl_cte_tx_params { - uint8_t handle; - uint8_t cte_len; - uint8_t cte_type; - uint8_t cte_count; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_CL_CTE_TX_ENABLE BT_OP(BT_OGF_LE, 0x0052) -struct bt_hci_cp_le_set_cl_cte_tx_enable { - uint8_t handle; - uint8_t cte_enable; -} __packed; - -#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US 0x1 -#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US 0x2 - -#define BT_HCI_LE_SAMPLE_CTE_ALL 0x0 -#define BT_HCI_LE_SAMPLE_CTE_COUNT_MIN 0x1 -#define BT_HCI_LE_SAMPLE_CTE_COUNT_MAX 0x10 - -#define BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE BT_OP(BT_OGF_LE, 0x0053) -struct bt_hci_cp_le_set_cl_cte_sampling_enable { - uint16_t sync_handle; - uint8_t sampling_enable; - uint8_t slot_durations; - uint8_t max_sampled_cte; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_cl_cte_sampling_enable { - uint8_t status; - uint16_t sync_handle; -} __packed; - -#define BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS BT_OP(BT_OGF_LE, 0x0054) -struct bt_hci_cp_le_set_conn_cte_rx_params { - uint16_t handle; - uint8_t sampling_enable; - uint8_t slot_durations; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_conn_cte_rx_params { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_LE_AOA_CTE_RSP BIT(0) -#define BT_HCI_LE_AOD_CTE_RSP_1US BIT(1) -#define BT_HCI_LE_AOD_CTE_RSP_2US BIT(2) - -#define BT_HCI_LE_SWITCH_PATTERN_LEN_MIN 0x2 -#define BT_HCI_LE_SWITCH_PATTERN_LEN_MAX 0x4B - -#define BT_HCI_OP_LE_SET_CONN_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0055) -struct bt_hci_cp_le_set_conn_cte_tx_params { - uint16_t handle; - uint8_t cte_types; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -struct bt_hci_rp_le_set_conn_cte_tx_params { - uint8_t status; - uint16_t handle; -} __packed; - -/* Interval between consecutive CTE request procedure starts in number of connection events. */ -#define BT_HCI_REQUEST_CTE_ONCE 0x0 -#define BT_HCI_REQUEST_CTE_INTERVAL_MIN 0x1 -#define BT_HCI_REQUEST_CTE_INTERVAL_MAX 0xFFFF - -#define BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE BT_OP(BT_OGF_LE, 0x0056) -struct bt_hci_cp_le_conn_cte_req_enable { - uint16_t handle; - uint8_t enable; - uint16_t cte_request_interval; - uint8_t requested_cte_length; - uint8_t requested_cte_type; -} __packed; - -struct bt_hci_rp_le_conn_cte_req_enable { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE BT_OP(BT_OGF_LE, 0x0057) -struct bt_hci_cp_le_conn_cte_rsp_enable { - uint16_t handle; - uint8_t enable; -} __packed; - -struct bt_hci_rp_le_conn_cte_rsp_enable { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_LE_1US_AOD_TX BIT(0) -#define BT_HCI_LE_1US_AOD_RX BIT(1) -#define BT_HCI_LE_1US_AOA_RX BIT(2) - -#define BT_HCI_LE_NUM_ANT_MIN 0x1 -#define BT_HCI_LE_NUM_ANT_MAX 0x4B - -#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MIN 0x2 -#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MAX 0x4B - -#define BT_HCI_LE_MAX_CTE_LEN_MIN 0x2 -#define BT_HCI_LE_MAX_CTE_LEN_MAX 0x14 - -#define BT_HCI_OP_LE_READ_ANT_INFO BT_OP(BT_OGF_LE, 0x0058) -struct bt_hci_rp_le_read_ant_info { - uint8_t status; - uint8_t switch_sample_rates; - uint8_t num_ant; - uint8_t max_switch_pattern_len; - uint8_t max_cte_len; -}; - -#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_ENABLE BIT(0) -#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_FILTER_DUPLICATE BIT(1) - -#define BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE BT_OP(BT_OGF_LE, 0x0059) -struct bt_hci_cp_le_set_per_adv_recv_enable { - uint16_t handle; - uint8_t enable; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER BT_OP(BT_OGF_LE, 0x005a) -struct bt_hci_cp_le_per_adv_sync_transfer { - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; -} __packed; - -struct bt_hci_rp_le_per_adv_sync_transfer { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER BT_OP(BT_OGF_LE, 0x005b) -struct bt_hci_cp_le_per_adv_set_info_transfer { - uint16_t conn_handle; - uint16_t service_data; - uint8_t adv_handle; -} __packed; - -struct bt_hci_rp_le_per_adv_set_info_transfer { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_LE_PAST_MODE_NO_SYNC 0x00 -#define BT_HCI_LE_PAST_MODE_NO_REPORTS 0x01 -#define BT_HCI_LE_PAST_MODE_SYNC 0x02 -#define BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES 0x03 - -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOA BIT(0) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_1US BIT(1) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_2US BIT(2) -#define BT_HCI_LE_PAST_CTE_TYPE_NO_CTE BIT(3) -#define BT_HCI_LE_PAST_CTE_TYPE_ONLY_CTE BIT(4) - -#define BT_HCI_OP_LE_PAST_PARAM BT_OP(BT_OGF_LE, 0x005c) -struct bt_hci_cp_le_past_param { - uint16_t conn_handle; - uint8_t mode; - uint16_t skip; - uint16_t timeout; - uint8_t cte_type; -} __packed; - -struct bt_hci_rp_le_past_param { - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_OP_LE_DEFAULT_PAST_PARAM BT_OP(BT_OGF_LE, 0x005d) -struct bt_hci_cp_le_default_past_param { - uint8_t mode; - uint16_t skip; - uint16_t timeout; - uint8_t cte_type; -} __packed; - -struct bt_hci_rp_le_default_past_param { - uint8_t status; -} __packed; - -#define BT_HCI_OP_LE_READ_BUFFER_SIZE_V2 BT_OP(BT_OGF_LE, 0x0060) -struct bt_hci_rp_le_read_buffer_size_v2 { - uint8_t status; - uint16_t acl_max_len; - uint8_t acl_max_num; - uint16_t iso_max_len; - uint8_t iso_max_num; -} __packed; - -#define BT_HCI_OP_LE_READ_ISO_TX_SYNC BT_OP(BT_OGF_LE, 0x0061) -struct bt_hci_cp_le_read_iso_tx_sync { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_iso_tx_sync { - uint8_t status; - uint16_t handle; - uint16_t seq; - uint32_t timestamp; - uint8_t offset[3]; -} __packed; - -#define BT_HCI_ISO_CIG_ID_MAX 0xFE -#define BT_HCI_ISO_CIS_COUNT_MAX 0x1F -#define BT_HCI_ISO_SDU_INTERVAL_MIN 0x0000FF -#define BT_HCI_ISO_SDU_INTERVAL_MAX 0x0FFFFF -#define BT_HCI_ISO_WORST_CASE_SCA_VALID_MASK 0x07 -#define BT_HCI_ISO_PACKING_VALID_MASK 0x01 -#define BT_HCI_ISO_FRAMING_VALID_MASK 0x01 -#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN 0x0005 -#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX 0x0FA0 -#define BT_HCI_ISO_CIS_ID_VALID_MAX 0xEF -#define BT_HCI_ISO_MAX_SDU_VALID_MASK 0x0FFF -#define BT_HCI_ISO_PHY_VALID_MASK 0x07 -#define BT_HCI_ISO_INTERVAL_MIN 0x0004 -#define BT_HCI_ISO_INTERVAL_MAX 0x0C80 - -#define BT_HCI_OP_LE_SET_CIG_PARAMS BT_OP(BT_OGF_LE, 0x0062) -struct bt_hci_cis_params { - uint8_t cis_id; - uint16_t c_sdu; - uint16_t p_sdu; - uint8_t c_phy; - uint8_t p_phy; - uint8_t c_rtn; - uint8_t p_rtn; -} __packed; - -struct bt_hci_cp_le_set_cig_params { - uint8_t cig_id; - uint8_t c_interval[3]; - uint8_t p_interval[3]; - uint8_t sca; - uint8_t packing; - uint8_t framing; - uint16_t c_latency; - uint16_t p_latency; - uint8_t num_cis; - struct bt_hci_cis_params cis[0]; -} __packed; - -struct bt_hci_rp_le_set_cig_params { - uint8_t status; - uint8_t cig_id; - uint8_t num_handles; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_OP_LE_SET_CIG_PARAMS_TEST BT_OP(BT_OGF_LE, 0x0063) -struct bt_hci_cis_params_test { - uint8_t cis_id; - uint8_t nse; - uint16_t c_sdu; - uint16_t p_sdu; - uint16_t c_pdu; - uint16_t p_pdu; - uint8_t c_phy; - uint8_t p_phy; - uint8_t c_bn; - uint8_t p_bn; -} __packed; - -struct bt_hci_cp_le_set_cig_params_test { - uint8_t cig_id; - uint8_t c_interval[3]; - uint8_t p_interval[3]; - uint8_t c_ft; - uint8_t p_ft; - uint16_t iso_interval; - uint8_t sca; - uint8_t packing; - uint8_t framing; - uint8_t num_cis; - struct bt_hci_cis_params_test cis[0]; -} __packed; - -struct bt_hci_rp_le_set_cig_params_test { - uint8_t status; - uint8_t cig_id; - uint8_t num_handles; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_OP_LE_CREATE_CIS BT_OP(BT_OGF_LE, 0x0064) -struct bt_hci_cis { - uint16_t cis_handle; - uint16_t acl_handle; -} __packed; - -struct bt_hci_cp_le_create_cis { - uint8_t num_cis; - struct bt_hci_cis cis[0]; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_CIG BT_OP(BT_OGF_LE, 0x0065) -struct bt_hci_cp_le_remove_cig { - uint8_t cig_id; -} __packed; - -struct bt_hci_rp_le_remove_cig { - uint8_t status; - uint8_t cig_id; -} __packed; - -#define BT_HCI_OP_LE_ACCEPT_CIS BT_OP(BT_OGF_LE, 0x0066) -struct bt_hci_cp_le_accept_cis { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_REJECT_CIS BT_OP(BT_OGF_LE, 0x0067) -struct bt_hci_cp_le_reject_cis { - uint16_t handle; - uint8_t reason; -} __packed; - -struct bt_hci_rp_le_reject_cis { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_CREATE_BIG BT_OP(BT_OGF_LE, 0x0068) -struct bt_hci_cp_le_create_big { - uint8_t big_handle; - uint8_t adv_handle; - uint8_t num_bis; - uint8_t sdu_interval[3]; - uint16_t max_sdu; - uint16_t max_latency; - uint8_t rtn; - uint8_t phy; - uint8_t packing; - uint8_t framing; - uint8_t encryption; - uint8_t bcode[16]; -} __packed; - -#define BT_HCI_OP_LE_CREATE_BIG_TEST BT_OP(BT_OGF_LE, 0x0069) -struct bt_hci_cp_le_create_big_test { - uint8_t big_handle; - uint8_t adv_handle; - uint8_t num_bis; - uint8_t sdu_interval[3]; - uint16_t iso_interval; - uint8_t nse; - uint16_t max_sdu; - uint16_t max_pdu; - uint8_t phy; - uint8_t packing; - uint8_t framing; - uint8_t bn; - uint8_t irc; - uint8_t pto; - uint8_t encryption; - uint8_t bcode[16]; -} __packed; - -#define BT_HCI_OP_LE_TERMINATE_BIG BT_OP(BT_OGF_LE, 0x006a) -struct bt_hci_cp_le_terminate_big { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_OP_LE_BIG_CREATE_SYNC BT_OP(BT_OGF_LE, 0x006b) -struct bt_hci_cp_le_big_create_sync { - uint8_t big_handle; - uint16_t sync_handle; - uint8_t encryption; - uint8_t bcode[16]; - uint8_t mse; - uint16_t sync_timeout; - uint8_t num_bis; - uint8_t bis[0]; -} __packed; - -#define BT_HCI_OP_LE_BIG_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x006c) -struct bt_hci_cp_le_big_terminate_sync { - uint8_t big_handle; -} __packed; - -struct bt_hci_rp_le_big_terminate_sync { - uint8_t status; - uint8_t big_handle; -} __packed; - -#define BT_HCI_OP_LE_REQ_PEER_SC BT_OP(BT_OGF_LE, 0x006d) -struct bt_hci_cp_le_req_peer_sca { - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_SETUP_ISO_PATH BT_OP(BT_OGF_LE, 0x006e) -struct bt_hci_cp_le_setup_iso_path { - uint16_t handle; - uint8_t path_dir; - uint8_t path_id; - struct bt_hci_cp_codec_id codec_id; - uint8_t controller_delay[3]; - uint8_t codec_config_len; - uint8_t codec_config[0]; -} __packed; - -struct bt_hci_rp_le_setup_iso_path { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_REMOVE_ISO_PATH BT_OP(BT_OGF_LE, 0x006f) -struct bt_hci_cp_le_remove_iso_path { - uint16_t handle; - uint8_t path_dir; -} __packed; - -struct bt_hci_rp_le_remove_iso_path { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU 0 -#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1 -#define BT_HCI_ISO_TEST_MAX_SIZE_SDU 2 - -#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST BT_OP(BT_OGF_LE, 0x0070) -struct bt_hci_cp_le_iso_transmit_test { - uint16_t handle; - uint8_t payload_type; -} __packed; - -struct bt_hci_rp_le_iso_transmit_test { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ISO_RECEIVE_TEST BT_OP(BT_OGF_LE, 0x0071) -struct bt_hci_cp_le_iso_receive_test { - uint16_t handle; - uint8_t payload_type; -} __packed; - -struct bt_hci_rp_le_iso_receive_test { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_OP_LE_ISO_READ_TEST_COUNTERS BT_OP(BT_OGF_LE, 0x0072) -struct bt_hci_cp_le_read_test_counters { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_test_counters { - uint8_t status; - uint16_t handle; - uint32_t received_cnt; - uint32_t missed_cnt; - uint32_t failed_cnt; -} __packed; - -#define BT_HCI_OP_LE_ISO_TEST_END BT_OP(BT_OGF_LE, 0x0073) -struct bt_hci_cp_le_iso_test_end { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_iso_test_end { - uint8_t status; - uint16_t handle; - uint32_t received_cnt; - uint32_t missed_cnt; - uint32_t failed_cnt; -} __packed; - -#define BT_HCI_OP_LE_SET_HOST_FEATURE BT_OP(BT_OGF_LE, 0x0074) -struct bt_hci_cp_le_set_host_feature { - uint8_t bit_number; - uint8_t bit_value; -} __packed; - -struct bt_hci_rp_le_set_host_feature { - uint8_t status; -} __packed; - -#define BT_HCI_OP_LE_READ_ISO_LINK_QUALITY BT_OP(BT_OGF_LE, 0x0075) -struct bt_hci_cp_le_read_iso_link_quality { - uint16_t handle; -} __packed; - -struct bt_hci_rp_le_read_iso_link_quality { - uint8_t status; - uint16_t handle; - uint32_t tx_unacked_packets; - uint32_t tx_flushed_packets; - uint32_t tx_last_subevent_packets; - uint32_t retransmitted_packets; - uint32_t crc_error_packets; - uint32_t rx_unreceived_packets; - uint32_t duplicate_packets; -} __packed; - -#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B) - -struct bt_hci_cp_le_tx_test_v4 { - uint8_t tx_ch; - uint8_t test_data_len; - uint8_t pkt_payload; - uint8_t phy; - uint8_t cte_len; - uint8_t cte_type; - uint8_t switch_pattern_len; - uint8_t ant_ids[0]; -} __packed; - -#define BT_HCI_TX_TEST_POWER_MIN -0x7F -#define BT_HCI_TX_TEST_POWER_MAX 0x14 - -#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E -#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F - -/* Helper structure for Tx power parameter in the HCI Tx Test v4 command. - * Previous parameter of this command is variable size so having separated structure - * for this parameter helps in command parameters unpacking. - */ -struct bt_hci_cp_le_tx_test_v4_tx_power { - int8_t tx_power; -} __packed; - -/* Event definitions */ - -#define BT_HCI_EVT_UNKNOWN 0x00 -#define BT_HCI_EVT_VENDOR 0xff - -#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 -struct bt_hci_evt_inquiry_complete { - uint8_t status; -} __packed; - -#define BT_HCI_EVT_CONN_COMPLETE 0x03 -struct bt_hci_evt_conn_complete { - uint8_t status; - uint16_t handle; - bt_addr_t bdaddr; - uint8_t link_type; - uint8_t encr_enabled; -} __packed; - -#define BT_HCI_EVT_CONN_REQUEST 0x04 -struct bt_hci_evt_conn_request { - bt_addr_t bdaddr; - uint8_t dev_class[3]; - uint8_t link_type; -} __packed; - -#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 -struct bt_hci_evt_disconn_complete { - uint8_t status; - uint16_t handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_AUTH_COMPLETE 0x06 -struct bt_hci_evt_auth_complete { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 -struct bt_hci_evt_remote_name_req_complete { - uint8_t status; - bt_addr_t bdaddr; - uint8_t name[248]; -} __packed; - -#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 -struct bt_hci_evt_encrypt_change { - uint8_t status; - uint16_t handle; - uint8_t encrypt; -} __packed; - -#define BT_HCI_EVT_REMOTE_FEATURES 0x0b -struct bt_hci_evt_remote_features { - uint8_t status; - uint16_t handle; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c -struct bt_hci_evt_remote_version_info { - uint8_t status; - uint16_t handle; - uint8_t version; - uint16_t manufacturer; - uint16_t subversion; -} __packed; - -#define BT_HCI_EVT_CMD_COMPLETE 0x0e -struct bt_hci_evt_cmd_complete { - uint8_t ncmd; - uint16_t opcode; -} __packed; - -struct bt_hci_evt_cc_status { - uint8_t status; -} __packed; - -#define BT_HCI_EVT_CMD_STATUS 0x0f -struct bt_hci_evt_cmd_status { - uint8_t status; - uint8_t ncmd; - uint16_t opcode; -} __packed; - -#define BT_HCI_EVT_HARDWARE_ERROR 0x10 -struct bt_hci_evt_hardware_error { - uint8_t hardware_code; -} __packed; - -#define BT_HCI_EVT_ROLE_CHANGE 0x12 -struct bt_hci_evt_role_change { - uint8_t status; - bt_addr_t bdaddr; - uint8_t role; -} __packed; - -#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 -struct bt_hci_evt_num_completed_packets { - uint8_t num_handles; - struct bt_hci_handle_count h[0]; -} __packed; - -#define BT_HCI_EVT_PIN_CODE_REQ 0x16 -struct bt_hci_evt_pin_code_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_LINK_KEY_REQ 0x17 -struct bt_hci_evt_link_key_req { - bt_addr_t bdaddr; -} __packed; - -/* Link Key types */ -#define BT_LK_COMBINATION 0x00 -#define BT_LK_LOCAL_UNIT 0x01 -#define BT_LK_REMOTE_UNIT 0x02 -#define BT_LK_DEBUG_COMBINATION 0x03 -#define BT_LK_UNAUTH_COMBINATION_P192 0x04 -#define BT_LK_AUTH_COMBINATION_P192 0x05 -#define BT_LK_CHANGED_COMBINATION 0x06 -#define BT_LK_UNAUTH_COMBINATION_P256 0x07 -#define BT_LK_AUTH_COMBINATION_P256 0x08 - -#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 -struct bt_hci_evt_link_key_notify { - bt_addr_t bdaddr; - uint8_t link_key[16]; - uint8_t key_type; -} __packed; - -/* Overflow link types */ -#define BT_OVERFLOW_LINK_SYNCH 0x00 -#define BT_OVERFLOW_LINK_ACL 0x01 -#define BT_OVERFLOW_LINK_ISO 0x02 - -#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a -struct bt_hci_evt_data_buf_overflow { - uint8_t link_type; -} __packed; - -#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 -struct bt_hci_evt_inquiry_result_with_rssi { - bt_addr_t addr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint8_t cod[3]; - uint16_t clock_offset; - int8_t rssi; -} __packed; - -#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 -struct bt_hci_evt_remote_ext_features { - uint8_t status; - uint16_t handle; - uint8_t page; - uint8_t max_page; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED_V2 0x24 -struct bt_hci_evt_le_per_adv_sync_established_v2 { - uint8_t status; - uint16_t handle; - uint8_t sid; - bt_addr_le_t adv_addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2 0x25 -struct bt_hci_evt_le_per_advertising_report_v2 { - uint16_t handle; - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint16_t periodic_event_counter; - uint8_t subevent; - uint8_t data_status; - uint8_t length; - uint8_t data[0]; -} __packed; - -#define BT_HCI_EVT_LE_PAST_RECEIVED_V2 0x26 -struct bt_hci_evt_le_past_received_v2 { - uint8_t status; - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; - uint8_t adv_sid; - bt_addr_le_t addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; - uint8_t num_subevents; - uint8_t subevent_interval; - uint8_t response_slot_delay; - uint8_t response_slot_spacing; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SUBEVENT_DATA_REQUEST 0x27 -struct bt_hci_evt_le_per_adv_subevent_data_request { - uint8_t adv_handle; - uint8_t subevent_start; - uint8_t subevent_data_count; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_RESPONSE_REPORT 0x28 - -struct bt_hci_evt_le_per_adv_response { - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint8_t response_slot; - uint8_t data_status; - uint8_t data_length; - uint8_t data[0]; -} __packed; - -struct bt_hci_evt_le_per_adv_response_report { - uint8_t adv_handle; - uint8_t subevent; - uint8_t tx_status; - uint8_t num_responses; - struct bt_hci_evt_le_per_adv_response responses[0]; -} __packed; - -#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2 0x29 -struct bt_hci_evt_le_enh_conn_complete_v2 { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - bt_addr_t local_rpa; - bt_addr_t peer_rpa; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; - uint8_t adv_handle; - uint16_t sync_handle; -} __packed; - -#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c -struct bt_hci_evt_sync_conn_complete { - uint8_t status; - uint16_t handle; - bt_addr_t bdaddr; - uint8_t link_type; - uint8_t tx_interval; - uint8_t retansmission_window; - uint16_t rx_pkt_length; - uint16_t tx_pkt_length; - uint8_t air_mode; -} __packed; - -#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f -struct bt_hci_evt_extended_inquiry_result { - uint8_t num_reports; - bt_addr_t addr; - uint8_t pscan_rep_mode; - uint8_t reserved; - uint8_t cod[3]; - uint16_t clock_offset; - int8_t rssi; - uint8_t eir[240]; -} __packed; - -#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 -struct bt_hci_evt_encrypt_key_refresh_complete { - uint8_t status; - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_IO_CAPA_REQ 0x31 -struct bt_hci_evt_io_capa_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_IO_CAPA_RESP 0x32 -struct bt_hci_evt_io_capa_resp { - bt_addr_t bdaddr; - uint8_t capability; - uint8_t oob_data; - uint8_t authentication; -} __packed; - -#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 -struct bt_hci_evt_user_confirm_req { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 -struct bt_hci_evt_user_passkey_req { - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_SSP_COMPLETE 0x36 -struct bt_hci_evt_ssp_complete { - uint8_t status; - bt_addr_t bdaddr; -} __packed; - -#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b -struct bt_hci_evt_user_passkey_notify { - bt_addr_t bdaddr; - uint32_t passkey; -} __packed; - -#define BT_HCI_EVT_LE_META_EVENT 0x3e -struct bt_hci_evt_le_meta_event { - uint8_t subevent; -} __packed; - -#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 -struct bt_hci_evt_auth_payload_timeout_exp { - uint16_t handle; -} __packed; - -#define BT_HCI_ROLE_CENTRAL 0x00 -#define BT_HCI_ROLE_PERIPHERAL 0x01 - -#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 -struct bt_hci_evt_le_conn_complete { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_LE_RSSI_NOT_AVAILABLE 0x7F - -#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 -struct bt_hci_evt_le_advertising_info { - uint8_t evt_type; - bt_addr_le_t addr; - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_evt_le_advertising_report { - uint8_t num_reports; - struct bt_hci_evt_le_advertising_info adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 -struct bt_hci_evt_le_conn_update_complete { - uint8_t status; - uint16_t handle; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; -} __packed; - -#define BT_HCI_EVT_LE_REMOTE_FEAT_COMPLETE 0x04 -struct bt_hci_evt_le_remote_feat_complete { - uint8_t status; - uint16_t handle; - uint8_t features[8]; -} __packed; - -#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 -struct bt_hci_evt_le_ltk_request { - uint16_t handle; - uint64_t rand; - uint16_t ediv; -} __packed; - -#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 -struct bt_hci_evt_le_conn_param_req { - uint16_t handle; - uint16_t interval_min; - uint16_t interval_max; - uint16_t latency; - uint16_t timeout; -} __packed; - -#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 -struct bt_hci_evt_le_data_len_change { - uint16_t handle; - uint16_t max_tx_octets; - uint16_t max_tx_time; - uint16_t max_rx_octets; - uint16_t max_rx_time; -} __packed; - -#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 -struct bt_hci_evt_le_p256_public_key_complete { - uint8_t status; - uint8_t key[64]; -} __packed; - -#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 -struct bt_hci_evt_le_generate_dhkey_complete { - uint8_t status; - uint8_t dhkey[32]; -} __packed; - -#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a -struct bt_hci_evt_le_enh_conn_complete { - uint8_t status; - uint16_t handle; - uint8_t role; - bt_addr_le_t peer_addr; - bt_addr_t local_rpa; - bt_addr_t peer_rpa; - uint16_t interval; - uint16_t latency; - uint16_t supv_timeout; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b -struct bt_hci_evt_le_direct_adv_info { - uint8_t evt_type; - bt_addr_le_t addr; - bt_addr_le_t dir_addr; - int8_t rssi; -} __packed; -struct bt_hci_evt_le_direct_adv_report { - uint8_t num_reports; - struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c -struct bt_hci_evt_le_phy_update_complete { - uint8_t status; - uint16_t handle; - uint8_t tx_phy; - uint8_t rx_phy; -} __packed; - -#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d - -#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) -#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) -#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) -#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) -#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) - -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 -#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF - -struct bt_hci_evt_le_ext_advertising_info { - uint16_t evt_type; - bt_addr_le_t addr; - uint8_t prim_phy; - uint8_t sec_phy; - uint8_t sid; - int8_t tx_power; - int8_t rssi; - uint16_t interval; - bt_addr_le_t direct_addr; - uint8_t length; - uint8_t data[0]; -} __packed; -struct bt_hci_evt_le_ext_advertising_report { - uint8_t num_reports; - struct bt_hci_evt_le_ext_advertising_info adv_info[0]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e -struct bt_hci_evt_le_per_adv_sync_established { - uint8_t status; - uint16_t handle; - uint8_t sid; - bt_addr_le_t adv_addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f -struct bt_hci_evt_le_per_advertising_report { - uint16_t handle; - int8_t tx_power; - int8_t rssi; - uint8_t cte_type; - uint8_t data_status; - uint8_t length; - uint8_t data[0]; -} __packed; - -#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 -struct bt_hci_evt_le_per_adv_sync_lost { - uint16_t handle; -} __packed; - -#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 - -#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 -struct bt_hci_evt_le_adv_set_terminated { - uint8_t status; - uint8_t adv_handle; - uint16_t conn_handle; - uint8_t num_completed_ext_adv_evts; -} __packed; - -#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 -struct bt_hci_evt_le_scan_req_received { - uint8_t handle; - bt_addr_le_t addr; -} __packed; - -#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 -#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 - -#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 -struct bt_hci_evt_le_chan_sel_algo { - uint16_t handle; - uint8_t chan_sel_algo; -} __packed; - -#define BT_HCI_LE_CTE_CRC_OK 0x0 -#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME 0x1 -#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER 0x2 -#define BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES 0xFF - -#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MIN 0x9 -#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX 0x52 - -#define BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE 0x80 - -#define BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT 0x15 -struct bt_hci_le_iq_sample { - int8_t i; - int8_t q; -}; - -struct bt_hci_evt_le_connectionless_iq_report { - uint16_t sync_handle; - uint8_t chan_idx; - int16_t rssi; - uint8_t rssi_ant_id; - uint8_t cte_type; - uint8_t slot_durations; - uint8_t packet_status; - uint16_t per_evt_counter; - uint8_t sample_count; - struct bt_hci_le_iq_sample sample[0]; -} __packed; - -#define BT_HCI_EVT_LE_CONNECTION_IQ_REPORT 0x16 -struct bt_hci_evt_le_connection_iq_report { - uint16_t conn_handle; - uint8_t rx_phy; - uint8_t data_chan_idx; - int16_t rssi; - uint8_t rssi_ant_id; - uint8_t cte_type; - uint8_t slot_durations; - uint8_t packet_status; - uint16_t conn_evt_counter; - uint8_t sample_count; - struct bt_hci_le_iq_sample sample[0]; -} __packed; - -#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 - -#define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 -struct bt_hci_evt_le_cte_req_failed { - /* According to BT 5.3 Core Spec the status field may have following - * values: - * - BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE when received LL_CTE_RSP_PDU without CTE. - * - Other Controller error code for peer rejected request. - */ - uint8_t status; - uint16_t conn_handle; -} __packed; - -#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18 -struct bt_hci_evt_le_past_received { - uint8_t status; - uint16_t conn_handle; - uint16_t service_data; - uint16_t sync_handle; - uint8_t adv_sid; - bt_addr_le_t addr; - uint8_t phy; - uint16_t interval; - uint8_t clock_accuracy; -} __packed; - -#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 -struct bt_hci_evt_le_cis_established { - uint8_t status; - uint16_t conn_handle; - uint8_t cig_sync_delay[3]; - uint8_t cis_sync_delay[3]; - uint8_t c_latency[3]; - uint8_t p_latency[3]; - uint8_t c_phy; - uint8_t p_phy; - uint8_t nse; - uint8_t c_bn; - uint8_t p_bn; - uint8_t c_ft; - uint8_t p_ft; - uint16_t c_max_pdu; - uint16_t p_max_pdu; - uint16_t interval; -} __packed; - -#define BT_HCI_EVT_LE_CIS_REQ 0x1a -struct bt_hci_evt_le_cis_req { - uint16_t acl_handle; - uint16_t cis_handle; - uint8_t cig_id; - uint8_t cis_id; -} __packed; - -#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b -struct bt_hci_evt_le_big_complete { - uint8_t status; - uint8_t big_handle; - uint8_t sync_delay[3]; - uint8_t latency[3]; - uint8_t phy; - uint8_t nse; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint16_t iso_interval; - uint8_t num_bis; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c -struct bt_hci_evt_le_big_terminate { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d -struct bt_hci_evt_le_big_sync_established { - uint8_t status; - uint8_t big_handle; - uint8_t latency[3]; - uint8_t nse; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint16_t iso_interval; - uint8_t num_bis; - uint16_t handle[0]; -} __packed; - -#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e -struct bt_hci_evt_le_big_sync_lost { - uint8_t big_handle; - uint8_t reason; -} __packed; - -#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f -struct bt_hci_evt_le_req_peer_sca_complete { - uint8_t status; - uint16_t handle; - uint8_t sca; -} __packed; - -#define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 -struct bt_hci_evt_le_biginfo_adv_report { - uint16_t sync_handle; - uint8_t num_bis; - uint8_t nse; - uint16_t iso_interval; - uint8_t bn; - uint8_t pto; - uint8_t irc; - uint16_t max_pdu; - uint8_t sdu_interval[3]; - uint16_t max_sdu; - uint8_t phy; - uint8_t framing; - uint8_t encryption; -} __packed; - -/* Event mask bits */ - -#define BT_EVT_BIT(n) (1ULL << (n)) - -#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) -#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) -#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) -#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) -#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) -#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) -#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) -#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) -#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) -#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) -#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) -#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) -#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) -#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) -#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) -#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) -#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) -#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) -#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) -#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) -#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) -#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) -#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) -#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) -#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) -#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) -#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) - -/* Page 2 */ -#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) -#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) -#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) -#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) -#define BT_EVT_MASK_CL_PER_BC_RX BT_EVT_BIT(17) -#define BT_EVT_MASK_CL_PER_BC_TIMEOUT BT_EVT_BIT(18) -#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) -#define BT_EVT_MASK_PER_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) -#define BT_EVT_MASK_CL_PER_BC_CH_MAP_CHANGE BT_EVT_BIT(21) -#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) -#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) -#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) - -#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) -#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) -#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) -#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) -#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) -#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) -#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) -#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) -#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) -#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) -#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) -#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) -#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) -#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) -#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) -#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) -#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) -#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) -#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) -#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) -#define BT_EVT_MASK_LE_CONNECTIONLESS_IQ_REPORT BT_EVT_BIT(20) -#define BT_EVT_MASK_LE_CONNECTION_IQ_REPORT BT_EVT_BIT(21) -#define BT_EVT_MASK_LE_CTE_REQUEST_FAILED BT_EVT_BIT(22) -#define BT_EVT_MASK_LE_PAST_RECEIVED BT_EVT_BIT(23) -#define BT_EVT_MASK_LE_CIS_ESTABLISHED BT_EVT_BIT(24) -#define BT_EVT_MASK_LE_CIS_REQ BT_EVT_BIT(25) -#define BT_EVT_MASK_LE_BIG_COMPLETE BT_EVT_BIT(26) -#define BT_EVT_MASK_LE_BIG_TERMINATED BT_EVT_BIT(27) -#define BT_EVT_MASK_LE_BIG_SYNC_ESTABLISHED BT_EVT_BIT(28) -#define BT_EVT_MASK_LE_BIG_SYNC_LOST BT_EVT_BIT(29) -#define BT_EVT_MASK_LE_REQ_PEER_SCA_COMPLETE BT_EVT_BIT(30) -#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31) -#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32) -#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33) - -#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35) -#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36) -#define BT_EVT_MASK_LE_PAST_RECEIVED_V2 BT_EVT_BIT(37) -#define BT_EVT_MASK_LE_PER_ADV_SUBEVENT_DATA_REQ BT_EVT_BIT(38) -#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) -#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) - /** Allocate a HCI command buffer. * * This function allocates a new buffer for a HCI command. It is given diff --git a/include/zephyr/bluetooth/hci_err.h b/include/zephyr/bluetooth/hci_err.h deleted file mode 100644 index 7740d270595e..000000000000 --- a/include/zephyr/bluetooth/hci_err.h +++ /dev/null @@ -1,90 +0,0 @@ -/** @file - * @brief Bluetooth Host Control Interface status codes. - */ - -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */ -#define BT_HCI_ERR_SUCCESS 0x00 -#define BT_HCI_ERR_UNKNOWN_CMD 0x01 -#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 -#define BT_HCI_ERR_HW_FAILURE 0x03 -#define BT_HCI_ERR_PAGE_TIMEOUT 0x04 -#define BT_HCI_ERR_AUTH_FAIL 0x05 -#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 -#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 -#define BT_HCI_ERR_CONN_TIMEOUT 0x08 -#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09 -#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a -#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b -#define BT_HCI_ERR_CMD_DISALLOWED 0x0c -#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d -#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e -#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f -#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10 -#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11 -#define BT_HCI_ERR_INVALID_PARAM 0x12 -#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 -#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14 -#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15 -#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16 -#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17 -#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 -#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19 -#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a -#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b -#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c -#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d -#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e -#define BT_HCI_ERR_UNSPECIFIED 0x1f -#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20 -#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 -#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22 -#define BT_HCI_ERR_LL_PROC_COLLISION 0x23 -#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 -#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 -#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26 -#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27 -#define BT_HCI_ERR_INSTANT_PASSED 0x28 -#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29 -#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a -#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c -#define BT_HCI_ERR_QOS_REJECTED 0x2d -#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e -#define BT_HCI_ERR_INSUFF_SECURITY 0x2f -#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30 -#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32 -#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 -#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35 -#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36 -#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37 -#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38 -#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39 -#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a -#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b -#define BT_HCI_ERR_ADV_TIMEOUT 0x3c -#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d -#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e -#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f -#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40 -#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41 -#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42 -#define BT_HCI_ERR_LIMIT_REACHED 0x43 -#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 -#define BT_HCI_ERR_PACKET_TOO_LONG 0x45 - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ */ diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h new file mode 100644 index 000000000000..3618ee5115a6 --- /dev/null +++ b/include/zephyr/bluetooth/hci_types.h @@ -0,0 +1,3073 @@ +/* hci.h - Bluetooth Host Control Interface types */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Special own address types for LL privacy (used in adv & scan parameters) */ +#define BT_HCI_OWN_ADDR_RPA_OR_PUBLIC 0x02 +#define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 +#define BT_HCI_OWN_ADDR_RPA_MASK 0x02 + +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + +#define BT_ENC_KEY_SIZE_MIN 0x07 +#define BT_ENC_KEY_SIZE_MAX 0x10 + +#define BT_HCI_ADV_HANDLE_INVALID 0xff +#define BT_HCI_SYNC_HANDLE_INVALID 0xffff +#define BT_HCI_PAWR_SUBEVENT_MAX 128 + +struct bt_hci_evt_hdr { + uint8_t evt; + uint8_t len; +} __packed; +#define BT_HCI_EVT_HDR_SIZE 2 + +#define BT_ACL_START_NO_FLUSH 0x00 +#define BT_ACL_CONT 0x01 +#define BT_ACL_START 0x02 +#define BT_ACL_COMPLETE 0x03 + +#define BT_ACL_POINT_TO_POINT 0x00 +#define BT_ACL_BROADCAST 0x01 + +#define BT_ACL_HANDLE_MASK BIT_MASK(12) + +#define bt_acl_handle(h) ((h) & BT_ACL_HANDLE_MASK) +#define bt_acl_flags(h) ((h) >> 12) +#define bt_acl_flags_pb(f) ((f) & BIT_MASK(2)) +#define bt_acl_flags_bc(f) ((f) >> 2) +#define bt_acl_handle_pack(h, f) ((h) | ((f) << 12)) + +struct bt_hci_acl_hdr { + uint16_t handle; + uint16_t len; +} __packed; +#define BT_HCI_ACL_HDR_SIZE 4 + +#define BT_ISO_START 0x00 +#define BT_ISO_CONT 0x01 +#define BT_ISO_SINGLE 0x02 +#define BT_ISO_END 0x03 + +#define bt_iso_handle(h) ((h) & 0x0fff) +#define bt_iso_flags(h) ((h) >> 12) +#define bt_iso_flags_pb(f) ((f) & 0x0003) +#define bt_iso_flags_ts(f) (((f) >> 2) & 0x0001) +#define bt_iso_pack_flags(pb, ts) \ + (((pb) & 0x0003) | (((ts) & 0x0001) << 2)) +#define bt_iso_handle_pack(h, pb, ts) \ + ((h) | (bt_iso_pack_flags(pb, ts) << 12)) +#define bt_iso_hdr_len(h) ((h) & BIT_MASK(14)) + +#define BT_ISO_DATA_VALID 0x00 +#define BT_ISO_DATA_INVALID 0x01 +#define BT_ISO_DATA_NOP 0x02 + +#define bt_iso_pkt_len(h) ((h) & 0x3fff) +#define bt_iso_pkt_flags(h) ((h) >> 14) +#define bt_iso_pkt_len_pack(h, f) ((h) | ((f) << 14)) + +struct bt_hci_iso_data_hdr { + uint16_t sn; + uint16_t slen; +} __packed; +#define BT_HCI_ISO_DATA_HDR_SIZE 4 + +struct bt_hci_iso_ts_data_hdr { + uint32_t ts; + struct bt_hci_iso_data_hdr data; +} __packed; +#define BT_HCI_ISO_TS_DATA_HDR_SIZE 8 + +struct bt_hci_iso_hdr { + uint16_t handle; /* 12 bit handle, 2 bit PB flags, 1 bit TS_Flag, 1 bit RFU */ + uint16_t len; /* 14 bits, 2 bits RFU */ +} __packed; +#define BT_HCI_ISO_HDR_SIZE 4 + +struct bt_hci_cmd_hdr { + uint16_t opcode; + uint8_t param_len; +} __packed; +#define BT_HCI_CMD_HDR_SIZE 3 + +/* Supported Commands */ +#define BT_CMD_TEST(cmd, octet, bit) (cmd[octet] & BIT(bit)) +#define BT_CMD_LE_STATES(cmd) BT_CMD_TEST(cmd, 28, 3) + +#define BT_FEAT_TEST(feat, page, octet, bit) (feat[page][octet] & BIT(bit)) + +#define BT_FEAT_BREDR(feat) !BT_FEAT_TEST(feat, 0, 4, 5) +#define BT_FEAT_LE(feat) BT_FEAT_TEST(feat, 0, 4, 6) +#define BT_FEAT_EXT_FEATURES(feat) BT_FEAT_TEST(feat, 0, 7, 7) +#define BT_FEAT_HOST_SSP(feat) BT_FEAT_TEST(feat, 1, 0, 0) +#define BT_FEAT_SC(feat) BT_FEAT_TEST(feat, 2, 1, 0) + +#define BT_FEAT_LMP_ESCO_CAPABLE(feat) BT_FEAT_TEST(feat, 0, 3, 7) +#define BT_FEAT_HV2_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 4) +#define BT_FEAT_HV3_PKT(feat) BT_FEAT_TEST(feat, 0, 1, 5) +#define BT_FEAT_EV4_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 0) +#define BT_FEAT_EV5_PKT(feat) BT_FEAT_TEST(feat, 0, 4, 1) +#define BT_FEAT_2EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 5) +#define BT_FEAT_3EV3_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 6) +#define BT_FEAT_3SLOT_PKT(feat) BT_FEAT_TEST(feat, 0, 5, 7) + +/* LE features */ +#define BT_LE_FEAT_BIT_ENC 0 +#define BT_LE_FEAT_BIT_CONN_PARAM_REQ 1 +#define BT_LE_FEAT_BIT_EXT_REJ_IND 2 +#define BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG 3 +#define BT_LE_FEAT_BIT_PING 4 +#define BT_LE_FEAT_BIT_DLE 5 +#define BT_LE_FEAT_BIT_PRIVACY 6 +#define BT_LE_FEAT_BIT_EXT_SCAN 7 +#define BT_LE_FEAT_BIT_PHY_2M 8 +#define BT_LE_FEAT_BIT_SMI_TX 9 +#define BT_LE_FEAT_BIT_SMI_RX 10 +#define BT_LE_FEAT_BIT_PHY_CODED 11 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 +#define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 +#define BT_LE_FEAT_BIT_PWR_CLASS_1 15 +#define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 +#define BT_LE_FEAT_BIT_CONN_CTE_REQ 17 +#define BT_LE_FEAT_BIT_CONN_CTE_RESP 18 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX 19 +#define BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX 20 +#define BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD 21 +#define BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA 22 +#define BT_LE_FEAT_BIT_RX_CTE 23 +#define BT_LE_FEAT_BIT_PAST_SEND 24 +#define BT_LE_FEAT_BIT_PAST_RECV 25 +#define BT_LE_FEAT_BIT_SCA_UPDATE 26 +#define BT_LE_FEAT_BIT_REMOTE_PUB_KEY_VALIDATE 27 +#define BT_LE_FEAT_BIT_CIS_CENTRAL 28 +#define BT_LE_FEAT_BIT_CIS_PERIPHERAL 29 +#define BT_LE_FEAT_BIT_ISO_BROADCASTER 30 +#define BT_LE_FEAT_BIT_SYNC_RECEIVER 31 +#define BT_LE_FEAT_BIT_ISO_CHANNELS 32 +#define BT_LE_FEAT_BIT_PWR_CTRL_REQ 33 +#define BT_LE_FEAT_BIT_PWR_CHG_IND 34 +#define BT_LE_FEAT_BIT_PATH_LOSS_MONITOR 35 +#define BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP 36 +#define BT_LE_FEAT_BIT_CONN_SUBRATING 37 +#define BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP 38 +#define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 + +#define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 +#define BT_LE_FEAT_BIT_PAWR_SCANNER 44 + +#define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ + BIT((n) & 7)) + +#define BT_FEAT_LE_ENCR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ENC) +#define BT_FEAT_LE_CONN_PARAM_REQ_PROC(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_PARAM_REQ) +#define BT_FEAT_LE_PER_INIT_FEAT_XCHG(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_INIT_FEAT_XCHG) +#define BT_FEAT_LE_DLE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_DLE) +#define BT_FEAT_LE_PHY_2M(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_2M) +#define BT_FEAT_LE_PHY_CODED(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PHY_CODED) +#define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) +#define BT_FEAT_LE_EXT_PER_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV) +#define BT_FEAT_LE_CONNECTION_CTE_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_REQ) +#define BT_FEAT_LE_CONNECTION_CTE_RESP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_CTE_RESP) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_TX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_TX) +#define BT_FEAT_LE_CONNECTIONLESS_CTE_RX(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONNECTIONLESS_CTE_RX) +#define BT_FEAT_LE_ANT_SWITCH_TX_AOD(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_TX_AOD) +#define BT_FEAT_LE_ANT_SWITCH_RX_AOA(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ANT_SWITCH_RX_AOA) +#define BT_FEAT_LE_RX_CTE(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_RX_CTE) +#define BT_FEAT_LE_PAST_SEND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_SEND) +#define BT_FEAT_LE_PAST_RECV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAST_RECV) +#define BT_FEAT_LE_CIS_CENTRAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_CENTRAL) +#define BT_FEAT_LE_CIS_PERIPHERAL(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CIS_PERIPHERAL) +#define BT_FEAT_LE_ISO_BROADCASTER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_BROADCASTER) +#define BT_FEAT_LE_SYNC_RECEIVER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_SYNC_RECEIVER) +#define BT_FEAT_LE_ISO_CHANNELS(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_ISO_CHANNELS) +#define BT_FEAT_LE_PWR_CTRL_REQ(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CTRL_REQ) +#define BT_FEAT_LE_PWR_CHG_IND(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PWR_CHG_IND) +#define BT_FEAT_LE_PATH_LOSS_MONITOR(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PATH_LOSS_MONITOR) +#define BT_FEAT_LE_PER_ADV_ADI_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PER_ADV_ADI_SUPP) +#define BT_FEAT_LE_CONN_SUBRATING(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING) +#define BT_FEAT_LE_CONN_SUBRATING_HOST_SUPP(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CONN_SUBRATING_HOST_SUPP) +#define BT_FEAT_LE_CHANNEL_CLASSIFICATION(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION) +#define BT_FEAT_LE_PAWR_ADVERTISER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_ADVERTISER) +#define BT_FEAT_LE_PAWR_SCANNER(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_PAWR_SCANNER) + +#define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ + BT_FEAT_LE_CIS_PERIPHERAL(feat)) +#define BT_FEAT_LE_BIS(feat) (BT_FEAT_LE_ISO_BROADCASTER(feat) | \ + BT_FEAT_LE_SYNC_RECEIVER(feat)) +#define BT_FEAT_LE_ISO(feat) (BT_FEAT_LE_CIS(feat) | \ + BT_FEAT_LE_BIS(feat)) + +/* LE States */ +#define BT_LE_STATES_PER_CONN_ADV(states) (states & 0x0000004000000000) + +/* Bonding/authentication types */ +#define BT_HCI_NO_BONDING 0x00 +#define BT_HCI_NO_BONDING_MITM 0x01 +#define BT_HCI_DEDICATED_BONDING 0x02 +#define BT_HCI_DEDICATED_BONDING_MITM 0x03 +#define BT_HCI_GENERAL_BONDING 0x04 +#define BT_HCI_GENERAL_BONDING_MITM 0x05 + +/* + * MITM protection is enabled in SSP authentication requirements octet when + * LSB bit is set. + */ +#define BT_MITM 0x01 + +/* I/O capabilities */ +#define BT_IO_DISPLAY_ONLY 0x00 +#define BT_IO_DISPLAY_YESNO 0x01 +#define BT_IO_KEYBOARD_ONLY 0x02 +#define BT_IO_NO_INPUT_OUTPUT 0x03 + +/* SCO packet types */ +#define HCI_PKT_TYPE_HV1 0x0020 +#define HCI_PKT_TYPE_HV2 0x0040 +#define HCI_PKT_TYPE_HV3 0x0080 + +/* eSCO packet types */ +#define HCI_PKT_TYPE_ESCO_HV1 0x0001 +#define HCI_PKT_TYPE_ESCO_HV2 0x0002 +#define HCI_PKT_TYPE_ESCO_HV3 0x0004 +#define HCI_PKT_TYPE_ESCO_EV3 0x0008 +#define HCI_PKT_TYPE_ESCO_EV4 0x0010 +#define HCI_PKT_TYPE_ESCO_EV5 0x0020 +#define HCI_PKT_TYPE_ESCO_2EV3 0x0040 +#define HCI_PKT_TYPE_ESCO_3EV3 0x0080 +#define HCI_PKT_TYPE_ESCO_2EV5 0x0100 +#define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ + HCI_PKT_TYPE_ESCO_HV2 | \ + HCI_PKT_TYPE_ESCO_HV3) +#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ + HCI_PKT_TYPE_HV2 | \ + HCI_PKT_TYPE_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + +/* HCI BR/EDR link types */ +#define BT_HCI_SCO 0x00 +#define BT_HCI_ACL 0x01 +#define BT_HCI_ESCO 0x02 + +/* OpCode Group Fields */ +#define BT_OGF_LINK_CTRL 0x01 +#define BT_OGF_BASEBAND 0x03 +#define BT_OGF_INFO 0x04 +#define BT_OGF_STATUS 0x05 +#define BT_OGF_LE 0x08 +#define BT_OGF_VS 0x3f + +/* Construct OpCode from OGF and OCF */ +#define BT_OP(ogf, ocf) ((ocf) | ((ogf) << 10)) + +/* Invalid opcode */ +#define BT_OP_NOP 0x0000 + +/* Obtain OGF from OpCode */ +#define BT_OGF(opcode) (((opcode) >> 10) & BIT_MASK(6)) +/* Obtain OCF from OpCode */ +#define BT_OCF(opcode) ((opcode) & BIT_MASK(10)) + +#define BT_HCI_OP_INQUIRY BT_OP(BT_OGF_LINK_CTRL, 0x0001) +struct bt_hci_op_inquiry { + uint8_t lap[3]; + uint8_t length; + uint8_t num_rsp; +} __packed; + +#define BT_HCI_OP_INQUIRY_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0002) + +#define BT_HCI_OP_CONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0005) +struct bt_hci_cp_connect { + bt_addr_t bdaddr; + uint16_t packet_type; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; + uint8_t allow_role_switch; +} __packed; + +#define BT_HCI_OP_DISCONNECT BT_OP(BT_OGF_LINK_CTRL, 0x0006) +struct bt_hci_cp_disconnect { + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_CONNECT_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x0008) +struct bt_hci_cp_connect_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_connect_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_ACCEPT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0009) +struct bt_hci_cp_accept_conn_req { + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_OP_SETUP_SYNC_CONN BT_OP(BT_OGF_LINK_CTRL, 0x0028) +struct bt_hci_cp_setup_sync_conn { + uint16_t handle; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + +#define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) +struct bt_hci_cp_reject_conn_req { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LINK_KEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000b) +struct bt_hci_cp_link_key_reply { + bt_addr_t bdaddr; + uint8_t link_key[16]; +} __packed; + +#define BT_HCI_OP_LINK_KEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000c) +struct bt_hci_cp_link_key_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000d) +struct bt_hci_cp_pin_code_reply { + bt_addr_t bdaddr; + uint8_t pin_len; + uint8_t pin_code[16]; +} __packed; +struct bt_hci_rp_pin_code_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_PIN_CODE_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x000e) +struct bt_hci_cp_pin_code_neg_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_pin_code_neg_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_AUTH_REQUESTED BT_OP(BT_OGF_LINK_CTRL, 0x0011) +struct bt_hci_cp_auth_requested { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_SET_CONN_ENCRYPT BT_OP(BT_OGF_LINK_CTRL, 0x0013) +struct bt_hci_cp_set_conn_encrypt { + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_REQUEST BT_OP(BT_OGF_LINK_CTRL, 0x0019) +struct bt_hci_cp_remote_name_request { + bt_addr_t bdaddr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint16_t clock_offset; +} __packed; + +#define BT_HCI_OP_REMOTE_NAME_CANCEL BT_OP(BT_OGF_LINK_CTRL, 0x001a) +struct bt_hci_cp_remote_name_cancel { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_remote_name_cancel { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001b) +struct bt_hci_cp_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_EXT_FEATURES BT_OP(BT_OGF_LINK_CTRL, 0x001c) +struct bt_hci_cp_read_remote_ext_features { + uint16_t handle; + uint8_t page; +} __packed; + +#define BT_HCI_OP_READ_REMOTE_VERSION_INFO BT_OP(BT_OGF_LINK_CTRL, 0x001d) +struct bt_hci_cp_read_remote_version_info { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002b) +struct bt_hci_cp_io_capability_reply { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_OP_USER_CONFIRM_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002c) +#define BT_HCI_OP_USER_CONFIRM_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002d) +struct bt_hci_cp_user_confirm_reply { + bt_addr_t bdaddr; +} __packed; +struct bt_hci_rp_user_confirm_reply { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002e) +struct bt_hci_cp_user_passkey_reply { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_OP_USER_PASSKEY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x002f) +struct bt_hci_cp_user_passkey_neg_reply { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_OP_IO_CAPABILITY_NEG_REPLY BT_OP(BT_OGF_LINK_CTRL, 0x0034) +struct bt_hci_cp_io_capability_neg_reply { + bt_addr_t bdaddr; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK BT_OP(BT_OGF_BASEBAND, 0x0001) +struct bt_hci_cp_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_RESET BT_OP(BT_OGF_BASEBAND, 0x0003) + +#define BT_HCI_OP_WRITE_LOCAL_NAME BT_OP(BT_OGF_BASEBAND, 0x0013) +struct bt_hci_write_local_name { + uint8_t local_name[248]; +} __packed; + +#define BT_HCI_OP_READ_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0015) +struct bt_hci_rp_read_conn_accept_timeout { + uint8_t status; + uint16_t conn_accept_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_CONN_ACCEPT_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0016) +struct bt_hci_cp_write_conn_accept_timeout { + uint16_t conn_accept_timeout; +} __packed; + +struct bt_hci_rp_write_conn_accept_timeout { + uint8_t status; +} __packed; + +#define BT_HCI_OP_WRITE_PAGE_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x0018) + +#define BT_HCI_OP_WRITE_SCAN_ENABLE BT_OP(BT_OGF_BASEBAND, 0x001a) +#define BT_BREDR_SCAN_DISABLED 0x00 +#define BT_BREDR_SCAN_INQUIRY 0x01 +#define BT_BREDR_SCAN_PAGE 0x02 + +#define BT_HCI_OP_WRITE_CLASS_OF_DEVICE BT_OP(BT_OGF_BASEBAND, 0x0024) +struct bt_hci_cp_write_class_of_device { + uint8_t class_of_device[3]; +} __packed; + +#define BT_TX_POWER_LEVEL_CURRENT 0x00 +#define BT_TX_POWER_LEVEL_MAX 0x01 +#define BT_HCI_OP_READ_TX_POWER_LEVEL BT_OP(BT_OGF_BASEBAND, 0x002d) +struct bt_hci_cp_read_tx_power_level { + uint16_t handle; + uint8_t type; +} __packed; + +struct bt_hci_rp_read_tx_power_level { + uint8_t status; + uint16_t handle; + int8_t tx_power_level; +} __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) +struct bt_hci_cp_set_ctl_to_host_flow { + uint8_t flow_enable; +} __packed; + +#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033) +struct bt_hci_cp_host_buffer_size { + uint16_t acl_mtu; + uint8_t sco_mtu; + uint16_t acl_pkts; + uint16_t sco_pkts; +} __packed; + +struct bt_hci_handle_count { + uint16_t handle; + uint16_t count; +} __packed; + +#define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) +struct bt_hci_cp_host_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_OP_WRITE_INQUIRY_MODE BT_OP(BT_OGF_BASEBAND, 0x0045) +struct bt_hci_cp_write_inquiry_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_WRITE_SSP_MODE BT_OP(BT_OGF_BASEBAND, 0x0056) +struct bt_hci_cp_write_ssp_mode { + uint8_t mode; +} __packed; + +#define BT_HCI_OP_SET_EVENT_MASK_PAGE_2 BT_OP(BT_OGF_BASEBAND, 0x0063) +struct bt_hci_cp_set_event_mask_page_2 { + uint8_t events_page_2[8]; +} __packed; + +#define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) +struct bt_hci_cp_write_le_host_supp { + uint8_t le; + uint8_t simul; +} __packed; + +#define BT_HCI_OP_WRITE_SC_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x007a) +struct bt_hci_cp_write_sc_host_supp { + uint8_t sc_support; +} __packed; + +#define BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007b) +struct bt_hci_cp_read_auth_payload_timeout { + uint16_t handle; +} __packed; + +struct bt_hci_rp_read_auth_payload_timeout { + uint8_t status; + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +#define BT_HCI_OP_WRITE_AUTH_PAYLOAD_TIMEOUT BT_OP(BT_OGF_BASEBAND, 0x007c) +struct bt_hci_cp_write_auth_payload_timeout { + uint16_t handle; + uint16_t auth_payload_timeout; +} __packed; + +struct bt_hci_rp_write_auth_payload_timeout { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_CONFIGURE_DATA_PATH BT_OP(BT_OGF_BASEBAND, 0x0083) +struct bt_hci_cp_configure_data_path { + uint8_t data_path_dir; + uint8_t data_path_id; + uint8_t vs_config_len; + uint8_t vs_config[0]; +} __packed; + +struct bt_hci_rp_configure_data_path { + uint8_t status; +} __packed; + +/* HCI version from Assigned Numbers */ +#define BT_HCI_VERSION_1_0B 0 +#define BT_HCI_VERSION_1_1 1 +#define BT_HCI_VERSION_1_2 2 +#define BT_HCI_VERSION_2_0 3 +#define BT_HCI_VERSION_2_1 4 +#define BT_HCI_VERSION_3_0 5 +#define BT_HCI_VERSION_4_0 6 +#define BT_HCI_VERSION_4_1 7 +#define BT_HCI_VERSION_4_2 8 +#define BT_HCI_VERSION_5_0 9 +#define BT_HCI_VERSION_5_1 10 +#define BT_HCI_VERSION_5_2 11 +#define BT_HCI_VERSION_5_3 12 +#define BT_HCI_VERSION_5_4 13 + +#define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) +struct bt_hci_rp_read_local_version_info { + uint8_t status; + uint8_t hci_version; + uint16_t hci_revision; + uint8_t lmp_version; + uint16_t manufacturer; + uint16_t lmp_subversion; +} __packed; + +#define BT_HCI_OP_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) +struct bt_hci_rp_read_supported_commands { + uint8_t status; + uint8_t commands[64]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_EXT_FEATURES BT_OP(BT_OGF_INFO, 0x0004) +struct bt_hci_cp_read_local_ext_features { + uint8_t page; +}; +struct bt_hci_rp_read_local_ext_features { + uint8_t status; + uint8_t page; + uint8_t max_page; + uint8_t ext_features[8]; +} __packed; + +#define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) +struct bt_hci_rp_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) +struct bt_hci_rp_read_buffer_size { + uint8_t status; + uint16_t acl_max_len; + uint8_t sco_max_len; + uint16_t acl_max_num; + uint16_t sco_max_num; +} __packed; + +#define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) +struct bt_hci_rp_read_bd_addr { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +/* logic transport type bits as returned when reading supported codecs */ +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_ACL BIT(0) +#define BT_HCI_CODEC_TRANSPORT_MASK_BREDR_SCO BIT(1) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_CIS BIT(2) +#define BT_HCI_CODEC_TRANSPORT_MASK_LE_BIS BIT(3) + +/* logic transport types for reading codec capabilities and controller delays */ +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_ACL 0x00 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_BREDR_SCO 0x01 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_CIS 0x02 +#define BT_HCI_LOGICAL_TRANSPORT_TYPE_LE_BIS 0x03 + +/* audio datapath directions */ +#define BT_HCI_DATAPATH_DIR_HOST_TO_CTLR 0x00 +#define BT_HCI_DATAPATH_DIR_CTLR_TO_HOST 0x01 + +/* audio datapath IDs */ +#define BT_HCI_DATAPATH_ID_HCI 0x00 +#define BT_HCI_DATAPATH_ID_VS 0x01 +#define BT_HCI_DATAPATH_ID_VS_END 0xfe + +/* coding format assigned numbers, used for codec IDs */ +#define BT_HCI_CODING_FORMAT_ULAW_LOG 0x00 +#define BT_HCI_CODING_FORMAT_ALAW_LOG 0x01 +#define BT_HCI_CODING_FORMAT_CVSD 0x02 +#define BT_HCI_CODING_FORMAT_TRANSPARENT 0x03 +#define BT_HCI_CODING_FORMAT_LINEAR_PCM 0x04 +#define BT_HCI_CODING_FORMAT_MSBC 0x05 +#define BT_HCI_CODING_FORMAT_VS 0xFF + + +#define BT_HCI_OP_READ_CODECS BT_OP(BT_OGF_INFO, 0x000b) +struct bt_hci_std_codec_info { + uint8_t codec_id; +} __packed; +struct bt_hci_std_codecs { + uint8_t num_codecs; + struct bt_hci_std_codec_info codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info { + uint16_t company_id; + uint16_t codec_id; +} __packed; +struct bt_hci_vs_codecs { + uint8_t num_codecs; + struct bt_hci_vs_codec_info codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +#define BT_HCI_OP_READ_CODECS_V2 BT_OP(BT_OGF_INFO, 0x000d) +struct bt_hci_std_codec_info_v2 { + uint8_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_std_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_std_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_vs_codec_info_v2 { + uint16_t company_id; + uint16_t codec_id; + uint8_t transports; /* bitmap */ +} __packed; +struct bt_hci_vs_codecs_v2 { + uint8_t num_codecs; + struct bt_hci_vs_codec_info_v2 codec_info[0]; +} __packed; +struct bt_hci_rp_read_codecs_v2 { + uint8_t status; + /* other fields filled in dynamically */ + uint8_t codecs[0]; +} __packed; + +struct bt_hci_cp_codec_id { + uint8_t coding_format; + uint16_t company_id; + uint16_t vs_codec_id; +} __packed; + +#define BT_HCI_OP_READ_CODEC_CAPABILITIES BT_OP(BT_OGF_INFO, 0x000e) +struct bt_hci_cp_read_codec_capabilities { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; +} __packed; +struct bt_hci_codec_capability_info { + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_rp_read_codec_capabilities { + uint8_t status; + uint8_t num_capabilities; + /* other fields filled in dynamically */ + uint8_t capabilities[0]; +} __packed; + +#define BT_HCI_OP_READ_CTLR_DELAY BT_OP(BT_OGF_INFO, 0x000f) +struct bt_hci_cp_read_ctlr_delay { + struct bt_hci_cp_codec_id codec_id; + uint8_t transport; + uint8_t direction; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; +struct bt_hci_rp_read_ctlr_delay { + uint8_t status; + uint8_t min_ctlr_delay[3]; + uint8_t max_ctlr_delay[3]; +} __packed; + +#define BT_HCI_OP_READ_RSSI BT_OP(BT_OGF_STATUS, 0x0005) +struct bt_hci_cp_read_rssi { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_rssi { + uint8_t status; + uint16_t handle; + int8_t rssi; +} __packed; + +#define BT_HCI_ENCRYPTION_KEY_SIZE_MIN 7 +#define BT_HCI_ENCRYPTION_KEY_SIZE_MAX 16 + +#define BT_HCI_OP_READ_ENCRYPTION_KEY_SIZE BT_OP(BT_OGF_STATUS, 0x0008) +struct bt_hci_cp_read_encryption_key_size { + uint16_t handle; +} __packed; +struct bt_hci_rp_read_encryption_key_size { + uint8_t status; + uint16_t handle; + uint8_t key_size; +} __packed; + +/* BLE */ + +#define BT_HCI_OP_LE_SET_EVENT_MASK BT_OP(BT_OGF_LE, 0x0001) +struct bt_hci_cp_le_set_event_mask { + uint8_t events[8]; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE BT_OP(BT_OGF_LE, 0x0002) +struct bt_hci_rp_le_read_buffer_size { + uint8_t status; + uint16_t le_max_len; + uint8_t le_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_FEATURES BT_OP(BT_OGF_LE, 0x0003) +struct bt_hci_rp_le_read_local_features { + uint8_t status; + uint8_t features[8]; +} __packed; + +#define BT_HCI_OP_LE_SET_RANDOM_ADDRESS BT_OP(BT_OGF_LE, 0x0005) +struct bt_hci_cp_le_set_random_address { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 + +#define BT_LE_ADV_INTERVAL_MIN 0x0020 +#define BT_LE_ADV_INTERVAL_MAX 0x4000 +#define BT_LE_ADV_INTERVAL_DEFAULT 0x0800 + +#define BT_LE_ADV_CHAN_MAP_CHAN_37 0x01 +#define BT_LE_ADV_CHAN_MAP_CHAN_38 0x02 +#define BT_LE_ADV_CHAN_MAP_CHAN_39 0x04 +#define BT_LE_ADV_CHAN_MAP_ALL 0x07 + +#define BT_LE_ADV_FP_NO_FILTER 0x00 +#define BT_LE_ADV_FP_FILTER_SCAN_REQ 0x01 +#define BT_LE_ADV_FP_FILTER_CONN_IND 0x02 +#define BT_LE_ADV_FP_FILTER_BOTH 0x03 + +#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) +struct bt_hci_cp_le_set_adv_param { + uint16_t min_interval; + uint16_t max_interval; + uint8_t type; + uint8_t own_addr_type; + bt_addr_le_t direct_addr; + uint8_t channel_map; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_READ_ADV_CHAN_TX_POWER BT_OP(BT_OGF_LE, 0x0007) +struct bt_hci_rp_le_read_chan_tx_power { + uint8_t status; + int8_t tx_power_level; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_DATA BT_OP(BT_OGF_LE, 0x0008) +struct bt_hci_cp_le_set_adv_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0009) +struct bt_hci_cp_le_set_scan_rsp_data { + uint8_t len; + uint8_t data[31]; +} __packed; + +#define BT_HCI_LE_ADV_DISABLE 0x00 +#define BT_HCI_LE_ADV_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADV_ENABLE BT_OP(BT_OGF_LE, 0x000a) +struct bt_hci_cp_le_set_adv_enable { + uint8_t enable; +} __packed; + +/* Scan types */ +#define BT_HCI_OP_LE_SET_SCAN_PARAM BT_OP(BT_OGF_LE, 0x000b) +#define BT_HCI_LE_SCAN_PASSIVE 0x00 +#define BT_HCI_LE_SCAN_ACTIVE 0x01 + +#define BT_HCI_LE_SCAN_FP_BASIC_NO_FILTER 0x00 +#define BT_HCI_LE_SCAN_FP_BASIC_FILTER 0x01 +#define BT_HCI_LE_SCAN_FP_EXT_NO_FILTER 0x02 +#define BT_HCI_LE_SCAN_FP_EXT_FILTER 0x03 + +struct bt_hci_cp_le_set_scan_param { + uint8_t scan_type; + uint16_t interval; + uint16_t window; + uint8_t addr_type; + uint8_t filter_policy; +} __packed; + +#define BT_HCI_OP_LE_SET_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x000c) + +#define BT_HCI_LE_SCAN_DISABLE 0x00 +#define BT_HCI_LE_SCAN_ENABLE 0x01 + +#define BT_HCI_LE_SCAN_FILTER_DUP_DISABLE 0x00 +#define BT_HCI_LE_SCAN_FILTER_DUP_ENABLE 0x01 + +struct bt_hci_cp_le_set_scan_enable { + uint8_t enable; + uint8_t filter_dup; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) + +#define BT_HCI_LE_CREATE_CONN_FP_NO_FILTER 0x00 +#define BT_HCI_LE_CREATE_CONN_FP_FILTER 0x01 + +struct bt_hci_cp_le_create_conn { + uint16_t scan_interval; + uint16_t scan_window; + uint8_t filter_policy; + bt_addr_le_t peer_addr; + uint8_t own_addr_type; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CONN_CANCEL BT_OP(BT_OGF_LE, 0x000e) + +#define BT_HCI_OP_LE_READ_FAL_SIZE BT_OP(BT_OGF_LE, 0x000f) +struct bt_hci_rp_le_read_fal_size { + uint8_t status; + uint8_t fal_size; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_FAL BT_OP(BT_OGF_LE, 0x0010) + +#define BT_HCI_OP_LE_ADD_DEV_TO_FAL BT_OP(BT_OGF_LE, 0x0011) +struct bt_hci_cp_le_add_dev_to_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_FAL BT_OP(BT_OGF_LE, 0x0012) +struct bt_hci_cp_le_rem_dev_from_fal { + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_OP_LE_CONN_UPDATE BT_OP(BT_OGF_LE, 0x0013) +struct hci_cp_le_conn_update { + uint16_t handle; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_CHAN_CLASSIF BT_OP(BT_OGF_LE, 0x0014) +struct bt_hci_cp_le_set_host_chan_classif { + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_CHAN_MAP BT_OP(BT_OGF_LE, 0x0015) +struct bt_hci_cp_le_read_chan_map { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_chan_map { + uint8_t status; + uint16_t handle; + uint8_t ch_map[5]; +} __packed; + +#define BT_HCI_OP_LE_READ_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0016) +struct bt_hci_cp_le_read_remote_features { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ENCRYPT BT_OP(BT_OGF_LE, 0x0017) +struct bt_hci_cp_le_encrypt { + uint8_t key[16]; + uint8_t plaintext[16]; +} __packed; +struct bt_hci_rp_le_encrypt { + uint8_t status; + uint8_t enc_data[16]; +} __packed; + +#define BT_HCI_OP_LE_RAND BT_OP(BT_OGF_LE, 0x0018) +struct bt_hci_rp_le_rand { + uint8_t status; + uint8_t rand[8]; +} __packed; + +#define BT_HCI_OP_LE_START_ENCRYPTION BT_OP(BT_OGF_LE, 0x0019) +struct bt_hci_cp_le_start_encryption { + uint16_t handle; + uint64_t rand; + uint16_t ediv; + uint8_t ltk[16]; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_REPLY BT_OP(BT_OGF_LE, 0x001a) +struct bt_hci_cp_le_ltk_req_reply { + uint16_t handle; + uint8_t ltk[16]; +} __packed; +struct bt_hci_rp_le_ltk_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_LTK_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x001b) +struct bt_hci_cp_le_ltk_req_neg_reply { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_ltk_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_SUPP_STATES BT_OP(BT_OGF_LE, 0x001c) +struct bt_hci_rp_le_read_supp_states { + uint8_t status; + uint8_t le_states[8]; +} __packed; + +#define BT_HCI_OP_LE_RX_TEST BT_OP(BT_OGF_LE, 0x001d) +struct bt_hci_cp_le_rx_test { + uint8_t rx_ch; +} __packed; + +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS9 0x00 +#define BT_HCI_TEST_PKT_PAYLOAD_11110000 0x01 +#define BT_HCI_TEST_PKT_PAYLOAD_10101010 0x02 +#define BT_HCI_TEST_PKT_PAYLOAD_PRBS15 0x03 +#define BT_HCI_TEST_PKT_PAYLOAD_11111111 0x04 +#define BT_HCI_TEST_PKT_PAYLOAD_00000000 0x05 +#define BT_HCI_TEST_PKT_PAYLOAD_00001111 0x06 +#define BT_HCI_TEST_PKT_PAYLOAD_01010101 0x07 + +#define BT_HCI_OP_LE_TX_TEST BT_OP(BT_OGF_LE, 0x001e) +struct bt_hci_cp_le_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; +} __packed; + +#define BT_HCI_OP_LE_TEST_END BT_OP(BT_OGF_LE, 0x001f) +struct bt_hci_rp_le_test_end { + uint8_t status; + uint16_t rx_pkt_count; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_REPLY BT_OP(BT_OGF_LE, 0x0020) +struct bt_hci_cp_le_conn_param_req_reply { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; +struct bt_hci_rp_le_conn_param_req_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY BT_OP(BT_OGF_LE, 0x0021) +struct bt_hci_cp_le_conn_param_req_neg_reply { + uint16_t handle; + uint8_t reason; +} __packed; +struct bt_hci_rp_le_conn_param_req_neg_reply { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_DATA_LEN BT_OP(BT_OGF_LE, 0x0022) +struct bt_hci_cp_le_set_data_len { + uint16_t handle; + uint16_t tx_octets; + uint16_t tx_time; +} __packed; +struct bt_hci_rp_le_set_data_len { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_READ_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0023) +struct bt_hci_rp_le_read_default_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_WRITE_DEFAULT_DATA_LEN BT_OP(BT_OGF_LE, 0x0024) +struct bt_hci_cp_le_write_default_data_len { + uint16_t max_tx_octets; + uint16_t max_tx_time; +} __packed; + +#define BT_HCI_OP_LE_P256_PUBLIC_KEY BT_OP(BT_OGF_LE, 0x0025) + +#define BT_HCI_OP_LE_GENERATE_DHKEY BT_OP(BT_OGF_LE, 0x0026) +struct bt_hci_cp_le_generate_dhkey { + uint8_t key[64]; +} __packed; + + +#define BT_HCI_OP_LE_GENERATE_DHKEY_V2 BT_OP(BT_OGF_LE, 0x005e) + +#define BT_HCI_LE_KEY_TYPE_GENERATED 0x00 +#define BT_HCI_LE_KEY_TYPE_DEBUG 0x01 + +struct bt_hci_cp_le_generate_dhkey_v2 { + uint8_t key[64]; + uint8_t key_type; +} __packed; + + +#define BT_HCI_OP_LE_ADD_DEV_TO_RL BT_OP(BT_OGF_LE, 0x0027) +struct bt_hci_cp_le_add_dev_to_rl { + bt_addr_le_t peer_id_addr; + uint8_t peer_irk[16]; + uint8_t local_irk[16]; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_RL BT_OP(BT_OGF_LE, 0x0028) +struct bt_hci_cp_le_rem_dev_from_rl { + bt_addr_le_t peer_id_addr; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_RL BT_OP(BT_OGF_LE, 0x0029) + +#define BT_HCI_OP_LE_READ_RL_SIZE BT_OP(BT_OGF_LE, 0x002a) +struct bt_hci_rp_le_read_rl_size { + uint8_t status; + uint8_t rl_size; +} __packed; + +#define BT_HCI_OP_LE_READ_PEER_RPA BT_OP(BT_OGF_LE, 0x002b) +struct bt_hci_cp_le_read_peer_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_peer_rpa { + uint8_t status; + bt_addr_t peer_rpa; +} __packed; + +#define BT_HCI_OP_LE_READ_LOCAL_RPA BT_OP(BT_OGF_LE, 0x002c) +struct bt_hci_cp_le_read_local_rpa { + bt_addr_le_t peer_id_addr; +} __packed; +struct bt_hci_rp_le_read_local_rpa { + uint8_t status; + bt_addr_t local_rpa; +} __packed; + +#define BT_HCI_ADDR_RES_DISABLE 0x00 +#define BT_HCI_ADDR_RES_ENABLE 0x01 + +#define BT_HCI_OP_LE_SET_ADDR_RES_ENABLE BT_OP(BT_OGF_LE, 0x002d) +struct bt_hci_cp_le_set_addr_res_enable { + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_SET_RPA_TIMEOUT BT_OP(BT_OGF_LE, 0x002e) +struct bt_hci_cp_le_set_rpa_timeout { + uint16_t rpa_timeout; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_DATA_LEN BT_OP(BT_OGF_LE, 0x002f) +struct bt_hci_rp_le_read_max_data_len { + uint8_t status; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_LE_PHY_1M 0x01 +#define BT_HCI_LE_PHY_2M 0x02 +#define BT_HCI_LE_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_READ_PHY BT_OP(BT_OGF_LE, 0x0030) +struct bt_hci_cp_le_read_phy { + uint16_t handle; +} __packed; +struct bt_hci_rp_le_read_phy { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_LE_PHY_TX_ANY BIT(0) +#define BT_HCI_LE_PHY_RX_ANY BIT(1) + +#define BT_HCI_LE_PHY_PREFER_1M BIT(0) +#define BT_HCI_LE_PHY_PREFER_2M BIT(1) +#define BT_HCI_LE_PHY_PREFER_CODED BIT(2) + +#define BT_HCI_OP_LE_SET_DEFAULT_PHY BT_OP(BT_OGF_LE, 0x0031) +struct bt_hci_cp_le_set_default_phy { + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; +} __packed; + +#define BT_HCI_LE_PHY_CODED_ANY 0x00 +#define BT_HCI_LE_PHY_CODED_S2 0x01 +#define BT_HCI_LE_PHY_CODED_S8 0x02 + +#define BT_HCI_OP_LE_SET_PHY BT_OP(BT_OGF_LE, 0x0032) +struct bt_hci_cp_le_set_phy { + uint16_t handle; + uint8_t all_phys; + uint8_t tx_phys; + uint8_t rx_phys; + uint16_t phy_opts; +} __packed; + +#define BT_HCI_LE_MOD_INDEX_STANDARD 0x00 +#define BT_HCI_LE_MOD_INDEX_STABLE 0x01 + +#define BT_HCI_LE_RX_PHY_1M 0x01 +#define BT_HCI_LE_RX_PHY_2M 0x02 +#define BT_HCI_LE_RX_PHY_CODED 0x03 + +#define BT_HCI_OP_LE_ENH_RX_TEST BT_OP(BT_OGF_LE, 0x0033) +struct bt_hci_cp_le_enh_rx_test { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; +} __packed; + +#define BT_HCI_LE_TX_PHY_1M 0x01 +#define BT_HCI_LE_TX_PHY_2M 0x02 +#define BT_HCI_LE_TX_PHY_CODED_S8 0x03 +#define BT_HCI_LE_TX_PHY_CODED_S2 0x04 + +#define BT_HCI_OP_LE_ENH_TX_TEST BT_OP(BT_OGF_LE, 0x0034) +struct bt_hci_cp_le_enh_tx_test { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; +} __packed; + +#define BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR BT_OP(BT_OGF_LE, 0x0035) +struct bt_hci_cp_le_set_adv_set_random_addr { + uint8_t handle; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_LE_ADV_PROP_CONN BIT(0) +#define BT_HCI_LE_ADV_PROP_SCAN BIT(1) +#define BT_HCI_LE_ADV_PROP_DIRECT BIT(2) +#define BT_HCI_LE_ADV_PROP_HI_DC_CONN BIT(3) +#define BT_HCI_LE_ADV_PROP_LEGACY BIT(4) +#define BT_HCI_LE_ADV_PROP_ANON BIT(5) +#define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) + +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MIN 0x000020 +#define BT_HCI_LE_PRIM_ADV_INTERVAL_MAX 0xFFFFFF + +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + +#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF + +#define BT_HCI_LE_EXT_ADV_SID_INVALID 0xFF + +#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) +struct bt_hci_cp_le_set_ext_adv_param { + uint8_t handle; + uint16_t props; + uint8_t prim_min_interval[3]; + uint8_t prim_max_interval[3]; + uint8_t prim_channel_map; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t filter_policy; + int8_t tx_power; + uint8_t prim_adv_phy; + uint8_t sec_adv_max_skip; + uint8_t sec_adv_phy; + uint8_t sid; + uint8_t scan_req_notify_enable; +} __packed; +struct bt_hci_rp_le_set_ext_adv_param { + uint8_t status; + int8_t tx_power; +} __packed; + +#define BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_EXT_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA 0x03 +#define BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA 0x04 + +#define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 +#define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 + +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + +#define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) +struct bt_hci_cp_le_set_ext_adv_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA BT_OP(BT_OGF_LE, 0x0038) +struct bt_hci_cp_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t op; + uint8_t frag_pref; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0039) +struct bt_hci_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_ext_adv_evts; +} __packed; + +struct bt_hci_cp_le_set_ext_adv_enable { + uint8_t enable; + uint8_t set_num; + struct bt_hci_ext_adv_set s[0]; +} __packed; + +#define BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN BT_OP(BT_OGF_LE, 0x003a) +struct bt_hci_rp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_adv_data_len; +} __packed; + +#define BT_HCI_OP_LE_READ_NUM_ADV_SETS BT_OP(BT_OGF_LE, 0x003b) +struct bt_hci_rp_le_read_num_adv_sets { + uint8_t status; + uint8_t num_sets; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ADV_SET BT_OP(BT_OGF_LE, 0x003c) +struct bt_hci_cp_le_remove_adv_set { + uint8_t handle; +} __packed; + +#define BT_HCI_OP_CLEAR_ADV_SETS BT_OP(BT_OGF_LE, 0x003d) + +#define BT_HCI_LE_PER_ADV_INTERVAL_MIN 0x0006 +#define BT_HCI_LE_PER_ADV_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM BT_OP(BT_OGF_LE, 0x003e) +struct bt_hci_cp_le_set_per_adv_param { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; +} __packed; + +#define BT_HCI_LE_PER_ADV_OP_INTERM_FRAG 0x00 +#define BT_HCI_LE_PER_ADV_OP_FIRST_FRAG 0x01 +#define BT_HCI_LE_PER_ADV_OP_LAST_FRAG 0x02 +#define BT_HCI_LE_PER_ADV_OP_COMPLETE_DATA 0x03 + +#define BT_HCI_LE_PER_ADV_FRAG_MAX_LEN 252 + +#define BT_HCI_OP_LE_SET_PER_ADV_DATA BT_OP(BT_OGF_LE, 0x003f) +struct bt_hci_cp_le_set_per_adv_data { + uint8_t handle; + uint8_t op; + uint8_t len; + uint8_t data[0]; +} __packed; + +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_ENABLE_ADI BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_ENABLE BT_OP(BT_OGF_LE, 0x0040) +struct bt_hci_cp_le_set_per_adv_enable { + uint8_t enable; + uint8_t handle; +} __packed; + +#define BT_HCI_OP_LE_SET_EXT_SCAN_PARAM BT_OP(BT_OGF_LE, 0x0041) +struct bt_hci_ext_scan_phy { + uint8_t type; + uint16_t interval; + uint16_t window; +} __packed; + +#define BT_HCI_LE_EXT_SCAN_PHY_1M BIT(0) +#define BT_HCI_LE_EXT_SCAN_PHY_2M BIT(1) +#define BT_HCI_LE_EXT_SCAN_PHY_CODED BIT(2) + +struct bt_hci_cp_le_set_ext_scan_param { + uint8_t own_addr_type; + uint8_t filter_policy; + uint8_t phys; + struct bt_hci_ext_scan_phy p[0]; +} __packed; + +/* Extends BT_HCI_LE_SCAN_FILTER_DUP */ +#define BT_HCI_LE_EXT_SCAN_FILTER_DUP_ENABLE_RESET 0x02 + +#define BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE BT_OP(BT_OGF_LE, 0x0042) +struct bt_hci_cp_le_set_ext_scan_enable { + uint8_t enable; + uint8_t filter_dup; + uint16_t duration; + uint16_t period; +} __packed; + +#define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) +#define BT_HCI_OP_LE_EXT_CREATE_CONN_V2 BT_OP(BT_OGF_LE, 0x0085) +struct bt_hci_ext_conn_phy { + uint16_t scan_interval; + uint16_t scan_window; + uint16_t conn_interval_min; + uint16_t conn_interval_max; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +} __packed; + +struct bt_hci_cp_le_ext_create_conn { + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +struct bt_hci_cp_le_ext_create_conn_v2 { + uint8_t adv_handle; + uint8_t subevent; + uint8_t filter_policy; + uint8_t own_addr_type; + bt_addr_le_t peer_addr; + uint8_t phys; + struct bt_hci_ext_conn_phy p[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SUBEVENT_DATA BT_OP(BT_OGF_LE, 0x0082) +struct bt_hci_cp_le_set_pawr_subevent_data_element { + uint8_t subevent; + uint8_t response_slot_start; + uint8_t response_slot_count; + uint8_t subevent_data_length; + uint8_t subevent_data[0]; +} __packed; + +struct bt_hci_cp_le_set_pawr_subevent_data { + uint8_t adv_handle; + uint8_t num_subevents; + struct bt_hci_cp_le_set_pawr_subevent_data_element subevents[0]; +} __packed; + + +#define BT_HCI_OP_LE_SET_PER_ADV_RESPONSE_DATA BT_OP(BT_OGF_LE, 0x0083) +struct bt_hci_cp_le_set_pawr_response_data { + uint16_t sync_handle; + uint16_t request_event; + uint8_t request_subevent; + uint8_t response_subevent; + uint8_t response_slot; + uint8_t response_data_length; + uint8_t response_data[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_PER_ADV_SYNC_SUBEVENT BT_OP(BT_OGF_LE, 0x0084) +struct bt_hci_cp_le_set_pawr_sync_subevent { + uint16_t sync_handle; + uint16_t periodic_adv_properties; + uint8_t num_subevents; + uint8_t subevents[0]; +} __packed; + + +#define BT_HCI_OP_LE_SET_PER_ADV_PARAM_V2 BT_OP(BT_OGF_LE, 0x0086) +struct bt_hci_cp_le_set_per_adv_param_v2 { + uint8_t handle; + uint16_t min_interval; + uint16_t max_interval; + uint16_t props; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; + uint8_t num_response_slots; +} __packed; + + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2) + +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ONLY_CTE BIT(4) +/* Constants to check correctness of CTE type */ +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS 5 +#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_INVALID_VALUE \ + (~BIT_MASK(BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_ALLOWED_BITS)) + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC BT_OP(BT_OGF_LE, 0x0044) +struct bt_hci_cp_le_per_adv_create_sync { + uint8_t options; + uint8_t sid; + bt_addr_le_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t cte_type; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_CREATE_SYNC_CANCEL BT_OP(BT_OGF_LE, 0x0045) + +#define BT_HCI_OP_LE_PER_ADV_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x0046) +struct bt_hci_cp_le_per_adv_terminate_sync { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ADD_DEV_TO_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0047) +struct bt_hci_cp_le_add_dev_to_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_REM_DEV_FROM_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0048) +struct bt_hci_cp_le_rem_dev_from_per_adv_list { + bt_addr_le_t addr; + uint8_t sid; +} __packed; + +#define BT_HCI_OP_LE_CLEAR_PER_ADV_LIST BT_OP(BT_OGF_LE, 0x0049) + +#define BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE BT_OP(BT_OGF_LE, 0x004a) +struct bt_hci_rp_le_read_per_adv_list_size { + uint8_t status; + uint8_t list_size; +} __packed; + +#define BT_HCI_OP_LE_READ_TX_POWER BT_OP(BT_OGF_LE, 0x004b) +struct bt_hci_rp_le_read_tx_power { + uint8_t status; + int8_t min_tx_power; + int8_t max_tx_power; +} __packed; + +#define BT_HCI_OP_LE_READ_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004c) +struct bt_hci_rp_le_read_rf_path_comp { + uint8_t status; + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_OP_LE_WRITE_RF_PATH_COMP BT_OP(BT_OGF_LE, 0x004d) +struct bt_hci_cp_le_write_rf_path_comp { + int16_t tx_path_comp; + int16_t rx_path_comp; +} __packed; + +#define BT_HCI_LE_PRIVACY_MODE_NETWORK 0x00 +#define BT_HCI_LE_PRIVACY_MODE_DEVICE 0x01 + +#define BT_HCI_OP_LE_SET_PRIVACY_MODE BT_OP(BT_OGF_LE, 0x004e) +struct bt_hci_cp_le_set_privacy_mode { + bt_addr_le_t id_addr; + uint8_t mode; +} __packed; + +#define BT_HCI_LE_TEST_CTE_DISABLED 0x00 +#define BT_HCI_LE_TEST_CTE_TYPE_ANY 0x00 +#define BT_HCI_LE_TEST_SLOT_DURATION_ANY 0x00 +#define BT_HCI_LE_TEST_SWITCH_PATTERN_LEN_ANY 0x00 + +#define BT_HCI_OP_LE_RX_TEST_V3 BT_OP(BT_OGF_LE, 0x004f) +struct bt_hci_cp_le_rx_test_v3 { + uint8_t rx_ch; + uint8_t phy; + uint8_t mod_index; + uint8_t expected_cte_len; + uint8_t expected_cte_type; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V3 BT_OP(BT_OGF_LE, 0x0050) + +struct bt_hci_cp_le_tx_test_v3 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +/* Min and max Constant Tone Extension length in 8us units */ +#define BT_HCI_LE_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_CTE_LEN_MAX 0x14 + +#define BT_HCI_LE_AOA_CTE 0x0 +#define BT_HCI_LE_AOD_CTE_1US 0x1 +#define BT_HCI_LE_AOD_CTE_2US 0x2 +#define BT_HCI_LE_NO_CTE 0xFF + +#define BT_HCI_LE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0051) +struct bt_hci_cp_le_set_cl_cte_tx_params { + uint8_t handle; + uint8_t cte_len; + uint8_t cte_type; + uint8_t cte_count; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CL_CTE_TX_ENABLE BT_OP(BT_OGF_LE, 0x0052) +struct bt_hci_cp_le_set_cl_cte_tx_enable { + uint8_t handle; + uint8_t cte_enable; +} __packed; + +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_1US 0x1 +#define BT_HCI_LE_ANTENNA_SWITCHING_SLOT_2US 0x2 + +#define BT_HCI_LE_SAMPLE_CTE_ALL 0x0 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MIN 0x1 +#define BT_HCI_LE_SAMPLE_CTE_COUNT_MAX 0x10 + +#define BT_HCI_OP_LE_SET_CL_CTE_SAMPLING_ENABLE BT_OP(BT_OGF_LE, 0x0053) +struct bt_hci_cp_le_set_cl_cte_sampling_enable { + uint16_t sync_handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t max_sampled_cte; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_cl_cte_sampling_enable { + uint8_t status; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_OP_LE_SET_CONN_CTE_RX_PARAMS BT_OP(BT_OGF_LE, 0x0054) +struct bt_hci_cp_le_set_conn_cte_rx_params { + uint16_t handle; + uint8_t sampling_enable; + uint8_t slot_durations; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_rx_params { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_AOA_CTE_RSP BIT(0) +#define BT_HCI_LE_AOD_CTE_RSP_1US BIT(1) +#define BT_HCI_LE_AOD_CTE_RSP_2US BIT(2) + +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_OP_LE_SET_CONN_CTE_TX_PARAMS BT_OP(BT_OGF_LE, 0x0055) +struct bt_hci_cp_le_set_conn_cte_tx_params { + uint16_t handle; + uint8_t cte_types; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +struct bt_hci_rp_le_set_conn_cte_tx_params { + uint8_t status; + uint16_t handle; +} __packed; + +/* Interval between consecutive CTE request procedure starts in number of connection events. */ +#define BT_HCI_REQUEST_CTE_ONCE 0x0 +#define BT_HCI_REQUEST_CTE_INTERVAL_MIN 0x1 +#define BT_HCI_REQUEST_CTE_INTERVAL_MAX 0xFFFF + +#define BT_HCI_OP_LE_CONN_CTE_REQ_ENABLE BT_OP(BT_OGF_LE, 0x0056) +struct bt_hci_cp_le_conn_cte_req_enable { + uint16_t handle; + uint8_t enable; + uint16_t cte_request_interval; + uint8_t requested_cte_length; + uint8_t requested_cte_type; +} __packed; + +struct bt_hci_rp_le_conn_cte_req_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CONN_CTE_RSP_ENABLE BT_OP(BT_OGF_LE, 0x0057) +struct bt_hci_cp_le_conn_cte_rsp_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +struct bt_hci_rp_le_conn_cte_rsp_enable { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_LE_1US_AOD_TX BIT(0) +#define BT_HCI_LE_1US_AOD_RX BIT(1) +#define BT_HCI_LE_1US_AOA_RX BIT(2) + +#define BT_HCI_LE_NUM_ANT_MIN 0x1 +#define BT_HCI_LE_NUM_ANT_MAX 0x4B + +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_SWITCH_PATTERN_LEN_MAX 0x4B + +#define BT_HCI_LE_MAX_CTE_LEN_MIN 0x2 +#define BT_HCI_LE_MAX_CTE_LEN_MAX 0x14 + +#define BT_HCI_OP_LE_READ_ANT_INFO BT_OP(BT_OGF_LE, 0x0058) +struct bt_hci_rp_le_read_ant_info { + uint8_t status; + uint8_t switch_sample_rates; + uint8_t num_ant; + uint8_t max_switch_pattern_len; + uint8_t max_cte_len; +}; + +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_ENABLE BIT(0) +#define BT_HCI_LE_SET_PER_ADV_RECV_ENABLE_FILTER_DUPLICATE BIT(1) + +#define BT_HCI_OP_LE_SET_PER_ADV_RECV_ENABLE BT_OP(BT_OGF_LE, 0x0059) +struct bt_hci_cp_le_set_per_adv_recv_enable { + uint16_t handle; + uint8_t enable; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SYNC_TRANSFER BT_OP(BT_OGF_LE, 0x005a) +struct bt_hci_cp_le_per_adv_sync_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_sync_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_PER_ADV_SET_INFO_TRANSFER BT_OP(BT_OGF_LE, 0x005b) +struct bt_hci_cp_le_per_adv_set_info_transfer { + uint16_t conn_handle; + uint16_t service_data; + uint8_t adv_handle; +} __packed; + +struct bt_hci_rp_le_per_adv_set_info_transfer { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_LE_PAST_MODE_NO_SYNC 0x00 +#define BT_HCI_LE_PAST_MODE_NO_REPORTS 0x01 +#define BT_HCI_LE_PAST_MODE_SYNC 0x02 +#define BT_HCI_LE_PAST_MODE_SYNC_FILTER_DUPLICATES 0x03 + +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOA BIT(0) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_1US BIT(1) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_AOD_2US BIT(2) +#define BT_HCI_LE_PAST_CTE_TYPE_NO_CTE BIT(3) +#define BT_HCI_LE_PAST_CTE_TYPE_ONLY_CTE BIT(4) + +#define BT_HCI_OP_LE_PAST_PARAM BT_OP(BT_OGF_LE, 0x005c) +struct bt_hci_cp_le_past_param { + uint16_t conn_handle; + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_past_param { + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_OP_LE_DEFAULT_PAST_PARAM BT_OP(BT_OGF_LE, 0x005d) +struct bt_hci_cp_le_default_past_param { + uint8_t mode; + uint16_t skip; + uint16_t timeout; + uint8_t cte_type; +} __packed; + +struct bt_hci_rp_le_default_past_param { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_BUFFER_SIZE_V2 BT_OP(BT_OGF_LE, 0x0060) +struct bt_hci_rp_le_read_buffer_size_v2 { + uint8_t status; + uint16_t acl_max_len; + uint8_t acl_max_num; + uint16_t iso_max_len; + uint8_t iso_max_num; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_TX_SYNC BT_OP(BT_OGF_LE, 0x0061) +struct bt_hci_cp_le_read_iso_tx_sync { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_tx_sync { + uint8_t status; + uint16_t handle; + uint16_t seq; + uint32_t timestamp; + uint8_t offset[3]; +} __packed; + +#define BT_HCI_ISO_CIG_ID_MAX 0xFE +#define BT_HCI_ISO_CIS_COUNT_MAX 0x1F +#define BT_HCI_ISO_SDU_INTERVAL_MIN 0x0000FF +#define BT_HCI_ISO_SDU_INTERVAL_MAX 0x0FFFFF +#define BT_HCI_ISO_WORST_CASE_SCA_VALID_MASK 0x07 +#define BT_HCI_ISO_PACKING_VALID_MASK 0x01 +#define BT_HCI_ISO_FRAMING_VALID_MASK 0x01 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MIN 0x0005 +#define BT_HCI_ISO_MAX_TRANSPORT_LATENCY_MAX 0x0FA0 +#define BT_HCI_ISO_CIS_ID_VALID_MAX 0xEF +#define BT_HCI_ISO_MAX_SDU_VALID_MASK 0x0FFF +#define BT_HCI_ISO_PHY_VALID_MASK 0x07 +#define BT_HCI_ISO_INTERVAL_MIN 0x0004 +#define BT_HCI_ISO_INTERVAL_MAX 0x0C80 + +#define BT_HCI_OP_LE_SET_CIG_PARAMS BT_OP(BT_OGF_LE, 0x0062) +struct bt_hci_cis_params { + uint8_t cis_id; + uint16_t c_sdu; + uint16_t p_sdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_rtn; + uint8_t p_rtn; +} __packed; + +struct bt_hci_cp_le_set_cig_params { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint16_t c_latency; + uint16_t p_latency; + uint8_t num_cis; + struct bt_hci_cis_params cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_SET_CIG_PARAMS_TEST BT_OP(BT_OGF_LE, 0x0063) +struct bt_hci_cis_params_test { + uint8_t cis_id; + uint8_t nse; + uint16_t c_sdu; + uint16_t p_sdu; + uint16_t c_pdu; + uint16_t p_pdu; + uint8_t c_phy; + uint8_t p_phy; + uint8_t c_bn; + uint8_t p_bn; +} __packed; + +struct bt_hci_cp_le_set_cig_params_test { + uint8_t cig_id; + uint8_t c_interval[3]; + uint8_t p_interval[3]; + uint8_t c_ft; + uint8_t p_ft; + uint16_t iso_interval; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint8_t num_cis; + struct bt_hci_cis_params_test cis[0]; +} __packed; + +struct bt_hci_rp_le_set_cig_params_test { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_CIS BT_OP(BT_OGF_LE, 0x0064) +struct bt_hci_cis { + uint16_t cis_handle; + uint16_t acl_handle; +} __packed; + +struct bt_hci_cp_le_create_cis { + uint8_t num_cis; + struct bt_hci_cis cis[0]; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_CIG BT_OP(BT_OGF_LE, 0x0065) +struct bt_hci_cp_le_remove_cig { + uint8_t cig_id; +} __packed; + +struct bt_hci_rp_le_remove_cig { + uint8_t status; + uint8_t cig_id; +} __packed; + +#define BT_HCI_OP_LE_ACCEPT_CIS BT_OP(BT_OGF_LE, 0x0066) +struct bt_hci_cp_le_accept_cis { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REJECT_CIS BT_OP(BT_OGF_LE, 0x0067) +struct bt_hci_cp_le_reject_cis { + uint16_t handle; + uint8_t reason; +} __packed; + +struct bt_hci_rp_le_reject_cis { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG BT_OP(BT_OGF_LE, 0x0068) +struct bt_hci_cp_le_create_big { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint16_t max_latency; + uint8_t rtn; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_CREATE_BIG_TEST BT_OP(BT_OGF_LE, 0x0069) +struct bt_hci_cp_le_create_big_test { + uint8_t big_handle; + uint8_t adv_handle; + uint8_t num_bis; + uint8_t sdu_interval[3]; + uint16_t iso_interval; + uint8_t nse; + uint16_t max_sdu; + uint16_t max_pdu; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t bn; + uint8_t irc; + uint8_t pto; + uint8_t encryption; + uint8_t bcode[16]; +} __packed; + +#define BT_HCI_OP_LE_TERMINATE_BIG BT_OP(BT_OGF_LE, 0x006a) +struct bt_hci_cp_le_terminate_big { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_OP_LE_BIG_CREATE_SYNC BT_OP(BT_OGF_LE, 0x006b) +struct bt_hci_cp_le_big_create_sync { + uint8_t big_handle; + uint16_t sync_handle; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t mse; + uint16_t sync_timeout; + uint8_t num_bis; + uint8_t bis[0]; +} __packed; + +#define BT_HCI_OP_LE_BIG_TERMINATE_SYNC BT_OP(BT_OGF_LE, 0x006c) +struct bt_hci_cp_le_big_terminate_sync { + uint8_t big_handle; +} __packed; + +struct bt_hci_rp_le_big_terminate_sync { + uint8_t status; + uint8_t big_handle; +} __packed; + +#define BT_HCI_OP_LE_REQ_PEER_SC BT_OP(BT_OGF_LE, 0x006d) +struct bt_hci_cp_le_req_peer_sca { + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_SETUP_ISO_PATH BT_OP(BT_OGF_LE, 0x006e) +struct bt_hci_cp_le_setup_iso_path { + uint16_t handle; + uint8_t path_dir; + uint8_t path_id; + struct bt_hci_cp_codec_id codec_id; + uint8_t controller_delay[3]; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __packed; + +struct bt_hci_rp_le_setup_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_REMOVE_ISO_PATH BT_OP(BT_OGF_LE, 0x006f) +struct bt_hci_cp_le_remove_iso_path { + uint16_t handle; + uint8_t path_dir; +} __packed; + +struct bt_hci_rp_le_remove_iso_path { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_ISO_TEST_ZERO_SIZE_SDU 0 +#define BT_HCI_ISO_TEST_VARIABLE_SIZE_SDU 1 +#define BT_HCI_ISO_TEST_MAX_SIZE_SDU 2 + +#define BT_HCI_OP_LE_ISO_TRANSMIT_TEST BT_OP(BT_OGF_LE, 0x0070) +struct bt_hci_cp_le_iso_transmit_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_transmit_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_RECEIVE_TEST BT_OP(BT_OGF_LE, 0x0071) +struct bt_hci_cp_le_iso_receive_test { + uint16_t handle; + uint8_t payload_type; +} __packed; + +struct bt_hci_rp_le_iso_receive_test { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_OP_LE_ISO_READ_TEST_COUNTERS BT_OP(BT_OGF_LE, 0x0072) +struct bt_hci_cp_le_read_test_counters { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_test_counters { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_ISO_TEST_END BT_OP(BT_OGF_LE, 0x0073) +struct bt_hci_cp_le_iso_test_end { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_iso_test_end { + uint8_t status; + uint16_t handle; + uint32_t received_cnt; + uint32_t missed_cnt; + uint32_t failed_cnt; +} __packed; + +#define BT_HCI_OP_LE_SET_HOST_FEATURE BT_OP(BT_OGF_LE, 0x0074) +struct bt_hci_cp_le_set_host_feature { + uint8_t bit_number; + uint8_t bit_value; +} __packed; + +struct bt_hci_rp_le_set_host_feature { + uint8_t status; +} __packed; + +#define BT_HCI_OP_LE_READ_ISO_LINK_QUALITY BT_OP(BT_OGF_LE, 0x0075) +struct bt_hci_cp_le_read_iso_link_quality { + uint16_t handle; +} __packed; + +struct bt_hci_rp_le_read_iso_link_quality { + uint8_t status; + uint16_t handle; + uint32_t tx_unacked_packets; + uint32_t tx_flushed_packets; + uint32_t tx_last_subevent_packets; + uint32_t retransmitted_packets; + uint32_t crc_error_packets; + uint32_t rx_unreceived_packets; + uint32_t duplicate_packets; +} __packed; + +#define BT_HCI_OP_LE_TX_TEST_V4 BT_OP(BT_OGF_LE, 0x007B) + +struct bt_hci_cp_le_tx_test_v4 { + uint8_t tx_ch; + uint8_t test_data_len; + uint8_t pkt_payload; + uint8_t phy; + uint8_t cte_len; + uint8_t cte_type; + uint8_t switch_pattern_len; + uint8_t ant_ids[0]; +} __packed; + +#define BT_HCI_TX_TEST_POWER_MIN -0x7F +#define BT_HCI_TX_TEST_POWER_MAX 0x14 + +#define BT_HCI_TX_TEST_POWER_MIN_SET 0x7E +#define BT_HCI_TX_TEST_POWER_MAX_SET 0x7F + +/* Helper structure for Tx power parameter in the HCI Tx Test v4 command. + * Previous parameter of this command is variable size so having separated structure + * for this parameter helps in command parameters unpacking. + */ +struct bt_hci_cp_le_tx_test_v4_tx_power { + int8_t tx_power; +} __packed; + +/* Event definitions */ + +#define BT_HCI_EVT_UNKNOWN 0x00 +#define BT_HCI_EVT_VENDOR 0xff + +#define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 +struct bt_hci_evt_inquiry_complete { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CONN_COMPLETE 0x03 +struct bt_hci_evt_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t encr_enabled; +} __packed; + +#define BT_HCI_EVT_CONN_REQUEST 0x04 +struct bt_hci_evt_conn_request { + bt_addr_t bdaddr; + uint8_t dev_class[3]; + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_DISCONN_COMPLETE 0x05 +struct bt_hci_evt_disconn_complete { + uint8_t status; + uint16_t handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE 0x07 +struct bt_hci_evt_remote_name_req_complete { + uint8_t status; + bt_addr_t bdaddr; + uint8_t name[248]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encrypt; +} __packed; + +#define BT_HCI_EVT_REMOTE_FEATURES 0x0b +struct bt_hci_evt_remote_features { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_REMOTE_VERSION_INFO 0x0c +struct bt_hci_evt_remote_version_info { + uint8_t status; + uint16_t handle; + uint8_t version; + uint16_t manufacturer; + uint16_t subversion; +} __packed; + +#define BT_HCI_EVT_CMD_COMPLETE 0x0e +struct bt_hci_evt_cmd_complete { + uint8_t ncmd; + uint16_t opcode; +} __packed; + +struct bt_hci_evt_cc_status { + uint8_t status; +} __packed; + +#define BT_HCI_EVT_CMD_STATUS 0x0f +struct bt_hci_evt_cmd_status { + uint8_t status; + uint8_t ncmd; + uint16_t opcode; +} __packed; + +#define BT_HCI_EVT_HARDWARE_ERROR 0x10 +struct bt_hci_evt_hardware_error { + uint8_t hardware_code; +} __packed; + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + bt_addr_t bdaddr; + uint8_t role; +} __packed; + +#define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 +struct bt_hci_evt_num_completed_packets { + uint8_t num_handles; + struct bt_hci_handle_count h[0]; +} __packed; + +#define BT_HCI_EVT_PIN_CODE_REQ 0x16 +struct bt_hci_evt_pin_code_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_LINK_KEY_REQ 0x17 +struct bt_hci_evt_link_key_req { + bt_addr_t bdaddr; +} __packed; + +/* Link Key types */ +#define BT_LK_COMBINATION 0x00 +#define BT_LK_LOCAL_UNIT 0x01 +#define BT_LK_REMOTE_UNIT 0x02 +#define BT_LK_DEBUG_COMBINATION 0x03 +#define BT_LK_UNAUTH_COMBINATION_P192 0x04 +#define BT_LK_AUTH_COMBINATION_P192 0x05 +#define BT_LK_CHANGED_COMBINATION 0x06 +#define BT_LK_UNAUTH_COMBINATION_P256 0x07 +#define BT_LK_AUTH_COMBINATION_P256 0x08 + +#define BT_HCI_EVT_LINK_KEY_NOTIFY 0x18 +struct bt_hci_evt_link_key_notify { + bt_addr_t bdaddr; + uint8_t link_key[16]; + uint8_t key_type; +} __packed; + +/* Overflow link types */ +#define BT_OVERFLOW_LINK_SYNCH 0x00 +#define BT_OVERFLOW_LINK_ACL 0x01 +#define BT_OVERFLOW_LINK_ISO 0x02 + +#define BT_HCI_EVT_DATA_BUF_OVERFLOW 0x1a +struct bt_hci_evt_data_buf_overflow { + uint8_t link_type; +} __packed; + +#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 +struct bt_hci_evt_inquiry_result_with_rssi { + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; +} __packed; + +#define BT_HCI_EVT_REMOTE_EXT_FEATURES 0x23 +struct bt_hci_evt_remote_ext_features { + uint8_t status; + uint16_t handle; + uint8_t page; + uint8_t max_page; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED_V2 0x24 +struct bt_hci_evt_le_per_adv_sync_established_v2 { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT_V2 0x25 +struct bt_hci_evt_le_per_advertising_report_v2 { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint16_t periodic_event_counter; + uint8_t subevent; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED_V2 0x26 +struct bt_hci_evt_le_past_received_v2 { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; + uint8_t num_subevents; + uint8_t subevent_interval; + uint8_t response_slot_delay; + uint8_t response_slot_spacing; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SUBEVENT_DATA_REQUEST 0x27 +struct bt_hci_evt_le_per_adv_subevent_data_request { + uint8_t adv_handle; + uint8_t subevent_start; + uint8_t subevent_data_count; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_RESPONSE_REPORT 0x28 + +struct bt_hci_evt_le_per_adv_response { + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t response_slot; + uint8_t data_status; + uint8_t data_length; + uint8_t data[0]; +} __packed; + +struct bt_hci_evt_le_per_adv_response_report { + uint8_t adv_handle; + uint8_t subevent; + uint8_t tx_status; + uint8_t num_responses; + struct bt_hci_evt_le_per_adv_response responses[0]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2 0x29 +struct bt_hci_evt_le_enh_conn_complete_v2 { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; + uint8_t adv_handle; + uint16_t sync_handle; +} __packed; + +#define BT_HCI_EVT_SYNC_CONN_COMPLETE 0x2c +struct bt_hci_evt_sync_conn_complete { + uint8_t status; + uint16_t handle; + bt_addr_t bdaddr; + uint8_t link_type; + uint8_t tx_interval; + uint8_t retansmission_window; + uint16_t rx_pkt_length; + uint16_t tx_pkt_length; + uint8_t air_mode; +} __packed; + +#define BT_HCI_EVT_EXTENDED_INQUIRY_RESULT 0x2f +struct bt_hci_evt_extended_inquiry_result { + uint8_t num_reports; + bt_addr_t addr; + uint8_t pscan_rep_mode; + uint8_t reserved; + uint8_t cod[3]; + uint16_t clock_offset; + int8_t rssi; + uint8_t eir[240]; +} __packed; + +#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE 0x30 +struct bt_hci_evt_encrypt_key_refresh_complete { + uint8_t status; + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_REQ 0x31 +struct bt_hci_evt_io_capa_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_IO_CAPA_RESP 0x32 +struct bt_hci_evt_io_capa_resp { + bt_addr_t bdaddr; + uint8_t capability; + uint8_t oob_data; + uint8_t authentication; +} __packed; + +#define BT_HCI_EVT_USER_CONFIRM_REQ 0x33 +struct bt_hci_evt_user_confirm_req { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_REQ 0x34 +struct bt_hci_evt_user_passkey_req { + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_SSP_COMPLETE 0x36 +struct bt_hci_evt_ssp_complete { + uint8_t status; + bt_addr_t bdaddr; +} __packed; + +#define BT_HCI_EVT_USER_PASSKEY_NOTIFY 0x3b +struct bt_hci_evt_user_passkey_notify { + bt_addr_t bdaddr; + uint32_t passkey; +} __packed; + +#define BT_HCI_EVT_LE_META_EVENT 0x3e +struct bt_hci_evt_le_meta_event { + uint8_t subevent; +} __packed; + +#define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 +struct bt_hci_evt_auth_payload_timeout_exp { + uint16_t handle; +} __packed; + +#define BT_HCI_ROLE_CENTRAL 0x00 +#define BT_HCI_ROLE_PERIPHERAL 0x01 + +#define BT_HCI_EVT_LE_CONN_COMPLETE 0x01 +struct bt_hci_evt_le_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_LE_RSSI_NOT_AVAILABLE 0x7F + +#define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02 +struct bt_hci_evt_le_advertising_info { + uint8_t evt_type; + bt_addr_le_t addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE 0x03 +struct bt_hci_evt_le_conn_update_complete { + uint8_t status; + uint16_t handle; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; +} __packed; + +#define BT_HCI_EVT_LE_REMOTE_FEAT_COMPLETE 0x04 +struct bt_hci_evt_le_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t features[8]; +} __packed; + +#define BT_HCI_EVT_LE_LTK_REQUEST 0x05 +struct bt_hci_evt_le_ltk_request { + uint16_t handle; + uint64_t rand; + uint16_t ediv; +} __packed; + +#define BT_HCI_EVT_LE_CONN_PARAM_REQ 0x06 +struct bt_hci_evt_le_conn_param_req { + uint16_t handle; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t timeout; +} __packed; + +#define BT_HCI_EVT_LE_DATA_LEN_CHANGE 0x07 +struct bt_hci_evt_le_data_len_change { + uint16_t handle; + uint16_t max_tx_octets; + uint16_t max_tx_time; + uint16_t max_rx_octets; + uint16_t max_rx_time; +} __packed; + +#define BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE 0x08 +struct bt_hci_evt_le_p256_public_key_complete { + uint8_t status; + uint8_t key[64]; +} __packed; + +#define BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE 0x09 +struct bt_hci_evt_le_generate_dhkey_complete { + uint8_t status; + uint8_t dhkey[32]; +} __packed; + +#define BT_HCI_EVT_LE_ENH_CONN_COMPLETE 0x0a +struct bt_hci_evt_le_enh_conn_complete { + uint8_t status; + uint16_t handle; + uint8_t role; + bt_addr_le_t peer_addr; + bt_addr_t local_rpa; + bt_addr_t peer_rpa; + uint16_t interval; + uint16_t latency; + uint16_t supv_timeout; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_DIRECT_ADV_REPORT 0x0b +struct bt_hci_evt_le_direct_adv_info { + uint8_t evt_type; + bt_addr_le_t addr; + bt_addr_le_t dir_addr; + int8_t rssi; +} __packed; +struct bt_hci_evt_le_direct_adv_report { + uint8_t num_reports; + struct bt_hci_evt_le_direct_adv_info direct_adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE 0x0c +struct bt_hci_evt_le_phy_update_complete { + uint8_t status; + uint16_t handle; + uint8_t tx_phy; + uint8_t rx_phy; +} __packed; + +#define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_RX_FAILED 0xFF + +struct bt_hci_evt_le_ext_advertising_info { + uint16_t evt_type; + bt_addr_le_t addr; + uint8_t prim_phy; + uint8_t sec_phy; + uint8_t sid; + int8_t tx_power; + int8_t rssi; + uint16_t interval; + bt_addr_le_t direct_addr; + uint8_t length; + uint8_t data[0]; +} __packed; +struct bt_hci_evt_le_ext_advertising_report { + uint8_t num_reports; + struct bt_hci_evt_le_ext_advertising_info adv_info[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_ESTABLISHED 0x0e +struct bt_hci_evt_le_per_adv_sync_established { + uint8_t status; + uint16_t handle; + uint8_t sid; + bt_addr_le_t adv_addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADVERTISING_REPORT 0x0f +struct bt_hci_evt_le_per_advertising_report { + uint16_t handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t data_status; + uint8_t length; + uint8_t data[0]; +} __packed; + +#define BT_HCI_EVT_LE_PER_ADV_SYNC_LOST 0x10 +struct bt_hci_evt_le_per_adv_sync_lost { + uint16_t handle; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 + +#define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 +struct bt_hci_evt_le_adv_set_terminated { + uint8_t status; + uint8_t adv_handle; + uint16_t conn_handle; + uint8_t num_completed_ext_adv_evts; +} __packed; + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + bt_addr_le_t addr; +} __packed; + +#define BT_HCI_LE_CHAN_SEL_ALGO_1 0x00 +#define BT_HCI_LE_CHAN_SEL_ALGO_2 0x01 + +#define BT_HCI_EVT_LE_CHAN_SEL_ALGO 0x14 +struct bt_hci_evt_le_chan_sel_algo { + uint16_t handle; + uint8_t chan_sel_algo; +} __packed; + +#define BT_HCI_LE_CTE_CRC_OK 0x0 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_TIME 0x1 +#define BT_HCI_LE_CTE_CRC_ERR_CTE_BASED_OTHER 0x2 +#define BT_HCI_LE_CTE_INSUFFICIENT_RESOURCES 0xFF + +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MIN 0x9 +#define B_HCI_LE_CTE_REPORT_SAMPLE_COUNT_MAX 0x52 + +#define BT_HCI_LE_CTE_REPORT_NO_VALID_SAMPLE 0x80 + +#define BT_HCI_EVT_LE_CONNECTIONLESS_IQ_REPORT 0x15 +struct bt_hci_le_iq_sample { + int8_t i; + int8_t q; +}; + +struct bt_hci_evt_le_connectionless_iq_report { + uint16_t sync_handle; + uint8_t chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t per_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_EVT_LE_CONNECTION_IQ_REPORT 0x16 +struct bt_hci_evt_le_connection_iq_report { + uint16_t conn_handle; + uint8_t rx_phy; + uint8_t data_chan_idx; + int16_t rssi; + uint8_t rssi_ant_id; + uint8_t cte_type; + uint8_t slot_durations; + uint8_t packet_status; + uint16_t conn_evt_counter; + uint8_t sample_count; + struct bt_hci_le_iq_sample sample[0]; +} __packed; + +#define BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE 0x0 + +#define BT_HCI_EVT_LE_CTE_REQUEST_FAILED 0x17 +struct bt_hci_evt_le_cte_req_failed { + /* According to BT 5.3 Core Spec the status field may have following + * values: + * - BT_HCI_CTE_REQ_STATUS_RSP_WITHOUT_CTE when received LL_CTE_RSP_PDU without CTE. + * - Other Controller error code for peer rejected request. + */ + uint8_t status; + uint16_t conn_handle; +} __packed; + +#define BT_HCI_EVT_LE_PAST_RECEIVED 0x18 +struct bt_hci_evt_le_past_received { + uint8_t status; + uint16_t conn_handle; + uint16_t service_data; + uint16_t sync_handle; + uint8_t adv_sid; + bt_addr_le_t addr; + uint8_t phy; + uint16_t interval; + uint8_t clock_accuracy; +} __packed; + +#define BT_HCI_EVT_LE_CIS_ESTABLISHED 0x19 +struct bt_hci_evt_le_cis_established { + uint8_t status; + uint16_t conn_handle; + uint8_t cig_sync_delay[3]; + uint8_t cis_sync_delay[3]; + uint8_t c_latency[3]; + uint8_t p_latency[3]; + uint8_t c_phy; + uint8_t p_phy; + uint8_t nse; + uint8_t c_bn; + uint8_t p_bn; + uint8_t c_ft; + uint8_t p_ft; + uint16_t c_max_pdu; + uint16_t p_max_pdu; + uint16_t interval; +} __packed; + +#define BT_HCI_EVT_LE_CIS_REQ 0x1a +struct bt_hci_evt_le_cis_req { + uint16_t acl_handle; + uint16_t cis_handle; + uint8_t cig_id; + uint8_t cis_id; +} __packed; + +#define BT_HCI_EVT_LE_BIG_COMPLETE 0x1b +struct bt_hci_evt_le_big_complete { + uint8_t status; + uint8_t big_handle; + uint8_t sync_delay[3]; + uint8_t latency[3]; + uint8_t phy; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_TERMINATE 0x1c +struct bt_hci_evt_le_big_terminate { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d +struct bt_hci_evt_le_big_sync_established { + uint8_t status; + uint8_t big_handle; + uint8_t latency[3]; + uint8_t nse; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint16_t iso_interval; + uint8_t num_bis; + uint16_t handle[0]; +} __packed; + +#define BT_HCI_EVT_LE_BIG_SYNC_LOST 0x1e +struct bt_hci_evt_le_big_sync_lost { + uint8_t big_handle; + uint8_t reason; +} __packed; + +#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE 0x1f +struct bt_hci_evt_le_req_peer_sca_complete { + uint8_t status; + uint16_t handle; + uint8_t sca; +} __packed; + +#define BT_HCI_EVT_LE_BIGINFO_ADV_REPORT 0x22 +struct bt_hci_evt_le_biginfo_adv_report { + uint16_t sync_handle; + uint8_t num_bis; + uint8_t nse; + uint16_t iso_interval; + uint8_t bn; + uint8_t pto; + uint8_t irc; + uint16_t max_pdu; + uint8_t sdu_interval[3]; + uint16_t max_sdu; + uint8_t phy; + uint8_t framing; + uint8_t encryption; +} __packed; + +/* Event mask bits */ + +#define BT_EVT_BIT(n) (1ULL << (n)) + +#define BT_EVT_MASK_INQUIRY_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_CONN_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_CONN_REQUEST BT_EVT_BIT(3) +#define BT_EVT_MASK_DISCONN_COMPLETE BT_EVT_BIT(4) +#define BT_EVT_MASK_AUTH_COMPLETE BT_EVT_BIT(5) +#define BT_EVT_MASK_REMOTE_NAME_REQ_COMPLETE BT_EVT_BIT(6) +#define BT_EVT_MASK_ENCRYPT_CHANGE BT_EVT_BIT(7) +#define BT_EVT_MASK_REMOTE_FEATURES BT_EVT_BIT(10) +#define BT_EVT_MASK_REMOTE_VERSION_INFO BT_EVT_BIT(11) +#define BT_EVT_MASK_HARDWARE_ERROR BT_EVT_BIT(15) +#define BT_EVT_MASK_ROLE_CHANGE BT_EVT_BIT(17) +#define BT_EVT_MASK_PIN_CODE_REQ BT_EVT_BIT(21) +#define BT_EVT_MASK_LINK_KEY_REQ BT_EVT_BIT(22) +#define BT_EVT_MASK_LINK_KEY_NOTIFY BT_EVT_BIT(23) +#define BT_EVT_MASK_DATA_BUFFER_OVERFLOW BT_EVT_BIT(25) +#define BT_EVT_MASK_INQUIRY_RESULT_WITH_RSSI BT_EVT_BIT(33) +#define BT_EVT_MASK_REMOTE_EXT_FEATURES BT_EVT_BIT(34) +#define BT_EVT_MASK_SYNC_CONN_COMPLETE BT_EVT_BIT(43) +#define BT_EVT_MASK_EXTENDED_INQUIRY_RESULT BT_EVT_BIT(46) +#define BT_EVT_MASK_ENCRYPT_KEY_REFRESH_COMPLETE BT_EVT_BIT(47) +#define BT_EVT_MASK_IO_CAPA_REQ BT_EVT_BIT(48) +#define BT_EVT_MASK_IO_CAPA_RESP BT_EVT_BIT(49) +#define BT_EVT_MASK_USER_CONFIRM_REQ BT_EVT_BIT(50) +#define BT_EVT_MASK_USER_PASSKEY_REQ BT_EVT_BIT(51) +#define BT_EVT_MASK_SSP_COMPLETE BT_EVT_BIT(53) +#define BT_EVT_MASK_USER_PASSKEY_NOTIFY BT_EVT_BIT(58) +#define BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61) + +/* Page 2 */ +#define BT_EVT_MASK_NUM_COMPLETE_DATA_BLOCKS BT_EVT_BIT(8) +#define BT_EVT_MASK_TRIGG_CLOCK_CAPTURE BT_EVT_BIT(14) +#define BT_EVT_MASK_SYNCH_TRAIN_COMPLETE BT_EVT_BIT(15) +#define BT_EVT_MASK_SYNCH_TRAIN_RX BT_EVT_BIT(16) +#define BT_EVT_MASK_CL_PER_BC_RX BT_EVT_BIT(17) +#define BT_EVT_MASK_CL_PER_BC_TIMEOUT BT_EVT_BIT(18) +#define BT_EVT_MASK_TRUNC_PAGE_COMPLETE BT_EVT_BIT(19) +#define BT_EVT_MASK_PER_PAGE_RSP_TIMEOUT BT_EVT_BIT(20) +#define BT_EVT_MASK_CL_PER_BC_CH_MAP_CHANGE BT_EVT_BIT(21) +#define BT_EVT_MASK_INQUIRY_RSP_NOT BT_EVT_BIT(22) +#define BT_EVT_MASK_AUTH_PAYLOAD_TIMEOUT_EXP BT_EVT_BIT(23) +#define BT_EVT_MASK_SAM_STATUS_CHANGE BT_EVT_BIT(24) + +#define BT_EVT_MASK_LE_CONN_COMPLETE BT_EVT_BIT(0) +#define BT_EVT_MASK_LE_ADVERTISING_REPORT BT_EVT_BIT(1) +#define BT_EVT_MASK_LE_CONN_UPDATE_COMPLETE BT_EVT_BIT(2) +#define BT_EVT_MASK_LE_REMOTE_FEAT_COMPLETE BT_EVT_BIT(3) +#define BT_EVT_MASK_LE_LTK_REQUEST BT_EVT_BIT(4) +#define BT_EVT_MASK_LE_CONN_PARAM_REQ BT_EVT_BIT(5) +#define BT_EVT_MASK_LE_DATA_LEN_CHANGE BT_EVT_BIT(6) +#define BT_EVT_MASK_LE_P256_PUBLIC_KEY_COMPLETE BT_EVT_BIT(7) +#define BT_EVT_MASK_LE_GENERATE_DHKEY_COMPLETE BT_EVT_BIT(8) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE BT_EVT_BIT(9) +#define BT_EVT_MASK_LE_DIRECT_ADV_REPORT BT_EVT_BIT(10) +#define BT_EVT_MASK_LE_PHY_UPDATE_COMPLETE BT_EVT_BIT(11) +#define BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT BT_EVT_BIT(12) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED BT_EVT_BIT(13) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT BT_EVT_BIT(14) +#define BT_EVT_MASK_LE_PER_ADV_SYNC_LOST BT_EVT_BIT(15) +#define BT_EVT_MASK_LE_SCAN_TIMEOUT BT_EVT_BIT(16) +#define BT_EVT_MASK_LE_ADV_SET_TERMINATED BT_EVT_BIT(17) +#define BT_EVT_MASK_LE_SCAN_REQ_RECEIVED BT_EVT_BIT(18) +#define BT_EVT_MASK_LE_CHAN_SEL_ALGO BT_EVT_BIT(19) +#define BT_EVT_MASK_LE_CONNECTIONLESS_IQ_REPORT BT_EVT_BIT(20) +#define BT_EVT_MASK_LE_CONNECTION_IQ_REPORT BT_EVT_BIT(21) +#define BT_EVT_MASK_LE_CTE_REQUEST_FAILED BT_EVT_BIT(22) +#define BT_EVT_MASK_LE_PAST_RECEIVED BT_EVT_BIT(23) +#define BT_EVT_MASK_LE_CIS_ESTABLISHED BT_EVT_BIT(24) +#define BT_EVT_MASK_LE_CIS_REQ BT_EVT_BIT(25) +#define BT_EVT_MASK_LE_BIG_COMPLETE BT_EVT_BIT(26) +#define BT_EVT_MASK_LE_BIG_TERMINATED BT_EVT_BIT(27) +#define BT_EVT_MASK_LE_BIG_SYNC_ESTABLISHED BT_EVT_BIT(28) +#define BT_EVT_MASK_LE_BIG_SYNC_LOST BT_EVT_BIT(29) +#define BT_EVT_MASK_LE_REQ_PEER_SCA_COMPLETE BT_EVT_BIT(30) +#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31) +#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32) +#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33) + +#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35) +#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36) +#define BT_EVT_MASK_LE_PAST_RECEIVED_V2 BT_EVT_BIT(37) +#define BT_EVT_MASK_LE_PER_ADV_SUBEVENT_DATA_REQ BT_EVT_BIT(38) +#define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) +#define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) + +/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */ +#define BT_HCI_ERR_SUCCESS 0x00 +#define BT_HCI_ERR_UNKNOWN_CMD 0x01 +#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 +#define BT_HCI_ERR_HW_FAILURE 0x03 +#define BT_HCI_ERR_PAGE_TIMEOUT 0x04 +#define BT_HCI_ERR_AUTH_FAIL 0x05 +#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06 +#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07 +#define BT_HCI_ERR_CONN_TIMEOUT 0x08 +#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09 +#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a +#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b +#define BT_HCI_ERR_CMD_DISALLOWED 0x0c +#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d +#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e +#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f +#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10 +#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11 +#define BT_HCI_ERR_INVALID_PARAM 0x12 +#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13 +#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14 +#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15 +#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16 +#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17 +#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18 +#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19 +#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a +#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b +#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c +#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d +#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e +#define BT_HCI_ERR_UNSPECIFIED 0x1f +#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20 +#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21 +#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22 +#define BT_HCI_ERR_LL_PROC_COLLISION 0x23 +#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24 +#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25 +#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26 +#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27 +#define BT_HCI_ERR_INSTANT_PASSED 0x28 +#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29 +#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a +#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c +#define BT_HCI_ERR_QOS_REJECTED 0x2d +#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e +#define BT_HCI_ERR_INSUFF_SECURITY 0x2f +#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30 +#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32 +#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34 +#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35 +#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36 +#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37 +#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38 +#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39 +#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a +#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b +#define BT_HCI_ERR_ADV_TIMEOUT 0x3c +#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d +#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e +#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f +#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40 +#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41 +#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42 +#define BT_HCI_ERR_LIMIT_REACHED 0x43 +#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 +#define BT_HCI_ERR_PACKET_TOO_LONG 0x45 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_TYPES_H_ */ diff --git a/subsys/bluetooth/controller/coex/coex_ticker.c b/subsys/bluetooth/controller/coex/coex_ticker.c index fa5c22f38316..229e2f9e1256 100644 --- a/subsys/bluetooth/controller/coex/coex_ticker.c +++ b/subsys/bluetooth/controller/coex/coex_ticker.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "controller/hal/ticker.h" #include "controller/ticker/ticker.h" diff --git a/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c b/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c index 8b9696e988b6..5286fb4a993b 100644 --- a/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c +++ b/subsys/bluetooth/controller/flash/soc_flash_nrf_ticker.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "hal/ticker.h" #include "ticker/ticker.h" diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index d17d00de02c1..9894da0ed909 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index b7bfa8c46e71..861d71582f7a 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #ifdef CONFIG_CLOCK_CONTROL_NRF diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 989dc1a2d67c..bd8a93053283 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -5,6 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + +#include + int ll_init(struct k_sem *sem_rx); int ll_deinit(void); void ll_reset(void); diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index ceb82e28de2a..3391428dc56d 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include "util/memq.h" diff --git a/subsys/bluetooth/controller/ll_sw/ll_addr.c b/subsys/bluetooth/controller/ll_sw/ll_addr.c index 2cb0f6381b11..096bec6638fd 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_addr.c +++ b/subsys/bluetooth/controller/ll_sw/ll_addr.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ll_feat.c b/subsys/bluetooth/controller/ll_sw/ll_feat.c index 53c69aaf6b46..a1aaa99ba6de 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_feat.c +++ b/subsys/bluetooth/controller/ll_sw/ll_feat.c @@ -26,7 +26,7 @@ #include "ll_feat.h" #include "ll_settings.h" -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c b/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c index c46b6b399694..3bafb7b3a34a 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c +++ b/subsys/bluetooth/controller/ll_sw/ll_tx_pwr.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 2060345d89f8..8c1b117203b5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 229b13b38313..620370f8e74b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c index b38ff0ff8dc1..b18d073002d6 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_conn.c @@ -39,7 +39,7 @@ #include "lll_tim_internal.h" #include "lll_prof_internal.h" -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c index d1500d2b29b3..1c1f07938e08 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_df.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "util/util.h" #include "util/memq.h" 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 b5c12ab537cf..ab8c5dc90b3a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" 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 652facac9e4d..26d8c3b84789 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 @@ -9,7 +9,7 @@ #include #include -#include +#include #include "hal/ccm.h" #include "hal/radio.h" 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 0136692d58c6..02173b6b92a5 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -40,7 +40,7 @@ #include "ll_feat.h" -#include +#include #include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c index 400c113b63c6..90d00e624d4d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_test.c @@ -41,7 +41,7 @@ #include "ull_df_internal.h" #endif /* CONFIG_BT_CTLR_DTM_HCI_DF_IQ_REPORT */ -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c b/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c index ffe57d1b2c1d..a8727318cc0b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/ull/ull_iso_vendor.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include "isoal.h" #include "ull_iso_types.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c index 8613c0945280..da627366143f 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c @@ -8,7 +8,7 @@ #include -#include +#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c index 0988a606e129..86301199ec80 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index 618be26ab5e5..0f4695d0bc01 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull.c b/subsys/bluetooth/controller/ll_sw/ull.c index 4ea6c837f82c..062e3357573c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull.c +++ b/subsys/bluetooth/controller/ll_sw/ull.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index f0940ca70324..5d77b4eabe29 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c index 59babfa4743c..1e47fdc89f47 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_aux.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 689129ee0cdd..70f4c19a079b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 5f9932435c37..0079e2aa7b78 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index c04ceea98f0f..451d38a8ea6d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index cc71a48cba60..866ff8eb9bb0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -49,7 +49,7 @@ #include "ll.h" #include "ll_feat.h" -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 3a7be227d365..365c743c9bf6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index a28eba5abc32..45da0451bc95 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "util/util.h" #include "util/mem.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_df.c b/subsys/bluetooth/controller/ll_sw/ull_df.c index 70de3e28f364..8be711539daf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_df.c +++ b/subsys/bluetooth/controller/ll_sw/ull_df.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_filter.c b/subsys/bluetooth/controller/ll_sw/ull_filter.c index 27a9799f5937..fd543b3c81a6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_filter.c +++ b/subsys/bluetooth/controller/ll_sw/ull_filter.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index a19bcc5df6e3..d83558f6a8ef 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index d48bda5ef824..01239b5d2e94 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index 46c32e7ae9e0..6cf4899888b4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c index d52da9325290..79835ff8cf64 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index ff72f45b23f4..be96a1ae0a60 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c index 3c1639bc52a7..62c06a3d2387 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c index 2612cc22d09b..54ebbdba5fe8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index 8e55f18c9439..3f8c91983c56 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 06d99bd72580..7162959a85a4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index dc3ea686d05e..cc8333204987 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index ea884073dfe3..5a204db52acf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -6,7 +6,7 @@ #include -#include +#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index c4255dbc450e..c06d9367a2dc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c index 647172032246..f47439514ac0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c @@ -46,7 +46,7 @@ #include "ull_conn_iso_internal.h" #include "ull_llcp_internal.h" -#include +#include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan.c b/subsys/bluetooth/controller/ll_sw/ull_scan.c index 2643771756dd..1ee99565a138 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index b272b6197de6..d46cfd1dba89 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -40,7 +40,7 @@ #include "ull_sync_iso_internal.h" #include "ull_df_internal.h" -#include +#include #include #include "hal/debug.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index 3242420a5c00..9a2d25921a6f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include "hal/ccm.h" #include "hal/radio.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index d2ef126d408f..f3386cdd9f12 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "util/util.h" #include "util/mem.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 604e731849a8..460f04494c36 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "util/util.h" #include "util/mem.h" diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 42151f260a03..4133bb08d7ca 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/tests/bluetooth/controller/mock_ctrl/src/ull_scan.c b/tests/bluetooth/controller/mock_ctrl/src/ull_scan.c index 35a54b679aed..12955b115573 100644 --- a/tests/bluetooth/controller/mock_ctrl/src/ull_scan.c +++ b/tests/bluetooth/controller/mock_ctrl/src/ull_scan.c @@ -9,7 +9,8 @@ #include #include -#include "hci_err.h" +#include + #include "util/mem.h" #include "util/memq.h" #include "pdu_df.h" 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 f655302c52b5..3b279a50fab8 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/central.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/central.c b/tests/bsim/bluetooth/host/security/ccc_update/src/central.c index 5b4e851a5752..fbdf7ee0108a 100644 --- a/tests/bsim/bluetooth/host/security/ccc_update/src/central.c +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/central.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include From 05aabdc6d9c348666646cfd143fd53724a9553d0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 12 Jun 2023 06:06:43 +0530 Subject: [PATCH 0087/2042] Bluetooth: Controller: Rework internal header includes Rework internal header files to not have includes, rather have the required includes in the c source files. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 1 - subsys/bluetooth/controller/hci/hci_driver.c | 1 - subsys/bluetooth/controller/include/ll.h | 5 ----- subsys/bluetooth/controller/ll_sw/isoal.c | 2 +- subsys/bluetooth/controller/ll_sw/isoal.h | 4 ---- subsys/bluetooth/controller/ll_sw/ll_settings.c | 4 ---- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c | 1 - subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c | 6 ++---- subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c | 5 +++-- subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c | 7 +++++-- subsys/bluetooth/controller/ll_sw/pdu.h | 3 +++ subsys/bluetooth/controller/ll_sw/ull_adv_iso.c | 1 - subsys/bluetooth/controller/ll_sw/ull_adv_sync.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 3 ++- subsys/bluetooth/controller/ll_sw/ull_conn.c | 1 - subsys/bluetooth/controller/ll_sw/ull_conn_iso.c | 1 - subsys/bluetooth/controller/ll_sw/ull_internal.h | 2 -- subsys/bluetooth/controller/ll_sw/ull_iso.c | 3 ++- subsys/bluetooth/controller/ll_sw/ull_llcp.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_common.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_llcp_local.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c | 5 +++-- subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c | 6 +++--- subsys/bluetooth/controller/ll_sw/ull_sched.c | 2 ++ subsys/bluetooth/controller/ll_sw/ull_sync.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_sync_iso.c | 1 - subsys/bluetooth/controller/ll_sw/ull_tx_queue.c | 2 ++ subsys/bluetooth/controller/ll_sw/ull_tx_queue.h | 2 -- 34 files changed, 57 insertions(+), 60 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 9894da0ed909..a5bbcb5d364b 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "../host/hci_ecc.h" diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index 861d71582f7a..d4788efa37ab 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -20,7 +20,6 @@ #include #include -#include #include #include diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index bd8a93053283..989dc1a2d67c 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -5,11 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include - -#include - int ll_init(struct k_sem *sem_rx); int ll_deinit(void); void ll_reset(void); diff --git a/subsys/bluetooth/controller/ll_sw/isoal.c b/subsys/bluetooth/controller/ll_sw/isoal.c index 3391428dc56d..0a500cfd05e8 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.c +++ b/subsys/bluetooth/controller/ll_sw/isoal.c @@ -13,8 +13,8 @@ #include -#include #include +#include #include "util/memq.h" diff --git a/subsys/bluetooth/controller/ll_sw/isoal.h b/subsys/bluetooth/controller/ll_sw/isoal.h index 2bceebe7de74..44f3504f1a6e 100644 --- a/subsys/bluetooth/controller/ll_sw/isoal.h +++ b/subsys/bluetooth/controller/ll_sw/isoal.h @@ -4,10 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include - #if defined(CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS) && (CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0) #define ISOAL_BUFFER_RX_SDUS_ENABLE #endif /* CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0 */ diff --git a/subsys/bluetooth/controller/ll_sw/ll_settings.c b/subsys/bluetooth/controller/ll_sw/ll_settings.c index 75723e4cf625..6ca3bb673759 100644 --- a/subsys/bluetooth/controller/ll_sw/ll_settings.c +++ b/subsys/bluetooth/controller/ll_sw/ll_settings.c @@ -4,12 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include -#include - #include "ll_settings.h" #include diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 8c1b117203b5..f8f3c8fa1f4a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -10,7 +10,6 @@ #include #include -#include #include "hal/cpu.h" #include "hal/ccm.h" 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 ab8c5dc90b3a..8401e94fcbf8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -5,10 +5,8 @@ */ #include - -#include - -#include +#include +#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c index 86301199ec80..df51202fdbcc 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_adv.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include +#include -#include -#include #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index 0f4695d0bc01..2f0acebd7030 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -5,8 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#include +#include +#include +#include + #include #include diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index 4fd61e815148..ceeb9ca12e70 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -251,6 +251,9 @@ #define PDU_ADV_DATA_HEADER_TYPE_OFFSET 1U #define PDU_ADV_DATA_HEADER_DATA_OFFSET 2U +/* Advertising Data Types in ACAD */ +#define PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND 0x28 + /* * Macros to return correct Data Channel PDU time * Note: formula is valid for 1M, 2M and Coded S8 diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index 70f4c19a079b..b5f88f25cc20 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "hal/cpu.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 0079e2aa7b78..ea848e1552ce 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -1308,7 +1308,7 @@ void ull_adv_sync_chm_complete(struct node_rx_hdr *rx) ad_len = ad[PDU_ADV_DATA_HEADER_LEN_OFFSET]; if (ad_len && (ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == - BT_DATA_CHANNEL_MAP_UPDATE_IND)) { + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND)) { break; } @@ -2132,7 +2132,8 @@ static uint8_t sync_chm_update(uint8_t handle) sizeof(acad)); acad += acad_len_prev; acad[PDU_ADV_DATA_HEADER_LEN_OFFSET] = sizeof(*chm_upd_ind) + 1U; - acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = BT_DATA_CHANNEL_MAP_UPDATE_IND; + acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND; /* Populate the Channel Map Indication structure */ chm_upd_ind = (void *)&acad[PDU_ADV_DATA_HEADER_DATA_OFFSET]; diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index 866ff8eb9bb0..df1cf4b4e5db 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -5,8 +5,9 @@ */ #include -#include #include + +#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 365c743c9bf6..03a0f7a0577b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index 45da0451bc95..d405b392b2cb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -6,7 +6,6 @@ #include #include -#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_internal.h b/subsys/bluetooth/controller/ll_sw/ull_internal.h index f4ad4c40d2aa..a0f6b7a6a0da 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_internal.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - /** * User CPR Interval */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index d83558f6a8ef..688bbb1b437a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -4,10 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include +#include #include #include +#include #include "hal/cpu.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index 01239b5d2e94..7ab387f624bf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c index 6cf4899888b4..904dc40a4dc3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_cc.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ecb.h" #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c index 79835ff8cf64..d1de4e87edba 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_chmu.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index be96a1ae0a60..896147879cbf 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c index 62c06a3d2387..e922901f67d0 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_conn_upd.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c index 54ebbdba5fe8..00cadfa2df81 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_enc.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index 3f8c91983c56..793e33934bce 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 7162959a85a4..d34caca87648 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index cc8333204987..31fc053f8494 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index 5a204db52acf..cb4f09956881 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -4,13 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include #include #include #include +#include + #include "hal/ccm.h" #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c index f47439514ac0..75116c9c7704 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c @@ -5,9 +5,11 @@ */ #include -#include #include +#include +#include + #include "util/util.h" #include "util/memq.h" #include "util/mayfly.h" @@ -46,8 +48,6 @@ #include "ull_conn_iso_internal.h" #include "ull_llcp_internal.h" -#include - #include "hal/debug.h" #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index 9a2d25921a6f..d9e043ccc05d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -5,6 +5,8 @@ */ #include +#include + #include #include "hal/ccm.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync.c b/subsys/bluetooth/controller/ll_sw/ull_sync.c index f3386cdd9f12..6c6748858109 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync.c @@ -1149,7 +1149,7 @@ void ull_sync_chm_update(uint8_t sync_handle, uint8_t *acad, uint8_t acad_len) ad_len = acad[PDU_ADV_DATA_HEADER_LEN_OFFSET]; if (ad_len && (acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == - BT_DATA_CHANNEL_MAP_UPDATE_IND)) { + PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND)) { break; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c index 460f04494c36..fbacb56f8b48 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sync_iso.c @@ -6,7 +6,6 @@ #include #include -#include #include #include "util/util.h" diff --git a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c index f253460c1104..6d188b8d5203 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c +++ b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include "ull_tx_queue.h" void ull_tx_q_init(struct ull_tx_q *queue) diff --git a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h index 33ae8783cd9f..bdeac3202b38 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h +++ b/subsys/bluetooth/controller/ll_sw/ull_tx_queue.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - struct ull_tx_q { uint8_t pause_data; /* Data pause state of the tx queue */ From 2f3a164fbe3e88e136e7fdc2e243b4198bab09c7 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 9 Jun 2023 10:42:09 -0700 Subject: [PATCH 0088/2042] doc: release-notes/3.4: add bits for UART This adds bits for various additions and fixes on UART drivers. Signed-off-by: Daniel Leung --- doc/releases/release-notes-3.4.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index b7b54896061d..f66a1e2ef22c 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -642,6 +642,22 @@ Drivers and Sensors * Serial * Add UART3 and UART4 configuration for ``gd32vf103`` SoCs. + * uart_altera: added new driver for Altera Avalon UART. + * uart_emul: added new driver for emulated UART. + * uart_esp32: + * Added support for ESP32S3 SoC. + * Added support for RS-485 half duplex mode. + * uart_hostlink: added new driver for virtual UART via Synopsys ARC hostlink channels. + * uart_ifx_cat1: added new driver for Infineon CAT1 UART. + * uart_mcux: added power management support. + * uart_mcux_flexcomm: added support for asynchronous operations. + * uart_mcux_lpuart: added support for parity. + * uart_ns16550: now supports per instance hardware access mode instead of + one access mode for all instances. + * uart_pl011: fixed interrupt support. + * uart_rpi_pico_pio: added new driver to support UART via + Programmable Input/Output (PIO) on Raspberry Pi Pico. + * uart_xmc4xxx: added support for asynchronous operations. * SPI From 50c70f553ee68b524a6e0cb2f892f91fcd887959 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 9 Jun 2023 11:16:07 -0700 Subject: [PATCH 0089/2042] doc: release-notes/3.4: small bit about PCIe Added a small bit about PCIe where it can now filter using class/revision register. Signed-off-by: Daniel Leung --- doc/releases/release-notes-3.4.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index f66a1e2ef22c..55bf1cdadc61 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -606,6 +606,8 @@ Drivers and Sensors * PCIE + * Enable filtering PCIe devices by class/revision. + * PECI * Retained memory From 7839d36d0b0ab832bd0ea34701c63af6979ab37b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 9 Jun 2023 11:37:00 -0700 Subject: [PATCH 0090/2042] doc: release-notes/3.4: bits on Xtensa This adds a few bits on additions and changes on Xtensa. Signed-off-by: Daniel Leung --- doc/releases/release-notes-3.4.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 55bf1cdadc61..4c30015d2447 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -302,6 +302,13 @@ Architectures * Xtensa + * Fixed the cross stack call mechanism during nested interrupts where stack would be + corrupted under certain conditions. + * Added initial support for MMU on Xtensa. + * Now supports building with :kconfig:option:`CONFIG_MULTITHREADING` disabled so + target can run in single thread only operations. + * Added C structs to represent interrupt frames to help with debugging. + Bluetooth ********* From dc900663909d941f074d621b497920403a60f240 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 13:17:40 +0200 Subject: [PATCH 0091/2042] doc: release: 3.4: Add POSIX arch and POSIX boards changes Add points related to the POSIX arch and boards to the 3.4 release notes. Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.4.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 4c30015d2447..807371ce5a7e 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -284,6 +284,11 @@ Architectures * NIOS2 * Removed absolute symbol :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` +* POSIX: + + * Added :c:macro:`Z_SPIN_DELAY` to allow to conditionally compile a k_busy_wait() for this arch + in tests and samples. + * RISC-V * Added :kconfig:option:`CONFIG_PMP_NO_TOR`, :kconfig:option:`CONFIG_PMP_NO_NA4`, and @@ -372,6 +377,17 @@ Boards & SoC Support * FVP revc_2xaemv8a / aemv8r: Added ethernet, PHY and MDIO nodes +* Made these changes to POSIX boards: + + * nrf52_bsim now includes support and models for: + + * 802.15.4 in the RADIO. + * EGU. + * FLASH (NVMC & UICR). + * TEMP. + * UART connected to a host ptty. + * Many more minor CMSIS API and nRF APIs and drivers. + * Made these changes for RISC-V boards: * ``gd32vf103``: No longer requires special OpenOCD version. @@ -531,6 +547,11 @@ Drivers and Sensors * Atmel SAM/SAM0: Introduce peripheral clock control. * Atmel SAM0: Improved ``samd20``/``samd21``/``samr21`` clocking mechanism. +* Console: + + * The native_posix and bsim console drivers have been merged into one generic + driver usable by all POSIX arch based boards. + * Counter * Crypto @@ -869,6 +890,8 @@ Documentation Tests and Samples ***************** +* For native_posix and the nrf52_bsim: Many tests have been fixed and enabled. + Issue Related Items ******************* From 6bf47f52fa4788a16f54007272779b0f00ee3f06 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 13:18:54 +0200 Subject: [PATCH 0092/2042] doc: release: 3.4: Add more flash simulator changes Add some extra relevant changes to the flash simulator Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.4.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 807371ce5a7e..cfaf835831c3 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -589,9 +589,15 @@ Drivers and Sensors with ``nrf_qspi_nor_xip_enable`` which apart from forcing the clock divider prevents the driver from deactivating the QSPI peripheral so that the XIP operation is actually possible. - * flash_simulator: A memory region can now be used as the storage area for the - flash simulator. Using the memory region allows the flash simulator to keep - its contents over a device reboot. + * flash_simulator: + + * A memory region can now be used as the storage area for the + flash simulator. Using the memory region allows the flash simulator to keep + its contents over a device reboot. + * When building in native_posix, command line options have been added to select + if the flash should be cleared at boot, the flash content kept in RAM, + or the flash content file be deleted on exit. + * spi_flash_at45: Fixed erase procedure to properly handle chips that have their initial sector split into two parts (usually marked as 0a and 0b). From 15ad2be01a38d594815f07c69f381a24a38fdd98 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 13:19:32 +0200 Subject: [PATCH 0093/2042] doc: release: 3.4: Add BabbleSim related points Add relevant bsim related changes. Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.4.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index cfaf835831c3..e9d09f59530f 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -505,6 +505,9 @@ Build system and infrastructure if signing is performed manually or outside of zephyr. This warning informs the user that the generated image will not be bootable by MCUboot as-is. +* Babblesim is now included in the west manifest. Users can fetch it by enabling + the ``babblesim`` group with west config. + Drivers and Sensors ******************* @@ -896,6 +899,9 @@ Documentation Tests and Samples ***************** +* Two Babblesim based networking (802.15.4) tests have been added, which are run in Zephyr's CI + system. One of them including the OpenThread stack. + * For native_posix and the nrf52_bsim: Many tests have been fixed and enabled. Issue Related Items From bc090178ab41a2a730ca52ae6e59b0dc77b41a61 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 13:23:08 +0200 Subject: [PATCH 0094/2042] doc: release: 3.4: Fix indent in ARCH's lists So they render properly. Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.4.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index e9d09f59530f..4f5ccf5d1dab 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -265,15 +265,18 @@ Architectures ************* * ARC + * Removed absolute symbols :c:macro:`___callee_saved_t_SIZEOF` and - :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` + :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` * ARM + * Removed absolute symbols :c:macro:`___basic_sf_t_SIZEOF`, - :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF`, :c:macro:`___cpu_context_t_SIZEOF` - and :c:macro:`___thread_stack_info_t_SIZEOF` + :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF`, :c:macro:`___cpu_context_t_SIZEOF` + and :c:macro:`___thread_stack_info_t_SIZEOF` * ARM64 + * Removed absolute symbol :c:macro:`___callee_saved_t_SIZEOF` * Enabled FPU and FPU_SHARING for v8r aarch64 * Fixed the STACK_INIT logic during the reset @@ -282,6 +285,7 @@ Architectures * Added ISBs after SCTLR Modifications * NIOS2 + * Removed absolute symbol :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` * POSIX: @@ -301,6 +305,7 @@ Architectures * Enabled single-threading support. * SPARC + * Removed absolute symbol :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` * X86 From b7717058ac55ec1bb724956fed44b7c63f715321 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 12 Jun 2023 10:46:06 +0200 Subject: [PATCH 0095/2042] doc: release-notes: add CAN release notes for v3.4.0 Add CAN related release notes for Zephyr v3.4.0. Signed-off-by: Henrik Brix Andersen --- doc/releases/release-notes-3.4.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 4f5ccf5d1dab..57d296ee3bc9 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -254,6 +254,8 @@ New APIs in this release * Introduced :ref:`barriers_api` for barrier operations. +* Added :c:macro:`CAN_FRAME_ESI` CAN-FD Error State Indicator flag. + Kernel ****** @@ -550,6 +552,23 @@ Drivers and Sensors * CAN + * The CAN statistics are now reset when calling :c:func:`can_start`. + + * Renamed the NXP FlexCAN devicetree binding compatible from ``nxp,kinetis-flexcan`` to + :dtcompatible:`nxp,flexcan`. + + * Added support for the CAN-FD variant of the NXP FlexCAN controller using devicetree binding + :dtcompatible:`nxp,flexcan-fd`. + + * Added support for the NXP NXP S32 CANEXCEL controller using devicetree binding + :dtcompatible:`nxp,s32-canxl`. + + * Added support for the Atmel SAM0 CAN controller using devicetree binding + :dtcompatible:`atmel,sam0-can`. + + * Refactored the Bosch M_CAN controller driver backend to allow for per-instance configuration via + devicetree. + * Clock control * Atmel SAM/SAM0: Introduce peripheral clock control. From 87aa25e4ada12c3b65e455cc6e2fbd693be9c17c Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Sun, 11 Jun 2023 13:23:54 +0200 Subject: [PATCH 0096/2042] sysbuild: Fix exporting BOARD.+ through sysbuild cache Lately, sysbuild started filtering out variable names matching ^BOARD during sysbuild cache file generation. As a result, one of the cache variables that is no longer exported to other domains is BOARD_ROOT, which breaks the recent support for out-of-tree boards in sysbuild. Of those variables, the only one which is reasonable to filter out is BOARD itself, because the purpose of that is to substitute a different value for the one found in sysbuild's own CMake cache, which has the board revision stripped out. Update the relevant if-condition and use a single regex for brevity. Fixes #59114. Signed-off-by: Grzegorz Swiderski --- share/sysbuild/cmake/modules/sysbuild_extensions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 5960c63c31e9..53cf1eb2e659 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -317,7 +317,7 @@ function(ExternalZephyrProject_Cmake) get_cmake_property(sysbuild_cache CACHE_VARIABLES) foreach(var_name ${sysbuild_cache}) - if(NOT ("${var_name}" MATCHES "^CMAKE_.*" OR "${var_name}" MATCHES "^BOARD")) + if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") # Perform a dummy read to prevent a false warning about unused variables # being emitted due to a cmake bug: https://gitlab.kitware.com/cmake/cmake/-/issues/24555 set(unused_tmp_var ${${var_name}}) From fc210a8cee8aa6a91ff19310e9bb9a370203c3c0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 9 Jun 2023 07:24:37 +0530 Subject: [PATCH 0097/2042] Bluetooth: Controller: Fix disable all advertising sets BlueZ stack in Linux distributions use disable all advertising sets when advertising is turned off. Add missing implementation to support disabling all active advertising sets. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 5 +++-- subsys/bluetooth/controller/include/ll.h | 2 ++ subsys/bluetooth/controller/ll_sw/ull_adv.c | 9 ++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index a5bbcb5d364b..2b3abb22b7af 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -3514,8 +3514,9 @@ static void le_set_ext_adv_enable(struct net_buf *buf, struct net_buf **evt) return; } - /* FIXME: Implement disable of all advertising sets */ - *evt = cmd_complete_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); + status = ll_adv_disable_all(); + + *evt = cmd_complete_status(status); return; } diff --git a/subsys/bluetooth/controller/include/ll.h b/subsys/bluetooth/controller/include/ll.h index 989dc1a2d67c..464fcc94cf9f 100644 --- a/subsys/bluetooth/controller/include/ll.h +++ b/subsys/bluetooth/controller/include/ll.h @@ -106,6 +106,8 @@ uint8_t ll_adv_enable(uint8_t handle, uint8_t enable, uint8_t ll_adv_enable(uint8_t enable); #endif /* !CONFIG_BT_CTLR_ADV_EXT || !CONFIG_BT_HCI_MESH_EXT */ +uint8_t ll_adv_disable_all(void); + uint8_t ll_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, uint32_t sdu_interval, uint16_t max_sdu, uint16_t max_latency, uint8_t rtn, uint8_t phy, diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 5d77b4eabe29..47c571151a4b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1620,7 +1620,7 @@ int ull_adv_init(void) return 0; } -int ull_adv_reset(void) +uint8_t ll_adv_disable_all(void) { uint8_t handle; @@ -1628,6 +1628,13 @@ int ull_adv_reset(void) (void)disable(handle); } + return 0U; +} + +int ull_adv_reset(void) +{ + (void)ll_adv_disable_all(); + #if defined(CONFIG_BT_CTLR_ADV_EXT) #if defined(CONFIG_BT_HCI_RAW) ll_adv_cmds = LL_ADV_CMDS_ANY; From c05d629841eb2816071dab348a15b6baa4ee15e5 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 12 Jun 2023 12:29:03 +0200 Subject: [PATCH 0098/2042] drivers: can: mcan: remove excessive debug on register access Remove excessive debug output on Bosch M_CAN register access. This was accidentially included in commit bbfc1f905c2d19c70b6138d8e5851870d01812e1. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_mcan.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 61240f2d3fd6..3c7bdc233b47 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -25,8 +25,6 @@ int can_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) err = config->ops->read_reg(dev, reg, val); if (err != 0) { LOG_ERR("failed to read reg 0x%03x (err %d)", reg, err); - } else { - LOG_DBG("read reg 0x%03x = 0x%08x", reg, *val); } return err; @@ -40,8 +38,6 @@ int can_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t val) err = config->ops->write_reg(dev, reg, val); if (err != 0) { LOG_ERR("failed to write reg 0x%03x (err %d)", reg, err); - } else { - LOG_DBG("write reg 0x%03x = 0x%08x", reg, val); } return err; From 1b7ef97c31f4b734cae9cfb2b251c1b86b40d109 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 9 Jun 2023 21:08:43 +0530 Subject: [PATCH 0099/2042] net: l2: ethernet: Fix IPv6 Kconfig Function net_if_ipv6_addr_rm is only defined for NATIVE_IPV6. Signed-off-by: Chaitanya Tata --- subsys/net/l2/ethernet/ethernet_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ethernet/ethernet_mgmt.c b/subsys/net/l2/ethernet/ethernet_mgmt.c index 26eea7369f52..e7fcae8ac99a 100644 --- a/subsys/net/l2/ethernet/ethernet_mgmt.c +++ b/subsys/net/l2/ethernet/ethernet_mgmt.c @@ -98,7 +98,7 @@ static int ethernet_set_config(uint32_t mgmt_request, * generated from old MAC address, from network interface if * needed. */ - if (IS_ENABLED(CONFIG_NET_IPV6)) { + if (IS_ENABLED(CONFIG_NET_NATIVE_IPV6)) { struct in6_addr iid; net_ipv6_addr_create_iid(&iid, From ad33d03dce75a5a6958b301526f7073d7d8065c7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 12 Jun 2023 16:21:30 +0200 Subject: [PATCH 0100/2042] Revert "net: context: Fix ambigous pointer check in net_context_connect()" This reverts commit 22b889e3b49def0a6423203581596076d2ef9c38. Signed-off-by: Robert Lubos --- subsys/net/ip/net_context.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 91a98a9a44ae..d3b44d33ea48 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1032,16 +1032,17 @@ int net_context_connect(struct net_context *context, goto unlock; } - NET_ASSERT(net_sin6_ptr(&context->local)->sin6_addr != NULL); - net_sin6_ptr(&context->local)->sin6_family = AF_INET6; net_sin6(&local_addr)->sin6_family = AF_INET6; net_sin6(&local_addr)->sin6_port = lport = net_sin6((struct sockaddr *)&context->local)->sin6_port; - net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr, - net_sin6_ptr(&context->local)->sin6_addr); - laddr = &local_addr; + if (net_sin6_ptr(&context->local)->sin6_addr) { + net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr, + net_sin6_ptr(&context->local)->sin6_addr); + + laddr = &local_addr; + } } else if (IS_ENABLED(CONFIG_NET_IPV4) && net_context_get_family(context) == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in *) @@ -1073,16 +1074,17 @@ int net_context_connect(struct net_context *context, goto unlock; } - NET_ASSERT(net_sin_ptr(&context->local)->sin_addr != NULL); - net_sin_ptr(&context->local)->sin_family = AF_INET; net_sin(&local_addr)->sin_family = AF_INET; net_sin(&local_addr)->sin_port = lport = net_sin((struct sockaddr *)&context->local)->sin_port; - net_ipaddr_copy(&net_sin(&local_addr)->sin_addr, - net_sin_ptr(&context->local)->sin_addr); - laddr = &local_addr; + if (net_sin_ptr(&context->local)->sin_addr) { + net_ipaddr_copy(&net_sin(&local_addr)->sin_addr, + net_sin_ptr(&context->local)->sin_addr); + + laddr = &local_addr; + } } else { ret = -EINVAL; /* Not IPv4 or IPv6 */ goto unlock; From 8287e56fa3479aad63590ffebc14a568cc2d085d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 12 Jun 2023 16:26:13 +0200 Subject: [PATCH 0101/2042] net: context: Verify that laddr was set before use in connect In previous patch fixing this issue, I've missed the fact that offloaded drivers would not set the context->local address, which resulted in a regression, where the previously introduced assert would hit in offloaded cases. Not setting laddr is not a problem in case of offloading, as it's only used in net_tcp_connect() which would not be reached in this case. Therefore I propose to remove previous patch to get rid of regression. As an alternative fix, verify the laddr just before use, so that it is only checked when native net stack is in use. Signed-off-by: Robert Lubos --- subsys/net/ip/net_context.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index d3b44d33ea48..571e08c2aebf 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1112,6 +1112,8 @@ int net_context_connect(struct net_context *context, ret = 0; } else if (IS_ENABLED(CONFIG_NET_TCP) && net_context_get_type(context) == SOCK_STREAM) { + NET_ASSERT(laddr != NULL); + ret = net_tcp_connect(context, addr, laddr, rport, lport, timeout, cb, user_data); } else { From bdaa870e59f1da7b09ba3e14e042b776544d9d42 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 7 Jun 2023 16:37:08 -0500 Subject: [PATCH 0102/2042] drivers: uart_mcux_flexcomm: Unlock IRQ if error Currently the flexcomm uart driver will not unlock IRQ if there is an error, which might cause some problems, fix this. Signed-off-by: Declan Snyder --- drivers/serial/uart_mcux_flexcomm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/serial/uart_mcux_flexcomm.c b/drivers/serial/uart_mcux_flexcomm.c index 5cf5800da9ef..38f97f8b39eb 100644 --- a/drivers/serial/uart_mcux_flexcomm.c +++ b/drivers/serial/uart_mcux_flexcomm.c @@ -422,11 +422,13 @@ static int mcux_flexcomm_uart_tx(const struct device *dev, const uint8_t *buf, ret = dma_get_status(config->tx_dma.dev, config->tx_dma.channel, &status); if (ret < 0) { + irq_unlock(key); return ret; } /* There is an ongoing transfer */ if (status.busy) { + irq_unlock(key); return -EBUSY; } @@ -444,6 +446,7 @@ static int mcux_flexcomm_uart_tx(const struct device *dev, const uint8_t *buf, ret = dma_config(config->tx_dma.dev, config->tx_dma.channel, (struct dma_config *) &config->tx_dma.cfg); if (ret) { + irq_unlock(key); return ret; } @@ -456,6 +459,7 @@ static int mcux_flexcomm_uart_tx(const struct device *dev, const uint8_t *buf, /* Trigger the DMA to start transfer */ ret = dma_start(config->tx_dma.dev, config->tx_dma.channel); if (ret) { + irq_unlock(key); return ret; } From a874fddadd917b16bfc0c907c55d9c87c1106797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 7 Jun 2023 13:06:41 +0200 Subject: [PATCH 0103/2042] tests: timer_behavior: Use bigger drift tolerance for nRF RTC timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 13% instead of the default 10% when the nRF RTC timer is used so that the allowed drift is at least one tick long (~122 us in this case). Signed-off-by: Andrzej Głąbek --- tests/kernel/timer/timer_behavior/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/kernel/timer/timer_behavior/Kconfig b/tests/kernel/timer/timer_behavior/Kconfig index d21510e11373..b881fdeb7411 100644 --- a/tests/kernel/timer/timer_behavior/Kconfig +++ b/tests/kernel/timer/timer_behavior/Kconfig @@ -31,6 +31,13 @@ config TIMER_TEST_MAX_DRIFT config TIMER_TEST_PERIOD_MAX_DRIFT_PERCENT int "Maximum drift percentage for the timer period" + # Use 13% on nRF platforms using the RTC timer because one tick there is + # ~122 us (see SYS_CLOCK_TICKS_PER_SEC configuration above) and one tick + # difference in the test period is nothing unusual (it can happen for + # example if a new tick elapses right after the kernel gets the number + # of elapsed ticks when scheduling a new timeout but before the timer + # driver sets up that timeout). + default 13 if NRF_RTC_TIMER && TICKLESS_KERNEL default 10 help A value of 10 means 10%. From 4d511cfb6a0c2c6875edc813dcb79ae56fd9a25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 7 Jun 2023 13:39:51 +0200 Subject: [PATCH 0104/2042] tests: timer_api: Decrease tick rate for nRF RTC timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default tick rate for the nRF RTC timer is 32768 Hz, so one tick is ~30 us. This turns out to be too little for the following loop executed in user mode on the Network core in nRF5340: ``` do { t0 = k_uptime_ticks(); rem_ticks = k_timer_remaining_ticks(&remain_timer); t1 = k_uptime_ticks(); } while (t0 != t1); ``` The time between the two calls to `k_uptime_tick()` is there always above 30 us, so the loop never ends. This patch decreases the tick rate for all nRF platforms because on other nRf SoCs the time mentioned above is also close to 30 us and apparently changes in code completely unrelated to this test affect execution time of system calls in the above loop - the test started to fail after commit 0014dd05f017c167827bf0e10846b641727b7a18 that changes fdtable was merged and if `fdtable.c` is for example just temporarily excluded from the build, the test passes. The root cause of the problem seems to be related to user space handling and this should to be investigated further. This patch is applied only to allow this test to pass for the time being. Signed-off-by: Andrzej Głąbek --- tests/kernel/timer/timer_api/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/kernel/timer/timer_api/Kconfig diff --git a/tests/kernel/timer/timer_api/Kconfig b/tests/kernel/timer/timer_api/Kconfig new file mode 100644 index 000000000000..9a0bfb8c74d8 --- /dev/null +++ b/tests/kernel/timer/timer_api/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Nordic Semiconductor ASA + +config SYS_CLOCK_TICKS_PER_SEC + default 16384 if NRF_RTC_TIMER && TICKLESS_KERNEL + +source "Kconfig.zephyr" From bfa0a87277c31d9e1b36104a29b17f3fc1a47444 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 12 Jun 2023 09:40:53 -0400 Subject: [PATCH 0105/2042] tests: posix: pthread_pressure: enable pthread barrier in twister In some cases, when GitHub CI is running several Qemu processes, each with heavy loads, SMP tests have shown some flakiness. This exhibits itself as something like ``` ... pthread_pressure on qemu_riscv32 failed (Timeout) ``` That is actually not at all limited to POSIX or any particular architecture, but is mainly to do with the host scheduler and perhaps memory barrier operations being lost in ISA translation by Qemu. Collectively, we can refer to these issues as "scheduler noise". To reduce scheduler noise in the `pthread_pressure` testsuite, enable `CONFIG_PTHREAD_CREATE_BARRIER` in `testcase.yaml`. Note: end-users will likely not experience the need to enable this in `prj.conf`. E.g. the following basic test demonstrates 0 failures locallly. ``` TEST=tests/posix/pthread_pressure twister --build-only -T $TEST &>/dev/null FAIL=0 for ((i=0; i < 100; i++)); do echo "Run $((i+1))/100" twister --test-only -T $TEST &>/dev/null if [ $? -ne 0 ]; then FAIL=$((FAIL+1)) echo "Failed $FAIL times" fi done echo "Failure Rate: $((FAIL))/100" ``` Signed-off-by: Christopher Friedt --- tests/posix/pthread_pressure/testcase.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/posix/pthread_pressure/testcase.yaml b/tests/posix/pthread_pressure/testcase.yaml index ff0c2c32a2fb..273757f73ab4 100644 --- a/tests/posix/pthread_pressure/testcase.yaml +++ b/tests/posix/pthread_pressure/testcase.yaml @@ -8,4 +8,8 @@ common: platform_exclude: - qemu_leon3 tests: - portability.posix.pthread_pressure: {} + portability.posix.pthread_pressure: + extra_configs: + # Enabled for GitHub CI to reduce host scheduling noise while running + # several concurrent Qemu processes each under stressful SMP load. + - CONFIG_PTHREAD_CREATE_BARRIER=y From 5e9de122c5f9337dd6f1522d2dd4e229279312bd Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 12 Jun 2023 12:21:27 +0200 Subject: [PATCH 0106/2042] drivers: gpio: pca95xx: check gpio_add_callback() return value Check the return value from gpio_add_callback() and fail driver initialization if non-zero. Fixes: #58584 Signed-off-by: Henrik Brix Andersen --- drivers/gpio/gpio_pca95xx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_pca95xx.c b/drivers/gpio/gpio_pca95xx.c index 7570abc727d7..e8ae5ca26a2d 100644 --- a/drivers/gpio/gpio_pca95xx.c +++ b/drivers/gpio/gpio_pca95xx.c @@ -830,7 +830,13 @@ static int gpio_pca95xx_init(const struct device *dev) gpio_init_callback(&drv_data->gpio_callback, gpio_pca95xx_interrupt_callback, BIT(config->int_gpio.pin)); - gpio_add_callback(config->int_gpio.port, &drv_data->gpio_callback); + ret = gpio_add_callback(config->int_gpio.port, &drv_data->gpio_callback); + if (ret != 0) { + LOG_ERR("PCA95XX[0x%X]: failed to add interrupt callback for" + " pin %d (%d)", config->bus.addr, + config->int_gpio.pin, ret); + return ret; + } } #endif From aefecf1a407d98c181500f6c5782b99712f6d6f1 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 9 Jun 2023 14:16:43 +0000 Subject: [PATCH 0107/2042] drivers: pwm: pwm_mcux: improve resolution by writing match register Write PWM match registers directly instead of using the frequency and duty cycle fields of the MCUX HAL driver. This allows the driver to take full advantage of the resolution supported by the FlexPWM when setting duty cycle and carrier frequency. Fixes #59080 Signed-off-by: Daniel DeGrasse --- drivers/pwm/pwm_mcux.c | 74 +++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/drivers/pwm/pwm_mcux.c b/drivers/pwm/pwm_mcux.c index 7405800b2447..a0368fd7c93c 100644 --- a/drivers/pwm/pwm_mcux.c +++ b/drivers/pwm/pwm_mcux.c @@ -43,7 +43,6 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, { const struct pwm_mcux_config *config = dev->config; struct pwm_mcux_data *data = dev->data; - uint8_t duty_cycle; pwm_level_select_t level; if (channel >= CHANNEL_COUNT) { @@ -64,58 +63,95 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, return -EINVAL; } - duty_cycle = 100 * pulse_cycles / period_cycles; - if (flags & PWM_POLARITY_INVERTED) { level = kPWM_LowTrue; } else { level = kPWM_HighTrue; } - /* FIXME: Force re-setup even for duty-cycle update */ if (period_cycles != data->period_cycles[channel] || level != data->channel[channel].level) { uint32_t clock_freq; - uint32_t pwm_freq; status_t status; data->period_cycles[channel] = period_cycles; - LOG_DBG("SETUP dutycycle to %u", duty_cycle); - if (clock_control_get_rate(config->clock_dev, config->clock_subsys, &clock_freq)) { return -EINVAL; } - pwm_freq = DIV_ROUND_UP(clock_freq >> config->prescale, period_cycles); - - if (pwm_freq == 0) { - LOG_ERR("Could not set up pwm_freq=%d", pwm_freq); - return -EINVAL; - } data->channel[channel].pwmchannelenable = true; PWM_StopTimer(config->base, 1U << config->index); - data->channel[channel].dutyCyclePercent = duty_cycle; + /* + * We will directly write the duty cycle pulse width + * and full pulse width into the VALx registers to + * setup PWM with higher resolution. + * Therefore we use dummy values for the duty cycle + * and frequency. + */ + data->channel[channel].dutyCyclePercent = 0; data->channel[channel].level = level; status = PWM_SetupPwm(config->base, config->index, - &data->channel[0], CHANNEL_COUNT, - config->mode, pwm_freq, clock_freq); + &data->channel[channel], CHANNEL_COUNT, + config->mode, 1, clock_freq); if (status != kStatus_Success) { LOG_ERR("Could not set up pwm"); return -ENOTSUP; } + /* Setup VALx values directly for edge aligned PWM */ + if (channel == 0) { + /* Side A */ + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_0, + (uint16_t)(period_cycles / 2U)); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_1, + (uint16_t)(period_cycles - 1U)); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_2, 0U); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_3, + (uint16_t)pulse_cycles); + } else { + /* Side B */ + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_0, + (uint16_t)(period_cycles / 2U)); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_1, + (uint16_t)(period_cycles - 1U)); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_4, 0U); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_5, + (uint16_t)pulse_cycles); + } + PWM_SetPwmLdok(config->base, 1U << config->index, true); PWM_StartTimer(config->base, 1U << config->index); } else { - PWM_UpdatePwmDutycycle(config->base, config->index, - (channel == 0) ? kPWM_PwmA : kPWM_PwmB, - config->mode, duty_cycle); + /* Setup VALx values directly for edge aligned PWM */ + if (channel == 0) { + /* Side A */ + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_2, 0U); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_3, + (uint16_t)pulse_cycles); + } else { + /* Side B */ + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_4, 0U); + PWM_SetVALxValue(config->base, config->index, + kPWM_ValueRegister_5, + (uint16_t)pulse_cycles); + } PWM_SetPwmLdok(config->base, 1U << config->index, true); } From 7c339e91a14159aef50324a9b7796d046a1c2802 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sun, 11 Jun 2023 16:08:10 +0200 Subject: [PATCH 0108/2042] drivers/clock_control: SAM PMC missing soc.h The source clock_control_sam_pmc.c can not build without the symbol SOC_ATMEL_SAM_MCK_FREQ_HZ which is contained in soc.h This bug only shows itself if CONFIG_ARM_MPU is not enabled, which probably includes soc.h through the which is not desired behavior. This commit adds the missing header, making the source build regardless of CONFIG_ARM_MPU. Signed-off-by: Bjarki Arge Andreasen --- drivers/clock_control/clock_control_sam_pmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clock_control/clock_control_sam_pmc.c b/drivers/clock_control/clock_control_sam_pmc.c index 3da52851bfe8..801f5c37e873 100644 --- a/drivers/clock_control/clock_control_sam_pmc.c +++ b/drivers/clock_control/clock_control_sam_pmc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(clock_control, CONFIG_CLOCK_CONTROL_LOG_LEVEL); From 378f0dd29d31ff13379a75dc60a30ebe2ac0e92e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 12 Jun 2023 07:52:55 +0200 Subject: [PATCH 0109/2042] net: lib: zperf: fix kernel panic due to invalid thread prio Compiling an application with CONFIG_NET_ZPERF=y leaving CONFIG_ZPERF_WORK_Q_THREAD_PRIORITY at its default value would systematically cause a kernel panic during thread initialization. The Kconfig variable is NUM_PREEMPT_PRIORITIES by default. Application threads may not define a priority lower than NUM_PREEMPT_PRIORITIES - 1, though. This change limits zperf's thread priority to a valid range. It does not change the default value as it makes sense to default the thread priority to the lowest possible value (which is NUM_PREEMPT_PRIORITIES) but Kconfig does not allow for arithmentic. So the combination of CLAMP() plus the Kconfig default will ensure min priority plus limit the range to valid values no matter what has been defined as priority in Kconfig. Fixes: #59141 Signed-off-by: Florian Grandel --- subsys/net/lib/zperf/zperf_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_common.c b/subsys/net/lib/zperf/zperf_common.c index e1efcafe3b2c..bb708f68a087 100644 --- a/subsys/net/lib/zperf/zperf_common.c +++ b/subsys/net/lib/zperf/zperf_common.c @@ -40,6 +40,9 @@ struct sockaddr_in *zperf_get_sin(void) return &in4_addr_my; } +#define ZPERF_WORK_Q_THREAD_PRIORITY \ + CLAMP(CONFIG_ZPERF_WORK_Q_THREAD_PRIORITY, K_HIGHEST_APPLICATION_THREAD_PRIO, \ + K_LOWEST_APPLICATION_THREAD_PRIO) K_THREAD_STACK_DEFINE(zperf_work_q_stack, CONFIG_ZPERF_WORK_Q_STACK_SIZE); static struct k_work_q zperf_work_q; @@ -215,8 +218,8 @@ static int zperf_init(void) k_work_queue_init(&zperf_work_q); k_work_queue_start(&zperf_work_q, zperf_work_q_stack, - K_THREAD_STACK_SIZEOF(zperf_work_q_stack), - CONFIG_ZPERF_WORK_Q_THREAD_PRIORITY, NULL); + K_THREAD_STACK_SIZEOF(zperf_work_q_stack), ZPERF_WORK_Q_THREAD_PRIORITY, + NULL); k_thread_name_set(&zperf_work_q.thread, "zperf_work_q"); zperf_udp_uploader_init(); From 8d8faae3e7706caaf3e3cd39674f527744ed4d9e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 5 Jun 2023 17:55:19 +0200 Subject: [PATCH 0110/2042] net: l2: ieee802154: shell: fix printing ext addr A bug was introduced in one of my earlier commits: The shell does no longer print the full extended address. Fixes the issue. Fixes: #59125 Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_shell.c b/subsys/net/l2/ieee802154/ieee802154_shell.c index 792969cd2dee..9abba9193c2c 100644 --- a/subsys/net/l2/ieee802154/ieee802154_shell.c +++ b/subsys/net/l2/ieee802154/ieee802154_shell.c @@ -472,7 +472,7 @@ static int cmd_ieee802154_get_ext_addr(const struct shell *sh, for (i = 0; i < IEEE802154_EXT_ADDR_LENGTH; i++) { pos += snprintk(ext_addr + pos, - IEEE802154_EXT_ADDR_LENGTH - pos, + EXT_ADDR_STR_LEN - pos, "%02X:", addr[i]); } From d451895907e528ae2e772e653c9f35850450c33a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:20:23 +0200 Subject: [PATCH 0111/2042] net: l2: ieee802154: fix buffer pointer ref The uncast reference caused a cbprintf() warning on the console. Fixes: #59125 Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 08f898785847..9f8f0ef749da 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -101,7 +101,7 @@ static inline bool validate_addr(uint8_t *buf, uint8_t **p_buf, uint8_t *length, *p_buf = buf; - NET_DBG("Buf %p - mode %d - pan id comp %d", buf, mode, pan_id_compression); + NET_DBG("Buf %p - mode %d - pan id comp %d", (void *)buf, mode, pan_id_compression); if (mode == IEEE802154_ADDR_MODE_NONE) { *addr = NULL; From d88840a8aabd2a0d620a750397ad646c04874959 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 5 Jun 2023 15:42:18 -0700 Subject: [PATCH 0112/2042] Revert "drivers: serial: ns16550: Add support for Async APIs" This reverts commit 2d03aaf99f326ec0c916da1ca7b8725c8b9fdbc8. The async API for NS16550 is incomplete. We are near the next release so it is better to revert it for now, and a proper correct implementation can be done before next-next release. Relates to #57103 Signed-off-by: Daniel Leung --- drivers/serial/Kconfig.ns16550 | 1 - drivers/serial/uart_ns16550.c | 577 +-------------------------------- 2 files changed, 1 insertion(+), 577 deletions(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index d439d65ef8a2..ae8f866a3e3e 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -6,7 +6,6 @@ menuconfig UART_NS16550 depends on DT_HAS_NS16550_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select SERIAL_SUPPORT_ASYNC help This option enables the NS16550 serial driver. This driver can be used for the serial hardware diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index f3b94c843685..086195615702 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -66,7 +66,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define REG_MDC 0x04 /* Modem control reg. */ #define REG_LSR 0x05 /* Line status reg. */ #define REG_MSR 0x06 /* Modem status reg. */ -#define REG_SCR 0x07 /* Scratchpad. */ #define REG_DLF 0xC0 /* Divisor Latch Fraction */ #define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */ @@ -143,18 +142,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); */ #define FCR_FIFO_64 0x20 /* Enable 64 bytes FIFO */ -/* FIFO Depth. */ -#if defined(CONFIG_UART_NS16550_VARIANT_NS16750) -#define UART_FIFO_DEPTH (64) -#elif defined(CONFIG_UART_NS16550_VARIANT_NS16950) -#define UART_FIFO_DEPTH (128) -#else -#define UART_FIFO_DEPTH (16) -#endif - -/* FIFO Half Depth. */ -#define UART_FIFO_HALF_DEPTH (UART_FIFO_DEPTH / 2) - /* constants for line control register */ #define LCR_CS5 0x00 /* 5 bits data size */ @@ -190,18 +177,6 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define LSR_THRE 0x20 /* transmit holding register empty */ #define LSR_TEMT 0x40 /* transmitter empty */ -/* Transfer Error */ -#define UART_PASS 0 /* Transfer completed */ -#define UART_ERROR_CANCELED -ECANCELED /* Operation was canceled */ -#define UART_DRIVER_ERROR -ENOTSUP /* Unsupported error */ - -/* Transfer Status */ -#define UART_TRANSFER_SUCCESS 0 /* Transfer success */ -#define UART_TRANSFER_FAILED -EPERM /* Transfer failed */ - -/* SCR bit to indicate updated status for LSR. */ -#define UART_SCR_STATUS_UPDATE BIT(0) - /* constants for modem status register */ #define MSR_DCTS 0x01 /* cts change */ @@ -224,44 +199,11 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define MDC(dev) (get_port(dev) + REG_MDC * reg_interval(dev)) #define LSR(dev) (get_port(dev) + REG_LSR * reg_interval(dev)) #define MSR(dev) (get_port(dev) + REG_MSR * reg_interval(dev)) -#define SCR(dev) (get_port(dev) + REG_SCR * reg_interval(dev)) #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) #define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache) -#if CONFIG_UART_ASYNC_API -/* Macro to get tx semamphore */ -#define GET_TX_SEM(dev) \ - (((const struct uart_ns16550_device_config *) \ - dev->config)->tx_sem) - -/* Macro to get rx sempahore */ -#define GET_RX_SEM(dev) \ - (((const struct uart_ns16550_device_config *) \ - dev->config)->rx_sem) -/** - * UART asynchronous transfer structure. - */ -struct uart_ns16550_transfer_t { - uint8_t *data; /**< Pre-allocated write or read buffer. */ - uint32_t data_len; /**< Number of bytes to transfer. */ - - /** Transfer callback - * - * @param[in] data Callback user data. - * @param[in] UART_PASS on success,negative value for possible - * errors. - * @param[in] status UART module status.To be interpreted with - * intel_uart_status_t for different error bits. - * @param[in] len Length of the UART transfer if successful, 0 - * otherwise. - */ - void (*callback)(void *data, int error, uint32_t status, uint32_t len); - void *callback_data; /**< Callback identifier. */ -}; -#endif /* CONFIG_UART_ASYNC_API */ - /* device config */ struct uart_ns16550_device_config { union { @@ -284,12 +226,6 @@ struct uart_ns16550_device_config { #if defined(CONFIG_PINCTRL) const struct pinctrl_dev_config *pincfg; #endif - -#ifdef CONFIG_UART_ASYNC_API - struct k_sem *tx_sem; - struct k_sem *rx_sem; -#endif - #if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS) bool io_map; #endif @@ -315,21 +251,8 @@ struct uart_ns16550_dev_data { #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM) bool tx_stream_on; #endif - - -#ifdef CONFIG_UART_ASYNC_API - struct uart_event evt; - uart_callback_t async_cb; - void *async_user_data; - struct uart_ns16550_transfer_t *rx_transfer; - struct uart_ns16550_transfer_t *tx_transfer; - uint32_t write_pos; - uint32_t read_pos; -#endif }; - - static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg, uintptr_t port, uint8_t val) { @@ -511,7 +434,7 @@ static int uart_ns16550_configure(const struct device *dev, } clock_control_get_rate(dev_cfg->clock_dev, dev_cfg->clock_subsys, - &pclk); + &pclk); } set_baud_rate(dev, cfg->baudrate, pclk); @@ -1070,221 +993,6 @@ static void uart_ns16550_irq_callback_set(const struct device *dev, k_spin_unlock(&dev_data->lock, key); } -#ifdef CONFIG_UART_ASYNC_API - -static bool is_async_write_complete(const struct device *dev) -{ - struct uart_ns16550_dev_data * const dev_data = dev->data; - struct uart_ns16550_transfer_t *transfer = dev_data->tx_transfer; - - return dev_data->write_pos >= transfer->data_len; -} - -static bool is_async_read_complete(const struct device *dev) -{ - struct uart_ns16550_dev_data * const dev_data = dev->data; - struct uart_ns16550_transfer_t *transfer = dev_data->rx_transfer; - - return dev_data->read_pos >= transfer->data_len; -} - -static void ns16550_write_transfer(const struct device *dev, - struct uart_ns16550_transfer_t *write_transfer) -{ - struct uart_ns16550_dev_data * const dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - int count; - - if (!write_transfer) { - return; - } - if (is_async_write_complete(dev)) { - ns16550_outbyte(dev_cfg, IER(dev), - ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE)); - /* - * At this point the FIFOs are empty, but the shift - * register still is transmitting the last 8 bits. - * So if we were to read LSR, it would say the device - * is still busy. - * Use the SCR Bit 0 to indicate an irq tx is complete. - */ - ns16550_outbyte(dev_cfg, SCR(dev), ns16550_inbyte(dev_cfg, SCR(dev)) - | UART_SCR_STATUS_UPDATE); - if (write_transfer->callback) { - write_transfer->callback(write_transfer->callback_data, - UART_PASS, UART_TRANSFER_SUCCESS, - dev_data->write_pos); - write_transfer->callback = NULL; - } - return; - } - /* - * If we are starting the transfer then the TX FIFO is empty. - * In that case we set 'count' variable to UART_FIFO_DEPTH - * in order to take advantage of the whole FIFO capacity. - */ - count = (dev_data->write_pos == 0) - ? UART_FIFO_DEPTH - : UART_FIFO_HALF_DEPTH; - while (count-- && !is_async_write_complete(dev)) { - ns16550_outbyte(dev_cfg, THR(dev), - write_transfer->data[dev_data->write_pos++]); - } - /* - * Change the threshold level to trigger an interrupt when the - * TX buffer is empty. - */ - if (is_async_write_complete(dev)) { - ns16550_outbyte(dev_cfg, FCR(dev), ns16550_inbyte(dev_cfg, FCR(dev)) | - (ns16550_inbyte(dev_cfg, IER(dev)) | IER_TBE)); - } - -} - -static void ns16550_read_transfer(const struct device *dev, - struct uart_ns16550_transfer_t *read_transfer) -{ - struct uart_ns16550_dev_data * const dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - int lsr; - - if (!read_transfer) { - return; - } - /* - * Copy data from RX FIFO to xfer buffer as long as the xfer - * has not completed and we have data in the RX FIFO. - */ - while (!is_async_read_complete(dev)) { - lsr = ns16550_inbyte(dev_cfg, LSR(dev)); - /* - * A break condition may cause a line status - * interrupt to follow very closely after a - * char timeout interrupt, but reading the lsr - * effectively clears the pending interrupts so - * we issue here the callback - * instead, otherwise we would miss it. - * NOTE: Returned len is 0 for now, this might - * change in the future. - */ - if (lsr & LSR_EOB_MASK) { - ns16550_outbyte(dev_cfg, IER(dev), - ns16550_inbyte(dev_cfg, IER(dev)) & - ~(IER_RXRDY | IER_LSR)); - if (read_transfer->callback) { - read_transfer->callback(read_transfer - ->callback_data, - UART_DRIVER_ERROR, - lsr & LSR_EOB_MASK, 0); - read_transfer->callback = NULL; - } - return; - } - if (lsr & LSR_RXRDY) { - read_transfer->data[dev_data->read_pos++] = - ns16550_inbyte(dev_cfg, THR(dev)); - } else { - /* No more data in the RX FIFO. */ - break; - } - } - if (is_async_read_complete(dev)) { - /* - * Disable both 'Receiver Data Available' and - * 'Receiver Line Status' interrupts. - */ - ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) & - ~(IER_RXRDY | IER_LSR)); - if (read_transfer->callback) { - read_transfer->callback(read_transfer->callback_data, - UART_PASS, UART_TRANSFER_SUCCESS, - dev_data->read_pos); - read_transfer->callback = NULL; - } - } -} - -static void ns16550_line_status(const struct device *dev, uint32_t line_status, - struct uart_ns16550_transfer_t *read_transfer) -{ - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - - if (!line_status) { - return; - } - if (read_transfer) { - ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) & - ~(IER_RXRDY | IER_LSR)); - if (read_transfer->callback) { - /* - * Return the number of bytes read - * a zero as a line status error - * was detected. - */ - read_transfer->callback(read_transfer->callback_data, - UART_DRIVER_ERROR, - line_status, 0); - read_transfer->callback = NULL; - } - } -} - - -static void uart_ns16550_callback(const struct device *dev) -{ - struct uart_ns16550_dev_data * const dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - struct uart_ns16550_transfer_t *write_transfer = dev_data->tx_transfer; - struct uart_ns16550_transfer_t *read_transfer = dev_data->rx_transfer; - uint8_t interrupt_id = ns16550_inbyte(dev_cfg, IIR(dev)) & IIR_MASK; - uint32_t line_status; - - /* - * Interrupt ID priority levels (from highest to lowest): - * 1: IIR_LS - * 2: IIR_RBRF and IIR_CH - * 3: IIR_THRE - */ - switch (interrupt_id) { - /* Spurious interrupt */ - case IIR_NIP: - break; - case IIR_LS: - line_status = ns16550_inbyte(dev_cfg, LSR(dev)) & LSR_EOB_MASK; - ns16550_line_status(dev, line_status, read_transfer); - break; - case IIR_CH: - case IIR_RBRF: - ns16550_read_transfer(dev, read_transfer); - break; - case IIR_THRE: - ns16550_write_transfer(dev, write_transfer); - break; - default: - /* Unhandled interrupt occurred,disable uart interrupts. - * and report error. - */ - if (read_transfer && read_transfer->callback) { - ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) & - ~(IER_RXRDY | IER_LSR)); - read_transfer->callback(read_transfer->callback_data, - UART_DRIVER_ERROR, - UART_TRANSFER_FAILED, 0); - read_transfer->callback = NULL; - } - - if (write_transfer && write_transfer->callback) { - ns16550_outbyte(dev_cfg, IER(dev), - ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE)); - write_transfer->callback(write_transfer->callback_data, - UART_DRIVER_ERROR, - UART_TRANSFER_FAILED, 0); - write_transfer->callback = NULL; - } - } -} -#endif /* CONFIG_UART_ASYNC_API */ - /** * @brief Interrupt service routine. * @@ -1298,10 +1006,6 @@ static void uart_ns16550_isr(const struct device *dev) if (dev_data->cb) { dev_data->cb(dev, dev_data->cb_data); -#ifdef CONFIG_UART_ASYNC_API - } else { - uart_ns16550_callback(dev); -#endif } #ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT @@ -1405,247 +1109,6 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd, #endif /* CONFIG_UART_NS16550_DRV_CMD */ -#ifdef CONFIG_UART_ASYNC_API -static uint32_t uart_ns16550_decode_line_err(uint32_t line_err) -{ - uint32_t zephyr_line_err = 0; - - if (line_err & LSR_OE) { - zephyr_line_err = UART_ERROR_OVERRUN; - } - - if (line_err & LSR_PE) { - zephyr_line_err = UART_ERROR_PARITY; - } - - if (line_err & LSR_FE) { - zephyr_line_err = UART_ERROR_FRAMING; - } - - if (line_err & LSR_BI) { - zephyr_line_err = UART_BREAK; - } - - return zephyr_line_err; -} - - -static void uart_ns16550_irq_tx_common_cb(void *data, int err, uint32_t status, - uint32_t len) -{ - const struct device *dev = data; - struct uart_ns16550_dev_data *dev_data = dev->data; - - if (dev_data->async_cb) { - dev_data->async_user_data = (void *)(uintptr_t) - uart_ns16550_decode_line_err(status); - dev_data->async_cb(dev, &dev_data->evt, dev_data->async_user_data); - } - k_sem_give(GET_TX_SEM(dev)); -} - -static void uart_ns16550_irq_rx_common_cb(void *data, int err, uint32_t status, - uint32_t len) -{ - const struct device *dev = data; - struct uart_ns16550_dev_data *dev_data = dev->data; - - if (dev_data->async_cb) { - dev_data->async_user_data = (void *)(uintptr_t) - uart_ns16550_decode_line_err(status); - dev_data->async_cb(dev, &dev_data->evt, dev_data->async_user_data); - } - k_sem_give(GET_RX_SEM(dev)); - -} - -static int uart_ns16550_async_callback_set(const struct device *dev, - uart_callback_t cb, - void *user_data) -{ - struct uart_ns16550_dev_data *dev_data = dev->data; - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - dev_data->async_cb = cb; - dev_data->async_user_data = user_data; - - k_spin_unlock(&dev_data->lock, key); - return 0; -} - -static int uart_ns16550_write_buffer_async(const struct device *dev, - const uint8_t *tx_buf, - size_t tx_buf_size, int32_t timeout) -{ - struct uart_ns16550_dev_data *dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - int ret; - - __ASSERT(tx_buf != NULL, ""); - __ASSERT(tx_buf_size != 0, ""); - - - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (k_sem_take(GET_TX_SEM(dev), K_NO_WAIT)) { - ret = -EBUSY; - goto out; - } - if (dev_data->async_cb) { - dev_data->evt.type = UART_TX_DONE; - } - - dev_data->tx_transfer->data = (uint8_t *)tx_buf; - dev_data->tx_transfer->data_len = tx_buf_size; - dev_data->tx_transfer->callback = uart_ns16550_irq_tx_common_cb; - dev_data->tx_transfer->callback_data = (void *)dev; - - dev_data->write_pos = 0; - - /* Set threshold. */ - ns16550_outbyte(dev_cfg, FCR(dev), (FCR_FIFO | FCR_FIFO_8)); - - /* Enable TX holding reg empty interrupt. */ - ns16550_outbyte(dev_cfg, IER(dev), (ns16550_inbyte(dev_cfg, IER(dev)) | IER_TBE)); - ret = 0; -out: - k_spin_unlock(&dev_data->lock, key); - return ret; -} - -static int uart_ns16550_write_abort_async(const struct device *dev) -{ - struct uart_ns16550_dev_data *dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - struct uart_ns16550_transfer_t *transfer = dev_data->tx_transfer; - int ret; - - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (dev_data->async_cb) { - dev_data->evt.type = UART_TX_ABORTED; - } - /* No ongoing write transaction to be terminated. */ - if (transfer == NULL) { - ret = -EIO; - goto out; - } - /* Disable TX holding reg empty interrupt. */ - ns16550_outbyte(dev_cfg, IER(dev), ns16550_inbyte(dev_cfg, IER(dev)) & (~IER_TBE)); - - if (transfer) { - if (transfer->callback) { - transfer->callback(transfer->callback_data, - UART_ERROR_CANCELED, - UART_TRANSFER_FAILED, - dev_data->write_pos); - } - dev_data->tx_transfer->callback = NULL; - dev_data->write_pos = 0; - } - ret = 0; -out: - k_spin_unlock(&dev_data->lock, key); - return ret; -} - -static int uart_ns16550_read_buffer_async(const struct device *dev, - uint8_t *rx_buf, - size_t rx_buf_size, - int32_t timeout) -{ - __ASSERT(rx_buf != NULL, ""); - __ASSERT(rx_buf_size != 0, ""); - struct uart_ns16550_dev_data *dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - int ret; - - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (k_sem_take(GET_RX_SEM(dev), K_NO_WAIT)) { - ret = -EBUSY; - goto out; - } - - if (dev_data->async_cb) { - dev_data->evt.type = UART_RX_RDY; - } - - dev_data->rx_transfer->data = rx_buf; - dev_data->rx_transfer->data_len = rx_buf_size; - dev_data->rx_transfer->callback = uart_ns16550_irq_rx_common_cb; - dev_data->rx_transfer->callback_data = (void *)dev; - - dev_data->read_pos = 0; - - /* Set threshold. */ - ns16550_outbyte(dev_cfg, FCR(dev), (FCR_FIFO | FCR_FIFO_8)); - - /* - * Enable both 'Receiver Data Available' and 'Receiver - * Line Status' interrupts. - */ - ns16550_outbyte(dev_cfg, IER(dev), - (ns16550_inbyte(dev_cfg, IER(dev)) | IER_RXRDY | IER_LSR)); - ret = 0; -out: - k_spin_unlock(&dev_data->lock, key); - return ret; -} - -static int uart_ns16550_read_disable_async(const struct device *dev) -{ - struct uart_ns16550_dev_data *dev_data = dev->data; - const struct uart_ns16550_device_config * const dev_cfg = dev->config; - struct uart_ns16550_transfer_t *transfer = dev_data->rx_transfer; - int ret; - - k_spinlock_key_t key = k_spin_lock(&dev_data->lock); - - if (dev_data->async_cb) { - dev_data->evt.type = UART_RX_DISABLED; - } - - /* No ongoing read transaction to be terminated. */ - if (transfer == NULL) { - ret = -EIO; - goto out; - } - - /* - * Disable both 'Receiver Data Available' and 'Receiver Line Status' - * interrupts. - */ - ns16550_outbyte(dev_cfg, IER(dev), - ns16550_inbyte(dev_cfg, IER(dev)) & ~(IER_RXRDY | IER_LSR)); - - if (transfer) { - if (transfer->callback) { - transfer->callback(transfer->callback_data, - UART_ERROR_CANCELED, - UART_TRANSFER_FAILED, - dev_data->read_pos); - transfer->callback = NULL; - } - dev_data->read_pos = 0; - } - ret = 0; - -out: - k_spin_unlock(&dev_data->lock, key); - return ret; -} - -static int uart_ns16550_read_buf_rsp(const struct device *dev, uint8_t *buf, - size_t len) -{ - ARG_UNUSED(dev); - ARG_UNUSED(buf); - ARG_UNUSED(len); - - return -ENOTSUP; -} -#endif /* CONFIG_UART_ASYNC_API */ static const struct uart_driver_api uart_ns16550_driver_api = { .poll_in = uart_ns16550_poll_in, @@ -1674,15 +1137,6 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #endif -#ifdef CONFIG_UART_ASYNC_API - .callback_set = uart_ns16550_async_callback_set, - .tx = uart_ns16550_write_buffer_async, - .tx_abort = uart_ns16550_write_abort_async, - .rx_enable = uart_ns16550_read_buffer_async, - .rx_disable = uart_ns16550_read_disable_async, - .rx_buf_rsp = uart_ns16550_read_buf_rsp, -#endif - #ifdef CONFIG_UART_NS16550_LINE_CTRL .line_ctrl_set = uart_ns16550_line_ctrl_set, #endif @@ -1794,36 +1248,9 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define DEV_DATA_DLF_INIT(n) \ _CONCAT(DEV_DATA_DLF, DT_INST_NODE_HAS_PROP(n, dlf))(n) -#ifdef CONFIG_UART_ASYNC_API -#define DEV_ASYNC_DECLARE(n) \ - static K_SEM_DEFINE(uart_##n##_tx_sem, 1, 1); \ - static K_SEM_DEFINE(uart_##n##_rx_sem, 1, 1); \ - static struct uart_ns16550_transfer_t tx_##n; \ - static struct uart_ns16550_transfer_t rx_##n; -#else -#define DEV_ASYNC_DECLARE(n) -#endif - -#ifdef CONFIG_UART_ASYNC_API -#define DEV_CONFIG_ASYNC_INIT(n) \ - .tx_sem = &uart_##n##_tx_sem, \ - .rx_sem = &uart_##n##_rx_sem, -#else -#define DEV_CONFIG_ASYNC_INIT(n) -#endif - -#ifdef CONFIG_UART_ASYNC_API -#define DEV_DATA_ASYNC_INIT(n) \ - .tx_transfer = &tx_##n, \ - .rx_transfer = &rx_##n, -#else -#define DEV_DATA_ASYNC_INIT(n) -#endif - #define UART_NS16550_DEVICE_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ DEV_PCIE_DECLARE(n); \ - DEV_ASYNC_DECLARE(n); \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ (PINCTRL_DT_INST_DEFINE(n))); \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ @@ -1842,7 +1269,6 @@ static const struct uart_driver_api uart_ns16550_driver_api = { DEV_CONFIG_IRQ_FUNC_INIT(n) \ DEV_CONFIG_PCP_INIT(n) \ .reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \ - DEV_CONFIG_ASYNC_INIT(n) \ DEV_CONFIG_PCIE_INIT(n) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ (.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \ @@ -1854,7 +1280,6 @@ static const struct uart_driver_api uart_ns16550_driver_api = { .uart_config.data_bits = UART_CFG_DATA_BITS_8, \ .uart_config.flow_ctrl = DEV_DATA_FLOW_CTRL(n), \ DEV_DATA_DLF_INIT(n) \ - DEV_DATA_ASYNC_INIT(n) \ }; \ DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \ &uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \ From bb81b428614fe5183578835a95546430e23a3cd9 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 5 Jun 2023 14:31:50 +0200 Subject: [PATCH 0113/2042] Bluetooth: TBS: Ensure that inst exist when notifying terminate When calling the `terminate_call` the `inst` would always be NULL as we had just terminated the call that we attempted to look up. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/tbs.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 8715935a0fe2..6956253e04b8 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1162,9 +1162,8 @@ static uint8_t join_calls(struct tbs_service_inst *inst, return BT_TBS_RESULT_CODE_SUCCESS; } -static void notify_app(struct bt_conn *conn, uint16_t len, - const union bt_tbs_call_cp_t *ccp, uint8_t status, - uint8_t call_index) +static void notify_app(struct bt_conn *conn, struct tbs_service_inst *inst, uint16_t len, + const union bt_tbs_call_cp_t *ccp, uint8_t status, uint8_t call_index) { if (tbs_cbs == NULL) { return; @@ -1178,13 +1177,6 @@ static void notify_app(struct bt_conn *conn, uint16_t len, break; case BT_TBS_CALL_OPCODE_TERMINATE: if (tbs_cbs->terminate_call != NULL) { - const struct tbs_service_inst *inst = lookup_inst_by_call_index(call_index); - - if (inst == NULL) { - LOG_DBG("Could not find instance by call index 0x%02X", call_index); - break; - } - tbs_cbs->terminate_call(conn, call_index, inst->terminate_reason.reason); } @@ -1205,14 +1197,6 @@ static void notify_app(struct bt_conn *conn, uint16_t len, const uint16_t uri_len = len - sizeof(ccp->originate); bool remote_party_alerted = false; struct bt_tbs_call *call; - struct tbs_service_inst *inst; - - inst = lookup_inst_by_call_index(call_index); - - if (inst == NULL) { - LOG_DBG("Could not find instance by call index 0x%02X", call_index); - break; - } call = lookup_call_in_inst(inst, call_index); @@ -1458,9 +1442,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 (status == BT_TBS_RESULT_CODE_SUCCESS) { + if (inst != NULL && status == BT_TBS_RESULT_CODE_SUCCESS) { notify_calls(inst); - notify_app(conn, len, ccp, status, call_index); + notify_app(conn, inst, len, ccp, status, call_index); } return len; From 1a6b6e7b84b46c5f20bdd5fb793ffbee5a7fed53 Mon Sep 17 00:00:00 2001 From: Siyuan Cheng Date: Mon, 5 Jun 2023 14:44:57 +0800 Subject: [PATCH 0114/2042] drivers: pinctrl_emsdp: add dummy mux for unmuxed peripheral ARC EMSDP board has some peripherals are internal connected, such as DW spi1 and DFSS i2c0. They are unmuxed and have fix connection to spi-flash or sensor. For these peripheral, add dummy mux type to avoid pinctrl ENOENT error. Signed-off-by: Siyuan Cheng --- boards/arc/emsdp/emsdp-pinctrl.dtsi | 5 +++++ boards/arc/emsdp/emsdp.dts | 2 ++ drivers/pinctrl/pinctrl_emsdp.c | 4 ++++ include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h | 2 ++ 4 files changed, 13 insertions(+) diff --git a/boards/arc/emsdp/emsdp-pinctrl.dtsi b/boards/arc/emsdp/emsdp-pinctrl.dtsi index efe492a4b2a0..0873c798c40d 100644 --- a/boards/arc/emsdp/emsdp-pinctrl.dtsi +++ b/boards/arc/emsdp/emsdp-pinctrl.dtsi @@ -130,4 +130,9 @@ arduino_CFG6_i2c: arduino_CFG6_i2c { pinmux = ; }; + + /* INNER_CONNECT, DUMMY MUX */ + unmuxed_pin: unmuxed_pin { + pinmux = ; + }; }; diff --git a/boards/arc/emsdp/emsdp.dts b/boards/arc/emsdp/emsdp.dts index 8976ddc34227..6a24a9ec5bd6 100644 --- a/boards/arc/emsdp/emsdp.dts +++ b/boards/arc/emsdp/emsdp.dts @@ -49,6 +49,8 @@ spi@f1000000 { interrupts = <84 1>; + pinctrl-0 = <&unmuxed_pin>; + pinctrl-names = "default"; }; spi@80010000 { diff --git a/drivers/pinctrl/pinctrl_emsdp.c b/drivers/pinctrl/pinctrl_emsdp.c index d19f850b37fe..07f5df354734 100644 --- a/drivers/pinctrl/pinctrl_emsdp.c +++ b/drivers/pinctrl/pinctrl_emsdp.c @@ -103,6 +103,10 @@ static int pinctrl_emsdp_set(uint32_t pin, uint32_t type) const uint32_t mux_regs = (EMSDP_CREG_BASE + EMSDP_CREG_PMOD_MUX_OFFSET); uint32_t reg; + if (pin == INNER_CONNECT) { + return 0; + } + if (pin <= PMOD_C) { reg = sys_read32(mux_regs + PMOD_MUX_CTRL); } else { diff --git a/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h index 1f6922f84e46..f3cfc60ffa43 100644 --- a/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h @@ -37,6 +37,7 @@ #define ARDUINO_PIN_AD3 20 #define ARDUINO_PIN_AD4 21 #define ARDUINO_PIN_AD5 22 +#define INNER_CONNECT 23 #define PMOD_GPIO 0 #define PMOD_UARTA 1 @@ -52,6 +53,7 @@ #define ARDUINO_I2C 11 #define ARDUINO_PWM 12 #define ARDUINO_ADC 13 +#define NOT_PINMUX 14 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_EMSDP_PINCTRL_H_ */ From 24efa6720dd76e9cba170e3432f32ca0423a67b9 Mon Sep 17 00:00:00 2001 From: Siyuan Cheng Date: Mon, 5 Jun 2023 14:56:36 +0800 Subject: [PATCH 0115/2042] drivers: pinctrl_emsdp: fix definition location Mux Control Register Index are internals of driver, now moved from dt-binding header to driver itself. Signed-off-by: Siyuan Cheng --- boards/arc/emsdp/emsdp-pinctrl.dtsi | 2 +- drivers/pinctrl/pinctrl_emsdp.c | 8 +++++++- include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h | 9 +-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/boards/arc/emsdp/emsdp-pinctrl.dtsi b/boards/arc/emsdp/emsdp-pinctrl.dtsi index 0873c798c40d..e54541a7bf14 100644 --- a/boards/arc/emsdp/emsdp-pinctrl.dtsi +++ b/boards/arc/emsdp/emsdp-pinctrl.dtsi @@ -133,6 +133,6 @@ /* INNER_CONNECT, DUMMY MUX */ unmuxed_pin: unmuxed_pin { - pinmux = ; + pinmux = ; }; }; diff --git a/drivers/pinctrl/pinctrl_emsdp.c b/drivers/pinctrl/pinctrl_emsdp.c index 07f5df354734..c535c91728fa 100644 --- a/drivers/pinctrl/pinctrl_emsdp.c +++ b/drivers/pinctrl/pinctrl_emsdp.c @@ -11,6 +11,12 @@ #include #include +/** + * Mux Control Register Index + */ +#define PMOD_MUX_CTRL 0 /*!< 32-bits, offset 0x0 */ +#define ARDUINO_MUX_CTRL 4 /*!< 32-bits, offset 0x4 */ + #define EMSDP_CREG_BASE DT_INST_REG_ADDR(0) #define EMSDP_CREG_PMOD_MUX_OFFSET (0x0030) @@ -103,7 +109,7 @@ static int pinctrl_emsdp_set(uint32_t pin, uint32_t type) const uint32_t mux_regs = (EMSDP_CREG_BASE + EMSDP_CREG_PMOD_MUX_OFFSET); uint32_t reg; - if (pin == INNER_CONNECT) { + if (pin == UNMUXED_PIN) { return 0; } diff --git a/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h index f3cfc60ffa43..7ba0534784bb 100644 --- a/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/emsdp-pinctrl.h @@ -7,13 +7,6 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_EMSDP_PINCTRL_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_EMSDP_PINCTRL_H_ -/** - * Mux Control Register Index - */ -#define PMOD_MUX_CTRL 0 /*!< 32-bits, offset 0x0 */ - -#define ARDUINO_MUX_CTRL 4 /*!< 32-bits, offset 0x4 */ - #define PMOD_A 0 #define PMOD_B 1 #define PMOD_C 2 @@ -37,7 +30,7 @@ #define ARDUINO_PIN_AD3 20 #define ARDUINO_PIN_AD4 21 #define ARDUINO_PIN_AD5 22 -#define INNER_CONNECT 23 +#define UNMUXED_PIN 23 #define PMOD_GPIO 0 #define PMOD_UARTA 1 From ae6c856128960a04a1dc05bc0246d255ab0c190c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Mon, 12 Jun 2023 14:43:14 +0200 Subject: [PATCH 0116/2042] usb: device: class: rndis: Limit response length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent potential buffer overflow when encapsulated response is more than CONFIG_USB_REQUEST_BUFFER_SIZE. Log error and truncate response if USB control transfer request buffer is not large enough. Signed-off-by: Tomasz Moń --- subsys/usb/device/class/netusb/function_rndis.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/subsys/usb/device/class/netusb/function_rndis.c b/subsys/usb/device/class/netusb/function_rndis.c index 57feabafca0b..1810494326a3 100644 --- a/subsys/usb/device/class/netusb/function_rndis.c +++ b/subsys/usb/device/class/netusb/function_rndis.c @@ -834,12 +834,18 @@ static int handle_encapsulated_rsp(uint8_t **data, uint32_t *len) return -ENODATA; } + *len = buf->len; + if (*len > CONFIG_USB_REQUEST_BUFFER_SIZE) { + LOG_ERR("Response too long %u, truncating to %u", buf->len, + CONFIG_USB_REQUEST_BUFFER_SIZE); + *len = CONFIG_USB_REQUEST_BUFFER_SIZE; + } + if (VERBOSE_DEBUG) { net_hexdump("RSP <", buf->data, buf->len); } - memcpy(*data, buf->data, buf->len); - *len = buf->len; + memcpy(*data, buf->data, *len); net_buf_unref(buf); From 21b5d423e80ed5a362f45754b04cdb2c7587562e Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 7 Jun 2023 15:02:35 +0200 Subject: [PATCH 0117/2042] Bluetooth: Mesh: Fix printing UUID log message CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL_INF may not be present while CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL is always present. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/prov_device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index a6b702cd01e4..4ec7ebabe432 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -670,12 +670,14 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } - if (IS_ENABLED(CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL_INF)) { +#if IS_ENABLED(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 } }; memcpy(uuid.val, bt_mesh_prov->uuid, 16); LOG_INF("Device UUID: %s", bt_uuid_str(&uuid.uuid)); } +#endif if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && (bearers & BT_MESH_PROV_ADV)) { From 8902de75eb34b9c27913eaae4a214e236b3a22fc Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 7 Jun 2023 15:03:37 +0200 Subject: [PATCH 0118/2042] Bluetooth: Mesh: Print UUID with correct endianess bt_uuid_str expects UUID in little endian while UUID encoded into unprovisioned mesh beacon is encoded in big endian. sys_memcpy_swap will change endianess of uuid so that bt_uuid_str can be used. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/prov_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index 4ec7ebabe432..6daf978f73e0 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -674,7 +674,7 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) if (CONFIG_BT_MESH_PROV_DEVICE_LOG_LEVEL > 2) { struct bt_uuid_128 uuid = { .uuid = { BT_UUID_TYPE_128 } }; - memcpy(uuid.val, bt_mesh_prov->uuid, 16); + sys_memcpy_swap(uuid.val, bt_mesh_prov->uuid, 16); LOG_INF("Device UUID: %s", bt_uuid_str(&uuid.uuid)); } #endif From de61b25b836e37a0eea31dffdf2b06ae049260d4 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 7 Jun 2023 15:06:45 +0200 Subject: [PATCH 0119/2042] tests: bluetooth: mesh_shell: Print correct command for provisioning Provisioning commands were moved under `mesh prov` subcommand. Signed-off-by: Pavel Vasilyev --- tests/bluetooth/mesh_shell/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bluetooth/mesh_shell/src/main.c b/tests/bluetooth/mesh_shell/src/main.c index 4e0394c234d0..60863f7455a3 100644 --- a/tests/bluetooth/mesh_shell/src/main.c +++ b/tests/bluetooth/mesh_shell/src/main.c @@ -141,7 +141,7 @@ static void bt_ready(int err) if (bt_mesh_is_provisioned()) { printk("Mesh network restored from flash\n"); } else { - printk("Use \"pb-adv on\" or \"pb-gatt on\" to " + printk("Use \"prov pb-adv on\" or \"prov pb-gatt on\" to " "enable advertising\n"); } } From d6c85c2f596de80e76310d727759dbd875cb9c7b Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Tue, 6 Jun 2023 12:37:50 +0300 Subject: [PATCH 0120/2042] net: coap: CoAP reply handler fix Fix corner case when client RX request with same token than own request where it wait responses. Signed-off-by: Juha Heiskanen --- subsys/net/lib/coap/coap.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index 44ee5f85e889..b0a30510fba7 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -913,6 +913,12 @@ static int method_from_code(const struct coap_resource *resource, } } + +static inline bool is_empty_message(const struct coap_packet *cpkt) +{ + return __coap_header_get_code(cpkt) == COAP_CODE_EMPTY; +} + static bool is_request(const struct coap_packet *cpkt) { uint8_t code = coap_header_get_code(cpkt); @@ -1465,6 +1471,11 @@ struct coap_reply *coap_response_received( uint8_t tkl; size_t i; + if (!is_empty_message(response) && is_request(response)) { + /* Request can't be response */ + return NULL; + } + id = coap_header_get_id(response); tkl = coap_header_get_token(response, token); From 2756c9b9a569f42cea23a13ea3590f9980327b9a Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Mon, 12 Jun 2023 22:43:00 +0300 Subject: [PATCH 0121/2042] arch: arm64: cache: fix usage of extern C linkage specification Reorder preprocessor condition endings in arm64/cache.h, this eliminates the breaking of the 'extern "C"' construction. Signed-off-by: Mykola Kvach --- include/zephyr/arch/arm64/cache.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/arch/arm64/cache.h b/include/zephyr/arch/arm64/cache.h index 418e109de56b..1ed55035b597 100644 --- a/include/zephyr/arch/arm64/cache.h +++ b/include/zephyr/arch/arm64/cache.h @@ -312,10 +312,11 @@ static ALWAYS_INLINE void arch_icache_disable(void) } #endif /* CONFIG_ICACHE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_CACHE_H_ */ #ifdef __cplusplus } #endif #endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_CACHE_H_ */ From 7bce75bd0ded9f639378364acbd1cd9dca1f62c0 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 8 Jun 2023 09:50:21 +0200 Subject: [PATCH 0122/2042] Shell: Add missing long long type in shell_strtoull shell_strtoull used a unsigned long instead of a unsigned long long to store the result in stroull, so the return value may have been truncated. Signed-off-by: Emil Gydesen --- 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 3fb316c5ba10..06033ec688b8 100644 --- a/subsys/shell/shell_utils.c +++ b/subsys/shell/shell_utils.c @@ -565,7 +565,7 @@ unsigned long shell_strtoul(const char *str, int base, int *err) unsigned long long shell_strtoull(const char *str, int base, int *err) { - unsigned long val; + unsigned long long val; char *endptr = NULL; if (*str == '-') { From 5f9737f48220ec7fd1f9266d5eed157b4c01ce11 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 12 Jun 2023 13:51:40 +0100 Subject: [PATCH 0123/2042] mgmt: mcumgr: fs_mgmt: Fix duplicate bool ok variables Fixes wrongly declaring duplicate local variables that already exist and hiding the previous variables definitions. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 8 -------- 1 file changed, 8 deletions(-) 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 0ba3aba4c414..0e5e934ed03f 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -254,8 +254,6 @@ static int fs_mgmt_file_download(struct smp_streamer *ctxt) sizeof(file_access_data), &ret_rc, &ret_group); if (status != MGMT_CB_OK) { - bool ok; - if (status == MGMT_CB_ERROR_RC) { return ret_rc; } @@ -405,8 +403,6 @@ static int fs_mgmt_file_upload(struct smp_streamer *ctxt) sizeof(file_access_data), &ret_rc, &ret_group); if (status != MGMT_CB_OK) { - bool ok; - if (status == MGMT_CB_ERROR_RC) { return ret_rc; } @@ -609,8 +605,6 @@ static int fs_mgmt_file_status(struct smp_streamer *ctxt) sizeof(file_access_data), &ret_rc, &ret_group); if (status != MGMT_CB_OK) { - bool ok; - if (status == MGMT_CB_ERROR_RC) { return ret_rc; } @@ -718,8 +712,6 @@ static int fs_mgmt_file_hash_checksum(struct smp_streamer *ctxt) sizeof(file_access_data), &ret_rc, &ret_group); if (status != MGMT_CB_OK) { - bool ok; - if (status == MGMT_CB_ERROR_RC) { return ret_rc; } From 6981e2e3cf636119a41693696dbe5a184be808af Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 12 Jun 2023 14:10:48 +0100 Subject: [PATCH 0124/2042] doc: services: device_mgmt: mcumgr: Update callback documentation Updates and fixes callback documentation to show functionality and definitions that were recently updated. Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/mcumgr_callbacks.rst | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/doc/services/device_mgmt/mcumgr_callbacks.rst b/doc/services/device_mgmt/mcumgr_callbacks.rst index e8700105ef3d..e1cef8d9ffc2 100644 --- a/doc/services/device_mgmt/mcumgr_callbacks.rst +++ b/doc/services/device_mgmt/mcumgr_callbacks.rst @@ -43,15 +43,16 @@ application code as per: struct mgmt_callback my_callback; - int32_t my_function(uint32_t event, int32_t rc, bool *abort_more, void *data, - size_t data_size) + enum mgmt_cb_return my_function(uint32_t event, enum mgmt_cb_return prev_status, + int32_t *rc, uint16_t *group, bool *abort_more, + void *data, size_t data_size) { if (event == MGMT_EVT_OP_CMD_DONE) { /* This is the event we registered for */ } /* Return OK status code to continue with acceptance to underlying handler */ - return MGMT_ERR_EOK; + return MGMT_CB_OK; } int main() @@ -142,32 +143,37 @@ An example of selectively denying file access: struct mgmt_callback my_callback; - int32_t my_function(uint32_t event, int32_t rc, bool *abort_more, void *data, - size_t data_size) + enum mgmt_cb_return my_function(uint32_t event, enum mgmt_cb_return prev_status, + int32_t *rc, uint16_t *group, bool *abort_more, + void *data, size_t data_size) { /* Only run this handler if a previous handler has not failed */ - if (event == MGMT_EVT_OP_FS_MGMT_FILE_ACCESS && rc == MGMT_ERR_EOK) { + if (event == MGMT_EVT_OP_FS_MGMT_FILE_ACCESS && prev_status == MGMT_CB_OK) { struct fs_mgmt_file_access *fs_data = (struct fs_mgmt_file_access *)data; /* Check if this is an upload and deny access if it is, otherwise check the * the path and deny if is matches a name */ - if (fs_data->upload == true) { + if (fs_data->access == FS_MGMT_FILE_ACCESS_WRITE) { /* Return an access denied error code to the client and abort calling * further handlers */ *abort_more = true; - return MGMT_ERR_EACCESSDENIED; + *rc = MGMT_ERR_EACCESSDENIED; + + return MGMT_CB_ERROR_RC; } else if (strcmp(fs_data->filename, "/lfs1/false_deny.txt") == 0) { /* Return a no entry error code to the client, call additional handlers * (which will have failed set to true) */ - return MGMT_ERR_ENOENT; + *rc = MGMT_ERR_ENOENT; + + return MGMT_CB_ERROR_RC; } } /* Return OK status code to continue with acceptance to underlying handler */ - return MGMT_ERR_EOK; + return MGMT_CB_OK; } int main() @@ -183,6 +189,11 @@ after a fs_mgmt file read/write command has been received to check if access to the file should be allowed or not, note that this requires that :kconfig:option:`CONFIG_MCUMGR_GRP_FS_FILE_ACCESS_HOOK` be enabled to receive this callback. +Two types of errors can be returned, the ``rc`` parameter can be set to an +:c:enumerator:`mcumgr_err_t` error code and :c:enumerator:`MGMT_CB_ERROR_RC` +can be returned, or a group error code (introduced with version 2 of the MCUmgr +protocol) can be set by setting the ``group`` value to the group and ``rc`` +value to the group error code and returning :c:enumerator:`MGMT_CB_ERROR_RET`. MCUmgr Command Callback Usage/Adding New Event Types ==================================================== @@ -199,6 +210,7 @@ An example MCUmgr command handler: #include #include #include + #include #include #include @@ -222,6 +234,8 @@ An example MCUmgr command handler: static int test_command(struct mgmt_ctxt *ctxt) { int rc; + int ret_rc; + uint16_t ret_group; zcbor_state_t *zse = ctxt->cnbe->zs; bool ok; struct test_struct test_data = { @@ -229,23 +243,28 @@ An example MCUmgr command handler: }; rc = mgmt_callback_notify(MGMT_EVT_OP_USER_ONE_FIRST, &test_data, - sizeof(test_data)); + sizeof(test_data), &ret_rc, &ret_group); - if (rc != MGMT_ERR_EOK) { + if (rc != MGMT_CB_OK) { /* A handler returned a failure code */ - return rc; + if (rc == MGMT_CB_ERROR_RC) { + /* The failure code is the RC value */ + return ret_rc; + } + + /* The failure is a group and ID error value */ + ok = smp_add_cmd_ret(zse, ret_group, (uint16_t)ret_rc); + goto end; } /* All handlers returned success codes */ - ok = zcbor_tstr_put_lit(zse, "output_value") && zcbor_int32_put(zse, 1234); - if (!ok) { - return MGMT_ERR_EMSGSIZE; - } + end: + rc = (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); - return MGMT_ERR_EOK; + return rc; } If no response is required for the callback, the function call be called and From 9d7bd523130645b3cfe7f122bd126c98055a8c2c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 12 Jun 2023 16:27:48 +0100 Subject: [PATCH 0125/2042] modules: lvgl: define the Kconfig types used in boards Some boards override default for few LVGL LV_Z_* symbols. This causes the build to fail if the module is not present in the system, and has been worked around on one board by repeating the types in the board Kconfig file. Fix this properly by defining the known type for all symbols used in boards in modules/Kconfig.lvgl. Signed-off-by: Fabio Baltieri --- .../shields/ls0xx_generic/Kconfig.defconfig | 3 --- modules/Kconfig.lvgl | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/boards/shields/ls0xx_generic/Kconfig.defconfig b/boards/shields/ls0xx_generic/Kconfig.defconfig index e8e3f3af4c1d..e9243e3f178d 100644 --- a/boards/shields/ls0xx_generic/Kconfig.defconfig +++ b/boards/shields/ls0xx_generic/Kconfig.defconfig @@ -8,15 +8,12 @@ if DISPLAY if LVGL config LV_Z_VDB_SIZE - int default 16 config LV_Z_DPI - int default 150 config LV_Z_BITS_PER_PIXEL - int default 1 choice LV_COLOR_DEPTH diff --git a/modules/Kconfig.lvgl b/modules/Kconfig.lvgl index 97261ed44989..fe56654c6dfb 100644 --- a/modules/Kconfig.lvgl +++ b/modules/Kconfig.lvgl @@ -8,6 +8,27 @@ config LVGL if LVGL +config LV_Z_BITS_PER_PIXEL + int + +config LV_Z_DOUBLE_VDB + bool + +config LV_Z_DPI + int + +config LV_Z_FULL_REFRESH + bool + +config LV_Z_VBD_CUSTOM_SECTION + bool + +config LV_Z_VDB_ALIGN + int + +config LV_Z_VDB_SIZE + int + config LV_Z_POINTER_KSCAN bool From b31215e34fbc8eab19a6f7ee135ccd2786ac4b23 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 12 Jun 2023 16:41:32 +0100 Subject: [PATCH 0126/2042] modules: lvgl: replace LV_Z_DPI with LV_DPI_DEF It looks like LV_Z_DPI is not used anywhere and only lived in the context of an incorrect board symbol definition so far (moved to Kconfig.lvgl in the previous patch). This was probably meant to be LV_DPI_DEF (which actually exists in the LVGL module) and was renamed incorrectly, fix it by renaming it everywhere. Signed-off-by: Fabio Baltieri --- boards/arm/mimxrt1050_evk/Kconfig.defconfig | 2 +- boards/arm/mimxrt1060_evk/Kconfig.defconfig | 2 +- boards/arm/mimxrt1064_evk/Kconfig.defconfig | 2 +- boards/arm/mimxrt1170_evk/Kconfig.defconfig | 2 +- boards/arm/mimxrt595_evk/Kconfig.defconfig | 4 ++-- boards/arm/reel_board/Kconfig.defconfig | 2 +- boards/shields/ls0xx_generic/Kconfig.defconfig | 2 +- boards/shields/ssd1306/Kconfig.defconfig | 2 +- boards/shields/waveshare_epaper/Kconfig.defconfig | 2 +- modules/Kconfig.lvgl | 6 +++--- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/boards/arm/mimxrt1050_evk/Kconfig.defconfig b/boards/arm/mimxrt1050_evk/Kconfig.defconfig index 94fc452cf877..0b69a094c47c 100644 --- a/boards/arm/mimxrt1050_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1050_evk/Kconfig.defconfig @@ -56,7 +56,7 @@ config LV_Z_POINTER_KSCAN config LV_Z_VDB_SIZE default 16 -config LV_Z_DPI +config LV_DPI_DEF default 128 choice LV_COLOR_DEPTH diff --git a/boards/arm/mimxrt1060_evk/Kconfig.defconfig b/boards/arm/mimxrt1060_evk/Kconfig.defconfig index 367d3512d3b2..1d6cef3cd6b0 100644 --- a/boards/arm/mimxrt1060_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1060_evk/Kconfig.defconfig @@ -69,7 +69,7 @@ config LV_Z_DOUBLE_VDB config LV_Z_FULL_REFRESH default y -config LV_Z_DPI +config LV_DPI_DEF default 128 config LV_Z_BITS_PER_PIXEL diff --git a/boards/arm/mimxrt1064_evk/Kconfig.defconfig b/boards/arm/mimxrt1064_evk/Kconfig.defconfig index 438cb5489098..9df588b77d09 100644 --- a/boards/arm/mimxrt1064_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1064_evk/Kconfig.defconfig @@ -43,7 +43,7 @@ config LV_Z_POINTER_KSCAN config LV_Z_VDB_SIZE default 16 -config LV_Z_DPI +config LV_DPI_DEF default 128 choice LV_COLOR_DEPTH diff --git a/boards/arm/mimxrt1170_evk/Kconfig.defconfig b/boards/arm/mimxrt1170_evk/Kconfig.defconfig index b5244b93866c..dac37e54ad3d 100644 --- a/boards/arm/mimxrt1170_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1170_evk/Kconfig.defconfig @@ -97,7 +97,7 @@ config LV_Z_FULL_REFRESH config LV_Z_BITS_PER_PIXEL default 16 -config LV_Z_DPI +config LV_DPI_DEF default 128 choice LV_COLOR_DEPTH diff --git a/boards/arm/mimxrt595_evk/Kconfig.defconfig b/boards/arm/mimxrt595_evk/Kconfig.defconfig index 577cd53144b5..6cc3f949607f 100644 --- a/boards/arm/mimxrt595_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt595_evk/Kconfig.defconfig @@ -59,7 +59,7 @@ config LV_Z_DOUBLE_VDB config LV_Z_FULL_REFRESH default y -config LV_Z_DPI +config LV_DPI_DEF default 128 config LV_Z_BITS_PER_PIXEL @@ -80,7 +80,7 @@ config LV_Z_POINTER_KSCAN config LV_Z_VDB_SIZE default 16 -config LV_Z_DPI +config LV_DPI_DEF default 128 choice LV_COLOR_DEPTH diff --git a/boards/arm/reel_board/Kconfig.defconfig b/boards/arm/reel_board/Kconfig.defconfig index b9eefd5d6df9..5bacbb05c5d7 100644 --- a/boards/arm/reel_board/Kconfig.defconfig +++ b/boards/arm/reel_board/Kconfig.defconfig @@ -33,7 +33,7 @@ endchoice config LV_Z_BITS_PER_PIXEL default 1 -config LV_Z_DPI +config LV_DPI_DEF default 130 config LV_Z_VDB_SIZE diff --git a/boards/shields/ls0xx_generic/Kconfig.defconfig b/boards/shields/ls0xx_generic/Kconfig.defconfig index e9243e3f178d..33a8f42ac0f6 100644 --- a/boards/shields/ls0xx_generic/Kconfig.defconfig +++ b/boards/shields/ls0xx_generic/Kconfig.defconfig @@ -10,7 +10,7 @@ if LVGL config LV_Z_VDB_SIZE default 16 -config LV_Z_DPI +config LV_DPI_DEF default 150 config LV_Z_BITS_PER_PIXEL diff --git a/boards/shields/ssd1306/Kconfig.defconfig b/boards/shields/ssd1306/Kconfig.defconfig index e35ddf132e25..960247d2f1d0 100644 --- a/boards/shields/ssd1306/Kconfig.defconfig +++ b/boards/shields/ssd1306/Kconfig.defconfig @@ -14,7 +14,7 @@ if LVGL config LV_Z_VDB_SIZE default 64 -config LV_Z_DPI +config LV_DPI_DEF default 116 if SHIELD_SH1106_128X64 default 148 diff --git a/boards/shields/waveshare_epaper/Kconfig.defconfig b/boards/shields/waveshare_epaper/Kconfig.defconfig index cfeab5b1881b..5f7f13a0b16e 100644 --- a/boards/shields/waveshare_epaper/Kconfig.defconfig +++ b/boards/shields/waveshare_epaper/Kconfig.defconfig @@ -16,7 +16,7 @@ config LV_Z_VDB_SIZE default 16 if SHIELD_WAVESHARE_EPAPER_GDEW075T7 default 16 -config LV_Z_DPI +config LV_DPI_DEF default 188 if SHIELD_WAVESHARE_EPAPER_GDEH0154A07 default 120 if SHIELD_WAVESHARE_EPAPER_GDEW042T2 default 130 diff --git a/modules/Kconfig.lvgl b/modules/Kconfig.lvgl index fe56654c6dfb..b51c5bc4e390 100644 --- a/modules/Kconfig.lvgl +++ b/modules/Kconfig.lvgl @@ -8,15 +8,15 @@ config LVGL if LVGL +config LV_DPI_DEF + int + config LV_Z_BITS_PER_PIXEL int config LV_Z_DOUBLE_VDB bool -config LV_Z_DPI - int - config LV_Z_FULL_REFRESH bool From 6002061efeea24e0d99153ae216b92ead3c7b6ed Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Mon, 12 Jun 2023 16:36:34 +0530 Subject: [PATCH 0127/2042] net: wifi_mgmt: Pass address instead of value as pointer Fix for not getting expected event information at application. net_mgmt_event_notify_with_info() expects the address not the value as pointer. Signed-off-by: Ajay Parida --- subsys/net/l2/wifi/wifi_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 5f1621026657..8bafb5d4475a 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -362,7 +362,7 @@ void wifi_mgmt_raise_twt_sleep_state(struct net_if *iface, int twt_sleep_state) { net_mgmt_event_notify_with_info(NET_EVENT_WIFI_TWT_SLEEP_STATE, - iface, INT_TO_POINTER(twt_sleep_state), + iface, &twt_sleep_state, sizeof(twt_sleep_state)); } From 0b1dd29799e0651056250253c2288894dc1af86c Mon Sep 17 00:00:00 2001 From: Naveen Saini Date: Mon, 29 May 2023 17:48:20 +0800 Subject: [PATCH 0128/2042] gcc/target.cmake: fix build with gcc-13 Configuration error: | -- Configuring done (4.9s) | CMake Error in CMakeLists.txt: | Target "zephyr_interface" contains relative path in its | INTERFACE_INCLUDE_DIRECTORIES: | | "include-fixed" With GCC-13, limits.h and syslimits.h header files are always being installed to include folder. https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=be9dd80f933480 Signed-off-by: Naveen Saini --- cmake/compiler/gcc/target.cmake | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmake/compiler/gcc/target.cmake b/cmake/compiler/gcc/target.cmake index c97004829730..02474090d724 100644 --- a/cmake/compiler/gcc/target.cmake +++ b/cmake/compiler/gcc/target.cmake @@ -34,7 +34,21 @@ if(NOT DEFINED NOSYSDEF_CFLAG) set(NOSYSDEF_CFLAG -undef) endif() -foreach(file_name include/stddef.h include-fixed/limits.h) +# GCC-13, does not install limits.h on include-fixed anymore +# https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=be9dd80f933480 +# Add check for GCC version >= 13.1 +execute_process( + COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE temp_compiler_version + ) + +if("${temp_compiler_version}" VERSION_GREATER_EQUAL 13.1.0) + set(fix_header_file include/limits.h) +else() + set(fix_header_file include-fixed/limits.h) +endif() + +foreach(file_name include/stddef.h "${fix_header_file}") execute_process( COMMAND ${CMAKE_C_COMPILER} --print-file-name=${file_name} OUTPUT_VARIABLE _OUTPUT From e31cea0f7173a84b158251133afeba5362c3eb1c Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 12 Jun 2023 20:37:24 +0200 Subject: [PATCH 0129/2042] release: relnotes: Add Bluetooth release notes for 3.4.0 As usual, populate the Bluetooth release notes. Signed-off-by: Carles Cufi --- doc/releases/release-notes-3.4.rst | 86 +++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 57d296ee3bc9..bc3905557e5b 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -324,20 +324,104 @@ Architectures Bluetooth ********* +* General + + * Moved all logging symbols together in a new ``Kconfig.logging`` file. + * Deprecated the ``BT_DEBUG_LOG`` option. Instead ``BT_LOG`` should be used. + * Made the ``BT_LOG`` and ``BT_LOG_LEGACY`` options hidden. + * Removed ``BT_DEBUG`` entirely. + + * Audio + * Implemented the CAP initiator broadcast audio start, stop and metadata + update procedures. + * Implemented the CAP unicast audio start, stop and metadata update procedures. + * Implemented the Telephony and Media Audio Service (TMAS). + * Added additional validation for MCC and MCS, including opcodes, values, etc. + * Refactored and extended the scan delegator implementation, including + integration with broadcast sink. + * Added support for creating a broadcast sink from a PA sink. + * Added support for optional characteristics in CSIP. + * Implemented discovery by UUID instead of reading by UUID for multiple + characteristics. + * Added support for long reads and writes for multiple profiles. + * Added support for long BAP ASE notifications and optimized long notify + reads. + * Offloaded MCS notifications to the system workqueue. + * Added the CAP initiator cancel procedure. + * Direction Finding * Host + * Updated the Host to the v5.4 specification. + * The GATT DB Hash is now recalculated upon loading settings. + * Added experimental support for SMP keypress notifications. + * Downgraded the severity of select log messages to avoid log flooding. + * Separated the handling of LE SC OOB pairing from the legacy OOB logic. + * Implemented the Encrypted Advertising Data feature. + * Added support for the new Periodic Advertising with Responses (PAwR), both + as an advertiser and as a scanner. + * Added support for initiating connections from PAwR, as well as receiving + connections while synced. + * Clarified the behavior that is enabled by the ``BT_PRIVACY`` Kconfig option. + * Introduced a new ``seg_recv`` L2CAP API for an application to receive + segments directly and manage credits explicitly. + * Mesh - * Added experimental support for Mesh Protocol d1.1r18 specification. + * Added experimental support for Mesh Protocol d1.1r18 specification, gated + by a new configuration option. This includes: + + * Enhanced Provisioning Authentication support. + * Mesh Remote Provisioning support including: + * Remote Provisioning Server and Client models. + * Composition Data Page 128 and Models Metadata Page 128 support. + * Large Composition Data support including: + * Large Composition Data Server and Client models. + * Models Metadata Page 0 support. + * New Transport Segmentation and Reassembly (SAR) implementation including: + * SAR Configuration Server and Client models. + * Mesh Private Beacons support including: + * Mesh Private Beacon Server and Client models. + * Opcodes Aggregator support including: + * Opcodes Aggregator Server and Client models. + * Proxy Solicitation support including: + * Solicitation PDU RPL Configuration Server and Client models. + * On-Demand Private Proxy Server and Client models. + * Composition Data Page 1 support. + * Other Mesh Profile Enhancements. * Added experimental support for Mesh Binary Large Object Transfer Model d1.0r04_PRr00 specification. * Added experimental support for Mesh Device Firmware Update Model d1.0r04_PRr00 specification. + * Fixed multiple profile errata. + * Added experimental support for the PSA crypto APIs. + * Added a new work queue to store mesh settings, including a new API for + storing user data. + * Disabled the models initialization macros for C++ as they use the compound + literal feature from C99. + * Deprecated Health Client and Configuration Client API have been removed. * Controller + * Implemented support for the central with multiple CIS usecase. + * Implemented support for multiple peripheral CIS establishment. + * Updated the Controller to the v5.4 specification. + * Added support for coexistence with other transceivers. + * Added support for multiple CIS/CIG setup/connect and teardown procedures in + sequence. + * Extended the ticker API to return expiration info. + * Re-implemented Extended and Periodic Advertising, as well as and Broadcast + ISO, using the new ticket expiration info feature. + * Modified the ticker implementation to reschedule unreserved tickers that use + ``ticks_slot_window``. Implement continuous scanning with it. + * Added support for considering the SDU interval, along with the packet + sequence number and time stamps, in SDU fragmentation. + * Added a new ``BT_CTRL_TX_PWR_DBM`` option to set the TX power directly in + dBm. + * Optimized the RX path with support for piggy-backing notifications on + already-allocated RX nodes. + * HCI Driver Boards & SoC Support From f6d7a6a7018462cd92a96b91ad2a205935bc5e13 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 13 Jun 2023 11:30:42 +0200 Subject: [PATCH 0130/2042] release-notes: v3.4: Document STM32 changes Document STM32 related changes on V3.4 release. Signed-off-by: Erwan Gouriou --- doc/releases/release-notes-3.4.rst | 84 ++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index bc3905557e5b..ad5dda84b59d 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -210,6 +210,11 @@ Deprecated in this release * Deprecated :c:macro:`PTHREAD_BARRIER_DEFINE` in favor of the standardized :c:func:`pthread_barrier_init` +* On all STM32 targets except STM32F2 series, ethernet drivers implementation + based on STM32Cube Ethernet API V1 (:kconfig:option:`CONFIG_ETH_STM32_HAL_API_V1`) + is now deprecated in favor of implementation based on more reliable and performant + STM32Cube Ethernet API V2. + Stable API changes in this release ================================== @@ -429,6 +434,10 @@ Boards & SoC Support * Added support for these SoC series: + * STM32C0 series are now supported (with introduction of STM32C031 SoC). + * STM32H5 series are now supported (with introduction of STM32H503 and STM32H573 SoCs). + * Added support for STM32U599 SoC variants + * Removed support for these SoC series: * Made these changes in other SoC series: @@ -437,7 +446,12 @@ Boards & SoC Support * Added support for these ARM boards: + * Alientek STM32L475 Pandora + * MXChip AZ3166 IoT DevKit * Seeed Studio Wio Terminal + * ST Nucleo C031C6 + * ST Nucleo H563ZI + * ST STM32H573I-DK Discovery * Added support for these ARM64 boards: @@ -463,6 +477,7 @@ Boards & SoC Support * ``nrf9160dk_nrf52840``: Enabled external_flash_pins_routing switch by default. * ``nrf9160dk_nrf9160``: Changed the order of buttons and switches on the GPIO expander to match the order when using GPIO directly on the nRF9160 SoC. + * ``STM32H747i_disco``: Enabled support for ST B-LCD40-DSI1 display extension * Made these changes for ARM64 boards: @@ -630,6 +645,14 @@ Drivers and Sensors were shifted to match the hardware as described in reference manual instead of matching the NXP SDK enum identifers. + * Added support for STM32C0 and STM32H5. + + * Added DMA support for STM32H7. + + * STM32: Resolutions are now listed in the device tree for each ADC instance + + * STM32: Sampling times are now listed in the device tree for each ADC instance + * Battery-backed RAM * Added MCP7940N battery-backed RTC SRAM driver. @@ -653,10 +676,13 @@ Drivers and Sensors * Refactored the Bosch M_CAN controller driver backend to allow for per-instance configuration via devicetree. + * Now supports STM32H5 series. + * Clock control * Atmel SAM/SAM0: Introduce peripheral clock control. * Atmel SAM0: Improved ``samd20``/``samd21``/``samr21`` clocking mechanism. + * STM32F4: Added support for PLL I2S * Console: @@ -665,24 +691,39 @@ Drivers and Sensors * Counter + * Added support on timer based counter on STM32H7 and STM32H5 + * Added support on RTC based counter on STM32C0 and STM32H5 + * Crypto + * Added support for STM32H5 AES + * DAC + * Added support on STM32H5 series. + * DFU * Disk + * SDMMC STM32L4+: Now compatible with internal DMA + * Display * DMA + * STM32C0: Added support for DMA + * STM32H5: Added support for GPDMA + * STM32H7: Added support for BDMA + * EEPROM * Switched from :dtcompatible:`atmel,at24` to dedicated :dtcompatible:`zephyr,i2c-target-eeprom` for I2C EEPROM target driver. * Entropy + * Added support for STM32H5 series. + * ESPI * Ethernet @@ -696,6 +737,8 @@ Drivers and Sensors selected by the driver to indicate that extra operations are supported. To enable extra operations user should select :kconfig:option:`CONFIG_FLASH_EX_OP_ENABLED`. + * STM32F4: Now supports write protection and readout protection through + new flash API call :c:func:`flash_ex_op`. * nrf_qspi_nor: Replaced custom API function ``nrf_qspi_nor_base_clock_div_force`` with ``nrf_qspi_nor_xip_enable`` which apart from forcing the clock divider prevents the driver from deactivating the QSPI peripheral so that the XIP @@ -711,6 +754,7 @@ Drivers and Sensors * spi_flash_at45: Fixed erase procedure to properly handle chips that have their initial sector split into two parts (usually marked as 0a and 0b). + * STM32H5 now supports OSPI * FPGA @@ -720,12 +764,19 @@ Drivers and Sensors * Converted the ``gpio_keys`` driver to the input subsystem. + * STM32: Supports newly introduced experimental API to enable/disable interrupts + without re-config + * hwinfo * I2C + * Added support for STM32C0 and STM32H5 series + * I2S + * STM32: Domain clock should now be configured by device tree. + * I3C * IEEE 802.15.4 @@ -749,6 +800,10 @@ Drivers and Sensors * MEMC +* MIPI-DSI + + * Added support on STM32H7 + * PCIE * Enable filtering PCIe devices by class/revision. @@ -768,6 +823,9 @@ Drivers and Sensors * PWM + * Added support for STM32C0. + * STM32: Now supports 6-PWM channels + * Power domain * Regulators @@ -786,6 +844,14 @@ Drivers and Sensors * Sensor + * Added generic voltage measurement sample + * Removed STM32 Vbat measurement sample (replaced by a generic one) + * Added STM32 Vref sensor driver + * Added STM32 Vref/Vbat measurement through the new generic voltage measurement sample + * Added temperature measurement driver for STM32C0 and STM32F0x0 + * Removed STM32 temperature measurement sample (replaced by a generic one) + * Added STM32 temperature measurement through the generic temperature measurement sample + * Serial * Add UART3 and UART4 configuration for ``gd32vf103`` SoCs. @@ -805,14 +871,22 @@ Drivers and Sensors * uart_rpi_pico_pio: added new driver to support UART via Programmable Input/Output (PIO) on Raspberry Pi Pico. * uart_xmc4xxx: added support for asynchronous operations. + * uart_stm32: Now support driver enable mode * SPI + * Added support on STM32H5 series. + * Timer * Support added for stopping Nordic nRF RTC system timer, which fixes an issue when booting applications built in prior version of Zephyr. + * STM32: Now supports a prescaler at the input of clock (default not divided). + Prescaler allows to achieve higher LPTIM timeout (up to 256s when lptim clocked by LSE) + and consequently higher core sleep durations but impacts the tick precision. + To be used with caution. + * USB * W1 @@ -824,6 +898,8 @@ Drivers and Sensors * Watchdog + * Added support for STM32C0 and STM32H5 series + * WiFi Networking @@ -968,6 +1044,14 @@ Libraries / Subsystems HALs **** +* STM32 + + * stm32cube: updated STM32F0 to cube version V1.11.4. + * stm32cube: updated STM32F3 to cube version V1.11.4 + * stm32cube: updated STM32L0 to cube version V1.12.2 + * stm32cube: updated STM32U5 to cube version V1.2.0 + * stm32cube: updated STM32WB to cube version V1.16.0 + MCUboot ******* From 523ba79d54cef2f7b55157ce61f041c6fb9990c2 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 13 Jun 2023 11:38:09 +0200 Subject: [PATCH 0131/2042] release-notes: v3.4: Document shield additions Document shields added in V3.4 release Signed-off-by: Erwan Gouriou --- doc/releases/release-notes-3.4.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index ad5dda84b59d..8c6e2b4b452d 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -518,6 +518,11 @@ Boards & SoC Support * Added support for these following shields: + * Adafruit Data Logger Shield + * nPM1300 EK (Power Management Integrated Circuit (PMIC)) + * Panasonic Grid-EYE Shields + * ST B_LCD40_DSI1_MB1166 + Build system and infrastructure ******************************* From 503b3672aa82c12dd2ffd83c7815a6e0e41be35a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 2 Mar 2023 12:57:05 +0000 Subject: [PATCH 0132/2042] doc: release: 3.4: Bulk of updates Add release notes on: - change in west sign internal logic; - additional LittleFS sample configuration for nrf52840dk_nrf52840 using SPI communication; Signed-off-by: Dominik Ermel --- doc/releases/release-notes-3.4.rst | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 8c6e2b4b452d..c4eaf882ff43 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -619,6 +619,26 @@ Build system and infrastructure * Babblesim is now included in the west manifest. Users can fetch it by enabling the ``babblesim`` group with west config. +* `west sign` now uses DT labels, of "fixed-partition" compatible nodes, to identify + application image slots, instead of previously used DT node label properties. + If you have been using custom partition layout for MCUboot, you will have to label + your MCUboot slot partitions with proper DT node labels; for example partition + with "image-0" label property will have to be given slot0_partition DT node label. + Label property does not have to be removed from partition node, but will not be used. + + DT node labels used are listed below + + .. table:: + :align: center + + +---------------------------------+---------------------------+ + | Partition with label property | Required DT node label | + +=================================+===========================+ + | "image-0" | slot0_partition | + +---------------------------------+---------------------------+ + | "image-1" | slot1_partition | + +---------------------------------+---------------------------+ + Drivers and Sensors ******************* @@ -1098,8 +1118,8 @@ Tests and Samples * Two Babblesim based networking (802.15.4) tests have been added, which are run in Zephyr's CI system. One of them including the OpenThread stack. - * For native_posix and the nrf52_bsim: Many tests have been fixed and enabled. +* LittleFS sample has been given SPI example configuration for nrf52840dk_nrf52840. Issue Related Items ******************* From cd3e1438ec2f3505965bb00007e2b1272e1023c0 Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Thu, 8 Jun 2023 20:18:35 +0300 Subject: [PATCH 0133/2042] doc: Added RP2040 related changes to the v3.4.0 release notes Added RP2040 related changes to the v3.4.0 release notes, including new boards, new drivers and HAL changes. Signed-off-by: Yonatan Schachter --- doc/releases/release-notes-3.4.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index c4eaf882ff43..c60a50249fc5 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -452,6 +452,7 @@ Boards & SoC Support * ST Nucleo C031C6 * ST Nucleo H563ZI * ST STM32H573I-DK Discovery + * Raspberry Pi Pico W * Added support for these ARM64 boards: @@ -740,6 +741,7 @@ Drivers and Sensors * STM32C0: Added support for DMA * STM32H5: Added support for GPDMA * STM32H7: Added support for BDMA + * Added DMA support for the RP2040 SoC * EEPROM @@ -788,6 +790,7 @@ Drivers and Sensors * GPIO * Converted the ``gpio_keys`` driver to the input subsystem. + * Added single-ended IO support for the RP2040 SoC * STM32: Supports newly introduced experimental API to enable/disable interrupts without re-config @@ -829,6 +832,10 @@ Drivers and Sensors * Added support on STM32H7 +* Misc + + * Added PIO support for the RP2040 SoC + * PCIE * Enable filtering PCIe devices by class/revision. @@ -897,6 +904,7 @@ Drivers and Sensors Programmable Input/Output (PIO) on Raspberry Pi Pico. * uart_xmc4xxx: added support for asynchronous operations. * uart_stm32: Now support driver enable mode + * Added hardware flow control support for the RP2040 SoC * SPI @@ -914,6 +922,8 @@ Drivers and Sensors * USB + * Added remote wakeup support for the RP2040 SoC + * W1 * Added DS2482-800 1-Wire master driver. See the :dtcompatible:`maxim,ds2482-800` @@ -1077,6 +1087,10 @@ HALs * stm32cube: updated STM32U5 to cube version V1.2.0 * stm32cube: updated STM32WB to cube version V1.16.0 +* Raspberry Pi Pico + + * Updated hal_rpi_pico to version 1.5.0 + MCUboot ******* From c1bb577f28fe98f0a655e75540cca27cfccd37c0 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 10 Jun 2023 01:05:31 +0000 Subject: [PATCH 0134/2042] samples: bluetooth: remove duplicate entry in test Also remove platforms where we overflow on RAM. Signed-off-by: Anas Nashif --- samples/bluetooth/hci_uart/sample.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/samples/bluetooth/hci_uart/sample.yaml b/samples/bluetooth/hci_uart/sample.yaml index 2e41621cccc8..c24ae0f68f53 100644 --- a/samples/bluetooth/hci_uart/sample.yaml +++ b/samples/bluetooth/hci_uart/sample.yaml @@ -2,21 +2,9 @@ sample: name: Bluetooth HCI UART description: Allows Zephyr to provide Bluetooth connectivity via UART tests: - sample.bluetooth.hci_uart.arm: - harness: bluetooth - platform_allow: - - 96b_nitrogen - - nrf51dk_nrf51422 - - nrf52dk_nrf52832 - - bbc_microbit - tags: - - uart - - bluetooth sample.bluetooth.hci_uart.nrf5: harness: bluetooth platform_allow: - - 96b_nitrogen - - nrf51dk_nrf51422 - nrf52dk_nrf52832 tags: - uart From b835b0213631bf1a4323c73f1a8ff8d24f64ed58 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 9 Jun 2023 12:30:46 +0000 Subject: [PATCH 0135/2042] tests: cleanup metadata and filtering - Add integration_platforms to avoid excessive filtering - Make sure integration platforms are actually part of the filter - Fix some tags and test meta data Signed-off-by: Anas Nashif --- .../arm/mimxrt685_evk/mimxrt685_evk_cm33.yaml | 1 + samples/arch/smp/pktqueue/sample.yaml | 2 + samples/basic/button/sample.yaml | 2 + samples/basic/fade_led/sample.yaml | 2 + samples/basic/rgb_led/sample.yaml | 6 ++- samples/basic/servo_motor/sample.yaml | 2 + samples/basic/threads/sample.yaml | 2 + .../stm32/power_mgmt/blinky/sample.yaml | 2 + samples/drivers/auxdisplay/sample.yaml | 2 + samples/drivers/can/babbling/sample.yaml | 2 + samples/drivers/can/counter/sample.yaml | 2 + samples/drivers/clock_control_xec/sample.yaml | 1 - samples/drivers/crypto/sample.yaml | 2 + samples/drivers/dac/sample.yaml | 2 + samples/drivers/flash_shell/sample.yaml | 2 + samples/drivers/led_ws2812/sample.yaml | 2 + samples/drivers/ps2/sample.yaml | 2 + .../tflite-micro/magic_wand/sample.yaml | 2 + .../modules/thrift/hello/client/sample.yaml | 2 + .../modules/thrift/hello/server/sample.yaml | 2 + samples/net/dsa/sample.yaml | 7 ++-- samples/net/stats/sample.yaml | 2 + samples/sensor/proximity_polling/sample.yaml | 3 +- samples/subsys/debug/gdbstub/sample.yaml | 4 +- samples/subsys/logging/dictionary/sample.yaml | 8 ---- samples/subsys/logging/syst/sample.yaml | 18 -------- samples/subsys/nvs/sample.yaml | 4 +- samples/subsys/tracing/sample.yaml | 2 + samples/subsys/zbus/dyn_channel/sample.yaml | 3 ++ samples/subsys/zbus/hello_world/sample.yaml | 2 + .../zbus/runtime_obs_registration/sample.yaml | 2 + samples/subsys/zbus/work_queue/sample.yaml | 2 + .../arm_irq_zero_latency_levels/testcase.yaml | 4 ++ .../arm/arm_sw_vector_relay/testcase.yaml | 5 ++- .../arch/arm/arm_thread_swap_tz/testcase.yaml | 4 ++ tests/arch/arm/arm_tz_wrap_func/testcase.yaml | 2 + tests/benchmarks/app_kernel/testcase.yaml | 1 - tests/crypto/rand32/testcase.yaml | 12 +++++- tests/drivers/build_all/pwm/prj.conf | 2 - tests/drivers/flash/common/testcase.yaml | 2 + tests/kernel/context/testcase.yaml | 1 + tests/kernel/fatal/exception/testcase.yaml | 6 +++ .../kernel/fpu_sharing/generic/testcase.yaml | 2 + .../kernel/mem_protect/mem_map/testcase.yaml | 9 +++- tests/kernel/mp/testcase.yaml | 2 + tests/kernel/spinlock/testcase.yaml | 5 ++- tests/kernel/workq/critical/testcase.yaml | 4 ++ tests/lib/cbprintf_package/testcase.yaml | 42 ++++++++++++++++++- tests/misc/print_format/testcase.yaml | 1 - .../logging/log_backend_init/testcase.yaml | 2 +- .../logging/log_switch_format/testcase.yaml | 6 --- tests/ztest/base/testcase.yaml | 2 +- 52 files changed, 156 insertions(+), 57 deletions(-) diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.yaml b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.yaml index 69904945e3d7..21aaa88535b7 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.yaml +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.yaml @@ -21,6 +21,7 @@ supported: - arduino_spi - counter - dma + - pwm - gpio - hwinfo - i2c diff --git a/samples/arch/smp/pktqueue/sample.yaml b/samples/arch/smp/pktqueue/sample.yaml index 65f9a6f01601..685de5cfd8f4 100644 --- a/samples/arch/smp/pktqueue/sample.yaml +++ b/samples/arch/smp/pktqueue/sample.yaml @@ -26,3 +26,5 @@ tests: - m5stickc_plus - odroid_go - olimex_esp32_evb + integration_platforms: + - qemu_x86_64 diff --git a/samples/basic/button/sample.yaml b/samples/basic/button/sample.yaml index d4d7372a265e..b0c748d6be25 100644 --- a/samples/basic/button/sample.yaml +++ b/samples/basic/button/sample.yaml @@ -6,5 +6,7 @@ tests: - button - gpio filter: dt_enabled_alias_with_parent_compat("sw0", "gpio-keys") + integration_platforms: + - nrf52833dk_nrf52820 depends_on: gpio harness: button diff --git a/samples/basic/fade_led/sample.yaml b/samples/basic/fade_led/sample.yaml index 0a00957a1444..f141f4abfc35 100644 --- a/samples/basic/fade_led/sample.yaml +++ b/samples/basic/fade_led/sample.yaml @@ -8,3 +8,5 @@ tests: depends_on: pwm harness: led filter: dt_alias_exists("pwm-led0") and dt_compat_enabled("pwm-leds") + integration_platforms: + - nrf51dk_nrf51422 diff --git a/samples/basic/rgb_led/sample.yaml b/samples/basic/rgb_led/sample.yaml index fb354ce5ae2a..e45dda1a1b15 100644 --- a/samples/basic/rgb_led/sample.yaml +++ b/samples/basic/rgb_led/sample.yaml @@ -2,10 +2,12 @@ sample: name: RGB LED tests: sample.basic.rgb_led: - filter: dt_alias_exists("red-pwm-led") and dt_alias_exists("green-pwm-led") and - dt_alias_exists("blue-pwm-led") + filter: dt_alias_exists("red-pwm-led") and dt_alias_exists("green-pwm-led") + and dt_alias_exists("blue-pwm-led") tags: - drivers - pwm depends_on: pwm harness: led + integration_platforms: + - nrf52840_mdk diff --git a/samples/basic/servo_motor/sample.yaml b/samples/basic/servo_motor/sample.yaml index 955c77f42dba..08eda429f0f6 100644 --- a/samples/basic/servo_motor/sample.yaml +++ b/samples/basic/servo_motor/sample.yaml @@ -8,3 +8,5 @@ tests: depends_on: pwm harness: motor filter: dt_compat_enabled("pwm-servo") + integration_platforms: + - bbc_microbit diff --git a/samples/basic/threads/sample.yaml b/samples/basic/threads/sample.yaml index 0e4446733b86..d76669c9263d 100644 --- a/samples/basic/threads/sample.yaml +++ b/samples/basic/threads/sample.yaml @@ -9,6 +9,8 @@ tests: - gpio filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and dt_enabled_alias_with_parent_compat("led1", "gpio-leds") + integration_platforms: + - nrf52833dk_nrf52820 depends_on: gpio harness: console harness_config: diff --git a/samples/boards/stm32/power_mgmt/blinky/sample.yaml b/samples/boards/stm32/power_mgmt/blinky/sample.yaml index 3e9acdc21d0b..103f204a189d 100644 --- a/samples/boards/stm32/power_mgmt/blinky/sample.yaml +++ b/samples/boards/stm32/power_mgmt/blinky/sample.yaml @@ -14,3 +14,5 @@ tests: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and dt_compat_enabled("st,stm32-lptim") extra_args: "CONFIG_DEBUG=y" + integration_platforms: + - nucleo_wb55rg diff --git a/samples/drivers/auxdisplay/sample.yaml b/samples/drivers/auxdisplay/sample.yaml index ea40db195e34..33d7c88412fe 100644 --- a/samples/drivers/auxdisplay/sample.yaml +++ b/samples/drivers/auxdisplay/sample.yaml @@ -5,3 +5,5 @@ tests: sample.drivers.auxdisplay: tags: auxdisplay platform_allow: nucleo_f746zg + integration_platforms: + - nucleo_f746zg diff --git a/samples/drivers/can/babbling/sample.yaml b/samples/drivers/can/babbling/sample.yaml index f34f523ec5e0..8a52e4f59cbe 100644 --- a/samples/drivers/can/babbling/sample.yaml +++ b/samples/drivers/can/babbling/sample.yaml @@ -5,6 +5,8 @@ tests: tags: can depends_on: can filter: dt_chosen_enabled("zephyr,canbus") + integration_platforms: + - native_posix harness: console harness_config: type: one_line diff --git a/samples/drivers/can/counter/sample.yaml b/samples/drivers/can/counter/sample.yaml index f220df376e37..20f609d0c367 100644 --- a/samples/drivers/can/counter/sample.yaml +++ b/samples/drivers/can/counter/sample.yaml @@ -4,6 +4,8 @@ tests: sample.drivers.can.counter: tags: can depends_on: can + integration_platforms: + - native_posix filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") harness: console harness_config: diff --git a/samples/drivers/clock_control_xec/sample.yaml b/samples/drivers/clock_control_xec/sample.yaml index 67e21be4ee20..d2977fa49b2a 100644 --- a/samples/drivers/clock_control_xec/sample.yaml +++ b/samples/drivers/clock_control_xec/sample.yaml @@ -3,7 +3,6 @@ sample: name: XEC clock control sample tests: sample.drivers.clock_control_xec: - build_only: true tags: clock_control platform_allow: - mec172xevb_assy6906 diff --git a/samples/drivers/crypto/sample.yaml b/samples/drivers/crypto/sample.yaml index 25c6d8e0bd67..9712990b4d92 100644 --- a/samples/drivers/crypto/sample.yaml +++ b/samples/drivers/crypto/sample.yaml @@ -38,6 +38,8 @@ tests: tags: crypto filter: dt_compat_enabled("st,stm32-aes") or dt_compat_enabled("st,stm32-cryp") extra_args: CONF_FILE=prj_stm32.conf + integration_platforms: + - stm32l562e_dk harness: console harness_config: type: multi_line diff --git a/samples/drivers/dac/sample.yaml b/samples/drivers/dac/sample.yaml index fe2b38e8a452..902371a18053 100644 --- a/samples/drivers/dac/sample.yaml +++ b/samples/drivers/dac/sample.yaml @@ -42,6 +42,8 @@ tests: - stm32l562e_dk - twr_ke18f depends_on: dac + integration_platforms: + - nucleo_l152re harness: console harness_config: type: one_line diff --git a/samples/drivers/flash_shell/sample.yaml b/samples/drivers/flash_shell/sample.yaml index d914358dd15a..2734a63c7dec 100644 --- a/samples/drivers/flash_shell/sample.yaml +++ b/samples/drivers/flash_shell/sample.yaml @@ -15,3 +15,5 @@ tests: - arduino_giga_r1_m4 harness: keyboard min_ram: 12 + integration_platforms: + - qemu_x86 diff --git a/samples/drivers/led_ws2812/sample.yaml b/samples/drivers/led_ws2812/sample.yaml index d2673b6c45d9..3add7297b331 100644 --- a/samples/drivers/led_ws2812/sample.yaml +++ b/samples/drivers/led_ws2812/sample.yaml @@ -7,3 +7,5 @@ tests: filter: dt_compat_enabled("worldsemi,ws2812-spi") harness_config: fixture: fixture_led_ws2812 + integration_platforms: + - mimxrt1050_evk diff --git a/samples/drivers/ps2/sample.yaml b/samples/drivers/ps2/sample.yaml index 82e105a0c0e3..334d59bda685 100644 --- a/samples/drivers/ps2/sample.yaml +++ b/samples/drivers/ps2/sample.yaml @@ -5,6 +5,8 @@ tests: tags: - drivers - ps2 + integration_platforms: + - mec172xmodular_assy6930 harness: console harness_config: type: multi_line diff --git a/samples/modules/tflite-micro/magic_wand/sample.yaml b/samples/modules/tflite-micro/magic_wand/sample.yaml index d65a61ee2f70..b67a9f9dea94 100644 --- a/samples/modules/tflite-micro/magic_wand/sample.yaml +++ b/samples/modules/tflite-micro/magic_wand/sample.yaml @@ -6,5 +6,7 @@ tests: platform_allow: litex_vexriscv build_only: true tags: tensorflow + integration_platforms: + - litex_vexriscv modules: - tflite-micro diff --git a/samples/modules/thrift/hello/client/sample.yaml b/samples/modules/thrift/hello/client/sample.yaml index bfdeb2e0bbaf..64ba41fe5e13 100644 --- a/samples/modules/thrift/hello/client/sample.yaml +++ b/samples/modules/thrift/hello/client/sample.yaml @@ -12,6 +12,8 @@ common: platform_allow: - mps2_an385 - qemu_x86_64 + integration_platforms: + - qemu_x86_64 filter: CONFIG_FULL_LIBCPP_SUPPORTED tests: sample.thrift.hello.client.binaryProtocol: {} diff --git a/samples/modules/thrift/hello/server/sample.yaml b/samples/modules/thrift/hello/server/sample.yaml index b4dbfed93aad..16b70a6b7103 100644 --- a/samples/modules/thrift/hello/server/sample.yaml +++ b/samples/modules/thrift/hello/server/sample.yaml @@ -12,6 +12,8 @@ common: platform_allow: - mps2_an385 - qemu_x86_64 + integration_platforms: + - qemu_x86_64 filter: CONFIG_FULL_LIBCPP_SUPPORTED tests: sample.thrift.hello.server.binaryProtocol: {} diff --git a/samples/net/dsa/sample.yaml b/samples/net/dsa/sample.yaml index 4de332936a32..fd4d4c3c867a 100644 --- a/samples/net/dsa/sample.yaml +++ b/samples/net/dsa/sample.yaml @@ -1,14 +1,13 @@ +sample: + description: Test DSA functionality + name: DSA sample app common: harness: net tags: - net - dsa -sample: - description: Test DSA functionality - name: DSA sample app tests: sample.net.dsa: build_only: true platform_allow: ip_k66f depends_on: netif - tags: tests diff --git a/samples/net/stats/sample.yaml b/samples/net/stats/sample.yaml index 0aacd87bde98..8ef6e3657f0d 100644 --- a/samples/net/stats/sample.yaml +++ b/samples/net/stats/sample.yaml @@ -9,3 +9,5 @@ tests: - net - statistics depends_on: netif + integration_platforms: + - qemu_x86 diff --git a/samples/sensor/proximity_polling/sample.yaml b/samples/sensor/proximity_polling/sample.yaml index b29235043dbb..8a5d8bb93071 100644 --- a/samples/sensor/proximity_polling/sample.yaml +++ b/samples/sensor/proximity_polling/sample.yaml @@ -8,5 +8,4 @@ tests: - proximity filter: dt_alias_exists("prox-sensor0") integration_platforms: - - "reel_board_v2" # PHYTEC reel board v2 - - "reel_board" # PHYTEC reel board + - nrf52840dk_nrf52840 diff --git a/samples/subsys/debug/gdbstub/sample.yaml b/samples/subsys/debug/gdbstub/sample.yaml index 6709029d6f6a..5f75a8015412 100644 --- a/samples/subsys/debug/gdbstub/sample.yaml +++ b/samples/subsys/debug/gdbstub/sample.yaml @@ -10,4 +10,6 @@ tests: sample.debug.gdbstub: build_only: true platform_allow: qemu_x86 - tags: debug + tags: + - debug + - gdbstub diff --git a/samples/subsys/logging/dictionary/sample.yaml b/samples/subsys/logging/dictionary/sample.yaml index ad3a1315e647..e5cc1f3be743 100644 --- a/samples/subsys/logging/dictionary/sample.yaml +++ b/samples/subsys/logging/dictionary/sample.yaml @@ -8,8 +8,6 @@ tests: integration_platforms: - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 - - qemu_cortex_a53_smp sample.logger.basic.dictionary.fpu: build_only: true tags: logging @@ -19,8 +17,6 @@ tests: integration_platforms: - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 - - qemu_cortex_a53_smp sample.logger.basic.dictionary.fpu.long_double: build_only: true tags: logging @@ -31,8 +27,6 @@ tests: integration_platforms: - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 - - qemu_cortex_a53_smp sample.logger.basic.dictionary.uart_async_frontend: build_only: true tags: logging @@ -54,8 +48,6 @@ tests: integration_platforms: - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 - - qemu_cortex_a53_smp extra_configs: - CONFIG_LOG_BACKEND_UART=n - CONFIG_LOG_BACKEND_RTT=n diff --git a/samples/subsys/logging/syst/sample.yaml b/samples/subsys/logging/syst/sample.yaml index b0d148132b45..4501d5740e3b 100644 --- a/samples/subsys/logging/syst/sample.yaml +++ b/samples/subsys/logging/syst/sample.yaml @@ -17,8 +17,6 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 - - sam_e70_xplained - - qemu_cortex_a53 extra_args: OVERLAY_CONFIG=overlay_deferred.conf harness: console harness_config: @@ -39,10 +37,8 @@ tests: toolchain_exclude: xcc extra_args: OVERLAY_CONFIG=overlay_immediate.conf integration_platforms: - - mps2_an385 - qemu_x86 - sam_e70_xplained - - qemu_cortex_a53 harness: console harness_config: type: multi_line @@ -56,10 +52,8 @@ tests: toolchain_exclude: xcc extra_args: OVERLAY_CONFIG=overlay_deferred.conf integration_platforms: - - mps2_an385 - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 harness: console harness_config: type: one_line @@ -72,10 +66,8 @@ tests: sample.logger.syst.catalog.immediate: toolchain_exclude: xcc integration_platforms: - - mps2_an385 - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 harness: console harness_config: type: one_line @@ -89,11 +81,8 @@ tests: toolchain_exclude: xcc extra_args: OVERLAY_CONFIG=overlay_deferred.conf integration_platforms: - - mps2_an385 - qemu_x86 - qemu_x86_64 - - sam_e70_xplained - - qemu_cortex_a53 harness: console harness_config: type: one_line @@ -108,9 +97,6 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 - - qemu_x86_64 - - sam_e70_xplained - - qemu_cortex_a53 harness: console harness_config: type: one_line @@ -124,10 +110,8 @@ tests: toolchain_exclude: xcc extra_args: OVERLAY_CONFIG=overlay_deferred.conf integration_platforms: - - mps2_an385 - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 harness: console harness_config: type: one_line @@ -141,10 +125,8 @@ tests: sample.logger.syst.catalog.immediate_cpp: toolchain_exclude: xcc integration_platforms: - - mps2_an385 - qemu_x86 - qemu_x86_64 - - qemu_cortex_a53 harness: console harness_config: type: one_line diff --git a/samples/subsys/nvs/sample.yaml b/samples/subsys/nvs/sample.yaml index d8a7d6339afa..e2249e9f3eb0 100644 --- a/samples/subsys/nvs/sample.yaml +++ b/samples/subsys/nvs/sample.yaml @@ -3,9 +3,11 @@ sample: tests: sample.nvs.basic: - tags: settings + tags: nvs depends_on: nvs platform_exclude: qemu_x86 + integration_platforms: + - nrf52dk_nrf52832 harness: console harness_config: type: multi_line diff --git a/samples/subsys/tracing/sample.yaml b/samples/subsys/tracing/sample.yaml index a4487e51e3c2..3306ef65a164 100644 --- a/samples/subsys/tracing/sample.yaml +++ b/samples/subsys/tracing/sample.yaml @@ -11,6 +11,8 @@ common: tests: sample.tracing.user: extra_args: CONF_FILE="prj_user.conf" + integration_platforms: + - qemu_x86 sample.tracing.format.sysview: platform_allow: - nrf52840dk_nrf52840 diff --git a/samples/subsys/zbus/dyn_channel/sample.yaml b/samples/subsys/zbus/dyn_channel/sample.yaml index f299ac7c58ee..478516474f18 100644 --- a/samples/subsys/zbus/dyn_channel/sample.yaml +++ b/samples/subsys/zbus/dyn_channel/sample.yaml @@ -66,3 +66,6 @@ common: tests: sample.zbus.dyn_channel: tags: zbus + integration_platforms: + - qemu_x86 + - mps2_an521 diff --git a/samples/subsys/zbus/hello_world/sample.yaml b/samples/subsys/zbus/hello_world/sample.yaml index 89dd9a408dd3..35d40ed9fe25 100644 --- a/samples/subsys/zbus/hello_world/sample.yaml +++ b/samples/subsys/zbus/hello_world/sample.yaml @@ -30,6 +30,8 @@ tests: - xtensa platform_exclude: qemu_leon3 tags: zbus + integration_platforms: + - qemu_x86 sample.zbus.hello_world_no_iterable_sections: harness: console harness_config: diff --git a/samples/subsys/zbus/runtime_obs_registration/sample.yaml b/samples/subsys/zbus/runtime_obs_registration/sample.yaml index 21b50d620df0..823ed8cf17ba 100644 --- a/samples/subsys/zbus/runtime_obs_registration/sample.yaml +++ b/samples/subsys/zbus/runtime_obs_registration/sample.yaml @@ -3,6 +3,8 @@ sample: tests: sample.zbus.runtime_os_registration: min_ram: 16 + integration_platforms: + - qemu_x86 harness: console harness_config: type: multi_line diff --git a/samples/subsys/zbus/work_queue/sample.yaml b/samples/subsys/zbus/work_queue/sample.yaml index a9267f9f3551..64981c4c41a8 100644 --- a/samples/subsys/zbus/work_queue/sample.yaml +++ b/samples/subsys/zbus/work_queue/sample.yaml @@ -3,6 +3,8 @@ sample: common: tags: zbus harness: console + integration_platforms: + - qemu_x86 harness_config: type: multi_line ordered: false diff --git a/tests/arch/arm/arm_irq_zero_latency_levels/testcase.yaml b/tests/arch/arm/arm_irq_zero_latency_levels/testcase.yaml index 2b6bcbd92d6f..b2cd459d1d30 100644 --- a/tests/arch/arm/arm_irq_zero_latency_levels/testcase.yaml +++ b/tests/arch/arm/arm_irq_zero_latency_levels/testcase.yaml @@ -8,5 +8,9 @@ common: tests: arch.arm.irq_zero_latency_levels: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE + integration_platforms: + - mps2_an521_remote arch.arm.irq_zero_latency_levels.secure_fw: filter: CONFIG_TRUSTED_EXECUTION_SECURE + integration_platforms: + - mps2_an521 diff --git a/tests/arch/arm/arm_sw_vector_relay/testcase.yaml b/tests/arch/arm/arm_sw_vector_relay/testcase.yaml index d1397b6566d9..37433433d914 100644 --- a/tests/arch/arm/arm_sw_vector_relay/testcase.yaml +++ b/tests/arch/arm/arm_sw_vector_relay/testcase.yaml @@ -1,5 +1,8 @@ tests: arch.arm.sw_vector_relay: filter: CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE - tags: arm + tags: + - vector_relay arch_allow: arm + integration_platforms: + - mps2_an385 diff --git a/tests/arch/arm/arm_thread_swap_tz/testcase.yaml b/tests/arch/arm/arm_thread_swap_tz/testcase.yaml index ccc2eca105ef..f8bbbc8dd937 100644 --- a/tests/arch/arm/arm_thread_swap_tz/testcase.yaml +++ b/tests/arch/arm/arm_thread_swap_tz/testcase.yaml @@ -11,6 +11,8 @@ tests: platform_exclude: - mps3_an547_ns - nucleo_l552ze_q_ns + integration_platforms: + - mps2_an521_ns arch.arm.swap.tz_off: extra_configs: - CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS=n @@ -18,3 +20,5 @@ tests: platform_exclude: - mps3_an547_ns - nucleo_l552ze_q_ns + integration_platforms: + - mps2_an521_ns diff --git a/tests/arch/arm/arm_tz_wrap_func/testcase.yaml b/tests/arch/arm/arm_tz_wrap_func/testcase.yaml index 2cd1329421d5..ef0e1eda7dbd 100644 --- a/tests/arch/arm/arm_tz_wrap_func/testcase.yaml +++ b/tests/arch/arm/arm_tz_wrap_func/testcase.yaml @@ -6,3 +6,5 @@ tests: - tz_ns - tz_wrap_func filter: CONFIG_CPU_CORTEX_M + integration_platforms: + - mps2_an385 diff --git a/tests/benchmarks/app_kernel/testcase.yaml b/tests/benchmarks/app_kernel/testcase.yaml index e54ec1e2d3a2..085ec0a32dc2 100644 --- a/tests/benchmarks/app_kernel/testcase.yaml +++ b/tests/benchmarks/app_kernel/testcase.yaml @@ -25,7 +25,6 @@ tests: - llvm - oneApi integration_platforms: - - mps2_an385 - qemu_x86 benchmark.kernel.application.fp.x86.no_sse: extra_args: CONF_FILE=prj_fp.conf diff --git a/tests/crypto/rand32/testcase.yaml b/tests/crypto/rand32/testcase.yaml index 8d7348d3c0f5..c2fd12f069f9 100644 --- a/tests/crypto/rand32/testcase.yaml +++ b/tests/crypto/rand32/testcase.yaml @@ -3,21 +3,27 @@ common: - crypto - random - security - integration_platforms: - - qemu_x86 tests: crypto.rand32: min_ram: 16 + integration_platforms: + - qemu_x86 crypto.rand32.random_sw_systimer: extra_args: CONF_FILE=prj_sw_random_systimer.conf + integration_platforms: + - qemu_x86 crypto.rand32.random_hw_xoshiro: extra_args: CONF_FILE=prj_hw_random_xoshiro.conf filter: CONFIG_ENTROPY_HAS_DRIVER min_ram: 16 + integration_platforms: + - native_posix 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 drivers.rand32.random_psa_crypto: filter: CONFIG_BUILD_WITH_TFM extra_args: @@ -25,3 +31,5 @@ tests: - CONF_FILE=prj_hw_random_psa_crypto.conf tags: - psa-crypto + integration_platforms: + - nrf5340dk_nrf5340_cpuapp_ns diff --git a/tests/drivers/build_all/pwm/prj.conf b/tests/drivers/build_all/pwm/prj.conf index 9ef85cf462e9..346c909b60ce 100644 --- a/tests/drivers/build_all/pwm/prj.conf +++ b/tests/drivers/build_all/pwm/prj.conf @@ -1,3 +1 @@ -CONFIG_TEST=y -CONFIG_TEST_USERSPACE=y CONFIG_PWM=y diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 7172fc1559c5..942589ec3ece 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -38,6 +38,8 @@ tests: 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")) + integration_platforms: + - nrf9161dk_nrf9161_ns drivers.flash.mcux: platform_allow: - mimxrt1060_evk diff --git a/tests/kernel/context/testcase.yaml b/tests/kernel/context/testcase.yaml index 5fac722f4f2b..4baa4e7102b7 100644 --- a/tests/kernel/context/testcase.yaml +++ b/tests/kernel/context/testcase.yaml @@ -3,6 +3,7 @@ tests: tags: kernel extra_configs: - CONFIG_TEST_EXTRA_STACK_SIZE=1024 + min_ram: 16 kernel.context.linker_generator: platform_allow: qemu_cortex_m3 tags: diff --git a/tests/kernel/fatal/exception/testcase.yaml b/tests/kernel/fatal/exception/testcase.yaml index 8d87242ec316..c325a84166b9 100644 --- a/tests/kernel/fatal/exception/testcase.yaml +++ b/tests/kernel/fatal/exception/testcase.yaml @@ -23,6 +23,8 @@ tests: - fpu - kernel - userspace + integration_platforms: + - mps2_an385 kernel.common.stack_protection_armv8m_mpu_stack_guard: extra_args: CONF_FILE=prj_armv8m_mpu_stack_guard.conf filter: CONFIG_ARM_MPU and CONFIG_ARMV8_M_MAINLINE @@ -30,8 +32,12 @@ tests: tags: - kernel - userspace + integration_platforms: + - mps2_an385 kernel.common.stack_sentinel: extra_args: CONF_FILE=sentinel.conf # FIXME: See issue #39948 platform_exclude: qemu_cortex_a9 tags: kernel + integration_platforms: + - qemu_x86 diff --git a/tests/kernel/fpu_sharing/generic/testcase.yaml b/tests/kernel/fpu_sharing/generic/testcase.yaml index 80bee14cfd77..64a328455118 100644 --- a/tests/kernel/fpu_sharing/generic/testcase.yaml +++ b/tests/kernel/fpu_sharing/generic/testcase.yaml @@ -1,6 +1,7 @@ tests: kernel.fpu_sharing.generic.arc: extra_args: PI_NUM_ITERATIONS=500 + arch_allow: arc filter: CONFIG_ISA_ARCV2 and CONFIG_CPU_HAS_FPU slow: true tags: @@ -12,6 +13,7 @@ tests: extra_args: PI_NUM_ITERATIONS=70000 filter: CONFIG_ARMV7_M_ARMV8_M_FP or CONFIG_ARMV7_R_FP slow: true + arch_allow: arm tags: - fpu - kernel diff --git a/tests/kernel/mem_protect/mem_map/testcase.yaml b/tests/kernel/mem_protect/mem_map/testcase.yaml index 949e663d5b04..ff42310403be 100644 --- a/tests/kernel/mem_protect/mem_map/testcase.yaml +++ b/tests/kernel/mem_protect/mem_map/testcase.yaml @@ -9,13 +9,20 @@ tests: extra_sections: _TRANSPLANTED_FUNC extra_args: CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 platform_exclude: qemu_x86_64 + integration_platforms: + - qemu_x86 kernel.memory_protection.mem_map.x86_64: filter: CONFIG_MMU and CONFIG_X86_64 and not CONFIG_COVERAGE extra_sections: _TRANSPLANTED_FUNC + integration_platforms: + - qemu_x86_64 kernel.memory_protection.mem_map.x86_64.coverage: filter: CONFIG_MMU and CONFIG_X86_64 and CONFIG_COVERAGE extra_sections: _TRANSPLANTED_FUNC - extra_args: EXTRA_CFLAGS=-DSKIP_EXECUTE_TESTS + extra_args: + - EXTRA_CFLAGS=-DSKIP_EXECUTE_TESTS + extra_configs: + - CONFIG_COVERAGE=y platform_allow: qemu_x86_64 kernel.memory_protection.mem_map.x86_64.coverage.exec: filter: CONFIG_MMU and CONFIG_X86_64 and CONFIG_COVERAGE diff --git a/tests/kernel/mp/testcase.yaml b/tests/kernel/mp/testcase.yaml index 010587381c11..65c98f378d0d 100644 --- a/tests/kernel/mp/testcase.yaml +++ b/tests/kernel/mp/testcase.yaml @@ -4,3 +4,5 @@ tests: - kernel - smp filter: CONFIG_MP_MAX_NUM_CPUS > 1 + depends_on: + - smp diff --git a/tests/kernel/spinlock/testcase.yaml b/tests/kernel/spinlock/testcase.yaml index 087cfde36625..ed03f11cd379 100644 --- a/tests/kernel/spinlock/testcase.yaml +++ b/tests/kernel/spinlock/testcase.yaml @@ -4,5 +4,6 @@ tests: - kernel - smp - spinlock - filter: CONFIG_SMP and CONFIG_MP_MAX_NUM_CPUS > 1 and CONFIG_MP_MAX_NUM_CPUS <= - 4 + filter: CONFIG_SMP and CONFIG_MP_MAX_NUM_CPUS > 1 and CONFIG_MP_MAX_NUM_CPUS <= 4 + depends_on: + - smp diff --git a/tests/kernel/workq/critical/testcase.yaml b/tests/kernel/workq/critical/testcase.yaml index d87aaca4ce4b..822e6d2af99e 100644 --- a/tests/kernel/workq/critical/testcase.yaml +++ b/tests/kernel/workq/critical/testcase.yaml @@ -6,10 +6,14 @@ tests: kernel.workqueue.critical: platform_exclude: nsim_sem_mpu_stack_guard filter: not CONFIG_WDT_SAM + integration_platforms: + - qemu_x86 kernel.workqueue.critical.sam: filter: CONFIG_WDT_SAM extra_configs: - CONFIG_WDT_DISABLE_AT_BOOT=y + integration_platforms: + - sam_e70_xplained kernel.workqueue.critical.nsim: platform_allow: nsim_sem_mpu_stack_guard extra_configs: diff --git a/tests/lib/cbprintf_package/testcase.yaml b/tests/lib/cbprintf_package/testcase.yaml index d5145901f1d8..61654bc11878 100644 --- a/tests/lib/cbprintf_package/testcase.yaml +++ b/tests/lib/cbprintf_package/testcase.yaml @@ -3,18 +3,20 @@ common: - qemu - native tags: cbprintf - integration_platforms: - - native_posix min_flash: 48 tests: libraries.cbprintf_package: extra_configs: - CONFIG_CBPRINTF_COMPLETE=y + integration_platforms: + - native_posix libraries.cbprintf_package_no_generic: extra_configs: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" + integration_platforms: + - native_posix libraries.cbprintf_package_fp: filter: CONFIG_CPU_HAS_FPU @@ -22,6 +24,8 @@ tests: - CONFIG_CBPRINTF_FP_SUPPORT=y - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y + integration_platforms: + - native_posix libraries.cbprintf_package_fp_align_offset: filter: CONFIG_CPU_HAS_FPU @@ -30,6 +34,8 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y + integration_platforms: + - native_posix libraries.cbprintf_package_long_double: filter: CONFIG_CPU_HAS_FPU @@ -39,6 +45,8 @@ tests: - CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE=y - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y + integration_platforms: + - native_posix libraries.cbprintf_package_long_double_align_offset: filter: CONFIG_CPU_HAS_FPU @@ -49,22 +57,30 @@ tests: - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y + integration_platforms: + - native_posix libraries.cbprintf_package_nano: extra_configs: - CONFIG_CBPRINTF_NANO=y + integration_platforms: + - native_posix # Same test but with test compiled as C++ libraries.cbprintf_package_cpp: extra_configs: - CONFIG_CPP=y - CONFIG_CBPRINTF_COMPLETE=y + integration_platforms: + - native_posix libraries.cbprintf_package_no_generic_cpp: extra_configs: - CONFIG_CPP=y - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" + integration_platforms: + - native_posix libraries.cbprintf_package_fp_cpp: filter: CONFIG_CPU_HAS_FPU @@ -73,6 +89,8 @@ tests: - CONFIG_CBPRINTF_FP_SUPPORT=y - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y + integration_platforms: + - native_posix libraries.cbprintf_package_fp_align_offset_cpp: filter: CONFIG_CPU_HAS_FPU @@ -82,6 +100,8 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y + integration_platforms: + - native_posix libraries.cbprintf_package_long_double_cpp: filter: CONFIG_CPU_HAS_FPU @@ -92,6 +112,8 @@ tests: - CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE=y - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y + integration_platforms: + - native_posix libraries.cbprintf_package_long_double_align_offset_cpp: filter: CONFIG_CPU_HAS_FPU @@ -103,11 +125,15 @@ tests: - CONFIG_COMPILER_OPT="-DCBPRINTF_PACKAGE_ALIGN_OFFSET=1" - CONFIG_FPU=y - CONFIG_MINIMAL_LIBC=y + integration_platforms: + - native_posix libraries.cbprintf_package_nano_cpp: extra_configs: - CONFIG_CPP=y - CONFIG_CBPRINTF_NANO=y + integration_platforms: + - native_posix libraries.cbprintf_package.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED @@ -115,6 +141,8 @@ tests: extra_configs: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 libraries.cbprintf_package_no_generic.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED @@ -123,6 +151,8 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 libraries.cbprintf_package_fp.picolibc: filter: CONFIG_CPU_HAS_FPU and CONFIG_PICOLIBC_SUPPORTED @@ -132,6 +162,8 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 # Same test but with test compiled as C++ libraries.cbprintf_package_cpp.picolibc: @@ -141,6 +173,8 @@ tests: - CONFIG_CPP=y - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 libraries.cbprintf_package_no_generic_cpp.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED @@ -150,6 +184,8 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_COMPILER_OPT="-DZ_C_GENERIC=0" - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 libraries.cbprintf_package_fp_cpp.picolibc: filter: CONFIG_CPU_HAS_FPU and CONFIG_PICOLIBC_SUPPORTED @@ -160,3 +196,5 @@ tests: - CONFIG_CBPRINTF_COMPLETE=y - CONFIG_FPU=y - CONFIG_PICOLIBC=y + integration_platforms: + - qemu_x86 diff --git a/tests/misc/print_format/testcase.yaml b/tests/misc/print_format/testcase.yaml index 7f1299d6f061..9c4d4caedba1 100644 --- a/tests/misc/print_format/testcase.yaml +++ b/tests/misc/print_format/testcase.yaml @@ -1,6 +1,5 @@ common: integration_platforms: - - native_posix - qemu_x86 harness: console harness_config: diff --git a/tests/subsys/logging/log_backend_init/testcase.yaml b/tests/subsys/logging/log_backend_init/testcase.yaml index 8134a58eff90..a8f9144f7ec9 100644 --- a/tests/subsys/logging/log_backend_init/testcase.yaml +++ b/tests/subsys/logging/log_backend_init/testcase.yaml @@ -1,7 +1,7 @@ tests: logging.log_backend_initialization: integration_platforms: - - native_posix + - qemu_x86 tags: - log_core - logging diff --git a/tests/subsys/logging/log_switch_format/testcase.yaml b/tests/subsys/logging/log_switch_format/testcase.yaml index 28d193032f6f..bd0e3a4a0e1b 100644 --- a/tests/subsys/logging/log_switch_format/testcase.yaml +++ b/tests/subsys/logging/log_switch_format/testcase.yaml @@ -15,8 +15,6 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 - - sam_e70_xplained - - qemu_cortex_a53 extra_args: OVERLAY_CONFIG=overlay_deferred.conf # "CONFIG_FULL_LIBC_SUPPORTED" filter was applied # because of following chain of dependencies: @@ -32,8 +30,6 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 - - sam_e70_xplained - - qemu_cortex_a53 filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_REQUIRES_FULL_LIBC=y @@ -42,8 +38,6 @@ tests: integration_platforms: - mps2_an385 - qemu_x86 - - sam_e70_xplained - - qemu_cortex_a53 filter: CONFIG_FULL_LIBC_SUPPORTED extra_configs: - CONFIG_REQUIRES_FULL_LIBC=y diff --git a/tests/ztest/base/testcase.yaml b/tests/ztest/base/testcase.yaml index e4a289dc775d..4ac55a1dc555 100644 --- a/tests/ztest/base/testcase.yaml +++ b/tests/ztest/base/testcase.yaml @@ -19,7 +19,7 @@ tests: extra_configs: - CONFIG_TEST_USERSPACE=y integration_platforms: - - native_posix + - qemu_x86 testing.ztest.base.verbose_1: extra_args: CONF_FILE=prj_verbose_1.conf integration_platforms: From 5411e7d4a86f3e9e845c8519b85c283bb8214b01 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 10 Jun 2023 10:52:53 +0000 Subject: [PATCH 0136/2042] tests: synchronization: do not build on all Do not build on platforms, we have other tests covering this already. Signed-off-by: Anas Nashif --- samples/synchronization/sample.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/synchronization/sample.yaml b/samples/synchronization/sample.yaml index 4483d3d3e4e4..173bfe22ea72 100644 --- a/samples/synchronization/sample.yaml +++ b/samples/synchronization/sample.yaml @@ -4,7 +4,6 @@ sample: name: Synchronization Sample tests: sample.kernel.synchronization: - build_on_all: true tags: synchronization harness: console harness_config: From 8ffb08b10ea8d29ec9dbde7671978451ebd33b99 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 10 Jun 2023 10:54:26 +0000 Subject: [PATCH 0137/2042] tests: net: sockets: remove scneario This scneario does not build and does not fit on hardware, remove. Signed-off-by: Anas Nashif --- samples/net/sockets/echo_server/sample.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/net/sockets/echo_server/sample.yaml b/samples/net/sockets/echo_server/sample.yaml index ed4291bc67be..6c90fa6eee0c 100644 --- a/samples/net/sockets/echo_server/sample.yaml +++ b/samples/net/sockets/echo_server/sample.yaml @@ -24,9 +24,6 @@ tests: platform_allow: qemu_x86 integration_platforms: - qemu_x86 - sample.net.sockets.echo_server.802154.rf2xx: - extra_args: OVERLAY_CONFIG="overlay-802154.conf" - platform_allow: atsamr21_xpro sample.net.sockets.echo_server.802154.rf2xx.xplained: extra_args: - SHIELD=atmel_rf2xx_xplained From dd43a655408d15f999063b1587734ba57a4472a4 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Sat, 10 Jun 2023 00:36:42 +0000 Subject: [PATCH 0138/2042] samples: watchdog: fix twister filter Fix devicetree filter. dt_has_compat is not a twister support filter. Signed-off-by: Anas Nashif --- samples/drivers/watchdog/sample.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/drivers/watchdog/sample.yaml b/samples/drivers/watchdog/sample.yaml index dda9cdb263b6..d9c908d536d4 100644 --- a/samples/drivers/watchdog/sample.yaml +++ b/samples/drivers/watchdog/sample.yaml @@ -70,7 +70,7 @@ tests: integration_platforms: - nucleo_f103rb sample.drivers.watchdog.gd32_fwdgt: - filter: dt_has_compat("gd,gd32-fwdgt") + filter: dt_compat_enabled("gd,gd32-fwdgt") extra_args: DTC_OVERLAY_FILE=boards/gd32_fwdgt.overlay platform_allow: - gd32e103v_eval @@ -86,7 +86,7 @@ tests: integration_platforms: - gd32e103v_eval sample.drivers.watchdog.gd32_wwdgt: - filter: dt_has_compat("gd,gd32-wwdgt") + filter: dt_compat_enabled("gd,gd32-wwdgt") extra_args: DTC_OVERLAY_FILE=boards/gd32_wwdgt.overlay platform_allow: - gd32e103v_eval From 9f37ae902bf30580b32b567c8f95d4b54bfac186 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 25 May 2023 09:46:27 +0000 Subject: [PATCH 0139/2042] tests/samples: set ram/rom limits on some samples/tests Increase RAM requirements for some test, we have many exotic platforms failing to link due to the size of the test. Signed-off-by: Anas Nashif --- samples/philosophers/sample.yaml | 1 + tests/kernel/common/testcase.yaml | 3 ++- tests/subsys/logging/log_api/testcase.yaml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/philosophers/sample.yaml b/samples/philosophers/sample.yaml index 5bba6207cd4f..d072f2c68878 100644 --- a/samples/philosophers/sample.yaml +++ b/samples/philosophers/sample.yaml @@ -6,6 +6,7 @@ common: - inroduction - kernel harness: console + min_ram: 16 integration_platforms: - native_posix harness_config: diff --git a/tests/kernel/common/testcase.yaml b/tests/kernel/common/testcase.yaml index a32226c3673a..721d4bb9c3de 100644 --- a/tests/kernel/common/testcase.yaml +++ b/tests/kernel/common/testcase.yaml @@ -3,7 +3,8 @@ common: - base - kernel - userspace - min_flash: 33 + min_flash: 32 + min_ram: 32 timeout: 120 tests: kernel.common: diff --git a/tests/subsys/logging/log_api/testcase.yaml b/tests/subsys/logging/log_api/testcase.yaml index 11b3f0192f13..36727d8d3462 100644 --- a/tests/subsys/logging/log_api/testcase.yaml +++ b/tests/subsys/logging/log_api/testcase.yaml @@ -10,6 +10,7 @@ common: - simulation integration_platforms: - native_posix + min_ram: 32 tests: logging.log_api_deferred_overflow_rt_filter: extra_configs: From d5815d6ad13ab80375dc1761092dfd5df103c7fb Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 16:19:36 +0200 Subject: [PATCH 0140/2042] doc: 3.4 release notes: Fix doc build Fix doc build error due to a bad indent Signed-off-by: Alberto Escolar Piedras --- doc/releases/release-notes-3.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index c60a50249fc5..9363d8fbbb31 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -741,7 +741,7 @@ Drivers and Sensors * STM32C0: Added support for DMA * STM32H5: Added support for GPDMA * STM32H7: Added support for BDMA - * Added DMA support for the RP2040 SoC + * Added DMA support for the RP2040 SoC * EEPROM From 5cdbd59c671fa396af6ea0b4264fba23da931308 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 13 Jun 2023 14:48:28 +0200 Subject: [PATCH 0141/2042] include: crypto: Remove duplicate assignment line The crypto hash context has a reference to the crypto device, but the assignment was duplicated. Signed-off-by: Pieter De Gendt --- include/zephyr/crypto/crypto.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/zephyr/crypto/crypto.h b/include/zephyr/crypto/crypto.h index 62c2495b026a..09168c3a5223 100644 --- a/include/zephyr/crypto/crypto.h +++ b/include/zephyr/crypto/crypto.h @@ -388,7 +388,6 @@ static inline int hash_begin_session(const struct device *dev, api = (struct crypto_driver_api *) dev->api; ctx->device = dev; - ctx->device = dev; flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)); __ASSERT(flags != 0U, "IO buffer type missing"); From 2019c044baebc7c0bb34533003a2734c808e2426 Mon Sep 17 00:00:00 2001 From: Pierce Lowe Date: Mon, 12 Jun 2023 12:37:06 +0200 Subject: [PATCH 0142/2042] Bluetooth: hci: Add 5.4 HCI error codes Add new bluetooth hci error codes from Bluetooth 5.4 specification Signed-off-by: Pierce Lowe --- include/zephyr/bluetooth/hci_types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 3618ee5115a6..36a1bd7cc33b 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -2997,7 +2997,7 @@ struct bt_hci_evt_le_biginfo_adv_report { #define BT_EVT_MASK_LE_PER_ADV_RESPONSE_REPORT BT_EVT_BIT(39) #define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) -/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */ +/** HCI Error Codes, BT Core Spec v5.4 [Vol 1, Part F]. */ #define BT_HCI_ERR_SUCCESS 0x00 #define BT_HCI_ERR_UNKNOWN_CMD 0x01 #define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 @@ -3065,6 +3065,8 @@ struct bt_hci_evt_le_biginfo_adv_report { #define BT_HCI_ERR_LIMIT_REACHED 0x43 #define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44 #define BT_HCI_ERR_PACKET_TOO_LONG 0x45 +#define BT_HCI_ERR_TOO_LATE 0x46 +#define BT_HCI_ERR_TOO_EARLY 0x47 #ifdef __cplusplus } From 3104ad0e393cc4df756b2d12aa15c0b3c9be3960 Mon Sep 17 00:00:00 2001 From: Peter McGaughey Date: Tue, 30 May 2023 17:29:26 -0400 Subject: [PATCH 0143/2042] drivers: serial: uart_sam0: fix uart_sam0_irq_update TXC reset drivers: serial: uart_sam0: fix uart_sam0_irq_update TXC reset bug uart_sam0_irq_update function resets flags that will cause int. re-entry existing implementation also clears the TXC flag if it is set this breaks transmit complete detection Per the SAMD5x/E5x Datasheet Sect. 34.8.6, writing '1' to the TXC will clear the flag and disable TX complete interrupts, this should be preserved through the irq_update for use in the tx_complete check function The proper fix will cache the TXC value before conditionally clearing the flag based on that cached value. If you do not condition this on the cached value a race condition will periodically occur where the TXC is cleared but never cached. Fixes zephyrproject-rtos#55386 Signed-off-by: Peter McGaughey --- drivers/serial/uart_sam0.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/serial/uart_sam0.c b/drivers/serial/uart_sam0.c index 1bcd5c8df618..82676b4f85bd 100644 --- a/drivers/serial/uart_sam0.c +++ b/drivers/serial/uart_sam0.c @@ -62,6 +62,7 @@ struct uart_sam0_dev_data { #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t cb; void *cb_data; + uint8_t txc_cache; #endif #if CONFIG_UART_ASYNC_API const struct device *dev; @@ -823,9 +824,10 @@ static int uart_sam0_irq_tx_ready(const struct device *dev) static int uart_sam0_irq_tx_complete(const struct device *dev) { const struct uart_sam0_dev_cfg *config = dev->config; + struct uart_sam0_dev_data *const dev_data = dev->data; SercomUsart * const regs = config->regs; - return (regs->INTFLAG.bit.TXC != 0) && (regs->INTENSET.bit.TXC != 0); + return (dev_data->txc_cache != 0) && (regs->INTENSET.bit.TXC != 0); } static void uart_sam0_irq_rx_enable(const struct device *dev) @@ -904,13 +906,23 @@ static int uart_sam0_irq_update(const struct device *dev) /* Clear sticky interrupts */ const struct uart_sam0_dev_cfg *config = dev->config; SercomUsart * const regs = config->regs; + #if defined(SERCOM_REV500) - regs->INTFLAG.reg |= SERCOM_USART_INTENCLR_ERROR - | SERCOM_USART_INTENCLR_RXBRK - | SERCOM_USART_INTENCLR_CTSIC - | SERCOM_USART_INTENCLR_RXS; + /* + * Cache the TXC flag, and use this cached value to clear the interrupt + * if we do not used the cached value, there is a chance TXC will set + * after caching...this will cause TXC to never cached. + */ + struct uart_sam0_dev_data *const dev_data = dev->data; + + dev_data->txc_cache = regs->INTFLAG.bit.TXC; + regs->INTFLAG.reg = SERCOM_USART_INTENCLR_ERROR + | SERCOM_USART_INTENCLR_RXBRK + | SERCOM_USART_INTENCLR_CTSIC + | SERCOM_USART_INTENCLR_RXS + | (dev_data->txc_cache << SERCOM_USART_INTENCLR_TXC_Pos); #else - regs->INTFLAG.reg = SERCOM_USART_INTENCLR_RXS; + regs->INTFLAG.reg = SERCOM_USART_INTENCLR_RXS; #endif return 1; } From a44f6bbb361778c68731cc7f599e8fc9c8a95816 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 13 Jun 2023 17:01:27 +0200 Subject: [PATCH 0144/2042] doc: release-notes: Add 3.4.0 release notes for networking Add Zephyr 3.4.0 release notes for the networking area. Signed-off-by: Robert Lubos --- doc/releases/release-notes-3.4.rst | 198 ++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 2 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 9363d8fbbb31..f024cff0b28c 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -939,9 +939,203 @@ Drivers and Sensors Networking ********** -* Wi-Fi - * TWT intervals are changed from milli-seconds to micro-seconds, interval variables are also renamed. +* CoAP: + + * Added :c:func:`coap_append_descriptive_block_option` and + :c:func:`coap_get_block1_option` APIs to facilitate block transfer handling. + * Added a :ref:`coap_client_interface` helper library, based on the existing CoAP APIs. + * Fixed missing token length validation in :c:func:`coap_header_get_token`. + * Fixed missing response check in :c:func:`coap_response_received`. + +* Connection Manger: + + * Extended the library with a generic L2 connectivity API. + * Refactored library internals significantly. + * Improved thread safety in the library. + * Reworked how Connection Manager events are notified - they are no longer + raised for each interface individually, but instead: + + * ``NET_EVENT_L4_CONNECTED`` is called only once after the first + interface gains connectivity. + * ``NET_EVENT_L4_DISCONNECTED`` is called only after connectivity is + lost on all interfaces. + + * Improved Connection Manager test coverage. + +* DHCPv4: + + * Fixed a potential packet leak in DHCPv4 input handler. + * Fixed a potential NULL pointer dereference in ``dhcpv4_create_message()``. + * Added a mechanism to register a callback for handling DHCPv4 options. + * Modified ``dhcpv4_client`` sample to trigger DHCP on all network interfaces + in the system. + +* DNS: + + * Fixed a possible crash on NULL pointer as a query callback. + * Added a check on existing DNS servers before reconfigure. + * Improved debug logging in DNS SD. + * Fixed IPv4/IPv6 address handling in mDNS responder, if both are IPv4 and IPv6 are enabled. + * Removed dead code in DNS SD query parsing. + +* Ethernet: + + * Fixed double packet dereference in case of ARP request transmission errors. + * Fixed a possible slist corruption in case Ethernet interface went up before + LLDP initialization. + +* HTTP: + + * Added HTTP service and resource iterable sections. + +* ICMPv6: + + * Implemented IPv6 RA Recursive DNS Server option handling. + +* IEEE802154: + + * Fixed a corner case with 6LoWPAN IP Header Compression and fragmentation, where + for a short range of packet sizes, fragmentation did not work correctly after IPHC. + * Added new radio API function to start continuous carrier wave transmission. + * Several improvements/fixes in IEEE802154 L2 security. + * Fixed a packet leak when handling beacon/command frames. + * Deprecated :kconfig:option:`CONFIG_IEEE802154_2015` Kconfig option. + * Added simple Babblesim echo test over IEEE802154 L2. + * Improved IEEE802154 L2 test coverage. + * Multiple other minor IEEE802154 L2 and documentation improvements/fixes. + +* IPv4: + + * Implemented a fallback to IPv4 Link Local address if no other address is available. + * Fixed :c:func:`net_ipv4_is_ll_addr` helper function to correctly identify LL address. + * Fixed possible NULL pointer dereference in IPv4 fragmentation. + +* LwM2M: + + * Added new :c:macro:`LWM2M_RD_CLIENT_EVENT_REG_UPDATE` event. + * Added missing ``const`` qualifier in the APIs, where applicable. + * Fixed socket error handling on packet transmission. + * Improved LwM2M context cleanup when falling back to regular Registration. + * Added possibility to register a callback function for FW update cancel action. + * Added possibility to register a callback function for LwM2M send operation. + * Added ISPO voltage sensor object support. + * Fixed stopping of the LwM2M client when it's suspended. + * Fixed a minor CoAP RFC incompatibility, where it should not be assumed that + consecutive data blocks in block transfer will carry the same token. + * Added block transfer support on TX. + * Fixed a possible out-of-bounds memory access when creating FW update object. + * Added possibility to override default socket option configuration with a + dedicated callback function (``set_socketoptions``). + * Improved LwM2M test coverage. + * Several other minor improvements and cleanups. + +* Misc: + + * Added generic ``OFFLOADED_NETDEV_L2`` for offloaded devices to allow + offloaded implementations to detect when interface is brought up/down. + * Factored out ``net_buf_simple`` routines to a separate source file. + * Fixed possible NULL pointer dereference in ``net_pkt_cursor_operate()``. + * Reimplemented ``net_mgmt`` to use message queue internally. This also fixed + a possible event loss with the old implementation. + * Fixed error handling in ``net ping`` shell command to avoid shell freeze. + * Improved Ethernet error statistics logging in ``net stats`` shell command. + * Moved SLIP TAP implementation into a separate file, to prevent build warnings + about missing sources for Ethernet drivers. + * Fixed crashes in ``echo_server`` and ``echo_client`` samples, when + userspace is enabled. + * Fixed IPv6 support in ``mqtt_sn_publisher`` sample. + * Fixed build issues with arm-clang in the networking stack. + * Added new ``NET_IF_IPV6_NO_ND`` and ``NET_IF_IPV6_NO_MLD`` interface flags, + which allow to disable ND/MLD respectively on an interface. + * Reworked network interface mutex protection, to use individual mutex for + each interface, instead of a global one. + * Added new :ref:`aws-iot-mqtt-sample`. + * Added a few missing NULL pointer checks in network interface functions. + +* OpenThread: + + * Implemented the following OpenThread platform APIs: + + * ``otPlatRadioSetMacFrameCounterIfLarger()``, + * ``otPlatCryptoEcdsaGenerateAndImportKey()``, + * ``otPlatCryptoEcdsaExportPublicKey()``, + * ``otPlatCryptoEcdsaVerifyUsingKeyRef()``, + * ``otPlatCryptoEcdsaSignUsingKeyRef()``. + + * Added :kconfig:option:`CONFIG_OPENTHREAD_CSL_TIMEOUT` option. + * Removed no longer needed ``CONFIG_OPENTHREAD_EXCLUDE_TCPLP_LIB``. + * Added simple Babblesim echo test over OpenThread. + +* SNTP: + + * Switched to use ``zsock_*`` functions internally. + +* Sockets: + + * Fixed ``SO_RCVBUF`` and ``SO_SNDBUF`` socket options handling, so that they + configure TCP window sizes correctly. + * Fixed ``SO_SNDTIMEO`` socket option handling - the timeout value was ignored + and socket behaved as in non-blocking mode when used. + * Reworked TLS sockets implementation, to allow parallel TX/RX from + different threads. + * Implemented TLS handshake timeout. + * Added support for asynchronous connect for TCP sockets. + * Fixed blocking :c:func:`recv` not being interrupted on socket close. + * Fixed blocking :c:func:`accept` not being interrupted on socket close. + * Improved sockets test coverage. + +* TCP: + + * Fixed incorrect TCP stats by improving packet processing result reporting. + * Added :kconfig:option:`CONFIG_NET_TCP_PKT_ALLOC_TIMEOUT` to allow to configure + packet allocation timeout. + * Improved TCP test coverage. + * Fixed TCP MSS calculation for IPv6. + * Fixed possible double acknowledgment of retransmitted data. + * Fixed local address setting for incoming connections. + * Fixed double TCP context dereferencing in certain corner cases. + +* TFTP: + + * Added ``tftp_put()`` API to support TFTP write request. + * Introduced ``tftp_callback_t`` callback to allow to read large files. + * Reworked ``struct tftpc`` client context structure, to allow for parallel + communication from several contexts. + +* UDP: + + * :kconfig:option:`CONFIG_NET_UDP_MISSING_CHECKSUM` is now enabled by default. + +* Websockets: + + * Implemented proper timeout handling in :c:func:`websocket_recv_msg`. + * Fixed implicit type conversion when parsing length field, which could lead + to data loss. + +* Wi-Fi: + + * Display TWT (Target Wake Time) configuration response status in Wi-Fi shell. + * Added more detailed TWT response parameters printout in Wi-Fi shell. + * Added new ``NET_EVENT_WIFI_TWT_SLEEP_STATE`` event to notify TWT sleep status. + * Fixed an issue where not all security modes were displayed correctly on scan. + * Added connection status and AP capabilities verification before initiating + TWT operation. + * TWT intervals are changed from milliseconds to microseconds, interval + variables are also renamed. + * Extended Power Saving configuration parameters with listening interval and + wake up mode. + * Added :kconfig:option:`CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS` option, which + enables providing of RAW (unprocessed) scan results to the application with + ``NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT`` event. + * Several other minor fixes/cleanups in the Wi-Fi management/shell modules. + +* zperf + + * Added an extra parameter to disable Nagle's algorithm with TCP benchmarks. + * Added support for handling multiple incoming TCP sessions. + * Made zperf thread priority and stack size configurable. + * Several minor cleanups in the module. USB *** From be04e30a889b67547fceb7adeb6f357220283c12 Mon Sep 17 00:00:00 2001 From: Andrei Hutanu Date: Tue, 13 Jun 2023 18:20:06 +0200 Subject: [PATCH 0145/2042] samples: net: mqtt_azure: hotfix stack overflow running samples/net/cloud/mqtt_azure in QEMU with default configuration crashes with exception. This PR change doubles the default workqueue stack size in a attempt to fix the issue reported in: GH#58930. Signed-off-by: Andrei Hutanu --- samples/net/cloud/mqtt_azure/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/net/cloud/mqtt_azure/prj.conf b/samples/net/cloud/mqtt_azure/prj.conf index 968898dc6fab..e3b8ac83edb4 100644 --- a/samples/net/cloud/mqtt_azure/prj.conf +++ b/samples/net/cloud/mqtt_azure/prj.conf @@ -53,6 +53,7 @@ CONFIG_INIT_STACKS=y CONFIG_NET_SHELL=y CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 # Enable Logging support CONFIG_LOG_MODE_IMMEDIATE=y From 0773cc88c881bce51ae510ec150f03b69501e6d1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 14 Jun 2023 10:44:25 +0000 Subject: [PATCH 0146/2042] release: document major changes added highlights to the 3.4 release notes. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index f024cff0b28c..e72d682c97a5 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -9,6 +9,31 @@ We are pleased to announce the release of Zephyr version 3.4.0. Major enhancements with this release include: +* Input subsystem: handles input events from various types of input devices and + distribute them to other threads in the application. +* Barrierr API: add architecture agnostic API for data memory barriers. +* USB Device support: + + * USB device controller API (UDC API) + * USB device controller API and nRF USBD controller driver. + * USB device stack implementation using new UDC API + +* Added Power Delivery Source Support to the USB-C Stack +* Bluetooth: Added support for Periodic Advertising with Responses (PAwR) +* Cache API functions are now fully inlined by compilers. +* Added an API for real-time clocks (RTC). +* Added Retention subsystem +* Added initial support for MMU on Xtensa +* SMBus (System Management Bus) API +* Various improvements to the testing framework and twister: + + - Introduction of 3 new test harnesses into twister supporting pyTest, + GoogleTest and RobotFramework + - Transitioning to new Ztest API was completed and legacy Ztest was deprecated. + +* Added Snippets: Support common configuration settings that can be used across + platforms. + The following sections provide detailed lists of changes by component. Security Vulnerability Related From 1edc8cc7627f6b714806f8e612731eb3f1c58987 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 14 Jun 2023 12:31:18 +0100 Subject: [PATCH 0147/2042] mgmt: mcumgr: grp: img_mgmt: Fix using signed values Fixes wrongly using signed values for slot and image number when listing images. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 11053d1c4a81..eae5aaa3e8bd 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 @@ -237,7 +237,7 @@ img_mgmt_state_read(struct smp_streamer *ctxt) struct image_version ver; uint32_t flags; uint8_t state_flags; - int i; + uint32_t i; zcbor_state_t *zse = ctxt->writer->zs; bool ok; struct zcbor_string zhash = { .value = hash, .len = IMAGE_HASH_LEN }; @@ -256,9 +256,9 @@ img_mgmt_state_read(struct smp_streamer *ctxt) ok = zcbor_map_start_encode(zse, MAX_IMG_CHARACTERISTICS) && (CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 1 || (zcbor_tstr_put_lit(zse, "image") && - zcbor_int32_put(zse, i >> 1))) && + zcbor_uint32_put(zse, i >> 1))) && zcbor_tstr_put_lit(zse, "slot") && - zcbor_int32_put(zse, i % 2) && + zcbor_uint32_put(zse, i % 2) && zcbor_tstr_put_lit(zse, "version"); if (ok) { From 3f8156d0a41ef2af34bc8b36939e4849b1fc259b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 14 Jun 2023 12:33:21 +0100 Subject: [PATCH 0148/2042] doc: mgmt: smp: Fix slot and image to be unsigned Fixes the documentation to show image and slot number for get state of image response being unsigned, not signed. Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/smp_groups/smp_group_1.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_1.rst b/doc/services/device_mgmt/smp_groups/smp_group_1.rst index e780cb61cecc..482361178c69 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_1.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_1.rst @@ -110,8 +110,8 @@ CBOR data of successful response: { (str)"images" : [ { - (str,opt)"image" : (int) - (str)"slot" : (int) + (str,opt)"image" : (uint) + (str)"slot" : (uint) (str)"version" : (str) (str,opt*)"hash" : (byte str) (str,opt)"bootable" : (bool) From f6512920cad6c0392f796f865bc487300543063d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 14 Jun 2023 12:35:18 +0100 Subject: [PATCH 0149/2042] doc: release: 3.4: Add MCUmgr signed type change Adds a note that slot and image have changed from signed to unsigned integer types. Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.4.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index e72d682c97a5..0e2d2d59ff12 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -1256,6 +1256,10 @@ Libraries / Subsystems fs_mgmt, :kconfig:option:`CONFIG_FLASH` and :kconfig:option:`CONFIG_IMG_MANAGER` are needed to enable MCUmgr img_mgmt. + * MCUmgr img_mgmt group now uses unsigned integer values for image and slot + numbers, these numbers would never have been negative and should have been + unsigned. + * POSIX API * Improved the locking strategy for :c:func:`eventfd_read()` and From 9f25fa20ce79d99e1bb66765e2b9b5afcea44014 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 10:24:51 +0200 Subject: [PATCH 0150/2042] device: set number_of_dynamic_devices only if needed This variable is only needed when gen_handles.py is called, so define it under the if() above. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09815b664452..b2b8da8f74c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -896,13 +896,13 @@ zephyr_get_include_directories_for_lang(C STRIP_PREFIX # Don't use a -I prefix ) -if(CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC) - set(number_of_dynamic_devices ${CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM}) -else() - set(number_of_dynamic_devices 0) -endif() - if(CONFIG_HAS_DTS) + if(CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC) + set(number_of_dynamic_devices ${CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM}) + else() + set(number_of_dynamic_devices 0) + endif() + # dev_handles.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by # gen_handles.py add_custom_command( From e5335f345a14c6f2f62b4e571fba3b16274d5a58 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 10:15:12 +0200 Subject: [PATCH 0151/2042] device: dynamic device handles were declared as const When CONFIG_HAS_DYNAMIC_DEVICE_HANDLES is selected, devices handles are placed in RAM region so that they can be modified at runtime. However, the gen_handles.py script added the `const` attribute to the device handle arrays regardless of this setting, leading to faults when running the application. This may be an indicator that this feature is not actively used. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 5 +++++ scripts/build/gen_handles.py | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b8da8f74c0..90c60baabaff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -897,6 +897,10 @@ zephyr_get_include_directories_for_lang(C ) if(CONFIG_HAS_DTS) + if(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) + set(dynamic_handles --dynamic-handles) + endif() + if(CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC) set(number_of_dynamic_devices ${CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM}) else() @@ -912,6 +916,7 @@ if(CONFIG_HAS_DTS) ${ZEPHYR_BASE}/scripts/build/gen_handles.py --output-source dev_handles.c --output-graphviz dev_graph.dot + ${dynamic_handles} --num-dynamic-devices ${number_of_dynamic_devices} --kernel $ --zephyr-base ${ZEPHYR_BASE} diff --git a/scripts/build/gen_handles.py b/scripts/build/gen_handles.py index e6807bff8774..799b9139171b 100755 --- a/scripts/build/gen_handles.py +++ b/scripts/build/gen_handles.py @@ -46,6 +46,8 @@ def parse_args(): parser.add_argument("-k", "--kernel", required=True, help="Input zephyr ELF binary") + parser.add_argument("--dynamic-handles", action="store_true", + help="Indicates if device handles are dynamic") parser.add_argument("-d", "--num-dynamic-devices", required=False, default=0, type=int, help="Input number of dynamic devices allowed") parser.add_argument("-o", "--output-source", required=True, @@ -93,7 +95,7 @@ def dev_path_str(dev): lines.append(' */') return lines -def c_handle_array(dev, handles, extra_support_handles=0): +def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): handles = [ *[str(d.handle) for d in handles["depends"]], 'DEVICE_HANDLE_SEP', @@ -103,7 +105,10 @@ def c_handle_array(dev, handles, extra_support_handles=0): *(extra_support_handles * ['DEVICE_HANDLE_NULL']), 'DEVICE_HANDLE_ENDS', ] - ctype = 'const Z_DECL_ALIGN(device_handle_t) __attribute__((__section__(".__device_handles_pass2")))' + ctype = ( + '{:s}Z_DECL_ALIGN(device_handle_t) ' + '__attribute__((__section__(".__device_handles_pass2")))' + ).format('const ' if not dynamic_handles else '') return [ # The `extern` line pretends this was first declared in some .h # file to silence "should it be static?" warnings in some @@ -153,7 +158,9 @@ def main(): } extra_sups = args.num_dynamic_devices if dev.pm and dev.pm.is_power_domain else 0 lines = c_handle_comment(dev, sorted_handles) - lines.extend(c_handle_array(dev, sorted_handles, extra_sups)) + lines.extend( + c_handle_array(dev, sorted_handles, args.dynamic_handles, extra_sups) + ) lines.extend(['']) fp.write('\n'.join(lines)) From 3ebdc1e330845464e47e27bbbffe3a8fe7ba4b21 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 14 Jun 2023 16:25:29 +0200 Subject: [PATCH 0152/2042] doc: nrf52_bsim: Update instructions on how to get BabbleSim As now we point to babblesim with the zephyr manifest, we can tell users to get it that way. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/doc/index.rst | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/boards/posix/nrf52_bsim/doc/index.rst b/boards/posix/nrf52_bsim/doc/index.rst index 909b9c4351e3..a1de9a4f7ba7 100644 --- a/boards/posix/nrf52_bsim/doc/index.rst +++ b/boards/posix/nrf52_bsim/doc/index.rst @@ -47,28 +47,32 @@ This board requires the host 32 bit C library. See :ref:`POSIX Arch dependencies`. To target this board you also need to have `BabbleSim`_ compiled in your system. -If you do not have it yet, in `its web page `_ -you can find instructions on how to -`fetch `_ and -`build `_ it. -In short, you can do: +If you do not have it yet, the easiest way to get it, is to enable the babblesim group +in your local west configuration, running west update, and building the simulator: .. code-block:: console - mkdir -p ${HOME}/bsim && cd ${HOME}/bsim - curl https://storage.googleapis.com/git-repo-downloads/repo > ./repo && chmod a+x ./repo - ./repo init -u https://github.com/BabbleSim/manifest.git -m everything.xml -b master - ./repo sync + west config manifest.group-filter -- +babblesim + west update + cd ${ZEPHYR_BASE}/../tools/bsim make everything -j 8 -Define two environment variables to point to your BabbleSim +.. note:: + + If you need more BabbleSim components, or more up to date versions, + you can check the `BabbleSim web page `_ + for instructions on how to + `fetch `_ and + `build `_ it. + +You will now need to define two environment variables to point to your BabbleSim installation, ``BSIM_OUT_PATH`` and ``BSIM_COMPONENTS_PATH``. If you followed the previous steps, you can just do: .. code-block:: console - export BSIM_OUT_PATH=${HOME}/bsim/ - export BSIM_COMPONENTS_PATH=${HOME}/bsim/components/ + export BSIM_OUT_PATH=${ZEPHYR_BASE}/../tools/bsim + export BSIM_COMPONENTS_PATH=${BSIM_OUT_PATH}/components/ .. note:: From 4dd3d8679e65eb9c9d94835256a064027c11323c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 14 Jun 2023 17:18:54 +0200 Subject: [PATCH 0153/2042] doc: release-notes: Fix typo in networking part Fix typo in networking part of the release notes. Signed-off-by: Robert Lubos --- doc/releases/release-notes-3.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 0e2d2d59ff12..6367a5b41f6e 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -973,7 +973,7 @@ Networking * Fixed missing token length validation in :c:func:`coap_header_get_token`. * Fixed missing response check in :c:func:`coap_response_received`. -* Connection Manger: +* Connection Manager: * Extended the library with a generic L2 connectivity API. * Refactored library internals significantly. From bc13ce12a148c94fc73b447cd1e252c1edd3c2a3 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 14 Jun 2023 09:47:55 -0500 Subject: [PATCH 0154/2042] doc: releases: updates for SDHC and Disk driver release notes Add release notes for SDHC and Disk drivers, highlighting addition of NVME support in the disk driver layer as well as CPOL/CPHA clock modes within the SDHC SPI driver. Signed-off-by: Daniel DeGrasse --- doc/releases/release-notes-3.4.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 6367a5b41f6e..03a869902734 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -758,6 +758,7 @@ Drivers and Sensors * Disk * SDMMC STM32L4+: Now compatible with internal DMA + * NVME disks are now supported using FATFS, with a single I/O queue enabled * Display @@ -899,6 +900,9 @@ Drivers and Sensors * SDHC + * Support was added for using CPOL/CPHA SPI clock modes with SD cards, as + some cards require the SPI clock switch to low when not active + * Sensor * Added generic voltage measurement sample From 79433b0ee3f27a9b4fa65962875bd993356da592 Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Wed, 14 Jun 2023 16:27:12 +0200 Subject: [PATCH 0155/2042] release-notes: 3.4: Add Aarch32 and TF-M notes Adds release notes for Aarch32 and TF-M for Zephyr 3.4.0. Signed-off-by: Kevin Townsend --- doc/releases/release-notes-3.4.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 03a869902734..cb0f8c958978 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -306,6 +306,11 @@ Architectures * Removed absolute symbols :c:macro:`___basic_sf_t_SIZEOF`, :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF`, :c:macro:`___cpu_context_t_SIZEOF` and :c:macro:`___thread_stack_info_t_SIZEOF` + * Enabled fp16 for Cortex-M55 + * Fixed a compilation issue with arm-clang and TrustZone + * Implemented a new cache-management API + * Added support for generating zImage headers + * Introduced a new :c:func:`z_arm_on_enter_cpu_idle` hook on CPU idle * ARM64 @@ -478,6 +483,7 @@ Boards & SoC Support * ST Nucleo H563ZI * ST STM32H573I-DK Discovery * Raspberry Pi Pico W + * Xilinx KV260 (Cortex-R5) * Added support for these ARM64 boards: @@ -1340,6 +1346,11 @@ Storage Trusted Firmware-M ****************** +* Enable routing of PSA Crypto API calls from NS to S, thanks to separating MbedTLS into three + distinct libraries at build time (crypto, TLS, X.509). This also resolves header conflicts with + earlier integrations of TF-M and MbedTLS. +* Added psa_crypto sample back. + zcbor ***** From e1efafa31db942f1a2557b967a22da522c4526ee Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Tue, 13 Jun 2023 15:20:24 +0100 Subject: [PATCH 0156/2042] ARC: don't align ROM region end if not required This extra MPU alignment of RAMABLE_REGION is only required if we put ROMABLE_REGION and RAMABLE_REGION into the same (continuous) memory (i.e. SRAM) - so we won't get beginning of the RAMABLE_REGION in the end of ROMABLE_REGION MPU aperture. If we use different regions (ICCM & DCCM, FLASH & SRAM, etc...) we don't need this extra MPU alignment. Let's drop it to decrease ROM memory usage. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- include/zephyr/arch/arc/v2/linker.ld | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/zephyr/arch/arc/v2/linker.ld b/include/zephyr/arch/arc/v2/linker.ld index f172c16cfa39..d33866370daf 100644 --- a/include/zephyr/arch/arc/v2/linker.ld +++ b/include/zephyr/arch/arc/v2/linker.ld @@ -17,13 +17,16 @@ #ifdef CONFIG_HARVARD #define ROMABLE_REGION ICCM #define RAMABLE_REGION DCCM + #define ROM_RAM_IN_SAME_REGION 0 #else #if defined(CONFIG_XIP) && (FLASH_SIZE != 0) #define ROMABLE_REGION FLASH #define RAMABLE_REGION SRAM + #define ROM_RAM_IN_SAME_REGION 0 #else #define ROMABLE_REGION SRAM #define RAMABLE_REGION SRAM + #define ROM_RAM_IN_SAME_REGION 1 #endif #endif @@ -138,7 +141,13 @@ SECTIONS { _ectors = .; #endif /* CONFIG_CPP && !CONFIG_CPP_STATIC_INIT_GNU && __MWDT_LINKER_CMD__ */ +/* This extra MPU alignment of RAMABLE_REGION is only required if we put ROMABLE_REGION and + * RAMABLE_REGION into the same (continuous) memory - otherwise we can get beginning of the + * RAMABLE_REGION in the end of ROMABLE_REGION MPU aperture. + */ +#if ROM_RAM_IN_SAME_REGION MPU_ALIGN(ABSOLUTE(.) - __rom_region_start); +#endif } GROUP_LINK_IN(ROMABLE_REGION) __rodata_region_end = .; From 9642c48a29fe80b61e136401ab1723754513a7fe Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 12 Jun 2023 15:37:37 +0100 Subject: [PATCH 0157/2042] cmake: boards: Fix issue with relative paths Fixes an issue with relative paths both with and without using sysbuild where they would not be updated properly or a warning would previously be emitted. Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae --- cmake/modules/root.cmake | 24 +++++++------------ .../cmake/modules/sysbuild_extensions.cmake | 21 ++++++++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cmake/modules/root.cmake b/cmake/modules/root.cmake index 603b3b59cc99..0f4d5e1437ba 100644 --- a/cmake/modules/root.cmake +++ b/cmake/modules/root.cmake @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # -# Copyright (c) 2021, Nordic Semiconductor ASA +# Copyright (c) 2021-2023, Nordic Semiconductor ASA # Convert Zephyr roots to absolute paths. # @@ -21,21 +21,6 @@ include_guard(GLOBAL) include(extensions) -# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR -zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT) - -# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR -zephyr_file(APPLICATION_ROOT BOARD_ROOT) - -# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR -zephyr_file(APPLICATION_ROOT SOC_ROOT) - -# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR -zephyr_file(APPLICATION_ROOT ARCH_ROOT) - -# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR -zephyr_file(APPLICATION_ROOT SCA_ROOT) - # Merge in variables from other sources (e.g. sysbuild) zephyr_get(MODULE_EXT_ROOT MERGE SYSBUILD GLOBAL) zephyr_get(BOARD_ROOT MERGE SYSBUILD GLOBAL) @@ -43,6 +28,13 @@ zephyr_get(SOC_ROOT MERGE SYSBUILD GLOBAL) zephyr_get(ARCH_ROOT MERGE SYSBUILD GLOBAL) zephyr_get(SCA_ROOT MERGE SYSBUILD GLOBAL) +# Convert paths to absolute, relative from APPLICATION_SOURCE_DIR +zephyr_file(APPLICATION_ROOT MODULE_EXT_ROOT) +zephyr_file(APPLICATION_ROOT BOARD_ROOT) +zephyr_file(APPLICATION_ROOT SOC_ROOT) +zephyr_file(APPLICATION_ROOT ARCH_ROOT) +zephyr_file(APPLICATION_ROOT SCA_ROOT) + if(unittest IN_LIST Zephyr_FIND_COMPONENTS) # Zephyr used in unittest mode, use dedicated unittest root. set(BOARD_ROOT ${ZEPHYR_BASE}/subsys/testsuite) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 53cf1eb2e659..bdf8f88b8055 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -182,6 +182,17 @@ function(ExternalZephyrProject_Add) ) endif() endif() + + # Update ROOT variables with relative paths to use absolute paths based on + # the source application directory. + foreach(type MODULE_EXT BOARD SOC ARCH SCA) + if(DEFINED CACHE{${ZBUILD_APPLICATION}_${type}_ROOT} AND NOT IS_ABSOLUTE $CACHE{${ZBUILD_APPLICATION}_${type}_ROOT}) + set(rel_path $CACHE{${ZBUILD_APPLICATION}_${type}_ROOT}) + cmake_path(ABSOLUTE_PATH rel_path BASE_DIRECTORY "${ZBUILD_SOURCE_DIR}" NORMALIZE OUTPUT_VARIABLE abs_path) + set(${ZBUILD_APPLICATION}_${type}_ROOT ${abs_path} CACHE PATH "Sysbuild adjusted absolute path" FORCE) + endif() + endforeach() + # CMake variables which must be known by all Zephyr CMake build systems # Those are settings which controls the build and must be known to CMake at # invocation time, and thus cannot be passed though the sysbuild cache file. @@ -315,6 +326,16 @@ function(ExternalZephyrProject_Cmake) get_target_property(${ZCMAKE_APPLICATION}_BOARD ${ZCMAKE_APPLICATION} BOARD) get_target_property(${ZCMAKE_APPLICATION}_MAIN_APP ${ZCMAKE_APPLICATION} MAIN_APP) + # Update ROOT variables with relative paths to use absolute paths based on + # the source application directory. + foreach(type MODULE_EXT BOARD SOC ARCH SCA) + if(DEFINED CACHE{${type}_ROOT} AND NOT IS_ABSOLUTE $CACHE{${type}_ROOT}) + set(rel_path $CACHE{${type}_ROOT}) + cmake_path(ABSOLUTE_PATH rel_path BASE_DIRECTORY "${APP_DIR}" NORMALIZE OUTPUT_VARIABLE abs_path) + set(${type}_ROOT ${abs_path} CACHE PATH "Sysbuild adjusted absolute path" FORCE) + endif() + endforeach() + get_cmake_property(sysbuild_cache CACHE_VARIABLES) foreach(var_name ${sysbuild_cache}) if(NOT "${var_name}" MATCHES "^(CMAKE_.*|BOARD)$") From 83b074c4185d2ddbae3a2936c02c572c96052222 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 14 Jun 2023 12:17:08 +0100 Subject: [PATCH 0158/2042] doc: release: 3.4: Add build system relative path fixes Adds a note that some relative path issues in the build system have been fixed. Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.4.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index cb0f8c958978..a960cdb46e19 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -671,6 +671,11 @@ Build system and infrastructure | "image-1" | slot1_partition | +---------------------------------+---------------------------+ +* Fixed an issue whereby relative paths supplied for the ``BOARD_ROOT`` value + might wrongly emit a warning about a ``boards`` directory not being found. + +* Fixed an issue whereby relative paths did not work for sysbuild images. + Drivers and Sensors ******************* From 8963b507163951da0ba0b7f60cc2039c8c775ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 15 Jun 2023 10:11:27 +0200 Subject: [PATCH 0159/2042] doc: release-notes: add missing boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a bunch of missing boards that were added since v3.3.0 Signed-off-by: Benjamin Cabé --- doc/releases/release-notes-3.4.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index a960cdb46e19..a311d47c560a 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -474,12 +474,33 @@ Boards & SoC Support * Added support for these ARC boards: + * DesignWare ARC HS4x/HS4xD Development Kit + * DesignWare ARC nSIM and HAPS FPGA + * Added support for these ARM boards: + * Aconno ACN52832 * Alientek STM32L475 Pandora + * Arduino GIGA R1 Wi-Fi + * BeagleConnect Freedom + * Infineon PSoC™ 6 BLE Prototyping Kit (CY8CPROTO-063-BLE) + * Infineon PSoC™ 6 Wi-Fi BT Prototyping Kit (CY8CPROTO-062-4343W) + * Infineon XMC4700 Relax Kit * MXChip AZ3166 IoT DevKit + * Nordic Semiconductor nRF9161 DK + * NXP MIMXRT1040-EVK + * NXP MIMXRT1062 FMURT6 + * PHYTEC PhyBOARD Polis (NXP i.MX8M Mini) + * PHYTEC PhyBOARD Pollux (NXP i.MX8M Plus) + * Raytac MDBT50Q-DB-33 + * Raytac MDBT50Q-DB-40 * Seeed Studio Wio Terminal + * Seeed Studio XIAO BLE Sense + * Silicon Labs BRD2601B + * Silicon Labs BRD4187C + * Silicon Labs EFR32 Thunderboard-style boards * ST Nucleo C031C6 + * ST Nucleo F042K6 * ST Nucleo H563ZI * ST STM32H573I-DK Discovery * Raspberry Pi Pico W @@ -492,10 +513,15 @@ Boards & SoC Support * Added support for these RISC-V boards: + * Intel FPGA Nios® V/m + * ITE IT82XX2 EV-Board + * Added support for these X86 boards: * Added support for these Xtensa boards: + * ESP32S3-DevKitM + * Made these changes for ARC boards: * Made these changes for ARM boards: From 4bc46e4e3aacc3d018e09769ef58466df5244bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 15 Jun 2023 10:13:12 +0200 Subject: [PATCH 0160/2042] doc: release-notes: sort ARM boards alphabetically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort ARM boards alphabetically. Signed-off-by: Benjamin Cabé --- doc/releases/release-notes-3.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index a311d47c560a..858300021d59 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -492,6 +492,7 @@ Boards & SoC Support * NXP MIMXRT1062 FMURT6 * PHYTEC PhyBOARD Polis (NXP i.MX8M Mini) * PHYTEC PhyBOARD Pollux (NXP i.MX8M Plus) + * Raspberry Pi Pico W * Raytac MDBT50Q-DB-33 * Raytac MDBT50Q-DB-40 * Seeed Studio Wio Terminal @@ -503,7 +504,6 @@ Boards & SoC Support * ST Nucleo F042K6 * ST Nucleo H563ZI * ST STM32H573I-DK Discovery - * Raspberry Pi Pico W * Xilinx KV260 (Cortex-R5) * Added support for these ARM64 boards: From 09a9a7edf4808589e1306167cb83b66b16d2f551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 15 Jun 2023 10:15:06 +0200 Subject: [PATCH 0161/2042] doc: release-notes: fix typo with i.MX93 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NXP i.MX93 is A55 not A53. Signed-off-by: Benjamin Cabé --- doc/releases/release-notes-3.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 858300021d59..4908a3a25468 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -509,7 +509,7 @@ Boards & SoC Support * Added support for these ARM64 boards: * PHYTEC phyCORE-AM62x A53 - * MIMX93 EVK A53 (SOF) + * NXP i.MX93 EVK A55 (SOF variant) * Added support for these RISC-V boards: From b335c19bcb63fedfe18da12febd77f96c14d062d Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Wed, 7 Jun 2023 13:42:50 +0200 Subject: [PATCH 0162/2042] doc: move USB documentation to connectivity Mostly moved and reorganised content to the Connectivity chapter, separated API references. Fill in some gaps in the USB device documentation. Signed-off-by: Johann Fischer --- MAINTAINERS.yml | 2 +- doc/connectivity/index.rst | 1 + doc/connectivity/usb/api/hid.rst | 25 + doc/connectivity/usb/device/api/index.rst | 11 + doc/connectivity/usb/device/api/usb_dc.rst | 16 + .../usb/device/api/usb_device.rst | 28 + .../usb/device/api/usb_device_hid.rst | 12 + doc/connectivity/usb/device/usb_device.rst | 506 ++++++++++++++++++ .../usb/device_next/api/index.rst | 10 + doc/connectivity/usb/device_next/api/udc.rst | 18 + doc/connectivity/usb/device_next/api/usbd.rst | 11 + .../usb/device_next/usb_device.rst | 57 ++ doc/connectivity/usb/host/api/index.rst | 9 + doc/connectivity/usb/host/api/uhc.rst | 15 + doc/connectivity/usb/index.rst | 28 + doc/services/index.rst | 1 - doc/services/usb/hid.rst | 56 -- doc/services/usb/index.rst | 29 - doc/services/usb/udc.rst | 17 - doc/services/usb/uds.rst | 164 ------ doc/services/usb/uds_cdc_acm.rst | 105 ---- doc/services/usb/uds_next.rst | 35 -- doc/services/usb/uds_testing.rst | 50 -- doc/services/usb/uhc.rst | 15 - 24 files changed, 748 insertions(+), 473 deletions(-) create mode 100644 doc/connectivity/usb/api/hid.rst create mode 100644 doc/connectivity/usb/device/api/index.rst create mode 100644 doc/connectivity/usb/device/api/usb_dc.rst create mode 100644 doc/connectivity/usb/device/api/usb_device.rst create mode 100644 doc/connectivity/usb/device/api/usb_device_hid.rst create mode 100644 doc/connectivity/usb/device/usb_device.rst create mode 100644 doc/connectivity/usb/device_next/api/index.rst create mode 100644 doc/connectivity/usb/device_next/api/udc.rst create mode 100644 doc/connectivity/usb/device_next/api/usbd.rst create mode 100644 doc/connectivity/usb/device_next/usb_device.rst create mode 100644 doc/connectivity/usb/host/api/index.rst create mode 100644 doc/connectivity/usb/host/api/uhc.rst create mode 100644 doc/connectivity/usb/index.rst delete mode 100644 doc/services/usb/hid.rst delete mode 100644 doc/services/usb/index.rst delete mode 100644 doc/services/usb/udc.rst delete mode 100644 doc/services/usb/uds.rst delete mode 100644 doc/services/usb/uds_cdc_acm.rst delete mode 100644 doc/services/usb/uds_next.rst delete mode 100644 doc/services/usb/uds_testing.rst delete mode 100644 doc/services/usb/uhc.rst diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 254908afffbd..b7ff4a12e1a0 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2619,7 +2619,7 @@ USB: - subsys/usb/ - tests/subsys/usb/ - tests/drivers/udc/ - - doc/services/usb/ + - doc/connectivity/usb/ labels: - "area: USB" diff --git a/doc/connectivity/index.rst b/doc/connectivity/index.rst index 1c70ccdf01b8..c3799eb15e12 100644 --- a/doc/connectivity/index.rst +++ b/doc/connectivity/index.rst @@ -9,4 +9,5 @@ Connectivity bluetooth/index.rst networking/index.rst lora_lorawan/index.rst + usb/index.rst usb_c/index.rst diff --git a/doc/connectivity/usb/api/hid.rst b/doc/connectivity/usb/api/hid.rst new file mode 100644 index 000000000000..46de3592aeba --- /dev/null +++ b/doc/connectivity/usb/api/hid.rst @@ -0,0 +1,25 @@ +.. _usb_hid_common: + +Human Interface Devices (HID) +############################# + +Common USB HID part that can be used outside of USB support, defined in +header file :zephyr_file:`include/zephyr/usb/class/hid.h`. + +HID types reference +******************* + +.. doxygengroup:: usb_hid_definitions + +HID items reference +******************* + +.. doxygengroup:: usb_hid_items + +HID Mouse and Keyboard report descriptors +***************************************** + +The pre-defined Mouse and Keyboard report descriptors can be used by +a HID device implementation or simply as examples. + +.. doxygengroup:: usb_hid_mk_report_desc diff --git a/doc/connectivity/usb/device/api/index.rst b/doc/connectivity/usb/device/api/index.rst new file mode 100644 index 000000000000..ddc06aa47686 --- /dev/null +++ b/doc/connectivity/usb/device/api/index.rst @@ -0,0 +1,11 @@ +.. _usb_api: + +USB device support APIs +####################### + +.. toctree:: + :maxdepth: 1 + + usb_dc.rst + usb_device.rst + usb_device_hid.rst diff --git a/doc/connectivity/usb/device/api/usb_dc.rst b/doc/connectivity/usb/device/api/usb_dc.rst new file mode 100644 index 000000000000..4340f0430cf8 --- /dev/null +++ b/doc/connectivity/usb/device/api/usb_dc.rst @@ -0,0 +1,16 @@ +.. _usb_dc_api: + +USB device controller driver API +################################ + +The USB device controller driver API is described in +:zephyr_file:`include/zephyr/drivers/usb/usb_dc.h` and sometimes referred to +as the ``usb_dc`` API. + +This API has some limitations by design, it does not follow :ref:`device_model_api` +and is being replaced by a new UDC driver API. + +API reference +************* + +.. doxygengroup:: _usb_device_controller_api diff --git a/doc/connectivity/usb/device/api/usb_device.rst b/doc/connectivity/usb/device/api/usb_device.rst new file mode 100644 index 000000000000..9e2b37801727 --- /dev/null +++ b/doc/connectivity/usb/device/api/usb_device.rst @@ -0,0 +1,28 @@ +.. _usb_device_stack_api: + +USB device stack API +#################### + +API reference +************* + +There are two ways to transmit data, using the 'low' level read/write API or +the 'high' level transfer API. + +Low level API + To transmit data to the host, the class driver should call usb_write(). + Upon completion the registered endpoint callback will be called. Before + sending another packet the class driver should wait for the completion of + the previous write. When data is received, the registered endpoint callback + is called. usb_read() should be used for retrieving the received data. + For CDC ACM sample driver this happens via the OUT bulk endpoint handler + (cdc_acm_bulk_out) mentioned in the endpoint array (cdc_acm_ep_data). + +High level API + The usb_transfer method can be used to transfer data to/from the host. The + transfer API will automatically split the data transmission into one or more + USB transaction(s), depending endpoint max packet size. The class driver does + not have to implement endpoint callback and should set this callback to the + generic usb_transfer_ep_callback. + +.. doxygengroup:: _usb_device_core_api diff --git a/doc/connectivity/usb/device/api/usb_device_hid.rst b/doc/connectivity/usb/device/api/usb_device_hid.rst new file mode 100644 index 000000000000..c75ac3a59731 --- /dev/null +++ b/doc/connectivity/usb/device/api/usb_device_hid.rst @@ -0,0 +1,12 @@ +.. _usb_hid_device: + +USB HID Class API +################# + +USB device specific part for HID support defined in +:zephyr_file:`include/zephyr/usb/class/usb_hid.h`. + +API Reference +************* + +.. doxygengroup:: usb_hid_device_api diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst new file mode 100644 index 000000000000..6b17e2ec2ca8 --- /dev/null +++ b/doc/connectivity/usb/device/usb_device.rst @@ -0,0 +1,506 @@ +.. _usb_device_stack: + +USB device support +################## + +.. contents:: + :local: + :depth: 3 + +Overview +******** + +The USB device stack is a hardware independent interface between USB +device controller driver and USB device class drivers or customer applications. +It is a port of the LPCUSB device stack and has been modified and expanded +over time. It provides the following functionalities: + +* Uses the :ref:`usb_dc_api` provided by the device controller drivers to interact with + the USB device controller. +* Responds to standard device requests and returns standard descriptors, + essentially handling 'Chapter 9' processing, specifically the standard + device requests in table 9-3 from the universal serial bus specification + revision 2.0. +* Provides a programming interface to be used by USB device classes or + customer applications. The APIs is described in + :zephyr_file:`include/zephyr/usb/usb_device.h` + +The device stack and :ref:`usb_dc_api` have some limitations, such as not being +able to support more than one controller instance at runtime and only supporting +one USB device configuration. We are actively working on new USB support, which +means we will continue to maintain the device stack described here until all +supported USB classes are ported, but do not expect any new features or enhancements. + +Supported USB classes +********************* + +Audio +===== + +There is an experimental implementation of the Audio class. It follows specification +version 1.00 (``bcdADC 0x0100``) and supports synchronous synchronisation type only. +See :ref:`usb_audio_headphones_microphone` and :ref:`usb_audio_headset` for reference. + +Bluetooth HCI USB transport layer +================================= + +Bluetooth HCI USB transport layer implementation uses :ref:`bt_hci_raw` +to expose HCI interface to the host. It is not fully in line with the description +in the Bluetooth specification and consists only of an interface with the endpoint +configuration: + +* HCI commands through control endpoint (host-to-device only) +* HCI events through interrupt IN endpoint +* ACL data through one bulk IN and one bulk OUT endpoints + +A second interface for the voice channels has not been implemented as there is +no support for this type in :ref:`bluetooth`. It is not a big problem under Linux +if HCI USB transport layer is the only interface that appears in the configuration, +the btusb driver would not try to claim a second (isochronous) interface. +The consequence is that if HCI USB is used in a composite configuration and is +the first interface, then the Linux btusb driver will claim both the first and +the next interface, preventing other composite functions from working. +Because of this problem, HCI USB should not be used in a composite configuration. +This problem is fixed in the implementation for new USB support. + +See :ref:`bluetooth-hci-usb-sample` sample for reference. + +.. _usb_device_cdc_acm: + +CDC ACM +======= + +The CDC ACM class is used as backend for different subsystems in Zephyr. +However, its configuration may not be easy for the inexperienced user. +Below is a description of the different use cases and some pitfalls. + +The interface for CDC ACM user is :ref:`uart_api` driver API. +But there are two important differences in behavior to a real UART controller: + +* Data transfer is only possible after the USB device stack has been + initialized and started, until then any data is discarded +* If device is connected to the host, it still needs an application + on the host side which requests the data + +The devicetree compatible property for CDC ACM UART is +:dtcompatible:`zephyr,cdc-acm-uart`. +CDC ACM support is automatically selected when USB device support is enabled +and a compatible node in the devicetree sources is present. If necessary, +CDC ACM support can be explicitly disabled by :kconfig:option:`CONFIG_USB_CDC_ACM`. +About four CDC ACM UART instances can be defined and used, +limited by the maximum number of supported endpoints on the controller. + +CDC ACM UART node is supposed to be child of a USB device controller node. +Since the designation of the controller nodes varies from vendor to vendor, +and our samples and application should be as generic as possible, +the default USB device controller is usually assigned an ``zephyr_udc0`` +node label. Often, CDC ACM UART is described in a devicetree overlay file +and looks like this: + +.. code-block:: devicetree + + &zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + label = "CDC_ACM_0"; + }; + }; + +Samples :ref:`usb_cdc-acm` and :ref:`usb_hid-cdc` have similar overlay files. +And since no special properties are present, it may seem overkill to use +devicetree to describe CDC ACM UART. The motivation behind using devicetree +is the easy interchangeability of a real UART controller and CDC ACM UART +in applications. + +Console over CDC ACM UART +------------------------- + +With the CDC ACM UART node from above and ``zephyr,console`` property of the +chosen node, we can describe that CDC ACM UART is to be used with the console. +A similar overlay file is used by :ref:`cdc-acm-console`. + +.. code-block:: devicetree + + / { + chosen { + zephyr,console = &cdc_acm_uart0; + }; + }; + + &zephyr_udc0 { + cdc_acm_uart0: cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + label = "CDC_ACM_0"; + }; + }; + +Before the application uses the console, it is recommended to wait for +the DTR signal: + +.. code-block:: c + + const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + uint32_t dtr = 0; + + if (usb_enable(NULL)) { + return; + } + + while (!dtr) { + uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); + k_sleep(K_MSEC(100)); + } + + printk("nuqneH\n"); + +CDC ACM UART as backend +----------------------- + +As for the console sample, it is possible to configure CDC ACM UART as +backend for other subsystems by setting :ref:`devicetree-chosen-nodes` +properties. + +List of few Zephyr specific chosen properties which can be used to select +CDC ACM UART as backend for a subsystem or application: + +* ``zephyr,bt-c2h-uart`` used in Bluetooth, + for example see :ref:`bluetooth-hci-uart-sample` +* ``zephyr,ot-uart`` used in OpenThread, + for example see :ref:`coprocessor-sample` +* ``zephyr,shell-uart`` used by shell for serial backend, + for example see :zephyr_file:`samples/subsys/shell/shell_module` +* ``zephyr,uart-mcumgr`` used by :ref:`smp_svr_sample` + +DFU +=== + +USB DFU class implementation is tightly coupled to :ref:`dfu` and :ref:`mcuboot_api`. +This means that the target platform must support the :ref:`flash_img_api` API. + +See :ref:`usb_dfu` for reference. + +USB Human Interface Devices (HID) support +========================================= + +HID support abuses :ref:`device_model_api` simply to allow applications to use +the :c:func:`device_get_binding`. Note that there is no HID device API as such, +instead the interface is provided by :c:struct:`hid_ops`. +The default instance name is ``HID_n``, where n can be {0, 1, 2, ...} depending on +the :kconfig:option:`CONFIG_USB_HID_DEVICE_COUNT`. + +Each HID instance requires a HID report descriptor. The interface to the core +and the report descriptor must be registered using :c:func:`usb_hid_register_device`. + +As the USB HID specification is not only used by the USB subsystem, the USB HID API +reference is split into two parts, :ref:`usb_hid_common` and :ref:`usb_hid_device`. +HID helper macros from :ref:`usb_hid_common` should be used to compose a +HID report descriptor. Macro names correspond to those used in the USB HID specification. + +For the HID class interface, an IN interrupt endpoint is required for each instance, +an OUT interrupt endpoint is optional. Thus, the minimum implementation requirement +for :c:struct:`hid_ops` is to provide ``int_in_ready`` callback. + +.. code-block:: c + + #define REPORT_ID 1 + static bool configured; + static const struct device *hdev; + + static void int_in_ready_cb(const struct device *dev) + { + static uint8_t report[2] = {REPORT_ID, 0}; + + if (hid_int_ep_write(hdev, report, sizeof(report), NULL)) { + LOG_ERR("Failed to submit report"); + } else { + report[1]++; + } + } + + static void status_cb(enum usb_dc_status_code status, const uint8_t *param) + { + if (status == USB_DC_RESET) { + configured = false; + } + + if (status == USB_DC_CONFIGURED && !configured) { + int_in_ready_cb(hdev); + configured = true; + } + } + + static const uint8_t hid_report_desc[] = { + HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), + HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED), + HID_COLLECTION(HID_COLLECTION_APPLICATION), + HID_LOGICAL_MIN8(0x00), + HID_LOGICAL_MAX16(0xFF, 0x00), + HID_REPORT_ID(REPORT_ID), + HID_REPORT_SIZE(8), + HID_REPORT_COUNT(1), + HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED), + HID_INPUT(0x02), + HID_END_COLLECTION, + }; + + static const struct hid_ops my_ops = { + .int_in_ready = int_in_ready_cb, + }; + + int main(void) + { + int ret; + + hdev = device_get_binding("HID_0"); + if (hdev == NULL) { + return -ENODEV; + } + + usb_hid_register_device(hdev, hid_report_desc, sizeof(hid_report_desc), + &my_ops); + + ret = usb_hid_init(hdev); + if (ret) { + return ret; + } + + return usb_enable(status_cb); + } + + +If the application wishes to receive output reports via the OUT interrupt endpoint, +it must enable :kconfig:option:`CONFIG_ENABLE_HID_INT_OUT_EP` and provide +``int_out_ready`` callback. +The disadvantage of this is that Kconfig options such as +:kconfig:option:`CONFIG_ENABLE_HID_INT_OUT_EP` or +:kconfig:option:`CONFIG_HID_INTERRUPT_EP_MPS` apply to all instances. This design +issue will be fixed in the HID class implementation for the new USB support. + +See :ref:`usb_hid` or :ref:`usb_hid-mouse` for reference. + +Mass Storage Class +================== + +MSC follows Bulk-Only Transport specification and uses :ref:`disk_access_api` to +access and expose a RAM disk, emulated block device on a flash partition, +or SD Card to the host. Only one disk instance can be exported at a time. + +The disc to be used by the implementation is set by the +:kconfig:option:`CONFIG_MASS_STORAGE_DISK_NAME` and should be equal to one +of the options used by the disc access driver that the application wants to expose to +the host, :kconfig:option:`CONFIG_DISK_RAM_VOLUME_NAME`, +:kconfig:option:`CONFIG_MMC_VOLUME_NAME`, or :kconfig:option:`CONFIG_SDMMC_VOLUME_NAME`. + +For the emulated block device on a flash partition, the flash partition and +flash disk to be used must be described in the devicetree. If a storage partition +is already described at the board level, application devicetree overlay must also +delete ``storage_partition`` node first. :kconfig:option:`CONFIG_MASS_STORAGE_DISK_NAME` +should be the same as ``disk-name`` property. + +.. code-block:: devicetree + + /delete-node/ &storage_partition; + + &mx25r64 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0x00000000 0x00020000>; + }; + }; + }; + + / { + msc_disk0 { + compatible = "zephyr,flash-disk"; + partition = <&storage_partition>; + disk-name = "NAND"; + cache-size = <4096>; + }; + }; + +The ``disk-property`` "NAND" may be confusing, but it is simply how some file +systems identifies the disc. Therefore, if the application also accesses the +file system on the exposed disc, default names should be used, see +:ref:`usb_mass` for reference. + +Networking +========== + +There are three implementations that work in a similar way, providing a virtual +Ethernet connection between the remote (USB host) and Zephyr network support. + +* CDC ECM class, enabled with :kconfig:option:`CONFIG_USB_DEVICE_NETWORK_ECM` +* CDC EEM class, enabled with :kconfig:option:`CONFIG_USB_DEVICE_NETWORK_EEM` +* RNDIS support, enabled with :kconfig:option:`CONFIG_USB_DEVICE_NETWORK_RNDIS` + +See :ref:`zperf-sample` or :ref:`sockets-dumb-http-server-sample` for reference. +Typically, users will need to add a configuration file overlay to the build, +such as :zephyr_file:`samples/net/zperf/overlay-netusb.conf`. + +Applications using RNDIS support should enable :kconfig:option:`CONFIG_USB_DEVICE_OS_DESC` +for a better user experience on a host running Microsoft Windows OS. + +Binary Device Object Store (BOS) support +**************************************** + +BOS handling can be enabled with Kconfig option :kconfig:option:`CONFIG_USB_DEVICE_BOS`. +This option also has the effect of changing device descriptor ``bcdUSB`` to ``0210``. +The application should register descriptors such as Capability Descriptor +using :c:func:`usb_bos_register_cap`. Registered descriptors are added to the root +BOS descriptor and handled by the stack. + +See :ref:`webusb-sample` for reference. + +Implementing a non-standard USB class +************************************* + +The configuration of USB device is done in the stack layer. + +The following structures and callbacks need to be defined: + +* Part of USB Descriptor table +* USB Endpoint configuration table +* USB Device configuration structure +* Endpoint callbacks +* Optionally class, vendor and custom handlers + +For example, for the USB loopback application: + +.. literalinclude:: ../../../../subsys/usb/device/class/loopback.c + :language: c + :start-after: usb.rst config structure start + :end-before: usb.rst config structure end + :linenos: + +Endpoint configuration: + +.. literalinclude:: ../../../../subsys/usb/device/class/loopback.c + :language: c + :start-after: usb.rst endpoint configuration start + :end-before: usb.rst endpoint configuration end + :linenos: + +USB Device configuration structure: + +.. literalinclude:: ../../../../subsys/usb/device/class/loopback.c + :language: c + :start-after: usb.rst device config data start + :end-before: usb.rst device config data end + :linenos: + + +The vendor device requests are forwarded by the USB stack core driver to the +class driver through the registered vendor handler. + +For the loopback class driver, :c:func:`loopback_vendor_handler` processes +the vendor requests: + +.. literalinclude:: ../../../../subsys/usb/device/class/loopback.c + :language: c + :start-after: usb.rst vendor handler start + :end-before: usb.rst vendor handler end + :linenos: + +The class driver waits for the :makevar:`USB_DC_CONFIGURED` device status code +before transmitting any data. + +.. _testing_USB_native_posix: + +Testing over USPIP in native_posix +*********************************** + +A virtual USB controller implemented through USBIP might be used to test the USB +device stack. Follow the general build procedure to build the USB sample for +the native_posix configuration. + +Run built sample with: + +.. code-block:: console + + west build -t run + +In a terminal window, run the following command to list USB devices: + +.. code-block:: console + + $ usbip list -r localhost + Exportable USB devices + ====================== + - 127.0.0.1 + 1-1: unknown vendor : unknown product (2fe3:0100) + : /sys/devices/pci0000:00/0000:00:01.2/usb1/1-1 + : (Defined at Interface level) (00/00/00) + : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00) + +In a terminal window, run the following command to attach the USB device: + +.. code-block:: console + + $ sudo usbip attach -r localhost -b 1-1 + +The USB device should be connected to your Linux host, and verified with the +following commands: + +.. code-block:: console + + $ sudo usbip port + Imported USB devices + ==================== + Port 00: at Full Speed(12Mbps) + unknown vendor : unknown product (2fe3:0100) + 7-1 -> usbip://localhost:3240/1-1 + -> remote bus/dev 001/002 + $ lsusb -d 2fe3:0100 + Bus 007 Device 004: ID 2fe3:0100 + +USB Vendor and Product identifiers +********************************** + +The USB Vendor ID for the Zephyr project is ``0x2FE3``. +This USB Vendor ID must not be used when a vendor +integrates Zephyr USB device support into its own product. + +Each USB :ref:`sample` has its own unique Product ID. +The USB maintainer, if one is assigned, or otherwise the Zephyr Technical +Steering Committee, may allocate other USB Product IDs based on well-motivated +and documented requests. + +The following Product IDs are currently used: + ++-------------------------------------+--------+ +| Sample | PID | ++=====================================+========+ +| :ref:`usb_cdc-acm` | 0x0001 | ++-------------------------------------+--------+ +| :ref:`usb_cdc-acm_composite` | 0x0002 | ++-------------------------------------+--------+ +| :ref:`usb_hid-cdc` | 0x0003 | ++-------------------------------------+--------+ +| :ref:`cdc-acm-console` | 0x0004 | ++-------------------------------------+--------+ +| :ref:`usb_dfu` | 0x0005 | ++-------------------------------------+--------+ +| :ref:`usb_hid` | 0x0006 | ++-------------------------------------+--------+ +| :ref:`usb_hid-mouse` | 0x0007 | ++-------------------------------------+--------+ +| :ref:`usb_mass` | 0x0008 | ++-------------------------------------+--------+ +| :ref:`testusb-app` | 0x0009 | ++-------------------------------------+--------+ +| :ref:`webusb-sample` | 0x000A | ++-------------------------------------+--------+ +| :ref:`bluetooth-hci-usb-sample` | 0x000B | ++-------------------------------------+--------+ +| :ref:`bluetooth-hci-usb-h4-sample` | 0x000C | ++-------------------------------------+--------+ +| :ref:`wpanusb-sample` | 0x000D | ++-------------------------------------+--------+ + +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/doc/connectivity/usb/device_next/api/index.rst b/doc/connectivity/usb/device_next/api/index.rst new file mode 100644 index 000000000000..bbc5bfc47a96 --- /dev/null +++ b/doc/connectivity/usb/device_next/api/index.rst @@ -0,0 +1,10 @@ +.. _usb_device_next_api: + +New USB device support APIs +########################### + +.. toctree:: + :maxdepth: 1 + + udc.rst + usbd.rst diff --git a/doc/connectivity/usb/device_next/api/udc.rst b/doc/connectivity/usb/device_next/api/udc.rst new file mode 100644 index 000000000000..1e62c6a66ac4 --- /dev/null +++ b/doc/connectivity/usb/device_next/api/udc.rst @@ -0,0 +1,18 @@ +.. _udc_api: + +USB device controller (UDC) driver API +###################################### + +The USB device controller driver API is described in +:zephyr_file:`include/zephyr/drivers/usb/udc.h` and referred to +as the ``UDC driver`` API. + +UDC driver API is experimental and is subject to change without notice. +It is a replacement for :ref:`usb_dc_api`. If you wish to port an existing +driver to UDC driver API, or add a new driver, please use +:zephyr_file:`drivers/usb/udc/udc_skeleton.c` as a starting point. + +API reference +************* + +.. doxygengroup:: udc_api diff --git a/doc/connectivity/usb/device_next/api/usbd.rst b/doc/connectivity/usb/device_next/api/usbd.rst new file mode 100644 index 000000000000..3336b90cbbaf --- /dev/null +++ b/doc/connectivity/usb/device_next/api/usbd.rst @@ -0,0 +1,11 @@ +.. _usbd_api: + +USB device stack (next) API +########################### + +New USB device stack API is experimental and is subject to change without notice. + +API reference +************* + +.. doxygengroup:: usbd_api diff --git a/doc/connectivity/usb/device_next/usb_device.rst b/doc/connectivity/usb/device_next/usb_device.rst new file mode 100644 index 000000000000..c77553295388 --- /dev/null +++ b/doc/connectivity/usb/device_next/usb_device.rst @@ -0,0 +1,57 @@ +.. _usb_device_stack_next: + +New experimental USB device support +################################### + +Overview +******** + +The new USB device support is experimental. It consists of :ref:`udc_api` +and :ref:`usbd_api`. The new device stack brings support for multiple device +controllers, support for multiple configurations, and dynamic registration of +class instances to a configuration at runtime. The stack also provides a specific +class API that should be used to implement the functions (classes). +It will replace :ref:`usb_device_stack`. + +If you would like to play around with the new device support, or the new USB +support in general, please try :ref:`usb_shell-app`. The sample is mainly to help +test the capabilities of the stack and correct implementation of the USB controller +drivers. + +Supported USB classes +********************* + +Bluetooth HCI USB transport layer +================================= + +See :ref:`bluetooth-hci-usb-sample` sample for reference. +To build the sample for the new device support, set the configuration +``-DCONF_FILE=usbd_next_prj.conf`` either directly or via ``west``. + +CDC ACM +======= + +CDC ACM implementation has support for multiple instances. +Description from :ref:`usb_device_cdc_acm` also applies to the new implementation. +See :ref:`usb_cdc-acm` sample for reference. +To build the sample for the new device support, set the configuration +``-DCONF_FILE=usbd_next_prj.conf`` either directly or via ``west``. + +Mass Storage Class +================== + +See :ref:`usb_mass` sample for reference. +To build the sample for the new device support, set the configuration +``-DCONF_FILE=usbd_next_prj.conf`` either directly or via ``west``. + +Networking +========== + +At the moment only CDC ECM class is implemented and has support for multiple instances. +It provides a virtual Ethernet connection between the remote (USB host) and +Zephyr network support. + +See :ref:`zperf-sample` for reference. +To build the sample for the new device support, set the configuration overlay file +``-DDEXTRA_CONF_FILE=overlay-usbd_next_ecm.conf`` and devicetree overlay file +``-DDTC_OVERLAY_FILE="usbd_next_ecm.overlay`` either directly or via ``west``. diff --git a/doc/connectivity/usb/host/api/index.rst b/doc/connectivity/usb/host/api/index.rst new file mode 100644 index 000000000000..4e225dae2718 --- /dev/null +++ b/doc/connectivity/usb/host/api/index.rst @@ -0,0 +1,9 @@ +.. _usb_host_api: + +USB host support APIs +##################### + +.. toctree:: + :maxdepth: 1 + + uhc.rst diff --git a/doc/connectivity/usb/host/api/uhc.rst b/doc/connectivity/usb/host/api/uhc.rst new file mode 100644 index 000000000000..89623e9e6aee --- /dev/null +++ b/doc/connectivity/usb/host/api/uhc.rst @@ -0,0 +1,15 @@ +.. _uhc_api: + +USB host controller (UHC) driver API +#################################### + +The USB host controller driver API is described in +:zephyr_file:`include/zephyr/drivers/usb/uhc.h` and referred to +as the ``UHC driver`` API. + +UHC driver API is experimental and is subject to change without notice. + +Driver API reference +******************** + +.. doxygengroup:: uhc_api diff --git a/doc/connectivity/usb/index.rst b/doc/connectivity/usb/index.rst new file mode 100644 index 000000000000..94da8a61057d --- /dev/null +++ b/doc/connectivity/usb/index.rst @@ -0,0 +1,28 @@ +.. _usb: + +USB +### + +**USB device support** + +.. toctree:: + :maxdepth: 1 + + device/usb_device.rst + device/api/index.rst + +**New experimental USB support** + +.. toctree:: + :maxdepth: 1 + + device_next/usb_device.rst + device_next/api/index.rst + host/api/index.rst + +**Common sections related to USB support** + +.. toctree:: + :maxdepth: 1 + + api/hid.rst diff --git a/doc/services/index.rst b/doc/services/index.rst index 7e2e7641348f..b85d729b13da 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -28,7 +28,6 @@ OS Services storage/index.rst task_wdt/index.rst tfm/index - usb/index.rst virtualization/index.rst retention/index.rst rtio/index.rst diff --git a/doc/services/usb/hid.rst b/doc/services/usb/hid.rst deleted file mode 100644 index 9007a8cf343d..000000000000 --- a/doc/services/usb/hid.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. _usb_device_hid: - -USB Human Interface Devices (HID) support -######################################### - -Since the USB HID specification is not only used by the USB subsystem, the USB HID API -is split into two header files :zephyr_file:`include/zephyr/usb/class/hid.h` -and :zephyr_file:`include/zephyr/usb/class/usb_hid.h`. The second includes a specific -part for HID support in the USB device stack. - -HID Item helpers -**************** - -HID item helper macros can be used to compose a HID Report Descriptor. -The names correspond to those used in the USB HID Specification. - -Example of a HID Report Descriptor: - -.. code-block:: c - - static const uint8_t hid_report_desc[] = { - HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), - HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED), - HID_COLLECTION(HID_COLLECTION_APPLICATION), - HID_LOGICAL_MIN8(0), - /* logical maximum 255 */ - HID_LOGICAL_MAX16(0xFF, 0x00), - HID_REPORT_ID(1), - HID_REPORT_SIZE(8), - HID_REPORT_COUNT(1), - HID_USAGE(HID_USAGE_GEN_DESKTOP_UNDEFINED), - /* HID_INPUT (Data, Variable, Absolute) */ - HID_INPUT(0x02), - HID_END_COLLECTION, - }; - - -HID items reference -******************* - -.. doxygengroup:: usb_hid_items - -HID Mouse and Keyboard report descriptors -***************************************** - -The pre-defined Mouse and Keyboard report descriptors can be used by -a HID device implementation or simply as examples. - -.. doxygengroup:: usb_hid_mk_report_desc - -HID Class Device API reference -****************************** - -USB HID devices like mouse, keyboard, or any other specific device use this API. - -.. doxygengroup:: usb_hid_device_api diff --git a/doc/services/usb/index.rst b/doc/services/usb/index.rst deleted file mode 100644 index 0e8029b3dc0a..000000000000 --- a/doc/services/usb/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _usb_api: - -USB device support -################## - -.. toctree:: - :maxdepth: 1 - - udc.rst - uds.rst - uds_testing.rst - hid.rst - uds_cdc_acm.rst - -New USB device support -###################### - -.. toctree:: - :maxdepth: 1 - - uds_next.rst - -USB host support -################ - -.. toctree:: - :maxdepth: 1 - - uhc.rst diff --git a/doc/services/usb/udc.rst b/doc/services/usb/udc.rst deleted file mode 100644 index 02d95d4add50..000000000000 --- a/doc/services/usb/udc.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _udc_api: - -USB device controller driver -############################ - -The USB Device Controller Driver Layer implements the low level control routines -to deal directly with the hardware. All device controller drivers should -implement the APIs described in :zephyr_file:`include/zephyr/drivers/usb/usb_dc.h`. -This allows the integration of new USB device controllers to be done without -changing the upper layers. -With this API it is not possible to support more than one controller -instance at runtime. - -API reference -************* - -.. doxygengroup:: _usb_device_controller_api diff --git a/doc/services/usb/uds.rst b/doc/services/usb/uds.rst deleted file mode 100644 index 20438b524b64..000000000000 --- a/doc/services/usb/uds.rst +++ /dev/null @@ -1,164 +0,0 @@ -.. _usb_device_stack: - -USB device stack -################ - -The USB device stack is a hardware independent interface between USB -device controller driver and USB device class drivers or customer applications. -It is a port of the LPCUSB device stack and has been modified and expanded -over time. It provides the following functionalities: - -* Uses the APIs provided by the device controller drivers to interact with - the USB device controller. -* Responds to standard device requests and returns standard descriptors, - essentially handling 'Chapter 9' processing, specifically the standard - device requests in table 9-3 from the universal serial bus specification - revision 2.0. -* Provides a programming interface to be used by USB device classes or - customer applications. The APIs is described in - :zephyr_file:`include/zephyr/usb/usb_device.h` - -The device stack has few limitations with which it is not possible to support -more than one controller instance at runtime, and only one USB device -configuration is supported. - -Supported USB classes: - -* USB Audio (experimental) -* USB CDC ACM -* USB CDC ECM -* USB CDC EEM -* RNDIS -* USB MSC -* USB DFU -* Bluetooth HCI over USB -* USB HID class - -:ref:`List` of samples for different purposes. -CDC ACM and HID samples have configuration overlays for composite configuration. - -Implementing a non-standard USB class -************************************* - -The configuration of USB Device is done in the stack layer. - -The following structures and callbacks need to be defined: - -* Part of USB Descriptor table -* USB Endpoint configuration table -* USB Device configuration structure -* Endpoint callbacks -* Optionally class, vendor and custom handlers - -For example, for the USB loopback application: - -.. literalinclude:: ../../../subsys/usb/device/class/loopback.c - :language: c - :start-after: usb.rst config structure start - :end-before: usb.rst config structure end - :linenos: - -Endpoint configuration: - -.. literalinclude:: ../../../subsys/usb/device/class/loopback.c - :language: c - :start-after: usb.rst endpoint configuration start - :end-before: usb.rst endpoint configuration end - :linenos: - -USB Device configuration structure: - -.. literalinclude:: ../../../subsys/usb/device/class/loopback.c - :language: c - :start-after: usb.rst device config data start - :end-before: usb.rst device config data end - :linenos: - - -The vendor device requests are forwarded by the USB stack core driver to the -class driver through the registered vendor handler. - -For the loopback class driver, :c:func:`loopback_vendor_handler` processes -the vendor requests: - -.. literalinclude:: ../../../subsys/usb/device/class/loopback.c - :language: c - :start-after: usb.rst vendor handler start - :end-before: usb.rst vendor handler end - :linenos: - -The class driver waits for the :makevar:`USB_DC_CONFIGURED` device status code -before transmitting any data. - -.. _testing_USB_native_posix: - -USB Vendor and Product identifiers -********************************** - -The USB Vendor ID for the Zephyr project is ``0x2FE3``. -This USB Vendor ID must not be used when a vendor -integrates Zephyr USB device support into its own product. - -Each USB sample has its own unique Product ID. -The USB maintainer, if one is assigned, or otherwise the Zephyr Technical -Steering Committee, may allocate other USB Product IDs based on well-motivated -and documented requests. - -The following Product IDs are currently used: - -+-------------------------------------+--------+ -| Sample | PID | -+=====================================+========+ -| :ref:`usb_cdc-acm` | 0x0001 | -+-------------------------------------+--------+ -| :ref:`usb_cdc-acm_composite` | 0x0002 | -+-------------------------------------+--------+ -| :ref:`usb_hid-cdc` | 0x0003 | -+-------------------------------------+--------+ -| :ref:`cdc-acm-console` | 0x0004 | -+-------------------------------------+--------+ -| :ref:`usb_dfu` | 0x0005 | -+-------------------------------------+--------+ -| :ref:`usb_hid` | 0x0006 | -+-------------------------------------+--------+ -| :ref:`usb_hid-mouse` | 0x0007 | -+-------------------------------------+--------+ -| :ref:`usb_mass` | 0x0008 | -+-------------------------------------+--------+ -| :ref:`testusb-app` | 0x0009 | -+-------------------------------------+--------+ -| :ref:`webusb-sample` | 0x000A | -+-------------------------------------+--------+ -| :ref:`bluetooth-hci-usb-sample` | 0x000B | -+-------------------------------------+--------+ -| :ref:`bluetooth-hci-usb-h4-sample` | 0x000C | -+-------------------------------------+--------+ -| :ref:`wpanusb-sample` | 0x000D | -+-------------------------------------+--------+ - -The USB device descriptor field ``bcdDevice`` (Device Release Number) represents -the Zephyr kernel major and minor versions as a binary coded decimal value. - -API reference -************* - -There are two ways to transmit data, using the 'low' level read/write API or -the 'high' level transfer API. - -Low level API - To transmit data to the host, the class driver should call usb_write(). - Upon completion the registered endpoint callback will be called. Before - sending another packet the class driver should wait for the completion of - the previous write. When data is received, the registered endpoint callback - is called. usb_read() should be used for retrieving the received data. - For CDC ACM sample driver this happens via the OUT bulk endpoint handler - (cdc_acm_bulk_out) mentioned in the endpoint array (cdc_acm_ep_data). - -High level API - The usb_transfer method can be used to transfer data to/from the host. The - transfer API will automatically split the data transmission into one or more - USB transaction(s), depending endpoint max packet size. The class driver does - not have to implement endpoint callback and should set this callback to the - generic usb_transfer_ep_callback. - -.. doxygengroup:: _usb_device_core_api diff --git a/doc/services/usb/uds_cdc_acm.rst b/doc/services/usb/uds_cdc_acm.rst deleted file mode 100644 index 09c75388e853..000000000000 --- a/doc/services/usb/uds_cdc_acm.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. _usb_device_cdc_acm: - -USB device stack CDC ACM support -################################ - -The CDC ACM class is used as backend for different subsystems in Zephyr. -However, its configuration may not be easy for the inexperienced user. -Below is a description of the different use cases and some pitfalls. - -The interface for CDC ACM user is :ref:`uart_api` driver API. -But there are two important differences in behavior to a real UART controller: - -* Data transfer is only possible after the USB device stack has been initialized and started, - until then any data is discarded -* If device is connected to the host, it still needs an application - on the host side which requests the data - -The devicetree compatible property for CDC ACM UART is -:dtcompatible:`zephyr,cdc-acm-uart`. -CDC ACM support is automatically selected when USB device support is enabled -and a compatible node in the devicetree sources is present. If necessary, -CDC ACM support can be explicitly disabled by :kconfig:option:`CONFIG_USB_CDC_ACM`. -About four CDC ACM UART instances can be defined and used, -limited by the maximum number of supported endpoints on the controller. - -CDC ACM UART node is supposed to be child of a USB device controller node. -Since the designation of the controller nodes varies from vendor to vendor, -and our samples and application should be as generic as possible, -the default USB device controller is usually assigned an ``zephyr_udc0`` -node label. Often, CDC ACM UART is described in a devicetree overlay file -and looks like this: - -.. code-block:: devicetree - - &zephyr_udc0 { - cdc_acm_uart0: cdc_acm_uart0 { - compatible = "zephyr,cdc-acm-uart"; - label = "CDC_ACM_0"; - }; - }; - -Samples :ref:`usb_cdc-acm` and :ref:`usb_hid-cdc` have similar overlay files. -And since no special properties are present, it may seem overkill to use -devicetree to describe CDC ACM UART. The motivation behind using devicetree -is the easy interchangeability of a real UART controller and CDC ACM UART -in applications. - -Console over CDC ACM UART -************************* - -With the CDC ACM UART node from above and ``zephyr,console`` property of the -chosen node, we can describe that CDC ACM UART is to be used with the console. -A similar overlay file is used by :ref:`cdc-acm-console`. - -.. code-block:: devicetree - - / { - chosen { - zephyr,console = &cdc_acm_uart0; - }; - }; - - &zephyr_udc0 { - cdc_acm_uart0: cdc_acm_uart0 { - compatible = "zephyr,cdc-acm-uart"; - label = "CDC_ACM_0"; - }; - }; - -Before the application uses the console, it is recommended to wait for -the DTR signal: - -.. code-block:: c - - const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); - uint32_t dtr = 0; - - if (usb_enable(NULL)) { - return; - } - - while (!dtr) { - uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); - k_sleep(K_MSEC(100)); - } - - printk("nuqneH\n"); - -CDC ACM UART as backend -*********************** - -As for the console sample, it is possible to configure CDC ACM UART as -backend for other subsystems by setting :ref:`devicetree-chosen-nodes` -properties. - -List of few Zephyr specific chosen properties which can be used to select -CDC ACM UART as backend for a subsystem or application: - -* ``zephyr,bt-c2h-uart`` used in Bluetooth, - for example see :ref:`bluetooth-hci-uart-sample` -* ``zephyr,ot-uart`` used in OpenThread, - for example see :ref:`coprocessor-sample` -* ``zephyr,shell-uart`` used by shell for serial backend, - for example see :zephyr_file:`samples/subsys/shell/shell_module` -* ``zephyr,uart-mcumgr`` used by :ref:`smp_svr_sample` diff --git a/doc/services/usb/uds_next.rst b/doc/services/usb/uds_next.rst deleted file mode 100644 index 7ca335a3f636..000000000000 --- a/doc/services/usb/uds_next.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _uds_next: - -USB device core support -####################### - -The new USB device support is experimental and under development. It consists -of low level USB device controller (UDC) driver API, USB device stack (core) -and different functions implementing specific classes. The device stack and -driver API bring multiple device support for the (rare) case that a board has -multiple USB device controllers. Device stack has support for multiple -configurations and a class instance can be added or removed at runtime to a -configuration. The stack provides a specific API for implementing the -functions (classes). This takes over the configuration of the class interfaces -and endpoints, and also the communication with the stack and driver API. -The stack can be enabled by the :kconfig:option:`CONFIG_USB_DEVICE_STACK_NEXT`. - -The first time there will be only one sample for the new USB support, -:ref:`usb_shell-app`, with all available USB support shell commands. -The sample is mainly to help test the capabilities of the stack and correct -implementation of the USB controller drivers. - -USB device stack core API reference -*********************************** - -.. doxygengroup:: usbd_api - -UDC driver API reference -************************ - -The new USB device controller (UDC) driver API implements the low level layer -to interface with USB device controller. -UDC driver API is experimental and is subject to change without notice, it -is described in :zephyr_file:`include/drivers/usb/udc.h`. - -.. doxygengroup:: udc_api diff --git a/doc/services/usb/uds_testing.rst b/doc/services/usb/uds_testing.rst deleted file mode 100644 index 34d80fddf475..000000000000 --- a/doc/services/usb/uds_testing.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. _usb_device_testing: - -Testing USB device support -########################## - -Testing over USPIP in native_posix -*********************************** - -A virtual USB controller implemented through USBIP might be used to test the USB -Device stack. Follow the general build procedure to build the USB sample for -the native_posix configuration. - -Run built sample with: - -.. code-block:: console - - west build -t run - -In a terminal window, run the following command to list USB devices: - -.. code-block:: console - - $ usbip list -r localhost - Exportable USB devices - ====================== - - 127.0.0.1 - 1-1: unknown vendor : unknown product (2fe3:0100) - : /sys/devices/pci0000:00/0000:00:01.2/usb1/1-1 - : (Defined at Interface level) (00/00/00) - : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00) - -In a terminal window, run the following command to attach the USB device: - -.. code-block:: console - - $ sudo usbip attach -r localhost -b 1-1 - -The USB device should be connected to your Linux host, and verified with the following commands: - -.. code-block:: console - - $ sudo usbip port - Imported USB devices - ==================== - Port 00: at Full Speed(12Mbps) - unknown vendor : unknown product (2fe3:0100) - 7-1 -> usbip://localhost:3240/1-1 - -> remote bus/dev 001/002 - $ lsusb -d 2fe3:0100 - Bus 007 Device 004: ID 2fe3:0100 diff --git a/doc/services/usb/uhc.rst b/doc/services/usb/uhc.rst deleted file mode 100644 index 8bf81acd17c5..000000000000 --- a/doc/services/usb/uhc.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _uhc_api: - -USB host controller driver API -############################## - -The USB host controller (UHC) driver API implements the low level layer -to interface with the host controller. All USB host controller drivers -should implement the APIs described in :zephyr_file:`include/zephyr/drivers/usb/uhc.h`. - -UHC driver API is experimental and is subject to change without notice. - -Driver API reference -******************** - -.. doxygengroup:: uhc_api From fbb6cd1a39993cb4878f20e4736006566026401a Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Wed, 14 Jun 2023 18:18:15 +0200 Subject: [PATCH 0163/2042] doc: connectivity: move USB-C device stack to USB chapter This looks a bit lost in its own USB-C chapter, move it to USB under the Power Delivery heading. Signed-off-by: Johann Fischer --- MAINTAINERS.yml | 2 +- doc/connectivity/index.rst | 1 - doc/connectivity/usb/index.rst | 7 ++++ doc/connectivity/{usb_c => usb/pd}/ucds.rst | 38 ++++++++++----------- doc/connectivity/usb_c/index.rst | 9 ----- 5 files changed, 27 insertions(+), 30 deletions(-) rename doc/connectivity/{usb_c => usb/pd}/ucds.rst (80%) delete mode 100644 doc/connectivity/usb_c/index.rst diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b7ff4a12e1a0..784d882a899c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2636,7 +2636,7 @@ USB-C: - include/zephyr/usb_c/ - samples/subsys/usb_c/ - subsys/usb/usb_c/ - - doc/connectivity/usb_c/ + - doc/connectivity/usb/pd/ labels: - "area: USB-C" diff --git a/doc/connectivity/index.rst b/doc/connectivity/index.rst index c3799eb15e12..c135ed410bb1 100644 --- a/doc/connectivity/index.rst +++ b/doc/connectivity/index.rst @@ -10,4 +10,3 @@ Connectivity networking/index.rst lora_lorawan/index.rst usb/index.rst - usb_c/index.rst diff --git a/doc/connectivity/usb/index.rst b/doc/connectivity/usb/index.rst index 94da8a61057d..b24bcb9954b4 100644 --- a/doc/connectivity/usb/index.rst +++ b/doc/connectivity/usb/index.rst @@ -20,6 +20,13 @@ USB device_next/api/index.rst host/api/index.rst +**USB Power Delivery support** + +.. toctree:: + :maxdepth: 1 + + pd/ucds.rst + **Common sections related to USB support** .. toctree:: diff --git a/doc/connectivity/usb_c/ucds.rst b/doc/connectivity/usb/pd/ucds.rst similarity index 80% rename from doc/connectivity/usb_c/ucds.rst rename to doc/connectivity/usb/pd/ucds.rst index 569f784eae24..a64b7ed63c2f 100644 --- a/doc/connectivity/usb_c/ucds.rst +++ b/doc/connectivity/usb/pd/ucds.rst @@ -1,4 +1,4 @@ -.. _usbc_device_stack: +.. _usbc_api: USB-C device stack ################## @@ -36,7 +36,7 @@ For example, for the Sample USB-C Sink application: Each Physical Type-C port is represented in the devicetree by a usb-c-connector compatible node: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay :language: dts :start-after: usbc.rst usbc-port start :end-before: usbc.rst usbc-port end @@ -45,7 +45,7 @@ compatible node: VBUS is measured by a device that's referenced in the devicetree by a usb-c-vbus-adc compatible node: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/boards/b_g474e_dpow1.overlay :language: dts :start-after: usbc.rst vbus-voltage-divider-adc start :end-before: usbc.rst vbus-voltage-divider-adc end @@ -55,7 +55,7 @@ usb-c-vbus-adc compatible node: A user defined structure is defined and later registered with the subsystem and can be accessed from callback through an API: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst port data object start :end-before: usbc.rst port data object end @@ -63,7 +63,7 @@ be accessed from callback through an API: These callbacks are used by the subsystem to set or get application specific data: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst callbacks start :end-before: usbc.rst callbacks end @@ -71,7 +71,7 @@ These callbacks are used by the subsystem to set or get application specific dat This callback is used by the subsystem to query if a certain action can be taken: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst check start :end-before: usbc.rst check end @@ -79,7 +79,7 @@ This callback is used by the subsystem to query if a certain action can be taken This callback is used by the subsystem to notify the application of an event: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst notify start :end-before: usbc.rst notify end @@ -87,7 +87,7 @@ This callback is used by the subsystem to notify the application of an event: Registering the callbacks: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst register start :end-before: usbc.rst register end @@ -95,7 +95,7 @@ Registering the callbacks: Register the user defined structure: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst user data start :end-before: usbc.rst user data end @@ -103,7 +103,7 @@ Register the user defined structure: Start the USB-C subsystem: -.. literalinclude:: ../../../samples/subsys/usb_c/sink/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/sink/src/main.c :language: c :start-after: usbc.rst usbc start :end-before: usbc.rst usbc end @@ -126,7 +126,7 @@ For example, for the Sample USB-C Source application: Each Physical Type-C port is represented in the devicetree by a ``usb-c-connector`` compatible node: -.. literalinclude:: ../../../samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay +.. literalinclude:: ../../../../samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay :language: dts :start-after: usbc.rst usbc-port start :end-before: usbc.rst usbc-port end @@ -135,7 +135,7 @@ compatible node: VBUS is measured by a device that's referenced in the devicetree by a ``usb-c-vbus-adc`` compatible node: -.. literalinclude:: ../../../samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay +.. literalinclude:: ../../../../samples/subsys/usb_c/source/boards/stm32g081b_eval.overlay :language: dts :start-after: usbc.rst vbus-voltage-divider-adc start :end-before: usbc.rst vbus-voltage-divider-adc end @@ -145,7 +145,7 @@ VBUS is measured by a device that's referenced in the devicetree by a A user defined structure is defined and later registered with the subsystem and can be accessed from callback through an API: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst port data object start :end-before: usbc.rst port data object end @@ -153,7 +153,7 @@ be accessed from callback through an API: These callbacks are used by the subsystem to set or get application specific data: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst callbacks start :end-before: usbc.rst callbacks end @@ -161,7 +161,7 @@ These callbacks are used by the subsystem to set or get application specific dat This callback is used by the subsystem to query if a certain action can be taken: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst check start :end-before: usbc.rst check end @@ -169,7 +169,7 @@ This callback is used by the subsystem to query if a certain action can be taken This callback is used by the subsystem to notify the application of an event: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst notify start :end-before: usbc.rst notify end @@ -177,7 +177,7 @@ This callback is used by the subsystem to notify the application of an event: Registering the callbacks: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst register start :end-before: usbc.rst register end @@ -185,7 +185,7 @@ Registering the callbacks: Register the user defined structure: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst user data start :end-before: usbc.rst user data end @@ -193,7 +193,7 @@ Register the user defined structure: Start the USB-C subsystem: -.. literalinclude:: ../../../samples/subsys/usb_c/source/src/main.c +.. literalinclude:: ../../../../samples/subsys/usb_c/source/src/main.c :language: c :start-after: usbc.rst usbc start :end-before: usbc.rst usbc end diff --git a/doc/connectivity/usb_c/index.rst b/doc/connectivity/usb_c/index.rst deleted file mode 100644 index c28931d59be6..000000000000 --- a/doc/connectivity/usb_c/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _usbc_api: - -USB-C device support -#################### - -.. toctree:: - :maxdepth: 1 - - ucds.rst From ecf2cb5932156c889b7886609a652abe79cc16fa Mon Sep 17 00:00:00 2001 From: Maxim Adelman Date: Wed, 14 Jun 2023 11:33:14 -0400 Subject: [PATCH 0164/2042] kernel shell, stacks shell commands: iterate unlocked on SMP call k_thread_foreach_unlocked to avoid assertions caused by calling shell_print while holding a global lock Signed-off-by: Maxim Adelman --- subsys/shell/modules/kernel_service.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subsys/shell/modules/kernel_service.c b/subsys/shell/modules/kernel_service.c index 531384c714b0..065cdcb4b968 100644 --- a/subsys/shell/modules/kernel_service.c +++ b/subsys/shell/modules/kernel_service.c @@ -164,7 +164,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 + k_thread_foreach_unlocked(shell_tdata_dump, (void *)sh); +#else k_thread_foreach(shell_tdata_dump, (void *)sh); +#endif return 0; } @@ -208,7 +213,11 @@ static int cmd_kernel_stacks(const struct shell *sh, memset(pad, ' ', MAX((THREAD_MAX_NAM_LEN - strlen("IRQ 00")), 1)); +#ifdef CONFIG_SMP + 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 c9f8b8b78aa492a8a077ddb455575f5b0efe8a02 Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Thu, 15 Jun 2023 14:12:43 +0200 Subject: [PATCH 0165/2042] drivers: sensor: shtcx: fix val2 calculation The calculation of the sensor val2 did not correctly take the sign into account. Signed-off-by: Thomas Stranger --- drivers/sensor/shtcx/shtcx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/shtcx/shtcx.c b/drivers/sensor/shtcx/shtcx.c index 69b96d2b3558..9e670087493e 100644 --- a/drivers/sensor/shtcx/shtcx.c +++ b/drivers/sensor/shtcx/shtcx.c @@ -53,7 +53,7 @@ static void shtcx_temperature_from_raw(uint16_t raw, struct sensor_value *val) tmp = (int32_t)raw * 175U - (45 << 16); val->val1 = tmp / 0x10000; /* x * 1.000.000 / 65.536 == x * 15625 / 2^10 */ - val->val2 = ((tmp % 0x10000) * 15625U) / 1024; + val->val2 = ((tmp % 0x10000) * 15625) / 1024; } /* val = 100 * sample / (2^16) */ From 644d02480e2650f65ad703864770741f00ee6a9b Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 15 Jun 2023 13:53:26 +0200 Subject: [PATCH 0166/2042] doc: release-notes-3.4: add release notes for USB and display Add release notes for USB support and display controller drivers. Signed-off-by: Johann Fischer --- doc/releases/release-notes-3.4.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 4908a3a25468..122db4cac811 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -799,6 +799,10 @@ Drivers and Sensors * Display + * Improved MCUX ELCDIF and SSD16XX display controller drivers + * Added support for ILI9342C display controller + * Added support for OTM8009A panel + * DMA * STM32C0: Added support for DMA @@ -989,6 +993,11 @@ Drivers and Sensors * USB * Added remote wakeup support for the RP2040 SoC + * Added Battery Charging (BC12) API and PI3USB9201 driver implementation. + * Added new USB device controller drivers (using usb_dc API) for ITE IT82xx2 + and smartbond platforms. + * Added USB device controller driver skeleton for UDC API. + * Reworked DWC2 driver and added support for STM32F4 SoC family * W1 @@ -1206,6 +1215,17 @@ Networking USB *** +* USB device support + + * Fixed control endpoint handling with MPS of 8 bytes. + +* New experimental USB support + + * Various improvements for new device support, better string descriptor support, + implemented usbd_class_shutdown API. + * Added USB Mass Storage class and CDC ECM class implementations for the new + device support. + Devicetree ********** From 721e4aa8b31723e16723e7fb2155f7d7741af91a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 14 Jun 2023 15:15:55 +0000 Subject: [PATCH 0167/2042] release: fix layout/typos in release notes Fixed layout and a few typos. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 31 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 122db4cac811..bee2f48c7ade 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -10,25 +10,24 @@ We are pleased to announce the release of Zephyr version 3.4.0. Major enhancements with this release include: * Input subsystem: handles input events from various types of input devices and - distribute them to other threads in the application. -* Barrierr API: add architecture agnostic API for data memory barriers. + distributes them to other threads in the application. +* Barrier API: add architecture agnostic API for data memory barriers. * USB Device support: - * USB device controller API (UDC API) - * USB device controller API and nRF USBD controller driver. - * USB device stack implementation using new UDC API + * USB device controller API (UDC API) and nRF USBD controller driver. + * USB device stack implementation using new UDC API. -* Added Power Delivery Source Support to the USB-C Stack -* Bluetooth: Added support for Periodic Advertising with Responses (PAwR) -* Cache API functions are now fully inlined by compilers. +* Added Power Delivery Source Support to the USB-C Stack. +* Bluetooth: Added support for Periodic Advertising with Responses (PAwR). +* Cache API functions are now fully in-lined by compilers. * Added an API for real-time clocks (RTC). -* Added Retention subsystem -* Added initial support for MMU on Xtensa -* SMBus (System Management Bus) API +* Added Retention subsystem. +* Added initial support for MMU on Xtensa. +* SMBus (System Management Bus) API. * Various improvements to the testing framework and twister: - Introduction of 3 new test harnesses into twister supporting pyTest, - GoogleTest and RobotFramework + GoogleTest and Robot Framework. - Transitioning to new Ztest API was completed and legacy Ztest was deprecated. * Added Snippets: Support common configuration settings that can be used across @@ -155,7 +154,7 @@ Changes in this release names from ``KSCAN_NPCX_...`` to ``INPUT_NPCX_KBD...`` and the compatible from ``nuvoton,npcx-kscan`` to :dtcompatible:`nuvoton,npcx-kbd`. * Touchscreen drivers converted to use the input APIs can use the - :dtcompatible:`zephyr,kscan-input` driver to maintain Kscan compatilibity. + :dtcompatible:`zephyr,kscan-input` driver to maintain Kscan compatibility. * The declaration of :c:func:`main` has been changed from ``void main(void)`` to ``int main(void)``. The main function is required to @@ -223,7 +222,7 @@ Deprecated in this release board-specific configuration in board Kconfig fragments in the ``boards`` folder of the application. -* On nRF51 and nRF52-based boards, the behaviour of the reset reason being +* On nRF51 and nRF52-based boards, the behavior of the reset reason being provided to :c:func:`sys_reboot` and being set in the GPREGRET register has been dropped. This function will now just reboot the device without changing the register contents. The new method for setting this register uses the boot @@ -235,11 +234,13 @@ Deprecated in this release * Deprecated :c:macro:`PTHREAD_BARRIER_DEFINE` in favor of the standardized :c:func:`pthread_barrier_init` -* On all STM32 targets except STM32F2 series, ethernet drivers implementation +* On all STM32 targets except STM32F2 series, Ethernet drivers implementation based on STM32Cube Ethernet API V1 (:kconfig:option:`CONFIG_ETH_STM32_HAL_API_V1`) is now deprecated in favor of implementation based on more reliable and performant STM32Cube Ethernet API V2. +* Legacy Ztest API was deprecated. All new tests shall use the new Ztest API. + Stable API changes in this release ================================== From c59b57c0be2addcc11ffb6aa677facd53eebd89f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:51:32 +0200 Subject: [PATCH 0168/2042] soc: esp32*: do not enable HAS_DYNAMIC_DEVICE_HANDLES It doesn't make sense to select this option at SoC level. This feature is meant for subsystems/modules that need device handles to be modifiable at runtime. Signed-off-by: Gerard Marull-Paretas --- soc/riscv/esp32c3/Kconfig.defconfig | 3 --- soc/xtensa/esp32/Kconfig.defconfig | 3 --- soc/xtensa/esp32s3/Kconfig.defconfig | 3 --- 3 files changed, 9 deletions(-) diff --git a/soc/riscv/esp32c3/Kconfig.defconfig b/soc/riscv/esp32c3/Kconfig.defconfig index 284aa77347f9..adc9eca040ea 100644 --- a/soc/riscv/esp32c3/Kconfig.defconfig +++ b/soc/riscv/esp32c3/Kconfig.defconfig @@ -19,9 +19,6 @@ config MCUBOOT_GENERATE_CONFIRMED_IMAGE config ROM_START_OFFSET default 0x20 -config HAS_DYNAMIC_DEVICE_HANDLES - default y - endif config SOC diff --git a/soc/xtensa/esp32/Kconfig.defconfig b/soc/xtensa/esp32/Kconfig.defconfig index c6af5cb81c33..229f6fb02e7c 100644 --- a/soc/xtensa/esp32/Kconfig.defconfig +++ b/soc/xtensa/esp32/Kconfig.defconfig @@ -17,9 +17,6 @@ if BOOTLOADER_MCUBOOT config ROM_START_OFFSET default 0x20 - - config HAS_DYNAMIC_DEVICE_HANDLES - default y endif config SOC diff --git a/soc/xtensa/esp32s3/Kconfig.defconfig b/soc/xtensa/esp32s3/Kconfig.defconfig index b20609d27c0e..864bc1351562 100644 --- a/soc/xtensa/esp32s3/Kconfig.defconfig +++ b/soc/xtensa/esp32s3/Kconfig.defconfig @@ -17,9 +17,6 @@ if BOOTLOADER_MCUBOOT config ROM_START_OFFSET default 0x20 - - config HAS_DYNAMIC_DEVICE_HANDLES - default y endif config SOC From 785d9bdc6709ed47616aec2ef09fabcea4e06ddf Mon Sep 17 00:00:00 2001 From: Aedan Cullen Date: Tue, 6 Jun 2023 02:54:06 -0400 Subject: [PATCH 0169/2042] drivers: display: fix zero-buffers-in-SRAM case in DCNANO LCDIF If CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM is not set and CONFIG_MCUX_DCNANO_LCDIF_FB_NUM is zero, a division by zero occurs. Use the same framebuffer size definition as in the external-framebuffer case to resolve this. Fixes #58908. Signed-off-by: Aedan Cullen --- drivers/display/display_mcux_dcnano_lcdif.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/display/display_mcux_dcnano_lcdif.c b/drivers/display/display_mcux_dcnano_lcdif.c index 7b4371aa74f5..a6ff62412c45 100644 --- a/drivers/display/display_mcux_dcnano_lcdif.c +++ b/drivers/display/display_mcux_dcnano_lcdif.c @@ -258,6 +258,8 @@ static const struct display_driver_api mcux_dcnano_lcdif_api = { #define MCUX_DCNANO_LCDIF_PIXEL_BYTES(n) \ (DISPLAY_BITS_PER_PIXEL(DT_INST_PROP(n, pixel_format)) / 8) +#define MCUX_DCNANO_LCDIF_FB_SIZE(n) DT_INST_PROP(n, width) * \ + DT_INST_PROP(n, height) * MCUX_DCNANO_LCDIF_PIXEL_BYTES(n) /* When using external framebuffer mem, we should not allocate framebuffers * in SRAM. Instead, we use external framebuffer address and size @@ -265,8 +267,6 @@ static const struct display_driver_api mcux_dcnano_lcdif_api = { */ #ifdef CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM #define MCUX_DCNANO_LCDIF_FRAMEBUFFER_DECL(n) -#define MCUX_DCNANO_LCDIF_FB_SIZE(n) DT_INST_PROP(n, width) * \ - DT_INST_PROP(n, height) * MCUX_DCNANO_LCDIF_PIXEL_BYTES(n) #define MCUX_DCNANO_LCDIF_FRAMEBUFFER(n) \ (uint8_t *)CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_ADDR #else @@ -275,8 +275,6 @@ static const struct display_driver_api mcux_dcnano_lcdif_api = { DT_INST_PROP(n, height) * \ MCUX_DCNANO_LCDIF_PIXEL_BYTES(n) * \ CONFIG_MCUX_DCNANO_LCDIF_FB_NUM] -#define MCUX_DCNANO_LCDIF_FB_SIZE(n) \ - sizeof(mcux_dcnano_lcdif_frame_buffer_##n) / CONFIG_MCUX_DCNANO_LCDIF_FB_NUM #define MCUX_DCNANO_LCDIF_FRAMEBUFFER(n) mcux_dcnano_lcdif_frame_buffer_##n #endif From f683b0f35e493d8165ed03079faef92933147f2d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 15 Jun 2023 08:24:50 -0700 Subject: [PATCH 0170/2042] doc: release-notes: Security related release-notes-3 Added information about CVEs fixed during 3.4 release. Signed-off-by: Flavio Ceolin --- doc/releases/release-notes-3.4.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index bee2f48c7ade..b75d481db093 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -38,6 +38,15 @@ The following sections provide detailed lists of changes by component. Security Vulnerability Related ****************************** +The following CVEs are addressed by this release: + +More detailed information can be found in: +https://docs.zephyrproject.org/latest/security/vulnerabilities.html + +* CVE-2023-1901: Under embargo until 2023-07-04 + +* CVE-2023-1902: Under embargo until 2023-07-04 + API Changes *********** From b7f35a8f29218af3a0faf9ca8090ead3e8bf212e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 15 Jun 2023 08:26:27 -0700 Subject: [PATCH 0171/2042] doc: vulnerabilities: Add information about new vulnerabilities Add a placeholder for CVE-2023-1901 and CVE-2023-1902. Signed-off-by: Flavio Ceolin --- doc/security/vulnerabilities.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index 85fbe09deb5b..81e92f8e9dca 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1312,3 +1312,13 @@ This has been fixed in main for v3.3.0 - `PR 54381 fix for v2.7.4 `_ + +CVE-2023-1901 +------------- + +Under embargo until 2023/07/04 + +CVE-2023-1902 +------------- + +Under embargo until 2023/07/04 From 68dc53b0779a37342f86a29362c8efdafdcea005 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 15 Jun 2023 08:54:36 -0700 Subject: [PATCH 0172/2042] doc: release-notes: PM related release notes Add PM release notes. Signed-off-by: Flavio Ceolin --- doc/releases/release-notes-3.4.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index b75d481db093..60f657567aba 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -1370,6 +1370,10 @@ Libraries / Subsystems that will wake the system up in the future. This can be used to influence the system on which low power states can be used. + * Added a new device tree property ``zephyr,pm-device-runtime-auto`` to + automatically enable device runtime power management on a device after its + initialization. + HALs **** From 3822870d2852e245c46caaed9675a0285bba9cd4 Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Thu, 15 Jun 2023 14:29:06 +0200 Subject: [PATCH 0173/2042] drivers: mdio: adin2111: correct prompt The prompt is referring to another existing driver(NXP S32), now the correct name is displayed. Signed-off-by: Thomas Stranger --- drivers/mdio/Kconfig.adin2111 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mdio/Kconfig.adin2111 b/drivers/mdio/Kconfig.adin2111 index 778bbbc25449..420a3d6c7b28 100644 --- a/drivers/mdio/Kconfig.adin2111 +++ b/drivers/mdio/Kconfig.adin2111 @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 config MDIO_ADIN2111 - bool "NXP S32 NETC External MDIO driver" + bool "ADIN2111 MDIO driver" default y depends on DT_HAS_ADI_ADIN2111_MDIO_ENABLED depends on ETH_ADIN2111 From 733a35864acc80310a63db894d90a387708afcb5 Mon Sep 17 00:00:00 2001 From: Divin Raj Date: Mon, 5 Jun 2023 16:31:14 +0100 Subject: [PATCH 0174/2042] drivers: ethernet: Fix typo in comment Update typo in the code comments. Signed-off-by: Divin Raj --- drivers/ethernet/eth_smsc91x_priv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ethernet/eth_smsc91x_priv.h b/drivers/ethernet/eth_smsc91x_priv.h index 2946c1544a46..ccb7d54c05c4 100644 --- a/drivers/ethernet/eth_smsc91x_priv.h +++ b/drivers/ethernet/eth_smsc91x_priv.h @@ -41,7 +41,7 @@ #define MIR_SIZE_MASK GENMASK(7, 0) /* Memory size (2k pages) */ #define MIR_FREE_MASK GENMASK(15, 8) /* Memory free (2k pages) */ -/* bank 0, offset 0xa: receive/phy control reigster */ +/* bank 0, offset 0xa: receive/phy control register */ #define RPCR 0xa #define RPCR_ANEG 0x0800 /* Put PHY in autonegotiation mode */ #define RPCR_DPLX 0x1000 /* Put PHY in full-duplex mode */ @@ -130,7 +130,7 @@ /* Bank 3, Offset 0x8: Management interface register */ #define MGMT 0x8 -#define MGMT_MDO 0x0001 /* MII managememt output */ +#define MGMT_MDO 0x0001 /* MII management output */ #define MGMT_MDI 0x0002 /* MII management input */ #define MGMT_MCLK 0x0004 /* MII management clock */ #define MGMT_MDOE 0x0008 /* MII management output enable */ From b2c00ec032d90b8b0a8ca6c7e44fc4365728bcdc Mon Sep 17 00:00:00 2001 From: Mingjie Shen Date: Thu, 15 Jun 2023 15:24:04 -0400 Subject: [PATCH 0175/2042] net: utils: fix offset used before range check This use of offset 'i' should follow the range check. Signed-off-by: Mingjie Shen --- subsys/net/ip/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 7399fc319e14..f71aa65936e0 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -894,7 +894,7 @@ bool net_ipaddr_parse(const char *str, size_t str_len, struct sockaddr *addr) return parse_ipv6(str, str_len, addr, true); } - for (count = i = 0; str[i] && i < str_len; i++) { + for (count = i = 0; i < str_len && str[i]; i++) { if (str[i] == ':') { count++; } From 09085ef63c0229bd46200931e36c66303b2c4784 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Thu, 15 Jun 2023 15:34:58 +0300 Subject: [PATCH 0176/2042] dts: xtensa: intel: update cavs25 sram size Cavs25 sram size should be 3MB instead of 2MB, thus update the correct value. Signed-off-by: Jaska Uimonen --- dts/xtensa/intel/intel_adsp_cavs25.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index c904f9a89f80..d9d839b92f9b 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -58,7 +58,7 @@ sram0: memory@be000000 { device_type = "memory"; compatible = "mmio-sram"; - reg = <0xbe000000 DT_SIZE_K(1920)>; + reg = <0xbe000000 DT_SIZE_K(2944)>; }; sram1: memory@be800000 { From 363676764ae93d96adadd61a36a6acb6f9c297cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 14 Jun 2023 15:28:42 +0200 Subject: [PATCH 0177/2042] Bluetooth: Host: Fix wrong ID being stored MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix an issue causing a wrong Bluetooth identity value to be stored. It was happening because the `bt_dev.id_count` was incremented after the settings being stored. To fix this, `bt_dev.id_count` is now incremented right before the ID creation and is decremented if the ID creation failed. Signed-off-by: Théo Battrel --- subsys/bluetooth/host/id.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index c021568b1810..8371ee043312 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -1273,12 +1273,11 @@ int bt_id_create(bt_addr_le_t *addr, uint8_t *irk) } } - new_id = bt_dev.id_count; + new_id = bt_dev.id_count++; err = id_create(new_id, addr, irk); if (err) { + bt_dev.id_count--; return err; - } else { - bt_dev.id_count++; } return new_id; From 14200f82dbaf47a6da688d5e3ee08c69b4248f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 14 Jun 2023 13:46:26 +0200 Subject: [PATCH 0178/2042] Bluetooth: Tests: New bsim test for ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new BabbleSim test checking that the value of the Bluetooth identity stored in the settings is correct. Signed-off-by: Théo Battrel --- tests/bsim/bluetooth/host/compile.sh | 2 + .../bluetooth/host/id/settings/CMakeLists.txt | 16 ++++ .../bsim/bluetooth/host/id/settings/prj.conf | 17 ++++ .../bluetooth/host/id/settings/src/common.h | 20 +++++ .../bsim/bluetooth/host/id/settings/src/dut.c | 82 +++++++++++++++++++ .../bluetooth/host/id/settings/src/main.c | 63 ++++++++++++++ .../host/id/settings/test_scripts/_compile.sh | 13 +++ .../host/id/settings/test_scripts/settings.sh | 30 +++++++ 8 files changed, 243 insertions(+) create mode 100644 tests/bsim/bluetooth/host/id/settings/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/id/settings/prj.conf create mode 100644 tests/bsim/bluetooth/host/id/settings/src/common.h create mode 100644 tests/bsim/bluetooth/host/id/settings/src/dut.c create mode 100644 tests/bsim/bluetooth/host/id/settings/src/main.c create mode 100755 tests/bsim/bluetooth/host/id/settings/test_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/id/settings/test_scripts/settings.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 6903a24beea8..33c71bc3ddfe 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -65,4 +65,6 @@ app=tests/bsim/bluetooth/host/security/bond_overwrite_denied compile app=tests/bsim/bluetooth/host/security/ccc_update compile app=tests/bsim/bluetooth/host/security/ccc_update conf_file=prj_2.conf compile +app=tests/bsim/bluetooth/host/id/settings compile + wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/id/settings/CMakeLists.txt b/tests/bsim/bluetooth/host/id/settings/CMakeLists.txt new file mode 100644 index 000000000000..659359fc027e --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_id_settings) + +target_sources(app PRIVATE + src/main.c + src/dut.c +) + +zephyr_include_directories( + $ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/ + $ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) diff --git a/tests/bsim/bluetooth/host/id/settings/prj.conf b/tests/bsim/bluetooth/host/id/settings/prj.conf new file mode 100644 index 000000000000..4559ba6f8f92 --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/prj.conf @@ -0,0 +1,17 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_DEVICE_NAME="ID Settings Test" + +CONFIG_LOG=y + +CONFIG_BT_ID_MAX=2 + +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_BT_SETTINGS=y + +# Increased stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/tests/bsim/bluetooth/host/id/settings/src/common.h b/tests/bsim/bluetooth/host/id/settings/src/common.h new file mode 100644 index 000000000000..41d8ba0346e8 --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/src/common.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_tracing.h" +#include "bstests.h" + +#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) + +extern enum bst_result_t bst_result; diff --git a/tests/bsim/bluetooth/host/id/settings/src/dut.c b/tests/bsim/bluetooth/host/id/settings/src/dut.c new file mode 100644 index 000000000000..572ceaec1885 --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/src/dut.c @@ -0,0 +1,82 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +#include +#include + +#include "common.h" + +LOG_MODULE_DECLARE(bt_bsim_id_settings, LOG_LEVEL_DBG); + +void run_dut1(void) +{ + int err; + size_t bt_id_count; + + LOG_DBG("Starting DUT 1"); + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth init failed (err %d)\n", err); + } + + LOG_DBG("Bluetooth initialised"); + + err = settings_load(); + if (err) { + FAIL("Failed to load settings (err %d)\n", err); + } + + bt_id_get(NULL, &bt_id_count); + LOG_DBG("Number of Bluetooth identities after settings load: %d", bt_id_count); + + err = bt_id_create(NULL, NULL); + if (err < 0) { + FAIL("Failed to create a new identity (err %d)\n", err); + } + + bt_id_get(NULL, &bt_id_count); + LOG_DBG("Number of Bluetooth identities after identity creation: %d", bt_id_count); + + /* Wait for the workqueue to complete before switching device */ + k_msleep(100); + + PASS("Test passed (DUT 1)\n"); +} + +void run_dut2(void) +{ + int err; + size_t bt_id_count; + size_t expected_id_count = 2; + + LOG_DBG("Starting DUT 2"); + + err = bt_enable(NULL); + if (err) { + FAIL("Bluetooth init failed (err %d)\n", err); + } + + LOG_DBG("Bluetooth initialised"); + + err = settings_load(); + if (err) { + FAIL("Failed to load settings (err %d)\n", err); + } + + LOG_DBG("Settings loaded"); + + bt_id_get(NULL, &bt_id_count); + if (bt_id_count != expected_id_count) { + FAIL("Wrong ID count (got %d; expected %d)\n", bt_id_count, expected_id_count); + } + + PASS("Test passed (DUT 2)\n"); +} diff --git a/tests/bsim/bluetooth/host/id/settings/src/main.c b/tests/bsim/bluetooth/host/id/settings/src/main.c new file mode 100644 index 000000000000..d32595127c2a --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/src/main.c @@ -0,0 +1,63 @@ +/* Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" +#include + +#include + +#include "common.h" + +#define WAIT_TIME_S 60 +#define WAIT_TIME (WAIT_TIME_S * 1e6) + +LOG_MODULE_REGISTER(bt_bsim_id_settings, LOG_LEVEL_DBG); + +extern void run_dut1(void); +extern void run_dut2(void); + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("Test failed (not passed after %d seconds)\n", WAIT_TIME_S); + } +} + +static void test_id_settings_init(void) +{ + bst_ticker_set_next_tick_absolute(WAIT_TIME); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "dut1", + .test_descr = "DUT 1", + .test_post_init_f = test_id_settings_init, + .test_tick_f = test_tick, + .test_main_f = run_dut1, + }, + { + .test_id = "dut2", + .test_descr = "DUT 2", + .test_post_init_f = test_id_settings_init, + .test_tick_f = test_tick, + .test_main_f = run_dut2, + }, + BSTEST_END_MARKER}; + +struct bst_test_list *test_id_settings_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} + +bst_test_install_t test_installers[] = {test_id_settings_install, NULL}; + +void main(void) +{ + bst_main(); +} diff --git a/tests/bsim/bluetooth/host/id/settings/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/id/settings/test_scripts/_compile.sh new file mode 100755 index 000000000000..9c23bf1a934e --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/test_scripts/_compile.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +bsim_bin="${BSIM_OUT_PATH}/bin" +BOARD="${BOARD:-nrf52_bsim}" +test_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_id_settings_prj_conf" + +west build -b nrf52_bsim -d build && \ + cp -v build/zephyr/zephyr.exe "${test_exe}" diff --git a/tests/bsim/bluetooth/host/id/settings/test_scripts/settings.sh b/tests/bsim/bluetooth/host/id/settings/test_scripts/settings.sh new file mode 100755 index 000000000000..2221b5c1ea4f --- /dev/null +++ b/tests/bsim/bluetooth/host/id/settings/test_scripts/settings.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_exe="bs_${BOARD}_tests_bsim_bluetooth_host_id_settings_prj_conf" +simulation_id="id_settings" +verbosity_level=2 +EXECUTE_TIMEOUT=30 + +cd ${BSIM_OUT_PATH}/bin + +Execute "./${test_exe}" \ + -v=${verbosity_level} -s="${simulation_id}_1" -d=0 -testid=dut1 \ + -flash="${simulation_id}.log.bin" + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}_1" \ + -D=1 -sim_length=60e6 + +wait_for_background_jobs + +Execute "./${test_exe}" \ + -v=${verbosity_level} -s="${simulation_id}_2" -d=0 -testid=dut2 \ + -flash="${simulation_id}.log.bin" -flash_rm + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s="${simulation_id}_2" \ + -D=1 -sim_length=60e6 + +wait_for_background_jobs From 7d89f784a47a37a611939bff171d40bbd35b3049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 16 Jun 2023 12:41:05 +0200 Subject: [PATCH 0179/2042] doc: release: Add v3.4 notes for ADC and PWM and Nordic related stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add release notes for ADC and PWM drivers, Nordic HAL and other things related to Nordic. Signed-off-by: Andrzej Głąbek --- doc/releases/release-notes-3.4.rst | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 60f657567aba..35fe7c2891d5 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -477,6 +477,7 @@ Boards & SoC Support * STM32C0 series are now supported (with introduction of STM32C031 SoC). * STM32H5 series are now supported (with introduction of STM32H503 and STM32H573 SoCs). * Added support for STM32U599 SoC variants + * Nordic Semiconductor nRF9161 * Removed support for these SoC series: @@ -546,6 +547,8 @@ Boards & SoC Support * ``nrf9160dk_nrf9160``: Changed the order of buttons and switches on the GPIO expander to match the order when using GPIO directly on the nRF9160 SoC. * ``STM32H747i_disco``: Enabled support for ST B-LCD40-DSI1 display extension + * ``qemu_cortex_m0``: Fixed prescaler of the system timer so that its frequency + is actually 1 MHz, not 2 MHz. * Made these changes for ARM64 boards: @@ -734,22 +737,23 @@ Drivers and Sensors * ADC - * MCUX LPADC driver now uses the channel parameter to select a software channel - configuration buffer. Use ``zephyr,input-positive`` and - ``zephyr,input-negative`` devicetree properties to select the hardware - 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. - - * Added support for STM32C0 and STM32H5. - - * Added DMA support for STM32H7. - - * STM32: Resolutions are now listed in the device tree for each ADC instance - - * STM32: Sampling times are now listed in the device tree for each ADC instance + * MCUX LPADC driver now uses the channel parameter to select a software channel + configuration buffer. Use ``zephyr,input-positive`` and + ``zephyr,input-negative`` devicetree properties to select the hardware + 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. + * Added support for STM32C0 and STM32H5. + * Added DMA support for STM32H7. + * STM32: Resolutions are now listed in the device tree for each ADC instance + * STM32: Sampling times are now listed in the device tree for each ADC instance + * Added driver for Atmel SAM family ADC. + * Added driver for Gecko Incremental ADC. + * Added driver for Infineon CAT1 ADC. + * Added driver for TI ADS7052. + * Added driver for TI ADS114S0x family. + * Added drivers for Renesas SmartBond GPADC and SDADC. * Battery-backed RAM @@ -934,6 +938,7 @@ Drivers and Sensors * Added support for STM32C0. * STM32: Now supports 6-PWM channels + * Added PWM driver for Microchip XEC BBLED. * Power domain @@ -1377,6 +1382,10 @@ Libraries / Subsystems HALs **** +* Nordic + + * Updated nrfx to version 3.0.0. + * STM32 * stm32cube: updated STM32F0 to cube version V1.11.4. From 052c23b92255c54efc653a23afbf0aaf53cfeac4 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 16 Jun 2023 15:09:58 +0100 Subject: [PATCH 0180/2042] doc: ARC: add release notes for ARC Add release notes for ARC for 3.4 release Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- doc/releases/release-notes-3.4.rst | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 35fe7c2891d5..62811778cac9 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -308,6 +308,23 @@ Architectures * ARC + * Added MPUv8 support + * Add support of virtual UART over ARC hostlink channel + * Improved ARCv2 HS4x processors handling - added proper Kconfig options, provided default mcpu + * Improved ARCMWDT toolchain handling: + + * added rollback to check METAWARE_ROOT if ARCMWDT_TOOLCHAIN_PATH missing + * reworked extra warnings options handling in twister so it can be used with ARCMWDT + * used 64bit MDB binary by default + + * Fixed excessive ROM memory consumption if MPU is enabled and ROM & RAM are located in different + memory regions + * Fixed DSP registers handling in case of ARCMWDT + * Improved SMP handling: + + * Fixed potential livelock in thread abort due to exception + * Fixed IDU mask setup + * Removed absolute symbols :c:macro:`___callee_saved_t_SIZEOF` and :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` @@ -485,8 +502,8 @@ Boards & SoC Support * Added support for these ARC boards: - * DesignWare ARC HS4x/HS4xD Development Kit - * DesignWare ARC nSIM and HAPS FPGA + * DesignWare ARC HS4x/HS4xD Development Kit (HSDK4xD) - ARCv2 HS47D, SMP 4 cores + * nsim_hs3x_hostlink - simulation (nSIM-based) platform with hostlink UART * Added support for these ARM boards: @@ -535,6 +552,12 @@ Boards & SoC Support * Made these changes for ARC boards: + * Added ARC MWDT toolchain support inforto qemu_arc_hs + * Improved emsdp platform support: + + * Added DFSS driver support + * Added pinctrl support + * Made these changes for ARM boards: * ``atsamc21n_xpro``: Enable support to CAN. From e86185522ce3bdfdc9aef0495a25751060959e96 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Fri, 16 Jun 2023 16:08:57 +0200 Subject: [PATCH 0181/2042] Bluetooth: release notes: Fix formatting of indented bullet points Without the extra spaces Sphinx does not render this correctly. Signed-off-by: Carles Cufi --- doc/releases/release-notes-3.4.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 62811778cac9..e3693e07f7fc 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -438,20 +438,32 @@ Bluetooth * Enhanced Provisioning Authentication support. * Mesh Remote Provisioning support including: + * Remote Provisioning Server and Client models. * Composition Data Page 128 and Models Metadata Page 128 support. + * Large Composition Data support including: + * Large Composition Data Server and Client models. * Models Metadata Page 0 support. + * New Transport Segmentation and Reassembly (SAR) implementation including: + * SAR Configuration Server and Client models. + * Mesh Private Beacons support including: + * Mesh Private Beacon Server and Client models. + * Opcodes Aggregator support including: + * Opcodes Aggregator Server and Client models. + * Proxy Solicitation support including: + * Solicitation PDU RPL Configuration Server and Client models. * On-Demand Private Proxy Server and Client models. + * Composition Data Page 1 support. * Other Mesh Profile Enhancements. * Added experimental support for Mesh Binary Large Object Transfer Model d1.0r04_PRr00 specification. From f8803090ca0dd76e6a4b227d0fa044443009ca35 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 16 Jun 2023 15:17:02 +0100 Subject: [PATCH 0182/2042] dos: ARC: mark DSP AGU/XY extensions as supported on ARC EM DSP AGU/XY extensions ARC EM processors are supported now in Zephyr. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- doc/hardware/arch/arc-support-status.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hardware/arch/arc-support-status.rst b/doc/hardware/arch/arc-support-status.rst index 5eb3b275e370..29ae83621967 100644 --- a/doc/hardware/arch/arc-support-status.rst +++ b/doc/hardware/arch/arc-support-status.rst @@ -51,7 +51,7 @@ Legend: +---------------------------------------------------------------------+------------+-------------+--------+------------+------------+ | DSP ISA | Y | N [#f3]_ | TBD | TBD | TBD | +---------------------------------------------------------------------+------------+-------------+--------+------------+------------+ -| DSP AGU/XY extensions | WIP [#f3]_ | N [#f3]_ | TBD | TBD | TBD | +| DSP AGU/XY extensions | Y | N [#f3]_ | TBD | TBD | TBD | +---------------------------------------------------------------------+------------+-------------+--------+------------+------------+ | Userspace | Y | Y | N | TBD | TBD | +---------------------------------------------------------------------+------------+-------------+--------+------------+------------+ From beae29964fd2a1f78586c1de9aad9b77ef4af482 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 16 Jun 2023 15:53:04 +0100 Subject: [PATCH 0183/2042] doc: ARC: release notes: typo fix Typo fix. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- doc/releases/release-notes-3.4.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index e3693e07f7fc..7e6b22c0ca09 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -564,7 +564,7 @@ Boards & SoC Support * Made these changes for ARC boards: - * Added ARC MWDT toolchain support inforto qemu_arc_hs + * Added ARC MWDT toolchain support for qemu_arc_hs * Improved emsdp platform support: * Added DFSS driver support From 288fd5d3f2cda81e4e6e6f5dbc24efba3272b8db Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:50:39 +0000 Subject: [PATCH 0184/2042] doc: release: adapt title of 3.4 release notes Remove 'Working Draft' from title. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 7e6b22c0ca09..d458a3c664c1 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -2,8 +2,8 @@ .. _zephyr_3.4: -Zephyr 3.4.0 (Working Draft) -############################ +Zephyr 3.4.0 +############ We are pleased to announce the release of Zephyr version 3.4.0. From 6015293447e59bb4b70786268729e3315f1bfbfc Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:51:34 +0000 Subject: [PATCH 0185/2042] doc: release: Use past tense on some entries Use past tense in some of the release notes. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index d458a3c664c1..45c67d67240f 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -11,7 +11,7 @@ Major enhancements with this release include: * Input subsystem: handles input events from various types of input devices and distributes them to other threads in the application. -* Barrier API: add architecture agnostic API for data memory barriers. +* Barrier API: added architecture agnostic API for data memory barriers. * USB Device support: * USB device controller API (UDC API) and nRF USBD controller driver. @@ -817,7 +817,7 @@ Drivers and Sensors * Clock control - * Atmel SAM/SAM0: Introduce peripheral clock control. + * Atmel SAM/SAM0: Introduced peripheral clock control. * Atmel SAM0: Improved ``samd20``/``samd21``/``samr21`` clocking mechanism. * STM32F4: Added support for PLL I2S @@ -1006,7 +1006,7 @@ Drivers and Sensors * Serial - * Add UART3 and UART4 configuration for ``gd32vf103`` SoCs. + * Added UART3 and UART4 configuration for ``gd32vf103`` SoCs. * uart_altera: added new driver for Altera Avalon UART. * uart_emul: added new driver for emulated UART. * uart_esp32: From 77496073434b095a14c19c59b1c6986c2e60dcab Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:52:16 +0000 Subject: [PATCH 0186/2042] doc: release: remove empty sections Remove all placeholders and empty sections. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 47 ------------------------------ 1 file changed, 47 deletions(-) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 45c67d67240f..ba2d57edc53d 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -372,8 +372,6 @@ Architectures * Removed absolute symbol :c:macro:`_K_THREAD_NO_FLOAT_SIZEOF` -* X86 - * Xtensa * Fixed the cross stack call mechanism during nested interrupts where stack would be @@ -839,8 +837,6 @@ Drivers and Sensors * Added support on STM32H5 series. -* DFU - * Disk * SDMMC STM32L4+: Now compatible with internal DMA @@ -867,10 +863,6 @@ Drivers and Sensors * Added support for STM32H5 series. -* ESPI - -* Ethernet - * Flash * Introduced new flash API call :c:func:`flash_ex_op` which calls @@ -899,10 +891,6 @@ Drivers and Sensors their initial sector split into two parts (usually marked as 0a and 0b). * STM32H5 now supports OSPI -* FPGA - -* Fuel Gauge - * GPIO * Converted the ``gpio_keys`` driver to the input subsystem. @@ -911,8 +899,6 @@ Drivers and Sensors * STM32: Supports newly introduced experimental API to enable/disable interrupts without re-config -* hwinfo - * I2C * Added support for STM32C0 and STM32H5 series @@ -921,29 +907,15 @@ Drivers and Sensors * STM32: Domain clock should now be configured by device tree. -* I3C - -* IEEE 802.15.4 - * Input * Introduced the :ref:`input` subsystem. -* Interrupt Controller - -* IPM - * KSCAN * Added a :dtcompatible:`zephyr,kscan-input` input to kscan compatibility driver. * Converted the ``ft5336`` and ``kscan_sdl`` drivers to the input subsystem. -* LED - -* MBOX - -* MEMC - * MIPI-DSI * Added support on STM32H7 @@ -987,8 +959,6 @@ Drivers and Sensors * Added support for nPM1300 PMIC * Added support for Raspberry Pi Pico core supply regulator -* Reset - * SDHC * Support was added for using CPOL/CPHA SPI clock modes with SD cards, as @@ -1060,8 +1030,6 @@ Drivers and Sensors * Added support for STM32C0 and STM32H5 series -* WiFi - Networking ********** @@ -1276,9 +1244,6 @@ USB * Added USB Mass Storage class and CDC ECM class implementations for the new device support. -Devicetree -********** - Libraries / Subsystems ********************** @@ -1471,9 +1436,6 @@ Among other things, this update brings: * Improved docs * -Wall and -Wconversion compliance -Documentation -************* - Tests and Samples ***************** @@ -1481,12 +1443,3 @@ Tests and Samples system. One of them including the OpenThread stack. * For native_posix and the nrf52_bsim: Many tests have been fixed and enabled. * LittleFS sample has been given SPI example configuration for nrf52840dk_nrf52840. - -Issue Related Items -******************* - -Known Issues -============ - -Addressed issues -================ From 8db0349bec4875a2e5ee15861752f7685e47fe27 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:53:03 +0000 Subject: [PATCH 0187/2042] doc: release: add one entry re ztest new API One more entry about ztest API being deprecated. Signed-off-by: Anas Nashif --- doc/releases/release-notes-3.4.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index ba2d57edc53d..0fb4efbe40f4 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -1443,3 +1443,4 @@ Tests and Samples system. One of them including the OpenThread stack. * For native_posix and the nrf52_bsim: Many tests have been fixed and enabled. * LittleFS sample has been given SPI example configuration for nrf52840dk_nrf52840. +* Migrated all tests to new Ztest API and deprecated legacy Ztest. From ee72dfa5e2f1e5dfde12ae2e66e7fc6ce99abbb4 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:55:00 +0000 Subject: [PATCH 0188/2042] doc: add 3.4.0 to the index of releases Add the new release to the doc index. Signed-off-by: Anas Nashif --- doc/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/conf.py b/doc/conf.py index 2545ffea54ef..f59acb5dd57b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -159,6 +159,7 @@ "current_version": version, "versions": ( ("latest", "/"), + ("3.4.0", "/3.4.0/"), ("3.3.0", "/3.3.0/"), ("3.2.0", "/3.2.0/"), ("3.1.0", "/3.1.0/"), From aa8c6aa0677d4501fbff52e9ee8f1e50c5138eff Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:56:37 +0000 Subject: [PATCH 0189/2042] doc: remove releases before 2.7 from index Remove all old releases from the index. Signed-off-by: Anas Nashif --- doc/conf.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index f59acb5dd57b..3fc170535c70 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -165,11 +165,6 @@ ("3.1.0", "/3.1.0/"), ("3.0.0", "/3.0.0/"), ("2.7.4 (LTS)", "/2.7.4/"), - ("2.6.0", "/2.6.0/"), - ("2.5.0", "/2.5.0/"), - ("2.4.0", "/2.4.0/"), - ("2.3.0", "/2.3.0/"), - ("1.14.1", "/1.14.1/"), ), "display_vcs_link": True, "reference_links": { From 7ce8b5598c2903275aad91920074e328f9d75801 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:58:23 +0000 Subject: [PATCH 0190/2042] doc: update LTS2 version in docs LTS is now 2.7.5. Signed-off-by: Anas Nashif --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 3fc170535c70..72263cfc11ea 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -164,7 +164,7 @@ ("3.2.0", "/3.2.0/"), ("3.1.0", "/3.1.0/"), ("3.0.0", "/3.0.0/"), - ("2.7.4 (LTS)", "/2.7.4/"), + ("2.7.5 (LTS)", "/2.7.5/"), ), "display_vcs_link": True, "reference_links": { From 356c8cbe63ae01b3ab438382639d25bb418a0213 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 10:30:25 +0000 Subject: [PATCH 0191/2042] release: Zephyr 3.4.0 release Make this the final release. Signed-off-by: Anas Nashif --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ccf2ed32034c..968819e3f260 100644 --- a/VERSION +++ b/VERSION @@ -2,4 +2,4 @@ VERSION_MAJOR = 3 VERSION_MINOR = 4 PATCHLEVEL = 0 VERSION_TWEAK = 0 -EXTRAVERSION = rc3 +EXTRAVERSION = From e1b69a548787a7bb5830eed463f230d43fbc0b88 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 13:05:31 -0400 Subject: [PATCH 0192/2042] release: bump main to v3.4.99 Update main development branch to version v3.4.99. Signed-off-by: Anas Nashif --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 968819e3f260..2d7dfb83b49e 100644 --- a/VERSION +++ b/VERSION @@ -1,5 +1,5 @@ VERSION_MAJOR = 3 VERSION_MINOR = 4 -PATCHLEVEL = 0 +PATCHLEVEL = 99 VERSION_TWEAK = 0 EXTRAVERSION = From 79d610a89338f422854cc8b2c679b72da8827ef7 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 16 Jun 2023 13:09:22 -0400 Subject: [PATCH 0193/2042] doc: release: remove old version from index Remove old releases from documentation index. Signed-off-by: Anas Nashif --- doc/conf.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 72263cfc11ea..79f2f51b9b59 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -162,8 +162,6 @@ ("3.4.0", "/3.4.0/"), ("3.3.0", "/3.3.0/"), ("3.2.0", "/3.2.0/"), - ("3.1.0", "/3.1.0/"), - ("3.0.0", "/3.0.0/"), ("2.7.5 (LTS)", "/2.7.5/"), ), "display_vcs_link": True, From b224a099fd3d56d068f22e825a9c4cd835590878 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 11 Jun 2023 14:32:55 +0200 Subject: [PATCH 0194/2042] net: l2: ieee802154: standardize RSSI value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RSSI value in net_pkt (net_pkt_cb_ieee802154.rssi) was used inconsistently across drivers. Some drivers did cast a signed dBm value directly to net_pkt's unsigned byte value. Others were assigning the negative value of the signed dBm value and again others were offsetting and stretching the signed dBm value linearly onto the full unsigned byte range. This change standardizes net_pkt's rssi attribute to represent RSSI on the RX path as an unsigned integer ranging from 0 (–174 dBm) to 254 (80 dBm) and lets 255 represent an "unknown RSSI" (IEEE 802.15.4-2020, section 6.16.2.8). On the TX path the rssi attribute will always be zero. Out-of-range values will be truncated to max/min values. The change also introduces conversion functions to and from signed dBm values and introduces these consistently to all existing call sites. The "unknown RSSI" value is represented as INT16_MIN in this case. In some cases drivers had to be changed to calculate dBm values from internal hardware specific representations. The conversion functions are fully covered by unit tests. Fixes: #58494 Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_b91.c | 2 +- drivers/ieee802154/ieee802154_cc1200.c | 13 ++- drivers/ieee802154/ieee802154_cc1200.h | 2 + drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 21 +--- drivers/ieee802154/ieee802154_cc13xx_cc26xx.h | 2 +- .../ieee802154_cc13xx_cc26xx_subg.c | 22 +--- .../ieee802154_cc13xx_cc26xx_subg.h | 3 +- drivers/ieee802154/ieee802154_cc2520.c | 14 +-- drivers/ieee802154/ieee802154_dw1000.c | 5 +- drivers/ieee802154/ieee802154_kw41z.c | 2 +- drivers/ieee802154/ieee802154_mcr20a.c | 48 +++++---- drivers/ieee802154/ieee802154_nrf5.c | 4 +- drivers/ieee802154/ieee802154_rf2xx.c | 2 +- include/zephyr/net/ieee802154_pkt.h | 101 +++++++++++++++++- modules/openthread/platform/radio.c | 4 +- subsys/net/ip/net_shell.c | 2 +- tests/net/ieee802154/l2/src/ieee802154_test.c | 72 +++++++++++++ tests/subsys/openthread/radio_test.c | 4 +- 18 files changed, 240 insertions(+), 83 deletions(-) diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index ddb6673a8531..14f79db01c18 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -169,7 +169,7 @@ static void b91_update_rssi_and_lqi(struct net_pkt *pkt) lqi = b91_convert_rssi_to_lqi(rssi); net_pkt_set_ieee802154_lqi(pkt, lqi); - net_pkt_set_ieee802154_rssi(pkt, rssi); + net_pkt_set_ieee802154_rssi_dbm(pkt, rssi); } /* Prepare TX buffer */ diff --git a/drivers/ieee802154/ieee802154_cc1200.c b/drivers/ieee802154/ieee802154_cc1200.c index 5d747e1631a5..fabbd1fe1061 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -427,18 +427,21 @@ static inline bool read_rxfifo_content(const struct device *dev, static inline bool verify_crc(const struct device *dev, struct net_pkt *pkt) { - uint8_t fcs[2]; + uint8_t status[2]; + int8_t rssi; - if (!read_rxfifo(dev, fcs, 2)) { + if (!read_rxfifo(dev, status, 2)) { return false; } - if (!(fcs[1] & CC1200_FCS_CRC_OK)) { + if (!(status[1] & CC1200_FCS_CRC_OK)) { return false; } - net_pkt_set_ieee802154_rssi(pkt, fcs[0]); - net_pkt_set_ieee802154_lqi(pkt, fcs[1] & CC1200_FCS_LQI_MASK); + rssi = (int8_t) status[0]; + net_pkt_set_ieee802154_rssi_dbm( + pkt, rssi == CC1200_INVALID_RSSI ? IEEE802154_MAC_RSSI_DBM_UNDEFINED : rssi); + net_pkt_set_ieee802154_lqi(pkt, status[1] & CC1200_FCS_LQI_MASK); return true; } diff --git a/drivers/ieee802154/ieee802154_cc1200.h b/drivers/ieee802154/ieee802154_cc1200.h index 544bf5a605ec..851ddd1e8afb 100644 --- a/drivers/ieee802154/ieee802154_cc1200.h +++ b/drivers/ieee802154/ieee802154_cc1200.h @@ -140,4 +140,6 @@ DEFINE_STROBE_INSTRUCTION(sftx, CC1200_INS_SFTX) DEFINE_STROBE_INSTRUCTION(sworrst, CC1200_INS_SWORRST) DEFINE_STROBE_INSTRUCTION(snop, CC1200_INS_SNOP) +#define CC1200_INVALID_RSSI INT8_MIN + #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_CC1200_H_ */ diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 7f0b9d9c7ed7..7e76bd2e2acf 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -390,20 +390,6 @@ static int ieee802154_cc13xx_cc26xx_tx(const struct device *dev, return r; } -static inline uint8_t ieee802154_cc13xx_cc26xx_convert_rssi(int8_t rssi) -{ - if (rssi > CC13XX_CC26XX_RECEIVER_SENSITIVITY + - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE) { - rssi = CC13XX_CC26XX_RECEIVER_SENSITIVITY + - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE; - } else if (rssi < CC13XX_CC26XX_RECEIVER_SENSITIVITY) { - rssi = CC13XX_CC26XX_RECEIVER_SENSITIVITY; - } - - return (255 * (rssi - CC13XX_CC26XX_RECEIVER_SENSITIVITY)) / - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE; -} - static void ieee802154_cc13xx_cc26xx_rx_done( struct ieee802154_cc13xx_cc26xx_data *drv_data) { @@ -450,9 +436,10 @@ static void ieee802154_cc13xx_cc26xx_rx_done( drv_data->rx_entry[i].status = DATA_ENTRY_PENDING; net_pkt_set_ieee802154_lqi(pkt, lqi); - net_pkt_set_ieee802154_rssi( - pkt, - ieee802154_cc13xx_cc26xx_convert_rssi(rssi)); + net_pkt_set_ieee802154_rssi_dbm(pkt, + rssi == CC13XX_CC26XX_INVALID_RSSI + ? IEEE802154_MAC_RSSI_DBM_UNDEFINED + : rssi); if (net_recv_data(drv_data->iface, pkt)) { LOG_WRN("Packet dropped"); diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h index 83142e095834..1a34193cd0fb 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h @@ -55,7 +55,7 @@ #define CC13XX_CC26XX_CPE1_IRQ (INT_RFC_CPE_1 - 16) #define CC13XX_CC26XX_RECEIVER_SENSITIVITY -100 -#define CC13XX_CC26XX_RSSI_DYNAMIC_RANGE 95 +#define CC13XX_CC26XX_INVALID_RSSI INT8_MIN struct ieee802154_cc13xx_cc26xx_data { RF_Handle rf_handle; diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 3c6d4aa25dd7..958c397b3e61 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -563,21 +563,6 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, return r; } -static inline uint8_t ieee802154_cc13xx_cc26xx_subg_convert_rssi( - int8_t rssi) -{ - if (rssi > CC13XX_CC26XX_RECEIVER_SENSITIVITY + - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE) { - rssi = CC13XX_CC26XX_RECEIVER_SENSITIVITY + - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE; - } else if (rssi < CC13XX_CC26XX_RECEIVER_SENSITIVITY) { - rssi = CC13XX_CC26XX_RECEIVER_SENSITIVITY; - } - - return (255 * (rssi - CC13XX_CC26XX_RECEIVER_SENSITIVITY)) / - CC13XX_CC26XX_RSSI_DYNAMIC_RANGE; -} - static void ieee802154_cc13xx_cc26xx_subg_rx_done( struct ieee802154_cc13xx_cc26xx_subg_data *drv_data) { @@ -622,9 +607,10 @@ static void ieee802154_cc13xx_cc26xx_subg_rx_done( /* TODO determine LQI in PROP mode */ net_pkt_set_ieee802154_lqi(pkt, 0xff); - net_pkt_set_ieee802154_rssi( - pkt, - ieee802154_cc13xx_cc26xx_subg_convert_rssi(rssi)); + net_pkt_set_ieee802154_rssi_dbm(pkt, + rssi == CC13XX_CC26XX_INVALID_RSSI + ? IEEE802154_MAC_RSSI_DBM_UNDEFINED + : rssi); if (net_recv_data(drv_data->iface, pkt)) { LOG_WRN("Packet dropped"); diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h index 3f68c989f0e6..6035f70209cd 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h @@ -64,8 +64,7 @@ #define CC13XX_CC26XX_TX_BUF_SIZE \ (IEEE802154_MAX_PHY_PACKET_SIZE + IEEE802154_SUN_PHY_FSK_PHR_LEN) -#define CC13XX_CC26XX_RECEIVER_SENSITIVITY -100 -#define CC13XX_CC26XX_RSSI_DYNAMIC_RANGE 95 +#define CC13XX_CC26XX_INVALID_RSSI INT8_MIN struct ieee802154_cc13xx_cc26xx_subg_data { RF_Handle rf_handle; diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index 27d334338419..417d208c1d58 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -536,11 +536,11 @@ static inline bool read_rxfifo_content(const struct device *dev, return true; } -static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *buf) +static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *status) { uint8_t lqi; - net_pkt_set_ieee802154_rssi(pkt, buf[0]); + net_pkt_set_ieee802154_rssi_dbm(pkt, (int8_t) status[0]); /** * CC2520 does not provide an LQI but a correlation factor. @@ -552,7 +552,7 @@ static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *buf) * else: * lqi = (lqi - 50) * 4 */ - lqi = buf[1] & CC2520_FCS_CORRELATION; + lqi = status[1] & CC2520_FCS_CORRELATION; if (lqi <= 50U) { lqi = 0U; } else if (lqi >= 110U) { @@ -566,17 +566,17 @@ static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *buf) static inline bool verify_crc(const struct device *dev, struct net_pkt *pkt) { - uint8_t fcs[2]; + uint8_t status[2]; - if (!z_cc2520_access(dev, true, CC2520_INS_RXBUF, 0, &fcs, 2)) { + if (!z_cc2520_access(dev, true, CC2520_INS_RXBUF, 0, &status, 2)) { return false; } - if (!(fcs[1] & CC2520_FCS_CRC_OK)) { + if (!(status[1] & CC2520_FCS_CRC_OK)) { return false; } - insert_radio_noise_details(pkt, fcs); + insert_radio_noise_details(pkt, status); return true; } diff --git a/drivers/ieee802154/ieee802154_dw1000.c b/drivers/ieee802154/ieee802154_dw1000.c index 0f18fc29f5c3..efeded45734b 100644 --- a/drivers/ieee802154/ieee802154_dw1000.c +++ b/drivers/ieee802154/ieee802154_dw1000.c @@ -478,7 +478,7 @@ static inline void dwt_irq_handle_rx(const struct device *dev, uint32_t sys_stat #endif } - net_pkt_set_ieee802154_rssi(pkt, rx_level); + net_pkt_set_ieee802154_rssi_dbm(pkt, rx_level); /* * Workaround for AAT status bit issue, @@ -497,8 +497,7 @@ static inline void dwt_irq_handle_rx(const struct device *dev, uint32_t sys_stat } /* LQI not implemented */ - LOG_DBG("Caught a packet (%u) (RSSI: %d)", - pkt_len, (int8_t)net_pkt_ieee802154_rssi(pkt)); + LOG_DBG("Caught a packet (%u) (RSSI: %d)", pkt_len, rx_level); LOG_HEXDUMP_DBG(pkt->buffer->data, pkt_len, "RX buffer:"); if (net_recv_data(ctx->iface, pkt) == NET_OK) { diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index 5a9f9a0443de..b68cd49b81c1 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -602,7 +602,7 @@ static void handle_ack(struct kw41z_context *kw41z, uint8_t seq_number) /* Use some fake values for LQI and RSSI. */ (void)net_pkt_set_ieee802154_lqi(ack_pkt, 80); - (void)net_pkt_set_ieee802154_rssi(ack_pkt, -40); + (void)net_pkt_set_ieee802154_rssi_dbm(ack_pkt, -40); net_pkt_cursor_init(ack_pkt); diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index e82512ad6c91..110d0df04b32 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -483,23 +483,33 @@ static inline int mcr20a_set_sequence(const struct device *dev, return 0; } -static inline uint32_t mcr20a_get_rssi(uint32_t lqi) +#define DIV_ROUND_CLOSEST_WITH_OPPOSITE_SIGNS(n, d) (((n) - (d)/2)/(d)) + +static inline int16_t mcr20a_get_rssi(uint8_t lqi) { - /* Get rssi (Received Signal Strength Indicator, unit is dBm) - * from lqi (Link Quality Indicator) value. - * There are two different equations for RSSI: + /* Calculate the RSSI (Received Signal Strength Indicator) + * in dBm from the LQI (Link Quality Indicator) value. + * + * There are two different equations for the RF value (which + * we use as the RSSI value) in the reference manuals: + * * RF = (LQI – 286.6) / 2.69333 (MKW2xD Reference Manual) * RF = (LQI – 295.4) / 2.84 (MCR20A Reference Manual) - * The last appears more to match the graphic (Figure 3-10). - * Since RSSI value is always positive and we want to - * avoid the floating point computation: - * -RF * 65536 = (LQI / 2.84 - 295.4 / 2.84) * 65536 - * RF * 65536 = (295.4 * 65536 / 2.84) - (LQI * 65536 / 2.84) + * + * The second is derived from empiric values (see Figure 3-10) + * so we use that one. + * + * Since we want to avoid floating point computation and + * the result needs to be rounded to a signed integer value + * anyways, we take the numerator and denominator times 100 + * each and round the end result of the division: + * RF = (LQI – 295.4) / 2.84 + * = (100 * (LQI – 295.4)) / (100 * 2.84) + * = (100 * LQI – 29540) / 284 */ - uint32_t a = (uint32_t)(295.4 * 65536 / 2.84); - uint32_t b = (uint32_t)(65536 / 2.84); + int16_t numerator = ((int16_t)100 * lqi) - 29540; /* always negative */ - return (a - (b * lqi)) >> 16; + return DIV_ROUND_CLOSEST_WITH_OPPOSITE_SIGNS(numerator, 284); } static inline uint8_t *get_mac(const struct device *dev) @@ -554,6 +564,8 @@ static inline void mcr20a_rx(const struct device *dev, uint8_t len) struct mcr20a_context *mcr20a = dev->data; struct net_pkt *pkt = NULL; uint8_t pkt_len; + uint16_t rssi; + uint8_t lqi; pkt_len = len - MCR20A_FCS_LENGTH; @@ -574,13 +586,13 @@ static inline void mcr20a_rx(const struct device *dev, uint8_t len) goto out; } - net_pkt_set_ieee802154_lqi(pkt, read_reg_lqi_value(dev)); - net_pkt_set_ieee802154_rssi(pkt, mcr20a_get_rssi( - net_pkt_ieee802154_lqi(pkt))); + lqi = read_reg_lqi_value(dev); + net_pkt_set_ieee802154_lqi(pkt, lqi); + + rssi = mcr20a_get_rssi(lqi); + net_pkt_set_ieee802154_rssi_dbm(pkt, rssi); - LOG_DBG("Caught a packet (%u) (LQI: %u, RSSI: %u)", - pkt_len, net_pkt_ieee802154_lqi(pkt), - net_pkt_ieee802154_rssi(pkt)); + LOG_DBG("Caught a packet (%u) (LQI: %u, RSSI: %d)", pkt_len, lqi, rssi); if (net_recv_data(mcr20a->iface, pkt) < 0) { LOG_DBG("Packet dropped by NET stack"); diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 6aa3e3b7d80b..0418217000fe 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -173,7 +173,7 @@ static void nrf5_rx_thread(void *arg1, void *arg2, void *arg3) } net_pkt_set_ieee802154_lqi(pkt, rx_frame->lqi); - net_pkt_set_ieee802154_rssi(pkt, rx_frame->rssi); + net_pkt_set_ieee802154_rssi_dbm(pkt, rx_frame->rssi); net_pkt_set_ieee802154_ack_fpb(pkt, rx_frame->ack_fpb); #if defined(CONFIG_NET_PKT_TIMESTAMP) @@ -399,7 +399,7 @@ static int handle_ack(struct nrf5_802154_data *nrf5_radio) } net_pkt_set_ieee802154_lqi(ack_pkt, nrf5_radio->ack_frame.lqi); - net_pkt_set_ieee802154_rssi(ack_pkt, nrf5_radio->ack_frame.rssi); + net_pkt_set_ieee802154_rssi_dbm(ack_pkt, nrf5_radio->ack_frame.rssi); #if defined(CONFIG_NET_PKT_TIMESTAMP) struct net_ptp_time timestamp = { diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index 8d80bdc7de1d..8e8947e56beb 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -217,7 +217,7 @@ static void rf2xx_trx_rx(const struct device *dev) memcpy(pkt->buffer->data, rx_buf + RX2XX_FRAME_HEADER_SIZE, pkt_len); net_buf_add(pkt->buffer, pkt_len); net_pkt_set_ieee802154_lqi(pkt, ctx->pkt_lqi); - net_pkt_set_ieee802154_rssi(pkt, ctx->pkt_ed + ctx->trx_rssi_base); + net_pkt_set_ieee802154_rssi_dbm(pkt, ctx->pkt_ed + ctx->trx_rssi_base); LOG_DBG("Caught a packet (%02X) (LQI: %02X, RSSI: %d, ED: %02X)", pkt_len, ctx->pkt_lqi, ctx->trx_rssi_base + ctx->pkt_ed, diff --git a/include/zephyr/net/ieee802154_pkt.h b/include/zephyr/net/ieee802154_pkt.h index a4b59069f92f..23921467d96c 100644 --- a/include/zephyr/net/ieee802154_pkt.h +++ b/include/zephyr/net/ieee802154_pkt.h @@ -8,6 +8,8 @@ /** * @file * @brief Packet data common to all IEEE 802.15.4 L2 layers + * + * All references to the spec refer to IEEE 802.15.4-2020. */ #ifndef ZEPHYR_INCLUDE_NET_IEEE802154_PKT_H_ @@ -27,6 +29,15 @@ extern "C" { #define NET_PKT_HAS_CONTROL_BLOCK #endif +/* See section 6.16.2.8 - Received Signal Strength Indicator (RSSI) */ +#define IEEE802154_MAC_RSSI_MIN 0U /* corresponds to -174 dBm */ +#define IEEE802154_MAC_RSSI_MAX 254U /* corresponds to 80 dBm */ +#define IEEE802154_MAC_RSSI_UNDEFINED 255U /* used by us to indicate an undefined RSSI value */ + +#define IEEE802154_MAC_RSSI_DBM_MIN -174 /* in dBm */ +#define IEEE802154_MAC_RSSI_DBM_MAX 80 /* in dBm */ +#define IEEE802154_MAC_RSSI_DBM_UNDEFINED INT16_MIN /* represents an undefined RSSI value */ + struct net_pkt_cb_ieee802154 { #if defined(CONFIG_NET_L2_OPENTHREAD) uint32_t ack_fc; /* Frame counter set in the ACK */ @@ -36,7 +47,17 @@ struct net_pkt_cb_ieee802154 { /* RX packets */ struct { uint8_t lqi; /* Link Quality Indicator */ - uint8_t rssi; /* Received Signal Strength Indication */ + /* See section 6.16.2.8 - Received Signal Strength Indicator (RSSI) + * "RSSI is represented as one octet of integer [...]; therefore, + * the minimum and maximum values are 0 (–174 dBm) and 254 (80 dBm), + * respectively. 255 is reserved." (MAC PIB attribute macRssi, see + * section 8.4.3.10, table 8-108) + * + * TX packets will show zero for this value. Drivers may set the + * field to the reserved value 255 (0xff) to indicate that an RSSI + * value is not available for this packet. + */ + uint8_t rssi; }; #if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) /* TX packets */ @@ -59,7 +80,9 @@ struct net_pkt_cb_ieee802154 { * e.g. Frame Counter injection. */ #if defined(CONFIG_NET_L2_OPENTHREAD) - uint8_t fv2015 : 1; /* Frame version is IEEE 802.15.4-2015 or later */ + uint8_t fv2015: 1; /* Frame version is IEEE 802.15.4 (0b10), + * see section 7.2.2.10, table 7-3. + */ uint8_t ack_seb : 1; /* Security Enabled Bit was set in the ACK */ #endif }; @@ -82,16 +105,90 @@ static inline void net_pkt_set_ieee802154_lqi(struct net_pkt *pkt, uint8_t lqi) net_pkt_cb_ieee802154(pkt)->lqi = lqi; } +/** + * @brief Get the unsigned RSSI value as defined in section 6.16.2.8, + * Received Signal Strength Indicator (RSSI) + * + * @param pkt Pointer to the packet. + * + * @returns RSSI represented as unsigned byte value, ranging from + * 0 (–174 dBm) to 254 (80 dBm). + * The special value 255 (IEEE802154_MAC_RSSI_UNDEFINED) + * indicates that an RSSI value is not available for this + * packet. Will return zero for packets on the TX path. + */ static inline uint8_t net_pkt_ieee802154_rssi(struct net_pkt *pkt) { return net_pkt_cb_ieee802154(pkt)->rssi; } +/** + * @brief Set the unsigned RSSI value as defined in section 6.16.2.8, + * Received Signal Strength Indicator (RSSI). + * + * @param pkt Pointer to the packet that was received with the given + * RSSI. + * @param rssi RSSI represented as unsigned byte value, ranging from + * 0 (–174 dBm) to 254 (80 dBm). + * The special value 255 (IEEE802154_MAC_RSSI_UNDEFINED) + * indicates that an RSSI value is not available for this + * packet. + */ static inline void net_pkt_set_ieee802154_rssi(struct net_pkt *pkt, uint8_t rssi) { net_pkt_cb_ieee802154(pkt)->rssi = rssi; } +/** + * @brief Get a signed RSSI value measured in dBm. + * + * @param pkt Pointer to the packet. + * + * @returns RSSI represented in dBm. Returns the special value + * IEEE802154_MAC_RSSI_DBM_UNDEFINED if an RSSI value + * is not available for this packet. Packets on the TX + * path will always show -174 dBm (which corresponds to + * an internal value of unsigned zero). + */ +static inline int16_t net_pkt_ieee802154_rssi_dbm(struct net_pkt *pkt) +{ + int16_t rssi = net_pkt_cb_ieee802154(pkt)->rssi; + return rssi == IEEE802154_MAC_RSSI_UNDEFINED ? IEEE802154_MAC_RSSI_DBM_UNDEFINED + : rssi + IEEE802154_MAC_RSSI_DBM_MIN; +} + +/** + * @brief Set the RSSI value as a signed integer measured in dBm. + * + * @param pkt Pointer to the packet that was received with the given + * RSSI. + * @param rssi represented in dBm. Set to the special value + * IEEE802154_MAC_RSSI_DBM_UNDEFINED if an RSSI value is + * not available for this packet. Values above 80 dBm will + * be mapped to 80 dBm, values below -174 dBm will be mapped + * to -174 dBm. + */ +static inline void net_pkt_set_ieee802154_rssi_dbm(struct net_pkt *pkt, int16_t rssi) +{ + if (likely(rssi >= IEEE802154_MAC_RSSI_DBM_MIN && rssi <= IEEE802154_MAC_RSSI_DBM_MAX)) { + int16_t unsigned_rssi = rssi - IEEE802154_MAC_RSSI_DBM_MIN; + + net_pkt_cb_ieee802154(pkt)->rssi = unsigned_rssi; + return; + } else if (rssi == IEEE802154_MAC_RSSI_DBM_UNDEFINED) { + net_pkt_cb_ieee802154(pkt)->rssi = IEEE802154_MAC_RSSI_UNDEFINED; + return; + } else if (rssi < IEEE802154_MAC_RSSI_DBM_MIN) { + net_pkt_cb_ieee802154(pkt)->rssi = IEEE802154_MAC_RSSI_MIN; + return; + } else if (rssi > IEEE802154_MAC_RSSI_DBM_MAX) { + net_pkt_cb_ieee802154(pkt)->rssi = IEEE802154_MAC_RSSI_MAX; + return; + } + + CODE_UNREACHABLE; +} + #if defined(CONFIG_IEEE802154_SELECTIVE_TXPOWER) static inline int8_t net_pkt_ieee802154_txpwr(struct net_pkt *pkt) { diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index ce6410e9933b..582a1cff5c62 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -181,7 +181,7 @@ enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, ack_frame.mPsdu = ack_psdu; ack_frame.mLength = ack_len; ack_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt); - ack_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi(pkt); + ack_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi_dbm(pkt); #if defined(CONFIG_NET_PKT_TIMESTAMP) struct net_ptp_time *pkt_time = net_pkt_timestamp(pkt); @@ -390,7 +390,7 @@ static void openthread_handle_received_frame(otInstance *instance, recv_frame.mLength = net_buf_frags_len(pkt->buffer); recv_frame.mChannel = platformRadioChannelGet(instance); recv_frame.mInfo.mRxInfo.mLqi = net_pkt_ieee802154_lqi(pkt); - recv_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi(pkt); + recv_frame.mInfo.mRxInfo.mRssi = net_pkt_ieee802154_rssi_dbm(pkt); recv_frame.mInfo.mRxInfo.mAckedWithFramePending = net_pkt_ieee802154_ack_fpb(pkt); #if defined(CONFIG_NET_PKT_TIMESTAMP) diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 1bd744b58b24..3a45d2d17cf3 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -4334,7 +4334,7 @@ static enum net_verdict handle_ipv6_echo_reply(struct net_pkt *pkt, ntohs(icmp_echo->sequence), ip_hdr->hop_limit, #ifdef CONFIG_IEEE802154 - net_pkt_ieee802154_rssi(pkt), + net_pkt_ieee802154_rssi_dbm(pkt), #endif time_buf); diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index 321ac0fcfd87..b7f4a3d55229 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -535,6 +535,68 @@ static bool test_packet_cloning_with_cb(void) return true; } +static bool test_packet_rssi_conversion(void) +{ + uint8_t raw_signed_rssi_dbm; + int8_t signed_rssi_dbm; + struct net_pkt *pkt; + + NET_INFO("- RSSI conversion between unsigned and signed representation\n"); + + pkt = net_pkt_rx_alloc_on_iface(iface, K_NO_WAIT); + if (!pkt) { + NET_ERR("*** No pkt to allocate\n"); + return false; + } + + /* Test setting/getting of unsigned RSSI. */ + net_pkt_set_ieee802154_rssi(pkt, 50U); + zassert_equal(net_pkt_ieee802154_rssi(pkt), 50U); + + /* Test setting/getting of signed RSSI (in range). */ + net_pkt_set_ieee802154_rssi_dbm(pkt, IEEE802154_MAC_RSSI_DBM_MIN); + zassert_equal(net_pkt_ieee802154_rssi(pkt), IEEE802154_MAC_RSSI_MIN); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), IEEE802154_MAC_RSSI_DBM_MIN); + net_pkt_set_ieee802154_rssi_dbm(pkt, IEEE802154_MAC_RSSI_DBM_MAX); + zassert_equal(net_pkt_ieee802154_rssi(pkt), IEEE802154_MAC_RSSI_MAX); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), IEEE802154_MAC_RSSI_DBM_MAX); + net_pkt_set_ieee802154_rssi_dbm(pkt, 0); + zassert_equal(net_pkt_ieee802154_rssi(pkt), 174U); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), 0); + + /* Test setting/getting of signed RSSI (outside range). */ + net_pkt_set_ieee802154_rssi_dbm(pkt, INT16_MIN + 1); + zassert_equal(net_pkt_ieee802154_rssi(pkt), IEEE802154_MAC_RSSI_MIN); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), IEEE802154_MAC_RSSI_DBM_MIN); + net_pkt_set_ieee802154_rssi_dbm(pkt, INT16_MAX); + zassert_equal(net_pkt_ieee802154_rssi(pkt), IEEE802154_MAC_RSSI_MAX); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), IEEE802154_MAC_RSSI_DBM_MAX); + + /* Test setting/getting of signed RSSI (special value - "no RSSI available"). */ + net_pkt_set_ieee802154_rssi_dbm(pkt, IEEE802154_MAC_RSSI_DBM_UNDEFINED); + zassert_equal(net_pkt_ieee802154_rssi(pkt), IEEE802154_MAC_RSSI_UNDEFINED); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), IEEE802154_MAC_RSSI_DBM_UNDEFINED); + + /* Demonstrate setting/getting of signed RSSI represented as a raw + * two-complements value in uint8_t (explicit cast required). + */ + raw_signed_rssi_dbm = (uint8_t)-2; + net_pkt_set_ieee802154_rssi_dbm(pkt, (int8_t) raw_signed_rssi_dbm); + zassert_equal(net_pkt_ieee802154_rssi(pkt), 172U); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), -2); + + /* Demonstrate setting/getting of signed RSSI represented as int8_t + * (no explicit cast required) + */ + signed_rssi_dbm = -2; + net_pkt_set_ieee802154_rssi_dbm(pkt, signed_rssi_dbm); + zassert_equal(net_pkt_ieee802154_rssi(pkt), 172U); + zassert_equal(net_pkt_ieee802154_rssi_dbm(pkt), -2); + + net_pkt_unref(pkt); + return true; +} + #ifdef CONFIG_NET_SOCKETS static bool test_dgram_packet_sending(void *dst_sll, uint8_t dst_sll_halen, uint32_t security_level) { @@ -1189,6 +1251,16 @@ ZTEST(ieee802154_l2, test_clone_cb) zassert_true(ret, "IEEE 802.15.4 net_pkt control block correctly cloned."); } +ZTEST(ieee802154_l2, test_convert_rssi) +{ + bool ret; + + ret = test_packet_rssi_conversion(); + + zassert_true(ret, "IEEE 802.15.4 net_pkt RSSI value correctly converted between dBm and " + "normalized value."); +} + ZTEST_SUITE(ieee802154_l2, NULL, test_setup, NULL, NULL, test_teardown); #ifdef CONFIG_NET_SOCKETS diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index ea28eaba7329..d791f964f097 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -243,7 +243,7 @@ static void create_ack_frame(void) buf->len = ACK_PKT_LENGTH; buf->data[0] = FRAME_TYPE_ACK; - net_pkt_set_ieee802154_rssi(packet, rssi); + net_pkt_set_ieee802154_rssi_dbm(packet, rssi); net_pkt_set_ieee802154_lqi(packet, lqi); zassert_equal(ieee802154_radio_handle_ack(NULL, packet), NET_OK, "Handling ack failed."); net_pkt_unref(packet); @@ -752,7 +752,7 @@ ZTEST(openthread_radio, test_receive_test) buf = packet->buffer; net_pkt_set_ieee802154_lqi(packet, lqi); - net_pkt_set_ieee802154_rssi(packet, rssi); + net_pkt_set_ieee802154_rssi_dbm(packet, rssi); zassert_equal(otPlatRadioSetTransmitPower(ot, power), OT_ERROR_NONE, "Failed to set TX power."); From 5bd42b9b2c3c4fdadf2f12148d48955edf73bb6e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 11 Jun 2023 16:05:58 +0200 Subject: [PATCH 0195/2042] MAINTAINERS: add IEEE 802.15.4 driver collaborators Added cfriedt and fgrandel as collaborators for IEEE 802.15.4 driver maintenance as suggested by cfried in https://github.com/zephyrproject-rtos/zephyr/pull/59133#pullrequestreview-1473704118 Signed-off-by: Florian Grandel --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 784d882a899c..bf4ea3f57866 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1015,6 +1015,8 @@ Release Notes: collaborators: - rlubos - jciupis + - cfriedt + - fgrandel files: - drivers/ieee802154/ labels: From ad826f3d69f5098f46a2f4c10e92bf9289e70888 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 16 Jun 2023 12:55:28 -0700 Subject: [PATCH 0196/2042] x86: x86_64 can only support max 4 CPUs With all the stacks and TSS (etc), the x86_64 arch code can only support maximum of 4 CPUs at the moment. So add a build assert if more CPUs are specified via CONFIG_MP_MAX_NUM_CPUS, also overwrite the range value for CONFIG_MP_MAX_NUM_CPUS. Signed-off-by: Daniel Leung --- arch/x86/core/Kconfig.intel64 | 3 +++ arch/x86/core/intel64/cpu.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/arch/x86/core/Kconfig.intel64 b/arch/x86/core/Kconfig.intel64 index 0896a2364993..64021959034e 100644 --- a/arch/x86/core/Kconfig.intel64 +++ b/arch/x86/core/Kconfig.intel64 @@ -87,4 +87,7 @@ config X86_USERSPACE supporting user-level threads that are protected from each other and from crashing the kernel. +config MP_MAX_NUM_CPUS + range 1 4 + endif # X86_64 diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 15b382b57171..26263b2e4625 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -13,6 +13,8 @@ #include #include +BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS <= 4, "Only supports max 4 CPUs"); + /* * Map of CPU logical IDs to CPU local APIC IDs. By default, * we assume this simple identity mapping, as found in QEMU. From 2a30acc82340e1936f8690838c196b9af7d4b0de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Apr 2023 08:51:37 -0700 Subject: [PATCH 0197/2042] samples/tfm_integration: Remove 'noreturn' attribute from main This conflicts with what the compiler expects for the definition of 'main' when -ffreestanding is not used. Signed-off-by: Keith Packard --- samples/tfm_integration/tfm_psa_test/src/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/tfm_integration/tfm_psa_test/src/main.c b/samples/tfm_integration/tfm_psa_test/src/main.c index 810ebf878e5a..232fc505cfdf 100644 --- a/samples/tfm_integration/tfm_psa_test/src/main.c +++ b/samples/tfm_integration/tfm_psa_test/src/main.c @@ -9,7 +9,6 @@ /* Run the PSA test suite */ void psa_test(void); -__attribute__((noreturn)) int main(void) { #ifdef CONFIG_TFM_PSA_TEST_NONE From 5dd87e7db3f4b847b23974c252ec52802cf263c9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 27 Apr 2023 08:52:37 -0700 Subject: [PATCH 0198/2042] samples/userspace: Set common malloc arena size to zero for syscall_perf The default malloc arena when using picolibc is too large for the hifive1_revb target. Signed-off-by: Keith Packard --- samples/userspace/syscall_perf/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/userspace/syscall_perf/prj.conf b/samples/userspace/syscall_perf/prj.conf index e91ecbb07045..c16c800cc935 100644 --- a/samples/userspace/syscall_perf/prj.conf +++ b/samples/userspace/syscall_perf/prj.conf @@ -4,3 +4,4 @@ CONFIG_ASSERT=y CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 From a476e870737c0ce959bd17157c2392dbdb77a0b4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 15 Jun 2023 20:18:47 -0700 Subject: [PATCH 0199/2042] samples/cmsis_rtos_v2/timer_synchronization: Set malloc arena size to zero This test fails when using picolibc with the default malloc arena value. Fix this by explicitly setting the malloc arena size to zero, as when using the minimal C library. Signed-off-by: Keith Packard --- .../portability/cmsis_rtos_v2/timer_synchronization/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/prj.conf b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/prj.conf index a186b930324f..bf45f311b3f6 100644 --- a/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/prj.conf +++ b/samples/subsys/portability/cmsis_rtos_v2/timer_synchronization/prj.conf @@ -11,3 +11,4 @@ CONFIG_POLL=y CONFIG_SCHED_SCALABLE=y # The Zephyr CMSIS v2 emulation assumes that ticks are ms, currently CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 From 5dfaf23f47b73b9b74f1982992eefac0dc328932 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 16 Jun 2023 04:56:52 +0000 Subject: [PATCH 0200/2042] xtensa: intel_adsp: lnl: Fix dspcs struct This is struct is used to access to contiguous registers for each core and lnl has 5. Signed-off-by: Flavio Ceolin --- .../intel_adsp/ace/include/intel_ace20_lnl/adsp_boot.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_boot.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_boot.h index acfdf1c6cbe4..f1fde19eac2a 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_boot.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_boot.h @@ -21,8 +21,8 @@ struct dspcs { struct { uint32_t cap; uint32_t ctl; - } capctl[3]; - uint32_t unused0[10]; + } capctl[5]; + uint32_t unused0[6]; /* * DSPBRx @@ -40,7 +40,7 @@ struct dspcs { uint32_t baddr; uint32_t battr; uint32_t unused2; - } bootctl[3]; + } bootctl[5]; }; #define DSPCS_CTL_SPA BIT(0) From 339b00de11e532a6b06bd77873ae43e4f981000a Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 13 Jun 2023 14:17:21 +0300 Subject: [PATCH 0201/2042] soc: xtensa: intel_adsp: fix memory bank shutdown Amount of memory banks should vary depending on platform, otherwise power down sequence might result in ipc timeout as the memory used by the ipc itself is shutdown. Lift the needed defines from sram.c to adsp_memory.h and shorten the names to avoid collision with sof code. No functional change to sram.c. Signed-off-by: Jaska Uimonen --- .../cavs/include/intel_tgl_adsp/adsp_memory.h | 9 ++++++++- soc/xtensa/intel_adsp/cavs/power.c | 9 +++++---- soc/xtensa/intel_adsp/cavs/power_down_cavs.S | 7 +++---- soc/xtensa/intel_adsp/cavs/sram.c | 18 +++++++----------- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h index 0edb304665fd..b989dd261885 100644 --- a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h +++ b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h @@ -6,7 +6,6 @@ #ifndef ZEPHYR_SOC_INTEL_ADSP_MEMORY_H_ #define ZEPHYR_SOC_INTEL_ADSP_MEMORY_H_ - #include #include @@ -22,6 +21,14 @@ #define RAM_BASE (L2_SRAM_BASE + CONFIG_HP_SRAM_RESERVE + VECTOR_TBL_SIZE) #define RAM_SIZE (L2_SRAM_SIZE - CONFIG_HP_SRAM_RESERVE - VECTOR_TBL_SIZE) +#define SRAM_BANK_SIZE (64 * 1024) +#define EBB_SEG_SIZE 32 +#define HPSRAM_EBB_COUNT (DT_REG_SIZE(DT_NODELABEL(sram0)) / SRAM_BANK_SIZE) + +/* div_round_up, but zephyr version is not defined for assembler where this is also used */ +#define HPSRAM_SEGMENTS (HPSRAM_EBB_COUNT + EBB_SEG_SIZE - 1) / EBB_SEG_SIZE +#define HPSRAM_MEMMASK(idx) ((1ULL << (HPSRAM_EBB_COUNT - EBB_SEG_SIZE * idx)) - 1) + /* The rimage tool produces two blob addresses we need to find: one is * our bootloader code block which starts at its entry point, the * other is the "manifest" containing the HP-SRAM data to unpack, diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index 758f8d88061a..ea8987814617 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,6 @@ LOG_MODULE_REGISTER(soc); #ifdef CONFIG_PM_POLICY_CUSTOM #define SRAM_ALIAS_BASE 0x9E000000 #define SRAM_ALIAS_MASK 0xFF000000 -#define EBB_BANKS_IN_SEGMENT 32 #define SRAM_ALIAS_OFFSET 0x20000000 #define L2_INTERRUPT_NUMBER 4 @@ -81,11 +81,12 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) soc_cpus_active[cpu] = false; sys_cache_data_flush_and_invd_all(); if (cpu == 0) { - uint32_t ebb = EBB_BANKS_IN_SEGMENT; + uint32_t hpsram_mask[HPSRAM_SEGMENTS]; /* turn off all HPSRAM banks - get a full bitmap */ - uint32_t hpsram_mask = (1 << ebb) - 1; + for (int i = 0; i < HPSRAM_SEGMENTS; i++) + hpsram_mask[i] = HPSRAM_MEMMASK(i); /* do power down - this function won't return */ - power_down_cavs(true, uncache_to_cache(&hpsram_mask)); + power_down_cavs(true, uncache_to_cache(&hpsram_mask[0])); } else { z_xt_ints_on(core_desc[cpu].intenable); k_cpu_idle(); diff --git a/soc/xtensa/intel_adsp/cavs/power_down_cavs.S b/soc/xtensa/intel_adsp/cavs/power_down_cavs.S index 8e70521c52fd..448b105ff618 100644 --- a/soc/xtensa/intel_adsp/cavs/power_down_cavs.S +++ b/soc/xtensa/intel_adsp/cavs/power_down_cavs.S @@ -4,6 +4,7 @@ #include "asm_ldo_management.h" #include "asm_memory_management.h" +#include "adsp_memory.h" #define IPC_HOST_BASE 0x00071E00 #define IPC_DIPCIDD 0x18 @@ -42,8 +43,6 @@ sram_dis_loop_cnt: #define host_base a10 #define pfl_reg a15 -#define MAX_MEMORY_SEGMENTS 2 - power_down_cavs: entry sp, 32 /** @@ -102,8 +101,8 @@ _PD_DISABLE_HPSRAM: * where mask is given in pu32_hpsram_mask register */ - .set seg_index, MAX_MEMORY_SEGMENTS - 1 - .rept MAX_MEMORY_SEGMENTS + .set seg_index, HPSRAM_SEGMENTS - 1 + .rept HPSRAM_SEGMENTS l32i temp_reg0, pu32_hpsram_mask, 4 * seg_index m_cavs_hpsram_power_change\ /*segment_index=*/ seg_index,\ diff --git a/soc/xtensa/intel_adsp/cavs/sram.c b/soc/xtensa/intel_adsp/cavs/sram.c index 070aa70256dd..0382f0d8056a 100644 --- a/soc/xtensa/intel_adsp/cavs/sram.c +++ b/soc/xtensa/intel_adsp/cavs/sram.c @@ -13,15 +13,11 @@ #include #include "manifest.h" - #define DELAY_COUNT 256 #define LPSRAM_MASK(x) 0x00000003 -#define SRAM_BANK_SIZE (64 * 1024) -#define EBB_SEGMENT_SIZE 32 #define PLATFORM_INIT_HPSRAM #define PLATFORM_INIT_LPSRAM -#define PLATFORM_HPSRAM_EBB_COUNT (DT_REG_SIZE(DT_NODELABEL(sram0)) / SRAM_BANK_SIZE) BUILD_ASSERT((DT_REG_SIZE(DT_NODELABEL(sram0)) % SRAM_BANK_SIZE) == 0, "sram0 must be divisible by 64*1024 bank size."); @@ -33,7 +29,7 @@ static __imr void hp_sram_pm_banks(uint32_t banks) { #ifdef CONFIG_ADSP_INIT_HPSRAM uint32_t status, ebb_mask0, ebb_mask1, ebb_avail_mask0, ebb_avail_mask1, - total_banks_count = PLATFORM_HPSRAM_EBB_COUNT; + total_banks_count = HPSRAM_EBB_COUNT; CAVS_SHIM.ldoctl = SHIM_LDOCTL_HPSRAM_LDO_ON; @@ -44,19 +40,19 @@ static __imr void hp_sram_pm_banks(uint32_t banks) * bit masks reflect total number of available EBB (banks) in each * segment; current implementation supports 2 segments 0,1 */ - if (total_banks_count > EBB_SEGMENT_SIZE) { - ebb_avail_mask0 = (uint32_t)GENMASK(EBB_SEGMENT_SIZE - 1, 0); + if (total_banks_count > EBB_SEG_SIZE) { + ebb_avail_mask0 = (uint32_t)GENMASK(EBB_SEG_SIZE - 1, 0); ebb_avail_mask1 = (uint32_t)GENMASK(total_banks_count - - EBB_SEGMENT_SIZE - 1, 0); + EBB_SEG_SIZE - 1, 0); } else { ebb_avail_mask0 = (uint32_t)GENMASK(total_banks_count - 1, 0); ebb_avail_mask1 = 0; } /* bit masks of banks that have to be powered up in each segment */ - if (banks > EBB_SEGMENT_SIZE) { - ebb_mask0 = (uint32_t)GENMASK(EBB_SEGMENT_SIZE - 1, 0); - ebb_mask1 = (uint32_t)GENMASK(banks - EBB_SEGMENT_SIZE - 1, + if (banks > EBB_SEG_SIZE) { + ebb_mask0 = (uint32_t)GENMASK(EBB_SEG_SIZE - 1, 0); + ebb_mask1 = (uint32_t)GENMASK(banks - EBB_SEG_SIZE - 1, 0); } else { /* assumption that ebb_in_use is > 0 */ From 2ba7855ddf23a51f59f01246c48511ea4ca27c57 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 15 Jun 2023 12:41:58 -0700 Subject: [PATCH 0202/2042] modules: mipi-syst: support minimal C library This allows the MIPI Sys-T library to be built with minimal C library. This is due to lack of support for wchar in our minimal C library. This simply tells the library to skip any wchar support. Signed-off-by: Daniel Leung --- modules/Kconfig.syst | 8 +++++++- west.yml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/Kconfig.syst b/modules/Kconfig.syst index 6d79059e07ba..e19c4fcd4fae 100644 --- a/modules/Kconfig.syst +++ b/modules/Kconfig.syst @@ -3,7 +3,6 @@ config MIPI_SYST_LIB bool "MIPI SyS-T Library Support" - select REQUIRES_FULL_LIBC help This option enables the MIPI SyS-T Library @@ -20,4 +19,11 @@ config MIPI_SYST_RAW_DATA help This option outputs MIPI SyS-T raw data packet +config MIPI_SYST_NO_WHCAR + bool + default y if MINIMAL_LIBC + help + Tell MIPI Sys-T library to not build with + wchar support. + endif diff --git a/west.yml b/west.yml index abe9772498ea..451c72ac4313 100644 --- a/west.yml +++ b/west.yml @@ -274,7 +274,7 @@ manifest: path: modules/debug/mipi-sys-t groups: - debug - revision: 0d521d8055f3b2b4842f728b0365d3f0ece9c37f + revision: a819419603a2dfcb47f7f39092e1bc112e45d1ef - name: nanopb revision: 42fa8b211e946b90b9d968523fce7b1cfe27617e path: modules/lib/nanopb From 477dd86b78d64df3719bd50e8a2084dba7014fda Mon Sep 17 00:00:00 2001 From: Donatien Garnier Date: Wed, 7 Jun 2023 11:35:34 +0100 Subject: [PATCH 0203/2042] Bluetooth: Host: Add sending L2CAP data from connection callback test Add BabbleSim test to make sure data can be sent immediately upon connection from the L2CAP channel connection callback Signed-off-by: Donatien Garnier --- tests/bsim/bluetooth/host/compile.sh | 2 + .../host/l2cap/send_on_connect/CMakeLists.txt | 17 ++ .../host/l2cap/send_on_connect/prj.conf | 10 + .../host/l2cap/send_on_connect/prj_ecred.conf | 10 + .../host/l2cap/send_on_connect/src/common.c | 22 ++ .../host/l2cap/send_on_connect/src/common.h | 44 +++ .../host/l2cap/send_on_connect/src/main.c | 20 ++ .../src/main_l2cap_send_on_connect.c | 259 ++++++++++++++++++ .../send_on_connect/tests_scripts/l2cap.sh | 39 +++ 9 files changed, 423 insertions(+) create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/prj.conf create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/prj_ecred.conf create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.c create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.h create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main.c create mode 100644 tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c create mode 100755 tests/bsim/bluetooth/host/l2cap/send_on_connect/tests_scripts/l2cap.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 33c71bc3ddfe..31a4b70162e6 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -53,6 +53,8 @@ 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/send_on_connect compile +app=tests/bsim/bluetooth/host/l2cap/send_on_connect conf_file=prj_ecred.conf compile app=tests/bsim/bluetooth/host/misc/disable compile diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/send_on_connect/CMakeLists.txt new file mode 100644 index 000000000000..f6db9d424e24 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/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_l2cap_send_on_connect) + +target_sources(app PRIVATE + src/common.c + src/main_l2cap_send_on_connect.c + src/main.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj.conf b/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj.conf new file mode 100644 index 000000000000..8206e01ea662 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj.conf @@ -0,0 +1,10 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=n + +CONFIG_BT_BUF_ACL_RX_SIZE=75 + +CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj_ecred.conf b/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj_ecred.conf new file mode 100644 index 000000000000..6d4180031747 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/prj_ecred.conf @@ -0,0 +1,10 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=y + +CONFIG_BT_BUF_ACL_RX_SIZE=75 + +CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.c b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.c new file mode 100644 index 000000000000..f725ac6129c3 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +extern enum bst_result_t bst_result; + +void test_init(void) +{ + bst_result = In_progress; + bst_ticker_set_next_tick_absolute(WAIT_TIME); +} + +void test_tick(bs_time_t HW_device_time) +{ + if (bst_result != Passed) { + FAIL("test failed (not passed after %i us)\n", WAIT_TIME); + } +} diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.h b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.h new file mode 100644 index 000000000000..3b0d09c53b6c --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/common.h @@ -0,0 +1,44 @@ +/* + * Common functions and helpers for L2CAP tests + * + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_types.h" +#include "bs_tracing.h" +#include "bstests.h" + +#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_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_TIME (30e6) /* 30 seconds*/ + +#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_init(void); +void test_tick(bs_time_t HW_device_time); diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main.c b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main.c new file mode 100644 index 000000000000..6fcc26c6cadb --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_main_l2cap_send_on_connect_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_main_l2cap_send_on_connect_install, + NULL +}; + +int main(void) +{ + bst_main(); + return 0; +} 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 new file mode 100644 index 000000000000..b7eab47736d7 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/src/main_l2cap_send_on_connect.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +#include +#include + +extern enum bst_result_t bst_result; + +static struct bt_conn *default_conn; + +#define PSM 0x80 + +CREATE_FLAG(is_connected); +CREATE_FLAG(chan_connected); +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); + +static void chan_connected_cb(struct bt_l2cap_chan *l2cap_chan) +{ + struct net_buf *buf; + int err; + + /* Send data immediately on L2CAP connection */ + buf = net_buf_alloc(&buf_pool, K_NO_WAIT); + if (!buf) { + FAIL("Buffer allocation failed\n"); + } + + (void)net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE); + (void)net_buf_add_u8(buf, DATA_BYTE_VAL); + + /* Try to send data */ + err = bt_l2cap_chan_send(l2cap_chan, buf); + if (err) { + FAIL("Could not send data, error %d\n", err); + } + + SET_FLAG(chan_connected); +} + +static void chan_disconnected_cb(struct bt_l2cap_chan *l2cap_chan) +{ + (void)l2cap_chan; + + UNSET_FLAG(chan_connected); +} + +static int chan_recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + (void)chan; + + if ((buf->len != 1) || (buf->data[0] != DATA_BYTE_VAL)) { + FAIL("Unexpected data received"); + } + + SET_FLAG(data_received); + + return 0; +} + +static const struct bt_l2cap_chan_ops l2cap_ops = { + .connected = chan_connected_cb, + .disconnected = chan_disconnected_cb, + .recv = chan_recv_cb, +}; + +static struct bt_l2cap_le_chan channel; + +static int accept(struct bt_conn *conn, struct bt_l2cap_chan **l2cap_chan) +{ + channel.chan.ops = &l2cap_ops; + *l2cap_chan = &channel.chan; + + return 0; +} + +static struct bt_l2cap_server server = { + .accept = accept, + .sec_level = BT_SECURITY_L1, + .psm = PSM, +}; + +static void connect_l2cap_channel(void) +{ + struct bt_l2cap_chan *chans[] = {&channel.chan, NULL}; + int err; + + channel.chan.ops = &l2cap_ops; + + if (IS_ENABLED(CONFIG_BT_L2CAP_ECRED)) { + err = bt_l2cap_ecred_chan_connect(default_conn, chans, server.psm); + if (err) { + FAIL("Failed to send ecred connection request (err %d)\n", err); + } + } else { + err = bt_l2cap_chan_connect(default_conn, &channel.chan, server.psm); + if (err) { + FAIL("Failed to send connection request (err %d)\n", err); + } + } +} + +static void register_l2cap_server(void) +{ + int err; + + err = bt_l2cap_server_register(&server); + if (err < 0) { + FAIL("Failed to get free server (err %d)\n"); + return; + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + if (err) { + FAIL("Failed to connect (err %d)\n", err); + bt_conn_unref(default_conn); + default_conn = NULL; + return; + } + + default_conn = bt_conn_ref(conn); + + SET_FLAG(is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + if (default_conn != conn) { + FAIL("Connection mismatch %p %p)\n", default_conn, conn); + return; + } + + bt_conn_unref(default_conn); + default_conn = NULL; + UNSET_FLAG(is_connected); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +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; + int err; + + err = bt_le_scan_stop(); + if (err) { + FAIL("Failed to stop scanning (err %d)\n", err); + return; + } + + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); + if (err) { + FAIL("Failed to create connection (err %d)\n", err); + return; + } +} + +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; + } + + register_l2cap_server(); + + 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; + } + + WAIT_FOR_FLAG_SET(is_connected); + + WAIT_FOR_FLAG_SET(chan_connected); + + WAIT_FOR_FLAG_SET(data_received); + + WAIT_FOR_FLAG_UNSET(is_connected); + + PASS("Test passed\n"); +} + +static void test_central_main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + FAIL("Bluetooth init 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); + } + + WAIT_FOR_FLAG_SET(is_connected); + + connect_l2cap_channel(); + WAIT_FOR_FLAG_SET(chan_connected); + + WAIT_FOR_FLAG_SET(data_received); + + err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err) { + FAIL("Failed to disconnect (err %d)\n", err); + return; + } + + WAIT_FOR_FLAG_UNSET(is_connected); + + PASS("Test passed\n"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "peripheral", + .test_descr = "Peripheral", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_peripheral_main, + }, + { + .test_id = "central", + .test_descr = "Central", + .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_send_on_connect_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} diff --git a/tests/bsim/bluetooth/host/l2cap/send_on_connect/tests_scripts/l2cap.sh b/tests/bsim/bluetooth/host/l2cap/send_on_connect/tests_scripts/l2cap.sh new file mode 100755 index 000000000000..7fa0459c3270 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/send_on_connect/tests_scripts/l2cap.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Copyright (c) 2022 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="l2cap_send_on_connect" +verbosity_level=2 +EXECUTE_TIMEOUT=120 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_l2cap_send_on_connect_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_l2cap_send_on_connect_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs + +simulation_id="l2cap_send_on_connect_ecred" +verbosity_level=2 +EXECUTE_TIMEOUT=120 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_l2cap_send_on_connect_prj_ecred_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_l2cap_send_on_connect_prj_ecred_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=30e6 $@ + +wait_for_background_jobs From cf0350e0210fcd5e1410e36b2e9a2aaf7c8341e0 Mon Sep 17 00:00:00 2001 From: Donatien Garnier Date: Tue, 30 May 2023 17:00:03 +0100 Subject: [PATCH 0204/2042] Bluetooth: Host: Re-order LE L2CAP connection accept procedure Currently, when an incoming dynamic LE L2CAP connection is requested by a peer, the connected() callback provided by the user is raised *before* a L2CAP_LE_CREDIT_BASED_CONNECTION_RSP is sent back to the peer. In some cases the user will start sending data in the connected() callback which would be received too early by the peer. This commit fixes this behavior by making sure the connected() callback is raised only after the connection response has been sent to the peer. Signed-off-by: Donatien Garnier --- subsys/bluetooth/host/l2cap.c | 38 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index 839abecd5e51..ff8c712bf096 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1088,10 +1088,6 @@ static uint16_t l2cap_chan_accept(struct bt_conn *conn, /* Update state */ bt_l2cap_chan_set_state(*chan, BT_L2CAP_CONNECTED); - if ((*chan)->ops->connected) { - (*chan)->ops->connected(*chan); - } - return BT_L2CAP_LE_SUCCESS; } @@ -1164,21 +1160,19 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident, /* Check if there is a server registered */ server = bt_l2cap_server_lookup_psm(psm); if (!server) { - rsp->result = sys_cpu_to_le16(BT_L2CAP_LE_ERR_PSM_NOT_SUPP); + result = BT_L2CAP_LE_ERR_PSM_NOT_SUPP; goto rsp; } /* Check if connection has minimum required security level */ result = l2cap_check_security(conn, server); if (result != BT_L2CAP_LE_SUCCESS) { - rsp->result = sys_cpu_to_le16(result); goto rsp; } result = l2cap_chan_accept(conn, server, scid, mtu, mps, credits, &chan); if (result != BT_L2CAP_LE_SUCCESS) { - rsp->result = sys_cpu_to_le16(result); goto rsp; } @@ -1190,10 +1184,20 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident, rsp->mtu = sys_cpu_to_le16(le_chan->rx.mtu); rsp->credits = sys_cpu_to_le16(le_chan->rx.credits); - rsp->result = BT_L2CAP_LE_SUCCESS; + result = BT_L2CAP_LE_SUCCESS; rsp: - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + rsp->result = sys_cpu_to_le16(result); + + if (bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { + net_buf_unref(buf); + return; + } + + /* Raise connected callback on success */ + if ((result == BT_L2CAP_LE_SUCCESS) && (chan->ops->connected != NULL)) { + chan->ops->connected(chan); + } } #if defined(CONFIG_BT_L2CAP_ECRED) @@ -1211,6 +1215,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, uint16_t scid, dcid[L2CAP_ECRED_CHAN_MAX_PER_REQ]; int i = 0; uint8_t req_cid_count; + bool rsp_queued = false; /* set dcid to zeros here, in case of all connections refused error */ memset(dcid, 0, sizeof(dcid)); @@ -1304,12 +1309,25 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, net_buf_add_mem(buf, dcid, sizeof(scid) * req_cid_count); - l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf); + if (bt_l2cap_send(conn, BT_L2CAP_CID_LE_SIG, buf)) { + net_buf_unref(buf); + goto callback; + } + + rsp_queued = true; callback: if (ecred_cb && ecred_cb->ecred_conn_req) { ecred_cb->ecred_conn_req(conn, result, psm); } + if (rsp_queued && result == BT_L2CAP_LE_SUCCESS) { + for (i = 0; i < req_cid_count; i++) { + /* Raise connected callback for established channels */ + if ((dcid[i] != 0x00) && (chan[i]->ops->connected != NULL)) { + chan[i]->ops->connected(chan[i]); + } + } + } } static void le_ecred_reconf_req(struct bt_l2cap *l2cap, uint8_t ident, From 5bf2260e900f27bebfe82207b23a924a01daa797 Mon Sep 17 00:00:00 2001 From: Khor Swee Aun Date: Thu, 8 Jun 2023 10:19:22 +0800 Subject: [PATCH 0205/2042] soc: riscv: riscv-privileged: INTEL Nios V/g support Add support for INTEL FPGA Nios V/g RISC-V based Processors. Also amended SOC_NIOSV_M to use ATOMIC_OPERATIONS_BUILTIN. Signed-off-by: Khor Swee Aun --- soc/riscv/riscv-privileged/niosv/Kconfig.soc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.soc b/soc/riscv/riscv-privileged/niosv/Kconfig.soc index 9c471f049999..67da5ccee383 100644 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.soc +++ b/soc/riscv/riscv-privileged/niosv/Kconfig.soc @@ -7,11 +7,21 @@ choice config SOC_NIOSV_M bool "Intel FPGA NIOSV Microcontroller Core Processor" - select ATOMIC_OPERATIONS_C + select ATOMIC_OPERATIONS_BUILTIN select INCLUDE_RESET_VECTOR select RISCV_ISA_RV32I select RISCV_ISA_EXT_A select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI +config SOC_NIOSV_G + bool "Intel FPGA NIOSV General Purpose Processor" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + endchoice From ad6bf7f45660a507607f1916afed63b353c8e6e6 Mon Sep 17 00:00:00 2001 From: Khor Swee Aun Date: Thu, 8 Jun 2023 10:22:11 +0800 Subject: [PATCH 0206/2042] dts: riscv: Add dts support for INTEL Nios V/g Add basic dts support for INTEL Nios V/g General Purpose Processor. Signed-off-by: Khor Swee Aun --- dts/riscv/niosv/niosv-g.dtsi | 57 ++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 dts/riscv/niosv/niosv-g.dtsi diff --git a/dts/riscv/niosv/niosv-g.dtsi b/dts/riscv/niosv/niosv-g.dtsi new file mode 100644 index 000000000000..587528a89726 --- /dev/null +++ b/dts/riscv/niosv/niosv-g.dtsi @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "intel,niosv"; + reg = <0>; + clock-frequency = <50000000>; + + /* Platform interrupts IRQs index start from 16 */ + intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "intel,niosv-g-soc", "simple-bus"; + interrupt-parent = <&intc>; + ranges; + + sram0: memory@0 { + compatible = "mmio-sram"; + }; + + mtimer: machine-timer@90000 { + compatible = "niosv-machine-timer"; + reg = <0x90000 0x10>; + interrupts = <7>; + }; + + uart0: serial@90078 { + compatible = "altr,jtag-uart"; + interrupts = <16>; + status = "disable"; + }; + }; +}; From d4df89ab8fc61045d2722fadb2b216f15c67ca2e Mon Sep 17 00:00:00 2001 From: Khor Swee Aun Date: Thu, 8 Jun 2023 10:34:15 +0800 Subject: [PATCH 0207/2042] boards: riscv: Add INTEL Nios V/g General Processor board Add board support for INTEL Nios V/g General Processor. Signed-off-by: Khor Swee Aun --- boards/riscv/niosv_g/Kconfig.board | 6 +++ boards/riscv/niosv_g/Kconfig.defconfig | 9 ++++ boards/riscv/niosv_g/doc/index.rst | 66 ++++++++++++++++++++++++++ boards/riscv/niosv_g/niosv_g.dts | 36 ++++++++++++++ boards/riscv/niosv_g/niosv_g.yaml | 7 +++ boards/riscv/niosv_g/niosv_g_defconfig | 11 +++++ 6 files changed, 135 insertions(+) create mode 100644 boards/riscv/niosv_g/Kconfig.board create mode 100644 boards/riscv/niosv_g/Kconfig.defconfig create mode 100644 boards/riscv/niosv_g/doc/index.rst create mode 100644 boards/riscv/niosv_g/niosv_g.dts create mode 100644 boards/riscv/niosv_g/niosv_g.yaml create mode 100644 boards/riscv/niosv_g/niosv_g_defconfig diff --git a/boards/riscv/niosv_g/Kconfig.board b/boards/riscv/niosv_g/Kconfig.board new file mode 100644 index 000000000000..bcc48f497d80 --- /dev/null +++ b/boards/riscv/niosv_g/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NIOSV_G + bool "Intel FPGA Nios V/g General Purpose Processor" + depends on SOC_NIOSV_G diff --git a/boards/riscv/niosv_g/Kconfig.defconfig b/boards/riscv/niosv_g/Kconfig.defconfig new file mode 100644 index 000000000000..ecfc8b41bab2 --- /dev/null +++ b/boards/riscv/niosv_g/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NIOSV_G + +config BOARD + default "niosv_g" + +endif # BOARD_NIOSV_G diff --git a/boards/riscv/niosv_g/doc/index.rst b/boards/riscv/niosv_g/doc/index.rst new file mode 100644 index 000000000000..bf0d0004bd67 --- /dev/null +++ b/boards/riscv/niosv_g/doc/index.rst @@ -0,0 +1,66 @@ +.. _niosv_g: + +INTEL FPGA niosv_g +#################### + +Overview +******** + +niosv_g board is based on Intel FPGA Design Store Nios® V/g Hello World Example Design system and this complete system is consisted of following IP blocks: + +.. code-block:: console + + Nios® V/g Processor Intel® FPGA IP + JTAG UART Intel® FPGA IP + On-Chip Memory Intel® FPGA IP + +Nios® V/g hello world example design system +=========================================== + +Prebuilt Nios® V/g hello world example design system is available in Intel FPGA Design store. +- https://www.intel.com/content/www/us/en/support/programmable/support-resources/design-examples/design-store.html?s=Newest + +For example, Arria10 Nios® V/g processor example design system prebuilt files can be downloaded from following link. +- https://www.intel.com/content/www/us/en/design-example/776196/intel-arria-10-fpga-hello-world-design-on-nios-v-g-processor.html + +ready_to_test/top.sof file is the prebuilt SRAM Object File for hello world example design system after the downloaded PAR files extracted successfully. + +Create Nios® V/g processor example design system in FPGA +======================================================== + +Please use Intel Quartus Programmer tool to program Nios® V/g processor based system into the FPGA and execute application. + +In order to create the Nios® V/g processor inside the FPGA device, please download the generated .sof file onto the board with the following command. + +.. code-block:: console + + quartus_pgm -c 1 -m JTAG -o "p;top.sof@1" + +.. code-block:: console + + Note: + -c 1 is referring to JTAG cable number connected to the Host Computer. + @1 is referring to device index on the JTAG Chain and may differ for your board. + top.sof is referring to Nios® V/m processor based system SRAM Object File. + +Download Zephyr elf file and run application +============================================ + +To download the Zephyr Executable and Linkable Format .elf file, please use the niosv-download command within Nios V Command Shell environment. + +.. code-block:: console + + niosv-download -g + +Use the JTAG UART terminal to print the stdout and stderr of the Nios® V/g processor system. + +.. code-block:: console + + juart-terminal + +Similar message shown below should be appeared in the JTAG UART terminal when using hello world sample code: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-vn.n.nn *** + Hello World! niosv_g diff --git a/boards/riscv/niosv_g/niosv_g.dts b/boards/riscv/niosv_g/niosv_g.dts new file mode 100644 index 000000000000..4ebd9c9721a9 --- /dev/null +++ b/boards/riscv/niosv_g/niosv_g.dts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "niosv_g"; + compatible = "intel,niosv_g"; + + chosen { + zephyr,console = &uart0; + zephyr,sram = &sram0; + }; +}; + +&cpu0 { + clock-frequency = <50000000>; +}; + +&sram0 { + reg = <0x0 0x40000>; +}; + +&mtimer { + reg = <0x90000 0x10>; +}; + +&uart0 { + reg = <0x90078 0x8>; + status = "okay"; +}; diff --git a/boards/riscv/niosv_g/niosv_g.yaml b/boards/riscv/niosv_g/niosv_g.yaml new file mode 100644 index 000000000000..e88c658cd187 --- /dev/null +++ b/boards/riscv/niosv_g/niosv_g.yaml @@ -0,0 +1,7 @@ +identifier: niosv_g +name: INTEL FPGA Nios V/g general purpose processor +type: mcu +arch: riscv32 +toolchain: + - zephyr +ram: 256 diff --git a/boards/riscv/niosv_g/niosv_g_defconfig b/boards/riscv/niosv_g/niosv_g_defconfig new file mode 100644 index 000000000000..f933bca38746 --- /dev/null +++ b/boards/riscv/niosv_g/niosv_g_defconfig @@ -0,0 +1,11 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NIOSV=y +CONFIG_SOC_NIOSV_G=y +CONFIG_BOARD_NIOSV_G=y +CONFIG_CONSOLE=y +CONFIG_PRINTK=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_XIP=n From d7141c96f4f78a7bfd336b812d7aafe970c2dd6d Mon Sep 17 00:00:00 2001 From: Khor Swee Aun Date: Thu, 8 Jun 2023 10:39:21 +0800 Subject: [PATCH 0208/2042] codeowners: Add code owner for INTEL FPGA Nios V/g Add code owner for INTEL FPGA Nios V/g dts, SoC and board. Signed-off-by: Khor Swee Aun --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 2cc376dc5f03..21fbd5e0b106 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -179,7 +179,7 @@ /boards/riscv/adp_xc7k_ae350/ @cwshu @kevinwang821020 @jimmyzhe /boards/riscv/longan_nano/ @soburi /boards/riscv/neorv32/ @henrikbrixandersen -/boards/riscv/niosv_m/ @sweeaun +/boards/riscv/niosv*/ @sweeaun /boards/shields/ @erwango /boards/shields/atmel_rf2xx/ @nandojve /boards/shields/esp_8266/ @nandojve @@ -531,7 +531,7 @@ /dts/riscv/riscv32-litex-vexriscv.dtsi @mateusz-holenko @kgugala @pgielda /dts/riscv/starfive/ @rajnesh-kanwal /dts/riscv/andes/andes_v5* @cwshu @kevinwang821020 @jimmyzhe -/dts/riscv/niosv/niosv-m.dtsi @sweeaun +/dts/riscv/niosv/ @sweeaun /dts/arm/armv*m.dtsi @galak @ioannisg /dts/arm/armv7-a.dtsi @ibirnbaum /dts/arm/armv7-r.dtsi @bbolen @stephanosio From 7bad2b3ad13c6738da62b4652fe6dd08f55e7f46 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 1 Jun 2023 13:54:26 +0200 Subject: [PATCH 0209/2042] manifest: Update nRF HW models to latest The nRF HW models have been updated to include the following fixes and improvements. * PPI: add support for nrf_ppi_group_enable * BLECrypt: Widen search for crypto library * Makefile: Switch to gnu11 from c11 due to HAL * NVMC: Minor fixes in command line options descriptions Which enable more 15.4 functionality with the nrf driver 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 451c72ac4313..72c863a6dd5a 100644 --- a/west.yml +++ b/west.yml @@ -284,7 +284,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: c8d2ecd25d6976d2d77eccf66878420fdb8ef5a1 + revision: 37c571ef7c4a86dad852566fc43eb36f42534e9f path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad From c3690a7d620011a55b19c742c3efbf754e801ff9 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 13 Jun 2023 10:44:54 +0200 Subject: [PATCH 0210/2042] tests: drivers: i2c: i2c_target_api add nucleo_f207zg Adds nucleo_f207zg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index e93d68a129e1..eb14ff445bcf 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -13,6 +13,7 @@ tests: - nucleo_f091rc - stm32f072b_disco - nucleo_g071rb + - nucleo_f207zg - rpi_pico integration_platforms: - nucleo_f091rc From 7d4a928e5be9bb657e48a6cbabd4eaab39c5d2a3 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 13 Jun 2023 10:46:09 +0200 Subject: [PATCH 0211/2042] boards: arm: nucleo_f207zg: add i2c2 Adds i2c2 on nucleo_f207zg to use the i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- boards/arm/nucleo_f207zg/nucleo_f207zg.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/nucleo_f207zg/nucleo_f207zg.dts b/boards/arm/nucleo_f207zg/nucleo_f207zg.dts index a2b9703b7a4e..c3d9fb7aeee4 100644 --- a/boards/arm/nucleo_f207zg/nucleo_f207zg.dts +++ b/boards/arm/nucleo_f207zg/nucleo_f207zg.dts @@ -118,6 +118,13 @@ clock-frequency = ; }; +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + &usart3 { pinctrl-0 = <&usart3_tx_pd8 &usart3_rx_pd9>; pinctrl-names = "default"; From d5123bfe2182e3f1ff8a9fba47131ad8d26608d5 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 13 Jun 2023 10:47:07 +0200 Subject: [PATCH 0212/2042] tests: drivers: i2c: i2c_target_api add nucleo_f207zg Adds necessary overlay nucleo_f207zg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_f207zg.conf | 2 ++ .../boards/nucleo_f207zg.overlay | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.conf new file mode 100644 index 000000000000..34b2571d1251 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.overlay new file mode 100644 index 000000000000..fc88c69010bf --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f207zg.overlay @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN7:4 PB8 CN7:2 + * i2c2 PB11 CN10:34 PB10 CN10:32 + * + * Short Pin PB9 to PB11, and PB8 to PB10, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From 844434351121ac9cd18b763ac935a2aa0b4a94d1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 14:02:09 +0200 Subject: [PATCH 0213/2042] usb: device: class: rndis: Fix for 64bit platforms Instead of assuming pointers are 32bits wide, cast them to the appropriate pointer arithmetic type. Signed-off-by: Alberto Escolar Piedras --- subsys/usb/device/class/netusb/function_rndis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/usb/device/class/netusb/function_rndis.c b/subsys/usb/device/class/netusb/function_rndis.c index 1810494326a3..c58f236f8666 100644 --- a/subsys/usb/device/class/netusb/function_rndis.c +++ b/subsys/usb/device/class/netusb/function_rndis.c @@ -652,7 +652,7 @@ static int rndis_set_handle(uint8_t *data, uint32_t len) /* Parameter starts at offset buf_offset of the req_id field ;) */ param = (uint8_t *)&cmd->req_id + sys_le32_to_cpu(cmd->buf_offset); - if (len - ((uint32_t)param - (uint32_t)cmd) != + if (len - ((uintptr_t)param - (uintptr_t)cmd) != sys_le32_to_cpu(cmd->buf_len)) { LOG_ERR("Packet parsing error"); return -EINVAL; From 931a089e2c6dc964a663f72c00ce871d9637d3bf Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Tue, 13 Jun 2023 12:30:16 +0200 Subject: [PATCH 0214/2042] Bluetooth: host: invalidate the RPA when starting legacy adv This fixes the failure to use a resolvable private address in this scenario. 1. call `bt_le_oob_get_local`, will generate and mark RPA as valid 2. start connectable adv w/ IDENTITY bit 3. start connectable adv w/o IDENTITY 4. RPA is not set (in `bt_id_set_private_addr`) because RPA is still marked as valid When EXT_ADV is enabled and the controller supports it, a different code path is taken that doesn't have this issue. Unconditionally invalidating the RPA when starting advertising works around this issue. Fixes #56326 Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/adv.c | 4 +- tests/bsim/bluetooth/host/compile.sh | 1 + .../host/privacy/legacy/CMakeLists.txt | 18 +++ .../bluetooth/host/privacy/legacy/prj.conf | 9 ++ .../host/privacy/legacy/src/bs_bt_utils.c | 73 +++++++++ .../host/privacy/legacy/src/bs_bt_utils.h | 54 +++++++ .../bluetooth/host/privacy/legacy/src/dut.c | 104 +++++++++++++ .../bluetooth/host/privacy/legacy/src/main.c | 40 +++++ .../host/privacy/legacy/src/tester.c | 146 ++++++++++++++++++ .../privacy/legacy/test_scripts/_compile.sh | 15 ++ .../host/privacy/legacy/test_scripts/_env.sh | 14 ++ .../privacy/legacy/test_scripts/run_test.sh | 24 +++ 12 files changed, 499 insertions(+), 3 deletions(-) create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/prj.conf create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.c create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.h create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/src/dut.c create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/src/main.c create mode 100644 tests/bsim/bluetooth/host/privacy/legacy/src/tester.c create mode 100755 tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_env.sh create mode 100755 tests/bsim/bluetooth/host/privacy/legacy/test_scripts/run_test.sh diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 614220ae5af4..dc6856ead2d2 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -997,9 +997,7 @@ int bt_le_adv_start_legacy(struct bt_le_ext_adv *adv, set_param.channel_map = get_adv_channel_map(param->options); set_param.filter_policy = get_filter_policy(param->options); - if (adv->id != param->id) { - atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); - } + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); adv->id = param->id; bt_dev.adv_conn_id = adv->id; diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 31a4b70162e6..aa12780f2d83 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -61,6 +61,7 @@ app=tests/bsim/bluetooth/host/misc/disable compile app=tests/bsim/bluetooth/host/privacy/central compile app=tests/bsim/bluetooth/host/privacy/peripheral compile app=tests/bsim/bluetooth/host/privacy/device compile +app=tests/bsim/bluetooth/host/privacy/legacy compile app=tests/bsim/bluetooth/host/security/bond_overwrite_allowed compile app=tests/bsim/bluetooth/host/security/bond_overwrite_denied compile diff --git a/tests/bsim/bluetooth/host/privacy/legacy/CMakeLists.txt b/tests/bsim/bluetooth/host/privacy/legacy/CMakeLists.txt new file mode 100644 index 000000000000..0f313743af07 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_privacy_legacy) + +target_sources(app PRIVATE + src/bs_bt_utils.c + src/tester.c + src/main.c + src/dut.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/privacy/legacy/prj.conf b/tests/bsim/bluetooth/host/privacy/legacy/prj.conf new file mode 100644 index 000000000000..c9acb0c30b31 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/prj.conf @@ -0,0 +1,9 @@ +CONFIG_LOG=y +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_SMP=y +CONFIG_ASSERT=y + +CONFIG_BT_PRIVACY=y +CONFIG_BT_RPA_TIMEOUT=10 diff --git a/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.c b/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.c new file mode 100644 index 000000000000..b367c0dfb296 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "argparse.h" +#include "bs_pc_backchannel.h" + +#define BS_SECONDS(dur_sec) ((bs_time_t)dur_sec * 1000000) +#define TEST_TIMEOUT_SIMULATED BS_SECONDS(70) + +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; +} + +#define CHANNEL_ID 0 +#define MSG_SIZE 1 + +void backchannel_init(uint peer) +{ + uint device_number = get_device_nbr(); + uint device_numbers[] = { peer }; + uint channel_numbers[] = { CHANNEL_ID }; + uint *ch; + + ch = bs_open_back_channel(device_number, device_numbers, + channel_numbers, ARRAY_SIZE(channel_numbers)); + if (!ch) { + FAIL("Unable to open backchannel\n"); + } +} + +void backchannel_sync_send(void) +{ + uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() }; + + printk("Sending sync\n"); + bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg)); +} + +void backchannel_sync_wait(void) +{ + uint8_t sync_msg[MSG_SIZE]; + + while (true) { + if (bs_bc_is_msg_received(CHANNEL_ID) > 0) { + bs_bc_receive_msg(CHANNEL_ID, sync_msg, + ARRAY_SIZE(sync_msg)); + if (sync_msg[0] != get_device_nbr()) { + /* Received a message from another device, exit */ + break; + } + } + + k_sleep(K_MSEC(1)); + } + + printk("Sync received\n"); +} diff --git a/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.h b/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.h new file mode 100644 index 000000000000..825804728812 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/src/bs_bt_utils.h @@ -0,0 +1,54 @@ +/** + * Common functions and helpers for BSIM ADV tests + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_tracing.h" +#include "bs_types.h" +#include "bstests.h" +#include "time_machine.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern enum bst_result_t bst_result; + +#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 CENTRAL_SIM_ID 0 +#define PERIPHERAL_SIM_ID 1 + +void test_tick(bs_time_t HW_device_time); +void test_init(void); + +void backchannel_init(uint peer); +void backchannel_sync_send(void); +void backchannel_sync_wait(void); diff --git a/tests/bsim/bluetooth/host/privacy/legacy/src/dut.c b/tests/bsim/bluetooth/host/privacy/legacy/src/dut.c new file mode 100644 index 000000000000..a38349908af1 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/src/dut.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" + +#include +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(dut, 4); + +static const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), +}; + +bt_addr_le_t dut_addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}}; + +static void set_public_addr(void) +{ + /* dummy irk so we don't get -EINVAL because of BT_PRIVACY=y */ + uint8_t irk[16]; + int err; + + for (uint8_t i = 0; i < 16; i++) { + irk[i] = i; + } + + err = bt_id_create(&dut_addr, irk); + if (err) { + FAIL("Failed to override addr %d\n", err); + } +} + +void start_advertising(uint32_t options) +{ + int err; + + struct bt_le_adv_param param = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_ONE_TIME, + BT_GAP_ADV_FAST_INT_MIN_2, + BT_GAP_ADV_FAST_INT_MAX_2, + NULL); + param.options |= options; + + err = bt_le_adv_start(¶m, ad, ARRAY_SIZE(ad), NULL, 0); + if (err) { + FAIL("Failed to start advertising (err %d)\n", err); + } +} + +void generate_new_rpa(void) +{ + /* This will generate a new RPA and mark it valid */ + struct bt_le_oob oob_local = { 0 }; + + bt_le_oob_get_local(BT_ID_DEFAULT, &oob_local); +} + +void dut_procedure(void) +{ + int err; + + /* open a backchannel to the peer */ + backchannel_init(CENTRAL_SIM_ID); + + /* override public address so the scanner can test if we're using it or not */ + set_public_addr(); + + LOG_DBG("enable bt"); + err = bt_enable(NULL); + if (err) { + FAIL("Failed to enable bluetooth (err %d\n)", err); + } + + LOG_DBG("generate new RPA"); + generate_new_rpa(); + + LOG_DBG("start adv with identity"); + start_advertising(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_IDENTITY); + + /* wait for the tester to validate we're using our identity address */ + LOG_DBG("wait for validation by tester"); + backchannel_sync_wait(); + LOG_DBG("wait for validation by tester"); + err = bt_le_adv_stop(); + if (err) { + FAIL("Failed to stop advertising (err %d\n)", err); + } + + LOG_DBG("start adv with RPA"); + start_advertising(BT_LE_ADV_OPT_CONNECTABLE); + + /* signal tester it can start scanning again, expecting an RPA this time */ + backchannel_sync_send(); + + /* Test pass verdict is decided by the tester */ + PASS("DUT done\n"); +} diff --git a/tests/bsim/bluetooth/host/privacy/legacy/src/main.c b/tests/bsim/bluetooth/host/privacy/legacy/src/main.c new file mode 100644 index 000000000000..91a4f3a03db7 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/src/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "bstests.h" + +void tester_procedure(void); +void dut_procedure(void); + +static const struct bst_test_instance test_to_add[] = { + { + .test_id = "central", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = tester_procedure, + }, + { + .test_id = "peripheral", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = dut_procedure, + }, + 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/privacy/legacy/src/tester.c b/tests/bsim/bluetooth/host/privacy/legacy/src/tester.c new file mode 100644 index 000000000000..1648e030be5d --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/src/tester.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "zephyr/bluetooth/addr.h" +#include "zephyr/bluetooth/conn.h" +#include +#include + +#include "common/bt_str.h" + +#define EXPECTED_NUM_ROTATIONS 5 + +#include +LOG_MODULE_REGISTER(tester, 4); + +struct test_data_t { + bt_addr_le_t old_addr; + int64_t old_time; + int rpa_rotations; + bool addr_set; +} static test_data; + +extern bt_addr_le_t dut_addr; + +void print_address(const bt_addr_le_t *addr) +{ + char array[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, array, sizeof(array)); + LOG_DBG("Address : %s", array); +} + +static void cb_expect_rpa(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + int64_t diff_ms, rpa_timeout_ms; + + if (bt_addr_le_eq(addr, &dut_addr)) { + FAIL("DUT used identity addr instead of RPA\n"); + } + + /* Only save the address + time if this is the first scan */ + if (bt_addr_le_eq(&test_data.old_addr, BT_ADDR_LE_ANY)) { + bt_addr_le_copy(&test_data.old_addr, addr); + test_data.old_time = k_uptime_get(); + return; + } + + /* Compare old and new address */ + if (bt_addr_le_eq(&test_data.old_addr, addr)) { + return; + } + test_data.addr_set = true; + LOG_DBG("Old "); + print_address(&test_data.old_addr); + LOG_DBG("New "); + print_address(addr); + + test_data.rpa_rotations++; + + /* Ensure the RPA rotation occurs within +-10% of CONFIG_BT_RPA_TIMEOUT */ + diff_ms = k_uptime_get() - test_data.old_time; + rpa_timeout_ms = CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC; + + if (abs(diff_ms - rpa_timeout_ms) > (rpa_timeout_ms / 10)) { + FAIL("RPA rotation did not occur within +-10% of CONFIG_BT_RPA_TIMEOUT\n"); + } + + bt_addr_le_copy(&test_data.old_addr, addr); + test_data.old_time = k_uptime_get(); + + if (test_data.rpa_rotations > EXPECTED_NUM_ROTATIONS) { + PASS("PASS\n"); + } +} + +static void cb_expect_id(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) +{ + int err; + + LOG_DBG("expecting addr:"); + print_address(&dut_addr); + LOG_DBG("got addr:"); + print_address(addr); + + if (addr->type != BT_ADDR_LE_RANDOM) { + FAIL("Expected public address (0x%x) got 0x%x\n", + BT_ADDR_LE_RANDOM, addr->type); + } + + if (!bt_addr_le_eq(&dut_addr, addr)) { + FAIL("DUT not using identity address\n"); + } + + err = bt_le_scan_stop(); + if (err) { + FAIL("Failed to stop scan: %d\n", err); + } + + backchannel_sync_send(); +} + +void start_scanning(bool expect_rpa) +{ + int err; + struct bt_le_scan_param scan_param = { + .type = BT_HCI_LE_SCAN_PASSIVE, + .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, + .interval = 0x0040, + .window = 0x0020, + }; + + if (expect_rpa) { + err = bt_le_scan_start(&scan_param, cb_expect_rpa); + } else { + err = bt_le_scan_start(&scan_param, cb_expect_id); + } + + if (err) { + FAIL("Failed to start scanning\n"); + } +} + +void tester_procedure(void) +{ + int err; + + /* open a backchannel to the peer */ + backchannel_init(PERIPHERAL_SIM_ID); + + err = bt_enable(NULL); + if (err) { + FAIL("Failed to enable bluetooth (err %d\n)", err); + } + + start_scanning(false); + + backchannel_sync_wait(); + + start_scanning(true); +} diff --git a/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_compile.sh new file mode 100755 index 000000000000..b754a9cc4817 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_compile.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +# Read variable definitions output by _env.sh +source "${bash_source_dir}/_env.sh" + +# terminate running simulations (if any) +${BSIM_COMPONENTS_PATH}/common/stop_bsim.sh + +west build -b nrf52_bsim && \ + cp build/zephyr/zephyr.exe $central_exe diff --git a/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_env.sh b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_env.sh new file mode 100755 index 000000000000..241e989c1003 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/_env.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +test_name="$(basename "$(realpath "$bash_source_dir/..")")" +bsim_bin="${BSIM_OUT_PATH}/bin" +verbosity_level=2 +BOARD="${BOARD:-nrf52_bsim}" +simulation_id="$test_name" +central_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_privacy_legacy_prj_conf" +peripheral_exe="${central_exe}" diff --git a/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/run_test.sh new file mode 100755 index 000000000000..2a574a297425 --- /dev/null +++ b/tests/bsim/bluetooth/host/privacy/legacy/test_scripts/run_test.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +source "${bash_source_dir}/_env.sh" +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +EXECUTE_TIMEOUT=30 + +cd ${BSIM_OUT_PATH}/bin + +Execute "$central_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 + +Execute "$peripheral_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs From 2d13329ecab5ab78bd70615650a5af40c6cb6a6a Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 5 Jun 2023 11:12:43 +0200 Subject: [PATCH 0215/2042] Bluetooth: Mesh: Store Private GATT Proxy state persistently State should be stored persistently. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/cfg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index 007fc7d7a0ae..fff11ebbb485 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -33,6 +33,7 @@ struct cfg_val { #if defined(CONFIG_BT_MESH_PRIV_BEACONS) uint8_t priv_beacon; uint8_t priv_beacon_int; + uint8_t priv_gatt_proxy; #endif #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) uint8_t on_demand_state; @@ -442,6 +443,7 @@ static int cfg_set(const char *name, size_t len_rd, #if defined(CONFIG_BT_MESH_PRIV_BEACONS) bt_mesh_priv_beacon_set(cfg.priv_beacon); bt_mesh_priv_beacon_update_interval_set(cfg.priv_beacon_int); + bt_mesh_priv_gatt_proxy_set(cfg.priv_gatt_proxy); #endif #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) bt_mesh_od_priv_proxy_set(cfg.on_demand_state); @@ -481,6 +483,7 @@ static void store_pending_cfg(void) #if defined(CONFIG_BT_MESH_PRIV_BEACONS) val.priv_beacon = bt_mesh_priv_beacon_get(); val.priv_beacon_int = bt_mesh_priv_beacon_update_interval_get(); + val.priv_gatt_proxy = bt_mesh_priv_gatt_proxy_get(); #endif #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) val.on_demand_state = bt_mesh_od_priv_proxy_get(); From c952cf4818c3f0997978defe5769bd7fa9eafa8f Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 5 Jun 2023 11:13:01 +0200 Subject: [PATCH 0216/2042] Bluetooth: Mesh: Fix binding between proxy related states Fix binding between GATT Proxy, Node Identity and their private counterpart states according to sections 4.2.45.1 and 4.2.46.1 accordingly. When non-private state is enabled, the private counterpart is disabled. The reverse binding prohibits change of non-private state. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/cfg.c | 14 ++++++++++++++ subsys/bluetooth/mesh/subnet.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index fff11ebbb485..287023afa688 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -187,6 +187,13 @@ int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy) return err; } + /* The binding from section 4.2.45.1 disables Private GATT Proxy state when non-private + * state is enabled. + */ + if (gatt_proxy == BT_MESH_FEATURE_ENABLED) { + feature_set(BT_MESH_PRIV_GATT_PROXY, BT_MESH_FEATURE_DISABLED); + } + if ((gatt_proxy == BT_MESH_FEATURE_ENABLED) || (gatt_proxy == BT_MESH_FEATURE_DISABLED && !bt_mesh_subnet_find(node_id_is_running, NULL))) { @@ -220,6 +227,13 @@ int bt_mesh_priv_gatt_proxy_set(enum bt_mesh_feat_state priv_gatt_proxy) return BT_MESH_FEATURE_NOT_SUPPORTED; } + /* Reverse binding from section 4.2.45.1 doesn't allow to enable private state if + * non-private state is enabled. + */ + if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) { + return BT_MESH_FEATURE_DISABLED; + } + err = feature_set(BT_MESH_PRIV_GATT_PROXY, priv_gatt_proxy); if (err) { return err; diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index 3baed0792d63..3893ade3e7b3 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -541,6 +541,19 @@ uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx, return STATUS_FEAT_NOT_SUPP; } +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + /* Implements binding from section 4.2.46.1 of MshPRTv1.1. When enabling non-private node + * identity state, disable its private counterpart. + */ + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + if (subnets[i].net_idx != BT_MESH_KEY_UNUSED && + subnets[i].node_id == BT_MESH_FEATURE_ENABLED && + subnets[i].priv_beacon_ctx.node_id) { + bt_mesh_proxy_identity_stop(&subnets[i]); + } + } +#endif + if (node_id) { bt_mesh_proxy_identity_start(sub, false); } else { @@ -564,6 +577,9 @@ uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx, } *node_id = sub->node_id; +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + *node_id &= !sub->priv_beacon_ctx.node_id; +#endif return STATUS_SUCCESS; } @@ -588,6 +604,19 @@ uint8_t bt_mesh_subnet_priv_node_id_set(uint16_t net_idx, return STATUS_FEAT_NOT_SUPP; } +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + /* Reverse binding from section 4.2.46.1 doesn't allow to set private state if non-private + * state is enabled. + */ + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + if (subnets[i].net_idx != BT_MESH_KEY_UNUSED && + subnets[i].node_id == BT_MESH_FEATURE_ENABLED && + !subnets[i].priv_beacon_ctx.node_id) { + return STATUS_CANNOT_SET; + } + } +#endif + if (priv_node_id) { bt_mesh_proxy_identity_start(sub, true); } else { From dfb8bcaf38862907e8d97ed91233cd7945abcc4d Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 5 Jun 2023 11:55:37 +0200 Subject: [PATCH 0217/2042] Bluetooth: Mesh: Fix Proxy Privacy parameter support According to section 6.7, upon connection Proxy Server shall determine value of Proxy Privacy parameter (sections 6.5 and 7.2.2.2.6). Depending on that, it will either send Secure Network Beacon or Private Beacon to Proxy Client, but never both. Proxy Privacy parameter is determined by GATT Proxy, Node Identity states and their private counterparts (section 7.2.2.2.6). Since non-private and private states are mutually exclusive, it is enough to only check either Private GATT Proxy state or Private Node Identity state of any known subnet for which the state is currenty enabled. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/beacon.c | 5 ++--- subsys/bluetooth/mesh/beacon.h | 3 +-- subsys/bluetooth/mesh/proxy_srv.c | 25 ++++++++++++++++++++++++- subsys/bluetooth/mesh/subnet.c | 18 ++++++++++++++++++ subsys/bluetooth/mesh/subnet.h | 18 ++++++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index b7baf13c12fa..19b672d1c6ff 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -227,11 +227,10 @@ static int private_beacon_create(struct bt_mesh_subnet *sub, } #endif -int bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf) +int bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct net_buf_simple *buf, bool priv) { #if defined(CONFIG_BT_MESH_PRIV_BEACONS) - if (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED) { + if (priv) { return private_beacon_create(sub, buf); } #endif diff --git a/subsys/bluetooth/mesh/beacon.h b/subsys/bluetooth/mesh/beacon.h index 84a01eed0cb8..7efebde167c6 100644 --- a/subsys/bluetooth/mesh/beacon.h +++ b/subsys/bluetooth/mesh/beacon.h @@ -11,8 +11,7 @@ void bt_mesh_beacon_ivu_initiator(bool enable); void bt_mesh_beacon_recv(struct net_buf_simple *buf); -int bt_mesh_beacon_create(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf); +int bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct net_buf_simple *buf, bool priv); void bt_mesh_beacon_init(void); void bt_mesh_beacon_update(struct bt_mesh_subnet *sub); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 94abab58fa37..fc7958006389 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -67,6 +67,9 @@ static struct bt_mesh_proxy_client { REJECT, } filter_type; struct k_work send_beacons; +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + bool privacy; +#endif } clients[CONFIG_BT_MAX_CONN] = { [0 ... (CONFIG_BT_MAX_CONN - 1)] = { .send_beacons = Z_WORK_INITIALIZER(proxy_send_beacons), @@ -324,7 +327,12 @@ static int beacon_send(struct bt_mesh_proxy_client *client, NET_BUF_SIMPLE_DEFINE(buf, 28); net_buf_simple_reserve(&buf, 1); - err = bt_mesh_beacon_create(sub, &buf); + +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + err = bt_mesh_beacon_create(sub, &buf, client->privacy); +#else + err = bt_mesh_beacon_create(sub, &buf, false); +#endif if (err) { return err; } @@ -1044,6 +1052,21 @@ static void gatt_connected(struct bt_conn *conn, uint8_t err) client->cli = bt_mesh_proxy_role_setup(conn, proxy_send, proxy_msg_recv); +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + /* Binding from section 7.2.2.2.6 of MshPRTv1.1. */ + enum bt_mesh_subnets_node_id_state cur_node_id = bt_mesh_subnets_node_id_state_get(); + + if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED || + cur_node_id == BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED) { + client->privacy = false; + } else { + client->privacy = (bt_mesh_priv_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) || + (cur_node_id == BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED_PRIVATE); + } + + LOG_DBG("privacy: %d", client->privacy); +#endif + /* If connection was formed after Proxy Solicitation we need to stop future * Private Network ID advertisements */ diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index 3893ade3e7b3..c3f64a310281 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -652,6 +652,24 @@ uint8_t bt_mesh_subnet_priv_node_id_get(uint16_t net_idx, return STATUS_SUCCESS; } +enum bt_mesh_subnets_node_id_state bt_mesh_subnets_node_id_state_get(void) +{ + for (int i = 0; i < ARRAY_SIZE(subnets); i++) { + bool priv_node_id = false; + +#if CONFIG_BT_MESH_PRIV_BEACONS + priv_node_id = subnets[i].priv_beacon_ctx.node_id; +#endif + + if (subnets[i].node_id || priv_node_id) { + return priv_node_id ? BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED_PRIVATE : + BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED; + } + } + + return BT_MESH_SUBNETS_NODE_ID_STATE_NONE; +} + ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip) { size_t count = 0; diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h index 99d894386913..7064313348ed 100644 --- a/subsys/bluetooth/mesh/subnet.h +++ b/subsys/bluetooth/mesh/subnet.h @@ -224,6 +224,24 @@ bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub) return sub->kr_phase != BT_MESH_KR_NORMAL; } +/** Kind of currently enabled Node Identity state on one or more subnets. */ +enum bt_mesh_subnets_node_id_state { + /* None node identity states are enabled on any subnets. */ + BT_MESH_SUBNETS_NODE_ID_STATE_NONE, + /* Node Identity state is enabled on one or more subnets. */ + BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED, + /* Private Node Identity state is enabled on one or more subnets. */ + BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED_PRIVATE, +}; + +/** @brief Returns what kind of node identity state is currently enabled on one or more subnets. + * + * Only one kind (either non-private or private) can be enabled at the same time on all subnets. + * + * @returns Kind of node identity state that is currently enabled. + */ +enum bt_mesh_subnets_node_id_state bt_mesh_subnets_node_id_state_get(void); + /** @brief Store the Subnet information in persistent storage. * * @param net_idx Network index to store. From c301ed07cabe61b3524f7c7a4907dce4ac6118bb Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Mon, 5 Jun 2023 10:45:45 +0200 Subject: [PATCH 0218/2042] Bluetooth: Mesh: Regenerate private beacon even when disabled Even if PRB state is disabled, PRB can still be sent over GATT if Proxy Privacy parameter is enabled. In such case PRB won't be regenerated. To keep the privacy of the network, PRB should be regenerated when sent over GATT regardless of PRB state. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/beacon.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index 19b672d1c6ff..d972c578e2b3 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -153,15 +153,11 @@ static int private_random_update(void) uint64_t uptime = k_uptime_get(); int err; - /* If private beacon will not be sent there is no point in generating new random */ - if (bt_mesh_priv_beacon_get() != BT_MESH_FEATURE_ENABLED) { - return 0; - } - /* The Private beacon random value should change every N seconds to maintain privacy. * N = (10 * interval) seconds, or on every beacon creation, if the interval is 0. */ - if (interval && + if (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED && + interval && uptime - priv_random.timestamp < (10 * interval * MSEC_PER_SEC) && priv_random.timestamp != 0) { /* Not time yet */ From 607efa8eddf4b2b1f872ded6575949f4610db312 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 22 May 2023 16:02:20 +1000 Subject: [PATCH 0219/2042] Bluetooth: hci: spi: don't block on IRQ line Don't wait for the IRQ line to be de-asserted in `bt_spi_send`. As this function can be called by the RX processing thread, the previous behaviour could cause deadlocks under heavy load: * SPI RX thread starts blocking on `bt_buf_get_evt` due to load * BT controller generates another event, asserting the IRQ line * RX processing thread calls `bt_spi_send` in reponse to event * RX processing thread blocks forever on the removed condition There is no need to attempt to rate-limit how often `bt_spi_send` is called to allow the RX thread to run. If the bus is so congested that there is no remaining capacity, prioritising RX over TX is not going to improve the situation. Signed-off-by: Jordan Yates --- drivers/bluetooth/hci/spi.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 934028bdd8f5..a28f673415f3 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -411,7 +411,6 @@ static void bt_spi_rx_thread(void) static int bt_spi_send(struct net_buf *buf) { uint8_t header[5] = { SPI_WRITE, 0x00, 0x00, 0x00, 0x00 }; - int pending; int ret; LOG_DBG(""); @@ -422,15 +421,7 @@ static int bt_spi_send(struct net_buf *buf) return -EINVAL; } - /* Allow time for the read thread to handle interrupt */ - while (true) { - pending = gpio_pin_get_dt(&irq_gpio); - if (pending <= 0) { - break; - } - k_sleep(K_MSEC(1)); - } - + /* Wait for SPI bus to be available */ k_sem_take(&sem_busy, K_FOREVER); switch (bt_buf_get_type(buf)) { From 118a68518a04ba8cb38c7921f5d8d6383306fc75 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 9 Jun 2023 17:13:14 +0200 Subject: [PATCH 0220/2042] Bluetooth: Shell: bt connect-name should only attempt connectable The auto-connect by name did not verify that the found device was connectable before attempting to connect. Signed-off-by: Emil Gydesen --- 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 a4083fad27ef..85dea6de0ede 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -410,7 +410,7 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, bt_addr_le_copy(&auto_connect.addr, info->addr); /* Use the above auto_connect.addr address to automatically connect */ - if (auto_connect.connect_name) { + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0U && auto_connect.connect_name) { auto_connect.connect_name = false; cmd_scan_off(ctx_shell); From 96e49ed9e7a8fcb91c55b87372806914bcb8f4d1 Mon Sep 17 00:00:00 2001 From: Hebo Hu Date: Tue, 23 Aug 2022 09:51:54 +0800 Subject: [PATCH 0221/2042] sensing: Adding Sensing Subsystem API This API introduced a new sensing subsystem, which is a high level sensor framework inside the OS user space service layer. It's a framework focus on sensor fusion, clients arbitration, sampling, timing, scheduling and sensor based power management. It's key concepts including physical sensor and virtual sensor objects, and a scheduling framework reflects sensor objects' reporting relationship. Physical sensors not depends on any other sensor objects for input, and will directly interact with existing zephyr sensor device drivers. Virtual sensors rely on other sensor objects (physical or virtual) as report inputs. The sensing subsystem relies on existing zephyr sensor device APIs or V2 zephyr sensor device APIs (#44098). So it can leverage current existing zephyr sensor device drivers (100+). And it's configurable, so, for some low cost IoT devices, may not need an advanced sensor framework, but just need access some simple sensor devices,can not configure and build this sensor subsystem, but just use the exiting zephyr sensor device APIs to save memory resources. Since the sensing subsystem is separated from device driver layer or kernel space and could support various customizations and sensor algorithms in user space with virtual sensor concepts. The existing sensor device driver can focus on low layer device side works, can keep simple as much as possible, just provide device HW abstraction and operations etc. This is very good for system stability. The sensing subsystem is decoupled with any sensor expose/transfer protocols, the target is to support various up-layer frameworks and Applications with different sensor expose/transfer protocols, such as CHRE, HID sensors Applications, MQTT sensor Applications according different products requirements. Or even support multiple Applications with different up-layer sensor protocols at the same time with it's multiple clients support design. For example can support CHRE and other normal zephyr sensor application (can use HID etc) at the same time. Signed-off-by: Hebo Hu Signed-off-by: Guangfu Hu --- include/zephyr/sensing/sensing.h | 279 ++++++++ include/zephyr/sensing/sensing_datatypes.h | 115 ++++ include/zephyr/sensing/sensing_sensor.h | 594 ++++++++++++++++++ include/zephyr/sensing/sensing_sensor_types.h | 50 ++ 4 files changed, 1038 insertions(+) create mode 100644 include/zephyr/sensing/sensing.h create mode 100644 include/zephyr/sensing/sensing_datatypes.h create mode 100644 include/zephyr/sensing/sensing_sensor.h create mode 100644 include/zephyr/sensing/sensing_sensor_types.h diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h new file mode 100644 index 000000000000..3b11d1b410ca --- /dev/null +++ b/include/zephyr/sensing/sensing.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SENSING_H_ +#define ZEPHYR_INCLUDE_SENSING_H_ + +/** + * @defgroup sensing Sensing + * @defgroup sensing_api Sensing Subsystem API + * @ingroup sensing + * @defgroup sensing_sensor_types Sensor Types + * @ingroup sensing + * @defgroup sensing_datatypes Data Types + * @ingroup sensing + */ + +#include +#include +#include + +/** + * @brief Sensing Subsystem API + * @addtogroup sensing_api + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @struct sensing_sensor_version + * @brief Sensor Version + */ +struct sensing_sensor_version { + union { + uint32_t value; + struct { + uint8_t major; + uint8_t minor; + uint8_t hotfix; + uint8_t build; + }; + }; +}; + +#define SENSING_SENSOR_VERSION(_major, _minor, _hotfix, _build) \ + (FIELD_PREP(GENMASK(31, 24), _major) | \ + FIELD_PREP(GENMASK(23, 16), _minor) | \ + FIELD_PREP(GENMASK(15, 8), _hotfix) | \ + FIELD_PREP(GENMASK(7, 0), _build)) + + +/** + * @brief Sensor flag indicating if this sensor is on event reporting data. + * + * Reporting sensor data when the sensor event occurs, such as a motion detect sensor reporting + * a motion or motionless detected event. + */ +#define SENSING_SENSOR_FLAG_REPORT_ON_EVENT BIT(0) + +/** + * @brief Sensor flag indicating if this sensor is on change reporting data. + * + * Reporting sensor data when the sensor data changes. + * + * Exclusive with \ref SENSING_SENSOR_FLAG_REPORT_ON_EVENT + */ +#define SENSING_SENSOR_FLAG_REPORT_ON_CHANGE BIT(1) + + +/** + * @brief Sensing subsystem sensor state. + * + */ +enum sensing_sensor_state { + SENSING_SENSOR_STATE_READY = 0, + SENSING_SENSOR_STATE_OFFLINE = 1, +}; + +/** + * @brief Sensing subsystem sensor config attribute + * + */ +enum sensing_sensor_attribute { + SENSING_SENSOR_ATTRIBUTE_INTERVAL = 0, + SENSING_SENSOR_ATTRIBUTE_SENSITIVITY = 1, + SENSING_SENSOR_ATTRIBUTE_LATENCY = 2, + SENSING_SENSOR_ATTRIBUTE_MAX, +}; + + +/** + * @brief Define Sensing subsystem sensor handle + * + */ +typedef void *sensing_sensor_handle_t; + + +/** + * @brief Sensor data event receive callback. + * + * @param handle The sensor instance handle. + * + * @param buf The data buffer with sensor data. + */ +typedef void (*sensing_data_event_t)( + sensing_sensor_handle_t handle, + const void *buf); + +/** + * @struct sensing_sensor_info + * @brief Sensor basic constant information + * + */ +struct sensing_sensor_info { + /** Name of the sensor instance */ + const char *name; + + /** Friendly name of the sensor instance */ + const char *friendly_name; + + /** Vendor name of the sensor instance */ + const char *vendor; + + /** Model name of the sensor instance */ + const char *model; + + /** Sensor type */ + const int32_t type; + + /** Minimal report interval in micro seconds */ + const uint32_t minimal_interval; +}; + +/** + * @struct sensing_callback_list + * @brief Sensing subsystem event callback list + * + */ +struct sensing_callback_list { + sensing_data_event_t on_data_event; +}; +/** + * @struct sensing_sensor_config + * @brief Sensing subsystem sensor configure, including interval, sensitivity, latency + * + */ +struct sensing_sensor_config { + enum sensing_sensor_attribute attri; + int8_t data_field; + union { + uint32_t interval; + uint32_t sensitivity; + uint64_t latency; + }; +}; + + + /** + * @brief Get all supported sensor instances' information. + * + * This API just returns read only information of sensor instances, pointer info will + * directly point to internal buffer, no need for caller to allocate buffer, + * no side effect to sensor instances. + * + * @param num_sensors Get number of sensor instances. + * + * @param info For receiving sensor instances' information array pointer. + * + * @return 0 on success or negative error value on failure. + */ +int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **info); + +/** + * @brief Open sensor instance by sensing sensor info + * + * Application clients use it to open a sensor instance and get its handle. + * Support multiple Application clients for open same sensor instance, + * in this case, the returned handle will different for different clients. + * meanwhile, also register sensing callback list + * + * @param info The sensor info got from \ref sensing_get_sensors + * + * @param cb_list callback list to be registered to sensing. + * + * @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( + const struct sensing_sensor_info *info, + const struct sensing_callback_list *cb_list, + sensing_sensor_handle_t *handle); + +/** + * @brief Open sensor instance by device. + * + * Application clients use it to open a sensor instance and get its handle. + * Support multiple Application clients for open same sensor instance, + * in this case, the returned handle will different for different clients. + * meanwhile, also register sensing callback list. + * + * @param dev pointer device get from device tree. + * + * @param cb_list callback list to be registered to sensing. + * + * @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, + sensing_sensor_handle_t *handle); + +/** + * @brief Close sensor instance. + * + * @param handle The sensor instance handle need to close. + * + * @return 0 on success or negative error value on failure. + */ +int sensing_close_sensor( + sensing_sensor_handle_t *handle); + +/** + * @brief Set current config items to Sensing subsystem. + * + * @param handle The sensor instance handle. + * + * @param configs The configs to be set according to config attribute. + * + * @param count count of configs. + * + * @return 0 on success or negative error value on failure, not support etc. + */ +int sensing_set_config( + sensing_sensor_handle_t handle, + struct sensing_sensor_config *configs, int count); + +/** + * @brief Get current config items from Sensing subsystem. + * + * @param handle The sensor instance handle. + * + * @param configs The configs to be get according to config attribute. + * + * @param count count of configs. + * + * @return 0 on success or negative error value on failure, not support etc. + */ +int sensing_get_config( + sensing_sensor_handle_t handle, + struct sensing_sensor_config *configs, int count); + +/** + * @brief Get sensor information from sensor instance handle. + * + * @param handle The sensor instance handle. + * + * @return a const pointer to \ref sensing_sensor_info on success or NULL on failure. + */ +const struct sensing_sensor_info *sensing_get_sensor_info( + sensing_sensor_handle_t handle); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + + +#endif /*ZEPHYR_INCLUDE_SENSING_H_*/ diff --git a/include/zephyr/sensing/sensing_datatypes.h b/include/zephyr/sensing/sensing_datatypes.h new file mode 100644 index 000000000000..3549aab4bdb6 --- /dev/null +++ b/include/zephyr/sensing/sensing_datatypes.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SENSING_DATATYPES_H_ +#define ZEPHYR_INCLUDE_SENSING_DATATYPES_H_ + +#include +#include + +/** + * @brief Data Types + * @addtogroup sensing_datatypes + * @{ + */ + +/** + * @struct sensing_sensor_value_header + * @brief sensor value header + * + * Each sensor value data structure should have this header + * + * Here use 'base_timestamp' (uint64_t) and 'timestamp_delta' (uint32_t) to + * save memory usage in batching mode. + * + * The 'base_timestamp' is for readings[0], the 'timestamp_delta' is relation + * to the previous 'readings'. So, + * timestamp of readings[0] is + * header.base_timestamp + readings[0].timestamp_delta. + * timestamp of readings[1] is + * timestamp of readings[0] + readings[1].timestamp_delta. + * + * Since timestamp unit is micro seconds, the max 'timestamp_delta' (uint32_t) + * is 4295 seconds. + * + * If a sensor has batched data where two consecutive readings differ by + * more than 4295 seconds, the sensor subsystem core will split them + * across multiple instances of the readings structure, and send multiple + * events. + * + * This concept is borrowed from CHRE: + * https://cs.android.com/android/platform/superproject/+/master:\ + * system/chre/chre_api/include/chre_api/chre/sensor_types.h + */ +struct sensing_sensor_value_header { + /** base timestamp of this data readings, unit is micro seconds */ + uint64_t base_timestamp; + /** count of this data readings */ + uint16_t reading_count; +}; + +/** + * @brief Sensor value data structure types based on common data types. + * Suitable for common sensors, such as IMU, Light sensors and orientation sensors. + */ + +/** + * @brief Sensor value data structure for 3-axis sensors. + * struct sensing_sensor_value_3d_q31 can be used by 3D IMU sensors like: + * SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, + * SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D, + * SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D, + * q31 version + */ +struct sensing_sensor_value_3d_q31 { + struct sensing_sensor_value_header header; + int8_t shift; + struct { + uint32_t timestamp_delta; + union { + q31_t v[3]; + struct { + q31_t x; + q31_t y; + q31_t z; + }; + }; + } readings[1]; +}; + +/** + * @brief Sensor value data structure for single 1-axis value. + * struct sensing_sensor_value_uint32 can be used by SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT sensor + * uint32_t version + */ +struct sensing_sensor_value_uint32 { + struct sensing_sensor_value_header header; + struct { + uint32_t timestamp_delta; + uint32_t v; + } readings[1]; +}; + +/** + * @brief Sensor value data structure for single 1-axis value. + * struct sensing_sensor_value_q31 can be used by SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE sensor + * q31 version + */ +struct sensing_sensor_value_q31 { + int8_t shift; + struct sensing_sensor_value_header header; + struct { + uint32_t timestamp_delta; + q31_t v; + } readings[1]; +}; + + +/** + * @} + */ + +#endif /*ZEPHYR_INCLUDE_SENSING_DATATYPES_H_*/ diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h new file mode 100644 index 000000000000..e7716a317d8e --- /dev/null +++ b/include/zephyr/sensing/sensing_sensor.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_H_ +#define ZEPHYR_INCLUDE_SENSING_SENSOR_H_ + +#include +#include +#include +#include + +/** + * @defgroup sensing_sensor Sensing Sensor API + * @ingroup sensing + * @defgroup sensing_sensor_callbacks Sensor Callbacks + * @ingroup sensing_sensor + */ + +/** + * @brief Sensing Sensor API + * @addtogroup sensing_sensor + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sensor registration information + * + */ +struct sensing_sensor_register_info { + + /** + * Sensor flags + */ + uint16_t flags; + + /** + * Sample size in bytes for a single sample of the registered sensor. + * sensing runtime need this information for internal buffer allocation. + */ + uint16_t sample_size; + + /** + * The number of sensor sensitivities + */ + uint8_t sensitivity_count; + + /** + * Sensor version. + * Version can be used to identify different versions of sensor implementation. + */ + 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; + + /** + * 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; +}; + +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; +} + +/** + * @brief Macro for define a sensor instance from device tree node id + * + * 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. + * + */ + +#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, APPLICATION, 10, api_ptr) + +/** + * @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; + + return data->sensor_ctx_ptr; +} + +/** + * @brief Post sensor data, sensor subsystem runtime will deliver to it's + * clients. + * + * Unblocked function, returned immediately. + * + * Used by a virtual sensor to post data to it's clients. + * + * 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 dev The sensor instance device structure. + * + * @param buf The data buffer. + * + * @param size The buffer size in bytes. + * + * @return 0 on success or negative error value on failure. + */ +int sensing_sensor_post_data( + const struct device *dev, + void *buf, int size); + +/** + * @brief Get reporter handles of a given sensor instance by sensor type. + * + * @param dev The sensor instance device structure. + * + * @param type The given type, \ref SENSING_SENSOR_TYPE_ALL to get reporters + * with all types. + * + * @param max_handles The max count of the \p reporter_handles array input. Can + * get real count number via \ref sensing_sensor_get_reporters_count + * + * @param *reporter_handles Input handles array for receiving found reporter + * sensor instances + * + * @return number of reporters found, 0 returned if not found. + */ +int sensing_sensor_get_reporters( + const struct device *dev, int type, + const int *reporter_handles, int max_handles); + +/** + * @brief Get reporters count of a given sensor instance by sensor type. + * + * @param dev The sensor instance device structure. + * + * @param type The sensor type for checking, \ref SENSING_SENSOR_TYPE_ALL + * + * @return Count of reporters by \p type, 0 returned if no reporters by \p type. + */ +int sensing_sensor_get_reporters_count( + const struct device *dev, int type); + +/** + * @brief Get this sensor's state + * + * @param dev The sensor instance device structure. + * + * @param state Returned sensor state value + * + * @return 0 on success or negative error value on failure. + */ +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; +}; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /*ZEPHYR_INCLUDE_SENSING_SENSOR_H_*/ diff --git a/include/zephyr/sensing/sensing_sensor_types.h b/include/zephyr/sensing/sensing_sensor_types.h new file mode 100644 index 000000000000..db15af1e279f --- /dev/null +++ b/include/zephyr/sensing/sensing_sensor_types.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_TYPES_H_ +#define ZEPHYR_INCLUDE_SENSING_SENSOR_TYPES_H_ + +/** + * @brief Sensor Types Definition + * + * Sensor types definition followed HID standard. + * https://usb.org/sites/default/files/hutrr39b_0.pdf + * + * TODO: will add more types + * + * @addtogroup sensing_sensor_types + * @{ + */ + +/** + * sensor category light + */ +#define SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT 0x41 + +/** + * sensor category motion + */ +#define SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D 0x73 +#define SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D 0x76 +#define SENSING_SENSOR_TYPE_MOTION_MOTION_DETECTOR 0x77 + + +/** + * sensor category other + */ +#define SENSING_SENSOR_TYPE_OTHER_CUSTOM 0xE1 + +#define SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D 0x240 + +#define SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE 0x20B + +#define SENSING_SENSOR_TYPE_ALL 0xFFFF + +/** + * @} + */ + +#endif /*ZEPHYR_INCLUDE_SENSING_SENSOR_TYPES_H_*/ From 703ad12188124e6425f19c4da2c64f60064f7bb3 Mon Sep 17 00:00:00 2001 From: Hebo Hu Date: Tue, 23 Aug 2022 10:00:56 +0800 Subject: [PATCH 0222/2042] doc: Add documents for Sensing Subsystem Add documents for sensing subsystem. Signed-off-by: Hebo Hu --- doc/services/index.rst | 1 + .../sensing/images/sensing_api_org.png | Bin 0 -> 40295 bytes .../sensing/images/sensing_solution.png | Bin 0 -> 121791 bytes .../sensing/images/sensor_config_flow.png | Bin 0 -> 171478 bytes .../sensing/images/sensor_data_flow.png | Bin 0 -> 182899 bytes doc/services/sensing/images/sensor_top.png | Bin 0 -> 131971 bytes doc/services/sensing/index.rst | 274 ++++++++++++++++++ 7 files changed, 275 insertions(+) create mode 100644 doc/services/sensing/images/sensing_api_org.png create mode 100644 doc/services/sensing/images/sensing_solution.png create mode 100755 doc/services/sensing/images/sensor_config_flow.png create mode 100755 doc/services/sensing/images/sensor_data_flow.png create mode 100755 doc/services/sensing/images/sensor_top.png create mode 100644 doc/services/sensing/index.rst diff --git a/doc/services/index.rst b/doc/services/index.rst index b85d729b13da..8b9e94092b24 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -26,6 +26,7 @@ OS Services settings/index.rst smf/index.rst storage/index.rst + sensing/index.rst task_wdt/index.rst tfm/index virtualization/index.rst diff --git a/doc/services/sensing/images/sensing_api_org.png b/doc/services/sensing/images/sensing_api_org.png new file mode 100644 index 0000000000000000000000000000000000000000..e747e9daff8d2f32d1d9b08e5124b1646dfba098 GIT binary patch literal 40295 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 P5Xc#03!`Gg%QyZH+P52Z literal 0 HcmV?d00001 diff --git a/doc/services/sensing/images/sensing_solution.png b/doc/services/sensing/images/sensing_solution.png new file mode 100644 index 0000000000000000000000000000000000000000..7672fd4a8b0316a8cd3697afc9dcf44005780398 GIT binary patch literal 121791 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

tH}DT%*-x+R|V$&MbF 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Ȇ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 UnXnSVf1uANs_Urbt6m8FFAVzvfB*mh literal 0 HcmV?d00001 diff --git a/doc/services/sensing/images/sensor_data_flow.png b/doc/services/sensing/images/sensor_data_flow.png new file mode 100755 index 0000000000000000000000000000000000000000..84ae087f84cb6de098a19d39b59754667b860f10 GIT binary patch literal 182899 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%0A@zzI&xxSGd8YFy2_4N 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

WC8 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 Gi$GUXjBNi5vNPyM3zrfuq@&-i8h)T%)h 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�C)rs&n8Ze>)JLH3nN;v%i zR#gnaujH@>`eqr<;&4nw*&lh4b+uU zR*44eLP-lLE>SE>e9yW*!1_nU%;4+cHWN`HQ(@O{U{u5aO`}!iDGDa`pkgJ$j0Qb% zMt_7t-wU$_4CVkEF?`p$?}|7j63*+@mV-bqhH{}M!b8-dhe?3IIpYy6u-VWHFUv>5 zY7%YZGq&rDUGjUVbWK6S<|zvMh+}Z=O-6VC^RoPxtrHe=s1{)43=0r3I8GuTV9V<8 z3~RzSjz;9Gk7mxi!F(ik;&oni2ySbj_CkyfGLLv$efL^8db%ZaX&K`XJVRV<82A}! zM=g124EV-O&288?*bjGCqQ*o8Fx+lwKym#=`hCduLdz+d#Fl_Ih39SEwRP)L03i;= zn`D7C;Tk=u0tBv7ClnI=Q&Ss%?yoU}83_2M%++j6L?(bgjno2yV%I+6)>B1`O&>uU z1%MA!jZmbwzQ4?3u56x^o1aBS4U>v22m*NFU}$)cE=x=WiA^1lNa4X1v0zG>V0Fv2 z52$Lusjb9x4~kz3#C!=Y7pQ5AwVTF8b`fVr~xZq#g)jC(O$Mb(dZ znKUA&u1z0V;-pzp8_)>B`CcBG8U@_&{|YG1hhWHYOcLjxQlgDWdF6D?>`|hYI^v+{ zB1XJI3NkAA-x8Y~_#7l0o2_b-pTP_Odpq>{Au>qF4C&(N!Rx*C3q>07$PUv&gD})E z1<^x0B0>#>yx#st5k8|20U|nyYIPfg8@UX-@O_Wfc zql}08=g;&?7gRZecvJCEd(Dpw!S#EEO1I^a5YGJ@ZAi?K3i44(f|K6n-!xN+<@M$Z z!uHPCYt~h;F9+nf7<|oOtFMNNjKYuhs6kQcFQ73Iqi^?WwNc9m?d}3l=qn5qjafR| z?iKg`U(=j%_kc0VEp8KWWg3=S} z4eZu3=oA2lfj_vr=TW^fb&mNg0Y)K=5LCL-<@==sV7LI`!h|h}%mAF7nq`o9)C*Fp zRZ!c~1GXz*XsXtyMv2b03nR_6$!(~+_=4CQ2k+9$s#XTZVTZ>*dF1iCz1f#Fdn-J| zBE1tCNy0{UPh|Z3+g1m0&C$dJjS;}rxKW8ab=h8B1d{15G|AINL%fJ+a#Qr`coKU6y! zerpb-1&|2}t5AIjSqTYVI)7%V(m{l>zy~u|kmUgk^URx<0yCTl$E;K_3&sV}+Ezcr z3Y^OT?$@0%n?8N|N(jlLy3~=bKhWD52Y8?pX*ektA&57AS2v~Z4@E^y zWNu@Hm_f$e>BG&E+u(0gBM3575LW}}@Z$6&V3o%Ei z5qHWQ|7bYSp|5)a@fPpzR23m{1CV&gYKWlQ3Ux+x_=?Jmyj!y|lR+O3aTgVtQIf!v zpGY);cY?D?!~{e&y%?KrEZvQ|Z$MZW6WK@tZruRH1C-f2()&j%{Q;iBg#&)feiRwV z1bgN>!ZIWOu{KlS(g;S|Ub0~VCb{_Ga%IpqilkVT`sLtismGe4B`{1LWw;=~LWO)O zut^OfpF-n73(U72!ONA9EiMbZNa+=7_{diiC_4i&0vBJ0pwGT!-tl+!uj(%XH)Xf7 z<9H___412`QoSbZMs{!QZj>3;KpP}OEto2JM9d*v2~H;&lj7F)ziH9%XG%rj47&@g zW%#=ilnuZkf{Ry-7{OIgc}@h@!FIc!KR1!ScN?hNgqUL%eqc2&L3^XaA7>#IqgAmJ;hdCv z6>plvpHOa5K=y1^UA{5k1H>TdYO87+lPrN$6^1Jx?GiZOrbrh=ClO}=_g_8IX>2k>OsC`acKnG3Rp&JY+V!b<#uzHxe_6U5B!5UZBHxHm)G zQ~|5jMd=YDpFh-2NH6RLZo{sN0!b4!0vCenQIJ3BqFza7djeN zs_I^yK6`e;>sra0cQ*&W&qv{ScbIr zk1N<$b?J^}L-mz)f^`Ahr79IC+TOjCZExaHyhM-h==3YjO`%_*i!A-xrVi*?ci}HfExQ})%Fd-xbl;5AOr+jwLpZeG9?kNg@ z%reM?{rc5k&`Igz|nsC_v@al+v_ zo-YyTBtj2tj?q|CRXBTr6`we!efoZqQkG}tj98Knr4*xm`CgB_+pE=TTQ(pZhY=IG z{ymL6HkFuB`rsVJ0h|pj3uSw6mhQbt@lzErLhA7qRZvh+&coGHjTT*Z!TDpuZvz^( zLg+>1wr4R6X-S+kiJRt}CwmPyTpKI2+PUu#!FUM?30s0jT_q8; zSO9~f3l`jK*I;OVcFIFk7)kBp_DkGY{6K?2nT-YM?uh*o=?JZ}x(l~Zu4EE* zhS)a0m)3V(Uu8@nMHlgFItm{}?4ikb42Y@1irXqgrjoJ99&tykiM?EpZzI-6(ydxcMhqq8xUROGs)v%AYW=ya4@-$g+=r|_$0@Gag zKb4#l+}u+ByKARP>)^d4-+PT+qn$fVqO8l0>(|^F-P-G9ep8QU{1`U*>t*IqDjUiR zTt<`h=F2-&RG#4>BJsPQF4p9KrtYx4ZVAB@i*IBJ)F`Rk99)F8<}`F!ZkIB=HB z(jVI{2y9rYdZT!+It;oNHl|wPoLv2s+NU>8Z*XJG9JT^6Osz9@Uj!yY5#Z6m3{;k= zg$XcsHBzPs0OHU^(*N@PWCY9W=&^fJHQoJ$F%xr@BE2?gQInsp1q6p5f9+C-2dAQe zoFN0aVN|)OgTQ6wbta*UatF2Z%h%e=OO|B313ajq6T=ak0ik7}^BX~4^Q}2JiIeGC zu%0LTy#U8=l>~o}_;INgjsu*htl)MQ?tj8 z;>c>UJ|Qn~0t&n3Gp0}PArd68+c^qOw~-O=-w@Dh;;0<^x;v<{ZAI|_)F<{2X)H?eTY*No< zumWKq$B5pjj01$=p5KkLjaaGm8&hLW_2gZlYorf$jxv>RSUEKdDfw)pQKkj}dsbwR zDfGu~!s9oiFQl`INGSN3`Gbqohkiaiv}d|g zG79WI?%%vsH>svf%X)Z^dU{RAT25*}R}KzU=BuseiZ<(R$p!IrA<;`H+3T0Ph{A3j zPFM}}L{;_|)tZ*h`RV-0dB@74I%Ks}iXg<{LLFzJ<890Nwm?{P0Gaxu*OLqk4HnIA zkMz#e5mDQY0KKw)hmwcDF280`5DRQ@Q9+$z{)k!sC1+N9UOk(^@x*dRIcT~rbPfeVjGH%0n zGKc@Kt1AJga_!o?QmHg3Qqph?Wo|%&A`vAjqL85uN2XGlLNYZIN<@lmL#Eg%B|}P1 z6EcPhA!H+wNE7~hZF2tqKUY`Zm$bd_GpuK=dsxo^sXKwb=z|{%ke#?963K=QWIWrp zZ&%3Xd#q3W6^OM*^~wpCsC?y-B?4gnm%Yneb#s2o)d}}imMpnZx{Ot$)w5SMD`COv zuSc-}ijz?45?_~B1VtYH-3$piIlVn8yYUPAqHmy4zMx6u@6mX+mH&8Jy&-pvFEa(} zJ)5s`>Y23sW~Q)-+%cdzcMPRL4cMheWg`7HlAens^iGJR+TZrs?Mv}TGI(f&`OYSo z$-oZxap9E^^0Uw!)DCbo290k@Tlxn~TVZi=F>m&n$*iV^DL?FSyA%Dy zVDVo4g7nwC{L0zmE=}o!Ge|gd6LZ=QeACxL?zBMW^B@}R;kRg6acp@uZQ0G}kr=(O9)9&a%D?~nN z2+>=E$(b22Z>1_l(|XU37dOBfNy#Pjgw{Y8sh*3Soh!)1ii}V?ejkYdLnqo$+2DtV zGNRu)p+KQn)01m*>Z6)}@idL*Hp08DdjwOO{<-bg1+=0X1yz7-Lfw%p6VmYuyW8sq zg+gYsiZ2_&4AE^?pHC`nxIo%BqgQvza!BvJRC|F9V1lr9TWB@!@}OiMB)WS+vIKRafBp&pM=B zGrezJEA70$`(P@BYZm8~ zz*>RcmPw?=L*3N}o6ASHI?M*n?ANH1ga%k3jpq8RqkNL7{^{#EJb0`gQhPF5qjYtG zV#XE<(%?A!$d~5n)~NU0qQW90Q&AUmz+$=w(gB>o2!crj3IiSyuU1BXy)xwW3LvF{ z52-?02T(4QKC1)GFLVwZIFMJG16Ko{p%1LIHGn3P1495SnNXR8CuXCxl00$^pH@cL zCJ5rfcBf=qI`tFxo+Xh+5?5Vge?DDw?;c6)7p&F>Ft-bY18VV`c4=7}2S zTm*}L-?wo>E<0Pm#Kb3~(;iio*Sc2&O7zDxS6k!C#8mX8G zPDU){&-rG3OAh)NVlE(iB6SPtegG^W1=53+Ila>`$0e1LVnEZ9*q4y>>5;k`>N~*S zG5^-i9KJP!Ykb58w>#L>Qej2$KwzzL6E{=htJ0z%Qi)+FzQ70~qEibbB>O)70`~^D zxG$1w&)O#WHeH}SOAsQ^F$bQW09mHVd_*$3Vbiv= zA?Fw?@7L$`niU8O`(m6aaDW+07EQt@QnLVB@Z`b*v|k1bgj2b?fMzgN`2cbV|3!ba zYI0}cj^MIvzh9@nLC?Vfx@j38#1MNx;uq+ItTBv$ydjBt_2fK{`YlmmbZVp_p$~67_b9v6E zRfp;x=pw!YAi7x7NfrQ(v=Nu(ZFN3-4VgP3`@q^z3}Gwnq1;y)SNoC2gq7RthnLS2 zP9@Q9cBAh!qRg?V37x@u2Ode$9-U(25YiNEYnPV{P2(C*WyU@9f~6A_!2sAAK~LmM z0Omv{t5+-I2k0%p9Ebz|1e~f1I|)Uq4rnMUP=wv0OXL7mmuB9_+0y=G+Val{0 zR$QFS(FsDw6|vDP51lGgguRw}0kEUg2|ER^sSpXd2z7Qr2@OQ_uav4}t>q8pZELA_ zUK;cmiO6>;YNH(y0X7iXm=cHwNyNQT@hS~H@y+1s$vS{4vG{J@hm7H^B^Kq%2K)nW z{QFG!51}@ZFH{)VTGQBTeWF|Dv+_ipyz-kqFR&V3v1c#&^?Rr^i|FKV#o62R!{5ZebZ8Jg6k zgm{t^mkPH17q8HVSp!w4`9mU?N`4?x2w>kiy;7*58>4=lnZ5}b>}v?eQW4O}tx4gZ z6nUBza-|z$u~1uGe^b%|Ab@%_QC@Nn7tvEX1&seSu*^On)dE>Anw)_Fj-nY%jwaN1 zCbY95V4?Mg-Y;y(UMhfa>&NvILkHreeBV&70D3I$qi-YuC!kFmj1Hm2G1-G3K0QKv z1|m0Y>mH<2h$D#_)ePhnK~~%jmW4X7sRlJXJf2BohucV%`pVR3Z+iazvV}&3i2LzA z-qcwXH>S%ryd!`eSrn(Y9#jS2x*J#!010HzgoZMjOnz`|LCus7|Kl1MbN7<@fmWP_ zsO^Ifi~Nb(MKSCA-mOhD7>w(Cp&L`k=qHL=yrW@wD3jXl6Se|{%}-RmPCbpAIBSJm zpZIpweFmDguSj)3h&++xVD5KAH&=~WkO_Jodr4%=N7q{o-8JMt0Z5M9Ne#doW4cl@ zES}GJbyaQ)5?QI9uQ5x+jM|8Dh8m1ubeez+$iQfBAkMr7$ww-tZEojeoMQo`*CLSy zjW=l-sp%zg$M{?dZn5_VQFGDVT~**tQxW&U<8P;O8HW{dg8fill4%KP3_S)u20QEo zdbVS*y#o9BGY16*Hq7mE4AsxIV2QRRTO(@r{u*4Tku~X2=f^c4Mp3$R`cbH*mxbH} zkh3iq`|7eq+>WEv+z?a?G6JHzRAbBIb5m7zXva_J+isDKjI`gl=;5-6bSD70MesVfJ$%2R_6J6WvVKW;pNWqNY!^*I zibaMRfLWkVg78X#!d0Fn>)O~?jO}&dqze3nMr{f7Evv7kK5lnD8FUR@K@c%>qCrwWJQ z=_?rRotT#3(zePt&C7lnc@3VwwpU!$J&-k^iLdu^DT>v59{slO_I;eGNyr-4RbNK< z$J@z0PYk5QmFNt(Ovq9NU_sN$_XWu@$uFZ88}Riq(pwlo3>TK^ae2wo z3g<-#*_7#vk{TL<3JYr^EM{UyG%MiD)^91lnBV*pkz#6B5JyD=tS{)@x4UTWf!B2I zey`-T52q9^C=jfGjruMS)7@D$ST54x_UOIXm;p)a|s^xqlzvNe4rS>GG{?ZLy(uTKHDz45L z{CzV{d)u~MIP>^{N79|SoeH;%Gj~uV`<(a7o+xjmbQW=G)%>RAyXA*0p0$ulc z+M~~hzS~jf0P+SQiE2Hb8jU#pamw?OXI(Cx@PuBB8=t_E`FxbGZU}uabga3B0=fjO zh9}w?BkrMc(SISOn|R+htw89ya_i`IwXXoc`}l|;<3f71_>;< zv3jE#-u86Ea15#)cD3M2^HU_7g3Q$hRSxq6Zfp2y&XTLx`?YorcBu|9N8o{wq?D8m zqCfc+QBvOg@ccaYScbi3^$!R!B#~Vpd{rydm|V8{fow$}V(!`p0Z+JsI%7;u#>CY^ zaq(h6@hMWQyf``L0nfI$#-N!`YAtL$hFV4g(eet%-8S5l(z0015e+BA`YW`SpO#Hx zJpOH6snRm^qtxq+r|9HpSNoi<)#QNzBwzW(bpvx)Yl3(bRuwhqUX9G0S8$Ok+wab- zPjRJ6rw@`F6OXSptc)cYweKqUC(U5$B!RW?F(;~#eHUuekc^fMP;v>UD0EBL=i71f z^}UO^mxsC1+!d(1oA|zD6x%`~L2<)fnK)DCK4?HhUXsNAC4=|IoG+Wz`9}-j;mFkc z4WwOOUg^LCl*FySzW+8m{x{1w80S&~OaZE$SK@HE0gVuch@_P7@uvLJr;S^?p46ee z0;z-hu^-u_L;`8zgqiH{lS+FbS12z?>1|F&atf+wElR2pl?>1(ALgSq*leb71DQo# zip$>-{9DytlZ4Z8a@~jA-QAjbhC*lE`+>$^hGm{mmY=@0$Id#tD(0M1WK*e>b&CTkv?sW3~H zZ<%4_cy_dXv`WSsF;#<*$o+}9ox%)|aamvdCS>O%h*BHIpk@HuyWG6;dC=l8Q9y=T z-ML>&j4}mspV`Ut%kN$DCf~H~n|@vY#P#>5xtkp^`dsp<(bE{FSg5j3R7dz_H&6#Q z5`oj`P@6=Oy&%NSe8{484(XRq>_-2u@BDkS3lcWSXdm&yVaM+-gao|^){v`(@|mbM zIaX^N4`hWW0T@%lVtH1}Y-EyR@(*p~@9(=lD1g0A#Rkr@YJ$lqm7>O1adP8c;hHD4 zM^jOyGn*5l{gV@J-aPZ<9>8>vvEMqxSTpFUZ}GJ?J4tE)&H;eg za^k*8KnVmSPA*p2>Q%(ePmXw}Tus=;lSuj!7|uB5RxVDKE{;eQ!K>YHM%k9GxXUCh2Wm-Y$M!@HYQl7O-4Lad_?^0w5KE8nGiPehcpnx0gl7_kow6kg4}5=#C@9=3 z8|3BY@)L5u4o3#{9iZ%rTu$zoJra(k0z?AgIrX$|{Jp`uNw^_`Zet>&3?)qTt~9r3 zYf*#5b6!NnYxDF|-v&_Cel@MZ?`k4~{&QS!Y(H`XeR&1Gha;nI$zsU|J+Pr3CYZ4@-_-g$Mdr8hJ85eUANTTi)TVJnU%D#X0ZF|) zs2vAT6p{r4I((+{c+cM2pi{hEk8Y{Er%7(lVzm|?+dl%(Z8m2{6G;9Nf?iGQv#HUX@7MjKhS%3&n=rXT6ao%+W7fgCkCZ7 zTKLBzLXuB{@Jt-6zzuCsFEcv>uYCLFA1m6`Al;U}wRHE$Sb1ON&5bE0JzQ|#FgjLH zn|A-f->5Byz7-sF%a8d}2luVp;+8^I;oJ`p%tt=u;KiUWkk#E%Z=+j8X8 zdjQw1UtD{oy|AXVas!TpnYvuX%|!jEpFSE7qcq#y(wVc(N+ZM6tu+)MV`CbDzeYQc zWtzh|Lr0A4AFT*8b5DvJu38$Iwe*(gLzK`zl$U)kIFIaJU4|PzH)`igSpm|bHlsW| zjR(trZ?HxB?b1_?*(J7GPim`PnHpF7jDh}jGuSQmulHQFwu_(Eg9G?H-(rztDj zlT*?vpfQowqz*LBU=KO~aTKpq1$S!);D=f6(*)#Ibzv1s&PNAIqrkR>HLs*<6?R>< zNcJZ5a|jhZfwQUHL(?)DrX9ku07ba*A<k`J16EiPunNgKA;eHESNf&Oa+lT{Qjo^r-Pl+}d(inddS zDu~>trZ!`#lW{2zptVq25C#W#Lb36XIR062`yRH#X?`m~@>*aP^sqdGMOX)#$( zynfX-WZ2g$0<%@#`9KaW$7t5b4?>YOv zaTuv&Bxj_H#+jZ*!uMjc5G+3P-gHbt**oM zPEJqx4cL&eSE>t`5-E^`NJ|C`oQSWH`rvbNUg!no^*ostTynt^$#Lf`GOsQD_a1%!;1830Bsu31cG`WX$?BkrpleM~SJQGmk;lqeLMbZ1ArU~$_`hbz z4h#Sel794$9v!WHGVo5qsogl*>3B(mCf!#0VqN$(;;L{$*7Fiy)#0hO4Su6g9LKO(RLw%kho5%_k{?mKcL_a zfwxx+0=!MY&T9u;O+lTg5SSPek+q|wQxgw=B~xLM?lnAg=k37=)WKw*q96%ig5;ZV zaz4~NALc72HdQjRdV>3@Bg-_|2P!~9q`uin7r9v6+e;6F%ih?C9Xuz@ov1iWfWs;x6+?fm1w0TMv8yx$NTa*fT7H zs00KEfsUV9q`M*2_wJ-!PpK$4ir|1;7&4v}@qo-VPAtvyyU?gmO#U_)#p$fZ$6$RV zw7BF1$fnfYHI!x=AH9GMG>>32k8C#It(pDyd`h#Bn8nT*T!))&jhvtTcpvt zYqe9x@b(hEkD=AyNl(F-z>8?*|B0@indRbu>oa>!y+HsWe1bi!^C67%>_>j{}u`uwY zYGiurM@fF_W~x2b32n3vme*hknwWqx5CyS@S=xhHRZrjIe=&9-(t=Q z7lFvt_TQR!fliSa0hGVhfPkFfutpd%CGYcVEDt3d(LbTH@b`Gt2FZ_Azu zeZ_36RwqS#NFw+KYkVFVy(pj~Q(i0oj)jd(j#fyF46iKD*CFf?rw`g=4SR%59zPCg zpxZ+;{Gtk|%S8(1F1aO^YKKPy$i8y4iaQLNT-XB99?}$RKqE}=CURzu!x_z z>|}xphltQfl2{baX6N%Q-tY>EOBO9nM?)JDf3kAP<`_4b({P=p1i&y4=f+&raW*_mM|&1squVU~vd1hVTN9(iRij5dEnQUFqxJ|l4X2ZA-R zC&VJNhMGVt_MY$rhzxM-CaCu?^(@^v+*|~2W1^I{Ob)N@ss@$+S9`J3zgW_%lQ(ZZ zUvEEi`@)4<=o^^)n(yqHzV1uiy_0Xa=_%ONOgXIvKc=P0U$c~;PRGv#>3E)PvRkOB zVT*6q^ASk}D3kP0F2~t(^25O90O}HX|#*6*xnY2@@=^Uo|{>FZ3z6eyX(Xa!se0hl~%v zAF`wq#f5aD<;YsqU&g_N2m*@Z|Na|EDp;TS$_o!4U7z#NjD?|002WRoPUKN-*NlJ* z+UR!+TFA&YcJ^8`-CYPx`jzi?)GK}O@Ce&DRL4UlgM6zELP603RgELUkUhPP1yEaP zpV@Xi4T*HWQR(idyga5SV~v_We1HONd03Gc!Vl_m=*Uj1*7O*E|GI8yL_wr88|x=D z4#EIC!1>7XLdaY})-8^L_LhUpfPBH86ou#3v+)t%zqfdi2GIV0O3@fnbTJ=pyvKYv5!1U*$)(eBj~1)?7;tn*P(p}Y`7L}v;b>mhkV zOB0fN0Y;h5OnJ%Q7QUkS`0T~7eA->W{kj3Kr8-w{W1q5?{A5C1;t~%@t@Tw{`%YnA z?xe#r&Wboq^W2yI_8_zE$fptI+7dx-vjXVsO#w#u(E&`I8BmH&aC~w@{r25euG3tc z6oqEcyRZd4aOdT9P?Ufq)z)lY3X>|1guw4V@_9EM$n`vmO8SEAxN~o=cJ{eWJ)zw* zS=#cg#+0a8hs2Z&_zhO5OdsYAFKD`0)H*f5V|t*cOqayj(V<<*oBJ^qi;|4z#AidA zG2e7YmU+6NYHYFZ!jPs|(}I%*P$KTNzxx*RbVJ0|GWqXju7V!KuLY)4b(m`-cW6$W z%!0TDH)t@+-7Tv$rd;3e(j<3;>(MbTwLJ-y5}4bB%BvQy?Rs*wdT^I0{imYIn;SKe zX*cAsbLGLiZ(F|pK+`*c2#vLCBNTGK%DJAXX>?FEXy$5IFQSnfA<@`0Pdx)HxY3=R zQT;3Pj{rx^(|#xJGsj$Wh3oW5Dfx>}WtpUvWfWv>$vv~LP2u;>kslNNfZL4s((flV zjTxT#w`en)-7MaW&DhrYdn%g)U2|VT@gug*DU75|Am13evZ}Q$xY*QZ8CM` z?rAn2d}7ta?K#Ztxn@e>l9@x%e|cm#)z!GgZy)`9QEoHcgZb@ePA&|E#t(5EzXRrG zKIdAmbh2{BWY&*D`GRNuK|w^9X}bj&JT3+Al};>#ufXer5of`peO8Wqse=EpO=xzVy`MAADhoZ4;m zBNq@f)hJ%#s=oP2Li4m8{Q0)-3#D1Ha} z6=;_;`^awTQ)!Qfy#i`f->I%}a?Ub|cSt>|YVhx!x{W;3W*QV6ZYl~lAH9C5T(!sV zT+8QZo-?dnC7mg)i&_h*htOMYLUv*BX_CMgw~Ir&mOvb?4NQ8YdJlwa3) z8Kb!jL_XnR?u|Z^(X7pw6WT$K69q>#BmMbl^A~oZ6pQ0kCPnBcwB4M!p~qVpUFhh@ z$4tv!0 zwH+X>Mi{Rg7PR?k=e@ISLpLHh!M>IaOVQ7?IMW!~JjYT(RyM87g;%JnXRUthj_3}U4=kPgQ1pf=i!T{eG++MXf?yQRP`bm2DdG8h zsfa0WC->-G6^!VEEA*;nYg#A_K7vSr`(kpxqI7Jd0NDvDA+(^#)e0TWHF|Dpl}xk95o;mkfwbTsN|?#zPk0t>J@fy<0<0@D#_TR3hx;7l^ab%=)apP%ND=BQuOCJGIA6x35~4|q`;&$M zBl;5+pZ`-*b?3Q9A~-^jAHhv$Xl9GqnfJvKSJIJ}?xLu%{6c_Gr4K+-8sQ_?e4Uj;J+ z-_N>Ei$aU-s$8k;tT&IT?P!(qwT7G#Jk<1POhTL28krN3M!>e!F1bOz(@64!}Kl70uci2e7k z4ye+zV*3F~nL2n45y3l{tg_H7nE!eEGzcl^@}z8@#~~=HM9vocjfLHAn7W6$mCzz3 zsV0zETH-n76B**v5wQ~TB2oJ3vt-EZKDJc>7jw)9KxEF)DMfvCVNqN_TNOahYgDzg zRaboAPkfBcamVtW!@E)J(A!Xb<_d2IpECaRz_Hk6zThG5BqAym*jz1pmFnoO@@pb* z77C98f8GPdw;L7xoLNMNAq+0+yOUXs`t6YQ)JwAaSkY_}UPN^?3eWaZ_N@w#8#XM@1OR)o*kMjtnV-x_S7>KN)@KSySA@#?6tmVRw9iU8nNqxhO5RpP>eOYP2Zzc|uBz^k5`f)}lQK zeCeE63yFv1`t{iCjLIoo;|YhP83Bw+ZCg3Vz}fjLu3BGkLN~lb5|H!#a>M*uVz9Q^ zqF&t#Civ!{)ExrDZ#L zY|f(N*fx`N#IZ3~jaffcf11(bske{)`|b7w_^XAYzD)U1+K##j+?Kh8lxj6PfQ3(rq$Uz3|&>i zHz0zA+`f`lCgJYMds68zXNf?+>-Zplr6CwyrG>K}RxrH7|JR(idly4h&Eob<{H{`7#c zncL6hp5WsE$L_fqW2?bim(85SgEhVRzg6>iYu~O3lY}wr|AqMd@|?5tM3!0&d<|IQ zCDFFtYz^2Z^>n<06kFs_Iyms&y5ZXl63b&03ooiDZj z;vK=Rh=#2ONZ_<&v*NVx&kR|LM{Ff#6M(mP&i@gjN!n zGr@czCt7)Ok=X0UCP&+L zTnt7_#jPJrZtS4_!wy@rjf7Q1uXn zZ)V2QS5{4X?0siX$fY!3LzqrWo$0eov11D5ST#~NO2;Bx2^?451DtbiQP5eVVsGxU zhAEp%x(AAyztB;icw6bsDVDgM<7SW)pJ^`6M=&w`25q-_5o$HG_i&uKE*8n zyYLG*_`>x^SM_xpdUX8>p+)Ahu3gmQv9Dc3lL)b!+E-(Mijxxs+y!$+*Z%KQ!x8$; zjie_95jX(8YiWD&x(<>;gZV(KFfE|DM&vaOEOYx)8SGzlAL>e{jB@qOc!$eHt-(dD zyC75qpv-Kb{AXgt;NlpEZ&4D-^s)Vs@FE$G~!a zv)Li*HS{MyB-7kq!n4k@G*`mL+xcipMN2KnA)ZP|adt}Lhv&GbO5xF%i1i>&Q z!s1(H`>H&t9(ZVM(PkdWQl^y7`=_?-h+3rmI71w-$07xS7G=a_jRr;sovw}!wzsff zdzK3#rRu`B$~TtF2gG7z3Yr?jEX4T{*IOjFu_YtttIyf6<@97$zGFy1(~9iPV{`wn zQ;*=MjQjAD!fDOR%J0mnND8n<927RVq-xM!9CQ+*b3pvLW-MSa;;yYif7aK>Ih7CV zFh&&lIr>M1ejK@gKdh7gek>g`KYJ0{o@Ca$7{9Kb9HOs2%`{%FEfHC@9i|r>_l08= zQgn?l?&xq*-oO@Cf(y0p@3~2Gr_)s2cIm2N;MT#=&hHus=n(HXI^5!ChG#y!{7uwIlRt{Sq^Z7RbDHXY G-~Rz39V6BN literal 0 HcmV?d00001 diff --git a/doc/services/sensing/images/sensor_top.png b/doc/services/sensing/images/sensor_top.png new file mode 100755 index 0000000000000000000000000000000000000000..3e8e4f4f9f209bf985d5378f265aa29a441f5c8a GIT binary patch literal 131971 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

iu+OnUERio%CX0=r{jM&apZ- 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 $>fkB=}&6L6A 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, HID sensors Applications, +MQTT sensor Applications according different products requirements. Or even support multiple +Applications with different up-layer sensor protocols at the same time +with it's multiple clients support design. + +Sensing subsystem can help build a unified Zephyr sensing architecture for +cross host OSes support and as well as IoT sensor solutions. + +The diagram below illustrates how the Sensing Subsystem integrates with up-layer frameworks. + +.. image:: images/sensing_solution.png + :align: center + :alt: Unified Zephyr sensing architecture. + +Configurability +=============== + +* Reusable and configurable standalone subsystem. +* Based on Zephyr existing low-level Sensor API (reuse 100+ existing sensor device drivers) +* Provide Zephyr high-level Sensing Subsystem API for Applications. +* Separate option CHRE Sensor PAL Implementation module to support CHRE. +* Decoupled with any host link protocols, it's Zephyr Application's role to handle different + protocols (MQTT, HID or Private, all configurable) + +Main Features +============= + +* Scope + * Focus on framework for sensor fusion, multiple clients, arbitration, data sampling, timing + management and scheduling. + +* Sensor Abstraction + * ``Physical sensor``: interacts with Zephyr sensor device drivers, focus on data collecting. + * ``Virtual sensor``: relies on other sensor(s), ``physical`` or ``virtual``, focus on + data fusion. + +* Data Driven Model + * ``Polling mode``: periodical sampling rate + * ``Interrupt mode``: data ready, threshold interrupt etc. + +* Scheduling + * single thread main loop for all sensor objects sampling and process. + +* Buffer Mode for Batching + +* Configurable Via Device Tree + +API Design +********** + +API Organization +================ + +* Sensing Subsystem + * Sensor Types + + .. doxygengroup:: sensing_sensor_types + + * Data Types + + .. doxygengroup:: sensing_datatypes + + * Sensing Subsystem API + + .. doxygengroup:: sensing_api + + * Sensing Sensor API + + .. doxygengroup:: sensing_sensor + +Below diagram shows the API position and scope: + +.. image:: images/sensing_api_org.png + :align: center + :alt: Sensing subsystem API organization. + +``Sensing Subsystem API`` is for Applications. +``Sensing Sensor API`` is for development ``sensors``. + + +Major Flows +========================= + +* Sensor Configuration Flow + +.. image:: images/sensor_config_flow.png + :align: center + :alt: Sensor Configuration Flow (App set report interval to hinge angel sensor example). + +* Sensor Data Flow + +.. image:: images/sensor_data_flow.png + :align: center + :alt: Sensor Data Flow (App receive hinge angel data through data event callback example). + +Sensor Types And Instance +========================= + +The ``Sensing Subsystem`` supports multiple instances of the same sensor type, +there're two methods for Applications to identify and open an unique sensor instance: + +* Enumerate all sensor instances + + :c:func:`sensing_get_sensors` returns all current board configuration supported sensor instances' + information in a :c:struct:`sensing_sensor_info` pointer array . + + Then Applications can use :c:func:`sensing_open_sensor` to + open specific sensor instance for future accessing, configuration and receive sensor data etc. + + This method is suitable for supporting some up-layer frameworks like ``CHRE``, ``HID`` which need + to dynamically enumerate the underlying platform's sensor instances. + +* Open the sensor instance by devicetree node directly + + Applications can use :c:func:`sensing_open_sensor_by_dt` to open a sensor instance directly with + sensor devicetree node identifier. + + For example: + +.. code-block:: c + + sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABLE(base_accel)), cb_list, handle); + sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_CHOSEN(zephyr_sensing_base_accel)), cb_list, handle); + +This method is useful and easy use for some simple Application which just want to access specific +sensor(s). + + +``Sensor type`` follows the +`HID standard sensor types definition `_. + +See :zephyr_file:`include/zephyr/sensing/sensing_sensor_types.h` + +Sensor Instance Handler +========================= + +Clients using a :c:type:`sensing_sensor_handle_t` type handler to handle a opened sensor +instance, and all subsequent operations on this sensor instance need use this handler, +such as set configurations, read sensor sample data, etc. + +For a sensor instance, could have two kinds of clients: +``Application clients`` and ``Sensor clients``. + +``Application clients`` can use :c:func:`sensing_open_sensor` to open a sensor instance +and get it's handler. + +For ``Sensor clients``, there is no open API for opening a reporter, because the client-report +relationship is built at the sensor's registration stage with devicetree. + +The ``Sensing Subsystem`` will auto open and create ``handlers`` for client sensor +to it's reporter sensors. +``Sensor clients`` can get it's reporters' handlers via :c:func:`sensing_sensor_get_reporters`. + +.. image:: images/sensor_top.png + :align: center + :alt: Sensor Reporting Topology. + +.. note:: + Sensors inside the Sensing Subsystem, the reporting relationship between them are all auto + generated by Sensing Subsystem according devicetree definitions, handlers between client sensor + and reporter sensors are auto created. + Application(s) need to call :c:func:`sensing_open_sensor` to explicitly open the sensor instance. + +Sensor Sample Value +================================== + +* Data Structure + + Each sensor sample value defines as a common ``header`` + ``readings[]`` data structure, like + :c:struct:`sensing_sensor_value_3d_q31`, :c:struct:`sensing_sensor_value_q31`, and + :c:struct:`sensing_sensor_value_uint32`. + + The ``header`` definition :c:func:`sensing_sensor_value_header`. + + +* Time Stamp + + Time stamp unit in sensing subsystem is ``micro seconds``. + + The ``header`` defines a **base_timestamp**, and + each element in the **readings[]** array defines **timestamp_delta**. + + The **timestamp_delta** is is in relation to the previous **readings** (or the **base_timestamp**) + + For example: + + * timestamp of ``readings[0]`` is ``header.base_timestamp`` + ``readings[0].timestamp_delta``. + + * timestamp of ``readings[1]`` is ``timestamp of readings[0]`` + ``readings[1].timestamp_delta``. + + Since timestamp unit is micro seconds, + the max **timestamp_delta** (``uint32_t``) is ``4295`` seconds. + + If a sensor has batched data where two consecutive readings differ by more than ``4295`` seconds, + the sensing subsystem runtime will split them across multiple instances of the readings structure, + and send multiple events. + + This concept is referred from `CHRE Sensor API `_. + +* Data Format + + ``Sensing Subsystem`` uses per sensor type defined data format structure, + and support ``Q Format`` defined in :zephyr_file:`include/zephyr/dsp/types.h` + for ``zdsp`` lib support. + + For example :c:struct:`sensing_sensor_value_3d_q31` can be used by 3D IMU sensors like + :c:macro:`SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D`, + :c:macro:`SENSING_SENSOR_TYPE_MOTION_UNCALIB_ACCELEROMETER_3D`, + and :c:macro:`SENSING_SENSOR_TYPE_MOTION_GYROMETER_3D`. + + :c:struct:`sensing_sensor_value_uint32` can be used by + :c:macro:`SENSING_SENSOR_TYPE_LIGHT_AMBIENTLIGHT` sensor, + + and :c:struct:`sensing_sensor_value_q31` can be used by + :c:macro:`SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE` sensor + + See :zephyr_file:`include/zephyr/sensing/sensing_datatypes.h` + + +Device Tree Configuration +************************* + +Sensing subsystem using device tree to configuration all sensor instances and their properties, +reporting relationships. + +See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_posix.overlay` + +API Reference +************* + +Sensing +======== + +.. doxygengroup:: sensing From 685160b4bf56d1f5be0d178e6a692d28ee677cde Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Mon, 6 Feb 2023 16:43:11 +0800 Subject: [PATCH 0223/2042] sensing: add Sensing Subsystem skeleton Add Sensing Subsystem skeleton. Signed-off-by: Guangfu Hu Signed-off-by: Zhang Lixu --- .../sensor/zephyr,sensing-phy-sensor.yaml | 13 +++++ .../sensor/zephyr,sensing-sensor.yaml | 25 +++++++++ dts/bindings/sensor/zephyr,sensing.yaml | 9 ++++ subsys/CMakeLists.txt | 1 + subsys/Kconfig | 1 + subsys/sensing/CMakeLists.txt | 10 ++++ subsys/sensing/Kconfig | 17 +++++++ subsys/sensing/sensing.c | 51 +++++++++++++++++++ subsys/sensing/sensing_sensor.c | 28 ++++++++++ subsys/sensing/sensor_mgmt.c | 32 ++++++++++++ subsys/sensing/sensor_mgmt.h | 31 +++++++++++ 11 files changed, 218 insertions(+) create mode 100644 dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml create mode 100644 dts/bindings/sensor/zephyr,sensing-sensor.yaml create mode 100644 dts/bindings/sensor/zephyr,sensing.yaml create mode 100644 subsys/sensing/CMakeLists.txt create mode 100644 subsys/sensing/Kconfig create mode 100644 subsys/sensing/sensing.c create mode 100644 subsys/sensing/sensing_sensor.c create mode 100644 subsys/sensing/sensor_mgmt.c create mode 100644 subsys/sensing/sensor_mgmt.h diff --git a/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml new file mode 100644 index 000000000000..8219f77a2103 --- /dev/null +++ b/dts/bindings/sensor/zephyr,sensing-phy-sensor.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing subsystem physical sensor properties bindings. + +include: zephyr,sensing-sensor.yaml + +properties: + underlying-device: + type: phandle + required: true + description: underlying sensor device for physical sensor diff --git a/dts/bindings/sensor/zephyr,sensing-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-sensor.yaml new file mode 100644 index 000000000000..5bcaa39f2570 --- /dev/null +++ b/dts/bindings/sensor/zephyr,sensing-sensor.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing subsystem sensor common properties bindings. + +include: sensor-device.yaml + +properties: + sensor-type: + type: int + required: true + description: sensor type id (follow HID spec definition) + + friendly-name: + required: true + + minimal-interval: + type: int + required: true + description: sensor minimal report interval + + reporters: + type: phandles + description: sensor reporters diff --git a/dts/bindings/sensor/zephyr,sensing.yaml b/dts/bindings/sensor/zephyr,sensing.yaml new file mode 100644 index 000000000000..00b5452a8471 --- /dev/null +++ b/dts/bindings/sensor/zephyr,sensing.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing Subsystem + +compatible: "zephyr,sensing" + +# To add sensor subsystem related common feature diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 53ee9f96c816..de5c85f51bb5 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -32,6 +32,7 @@ add_subdirectory_ifdef(CONFIG_JWT jwt) add_subdirectory_ifdef(CONFIG_LORAWAN lorawan) add_subdirectory_ifdef(CONFIG_NET_BUF net) add_subdirectory_ifdef(CONFIG_RETENTION retention) +add_subdirectory_ifdef(CONFIG_SENSING sensing) add_subdirectory_ifdef(CONFIG_SETTINGS settings) add_subdirectory_ifdef(CONFIG_SHELL shell) add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing) diff --git a/subsys/Kconfig b/subsys/Kconfig index 0bf699da96ce..c2b4b914548d 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -31,6 +31,7 @@ source "subsys/random/Kconfig" source "subsys/retention/Kconfig" source "subsys/rtio/Kconfig" source "subsys/sd/Kconfig" +source "subsys/sensing/Kconfig" source "subsys/settings/Kconfig" source "subsys/shell/Kconfig" source "subsys/stats/Kconfig" diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt new file mode 100644 index 000000000000..df08e6633cdf --- /dev/null +++ b/subsys/sensing/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_include_directories(include) + +zephyr_library_sources( + sensor_mgmt.c + sensing.c + sensing_sensor.c +) diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig new file mode 100644 index 000000000000..64423297e424 --- /dev/null +++ b/subsys/sensing/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SENSING + bool "Sensing Subsystem" + default y + depends on DT_HAS_ZEPHYR_SENSING_ENABLED + help + Enable Sensing Subsystem. + +if SENSING + +module = SENSING +module-str = sensing +source "subsys/logging/Kconfig.template.log_config" + +endif # SENSING diff --git a/subsys/sensing/sensing.c b/subsys/sensing/sensing.c new file mode 100644 index 000000000000..4a73df5a993b --- /dev/null +++ b/subsys/sensing/sensing.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +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 *info, + const struct sensing_callback_list *cb_list, + sensing_sensor_handle_t *handle) +{ + return -ENOTSUP; +} + +int sensing_open_sensor_by_dt(const struct device *dev, + const struct sensing_callback_list *cb_list, + sensing_sensor_handle_t *handle) +{ + return -ENOTSUP; +} + +/* sensing_close_sensor is normally called by applications: hid, chre, zephyr main, etc */ +int sensing_close_sensor(sensing_sensor_handle_t handle) +{ + return -ENOTSUP; +} + +int sensing_set_config(sensing_sensor_handle_t handle, + struct sensing_sensor_config *configs, + int count) +{ + return -ENOTSUP; +} + +int sensing_get_config(sensing_sensor_handle_t handle, + struct sensing_sensor_config *configs, + int count) +{ + return -ENOTSUP; +} + +const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle) +{ + return NULL; +} diff --git a/subsys/sensing/sensing_sensor.c b/subsys/sensing/sensing_sensor.c new file mode 100644 index 000000000000..c305cbb35c4f --- /dev/null +++ b/subsys/sensing/sensing_sensor.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(sensing, CONFIG_SENSING_LOG_LEVEL); + +int sensing_sensor_notify_data_ready(const struct device *dev) +{ + return -ENOTSUP; +} + +int sensing_sensor_set_data_ready(const struct device *dev, bool data_ready) +{ + return -ENOTSUP; +} + +int sensing_sensor_post_data(const struct device *dev, void *buf, int size) +{ + return -ENOTSUP; +} diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c new file mode 100644 index 000000000000..019750a1f104 --- /dev/null +++ b/subsys/sensing/sensor_mgmt.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "sensor_mgmt.h" + +#define DT_DRV_COMPAT zephyr_sensing + +LOG_MODULE_REGISTER(sensing, CONFIG_SENSING_LOG_LEVEL); + +static struct sensing_mgmt_context sensing_ctx = {0}; + +static int sensing_init(void) +{ + return -ENOTSUP; +} + +int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **info) +{ + return 0; +} + +SYS_INIT(sensing_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h new file mode 100644 index 000000000000..c37989c8e4d4 --- /dev/null +++ b/subsys/sensing/sensor_mgmt.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SENSOR_MGMT_H_ +#define SENSOR_MGMT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sensing_mgmt_context { + bool sensing_initialized; + int sensor_num; + struct sensing_sensor_info *info; +}; +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* SENSOR_MGMT_H_ */ From 25ca09ea0196dd6852e9770c35486236c35961cc Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Wed, 8 Feb 2023 15:59:47 +0800 Subject: [PATCH 0224/2042] sensing: phy_3d_sensor: add phy_3d_sensor skeleton Add the sensor phy_3d_sensor skeleton in Sensing Subsystem. Signed-off-by: Zhang Lixu --- .../sensor/zephyr,senss-phy-3d-sensor.yaml | 9 ++ subsys/sensing/CMakeLists.txt | 2 + .../sensor/phy_3d_sensor/CMakeLists.txt | 3 + subsys/sensing/sensor/phy_3d_sensor/Kconfig | 9 ++ .../sensor/phy_3d_sensor/phy_3d_sensor.c | 100 ++++++++++++++++++ .../sensor/phy_3d_sensor/phy_3d_sensor.h | 20 ++++ 6 files changed, 143 insertions(+) create mode 100644 dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml create mode 100644 subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt create mode 100644 subsys/sensing/sensor/phy_3d_sensor/Kconfig create mode 100644 subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c create mode 100644 subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h diff --git a/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml b/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml new file mode 100644 index 000000000000..ed8cb8af1949 --- /dev/null +++ b/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing subsystem physical 3d sensors(accel, gyro, mag) bindings. + +compatible: "zephyr,sensing-phy-3d-sensor" + +include: zephyr,sensing-phy-sensor.yaml diff --git a/subsys/sensing/CMakeLists.txt b/subsys/sensing/CMakeLists.txt index df08e6633cdf..59aa28514b03 100644 --- a/subsys/sensing/CMakeLists.txt +++ b/subsys/sensing/CMakeLists.txt @@ -8,3 +8,5 @@ zephyr_library_sources( sensing.c sensing_sensor.c ) + +add_subdirectory_ifdef(CONFIG_SENSING_SENSOR_PHY_3D_SENSOR sensor/phy_3d_sensor) diff --git a/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt b/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt new file mode 100644 index 000000000000..69f0b70637c7 --- /dev/null +++ b/subsys/sensing/sensor/phy_3d_sensor/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources(phy_3d_sensor.c) diff --git a/subsys/sensing/sensor/phy_3d_sensor/Kconfig b/subsys/sensing/sensor/phy_3d_sensor/Kconfig new file mode 100644 index 000000000000..3e8ca66bcb0e --- /dev/null +++ b/subsys/sensing/sensor/phy_3d_sensor/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SENSING_SENSOR_PHY_3D_SENSOR + bool "sensing subsystem physical 3d sensors(accel, gyro, mag)" + default y + depends on DT_HAS_ZEPHYR_SENSING_PHY_3D_SENSOR_ENABLED + help + Enable sensing subsystem physical 3d sensors(accel, gyro, mag). diff --git a/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c new file mode 100644 index 000000000000..6ee2131bc3bd --- /dev/null +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_sensing_phy_3d_sensor + +#include +#include +#include +#include +#include +#include +#include + +#include "phy_3d_sensor.h" + +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) +{ + 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; +} + +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; +} + +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) +{ + return 0; +} + +static int phy_3d_sensor_get_sensitivity(const struct device *dev, + int index, uint32_t *value) +{ + 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 sensing_sensor_register_info phy_3d_sensor_reg = { + .flags = SENSING_SENSOR_FLAG_REPORT_ON_CHANGE, + .sample_size = sizeof(struct sensing_sensor_value_3d_q31), + .sensitivity_count = PHY_3D_SENSOR_CHANNEL_NUM, + .version.value = SENSING_SENSOR_VERSION(0, 8, 0, 0), +}; + +#define SENSING_PHY_3D_SENSOR_DT_DEFINE(_inst) \ + static struct phy_3d_sensor_context _CONCAT(ctx, _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), \ + &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 new file mode 100644 index 000000000000..966a6f088c33 --- /dev/null +++ b/subsys/sensing/sensor/phy_3d_sensor/phy_3d_sensor.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SPHY_3D_SENSOR_H_ +#define ZEPHYR_INCLUDE_SPHY_3D_SENSOR_H_ + +#include + +#define PHY_3D_SENSOR_CHANNEL_NUM 3 + +struct phy_3d_sensor_context { + const struct device *dev; + const struct device *hw_dev; + const int32_t sensor_type; +}; + +#endif From 335278d60a19428ae9556395a5e45570eed2fb9f Mon Sep 17 00:00:00 2001 From: Guangfu Hu Date: Fri, 19 May 2023 10:26:13 +0800 Subject: [PATCH 0225/2042] sensing: initial sensor list and enumerate each sensor Implement sensing_init(): 1) create sensors from device tree 2) sequence sensors following node dependency ordering rule generated by Zephyr DTS 3) initial each sensor, includes: a) creating sensor connection between reporter and client, b) calling sensor init callback, c) setting sensor state Implement sensing_open_sensor(): 1) malloc connection from reporter to application 2) bind connection Implement sensing_close_sensr(): 1) unbind connection 2) free connection from reporter to application Implement sensing_set_config(): 1) call set_interval 2) cann set_sensitivity Implement sensing_get_config(): 1) call get_interval 2) call get_sensitivity Signed-off-by: Guangfu Hu --- cmake/linker_script/common/common-ram.cmake | 4 + cmake/linker_script/common/common-rom.cmake | 4 + include/zephyr/linker/common-ram.ld | 4 + .../linker/common-rom/common-rom-misc.ld | 4 + subsys/sensing/Kconfig | 12 + subsys/sensing/sensing.c | 110 ++++++- subsys/sensing/sensor_mgmt.c | 293 +++++++++++++++++- subsys/sensing/sensor_mgmt.h | 143 ++++++++- 8 files changed, 561 insertions(+), 13 deletions(-) diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index 27461cc1c5ce..b625ac9daa58 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -54,6 +54,10 @@ if(CONFIG_NETWORKING) zephyr_iterable_section(NAME eth_bridge GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() +if(CONFIG_SENSING) + zephyr_iterable_section(NAME sensing_sensor GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +endif() + if(CONFIG_UART_MUX) zephyr_iterable_section(NAME uart_mux GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index ed9f3fe7c8c3..811a681a8c2f 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -136,6 +136,10 @@ if(CONFIG_SETTINGS) zephyr_iterable_section(NAME settings_handler_static KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) endif() +if(CONFIG_SENSING) + zephyr_iterable_section(NAME sensing_sensor_info KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) +endif() + if(CONFIG_SENSOR_INFO) zephyr_iterable_section(NAME sensor_info 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 b4f67293610d..a29839306309 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -120,6 +120,10 @@ ITERABLE_SECTION_RAM(rtio_cqe_pool, 4) #endif /* CONFIG_RTIO */ +#if defined(CONFIG_SENSING) + ITERABLE_SECTION_RAM(sensing_sensor, 4) +#endif /* CONFIG_SENSING */ + #ifdef CONFIG_USERSPACE _static_kernel_objects_end = .; #endif diff --git a/include/zephyr/linker/common-rom/common-rom-misc.ld b/include/zephyr/linker/common-rom/common-rom-misc.ld index 51d4865fa3ab..35c6f011305d 100644 --- a/include/zephyr/linker/common-rom/common-rom-misc.ld +++ b/include/zephyr/linker/common-rom/common-rom-misc.ld @@ -10,6 +10,10 @@ ITERABLE_SECTION_ROM(settings_handler_static, 4) #endif +#if defined(CONFIG_SENSING) + ITERABLE_SECTION_ROM(sensing_sensor_info, 4) +#endif + #if defined(CONFIG_SENSOR_INFO) ITERABLE_SECTION_ROM(sensor_info, 4) #endif diff --git a/subsys/sensing/Kconfig b/subsys/sensing/Kconfig index 64423297e424..9101db074457 100644 --- a/subsys/sensing/Kconfig +++ b/subsys/sensing/Kconfig @@ -14,4 +14,16 @@ module = SENSING module-str = sensing source "subsys/logging/Kconfig.template.log_config" +config SENSING_MAX_SENSITIVITY_COUNT + int "maximum sensitivity count one sensor could support" + depends on SENSING + default 6 + help + This is the maximum sensitivity count one sensor could support, + some sensors such as ALS sensor could define different sensitivity for each data filed, + So, maximum sensitivity count is needed for sensors + Typical values are 6 + +source "subsys/sensing/sensor/phy_3d_sensor/Kconfig" + endif # SENSING diff --git a/subsys/sensing/sensing.c b/subsys/sensing/sensing.c index 4a73df5a993b..607492543792 100644 --- a/subsys/sensing/sensing.c +++ b/subsys/sensing/sensing.c @@ -6,46 +6,140 @@ #include #include +#include +#include "sensor_mgmt.h" #include 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 *info, +int sensing_open_sensor(const struct sensing_sensor_info *sensor_info, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) { - return -ENOTSUP; + int ret = 0; + + if (handle == NULL) { + return -ENODEV; + } + + STRUCT_SECTION_FOREACH(sensing_sensor, sensor) { + if (sensor_info == sensor->info) { + ret = open_sensor(sensor, (struct sensing_connection **)handle); + if (ret) { + return -EINVAL; + } + break; + } + } + + return sensing_register_callback(*handle, cb_list); } int sensing_open_sensor_by_dt(const struct device *dev, const struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle) { - return -ENOTSUP; + int ret = 0; + struct sensing_sensor *sensor; + + if (handle == NULL) { + return -ENODEV; + } + + sensor = get_sensor_by_dev(dev); + if (sensor == NULL) { + LOG_ERR("cannot get sensor from dev:%p", dev); + return -ENODEV; + } + + ret = open_sensor(sensor, (struct sensing_connection **)handle); + if (ret) { + return -EINVAL; + } + + return sensing_register_callback(*handle, cb_list); } /* sensing_close_sensor is normally called by applications: hid, chre, zephyr main, etc */ -int sensing_close_sensor(sensing_sensor_handle_t handle) +int sensing_close_sensor(sensing_sensor_handle_t *handle) { - return -ENOTSUP; + return close_sensor((struct sensing_connection **)handle); } int sensing_set_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *configs, int count) { - return -ENOTSUP; + struct sensing_sensor_config *cfg; + int i, ret = 0; + + if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { + LOG_ERR("invalid config count:%d", count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + cfg = &configs[i]; + switch (cfg->attri) { + case SENSING_SENSOR_ATTRIBUTE_INTERVAL: + ret |= set_interval(handle, cfg->interval); + break; + + case SENSING_SENSOR_ATTRIBUTE_SENSITIVITY: + ret |= set_sensitivity(handle, cfg->data_field, cfg->sensitivity); + break; + + case SENSING_SENSOR_ATTRIBUTE_LATENCY: + break; + + default: + ret = -EINVAL; + LOG_ERR("invalid config attribute:%d\n", cfg->attri); + break; + } + } + + return ret; } int sensing_get_config(sensing_sensor_handle_t handle, struct sensing_sensor_config *configs, int count) { - return -ENOTSUP; + struct sensing_sensor_config *cfg; + int i, ret = 0; + + if (count <= 0 || count > SENSING_SENSOR_ATTRIBUTE_MAX) { + LOG_ERR("invalid config count:%d", count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + cfg = &configs[i]; + switch (cfg->attri) { + case SENSING_SENSOR_ATTRIBUTE_INTERVAL: + ret |= get_interval(handle, &cfg->interval); + break; + + case SENSING_SENSOR_ATTRIBUTE_SENSITIVITY: + ret |= get_sensitivity(handle, cfg->data_field, &cfg->sensitivity); + break; + + case SENSING_SENSOR_ATTRIBUTE_LATENCY: + break; + + default: + ret = -EINVAL; + LOG_ERR("invalid config attribute:%d\n", cfg->attri); + break; + } + } + + return ret; } const struct sensing_sensor_info *sensing_get_sensor_info(sensing_sensor_handle_t handle) { - return NULL; + return get_sensor_info(handle); } diff --git a/subsys/sensing/sensor_mgmt.c b/subsys/sensing/sensor_mgmt.c index 019750a1f104..9ecde551a02a 100644 --- a/subsys/sensing/sensor_mgmt.c +++ b/subsys/sensing/sensor_mgmt.c @@ -15,18 +15,309 @@ #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); -static struct sensing_mgmt_context sensing_ctx = {0}; +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"); + + sensor->state = state; + + return 0; +} + +static void init_connection(struct sensing_connection *conn, + struct sensing_sensor *source, + struct sensing_sensor *sink) +{ + __ASSERT(conn, "init each connection, invalid connection"); + + conn->source = source; + 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); +} + +static int init_sensor(struct sensing_sensor *sensor, int conns_num) +{ + 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"); + + 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); + + 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); + } + + 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("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) +{ + struct sensing_context *ctx = &sensing_ctx; + struct sensing_sensor *sensor; + 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); + if (ret) { + LOG_ERR("sensor:%s initial error", sensor->dev->name); + } + state = (ret ? SENSING_SENSOR_STATE_OFFLINE : SENSING_SENSOR_STATE_READY); + ret = set_sensor_state(sensor, state); + 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); + } + + return ret; +} + +int open_sensor(struct sensing_sensor *sensor, struct sensing_connection **conn) +{ + struct sensing_connection *tmp_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); + 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; + + return 0; +} + +int close_sensor(struct sensing_connection **conn) +{ + struct sensing_connection *tmp_conn = *conn; + + if (tmp_conn == NULL) { + LOG_ERR("connection should not be NULL"); + return -EINVAL; + } + + __ASSERT(!tmp_conn->sink, "sensor derived from device tree cannot be closed"); + + sys_slist_find_and_remove(&tmp_conn->source->client_list, &tmp_conn->snode); + + *conn = NULL; + free(*conn); + + return 0; +} + +int sensing_register_callback(struct sensing_connection *conn, + const struct sensing_callback_list *cb_list) +{ + if (conn == NULL) { + LOG_ERR("register sensing callback list, connection not be NULL"); + return -ENODEV; + } + + __ASSERT(!conn->sink, "only connection to application could register sensing callback"); + + if (cb_list == NULL) { + LOG_ERR("callback should not be NULL"); + return -ENODEV; + } + conn->data_evt_cb = cb_list->on_data_event; + + return 0; +} + +int set_interval(struct sensing_connection *conn, uint32_t interval) +{ + return -ENOTSUP; +} + +int get_interval(struct sensing_connection *conn, uint32_t *interval) +{ + return -ENOTSUP; +} + +int set_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t sensitivity) +{ + return -ENOTSUP; +} + +int get_sensitivity(struct sensing_connection *conn, int8_t index, uint32_t *sensitivity) { return -ENOTSUP; } int sensing_get_sensors(int *sensor_nums, const struct sensing_sensor_info **info) { + if (info == NULL) { + LOG_ERR("sensing_sensor_info should not be NULL"); + return -ENODEV; + } + + STRUCT_SECTION_COUNT(sensing_sensor_info, sensor_nums); + + STRUCT_SECTION_GET(sensing_sensor_info, 0, info); + return 0; } + SYS_INIT(sensing_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/sensing/sensor_mgmt.h b/subsys/sensing/sensor_mgmt.h index c37989c8e4d4..38219305304d 100644 --- a/subsys/sensing/sensor_mgmt.h +++ b/subsys/sensing/sensor_mgmt.h @@ -9,16 +9,151 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { #endif -struct sensing_mgmt_context { - bool sensing_initialized; - int sensor_num; - struct sensing_sensor_info *info; +#define PHANDLE_DEVICE_BY_IDX(idx, node, prop) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node, prop, idx)) + +#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) \ + 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; +}; + +/** + * @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_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[]; }; + +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); +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); +int get_sensitivity(struct sensing_connection *con, int8_t index, uint32_t *sensitivity); + + +static inline bool is_phy_sensor(struct sensing_sensor *sensor) +{ + return sensor->reporter_num == 0; +} + +static inline uint16_t get_reporter_sample_size(const struct sensing_sensor *sensor, int i) +{ + __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; +} + +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; +} + +static inline struct sensing_sensor *get_reporter_sensor(struct sensing_sensor *sensor, int index) +{ + if (!sensor || index >= sensor->reporter_num) { + return NULL; + } + + return get_sensor_by_dev(sensor->reporters[index]); +} + +static inline const struct sensing_sensor_info *get_sensor_info(struct sensing_connection *conn) +{ + __ASSERT(conn, "get sensor info, connection not be NULL"); + + __ASSERT(conn->source, "get sensor info, sensing_sensor is NULL"); + + return conn->source->info; +} + /** * @} */ From 518cfe02a3e2c8b1a9e3862dcd454393fcc0cb98 Mon Sep 17 00:00:00 2001 From: Guangfu Hu Date: Fri, 19 May 2023 10:28:56 +0800 Subject: [PATCH 0226/2042] samples: sensing: add a simple sensing subsystem app Add a simple sensing subsystem application. Signed-off-by: Guangfu Hu --- samples/subsys/sensing/sensing.rst | 10 +++ samples/subsys/sensing/simple/CMakeLists.txt | 8 ++ samples/subsys/sensing/simple/README.rst | 38 +++++++++ samples/subsys/sensing/simple/app.overlay | 19 +++++ .../sensing/simple/boards/native_posix.conf | 5 ++ .../simple/boards/native_posix.overlay | 45 +++++++++++ samples/subsys/sensing/simple/prj.conf | 1 + samples/subsys/sensing/simple/sample.yaml | 16 ++++ samples/subsys/sensing/simple/src/main.c | 79 +++++++++++++++++++ 9 files changed, 221 insertions(+) create mode 100644 samples/subsys/sensing/sensing.rst create mode 100644 samples/subsys/sensing/simple/CMakeLists.txt create mode 100644 samples/subsys/sensing/simple/README.rst create mode 100644 samples/subsys/sensing/simple/app.overlay create mode 100644 samples/subsys/sensing/simple/boards/native_posix.conf create mode 100644 samples/subsys/sensing/simple/boards/native_posix.overlay create mode 100644 samples/subsys/sensing/simple/prj.conf create mode 100644 samples/subsys/sensing/simple/sample.yaml create mode 100644 samples/subsys/sensing/simple/src/main.c diff --git a/samples/subsys/sensing/sensing.rst b/samples/subsys/sensing/sensing.rst new file mode 100644 index 000000000000..99fdf509c082 --- /dev/null +++ b/samples/subsys/sensing/sensing.rst @@ -0,0 +1,10 @@ +.. _sensing-subsystem-samples: + +Sensing Subsystem Samples +######################### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/samples/subsys/sensing/simple/CMakeLists.txt b/samples/subsys/sensing/simple/CMakeLists.txt new file mode 100644 index 000000000000..4f35ea3e3420 --- /dev/null +++ b/samples/subsys/sensing/simple/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(sensing) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/subsys/sensing/simple/README.rst b/samples/subsys/sensing/simple/README.rst new file mode 100644 index 000000000000..11a72341fcb4 --- /dev/null +++ b/samples/subsys/sensing/simple/README.rst @@ -0,0 +1,38 @@ +.. _sensing subsytem-sample: + +Sensing subsystem sample +######################## + +Overview +******** + +A simple sample that shows how to use the sensors with sensing subsystem APIs. It defines +two sensors, with the underlying device bmi160 emulator, and gets the sensor +data in defined interval. + +The program runs in the following sequence: + +#. Define the sensor in the dts + +#. Open the sensor + +#. Register call back. + +#. Set sample interval + +#. Run forever and get the sensor data. + +Building and Running +******************** + +This application can be built and executed on native_posix as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/sensing/simple + :host-os: unix + :board: native_posix + :goals: run + :compact: + +To build for another board, change "native_posix" above to that board's name. +At the current stage, it only support native posix diff --git a/samples/subsys/sensing/simple/app.overlay b/samples/subsys/sensing/simple/app.overlay new file mode 100644 index 000000000000..f9892f42a56a --- /dev/null +++ b/samples/subsys/sensing/simple/app.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for testing the devicetree.h API. + * + * 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. + */ + + +/ { + sensing: sensing-node { + compatible = "zephyr,sensing"; + status = "okay"; + }; +}; diff --git a/samples/subsys/sensing/simple/boards/native_posix.conf b/samples/subsys/sensing/simple/boards/native_posix.conf new file mode 100644 index 000000000000..b5a8eb94dc8e --- /dev/null +++ b/samples/subsys/sensing/simple/boards/native_posix.conf @@ -0,0 +1,5 @@ +#Enable BMI160 and BMI160 Emulator +CONFIG_BMI160_TRIGGER_NONE=y +CONFIG_EMUL_BMI160=y +CONFIG_SENSOR=y +CONFIG_SENSOR_INFO=y diff --git a/samples/subsys/sensing/simple/boards/native_posix.overlay b/samples/subsys/sensing/simple/boards/native_posix.overlay new file mode 100644 index 000000000000..d11630cd5d98 --- /dev/null +++ b/samples/subsys/sensing/simple/boards/native_posix.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c0 { + bmi160_i2c: bmi@68 { + compatible = "bosch,bmi160"; + reg = <0x68>; + }; +}; + +&spi0 { + bmi160_spi: bmi@3 { + compatible = "bosch,bmi160"; + spi-max-frequency = <50000000>; + reg = <0x3>; + }; +}; + +/ { + sensing: sensing-node { + compatible = "zephyr,sensing"; + status = "okay"; + + base_accel: base-accel { + compatible = "zephyr,sensing-phy-3d-sensor"; + status = "okay"; + sensor-type = <0x73>; + friendly-name = "Base Accelerometer Sensor"; + minimal-interval = <625>; + underlying-device = <&bmi160_i2c>; + }; + + lid_accel: lid-accel { + compatible = "zephyr,sensing-phy-3d-sensor"; + status = "okay"; + sensor-type = <0x73>; + friendly-name = "Lid Accelerometer Sensor"; + minimal-interval = <625>; + underlying-device = <&bmi160_spi>; + }; + }; +}; diff --git a/samples/subsys/sensing/simple/prj.conf b/samples/subsys/sensing/simple/prj.conf new file mode 100644 index 000000000000..1e935e973c76 --- /dev/null +++ b/samples/subsys/sensing/simple/prj.conf @@ -0,0 +1 @@ +CONFIG_LOG=y diff --git a/samples/subsys/sensing/simple/sample.yaml b/samples/subsys/sensing/simple/sample.yaml new file mode 100644 index 000000000000..b930aff274be --- /dev/null +++ b/samples/subsys/sensing/simple/sample.yaml @@ -0,0 +1,16 @@ +sample: + description: A sensor framework sample + name: sensing sample +common: + tags: sensing + integration_platforms: + - native_posix + harness: console + harness_config: + type: multi_line + regex: + - "sensing subsystem run successfully" +tests: + sample.subsys.sensing.simple: + platform_allow: native_posix + tags: sensing diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c new file mode 100644 index 000000000000..bc1b3bb8b916 --- /dev/null +++ b/samples/subsys/sensing/simple/src/main.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); + +static void acc_data_event_callback(sensing_sensor_handle_t handle, const void *buf) +{ + 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; + + LOG_INF("%s(%d), handle:%p, Sensor:%s data:(x:%d, y:%d, z:%d)", + __func__, __LINE__, handle, info->name, + sample->readings[0].x, + sample->readings[0].y, + sample->readings[0].z); +} + +void 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_sensor_info *info; + sensing_sensor_handle_t base_acc; + sensing_sensor_handle_t lid_acc; + int ret, i, num = 0; + + ret = sensing_get_sensors(&num, &info); + if (ret) { + LOG_ERR("sensing_get_sensors error"); + return; + } + + for (i = 0; i < num; ++i) { + LOG_INF("Sensor %d: name: %s friendly_name: %s type: %d", + i, + info[i].name, + info[i].friendly_name, + info[i].type); + } + + LOG_INF("sensing subsystem run successfully"); + + ret = sensing_open_sensor(&info[0], &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, type:0x%x index:1 error:%d", + SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); + } + + ret = sensing_close_sensor(&base_acc); + if (ret) { + LOG_ERR("sensing_close_sensor:%p error:%d", base_acc, ret); + } + + ret = sensing_close_sensor(&lid_acc); + if (ret) { + LOG_ERR("sensing_close_sensor:%p error:%d", lid_acc, ret); + } +} From b2c74320427b2db2a0cba12a3649de72ca0a4a99 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Fri, 24 Feb 2023 15:48:02 +0800 Subject: [PATCH 0227/2042] MAINTAINERS: Add maintainer and collaborator for Sensing Subsystem Add lixuzha, ghu0510, qianruh as maintainer and collaborators for the Sensing Subsystem. Signed-off-by: Zhang Lixu --- MAINTAINERS.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index bf4ea3f57866..7bafdc0be0e1 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2004,6 +2004,24 @@ Retention: labels: - "area: Retention" +Sensor Subsystem: + status: maintained + maintainers: + - lixuzha + - ghu0510 + - yperess + collaborators: + - qianruh + files: + - dts/bindings/sensor/zephyr,sensing.yaml + - dts/bindings/sensor/zephyr,sensing*.yaml + - include/zephyr/sensing/ + - doc/services/sensing/ + - subsys/sensing/ + - samples/subsys/sensing/ + labels: + - "area: Sensor Subsystem" + Twister: status: maintained maintainers: From 2378d45604218a431112b12d238b9b7467e660b2 Mon Sep 17 00:00:00 2001 From: Zhang Lixu Date: Tue, 11 Apr 2023 13:04:49 +0800 Subject: [PATCH 0228/2042] CODEOWNERS: Add code owners for Sensing Subsystem Add lixuzha, ghu0510, qianruh for the Sensor Subsystem. Signed-off-by: Zhang Lixu --- CODEOWNERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 21fbd5e0b106..176da459cc0b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -210,6 +210,7 @@ /doc/develop/tools/coccinelle.rst @himanshujha199640 @JuliaLawall /doc/services/device_mgmt/smp_protocol.rst @de-nordic @nordicjm /doc/services/device_mgmt/smp_groups/ @de-nordic @nordicjm +/doc/services/sensing/ @lixuzha @ghu0510 @qianruh /doc/CMakeLists.txt @carlescufi /doc/_scripts/ @carlescufi /doc/connectivity/bluetooth/ @alwa-nordic @jhedberg @Vudentz @@ -575,6 +576,8 @@ /dts/bindings/sensor/*bme680* @BoschSensortec /dts/bindings/sensor/*ina23* @bbilas /dts/bindings/sensor/st* @avisconti +/dts/bindings/sensor/zephyr,sensing.yaml @lixuzha @ghu0510 @qianruh +/dts/bindings/sensor/zephyr,sensing*.yaml @lixuzha @ghu0510 @qianruh /dts/bindings/smbus/ @finikorg /dts/bindings/sip_svc/ @maheshraotm /dts/bindings/cpu/intel,niosv.yaml @sweeaun @@ -671,6 +674,7 @@ /include/zephyr/pm/pm.h @nashif @ceolin /include/zephyr/drivers/ptp_clock.h @tbursztyka /include/zephyr/rtio/ @teburd +/include/zephyr/sensing/ @lixuzha @ghu0510 @qianruh /include/zephyr/shared_irq.h @dcpleung @nashif @andyross /include/zephyr/shell/ @jakub-uC @nordic-krch /include/zephyr/shell/shell_mqtt.h @ycsin @@ -694,6 +698,7 @@ /lib/posix/ @cfriedt /lib/posix/getopt/ @jakub-uC /subsys/portability/ @nashif +/subsys/sensing/ @lixuzha @ghu0510 @qianruh /lib/libc/ @nashif /lib/libc/arcmwdt/ @abrodkin @ruuddw @evgeniy-paltsev /misc/ @tejlmand @@ -740,6 +745,7 @@ /samples/subsys/usb/ @jfischer-no /samples/subsys/usb_c/ @sambhurst /samples/subsys/pm/ @nashif @ceolin +/samples/subsys/sensing/ @lixuzha @ghu0510 @qianruh /samples/tfm_integration/ @microbuilder /samples/userspace/ @dcpleung @nashif /scripts/release/bug_bash.py @cfriedt From b64cfe98325e95865a618a234428ae839d43806b Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 26 May 2023 13:23:35 +0100 Subject: [PATCH 0229/2042] ARC: MWDT: rework GNU helper tools usage As of today MWDT toolchain in case of Zephyr may use few tools from GNU toolchain - GNU compiler for DTS preprocessing and objcopy for section renaming. Currently we were trying to find any GNU compiler & objcopy which start to cause compatibility issues for new targets - i.e. not every objcopy knows new ARC targets. Let's use ARC GNU tools from Zephyr SDK as we still usually require it when building with MWDT for other tools like DTC (device tree compiler) Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- cmake/bintools/arcmwdt/target.cmake | 14 ++------------ cmake/compiler/arcmwdt/generic.cmake | 17 ++--------------- cmake/modules/FindZephyr-sdk.cmake | 3 ++- cmake/toolchain/arcmwdt/generic.cmake | 12 ++++++++++++ 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/cmake/bintools/arcmwdt/target.cmake b/cmake/bintools/arcmwdt/target.cmake index a093049f4951..ea4617718301 100644 --- a/cmake/bintools/arcmwdt/target.cmake +++ b/cmake/bintools/arcmwdt/target.cmake @@ -22,17 +22,7 @@ find_program(CMAKE_GDB ${CROSS_COMPILE}mdb PATHS ${TOOLCHAIN_HOME} NO_DE # MWDT binutils don't support required features like section renaming, so we # temporarily had to use GNU objcopy instead -find_program(CMAKE_OBJCOPY arc-elf32-objcopy) -if (NOT CMAKE_OBJCOPY) - find_program(CMAKE_OBJCOPY arc-linux-objcopy) -endif() - -if (NOT CMAKE_OBJCOPY) - find_program(CMAKE_OBJCOPY objcopy) -endif() - -if(NOT CMAKE_OBJCOPY) - message(FATAL_ERROR "Zephyr unable to find any GNU objcopy (ARC or host one)") -endif() +find_program(CMAKE_OBJCOPY ${ZEPHYR_SDK_CROSS_COMPILE}objcopy PATHS ${ZEPHYR_SDK_INSTALL_DIR} NO_DEFAULT_PATH) +message(STATUS "Found GNU objcopy helper for MWDT: ${CMAKE_OBJCOPY} (Zephyr SDK ${SDK_VERSION})") include(${ZEPHYR_BASE}/cmake/bintools/arcmwdt/target_bintools.cmake) diff --git a/cmake/compiler/arcmwdt/generic.cmake b/cmake/compiler/arcmwdt/generic.cmake index c98169e6b20c..c7ab586b3f3b 100644 --- a/cmake/compiler/arcmwdt/generic.cmake +++ b/cmake/compiler/arcmwdt/generic.cmake @@ -2,21 +2,8 @@ # Configures CMake for using ccac -# MWDT compiler (CCAC) can't be used for preprocessing the DTS sources as it has -# weird restrictions about file extensions. Synopsys Jira issue: P10019563-38578 -# Let's temporarily use GNU compiler instead. -find_program(CMAKE_DTS_PREPROCESSOR arc-elf32-gcc) -if (NOT CMAKE_DTS_PREPROCESSOR) - find_program(CMAKE_DTS_PREPROCESSOR arc-linux-gcc) -endif() - -if (NOT CMAKE_DTS_PREPROCESSOR) - find_program(CMAKE_DTS_PREPROCESSOR gcc) -endif() - -if(NOT CMAKE_DTS_PREPROCESSOR) - message(FATAL_ERROR "Zephyr was unable to find any GNU compiler (ARC or host one) for DTS preprocessing") -endif() +find_program(CMAKE_DTS_PREPROCESSOR ${ZEPHYR_SDK_CROSS_COMPILE}gcc PATHS ${ZEPHYR_SDK_INSTALL_DIR} NO_DEFAULT_PATH) +message(STATUS "Found dts preprocessor: ${CMAKE_DTS_PREPROCESSOR} (Zephyr SDK ${SDK_VERSION})") find_program(CMAKE_C_COMPILER ${CROSS_COMPILE}ccac PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_LLVM_COV ${CROSS_COMPILE}llvm-cov PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) diff --git a/cmake/modules/FindZephyr-sdk.cmake b/cmake/modules/FindZephyr-sdk.cmake index bf5b243e91a5..dae75f262d87 100644 --- a/cmake/modules/FindZephyr-sdk.cmake +++ b/cmake/modules/FindZephyr-sdk.cmake @@ -34,7 +34,8 @@ zephyr_get(ZEPHYR_SDK_INSTALL_DIR) # Until we completely deprecate it if(("zephyr" STREQUAL ${ZEPHYR_TOOLCHAIN_VARIANT}) OR (NOT DEFINED ZEPHYR_TOOLCHAIN_VARIANT) OR - (DEFINED ZEPHYR_SDK_INSTALL_DIR)) + (DEFINED ZEPHYR_SDK_INSTALL_DIR) OR + (Zephyr-sdk_FIND_REQUIRED)) # No toolchain was specified, so inform user that we will be searching. if (NOT DEFINED ZEPHYR_SDK_INSTALL_DIR AND diff --git a/cmake/toolchain/arcmwdt/generic.cmake b/cmake/toolchain/arcmwdt/generic.cmake index f7e98d89129f..ddd517770a2a 100644 --- a/cmake/toolchain/arcmwdt/generic.cmake +++ b/cmake/toolchain/arcmwdt/generic.cmake @@ -17,6 +17,18 @@ if(NOT EXISTS ${ARCMWDT_TOOLCHAIN_PATH}) message(FATAL_ERROR "Nothing found at ARCMWDT_TOOLCHAIN_PATH: '${ARCMWDT_TOOLCHAIN_PATH}'") endif() +# arcmwdt relies on Zephyr SDK for the use of C preprocessor (devicetree) and objcopy +find_package(Zephyr-sdk 0.15 REQUIRED) +# Handling to be improved in Zephyr SDK, we can drop setting TOOLCHAIN_HOME after +# https://github.com/zephyrproject-rtos/sdk-ng/pull/682 got merged and we switch to proper SDK +# version. +set(TOOLCHAIN_HOME ${ZEPHYR_SDK_INSTALL_DIR}) +include(${ZEPHYR_SDK_INSTALL_DIR}/cmake/zephyr/target.cmake) +set(ZEPHYR_SDK_CROSS_COMPILE ${CROSS_COMPILE}) +# Handling to be improved in Zephyr SDK, to avoid overriding ZEPHYR_TOOLCHAIN_VARIANT by +# find_package(Zephyr-sdk) if it's already set +set(ZEPHYR_TOOLCHAIN_VARIANT arcmwdt) + set(TOOLCHAIN_HOME ${ARCMWDT_TOOLCHAIN_PATH}/MetaWare) set(COMPILER arcmwdt) From 252d68ff9f5d155cc4eda331d414d35b2edb4e7e Mon Sep 17 00:00:00 2001 From: Dino Li Date: Tue, 23 May 2023 11:55:43 +0800 Subject: [PATCH 0230/2042] arch/riscv: add support for detecting null pointer exception using PMP This change uses a PMP slot to implement null pointer detection. Signed-off-by: Dino Li --- arch/riscv/Kconfig | 21 +++++++++++++++++++++ arch/riscv/core/pmp.c | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 7e3eb9679570..20faced0ca8a 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -261,6 +261,27 @@ config PMP_STACK_GUARD_MIN_SIZE wiggle room to accommodate the eventual overflow exception stack usage. +# Implement the null pointer detection using the Physical Memory Protection +# (PMP) Unit. +config NULL_POINTER_EXCEPTION_DETECTION_PMP + bool "Use PMP for null pointer exception detection" + depends on RISCV_PMP + help + Null pointer dereference detection implemented + using PMP functionality. + +if NULL_POINTER_EXCEPTION_DETECTION_PMP + +config NULL_POINTER_EXCEPTION_REGION_SIZE + hex "Inaccessible region to implement null pointer detection" + default 0x10 + help + Use a PMP slot to make region (starting at address 0x0) inaccessible for + detecting null pointer dereferencing (raising a CPU access fault). + Minimum is 4 bytes. + +endif # NULL_POINTER_EXCEPTION_DETECTION_PMP + endmenu config MAIN_STACK_SIZE diff --git a/arch/riscv/core/pmp.c b/arch/riscv/core/pmp.c index 7fbf1fa533f6..b8ddd1c3203e 100644 --- a/arch/riscv/core/pmp.c +++ b/arch/riscv/core/pmp.c @@ -330,6 +330,17 @@ void z_riscv_pmp_init(void) (size_t)__rom_region_size, pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr)); +#ifdef CONFIG_NULL_POINTER_EXCEPTION_DETECTION_PMP + /* + * Use a PMP slot to make region (starting at address 0x0) inaccessible + * for detecting null pointer dereferencing. + */ + set_pmp_entry(&index, PMP_NONE | PMP_L, + 0, + CONFIG_NULL_POINTER_EXCEPTION_REGION_SIZE, + pmp_addr, pmp_cfg, ARRAY_SIZE(pmp_addr)); +#endif + #ifdef CONFIG_PMP_STACK_GUARD /* * Set the stack guard for this CPU's IRQ stack by making the bottom From 29895d827595cce0ca104afbcd87f77410342824 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Fri, 21 Apr 2023 12:49:14 +0200 Subject: [PATCH 0231/2042] Bluetooth: Mesh: refactor mesh to use both tinycrypt and psa based crypto A mesh key type has been added to be able to choose the different key representation for different security libraries. The type as well as some functionality related to Mesh key management has been added as a public API. If tynicrypt is chosen then keys have representation as 16 bytes array. If mbedTLS with PSA is used then keys are the PSA key id. Raw value is not kept within BLE Mesh stack for mbedTLS. Keys are imported into the security library and key ids are gotten back. This refactoring has been done for the network(including all derivated keys), application, device, and session keys. Signed-off-by: Aleksandr Khromykh --- include/zephyr/bluetooth/mesh.h | 1 + include/zephyr/bluetooth/mesh/cdb.h | 98 ++++- include/zephyr/bluetooth/mesh/keys.h | 47 +++ modules/mbedtls/CMakeLists.txt | 2 +- modules/mbedtls/configs/config-tls-generic.h | 8 + samples/bluetooth/mesh_provisioner/src/main.c | 29 +- subsys/bluetooth/mesh/Kconfig | 16 + subsys/bluetooth/mesh/app_keys.c | 91 +++-- subsys/bluetooth/mesh/app_keys.h | 6 +- subsys/bluetooth/mesh/beacon.c | 17 +- subsys/bluetooth/mesh/cdb.c | 126 +++++-- subsys/bluetooth/mesh/crypto.c | 186 ++++++---- subsys/bluetooth/mesh/crypto.h | 64 ++-- subsys/bluetooth/mesh/crypto_psa.c | 334 ++++++++++++------ subsys/bluetooth/mesh/crypto_tc.c | 26 +- subsys/bluetooth/mesh/friend.c | 14 +- subsys/bluetooth/mesh/keys.h | 54 +++ subsys/bluetooth/mesh/lpn.c | 19 +- subsys/bluetooth/mesh/main.c | 80 ++++- subsys/bluetooth/mesh/net.c | 38 +- subsys/bluetooth/mesh/net.h | 8 +- subsys/bluetooth/mesh/prov_device.c | 32 +- subsys/bluetooth/mesh/provisioner.c | 44 ++- subsys/bluetooth/mesh/proxy_srv.c | 2 +- subsys/bluetooth/mesh/rpr_srv.c | 1 + subsys/bluetooth/mesh/settings.c | 1 + subsys/bluetooth/mesh/shell/cfg.c | 28 +- subsys/bluetooth/mesh/shell/shell.c | 69 ++-- subsys/bluetooth/mesh/subnet.c | 133 +++++-- subsys/bluetooth/mesh/subnet.h | 26 +- subsys/bluetooth/mesh/transport.c | 6 +- subsys/bluetooth/mesh/transport_legacy.c | 6 +- tests/bluetooth/mesh/rpl/CMakeLists.txt | 3 +- tests/bsim/bluetooth/mesh/CMakeLists.txt | 6 + .../bluetooth/mesh/src/distribute_keyid.c | 82 +++++ .../bluetooth/mesh/src/distribute_keyid.h | 17 + tests/bsim/bluetooth/mesh/src/mesh_test.c | 13 + tests/bsim/bluetooth/mesh/src/mesh_test.h | 2 + tests/bsim/bluetooth/mesh/src/test_beacon.c | 34 +- tests/bsim/bluetooth/mesh/src/test_blob.c | 5 +- tests/bsim/bluetooth/mesh/src/test_dfu.c | 17 +- tests/bsim/bluetooth/mesh/src/test_lcd.c | 7 +- .../bluetooth/mesh/src/test_persistence.c | 34 +- .../bsim/bluetooth/mesh/src/test_provision.c | 57 +-- .../bluetooth/mesh/src/test_replay_cache.c | 11 +- tests/bsim/bluetooth/mesh/src/test_sar.c | 7 +- 46 files changed, 1386 insertions(+), 521 deletions(-) create mode 100644 include/zephyr/bluetooth/mesh/keys.h create mode 100644 subsys/bluetooth/mesh/keys.h create mode 100644 tests/bsim/bluetooth/mesh/src/distribute_keyid.c create mode 100644 tests/bsim/bluetooth/mesh/src/distribute_keyid.h diff --git a/include/zephyr/bluetooth/mesh.h b/include/zephyr/bluetooth/mesh.h index 8eadaa56bb48..eeea9e4bccaa 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include diff --git a/include/zephyr/bluetooth/mesh/cdb.h b/include/zephyr/bluetooth/mesh/cdb.h index f202a4f6904d..800ae07edc49 100644 --- a/include/zephyr/bluetooth/mesh/cdb.h +++ b/include/zephyr/bluetooth/mesh/cdb.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -36,7 +37,7 @@ struct bt_mesh_cdb_node { uint16_t addr; uint16_t net_idx; uint8_t num_elem; - uint8_t dev_key[16]; + struct bt_mesh_key dev_key; ATOMIC_DEFINE(flags, BT_MESH_CDB_NODE_FLAG_COUNT); }; @@ -47,7 +48,7 @@ struct bt_mesh_cdb_subnet { uint8_t kr_phase; struct { - uint8_t net_key[16]; + struct bt_mesh_key net_key; } keys[2]; }; @@ -56,7 +57,7 @@ struct bt_mesh_cdb_app_key { uint16_t app_idx; struct { - uint8_t app_key[16]; + struct bt_mesh_key app_key; } keys[2]; }; @@ -189,6 +190,32 @@ struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr); */ void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node); +/** @brief Import device key for selected node. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to import the key. + * + * @param node Selected node. + * @param in key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_node_key_import(struct bt_mesh_cdb_node *node, const uint8_t in[16]); + +/** @brief Export device key from selected node. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to export the key. + * + * @param node Selected node. + * @param out key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_node_key_export(const struct bt_mesh_cdb_node *node, uint8_t out[16]); + enum { BT_MESH_CDB_ITER_STOP = 0, BT_MESH_CDB_ITER_CONTINUE, @@ -260,6 +287,39 @@ void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub); */ uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub); +/** @brief Import network key for selected subnetwork. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to import the key. + * + * @param sub Selected subnetwork. + * @param key_idx 0 or 1. If Key Refresh procedure is in progress then two keys are available. + * The old key has an index 0 and the new one has an index 1. + * Otherwise, the only key with index 0 exists. + * @param in key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_subnet_key_import(struct bt_mesh_cdb_subnet *sub, int key_idx, + const uint8_t in[16]); + +/** @brief Export network key from selected subnetwork. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to export the key. + * + * @param sub Selected subnetwork. + * @param key_idx 0 or 1. If Key Refresh procedure is in progress then two keys are available. + * The old key has an index 0 and the new one has an index 1. + * Otherwise, the only key with index 0 exists. + * @param out key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_subnet_key_export(const struct bt_mesh_cdb_subnet *sub, int key_idx, + uint8_t out[16]); /** @brief Allocate an application key. * @@ -299,6 +359,38 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx); */ void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key); +/** @brief Import application key. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to import the key. + * + * @param key cdb application key structure. + * @param key_idx 0 or 1. If Key Refresh procedure is in progress then two keys are available. + * The old key has an index 0 and the new one has an index 1. + * Otherwise, the only key with index 0 exists. + * @param in key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_app_key_import(struct bt_mesh_cdb_app_key *key, int key_idx, const uint8_t in[16]); + +/** @brief Export application key. + * + * Using security library with PSA implementation access to the key by pointer + * will not give a valid value since the key is hidden in the library. + * The application has to export the key. + * + * @param key cdb application key structure. + * @param key_idx 0 or 1. If Key Refresh procedure is in progress then two keys are available. + * The old key has an index 0 and the new one has an index 1. + * Otherwise, the only key with index 0 exists. + * @param out key value. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_cdb_app_key_export(const struct bt_mesh_cdb_app_key *key, int key_idx, uint8_t out[16]); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/mesh/keys.h b/include/zephyr/bluetooth/mesh/keys.h new file mode 100644 index 000000000000..db2a2ca45a93 --- /dev/null +++ b/include/zephyr/bluetooth/mesh/keys.h @@ -0,0 +1,47 @@ +/** @file + * @brief Keys APIs. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_KEYS_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_KEYS_H_ + +#include +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA + +/** The structure that keeps representation of key. */ +struct bt_mesh_key { + /** PSA key representation is the PSA key identifier. */ + psa_key_id_t key; +}; + +#elif defined CONFIG_BT_MESH_USES_TINYCRYPT + +/** The structure that keeps representation of key. */ +struct bt_mesh_key { + /** tinycrypt key representation is the pure key value. */ + uint8_t key[16]; +}; + +#else +#error "Crypto library has not been chosen" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_KEYS_H_ */ diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index 09017a5b83e8..aee2f78bd110 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -107,7 +107,7 @@ zephyr_interface_library_named(mbedTLS) zephyr_library_named(mbedTLSCrypto) - if (MBEDTLS_USE_PSA_CRYPTO) + if (CONFIG_MBEDTLS_PSA_CRYPTO_C) list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_aead.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.c diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index b95d0f1f0f13..52a5bb2fd16c 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -458,6 +458,14 @@ #if defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) #define MBEDTLS_PSA_CRYPTO_C #define MBEDTLS_USE_PSA_CRYPTO + +#if defined(CONFIG_BOARD_NRF52_BSIM) || defined(CONFIG_BOARD_NATIVE_POSIX) +#define MBEDTLS_PSA_KEY_SLOT_COUNT 64 +#define MBEDTLS_PSA_CRYPTO_STORAGE_C +#define MBEDTLS_PSA_ITS_FILE_C +#define MBEDTLS_FS_IO +#endif + #endif #if defined(CONFIG_MBEDTLS_TLS_VERSION_1_2) && defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) diff --git a/samples/bluetooth/mesh_provisioner/src/main.c b/samples/bluetooth/mesh_provisioner/src/main.c index dd313e83b110..a605679596e4 100644 --- a/samples/bluetooth/mesh_provisioner/src/main.c +++ b/samples/bluetooth/mesh_provisioner/src/main.c @@ -72,6 +72,8 @@ static const struct bt_mesh_comp comp = { static void setup_cdb(void) { struct bt_mesh_cdb_app_key *key; + uint8_t app_key[16]; + int err; key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx); if (key == NULL) { @@ -79,7 +81,13 @@ static void setup_cdb(void) return; } - bt_rand(key->keys[0].app_key, 16); + bt_rand(app_key, 16); + + err = bt_mesh_cdb_app_key_import(key, 0, app_key); + if (err) { + printk("Failed to import appkey into cdb. Err:%d\n", err); + return; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_app_key_store(key); @@ -89,6 +97,7 @@ static void setup_cdb(void) static void configure_self(struct bt_mesh_cdb_node *self) { struct bt_mesh_cdb_app_key *key; + uint8_t app_key[16]; uint8_t status = 0; int err; @@ -100,9 +109,15 @@ static void configure_self(struct bt_mesh_cdb_node *self) return; } + err = bt_mesh_cdb_app_key_export(key, 0, app_key); + if (err) { + printk("Failed to export appkey from cdb. Err:%d\n", err); + return; + } + /* Add Application Key */ err = bt_mesh_cfg_cli_app_key_add(self->net_idx, self->addr, self->net_idx, app_idx, - key->keys[0].app_key, &status); + app_key, &status); if (err || status) { printk("Failed to add app-key (err %d, status %d)\n", err, status); @@ -131,6 +146,7 @@ static void configure_node(struct bt_mesh_cdb_node *node) NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_RX_SDU_MAX); struct bt_mesh_comp_p0_elem elem; struct bt_mesh_cdb_app_key *key; + uint8_t app_key[16]; struct bt_mesh_comp_p0 comp; uint8_t status; int err, elem_addr; @@ -143,9 +159,14 @@ static void configure_node(struct bt_mesh_cdb_node *node) return; } + err = bt_mesh_cdb_app_key_export(key, 0, app_key); + if (err) { + printk("Failed to export appkey from cdb. Err:%d\n", err); + return; + } + /* Add Application Key */ - err = bt_mesh_cfg_cli_app_key_add(net_idx, node->addr, net_idx, app_idx, - key->keys[0].app_key, &status); + err = bt_mesh_cfg_cli_app_key_add(net_idx, node->addr, net_idx, app_idx, app_key, &status); if (err || status) { printk("Failed to add app-key (err %d status %d)\n", err, status); return; diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 94888dbb31a2..84683871c4ee 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -55,6 +55,22 @@ config BT_MESH_USES_MBEDTLS_PSA endchoice +if BT_MESH_USES_MBEDTLS_PSA + +config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET + int "Offset of BLE Mesh key id range regarding PSA_KEY_ID_USER_MIN" + default 0 + help + The PSA specification mandates to set key identifiers for keys + with persistent lifetime. The users of the PSA API is responsible + (BLE Mesh is user of PSA API) to provide correct and unique identifiers. + The BLE Mesh identifier range should be between PSA_KEY_ID_USER_MIN and + PSA_KEY_ID_USER_MAX. BLE Mesh requires two ids for each subnetwork, two ids + for each application key, and two ids for the device key and device key candidate. + It should consider the Mesh Configuration Database instances if database enabled. + +endif # BT_MESH_USES_MBEDTLS_PSA + # Virtual option enabled whenever Generic Provisioning layer is needed config BT_MESH_PROV bool diff --git a/subsys/bluetooth/mesh/app_keys.c b/subsys/bluetooth/mesh/app_keys.c index f7a6045742e9..64677a3386e8 100644 --- a/subsys/bluetooth/mesh/app_keys.c +++ b/subsys/bluetooth/mesh/app_keys.c @@ -43,8 +43,8 @@ struct app_key_update { /* AppKey information for persistent storage. */ struct app_key_val { uint16_t net_idx; - bool updated; - uint8_t val[2][16]; + bool updated; + struct bt_mesh_key val[2]; } __packed; /** Mesh Application Key. */ @@ -54,7 +54,7 @@ struct app_key { bool updated; struct bt_mesh_app_cred { uint8_t id; - uint8_t val[16]; + struct bt_mesh_key val; } keys[2]; }; @@ -110,8 +110,8 @@ static void store_app_key(uint16_t app_idx) key.net_idx = app->net_idx, key.updated = app->updated, - memcpy(key.val[0], app->keys[0].val, 16); - memcpy(key.val[1], app->keys[1].val, 16); + memcpy(&key.val[0], &app->keys[0].val, sizeof(struct bt_mesh_key)); + memcpy(&key.val[1], &app->keys[1].val, sizeof(struct bt_mesh_key)); err = settings_save_one(path, &key, sizeof(key)); if (err) { @@ -214,7 +214,9 @@ static void app_key_del(struct app_key *app) app->net_idx = BT_MESH_KEY_UNUSED; app->app_idx = BT_MESH_KEY_UNUSED; - (void)memset(app->keys, 0, sizeof(app->keys)); + bt_mesh_key_destroy(&app->keys[0].val); + bt_mesh_key_destroy(&app->keys[1].val); + memset(app->keys, 0, sizeof(app->keys)); } static void app_key_revoke(struct app_key *app) @@ -223,6 +225,7 @@ static void app_key_revoke(struct app_key *app) return; } + bt_mesh_key_destroy(&app->keys[0].val); memcpy(&app->keys[0], &app->keys[1], sizeof(app->keys[0])); memset(&app->keys[1], 0, sizeof(app->keys[1])); app->updated = false; @@ -255,7 +258,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, return STATUS_INVALID_NETKEY; } - if (memcmp(key, app->keys[0].val, 16)) { + if (bt_mesh_key_compare(key, &app->keys[0].val)) { return STATUS_IDX_ALREADY_STORED; } @@ -271,7 +274,10 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, app->net_idx = net_idx; app->app_idx = app_idx; app->updated = false; - memcpy(app->keys[0].val, key, 16); + if (bt_mesh_key_import(BT_MESH_KEY_TYPE_APP, key, &app->keys[0].val)) { + LOG_ERR("Unable to import application key"); + return STATUS_CANNOT_SET; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { LOG_DBG("Storing AppKey persistently"); @@ -315,7 +321,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, } if (app->updated) { - if (memcmp(app->keys[1].val, key, 16)) { + if (bt_mesh_key_compare(key, &app->keys[1].val)) { return STATUS_IDX_ALREADY_STORED; } @@ -329,7 +335,10 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, LOG_DBG("app_idx 0x%04x AID 0x%02x", app_idx, app->keys[1].id); app->updated = true; - memcpy(app->keys[1].val, key, 16); + if (bt_mesh_key_import(BT_MESH_KEY_TYPE_APP, key, &app->keys[1].val)) { + LOG_ERR("Unable to import application key"); + return STATUS_CANNOT_UPDATE; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { LOG_DBG("Storing AppKey persistently"); @@ -368,8 +377,28 @@ uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) return STATUS_SUCCESS; } +static int app_id_set(struct app_key *app, int key_idx, const struct bt_mesh_key *key) +{ + uint8_t raw_key[16]; + int err; + + err = bt_mesh_key_export(raw_key, key); + if (err) { + return err; + } + + err = bt_mesh_app_id(raw_key, &app->keys[key_idx].id); + if (err) { + return err; + } + + bt_mesh_key_assign(&app->keys[key_idx].val, key); + + return 0; +} + int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, - const uint8_t old_key[16], const uint8_t new_key[16]) + const struct bt_mesh_key *old_key, const struct bt_mesh_key *new_key) { struct app_key *app; @@ -384,16 +413,12 @@ int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, LOG_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id); - memcpy(app->keys[0].val, old_key, 16); - if (bt_mesh_app_id(old_key, &app->keys[0].id)) { + if (app_id_set(app, 0, old_key)) { return -EIO; } - if (new_key) { - memcpy(app->keys[1].val, new_key, 16); - if (bt_mesh_app_id(new_key, &app->keys[1].id)) { - return -EIO; - } + if (new_key != NULL && app_id_set(app, 1, new_key)) { + return -EIO; } app->net_idx = net_idx; @@ -447,7 +472,7 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t **app_key, uint8_t *aid) + const struct bt_mesh_key **app_key, uint8_t *aid) { struct app_key *app = NULL; @@ -476,9 +501,9 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, return -EINVAL; } - *app_key = node->dev_key; + *app_key = &node->dev_key; } else { - *app_key = bt_mesh.dev_key; + *app_key = &bt_mesh.dev_key; } *aid = 0; @@ -499,10 +524,10 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, if ((*sub)->kr_phase == BT_MESH_KR_PHASE_2 && app->updated) { *aid = app->keys[1].id; - *app_key = app->keys[1].val; + *app_key = &app->keys[1].val; } else { *aid = app->keys[0].id; - *app_key = app->keys[0].val; + *app_key = &app->keys[0].val; } return 0; @@ -511,7 +536,7 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, struct bt_mesh_net_rx *rx, int (*cb)(struct bt_mesh_net_rx *rx, - const uint8_t key[16], void *cb_data), + const struct bt_mesh_key *key, void *cb_data), void *cb_data) { int err, i; @@ -526,7 +551,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, struct bt_mesh_cdb_node *node; node = bt_mesh_cdb_node_get(rx->ctx.addr); - if (node && !cb(rx, node->dev_key, cb_data)) { + if (node && !cb(rx, &node->dev_key, cb_data)) { return BT_MESH_KEY_DEV_REMOTE; } } @@ -535,14 +560,14 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, * The Device key is only valid for unicast addresses. */ if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - err = cb(rx, bt_mesh.dev_key, cb_data); + err = cb(rx, &bt_mesh.dev_key, cb_data); if (!err) { return BT_MESH_KEY_DEV_LOCAL; } #if defined(CONFIG_BT_MESH_RPR_SRV) if (atomic_test_bit(bt_mesh.flags, BT_MESH_DEVKEY_CAND)) { - err = cb(rx, bt_mesh.dev_key_cand, cb_data); + err = cb(rx, &bt_mesh.dev_key_cand, cb_data); if (!err) { /* Bluetooth Mesh Specification v1.1.0, section 3.6.4.2: * If a message is successfully decrypted using the device @@ -581,7 +606,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, continue; } - err = cb(rx, cred->val, cb_data); + err = cb(rx, &cred->val, cb_data); if (err) { continue; } @@ -638,6 +663,7 @@ static int app_key_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { struct app_key_val key; + struct bt_mesh_key val[2]; uint16_t app_idx; int err; @@ -657,8 +683,13 @@ static int app_key_set(const char *name, size_t len_rd, return -EINVAL; } - err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], - key.updated ? key.val[1] : NULL); + /* One extra copying since key.val array is from packed structure + * and might be unaligned. + */ + memcpy(val, key.val, sizeof(key.val)); + + err = bt_mesh_app_key_set(app_idx, key.net_idx, &val[0], + key.updated ? &val[1] : NULL); if (err) { LOG_ERR("Failed to set \'app-key\'"); return err; diff --git a/subsys/bluetooth/mesh/app_keys.h b/subsys/bluetooth/mesh/app_keys.h index d64958341f76..480445377cfa 100644 --- a/subsys/bluetooth/mesh/app_keys.h +++ b/subsys/bluetooth/mesh/app_keys.h @@ -23,7 +23,7 @@ void bt_mesh_app_keys_reset(void); * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, - const uint8_t old_key[16], const uint8_t new_key[16]); + const struct bt_mesh_key *old_key, const struct bt_mesh_key *new_key); /** @brief Resolve the message encryption keys, given a message context. * @@ -41,7 +41,7 @@ int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, */ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t **app_key, uint8_t *aid); + const struct bt_mesh_key **app_key, uint8_t *aid); /** @brief Iterate through all matching application keys and call @c cb on each. * @@ -56,7 +56,7 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, struct bt_mesh_net_rx *rx, int (*cb)(struct bt_mesh_net_rx *rx, - const uint8_t key[16], void *cb_data), + const struct bt_mesh_key *key, void *cb_data), void *cb_data); /** @brief Store pending application keys in persistent storage. */ diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index d972c578e2b3..94e1c3e774fe 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -184,10 +184,11 @@ static int private_beacon_update(struct bt_mesh_subnet *sub) uint8_t flags = bt_mesh_net_flags(sub); int err; - err = bt_mesh_beacon_encrypt(keys->priv_beacon, flags, bt_mesh.iv_index, + err = bt_mesh_beacon_encrypt(&keys->priv_beacon, flags, bt_mesh.iv_index, priv_random.val, sub->priv_beacon_ctx.data, sub->priv_beacon.auth); if (err) { + LOG_ERR("Can't encrypt private beacon"); return err; } @@ -483,12 +484,14 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, return false; } - bt_mesh_beacon_auth(keys->beacon, params->flags, keys->net_id, - params->iv_index, net_auth); + if (bt_mesh_beacon_auth(&keys->beacon, params->flags, keys->net_id, params->iv_index, + net_auth)) { + return false; + } if (memcmp(params->auth, net_auth, 8)) { - LOG_WRN("Authentication Value %s != %s", bt_hex(params->auth, 8), - bt_hex(net_auth, 8)); + LOG_WRN("Invalid auth value. Received auth: %s", bt_hex(params->auth, 8)); + LOG_WRN("Calculated auth: %s", bt_hex(net_auth, 8)); return false; } @@ -536,7 +539,7 @@ static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data) continue; } - err = bt_mesh_beacon_decrypt(sub->keys[i].priv_beacon, params->random, + err = bt_mesh_beacon_decrypt(&sub->keys[i].priv_beacon, params->random, params->data, params->auth, out); if (!err) { params->new_key = (i > 0); @@ -722,7 +725,7 @@ void bt_mesh_beacon_update(struct bt_mesh_subnet *sub) priv_random.timestamp = 0; #endif - bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index, + bt_mesh_beacon_auth(&keys->beacon, flags, keys->net_id, bt_mesh.iv_index, sub->secure_beacon.auth); } diff --git a/subsys/bluetooth/mesh/cdb.c b/subsys/bluetooth/mesh/cdb.c index 8b40ec033a4e..2735c2697981 100644 --- a/subsys/bluetooth/mesh/cdb.c +++ b/subsys/bluetooth/mesh/cdb.c @@ -19,6 +19,7 @@ #include "net.h" #include "rpl.h" #include "settings.h" +#include "keys.h" #define LOG_LEVEL CONFIG_BT_MESH_CDB_LOG_LEVEL #include @@ -45,25 +46,25 @@ struct node_update { /* Node information for persistent storage. */ struct node_val { uint16_t net_idx; - uint8_t num_elem; - uint8_t flags; + uint8_t num_elem; + uint8_t flags; #define F_NODE_CONFIGURED 0x01 - uint8_t uuid[16]; - uint8_t dev_key[16]; + uint8_t uuid[16]; + struct bt_mesh_key dev_key; } __packed; /* NetKey storage information */ struct net_key_val { uint8_t kr_flag:1, kr_phase:7; - uint8_t val[2][16]; + struct bt_mesh_key val[2]; } __packed; /* AppKey information for persistent storage. */ struct app_key_val { uint16_t net_idx; - bool updated; - uint8_t val[2][16]; + bool updated; + struct bt_mesh_key val[2]; } __packed; /* Network information for persistent storage. */ @@ -213,6 +214,7 @@ static int cdb_node_set(const char *name, size_t len_rd, { struct bt_mesh_cdb_node *node; struct node_val val; + struct bt_mesh_key tmp; uint16_t addr; int err; @@ -257,7 +259,12 @@ static int cdb_node_set(const char *name, size_t len_rd, } memcpy(node->uuid, val.uuid, 16); - memcpy(node->dev_key, val.dev_key, 16); + + /* One extra copying since val.dev_key is from packed structure + * and might be unaligned. + */ + memcpy(&tmp, &val.dev_key, sizeof(struct bt_mesh_key)); + bt_mesh_key_assign(&node->dev_key, &tmp); LOG_DBG("Node 0x%04x recovered from storage", addr); @@ -269,6 +276,7 @@ static int cdb_subnet_set(const char *name, size_t len_rd, { struct bt_mesh_cdb_subnet *sub; struct net_key_val key; + struct bt_mesh_key tmp[2]; uint16_t net_idx; int err; @@ -298,12 +306,18 @@ static int cdb_subnet_set(const char *name, size_t len_rd, return err; } + /* One extra copying since key.val[] is from packed structure + * and might be unaligned. + */ + memcpy(&tmp[0], &key.val[0], sizeof(struct bt_mesh_key)); + memcpy(&tmp[1], &key.val[1], sizeof(struct bt_mesh_key)); + if (sub) { LOG_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); + bt_mesh_key_assign(&sub->keys[0].net_key, &tmp[0]); + bt_mesh_key_assign(&sub->keys[1].net_key, &tmp[1]); return 0; } @@ -315,8 +329,8 @@ static int cdb_subnet_set(const char *name, size_t len_rd, } sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); + bt_mesh_key_assign(&sub->keys[0].net_key, &tmp[0]); + bt_mesh_key_assign(&sub->keys[1].net_key, &tmp[1]); LOG_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); @@ -328,6 +342,7 @@ static int cdb_app_key_set(const char *name, size_t len_rd, { struct bt_mesh_cdb_app_key *app; struct app_key_val key; + struct bt_mesh_key tmp[2]; uint16_t app_idx; int err; @@ -356,6 +371,12 @@ static int cdb_app_key_set(const char *name, size_t len_rd, return err; } + /* One extra copying since key.val[] is from packed structure + * and might be unaligned. + */ + memcpy(&tmp[0], &key.val[0], sizeof(struct bt_mesh_key)); + memcpy(&tmp[1], &key.val[1], sizeof(struct bt_mesh_key)); + app = bt_mesh_cdb_app_key_get(app_idx); if (!app) { app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); @@ -366,8 +387,8 @@ static int cdb_app_key_set(const char *name, size_t len_rd, return -ENOMEM; } - memcpy(app->keys[0].app_key, key.val[0], 16); - memcpy(app->keys[1].app_key, key.val[1], 16); + bt_mesh_key_assign(&app->keys[0].app_key, &tmp[0]); + bt_mesh_key_assign(&app->keys[1].app_key, &tmp[1]); LOG_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); @@ -430,7 +451,7 @@ static void store_cdb_node(const struct bt_mesh_cdb_node *node) } memcpy(val.uuid, node->uuid, 16); - memcpy(val.dev_key, node->dev_key, 16); + memcpy(&val.dev_key, &node->dev_key, sizeof(struct bt_mesh_key)); snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", node->addr); @@ -464,10 +485,11 @@ static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) char path[30]; int err; - LOG_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, bt_hex(sub->keys[0].net_key, 16)); + LOG_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, + bt_hex(&sub->keys[0].net_key, sizeof(struct bt_mesh_key))); - memcpy(&key.val[0], sub->keys[0].net_key, 16); - memcpy(&key.val[1], sub->keys[1].net_key, 16); + memcpy(&key.val[0], &sub->keys[0].net_key, sizeof(struct bt_mesh_key)); + memcpy(&key.val[1], &sub->keys[1].net_key, sizeof(struct bt_mesh_key)); key.kr_flag = 0U; /* Deprecated */ key.kr_phase = sub->kr_phase; @@ -505,8 +527,8 @@ static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) key.net_idx = app->net_idx; key.updated = false; - memcpy(key.val[0], app->keys[0].app_key, 16); - memcpy(key.val[1], app->keys[1].app_key, 16); + memcpy(&key.val[0], &app->keys[0].app_key, sizeof(struct bt_mesh_key)); + memcpy(&key.val[1], &app->keys[1].app_key, sizeof(struct bt_mesh_key)); snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx); @@ -709,6 +731,7 @@ static uint16_t addr_assign(uint16_t addr, uint8_t num_elem) int bt_mesh_cdb_create(const uint8_t key[16]) { struct bt_mesh_cdb_subnet *sub; + int err; if (atomic_test_and_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { @@ -720,7 +743,11 @@ int bt_mesh_cdb_create(const uint8_t key[16]) return -ENOMEM; } - memcpy(sub->keys[0].net_key, key, 16); + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, key, &sub->keys[0].net_key); + if (err) { + return err; + } + bt_mesh_cdb.iv_index = 0; bt_mesh_cdb.lowest_avail_addr = 1; @@ -814,6 +841,8 @@ void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store) } sub->net_idx = BT_MESH_KEY_UNUSED; + bt_mesh_key_destroy(&sub->keys[0].net_key); + bt_mesh_key_destroy(&sub->keys[1].net_key); memset(sub->keys, 0, sizeof(sub->keys)); } @@ -852,6 +881,24 @@ uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub) return flags; } +int bt_mesh_cdb_subnet_key_import(struct bt_mesh_cdb_subnet *sub, int key_idx, + const uint8_t in[16]) +{ + if (!bt_mesh_key_compare(in, &sub->keys[key_idx].net_key)) { + return 0; + } + + bt_mesh_key_destroy(&sub->keys[key_idx].net_key); + + return bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, in, &sub->keys[key_idx].net_key); +} + +int bt_mesh_cdb_subnet_key_export(const struct bt_mesh_cdb_subnet *sub, int key_idx, + uint8_t out[16]) +{ + return bt_mesh_key_export(out, &sub->keys[key_idx].net_key); +} + struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr, uint8_t num_elem, uint16_t net_idx) { @@ -900,7 +947,8 @@ void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store) } node->addr = BT_MESH_ADDR_UNASSIGNED; - memset(node->dev_key, 0, sizeof(node->dev_key)); + bt_mesh_key_destroy(&node->dev_key); + memset(&node->dev_key, 0, sizeof(node->dev_key)); } void bt_mesh_cdb_node_update(struct bt_mesh_cdb_node *node, uint16_t addr, @@ -960,6 +1008,22 @@ void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data) } } +int bt_mesh_cdb_node_key_import(struct bt_mesh_cdb_node *node, const uint8_t in[16]) +{ + if (!bt_mesh_key_compare(in, &node->dev_key)) { + return 0; + } + + bt_mesh_key_destroy(&node->dev_key); + + return bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, in, &node->dev_key); +} + +int bt_mesh_cdb_node_key_export(const struct bt_mesh_cdb_node *node, uint8_t out[16]) +{ + return bt_mesh_key_export(out, &node->dev_key); +} + struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx, uint16_t app_idx) { @@ -991,6 +1055,8 @@ void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store) } key->net_idx = BT_MESH_KEY_UNUSED; + bt_mesh_key_destroy(&key->keys[0].app_key); + bt_mesh_key_destroy(&key->keys[1].app_key); memset(key->keys, 0, sizeof(key->keys)); } @@ -1017,6 +1083,22 @@ void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key) } } +int bt_mesh_cdb_app_key_import(struct bt_mesh_cdb_app_key *key, int key_idx, const uint8_t in[16]) +{ + if (!bt_mesh_key_compare(in, &key->keys[key_idx].app_key)) { + return 0; + } + + bt_mesh_key_destroy(&key->keys[key_idx].app_key); + + return bt_mesh_key_import(BT_MESH_KEY_TYPE_APP, in, &key->keys[key_idx].app_key); +} + +int bt_mesh_cdb_app_key_export(const struct bt_mesh_cdb_app_key *key, int key_idx, uint8_t out[16]) +{ + return bt_mesh_key_export(out, &key->keys[key_idx].app_key); +} + static void clear_cdb_net(void) { int err; diff --git a/subsys/bluetooth/mesh/crypto.c b/subsys/bluetooth/mesh/crypto.c index 2688515e59fc..e42717475c09 100644 --- a/subsys/bluetooth/mesh/crypto.c +++ b/subsys/bluetooth/mesh/crypto.c @@ -23,33 +23,42 @@ LOG_MODULE_REGISTER(bt_mesh_crypto); #define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) -static int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m, size_t len, uint8_t mac[16]) +static int bt_mesh_aes_cmac_one_raw_key(const uint8_t key[16], const void *m, + size_t len, uint8_t mac[16]) { - struct bt_mesh_sg sg = {m, len}; + struct bt_mesh_sg sg = {.data = m, .len = len}; - return bt_mesh_aes_cmac(key, &sg, 1, mac); + return bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); } -static int bt_mesh_sha256_hmac_one(const uint8_t key[32], const void *m, size_t len, +static int bt_mesh_aes_cmac_one_mesh_key(const struct bt_mesh_key *key, const void *m, + size_t len, uint8_t mac[16]) +{ + struct bt_mesh_sg sg = {.data = m, .len = len}; + + return bt_mesh_aes_cmac_mesh_key(key, &sg, 1, mac); +} + +static int bt_mesh_sha256_hmac_one_raw_key(const uint8_t key[32], const void *m, size_t len, uint8_t mac[32]) { - struct bt_mesh_sg sg = {m, len}; + struct bt_mesh_sg sg = {.data = m, .len = len}; - return bt_mesh_sha256_hmac(key, &sg, 1, mac); + return bt_mesh_sha256_hmac_raw_key(key, &sg, 1, mac); } int bt_mesh_s1(const char *m, size_t m_len, uint8_t salt[16]) { const uint8_t zero[16] = { 0 }; - return bt_mesh_aes_cmac_one(zero, m, m_len, salt); + return bt_mesh_aes_cmac_one_raw_key(zero, m, m_len, salt); } int bt_mesh_s2(const char *m, size_t m_len, uint8_t salt[32]) { const uint8_t zero[32] = { 0 }; - return bt_mesh_sha256_hmac_one(zero, m, m_len, salt); + return bt_mesh_sha256_hmac_one_raw_key(zero, m, m_len, salt); } int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], @@ -57,16 +66,16 @@ int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], { int err; - err = bt_mesh_aes_cmac_one(salt, ikm, ikm_len, okm); + err = bt_mesh_aes_cmac_one_raw_key(salt, ikm, ikm_len, okm); if (err < 0) { return err; } - return bt_mesh_aes_cmac_one(okm, info, strlen(info), okm); + return bt_mesh_aes_cmac_one_raw_key(okm, info, strlen(info), okm); } int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, - uint8_t net_id[1], uint8_t enc_key[16], uint8_t priv_key[16]) + uint8_t net_id[1], struct bt_mesh_key *enc_key, struct bt_mesh_key *priv_key) { struct bt_mesh_sg sg[3]; uint8_t salt[16]; @@ -83,7 +92,7 @@ int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, return err; } - err = bt_mesh_aes_cmac_one(salt, n, 16, t); + err = bt_mesh_aes_cmac_one_raw_key(salt, n, 16, t); if (err) { return err; } @@ -97,7 +106,7 @@ int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, sg[2].data = &pad; sg[2].len = sizeof(pad); - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + err = bt_mesh_aes_cmac_raw_key(t, sg, ARRAY_SIZE(sg), out); if (err) { return err; } @@ -108,24 +117,30 @@ int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, sg[0].len = sizeof(out); pad = 0x02; - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + err = bt_mesh_aes_cmac_raw_key(t, sg, ARRAY_SIZE(sg), out); if (err) { return err; } - memcpy(enc_key, out, 16); + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, out, enc_key); + if (err) { + return err; + } pad = 0x03; - err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out); + err = bt_mesh_aes_cmac_raw_key(t, sg, ARRAY_SIZE(sg), out); if (err) { return err; } - memcpy(priv_key, out, 16); + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_ECB, out, priv_key); + if (err) { + return err; + } - LOG_DBG("NID 0x%02x enc_key %s", net_id[0], bt_hex(enc_key, 16)); - LOG_DBG("priv_key %s", bt_hex(priv_key, 16)); + LOG_DBG("NID 0x%02x enc_key %s", net_id[0], bt_hex(enc_key, sizeof(struct bt_mesh_key))); + LOG_DBG("priv_key %s", bt_hex(priv_key, sizeof(struct bt_mesh_key))); return 0; } @@ -142,12 +157,12 @@ int bt_mesh_k3(const uint8_t n[16], uint8_t out[8]) return err; } - err = bt_mesh_aes_cmac_one(tmp, n, 16, t); + err = bt_mesh_aes_cmac_one_raw_key(tmp, n, 16, t); if (err) { return err; } - err = bt_mesh_aes_cmac_one(t, id64, sizeof(id64), tmp); + err = bt_mesh_aes_cmac_one_raw_key(t, id64, sizeof(id64), tmp); if (err) { return err; } @@ -169,12 +184,12 @@ int bt_mesh_k4(const uint8_t n[16], uint8_t out[1]) return err; } - err = bt_mesh_aes_cmac_one(tmp, n, 16, t); + err = bt_mesh_aes_cmac_one_raw_key(tmp, n, 16, t); if (err) { return err; } - err = bt_mesh_aes_cmac_one(t, id6, sizeof(id6), tmp); + err = bt_mesh_aes_cmac_one_raw_key(t, id6, sizeof(id6), tmp); if (err) { return err; } @@ -190,12 +205,12 @@ int bt_mesh_k5(const uint8_t *n, size_t n_len, const uint8_t salt[32], uint8_t t[32]; int err; - err = bt_mesh_sha256_hmac_one(salt, n, n_len, t); + err = bt_mesh_sha256_hmac_one_raw_key(salt, n, n_len, t); if (err) { return err; } - err = bt_mesh_sha256_hmac_one(t, p, strlen(p), out); + err = bt_mesh_sha256_hmac_one_raw_key(t, p, strlen(p), out); if (err) { return err; } @@ -203,10 +218,12 @@ int bt_mesh_k5(const uint8_t *n, size_t n_len, const uint8_t salt[32], return 0; } -int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]) +int bt_mesh_id128(const uint8_t n[16], const char *s, enum bt_mesh_key_type type, + struct bt_mesh_key *out) { const char *id128 = "id128\x01"; uint8_t salt[16]; + uint8_t k1_out[16]; int err; err = bt_mesh_s1_str(s, salt); @@ -214,7 +231,17 @@ int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]) return err; } - return bt_mesh_k1(n, 16, salt, id128, out); + err = bt_mesh_k1(n, 16, salt, id128, k1_out); + if (err) { + return err; + } + + err = bt_mesh_key_import(type, k1_out, out); + if (err) { + return err; + } + + return 0; } int bt_mesh_prov_nonce(const uint8_t dhkey[32], const uint8_t prov_salt[16], uint8_t nonce[13]) @@ -231,14 +258,32 @@ int bt_mesh_prov_nonce(const uint8_t dhkey[32], const uint8_t prov_salt[16], uin } int bt_mesh_session_key(const uint8_t dhkey[32], const uint8_t prov_salt[16], - uint8_t session_key[16]) + struct bt_mesh_key *session_key) { - return bt_mesh_k1(dhkey, 32, prov_salt, "prsk", session_key); + uint8_t raw_key[16]; + int err; + + err = bt_mesh_k1(dhkey, 32, prov_salt, "prsk", raw_key); + + if (!err) { + LOG_DBG("SessionKey: %s", bt_hex(raw_key, 16)); + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, raw_key, session_key); + } + + return err; } int bt_mesh_dev_key(const uint8_t dhkey[32], const uint8_t prov_salt[16], uint8_t dev_key[16]) { - return bt_mesh_k1(dhkey, 32, prov_salt, "prdk", dev_key); + int err; + + err = bt_mesh_k1(dhkey, 32, prov_salt, "prdk", dev_key); + + if (!err) { + LOG_DBG("DevKey: %s", bt_hex(dev_key, 16)); + } + + return err; } static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu, @@ -305,14 +350,14 @@ static void create_net_nonce(uint8_t nonce[13], const uint8_t *pdu, sys_put_be32(iv_index, &nonce[9]); } -int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, - const uint8_t privacy_key[16]) +int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, const struct bt_mesh_key *privacy_key) { uint8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, }; uint8_t tmp[16]; int err, i; - LOG_DBG("IVIndex %u, PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); + LOG_DBG("IVIndex %u, PrivacyKey %s", iv_index, + bt_hex(privacy_key, sizeof(struct bt_mesh_key))); sys_put_be32(iv_index, &priv_rand[5]); memcpy(&priv_rand[9], &pdu[7], 7); @@ -331,14 +376,15 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, return 0; } -int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, +int bt_mesh_net_encrypt(const struct bt_mesh_key *key, struct net_buf_simple *buf, uint32_t iv_index, enum bt_mesh_nonce_type type) { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13]; int err; - LOG_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16), mic_len); + LOG_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, + bt_hex(key, sizeof(struct bt_mesh_key)), mic_len); LOG_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && type == BT_MESH_NONCE_PROXY) { @@ -361,14 +407,15 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, return err; } -int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, +int bt_mesh_net_decrypt(const struct bt_mesh_key *key, struct net_buf_simple *buf, uint32_t iv_index, enum bt_mesh_nonce_type type) { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13]; LOG_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len)); - LOG_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), mic_len); + LOG_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, sizeof(struct bt_mesh_key)), + mic_len); if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && type == BT_MESH_NONCE_PROXY) { create_proxy_nonce(nonce, buf->data, iv_index); @@ -404,14 +451,13 @@ static void create_app_nonce(uint8_t nonce[13], sys_put_be32(ctx->iv_index, &nonce[9]); } -int bt_mesh_app_encrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, +int bt_mesh_app_encrypt(const struct bt_mesh_key *key, const struct bt_mesh_app_crypto_ctx *ctx, struct net_buf_simple *buf) { uint8_t nonce[13]; int err; - LOG_DBG("AppKey %s", bt_hex(key, 16)); + LOG_DBG("AppKey %s", bt_hex(key, sizeof(struct bt_mesh_key))); LOG_DBG("dev_key %u src 0x%04x dst 0x%04x", ctx->dev_key, ctx->src, ctx->dst); LOG_DBG("seq_num 0x%08x iv_index 0x%08x", ctx->seq_num, ctx->iv_index); LOG_DBG("Clear: %s", bt_hex(buf->data, buf->len)); @@ -431,8 +477,7 @@ int bt_mesh_app_encrypt(const uint8_t key[16], return err; } -int bt_mesh_app_decrypt(const uint8_t key[16], - const struct bt_mesh_app_crypto_ctx *ctx, +int bt_mesh_app_decrypt(const struct bt_mesh_key *key, const struct bt_mesh_app_crypto_ctx *ctx, struct net_buf_simple *buf, struct net_buf_simple *out) { uint8_t nonce[13]; @@ -442,7 +487,7 @@ int bt_mesh_app_decrypt(const uint8_t key[16], create_app_nonce(nonce, ctx); - LOG_DBG("AppKey %s", bt_hex(key, 16)); + LOG_DBG("AppKey %s", bt_hex(key, sizeof(struct bt_mesh_key))); LOG_DBG("Nonce %s", bt_hex(nonce, 13)); err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ctx->ad, @@ -535,7 +580,7 @@ int bt_mesh_virtual_addr(const uint8_t virtual_label[16], uint16_t *addr) return err; } - err = bt_mesh_aes_cmac_one(salt, virtual_label, 16, tmp); + err = bt_mesh_aes_cmac_one_raw_key(salt, virtual_label, 16, tmp); if (err) { return err; } @@ -559,7 +604,7 @@ int bt_mesh_prov_salt(uint8_t algorithm, { dev_rand, size }, }; - return bt_mesh_aes_cmac(prov_salt_key, sg, ARRAY_SIZE(sg), prov_salt); + return bt_mesh_aes_cmac_raw_key(prov_salt_key, sg, ARRAY_SIZE(sg), prov_salt); } int bt_mesh_prov_conf_salt(uint8_t algorithm, const uint8_t conf_inputs[145], @@ -610,39 +655,46 @@ int bt_mesh_prov_conf(uint8_t algorithm, const uint8_t *conf_key, if (algorithm == BT_MESH_PROV_AUTH_HMAC_SHA256_AES_CCM && IS_ENABLED(CONFIG_BT_MESH_ECDH_P256_HMAC_SHA256_AES_CCM)) { - return bt_mesh_sha256_hmac_one(conf_key, prov_rand, 32, conf); + return bt_mesh_sha256_hmac_one_raw_key(conf_key, prov_rand, 32, conf); } if (algorithm == BT_MESH_PROV_AUTH_CMAC_AES128_AES_CCM && IS_ENABLED(CONFIG_BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM)) { struct bt_mesh_sg sg[] = { { prov_rand, 16 }, { auth, 16 } }; - return bt_mesh_aes_cmac(conf_key, sg, ARRAY_SIZE(sg), conf); + return bt_mesh_aes_cmac_raw_key(conf_key, sg, ARRAY_SIZE(sg), conf); } return -EINVAL; } -int bt_mesh_prov_decrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25 + 8], uint8_t out[25]) +int bt_mesh_prov_decrypt(struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t data[25 + 8], + uint8_t out[25]) { - return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); + int err; + + err = bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); + + return err; } -int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13], - const uint8_t data[25], uint8_t out[25 + 8]) +int bt_mesh_prov_encrypt(struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t data[25], + uint8_t out[25 + 8]) { - return bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); + int err; + + err = bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); + + return err; } -int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[8], uint32_t iv_index, - uint8_t auth[8]) +int bt_mesh_beacon_auth(const struct bt_mesh_key *beacon_key, uint8_t flags, + const uint8_t net_id[8], uint32_t iv_index, uint8_t auth[8]) { uint8_t msg[13], tmp[16]; int err; - LOG_DBG("BeaconKey %s", bt_hex(beacon_key, 16)); + LOG_DBG("BeaconKey %s", bt_hex(beacon_key, sizeof(struct bt_mesh_key))); LOG_DBG("NetId %s", bt_hex(net_id, 8)); LOG_DBG("IV Index 0x%08x", iv_index); @@ -652,7 +704,7 @@ int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, LOG_DBG("BeaconMsg %s", bt_hex(msg, sizeof(msg))); - err = bt_mesh_aes_cmac_one(beacon_key, msg, sizeof(msg), tmp); + err = bt_mesh_aes_cmac_one_mesh_key(beacon_key, msg, sizeof(msg), tmp); if (!err) { memcpy(auth, tmp, 8); } @@ -660,7 +712,7 @@ int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, return err; } -static int private_beacon_obf(const uint8_t pbk[16], const uint8_t data[5], +static int private_beacon_obf(const struct bt_mesh_key *pbk, const uint8_t data[5], const uint8_t random[13], uint8_t out[5]) { uint8_t salt[16]; @@ -685,7 +737,7 @@ static int private_beacon_obf(const uint8_t pbk[16], const uint8_t data[5], return 0; } -static int private_beacon_auth(const uint8_t pbk[16], +static int private_beacon_auth(const struct bt_mesh_key *pbk, const uint8_t beacon_data[5], const uint8_t random[13], uint8_t auth[8]) { @@ -734,9 +786,8 @@ static int private_beacon_auth(const uint8_t pbk[16], return 0; } -int bt_mesh_beacon_decrypt(const uint8_t pbk[16], const uint8_t random[13], - const uint8_t data[5], - const uint8_t expected_auth[8], uint8_t out[5]) +int bt_mesh_beacon_decrypt(const struct bt_mesh_key *pbk, const uint8_t random[13], + const uint8_t data[5], const uint8_t expected_auth[8], uint8_t out[5]) { uint8_t auth[8]; int err; @@ -756,17 +807,16 @@ int bt_mesh_beacon_decrypt(const uint8_t pbk[16], const uint8_t random[13], LOG_DBG("0x%02x, 0x%08x", out[0], sys_get_be32(&out[1])); if (memcmp(auth, expected_auth, 8)) { - LOG_DBG("Invalid auth: %s expected %s", bt_hex(auth, 8), - bt_hex(expected_auth, 8)); + LOG_DBG("Invalid auth rx: %s", bt_hex(auth, 8)); + LOG_DBG("Expected auth: %s", bt_hex(expected_auth, 8)); return -EBADMSG; } return 0; } -int bt_mesh_beacon_encrypt(const uint8_t pbk[16], uint8_t flags, - uint32_t iv_index, const uint8_t random[13], - uint8_t data[5], uint8_t auth[8]) +int bt_mesh_beacon_encrypt(const struct bt_mesh_key *pbk, uint8_t flags, uint32_t iv_index, + const uint8_t random[13], uint8_t data[5], uint8_t auth[8]) { int err; diff --git a/subsys/bluetooth/mesh/crypto.h b/subsys/bluetooth/mesh/crypto.h index 70eb4fdd24df..1ff3857f1fe0 100644 --- a/subsys/bluetooth/mesh/crypto.h +++ b/subsys/bluetooth/mesh/crypto.h @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "keys.h" + enum bt_mesh_nonce_type { BT_MESH_NONCE_NETWORK, BT_MESH_NONCE_PROXY, @@ -18,19 +20,24 @@ struct bt_mesh_sg { int bt_mesh_crypto_init(void); -int bt_mesh_encrypt(const uint8_t key[16], const uint8_t plaintext[16], uint8_t enc_data[16]); +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]); -int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *plaintext, +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *plaintext, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *enc_data, size_t mic_size); -int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data, +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *enc_data, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *plaintext, size_t mic_size); -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[16]); +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]); + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]); -int bt_mesh_sha256_hmac(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[32]); int bt_mesh_s1(const char *m, size_t m_len, uint8_t salt[16]); @@ -46,7 +53,7 @@ int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16], const uint8_t okm[16]); int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len, uint8_t net_id[1], - uint8_t enc_key[16], uint8_t priv_key[16]); + struct bt_mesh_key *enc_key, struct bt_mesh_key *priv_key); int bt_mesh_k3(const uint8_t n[16], uint8_t out[8]); @@ -54,26 +61,27 @@ int bt_mesh_k4(const uint8_t n[16], uint8_t out[1]); int bt_mesh_k5(const uint8_t *n, size_t n_len, const uint8_t salt[32], uint8_t *p, uint8_t out[32]); -int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]); +int bt_mesh_id128(const uint8_t n[16], const char *s, enum bt_mesh_key_type type, + struct bt_mesh_key *out); -static inline int bt_mesh_identity_key(const uint8_t net_key[16], uint8_t identity_key[16]) +static inline int bt_mesh_identity_key(const uint8_t net_key[16], struct bt_mesh_key *identity_key) { - return bt_mesh_id128(net_key, "nkik", identity_key); + return bt_mesh_id128(net_key, "nkik", BT_MESH_KEY_TYPE_ECB, identity_key); } -static inline int bt_mesh_beacon_key(const uint8_t net_key[16], uint8_t beacon_key[16]) +static inline int bt_mesh_beacon_key(const uint8_t net_key[16], struct bt_mesh_key *beacon_key) { - return bt_mesh_id128(net_key, "nkbk", beacon_key); + return bt_mesh_id128(net_key, "nkbk", BT_MESH_KEY_TYPE_CMAC, beacon_key); } static inline int bt_mesh_private_beacon_key(const uint8_t net_key[16], - uint8_t private_beacon_key[16]) + struct bt_mesh_key *private_beacon_key) { - return bt_mesh_id128(net_key, "nkpk", private_beacon_key); + return bt_mesh_id128(net_key, "nkpk", BT_MESH_KEY_TYPE_ECB, private_beacon_key); } -int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, const uint8_t net_id[8], - uint32_t iv_index, uint8_t auth[8]); +int bt_mesh_beacon_auth(const struct bt_mesh_key *beacon_key, uint8_t flags, + const uint8_t net_id[8], uint32_t iv_index, uint8_t auth[8]); static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) { @@ -81,7 +89,7 @@ static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) } int bt_mesh_session_key(const uint8_t dhkey[32], const uint8_t prov_salt[16], - uint8_t session_key[16]); + struct bt_mesh_key *session_key); int bt_mesh_prov_nonce(const uint8_t dhkey[32], const uint8_t prov_salt[16], uint8_t nonce[13]); @@ -90,13 +98,13 @@ int bt_mesh_dev_key(const uint8_t dhkey[32], const uint8_t prov_salt[16], uint8_ int bt_mesh_prov_salt(uint8_t algorithm, const uint8_t *conf_salt, const uint8_t *prov_rand, const uint8_t *dev_rand, uint8_t *prov_salt); -int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, const uint8_t privacy_key[16]); +int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, const struct bt_mesh_key *privacy_key); -int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, uint32_t iv_index, - enum bt_mesh_nonce_type type); +int bt_mesh_net_encrypt(const struct bt_mesh_key *key, struct net_buf_simple *buf, + uint32_t iv_index, enum bt_mesh_nonce_type type); -int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, uint32_t iv_index, - enum bt_mesh_nonce_type type); +int bt_mesh_net_decrypt(const struct bt_mesh_key *key, struct net_buf_simple *buf, + uint32_t iv_index, enum bt_mesh_nonce_type type); struct bt_mesh_app_crypto_ctx { bool dev_key; @@ -108,10 +116,10 @@ struct bt_mesh_app_crypto_ctx { const uint8_t *ad; }; -int bt_mesh_app_encrypt(const uint8_t key[16], const struct bt_mesh_app_crypto_ctx *ctx, +int bt_mesh_app_encrypt(const struct bt_mesh_key *key, const struct bt_mesh_app_crypto_ctx *ctx, struct net_buf_simple *buf); -int bt_mesh_app_decrypt(const uint8_t key[16], const struct bt_mesh_app_crypto_ctx *ctx, +int bt_mesh_app_decrypt(const struct bt_mesh_key *key, const struct bt_mesh_app_crypto_ctx *ctx, struct net_buf_simple *buf, struct net_buf_simple *out); uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len); @@ -128,10 +136,10 @@ int bt_mesh_prov_conf_key(uint8_t algorithm, const uint8_t *k_input, const uint8 int bt_mesh_prov_conf(uint8_t algorithm, const uint8_t *conf_key, const uint8_t *prov_rand, const uint8_t *auth, uint8_t *conf); -int bt_mesh_prov_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t data[25 + 8], +int bt_mesh_prov_decrypt(struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t data[25 + 8], uint8_t out[25]); -int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t data[25], +int bt_mesh_prov_encrypt(struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t data[25], uint8_t out[25 + 8]); int bt_mesh_pub_key_gen(void); @@ -140,8 +148,8 @@ const uint8_t *bt_mesh_pub_key_get(void); int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t *dhkey); -int bt_mesh_beacon_decrypt(const uint8_t pbk[16], const uint8_t random[13], const uint8_t data[5], - const uint8_t expected_auth[8], uint8_t out[5]); +int bt_mesh_beacon_decrypt(const struct bt_mesh_key *pbk, const uint8_t random[13], + const uint8_t data[5], const uint8_t expected_auth[8], uint8_t out[5]); -int bt_mesh_beacon_encrypt(const uint8_t pbk[16], uint8_t flags, uint32_t iv_index, +int bt_mesh_beacon_encrypt(const struct bt_mesh_key *pbk, uint8_t flags, uint32_t iv_index, const uint8_t random[13], uint8_t data[5], uint8_t auth[8]); diff --git a/subsys/bluetooth/mesh/crypto_psa.c b/subsys/bluetooth/mesh/crypto_psa.c index e2bab6d9eaa9..aea259e4cbff 100644 --- a/subsys/bluetooth/mesh/crypto_psa.c +++ b/subsys/bluetooth/mesh/crypto_psa.c @@ -6,8 +6,6 @@ #include -#include - #include #define LOG_LEVEL CONFIG_BT_MESH_CRYPTO_LOG_LEVEL @@ -18,12 +16,37 @@ LOG_MODULE_REGISTER(bt_mesh_crypto_psa); #include "crypto.h" #include "prov.h" +/* Mesh requires to keep in persistent memory network keys (2 keys per subnetwork), + * application keys (2 real keys per 1 configured) and device key + device key candidate. + */ +#if defined CONFIG_BT_MESH_CDB +#define BT_MESH_CDB_KEY_ID_RANGE_SIZE (2 * SUBNET_COUNT + \ + 2 * APP_KEY_COUNT + NODE_COUNT) +#else +#define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0 +#endif +#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ + 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 2 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) +#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \ + CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET) + +BUILD_ASSERT(BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE <= PSA_KEY_ID_USER_MAX, + "BLE Mesh PSA key id range overlaps maximum allowed boundary."); + +BUILD_ASSERT(PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, PSA_ALG_CMAC) == 16, + "MAC length should be 16 bytes for 128-bits key for CMAC-AES"); + +BUILD_ASSERT(PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 256, PSA_ALG_HMAC(PSA_ALG_SHA_256)) == 32, + "MAC length should be 32 bytes for 256-bits key for HMAC-SHA"); + static struct { bool is_ready; psa_key_id_t priv_key_id; uint8_t public_key_be[PUB_KEY_SIZE + 1]; } key; +static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE); + int bt_mesh_crypto_init(void) { if (psa_crypto_init() != PSA_SUCCESS) { @@ -33,27 +56,14 @@ int bt_mesh_crypto_init(void) return 0; } -int bt_mesh_encrypt(const uint8_t key[16], const uint8_t plaintext[16], uint8_t enc_data[16]) +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) { - psa_key_id_t key_id; uint32_t output_len; psa_status_t status; int err = 0; - psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING); - psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&key_attributes, 128); - - status = psa_import_key(&key_attributes, key, 16, &key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - - status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, + status = psa_cipher_encrypt(key->key, PSA_ALG_ECB_NO_PADDING, plaintext, 16, enc_data, 16, &output_len); @@ -62,41 +72,19 @@ int bt_mesh_encrypt(const uint8_t key[16], const uint8_t plaintext[16], uint8_t err = -EIO; } - psa_reset_key_attributes(&key_attributes); - - status = psa_destroy_key(key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - return err; } -int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *plaintext, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *enc_data, size_t mic_size) { - psa_key_id_t key_id; uint32_t output_len; psa_status_t status; int err = 0; - psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); - psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_algorithm(&key_attributes, alg); - psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&key_attributes, 128); - - status = psa_import_key(&key_attributes, key, 16, &key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - - status = psa_aead_encrypt(key_id, alg, + status = psa_aead_encrypt(key->key, alg, nonce, 13, aad, aad_len, plaintext, len, @@ -107,41 +95,19 @@ int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], err = -EIO; } - psa_reset_key_attributes(&key_attributes); - - status = psa_destroy_key(key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - return err; } -int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *enc_data, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *plaintext, size_t mic_size) { - psa_key_id_t key_id; uint32_t output_len; psa_status_t status; int err = 0; - psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size); - psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); - psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_algorithm(&key_attributes, alg); - psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&key_attributes, 128); - - status = psa_import_key(&key_attributes, key, 16, &key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - - status = psa_aead_decrypt(key_id, alg, + status = psa_aead_decrypt(key->key, alg, nonce, 13, aad, aad_len, enc_data, len + mic_size, @@ -152,82 +118,62 @@ int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], err = -EIO; } - psa_reset_key_attributes(&key_attributes); - - status = psa_destroy_key(key_id); - if (status != PSA_SUCCESS) { - return -EIO; - } - return err; } -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[16]) { psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_algorithm_t alg = PSA_ALG_CMAC; - - psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t key_id; - psa_status_t status; - int err = 0; - - /* Import a key */ - psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE); - psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); - psa_set_key_algorithm(&attributes, PSA_ALG_CMAC); - psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attributes, 128); - status = psa_import_key(&attributes, key, 16, &key_id); + status = psa_mac_sign_setup(&operation, key->key, alg); if (status != PSA_SUCCESS) { - err = -EIO; - goto end; - } - - psa_reset_key_attributes(&attributes); - - status = psa_mac_sign_setup(&operation, key_id, alg); - if (status != PSA_SUCCESS) { - err = -EIO; - goto end; + return -EIO; } for (; sg_len; sg_len--, sg++) { status = psa_mac_update(&operation, sg->data, sg->len); if (status != PSA_SUCCESS) { - err = -EIO; - goto end; + psa_mac_abort(&operation); + return -EIO; } } - if (PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128, alg) > 16) { - err = -ERANGE; - goto end; - } - size_t mac_len; status = psa_mac_sign_finish(&operation, mac, 16, &mac_len); if (status != PSA_SUCCESS) { - err = -EIO; - goto end; + return -EIO; } if (mac_len != 16) { - err = -ERANGE; + return -ERANGE; } -end: - /* Destroy the key */ - psa_destroy_key(key_id); + return 0; +} + +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + struct bt_mesh_key key_id; + int err; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CMAC, key, &key_id); + if (err) { + return err; + } + + err = bt_mesh_aes_cmac_mesh_key(&key_id, sg, sg_len, mac); + + psa_destroy_key(key_id.key); return err; } -int bt_mesh_sha256_hmac(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[32]) { psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; @@ -263,16 +209,12 @@ int bt_mesh_sha256_hmac(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_ for (; sg_len; sg_len--, sg++) { status = psa_mac_update(&operation, sg->data, sg->len); if (status != PSA_SUCCESS) { + psa_mac_abort(&operation); err = -EIO; goto end; } } - if (PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, 256, alg) > 32) { - err = -ERANGE; - goto end; - } - size_t mac_len; status = psa_mac_sign_finish(&operation, mac, 32, &mac_len); @@ -408,3 +350,163 @@ int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t * return err; } + +__weak psa_key_id_t bt_mesh_user_keyid_alloc(void) +{ + for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) { + if (!atomic_test_bit(pst_keys, i)) { + atomic_set_bit(pst_keys, i); + return BT_MESH_PSA_KEY_ID_USER_MIN + i; + } + } + + return PSA_KEY_ID_NULL; +} + +__weak int bt_mesh_user_keyid_free(psa_key_id_t key_id) +{ + if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN, + BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { + atomic_clear_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN); + return 0; + } + + return -EIO; +} + +__weak void bt_mesh_user_keyid_assign(psa_key_id_t key_id) +{ + if (IN_RANGE(key_id, BT_MESH_PSA_KEY_ID_USER_MIN, + BT_MESH_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { + atomic_set_bit(pst_keys, key_id - BT_MESH_PSA_KEY_ID_USER_MIN); + } +} + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], struct bt_mesh_key *out) +{ + psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_status_t status; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + int err = 0; + + switch (type) { + case BT_MESH_KEY_TYPE_ECB: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING); + break; + case BT_MESH_KEY_TYPE_CCM: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + case BT_MESH_KEY_TYPE_CMAC: + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE); + psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC); + break; + case BT_MESH_KEY_TYPE_NET: + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + key_id = bt_mesh_user_keyid_alloc(); + + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); + } else { + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + } + psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT); + break; + case BT_MESH_KEY_TYPE_APP: + case BT_MESH_KEY_TYPE_DEV: + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + key_id = bt_mesh_user_keyid_alloc(); + + if (key_id == PSA_KEY_ID_NULL) { + return -ENOMEM; + } + + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_id(&key_attributes, key_id); + } else { + psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE); + } + psa_set_key_usage_flags(&key_attributes, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&key_attributes, + PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4)); + break; + default: + return -EIO; + } + + psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES); + psa_set_key_bits(&key_attributes, 128); + + status = psa_import_key(&key_attributes, in, 16, &out->key); + err = status == PSA_SUCCESS ? 0 : + status == PSA_ERROR_ALREADY_EXISTS ? -EALREADY : -EIO; + + if (err && key_id != PSA_KEY_ID_NULL) { + bt_mesh_user_keyid_free(key_id); + } + + psa_reset_key_attributes(&key_attributes); + + return err; +} + +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + size_t data_length; + + if (psa_export_key(in->key, out, 16, &data_length) != PSA_SUCCESS) { + return -EIO; + } + + if (data_length != 16) { + return -EIO; + } + + return 0; +} + +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_user_keyid_assign(dst->key); + } +} + +int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + if (psa_destroy_key(key->key) != PSA_SUCCESS) { + return -EIO; + } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + return bt_mesh_user_keyid_free(key->key); + } + + return 0; +} + +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key) +{ + uint8_t out[16]; + int err; + + err = bt_mesh_key_export(out, key); + if (err) { + return err; + } + + return memcmp(out, raw_key, 16); +} diff --git a/subsys/bluetooth/mesh/crypto_tc.c b/subsys/bluetooth/mesh/crypto_tc.c index 83a62c6970fd..0c95f4382fe7 100644 --- a/subsys/bluetooth/mesh/crypto_tc.c +++ b/subsys/bluetooth/mesh/crypto_tc.c @@ -33,26 +33,28 @@ static struct { uint8_t public_key_be[PUB_KEY_SIZE]; } key; -int bt_mesh_encrypt(const uint8_t key[16], const uint8_t plaintext[16], uint8_t enc_data[16]) +int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16], + uint8_t enc_data[16]) { - return bt_encrypt_be(key, plaintext, enc_data); + return bt_encrypt_be(key->key, plaintext, enc_data); } -int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *plaintext, +int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *plaintext, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *enc_data, size_t mic_size) { - return bt_ccm_encrypt(key, nonce, plaintext, len, aad, aad_len, enc_data, mic_size); + return bt_ccm_encrypt(key->key, nonce, plaintext, len, aad, aad_len, enc_data, mic_size); } -int bt_mesh_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data, +int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13], const uint8_t *enc_data, size_t len, const uint8_t *aad, size_t aad_len, uint8_t *plaintext, size_t mic_size) { - return bt_ccm_decrypt(key, nonce, enc_data, len, aad, aad_len, plaintext, mic_size); + return bt_ccm_decrypt(key->key, nonce, enc_data, len, aad, aad_len, plaintext, mic_size); } -int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, size_t sg_len, uint8_t mac[16]) +int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[16]) { struct tc_aes_key_sched_struct sched; struct tc_cmac_struct state; @@ -74,8 +76,14 @@ int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, size_t sg_len return 0; } -int bt_mesh_sha256_hmac(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, - uint8_t mac[32]) +int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key, struct bt_mesh_sg *sg, + size_t sg_len, uint8_t mac[16]) +{ + return bt_mesh_aes_cmac_raw_key(key->key, sg, sg_len, mac); +} + +int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg, size_t sg_len, + uint8_t mac[32]) { struct tc_hmac_state_struct h; diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 69de0bb22646..5a1a51801e17 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -129,7 +129,7 @@ static int friend_cred_create(struct bt_mesh_friend *frnd, uint8_t idx) return bt_mesh_friend_cred_create(&frnd->cred[idx], frnd->lpn, bt_mesh_primary_addr(), frnd->lpn_counter, frnd->counter, - frnd->subnet->keys[idx].net); + &frnd->subnet->keys[idx].net); } static void purge_buffers(sys_slist_t *list) @@ -164,6 +164,11 @@ static void friend_clear(struct bt_mesh_friend *frnd) /* If cancelling the timer fails, we'll exit early in the work handler. */ (void)k_work_cancel_delayable(&frnd->timer); + for (int i = 0; i < ARRAY_SIZE(frnd->cred); i++) { + if (frnd->subnet->keys[i].valid) { + bt_mesh_friend_cred_destroy(&frnd->cred[i]); + } + } memset(frnd->cred, 0, sizeof(frnd->cred)); if (frnd->last) { @@ -355,7 +360,7 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta { struct bt_mesh_app_crypto_ctx crypto; - const uint8_t *key; + const struct bt_mesh_key *key; struct bt_mesh_subnet *subnet; uint8_t aid; }; @@ -514,12 +519,12 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, buf->data[0] = (cred->nid | (iv_index & 1) << 7); - if (bt_mesh_net_encrypt(cred->enc, &buf->b, iv_index, BT_MESH_NONCE_NETWORK)) { + if (bt_mesh_net_encrypt(&cred->enc, &buf->b, iv_index, BT_MESH_NONCE_NETWORK)) { LOG_ERR("Encrypting failed"); return -EINVAL; } - if (bt_mesh_net_obfuscate(buf->data, iv_index, cred->privacy)) { + if (bt_mesh_net_obfuscate(buf->data, iv_index, &cred->privacy)) { LOG_ERR("Obfuscating failed"); return -EINVAL; } @@ -1317,6 +1322,7 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) break; case BT_MESH_KEY_REVOKED: LOG_DBG("Revoking old keys for 0x%04x", frnd->lpn); + bt_mesh_friend_cred_destroy(&frnd->cred[0]); memcpy(&frnd->cred[0], &frnd->cred[1], sizeof(frnd->cred[0])); memset(&frnd->cred[1], 0, sizeof(frnd->cred[1])); diff --git a/subsys/bluetooth/mesh/keys.h b/subsys/bluetooth/mesh/keys.h new file mode 100644 index 000000000000..f9a559a1c873 --- /dev/null +++ b/subsys/bluetooth/mesh/keys.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +enum bt_mesh_key_type { + BT_MESH_KEY_TYPE_ECB, + BT_MESH_KEY_TYPE_CCM, + BT_MESH_KEY_TYPE_CMAC, + BT_MESH_KEY_TYPE_NET, + BT_MESH_KEY_TYPE_APP, + BT_MESH_KEY_TYPE_DEV +}; + +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA + +int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], struct bt_mesh_key *out); +int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in); +void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src); +int bt_mesh_key_destroy(const struct bt_mesh_key *key); +int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *mesh_key); + +#elif defined CONFIG_BT_MESH_USES_TINYCRYPT + +static inline int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], + struct bt_mesh_key *out) +{ + memcpy(out, in, 16); + return 0; +} + +static inline int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in) +{ + memcpy(out, in, 16); + return 0; +} + +static inline void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src) +{ + memcpy(dst, src, sizeof(struct bt_mesh_key)); +} + +static inline int bt_mesh_key_destroy(const struct bt_mesh_key *key) +{ + return 0; +} + +static inline int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *mesh_key) +{ + return memcmp(mesh_key, raw_key, 16); +} + +#endif diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 9947dc079642..5dfecc5b35a0 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -264,6 +264,12 @@ static void clear_friendship(bool force, bool disable) lpn->old_friend = lpn->frnd; } + for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) { + if (lpn->sub->keys[i].valid) { + bt_mesh_friend_cred_destroy(&lpn->cred[i]); + } + } + lpn->frnd = BT_MESH_ADDR_UNASSIGNED; lpn->fsn = 0U; lpn->req_attempts = 0U; @@ -607,8 +613,7 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) send_friend_poll(); } -static int friend_cred_create(struct bt_mesh_net_cred *cred, - const uint8_t key[16]) +static int friend_cred_create(struct bt_mesh_net_cred *cred, const struct bt_mesh_key *key) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; @@ -656,7 +661,7 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, continue; } - err = friend_cred_create(&lpn->cred[i], lpn->sub->keys[i].net); + err = friend_cred_create(&lpn->cred[i], &lpn->sub->keys[i].net); if (err) { lpn->frnd = BT_MESH_ADDR_UNASSIGNED; return err; @@ -671,6 +676,12 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, err = send_friend_poll(); if (err) { /* Will retry sending later */ + for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) { + if (lpn->sub->keys[i].valid) { + bt_mesh_friend_cred_destroy(&lpn->cred[i]); + } + } + lpn->sub = NULL; lpn->frnd = BT_MESH_ADDR_UNASSIGNED; lpn->recv_win = 0U; @@ -1143,7 +1154,7 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) break; case BT_MESH_KEY_UPDATED: LOG_DBG("NetKey updated"); - friend_cred_create(&bt_mesh.lpn.cred[1], sub->keys[1].net); + friend_cred_create(&bt_mesh.lpn.cred[1], &sub->keys[1].net); break; default: break; diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 099ed2891123..18a52e238ffe 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -47,7 +47,11 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, uint8_t flags, uint32_t iv_index, uint16_t addr, const uint8_t dev_key[16]) { - int err; + struct bt_mesh_key mesh_dev_key; + struct bt_mesh_key mesh_net_key; + bool is_net_key_valid = false; + bool is_dev_key_valid = false; + int err = 0; if (!atomic_test_bit(bt_mesh.flags, BT_MESH_INIT)) { return -ENODEV; @@ -92,28 +96,57 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, } if (BT_MESH_KEY_REFRESH(flags)) { - memcpy(subnet->keys[1].net_key, net_key, 16); subnet->kr_phase = BT_MESH_KR_PHASE_2; } else { - memcpy(subnet->keys[0].net_key, net_key, 16); subnet->kr_phase = BT_MESH_KR_NORMAL; } + + err = bt_mesh_cdb_subnet_key_import(subnet, BT_MESH_KEY_REFRESH(flags) ? 1 : 0, + net_key); + if (err) { + LOG_ERR("Failed to import cdb network key"); + goto end; + } + memcpy(&mesh_net_key, &subnet->keys[BT_MESH_KEY_REFRESH(flags) ? 1 : 0].net_key, + sizeof(struct bt_mesh_key)); + is_net_key_valid = true; + bt_mesh_cdb_subnet_store(subnet); addr = node->addr; bt_mesh_cdb_iv_update(iv_index, BT_MESH_IV_UPDATE(flags)); - memcpy(node->dev_key, dev_key, 16); + err = bt_mesh_cdb_node_key_import(node, dev_key); + if (err) { + LOG_ERR("Failed to import cdb device key"); + goto end; + } + memcpy(&mesh_dev_key, &node->dev_key, sizeof(struct bt_mesh_key)); + is_dev_key_valid = true; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_node_store(node); } + } else { + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, net_key, &mesh_net_key); + if (err) { + LOG_ERR("Failed to import network key"); + goto end; + } + is_net_key_valid = true; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, dev_key, &mesh_dev_key); + if (err) { + LOG_ERR("Failed to import device key"); + goto end; + } + is_dev_key_valid = true; } - err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); + err = bt_mesh_net_create(net_idx, flags, &mesh_net_key, iv_index); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return err; + goto end; } bt_mesh_net_settings_commit(); @@ -122,7 +155,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_comp_provision(addr); - memcpy(bt_mesh.dev_key, dev_key, 16); + memcpy(&bt_mesh.dev_key, &mesh_dev_key, sizeof(struct bt_mesh_key)); if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && IS_ENABLED(CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR)) { @@ -135,13 +168,24 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_start(); - return 0; +end: + if (err && is_dev_key_valid) { + bt_mesh_key_destroy(&mesh_dev_key); + } + + if (err && is_net_key_valid) { + bt_mesh_key_destroy(&mesh_net_key); + } + + return err; } #if defined(CONFIG_BT_MESH_RPR_SRV) void bt_mesh_reprovision(uint16_t addr) { - LOG_DBG("0x%04x devkey: %s", addr, bt_hex(bt_mesh.dev_key_cand, 16)); + LOG_DBG("0x%04x devkey: %s", addr, + bt_hex(&bt_mesh.dev_key_cand, sizeof(struct bt_mesh_key))); + if (addr != bt_mesh_primary_addr()) { bt_mesh.seq = 0U; @@ -167,11 +211,18 @@ void bt_mesh_reprovision(uint16_t addr) void bt_mesh_dev_key_cand(const uint8_t *key) { - memcpy(bt_mesh.dev_key_cand, key, 16); - atomic_set_bit(bt_mesh.flags, BT_MESH_DEVKEY_CAND); + int err; LOG_DBG("%s", bt_hex(key, 16)); + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, key, &bt_mesh.dev_key_cand); + if (err) { + LOG_ERR("Failed to import device key candidate"); + return; + } + + atomic_set_bit(bt_mesh.flags, BT_MESH_DEVKEY_CAND); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_net_dev_key_cand_store(); } @@ -196,7 +247,9 @@ void bt_mesh_dev_key_cand_activate(void) return; } - memcpy(bt_mesh.dev_key, bt_mesh.dev_key_cand, 16); + bt_mesh_key_destroy(&bt_mesh.dev_key); + memcpy(&bt_mesh.dev_key, &bt_mesh.dev_key_cand, sizeof(struct bt_mesh_key)); + memset(&bt_mesh.dev_key_cand, 0, sizeof(struct bt_mesh_key)); LOG_DBG(""); @@ -339,7 +392,8 @@ void bt_mesh_reset(void) bt_mesh_net_clear(); } - (void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); + bt_mesh_key_destroy(&bt_mesh.dev_key); + memset(&bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); bt_mesh_beacon_disable(); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 11412112ea43..7a65ffe2e6fe 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -67,7 +67,7 @@ LOG_MODULE_REGISTER(bt_mesh_net); /* Mesh network information for persistent storage. */ struct net_val { uint16_t primary_addr; - uint8_t dev_key[16]; + struct bt_mesh_key dev_key; } __packed; /* Sequence number information for persistent storage. */ @@ -200,14 +200,14 @@ void bt_mesh_net_seq_store(bool force) bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); } -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t idx, uint8_t flags, const struct bt_mesh_key *key, uint32_t iv_index) { int err; LOG_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); - LOG_DBG("NetKey %s", bt_hex(key, 16)); + LOG_DBG("NetKey %s", bt_hex(key, sizeof(struct bt_mesh_key))); if (BT_MESH_KEY_REFRESH(flags)) { err = bt_mesh_subnet_set(idx, BT_MESH_KR_PHASE_2, NULL, key); @@ -480,12 +480,12 @@ static int net_encrypt(struct net_buf_simple *buf, { int err; - err = bt_mesh_net_encrypt(cred->enc, buf, iv_index, proxy); + err = bt_mesh_net_encrypt(&cred->enc, buf, iv_index, proxy); if (err) { return err; } - return bt_mesh_net_obfuscate(buf->data, iv_index, cred->privacy); + return bt_mesh_net_obfuscate(buf->data, iv_index, &cred->privacy); } int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, @@ -637,7 +637,7 @@ static bool net_decrypt(struct bt_mesh_net_rx *rx, struct net_buf_simple *in, net_buf_simple_add_mem(out, in->data, in->len); if (bt_mesh_net_obfuscate(out->data, BT_MESH_NET_IVI_RX(rx), - cred->privacy)) { + &cred->privacy)) { return false; } @@ -659,7 +659,7 @@ static bool net_decrypt(struct bt_mesh_net_rx *rx, struct net_buf_simple *in, LOG_DBG("src 0x%04x", rx->ctx.addr); - return bt_mesh_net_decrypt(cred->enc, out, BT_MESH_NET_IVI_RX(rx), + return bt_mesh_net_decrypt(&cred->enc, out, BT_MESH_NET_IVI_RX(rx), proxy) == 0; } @@ -950,13 +950,15 @@ static int net_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { struct net_val net; + struct bt_mesh_key key; int err; if (len_rd == 0) { LOG_DBG("val (null)"); bt_mesh_comp_unprovision(); - (void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); + bt_mesh_key_destroy(&bt_mesh.dev_key); + memset(&bt_mesh.dev_key, 0, sizeof(struct bt_mesh_key)); return 0; } @@ -966,11 +968,16 @@ static int net_set(const char *name, size_t len_rd, settings_read_cb read_cb, return err; } - memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key)); + /* One extra copying since net.dev_key is from packed structure + * and might be unaligned. + */ + memcpy(&key, &net.dev_key, sizeof(struct bt_mesh_key)); + + bt_mesh_key_assign(&bt_mesh.dev_key, &key); bt_mesh_comp_provision(net.primary_addr); LOG_DBG("Provisioned with primary address 0x%04x", net.primary_addr); - LOG_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16)); + LOG_DBG("Recovered DevKey %s", bt_hex(&bt_mesh.dev_key, sizeof(struct bt_mesh_key))); return 0; } @@ -1056,7 +1063,8 @@ static int dev_key_cand_set(const char *name, size_t len_rd, settings_read_cb re return -EINVAL; } - err = bt_mesh_settings_set(read_cb, cb_arg, bt_mesh.dev_key_cand, 16); + err = bt_mesh_settings_set(read_cb, cb_arg, &bt_mesh.dev_key_cand, + sizeof(struct bt_mesh_key)); if (!err) { LOG_DBG("DevKey candidate recovered from storage"); atomic_set_bit(bt_mesh.flags, BT_MESH_DEVKEY_CAND); @@ -1074,7 +1082,8 @@ void bt_mesh_net_pending_dev_key_cand_store(void) int err; if (atomic_test_bit(bt_mesh.flags, BT_MESH_DEVKEY_CAND)) { - err = settings_save_one("bt/mesh/DevKeyC", bt_mesh.dev_key_cand, 16); + err = settings_save_one("bt/mesh/DevKeyC", &bt_mesh.dev_key_cand, + sizeof(struct bt_mesh_key)); } else { err = settings_delete("bt/mesh/DevKeyC"); } @@ -1147,10 +1156,11 @@ static void store_pending_net(void) struct net_val net; int err; - LOG_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), bt_hex(bt_mesh.dev_key, 16)); + LOG_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), + bt_hex(&bt_mesh.dev_key, sizeof(struct bt_mesh_key))); net.primary_addr = bt_mesh_primary_addr(); - memcpy(net.dev_key, bt_mesh.dev_key, 16); + memcpy(&net.dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)); err = settings_save_one("bt/mesh/Net", &net, sizeof(net)); if (err) { diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index 84f5c8998e91..04179a4dd491 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -35,7 +35,7 @@ enum bt_mesh_nonce_type; struct bt_mesh_node { uint16_t addr; uint16_t net_idx; - uint8_t dev_key[16]; + struct bt_mesh_key dev_key; uint8_t num_elem; }; @@ -229,10 +229,10 @@ struct bt_mesh_net { /* Timer to track duration in current IV Update state */ struct k_work_delayable ivu_timer; - uint8_t dev_key[16]; + struct bt_mesh_key dev_key; #if defined(CONFIG_BT_MESH_RPR_SRV) - uint8_t dev_key_cand[16]; + struct bt_mesh_key dev_key_cand; #endif #if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) uint8_t on_demand_state; @@ -283,7 +283,7 @@ extern struct bt_mesh_net bt_mesh; #define BT_MESH_NET_HDR_LEN 9 -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t idx, uint8_t flags, const struct bt_mesh_key *key, uint32_t iv_index); bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update); diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index 6daf978f73e0..deceae58ad0e 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -459,7 +459,7 @@ static bool refresh_is_valid(const uint8_t *netkey, uint16_t net_idx, return false; } - if (!sub || memcmp(netkey, sub->keys[SUBNET_KEY_TX_IDX(sub)].net, 16)) { + if (!sub || bt_mesh_key_compare(netkey, &sub->keys[SUBNET_KEY_TX_IDX(sub)].net)) { LOG_ERR("Invalid netkey"); return false; } @@ -481,7 +481,7 @@ static bool refresh_is_valid(const uint8_t *netkey, uint16_t net_idx, static void prov_data(const uint8_t *data) { PROV_BUF(msg, PDU_LEN_COMPLETE); - uint8_t session_key[16]; + struct bt_mesh_key session_key; uint8_t nonce[13]; uint8_t dev_key[16]; uint8_t pdu[25]; @@ -494,30 +494,28 @@ static void prov_data(const uint8_t *data) LOG_DBG(""); err = bt_mesh_session_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, session_key); + bt_mesh_prov_link.prov_salt, &session_key); if (err) { LOG_ERR("Unable to generate session key"); prov_fail(PROV_ERR_UNEXP_ERR); return; } - LOG_DBG("SessionKey: %s", bt_hex(session_key, 16)); - err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey, bt_mesh_prov_link.prov_salt, nonce); if (err) { LOG_ERR("Unable to generate session nonce"); prov_fail(PROV_ERR_UNEXP_ERR); - return; + goto session_key_destructor; } LOG_DBG("Nonce: %s", bt_hex(nonce, 13)); - err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu); + err = bt_mesh_prov_decrypt(&session_key, nonce, data, pdu); if (err) { LOG_ERR("Unable to decrypt provisioning data"); prov_fail(PROV_ERR_DECRYPT); - return; + goto session_key_destructor; } err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey, @@ -525,11 +523,9 @@ static void prov_data(const uint8_t *data) if (err) { LOG_ERR("Unable to generate device key"); prov_fail(PROV_ERR_UNEXP_ERR); - return; + goto session_key_destructor; } - LOG_DBG("DevKey: %s", bt_hex(dev_key, 16)); - net_idx = sys_get_be16(&pdu[16]); flags = pdu[18]; iv_index = sys_get_be32(&pdu[19]); @@ -539,7 +535,7 @@ static void prov_data(const uint8_t *data) atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION) && !refresh_is_valid(pdu, net_idx, iv_index)) { prov_send_fail_msg(PROV_ERR_INVALID_DATA); - return; + goto session_key_destructor; } LOG_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x", @@ -548,7 +544,7 @@ static void prov_data(const uint8_t *data) bt_mesh_prov_buf_init(&msg, PROV_COMPLETE); if (bt_mesh_prov_send(&msg, NULL)) { LOG_ERR("Failed to send Provisioning Complete"); - return; + goto session_key_destructor; } /* Ignore any further PDUs on this link */ @@ -558,7 +554,7 @@ static void prov_data(const uint8_t *data) if (IS_ENABLED(CONFIG_BT_MESH_RPR_SRV) && atomic_test_bit(bt_mesh_prov_link.flags, REPROVISION)) { bt_mesh_dev_key_cand(dev_key); - return; + goto session_key_destructor; } /* Store info, since bt_mesh_provision() will end up clearing it */ @@ -568,11 +564,10 @@ static void prov_data(const uint8_t *data) identity_enable = false; } - err = bt_mesh_provision(pdu, net_idx, flags, iv_index, - bt_mesh_prov_link.addr, dev_key); + err = bt_mesh_provision(pdu, net_idx, flags, iv_index, bt_mesh_prov_link.addr, dev_key); if (err) { LOG_ERR("Failed to provision (err %d)", err); - return; + goto session_key_destructor; } /* After PB-GATT provisioning we should start advertising @@ -581,6 +576,9 @@ static void prov_data(const uint8_t *data) if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && identity_enable) { bt_mesh_proxy_identity_enable(); } + +session_key_destructor: + bt_mesh_key_destroy(&session_key); } static void reprovision_complete(void) diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index c604efd93e65..25f0a2994805 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -488,26 +488,25 @@ static void send_prov_data(void) { PROV_BUF(pdu, PDU_LEN_DATA); struct bt_mesh_cdb_subnet *sub; - uint8_t session_key[16]; + uint8_t net_key[16]; + struct bt_mesh_key session_key; uint8_t nonce[13]; int err; err = bt_mesh_session_key(bt_mesh_prov_link.dhkey, - bt_mesh_prov_link.prov_salt, session_key); + bt_mesh_prov_link.prov_salt, &session_key); if (err) { LOG_ERR("Unable to generate session key"); prov_fail(PROV_ERR_UNEXP_ERR); return; } - LOG_DBG("SessionKey: %s", bt_hex(session_key, 16)); - err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey, bt_mesh_prov_link.prov_salt, nonce); if (err) { LOG_ERR("Unable to generate session nonce"); prov_fail(PROV_ERR_UNEXP_ERR); - return; + goto session_key_destructor; } LOG_DBG("Nonce: %s", bt_hex(nonce, 13)); @@ -517,20 +516,25 @@ static void send_prov_data(void) if (err) { LOG_ERR("Unable to generate device key"); prov_fail(PROV_ERR_UNEXP_ERR); - return; + goto session_key_destructor; } - LOG_DBG("DevKey: %s", bt_hex(prov_device.new_dev_key, 16)); - sub = bt_mesh_cdb_subnet_get(prov_device.node->net_idx); if (sub == NULL) { LOG_ERR("No subnet with net_idx %u", prov_device.node->net_idx); prov_fail(PROV_ERR_UNEXP_ERR); - return; + goto session_key_destructor; + } + + err = bt_mesh_key_export(net_key, &sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key); + if (err) { + LOG_ERR("Unable to export network key"); + prov_fail(PROV_ERR_UNEXP_ERR); + goto session_key_destructor; } bt_mesh_prov_buf_init(&pdu, PROV_DATA); - net_buf_simple_add_mem(&pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key, 16); + 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_u8(&pdu, bt_mesh_cdb_subnet_flags(sub)); net_buf_simple_add_be32(&pdu, bt_mesh_cdb.iv_index); @@ -541,20 +545,23 @@ static void send_prov_data(void) 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], + err = bt_mesh_prov_encrypt(&session_key, nonce, &pdu.data[1], &pdu.data[1]); if (err) { LOG_ERR("Unable to encrypt provisioning data"); prov_fail(PROV_ERR_DECRYPT); - return; + goto session_key_destructor; } if (bt_mesh_prov_send(&pdu, NULL)) { LOG_ERR("Failed to send Provisioning Data"); - return; + goto session_key_destructor; } bt_mesh_prov_link.expect = PROV_COMPLETE; + +session_key_destructor: + bt_mesh_key_destroy(&session_key); } static void prov_complete(const uint8_t *data) @@ -562,8 +569,8 @@ static void prov_complete(const uint8_t *data) struct bt_mesh_cdb_node *node = prov_device.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, node->num_elem, - node->addr); + bt_hex(&prov_device.new_dev_key, 16), node->net_idx, + node->num_elem, node->addr); bt_mesh_prov_link.expect = PROV_NO_PDU; atomic_set_bit(bt_mesh_prov_link.flags, COMPLETE); @@ -575,13 +582,18 @@ static void prov_node_add(void) { LOG_DBG(""); 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, prov_device.elem_count); } - memcpy(node->dev_key, prov_device.new_dev_key, 16); + err = bt_mesh_cdb_node_key_import(node, prov_device.new_dev_key); + if (err) { + LOG_ERR("Failed to import node device key"); + return; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_node_store(node); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index fc7958006389..8ff026fb991d 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -504,7 +504,7 @@ static int enc_id_adv(struct bt_mesh_subnet *sub, uint8_t type, }; int err; - err = bt_mesh_encrypt(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, hash, hash); + err = bt_mesh_encrypt(&sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, hash, hash); if (err) { return err; } diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index 3d48260c80eb..5b66ac441c42 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "access.h" #include "adv.h" #include "prov.h" diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 2c3ef3bc9022..ef4eec6f6a77 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -12,6 +12,7 @@ #include #include +#include #include "host/hci_core.h" #include "mesh.h" diff --git a/subsys/bluetooth/mesh/shell/cfg.c b/subsys/bluetooth/mesh/shell/cfg.c index 84b20fa4650c..9843bece328e 100644 --- a/subsys/bluetooth/mesh/shell/cfg.c +++ b/subsys/bluetooth/mesh/shell/cfg.c @@ -8,8 +8,8 @@ #include #include -#include "../net.h" -#include "../access.h" +#include "mesh/net.h" +#include "mesh/access.h" #include "utils.h" #include @@ -530,7 +530,11 @@ static int cmd_net_key_add(const struct shell *sh, size_t argc, char *argv[]) return 0; } - memcpy(key_val, subnet->keys[0].net_key, 16); + if (bt_mesh_cdb_subnet_key_export(subnet, 0, key_val)) { + shell_error(sh, "Unable to export subnet key from cdb 0x%03x", + key_net_idx); + return 0; + } } else { subnet = bt_mesh_cdb_subnet_alloc(key_net_idx); if (!subnet) { @@ -538,7 +542,11 @@ static int cmd_net_key_add(const struct shell *sh, size_t argc, char *argv[]) return 0; } - memcpy(subnet->keys[0].net_key, key_val, 16); + if (bt_mesh_cdb_subnet_key_import(subnet, 0, key_val)) { + shell_error(sh, "Unable to import subnet key into cdb 0x%03x", + key_net_idx); + return 0; + } bt_mesh_cdb_subnet_store(subnet); } } @@ -684,7 +692,11 @@ static int cmd_app_key_add(const struct shell *sh, size_t argc, char *argv[]) return 0; } - memcpy(key_val, app_key->keys[0].app_key, 16); + if (bt_mesh_cdb_app_key_export(app_key, 0, key_val)) { + shell_error(sh, "Unable to export app key 0x%03x from cdb", + key_app_idx); + return 0; + } } else { app_key = bt_mesh_cdb_app_key_alloc(key_net_idx, key_app_idx); if (!app_key) { @@ -692,7 +704,11 @@ static int cmd_app_key_add(const struct shell *sh, size_t argc, char *argv[]) return 0; } - memcpy(app_key->keys[0].app_key, key_val, 16); + if (bt_mesh_cdb_app_key_import(app_key, 0, key_val)) { + shell_error(sh, "Unable to import app key 0x%03x into cdb", + key_app_idx); + return 0; + } bt_mesh_cdb_app_key_store(app_key); } } diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index e9fa8bfef159..a5231ce2e7d0 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -935,7 +935,7 @@ static int cmd_provision_adv(const struct shell *sh, size_t argc, static int cmd_provision_local(const struct shell *sh, size_t argc, char *argv[]) { - const uint8_t *net_key = bt_mesh_shell_default_key; + uint8_t *net_key = (uint8_t *)bt_mesh_shell_default_key; uint16_t net_idx, addr; uint32_t iv_index; int err = 0; @@ -955,20 +955,21 @@ static int cmd_provision_local(const struct shell *sh, size_t argc, char *argv[] } if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - const struct bt_mesh_cdb_subnet *sub; + struct bt_mesh_cdb_subnet *sub; sub = bt_mesh_cdb_subnet_get(net_idx); if (!sub) { - shell_error(sh, "No cdb entry for subnet 0x%03x", - net_idx); + shell_error(sh, "No cdb entry for subnet 0x%03x", net_idx); return 0; } - net_key = sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key; + if (bt_mesh_cdb_subnet_key_export(sub, SUBNET_KEY_TX_IDX(sub), net_key)) { + shell_error(sh, "Unable to export key for subnet 0x%03x", net_idx); + return 0; + } } - err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, - bt_mesh_shell_default_key); + err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, bt_mesh_shell_default_key); if (err) { shell_error(sh, "Provisioning failed (err %d)", err); } @@ -1207,6 +1208,7 @@ static void cdb_print_nodes(const struct shell *sh) struct bt_mesh_cdb_node *node; int i, total = 0; bool configured; + uint8_t dev_key[16]; shell_print(sh, "Address Elements Flags %-32s DevKey", "UUID"); @@ -1221,7 +1223,11 @@ static void cdb_print_nodes(const struct shell *sh) total++; bin2hex(node->uuid, 16, uuid_hex_str, sizeof(uuid_hex_str)); - bin2hex(node->dev_key, 16, key_hex_str, sizeof(key_hex_str)); + if (bt_mesh_cdb_node_key_export(node, dev_key)) { + shell_error(sh, "Unable to export key for node 0x%04x", node->addr); + continue; + } + bin2hex(dev_key, 16, key_hex_str, sizeof(key_hex_str)); shell_print(sh, "0x%04x %-8d %-5s %s %s", node->addr, node->num_elem, configured ? "C" : "-", uuid_hex_str, key_hex_str); @@ -1235,6 +1241,7 @@ static void cdb_print_subnets(const struct shell *sh) struct bt_mesh_cdb_subnet *subnet; char key_hex_str[32 + 1]; int i, total = 0; + uint8_t net_key[16]; shell_print(sh, "NetIdx NetKey"); @@ -1244,11 +1251,15 @@ static void cdb_print_subnets(const struct shell *sh) continue; } + if (bt_mesh_cdb_subnet_key_export(subnet, 0, net_key)) { + shell_error(sh, "Unable to export key for subnet 0x%03x", + subnet->net_idx); + continue; + } + total++; - bin2hex(subnet->keys[0].net_key, 16, key_hex_str, - sizeof(key_hex_str)); - shell_print(sh, "0x%03x %s", subnet->net_idx, - key_hex_str); + bin2hex(net_key, 16, key_hex_str, sizeof(key_hex_str)); + shell_print(sh, "0x%03x %s", subnet->net_idx, key_hex_str); } shell_print(sh, "> Total subnets: %d", total); @@ -1256,23 +1267,27 @@ static void cdb_print_subnets(const struct shell *sh) static void cdb_print_app_keys(const struct shell *sh) { - struct bt_mesh_cdb_app_key *app_key; + struct bt_mesh_cdb_app_key *key; char key_hex_str[32 + 1]; int i, total = 0; + uint8_t app_key[16]; shell_print(sh, "NetIdx AppIdx AppKey"); for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { - app_key = &bt_mesh_cdb.app_keys[i]; - if (app_key->net_idx == BT_MESH_KEY_UNUSED) { + key = &bt_mesh_cdb.app_keys[i]; + if (key->net_idx == BT_MESH_KEY_UNUSED) { + continue; + } + + if (bt_mesh_cdb_app_key_export(key, 0, app_key)) { + shell_error(sh, "Unable to export app key 0x%03x", key->app_idx); continue; } total++; - bin2hex(app_key->keys[0].app_key, 16, key_hex_str, - sizeof(key_hex_str)); - shell_print(sh, "0x%03x 0x%03x %s", - app_key->net_idx, app_key->app_idx, key_hex_str); + bin2hex(app_key, 16, key_hex_str, sizeof(key_hex_str)); + shell_print(sh, "0x%03x 0x%03x %s", key->net_idx, key->app_idx, key_hex_str); } shell_print(sh, "> Total app-keys: %d", total); @@ -1333,7 +1348,11 @@ static int cmd_cdb_node_add(const struct shell *sh, size_t argc, return 0; } - memcpy(node->dev_key, dev_key, 16); + err = bt_mesh_cdb_node_key_import(node, dev_key); + if (err) { + shell_warn(sh, "Unable to import device key into cdb"); + return err; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_node_store(node); @@ -1399,7 +1418,10 @@ static int cmd_cdb_subnet_add(const struct shell *sh, size_t argc, return 0; } - memcpy(sub->keys[0].net_key, net_key, 16); + if (bt_mesh_cdb_subnet_key_import(sub, 0, net_key)) { + shell_error(sh, "Unable to import key for subnet 0x%03x", net_idx); + return 0; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_subnet_store(sub); @@ -1466,7 +1488,10 @@ static int cmd_cdb_app_key_add(const struct shell *sh, size_t argc, return 0; } - memcpy(key->keys[0].app_key, app_key, 16); + if (bt_mesh_cdb_app_key_import(key, 0, app_key)) { + shell_error(sh, "Unable to import app key 0x%03x", app_idx); + return 0; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_app_key_store(key); diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index c3f64a310281..df71d3a4eb83 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -55,7 +55,7 @@ struct net_key_update { struct net_key_val { uint8_t kr_flag:1, kr_phase:7; - uint8_t val[2][16]; + struct bt_mesh_key val[2]; } __packed; static struct net_key_update net_key_updates[CONFIG_BT_MESH_SUBNET_COUNT]; @@ -106,8 +106,8 @@ static void store_subnet(uint16_t net_idx) snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", net_idx); - memcpy(&key.val[0], sub->keys[0].net, 16); - memcpy(&key.val[1], sub->keys[1].net, 16); + memcpy(&key.val[0], &sub->keys[0].net, sizeof(struct bt_mesh_key)); + memcpy(&key.val[1], &sub->keys[1].net, sizeof(struct bt_mesh_key)); key.kr_flag = 0U; /* Deprecated */ key.kr_phase = sub->kr_phase; @@ -195,6 +195,20 @@ void bt_mesh_subnet_store(uint16_t net_idx) update_subnet_settings(net_idx, true); } +static void subnet_keys_destroy(struct bt_mesh_subnet_keys *key) +{ + bt_mesh_key_destroy(&key->net); + bt_mesh_key_destroy(&key->msg.enc); + bt_mesh_key_destroy(&key->msg.privacy); + bt_mesh_key_destroy(&key->beacon); +#if defined(CONFIG_BT_MESH_GATT_PROXY) + bt_mesh_key_destroy(&key->identity); +#endif +#if defined(CONFIG_BT_MESH_V1d1) + bt_mesh_key_destroy(&key->priv_beacon); +#endif +} + static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) { LOG_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase); @@ -218,6 +232,7 @@ static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) __fallthrough; case BT_MESH_KR_NORMAL: sub->kr_phase = BT_MESH_KR_NORMAL; + subnet_keys_destroy(&sub->keys[0]); memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); sub->keys[1].valid = 0U; subnet_evt(sub, BT_MESH_KEY_REVOKED); @@ -271,6 +286,12 @@ static void subnet_del(struct bt_mesh_subnet *sub) update_subnet_settings(sub->net_idx, false); } + for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) { + if (sub->keys[i].valid) { + subnet_keys_destroy(&sub->keys[i]); + } + } + bt_mesh_net_loopback_clear(sub->net_idx); subnet_evt(sub, BT_MESH_KEY_DELETED); @@ -281,11 +302,10 @@ static void subnet_del(struct bt_mesh_subnet *sub) static int msg_cred_create(struct bt_mesh_net_cred *cred, const uint8_t *p, size_t p_len, const uint8_t key[16]) { - return bt_mesh_k2(key, p, p_len, &cred->nid, cred->enc, cred->privacy); + return bt_mesh_k2(key, p, p_len, &cred->nid, &cred->enc, &cred->privacy); } -static int net_keys_create(struct bt_mesh_subnet_keys *keys, - const uint8_t key[16]) +static int net_keys_create(struct bt_mesh_subnet_keys *keys, bool import, const uint8_t key[16]) { uint8_t p = 0; int err; @@ -296,10 +316,17 @@ static int net_keys_create(struct bt_mesh_subnet_keys *keys, return err; } - memcpy(keys->net, key, 16); + if (import) { + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, key, &keys->net); + if (err) { + LOG_ERR("Unable to import network key"); + return err; + } + } - LOG_DBG("NID 0x%02x EncKey %s", keys->msg.nid, bt_hex(keys->msg.enc, 16)); - LOG_DBG("PrivacyKey %s", bt_hex(keys->msg.privacy, 16)); + LOG_DBG("NID 0x%02x EncKey %s", keys->msg.nid, + bt_hex(&keys->msg.enc, sizeof(struct bt_mesh_key))); + LOG_DBG("PrivacyKey %s", bt_hex(&keys->msg.privacy, sizeof(struct bt_mesh_key))); err = bt_mesh_k3(key, keys->net_id); if (err) { @@ -310,31 +337,31 @@ static int net_keys_create(struct bt_mesh_subnet_keys *keys, LOG_DBG("NetID %s", bt_hex(keys->net_id, 8)); #if defined(CONFIG_BT_MESH_GATT_PROXY) - err = bt_mesh_identity_key(key, keys->identity); + err = bt_mesh_identity_key(key, &keys->identity); if (err) { LOG_ERR("Unable to generate IdentityKey"); return err; } - LOG_DBG("IdentityKey %s", bt_hex(keys->identity, 16)); + LOG_DBG("IdentityKey %s", bt_hex(&keys->identity, sizeof(struct bt_mesh_key))); #endif /* GATT_PROXY */ - err = bt_mesh_beacon_key(key, keys->beacon); + err = bt_mesh_beacon_key(key, &keys->beacon); if (err) { LOG_ERR("Unable to generate beacon key"); return err; } - LOG_DBG("BeaconKey %s", bt_hex(keys->beacon, 16)); + LOG_DBG("BeaconKey %s", bt_hex(&keys->beacon, sizeof(struct bt_mesh_key))); #if defined(CONFIG_BT_MESH_PRIV_BEACONS) - err = bt_mesh_private_beacon_key(key, keys->priv_beacon); + err = bt_mesh_private_beacon_key(key, &keys->priv_beacon); if (err) { LOG_ERR("Unable to generate private beacon key"); return err; } - LOG_DBG("PrivateBeaconKey %s", bt_hex(keys->priv_beacon, 16)); + LOG_DBG("PrivateBeaconKey %s", bt_hex(&keys->priv_beacon, sizeof(struct bt_mesh_key))); #endif keys->valid = 1U; @@ -355,14 +382,14 @@ uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]) } if (sub->net_idx == net_idx) { - if (memcmp(key, sub->keys[0].net, 16)) { + if (bt_mesh_key_compare(key, &sub->keys[0].net)) { return STATUS_IDX_ALREADY_STORED; } return STATUS_SUCCESS; } - err = net_keys_create(&sub->keys[0], key); + err = net_keys_create(&sub->keys[0], true, key); if (err) { return STATUS_UNSPECIFIED; } @@ -411,12 +438,12 @@ uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]) */ switch (sub->kr_phase) { case BT_MESH_KR_NORMAL: - if (!memcmp(key, sub->keys[0].net, 16)) { + if (!bt_mesh_key_compare(key, &sub->keys[0].net)) { return STATUS_IDX_ALREADY_STORED; } break; case BT_MESH_KR_PHASE_1: - if (!memcmp(key, sub->keys[1].net, 16)) { + if (!bt_mesh_key_compare(key, &sub->keys[1].net)) { return STATUS_SUCCESS; } __fallthrough; @@ -425,7 +452,7 @@ uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]) return STATUS_CANNOT_UPDATE; } - err = net_keys_create(&sub->keys[1], key); + err = net_keys_create(&sub->keys[1], true, key); if (err) { return STATUS_CANNOT_UPDATE; } @@ -456,9 +483,11 @@ uint8_t bt_mesh_subnet_del(uint16_t net_idx) int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, uint16_t lpn_addr, uint16_t frnd_addr, uint16_t lpn_counter, - uint16_t frnd_counter, const uint8_t key[16]) + uint16_t frnd_counter, const struct bt_mesh_key *key) { uint8_t p[9]; + uint8_t raw_key[16]; + int err; p[0] = 0x01; sys_put_be16(lpn_addr, p + 1); @@ -466,7 +495,18 @@ int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, uint16_t lpn_addr, sys_put_be16(lpn_counter, p + 5); sys_put_be16(frnd_counter, p + 7); - return msg_cred_create(cred, p, sizeof(p), key); + err = bt_mesh_key_export(raw_key, key); + if (err) { + return err; + } + + return msg_cred_create(cred, p, sizeof(p), raw_key); +} + +void bt_mesh_friend_cred_destroy(struct bt_mesh_net_cred *cred) +{ + bt_mesh_key_destroy(&cred->enc); + bt_mesh_key_destroy(&cred->privacy); } uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase) @@ -709,11 +749,30 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) return NULL; } -int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, - const uint8_t old_key[16], const uint8_t new_key[16]) +static int subnet_key_set(struct bt_mesh_subnet *sub, int key_idx, const struct bt_mesh_key *key) +{ + uint8_t raw_key[16]; + int err; + + err = bt_mesh_key_export(raw_key, key); + if (err) { + return err; + } + + bt_mesh_key_assign(&sub->keys[key_idx].net, key); + err = net_keys_create(&sub->keys[key_idx], false, raw_key); + if (err) { + return err; + } + + return 0; +} + +int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, const struct bt_mesh_key *old_key, + const struct bt_mesh_key *new_key) { - const uint8_t *keys[] = { old_key, new_key }; struct bt_mesh_subnet *sub; + int err; sub = subnet_alloc(net_idx); if (!sub) { @@ -724,13 +783,17 @@ int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, return -EALREADY; } - for (int i = 0; i < ARRAY_SIZE(keys); i++) { - if (!keys[i]) { - continue; + if (old_key != NULL) { + err = subnet_key_set(sub, 0, old_key); + if (err) { + return err; } + } - if (net_keys_create(&sub->keys[i], keys[i])) { - return -EIO; + if (new_key != NULL) { + err = subnet_key_set(sub, 1, new_key); + if (err) { + return err; } } @@ -907,6 +970,7 @@ static int net_key_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { struct net_key_val key; + struct bt_mesh_key val[2]; int err; uint16_t net_idx; @@ -922,11 +986,16 @@ static int net_key_set(const char *name, size_t len_rd, return err; } + /* One extra copying since key.val array is from packed structure + * and might be unaligned. + */ + memcpy(val, key.val, sizeof(key.val)); + LOG_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); return bt_mesh_subnet_set( - net_idx, key.kr_phase, key.val[0], - (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); + net_idx, key.kr_phase, &val[0], + (key.kr_phase != BT_MESH_KR_NORMAL) ? &val[1] : NULL); } BT_MESH_SETTINGS_DEFINE(subnet, "NetKey", net_key_set); diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h index 7064313348ed..f19b1d2abea6 100644 --- a/subsys/bluetooth/mesh/subnet.h +++ b/subsys/bluetooth/mesh/subnet.h @@ -29,9 +29,9 @@ enum bt_mesh_key_evt; /** Network message encryption credentials */ struct bt_mesh_net_cred { - uint8_t nid; /* NID */ - uint8_t enc[16]; /* EncKey */ - uint8_t privacy[16]; /* PrivacyKey */ + uint8_t nid; /* NID */ + struct bt_mesh_key enc; /* EncKey */ + struct bt_mesh_key privacy; /* PrivacyKey */ }; struct bt_mesh_beacon { @@ -69,15 +69,15 @@ struct bt_mesh_subnet { struct bt_mesh_subnet_keys { bool valid; - uint8_t net[16]; /* NetKey */ + struct bt_mesh_key net; /* NetKey */ struct bt_mesh_net_cred msg; - uint8_t net_id[8]; /* Network ID */ + uint8_t net_id[8]; /* Network ID */ #if defined(CONFIG_BT_MESH_GATT_PROXY) - uint8_t identity[16]; /* IdentityKey */ + struct bt_mesh_key identity; /* IdentityKey */ #endif - uint8_t beacon[16]; /* BeaconKey */ + struct bt_mesh_key beacon; /* BeaconKey */ #if defined(CONFIG_BT_MESH_V1d1) - uint8_t priv_beacon[16]; /* PrivateBeaconKey */ + struct bt_mesh_key priv_beacon; /* PrivateBeaconKey */ #endif } keys[2]; #if defined(CONFIG_BT_MESH_PROXY_SOLICITATION) @@ -157,7 +157,7 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx); * @returns 0 on success, or (negative) error code on failure. */ int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, - const uint8_t key[16], const uint8_t new_key[16]); + const struct bt_mesh_key *key, const struct bt_mesh_key *new_key); /** @brief Create Friendship credentials. * @@ -173,7 +173,13 @@ int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase, int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, uint16_t lpn_addr, uint16_t frnd_addr, uint16_t lpn_counter, uint16_t frnd_counter, - const uint8_t key[16]); + const struct bt_mesh_key *key); + +/** @brief Destroy Friendship credentials. + * + * @param cred Credential object to destroy. + */ +void bt_mesh_friend_cred_destroy(struct bt_mesh_net_cred *cred); /** @brief Iterate through all valid network credentials to decrypt a message. * diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index b4b0f9179049..2e6d1726b5c8 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -639,7 +639,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, return 0; } -static int trans_encrypt(const struct bt_mesh_net_tx *tx, const uint8_t *key, +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 = { @@ -661,7 +661,7 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const uint8_t *key, 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 uint8_t *key; + const struct bt_mesh_key *key; uint8_t aid; int err; @@ -756,7 +756,7 @@ struct decrypt_ctx { struct seg_rx *seg; }; -static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const uint8_t key[16], +static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { const struct decrypt_ctx *ctx = cb_data; diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index 144a26613c7d..7f7e0a54e33a 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -600,7 +600,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, return 0; } -static int trans_encrypt(const struct bt_mesh_net_tx *tx, const uint8_t *key, +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 = { @@ -622,7 +622,7 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const uint8_t *key, 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 uint8_t *key; + const struct bt_mesh_key *key; uint8_t aid; int err; @@ -717,7 +717,7 @@ struct decrypt_ctx { struct seg_rx *seg; }; -static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const uint8_t key[16], +static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { const struct decrypt_ctx *ctx = cb_data; diff --git a/tests/bluetooth/mesh/rpl/CMakeLists.txt b/tests/bluetooth/mesh/rpl/CMakeLists.txt index 075c0c12ad5f..b22dcae3e7c8 100644 --- a/tests/bluetooth/mesh/rpl/CMakeLists.txt +++ b/tests/bluetooth/mesh/rpl/CMakeLists.txt @@ -18,4 +18,5 @@ target_compile_options(app PRIVATE -DCONFIG_BT_MESH_CRPL=10 -DCONFIG_BT_MESH_RPL_STORE_TIMEOUT=1 - -DCONFIG_BT_SETTINGS) + -DCONFIG_BT_SETTINGS + -DCONFIG_BT_MESH_USES_TINYCRYPT) diff --git a/tests/bsim/bluetooth/mesh/CMakeLists.txt b/tests/bsim/bluetooth/mesh/CMakeLists.txt index 3c9bb53fa17c..f389e75a74e8 100644 --- a/tests/bsim/bluetooth/mesh/CMakeLists.txt +++ b/tests/bsim/bluetooth/mesh/CMakeLists.txt @@ -34,6 +34,12 @@ if(CONFIG_SETTINGS) ) endif() +if(CONFIG_BT_MESH_USES_MBEDTLS_PSA) + target_sources(app PRIVATE + src/distribute_keyid.c + ) +endif() + elseif(CONFIG_BT_MESH_GATT_PROXY) target_sources(app PRIVATE diff --git a/tests/bsim/bluetooth/mesh/src/distribute_keyid.c b/tests/bsim/bluetooth/mesh/src/distribute_keyid.c new file mode 100644 index 000000000000..3f1001734acd --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/distribute_keyid.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "argparse.h" +#include "mesh/crypto.h" + +#define LOG_MODULE_NAME distribute_keys +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +/* Mesh requires to keep in persistent memory network keys (2 keys per subnetwork), + * application keys (2 real keys per 1 configured) and device key + device key candidate. + */ +#if defined CONFIG_BT_MESH_CDB +#define BT_MESH_CDB_KEY_ID_RANGE_SIZE (2 * SUBNET_COUNT + \ + 2 * APP_KEY_COUNT + NODE_COUNT) +#else +#define BT_MESH_CDB_KEY_ID_RANGE_SIZE 0 +#endif +#define BT_MESH_KEY_ID_RANGE_SIZE (2 * CONFIG_BT_MESH_SUBNET_COUNT + \ + 2 * CONFIG_BT_MESH_APP_KEY_COUNT + 1 + BT_MESH_CDB_KEY_ID_RANGE_SIZE) +#define BT_MESH_PSA_KEY_ID_USER_MIN (PSA_KEY_ID_USER_MIN + \ + CONFIG_BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET) +#define BT_MESH_TEST_PSA_KEY_ID_USER_MIN (BT_MESH_PSA_KEY_ID_USER_MIN + \ + BT_MESH_KEY_ID_RANGE_SIZE * get_device_nbr()) + +static ATOMIC_DEFINE(pst_keys, BT_MESH_KEY_ID_RANGE_SIZE); + +psa_key_id_t bt_mesh_user_keyid_alloc(void) +{ + for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) { + if (!atomic_test_bit(pst_keys, i)) { + atomic_set_bit(pst_keys, i); + + LOG_INF("key id %d is allocated", BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i); + + return BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i; + } + } + + return PSA_KEY_ID_NULL; +} + +int bt_mesh_user_keyid_free(psa_key_id_t key_id) +{ + if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN, + BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { + atomic_clear_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN); + + LOG_INF("key id %d is freed", key_id); + + return 0; + } + + return -EIO; +} + +void bt_mesh_user_keyid_assign(psa_key_id_t key_id) +{ + if (IN_RANGE(key_id, BT_MESH_TEST_PSA_KEY_ID_USER_MIN, + BT_MESH_TEST_PSA_KEY_ID_USER_MIN + BT_MESH_KEY_ID_RANGE_SIZE - 1)) { + atomic_set_bit(pst_keys, key_id - BT_MESH_TEST_PSA_KEY_ID_USER_MIN); + LOG_INF("key id %d is assigned", key_id); + } else { + LOG_WRN("key id %d is out of the reserved id range", key_id); + } +} + +void stored_keys_clear(void) +{ + struct bt_mesh_key key; + + for (int i = 0; i < BT_MESH_KEY_ID_RANGE_SIZE; i++) { + key.key = BT_MESH_TEST_PSA_KEY_ID_USER_MIN + i; + bt_mesh_key_destroy(&key); + } +} diff --git a/tests/bsim/bluetooth/mesh/src/distribute_keyid.h b/tests/bsim/bluetooth/mesh/src/distribute_keyid.h new file mode 100644 index 000000000000..b78c6cb7480f --- /dev/null +++ b/tests/bsim/bluetooth/mesh/src/distribute_keyid.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TESTS_BSIM_BLUETOOTH_MESH_SRC_DISTRIBUTE_KEYID_H_ +#define TESTS_BSIM_BLUETOOTH_MESH_SRC_DISTRIBUTE_KEYID_H_ + +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA +void stored_keys_clear(void); +#else +static inline void stored_keys_clear(void) +{} +#endif + +#endif /* TESTS_BSIM_BLUETOOTH_MESH_SRC_DISTRIBUTE_KEYID_H_ */ diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index 61eec7538c65..583e8eb86a59 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -6,6 +6,9 @@ #include "mesh_test.h" #include "argparse.h" #include +#include "settings_test_backend.h" +#include "distribute_keyid.h" +#include "mesh/crypto.h" #define LOG_MODULE_NAME mesh_test @@ -532,3 +535,13 @@ void bt_mesh_test_sar_conf_set(struct bt_mesh_sar_tx *tx_set, struct bt_mesh_sar } } #endif /* defined(CONFIG_BT_MESH_SAR_CFG) */ + +void bt_mesh_test_host_files_remove(void) +{ +#if defined(CONFIG_SETTINGS) + /* crypto library initialization to be able to remove stored keys. */ + bt_mesh_crypto_init(); + stored_keys_clear(); + settings_test_backend_clear(); +#endif +} diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index a4db379a175f..ca28964dce39 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -162,4 +162,6 @@ uint16_t bt_mesh_test_own_addr_get(uint16_t start_addr); void bt_mesh_test_sar_conf_set(struct bt_mesh_sar_tx *tx_set, struct bt_mesh_sar_rx *rx_set); #endif +void bt_mesh_test_host_files_remove(void); + #endif /* ZEPHYR_TESTS_BLUETOOTH_BSIM_BT_BSIM_TEST_MESH_MESH_TEST_H_ */ diff --git a/tests/bsim/bluetooth/mesh/src/test_beacon.c b/tests/bsim/bluetooth/mesh/src/test_beacon.c index 58a4d963d2d2..117a90c1d86a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_beacon.c +++ b/tests/bsim/bluetooth/mesh/src/test_beacon.c @@ -81,7 +81,7 @@ static uint8_t last_random[13]; static bt_addr_le_t last_beacon_adv_addr; -static uint8_t priv_beacon_key[16]; +static struct bt_mesh_key priv_beacon_key; #endif /* CONFIG_BT_MESH_V1d1 */ static int random_interval; @@ -352,8 +352,8 @@ static void beacon_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_ty memcpy(beacon.random, buf->data, 13); bt_addr_le_copy(&beacon.adv_addr, addr); - bt_mesh_beacon_decrypt(priv_beacon_key, &buf->data[0], &buf->data[13], - &buf->data[20], private_beacon_data); + bt_mesh_beacon_decrypt(&priv_beacon_key, &buf->data[0], &buf->data[13], + &buf->data[20], private_beacon_data); beacon.flags = private_beacon_data[0]; beacon.iv_index = sys_get_be32(&private_beacon_data[1]); } @@ -439,10 +439,10 @@ static void send_beacon(struct net_buf_simple *buf) } } -static void beacon_create(struct net_buf_simple *buf, const uint8_t *net_key, uint8_t flags, +static void beacon_create(struct net_buf_simple *buf, const uint8_t net_key[16], uint8_t flags, uint32_t iv_index) { - uint8_t beacon_key[16]; + struct bt_mesh_key beacon_key; uint8_t net_id[8]; uint8_t auth[8]; int err; @@ -452,16 +452,21 @@ static void beacon_create(struct net_buf_simple *buf, const uint8_t *net_key, ui FAIL("Unable to generate Net ID"); } - err = bt_mesh_beacon_key(net_key, beacon_key); + err = bt_mesh_beacon_key(net_key, &beacon_key); if (err) { FAIL("Unable to generate beacon key"); } - err = bt_mesh_beacon_auth(beacon_key, flags, net_id, iv_index, auth); + err = bt_mesh_beacon_auth(&beacon_key, flags, net_id, iv_index, auth); if (err) { FAIL("Unable to generate auth value"); } + err = bt_mesh_key_destroy(&beacon_key); + if (err) { + FAIL("Unable to destroy beacon key"); + } + net_buf_simple_reset(buf); net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); net_buf_simple_add_u8(buf, flags); @@ -1149,18 +1154,13 @@ static void private_beacon_create(struct net_buf_simple *buf, const uint8_t *net FAIL("Unable to generate Net ID"); } - err = bt_mesh_private_beacon_key(net_key, priv_beacon_key); + err = bt_mesh_private_beacon_key(net_key, &priv_beacon_key); if (err) { FAIL("Unable to generate beacon key"); } - err = bt_mesh_beacon_auth(priv_beacon_key, flags, net_id, iv_index, auth); - if (err) { - FAIL("Unable to generate auth value"); - } - bt_rand(random_val, sizeof(random_val)); - bt_mesh_beacon_encrypt(priv_beacon_key, flags, bt_mesh.iv_index + 1, + bt_mesh_beacon_encrypt(&priv_beacon_key, flags, bt_mesh.iv_index + 1, random_val, data, auth); net_buf_simple_reset(buf); @@ -1168,7 +1168,6 @@ static void private_beacon_create(struct net_buf_simple *buf, const uint8_t *net net_buf_simple_add_mem(buf, random_val, 13); net_buf_simple_add_mem(buf, data, 5); net_buf_simple_add_mem(buf, auth, 8); - } static void test_tx_priv_invalid(void) @@ -1325,9 +1324,10 @@ static void test_rx_priv_interleave(void) int err; bt_mesh_test_cfg_set(&rx_cfg, BEACON_INTERVAL_WAIT_TIME); + bt_mesh_crypto_init(); k_sem_init(&observer_sem, 0, 1); - err = bt_mesh_private_beacon_key(net_key, priv_beacon_key); + err = bt_mesh_private_beacon_key(net_key, &priv_beacon_key); if (err) { FAIL("Unable to generate beacon key"); } @@ -1362,7 +1362,7 @@ static void test_rx_priv_interleave(void) expected_beacon = BEACON_TYPE_PRIVATE; - err = bt_mesh_private_beacon_key(net_key_new, priv_beacon_key); + err = bt_mesh_private_beacon_key(net_key_new, &priv_beacon_key); ASSERT_TRUE(wait_for_beacon(private_beacon_check, false)); ASSERT_EQUAL(0x03, beacon.flags); diff --git a/tests/bsim/bluetooth/mesh/src/test_blob.c b/tests/bsim/bluetooth/mesh/src/test_blob.c index fe6deceaad73..851357298a4b 100644 --- a/tests/bsim/bluetooth/mesh/src/test_blob.c +++ b/tests/bsim/bluetooth/mesh/src/test_blob.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "mesh_test.h" -#include "settings_test_backend.h" #include "dfu_blob_common.h" #include "friendship_common.h" #include "mesh/blob.h" @@ -1454,7 +1453,7 @@ static void test_cli_stop(void) int err; if (!recover_settings) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); } bt_mesh_test_cfg_set(NULL, 1000); @@ -1553,7 +1552,7 @@ static void srv_check_reboot_and_continue(void) static void test_srv_stop(void) { if (!recover_settings) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); } bt_mesh_test_cfg_set(NULL, 1000); diff --git a/tests/bsim/bluetooth/mesh/src/test_dfu.c b/tests/bsim/bluetooth/mesh/src/test_dfu.c index 3dccb31d7daa..b2824f54b46d 100644 --- a/tests/bsim/bluetooth/mesh/src/test_dfu.c +++ b/tests/bsim/bluetooth/mesh/src/test_dfu.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "mesh_test.h" -#include "settings_test_backend.h" #include "mesh/dfd_srv_internal.h" #include "mesh/dfu_slot.h" #include "mesh/adv.h" @@ -417,7 +416,7 @@ static void dist_self_update_prov_and_conf(uint16_t addr) static void target_prov_and_conf(uint16_t addr, struct bind_params *params, size_t len) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); provision(addr); common_configure(addr); @@ -519,7 +518,7 @@ static void test_dist_dfu(void) { enum bt_mesh_dfd_status status; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &dist_comp); dist_prov_and_conf(DIST_ADDR); @@ -544,7 +543,7 @@ static void test_dist_dfu_self_update(void) ASSERT_TRUE(dfu_targets_cnt > 0); - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &dist_comp_self_update); dist_self_update_prov_and_conf(DIST_ADDR); @@ -584,7 +583,7 @@ static void test_dist_dfu_slot_create(void) ASSERT_TRUE(CONFIG_BT_MESH_DFU_SLOT_CNT >= 3, "CONFIG_BT_MESH_DFU_SLOT_CNT must be at least 3"); - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &dist_comp); @@ -752,7 +751,7 @@ static void target_test_effect(enum bt_mesh_dfu_effect effect) { dfu_target_effect = effect; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &target_comp); target_prov_and_conf_default(); @@ -914,7 +913,7 @@ static void cli_common_fail_on_init(void) { const struct bt_mesh_dfu_slot *slot; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, 300); bt_mesh_device_setup(&prov, &cli_comp); dist_prov_and_conf(DIST_ADDR); @@ -1407,7 +1406,7 @@ static void target_prov_and_conf_with_imposer(void) static void common_fail_on_target_init(const struct bt_mesh_comp *comp) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, 300); bt_mesh_device_setup(&prov, comp); @@ -1507,7 +1506,7 @@ static void test_target_dfu_stop(void) dfu_target_effect = BT_MESH_DFU_EFFECT_NONE; if (!recover) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); common_fail_on_target_init(expected_stop_phase == BT_MESH_DFU_PHASE_VERIFY_FAIL ? diff --git a/tests/bsim/bluetooth/mesh/src/test_lcd.c b/tests/bsim/bluetooth/mesh/src/test_lcd.c index 1dc5fc70054f..dc819b8d0dec 100644 --- a/tests/bsim/bluetooth/mesh/src/test_lcd.c +++ b/tests/bsim/bluetooth/mesh/src/test_lcd.c @@ -123,10 +123,15 @@ static void prov_and_conf(struct bt_mesh_test_cfg cfg) static void target_node_alloc(struct bt_mesh_comp comp, struct bt_mesh_test_cfg cfg) { struct bt_mesh_cdb_node *node; + int err; node = bt_mesh_cdb_node_alloc(test_va_uuid, cfg.addr, comp.elem_count, 0); ASSERT_TRUE(node); - memcpy(node->dev_key, cfg.dev_key, 16); + + err = bt_mesh_cdb_node_key_import(node, cfg.dev_key); + if (err) { + FAIL("Unable to import the target node device key (err: %d)", err); + } } /* Assert equality between local data and merged sample data */ diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index db780cb45989..a054a423f40a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -5,12 +5,11 @@ */ #include "mesh_test.h" -#include "settings_test_backend.h" #include #include #include "mesh/net.h" #include "mesh/app_keys.h" -#include "mesh/crypto.h" +#include "mesh/keys.h" #include #define LOG_MODULE_NAME test_persistence @@ -405,7 +404,10 @@ static void provisioner_setup(void) /* Adding a subnet for test_netkey as it is not primary. */ subnet = bt_mesh_cdb_subnet_alloc(test_netkey_idx); ASSERT_TRUE(subnet != NULL); - memcpy(subnet->keys[0].net_key, test_netkey, 16); + err = bt_mesh_cdb_subnet_key_import(subnet, 0, test_netkey); + if (err) { + FAIL("Unable to import test_netkey (err: %d)", err); + } bt_mesh_cdb_subnet_store(subnet); err = bt_mesh_cfg_cli_net_key_add(0, TEST_PROV_ADDR, test_netkey_idx, test_netkey, &status); @@ -418,7 +420,7 @@ static void provisioner_setup(void) static void test_provisioning_data_save(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); if (device_setup_and_self_provision()) { @@ -443,8 +445,10 @@ static void test_provisioning_data_load(void) /* explicitly verify that the keys resolves for a given addr and net_idx */ struct bt_mesh_msg_ctx ctx; struct bt_mesh_net_tx tx = { .ctx = &ctx }; - const uint8_t *dkey; + const struct bt_mesh_key *dkey; uint8_t aid; + uint8_t net_key[16]; + uint8_t dev_key[16]; tx.ctx->addr = TEST_ADDR; tx.ctx->net_idx = test_netkey_idx; @@ -456,12 +460,18 @@ static void test_provisioning_data_load(void) FAIL("Failed to resolve keys"); } - if (memcmp(dkey, test_devkey, sizeof(test_devkey))) { + ASSERT_OK(bt_mesh_key_export(dev_key, dkey)); + LOG_HEXDUMP_INF(dev_key, sizeof(dev_key), "Exported device key:"); + + if (memcmp(dev_key, test_devkey, sizeof(test_devkey))) { FAIL("Resolved dev_key does not match"); } - if (memcmp(tx.sub->keys[0].net, test_netkey, sizeof(test_netkey))) { - FAIL("Resolved net_key does not match"); + ASSERT_OK(bt_mesh_key_export(net_key, &tx.sub->keys[0].net)); + LOG_HEXDUMP_INF(net_key, sizeof(net_key), "Exported network key:"); + + if (memcmp(net_key, test_netkey, sizeof(test_netkey))) { + FAIL("Resolved raw value of the net_key does not match"); } if (tx.sub->kr_phase != ((test_flags & 1) << 1)) { @@ -589,7 +599,7 @@ static void node_configure(void) static void test_access_data_save(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); if (device_setup_and_self_provision()) { @@ -810,7 +820,7 @@ static void test_cfg_save(void) ASSERT_TRUE(current_stack_cfg != NULL); - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); if (device_setup_and_self_provision()) { @@ -927,7 +937,7 @@ static int mesh_settings_load_cb(const char *key, size_t len, settings_read_cb r static void test_reprovisioning_device(void) { if (clear_settings) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); } bt_mesh_test_cfg_set(NULL, WAIT_TIME); @@ -961,7 +971,7 @@ static void test_reprovisioning_provisioner(void) int err; bool status; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); provisioner_setup(); diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 641bcc23288d..2f6e43469c56 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -8,8 +8,8 @@ #include "mesh_test.h" #include "mesh/access.h" #include "mesh/net.h" +#include "mesh/crypto.h" #include "argparse.h" -#include "settings_test_backend.h" #include #include @@ -1074,7 +1074,8 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) node = bt_mesh_cdb_node_get(current_dev_addr); ASSERT_TRUE(node); - memcpy(prev_node_dev_key, node->dev_key, 16); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key), + "Can't export device key from cdb"); LOG_INF("Testing DevKey refresh..."); for (int i = 0; i < PROV_REPROV_COUNT; i++) { @@ -1084,8 +1085,9 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20))); /* Check that CDB has updated Device Key for the node. */ - ASSERT_TRUE(memcmp(prev_node_dev_key, node->dev_key, 16)); - memcpy(prev_node_dev_key, node->dev_key, 16); + ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key)); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key), + "Can't export device key from cdb"); /* Check device key by adding appkey. */ ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key, @@ -1104,8 +1106,9 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) ASSERT_OK(k_sem_take(&reprov_sem, K_SECONDS(20))); /* Check that CDB has updated Device Key for the node. */ - ASSERT_TRUE(memcmp(prev_node_dev_key, node->dev_key, 16)); - memcpy(prev_node_dev_key, node->dev_key, 16); + ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key)); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key), + "Can't export device key from cdb"); /* Check that Composition Data Page 128 is now Page 0. */ net_buf_simple_reset(&new_dev_comp); @@ -1133,20 +1136,26 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) /* Check that device doesn't respond to old address with old and new device key. */ struct bt_mesh_cdb_node *prev_node; + uint8_t tmp[16]; prev_node = bt_mesh_cdb_node_alloc((uint8_t[16]) {}, current_dev_addr - 1, 1, 0); ASSERT_TRUE(node); - memcpy(prev_node->dev_key, prev_node_dev_key, 16); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, prev_node_dev_key), + "Can't import device key into cdb"); ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0, test_app_key, &status)); - memcpy(prev_node->dev_key, node->dev_key, 16); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, tmp), + "Can't export device key from cdb"); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_import(prev_node, tmp), + "Can't import device key into cdb"); ASSERT_EQUAL(-ETIMEDOUT, bt_mesh_cfg_cli_app_key_add(0, current_dev_addr - 1, 0, 0, test_app_key, &status)); bt_mesh_cdb_node_del(prev_node, false); /* Check that CDB has updated Device Key for the node. */ - ASSERT_TRUE(memcmp(prev_node_dev_key, node->dev_key, 16)); - memcpy(prev_node_dev_key, node->dev_key, 16); + ASSERT_TRUE(bt_mesh_key_compare(prev_node_dev_key, &node->dev_key)); + ASSERT_OK_MSG(bt_mesh_cdb_node_key_export(node, prev_node_dev_key), + "Can't export device key from cdb"); /* Check new device address by adding appkey. */ ASSERT_OK(bt_mesh_cfg_cli_app_key_add(0, current_dev_addr, 0, 0, test_app_key, @@ -1165,9 +1174,7 @@ static void test_provisioner_pb_remote_client_nppi_robustness(void) */ static void test_device_pb_remote_server_unproved(void) { -#if defined(CONFIG_BT_SETTINGS) - settings_test_backend_clear(); -#endif + bt_mesh_test_host_files_remove(); device_pb_remote_server_setup_unproved(&rpr_srv_comp); @@ -1180,9 +1187,7 @@ static void test_device_pb_remote_server_unproved(void) */ static void test_device_pb_remote_server_unproved_unresponsive(void) { -#if defined(CONFIG_BT_SETTINGS) - settings_test_backend_clear(); -#endif + bt_mesh_test_host_files_remove(); device_pb_remote_server_setup_unproved(&rpr_srv_comp_unresponsive); k_sem_init(&pdu_send_sem, 0, 1); @@ -1206,7 +1211,7 @@ static void test_device_pb_remote_server_proved(void) */ static void test_device_pb_remote_server_nppi_robustness(void) { - uint8_t prev_dev_key[16]; + struct bt_mesh_key prev_dev_key; k_sem_init(&prov_sem, 0, 1); k_sem_init(&reprov_sem, 0, 1); @@ -1220,7 +1225,7 @@ static void test_device_pb_remote_server_nppi_robustness(void) ASSERT_OK(k_sem_take(&prov_sem, K_SECONDS(20))); const uint16_t initial_addr = bt_mesh_primary_addr(); - memcpy(prev_dev_key, bt_mesh.dev_key, 16); + memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)); LOG_INF("Enabling PB-Remote server"); ASSERT_OK(bt_mesh_prov_enable(BT_MESH_PROV_REMOTE)); @@ -1235,8 +1240,8 @@ static void test_device_pb_remote_server_nppi_robustness(void) * been changed. */ k_sleep(K_SECONDS(2)); - ASSERT_TRUE(memcmp(prev_dev_key, bt_mesh.dev_key, 16)); - memcpy(prev_dev_key, bt_mesh.dev_key, 16); + ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key))); + memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)); } /* Test Node Composition Refresh procedure robustness. */ @@ -1263,8 +1268,8 @@ static void test_device_pb_remote_server_nppi_robustness(void) * been changed. */ k_sleep(K_SECONDS(2)); - ASSERT_TRUE(memcmp(prev_dev_key, bt_mesh.dev_key, 16)); - memcpy(prev_dev_key, bt_mesh.dev_key, 16); + ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key))); + memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)); } /* Node Address Refresh robustness. */ @@ -1277,8 +1282,8 @@ static void test_device_pb_remote_server_nppi_robustness(void) * been changed. */ k_sleep(K_SECONDS(2)); - ASSERT_TRUE(memcmp(prev_dev_key, bt_mesh.dev_key, 16)); - memcpy(prev_dev_key, bt_mesh.dev_key, 16); + ASSERT_TRUE(memcmp(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key))); + memcpy(&prev_dev_key, &bt_mesh.dev_key, sizeof(struct bt_mesh_key)); } PASS(); @@ -1293,7 +1298,7 @@ static void test_provisioner_pb_remote_client_ncrp_provision(void) uint16_t pb_remote_server_addr; uint8_t status; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); provisioner_pb_remote_client_setup(); /* Provision the 2nd device over PB-Adv. */ @@ -1420,7 +1425,7 @@ static void test_provisioner_pb_remote_client_ncrp_second_time(void) */ static void test_device_pb_remote_server_ncrp_prepare(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); device_pb_remote_server_setup_unproved(&rpr_srv_comp); LOG_INF("Preparing for Composition Data change"); diff --git a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c index 512d16505cae..6af09ee52a9a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_replay_cache.c +++ b/tests/bsim/bluetooth/mesh/src/test_replay_cache.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "mesh_test.h" -#include "settings_test_backend.h" #include "mesh/mesh.h" #include "mesh/net.h" #include "mesh/rpl.h" @@ -125,7 +124,7 @@ static void rx_sar_conf(void) static void test_tx_immediate_replay_attack(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_setup(); tx_sar_conf(); @@ -174,7 +173,7 @@ static void test_tx_immediate_replay_attack(void) static void test_rx_immediate_replay_attack(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_setup(); rx_sar_conf(); bt_mesh_test_ra_cb_setup(rx_ended); @@ -188,7 +187,7 @@ static void test_rx_immediate_replay_attack(void) static void test_tx_power_replay_attack(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_setup(); tx_sar_conf(); @@ -321,7 +320,7 @@ static bool ivi_update_toggle(void) static void test_rx_rpl_frag(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_setup(); k_sleep(K_SECONDS(10)); @@ -387,7 +386,7 @@ static void test_rx_rpl_frag(void) static void test_tx_rpl_frag(void) { - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_setup(); k_sleep(K_SECONDS(10)); diff --git a/tests/bsim/bluetooth/mesh/src/test_sar.c b/tests/bsim/bluetooth/mesh/src/test_sar.c index b96c7c45219f..5d23233efa2c 100644 --- a/tests/bsim/bluetooth/mesh/src/test_sar.c +++ b/tests/bsim/bluetooth/mesh/src/test_sar.c @@ -7,12 +7,7 @@ */ #include "mesh_test.h" -#if CONFIG_BT_SETTINGS -#include "settings_test_backend.h" -#endif - #include - #include LOG_MODULE_REGISTER(test_sar, LOG_LEVEL_INF); @@ -263,7 +258,7 @@ static void test_srv_cfg_store(void) struct bt_mesh_sar_rx rx_cfg; struct bt_mesh_sar_tx tx_cfg; - settings_test_backend_clear(); + bt_mesh_test_host_files_remove(); bt_mesh_test_cfg_set(NULL, WAIT_TIME); bt_mesh_device_setup(&prov, &comp); From df88664864f50debd33aeb0ed18c00374c6356c1 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 10 Jun 2023 20:34:41 +0200 Subject: [PATCH 0232/2042] subsys/net/ppp: Make NET L2 PPP use net_if properly Currently, the L2 PPP subsystem is not using the network interface subsystem appropriately. Here are the issues: 1. net_if_up hidden away internally in net L2 PPP 2. net_if_down not used at all... 3. net_if_carrier_on / off is not used, a workaround is used instead, which results in duplicated code 4. L2 PPP does not listen for network events, instead it needs the workaround callbacks from drivers. 5. The carrier_on workaround is delegated to a complex and broken sys work queue item. This commit fixes all above issues. net_if_up/down and net_if_carrier_on/off now work as expected. workaround for carrier_on/off has been removed. Signed-off-by: Bjarki Arge Andreasen --- include/zephyr/net/ppp.h | 33 +----- subsys/net/l2/ppp/Kconfig | 12 +-- subsys/net/l2/ppp/fsm.c | 4 + subsys/net/l2/ppp/lcp.c | 5 - subsys/net/l2/ppp/ppp_l2.c | 209 +++++++++---------------------------- 5 files changed, 60 insertions(+), 203 deletions(-) diff --git a/include/zephyr/net/ppp.h b/include/zephyr/net/ppp.h index f073001af336..686f34aecf2b 100644 --- a/include/zephyr/net/ppp.h +++ b/include/zephyr/net/ppp.h @@ -384,14 +384,6 @@ struct ppp_context { /** PPP startup worker. */ struct k_work_delayable startup; - /** Carrier ON/OFF handler worker. This is used to create - * network interface UP/DOWN event when PPP L2 driver - * notices carrier ON/OFF situation. We must not create another - * network management event from inside management handler thus - * we use worker thread to trigger the UP/DOWN event. - */ - struct k_work carrier_work; - struct { /** Finite state machine for LCP */ struct ppp_fsm fsm; @@ -476,6 +468,9 @@ struct ppp_context { /** Network interface related to this PPP connection */ struct net_if *iface; + /** Network management callback structure */ + struct net_mgmt_event_callback mgmt_evt_cb; + /** Current phase of PPP link */ enum ppp_phase phase; @@ -494,12 +489,6 @@ struct ppp_context { /** Is PPP ready to receive packets */ uint16_t is_ready_to_serve : 1; - /** Is PPP L2 enabled or not */ - uint16_t is_enabled : 1; - - /** PPP startup pending */ - uint16_t is_startup_pending : 1; - /** PPP enable pending */ uint16_t is_enable_done : 1; @@ -522,22 +511,6 @@ struct ppp_context { uint16_t is_pap_open : 1; }; -/** - * @brief Inform PPP L2 driver that carrier is detected. - * This happens when cable is connected etc. - * - * @param iface Network interface - */ -void net_ppp_carrier_on(struct net_if *iface); - -/** - * @brief Inform PPP L2 driver that carrier was lost. - * This happens when cable is disconnected etc. - * - * @param iface Network interface - */ -void net_ppp_carrier_off(struct net_if *iface); - /** * @brief Initialize PPP L2 stack for a given interface * diff --git a/subsys/net/l2/ppp/Kconfig b/subsys/net/l2/ppp/Kconfig index 38beab30bdb5..e1ccbd044f99 100644 --- a/subsys/net/l2/ppp/Kconfig +++ b/subsys/net/l2/ppp/Kconfig @@ -4,21 +4,13 @@ menuconfig NET_L2_PPP bool "Point-to-point (PPP) support [EXPERIMENTAL]" select EXPERIMENTAL + select NET_MGMT + select NET_MGMT_EVENT help Add support for PPP. if NET_L2_PPP -config NET_L2_PPP_DELAY_STARTUP_MS - int "PPP delay startup ms" - default 0 - help - If the PPP starts too fast, it is possible to delay it - a bit. This is mostly useful in debugging if you want the - device be fully up before PPP handshake is started. - Wait amount of milliseconds before starting PPP. Value 0 disables - the wait. - config NET_L2_PPP_TIMEOUT int "Maximum timeout in ms for Configure-Req" default 3000 diff --git a/subsys/net/l2/ppp/fsm.c b/subsys/net/l2/ppp/fsm.c index bceffa1f9011..7e2c739e779f 100644 --- a/subsys/net/l2/ppp/fsm.c +++ b/subsys/net/l2/ppp/fsm.c @@ -391,6 +391,10 @@ int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface, iface = ppp_fsm_iface(fsm); } + if (!net_if_is_carrier_ok(iface)) { + return -ENETDOWN; + } + if (fsm) { protocol = fsm->protocol; } diff --git a/subsys/net/l2/ppp/lcp.c b/subsys/net/l2/ppp/lcp.c index 76fbfc21936d..0d46b5b66fa1 100644 --- a/subsys/net/l2/ppp/lcp.c +++ b/subsys/net/l2/ppp/lcp.c @@ -206,11 +206,6 @@ static void lcp_finished(struct ppp_fsm *fsm) lcp.fsm); ppp_link_terminated(ctx); - - /* take the remainder down */ - ppp_mgmt_raise_carrier_off_event(ctx->iface); - - ppp_if_carrier_down(ctx->iface); } #if defined(CONFIG_NET_L2_PPP_OPTION_MRU) diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index 6e08825f8b04..8f2bfac7d545 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -195,62 +195,22 @@ static void ppp_close(struct ppp_context *ctx) { if (ppp_lcp) { ppp_lcp->close(ctx, "Shutdown"); + } else { + ppp_change_phase(ctx, PPP_DEAD); } } -static void ppp_lower_up(struct ppp_context *ctx) -{ - if (ppp_lcp) { - ppp_lcp->lower_up(ctx); - } -} - -static void start_ppp(struct ppp_context *ctx) +static void ppp_open(struct ppp_context *ctx) { ppp_change_phase(ctx, PPP_ESTABLISH); - ppp_lower_up(ctx); - if (ppp_lcp) { NET_DBG("Starting LCP"); + ppp_lcp->lower_up(ctx); ppp_lcp->open(ctx); } } -static int ppp_enable(struct net_if *iface, bool state) -{ - const struct ppp_api *ppp = - net_if_get_device(iface)->api; - struct ppp_context *ctx = net_if_l2_data(iface); - - - if (ctx->is_enabled == state) { - return 0; - } - - ctx->is_enabled = state; - - if (!state) { - ppp_close(ctx); - - if (ppp->stop) { - ppp->stop(net_if_get_device(iface)); - } - } else { - if (ppp->start) { - ppp->start(net_if_get_device(iface)); - } - - if (ctx->is_startup_pending) { - ctx->is_enable_done = true; - } else { - start_ppp(ctx); - } - } - - return 0; -} - static enum net_l2_flags ppp_flags(struct net_if *iface) { struct ppp_context *ctx = net_if_l2_data(iface); @@ -258,70 +218,7 @@ static enum net_l2_flags ppp_flags(struct net_if *iface) return ctx->ppp_l2_flags; } -NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, ppp_enable, ppp_flags); - -/* A workaround for PPP L2 not yet supporting net_if_carrier_on/off(). */ -void ppp_if_carrier_down(struct net_if *iface) -{ - net_if_flag_clear(iface, NET_IF_UP); - net_mgmt_event_notify(NET_EVENT_IF_DOWN, iface); - net_ipv4_autoconf_reset(iface); -} - -static void carrier_on_off(struct k_work *work) -{ - struct ppp_context *ctx = CONTAINER_OF(work, struct ppp_context, - carrier_work); - bool ppp_carrier_up; - - if (ctx->iface == NULL) { - return; - } - - ppp_carrier_up = atomic_test_bit(&ctx->flags, PPP_CARRIER_UP); - - if (ppp_carrier_up == (bool) ctx->is_net_carrier_up) { - return; - } - - ctx->is_net_carrier_up = ppp_carrier_up; - - NET_DBG("Carrier %s for interface %p", ppp_carrier_up ? "ON" : "OFF", - ctx->iface); - - if (ppp_carrier_up) { - ppp_mgmt_raise_carrier_on_event(ctx->iface); - net_if_up(ctx->iface); - } else { - if (ppp_lcp) { - ppp_lcp->close(ctx, "Shutdown"); - /* signaling for the carrier off event is done from the LCP callback */ - } else { - ppp_change_phase(ctx, PPP_DEAD); - - ppp_mgmt_raise_carrier_off_event(ctx->iface); - ppp_if_carrier_down(ctx->iface); - } - } -} - -void net_ppp_carrier_on(struct net_if *iface) -{ - struct ppp_context *ctx = net_if_l2_data(iface); - - if (!atomic_test_and_set_bit(&ctx->flags, PPP_CARRIER_UP)) { - k_work_submit(&ctx->carrier_work); - } -} - -void net_ppp_carrier_off(struct net_if *iface) -{ - struct ppp_context *ctx = net_if_l2_data(iface); - - if (atomic_test_and_clear_bit(&ctx->flags, PPP_CARRIER_UP)) { - k_work_submit(&ctx->carrier_work); - } -} +NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, NULL, ppp_flags); #if defined(CONFIG_NET_SHELL) static int get_ppp_context(int idx, struct ppp_context **ctx, @@ -419,45 +316,6 @@ const struct ppp_protocol_handler *ppp_lcp_get(void) return ppp_lcp; } -static void ppp_startup(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct ppp_context *ctx = CONTAINER_OF(dwork, struct ppp_context, - startup); - int count = 0; - - NET_DBG("PPP %p startup for interface %p", ctx, ctx->iface); - - STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) { - if (proto->protocol == PPP_LCP) { - ppp_lcp = proto; - } - - proto->init(ctx); - count++; - } - - if (count == 0) { - NET_ERR("There are no PPP protocols configured!"); - goto bail_out; - } - - if (ppp_lcp == NULL) { - NET_ERR("No LCP found!"); - goto bail_out; - } - - ctx->is_ready_to_serve = true; - -bail_out: - ctx->is_startup_pending = false; - - if (ctx->is_enable_done) { - start_ppp(ctx); - ctx->is_enable_done = false; - } -} - void ppp_queue_pkt(struct net_pkt *pkt) { k_fifo_put(&tx_queue, pkt); @@ -485,9 +343,32 @@ static void tx_handler(void) } } +static void net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + struct ppp_context *ctx = net_if_l2_data(iface); + + if (net_if_is_carrier_ok(iface)) { + ppp_mgmt_raise_carrier_on_event(iface); + } else { + ppp_mgmt_raise_carrier_off_event(iface); + } + + if (mgmt_event == NET_EVENT_IF_UP) { + ppp_open(ctx); + return; + } + + if (mgmt_event == NET_EVENT_IF_DOWN) { + ppp_close(ctx); + return; + } +} + void net_ppp_init(struct net_if *iface) { struct ppp_context *ctx = net_if_l2_data(iface); + uint8_t count = 0; NET_DBG("Initializing PPP L2 %p for iface %p", ctx, iface); @@ -496,21 +377,33 @@ void net_ppp_init(struct net_if *iface) ctx->ppp_l2_flags = NET_L2_MULTICAST | NET_L2_POINT_TO_POINT; ctx->iface = iface; - k_work_init(&ctx->carrier_work, carrier_on_off); - #if defined(CONFIG_NET_SHELL) k_sem_init(&ctx->shell.wait_echo_reply, 0, K_SEM_MAX_LIMIT); #endif - /* TODO: Unify the startup worker code so that we can save - * some memory if there are more than one PPP context in the - * system. The issue is not very likely as typically there - * would be only one PPP network interface in the system. - */ - k_work_init_delayable(&ctx->startup, ppp_startup); + net_mgmt_init_event_callback(&ctx->mgmt_evt_cb, net_ppp_mgmt_evt_handler, + (NET_EVENT_IF_UP | NET_EVENT_IF_DOWN)); + + net_mgmt_add_event_callback(&ctx->mgmt_evt_cb); + + STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) { + if (proto->protocol == PPP_LCP) { + ppp_lcp = proto; + } - ctx->is_startup_pending = true; + proto->init(ctx); + count++; + } - k_work_reschedule(&ctx->startup, - K_MSEC(CONFIG_NET_L2_PPP_DELAY_STARTUP_MS)); + if (count == 0) { + NET_ERR("There are no PPP protocols configured!"); + return; + } + + if (ppp_lcp == NULL) { + NET_ERR("No LCP found!"); + return; + } + + ctx->is_ready_to_serve = true; } From 22152915abd5766ea149558be47df0863e127a95 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Sat, 10 Jun 2023 22:34:29 +0200 Subject: [PATCH 0233/2042] drivers/gsm_ppp: Update existing modules to use PPP L2 This commit replaces the workarounds spread around the drivers and subsystems with the updated PPP L2 interface. Signed-off-by: Bjarki Arge Andreasen --- drivers/modem/gsm_ppp.c | 26 ++++++++----------- drivers/net/ppp.c | 4 +-- samples/net/sockets/echo_server/README.rst | 3 --- .../net/sockets/echo_server/overlay-ppp.conf | 13 ---------- subsys/net/l2/ppp/ppp_l2.c | 8 +++++- tests/net/ppp/driver/prj.conf | 1 - 6 files changed, 19 insertions(+), 36 deletions(-) delete mode 100644 samples/net/sockets/echo_server/overlay-ppp.conf diff --git a/drivers/modem/gsm_ppp.c b/drivers/modem/gsm_ppp.c index f10e9fc149d4..7eca5f669c92 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -614,8 +614,8 @@ static struct net_if *ppp_net_if(void) static void set_ppp_carrier_on(struct gsm_modem *gsm) { - static const struct ppp_api *api; const struct device *ppp_dev = device_get_binding(CONFIG_NET_PPP_DRV_NAME); + const struct ppp_api *api = (const struct ppp_api *)ppp_dev->api; struct net_if *iface = gsm->iface; int ret; @@ -624,21 +624,13 @@ static void set_ppp_carrier_on(struct gsm_modem *gsm) return; } - if (api == NULL) { - api = (const struct ppp_api *)ppp_dev->api; + ret = api->start(ppp_dev); - /* For the first call, we want to call ppp_start()... */ - ret = api->start(ppp_dev); - if (ret < 0) { - LOG_ERR("ppp start returned %d", ret); - } - } else { - /* ...but subsequent calls should be to ppp_enable() */ - ret = net_if_l2(iface)->enable(iface, true); - if (ret < 0) { - LOG_ERR("ppp l2 enable returned %d", ret); - } + if (ret < 0) { + LOG_ERR("ppp start returned %d", ret); } + + net_if_up(iface); } static void query_rssi(struct gsm_modem *gsm, bool lock) @@ -1177,6 +1169,8 @@ void gsm_ppp_start(const struct device *dev) void gsm_ppp_stop(const struct device *dev) { + const struct device *ppp_dev = device_get_binding(CONFIG_NET_PPP_DRV_NAME); + const struct ppp_api *api = (const struct ppp_api *)ppp_dev->api; struct gsm_modem *gsm = dev->data; struct net_if *iface = gsm->iface; struct k_work_sync work_sync; @@ -1191,11 +1185,13 @@ void gsm_ppp_stop(const struct device *dev) (void)k_work_cancel_delayable_sync(&gsm->rssi_work_handle, &work_sync); } + api->stop(ppp_dev); + gsm_ppp_lock(gsm); /* wait for the interface to be properly down */ if (net_if_is_up(iface)) { - (void)(net_if_l2(iface)->enable(iface, false)); + net_if_down(ppp_net_if()); (void)k_sem_take(&gsm->sem_if_down, K_FOREVER); } diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 67ebc0f3b0c0..4db963beeb7c 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -1046,8 +1046,7 @@ static int ppp_start(const struct device *dev) } #endif /* !CONFIG_NET_TEST */ - net_ppp_carrier_on(context->iface); - + ARG_UNUSED(context); return 0; } @@ -1055,7 +1054,6 @@ static int ppp_stop(const struct device *dev) { struct ppp_driver_context *context = dev->data; - net_ppp_carrier_off(context->iface); context->modem_init_done = false; return 0; } diff --git a/samples/net/sockets/echo_server/README.rst b/samples/net/sockets/echo_server/README.rst index 98260d798730..fed7ef00a41e 100644 --- a/samples/net/sockets/echo_server/README.rst +++ b/samples/net/sockets/echo_server/README.rst @@ -48,9 +48,6 @@ echo-server directory: This overlay config enables support for two QEMU's when simulating IEEE 802.15.4 network that are connected together. -- :file:`overlay-ppp.conf` - This overlay config enables support for PPP (Point-to-Point Protocol). - - :file:`overlay-tls.conf` This overlay config enables support for TLS. diff --git a/samples/net/sockets/echo_server/overlay-ppp.conf b/samples/net/sockets/echo_server/overlay-ppp.conf deleted file mode 100644 index 358b8b584e4e..000000000000 --- a/samples/net/sockets/echo_server/overlay-ppp.conf +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG_NET_DRIVERS=y -CONFIG_NET_PPP=y -CONFIG_NET_L2_PPP=y -CONFIG_NET_STATISTICS_PPP=y -CONFIG_NET_STATISTICS_USER_API=y - -# Wait milliseconds before starting ppp handshakes -CONFIG_NET_L2_PPP_DELAY_STARTUP_MS=5000 - -# Debug options in order to see the sent and received packets -#CONFIG_NET_PPP_LOG_LEVEL_DBG=y -#CONFIG_NET_L2_PPP_LOG_LEVEL_DBG=y -#CONFIG_UART_CONSOLE_LOG_LEVEL_DBG=y diff --git a/subsys/net/l2/ppp/ppp_l2.c b/subsys/net/l2/ppp/ppp_l2.c index 8f2bfac7d545..5e04668e508a 100644 --- a/subsys/net/l2/ppp/ppp_l2.c +++ b/subsys/net/l2/ppp/ppp_l2.c @@ -346,7 +346,13 @@ static void tx_handler(void) static void net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { - struct ppp_context *ctx = net_if_l2_data(iface); + struct ppp_context *ctx; + + if (net_if_l2(iface) != &NET_L2_GET_NAME(PPP)) { + return; + } + + ctx = net_if_l2_data(iface); if (net_if_is_carrier_ok(iface)) { ppp_mgmt_raise_carrier_on_event(iface); diff --git a/tests/net/ppp/driver/prj.conf b/tests/net/ppp/driver/prj.conf index d1421d02487f..02f619cf24fd 100644 --- a/tests/net/ppp/driver/prj.conf +++ b/tests/net/ppp/driver/prj.conf @@ -21,7 +21,6 @@ CONFIG_NET_BUF_TX_COUNT=10 CONFIG_NET_IF_MAX_IPV6_COUNT=3 CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6 CONFIG_NET_IPV6_ND=n -CONFIG_NET_L2_PPP_DELAY_STARTUP_MS=0 CONFIG_NET_CONFIG_AUTO_INIT=n CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y From 070122f55b6460ea38ceff3cbcd3d0dce3c517be Mon Sep 17 00:00:00 2001 From: Henrik Eriksen Date: Thu, 25 May 2023 10:57:48 +0200 Subject: [PATCH 0234/2042] bluetooth: tester: Added support for testing Hearing Access Service (HAS). - Initialisation of Hearing Access Service. - Adding/removing presets. - Changing preset properties. - Changing preset name. Signed-off-by: Henrik Eriksen --- tests/bluetooth/tester/CMakeLists.txt | 4 + tests/bluetooth/tester/overlay-le-audio.conf | 5 + tests/bluetooth/tester/src/btp/btp.h | 7 +- tests/bluetooth/tester/src/btp/btp_has.h | 61 ++++++ tests/bluetooth/tester/src/btp/bttester.h | 3 + tests/bluetooth/tester/src/btp_core.c | 13 ++ tests/bluetooth/tester/src/btp_has.c | 215 +++++++++++++++++++ 7 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 tests/bluetooth/tester/src/btp/btp_has.h create mode 100644 tests/bluetooth/tester/src/btp_has.c diff --git a/tests/bluetooth/tester/CMakeLists.txt b/tests/bluetooth/tester/CMakeLists.txt index 2a407f2d20a8..e44159223fc1 100644 --- a/tests/bluetooth/tester/CMakeLists.txt +++ b/tests/bluetooth/tester/CMakeLists.txt @@ -35,3 +35,7 @@ endif() if(CONFIG_BT_BAP_UNICAST) target_sources(app PRIVATE src/btp_bap.c) endif() + +if(CONFIG_BT_HAS) + target_sources(app PRIVATE src/btp_has.c) +endif() diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index e4a79bc9b2c0..1645f10c8db7 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -45,3 +45,8 @@ CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y # IAS CONFIG_BT_IAS=y CONFIG_BT_IAS_CLIENT=y + +# HAS +CONFIG_BT_HAS=y +CONFIG_BT_HAS_PRESET_COUNT=5 +CONFIG_BT_HAS_PRESET_NAME_DYNAMIC=y diff --git a/tests/bluetooth/tester/src/btp/btp.h b/tests/bluetooth/tester/src/btp/btp.h index c204e6c1d55f..3edbf6b036fb 100644 --- a/tests/bluetooth/tester/src/btp/btp.h +++ b/tests/bluetooth/tester/src/btp/btp.h @@ -23,6 +23,7 @@ #include "btp_pacs.h" #include "btp_ascs.h" #include "btp_bap.h" +#include "btp_has.h" #define BTP_MTU 1024 #define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) @@ -45,7 +46,9 @@ #define BTP_SERVICE_ID_PACS 12 #define BTP_SERVICE_ID_ASCS 13 #define BTP_SERVICE_ID_BAP 14 -#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_BAP +#define BTP_SERVICE_ID_HAS 15 + +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_HAS #define BTP_STATUS_SUCCESS 0x00 #define BTP_STATUS_FAILED 0x01 @@ -65,7 +68,7 @@ struct btp_hdr { uint8_t data[]; } __packed; -#define BTP_STATUS 0x00 +#define BTP_STATUS 0x00 struct btp_status { uint8_t code; } __packed; diff --git a/tests/bluetooth/tester/src/btp/btp_has.h b/tests/bluetooth/tester/src/btp/btp_has.h new file mode 100644 index 000000000000..fc87a3f32397 --- /dev/null +++ b/tests/bluetooth/tester/src/btp/btp_has.h @@ -0,0 +1,61 @@ +/* btp_has.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2023 Oticon + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* HAS commands */ +#define BTP_HAS_READ_SUPPORTED_COMMANDS 0x01 +struct btp_has_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_HAS_SET_ACTIVE_INDEX 0x02 +struct btp_has_set_active_index_cmd { + bt_addr_le_t address; + uint8_t index; +} __packed; + +#define BTP_HAS_SET_PRESET_NAME 0x03 +struct btp_has_set_preset_name_cmd { + bt_addr_le_t address; + uint8_t index; + uint8_t length; + char name[0]; +} __packed; + +#define BTP_HAS_REMOVE_PRESET 0x04 +struct btp_has_remove_preset_cmd { + bt_addr_le_t address; + uint8_t index; +} __packed; + +#define BTP_HAS_ADD_PRESET 0x05 +struct btp_has_add_preset_cmd { + bt_addr_le_t address; + uint8_t index; + uint8_t props; + uint8_t length; + char name[0]; +} __packed; + +#define BTP_HAS_SET_PROPERTIES 0x06 +struct btp_has_set_properties_cmd { + bt_addr_le_t address; + uint8_t index; + uint8_t props; +} __packed; + +/* HAS events */ +#define BTP_HAS_EV_OPERATION_COMPLETED 0x80 +struct btp_has_operation_completed_ev { + bt_addr_le_t address; + uint8_t index; + uint8_t opcode; + uint8_t status; + + /* RFU */ + uint8_t flags; +} __packed; diff --git a/tests/bluetooth/tester/src/btp/bttester.h b/tests/bluetooth/tester/src/btp/bttester.h index 7550d036062c..a68cb3c5c737 100644 --- a/tests/bluetooth/tester/src/btp/bttester.h +++ b/tests/bluetooth/tester/src/btp/bttester.h @@ -86,3 +86,6 @@ uint8_t tester_unregister_ascs(void); uint8_t tester_init_bap(void); uint8_t tester_unregister_bap(void); + +uint8_t tester_init_has(void); +uint8_t tester_unregister_has(void); diff --git a/tests/bluetooth/tester/src/btp_core.c b/tests/bluetooth/tester/src/btp_core.c index 5076d7c4a1bd..b0b9a366a93c 100644 --- a/tests/bluetooth/tester/src/btp_core.c +++ b/tests/bluetooth/tester/src/btp_core.c @@ -74,6 +74,9 @@ static uint8_t supported_services(const void *cmd, uint16_t cmd_len, #if defined(CONFIG_BT_VOCS) || defined(CONFIG_BT_VOCS_CLIENT) tester_set_bit(rp->data, BTP_SERVICE_ID_VOCS); #endif /* CONFIG_BT_VOCS */ +#if defined(CONFIG_BT_HAS) || defined(CONFIG_BT_HAS_CLIENT) + tester_set_bit(rp->data, BTP_SERVICE_ID_HAS); +#endif /* CONFIG_BT_HAS */ *rsp_len = sizeof(*rp) + 2; @@ -140,6 +143,11 @@ static uint8_t register_service(const void *cmd, uint16_t cmd_len, status = tester_init_bap(); break; #endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */ +#if defined(CONFIG_BT_HAS) + case BTP_SERVICE_ID_HAS: + status = tester_init_has(); + break; +#endif /* CONFIG_BT_HAS */ default: LOG_WRN("unknown id: 0x%02x", cp->id); status = BTP_STATUS_FAILED; @@ -213,6 +221,11 @@ static uint8_t unregister_service(const void *cmd, uint16_t cmd_len, status = tester_unregister_bap(); break; #endif /* CONFIG_BT_BAP_UNICAST_CLIENT or CONFIG_BT_BAP_UNICAST_SERVER */ +#if defined(CONFIG_BT_HAS) + case BTP_SERVICE_ID_HAS: + status = tester_unregister_has(); + 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_has.c b/tests/bluetooth/tester/src/btp_has.c new file mode 100644 index 000000000000..1ea93a593e7b --- /dev/null +++ b/tests/bluetooth/tester/src/btp_has.c @@ -0,0 +1,215 @@ +/* btp_has.c - Bluetooth HAS Tester */ + +/* + * Copyright (c) 2023 Oticon + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include "btp/btp.h" +#include "zephyr/sys/byteorder.h" +#include "zephyr/arch/common/ffs.h" +#include + +#include +#define LOG_MODULE_NAME bttester_has +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); + +static uint8_t has_supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_has_read_supported_commands_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_HAS_READ_SUPPORTED_COMMANDS); + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t has_set_active_index(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_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; +} + +static uint16_t has_presets; +static char temp_name[BT_HAS_PRESET_NAME_MAX + 1]; + +static uint8_t has_set_preset_name(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_has_set_preset_name_cmd *cp = cmd; + const uint16_t fixed_size = sizeof(*cp); + int err = -1; + + if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) { + int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX); + + memcpy(temp_name, cp->name, name_len); + temp_name[name_len] = '\0'; + err = bt_has_preset_name_change(cp->index, temp_name); + } + return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static uint8_t has_remove_preset(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_has_remove_preset_cmd *cp = cmd; + int err = 0; + + if (cp->index == BT_HAS_PRESET_INDEX_NONE) { + while (has_presets) { + uint8_t index = find_lsb_set(has_presets); + + err = bt_has_preset_unregister(index); + if (err) { + break; + } + has_presets &= ~(1 << (index - 1)); + } + } else { + err = bt_has_preset_unregister(cp->index); + if (!err) { + has_presets &= ~(1 << (cp->index - 1)); + } + } + return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static int has_preset_selected(unsigned char index, bool sync) +{ + return BTP_STATUS_SUCCESS; +} + +static const struct bt_has_preset_ops has_preset_ops = { + has_preset_selected, NULL +}; + +static uint8_t has_add_preset(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_has_add_preset_cmd *cp = cmd; + const uint16_t fixed_size = sizeof(*cp); + int err = -1; + + if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) { + int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX); + + memcpy(temp_name, cp->name, name_len); + temp_name[name_len] = '\0'; + struct bt_has_preset_register_param preset_params = { + cp->index, cp->props, temp_name, &has_preset_ops + }; + err = bt_has_preset_register(&preset_params); + if (!err) { + has_presets |= 1 << (cp->index - 1); + } + } + return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static uint8_t has_set_properties(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_has_set_properties_cmd *cp = cmd; + int err = (cp->props & BT_HAS_PROP_AVAILABLE) ? + bt_has_preset_available(cp->index) : + bt_has_preset_unavailable(cp->index); + + return (err) ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static const struct btp_handler has_handlers[] = { + { + .opcode = BTP_HAS_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = has_supported_commands + }, + { + .opcode = BTP_HAS_SET_ACTIVE_INDEX, + .expect_len = sizeof(struct btp_has_set_active_index_cmd), + .func = has_set_active_index + }, + { + .opcode = BTP_HAS_SET_PRESET_NAME, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = has_set_preset_name + }, + { + .opcode = BTP_HAS_REMOVE_PRESET, + .expect_len = sizeof(struct btp_has_remove_preset_cmd), + .func = has_remove_preset + }, + { + .opcode = BTP_HAS_ADD_PRESET, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = has_add_preset + }, + { + .opcode = BTP_HAS_SET_PROPERTIES, + .expect_len = sizeof(struct btp_has_set_properties_cmd), + .func = has_set_properties + } +}; + +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_register_param params = { + BT_HAS_HEARING_AID_TYPE_BINAURAL, false, true + }; + 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; +} + +uint8_t tester_unregister_has(void) +{ + return BTP_STATUS_SUCCESS; +} From 3cecb92e5384b516c96ceec30e2be368879ce736 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Wed, 14 Jun 2023 13:02:43 +0200 Subject: [PATCH 0235/2042] Bluetooth: controller: Fix CIS peripheral conditional offset_min When config BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START is enabled, the minimum accepted offset value in the CIS_REQ is the minimum defined by the spec. Add define CIS_MIN_OFFSET_MIN with value 500 us, as defined in the Core spec. The previously used value of 400 us was incorrect. Signed-off-by: Morten Priess --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 3 +-- subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h | 3 +++ subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index df1cf4b4e5db..11a217d662fc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -854,8 +854,7 @@ int ull_central_iso_cis_offset_get(uint16_t cis_handle, cig->sync_delay; if (IS_ENABLED(CONFIG_BT_CTLR_JIT_SCHEDULING)) { - *cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US); - + *cis_offset_min = MAX(CIS_MIN_OFFSET_MIN, EVENT_OVERHEAD_CIS_SETUP_US); return 0; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h index f6b4e172e27f..fe19f73b1727 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso_internal.h @@ -12,6 +12,9 @@ (IS_ENABLED(CONFIG_BT_CTLR_CENTRAL_ISO) && \ (cig->lll.role == BT_HCI_ROLE_CENTRAL)) +/* BT Core 5.4, Vol 6, Part B, section 2.4.2.29 */ +#define CIS_MIN_OFFSET_MIN 500U + /* Helper functions to initialize and reset ull_conn_iso module */ int ull_conn_iso_init(void); int ull_conn_iso_reset(void); diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c index 75116c9c7704..1fc0133717e3 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c @@ -104,8 +104,9 @@ uint8_t ll_cis_accept(uint16_t handle) if (conn) { uint32_t cis_offset_min; - if (IS_ENABLED(CONFIG_BT_CTLR_JIT_SCHEDULING)) { - cis_offset_min = MAX(400, EVENT_OVERHEAD_CIS_SETUP_US); + if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START)) { + /* Early start allows offset down to spec defined minimum */ + cis_offset_min = CIS_MIN_OFFSET_MIN; } else { cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) + (EVENT_TICKER_RES_MARGIN_US << 1U); From 574a533cb63f67d1d8c1e028366ba9b00286199c Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Tue, 6 Jun 2023 11:38:46 +0200 Subject: [PATCH 0236/2042] net: openthread: allow to configure CSL debugging Add new `IEEE802154_CSL_DEBUG` Kconfig option that, when enabled, prevents the radio to sleep after a delayed reception is finished. This allows to debug CSL timing issues due to accuracy drifts in communications between receiver and transmitter. Signed-off-by: Eduardo Montoya --- drivers/ieee802154/Kconfig | 6 ++++++ drivers/ieee802154/ieee802154_nrf5.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 72a0f5471a52..feccd4a60012 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -92,6 +92,12 @@ config IEEE802154_CSL_ENDPOINT Make this device a CSL (coordinated sampled listening) endpoint with delayed reception handling and CSL IE injection. +config IEEE802154_CSL_DEBUG + bool "Support for CSL debugging" + depends on IEEE802154_CSL_ENDPOINT + 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 diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 0418217000fe..426d90578a62 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -1019,7 +1019,15 @@ 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) { __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_SLEEP, NULL); +#endif if (error == NRF_802154_RX_ERROR_DELAYED_TIMEOUT) { return; } From 6160383ec7d9318940ee2ec8abae485ca494c4f8 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 6 Jun 2023 15:19:25 +0200 Subject: [PATCH 0237/2042] riscv: Rename RISCV_MTVEC_VECTORED_MODE to RISCV_VECTORED_MODE Before adding support for the CLIC vectored mode, rename CONFIG_RISCV_MTVEC_VECTORED_MODE to CONFIG_RISCV_VECTORED_MODE to be more generic and eventually include also the CLIC vectored mode. Signed-off-by: Carlo Caione --- arch/riscv/Kconfig | 2 +- soc/riscv/riscv-privileged/Kconfig | 6 +++--- soc/riscv/riscv-privileged/common/vector.S | 4 ++-- soc/riscv/riscv-privileged/opentitan/Kconfig.series | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 20faced0ca8a..3c45c5811f73 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -301,7 +301,7 @@ config ARCH_IRQ_VECTOR_TABLE_ALIGN default 256 config GEN_IRQ_VECTOR_TABLE - select RISCV_MTVEC_VECTORED_MODE if SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_VECTORED_MODE if SOC_FAMILY_RISCV_PRIVILEGED config ARCH_HAS_SINGLE_THREAD_SUPPORT default y if !SMP diff --git a/soc/riscv/riscv-privileged/Kconfig b/soc/riscv/riscv-privileged/Kconfig index 9d3b9f4a3567..f94eabd96a7a 100644 --- a/soc/riscv/riscv-privileged/Kconfig +++ b/soc/riscv/riscv-privileged/Kconfig @@ -28,10 +28,10 @@ config RISCV_HAS_CLIC help Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). -config RISCV_MTVEC_VECTORED_MODE - bool "Should the SOC use mtvec in vectored mode" +config RISCV_VECTORED_MODE + bool "Should the SOC use vectored mode" depends on SOC_FAMILY_RISCV_PRIVILEGED help - Should the SOC use mtvec in vectored mode + Should the SOC use vectored mode. source "soc/riscv/riscv-privileged/*/Kconfig.soc" diff --git a/soc/riscv/riscv-privileged/common/vector.S b/soc/riscv/riscv-privileged/common/vector.S index 712e550969a7..67d203c473d5 100644 --- a/soc/riscv/riscv-privileged/common/vector.S +++ b/soc/riscv/riscv-privileged/common/vector.S @@ -25,7 +25,7 @@ SECTION_FUNC(vectors, __start) .option norvc; -#if defined(CONFIG_RISCV_MTVEC_VECTORED_MODE) +#if defined(CONFIG_RISCV_VECTORED_MODE) /* * Set mtvec (Machine Trap-Vector Base-Address Register) * to _irq_vector_table (interrupt vector table). Add 1 to base @@ -39,7 +39,7 @@ SECTION_FUNC(vectors, __start) la t0, _irq_vector_table /* Load address of interrupt vector table */ addi t0, t0, 1 /* Enable vectored mode by setting LSB */ -/* MTVEC_DIRECT_MODE */ +/* DIRECT_MODE */ #else /* * Set mtvec (Machine Trap-Vector Base-Address Register) diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.series index f9cdf3bea479..f8bbc2840fed 100644 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.series +++ b/soc/riscv/riscv-privileged/opentitan/Kconfig.series @@ -6,7 +6,7 @@ config SOC_SERIES_RISCV_OPENTITAN select RISCV select SOC_FAMILY_RISCV_PRIVILEGED # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. - select RISCV_MTVEC_VECTORED_MODE + select RISCV_VECTORED_MODE select GEN_IRQ_VECTOR_TABLE help Enable support for OpenTitan From fc480c9382a218130eaf7308cbbad7194c71b414 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 6 Jun 2023 21:52:06 +0200 Subject: [PATCH 0238/2042] riscv: privileged: Add support for CLIC vectored mode Zephyr currently only supports CLINT direct mode and CLINT vectored mode. Add support for CLIC vectored mode as well. Signed-off-by: Carlo Caione --- arch/Kconfig | 3 +- soc/riscv/riscv-privileged/common/vector.S | 47 +++++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 8e75098f57c3..24dce5c0c9cd 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -461,13 +461,14 @@ config GEN_SW_ISR_TABLE config ARCH_SW_ISR_TABLE_ALIGN int "Alignment size of a software ISR table" + default 64 if RISCV_HAS_CLIC default 4 depends on GEN_SW_ISR_TABLE help This option controls alignment size of generated _sw_isr_table. Some architecture needs a software ISR table to be aligned to architecture specific size. The default - size is 0 for no alignment. + size is 4. config GEN_IRQ_START_VECTOR int diff --git a/soc/riscv/riscv-privileged/common/vector.S b/soc/riscv/riscv-privileged/common/vector.S index 67d203c473d5..5883bdcca853 100644 --- a/soc/riscv/riscv-privileged/common/vector.S +++ b/soc/riscv/riscv-privileged/common/vector.S @@ -26,7 +26,39 @@ SECTION_FUNC(vectors, __start) .option norvc; #if defined(CONFIG_RISCV_VECTORED_MODE) +#if defined(CONFIG_RISCV_HAS_CLIC) + + /* + * CLIC vectored mode + * + * CLIC vectored mode uses mtvec exclusively for exception handling and + * mtvec.base must be aligned to 64 bytes (this is done using + * CONFIG_ARCH_SW_ISR_TABLE_ALIGN) + */ + la t0, _isr_wrapper + addi t0, t0, 0x03 /* Enable CLIC vectored mode by setting LSB */ + csrw mtvec, t0 + /* + * CLIC vectored mode has a similar concept to CLINT vectored mode, + * where an interrupt vector table is used for specific interrupts. + * However, in CLIC vectored mode, the handler table contains the + * address of the interrupt handler instead of an opcode containing a + * jump instruction, this is done by leveraging + * CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS. + * When an interrupt occurs in CLIC vectored mode, the address of the + * handler entry from the vector table is loaded and then jumped to in + * hardware. This time mtvt is used as the base address for the + * interrupt table. + */ + la t0, _irq_vector_table + csrw 0x307, t0 /* mtvt */ + +#else /* !CONFIG_RISCV_HAS_CLIC */ + + /* + * CLINT vectored mode + * * Set mtvec (Machine Trap-Vector Base-Address Register) * to _irq_vector_table (interrupt vector table). Add 1 to base * address of _irq_vector_table to indicate that vectored mode @@ -37,18 +69,23 @@ SECTION_FUNC(vectors, __start) * of _irq_vector_table breaks this code. */ la t0, _irq_vector_table /* Load address of interrupt vector table */ - addi t0, t0, 1 /* Enable vectored mode by setting LSB */ + addi t0, t0, 0x01 /* Enable vectored mode by setting LSB */ + csrw mtvec, t0 + +#endif /* CONFIG_RISCV_HAS_CLIC */ + +#else /* !CONFIG_RISCV_VECTORED_MODE */ -/* DIRECT_MODE */ -#else /* + * CLINT direct mode + * * Set mtvec (Machine Trap-Vector Base-Address Register) * to _isr_wrapper. */ la t0, _isr_wrapper -#endif - csrw mtvec, t0 +#endif /* CONFIG_RISCV_VECTORED_MODE */ + /* Jump to __reset */ tail __reset From d395b7f1e8e61b6848ebf19f49bf0e778346c74e Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 7 Jun 2023 16:03:45 +0200 Subject: [PATCH 0239/2042] riscv: Add CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET Some RISCV platforms shipping a CLIC have a peculiar interrupt ID ordering / mapping. According to the "Core-Local Interrupt Controller (CLIC) RISC-V Privileged Architecture Extensions" Version 0.9-draft at paragraph 16.1 one of these ordering recommendations is "CLIC-mode interrupt-map for systems retaining interrupt ID compatible with CLINT mode" that is described how: The CLINT-mode interrupts retain their interrupt ID in CLIC mode. [...] The existing CLINT software interrupt bits are primarily intended for inter-hart interrupt signaling, and so are retained for that purpose. [...] CLIC interrupt inputs are allocated IDs beginning at interrupt ID 17. Any fast local interrupts that would have been connected at interrupt ID 16 and above should now be mapped into corresponding inputs of the CLIC. That is a very convoluted way to say that interrupts 0 to 15 are reserved for internal use and CLIC only controls interrupts reserved for platform use (16 up to n + 16, where n is the maximum number of interrupts supported). Let's now take now into consideration this situation in the DT: clic: interrupt-controller { ... }; device0: some-device { interrupt-parent = <&clic>; interrupts = <0x1>; ... }; and in the driver for device0: IRQ_CONNECT(DT_IRQN(node), ...); From the hardware prospective: (1a) device0 is using the first IRQ line of the CLIC (2a) the interrupt ID / exception code of the `MSTATUS` register associated to this IRQ is 17, because the IDs 0 to 15 are reserved From the software / Zephyr prospective: (1b) Zephyr is installing the IRQ vector into the SW ISR table (and into the IRQ vector table for DIRECT ISRs in case of CLIC vectored mode) at index 0x1. (2b) Zephyr is using the interrupt ID of the `MSTATUS` register to index into the SW ISR table (or IRQ vector table) It's now clear how (2a) and (2b) are in contrast with each other. To fix this problem we have to take into account the offset introduced by the reserved interrupts. To do so we introduce CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET as hidden option for the platforms to set. This Kconfig option is used to shift the interrupt numbers when installing the IRQ vector into the SW ISR table and/or IRQ vector table. So for example in the previous case and using CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET == 16, the IRQ vector associated to the device0 would be correctly installed at index 17 (16 + 1), matching what is reported by the `MSTATUS` register. CONFIG_NUM_IRQS must be increased accordingly. Signed-off-by: Carlo Caione --- arch/riscv/Kconfig | 13 +++++++++++++ include/zephyr/arch/riscv/irq.h | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 3c45c5811f73..0559e50d4b6f 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -169,6 +169,19 @@ config GEN_ISR_TABLES config GEN_IRQ_VECTOR_TABLE default n +config RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET + int + default 0 + depends on GEN_ISR_TABLES + help + On some RISCV platform the first interrupt vectors are primarly + intended for inter-hart interrupt signaling and so retained for that + purpose and not available. When this option is set, all the IRQ + vectors are shifted by this offset value when installed into the + software ISR table and the IRQ vector table. CONFIG_NUM_IRQS must be + properly sized to take into account this offset. This is a hidden + option which needs to be set per architecture and left alone. + config NUM_IRQS int diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 35fec3b20f7f..77c0d4057aaf 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -39,13 +39,15 @@ extern void z_riscv_irq_priority_set(unsigned int irq, #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ { \ - Z_ISR_DECLARE(irq_p, 0, isr_p, isr_param_p); \ + Z_ISR_DECLARE(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ + 0, isr_p, isr_param_p); \ z_riscv_irq_priority_set(irq_p, priority_p, flags_p); \ } #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(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ + ISR_FLAG_DIRECT, isr_p, NULL); \ } #define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header() From 0af2e0ef04ada80efd7570cd3429ce7caa9acb0c Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Mon, 25 Jul 2022 02:27:08 -0700 Subject: [PATCH 0240/2042] dts: npcx: move npcx/npcx7/npcx9.dtsi to npcx folder Move dt files related to SoC family and series to npcx folder. It only leaves SoC dt file in `dts/arm/nuvoton folder` in case of confusion with the other Nuvoton SoCs. The dt files path will be: dts/arm/nuvoton |--npcx | |--npcx7 | | |--npcx7-miwus-wui-map.dtsi | | |--npcx7-alts-map.dtsi | | |--..... | +--npcx9 | | |--npcx9-miwus-wui-map.dtsi | | |--npcx9-alts-map.dtsi | | +--..... | |--npcx-miwus-wui-map.dtsi | |--npcx-alts-map.dtsi | |--npcx.dtsi | |--npcx7.dtsi | |--npcx9.dtsi |--npcx7m6fb.dtsi |--npcx7m6fc.dtsi |--npcx9m8f.dtsi +--npcx9m3f.dtsi Signed-off-by: Mulin Chao --- dts/arm/nuvoton/{ => npcx}/npcx.dtsi | 0 dts/arm/nuvoton/{ => npcx}/npcx7.dtsi | 10 +++++----- dts/arm/nuvoton/{ => npcx}/npcx9.dtsi | 10 +++++----- dts/arm/nuvoton/npcx7m6fb.dtsi | 2 +- dts/arm/nuvoton/npcx7m6fc.dtsi | 2 +- dts/arm/nuvoton/npcx7m7fc.dtsi | 2 +- dts/arm/nuvoton/npcx9m3f.dtsi | 2 +- dts/arm/nuvoton/npcx9m6f.dtsi | 2 +- dts/arm/nuvoton/npcx9m7f.dtsi | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) rename dts/arm/nuvoton/{ => npcx}/npcx.dtsi (100%) rename dts/arm/nuvoton/{ => npcx}/npcx7.dtsi (96%) rename dts/arm/nuvoton/{ => npcx}/npcx9.dtsi (97%) diff --git a/dts/arm/nuvoton/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi similarity index 100% rename from dts/arm/nuvoton/npcx.dtsi rename to dts/arm/nuvoton/npcx/npcx.dtsi diff --git a/dts/arm/nuvoton/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi similarity index 96% rename from dts/arm/nuvoton/npcx7.dtsi rename to dts/arm/nuvoton/npcx/npcx7.dtsi index 00d74f93e813..a1b92d83a875 100644 --- a/dts/arm/nuvoton/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -5,15 +5,15 @@ */ /* NPCX7 series pinmux mapping table */ -#include "npcx/npcx7/npcx7-alts-map.dtsi" +#include "npcx7/npcx7-alts-map.dtsi" /* NPCX7 series mapping table between MIWU wui bits and source device */ -#include "npcx/npcx7/npcx7-miwus-wui-map.dtsi" +#include "npcx7/npcx7-miwus-wui-map.dtsi" /* NPCX7 series mapping table between MIWU groups and interrupts */ -#include "npcx/npcx7/npcx7-miwus-int-map.dtsi" +#include "npcx7/npcx7-miwus-int-map.dtsi" /* NPCX7 series eSPI VW mapping table */ -#include "npcx/npcx7/npcx7-espi-vws-map.dtsi" +#include "npcx7/npcx7-espi-vws-map.dtsi" /* NPCX7 series low-voltage io controls mapping table */ -#include "npcx/npcx7/npcx7-lvol-ctrl-map.dtsi" +#include "npcx7/npcx7-lvol-ctrl-map.dtsi" /* Device tree declarations of npcx soc family */ #include "npcx.dtsi" diff --git a/dts/arm/nuvoton/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi similarity index 97% rename from dts/arm/nuvoton/npcx9.dtsi rename to dts/arm/nuvoton/npcx/npcx9.dtsi index b24965fedb13..300c589b3ac0 100644 --- a/dts/arm/nuvoton/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -5,15 +5,15 @@ */ /* NPCX9 series pinmux mapping table */ -#include "npcx/npcx9/npcx9-alts-map.dtsi" +#include "npcx9/npcx9-alts-map.dtsi" /* NPCX9 series mapping table between MIWU wui bits and source device */ -#include "npcx/npcx9/npcx9-miwus-wui-map.dtsi" +#include "npcx9/npcx9-miwus-wui-map.dtsi" /* NPCX9 series mapping table between MIWU groups and interrupts */ -#include "npcx/npcx9/npcx9-miwus-int-map.dtsi" +#include "npcx9/npcx9-miwus-int-map.dtsi" /* NPCX9 series eSPI VW mapping table */ -#include "npcx/npcx9/npcx9-espi-vws-map.dtsi" +#include "npcx9/npcx9-espi-vws-map.dtsi" /* NPCX9 series low-voltage io controls mapping table */ -#include "npcx/npcx9/npcx9-lvol-ctrl-map.dtsi" +#include "npcx9/npcx9-lvol-ctrl-map.dtsi" /* Device tree declarations of npcx soc family */ #include "npcx.dtsi" diff --git a/dts/arm/nuvoton/npcx7m6fb.dtsi b/dts/arm/nuvoton/npcx7m6fb.dtsi index df77f4857beb..c4bd84bf5319 100644 --- a/dts/arm/nuvoton/npcx7m6fb.dtsi +++ b/dts/arm/nuvoton/npcx7m6fb.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx7.dtsi" +#include "npcx/npcx7.dtsi" / { flash0: flash@10090000 { diff --git a/dts/arm/nuvoton/npcx7m6fc.dtsi b/dts/arm/nuvoton/npcx7m6fc.dtsi index 9c6d31110e69..531b6da6329b 100644 --- a/dts/arm/nuvoton/npcx7m6fc.dtsi +++ b/dts/arm/nuvoton/npcx7m6fc.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx7.dtsi" +#include "npcx/npcx7.dtsi" / { flash0: flash@10090000 { diff --git a/dts/arm/nuvoton/npcx7m7fc.dtsi b/dts/arm/nuvoton/npcx7m7fc.dtsi index c0ccc503d7d1..31670039d699 100644 --- a/dts/arm/nuvoton/npcx7m7fc.dtsi +++ b/dts/arm/nuvoton/npcx7m7fc.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx7.dtsi" +#include "npcx/npcx7.dtsi" / { flash0: flash@10070000 { diff --git a/dts/arm/nuvoton/npcx9m3f.dtsi b/dts/arm/nuvoton/npcx9m3f.dtsi index e47d3003a8e1..4f32f2f06322 100644 --- a/dts/arm/nuvoton/npcx9m3f.dtsi +++ b/dts/arm/nuvoton/npcx9m3f.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx9.dtsi" +#include "npcx/npcx9.dtsi" / { flash0: flash@10080000 { diff --git a/dts/arm/nuvoton/npcx9m6f.dtsi b/dts/arm/nuvoton/npcx9m6f.dtsi index 4f92635b5cfb..a918784f46a1 100644 --- a/dts/arm/nuvoton/npcx9m6f.dtsi +++ b/dts/arm/nuvoton/npcx9m6f.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx9.dtsi" +#include "npcx/npcx9.dtsi" / { flash0: flash@10090000 { diff --git a/dts/arm/nuvoton/npcx9m7f.dtsi b/dts/arm/nuvoton/npcx9m7f.dtsi index f52dd88f449d..646225431ceb 100644 --- a/dts/arm/nuvoton/npcx9m7f.dtsi +++ b/dts/arm/nuvoton/npcx9m7f.dtsi @@ -5,7 +5,7 @@ */ #include -#include "npcx9.dtsi" +#include "npcx/npcx9.dtsi" / { flash0: flash@10070000 { From a7014d01da49644299760d91a3471208285d41fc Mon Sep 17 00:00:00 2001 From: Jordan Montgomery Date: Tue, 11 Apr 2023 15:06:10 -0700 Subject: [PATCH 0241/2042] drivers: adc: Add support for TI ADS1112 ADCs This PR adds a custom driver for the ADS1112 ADCs. Unlike ADS1113/4/5 family served by the ADS1x1x driver, the ADS1112 does not use an address pointer to address config registers. Instead, there is only one writable register and all i2c writes will set it. The registers resemble the ADS1119 device, but config bitmap is different, include a distinct data rate table, gain table, and input multiplexing table. There is also not a status register to be monitored with the ADS1112, as it uses config bit 7 for the same purpose instead of a separate register. The driver was tested on hardware using the ADC shell interface. Manual probing validated the voltages for the MUX_SINGLE configs at datarate 15 in CM_SINGLE. Higher gains were not tested and CM_CONTINUOUS is not supported in this initial implementation. The new driver has also been added to the existing ADC test using adc_emul for completeness. Origin: original License: Apache 2.0 Purpose: Adding support for ADS1112 ADCs Signed-off-by: Jordan Montgomery --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.ads1112 | 12 + drivers/adc/adc_ads1112.c | 397 ++++++++++++++++++++++ dts/bindings/adc/ti,ads1112.yaml | 5 + tests/drivers/build_all/adc/app.overlay | 6 + tests/drivers/build_all/adc/testcase.yaml | 1 + 7 files changed, 424 insertions(+) create mode 100644 drivers/adc/Kconfig.ads1112 create mode 100644 drivers/adc/adc_ads1112.c create mode 100644 dts/bindings/adc/ti,ads1112.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index d624b33fd16f..24e593c2eda9 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -28,6 +28,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_EMUL adc_emul.c) zephyr_library_sources_ifdef(CONFIG_ADC_TEST adc_test.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS1X1X adc_ads1x1x.c) zephyr_library_sources_ifdef(CONFIG_ADC_GD32 adc_gd32.c) +zephyr_library_sources_ifdef(CONFIG_ADC_ADS1112 adc_ads1112.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS1119 adc_ads1119.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS7052 adc_ads7052.c) zephyr_library_sources_ifdef(CONFIG_ADC_ADS114S0X adc_ads114s0x.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 120f4a05e644..0cfcbf05ecbd 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -90,6 +90,8 @@ source "drivers/adc/Kconfig.ads1x1x" source "drivers/adc/Kconfig.gd32" +source "drivers/adc/Kconfig.ads1112" + source "drivers/adc/Kconfig.ads1119" source "drivers/adc/Kconfig.ads7052" diff --git a/drivers/adc/Kconfig.ads1112 b/drivers/adc/Kconfig.ads1112 new file mode 100644 index 000000000000..fda91c974c6f --- /dev/null +++ b/drivers/adc/Kconfig.ads1112 @@ -0,0 +1,12 @@ +# ADS1112 ADC configuration options + +# Copyright (c) 2023 Cruise, LLC. +# SPDX-License-Identifier: Apache-2.0 + +config ADC_ADS1112 + bool "Texas Instruments ADS1112 ADC driver" + depends on DT_HAS_TI_ADS1112_ENABLED + select I2C + select ADC_CONFIGURABLE_INPUTS + help + Enable the driver implementation for the ADS1112 diff --git a/drivers/adc/adc_ads1112.c b/drivers/adc/adc_ads1112.c new file mode 100644 index 000000000000..4ff8c5e0dbc4 --- /dev/null +++ b/drivers/adc/adc_ads1112.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright (c) 2020 Innoseis BV + * Copyright (c) 2023 Cruise LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER 1 +#include "adc_context.h" + +#define DT_DRV_COMPAT ti_ads1112 + +LOG_MODULE_REGISTER(ADS1112, CONFIG_ADC_LOG_LEVEL); + +#define ADS1112_CONFIG_GAIN(x) ((x)&BIT_MASK(2)) +#define ADS1112_CONFIG_DR(x) (((x)&BIT_MASK(2)) << 2) +#define ADS1112_CONFIG_CM(x) (((x)&BIT_MASK(1)) << 4) +#define ADS1112_CONFIG_MUX(x) (((x)&BIT_MASK(2)) << 5) + +#define ADS1112_CONFIG_MASK_READY BIT(7) + +#define ADS1112_DEFAULT_CONFIG 0x8C +#define ADS1112_REF_INTERNAL 2048 + +enum ads1112_reg { + ADS1112_REG_OUTPUT = 0, + ADS1112_REG_CONFIG = 1, +}; + +enum { + ADS1112_CONFIG_MUX_DIFF_0_1 = 0, + ADS1112_CONFIG_MUX_BOTH_2_3 = 1, + ADS1112_CONFIG_MUX_SINGLE_0_3 = 2, + ADS1112_CONFIG_MUX_SINGLE_1_3 = 3, +}; + +enum { + ADS1112_CONFIG_DR_RATE_240_RES_12 = 0, + ADS1112_CONFIG_DR_RATE_60_RES_14 = 1, + ADS1112_CONFIG_DR_RATE_30_RES_15 = 2, + ADS1112_CONFIG_DR_RATE_15_RES_16 = 3, + ADS1112_CONFIG_DR_DEFAULT = ADS1112_CONFIG_DR_RATE_15_RES_16, +}; + +enum { + ADS1112_CONFIG_GAIN_1 = 0, + ADS1112_CONFIG_GAIN_2 = 1, + ADS1112_CONFIG_GAIN_4 = 2, + ADS1112_CONFIG_GAIN_8 = 3, +}; + +enum { + ADS1112_CONFIG_CM_SINGLE = 0, + ADS1112_CONFIG_CM_CONTINUOUS = 1, +}; + +struct ads1112_config { + const struct i2c_dt_spec bus; +}; + +struct ads1112_data { + struct adc_context ctx; + k_timeout_t ready_time; + struct k_sem acq_sem; + int16_t *buffer; + int16_t *buffer_ptr; + bool differential; +}; + +static int ads1112_read_reg(const struct device *dev, enum ads1112_reg reg_addr, uint8_t *reg_val) +{ + const struct ads1112_config *config = dev->config; + uint8_t buf[3] = {0}; + int rc = i2c_read_dt(&config->bus, buf, sizeof(buf)); + + if (reg_addr == ADS1112_REG_OUTPUT) { + reg_val[0] = buf[0]; + reg_val[1] = buf[1]; + } else { + reg_val[0] = buf[2]; + } + + return rc; +} + +static int ads1112_write_reg(const struct device *dev, uint8_t reg) +{ + uint8_t msg[1] = {reg}; + const struct ads1112_config *config = dev->config; + + /* It's only possible to write the config register, so the ADS1112 + * assumes all writes are going to that register and omits the register + * parameter from write transactions + */ + return i2c_write_dt(&config->bus, msg, sizeof(msg)); +} + +static inline int ads1112_acq_time_to_dr(const struct device *dev, uint16_t acq_time) +{ + struct ads1112_data *data = dev->data; + int odr = -EINVAL; + uint16_t acq_value = ADC_ACQ_TIME_VALUE(acq_time); + uint32_t ready_time_us = 0; + + if (acq_time == ADC_ACQ_TIME_DEFAULT) { + acq_value = ADS1112_CONFIG_DR_DEFAULT; + } else if (ADC_ACQ_TIME_UNIT(acq_time) != ADC_ACQ_TIME_TICKS) { + return -EINVAL; + } + + switch (acq_value) { + case ADS1112_CONFIG_DR_RATE_15_RES_16: + odr = ADS1112_CONFIG_DR_RATE_15_RES_16; + ready_time_us = (1000 * 1000) / 15; + break; + case ADS1112_CONFIG_DR_RATE_30_RES_15: + odr = ADS1112_CONFIG_DR_RATE_30_RES_15; + ready_time_us = (1000 * 1000) / 30; + break; + case ADS1112_CONFIG_DR_RATE_60_RES_14: + odr = ADS1112_CONFIG_DR_RATE_60_RES_14; + ready_time_us = (1000 * 1000) / 60; + break; + case ADS1112_CONFIG_DR_RATE_240_RES_12: + odr = ADS1112_CONFIG_DR_RATE_240_RES_12; + ready_time_us = (1000 * 1000) / 240; + break; + default: + break; + } + + /* Add some additional time to ensure that the data is truly ready, + * as chips in this family often require some additional time beyond + * the listed times + */ + data->ready_time = K_USEC(ready_time_us + 10); + + return odr; +} + +static int ads1112_wait_data_ready(const struct device *dev) +{ + int rc; + struct ads1112_data *data = dev->data; + + k_sleep(data->ready_time); + uint8_t status = 0; + + rc = ads1112_read_reg(dev, ADS1112_REG_CONFIG, &status); + if (rc != 0) { + return rc; + } + + while ((status & ADS1112_CONFIG_MASK_READY) == 0) { + + k_sleep(K_USEC(100)); + rc = ads1112_read_reg(dev, ADS1112_REG_CONFIG, &status); + if (rc != 0) { + return rc; + } + } + + return 0; +} + +static int ads1112_read_sample(const struct device *dev, uint16_t *buff) +{ + int res; + uint8_t sample[2] = {0}; + const struct ads1112_config *config = dev->config; + + res = ads1112_read_reg(dev, ADS1112_REG_OUTPUT, sample); + buff[0] = sys_get_be16(sample); + return res; +} + +static int ads1112_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + struct ads1112_data *data = dev->data; + uint8_t config = 0; + int dr = 0; + + if (channel_cfg->channel_id != 0) { + return -EINVAL; + } + + if (channel_cfg->differential) { + if (channel_cfg->input_positive == 0 && channel_cfg->input_negative == 1) { + config |= ADS1112_CONFIG_MUX(ADS1112_CONFIG_MUX_DIFF_0_1); + } else if (channel_cfg->input_positive == 2 && channel_cfg->input_negative == 3) { + config |= ADS1112_CONFIG_MUX(ADS1112_CONFIG_MUX_BOTH_2_3); + } else { + return -EINVAL; + } + } else { + if (channel_cfg->input_positive == 0) { + config |= ADS1112_CONFIG_MUX(ADS1112_CONFIG_MUX_SINGLE_0_3); + } else if (channel_cfg->input_positive == 1) { + config |= ADS1112_CONFIG_MUX(ADS1112_CONFIG_MUX_SINGLE_1_3); + } else if (channel_cfg->input_positive == 2) { + config |= ADS1112_CONFIG_MUX(ADS1112_CONFIG_MUX_BOTH_2_3); + } else { + return -EINVAL; + } + } + + data->differential = channel_cfg->differential; + + dr = ads1112_acq_time_to_dr(dev, channel_cfg->acquisition_time); + if (dr < 0) { + return dr; + } + + config |= ADS1112_CONFIG_DR(dr); + + switch (channel_cfg->gain) { + case ADC_GAIN_1: + config |= ADS1112_CONFIG_GAIN(ADS1112_CONFIG_GAIN_1); + break; + case ADC_GAIN_2: + config |= ADS1112_CONFIG_GAIN(ADS1112_CONFIG_GAIN_2); + break; + case ADC_GAIN_3: + config |= ADS1112_CONFIG_GAIN(ADS1112_CONFIG_GAIN_4); + break; + case ADC_GAIN_4: + config |= ADS1112_CONFIG_GAIN(ADS1112_CONFIG_GAIN_8); + break; + default: + return -EINVAL; + } + + config |= ADS1112_CONFIG_CM(ADS1112_CONFIG_CM_SINGLE); /* Only single shot supported */ + + return ads1112_write_reg(dev, config); +} + +static int ads1112_validate_buffer_size(const struct adc_sequence *sequence) +{ + size_t needed = sizeof(int16_t); + + if (sequence->options) { + needed *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed) { + LOG_ERR("Insufficient buffer %i < %i", sequence->buffer_size, needed); + return -ENOMEM; + } + + return 0; +} + +static int ads1112_validate_sequence(const struct device *dev, const struct adc_sequence *sequence) +{ + const struct ads1112_data *data = dev->data; + + if (sequence->channels != BIT(0)) { + LOG_ERR("Invalid Channel 0x%x", sequence->channels); + return -EINVAL; + } + + if (sequence->oversampling) { + LOG_ERR("Oversampling not supported"); + return -EINVAL; + } + + return ads1112_validate_buffer_size(sequence); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct ads1112_data *data = CONTAINER_OF(ctx, struct ads1112_data, ctx); + + if (repeat_sampling) { + data->buffer = data->buffer_ptr; + } +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct ads1112_data *data = CONTAINER_OF(ctx, struct ads1112_data, ctx); + + data->buffer_ptr = data->buffer; + k_sem_give(&data->acq_sem); +} + +static int ads1112_adc_start_read(const struct device *dev, const struct adc_sequence *sequence, + bool wait) +{ + int rc = 0; + struct ads1112_data *data = dev->data; + + rc = ads1112_validate_sequence(dev, sequence); + if (rc != 0) { + return rc; + } + + data->buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + + if (wait) { + rc = adc_context_wait_for_completion(&data->ctx); + } + return rc; +} + +static int ads1112_adc_perform_read(const struct device *dev) +{ + int rc; + struct ads1112_data *data = dev->data; + + k_sem_take(&data->acq_sem, K_FOREVER); + + rc = ads1112_wait_data_ready(dev); + if (rc != 0) { + adc_context_complete(&data->ctx, rc); + return rc; + } + + rc = ads1112_read_sample(dev, data->buffer); + if (rc != 0) { + adc_context_complete(&data->ctx, rc); + return rc; + } + data->buffer++; + + adc_context_on_sampling_done(&data->ctx, dev); + + return rc; +} + +static int ads1112_read(const struct device *dev, const struct adc_sequence *sequence) +{ + int rc; + struct ads1112_data *data = dev->data; + + adc_context_lock(&data->ctx, false, NULL); + rc = ads1112_adc_start_read(dev, sequence, false); + + while (rc == 0 && k_sem_take(&data->ctx.sync, K_NO_WAIT) != 0) { + rc = ads1112_adc_perform_read(dev); + } + + adc_context_release(&data->ctx, rc); + return rc; +} + +static int ads1112_init(const struct device *dev) +{ + int rc = 0; + uint8_t status; + const struct ads1112_config *config = dev->config; + struct ads1112_data *data = dev->data; + + adc_context_init(&data->ctx); + + k_sem_init(&data->acq_sem, 0, 1); + + if (!device_is_ready(config->bus.bus)) { + return -ENODEV; + } + + rc = ads1112_write_reg(dev, ADS1112_DEFAULT_CONFIG); + if (rc) { + LOG_ERR("Could not set default config 0x%x", ADS1112_DEFAULT_CONFIG); + return rc; + } + + adc_context_unlock_unconditionally(&data->ctx); + + return rc; +} + +static const struct adc_driver_api api = { + .channel_setup = ads1112_channel_setup, + .read = ads1112_read, + .ref_internal = ADS1112_REF_INTERNAL, +}; +#define ADC_ADS1112_INST_DEFINE(n) \ + static const struct ads1112_config config_##n = {.bus = I2C_DT_SPEC_INST_GET(n)}; \ + static struct ads1112_data data_##n; \ + DEVICE_DT_INST_DEFINE(n, ads1112_init, NULL, &data_##n, &config_##n, POST_KERNEL, \ + CONFIG_ADC_INIT_PRIORITY, &api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_ADS1112_INST_DEFINE); diff --git a/dts/bindings/adc/ti,ads1112.yaml b/dts/bindings/adc/ti,ads1112.yaml new file mode 100644 index 000000000000..aac1d695d9ed --- /dev/null +++ b/dts/bindings/adc/ti,ads1112.yaml @@ -0,0 +1,5 @@ +description: Texas Instrument ADS1112 I2C ADC + +compatible: "ti,ads1112" + +include: ti,ads1x1x-base.yaml diff --git a/tests/drivers/build_all/adc/app.overlay b/tests/drivers/build_all/adc/app.overlay index 6bf466bd2088..9c063197863f 100644 --- a/tests/drivers/build_all/adc/app.overlay +++ b/tests/drivers/build_all/adc/app.overlay @@ -81,6 +81,12 @@ reg = <0x6>; #io-channel-cells = <1>; }; + + test_i2c_ads1112: ads1112@7 { + compatible = "ti,ads1112"; + reg = <0x7>; + #io-channel-cells = <1>; + }; }; test_spi: spi@33334444 { diff --git a/tests/drivers/build_all/adc/testcase.yaml b/tests/drivers/build_all/adc/testcase.yaml index 512cc74dbece..a069e748f2a7 100644 --- a/tests/drivers/build_all/adc/testcase.yaml +++ b/tests/drivers/build_all/adc/testcase.yaml @@ -12,6 +12,7 @@ tests: - adc_lmp90xxx - adc_ads1x1x - adc_ads1119 + - adc_ads1112 - adc_ads114s08 - adc_emul extra_args: "CONFIG_GPIO=y" From b1e9a813fe3b646e57668274d1a78dada99e46cc Mon Sep 17 00:00:00 2001 From: Jordan Montgomery Date: Wed, 12 Apr 2023 08:56:26 -0700 Subject: [PATCH 0242/2042] drivers: adc: adc-shell: Add support for ADS111x ADCs to adc-shell.c The adc-shell uses a hardcoded list of defines to check whether it should throw a compile-time error. The ADS1119 and ADS1112 driver both support the APIs needed by the shell, so this commit enables support for them in the hardcoded support list. Signed-off-by: Jordan Montgomery --- drivers/adc/adc_shell.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 804f9cf2add1..164e706b9aa2 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -39,6 +39,10 @@ #define DT_DRV_COMPAT st_stm32_adc #elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_adc) #define DT_DRV_COMPAT nuvoton_npcx_adc +#elif DT_HAS_COMPAT_STATUS_OKAY(ti_ads1112) +#define DT_DRV_COMPAT ti_ads1112 +#elif DT_HAS_COMPAT_STATUS_OKAY(ti_ads1119) +#define DT_DRV_COMPAT ti_ads1119 #elif DT_HAS_COMPAT_STATUS_OKAY(ti_cc32xx_adc) #define DT_DRV_COMPAT ti_cc32xx_adc #elif DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_adc) From b617f03439878e999aaf74f3a70ec4e82971da36 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 10:26:29 +0200 Subject: [PATCH 0243/2042] bluetooth: controller: rv32m1: configure debug pins in DEBUG_INIT The debug pins were configured in a board specific file, however, the subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h file already contains board-specific pins, meaning there's no need to split the information in 2 places. Move the GPIO configuration calls to the DEBUG_INIT() macro in the controller debug header. Note that in the future, Devicetree should be used to provide a hardware-agnostic debug module. Signed-off-by: Gerard Marull-Paretas --- .../controller/ll_sw/openisa/hal/RV32M1/debug.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h index f1f87c2efe03..45469ddeecd4 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/debug.h @@ -85,6 +85,21 @@ extern const struct device *vega_debug_portd; vega_debug_portc = DEVICE_DT_GET(DT_NODELABEL(gpioc)); \ vega_debug_portd = DEVICE_DT_GET(DT_NODELABEL(gpiod)); \ \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portb)); \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portc)); \ + __ASSERT_NO_MSG(device_is_ready(vega_debug_portd)); \ + \ + gpio_pin_configure(DEBUG0_PORT, DEBUG0_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG1_PORT, DEBUG1_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG2_PORT, DEBUG2_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG3_PORT, DEBUG3_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG4_PORT, DEBUG4_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG5_PORT, DEBUG5_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG6_PORT, DEBUG6_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG7_PORT, DEBUG7_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG8_PORT, DEBUG8_PIN, GPIO_OUTPUT); \ + gpio_pin_configure(DEBUG9_PORT, DEBUG9_PIN, GPIO_OUTPUT); \ + \ gpio_pin_set(DEBUG0_PORT, DEBUG0_PIN, 1); \ gpio_pin_set(DEBUG0_PORT, DEBUG0_PIN, 0); \ } while (0) From dfafe131bf723fd1ca23a7ad6d63393f96014a9e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 10:28:24 +0200 Subject: [PATCH 0244/2042] boards: rv32m1_vega: remove debug pins initialization code The debug pins are now configured in the Bluetooth debug module as part of the DEBUG_INIT() macro. Signed-off-by: Gerard Marull-Paretas --- boards/riscv/rv32m1_vega/CMakeLists.txt | 6 ---- boards/riscv/rv32m1_vega/Kconfig | 12 -------- boards/riscv/rv32m1_vega/board.c | 38 ------------------------- 3 files changed, 56 deletions(-) delete mode 100644 boards/riscv/rv32m1_vega/CMakeLists.txt delete mode 100644 boards/riscv/rv32m1_vega/Kconfig delete mode 100644 boards/riscv/rv32m1_vega/board.c diff --git a/boards/riscv/rv32m1_vega/CMakeLists.txt b/boards/riscv/rv32m1_vega/CMakeLists.txt deleted file mode 100644 index 18bb64863ddf..000000000000 --- a/boards/riscv/rv32m1_vega/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_BT_CTLR_DEBUG_PINS) - zephyr_library() - zephyr_library_sources(board.c) -endif() diff --git a/boards/riscv/rv32m1_vega/Kconfig b/boards/riscv/rv32m1_vega/Kconfig deleted file mode 100644 index b76834fc3be6..000000000000 --- a/boards/riscv/rv32m1_vega/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# OpenISA VEGAboard board configuration - -# Copyright (c) 2022 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_INIT_PRIORITY - int "Board initialization priority" - default 45 - depends on BOARD_RV32M1_VEGA && BT_CTLR_DEBUG_PINS - help - Board initialization priority. The board initialization must take - place after the GPIO driver is initialized. diff --git a/boards/riscv/rv32m1_vega/board.c b/boards/riscv/rv32m1_vega/board.c deleted file mode 100644 index 19ddc931d617..000000000000 --- a/boards/riscv/rv32m1_vega/board.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022 Henrik Brix Andersen - * Copyright 2018 Foundries.io Ltd - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -static int rv32m1_vega_board_init(void) -{ - const struct device *const gpiob = DEVICE_DT_GET(DT_NODELABEL(gpiob)); - const struct device *const gpioc = DEVICE_DT_GET(DT_NODELABEL(gpioc)); - const struct device *const gpiod = DEVICE_DT_GET(DT_NODELABEL(gpiod)); - - - __ASSERT_NO_MSG(device_is_ready(gpiob)); - __ASSERT_NO_MSG(device_is_ready(gpioc)); - __ASSERT_NO_MSG(device_is_ready(gpiod)); - - gpio_pin_configure(gpiob, 29, GPIO_OUTPUT); - - gpio_pin_configure(gpioc, 28, GPIO_OUTPUT); - gpio_pin_configure(gpioc, 29, GPIO_OUTPUT); - gpio_pin_configure(gpioc, 30, GPIO_OUTPUT); - - gpio_pin_configure(gpiod, 0, GPIO_OUTPUT); - gpio_pin_configure(gpiod, 1, GPIO_OUTPUT); - gpio_pin_configure(gpiod, 2, GPIO_OUTPUT); - gpio_pin_configure(gpiod, 3, GPIO_OUTPUT); - gpio_pin_configure(gpiod, 4, GPIO_OUTPUT); - gpio_pin_configure(gpiod, 5, GPIO_OUTPUT); - - return 0; -} - -SYS_INIT(rv32m1_vega_board_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY); From 9c6853c42fa34b7335db54b0e3c5be0fb84eb06a Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 23:21:38 +0000 Subject: [PATCH 0245/2042] soc: arm: nxp_imx: do not enable RT boot header for CM4 core Disable RT boot header for CM4 core. This will ensure the boot header is not present when building an application targeting RAM on the CM4. Signed-off-by: Daniel DeGrasse --- soc/arm/nxp_imx/rt/Kconfig.soc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 3eb2e3cad29c..0f3759c6d70e 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -703,7 +703,7 @@ config PM_MCUX_PMU menuconfig NXP_IMX_RT_BOOT_HEADER bool "Boot header" - depends on (!BOOTLOADER_MCUBOOT) + depends on (!BOOTLOADER_MCUBOOT) && CPU_CORTEX_M7 help Enable data structures required by the boot ROM to boot the application from an external flash device. From fcf6efe8ecabc32967652e24639a805c8d41c9f1 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 23:23:03 +0000 Subject: [PATCH 0246/2042] samples: ipc: set flash location for CM4 in openamp sample Set flash location for CM4 to ocram, so CONFIG_FLASH_BASE_ADDRESS is set correctly. Fixes #59213 Signed-off-by: Daniel DeGrasse --- .../ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay | 3 ++- .../ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay index caff1f413a50..ae2b4c56250e 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ / { /* Switch to lpuart2, since primary core uses lpuart1 */ chosen { + zephyr,flash = &ocram; zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2; zephyr,ipc_shm = &ocram2_overlay; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay index caff1f413a50..ae2b4c56250e 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ / { /* Switch to lpuart2, since primary core uses lpuart1 */ chosen { + zephyr,flash = &ocram; zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2; zephyr,ipc_shm = &ocram2_overlay; From a255d28b1a3f34ceffd4e3d5e71bc3ff0db3177f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 13 Jun 2023 11:23:27 +0200 Subject: [PATCH 0247/2042] boards: sparkfun_thing_plus_nrf9160: use regulator-fixed Use a regulator-fixed node to describe the 3.3V power rail. Make sure it is always enabled by setting CONFIG_REGULATOR=y at board level. Signed-off-by: Gerard Marull-Paretas --- .../CMakeLists.txt | 4 --- .../arm/sparkfun_thing_plus_nrf9160/board.c | 31 ------------------- .../sparkfun_thing_plus_nrf9160_common.dtsi | 8 +++++ .../sparkfun_thing_plus_nrf9160_defconfig | 2 ++ .../sparkfun_thing_plus_nrf9160_ns_defconfig | 2 ++ 5 files changed, 12 insertions(+), 35 deletions(-) delete mode 100644 boards/arm/sparkfun_thing_plus_nrf9160/CMakeLists.txt delete mode 100644 boards/arm/sparkfun_thing_plus_nrf9160/board.c diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/CMakeLists.txt b/boards/arm/sparkfun_thing_plus_nrf9160/CMakeLists.txt deleted file mode 100644 index 218a0602483a..000000000000 --- a/boards/arm/sparkfun_thing_plus_nrf9160/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library() -zephyr_library_sources(board.c) diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/board.c b/boards/arm/sparkfun_thing_plus_nrf9160/board.c deleted file mode 100644 index b582182e6fcf..000000000000 --- a/boards/arm/sparkfun_thing_plus_nrf9160/board.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 Circuit Dojo LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#define GPIO0 DT_NODELABEL(gpio0) -#define POWER_LATCH_PIN 31 - -static int board_sparkfun_thing_plus_nrf9160_init(void) -{ - - /* Get handle of the GPIO device. */ - const struct device *const gpio = DEVICE_DT_GET(GPIO0); - - if (!device_is_ready(gpio)) { - return -ENODEV; - } - - /* Configure latch pin as output. */ - gpio_pin_configure(gpio, POWER_LATCH_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(board_sparkfun_thing_plus_nrf9160_init, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi index cf7502c082db..ab268f3cdca2 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_common.dtsi @@ -39,6 +39,14 @@ }; }; + /* TPS63031 Buck/Boost converter (provides 3.3V) */ + pwr-3v3 { + compatible = "regulator-fixed"; + regulator-name = "pwr-3v3"; + enable-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + regulator-always-on; + }; + /* These aliases are provided for compatibility with samples */ aliases { led0 = &blue_led; diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig index b3bfc6a11ee0..6c5fdd1cdd9e 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig @@ -24,3 +24,5 @@ CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_PINCTRL=y + +CONFIG_REGULATOR=y diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig index 4384ea780d3c..7386d5b08831 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig @@ -27,3 +27,5 @@ CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_PINCTRL=y + +CONFIG_REGULATOR=y From bb87a875c2c49c05864dd81f9bcbb4d5f20e2f61 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sat, 10 Jun 2023 08:29:36 +1000 Subject: [PATCH 0248/2042] drivers: sensor: adxl362: remove \n from logs Tidy Signed-off-by: Nick Ward --- drivers/sensor/adxl362/adxl362.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/adxl362/adxl362.c b/drivers/sensor/adxl362/adxl362.c index b203bda45d78..d560087ade73 100644 --- a/drivers/sensor/adxl362/adxl362.c +++ b/drivers/sensor/adxl362/adxl362.c @@ -716,7 +716,7 @@ static int adxl362_init(const struct device *dev) err = adxl362_software_reset(dev); if (err) { - LOG_ERR("adxl362_software_reset failed, error %d\n", err); + LOG_ERR("adxl362_software_reset failed, error %d", err); return -ENODEV; } @@ -724,7 +724,7 @@ static int adxl362_init(const struct device *dev) adxl362_get_reg(dev, &value, ADXL362_REG_PARTID, 1); if (value != ADXL362_PART_ID) { - LOG_ERR("wrong part_id: %d\n", value); + LOG_ERR("wrong part_id: %d", value); return -ENODEV; } From cbe8c35f9e43444f4d1b01ec576af3563b1f1546 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sat, 10 Jun 2023 19:00:58 +1000 Subject: [PATCH 0249/2042] drivers: sensor: update function parameters to const These parameters are not modified by the functions. Signed-off-by: Nick Ward --- include/zephyr/drivers/sensor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index add8b51306d1..9a74a5369499 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -1211,7 +1211,7 @@ struct sensor_info { * @param val A pointer to a sensor_value struct. * @return The converted value. */ -static inline int64_t sensor_value_to_milli(struct sensor_value *val) +static inline int64_t sensor_value_to_milli(const struct sensor_value *val) { return ((int64_t)val->val1 * 1000) + val->val2 / 1000; } @@ -1222,7 +1222,7 @@ static inline int64_t sensor_value_to_milli(struct sensor_value *val) * @param val A pointer to a sensor_value struct. * @return The converted value. */ -static inline int64_t sensor_value_to_micro(struct sensor_value *val) +static inline int64_t sensor_value_to_micro(const struct sensor_value *val) { return ((int64_t)val->val1 * 1000000) + val->val2; } From f14d06f82e859575c80c82414b74399d4e751114 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sat, 10 Jun 2023 08:34:04 +1000 Subject: [PATCH 0250/2042] drivers: sensor: bmm150: use common conversion function Better to reuse. Signed-off-by: Nick Ward --- drivers/sensor/bmi323/bmi323.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/sensor/bmi323/bmi323.c b/drivers/sensor/bmi323/bmi323.c index 1669f906c2b9..ddca1d9ed908 100644 --- a/drivers/sensor/bmi323/bmi323.c +++ b/drivers/sensor/bmi323/bmi323.c @@ -108,11 +108,6 @@ static void bosch_bmi323_value_to_sensor_value(struct sensor_value *result, int1 result->val2 = frac_part; } -static int64_t bosch_bmi323_sensor_value_to_milli(const struct sensor_value *val) -{ - return ((int64_t)val->val1 * 1000) + val->val2 / 1000; -} - static void bosch_bmi323_sensor_value_from_micro(struct sensor_value *result, int64_t micro) { int32_t int_part = (int32_t)(micro / 1000000); @@ -194,7 +189,7 @@ static int bosch_bmi323_driver_api_set_acc_odr(const struct device *dev, { int ret; uint16_t acc_conf; - int64_t odr = bosch_bmi323_sensor_value_to_milli(val); + int64_t odr = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); @@ -243,7 +238,7 @@ static int bosch_bmi323_driver_api_set_acc_full_scale(const struct device *dev, struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; uint16_t acc_conf; - int64_t fullscale = bosch_bmi323_sensor_value_to_milli(val); + int64_t fullscale = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); @@ -296,7 +291,7 @@ static int bosch_bmi323_driver_api_set_gyro_odr(const struct device *dev, { int ret; uint16_t gyro_conf; - int64_t odr = bosch_bmi323_sensor_value_to_milli(val); + int64_t odr = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); @@ -345,7 +340,7 @@ static int bosch_bmi323_driver_api_set_gyro_full_scale(const struct device *dev, struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; uint16_t gyro_conf; - int32_t fullscale = bosch_bmi323_sensor_value_to_milli(val); + int32_t fullscale = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); @@ -909,7 +904,7 @@ static int bosch_bmi323_driver_api_fetch_acc_samples(const struct device *dev) return ret; } - data->acc_full_scale = bosch_bmi323_sensor_value_to_milli(&full_scale); + data->acc_full_scale = sensor_value_to_milli(&full_scale); } ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_DATA_X, (uint16_t *)buf, 3); @@ -951,7 +946,7 @@ static int bosch_bmi323_driver_api_fetch_gyro_samples(const struct device *dev) return ret; } - data->gyro_full_scale = bosch_bmi323_sensor_value_to_milli(&full_scale); + data->gyro_full_scale = sensor_value_to_milli(&full_scale); } ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_DATA_X, (uint16_t *)buf, From c37deeb0c4602dc3eeb700a7dc3ed317283fff17 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Tue, 6 Jun 2023 14:12:37 +0200 Subject: [PATCH 0251/2042] twister: Use natural sort when generating hardware map Use the natural sort of list when generating a hardware map. The list is sorted with a serial port as a key. When more than 10 ports are active and some of devices use more than one port, the ports of one device may be listed in wrong sequence, which may cause futher problems with selecting the right port for listening to the device. Signed-off-by: Grzegorz Chwierut --- scripts/pylib/twister/twisterlib/hardwaremap.py | 3 ++- scripts/requirements-run-test.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index a0ea7c59a8eb..5e90b7c84c6f 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -13,6 +13,7 @@ import scl import logging from pathlib import Path +from natsort import natsorted from twisterlib.environment import ZEPHYR_BASE @@ -321,7 +322,7 @@ def readlink(link): def save(self, hwm_file): # use existing map - self.detected.sort(key=lambda x: x.serial or '') + self.detected = natsorted(self.detected, key=lambda x: x.serial or '') if os.path.exists(hwm_file): with open(hwm_file, 'r') as yaml_file: hwm = yaml.load(yaml_file, Loader=SafeLoader) diff --git a/scripts/requirements-run-test.txt b/scripts/requirements-run-test.txt index 3bb0b21c44e8..836921281102 100644 --- a/scripts/requirements-run-test.txt +++ b/scripts/requirements-run-test.txt @@ -7,6 +7,7 @@ pyocd>=0.35.0 # used by twister for board/hardware map tabulate +natsort # used by mcuboot cbor>=1.0.0 From c0bc9f974fb66e4eb88b5c71d65043fa773793c6 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 13:41:32 +0200 Subject: [PATCH 0252/2042] drivers: pinctrl: add TI CC32XX driver Add a new pinctrl driver for TI CC32XX SoC. The driver has not been tested, just implemented following datasheet specs and checked that it compiles. Consider this as a best-effort driver to remove custom pinmux code in board files. Signed-off-by: Gerard Marull-Paretas --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.ti_cc32xx | 9 + drivers/pinctrl/pinctrl_ti_cc32xx.c | 52 +++++ dts/arm/ti/cc32xx.dtsi | 5 + dts/bindings/pinctrl/ti,cc32xx-pinctrl.yaml | 110 +++++++++ .../dt-bindings/pinctrl/ti-cc32xx-pinctrl.h | 220 ++++++++++++++++++ soc/arm/ti_simplelink/cc32xx/CMakeLists.txt | 1 + soc/arm/ti_simplelink/cc32xx/pinctrl_soc.h | 71 ++++++ 9 files changed, 470 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.ti_cc32xx create mode 100644 drivers/pinctrl/pinctrl_ti_cc32xx.c create mode 100644 dts/bindings/pinctrl/ti,cc32xx-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/ti-cc32xx-pinctrl.h create mode 100644 soc/arm/ti_simplelink/cc32xx/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 0f18755a24c7..656fc5f27d10 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -31,3 +31,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_NXP_S32 pinctrl_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_GECKO pinctrl_gecko.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_K3 pinctrl_ti_k3.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_EMSDP pinctrl_emsdp.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 0c1f4c05b2f2..b16821edff8f 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -60,5 +60,6 @@ source "drivers/pinctrl/Kconfig.nxp_s32" source "drivers/pinctrl/Kconfig.gecko" source "drivers/pinctrl/Kconfig.ti_k3" source "drivers/pinctrl/Kconfig.emsdp" +source "drivers/pinctrl/Kconfig.ti_cc32xx" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.ti_cc32xx b/drivers/pinctrl/Kconfig.ti_cc32xx new file mode 100644 index 000000000000..708984c6535e --- /dev/null +++ b/drivers/pinctrl/Kconfig.ti_cc32xx @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_TI_CC32XX + bool "TI CC32XX pinctrl driver" + default y + depends on DT_HAS_TI_CC32XX_PINCTRL_ENABLED + help + Enable the TI CC32XX pinctrl driver diff --git a/drivers/pinctrl/pinctrl_ti_cc32xx.c b/drivers/pinctrl/pinctrl_ti_cc32xx.c new file mode 100644 index 000000000000..3d096fd894cb --- /dev/null +++ b/drivers/pinctrl/pinctrl_ti_cc32xx.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc32xx_pinctrl + +#include +#include +#include +#include + +#define MEM_GPIO_PAD_CONFIG_MSK 0xFFFU + +/* pin to pad mapping (255 indicates invalid pin) */ +static const uint8_t pin2pad[] = { + 10U, 11U, 12U, 13U, 14U, 15U, 16U, 17U, 255U, 255U, 18U, 19U, 20U, + 21U, 22U, 23U, 24U, 40U, 28U, 29U, 25U, 255U, 255U, 255U, 255U, 255U, + 255U, 255U, 26U, 27U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, + 255U, 255U, 255U, 255U, 255U, 31U, 255U, 255U, 255U, 255U, 0U, 255U, 32U, + 30U, 255U, 1U, 255U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, +}; + +static int pinctrl_configure_pin(pinctrl_soc_pin_t pincfg) +{ + uint8_t pin; + + pin = (pincfg >> TI_CC32XX_PIN_POS) & TI_CC32XX_PIN_MSK; + if ((pin >= ARRAY_SIZE(pin2pad)) || (pin2pad[pin] == 255U)) { + return -EINVAL; + } + + sys_write32(pincfg & MEM_GPIO_PAD_CONFIG_MSK, DT_INST_REG_ADDR(0) + (pin2pad[pin] << 2U)); + + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + int ret; + + ret = pinctrl_configure_pin(pins[i]); + if (ret < 0) { + return ret; + } + } + + return 0; +} diff --git a/dts/arm/ti/cc32xx.dtsi b/dts/arm/ti/cc32xx.dtsi index b179fa62b730..c2e7cfc598e4 100644 --- a/dts/arm/ti/cc32xx.dtsi +++ b/dts/arm/ti/cc32xx.dtsi @@ -130,6 +130,11 @@ interrupts = ; status = "disabled"; }; + + pinctrl: pin-controller@4402e0a0 { + compatible = "ti,cc32xx-pinctrl"; + reg = <0x4402e0a0 0x80>; + }; }; }; diff --git a/dts/bindings/pinctrl/ti,cc32xx-pinctrl.yaml b/dts/bindings/pinctrl/ti,cc32xx-pinctrl.yaml new file mode 100644 index 000000000000..60f78fe8df85 --- /dev/null +++ b/dts/bindings/pinctrl/ti,cc32xx-pinctrl.yaml @@ -0,0 +1,110 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + The TI CC32XX pin controller is a singleton node responsible for controlling + pin function selection and pin properties. For example, you can + use this node to route UART0 RX to pin 55 and enable the pull-up resistor + on the pin. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + /* You can put this in places like a board-pinctrl.dtsi file in + * your board directory, or a devicetree overlay in your application. + */ + + /* include pre-defined combinations for the SoC variant used by the board */ + #include + + &pinctrl { + /* configuration for the uart0 "default" state */ + uart0_default: uart0_default { + /* group 1 */ + group1 { + /* configure pin 55 as UART0 TX and pin 61 as UART0 CTS */ + pinmux = , ; + }; + /* group 2 */ + group2 { + /* configure pin 57 as UART0 RX and pin 62 as UART0 RTS */ + pinmux = , ; + /* both pin 57 and 62 have pull-up enabled */ + bias-pull-up; + }; + }; + + The 'uart0_default' child node encodes the pin configurations for a + particular state of a device; in this case, the default (that is, active) + state. + + As shown, pin configurations are organized in groups within each child node. + Each group can specify a list of pin function selections in the 'pinmux' + property. + + A group can also specify shared pin properties common to all the specified + pins, such as the 'bias-pull-up' property in group 2. Here is a list of + supported standard pin properties: + + - drive-push-pull: Push-pull drive mode (default, not required). + - drive-open-drain: Open-drain drive mode. + - bias-disable: Disable pull-up/down (default, not required). + - bias-pull-up: Enable pull-up resistor. + - bias-pull-down: Enable pull-down resistor. + - drive-strength: Configure drive strength in mA (defaults to 6mA, IC default). + + Note that drive and bias options are mutually exclusive. + + 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: + + #include "board-pinctrl.dtsi" + + &uart0 { + pinctrl-0 = <&uart0_default> + pinctrl-names = "default"; + }; + +compatible: "ti,cc32xx-pinctrl" + +include: base.yaml + +child-binding: + child-binding: + include: + - name: pincfg-node.yaml + property-allowlist: + - drive-push-pull + - drive-open-drain + - bias-disable + - bias-pull-down + - bias-pull-up + - drive-strength + + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should + be defined using pre-defined macros or, alternatively, using the + TI_CC32XX_PINMUX helper macro. + + drive-strength: + default: 6 + enum: + - 0 + - 2 + - 4 + - 6 + - 8 + - 10 + - 12 + - 14 diff --git a/include/zephyr/dt-bindings/pinctrl/ti-cc32xx-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/ti-cc32xx-pinctrl.h new file mode 100644 index 000000000000..0b125c42f964 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/ti-cc32xx-pinctrl.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_TI_CC32XX_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_TI_CC32XX_PINCTRL_H_ + +/* + * The whole TI CC32XX pin configuration information is encoded in a 32-bit + * bitfield organized as follows: + * + * - 31..22: Reserved + * - 21..16: Pin. + * - 15..10: Reserved. + * - 9: Pull-down flag. + * - 8: Pull-up flag. + * - 7..5: Drive strength. + * - 4: Enable open-drain flag. + * - 3..0: Configuration mode + * + * Note that the lower bits (11..0) map directly to the MEM_GPIO_PAD_CONFIG + * register. + */ + +/** + * @name TI CC32XX pin configuration bit field positions and masks. + * @{ + */ + +#define TI_CC32XX_PIN_MSK 0x3FU +#define TI_CC32XX_PIN_POS 16U +#define TI_CC32XX_MUX_MSK 0xFU +#define TI_CC32XX_MUX_POS 0U + +/** @} */ + +/** + * @brief Utility macro to build TI CC32XX pinmux property entry. + * + * @param pin Pin + * @param mux Multiplexer choice + */ +#define TI_CC32XX_PINMUX(pin, mux) \ + ((((pin)&TI_CC32XX_PIN_MSK) << TI_CC32XX_PIN_POS) | \ + (((mux)&TI_CC32XX_MUX_MSK) << TI_CC32XX_MUX_POS)) + +/** + * @name TI CC32XX pinctrl pin functions (reference: SWRU465). + * @{ + */ + +#define GPIO10_P1 TI_CC32XX_PINMUX(1U, 0U) +#define I2C_SCL_P1 TI_CC32XX_PINMUX(1U, 1U) +#define GT_PWM06_P1 TI_CC32XX_PINMUX(1U, 3U) +#define UART1_TX_P1 TI_CC32XX_PINMUX(1U, 7U) +#define SDCARD_CLK_P1 TI_CC32XX_PINMUX(1U, 6U) +#define GT_CCP01_P1 TI_CC32XX_PINMUX(1U, 12U) + +#define GPIO11_P2 TI_CC32XX_PINMUX(2U, 0U) +#define I2C_SDA_P2 TI_CC32XX_PINMUX(2U, 1U) +#define GT_PWM07_P2 TI_CC32XX_PINMUX(2U, 3U) +#define PXCLK_P2 TI_CC32XX_PINMUX(2U, 4U) +#define SDCARD_CMD_P2 TI_CC32XX_PINMUX(2U, 6U) +#define UART1_RX_P2 TI_CC32XX_PINMUX(2U, 7U) +#define GT_CCP02_P2 TI_CC32XX_PINMUX(2U, 12U) +#define MCAFSX_P2 TI_CC32XX_PINMUX(2U, 13U) + +#define GPIO12_P3 TI_CC32XX_PINMUX(3U, 0U) +#define MCACLK_P3 TI_CC32XX_PINMUX(3U, 3U) +#define PVS_P3 TI_CC32XX_PINMUX(3U, 4U) +#define I2C_SCL_P3 TI_CC32XX_PINMUX(3U, 5U) +#define UART0_TX_P3 TI_CC32XX_PINMUX(3U, 7U) +#define GT_CCP03_P3 TI_CC32XX_PINMUX(3U, 12U) + +#define GPIO13_P4 TI_CC32XX_PINMUX(4U, 0U) +#define I2C_SDA_P4 TI_CC32XX_PINMUX(4U, 5U) +#define PHS_P4 TI_CC32XX_PINMUX(4U, 4U) +#define UART0_RX_P4 TI_CC32XX_PINMUX(4U, 7U) +#define GT_CCP04_P4 TI_CC32XX_PINMUX(4U, 12U) + +#define GPIO14_P5 TI_CC32XX_PINMUX(5U, 0U) +#define I2C_SCL_P5 TI_CC32XX_PINMUX(5U, 5U) +#define GSPI_CLK_P5 TI_CC32XX_PINMUX(5U, 7U) +#define PDATA8_P5 TI_CC32XX_PINMUX(5U, 4U) +#define GT_CCP05_P5 TI_CC32XX_PINMUX(5U, 12U) + +#define GPIO15_P6 TI_CC32XX_PINMUX(6U, 0U) +#define I2C_SDA_P6 TI_CC32XX_PINMUX(6U, 5U) +#define GSPI_MISO_P6 TI_CC32XX_PINMUX(6U, 7U) +#define PDATA9_P6 TI_CC32XX_PINMUX(6U, 4U) +#define SDCARD_DATA3_P6 TI_CC32XX_PINMUX(6U, 8U) +#define GT_CCP06_P6 TI_CC32XX_PINMUX(6U, 13U) + +#define GPIO16_P7 TI_CC32XX_PINMUX(7U, 0U) +#define GSPI_MOSI_P7 TI_CC32XX_PINMUX(7U, 7U) +#define PDATA10_P7 TI_CC32XX_PINMUX(7U, 4U) +#define UART1_TX_P7 TI_CC32XX_PINMUX(7U, 5U) +#define SDCARD_CLK_P7 TI_CC32XX_PINMUX(7U, 8U) +#define GT_CCP07_P7 TI_CC32XX_PINMUX(7U, 13U) + +#define GPIO17_P8 TI_CC32XX_PINMUX(8U, 0U) +#define UART1_RX_P8 TI_CC32XX_PINMUX(8U, 5U) +#define GSPI_CS_P8 TI_CC32XX_PINMUX(8U, 7U) +#define SDCARD_CMD_P8 TI_CC32XX_PINMUX(8U, 8U) +#define PDATA11_P8 TI_CC32XX_PINMUX(8U, 4U) + +#define GPIO22_P15 TI_CC32XX_PINMUX(15U, 0U) +#define MCAFSX_P15 TI_CC32XX_PINMUX(15U, 7U) +#define GT_CCP04_P15 TI_CC32XX_PINMUX(15U, 5U) + +#define GPIO23_P16 TI_CC32XX_PINMUX(16U, 0U) +#define TDI_P16 TI_CC32XX_PINMUX(16U, 1U) +#define UART1_TX_P16 TI_CC32XX_PINMUX(16U, 2U) +#define I2C_SCL_P16 TI_CC32XX_PINMUX(16U, 9U) + +#define GPIO24_P17 TI_CC32XX_PINMUX(17U, 0U) +#define TDO_P17 TI_CC32XX_PINMUX(17U, 1U) +#define PWM0_P17 TI_CC32XX_PINMUX(17U, 5U) +#define UART1_RX_P17 TI_CC32XX_PINMUX(17U, 2U) +#define I2C_SDA_P17 TI_CC32XX_PINMUX(17U, 9U) +#define GT_CCP06_P17 TI_CC32XX_PINMUX(17U, 4U) +#define MCAFSX_P17 TI_CC32XX_PINMUX(17U, 6U) + +#define GPIO28_P18 TI_CC32XX_PINMUX(18U, 0U) + +#define TCK_P19 TI_CC32XX_PINMUX(19U, 1U) +#define GT_PWM03_P19 TI_CC32XX_PINMUX(19U, 8U) + +#define GPIO29_P20 TI_CC32XX_PINMUX(20U, 0U) +#define TMS_P20 TI_CC32XX_PINMUX(20U, 1U) + +#define GPIO25_P21 TI_CC32XX_PINMUX(21U, 0U) +#define GT_PWM02_P21 TI_CC32XX_PINMUX(21U, 9U) +#define MCASFX_P21 TI_CC32XX_PINMUX(21U, 2U) + +#define ANTSEL1_P29 TI_CC32XX_PINMUX(29U, 0U) + +#define ANTSEL2_P30 TI_CC32XX_PINMUX(30U, 0U) + +#define GPIO31_P45 TI_CC32XX_PINMUX(45U, 0U) +#define UART0_RX_P45 TI_CC32XX_PINMUX(45U, 9U) +#define MCAFSX_P45 TI_CC32XX_PINMUX(45U, 12U) +#define UART1_RX_P45 TI_CC32XX_PINMUX(45U, 2U) +#define MCAXR0_P45 TI_CC32XX_PINMUX(45U, 6U) +#define GSPI_CLK_P45 TI_CC32XX_PINMUX(45U, 7U) + +#define GPIO0_P50 TI_CC32XX_PINMUX(50U, 0U) +#define UART0_CTSN_P50 TI_CC32XX_PINMUX(50U, 12U) +#define MCAXR1_P50 TI_CC32XX_PINMUX(50U, 6U) +#define GT_CCP00_P50 TI_CC32XX_PINMUX(50U, 7U) +#define GSPI_CS_P50 TI_CC32XX_PINMUX(50U, 9U) +#define UART1_RTS_P50 TI_CC32XX_PINMUX(50U, 10U) +#define UART0_RTS_P50 TI_CC32XX_PINMUX(50U, 3U) +#define MCAXR0_P50 TI_CC32XX_PINMUX(50U, 4U) + +#define GPIO32_P52 TI_CC32XX_PINMUX(52U, 0U) +#define MCACLK_P52 TI_CC32XX_PINMUX(52U, 2U) +#define MCAXR0_P52 TI_CC32XX_PINMUX(52U, 4U) +#define UART0_RTS_P52 TI_CC32XX_PINMUX(52U, 6U) +#define GSPI_MOSI_P52 TI_CC32XX_PINMUX(52U, 8U) + +#define GPIO30_P53 TI_CC32XX_PINMUX(53U, 0U) +#define UART0_TX_P53 TI_CC32XX_PINMUX(53U, 9U) +#define MCACLK_P53 TI_CC32XX_PINMUX(53U, 2U) +#define MCAFSX_P53 TI_CC32XX_PINMUX(53U, 3U) +#define GT_CCP05_P53 TI_CC32XX_PINMUX(53U, 4U) +#define GSPI_MISO_P53 TI_CC32XX_PINMUX(53U, 7U) + +#define GPIO1_P55 TI_CC32XX_PINMUX(55U, 0U) +#define UART0_TX_P55 TI_CC32XX_PINMUX(55U, 3U) +#define PCLK_P55 TI_CC32XX_PINMUX(55U, 4U) +#define UART1_TX_P55 TI_CC32XX_PINMUX(55U, 6U) +#define GT_CCP01_P55 TI_CC32XX_PINMUX(55U, 7U) + +#define GPIO2_P57 TI_CC32XX_PINMUX(57U, 0U) +#define UART0_RX_P57 TI_CC32XX_PINMUX(57U, 3U) +#define UART1_RX_P57 TI_CC32XX_PINMUX(57U, 6U) +#define GT_CCP02_P57 TI_CC32XX_PINMUX(57U, 7U) + +#define GPIO3_P58 TI_CC32XX_PINMUX(58U, 0U) +#define UART1_TX_P58 TI_CC32XX_PINMUX(58U, 6U) +#define PDATA7_P58 TI_CC32XX_PINMUX(58U, 7U) + +#define GPIO5_P59 TI_CC32XX_PINMUX(59U, 0U) +#define UART1_RX_P59 TI_CC32XX_PINMUX(59U, 6U) +#define PDATA6_P59 TI_CC32XX_PINMUX(59U, 4U) + +#define GPIO5_P60 TI_CC32XX_PINMUX(60U, 0U) +#define PDATA5_P60 TI_CC32XX_PINMUX(60U, 4U) +#define MCAXR1_P60 TI_CC32XX_PINMUX(60U, 6U) +#define GT_CCP05_P60 TI_CC32XX_PINMUX(60U, 7U) + +#define GPIO6_P61 TI_CC32XX_PINMUX(61U, 0U) +#define UART0_RTS_P61 TI_CC32XX_PINMUX(61U, 5U) +#define PDATA4_P61 TI_CC32XX_PINMUX(61U, 4U) +#define UART1_CTS_P61 TI_CC32XX_PINMUX(61U, 3U) +#define UART0_CTS_P61 TI_CC32XX_PINMUX(61U, 6U) +#define GT_CCP06_P61 TI_CC32XX_PINMUX(61U, 7U) + +#define GPIO7_P62 TI_CC32XX_PINMUX(62U, 0U) +#define MCACLKX_P62 TI_CC32XX_PINMUX(62U, 13U) +#define UART1_RTS_P62 TI_CC32XX_PINMUX(62U, 3U) +#define UART0_RTS_P62 TI_CC32XX_PINMUX(62U, 10U) +#define UART0_TX_P62 TI_CC32XX_PINMUX(62U, 11U) + +#define GPIO8_P63 TI_CC32XX_PINMUX(63U, 0U) +#define SDCARD_IRQ_P63 TI_CC32XX_PINMUX(63U, 6U) +#define MCAFSX_P63 TI_CC32XX_PINMUX(63U, 7U) +#define GT_CCP06_P63 TI_CC32XX_PINMUX(63U, 12U) + +#define GPIO9_P64 TI_CC32XX_PINMUX(64U, 0U) +#define GT_PWM05_P64 TI_CC32XX_PINMUX(64U, 3U) +#define SDCARD_DATA_P64 TI_CC32XX_PINMUX(64U, 6U) +#define MCAXR0_P64 TI_CC32XX_PINMUX(64U, 7U) +#define GT_CCP00_P64 TI_CC32XX_PINMUX(64U, 12U) + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_TI_CC32XX_PINCTRL_H_ */ diff --git a/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt b/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt index 245f72601131..cc11ff419540 100644 --- a/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt +++ b/soc/arm/ti_simplelink/cc32xx/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources(soc.c) +zephyr_include_directories(.) if (DEFINED CONFIG_CC3220SF_DEBUG OR DEFINED CONFIG_CC3235SF_DEBUG) zephyr_linker_sources(ROM_START SORT_KEY 0 cc32xx_debug.ld) diff --git a/soc/arm/ti_simplelink/cc32xx/pinctrl_soc.h b/soc/arm/ti_simplelink/cc32xx/pinctrl_soc.h new file mode 100644 index 000000000000..20199a1b6ed0 --- /dev/null +++ b/soc/arm/ti_simplelink/cc32xx/pinctrl_soc.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_TI_SIMPLELINK_CC32XX_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_TI_SIMPLELINK_CC32XX_PINCTRL_SOC_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** Type for TI CC32XX pin. */ +typedef uint32_t pinctrl_soc_pin_t; + +/** + * @name TI CC32XX pin configuration bit field positions and masks. + */ + +#define TI_CC32XX_OPEN_DRAIN BIT(4) +#define TI_CC32XX_DRIVE_STRENGTH_MSK 0x7U +#define TI_CC32XX_DRIVE_STRENGTH_POS 5U +#define TI_CC32XX_PULL_UP BIT(8) +#define TI_CC32XX_PULL_DOWN BIT(9) +#define TI_CC32XX_PAD_OUT_OVERRIDE BIT(10) +#define TI_CC32XX_PAD_OUT_BUF_OVERRIDE BIT(11) + +/** @} */ + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param prop Property name. + * @param idx Property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + (DT_PROP_BY_IDX(node_id, prop, idx) | \ + (TI_CC32XX_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) | \ + (TI_CC32XX_PULL_UP * DT_PROP(node_id, bias_pull_down)) | \ + (TI_CC32XX_PULL_DOWN * DT_PROP(node_id, bias_pull_up)) | \ + ((DT_ENUM_IDX(node_id, drive_strength) & TI_CC32XX_DRIVE_STRENGTH_MSK) \ + << TI_CC32XX_DRIVE_STRENGTH_POS) | \ + TI_CC32XX_PAD_OUT_OVERRIDE | TI_CC32XX_PAD_OUT_BUF_OVERRIDE), + +/** + * @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_CHILD_VARGS(DT_PHANDLE(node_id, prop), DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT) \ + } + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_TI_SIMPLELINK_CC32XX_PINCTRL_SOC_H_ */ From 8654f321e99b5720cdb4a7010425adf1cdebc231 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 13:59:46 +0200 Subject: [PATCH 0253/2042] boards: cc32(20|35)sf_launchxl: add I2C pinctrl entries Add I2C pinctrl entries, and make them required at bindings level. Signed-off-by: Gerard Marull-Paretas --- .../cc3220sf_launchxl-pinctrl.dtsi | 14 ++++++++++++++ boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts | 3 +++ .../cc3235sf_launchxl-pinctrl.dtsi | 14 ++++++++++++++ boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts | 3 +++ dts/bindings/i2c/ti,cc32xx-i2c.yaml | 8 +++++++- 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi create mode 100644 boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi diff --git a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi new file mode 100644 index 000000000000..cc9f90d933a1 --- /dev/null +++ b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts index 6494e216b45d..48b702b56091 100644 --- a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts +++ b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts @@ -4,6 +4,7 @@ #include #include "boosterpack_connector.dtsi" +#include "cc3220sf_launchxl-pinctrl.dtsi" / { model = "TI CC3220SF LaunchXL"; @@ -87,6 +88,8 @@ &i2c0 { status = "okay"; clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; }; &wdt0 { diff --git a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi new file mode 100644 index 000000000000..cc9f90d933a1 --- /dev/null +++ b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + }; + }; +}; diff --git a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts index eb2e21a0ea66..45385898d215 100644 --- a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts +++ b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include "cc3235sf_launchxl-pinctrl.dtsi" / { model = "TI CC3235SF LaunchXL"; @@ -75,6 +76,8 @@ &i2c0 { status = "okay"; clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; }; &wdt0 { diff --git a/dts/bindings/i2c/ti,cc32xx-i2c.yaml b/dts/bindings/i2c/ti,cc32xx-i2c.yaml index f76fb35a805c..830af2664df6 100644 --- a/dts/bindings/i2c/ti,cc32xx-i2c.yaml +++ b/dts/bindings/i2c/ti,cc32xx-i2c.yaml @@ -2,7 +2,7 @@ description: TI CC32XX I2C controller compatible: "ti,cc32xx-i2c" -include: i2c-controller.yaml +include: [i2c-controller.yaml, pinctrl-device.yaml] properties: reg: @@ -10,3 +10,9 @@ properties: interrupts: required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true From 74b063ed58ff49f9b2eab95cfc2e2b0d34765c9e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 14:02:54 +0200 Subject: [PATCH 0254/2042] boards: cc32(20|35)sf_launchxl: add UART0 pinctrl entries Add UART0 pinctrl entries, and make them required at bindings level. Signed-off-by: Gerard Marull-Paretas --- .../arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi | 6 ++++++ boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts | 2 ++ .../arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi | 6 ++++++ boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts | 2 ++ dts/bindings/serial/ti,cc32xx-uart.yaml | 8 +++++++- 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi index cc9f90d933a1..6404883c98bc 100644 --- a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi +++ b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl-pinctrl.dtsi @@ -6,6 +6,12 @@ #include &pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = , ; + }; + }; + i2c0_default: i2c0_default { group1 { pinmux = , ; diff --git a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts index 48b702b56091..ad3e0f2155b6 100644 --- a/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts +++ b/boards/arm/cc3220sf_launchxl/cc3220sf_launchxl.dts @@ -83,6 +83,8 @@ &uart0 { status = "okay"; current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; }; &i2c0 { diff --git a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi index cc9f90d933a1..6404883c98bc 100644 --- a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi +++ b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl-pinctrl.dtsi @@ -6,6 +6,12 @@ #include &pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = , ; + }; + }; + i2c0_default: i2c0_default { group1 { pinmux = , ; diff --git a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts index 45385898d215..5851ece300b6 100644 --- a/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts +++ b/boards/arm/cc3235sf_launchxl/cc3235sf_launchxl.dts @@ -71,6 +71,8 @@ &uart0 { status = "okay"; current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; }; &i2c0 { diff --git a/dts/bindings/serial/ti,cc32xx-uart.yaml b/dts/bindings/serial/ti,cc32xx-uart.yaml index 2ff828d81c8b..b6d7488c4b51 100644 --- a/dts/bindings/serial/ti,cc32xx-uart.yaml +++ b/dts/bindings/serial/ti,cc32xx-uart.yaml @@ -2,7 +2,7 @@ description: TI CC32XX UART compatible: "ti,cc32xx-uart" -include: uart-controller.yaml +include: [uart-controller.yaml, pinctrl-device.yaml] properties: reg: @@ -10,3 +10,9 @@ properties: interrupts: required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true From a3ab08b7ce4f6260ee441ff7ac16887e3889c7c0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 13:57:52 +0200 Subject: [PATCH 0255/2042] drivers: i2c: cc32xx: add support for pinctrl Driver will configure pins using the pinctrl API now. Signed-off-by: Gerard Marull-Paretas --- drivers/i2c/Kconfig | 1 + drivers/i2c/i2c_cc32xx.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 5a327aea7b12..30fbcb6087a3 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -151,6 +151,7 @@ config I2C_CC32XX bool "CC32XX I2C driver" default y depends on DT_HAS_TI_CC32XX_I2C_ENABLED + select PINCTRL help Enable the CC32XX I2C driver. diff --git a/drivers/i2c/i2c_cc32xx.c b/drivers/i2c/i2c_cc32xx.c index fc34756030f6..afbaefb3487f 100644 --- a/drivers/i2c/i2c_cc32xx.c +++ b/drivers/i2c/i2c_cc32xx.c @@ -11,6 +11,7 @@ #include #include #include +#include #include /* Driverlib includes */ @@ -64,6 +65,7 @@ struct i2c_cc32xx_config { uint32_t base; uint32_t bitrate; unsigned int irq_no; + const struct pinctrl_dev_config *pcfg; }; struct i2c_cc32xx_data { @@ -329,6 +331,11 @@ static int i2c_cc32xx_init(const struct device *dev) int error; uint32_t regval; + error = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (error < 0) { + return error; + } + k_sem_init(&data->mutex, 1, K_SEM_MAX_LIMIT); k_sem_init(&data->transfer_complete, 0, K_SEM_MAX_LIMIT); @@ -371,10 +378,13 @@ static const struct i2c_driver_api i2c_cc32xx_driver_api = { }; +PINCTRL_DT_INST_DEFINE(0); + static const struct i2c_cc32xx_config i2c_cc32xx_config = { .base = DT_INST_REG_ADDR(0), .bitrate = DT_INST_PROP(0, clock_frequency), .irq_no = DT_INST_IRQN(0), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; static struct i2c_cc32xx_data i2c_cc32xx_data; From ecc241e0cec460fe268d37a835bb44f20633b945 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 13:58:36 +0200 Subject: [PATCH 0256/2042] drivers: serial: cc32xx: add support for pinctrl Driver will configure pins using the pinctrl API now. Signed-off-by: Gerard Marull-Paretas --- drivers/serial/Kconfig.cc32xx | 1 + drivers/serial/uart_cc32xx.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/serial/Kconfig.cc32xx b/drivers/serial/Kconfig.cc32xx index 5dc090afaedc..26fb0ed33c72 100644 --- a/drivers/serial/Kconfig.cc32xx +++ b/drivers/serial/Kconfig.cc32xx @@ -6,5 +6,6 @@ config UART_CC32XX depends on DT_HAS_TI_CC32XX_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT + select PINCTRL help This option enables the CC32XX UART driver, for UART_0. diff --git a/drivers/serial/uart_cc32xx.c b/drivers/serial/uart_cc32xx.c index 19b4a952d940..9427e0a625ed 100644 --- a/drivers/serial/uart_cc32xx.c +++ b/drivers/serial/uart_cc32xx.c @@ -9,6 +9,7 @@ #include #include #include +#include /* Driverlib includes */ #include @@ -21,6 +22,7 @@ struct uart_cc32xx_dev_config { unsigned long base; uint32_t sys_clk_freq; + const struct pinctrl_dev_config *pcfg; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_config_func_t irq_config_func; #endif @@ -53,12 +55,18 @@ static int uart_cc32xx_init(const struct device *dev) { const struct uart_cc32xx_dev_config *config = dev->config; const struct uart_cc32xx_dev_data_t *data = dev->data; + int ret; MAP_PRCMPeripheralClkEnable(data->prcm, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); MAP_PRCMPeripheralReset(data->prcm); + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + /* This also calls MAP_UARTEnable() to enable the FIFOs: */ MAP_UARTConfigSetExpClk(config->base, MAP_PRCMPeripheralClockGet(data->prcm), @@ -305,6 +313,7 @@ static const struct uart_driver_api uart_cc32xx_driver_api = { }; #define UART_32XX_DEVICE(idx) \ +PINCTRL_DT_INST_DEFINE(idx); \ IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ (static void uart_cc32xx_cfg_func_##idx(const struct device *dev) \ { \ @@ -319,6 +328,7 @@ IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ static const struct uart_cc32xx_dev_config uart_cc32xx_dev_cfg_##idx = { \ .base = DT_INST_REG_ADDR(idx), \ .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency),\ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \ (.irq_config_func = uart_cc32xx_cfg_func_##idx,)) \ }; \ From 49c4973d8ee13c89b7a9b469ab894eebd49d69b5 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 15:36:52 +0200 Subject: [PATCH 0257/2042] drivers: i2c: cc32xx: enable I2C module clock The I2C driver clock was initialized in board specific code, move it to the driver as it is part of its responsabilities. Signed-off-by: Gerard Marull-Paretas --- boards/arm/cc3220sf_launchxl/pinmux.c | 7 ------- boards/arm/cc3235sf_launchxl/pinmux.c | 7 ------- drivers/i2c/i2c_cc32xx.c | 7 +++++++ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/boards/arm/cc3220sf_launchxl/pinmux.c b/boards/arm/cc3220sf_launchxl/pinmux.c index 69947a875d18..a67d729d821f 100644 --- a/boards/arm/cc3220sf_launchxl/pinmux.c +++ b/boards/arm/cc3220sf_launchxl/pinmux.c @@ -134,13 +134,6 @@ int pinmux_initialize(void) unsigned long pin; unsigned long mode; - /* Enable the I2C module clocks and wait for completion:*/ - MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, - PRCM_RUN_MODE_CLK | - PRCM_SLP_MODE_CLK); - while (!MAP_PRCMPeripheralStatusGet(PRCM_I2CA0)) { - } - pin = I2C_CC32XX_PIN_01_I2C_SCL & 0xff; mode = (I2C_CC32XX_PIN_01_I2C_SCL >> 8) & 0xff; MAP_PinTypeI2C(pin, mode); diff --git a/boards/arm/cc3235sf_launchxl/pinmux.c b/boards/arm/cc3235sf_launchxl/pinmux.c index f4ebff48d650..24ac586e624b 100644 --- a/boards/arm/cc3235sf_launchxl/pinmux.c +++ b/boards/arm/cc3235sf_launchxl/pinmux.c @@ -110,13 +110,6 @@ int pinmux_initialize(void) unsigned long pin; unsigned long mode; - /* Enable the I2C module clocks and wait for completion:*/ - MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, - PRCM_RUN_MODE_CLK | - PRCM_SLP_MODE_CLK); - while (!MAP_PRCMPeripheralStatusGet(PRCM_I2CA0)) { - } - pin = I2C_CC32XX_PIN_01_I2C_SCL & 0xff; mode = (I2C_CC32XX_PIN_01_I2C_SCL >> 8) & 0xff; MAP_PinTypeI2C(pin, mode); diff --git a/drivers/i2c/i2c_cc32xx.c b/drivers/i2c/i2c_cc32xx.c index afbaefb3487f..b7caf5393fe3 100644 --- a/drivers/i2c/i2c_cc32xx.c +++ b/drivers/i2c/i2c_cc32xx.c @@ -331,6 +331,13 @@ static int i2c_cc32xx_init(const struct device *dev) int error; uint32_t regval; + /* Enable the I2C module clocks and wait for completion:*/ + MAP_PRCMPeripheralClkEnable(PRCM_I2CA0, + PRCM_RUN_MODE_CLK | + PRCM_SLP_MODE_CLK); + while (!MAP_PRCMPeripheralStatusGet(PRCM_I2CA0)) { + } + error = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (error < 0) { return error; From 1b9a237ec65fcdddecb585669b72dbe85a53ba79 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 11:24:53 +0200 Subject: [PATCH 0258/2042] boards: cc32(20|35)sf_launchxl: remove custom GPIO configuration Remove pin configurations for board LEDs/switches. It doesn't make sense to do this at board level when the samples take care of doing the same using the standard GPIO API. Signed-off-by: Gerard Marull-Paretas --- boards/arm/cc3220sf_launchxl/pinmux.c | 30 --------------------------- boards/arm/cc3235sf_launchxl/pinmux.c | 30 --------------------------- 2 files changed, 60 deletions(-) diff --git a/boards/arm/cc3220sf_launchxl/pinmux.c b/boards/arm/cc3220sf_launchxl/pinmux.c index a67d729d821f..25fca9621bdc 100644 --- a/boards/arm/cc3220sf_launchxl/pinmux.c +++ b/boards/arm/cc3220sf_launchxl/pinmux.c @@ -95,40 +95,10 @@ int pinmux_initialize(void) #ifdef CONFIG_UART_CC32XX /* Configure PIN_55 for UART0 UART0_TX */ MAP_PinTypeUART(PIN_55, PIN_MODE_3); - /* Configure PIN_57 for UART0 UART0_RX */ MAP_PinTypeUART(PIN_57, PIN_MODE_3); #endif - /* Enable Peripheral Clocks */ - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK); - - /* The following enables the 3 LEDs for the blinking samples */ - - /* Configure PIN_64 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_64, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x2, GPIO_DIR_MODE_OUT); - - /* Configure PIN_01 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_01, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x4, GPIO_DIR_MODE_OUT); - - /* Configure PIN_02 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_02, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x8, GPIO_DIR_MODE_OUT); - - /* SW3: Configure PIN_04 (GPIO13) for GPIOInput */ - MAP_PinTypeGPIO(PIN_04, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x20, GPIO_DIR_MODE_IN); - - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA2, PRCM_RUN_MODE_CLK); - - /* SW2: Configure PIN_15 (GPIO22) for GPIOInput */ - MAP_PinTypeGPIO(PIN_15, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA2_BASE, 0x40, GPIO_DIR_MODE_IN); - - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK); - #ifdef CONFIG_I2C_CC32XX { unsigned long pin; diff --git a/boards/arm/cc3235sf_launchxl/pinmux.c b/boards/arm/cc3235sf_launchxl/pinmux.c index 24ac586e624b..e2f5b94b79cf 100644 --- a/boards/arm/cc3235sf_launchxl/pinmux.c +++ b/boards/arm/cc3235sf_launchxl/pinmux.c @@ -75,36 +75,6 @@ int pinmux_initialize(void) MAP_PinTypeUART(PIN_57, PIN_MODE_3); #endif - /* Enable Peripheral Clocks */ - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK); - - /* The following enables the 3 LEDs for the blinking samples */ - - /* Configure PIN_64 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_64, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x2, GPIO_DIR_MODE_OUT); - - /* Configure PIN_01 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_01, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x4, GPIO_DIR_MODE_OUT); - - /* Configure PIN_02 for GPIOOutput */ - MAP_PinTypeGPIO(PIN_02, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x8, GPIO_DIR_MODE_OUT); - - /* SW3: Configure PIN_04 (GPIO13) for GPIOInput */ - MAP_PinTypeGPIO(PIN_04, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA1_BASE, 0x20, GPIO_DIR_MODE_IN); - - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA2, PRCM_RUN_MODE_CLK); - - /* SW2: Configure PIN_15 (GPIO22) for GPIOInput */ - MAP_PinTypeGPIO(PIN_15, PIN_MODE_0, false); - MAP_GPIODirModeSet(GPIOA2_BASE, 0x40, GPIO_DIR_MODE_IN); - - MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK); - - #ifdef CONFIG_I2C_CC32XX { unsigned long pin; From 28b192f7bf04b25d322a615fef2355f71c072474 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 12 Jun 2023 15:38:23 +0200 Subject: [PATCH 0259/2042] boards: cc32(20|35)sf_launchxl: remove obsolete pinmux code Pin multiplexing is now done by drivers using the pinctrl API. Signed-off-by: Gerard Marull-Paretas --- boards/arm/cc3220sf_launchxl/CMakeLists.txt | 5 +- boards/arm/cc3220sf_launchxl/pinmux.c | 120 -------------------- boards/arm/cc3235sf_launchxl/CMakeLists.txt | 5 +- boards/arm/cc3235sf_launchxl/pinmux.c | 96 ---------------- 4 files changed, 2 insertions(+), 224 deletions(-) delete mode 100644 boards/arm/cc3220sf_launchxl/pinmux.c delete mode 100644 boards/arm/cc3235sf_launchxl/pinmux.c diff --git a/boards/arm/cc3220sf_launchxl/CMakeLists.txt b/boards/arm/cc3220sf_launchxl/CMakeLists.txt index b2aecd19cdbf..750f93d4af98 100644 --- a/boards/arm/cc3220sf_launchxl/CMakeLists.txt +++ b/boards/arm/cc3220sf_launchxl/CMakeLists.txt @@ -1,7 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() -zephyr_library_sources( - pinmux.c - dbghdr.c - ) +zephyr_library_sources(dbghdr.c) diff --git a/boards/arm/cc3220sf_launchxl/pinmux.c b/boards/arm/cc3220sf_launchxl/pinmux.c deleted file mode 100644 index 25fca9621bdc..000000000000 --- a/boards/arm/cc3220sf_launchxl/pinmux.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * pinmux.c - * - * configure the device pins for different peripheral signals - * - * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the - * distribution. - * - * Neither the name of Texas Instruments Incorporated nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This file was automatically generated on 7/21/2014 at 3:06:20 PM - * by TI PinMux version 3.0.334 - * (Then modified to meet Zephyr coding style) - */ - -/* - * TI Recommends use of the PinMux utility to ensure consistent configuration - * of pins: http://processors.wiki.ti.com/index.php/TI_PinMux_Tool - * - * Zephyr GPIO API however allows runtime configuration by applications. - * - * For the TI CC32XX port we leverage this output file - * from the PinMux tool, and guard sections based on Kconfig variables. - * - * The individual (uart/gpio) driver init/configuration functions - * therefore assume pinmux initialization is done here rather in the drivers - * at runtime. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Defines taken from SimpleLink SDK's I2CCC32XX.h: */ -/* - * Macros defining possible I2C signal pin mux options - * - * The bits in the pin mode macros are as follows: - * The lower 8 bits of the macro refer to the pin, offset by 1, to match - * driverlib pin defines. For example, I2C_CC32XX_PIN_01_I2C_SCL & 0xff = 0, - * which equals PIN_01 in driverlib pin.h. By matching the PIN_xx defines in - * driverlib pin.h, we can pass the pin directly to the driverlib functions. - * The upper 8 bits of the macro correspond to the pin mux config mode - * value for the pin to operate in the I2C mode. For example, pin 1 is - * configured with mode 1 to operate as I2C_SCL. - */ -#define I2C_CC32XX_PIN_01_I2C_SCL 0x100 /*!< PIN 1 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_02_I2C_SDA 0x101 /*!< PIN 2 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_03_I2C_SCL 0x502 /*!< PIN 3 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_04_I2C_SDA 0x503 /*!< PIN 4 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_05_I2C_SCL 0x504 /*!< PIN 5 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_06_I2C_SDA 0x505 /*!< PIN 6 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_16_I2C_SCL 0x90F /*!< PIN 16 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_17_I2C_SDA 0x910 /*!< PIN 17 is used for I2C_SDA */ - -int pinmux_initialize(void) -{ - -#ifdef CONFIG_UART_CC32XX - /* Configure PIN_55 for UART0 UART0_TX */ - MAP_PinTypeUART(PIN_55, PIN_MODE_3); - /* Configure PIN_57 for UART0 UART0_RX */ - MAP_PinTypeUART(PIN_57, PIN_MODE_3); -#endif - -#ifdef CONFIG_I2C_CC32XX - { - unsigned long pin; - unsigned long mode; - - pin = I2C_CC32XX_PIN_01_I2C_SCL & 0xff; - mode = (I2C_CC32XX_PIN_01_I2C_SCL >> 8) & 0xff; - MAP_PinTypeI2C(pin, mode); - - pin = I2C_CC32XX_PIN_02_I2C_SDA & 0xff; - mode = (I2C_CC32XX_PIN_02_I2C_SDA >> 8) & 0xff; - MAP_PinTypeI2C(pin, mode); - } -#endif - - return 0; -} - -SYS_INIT(pinmux_initialize, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/boards/arm/cc3235sf_launchxl/CMakeLists.txt b/boards/arm/cc3235sf_launchxl/CMakeLists.txt index b2aecd19cdbf..750f93d4af98 100644 --- a/boards/arm/cc3235sf_launchxl/CMakeLists.txt +++ b/boards/arm/cc3235sf_launchxl/CMakeLists.txt @@ -1,7 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library() -zephyr_library_sources( - pinmux.c - dbghdr.c - ) +zephyr_library_sources(dbghdr.c) diff --git a/boards/arm/cc3235sf_launchxl/pinmux.c b/boards/arm/cc3235sf_launchxl/pinmux.c deleted file mode 100644 index e2f5b94b79cf..000000000000 --- a/boards/arm/cc3235sf_launchxl/pinmux.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2019, Texas Instruments Incorporated - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * pinmux.c - * - * configure the device pins for different peripheral signals - */ - -/* - * This file was automatically generated on 7/21/2014 at 3:06:20 PM - * by TI PinMux version 3.0.334 - * (Then modified to meet Zephyr coding style) - */ - -/* - * TI Recommends use of the PinMux utility to ensure consistent configuration - * of pins: http://processors.wiki.ti.com/index.php/TI_PinMux_Tool - * - * Zephyr GPIO API however allows runtime configuration by applications. - * - * For the TI CC32XX port we leverage this output file - * from the PinMux tool, and guard sections based on Kconfig variables. - * - * The individual (uart/gpio) driver init/configuration functions - * therefore assume pinmux initialization is done here rather in the drivers - * at runtime. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Defines taken from SimpleLink SDK's I2CCC32XX.h: */ -/* - * Macros defining possible I2C signal pin mux options - * - * The bits in the pin mode macros are as follows: - * The lower 8 bits of the macro refer to the pin, offset by 1, to match - * driverlib pin defines. For example, I2C_CC32XX_PIN_01_I2C_SCL & 0xff = 0, - * which equals PIN_01 in driverlib pin.h. By matching the PIN_xx defines in - * driverlib pin.h, we can pass the pin directly to the driverlib functions. - * The upper 8 bits of the macro correspond to the pin mux config mode - * value for the pin to operate in the I2C mode. For example, pin 1 is - * configured with mode 1 to operate as I2C_SCL. - */ -#define I2C_CC32XX_PIN_01_I2C_SCL 0x100 /*!< PIN 1 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_02_I2C_SDA 0x101 /*!< PIN 2 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_03_I2C_SCL 0x502 /*!< PIN 3 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_04_I2C_SDA 0x503 /*!< PIN 4 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_05_I2C_SCL 0x504 /*!< PIN 5 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_06_I2C_SDA 0x505 /*!< PIN 6 is used for I2C_SDA */ -#define I2C_CC32XX_PIN_16_I2C_SCL 0x90F /*!< PIN 16 is used for I2C_SCL */ -#define I2C_CC32XX_PIN_17_I2C_SDA 0x910 /*!< PIN 17 is used for I2C_SDA */ - -int pinmux_initialize(void) -{ - -#ifdef CONFIG_UART_CC32XX - /* Configure PIN_55 for UART0 UART0_TX */ - MAP_PinTypeUART(PIN_55, PIN_MODE_3); - - /* Configure PIN_57 for UART0 UART0_RX */ - MAP_PinTypeUART(PIN_57, PIN_MODE_3); -#endif - -#ifdef CONFIG_I2C_CC32XX - { - unsigned long pin; - unsigned long mode; - - pin = I2C_CC32XX_PIN_01_I2C_SCL & 0xff; - mode = (I2C_CC32XX_PIN_01_I2C_SCL >> 8) & 0xff; - MAP_PinTypeI2C(pin, mode); - - pin = I2C_CC32XX_PIN_02_I2C_SDA & 0xff; - mode = (I2C_CC32XX_PIN_02_I2C_SDA >> 8) & 0xff; - MAP_PinTypeI2C(pin, mode); - } -#endif - - return 0; -} - -SYS_INIT(pinmux_initialize, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 041201b0d19e0ca2e5b530b67a7bde0fb1814b26 Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Thu, 1 Jun 2023 14:43:43 +0530 Subject: [PATCH 0260/2042] net: wifi_mgmt: Reject TWT setup till IP address is configured If a user tries to enable TWT too early in the connection, then we might enter TWT sleep even before DHCP is completed, this can result in packet loss as when we wakeup we cannot receive traffic and completing DHCP itself can take multiple intervals. Though static ip address can be assigned too. Reject TWT till Wi-Fi interface has a valid IP address. Signed-off-by: Ajay Parida --- include/zephyr/net/wifi.h | 3 +++ subsys/net/l2/wifi/Kconfig | 11 +++++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index cace143c93d6..75139ae36c48 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -351,6 +351,7 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_PEER_NOT_TWT_CAPAB, WIFI_TWT_FAIL_OPERATION_IN_PROGRESS, WIFI_TWT_FAIL_INVALID_FLOW_ID, + WIFI_TWT_FAIL_IP_NOT_ASSIGNED, }; static const char * const twt_err_code_tbl[] = { @@ -368,6 +369,8 @@ static const char * const twt_err_code_tbl[] = { "Operation already in progress", [WIFI_TWT_FAIL_INVALID_FLOW_ID] = "Invalid negotiated flow id", + [WIFI_TWT_FAIL_IP_NOT_ASSIGNED] = + "IP address not assigned", }; static inline const char *get_twt_err_code_str(int16_t err_no) diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index ecd1d002bc3d..48bcff3943e6 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -27,3 +27,14 @@ config WIFI_MGMT_RAW_SCAN_RESULTS_ONLY to the application. endif # WIFI_MGMT_RAW_SCAN_RESULTS + +config WIFI_MGMT_TWT_CHECK_IP + bool "Check IP Assignment for TWT" + default y + help + This option enables check for valid IP address before TWT setup. + If TWT setup is triggered early in the connection, then device might + enter deep sleep without having a valid IP, this can result in device + being unreachable (IP Level) or unable to receive down link traffic + even when it is awake intervals. Rejecting TWT setup till Wi-Fi + interface has a valid IP address might be desirable in most scenarios. diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 8bafb5d4475a..104a79819814 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -310,6 +310,18 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, goto fail; } +#ifdef CONFIG_WIFI_MGMT_TWT_CHECK_IP + if ((!net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED)) && + (!net_if_ipv6_get_global_addr(NET_ADDR_PREFERRED, &iface))) { + twt_params->fail_reason = + WIFI_TWT_FAIL_IP_NOT_ASSIGNED; + goto fail; + } +#else + NET_WARN("Check for valid IP address been disabled. " + "Device might be unreachable or might not receive traffic.\n"); +#endif /* CONFIG_WIFI_MGMT_TWT_CHECK_IP */ + if (info.link_mode < WIFI_6) { twt_params->fail_reason = WIFI_TWT_FAIL_PEER_NOT_HE_CAPAB; From f9baca493cf31e7a4a26c8bb01e361b3084a03b6 Mon Sep 17 00:00:00 2001 From: Marcin Zapolski Date: Tue, 30 May 2023 10:07:19 +0200 Subject: [PATCH 0261/2042] soc: arm: stm32l4: Add STM32L4Q5 support Add STM32L4Q5 to the list of supported SOCs. Fix copy-paste error in STM32L4P5 SOC file. Signed-off-by: Marcin Zapolski --- .../st_stm32/stm32l4/Kconfig.defconfig.stm32l4p5xx | 2 +- .../st_stm32/stm32l4/Kconfig.defconfig.stm32l4q5xx | 14 ++++++++++++++ soc/arm/st_stm32/stm32l4/Kconfig.soc | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4q5xx diff --git a/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4p5xx b/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4p5xx index 7391d425d942..605264f36a04 100644 --- a/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4p5xx +++ b/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4p5xx @@ -1,4 +1,4 @@ -# ST Microelectronics STM32L4R5xx MCU +# ST Microelectronics STM32L4P5xx MCU # Copyright (c) 2018 Pushpal Sidhu # SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4q5xx b/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4q5xx new file mode 100644 index 000000000000..964cd4ad9ad2 --- /dev/null +++ b/soc/arm/st_stm32/stm32l4/Kconfig.defconfig.stm32l4q5xx @@ -0,0 +1,14 @@ +# ST Microelectronics STM32L4Q5xx MCU + +# Copyright (c) 2023 Marcin Zapolski +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32L4Q5XX + +config SOC + default "stm32l4q5xx" + +config NUM_IRQS + default 95 + +endif # SOC_STM32L4Q5XX diff --git a/soc/arm/st_stm32/stm32l4/Kconfig.soc b/soc/arm/st_stm32/stm32l4/Kconfig.soc index 7dacc3b601d8..f3e042c00084 100644 --- a/soc/arm/st_stm32/stm32l4/Kconfig.soc +++ b/soc/arm/st_stm32/stm32l4/Kconfig.soc @@ -49,6 +49,9 @@ config SOC_STM32L475XX config SOC_STM32L4P5XX bool "STM32L4P5XX" +config SOC_STM32L4Q5XX + bool "STM32L4Q5XX" + config SOC_STM32L4S5XX bool "STM32L4S5XX" From f95826b9ef7cfc2fe505a2277c8d86d434f115df Mon Sep 17 00:00:00 2001 From: Jose Alberto Meza Date: Mon, 5 Jun 2023 16:44:18 -0700 Subject: [PATCH 0262/2042] boards: arm: mec172xmodular: Perform device tree corrections MEC172x modular card has no onboard I2C IO expander. Remove obsolote dts SPI properties and choose LDMA driver. Signed-off-by: Jose Alberto Meza --- .../mec172xmodular_assy6930.dts | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts b/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts index 928991124e73..f44c554c88c9 100644 --- a/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts +++ b/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts @@ -138,22 +138,6 @@ pinctrl-0 = < &i2c00_scl_gpio004 &i2c00_sda_gpio003 >; pinctrl-names = "default"; - - pca9555@26 { - compatible = "nxp,pca95xx"; - - /* Depends on JP53 for device address. - * Pin 1-2 = A0, pin 3-4 = A1, pin 5-6 = A2. - * Address is: 0100b. - * - * Default has pin 1-2 on JP53 connected, - * resulting in device address 0x26. - */ - reg = <0x26>; - - gpio-controller; - #gpio-cells = <2>; - }; }; &i2c00_scl_gpio004 { @@ -208,10 +192,10 @@ &spi0 { status = "okay"; + compatible = "microchip,xec-qmspi-ldma"; clock-frequency = <4000000>; lines = <4>; - chip_select = <0>; - port_sel = <0>; /* Shared SPI */ + chip-select = <0>; pinctrl-0 = < &shd_cs0_n_gpio055 &shd_clk_gpio056 @@ -299,3 +283,7 @@ pinctrl-0 = <&ps2_clk0a_gpio114 &ps2_dat0a_gpio115>; pinctrl-names = "default"; }; + +&timer5 { + status = "okay"; +}; From 19d5aa89d3988aca51cf6566c2236dc25d07cd14 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 24 May 2023 15:26:00 -0700 Subject: [PATCH 0263/2042] flash: use CONFIG_FLASH to guard cmake include... ...instead of using CONFIG_FLASH_HAS_DRIVER_ENABLED. Since kconfigs are guarded by CONFIG_FLASH anyway, drivers are not built unless CONFIG_FLASH is also enabled. Signed-off-by: Daniel Leung --- drivers/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 31177ae24c4e..8c8de71ae3b1 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -30,7 +30,7 @@ add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_EEPROM eeprom) add_subdirectory_ifdef(CONFIG_ENTROPY_HAS_DRIVER entropy) add_subdirectory_ifdef(CONFIG_ESPI espi) -add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash) +add_subdirectory_ifdef(CONFIG_FLASH flash) add_subdirectory_ifdef(CONFIG_FPGA fpga) add_subdirectory_ifdef(CONFIG_FUEL_GAUGE fuel_gauge) add_subdirectory_ifdef(CONFIG_GPIO gpio) From e7726bfc00f483a94cbc78b93f1eadf3a06bd60e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 24 May 2023 15:24:34 -0700 Subject: [PATCH 0264/2042] serial: use CONFIG_SERIAL to guard cmake include... ...instead of using CONFIG_SERIAL_HAS_DRIVER. Since kconfigs are guarded by CONFIG_SERIAL anyway, drivers are not built unless CONFIG_SERIAL is also enabled. Signed-off-by: Daniel Leung --- drivers/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 8c8de71ae3b1..1ac2770f87ae 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -68,7 +68,7 @@ add_subdirectory_ifdef(CONFIG_RESET reset) add_subdirectory_ifdef(CONFIG_RETAINED_MEM retained_mem) add_subdirectory_ifdef(CONFIG_SDHC sdhc) add_subdirectory_ifdef(CONFIG_SENSOR sensor) -add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) +add_subdirectory_ifdef(CONFIG_SERIAL serial) add_subdirectory_ifdef(CONFIG_SPI spi) add_subdirectory_ifdef(CONFIG_SYSCON syscon) add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer) From e488c9e42dc4c3bcac385ba81c88fddf45330b11 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 24 May 2023 15:15:41 -0700 Subject: [PATCH 0265/2042] entropy: use CONFIG_ENTROPY_GENERATOR to guard cmake include... ...instead of using CONFIG_ENTROPY_HAS_DRIVER. Since kconfigs are guarded by CONFIG_ENTROPY_GENERATOR anyway, drivers are not built unless CONFIG_ENTROPY_GENERATOR is also enabled. Signed-off-by: Daniel Leung --- drivers/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 1ac2770f87ae..6005b4589b66 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -28,7 +28,7 @@ add_subdirectory_ifdef(CONFIG_AUXDISPLAY auxdisplay) add_subdirectory_ifdef(CONFIG_DMA dma) add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_EEPROM eeprom) -add_subdirectory_ifdef(CONFIG_ENTROPY_HAS_DRIVER entropy) +add_subdirectory_ifdef(CONFIG_ENTROPY_GENERATOR entropy) add_subdirectory_ifdef(CONFIG_ESPI espi) add_subdirectory_ifdef(CONFIG_FLASH flash) add_subdirectory_ifdef(CONFIG_FPGA fpga) From 9eec3fc6ebe96da24bf92aad78b5de41732329c3 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 10 Mar 2023 15:03:48 -0800 Subject: [PATCH 0266/2042] cmake: add zephyr_syscall_header stub This adds a new cmake function zephyr_syscall_header() which will be used in the future to limit the scope of syscalls in the built binary. Currently this is just an empty stub so that add zephyr_syscall_header() to kernel, subsys, etc. without breaking the build. Signed-off-by: Daniel Leung --- cmake/modules/extensions.cmake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index fe5fd26d0926..c6dc67790d21 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1486,6 +1486,19 @@ function(zephyr_build_string outvar) set(${outvar} ${${outvar}} PARENT_SCOPE) endfunction() +# Function to add header file(s) to the list to be passed to syscall generator. +function(zephyr_syscall_header) + # Empty function for now. Will implement later. +endfunction() + +# Function to add header file(s) to the list to be passed to syscall generator +# if condition is true. +function(zephyr_syscall_header_ifdef feature_toggle) + if(${${feature_toggle}}) + # Empty function for now. Will implement later. + endif() +endfunction() + ######################################################## # 2. Kconfig-aware extensions ######################################################## From 97dc67e6662d929725d8ad5d16b25b8a4dcccb75 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 24 May 2023 14:37:00 -0700 Subject: [PATCH 0267/2042] riscv: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- arch/riscv/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/CMakeLists.txt b/arch/riscv/CMakeLists.txt index e8065f777470..c471c4c6b51f 100644 --- a/arch/riscv/CMakeLists.txt +++ b/arch/riscv/CMakeLists.txt @@ -2,6 +2,8 @@ add_subdirectory(core) +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/riscv/error.h) + if(CONFIG_64BIT) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf64-littleriscv) else() From b93ccd22c7d71fc2641ad41dbfb792dd04384112 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 10 Mar 2023 15:06:16 -0800 Subject: [PATCH 0268/2042] kernel: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- kernel/CMakeLists.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 9c648bf8c214..7b4781e4fd33 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -3,6 +3,27 @@ # kernel is a normal CMake library and not a zephyr_library because it # should not be --whole-archive'd +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/device.h + ${ZEPHYR_BASE}/include/zephyr/kernel.h + ${ZEPHYR_BASE}/include/zephyr/sys/kobject.h + ${ZEPHYR_BASE}/include/zephyr/sys/time_units.h +) + +if(NOT CONFIG_ERRNO_IN_TLS AND NOT CONFIG_LIBC_ERRNO) + zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/sys/errno_private.h) +endif() + +zephyr_syscall_header_ifdef( + CONFIG_ATOMIC_OPERATIONS_C + ${ZEPHYR_BASE}/include/zephyr/sys/atomic_c.h +) + +zephyr_syscall_header_ifdef( + CONFIG_MMU + ${ZEPHYR_BASE}/include/zephyr/sys/mem_manage.h +) + # If a pre-built static library containing kernel code exists in # this directory, libkernel.a, link it with the application code # instead of building from source. From 057ceb1408e35896d6b4d077392f572620ab91f1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:37:52 -0700 Subject: [PATCH 0269/2042] logging: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/logging/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/logging/CMakeLists.txt b/subsys/logging/CMakeLists.txt index 4497058e285d..715577f79ab5 100644 --- a/subsys/logging/CMakeLists.txt +++ b/subsys/logging/CMakeLists.txt @@ -1,5 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/logging/log_msg.h + ${ZEPHYR_BASE}/include/zephyr/logging/log_ctrl.h +) + if(NOT CONFIG_LOG_MODE_MINIMAL) zephyr_sources_ifdef( CONFIG_LOG From cacefd4c33f979c30e4927059a3026ed48aeb1ad Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:38:34 -0700 Subject: [PATCH 0270/2042] mgmt: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/mgmt/updatehub/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/mgmt/updatehub/CMakeLists.txt b/subsys/mgmt/updatehub/CMakeLists.txt index 285616b57c9b..b71f17fab1b0 100644 --- a/subsys/mgmt/updatehub/CMakeLists.txt +++ b/subsys/mgmt/updatehub/CMakeLists.txt @@ -4,6 +4,10 @@ # SPDX -License-Identifier: Apache-2.0 # +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/mgmt/updatehub.h +) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_UPDATEHUB updatehub.c) From 1e1ab38bf039914c5d4a14c43599b77c2c5e1b5a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:38:57 -0700 Subject: [PATCH 0271/2042] net: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/net/ip/CMakeLists.txt | 5 +++++ subsys/net/l2/ethernet/CMakeLists.txt | 4 ++++ subsys/net/lib/sockets/CMakeLists.txt | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/subsys/net/ip/CMakeLists.txt b/subsys/net/ip/CMakeLists.txt index 548033b32f05..70655e2f61c1 100644 --- a/subsys/net/ip/CMakeLists.txt +++ b/subsys/net/ip/CMakeLists.txt @@ -1,5 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/net/net_if.h + ${ZEPHYR_BASE}/include/zephyr/net/net_ip.h +) + zephyr_library() zephyr_library_include_directories(.) zephyr_library_compile_definitions_ifdef( diff --git a/subsys/net/l2/ethernet/CMakeLists.txt b/subsys/net/l2/ethernet/CMakeLists.txt index 7b644ef13512..aa23df860f6b 100644 --- a/subsys/net/l2/ethernet/CMakeLists.txt +++ b/subsys/net/l2/ethernet/CMakeLists.txt @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/net/ethernet.h +) + zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/l2) zephyr_library() diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 189c79488393..14f4f241183b 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -1,5 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/net/socket.h + ${ZEPHYR_BASE}/include/zephyr/net/socket_select.h +) + zephyr_include_directories(.) zephyr_sources( From c51d80fd40a4cf95a3f3b18ccf9242acf78e737a Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:39:13 -0700 Subject: [PATCH 0272/2042] random: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/random/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/random/CMakeLists.txt b/subsys/random/CMakeLists.txt index 3bacc9b014f6..1cb72f2bea14 100644 --- a/subsys/random/CMakeLists.txt +++ b/subsys/random/CMakeLists.txt @@ -3,6 +3,7 @@ if (CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR OR CONFIG_TIMER_RANDOM_GENERATOR OR CONFIG_XOSHIRO_RANDOM_GENERATOR) +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/random/rand32.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE rand32_handlers.c) endif() From c1d9dc4f18b269d53eaa02e3dd4bafb80a109c9d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:39:29 -0700 Subject: [PATCH 0273/2042] rtio: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/rtio/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/rtio/CMakeLists.txt b/subsys/rtio/CMakeLists.txt index 41b457b28461..d48958614a9d 100644 --- a/subsys/rtio/CMakeLists.txt +++ b/subsys/rtio/CMakeLists.txt @@ -2,6 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 if(CONFIG_RTIO) + zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/rtio/rtio.h) + zephyr_library() zephyr_include_directories(${ZEPHYR_BASE}/subsys/rtio) From e734911c964393e5ff7987a85bfe88b35c6199f8 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:39:48 -0700 Subject: [PATCH 0274/2042] ztest: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- subsys/testsuite/ztest/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/testsuite/ztest/CMakeLists.txt b/subsys/testsuite/ztest/CMakeLists.txt index 9ebac5ecbc95..c9c933289858 100644 --- a/subsys/testsuite/ztest/CMakeLists.txt +++ b/subsys/testsuite/ztest/CMakeLists.txt @@ -1,5 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/subsys/testsuite/ztest/include/zephyr/ztest_error_hook.h + ${ZEPHYR_BASE}/subsys/testsuite/ztest/include/zephyr/ztest_test.h + ${ZEPHYR_BASE}/subsys/testsuite/ztest/include/zephyr/ztest_test_new.h +) + zephyr_include_directories( ${ZEPHYR_BASE}/subsys/testsuite/include ${ZEPHYR_BASE}/subsys/testsuite/ztest/include From 1d4d718a9b3e92c854301fffeb17775522e9310c Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 13 Mar 2023 14:47:23 -0700 Subject: [PATCH 0275/2042] lib: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- lib/libc/CMakeLists.txt | 4 ++++ lib/os/CMakeLists.txt | 4 ++++ lib/posix/CMakeLists.txt | 3 +++ 3 files changed, 11 insertions(+) diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index e640e36c145c..a6fecf09d66c 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/sys/libc-hooks.h +) + add_subdirectory_ifdef(CONFIG_ARCMWDT_LIBC arcmwdt) add_subdirectory_ifdef(CONFIG_ARMCLANG_STD_LIBC armstdc) add_subdirectory_ifdef(CONFIG_MINIMAL_LIBC minimal) diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index df75c47c00f9..ac542223b934 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/sys/mutex.h +) + zephyr_sources_ifdef(CONFIG_BASE64 base64.c) zephyr_sources( diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index f9a471d02266..cd6caf6b25eb 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,5 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/posix/time.h +) zephyr_interface_library_named(posix_subsys) From 26ecaba4af068f51be0fe5e37b0f7518af2d3029 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 24 May 2023 15:27:04 -0700 Subject: [PATCH 0276/2042] drivers: syscalls: use zephyr_syscall_header This adds a few line use zephyr_syscall_header() to include headers containing syscall function prototypes. Signed-off-by: Daniel Leung --- drivers/adc/CMakeLists.txt | 2 ++ drivers/auxdisplay/CMakeLists.txt | 2 ++ drivers/cache/CMakeLists.txt | 2 ++ drivers/can/CMakeLists.txt | 2 ++ drivers/console/CMakeLists.txt | 5 +++++ drivers/counter/CMakeLists.txt | 7 +++++++ drivers/dac/CMakeLists.txt | 2 ++ drivers/dma/CMakeLists.txt | 2 ++ drivers/eeprom/CMakeLists.txt | 2 ++ drivers/entropy/CMakeLists.txt | 2 ++ drivers/espi/CMakeLists.txt | 2 ++ drivers/flash/CMakeLists.txt | 12 ++++++++++++ drivers/fuel_gauge/CMakeLists.txt | 2 ++ drivers/gpio/CMakeLists.txt | 2 ++ drivers/hwinfo/CMakeLists.txt | 2 ++ drivers/i2c/CMakeLists.txt | 2 ++ drivers/i2s/CMakeLists.txt | 2 ++ drivers/i3c/CMakeLists.txt | 2 ++ drivers/ipm/CMakeLists.txt | 2 ++ drivers/led/CMakeLists.txt | 2 ++ drivers/mbox/CMakeLists.txt | 2 ++ drivers/peci/CMakeLists.txt | 2 ++ drivers/ps2/CMakeLists.txt | 2 ++ drivers/ptp_clock/CMakeLists.txt | 2 ++ drivers/pwm/CMakeLists.txt | 2 ++ drivers/reset/CMakeLists.txt | 2 ++ drivers/retained_mem/CMakeLists.txt | 2 ++ drivers/rtc/CMakeLists.txt | 2 ++ drivers/sensor/CMakeLists.txt | 2 ++ drivers/serial/CMakeLists.txt | 2 ++ drivers/smbus/CMakeLists.txt | 2 ++ drivers/spi/CMakeLists.txt | 2 ++ drivers/usb/bc12/CMakeLists.txt | 2 ++ drivers/virtualization/CMakeLists.txt | 4 ++++ drivers/w1/CMakeLists.txt | 2 ++ drivers/watchdog/CMakeLists.txt | 2 ++ 36 files changed, 92 insertions(+) diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 24e593c2eda9..63be06b419aa 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/adc.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_ADC adc_common.c) diff --git a/drivers/auxdisplay/CMakeLists.txt b/drivers/auxdisplay/CMakeLists.txt index 1cc566fbfe0f..654d68921c72 100644 --- a/drivers/auxdisplay/CMakeLists.txt +++ b/drivers/auxdisplay/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/auxdisplay.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_HD44780 auxdisplay_hd44780.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_ITRON auxdisplay_itron.c) diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index d99135ca435b..47c790f0a890 100644 --- a/drivers/cache/CMakeLists.txt +++ b/drivers/cache/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/cache.h) + zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index c5a39471ea9c..3302c7e6af59 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/can.h) + zephyr_library() zephyr_sources_ifdef(CONFIG_CAN_MCUX_MCAN can_mcux_mcan.c) diff --git a/drivers/console/CMakeLists.txt b/drivers/console/CMakeLists.txt index 40d1e53081de..8e5e26aaabc9 100644 --- a/drivers/console/CMakeLists.txt +++ b/drivers/console/CMakeLists.txt @@ -1,5 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header_ifdef( + CONFIG_UART_MUX + ${ZEPHYR_BASE}/include/zephyr/drivers/console/uart_mux.h +) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_GSM_MUX gsm_mux.c) diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 38ae41fbf9f5..147f0ca761c8 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -1,5 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header_ifdef( + CONFIG_COUNTER_MAXIM_DS3231 + ${ZEPHYR_BASE}/include/zephyr/drivers/rtc/maxim_ds3231.h +) + +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/counter.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_TIMER_TMR_CMSDK_APB timer_tmr_cmsdk_apb.c) diff --git a/drivers/dac/CMakeLists.txt b/drivers/dac/CMakeLists.txt index 800bc895fde7..5689bea3086d 100644 --- a/drivers/dac/CMakeLists.txt +++ b/drivers/dac/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/dac.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_DAC dac_mcux_dac.c) diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 8b91184cc2bb..4f8fd7550863 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/dma.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_DMA_SAM_XDMAC dma_sam_xdmac.c) diff --git a/drivers/eeprom/CMakeLists.txt b/drivers/eeprom/CMakeLists.txt index fd2783517407..e3fd985d038f 100644 --- a/drivers/eeprom/CMakeLists.txt +++ b/drivers/eeprom/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/eeprom.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE eeprom_handlers.c) diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index f46f16e96968..99184f3b1e5a 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/entropy.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_ENTROPY_TELINK_B91_TRNG entropy_b91_trng.c) diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index cfdf84fd7575..77455ebda016 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/espi.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c) diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index a68281b071f6..181f16101db1 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -1,5 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header_ifdef( + CONFIG_FLASH_SIMULATOR + ${ZEPHYR_BASE}/include/zephyr/drivers/flash/flash_simulator.h +) + +zephyr_syscall_header_ifdef( + CONFIG_NORDIC_QSPI_NOR + ${ZEPHYR_BASE}/include/zephyr/drivers/flash/nrf_qspi_nor.h +) + +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/flash.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc26xx.c) diff --git a/drivers/fuel_gauge/CMakeLists.txt b/drivers/fuel_gauge/CMakeLists.txt index a2d8148a1a47..bf7d5e4918e6 100644 --- a/drivers/fuel_gauge/CMakeLists.txt +++ b/drivers/fuel_gauge/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/fuel_gauge.h) + add_subdirectory_ifdef(CONFIG_SBS_GAUGE_NEW_API sbs_gauge) add_subdirectory_ifdef(CONFIG_MAX17048 max17048) diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 1237fe7bd741..16eb3caeb2ad 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/gpio.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) diff --git a/drivers/hwinfo/CMakeLists.txt b/drivers/hwinfo/CMakeLists.txt index 45d0fb297c17..6ff5d1929f6f 100644 --- a/drivers/hwinfo/CMakeLists.txt +++ b/drivers/hwinfo/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/hwinfo.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE hwinfo_handlers.c) diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 9f381a69b2c0..25e4b2349948 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/i2c.h) + zephyr_library() zephyr_library_sources(i2c_common.c) diff --git a/drivers/i2s/CMakeLists.txt b/drivers/i2s/CMakeLists.txt index 4b3ce8eca379..c6f6d17f4f93 100644 --- a/drivers/i2s/CMakeLists.txt +++ b/drivers/i2s/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/i2s.h) + zephyr_library() zephyr_library_sources(i2s_common.c) diff --git a/drivers/i3c/CMakeLists.txt b/drivers/i3c/CMakeLists.txt index 4371cd385000..2645dbeabb59 100644 --- a/drivers/i3c/CMakeLists.txt +++ b/drivers/i3c/CMakeLists.txt @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/i3c.h) + zephyr_library() zephyr_library_sources( diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index cee766242d3d..63148148e87e 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/ipm.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_IPM_MCUX ipm_mcux.c) diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index ba1dd973fa2a..c9a7478286dd 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/led.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c) diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index 69969bc60506..be9d00e36e67 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/mbox.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c) diff --git a/drivers/peci/CMakeLists.txt b/drivers/peci/CMakeLists.txt index 61cfc9deeb9d..f73bcd120342 100644 --- a/drivers/peci/CMakeLists.txt +++ b/drivers/peci/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/peci.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_PECI_XEC peci_mchp_xec.c) diff --git a/drivers/ps2/CMakeLists.txt b/drivers/ps2/CMakeLists.txt index 006c70d63f62..bfcaae96ea28 100644 --- a/drivers/ps2/CMakeLists.txt +++ b/drivers/ps2/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/ps2.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_PS2_XEC ps2_mchp_xec.c) diff --git a/drivers/ptp_clock/CMakeLists.txt b/drivers/ptp_clock/CMakeLists.txt index 719dc0398a72..7987b588ceaa 100644 --- a/drivers/ptp_clock/CMakeLists.txt +++ b/drivers/ptp_clock/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/ptp_clock.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK ptp_clock.c) diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index be63c0977c2a..fcd0075eeed1 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/pwm.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_PWM_TELINK_B91 pwm_b91.c) diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index a589886a4da7..d65dd5a5e95c 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/reset.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_RESET_GD32 reset_gd32.c) zephyr_library_sources_ifdef(CONFIG_RESET_RPI_PICO reset_rpi_pico.c) diff --git a/drivers/retained_mem/CMakeLists.txt b/drivers/retained_mem/CMakeLists.txt index c3c9ea6d0bdd..f8e34a5a7c73 100644 --- a/drivers/retained_mem/CMakeLists.txt +++ b/drivers/retained_mem/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/retained_mem.h) + zephyr_library() 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) diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index b807adc927b8..6272b12a41e9 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -1,6 +1,8 @@ # Copyright (c) 2022 Bjarki Arge Andreasen # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 3821ba469e83..d13ac7e56eb4 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -142,6 +142,8 @@ add_subdirectory_ifdef(CONFIG_WSEN_PDUS wsen_pdus) add_subdirectory_ifdef(CONFIG_WSEN_TIDS wsen_tids) add_subdirectory_ifdef(CONFIG_XMC4XXX_TEMP xmc4xxx_temp) +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/sensor.h) + zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index fcbfd6b079a1..a860c8d1d61f 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/uart.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag.c) zephyr_library_sources_ifdef(CONFIG_UART_ALTERA uart_altera.c) diff --git a/drivers/smbus/CMakeLists.txt b/drivers/smbus/CMakeLists.txt index e7c76704d2bc..13a260681f05 100644 --- a/drivers/smbus/CMakeLists.txt +++ b/drivers/smbus/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/smbus.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_SMBUS_SHELL smbus_shell.c) diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 0f7d5bcb16b6..a544b4e7b684 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/spi.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_SPI_TELINK_B91 spi_b91.c) diff --git a/drivers/usb/bc12/CMakeLists.txt b/drivers/usb/bc12/CMakeLists.txt index abf068604b74..31b9c3212a29 100644 --- a/drivers/usb/bc12/CMakeLists.txt +++ b/drivers/usb/bc12/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/usb/usb_bc12.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_USB_BC12_PI3USB9201 bc12_pi3usb9201.c) diff --git a/drivers/virtualization/CMakeLists.txt b/drivers/virtualization/CMakeLists.txt index 2829e64169da..c16ed84e3190 100644 --- a/drivers/virtualization/CMakeLists.txt +++ b/drivers/virtualization/CMakeLists.txt @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/drivers/virtualization/ivshmem.h +) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_IVSHMEM virt_ivshmem.c) diff --git a/drivers/w1/CMakeLists.txt b/drivers/w1/CMakeLists.txt index 29680119e0d1..57d010f4e4d5 100644 --- a/drivers/w1/CMakeLists.txt +++ b/drivers/w1/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/w1.h) + zephyr_library() zephyr_sources_ifdef(CONFIG_USERSPACE w1_handlers.c) diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index cd40a5a7984e..12317539ac7b 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/watchdog.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_IWDG_STM32 wdt_iwdg_stm32.c) From 80e78208e6cda603c9c909e934fbdf49d23c181e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 25 May 2023 11:41:48 -0700 Subject: [PATCH 0277/2042] kernel: syscalls: no need to include all syscalls in binary The syscall generation phase parses all header files to look for potential syscalls, and emits all the relevant files to enable syscalls. However, this results in all the syscall marshalling functions being included in the final binary. This is due to these functions being referred to inside the dispatch list, resulting in ineffective garbage collection during linking. Previous commits allows each drivers and subsystems to specify which header files containing syscalls are relevant. So this commit changes the syscall generation to only include the syscalls needed for the build in the syscall dispatch list and removing various bits related to that. This allows the linker to garbage collect unused syscall related function, and thus reducing final binary size. Signed-off-by: Daniel Leung --- CMakeLists.txt | 22 ++++++-- Kconfig.zephyr | 7 +++ cmake/modules/extensions.cmake | 27 +++++++++- scripts/build/gen_syscalls.py | 35 ++++++++---- scripts/build/parse_syscalls.py | 95 +++++++++++++++++++++++++-------- 5 files changed, 151 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90c60baabaff..f6b06937f873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,11 @@ set(PARSE_SYSCALLS_TARGET parse_syscalls_target) define_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT BRIEF_DOCS " " FULL_DOCS " ") set_property( GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-little${ARCH}) # BFD format +# Contains the list of files with syscall function prototypes. +add_library(syscalls_interface INTERFACE) +set(syscalls_file_list_output + ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls_file_list.txt) + # "zephyr_interface" is a source-less library that encapsulates all the global # compiler options needed by all source files. All zephyr libraries, # including the library named "zephyr" link with this library to @@ -728,13 +733,16 @@ add_custom_command( COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/parse_syscalls.py - --include ${ZEPHYR_BASE}/include # Read files from this dir - --include ${ZEPHYR_BASE}/drivers # For net sockets - --include ${ZEPHYR_BASE}/subsys/net # More net sockets + --scan ${ZEPHYR_BASE}/include # Read files from this dir + --scan ${ZEPHYR_BASE}/drivers # For net sockets + --scan ${ZEPHYR_BASE}/subsys/net # More net sockets ${parse_syscalls_include_args} # Read files from these dirs also --json-file ${syscalls_json} # Write this file --tag-struct-file ${struct_tags_json} # Write subsystem list to this file + --file-list ${syscalls_file_list_output} + $<$:--emit-all-syscalls> DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS} + ${syscalls_file_list_output} ${syscalls_interface} ) # Make sure Picolibc is built before the rest of the system; there's no explicit @@ -850,6 +858,14 @@ zephyr_get_include_directories_for_lang(C ZEPHYR_INCLUDES) add_subdirectory(kernel) +get_property( + syscalls_file_list + TARGET syscalls_interface + PROPERTY INTERFACE_INCLUDE_DIRECTORIES +) +file(CONFIGURE OUTPUT ${syscalls_file_list_output} + CONTENT "@syscalls_file_list@" @ONLY) + # Read list content get_property(ZEPHYR_LIBS_PROPERTY GLOBAL PROPERTY ZEPHYR_LIBS) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 05670647bfd7..38d86271311e 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -738,6 +738,13 @@ config CHECK_INIT_PRIORITIES_FAIL_ON_WARNING devices depending on each other but initialized with the same priority. +config EMIT_ALL_SYSCALLS + bool "Emit all possible syscalls in the tree" + help + This tells the build system to emit all possible syscalls found + in the tree, instead of only those syscalls associated with enabled + drivers and subsystems. + endmenu config DEPRECATED diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index c6dc67790d21..69d802e32cac 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1488,14 +1488,37 @@ endfunction() # Function to add header file(s) to the list to be passed to syscall generator. function(zephyr_syscall_header) - # Empty function for now. Will implement later. + foreach(one_file ${ARGV}) + if(EXISTS ${one_file}) + set(header_file ${one_file}) + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${one_file}) + set(header_file ${CMAKE_CURRENT_SOURCE_DIR}/${one_file}) + else() + message(FATAL_ERROR "Syscall header file not found: ${one_file}") + endif() + + target_sources( + syscalls_interface INTERFACE + ${header_file} + ) + target_include_directories( + syscalls_interface INTERFACE + ${header_file} + ) + add_dependencies( + syscalls_interface + ${header_file} + ) + + unset(header_file) + endforeach() endfunction() # Function to add header file(s) to the list to be passed to syscall generator # if condition is true. function(zephyr_syscall_header_ifdef feature_toggle) if(${${feature_toggle}}) - # Empty function for now. Will implement later. + zephyr_syscall_header(${ARGN}) endif() endfunction() diff --git a/scripts/build/gen_syscalls.py b/scripts/build/gen_syscalls.py index 301b963e8701..3a95207a4149 100755 --- a/scripts/build/gen_syscalls.py +++ b/scripts/build/gen_syscalls.py @@ -419,22 +419,29 @@ def main(): invocations = {} mrsh_defs = {} mrsh_includes = {} - ids = [] + ids_emit = [] + ids_not_emit = [] table_entries = [] handlers = [] + emit_list = [] - for match_group, fn in syscalls: + for match_group, fn, to_emit in syscalls: handler, inv, mrsh, sys_id, entry = analyze_fn(match_group, fn) if fn not in invocations: invocations[fn] = [] invocations[fn].append(inv) - ids.append(sys_id) - table_entries.append(entry) handlers.append(handler) - if mrsh: + if to_emit: + ids_emit.append(sys_id) + table_entries.append(entry) + emit_list.append(handler) + else: + ids_not_emit.append(sys_id) + + if mrsh and to_emit: syscall = typename_split(match_group[0])[1] mrsh_defs[syscall] = mrsh mrsh_includes[syscall] = "#include " % fn @@ -444,7 +451,7 @@ def main(): weak_defines = "".join([weak_template % name for name in handlers - if not name in noweak]) + if not name in noweak and name in emit_list]) # The "noweak" ones just get a regular declaration weak_defines += "\n".join(["extern uintptr_t %s(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, void *ssf);" @@ -454,13 +461,23 @@ def main(): ",\n\t".join(table_entries))) # Listing header emitted to stdout - ids.sort() - ids.extend(["K_SYSCALL_BAD", "K_SYSCALL_LIMIT"]) + ids_emit.sort() + ids_emit.extend(["K_SYSCALL_BAD", "K_SYSCALL_LIMIT"]) ids_as_defines = "" - for i, item in enumerate(ids): + for i, item in enumerate(ids_emit): ids_as_defines += "#define {} {}\n".format(item, i) + if ids_not_emit: + # There are syscalls that are not used in the image but + # their IDs are used in the generated stubs. So need to + # make them usable but outside the syscall ID range. + ids_as_defines += "\n\n/* Following syscalls are not used in image */\n" + ids_not_emit.sort() + num_emitted_ids = len(ids_emit) + for i, item in enumerate(ids_not_emit): + ids_as_defines += "#define {} {}\n".format(item, i + num_emitted_ids) + with open(args.syscall_list, "w") as fp: fp.write(list_template % ids_as_defines) diff --git a/scripts/build/parse_syscalls.py b/scripts/build/parse_syscalls.py index 3536d52a9c48..c9c259980119 100644 --- a/scripts/build/parse_syscalls.py +++ b/scripts/build/parse_syscalls.py @@ -55,13 +55,38 @@ def tagged_struct_update(target_list, tag, contents): target_list.extend(items) -def analyze_headers(multiple_directories): +def analyze_headers(include_dir, scan_dir, file_list): syscall_ret = [] tagged_ret = {} for tag in struct_tags: tagged_ret[tag] = [] + syscall_files = dict() + + # Get the list of header files which contains syscalls to be emitted. + # If file_list does not exist, we emit all syscalls. + if file_list: + with open(file_list, "r", encoding="utf-8") as fp: + contents = fp.read() + + for one_file in contents.split(";"): + if os.path.isfile(one_file): + syscall_files[one_file] = {"emit": True} + else: + sys.stderr.write(f"{one_file} does not exists!\n") + sys.exit(1) + + multiple_directories = set() + if include_dir: + multiple_directories |= set(include_dir) + if scan_dir: + multiple_directories |= set(scan_dir) + + # 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 + # header files (e.g. for function stubs). for base_path in multiple_directories: for root, dirs, files in os.walk(base_path, topdown=True): dirs.sort() @@ -76,23 +101,35 @@ def analyze_headers(multiple_directories): 'common.h'))): continue - with open(path, "r", encoding="utf-8") as fp: - try: - contents = fp.read() - except Exception: - sys.stderr.write("Error decoding %s\n" % path) - raise + if path not in syscall_files: + if include_dir and base_path in include_dir: + syscall_files[path] = {"emit" : True} + else: + syscall_files[path] = {"emit" : False} - try: - syscall_result = [(mo.groups(), fn) - for mo in syscall_regex.finditer(contents)] - for tag in struct_tags: - tagged_struct_update(tagged_ret[tag], tag, contents) - except Exception: - sys.stderr.write("While parsing %s\n" % fn) - raise + # Parse files to extract syscall functions + for one_file in syscall_files: + with open(one_file, "r", encoding="utf-8") as fp: + try: + contents = fp.read() + except Exception: + sys.stderr.write("Error decoding %s\n" % path) + raise - syscall_ret.extend(syscall_result) + fn = os.path.basename(one_file) + + try: + to_emit = syscall_files[one_file]["emit"] | args.emit_all_syscalls + + syscall_result = [(mo.groups(), fn, to_emit) + for mo in syscall_regex.finditer(contents)] + for tag in struct_tags: + tagged_struct_update(tagged_ret[tag], tag, contents) + except Exception: + sys.stderr.write("While parsing %s\n" % fn) + raise + + syscall_ret.extend(syscall_result) return syscall_ret, tagged_ret @@ -116,16 +153,31 @@ def parse_args(): description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) - parser.add_argument("-i", "--include", required=True, action='append', - help='''include directories recursively scanned - for .h files. Can be specified multiple times: - -i topdir1 -i topdir2 ...''') + parser.add_argument( + "-i", "--include", required=False, action="append", + help="Include directories recursively scanned for .h files " + "containing syscalls that must be present in final binary. " + "Can be specified multiple times: -i topdir1 -i topdir2 ...") + parser.add_argument( + "--scan", required=False, action="append", + help="Scan directories recursively for .h files containing " + "syscalls that need stubs generated but may not need to " + "be present in final binary. Can be specified multiple " + "times.") parser.add_argument( "-j", "--json-file", required=True, help="Write system call prototype information as json to file") parser.add_argument( "-t", "--tag-struct-file", required=True, help="Write tagged struct name information as json to file") + parser.add_argument( + "--file-list", required=False, + help="Text file containing semi-colon separated list of " + "header file where only syscalls in these files " + "are emitted.") + parser.add_argument( + "--emit-all-syscalls", required=False, action="store_true", + help="Emit all potential syscalls in the tree") args = parser.parse_args() @@ -133,7 +185,8 @@ def parse_args(): def main(): parse_args() - syscalls, tagged = analyze_headers(args.include) + syscalls, tagged = analyze_headers(args.include, args.scan, + args.file_list) # Only write json files if they don't exist or have changes since # they will force an incremental rebuild. From dbeb4d8f48176019ce67e26987c061c7a7055878 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 26 May 2023 16:14:10 -0700 Subject: [PATCH 0278/2042] doc: kernel/syscalls: about limiting syscalls in binaries Since not all syscalls are generated to be included in the final binaries due to changes in build steps and CMake files, update the document to clarify what needs to be done to include specific syscalls in final binaries. Signed-off-by: Daniel Leung --- doc/kernel/usermode/syscalls.rst | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/doc/kernel/usermode/syscalls.rst b/doc/kernel/usermode/syscalls.rst index 43ff5f23eb5c..af16fbd2e4f5 100644 --- a/doc/kernel/usermode/syscalls.rst +++ b/doc/kernel/usermode/syscalls.rst @@ -91,12 +91,23 @@ bottom of ``include/sensor.h``: C prototype functions must be declared in one of the directories listed in the CMake variable ``SYSCALL_INCLUDE_DIRS``. This list -always contains ``${ZEPHYR_BASE}/include``, but will also contain -``APPLICATION_SOURCE_DIR`` when ``CONFIG_APPLICATION_DEFINED_SYSCALL`` -is set, or ``${ZEPHYR_BASE}/subsys/testsuite/ztest/include`` when +always contains ``APPLICATION_SOURCE_DIR`` when +``CONFIG_APPLICATION_DEFINED_SYSCALL`` is set, or +``${ZEPHYR_BASE}/subsys/testsuite/ztest/include`` when ``CONFIG_ZTEST`` is set. Additional paths can be added to the list through the CMake command line or in CMake code that is run before -``find_package(Zephyr ...)`` is run. +``find_package(Zephyr ...)`` is run. ``${ZEPHYR_BASE}/include`` +is always scanned for potential syscall prototypes. + +Note that not all syscalls will be included in the final binaries. +CMake functions ``zephyr_syscall_header`` and +``zephyr_syscall_header_ifdef`` are used to specify which header +files contain syscall prototypes where those syscalls must be +present in the final binaries. Note that header files inside +directories listed in CMake variable ``SYSCALL_INCLUDE_DIRS`` +will always have their syscalls present in final binaries. +To force all syscalls to be included in the final binaries, +turn on :kconfig:option:`CONFIG_EMIT_ALL_SYSCALLS`. Invocation Context ================== @@ -138,6 +149,16 @@ the project out directory under ``include/generated/``: * An entry for the system call is created in the dispatch table ``_k_syscall_table``, expressed in ``include/generated/syscall_dispatch.c`` + * This table only contains syscalls where their corresponding + prototypes are declared in header files when + :kconfig:option:`CONFIG_EMIT_ALL_SYSCALLS` is enabled: + + * Indicated by CMake functions ``zephyr_syscall_header`` and + ``zephyr_syscall_header_ifdef``, or + + * Under directories specified in CMake variable + ``SYSCALL_INCLUDE_DIRS``. + * A weak verification function is declared, which is just an alias of the 'unimplemented system call' verifier. This is necessary since the real verification function may or may not be built depending on the kernel @@ -603,6 +624,7 @@ Configuration Options Related configuration options: * :kconfig:option:`CONFIG_USERSPACE` +* :kconfig:option:`CONFIG_EMIT_ALL_SYSCALLS` APIs **** From 37cac7f2e278b9697ebce72c67aefc9cccf9f1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Tue, 13 Jun 2023 10:05:18 +0200 Subject: [PATCH 0279/2042] Bluetooth: Host: Use custom API for Bluetooth settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit wrap the `settings_set_one` and `settings_delete` functions in `bt_settings_store_one` and `bt_settings_delete`. By doing that the Bluetooth settings can be managed in a single place. This commit also introduce a new API to manage Bluetooth storage with `bt_settings_store_*` and `bt_settings_delete_*` functions. Each Bluetooth settings key have their own store and delete functions. Doing that so custom behavior for key can be done if necessary. This change is motivated by a need of keeping track of different persistently stored settings inside the Bluetooth subsystem. This will allow a better management of the settings that the Bluetooth subsystem is responsible of. Signed-off-by: Théo Battrel --- subsys/bluetooth/host/gatt.c | 107 +++------------- subsys/bluetooth/host/hci_core.c | 6 +- subsys/bluetooth/host/id.c | 6 +- subsys/bluetooth/host/keys.c | 36 +----- subsys/bluetooth/host/keys_br.c | 13 +- subsys/bluetooth/host/settings.c | 204 ++++++++++++++++++++++++++----- subsys/bluetooth/host/settings.h | 41 +++++++ 7 files changed, 248 insertions(+), 165 deletions(-) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 5539c4997f3b..9de7fb161217 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -332,28 +332,16 @@ static struct gatt_sc_cfg *find_sc_cfg(uint8_t id, const bt_addr_le_t *addr) static void sc_store(struct gatt_sc_cfg *cfg) { - char key[BT_SETTINGS_KEY_MAX]; int err; - if (cfg->id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), cfg->id); - bt_settings_encode_key(key, sizeof(key), "sc", - &cfg->peer, id_str); - } else { - bt_settings_encode_key(key, sizeof(key), "sc", - &cfg->peer, NULL); - } - - err = settings_save_one(key, (char *)&cfg->data, sizeof(cfg->data)); + err = bt_settings_store_sc(cfg->id, &cfg->peer, &cfg->data, sizeof(cfg->data)); if (err) { LOG_ERR("failed to store SC (err %d)", err); return; } - LOG_DBG("stored SC for %s (%s, 0x%04x-0x%04x)", bt_addr_le_str(&cfg->peer), key, - cfg->data.start, cfg->data.end); + LOG_DBG("stored SC for %s (0x%04x-0x%04x)", bt_addr_le_str(&cfg->peer), cfg->data.start, + cfg->data.end); } static void clear_sc_cfg(struct gatt_sc_cfg *cfg) @@ -372,25 +360,13 @@ static int bt_gatt_clear_sc(uint8_t id, const bt_addr_le_t *addr) } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - char key[BT_SETTINGS_KEY_MAX]; int err; - if (cfg->id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), cfg->id); - bt_settings_encode_key(key, sizeof(key), "sc", - &cfg->peer, id_str); - } else { - bt_settings_encode_key(key, sizeof(key), "sc", - &cfg->peer, NULL); - } - - err = settings_delete(key); + err = bt_settings_delete_sc(cfg->id, &cfg->peer); if (err) { LOG_ERR("failed to delete SC (err %d)", err); } else { - LOG_DBG("deleted SC for %s (%s)", bt_addr_le_str(&cfg->peer), key); + LOG_DBG("deleted SC for %s", bt_addr_le_str(&cfg->peer)); } } @@ -836,7 +812,7 @@ static void db_hash_store(void) #if defined(CONFIG_BT_SETTINGS) int err; - err = settings_save_one("bt/hash", &db_hash.hash, sizeof(db_hash.hash)); + err = bt_settings_store_hash(&db_hash.hash, sizeof(db_hash.hash)); if (err) { LOG_ERR("Failed to save Database Hash (err %d)", err); } @@ -1032,7 +1008,6 @@ static int bt_gatt_store_cf(uint8_t id, const bt_addr_le_t *peer) { #if defined(CONFIG_BT_GATT_CACHING) struct gatt_cf_cfg *cfg; - char key[BT_SETTINGS_KEY_MAX]; char dst[CF_NUM_BYTES + CF_FLAGS_STORE_LEN]; char *str; size_t len; @@ -1048,14 +1023,6 @@ static int bt_gatt_store_cf(uint8_t id, const bt_addr_le_t *peer) str = (char *)cfg->data; len = sizeof(cfg->data); - if (id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), id); - bt_settings_encode_key(key, sizeof(key), "cf", - peer, id_str); - } - /* add the CF data to a temp array */ memcpy(dst, str, len); @@ -1069,18 +1036,13 @@ static int bt_gatt_store_cf(uint8_t id, const bt_addr_le_t *peer) str = dst; } - if (!cfg || !id) { - bt_settings_encode_key(key, sizeof(key), "cf", - peer, NULL); - } - - err = settings_save_one(key, str, len); + err = bt_settings_store_cf(id, peer, str, len); if (err) { LOG_ERR("Failed to store Client Features (err %d)", err); return err; } - LOG_DBG("Stored CF for %s (%s)", bt_addr_le_str(peer), key); + LOG_DBG("Stored CF for %s", bt_addr_le_str(peer)); LOG_HEXDUMP_DBG(str, len, "Saved data"); #endif /* CONFIG_BT_GATT_CACHING */ return 0; @@ -5702,7 +5664,7 @@ static int ccc_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, return ccc_set(name, len_rd, read_cb, cb_arg); } -SETTINGS_STATIC_HANDLER_DEFINE(bt_ccc, "bt/ccc", NULL, ccc_set_cb, NULL, NULL); +BT_SETTINGS_DEFINE(ccc, "ccc", ccc_set_cb, NULL); static int ccc_set_direct(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg, void *param) @@ -5938,7 +5900,6 @@ static uint8_t ccc_save(const struct bt_gatt_attr *attr, uint16_t handle, int bt_gatt_store_ccc(uint8_t id, const bt_addr_le_t *addr) { struct ccc_save save; - char key[BT_SETTINGS_KEY_MAX]; size_t len; char *str; int err; @@ -5949,15 +5910,6 @@ int bt_gatt_store_ccc(uint8_t id, const bt_addr_le_t *addr) bt_gatt_foreach_attr(0x0001, 0xffff, ccc_save, &save); - if (id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), id); - bt_settings_encode_key(key, sizeof(key), "ccc", addr, id_str); - } else { - bt_settings_encode_key(key, sizeof(key), "ccc", addr, NULL); - } - if (save.count) { str = (char *)save.store; len = save.count * sizeof(*save.store); @@ -5967,13 +5919,13 @@ int bt_gatt_store_ccc(uint8_t id, const bt_addr_le_t *addr) len = 0; } - err = settings_save_one(key, str, len); + err = bt_settings_store_ccc(id, addr, str, len); if (err) { LOG_ERR("Failed to store CCCs (err %d)", err); return err; } - LOG_DBG("Stored CCCs for %s (%s)", bt_addr_le_str(addr), key); + LOG_DBG("Stored CCCs for %s", bt_addr_le_str(addr)); if (len) { for (size_t i = 0; i < save.count; i++) { LOG_DBG(" CCC: handle 0x%04x value 0x%04x", save.store[i].handle, @@ -6069,7 +6021,7 @@ static int sc_commit(void) return 0; } -SETTINGS_STATIC_HANDLER_DEFINE(bt_sc, "bt/sc", NULL, sc_set, sc_commit, NULL); +BT_SETTINGS_DEFINE(sc, "sc", sc_set, sc_commit); #endif /* CONFIG_BT_GATT_SERVICE_CHANGED */ #if defined(CONFIG_BT_GATT_CACHING) @@ -6159,7 +6111,7 @@ static int cf_set(const char *name, size_t len_rd, settings_read_cb read_cb, return 0; } -SETTINGS_STATIC_HANDLER_DEFINE(bt_cf, "bt/cf", NULL, cf_set, NULL, NULL); +BT_SETTINGS_DEFINE(cf, "cf", cf_set, NULL); static int db_hash_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) @@ -6190,8 +6142,7 @@ static int db_hash_commit(void) return 0; } -SETTINGS_STATIC_HANDLER_DEFINE(bt_hash, "bt/hash", NULL, db_hash_set, - db_hash_commit, NULL); +BT_SETTINGS_DEFINE(hash, "hash", db_hash_set, db_hash_commit); #endif /*CONFIG_BT_GATT_CACHING */ #endif /* CONFIG_BT_SETTINGS */ @@ -6229,20 +6180,7 @@ static int bt_gatt_clear_ccc(uint8_t id, const bt_addr_le_t *addr) &addr_with_id); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - char key[BT_SETTINGS_KEY_MAX]; - - if (id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), id); - bt_settings_encode_key(key, sizeof(key), "ccc", - addr, id_str); - } else { - bt_settings_encode_key(key, sizeof(key), "ccc", - addr, NULL); - } - - return settings_delete(key); + return bt_settings_delete_ccc(id, addr); } return 0; @@ -6258,20 +6196,7 @@ static int bt_gatt_clear_cf(uint8_t id, const bt_addr_le_t *addr) } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - char key[BT_SETTINGS_KEY_MAX]; - - if (id) { - char id_str[4]; - - u8_to_dec(id_str, sizeof(id_str), id); - bt_settings_encode_key(key, sizeof(key), "cf", - addr, id_str); - } else { - bt_settings_encode_key(key, sizeof(key), "cf", - addr, NULL); - } - - return settings_delete(key); + return bt_settings_delete_ccc(id, addr); } return 0; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 0f67e646c9a5..8a793d3108f4 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -4093,7 +4093,7 @@ int bt_set_name(const char *name) bt_dev.name[len] = '\0'; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - err = settings_save_one("bt/name", bt_dev.name, len); + err = bt_settings_store_name(bt_dev.name, len); if (err) { LOG_WRN("Unable to store name"); } @@ -4128,9 +4128,7 @@ int bt_set_appearance(uint16_t appearance) { if (bt_dev.appearance != appearance) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - int err = settings_save_one("bt/appearance", &appearance, - sizeof(appearance)); - + int err = bt_settings_store_appearance(&appearance, sizeof(appearance)); if (err) { LOG_ERR("Unable to save setting 'bt/appearance' (err %d).", err); return err; diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 8371ee043312..a7a29a14d215 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -1229,7 +1229,8 @@ static int id_create(uint8_t id, bt_addr_le_t *addr, uint8_t *irk) */ if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { - bt_settings_save_id(); + (void)bt_settings_store_id(); + (void)bt_settings_store_irk(); } return 0; @@ -1377,7 +1378,8 @@ int bt_id_delete(uint8_t id) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { - bt_settings_save_id(); + (void)bt_settings_store_id(); + (void)bt_settings_store_irk(); } return 0; diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index b25463134c9d..7b0b13b6493b 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -311,22 +311,8 @@ void bt_keys_clear(struct bt_keys *keys) } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - char key[BT_SETTINGS_KEY_MAX]; - /* Delete stored keys from flash */ - if (keys->id) { - char id[4]; - - u8_to_dec(id, sizeof(id), keys->id); - bt_settings_encode_key(key, sizeof(key), "keys", - &keys->addr, id); - } else { - bt_settings_encode_key(key, sizeof(key), "keys", - &keys->addr, NULL); - } - - LOG_DBG("Deleting key %s", key); - settings_delete(key); + bt_settings_delete_keys(keys->id, &keys->addr); } (void)memset(keys, 0, sizeof(*keys)); @@ -335,29 +321,18 @@ void bt_keys_clear(struct bt_keys *keys) #if defined(CONFIG_BT_SETTINGS) int bt_keys_store(struct bt_keys *keys) { - char key[BT_SETTINGS_KEY_MAX]; int err; __ASSERT_NO_MSG(keys != NULL); - if (keys->id) { - char id[4]; - - u8_to_dec(id, sizeof(id), keys->id); - bt_settings_encode_key(key, sizeof(key), "keys", &keys->addr, - id); - } else { - bt_settings_encode_key(key, sizeof(key), "keys", &keys->addr, - NULL); - } - - err = settings_save_one(key, keys->storage_start, BT_KEYS_STORAGE_LEN); + err = bt_settings_store_keys(keys->id, &keys->addr, keys->storage_start, + BT_KEYS_STORAGE_LEN); if (err) { LOG_ERR("Failed to save keys (err %d)", err); return err; } - LOG_DBG("Stored keys for %s (%s)", bt_addr_le_str(&keys->addr), key); + LOG_DBG("Stored keys for %s", bt_addr_le_str(&keys->addr)); return 0; } @@ -473,8 +448,7 @@ static int keys_commit(void) return 0; } -SETTINGS_STATIC_HANDLER_DEFINE(bt_keys, "bt/keys", NULL, keys_set, keys_commit, - NULL); +BT_SETTINGS_DEFINE(keys, "keys", keys_set, keys_commit); #endif /* CONFIG_BT_SETTINGS */ diff --git a/subsys/bluetooth/host/keys_br.c b/subsys/bluetooth/host/keys_br.c index afccc1b11072..47799d49289e 100644 --- a/subsys/bluetooth/host/keys_br.c +++ b/subsys/bluetooth/host/keys_br.c @@ -98,14 +98,12 @@ struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr) void bt_keys_link_key_clear(struct bt_keys_link_key *link_key) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - char key[BT_SETTINGS_KEY_MAX]; bt_addr_le_t le_addr; le_addr.type = BT_ADDR_LE_PUBLIC; bt_addr_copy(&le_addr.a, &link_key->addr); - bt_settings_encode_key(key, sizeof(key), "link_key", - &le_addr, NULL); - settings_delete(key); + + bt_settings_delete_link_key(&le_addr); } LOG_DBG("%s", bt_addr_str(&link_key->addr)); @@ -135,16 +133,13 @@ void bt_keys_link_key_store(struct bt_keys_link_key *link_key) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { int err; - char key[BT_SETTINGS_KEY_MAX]; bt_addr_le_t le_addr; le_addr.type = BT_ADDR_LE_PUBLIC; bt_addr_copy(&le_addr.a, &link_key->addr); - bt_settings_encode_key(key, sizeof(key), "link_key", - &le_addr, NULL); - err = settings_save_one(key, link_key->storage_start, - BT_KEYS_LINK_KEY_STORAGE_LEN); + err = bt_settings_store_link_key(&le_addr, link_key->storage_start, + BT_KEYS_LINK_KEY_STORAGE_LEN); if (err) { LOG_ERR("Failed to save link key (err %d)", err); } diff --git a/subsys/bluetooth/host/settings.c b/subsys/bluetooth/host/settings.c index b0abba0fb733..1623645ae212 100644 --- a/subsys/bluetooth/host/settings.c +++ b/subsys/bluetooth/host/settings.c @@ -228,33 +228,6 @@ static int set_setting(const char *name, size_t len_rd, settings_read_cb read_cb return -ENOENT; } -#define ID_DATA_LEN(array) (bt_dev.id_count * sizeof(array[0])) - -static void save_id(struct k_work *work) -{ - int err; - LOG_INF("Saving ID"); - err = settings_save_one("bt/id", &bt_dev.id_addr, - ID_DATA_LEN(bt_dev.id_addr)); - if (err) { - LOG_ERR("Failed to save ID (err %d)", err); - } - -#if defined(CONFIG_BT_PRIVACY) - err = settings_save_one("bt/irk", bt_dev.irk, ID_DATA_LEN(bt_dev.irk)); - if (err) { - LOG_ERR("Failed to save IRK (err %d)", err); - } -#endif -} - -K_WORK_DEFINE(save_id_work, save_id); - -void bt_settings_save_id(void) -{ - k_work_submit(&save_id_work); -} - static int commit_settings(void) { int err; @@ -301,7 +274,8 @@ static int commit_settings(void) */ if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_STORE_ID)) { LOG_DBG("Storing Identity Information"); - bt_settings_save_id(); + bt_settings_store_id(); + bt_settings_store_irk(); } return 0; @@ -323,3 +297,177 @@ int bt_settings_init(void) return 0; } + +int bt_settings_store(const char *key, uint8_t id, const bt_addr_le_t *addr, const void *value, + size_t val_len) +{ + int err; + char id_str[4]; + char key_str[BT_SETTINGS_KEY_MAX]; + + if (addr) { + if (id) { + u8_to_dec(id_str, sizeof(id_str), id); + } + + bt_settings_encode_key(key_str, sizeof(key_str), key, addr, (id ? id_str : NULL)); + } else { + err = snprintk(key_str, sizeof(key_str), "bt/%s", key); + if (err < 0) { + return -EINVAL; + } + } + + return settings_save_one(key_str, value, val_len); +} + +int bt_settings_delete(const char *key, uint8_t id, const bt_addr_le_t *addr) +{ + int err; + char id_str[4]; + char key_str[BT_SETTINGS_KEY_MAX]; + + if (addr) { + if (id) { + u8_to_dec(id_str, sizeof(id_str), id); + } + + bt_settings_encode_key(key_str, sizeof(key_str), key, addr, (id ? id_str : NULL)); + } else { + err = snprintk(key_str, sizeof(key_str), "bt/%s", key); + if (err < 0) { + return -EINVAL; + } + } + + return settings_delete(key_str); +} + +int bt_settings_store_sc(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len) +{ + return bt_settings_store("sc", id, addr, value, val_len); +} + +int bt_settings_delete_sc(uint8_t id, const bt_addr_le_t *addr) +{ + return bt_settings_delete("sc", id, addr); +} + +int bt_settings_store_cf(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len) +{ + return bt_settings_store("cf", id, addr, value, val_len); +} + +int bt_settings_delete_cf(uint8_t id, const bt_addr_le_t *addr) +{ + return bt_settings_delete("cf", id, addr); +} + +int bt_settings_store_ccc(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len) +{ + return bt_settings_store("ccc", id, addr, value, val_len); +} + +int bt_settings_delete_ccc(uint8_t id, const bt_addr_le_t *addr) +{ + return bt_settings_delete("ccc", id, addr); +} + +int bt_settings_store_hash(const void *value, size_t val_len) +{ + return bt_settings_store("hash", 0, NULL, value, val_len); +} + +int bt_settings_delete_hash(void) +{ + return bt_settings_delete("hash", 0, NULL); +} + +int bt_settings_store_name(const void *value, size_t val_len) +{ + return bt_settings_store("name", 0, NULL, value, val_len); +} + +int bt_settings_delete_name(void) +{ + return bt_settings_delete("name", 0, NULL); +} + +int bt_settings_store_appearance(const void *value, size_t val_len) +{ + return bt_settings_store("appearance", 0, NULL, value, val_len); +} + +int bt_settings_delete_appearance(void) +{ + return bt_settings_delete("appearance", 0, NULL); +} + +static void do_store_id(struct k_work *work) +{ + int err = bt_settings_store("id", 0, NULL, &bt_dev.id_addr, ID_DATA_LEN(bt_dev.id_addr)); + + if (err) { + LOG_ERR("Failed to save ID (err %d)", err); + } +} + +K_WORK_DEFINE(store_id_work, do_store_id); + +int bt_settings_store_id(void) +{ + k_work_submit(&store_id_work); + + return 0; +} + +int bt_settings_delete_id(void) +{ + return bt_settings_delete("id", 0, NULL); +} + +static void do_store_irk(struct k_work *work) +{ +#if defined(CONFIG_BT_PRIVACY) + int err = bt_settings_store("irk", 0, NULL, bt_dev.irk, ID_DATA_LEN(bt_dev.irk)); + + if (err) { + LOG_ERR("Failed to save IRK (err %d)", err); + } +#endif +} + +K_WORK_DEFINE(store_irk_work, do_store_irk); + +int bt_settings_store_irk(void) +{ +#if defined(CONFIG_BT_PRIVACY) + k_work_submit(&store_irk_work); +#endif /* defined(CONFIG_BT_PRIVACY) */ + return 0; +} + +int bt_settings_delete_irk(void) +{ + return bt_settings_delete("irk", 0, NULL); +} + +int bt_settings_store_link_key(const bt_addr_le_t *addr, const void *value, size_t val_len) +{ + return bt_settings_store("link_key", 0, addr, value, val_len); +} + +int bt_settings_delete_link_key(const bt_addr_le_t *addr) +{ + return bt_settings_delete("link_key", 0, addr); +} + +int bt_settings_store_keys(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len) +{ + return bt_settings_store("keys", id, addr, value, val_len); +} + +int bt_settings_delete_keys(uint8_t id, const bt_addr_le_t *addr) +{ + return bt_settings_delete("keys", id, addr); +} diff --git a/subsys/bluetooth/host/settings.h b/subsys/bluetooth/host/settings.h index e4854e437c14..271163d182d9 100644 --- a/subsys/bluetooth/host/settings.h +++ b/subsys/bluetooth/host/settings.h @@ -4,12 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /* Max settings key length (with all components) */ #define BT_SETTINGS_KEY_MAX 36 /* Base64-encoded string buffer size of in_size bytes */ #define BT_SETTINGS_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1) +#define BT_SETTINGS_DEFINE(_hname, _subtree, _set, _commit) \ + SETTINGS_STATIC_HANDLER_DEFINE(bt_##_hname, "bt/" _subtree, NULL, _set, _commit, NULL) + +#define ID_DATA_LEN(array) (bt_dev.id_count * sizeof(array[0])) + +int bt_settings_store(const char *key, uint8_t id, const bt_addr_le_t *addr, const void *value, + size_t val_len); +int bt_settings_delete(const char *key, uint8_t id, const bt_addr_le_t *addr); + /* Helpers for keys containing a bdaddr */ void bt_settings_encode_key(char *path, size_t path_size, const char *subsys, const bt_addr_le_t *addr, const char *key); @@ -18,3 +29,33 @@ int bt_settings_decode_key(const char *key, bt_addr_le_t *addr); void bt_settings_save_id(void); int bt_settings_init(void); + +int bt_settings_store_sc(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len); +int bt_settings_delete_sc(uint8_t id, const bt_addr_le_t *addr); + +int bt_settings_store_cf(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len); +int bt_settings_delete_cf(uint8_t id, const bt_addr_le_t *addr); + +int bt_settings_store_ccc(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len); +int bt_settings_delete_ccc(uint8_t id, const bt_addr_le_t *addr); + +int bt_settings_store_hash(const void *value, size_t val_len); +int bt_settings_delete_hash(void); + +int bt_settings_store_name(const void *value, size_t val_len); +int bt_settings_delete_name(void); + +int bt_settings_store_appearance(const void *value, size_t val_len); +int bt_settings_delete_appearance(void); + +int bt_settings_store_id(void); +int bt_settings_delete_id(void); + +int bt_settings_store_irk(void); +int bt_settings_delete_irk(void); + +int bt_settings_store_link_key(const bt_addr_le_t *addr, const void *value, size_t val_len); +int bt_settings_delete_link_key(const bt_addr_le_t *addr); + +int bt_settings_store_keys(uint8_t id, const bt_addr_le_t *addr, const void *value, size_t val_len); +int bt_settings_delete_keys(uint8_t id, const bt_addr_le_t *addr); From 0f079a1ab8dd62fd4b091d1a566784439f81aa99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Tue, 13 Jun 2023 10:06:49 +0200 Subject: [PATCH 0280/2042] Bluetooth: Unit: Fix unit tests that rely on settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the previous commit that introduce the settings API for the Bluetooth subsystem, some unit tests needed to be updated to use it. Signed-off-by: Théo Battrel --- .../bluetooth/host/id/bt_id_delete/src/main.c | 6 ++- .../bt_id_delete/src/test_suite_bt_settings.c | 23 ++++++----- .../src/test_suite_bt_settings_enabled.c | 14 +++---- .../src/test_suite_bt_settings_enabled.c | 20 +++++----- tests/bluetooth/host/id/mocks/kernel.c | 1 + tests/bluetooth/host/id/mocks/kernel.h | 1 + tests/bluetooth/host/id/mocks/settings.c | 5 ++- tests/bluetooth/host/id/mocks/settings.h | 11 ++++- .../host/id/mocks/settings_expects.c | 28 ++++++++++--- .../host/id/mocks/settings_expects.h | 28 ++++++++++--- .../src/test_suite_bt_settings.c | 8 +--- .../host/keys/bt_keys_store/src/main.c | 40 ++++++++----------- .../host/keys/bt_keys_update_usage/src/main.c | 2 +- .../src/test_suite_save_aging_counter.c | 2 +- .../host/keys/mocks/settings_expects.c | 5 ++- .../host/keys/mocks/settings_store.c | 5 ++- .../host/keys/mocks/settings_store.h | 12 +++--- .../host/keys/mocks/settings_store_expects.c | 29 ++++++-------- .../host/keys/mocks/settings_store_expects.h | 18 ++++----- 19 files changed, 149 insertions(+), 109 deletions(-) diff --git a/tests/bluetooth/host/id/bt_id_delete/src/main.c b/tests/bluetooth/host/id/bt_id_delete/src/main.c index d30c47991d0e..58c2c8c5733f 100644 --- a/tests/bluetooth/host/id/bt_id_delete/src/main.c +++ b/tests/bluetooth/host/id/bt_id_delete/src/main.c @@ -64,7 +64,8 @@ ZTEST(bt_id_delete, test_delete_non_default_no_last_item) err = bt_id_delete(id); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); + expect_not_called_bt_settings_store_irk(); zassert_ok(err, "Unexpected error code '%d' was returned", err); zassert_true(bt_dev.id_count == id_count, "Incorrect ID count %d was set", bt_dev.id_count); @@ -109,7 +110,8 @@ ZTEST(bt_id_delete, test_delete_last_id) err = bt_id_delete(id); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); + expect_not_called_bt_settings_store_irk(); zassert_ok(err, "Unexpected error code '%d' was returned", err); diff --git a/tests/bluetooth/host/id/bt_id_delete/src/test_suite_bt_settings.c b/tests/bluetooth/host/id/bt_id_delete/src/test_suite_bt_settings.c index ef922ccd00a6..d7cefdd9fea9 100644 --- a/tests/bluetooth/host/id/bt_id_delete/src/test_suite_bt_settings.c +++ b/tests/bluetooth/host/id/bt_id_delete/src/test_suite_bt_settings.c @@ -21,8 +21,8 @@ ZTEST_SUITE(bt_id_delete_bt_settings, NULL, NULL, NULL, NULL, NULL); /* * Test deleting an ID, but not the last one - * As 'CONFIG_BT_SETTINGS' is enabled, settings should be saved by calling bt_settings_save_id() - * if 'BT_DEV_READY' flag in bt_dev.flags is set + * As 'CONFIG_BT_SETTINGS' is enabled, settings should be saved by calling bt_settings_store_id() + * and bt_settings_store_irk() if 'BT_DEV_READY' flag in bt_dev.flags is set * * Constraints: * - ID value used is neither corresponds to default index nor the last index @@ -32,7 +32,7 @@ ZTEST_SUITE(bt_id_delete_bt_settings, NULL, NULL, NULL, NULL, NULL); * Expected behaviour: * - bt_dev.id_addr[] at index equals to the ID value used is cleared * - bt_dev.irk[] at index equals to the ID value used is cleared (if privacy is enabled) - * - bt_settings_save_id() is called to save settings + * - bt_settings_store_id() and bt_settings_store_irk() are called to save settings * - bt_dev.id_count is kept unchanged * - bt_id_delete() returns 0 */ @@ -59,7 +59,8 @@ ZTEST(bt_id_delete_bt_settings, test_delete_non_default_no_last_item_settings_en err = bt_id_delete(id); - expect_single_call_bt_settings_save_id(); + expect_single_call_bt_settings_store_id(); + expect_single_call_bt_settings_store_irk(); zassert_ok(err, "Unexpected error code '%d' was returned", err); zassert_true(bt_dev.id_count == id_count, "Incorrect ID count %d was set", bt_dev.id_count); @@ -73,9 +74,9 @@ ZTEST(bt_id_delete_bt_settings, test_delete_non_default_no_last_item_settings_en } /* - * Test deleting last ID. - * As 'CONFIG_BT_SETTINGS' is enabled, settings should be saved by calling bt_settings_save_id() - * if 'BT_DEV_READY' flag in bt_dev.flags is set + * Test deleting last ID. As 'CONFIG_BT_SETTINGS' is enabled, settings should + * be saved by calling bt_settings_store_id() and bt_settings_store_irk() if + * 'BT_DEV_READY' flag in bt_dev.flags is set * * Constraints: * - ID value used corresponds to the last item in the list bt_dev.id_addr[] @@ -84,8 +85,9 @@ ZTEST(bt_id_delete_bt_settings, test_delete_non_default_no_last_item_settings_en * * Expected behaviour: * - bt_dev.id_addr[] at index equals to the ID value used is cleared - * - bt_dev.irk[] at index equals to the ID value used is cleared (if privacy is enabled) - * - bt_settings_save_id() is called to save settings + * - bt_dev.irk[] at index equals to the ID value used is cleared (if privacy + * is enabled) + * - bt_settings_store_id() and bt_settings_store_irk() are called to save settings * - bt_dev.id_count is decremented * - bt_id_delete() returns 0 */ @@ -111,7 +113,8 @@ ZTEST(bt_id_delete_bt_settings, test_delete_last_id_settings_enabled) err = bt_id_delete(id); - expect_single_call_bt_settings_save_id(); + expect_single_call_bt_settings_store_id(); + expect_single_call_bt_settings_store_irk(); zassert_ok(err, "Unexpected error code '%d' was returned", err); zassert_true(bt_dev.id_count == (id_count - 1), "Incorrect ID count %d was set", diff --git a/tests/bluetooth/host/id/bt_setup_public_id_addr/src/test_suite_bt_settings_enabled.c b/tests/bluetooth/host/id/bt_setup_public_id_addr/src/test_suite_bt_settings_enabled.c index b634eeba92b5..77313336f2a4 100644 --- a/tests/bluetooth/host/id/bt_setup_public_id_addr/src/test_suite_bt_settings_enabled.c +++ b/tests/bluetooth/host/id/bt_setup_public_id_addr/src/test_suite_bt_settings_enabled.c @@ -50,7 +50,7 @@ ZTEST_SUITE(bt_setup_public_id_addr_bt_settings_enabled, NULL, NULL, tc_setup, N * * Expected behaviour: * - ID count is set to 0 and bt_setup_public_id_addr() returns 0 - * - No expected calls to bt_settings_save_id() + * - No expected calls to bt_settings_store_id() */ ZTEST(bt_setup_public_id_addr_bt_settings_enabled, test_bt_id_read_public_addr_returns_zero) { @@ -61,7 +61,7 @@ ZTEST(bt_setup_public_id_addr_bt_settings_enabled, test_bt_id_read_public_addr_r err = bt_setup_public_id_addr(); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); zassert_true(bt_dev.id_count == 0, "Incorrect value '%d' was set to bt_dev.id_count", bt_dev.id_count); @@ -86,7 +86,7 @@ static int bt_hci_cmd_send_sync_custom_fake(uint16_t opcode, struct net_buf *buf /* * Test reading controller public address through bt_hci_cmd_send_sync(). - * Even if the operation succeeded, bt_settings_save_id() shouldn't be called to + * Even if the operation succeeded, bt_settings_store_id() shouldn't be called to * store settings as the 'BT_DEV_READY' bit isn't set. * * Constraints: @@ -112,7 +112,7 @@ ZTEST(bt_setup_public_id_addr_bt_settings_enabled, err = bt_setup_public_id_addr(); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); zassert_true(err == 0, "Unexpected error code '%d' was returned", err); zassert_mem_equal(&bt_dev.id_addr[BT_ID_DEFAULT], BT_LE_ADDR, sizeof(bt_addr_le_t), @@ -122,8 +122,8 @@ ZTEST(bt_setup_public_id_addr_bt_settings_enabled, } /* - * Test reading controller public address through bt_hci_cmd_send_sync(). - * With the 'BT_DEV_READY' bit set, bt_settings_save_id() should be called to store + * Test reading controller public address through bt_hci_cmd_send_sync(). With + * the 'BT_DEV_READY' bit set, bt_settings_store_id() should be called to store * settings to persistent memory. * * Constraints: @@ -149,7 +149,7 @@ ZTEST(bt_setup_public_id_addr_bt_settings_enabled, err = bt_setup_public_id_addr(); - expect_single_call_bt_settings_save_id(); + expect_single_call_bt_settings_store_id(); zassert_true(err == 0, "Unexpected error code '%d' was returned", err); zassert_mem_equal(&bt_dev.id_addr[BT_ID_DEFAULT], BT_LE_ADDR, sizeof(bt_addr_le_t), diff --git a/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c b/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c index 65ed4b64b19d..e2b63adfefed 100644 --- a/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c +++ b/tests/bluetooth/host/id/bt_setup_random_id_addr/src/test_suite_bt_settings_enabled.c @@ -54,7 +54,7 @@ ZTEST_SUITE(bt_setup_random_id_addr_bt_settings_enabled, NULL, NULL, tc_setup, N * * Expected behaviour: * - ID count is set to 0 and bt_setup_random_id_addr() returns a negative error code - * - No expected calls to bt_settings_save_id() + * - No expected calls to bt_settings_store_id() */ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, test_bt_read_static_addr_returns_zero) { @@ -65,7 +65,7 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, test_bt_read_static_addr_retu err = bt_setup_random_id_addr(); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); zassert_true(bt_dev.id_count == 0, "Incorrect value '%d' was set to bt_dev.id_count", bt_dev.id_count); @@ -90,7 +90,7 @@ static int bt_hci_cmd_send_sync_custom_fake(uint16_t opcode, struct net_buf *buf /* * Test reading controller static random address through bt_hci_cmd_send_sync(). - * Even if the operation succeeded, bt_settings_save_id() shouldn't be called to + * Even if the operation succeeded, bt_settings_store_id() shouldn't be called to * store settings as the 'BT_DEV_READY' bit isn't set. * * Constraints: @@ -101,7 +101,7 @@ static int bt_hci_cmd_send_sync_custom_fake(uint16_t opcode, struct net_buf *buf * Expected behaviour: * - Return value is 0 * - Static random address is loaded to bt_dev.id_addr[] - * - No expected calls to bt_settings_save_id() + * - No expected calls to bt_settings_store_id() */ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, test_bt_read_static_addr_succeeds_bt_dev_ready_cleared) @@ -126,7 +126,7 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, err = bt_setup_random_id_addr(); - expect_not_called_bt_settings_save_id(); + expect_not_called_bt_settings_store_id(); zassert_true(err == 0, "Unexpected error code '%d' was returned", err); zassert_mem_equal(&bt_dev.id_addr[0], BT_STATIC_RANDOM_LE_ADDR_1, sizeof(bt_addr_le_t), @@ -136,8 +136,9 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, } /* - * Test reading controller static random address through bt_hci_cmd_send_sync(). - * With the 'BT_DEV_READY' bit set, bt_settings_save_id() should be called to store + * Test reading controller static random address through + * bt_hci_cmd_send_sync(). With the 'BT_DEV_READY' bit set, + * bt_settings_store_id() and bt_settings_store_irk() should be called to store * settings to persistent memory. * * Constraints: @@ -148,7 +149,7 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, * Expected behaviour: * - Return value is 0 * - Static random address is loaded to bt_dev.id_addr[] - * - No expected calls to bt_settings_save_id() + * - No expected calls to bt_settings_store_id() */ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, test_bt_read_static_addr_succeeds_bt_dev_ready_set) @@ -173,7 +174,8 @@ ZTEST(bt_setup_random_id_addr_bt_settings_enabled, err = bt_setup_random_id_addr(); - expect_single_call_bt_settings_save_id(); + expect_single_call_bt_settings_store_id(); + expect_single_call_bt_settings_store_irk(); zassert_true(err == 0, "Unexpected error code '%d' was returned", err); zassert_mem_equal(&bt_dev.id_addr[0], BT_STATIC_RANDOM_LE_ADDR_1, sizeof(bt_addr_le_t), diff --git a/tests/bluetooth/host/id/mocks/kernel.c b/tests/bluetooth/host/id/mocks/kernel.c index 218a8f7399d3..889f82666800 100644 --- a/tests/bluetooth/host/id/mocks/kernel.c +++ b/tests/bluetooth/host/id/mocks/kernel.c @@ -13,3 +13,4 @@ DEFINE_FAKE_VALUE_FUNC(int, k_work_schedule, struct k_work_delayable *, k_timeou DEFINE_FAKE_VALUE_FUNC(bool, k_work_cancel_delayable_sync, struct k_work_delayable *, struct k_work_sync *); DEFINE_FAKE_VOID_FUNC(k_work_init_delayable, struct k_work_delayable *, k_work_handler_t); +DEFINE_FAKE_VALUE_FUNC(int, k_work_submit, struct k_work *); diff --git a/tests/bluetooth/host/id/mocks/kernel.h b/tests/bluetooth/host/id/mocks/kernel.h index c587e43a9190..35a51d570929 100644 --- a/tests/bluetooth/host/id/mocks/kernel.h +++ b/tests/bluetooth/host/id/mocks/kernel.h @@ -20,3 +20,4 @@ DECLARE_FAKE_VALUE_FUNC(int, k_work_schedule, struct k_work_delayable *, k_timeo DECLARE_FAKE_VALUE_FUNC(bool, k_work_cancel_delayable_sync, struct k_work_delayable *, struct k_work_sync *); DECLARE_FAKE_VOID_FUNC(k_work_init_delayable, struct k_work_delayable *, k_work_handler_t); +DECLARE_FAKE_VALUE_FUNC(int, k_work_submit, struct k_work *); diff --git a/tests/bluetooth/host/id/mocks/settings.c b/tests/bluetooth/host/id/mocks/settings.c index b4fe196e2de2..c690d7bd329f 100644 --- a/tests/bluetooth/host/id/mocks/settings.c +++ b/tests/bluetooth/host/id/mocks/settings.c @@ -8,4 +8,7 @@ #include -DEFINE_FAKE_VOID_FUNC(bt_settings_save_id); +DEFINE_FAKE_VOID_FUNC(bt_settings_store_id); +DEFINE_FAKE_VOID_FUNC(bt_settings_delete_id); +DEFINE_FAKE_VOID_FUNC(bt_settings_store_irk); +DEFINE_FAKE_VOID_FUNC(bt_settings_delete_irk); diff --git a/tests/bluetooth/host/id/mocks/settings.h b/tests/bluetooth/host/id/mocks/settings.h index 9e593375ab1e..07630479eaa1 100644 --- a/tests/bluetooth/host/id/mocks/settings.h +++ b/tests/bluetooth/host/id/mocks/settings.h @@ -8,6 +8,13 @@ #include /* List of fakes used by this unit tester */ -#define SETTINGS_FFF_FAKES_LIST(FAKE) FAKE(bt_settings_save_id) +#define SETTINGS_FFF_FAKES_LIST(FAKE) \ + FAKE(bt_settings_store_id) \ + FAKE(bt_settings_delete_id) \ + FAKE(bt_settings_store_irk) \ + FAKE(bt_settings_delete_irk) -DECLARE_FAKE_VOID_FUNC(bt_settings_save_id); +DECLARE_FAKE_VOID_FUNC(bt_settings_store_id); +DECLARE_FAKE_VOID_FUNC(bt_settings_delete_id); +DECLARE_FAKE_VOID_FUNC(bt_settings_store_irk); +DECLARE_FAKE_VOID_FUNC(bt_settings_delete_irk); diff --git a/tests/bluetooth/host/id/mocks/settings_expects.c b/tests/bluetooth/host/id/mocks/settings_expects.c index b8ba5a042a07..71bca4d12d5b 100644 --- a/tests/bluetooth/host/id/mocks/settings_expects.c +++ b/tests/bluetooth/host/id/mocks/settings_expects.c @@ -9,18 +9,34 @@ #include -void expect_single_call_bt_settings_save_id(void) +void expect_single_call_bt_settings_store_id(void) { - const char *func_name = "bt_settings_save_id"; + const char *func_name = "bt_settings_store_id"; - zassert_equal(bt_settings_save_id_fake.call_count, 1, "'%s()' was called more than once", + zassert_equal(bt_settings_store_id_fake.call_count, 1, "'%s()' was called more than once", func_name); } -void expect_not_called_bt_settings_save_id(void) +void expect_not_called_bt_settings_store_id(void) { - const char *func_name = "bt_settings_save_id"; + const char *func_name = "bt_settings_store_id"; - zassert_equal(bt_settings_save_id_fake.call_count, 0, "'%s()' was called unexpectedly", + zassert_equal(bt_settings_store_id_fake.call_count, 0, "'%s()' was called unexpectedly", + func_name); +} + +void expect_single_call_bt_settings_store_irk(void) +{ + const char *func_name = "bt_settings_store_irk"; + + zassert_equal(bt_settings_store_irk_fake.call_count, 1, "'%s()' was called more than once", + func_name); +} + +void expect_not_called_bt_settings_store_irk(void) +{ + const char *func_name = "bt_settings_store_irk"; + + zassert_equal(bt_settings_store_irk_fake.call_count, 0, "'%s()' was called unexpectedly", func_name); } diff --git a/tests/bluetooth/host/id/mocks/settings_expects.h b/tests/bluetooth/host/id/mocks/settings_expects.h index a267eb7de639..c96b8f77393b 100644 --- a/tests/bluetooth/host/id/mocks/settings_expects.h +++ b/tests/bluetooth/host/id/mocks/settings_expects.h @@ -7,17 +7,33 @@ #include /* - * Validate expected behaviour when bt_settings_save_id() is called + * Validate expected behaviour when bt_settings_store_id() is called * * Expected behaviour: - * - bt_settings_save_id() to be called once with correct parameters + * - bt_settings_store_id() to be called once with correct parameters */ -void expect_single_call_bt_settings_save_id(void); +void expect_single_call_bt_settings_store_id(void); /* - * Validate expected behaviour when bt_settings_save_id() isn't called + * Validate expected behaviour when bt_settings_store_id() isn't called * * Expected behaviour: - * - bt_settings_save_id() isn't called at all + * - bt_settings_store_id() isn't called at all */ -void expect_not_called_bt_settings_save_id(void); +void expect_not_called_bt_settings_store_id(void); + +/* + * Validate expected behaviour when bt_settings_store_irk() is called + * + * Expected behaviour: + * - bt_settings_store_irk() to be called once with correct parameters + */ +void expect_single_call_bt_settings_store_irk(void); + +/* + * Validate expected behaviour when bt_settings_store_irk) isn't called + * + * Expected behaviour: + * - bt_settings_store_irk() isn't called at all + */ +void expect_not_called_bt_settings_store_irk(void); diff --git a/tests/bluetooth/host/keys/bt_keys_clear/src/test_suite_bt_settings.c b/tests/bluetooth/host/keys/bt_keys_clear/src/test_suite_bt_settings.c index 3e6f1d010976..52418e266ba8 100644 --- a/tests/bluetooth/host/keys/bt_keys_clear/src/test_suite_bt_settings.c +++ b/tests/bluetooth/host/keys/bt_keys_clear/src/test_suite_bt_settings.c @@ -68,9 +68,7 @@ ZTEST(bt_keys_clear_bt_settings_enabled, test_clear_key_with_id_equal_0) zassert_true(find_returned_ref == NULL, "bt_keys_find_addr() returned a non-NULL reference"); - expect_not_called_u8_to_dec(); - expect_single_call_bt_settings_encode_key_with_null_key(&returned_key->addr); - expect_single_call_settings_delete(); + expect_single_call_bt_settings_delete_keys(); } /* @@ -108,7 +106,5 @@ ZTEST(bt_keys_clear_bt_settings_enabled, test_clear_key_with_id_not_equal_0) zassert_true(find_returned_ref == NULL, "bt_keys_find_addr() returned a non-NULL reference"); - expect_single_call_u8_to_dec(id); - expect_single_call_bt_settings_encode_key_with_not_null_key(&returned_key->addr); - expect_single_call_settings_delete(); + expect_single_call_bt_settings_delete_keys(); } diff --git a/tests/bluetooth/host/keys/bt_keys_store/src/main.c b/tests/bluetooth/host/keys/bt_keys_store/src/main.c index acecdbc2a42b..e4a5f4e1952e 100644 --- a/tests/bluetooth/host/keys/bt_keys_store/src/main.c +++ b/tests/bluetooth/host/keys/bt_keys_store/src/main.c @@ -36,12 +36,12 @@ ZTEST_SUITE(bt_keys_store_key_bt_settings_enabled, NULL, NULL, tc_setup, NULL, N /* * Store an existing key (ID = 0) and verify the result. - * settings_save_one() returns 0 which represents success. + * bt_settings_store_keys() returns 0 which represents success. * * Constraints: * - Key reference points to a valid item * - Item ID is set to 0 - * - Return value from settings_save_one() is 0 + * - Return value from bt_settings_store_keys() is 0 * * Expected behaviour: * - bt_keys_store() returns 0 which represent success @@ -57,26 +57,25 @@ ZTEST(bt_keys_store_key_bt_settings_enabled, test_id_equal_0_with_no_error) returned_key = bt_keys_get_addr(id, addr); zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a non-valid reference"); - settings_save_one_fake.return_val = 0; + bt_settings_store_keys_fake.return_val = 0; /* Store the key */ returned_code = bt_keys_store(returned_key); zassert_true(returned_code == 0, "bt_keys_store() returned a non-zero code"); - expect_not_called_u8_to_dec(); - expect_single_call_bt_settings_encode_key_with_null_key(&returned_key->addr); - expect_single_call_settings_save_one(returned_key->storage_start); + expect_single_call_bt_settings_store_keys(returned_key->storage_start); } /* * Store an existing key (ID = 0) and verify the result. - * settings_save_one() returns a negative value of -1 which represents failure. + * bt_settings_store_keys() returns a negative value of -1 which represents + * failure. * * Constraints: * - Key reference points to a valid item * - Item ID is set to 0 - * - Return value from settings_save_one() is -1 + * - Return value from bt_settings_store_keys() is -1 * * Expected behaviour: * - bt_keys_store() returns a negative error code of -1 @@ -92,26 +91,24 @@ ZTEST(bt_keys_store_key_bt_settings_enabled, test_id_equal_0_with_error) returned_key = bt_keys_get_addr(id, addr); zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a non-valid reference"); - settings_save_one_fake.return_val = -1; + bt_settings_store_keys_fake.return_val = -1; /* Store the key */ returned_code = bt_keys_store(returned_key); zassert_true(returned_code == -1, "bt_keys_store() returned a non-zero code"); - expect_not_called_u8_to_dec(); - expect_single_call_bt_settings_encode_key_with_null_key(&returned_key->addr); - expect_single_call_settings_save_one(returned_key->storage_start); + expect_single_call_bt_settings_store_keys(returned_key->storage_start); } /* * Store an existing key (ID != 0) and verify the result. - * settings_save_one() returns 0 which represents success. + * bt_settings_store_keys() returns 0 which represents success. * * Constraints: * - Key reference points to a valid item * - Item ID isn't set to 0 - * - Return value from settings_save_one() is 0 + * - Return value from bt_settings_store_keys() is 0 * * Expected behaviour: * - bt_keys_store() returns 0 which represent success @@ -127,21 +124,20 @@ ZTEST(bt_keys_store_key_bt_settings_enabled, test_id_not_equal_0_with_no_error) returned_key = bt_keys_get_addr(id, addr); zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a non-valid reference"); - settings_save_one_fake.return_val = 0; + bt_settings_store_keys_fake.return_val = 0; /* Store the key */ returned_code = bt_keys_store(returned_key); zassert_true(returned_code == 0, "bt_keys_store() returned a non-zero code"); - expect_single_call_u8_to_dec(id); - expect_single_call_bt_settings_encode_key_with_not_null_key(&returned_key->addr); - expect_single_call_settings_save_one(returned_key->storage_start); + expect_single_call_bt_settings_store_keys(returned_key->storage_start); } /* * Store an existing key (ID != 0) and verify the result - * settings_save_one() returns a negative value of -1 which represents failure. + * bt_settings_store_keys() returns a negative value of -1 which represents + * failure. * * Constraints: * - Key reference points to a valid item @@ -162,14 +158,12 @@ ZTEST(bt_keys_store_key_bt_settings_enabled, test_id_not_equal_0_with_error) returned_key = bt_keys_get_addr(id, addr); zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a non-valid reference"); - settings_save_one_fake.return_val = -1; + bt_settings_store_keys_fake.return_val = -1; /* Store the key */ returned_code = bt_keys_store(returned_key); zassert_true(returned_code == -1, "bt_keys_store() returned a non-zero code"); - expect_single_call_u8_to_dec(id); - expect_single_call_bt_settings_encode_key_with_not_null_key(&returned_key->addr); - expect_single_call_settings_save_one(returned_key->storage_start); + expect_single_call_bt_settings_store_keys(returned_key->storage_start); } diff --git a/tests/bluetooth/host/keys/bt_keys_update_usage/src/main.c b/tests/bluetooth/host/keys/bt_keys_update_usage/src/main.c index e10d43d0ac34..0e38719b2b6a 100644 --- a/tests/bluetooth/host/keys/bt_keys_update_usage/src/main.c +++ b/tests/bluetooth/host/keys/bt_keys_update_usage/src/main.c @@ -134,6 +134,6 @@ ZTEST(bt_keys_update_usage_overwrite_oldest_enabled, test_update_non_latest_refe bt_keys_get_last_keys_updated(), expected_updated_keys, "bt_keys_update_usage() changed last updated key reference unexpectedly"); - expect_not_called_settings_save_one(); + expect_not_called_bt_settings_store_keys(); } } diff --git a/tests/bluetooth/host/keys/bt_keys_update_usage/src/test_suite_save_aging_counter.c b/tests/bluetooth/host/keys/bt_keys_update_usage/src/test_suite_save_aging_counter.c index c6402a95dcdb..bfe1486790ba 100644 --- a/tests/bluetooth/host/keys/bt_keys_update_usage/src/test_suite_save_aging_counter.c +++ b/tests/bluetooth/host/keys/bt_keys_update_usage/src/test_suite_save_aging_counter.c @@ -77,6 +77,6 @@ ZTEST(bt_keys_update_usage_save_aging_counter, test_update_usage_and_save_aging_ "bt_keys_update_usage() changed last updated key reference unexpectedly"); /* Check if bt_keys_store() was called */ - expect_single_call_settings_save_one(expected_updated_keys->storage_start); + expect_single_call_bt_settings_store_keys(expected_updated_keys->storage_start); } } diff --git a/tests/bluetooth/host/keys/mocks/settings_expects.c b/tests/bluetooth/host/keys/mocks/settings_expects.c index 1cd8f8c2f948..f69b466b657d 100644 --- a/tests/bluetooth/host/keys/mocks/settings_expects.c +++ b/tests/bluetooth/host/keys/mocks/settings_expects.c @@ -31,8 +31,9 @@ void expect_single_call_bt_settings_encode_key_with_null_key(const bt_addr_le_t { const char *func_name = "bt_settings_encode_key"; - zassert_equal(bt_settings_encode_key_fake.call_count, 1, "'%s()' was called more than once", - func_name); + zassert_equal(bt_settings_encode_key_fake.call_count, 1, + "'%s()' was called more than once (%d)", func_name, + bt_settings_encode_key_fake.call_count); zassert_not_null(bt_settings_encode_key_fake.arg0_val, "'%s()' was called with incorrect '%s' value", func_name, "path"); zassert_true(bt_settings_encode_key_fake.arg1_val != 0, diff --git a/tests/bluetooth/host/keys/mocks/settings_store.c b/tests/bluetooth/host/keys/mocks/settings_store.c index 0d1c9faa6a74..b38a0a9cc3cd 100644 --- a/tests/bluetooth/host/keys/mocks/settings_store.c +++ b/tests/bluetooth/host/keys/mocks/settings_store.c @@ -7,5 +7,6 @@ #include #include "mocks/settings_store.h" -DEFINE_FAKE_VALUE_FUNC(int, settings_delete, const char *); -DEFINE_FAKE_VALUE_FUNC(int, settings_save_one, const char *, const void *, size_t); +DEFINE_FAKE_VALUE_FUNC(int, bt_settings_store_keys, uint8_t, struct bt_addr_le_t *, const void *, + size_t); +DEFINE_FAKE_VALUE_FUNC(int, bt_settings_delete_keys, uint8_t, struct bt_addr_le_t *); diff --git a/tests/bluetooth/host/keys/mocks/settings_store.h b/tests/bluetooth/host/keys/mocks/settings_store.h index 8bafd27a6b87..2049b36ce24a 100644 --- a/tests/bluetooth/host/keys/mocks/settings_store.h +++ b/tests/bluetooth/host/keys/mocks/settings_store.h @@ -6,11 +6,13 @@ #include #include +#include /* List of fakes used by this unit tester */ -#define SETTINGS_STORE_FFF_FAKES_LIST(FAKE) \ - FAKE(settings_delete) \ - FAKE(settings_save_one) \ +#define SETTINGS_STORE_FFF_FAKES_LIST(FAKE) \ + FAKE(bt_settings_store_keys) \ + FAKE(bt_settings_delete_keys) -DECLARE_FAKE_VALUE_FUNC(int, settings_delete, const char *); -DECLARE_FAKE_VALUE_FUNC(int, settings_save_one, const char *, const void *, size_t); +DECLARE_FAKE_VALUE_FUNC(int, bt_settings_store_keys, uint8_t, struct bt_addr_le_t *, const void *, + size_t); +DECLARE_FAKE_VALUE_FUNC(int, bt_settings_delete_keys, uint8_t, struct bt_addr_le_t *); diff --git a/tests/bluetooth/host/keys/mocks/settings_store_expects.c b/tests/bluetooth/host/keys/mocks/settings_store_expects.c index 11da81c21af8..c4eb4204f22f 100644 --- a/tests/bluetooth/host/keys/mocks/settings_store_expects.c +++ b/tests/bluetooth/host/keys/mocks/settings_store_expects.c @@ -10,36 +10,31 @@ #include "mocks/settings_store.h" #include "mocks/settings_store_expects.h" -void expect_single_call_settings_delete(void) +void expect_single_call_bt_settings_delete_keys(void) { - const char *func_name = "settings_delete"; + const char *func_name = "bt_settings_delete_keys"; - zassert_equal(settings_delete_fake.call_count, 1, "'%s()' was called more than once", - func_name); - - zassert_not_null(settings_delete_fake.arg0_val, - "'%s()' was called with incorrect '%s' value", func_name, "key"); + zassert_equal(bt_settings_delete_keys_fake.call_count, 1, + "'%s()' was called more than once", func_name); } -void expect_single_call_settings_save_one(const void *value) +void expect_single_call_bt_settings_store_keys(const void *value) { - const char *func_name = "settings_save_one"; + const char *func_name = "bt_settings_store_keys"; - zassert_equal(settings_save_one_fake.call_count, 1, "'%s()' was called more than once", + zassert_equal(bt_settings_store_keys_fake.call_count, 1, "'%s()' was called more than once", func_name); - zassert_not_null(settings_save_one_fake.arg0_val, - "'%s()' was called with incorrect '%s' value", func_name, "key"); - zassert_equal(settings_save_one_fake.arg1_val, value, + zassert_equal(bt_settings_store_keys_fake.arg2_val, value, "'%s()' was called with incorrect '%s' value", func_name, "value"); - zassert_equal(settings_save_one_fake.arg2_val, BT_KEYS_STORAGE_LEN, + zassert_equal(bt_settings_store_keys_fake.arg3_val, BT_KEYS_STORAGE_LEN, "'%s()' was called with incorrect '%s' value", func_name, "val_len"); } -void expect_not_called_settings_save_one(void) +void expect_not_called_bt_settings_store_keys(void) { - const char *func_name = "settings_save_one"; + const char *func_name = "bt_settings_store_keys"; - zassert_equal(settings_save_one_fake.call_count, 0, "'%s()' was called unexpectedly", + zassert_equal(bt_settings_store_keys_fake.call_count, 0, "'%s()' was called unexpectedly", func_name); } diff --git a/tests/bluetooth/host/keys/mocks/settings_store_expects.h b/tests/bluetooth/host/keys/mocks/settings_store_expects.h index 2e6a99ca7239..2cd2035b1f02 100644 --- a/tests/bluetooth/host/keys/mocks/settings_store_expects.h +++ b/tests/bluetooth/host/keys/mocks/settings_store_expects.h @@ -7,25 +7,25 @@ #include /* - * Validate expected behaviour when settings_delete() is called + * Validate expected behaviour when bt_settings_delete_keys() is called * * Expected behaviour: - * - settings_delete() to be called once with correct parameters + * - bt_settings_delete_keys() to be called once with correct parameters */ -void expect_single_call_settings_delete(void); +void expect_single_call_bt_settings_delete_keys(void); /* - * Validate expected behaviour when settings_save_one() is called + * Validate expected behaviour when bt_settings_store_keys() is called * * Expected behaviour: - * - settings_save_one() to be called once with correct parameters + * - bt_settings_store_keys() to be called once with correct parameters */ -void expect_single_call_settings_save_one(const void *value); +void expect_single_call_bt_settings_store_keys(const void *value); /* - * Validate expected behaviour when settings_save_one() isn't called + * Validate expected behaviour when bt_settings_store_keys() isn't called * * Expected behaviour: - * - settings_save_one() isn't called at all + * - bt_settings_store_keys() isn't called at all */ -void expect_not_called_settings_save_one(void); +void expect_not_called_bt_settings_store_keys(void); From d39645a20607e719d831720a86ebbd40c94b6df8 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 6 Jun 2023 11:11:18 +0200 Subject: [PATCH 0281/2042] drivers/pcie: Add capabilities output to shell module This help to decipher PCIe capabilities supported by each listed device. Shown only on a selected device and not on the general list. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/shell.c | 118 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/drivers/pcie/host/shell.c b/drivers/pcie/host/shell.c index 4137aecf48e7..d5b201734e15 100644 --- a/drivers/pcie/host/shell.c +++ b/drivers/pcie/host/shell.c @@ -10,9 +10,83 @@ #ifdef CONFIG_PCIE_MSI #include -#include #endif +#include + +struct pcie_cap_id_to_str { + uint32_t id; + char *str; +}; + +static struct pcie_cap_id_to_str pcie_cap_list[] = { + { PCI_CAP_ID_PM, "Power Management" }, + { PCI_CAP_ID_AGP, "Accelerated Graphics Port" }, + { PCI_CAP_ID_VPD, "Vital Product Data" }, + { PCI_CAP_ID_SLOTID, "Slot Identification" }, + { PCI_CAP_ID_MSI, "Message Signalled Interrupts" }, + { PCI_CAP_ID_CHSWP, "CompactPCI HotSwap" }, + { PCI_CAP_ID_PCIX, "PCI-X" }, + { PCI_CAP_ID_HT, "HyperTransport" }, + { PCI_CAP_ID_VNDR, "Vendor-Specific" }, + { PCI_CAP_ID_DBG, "Debug port" }, + { PCI_CAP_ID_CCRC, "CompactPCI Central Resource Control" }, + { PCI_CAP_ID_SHPC, "PCI Standard Hot-Plug Controller" }, + { PCI_CAP_ID_SSVID, "Bridge subsystem vendor/device ID" }, + { PCI_CAP_ID_AGP3, "AGP 8x" }, + { PCI_CAP_ID_SECDEV, "Secure Device" }, + { PCI_CAP_ID_EXP, "PCI Express" }, + { PCI_CAP_ID_MSIX, "MSI-X" }, + { PCI_CAP_ID_SATA, "Serial ATA Data/Index Configuration" }, + { PCI_CAP_ID_AF, "PCI Advanced Features" }, + { PCI_CAP_ID_EA, "PCI Enhanced Allocation" }, + { PCI_CAP_ID_FPB, "Flattening Portal Bridge" }, + { PCI_CAP_ID_NULL, NULL }, +}; + +static struct pcie_cap_id_to_str pcie_ext_cap_list[] = { + { PCIE_EXT_CAP_ID_ERR, "Advanced Error Reporting" }, + { PCIE_EXT_CAP_ID_VC, "Virtual Channel when no MFVC" }, + { PCIE_EXT_CAP_ID_DSN, "Device Serial Number" }, + { PCIE_EXT_CAP_ID_PWR, "Power Budgeting" }, + { PCIE_EXT_CAP_ID_RCLD, "Root Complex Link Declaration" }, + { PCIE_EXT_CAP_ID_RCILC, "Root Complex Internal Link Control" }, + { PCIE_EXT_CAP_ID_RCEC, "Root Complex Event Collector Endpoint Association" }, + { PCIE_EXT_CAP_ID_MFVC, "Multi-Function VC Capability" }, + { PCIE_EXT_CAP_ID_MFVC_VC, "Virtual Channel used with MFVC" }, + { PCIE_EXT_CAP_ID_RCRB, "Root Complex Register Block" }, + { PCIE_EXT_CAP_ID_VNDR, "Vendor-Specific Extended Capability" }, + { PCIE_EXT_CAP_ID_CAC, "Config Access Correlation - obsolete" }, + { PCIE_EXT_CAP_ID_ACS, "Access Control Services" }, + { PCIE_EXT_CAP_ID_ARI, "Alternate Routing-ID Interpretation" }, + { PCIE_EXT_CAP_ID_ATS, "Address Translation Services" }, + { PCIE_EXT_CAP_ID_SRIOV, "Single Root I/O Virtualization" }, + { PCIE_EXT_CAP_ID_MRIOV, "Multi Root I/O Virtualization" }, + { PCIE_EXT_CAP_ID_MCAST, "Multicast" }, + { PCIE_EXT_CAP_ID_PRI, "Page Request Interface" }, + { PCIE_EXT_CAP_ID_AMD_XXX, "Reserved for AMD" }, + { PCIE_EXT_CAP_ID_REBAR, "Resizable BAR" }, + { PCIE_EXT_CAP_ID_DPA, "Dynamic Power Allocation" }, + { PCIE_EXT_CAP_ID_TPH, "TPH Requester" }, + { PCIE_EXT_CAP_ID_LTR, "Latency Tolerance Reporting" }, + { PCIE_EXT_CAP_ID_SECPCI, "Secondary PCIe Capability" }, + { PCIE_EXT_CAP_ID_PMUX, "Protocol Multiplexing" }, + { PCIE_EXT_CAP_ID_PASID, "Process Address Space ID" }, + { PCIE_EXT_CAP_ID_DPC, "Downstream Port Containment" }, + { PCIE_EXT_CAP_ID_L1SS, "L1 PM Substates" }, + { PCIE_EXT_CAP_ID_PTM, "Precision Time Measurement" }, + { PCIE_EXT_CAP_ID_DVSEC, "Designated Vendor-Specific Extended Capability" }, + { PCIE_EXT_CAP_ID_DLF, "Data Link Feature" }, + { PCIE_EXT_CAP_ID_PL_16GT, "Physical Layer 16.0 GT/s" }, + { PCIE_EXT_CAP_ID_LMR, "Lane Margining at the Receiver" }, + { PCIE_EXT_CAP_ID_HID, "Hierarchy ID" }, + { PCIE_EXT_CAP_ID_NPEM, "Native PCIe Enclosure Management" }, + { PCIE_EXT_CAP_ID_PL_32GT, "Physical Layer 32.0 GT/s" }, + { PCIE_EXT_CAP_ID_AP, "Alternate Protocol" }, + { PCIE_EXT_CAP_ID_SFI, "System Firmware Intermediary" }, + { PCIE_EXT_CAP_ID_NULL, NULL }, +}; + static void show_msi(const struct shell *sh, pcie_bdf_t bdf) { #ifdef CONFIG_PCIE_MSI @@ -94,6 +168,38 @@ static void show_bars(const struct shell *sh, pcie_bdf_t bdf) } } +static void show_capabilities(const struct shell *sh, pcie_bdf_t bdf) +{ + struct pcie_cap_id_to_str *cap_id2str; + uint32_t base; + + shell_fprintf(sh, SHELL_NORMAL, " PCI capabilities:\n"); + + cap_id2str = pcie_cap_list; + while (cap_id2str->str != NULL) { + base = pcie_get_cap(bdf, cap_id2str->id); + if (base != 0) { + shell_fprintf(sh, SHELL_NORMAL, + " %s\n", cap_id2str->str); + } + + cap_id2str++; + } + + shell_fprintf(sh, SHELL_NORMAL, " PCIe capabilities:\n"); + + cap_id2str = pcie_ext_cap_list; + while (cap_id2str->str != NULL) { + base = pcie_get_ext_cap(bdf, cap_id2str->id); + if (base != 0) { + shell_fprintf(sh, SHELL_NORMAL, + " %s\n", cap_id2str->str); + } + + cap_id2str++; + } +} + static void pcie_dump(const struct shell *sh, pcie_bdf_t bdf) { for (int i = 0; i < 16; i++) { @@ -140,7 +246,7 @@ static pcie_bdf_t get_bdf(char *str) return PCIE_BDF(bus, dev, func); } -static void show(const struct shell *sh, pcie_bdf_t bdf, bool dump) +static void show(const struct shell *sh, pcie_bdf_t bdf, bool details, bool dump) { uint32_t data; unsigned int irq; @@ -181,6 +287,10 @@ static void show(const struct shell *sh, pcie_bdf_t bdf, bool dump) } } + if (details) { + show_capabilities(sh, bdf); + } + if (dump) { pcie_dump(sh, bdf); } @@ -195,7 +305,7 @@ static bool scan_cb(pcie_bdf_t bdf, pcie_id_t id, void *cb_data) { struct scan_cb_data *data = cb_data; - show(data->sh, bdf, data->dump); + show(data->sh, bdf, false, data->dump); return true; } @@ -233,7 +343,7 @@ static int cmd_pcie_ls(const struct shell *sh, size_t argc, char **argv) /* Show only specified device */ if (bdf != PCIE_BDF_NONE) { - show(sh, bdf, data.dump); + show(sh, bdf, true, data.dump); return 0; } From 1b51be4ba00017472bea6cb90a56506a1543348f Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 6 Jun 2023 11:37:54 +0200 Subject: [PATCH 0282/2042] doc/pcie: Add basic entry for PCIe doxygen documentation This has been missing so let's add it. Signed-off-by: Tomasz Bursztyka --- doc/hardware/peripherals/index.rst | 1 + doc/hardware/peripherals/pcie.rst | 13 +++++++++++++ include/zephyr/drivers/pcie/cap.h | 11 +++++++++++ include/zephyr/drivers/pcie/msi.h | 11 +++++++++++ include/zephyr/drivers/pcie/pcie.h | 11 +++++++++++ include/zephyr/drivers/pcie/ptm.h | 11 +++++++++++ 6 files changed, 58 insertions(+) create mode 100644 doc/hardware/peripherals/pcie.rst diff --git a/doc/hardware/peripherals/index.rst b/doc/hardware/peripherals/index.rst index 767b86340b93..6e59ca3c44fe 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -40,6 +40,7 @@ Peripherals mdio.rst mipi_dsi.rst mbox.rst + pcie.rst peci.rst ps2.rst pwm.rst diff --git a/doc/hardware/peripherals/pcie.rst b/doc/hardware/peripherals/pcie.rst new file mode 100644 index 000000000000..9cffaae53fda --- /dev/null +++ b/doc/hardware/peripherals/pcie.rst @@ -0,0 +1,13 @@ +.. _pcie_api: + +Peripheral Component Interconnect express Bus (PCIe) +#################################################### + +Overview +******** + + +API Reference +************* + +.. doxygengroup:: pcie_host_interface diff --git a/include/zephyr/drivers/pcie/cap.h b/include/zephyr/drivers/pcie/cap.h index ccf6f724a148..7a0aeb954ce6 100644 --- a/include/zephyr/drivers/pcie/cap.h +++ b/include/zephyr/drivers/pcie/cap.h @@ -6,6 +6,13 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_CAP_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_CAP_H_ +/** + * @brief PCIe Capabilities + * @defgroup pcie_capabilities PCIe Capabilities + * @ingroup pcie_host_interface + * @{ + */ + /* * PCI & PCI Express Capabilities * from PCI Code and ID Assignment Specification Revision 1.11 @@ -79,4 +86,8 @@ #define PCIE_EXT_CAP_ID_AP 0x002BU /* Alternate Protocol */ #define PCIE_EXT_CAP_ID_SFI 0x002CU /* System Firmware Intermediary */ +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_CAP_H_ */ diff --git a/include/zephyr/drivers/pcie/msi.h b/include/zephyr/drivers/pcie/msi.h index abd6dfd03704..caa4e77a2e98 100644 --- a/include/zephyr/drivers/pcie/msi.h +++ b/include/zephyr/drivers/pcie/msi.h @@ -7,6 +7,13 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_MSI_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_MSI_H_ +/** + * @brief PCIe Host MSI Interface + * @defgroup pcie_host_msi_interface PCIe Host MSI Interface + * @ingroup pcie_host_interface + * @{ + */ + #include #include #include @@ -190,4 +197,8 @@ extern bool pcie_is_msi(pcie_bdf_t bdf); } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_MSI_H_ */ diff --git a/include/zephyr/drivers/pcie/pcie.h b/include/zephyr/drivers/pcie/pcie.h index b6ad2209d147..ff3cb0780640 100644 --- a/include/zephyr/drivers/pcie/pcie.h +++ b/include/zephyr/drivers/pcie/pcie.h @@ -7,6 +7,13 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ +/** + * @brief PCIe Host Interface + * @defgroup pcie_host_interface PCIe Host Interface + * @ingroup io_interfaces + * @{ + */ + #include #include #include @@ -596,4 +603,8 @@ extern bool pcie_connect_dynamic_irq(pcie_bdf_t bdf, } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_PCIE_H_ */ diff --git a/include/zephyr/drivers/pcie/ptm.h b/include/zephyr/drivers/pcie/ptm.h index 181ea7092f2f..9ae5af85ae3f 100644 --- a/include/zephyr/drivers/pcie/ptm.h +++ b/include/zephyr/drivers/pcie/ptm.h @@ -8,6 +8,13 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_PTM_H_ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_PTM_H_ +/** + * @brief PCIe Host PTM Interface + * @defgroup pcie_host_ptm_interface PCIe Host PTM Interface + * @ingroup pcie_host_interface + * @{ + */ + #include #include @@ -27,4 +34,8 @@ bool pcie_ptm_enable(pcie_bdf_t bdf); } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_PTM_H_ */ From 0f6cb5edcddd4c6ced4d8f7e4019c8066611c97f Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Sun, 16 Apr 2023 14:44:02 +0530 Subject: [PATCH 0283/2042] drivers: ps2: microchip: Low power and wakeup enabled ps2 driver updated to support low power and wakeup. Signed-off-by: Manimaran A --- .../mec1501modular_assy6885.dts | 6 +- .../mec15xxevb_assy6853.dts | 6 +- .../mec172xevb_assy6906.dts | 3 +- drivers/ps2/ps2_mchp_xec.c | 170 +++++++++++++++--- dts/arm/microchip/mec1501hsz.dtsi | 4 +- .../microchip/mec152x/mec152xhsz-pinctrl.dtsi | 18 ++ .../microchip/mec172x/mec172xnsz-pinctrl.dtsi | 11 ++ dts/arm/microchip/mec172xnsz.dtsi | 2 +- dts/bindings/ps2/microchip,xec-ps2.yaml | 4 + samples/drivers/ps2/prj.conf | 2 +- soc/arm/microchip_mec/mec172x/device_power.c | 7 +- 11 files changed, 195 insertions(+), 38 deletions(-) diff --git a/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts b/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts index 5b66d1a2bd2d..7f696fc6e3ce 100644 --- a/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts +++ b/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts @@ -101,13 +101,15 @@ &ps2_0 { status = "okay"; pinctrl-0 = <&ps2_clk0b_gpio007 &ps2_dat0b_gpio010>; - pinctrl-names = "default"; + pinctrl-1 = <&ps2_clk0b_gpio007_sleep &ps2_dat0b_gpio010_sleep>; + pinctrl-names = "default", "sleep"; }; &ps2_1 { status = "okay"; pinctrl-0 = <&ps2_clk1b_gpio154 &ps2_dat1b_gpio155>; - pinctrl-names = "default"; + pinctrl-1 = <&ps2_clk1b_gpio154_sleep &ps2_dat1b_gpio155_sleep>; + pinctrl-names = "default", "sleep"; }; &pwm0 { diff --git a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts index fbbb1ac5a327..d15c278604ae 100644 --- a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts +++ b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts @@ -158,13 +158,15 @@ &ps2_0 { status = "okay"; pinctrl-0 = <&ps2_clk0b_gpio007 &ps2_dat0b_gpio010>; - pinctrl-names = "default"; + pinctrl-1 = <&ps2_clk0b_gpio007_sleep &ps2_dat0b_gpio010_sleep>; + pinctrl-names = "default", "sleep"; }; &ps2_1 { status = "okay"; pinctrl-0 = <&ps2_clk1b_gpio154 &ps2_dat1b_gpio155>; - pinctrl-names = "default"; + pinctrl-1 = <&ps2_clk1b_gpio154_sleep &ps2_dat1b_gpio155_sleep>; + pinctrl-names = "default", "sleep"; }; &pwm0 { diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts index ffd7c2427bad..d01176bf9a6d 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -303,7 +303,8 @@ &ps2_0 { status = "okay"; pinctrl-0 = <&ps2_clk0a_gpio114 &ps2_dat0a_gpio115>; - pinctrl-names = "default"; + pinctrl-1 = <&ps2_clk0a_gpio114_sleep &ps2_dat0a_gpio115_sleep>; + pinctrl-names = "default", "sleep"; }; &timer5 { diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index dd977590c9ed..f2dd97d27381 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -16,10 +16,15 @@ #include #endif #include +#ifdef CONFIG_PM_DEVICE +#include +#include +#endif #include #include #include #include +#include #define LOG_LEVEL CONFIG_PS2_LOG_LEVEL LOG_MODULE_REGISTER(ps2_mchp_xec); @@ -32,17 +37,25 @@ struct ps2_xec_config { int isr_nvic; uint8_t girq_id; uint8_t girq_bit; + uint8_t girq_id_wk; + uint8_t girq_bit_wk; uint8_t pcr_idx; uint8_t pcr_pos; void (*irq_config_func)(void); const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_PM_DEVICE + struct gpio_dt_spec wakerx_gpio; + bool wakeup_source; +#endif }; + struct ps2_xec_data { ps2_callback_t callback_isr; struct k_sem tx_lock; }; + #ifdef CONFIG_SOC_SERIES_MEC172X static inline void ps2_xec_slp_en_clr(const struct device *dev) { @@ -51,18 +64,19 @@ static inline void ps2_xec_slp_en_clr(const struct device *dev) z_mchp_xec_pcr_periph_sleep(cfg->pcr_idx, cfg->pcr_pos, 0); } -static inline void ps2_xec_girq_clr(const struct device *dev) +static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn) { - const struct ps2_xec_config * const cfg = dev->config; - - mchp_soc_ecia_girq_src_clr(cfg->girq_id, cfg->girq_bit); + mchp_soc_ecia_girq_src_clr(girq_idx, girq_posn); } -static inline void ps2_xec_girq_en(const struct device *dev) +static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn) { - const struct ps2_xec_config * const cfg = dev->config; + mchp_xec_ecia_girq_src_en(girq_idx, girq_posn); +} - mchp_xec_ecia_girq_src_en(cfg->girq_id, cfg->girq_bit); +static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn) +{ + mchp_xec_ecia_girq_src_dis(girq_idx, girq_posn); } #else static inline void ps2_xec_slp_en_clr(const struct device *dev) @@ -76,18 +90,19 @@ static inline void ps2_xec_slp_en_clr(const struct device *dev) } } -static inline void ps2_xec_girq_clr(const struct device *dev) +static inline void ps2_xec_girq_clr(uint8_t girq_idx, uint8_t girq_posn) { - const struct ps2_xec_config * const cfg = dev->config; - - MCHP_GIRQ_SRC(cfg->girq_id) = BIT(cfg->girq_bit); + MCHP_GIRQ_SRC(girq_idx) = BIT(girq_posn); } -static inline void ps2_xec_girq_en(const struct device *dev) +static inline void ps2_xec_girq_en(uint8_t girq_idx, uint8_t girq_posn) { - const struct ps2_xec_config * const cfg = dev->config; + MCHP_GIRQ_ENSET(girq_idx) = BIT(girq_posn); +} - MCHP_GIRQ_ENSET(cfg->girq_id) = BIT(cfg->girq_bit); +static inline void ps2_xec_girq_dis(uint8_t girq_idx, uint8_t girq_posn) +{ + MCHP_GIRQ_ENCLR(girq_idx) = MCHP_KBC_IBF_GIRQ; } #endif /* CONFIG_SOC_SERIES_MEC172X */ @@ -108,13 +123,13 @@ static int ps2_xec_configure(const struct device *dev, /* In case the self test for a PS2 device already finished and * set the SOURCE bit to 1 we clear it before enabling the - * interrupts. Instances must be allocated before the BAT or - * the host may time out. + * interrupts. Instances must be allocated before the BAT + * (Basic Assurance Test) or the host may time out. */ temp = regs->TRX_BUFF; regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; /* clear next higher level */ - ps2_xec_girq_clr(dev); + ps2_xec_girq_clr(config->girq_id, config->girq_bit); /* Enable FSM and init instance in rx mode*/ regs->CTRL = MCHP_PS2_CTRL_EN_POS; @@ -122,7 +137,7 @@ static int ps2_xec_configure(const struct device *dev, /* We enable the interrupts in the EC aggregator so that the * result can be forwarded to the ARM NVIC */ - ps2_xec_girq_en(dev); + ps2_xec_girq_en(config->girq_id, config->girq_bit); k_sem_give(&data->tx_lock); @@ -159,7 +174,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; @@ -191,7 +208,7 @@ static int ps2_xec_inhibit_interface(const struct device *dev) regs->CTRL = 0x00; regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; - ps2_xec_girq_clr(dev); + ps2_xec_girq_clr(config->girq_id, config->girq_bit); NVIC_ClearPendingIRQ(config->isr_nvic); k_sem_give(&data->tx_lock); @@ -205,7 +222,7 @@ static int ps2_xec_enable_interface(const struct device *dev) struct ps2_xec_data * const data = dev->data; struct ps2_regs * const regs = config->regs; - ps2_xec_girq_clr(dev); + ps2_xec_girq_clr(config->girq_id, config->girq_bit); regs->CTRL = MCHP_PS2_CTRL_EN; k_sem_give(&data->tx_lock); @@ -213,6 +230,70 @@ static int ps2_xec_enable_interface(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int ps2_xec_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct ps2_xec_config *const devcfg = dev->config; + struct ps2_regs * const regs = devcfg->regs; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + if (devcfg->wakeup_source) { + /* Disable PS2 wake interrupt + * Disable interrupt on PS2DAT pin + */ + if (devcfg->wakerx_gpio.port != NULL) { + ret = gpio_pin_interrupt_configure_dt( + &devcfg->wakerx_gpio, + GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Fail to disable PS2 wake interrupt (ret %d)", ret); + return ret; + } + } + ps2_xec_girq_dis(devcfg->girq_id_wk, devcfg->girq_bit_wk); + ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk); + } else { + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + regs->CTRL |= MCHP_PS2_CTRL_EN; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + if (devcfg->wakeup_source) { + /* Enable PS2 wake interrupt + * Configure Falling Edge Trigger interrupt on PS2DAT pin + */ + ps2_xec_girq_clr(devcfg->girq_id_wk, devcfg->girq_bit_wk); + ps2_xec_girq_en(devcfg->girq_id_wk, devcfg->girq_bit_wk); + if (devcfg->wakerx_gpio.port != NULL) { + ret = gpio_pin_interrupt_configure_dt( + &devcfg->wakerx_gpio, + GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW); + if (ret < 0) { + LOG_ERR("Fail to enable PS2 wake interrupt(ret %d)", ret); + return ret; + } + } + } else { + regs->CTRL &= ~MCHP_PS2_CTRL_EN; + /* If application does not want to turn off PS2 pins it will + * not define pinctrl-1 for this node. + */ + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP); + if (ret == -ENOENT) { /* pinctrl-1 does not exist. */ + ret = 0; + } + } + break; + default: + ret = -ENOTSUP; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + static void ps2_xec_isr(const struct device *dev) { const struct ps2_xec_config * const config = dev->config; @@ -224,18 +305,36 @@ static void ps2_xec_isr(const struct device *dev) status = regs->STATUS; /* clear next higher level the GIRQ */ - ps2_xec_girq_clr(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 @@ -256,9 +355,7 @@ static int ps2_xec_init(const struct device *dev) { const struct ps2_xec_config * const cfg = dev->config; struct ps2_xec_data * const data = dev->data; - int ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); - if (ret != 0) { LOG_ERR("XEC PS2 pinctrl init failed (%d)", ret); return ret; @@ -273,16 +370,35 @@ static int ps2_xec_init(const struct device *dev) return 0; } +/* To enable wakeup on the PS2, the DTS needs to have two entries defined + * in the corresponding PS2 node in the DTS specifying it as a wake source + * and specifying the PS2DAT GPIO; example as below + * + * wakerx-gpios = + * wakeup-source; + */ +#ifdef CONFIG_PM_DEVICE +#define XEC_PS2_PM_WAKEUP(n) \ + .wakeup_source = (uint8_t)DT_INST_PROP_OR(n, wakeup_source, 0), \ + .wakerx_gpio = GPIO_DT_SPEC_INST_GET_OR(n, wakerx_gpios, {0}), +#else +#define XEC_PS2_PM_WAKEUP(index) /* Not used */ +#endif + +#define XEC_PS2_PINCTRL_CFG(inst) PINCTRL_DT_INST_DEFINE(inst) #define XEC_PS2_CONFIG(inst) \ static const struct ps2_xec_config ps2_xec_config_##inst = { \ .regs = (struct ps2_regs * const)(DT_INST_REG_ADDR(inst)), \ .isr_nvic = DT_INST_IRQN(inst), \ .girq_id = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 0)), \ .girq_bit = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 1)), \ + .girq_id_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 2)), \ + .girq_bit_wk = (uint8_t)(DT_INST_PROP_BY_IDX(inst, girqs, 3)), \ .pcr_idx = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 0)), \ .pcr_pos = (uint8_t)(DT_INST_PROP_BY_IDX(inst, pcrs, 1)), \ .irq_config_func = ps2_xec_irq_config_func_##inst, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + XEC_PS2_PM_WAKEUP(inst) \ } #define PS2_XEC_DEVICE(i) \ @@ -298,12 +414,14 @@ static int ps2_xec_init(const struct device *dev) \ static struct ps2_xec_data ps2_xec_port_data_##i; \ \ - PINCTRL_DT_INST_DEFINE(i); \ + XEC_PS2_PINCTRL_CFG(i); \ \ XEC_PS2_CONFIG(i); \ \ + PM_DEVICE_DT_INST_DEFINE(i, ps2_xec_pm_action); \ + \ DEVICE_DT_INST_DEFINE(i, &ps2_xec_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(i), \ &ps2_xec_port_data_##i, &ps2_xec_config_##i, \ POST_KERNEL, CONFIG_PS2_INIT_PRIORITY, \ &ps2_xec_driver_api); diff --git a/dts/arm/microchip/mec1501hsz.dtsi b/dts/arm/microchip/mec1501hsz.dtsi index 4700a2d746e5..dade0c7ca181 100644 --- a/dts/arm/microchip/mec1501hsz.dtsi +++ b/dts/arm/microchip/mec1501hsz.dtsi @@ -342,7 +342,7 @@ compatible = "microchip,xec-ps2"; reg = <0x40009000 0x40>; interrupts = <100 1>; - girqs = <18 10>; + girqs = <18 10>, <21 18>; pcrs = <3 5>; #address-cells = <1>; #size-cells = <0>; @@ -352,7 +352,7 @@ compatible = "microchip,xec-ps2"; reg = <0x40009040 0x40>; interrupts = <101 1>; - girqs = <18 11>; + girqs = <18 11>, <21 21>; pcrs = <3 6>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi b/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi index ba1556519a75..3625736add3f 100644 --- a/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi +++ b/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi @@ -1070,4 +1070,22 @@ pinmux = < MCHP_XEC_PINMUX(044, MCHP_AF1) >; low-power-enable; }; + + /* PS2 */ + ps2_clk0b_gpio007_sleep: ps2_clk0b_gpio007_sleep { + pinmux = < MCHP_XEC_PINMUX(007, MCHP_AF2) >; + low-power-enable; + }; + ps2_dat0b_gpio010_sleep: ps2_dat0b_gpio010_sleep { + pinmux = < MCHP_XEC_PINMUX(010, MCHP_AF2) >; + low-power-enable; + }; + ps2_clk1b_gpio154_sleep: ps2_clk1b_gpio154_sleep { + pinmux = < MCHP_XEC_PINMUX(0154, MCHP_AF2) >; + low-power-enable; + }; + ps2_dat1b_gpio155_sleep: ps2_dat1b_gpio155_sleep { + pinmux = < MCHP_XEC_PINMUX(0155, MCHP_AF2) >; + low-power-enable; + }; }; diff --git a/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi b/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi index 6968c1c3cfc2..b218d28c6d2b 100644 --- a/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi +++ b/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi @@ -1102,4 +1102,15 @@ pinmux = < MCHP_XEC_PINMUX(044, MCHP_AF1) >; low-power-enable; }; + + ps2_clk0a_gpio114_sleep: ps2_clk0a_gpio114_sleep { + pinmux = < MCHP_XEC_PINMUX(0114, MCHP_AF1) >; + low-power-enable; + }; + + ps2_dat0a_gpio115_sleep: ps2_dat0a_gpio115_sleep { + pinmux = < MCHP_XEC_PINMUX(0115, MCHP_AF1) >; + low-power-enable; + }; + }; diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index ca65168b8de6..75a059e046c9 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -565,7 +565,7 @@ compatible = "microchip,xec-ps2"; reg = <0x40009000 0x40>; interrupts = <100 1>; - girqs = <18 10>; + girqs = <18 10>, <21 18>; pcrs = <3 5>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/bindings/ps2/microchip,xec-ps2.yaml b/dts/bindings/ps2/microchip,xec-ps2.yaml index 0480b5ed0596..b3521f960f23 100644 --- a/dts/bindings/ps2/microchip,xec-ps2.yaml +++ b/dts/bindings/ps2/microchip,xec-ps2.yaml @@ -25,3 +25,7 @@ properties: type: array required: true description: PS2 PCR register index and bit position + + wakerx-gpios: + type: phandle-array + description: GPIO configured as PS2 DAT wake source diff --git a/samples/drivers/ps2/prj.conf b/samples/drivers/ps2/prj.conf index 01cb3bb233f9..743787bd855c 100644 --- a/samples/drivers/ps2/prj.conf +++ b/samples/drivers/ps2/prj.conf @@ -1,4 +1,4 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_PRINTK=y CONFIG_PS2=y - +CONFIG_PM_DEVICE=y diff --git a/soc/arm/microchip_mec/mec172x/device_power.c b/soc/arm/microchip_mec/mec172x/device_power.c index cf7d41217194..8a35d6ddd00e 100644 --- a/soc/arm/microchip_mec/mec172x/device_power.c +++ b/soc/arm/microchip_mec/mec172x/device_power.c @@ -92,14 +92,15 @@ void soc_deep_sleep_non_wake_dis(void) /* When MEC172x drivers are power-aware this should be move there */ void soc_deep_sleep_wake_en(void) { -#if defined(CONFIG_KSCAN) || DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay) +#if defined(CONFIG_KSCAN) || \ + (!defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay)) struct ecia_named_regs *regs = ECIA_XEC_REG_BASE; #if defined(CONFIG_KSCAN) /* Enable PLL wake via KSCAN */ regs->GIRQ21.SRC = MCHP_KEYSCAN_GIRQ_BIT; regs->GIRQ21.EN_SET = MCHP_KEYSCAN_GIRQ_BIT; #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay) +#if !defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay) /* Enable PS2_0B_WK */ regs->GIRQ21.SRC = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT; regs->GIRQ21.EN_SET = MCHP_PS2_0_PORT0B_WK_GIRQ_BIT; @@ -109,7 +110,7 @@ void soc_deep_sleep_wake_en(void) void soc_deep_sleep_wake_dis(void) { -#if DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay) +#if !defined(CONFIG_PM_DEVICE) && DT_NODE_HAS_STATUS(DT_NODELABEL(ps2_0), okay) struct ecia_named_regs *regs = ECIA_XEC_REG_BASE; /* Enable PS2_0B_WK */ From ed27c1b75cfed5926bc232ac73ff14cd1ab7378c Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Sun, 23 Apr 2023 14:32:09 +0530 Subject: [PATCH 0284/2042] drivers: ps2: microchip: PS2 wakeup pin configured in overlay Updated the overlay files with PS2 wakeup pin Signed-off-by: Manimaran A --- .../ps2/boards/mec1501modular_assy6885.overlay | 15 +++++++++++++++ .../ps2/boards/mec15xxevb_assy6853.overlay | 15 +++++++++++++++ .../ps2/boards/mec172xevb_assy6906.overlay | 10 ++++++++++ 3 files changed, 40 insertions(+) create mode 100644 samples/drivers/ps2/boards/mec1501modular_assy6885.overlay create mode 100644 samples/drivers/ps2/boards/mec15xxevb_assy6853.overlay create mode 100644 samples/drivers/ps2/boards/mec172xevb_assy6906.overlay diff --git a/samples/drivers/ps2/boards/mec1501modular_assy6885.overlay b/samples/drivers/ps2/boards/mec1501modular_assy6885.overlay new file mode 100644 index 000000000000..902b54ccae8d --- /dev/null +++ b/samples/drivers/ps2/boards/mec1501modular_assy6885.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ps2_0 { /* PS2DAT0B */ + wakerx-gpios = ; + wakeup-source; +}; + +&ps2_1 { /* PS2DAT1B */ + wakerx-gpios = ; + wakeup-source; +}; diff --git a/samples/drivers/ps2/boards/mec15xxevb_assy6853.overlay b/samples/drivers/ps2/boards/mec15xxevb_assy6853.overlay new file mode 100644 index 000000000000..902b54ccae8d --- /dev/null +++ b/samples/drivers/ps2/boards/mec15xxevb_assy6853.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ps2_0 { /* PS2DAT0B */ + wakerx-gpios = ; + wakeup-source; +}; + +&ps2_1 { /* PS2DAT1B */ + wakerx-gpios = ; + wakeup-source; +}; diff --git a/samples/drivers/ps2/boards/mec172xevb_assy6906.overlay b/samples/drivers/ps2/boards/mec172xevb_assy6906.overlay new file mode 100644 index 000000000000..7da0650e31be --- /dev/null +++ b/samples/drivers/ps2/boards/mec172xevb_assy6906.overlay @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ps2_0 { /* PS2DAT0A */ + wakerx-gpios = ; + wakeup-source; +}; From bd1cf25821039d4d36283f4a4a969b30fdd8bbfa Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 5 Jun 2023 18:36:58 -0500 Subject: [PATCH 0285/2042] drivers: regulator: regulator_shell: add command to set DVS mode Add command to set DVS mode, to aid in testing regulators that expose this functionality. Since DVS modes are device specific, take an integer as the mode identifier and pass it to the driver directly. Signed-off-by: Daniel DeGrasse --- drivers/regulator/regulator_shell.c | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index 190130ec7c3f..ce7c262ed5c3 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -364,6 +364,33 @@ static int cmd_errors(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_dvsset(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int ret = 0; + regulator_dvs_state_t state; + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + state = shell_strtoul(argv[2], 10, &ret); + if (ret < 0) { + shell_error(sh, "Could not parse state (%d)", ret); + return ret; + } + + ret = regulator_parent_dvs_state_set(dev, state); + if (ret < 0) { + shell_error(sh, "Could not set DVS state (%d)", ret); + return ret; + } + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE( sub_regulator_cmds, SHELL_CMD_ARG(enable, NULL, @@ -410,6 +437,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Get errors\n" "Usage: errors ", cmd_errors, 2, 0), + SHELL_CMD_ARG(dvsset, NULL, + "Set regulator dynamic voltage scaling state\n" + "Usage: dvsset ", + cmd_dvsset, 3, 0), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(regulator, &sub_regulator_cmds, "Regulator playground", From 97be30cccb23c3b98eb296afaec0ca663f69495e Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 10 May 2023 07:17:51 -0300 Subject: [PATCH 0286/2042] drivers: uart: esp32s3: add async support Add uart async api support for esp32s3. Signed-off-by: Lucas Tamborrino --- drivers/serial/Kconfig.esp32 | 2 +- drivers/serial/uart_esp32.c | 31 +++++++++++++++++++++----- include/zephyr/drivers/dma/dma_esp32.h | 10 +++++++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/drivers/serial/Kconfig.esp32 b/drivers/serial/Kconfig.esp32 index 582badfc10eb..729d61b35ff9 100644 --- a/drivers/serial/Kconfig.esp32 +++ b/drivers/serial/Kconfig.esp32 @@ -7,7 +7,7 @@ config UART_ESP32 depends on DT_HAS_ESPRESSIF_ESP32_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select SERIAL_SUPPORT_ASYNC if SOC_ESP32C3 + select SERIAL_SUPPORT_ASYNC if (SOC_ESP32C3 || SOC_ESP32S3) select GPIO_ESP32 help Enable the ESP32 UART. diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 4b9fba97c862..380226dcfe6e 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Mohamed ElShahawi (extremegtx@hotmail.com) + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,15 +20,16 @@ #elif defined(CONFIG_SOC_ESP32S3) #include #include +#include #elif defined(CONFIG_SOC_ESP32C3) #include #include +#include +#endif #ifdef CONFIG_UART_ASYNC_API #include #include #include -#include -#endif #endif #include #include @@ -64,6 +66,7 @@ struct uart_esp32_config { const struct pinctrl_dev_config *pcfg; const clock_control_subsys_t clock_subsys; int irq_source; + int irq_priority; #if CONFIG_UART_ASYNC_API const struct device *dma_dev; uint8_t tx_dma_channel; @@ -94,7 +97,6 @@ struct uart_esp32_async_data { struct uart_esp32_data { struct uart_config uart_config; uart_hal_context_t hal; - int irq_line; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_callback_user_data_t irq_cb; void *irq_cb_data; @@ -466,6 +468,7 @@ static void uart_esp32_isr(void *arg) struct uart_esp32_data *data = dev->data; uint32_t uart_intr_status = uart_hal_get_intsts_mask(&data->hal); const struct uart_esp32_config *config = dev->config; + if (uart_intr_status == 0) { return; } @@ -884,9 +887,21 @@ static int uart_esp32_init(const struct device *dev) struct uart_esp32_data *data = dev->data; int ret = uart_esp32_configure(dev, &data->uart_config); + if (ret < 0) { + LOG_ERR("Error configuring UART (%d)", ret); + return ret; + } + #if CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API - data->irq_line = esp_intr_alloc(config->irq_source, 0, (ISR_HANDLER)uart_esp32_isr, - (void *)dev, NULL); + ret = esp_intr_alloc(config->irq_source, + config->irq_priority, + (ISR_HANDLER)uart_esp32_isr, + (void *)dev, + NULL); + if (ret < 0) { + LOG_ERR("Error allocating UART interrupt (%d)", ret); + return ret; + } #endif #if CONFIG_UART_ASYNC_API if (config->dma_dev) { @@ -905,7 +920,7 @@ static int uart_esp32_init(const struct device *dev) k_work_init_delayable(&data->async.rx_timeout_work, uart_esp32_async_rx_timeout); } #endif - return ret; + return 0; } static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { @@ -952,9 +967,12 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { #define ESP_UART_UHCI_INIT(n) \ .uhci_dev = COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), (&UHCI0), (NULL)) +#define UART_IRQ_PRIORITY ESP_INTR_FLAG_LEVEL2 + #else #define ESP_UART_DMA_INIT(n) #define ESP_UART_UHCI_INIT(n) +#define UART_IRQ_PRIORITY (0) #endif #define ESP32_UART_INIT(idx) \ @@ -966,6 +984,7 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset), \ .irq_source = DT_INST_IRQN(idx), \ + .irq_priority = UART_IRQ_PRIORITY, \ ESP_UART_DMA_INIT(idx)}; \ \ static struct uart_esp32_data uart_esp32_data_##idx = { \ diff --git a/include/zephyr/drivers/dma/dma_esp32.h b/include/zephyr/drivers/dma/dma_esp32.h index b04db7f05a1c..56366e858d16 100644 --- a/include/zephyr/drivers/dma/dma_esp32.h +++ b/include/zephyr/drivers/dma/dma_esp32.h @@ -10,11 +10,17 @@ enum gdma_trigger_peripheral { GDMA_TRIG_PERIPH_M2M = -1, GDMA_TRIG_PERIPH_SPI2 = 0, + GDMA_TRIG_PERIPH_SPI3 = 1, GDMA_TRIG_PERIPH_UHCI0 = 2, - GDMA_TRIG_PERIPH_I2S = 4, + GDMA_TRIG_PERIPH_I2S0 = 3, + GDMA_TRIG_PERIPH_I2S1 = 4, + GDMA_TRIG_PERIPH_LCD0 = 5, + GDMA_TRIG_PERIPH_CAM0 = 5, GDMA_TRIG_PERIPH_AES = 6, GDMA_TRIG_PERIPH_SHA = 7, - GDMA_TRIG_PERIPH_ADC = 8, + GDMA_TRIG_PERIPH_ADC0 = 8, + GDMA_TRIG_PERIPH_DAC0 = 8, + GDMA_TRIG_PERIPH_RMT = 9, GDMA_TRIG_PERIPH_INVALID = 0x3F, }; From 8cbf1be28ee87cd63ab38b745156de9c22570342 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 10 May 2023 07:18:23 -0300 Subject: [PATCH 0287/2042] tests: drivers: uart: uart async: Add esp32s3 overlay Add esp32s3 support for uart async tests. Signed-off-by: Lucas Tamborrino --- .../boards/esp32c3_devkitm.overlay | 1 - .../boards/esp32s3_devkitm.conf | 1 + .../boards/esp32s3_devkitm.overlay | 30 +++++++++++++++++++ .../uart/uart_async_api/src/test_uart.h | 2 -- 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf create mode 100644 tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay diff --git a/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay b/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay index 8fdb4f5e90cb..7f6a51cbb3d8 100644 --- a/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay @@ -5,7 +5,6 @@ */ &pinctrl { - uart1_test: uart1_test { group1 { pinmux = ; diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf new file mode 100644 index 000000000000..73aff8957e7a --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.conf @@ -0,0 +1 @@ +CONFIG_DMA=y diff --git a/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay new file mode 100644 index 000000000000..50d6012d7bd0 --- /dev/null +++ b/tests/drivers/uart/uart_async_api/boards/esp32s3_devkitm.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart1_test: uart1_test { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; +}; + +dut: &uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_test>; + pinctrl-names = "default"; + dmas = <&dma 0>, <&dma 1>; + dma-names = "rx", "tx"; +}; + +&dma { + status = "okay"; +}; diff --git a/tests/drivers/uart/uart_async_api/src/test_uart.h b/tests/drivers/uart/uart_async_api/src/test_uart.h index 2bfa470e464f..b6b5ee66f563 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart.h +++ b/tests/drivers/uart/uart_async_api/src/test_uart.h @@ -21,8 +21,6 @@ #if DT_NODE_EXISTS(DT_NODELABEL(dut)) #define UART_NODE DT_NODELABEL(dut) -#elif defined(CONFIG_SOC_ESP32C3) -#define UART_NODE DT_NODELABEL(uart1) #else #define UART_NODE DT_CHOSEN(zephyr_console) #endif From 1956b06eccd5b159e0236914157812833932634f Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 18:40:06 +0200 Subject: [PATCH 0288/2042] Bluetooth: Mesh: Don't poll friend when sending over loopback When LPN sends a segmented message to itself, it unnecesseraly polls Friend. Since Friend doesn't receive this message, the segmented message transmission will eventually fail (send end callback will return error), while the message will actually be passed to the access layer. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/lpn.c | 1 + subsys/bluetooth/mesh/transport.c | 4 ++-- subsys/bluetooth/mesh/transport_legacy.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 5dfecc5b35a0..03ff672338f3 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -120,6 +120,7 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) { /* If we're waiting for segment acks keep polling at high freq */ if (bt_mesh_tx_in_progress()) { + LOG_DBG("Tx is in progress. Keep polling"); return MIN(POLL_TIMEOUT_MAX(lpn), 1 * MSEC_PER_SEC); } diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 2e6d1726b5c8..1501c88217b1 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -467,7 +467,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) end: if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - bt_mesh_lpn_established()) { + bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { bt_mesh_lpn_poll(); } @@ -1104,7 +1104,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, LOG_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); - if (bt_mesh_lpn_established()) { + if (bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { LOG_WRN("Not sending ack when LPN is enabled"); return 0; } diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index 7f7e0a54e33a..f619473c606e 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -445,7 +445,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) end: if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - bt_mesh_lpn_established()) { + bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { bt_mesh_lpn_poll(); } @@ -1069,7 +1069,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, LOG_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); - if (bt_mesh_lpn_established()) { + if (bt_mesh_lpn_established() && !bt_mesh_has_addr(ctx.addr)) { LOG_WRN("Not sending ack when LPN is enabled"); return 0; } From 648378b29253e036951edbd52f5f17afd81a4f67 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 18:43:12 +0200 Subject: [PATCH 0289/2042] Bluetooth: Mesh: Add full virtual addresses support This commit adds the following features related to virtual addresses support: - Allows to store Label UUIDs which virtual addresses collide; - Allows to decrypt messages encrypted with a virtual address with collision; - Allows to publish a message to a specific Label UUID to avoid virtual addresses collision by adding a pointer to Label UUID to struct bt_mesh_msg_ctx and struct bt_mesh_model_pub; - Allows to differentiate Label UUIDs in the model's Subscription List by storing all subscribed UUIDs in struct bt_mesh_model.uuids field. Signed-off-by: Pavel Vasilyev --- include/zephyr/bluetooth/mesh/access.h | 18 + include/zephyr/bluetooth/mesh/main.h | 17 + include/zephyr/bluetooth/mesh/msg.h | 12 +- subsys/bluetooth/mesh/CMakeLists.txt | 1 + subsys/bluetooth/mesh/access.c | 293 +++++++++++++--- subsys/bluetooth/mesh/access.h | 1 + subsys/bluetooth/mesh/cfg_srv.c | 203 ++++++----- subsys/bluetooth/mesh/friend.c | 34 +- subsys/bluetooth/mesh/lpn.c | 2 +- subsys/bluetooth/mesh/lpn.h | 2 +- subsys/bluetooth/mesh/settings.c | 1 + subsys/bluetooth/mesh/transport.c | 270 ++------------- subsys/bluetooth/mesh/transport.h | 9 - subsys/bluetooth/mesh/transport_legacy.c | 271 ++------------- subsys/bluetooth/mesh/va.c | 319 ++++++++++++++++++ subsys/bluetooth/mesh/va.h | 79 +++++ tests/bsim/bluetooth/mesh/src/mesh_test.c | 26 +- tests/bsim/bluetooth/mesh/src/mesh_test.h | 6 +- .../bsim/bluetooth/mesh/src/test_friendship.c | 120 ++++--- tests/bsim/bluetooth/mesh/src/test_iv_index.c | 3 +- tests/bsim/bluetooth/mesh/src/test_scanner.c | 2 +- .../bsim/bluetooth/mesh/src/test_transport.c | 68 ++-- 22 files changed, 1041 insertions(+), 716 deletions(-) create mode 100644 subsys/bluetooth/mesh/va.c create mode 100644 subsys/bluetooth/mesh/va.h diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index 58219437958d..d033d9e88499 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -17,10 +17,18 @@ /* Internal macros used to initialize array members */ #define BT_MESH_KEY_UNUSED_ELT_(IDX, _) BT_MESH_KEY_UNUSED #define BT_MESH_ADDR_UNASSIGNED_ELT_(IDX, _) BT_MESH_ADDR_UNASSIGNED +#define BT_MESH_UUID_UNASSIGNED_ELT_(IDX, _) NULL #define BT_MESH_MODEL_KEYS_UNUSED(_keys) \ { LISTIFY(_keys, BT_MESH_KEY_UNUSED_ELT_, (,)) } #define BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps) \ { LISTIFY(_grps, BT_MESH_ADDR_UNASSIGNED_ELT_, (,)) } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +#define BT_MESH_MODEL_UUIDS_UNASSIGNED() \ + .uuids = (const uint8_t *[]){ LISTIFY(CONFIG_BT_MESH_LABEL_COUNT, \ + BT_MESH_UUID_UNASSIGNED_ELT_, (,)) }, +#else +#define BT_MESH_MODEL_UUIDS_UNASSIGNED() +#endif /** * @brief Access layer @@ -286,6 +294,7 @@ struct bt_mesh_model_op { .keys_cnt = _keys, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ .user_data = _user_data, \ @@ -319,6 +328,7 @@ struct bt_mesh_model_op { .keys_cnt = _keys, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \ .groups_cnt = _grps, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .user_data = _user_data, \ .cb = _cb, \ } @@ -364,6 +374,7 @@ struct bt_mesh_model_op { .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .op = _op, \ .cb = _cb, \ .user_data = _user_data, \ @@ -418,6 +429,7 @@ struct bt_mesh_model_op { .keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \ .groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \ .groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \ + BT_MESH_MODEL_UUIDS_UNASSIGNED() \ .user_data = _user_data, \ .cb = _cb, \ .metadata = _metadata, \ @@ -545,6 +557,7 @@ struct bt_mesh_model_pub { struct bt_mesh_model *mod; uint16_t addr; /**< Publish Address. */ + const uint8_t *uuid; /**< Label UUID if Publish Address is Virtual Address. */ uint16_t key:12, /**< Publish AppKey Index. */ cred:1, /**< Friendship Credentials Flag. */ send_rel:1, /**< Force reliable sending (segment acks) */ @@ -744,6 +757,11 @@ struct bt_mesh_model { uint16_t * const groups; const uint16_t groups_cnt; +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /** List of Label UUIDs the model is subscribed to. */ + const uint8_t ** const uuids; +#endif + /** Opcode handler list */ const struct bt_mesh_model_op * const op; diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 96f2b343a70c..5d37b581f4d3 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -854,6 +854,23 @@ int bt_mesh_friend_terminate(uint16_t lpn_addr); */ void bt_mesh_rpl_pending_store(uint16_t addr); +/** @brief Iterate stored Label UUIDs. + * + * When @c addr is @ref BT_MESH_ADDR_UNASSIGNED, this function iterates over all available addresses + * starting with @c uuid. In this case, use @c retaddr to get virtual address representation of + * the returned Label UUID. When @c addr is a virtual address, this function returns next Label + * UUID corresponding to the @c addr. When @c uuid is NULL, this function returns the first + * available UUID. If @c uuid is previously returned uuid, this function returns following uuid. + * + * @param addr Virtual address to search for, or @ref BT_MESH_ADDR_UNASSIGNED. + * @param uuid Pointer to the previously returned Label UUID or NULL. + * @param retaddr Pointer to a memory where virtual address representation of the returning UUID is + * to be stored to. + * + * @return Pointer to Label UUID, or NULL if no more entries found. + */ +const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/mesh/msg.h b/include/zephyr/bluetooth/mesh/msg.h index ff2e3ffeba4c..e52ca85e3a41 100644 --- a/include/zephyr/bluetooth/mesh/msg.h +++ b/include/zephyr/bluetooth/mesh/msg.h @@ -86,6 +86,9 @@ struct bt_mesh_msg_ctx { /** Destination address of a received message. Not used for sending. */ uint16_t recv_dst; + /** Label UUID if Remote address is Virtual address, or NULL otherwise. */ + const uint8_t *uuid; + /** RSSI of received packet. Not used for sending. */ int8_t recv_rssi; @@ -102,6 +105,8 @@ struct bt_mesh_msg_ctx { /** * @brief Helper for bt_mesh_msg_ctx structure initialization. * + * @note If @c dst is a Virtual Address, Label UUID shall be initialized separately. + * * @param net_key_idx NetKey Index of the subnet to send the message on. Only used if * @c app_key_idx points to devkey. * @param app_key_idx AppKey Index to encrypt the message with. @@ -141,7 +146,12 @@ struct bt_mesh_msg_ctx { * @param pub Pointer to a model publication context. */ #define BT_MESH_MSG_CTX_INIT_PUB(pub) \ - BT_MESH_MSG_CTX_INIT(0, (pub)->key, (pub)->addr, (pub)->ttl) + { \ + .app_idx = (pub)->key, \ + .addr = (pub)->addr, \ + .send_ttl = (pub)->ttl, \ + .uuid = (pub)->uuid, \ + } /** @brief Initialize a model message. * diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index e4aa8f8933d9..a1a5b1de93a2 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH msg.c cfg_srv.c health_srv.c + va.c ) if (CONFIG_BT_MESH_V1d1) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 7df72d698fe9..483e7dcc0283 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -27,6 +27,7 @@ #include "foundation.h" #include "op_agg.h" #include "settings.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL #include @@ -34,13 +35,16 @@ LOG_MODULE_REGISTER(bt_mesh_access); /* Model publication information for persistent storage. */ struct mod_pub_val { - uint16_t addr; - uint16_t key; - uint8_t ttl; - uint8_t retransmit; - uint8_t period; - uint8_t period_div:4, - cred:1; + struct { + uint16_t addr; + uint16_t key; + uint8_t ttl; + uint8_t retransmit; + uint8_t period; + uint8_t period_div:4, + cred:1; + } base; + uint16_t uuidx; }; struct comp_foreach_model_arg { @@ -1002,6 +1006,69 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) return ctx.entry; } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +static const uint8_t **model_uuid_get(struct bt_mesh_model *mod, const uint8_t *uuid) +{ + int i; + + for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] == uuid) { + /* If we are looking for a new entry, ensure that we find a model where + * there is empty entry in both, uuids and groups list. + */ + if (uuid == NULL && !model_group_get(mod, BT_MESH_ADDR_UNASSIGNED)) { + continue; + } + + return &mod->uuids[i]; + } + } + + return NULL; +} + +struct find_uuid_visitor_ctx { + const uint8_t **entry; + struct bt_mesh_model *mod; + const uint8_t *uuid; +}; + +static enum bt_mesh_walk find_uuid_mod_visitor(struct bt_mesh_model *mod, void *user_data) +{ + struct find_uuid_visitor_ctx *ctx = user_data; + + if (mod->elem_idx != ctx->mod->elem_idx) { + return BT_MESH_WALK_CONTINUE; + } + + ctx->entry = model_uuid_get(mod, ctx->uuid); + if (ctx->entry) { + ctx->mod = mod; + return BT_MESH_WALK_STOP; + } + + return BT_MESH_WALK_CONTINUE; +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ + +const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + struct find_uuid_visitor_ctx ctx = { + .mod = *mod, + .entry = NULL, + .uuid = uuid, + }; + + bt_mesh_model_extensions_walk(*mod, find_uuid_mod_visitor, &ctx); + + *mod = ctx.mod; + return ctx.entry; +#else + return NULL; +#endif +} + static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, uint16_t group_addr) { @@ -1117,11 +1184,13 @@ bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) return false; } -static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst) +static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid) { if (BT_MESH_ADDR_IS_UNICAST(dst)) { return (dev_comp->elem[mod->elem_idx].addr == dst); - } else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst) || + } else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) { + return !!bt_mesh_model_find_uuid(&mod, uuid); + } else if (BT_MESH_ADDR_IS_GROUP(dst) || (BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) { return !!bt_mesh_model_find_group(&mod, dst); } @@ -1217,8 +1286,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode) CODE_UNREACHABLE; } -static int element_model_recv(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, uint16_t addr, +static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, struct bt_mesh_elem *elem, uint32_t opcode) { const struct bt_mesh_model_op *op; @@ -1237,8 +1305,8 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx, return ACCESS_STATUS_WRONG_KEY; } - if (!model_has_dst(model, addr)) { - LOG_ERR("Invalid address 0x%02x", addr); + if (!model_has_dst(model, ctx->recv_dst, ctx->uuid)) { + LOG_ERR("Invalid address 0x%02x", ctx->recv_dst); return ACCESS_STATUS_INVALID_ADDRESS; } @@ -1291,13 +1359,13 @@ int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) } else { struct bt_mesh_elem *elem = &dev_comp->elem[index]; - err = element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode); + err = element_model_recv(ctx, buf, elem, opcode); } } else { for (index = 0; index < dev_comp->elem_count; index++) { struct bt_mesh_elem *elem = &dev_comp->elem[index]; - (void)element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode); + (void)element_model_recv(ctx, buf, elem, opcode); } } @@ -1581,6 +1649,64 @@ static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd, LOG_HEXDUMP_DBG(mod->groups, len, "val"); LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0])); + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /* If uuids[0] is NULL, then either the model is not subscribed to virtual addresses or + * uuids are not yet recovered. + */ + if (mod->uuids[0] == NULL) { + int i, j = 0; + + for (i = 0; i < mod->groups_cnt && j < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { + /* Recover from implementation where uuid was not stored for + * virtual address. It is safe to pick first matched label because + * previously the stack wasn't able to store virtual addresses with + * collisions. + */ + mod->uuids[j] = bt_mesh_va_uuid_get(mod->groups[i], NULL, NULL); + j++; + } + } + } +#endif + return 0; +} + +static int mod_set_sub_va(struct bt_mesh_model *mod, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT]; + ssize_t len; + int i; + int count; + + /* Start with empty array regardless of cleared or set value */ + (void)memset(mod->uuids, 0, CONFIG_BT_MESH_LABEL_COUNT * sizeof(mod->uuids[0])); + + if (len_rd == 0) { + LOG_DBG("Cleared subscriptions for model"); + return 0; + } + + len = read_cb(cb_arg, uuidxs, sizeof(uuidxs)); + if (len < 0) { + LOG_ERR("Failed to read value (err %zd)", len); + return len; + } + + LOG_HEXDUMP_DBG(uuidxs, len, "val"); + + for (i = 0, count = 0; i < len / sizeof(uint16_t); i++) { + mod->uuids[count] = bt_mesh_va_get_uuid_by_idx(uuidxs[i]); + if (mod->uuids[count] != NULL) { + count++; + } + } + + LOG_DBG("Decoded %zu subscribed virtual addresses for model", count); +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ return 0; } @@ -1603,6 +1729,7 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, mod->pub->period = 0U; mod->pub->retransmit = 0U; mod->pub->count = 0U; + mod->pub->uuid = NULL; LOG_DBG("Cleared publication for model"); return 0; @@ -1612,22 +1739,41 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, return 0; } - err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); - if (err) { - LOG_ERR("Failed to set \'model-pub\'"); - return err; + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub.base)); + if (!err) { + /* Recover from implementation where uuid was not stored for virtual address. It + * is safe to pick first matched label because previously the stack wasn't able + * to store virtual addresses with collisions. + */ + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { + mod->pub->uuid = bt_mesh_va_uuid_get(pub.base.addr, NULL, NULL); + } + + goto pub_base_set; + } else { + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); + if (err) { + LOG_ERR("Failed to set \'model-pub\'"); + return err; + } } - mod->pub->addr = pub.addr; - mod->pub->key = pub.key; - mod->pub->cred = pub.cred; - mod->pub->ttl = pub.ttl; - mod->pub->period = pub.period; - mod->pub->retransmit = pub.retransmit; - mod->pub->period_div = pub.period_div; + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { + mod->pub->uuid = bt_mesh_va_get_uuid_by_idx(pub.uuidx); + } + +pub_base_set: + mod->pub->addr = pub.base.addr; + mod->pub->key = pub.base.key; + mod->pub->cred = pub.base.cred; + mod->pub->ttl = pub.base.ttl; + mod->pub->period = pub.base.period; + mod->pub->retransmit = pub.base.retransmit; + mod->pub->period_div = pub.base.period_div; mod->pub->count = 0U; - LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.addr, pub.key); + LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.base.addr, + pub.base.key); return 0; } @@ -1675,26 +1821,35 @@ static int mod_set(bool vnd, const char *name, size_t len_rd, } len = settings_name_next(name, &next); - if (!next) { LOG_ERR("Insufficient number of arguments"); return -ENOENT; } - if (!strncmp(next, "bind", len)) { - return mod_set_bind(mod, len_rd, read_cb, cb_arg); - } - - if (!strncmp(next, "sub", len)) { - return mod_set_sub(mod, len_rd, read_cb, cb_arg); - } + /* `len` contains length of model id string representation. Call settings_name_next() again + * to get length of `next`. + */ + switch (settings_name_next(next, NULL)) { + case 4: + if (!strncmp(next, "bind", 4)) { + return mod_set_bind(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "subv", 4)) { + return mod_set_sub_va(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "data", 4)) { + return mod_data_set(mod, next, len_rd, read_cb, cb_arg); + } - if (!strncmp(next, "pub", len)) { - return mod_set_pub(mod, len_rd, read_cb, cb_arg); - } + break; + case 3: + if (!strncmp(next, "sub", 3)) { + return mod_set_sub(mod, len_rd, read_cb, cb_arg); + } else if (!strncmp(next, "pub", 3)) { + return mod_set_pub(mod, len_rd, read_cb, cb_arg); + } - if (!strncmp(next, "data", len)) { - return mod_data_set(mod, next, len_rd, read_cb, cb_arg); + break; + default: + break; } LOG_WRN("Unknown module key %s", next); @@ -1786,8 +1941,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) encode_mod_path(mod, vnd, "sub", path, sizeof(path)); if (count) { - err = settings_save_one(path, groups, - count * sizeof(groups[0])); + err = settings_save_one(path, groups, count * sizeof(groups[0])); } else { err = settings_delete(path); } @@ -1799,6 +1953,38 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) } } +static void store_pending_mod_sub_va(struct bt_mesh_model *mod, bool vnd) +{ +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT]; + char path[20]; + int i, count, err; + + for (i = 0, count = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] != NULL) { + err = bt_mesh_va_get_idx_by_uuid(mod->uuids[i], &uuidxs[count]); + if (!err) { + count++; + } + } + } + + encode_mod_path(mod, vnd, "subv", path, sizeof(path)); + + if (count) { + err = settings_save_one(path, uuidxs, count * sizeof(uuidxs[0])); + } else { + err = settings_delete(path); + } + + if (err) { + LOG_ERR("Failed to store %s value", path); + } else { + LOG_DBG("Stored %s value", path); + } +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ +} + static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) { struct mod_pub_val pub = {0}; @@ -1810,15 +1996,21 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { err = settings_delete(path); } else { - pub.addr = mod->pub->addr; - pub.key = mod->pub->key; - pub.ttl = mod->pub->ttl; - pub.retransmit = mod->pub->retransmit; - pub.period = mod->pub->period; - pub.period_div = mod->pub->period_div; - pub.cred = mod->pub->cred; + pub.base.addr = mod->pub->addr; + pub.base.key = mod->pub->key; + pub.base.ttl = mod->pub->ttl; + pub.base.retransmit = mod->pub->retransmit; + pub.base.period = mod->pub->period; + pub.base.period_div = mod->pub->period_div; + pub.base.cred = mod->pub->cred; + + if (BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr)) { + (void)bt_mesh_va_get_idx_by_uuid(mod->pub->uuid, &pub.uuidx); + } - err = settings_save_one(path, &pub, sizeof(pub)); + err = settings_save_one(path, &pub, + BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr) ? sizeof(pub) : + sizeof(pub.base)); } if (err) { @@ -1844,6 +2036,7 @@ static void store_pending_mod(struct bt_mesh_model *mod, if (mod->flags & BT_MESH_MOD_SUB_PENDING) { mod->flags &= ~BT_MESH_MOD_SUB_PENDING; store_pending_mod_sub(mod, vnd); + store_pending_mod_sub_va(mod, vnd); } if (mod->flags & BT_MESH_MOD_PUB_PENDING) { diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 43ec18391600..43d5ad439130 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -41,6 +41,7 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *root, void *user_data); uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); +const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid); void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 7dbba2e8b582..512f2eb57f9a 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -35,6 +35,7 @@ #include "friend.h" #include "settings.h" #include "cfg.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL #include @@ -130,7 +131,7 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, } } -static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, +static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, const uint8_t *uuid, uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, uint8_t retransmit, bool store) { @@ -158,6 +159,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->period = 0U; model->pub->retransmit = 0U; model->pub->count = 0U; + model->pub->uuid = NULL; if (model->pub->update) { /* If this fails, the timer will check pub->addr and @@ -179,11 +181,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, #if CONFIG_BT_MESH_LABEL_COUNT > 0 if (BT_MESH_ADDR_IS_VIRTUAL(model->pub->addr)) { - uint8_t *uuid = bt_mesh_va_label_get(model->pub->addr); - - if (uuid) { - bt_mesh_va_del(uuid, NULL); - } + (void)bt_mesh_va_del(model->pub->uuid); } #endif @@ -193,6 +191,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->ttl = ttl; model->pub->period = period; model->pub->retransmit = retransmit; + model->pub->uuid = uuid; if (model->pub->update) { int32_t period_ms; @@ -273,7 +272,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st } if (model->pub && model->pub->key == key_idx) { - _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, + _mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, NULL, 0, 0, 0, 0, 0, store); } } @@ -803,7 +802,7 @@ static int mod_pub_set(struct bt_mesh_model *model, goto send_status; } - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, + status = _mod_pub_set(mod, pub_addr, NULL, pub_app_idx, cred_flag, pub_ttl, pub_period, retransmit, true); send_status: @@ -813,32 +812,31 @@ static int mod_pub_set(struct bt_mesh_model *model, static size_t mod_sub_list_clear(struct bt_mesh_model *mod) { - uint8_t *label_uuid; size_t clear_count; int i; - /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < mod->groups_cnt; i++) { - if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - } + /* mod->groups contains both, group and virtual addrs. Virtual addrs deletion will + * be handled separately. + */ + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; + clear_count++; + } + } +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + /* Unref stored labels related to this model */ + for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) { + if (mod->uuids[i] == NULL) { continue; } - label_uuid = bt_mesh_va_label_get(mod->groups[i]); - - mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; - clear_count++; - - if (label_uuid) { - bt_mesh_va_del(label_uuid, NULL); - } else { - LOG_ERR("Label UUID not found"); - } + (void)bt_mesh_va_del(mod->uuids[i]); + mod->uuids[i] = NULL; + /* No need to increment `clear_count` as `groups` contains virtual addresses. */ } +#endif return clear_count; } @@ -847,11 +845,13 @@ static int mod_pub_va_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + const struct bt_mesh_va *va; uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; - uint16_t elem_addr, pub_addr, pub_app_idx; + uint16_t elem_addr, pub_app_idx; + uint16_t pub_addr = 0U; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; bool vnd; @@ -866,7 +866,7 @@ static int mod_pub_va_set(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); pub_app_idx = net_buf_simple_pull_le16(buf); cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1)); pub_app_idx &= BIT_MASK(12); @@ -890,27 +890,27 @@ static int mod_pub_va_set(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - pub_addr = 0U; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - pub_addr = 0U; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_add(label_uuid, &pub_addr); + status = bt_mesh_va_add(uuid, &va); if (status != STATUS_SUCCESS) { goto send_status; } - status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl, + pub_addr = va->addr; + + status = _mod_pub_set(mod, pub_addr, va->uuid, pub_app_idx, cred_flag, pub_ttl, pub_period, retransmit, true); if (status != STATUS_SUCCESS) { - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); } send_status: @@ -1383,12 +1383,14 @@ static int mod_sub_va_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - uint16_t elem_addr, sub_addr; + const struct bt_mesh_va *va; + uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; - uint16_t *entry; + uint16_t *group_entry; + const uint8_t **label_entry; uint8_t status; bool vnd; @@ -1403,7 +1405,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1412,42 +1414,59 @@ static int mod_sub_va_add(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_add(label_uuid, &sub_addr); + status = bt_mesh_va_add(uuid, &va); if (status != STATUS_SUCCESS) { goto send_status; } - if (bt_mesh_model_find_group(&mod, sub_addr)) { + if (bt_mesh_model_find_uuid(&mod, va->uuid)) { /* Tried to add existing subscription */ status = STATUS_SUCCESS; - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); goto send_status; } + label_entry = bt_mesh_model_find_uuid(&mod, NULL); + if (!label_entry) { + status = STATUS_INSUFF_RESOURCES; + (void)bt_mesh_va_del(va->uuid); + goto send_status; + } - entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED); - if (!entry) { + group_entry = NULL; + + for (int i = 0; i < mod->groups_cnt; i++) { + if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) { + group_entry = &mod->groups[i]; + break; + } + } + + /* bt_mesh_model_find_uuid() should find a model where both, uuids and groups lists have + * empty entry. + */ + if (!group_entry) { status = STATUS_INSUFF_RESOURCES; - bt_mesh_va_del(label_uuid, NULL); + (void)bt_mesh_va_del(va->uuid); goto send_status; } - *entry = sub_addr; + *group_entry = va->addr; + *label_entry = va->uuid; - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_add(va->addr); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { @@ -1455,6 +1474,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model, } status = STATUS_SUCCESS; + sub_addr = va->addr; send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, @@ -1465,12 +1485,13 @@ static int mod_sub_va_del(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - uint16_t elem_addr, sub_addr; + const struct bt_mesh_va *va; + uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; - uint16_t *match; + const uint8_t **label_match; uint8_t status; bool vnd; @@ -1485,7 +1506,7 @@ static int mod_sub_va_del(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1495,40 +1516,50 @@ static int mod_sub_va_del(struct bt_mesh_model *model, if (!elem) { mod = NULL; vnd = (buf->len == 4U); - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_ADDRESS; goto send_status; } mod = get_model(elem, buf, &vnd); if (!mod) { - sub_addr = BT_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; } - status = bt_mesh_va_del(label_uuid, &sub_addr); - if (sub_addr == BT_MESH_ADDR_UNASSIGNED) { + va = bt_mesh_va_find(uuid); + if (!va) { + status = STATUS_CANNOT_REMOVE; goto send_status; } - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_del(&sub_addr, 1); + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_del(&va->addr, 1); } - match = bt_mesh_model_find_group(&mod, sub_addr); - if (match) { - *match = BT_MESH_ADDR_UNASSIGNED; + label_match = bt_mesh_model_find_uuid(&mod, va->uuid); + if (!label_match) { + status = STATUS_CANNOT_REMOVE; + goto send_status; + } - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_model_sub_store(mod); + for (int i = 0; i < mod->groups_cnt; i++) { + if (mod->groups[i] == va->addr) { + mod->groups[i] = BT_MESH_ADDR_UNASSIGNED; + break; } + } - status = STATUS_SUCCESS; - } else { - status = STATUS_CANNOT_REMOVE; + *label_match = NULL; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_model_sub_store(mod); } + sub_addr = va->addr; + (void)bt_mesh_va_del(va->uuid); + status = STATUS_SUCCESS; + send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); @@ -1538,10 +1569,11 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + const struct bt_mesh_va *va; uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; - uint8_t *label_uuid; + const uint8_t *uuid; uint8_t *mod_id; uint8_t status; bool vnd; @@ -1557,7 +1589,7 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, return -EINVAL; } - label_uuid = net_buf_simple_pull_mem(buf, 16); + uuid = net_buf_simple_pull_mem(buf, 16); LOG_DBG("elem_addr 0x%04x", elem_addr); @@ -1577,26 +1609,33 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model, goto send_status; } + if (CONFIG_BT_MESH_LABEL_COUNT == 0 || mod->groups_cnt == 0) { + (void)va; + status = STATUS_INSUFF_RESOURCES; + goto send_status; + } - if (mod->groups_cnt > 0) { +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + status = bt_mesh_va_add(uuid, &va); + if (status != STATUS_SUCCESS) { + goto send_status; + } - status = bt_mesh_va_add(label_uuid, &sub_addr); - if (status == STATUS_SUCCESS) { - bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); - mod->groups[0] = sub_addr; + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); + mod->groups[0] = va->addr; + mod->uuids[0] = va->uuid; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_model_sub_store(mod); - } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_model_sub_store(mod); + } - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - bt_mesh_lpn_group_add(sub_addr); - } - } - } else { - status = STATUS_INSUFF_RESOURCES; + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 && + !bt_mesh_va_collision_check(va->addr)) { + bt_mesh_lpn_group_add(va->addr); } + sub_addr = va->addr; +#endif send_status: return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 5a1a51801e17..e14fc1e91a28 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -21,6 +21,7 @@ #include "access.h" #include "foundation.h" #include "friend.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_FRIEND_LOG_LEVEL #include @@ -60,9 +61,15 @@ struct friend_pdu_info { uint32_t iv_index; }; +BUILD_ASSERT(CONFIG_BT_MESH_LABEL_COUNT <= 0xFFFU, "Friend doesn't support more than 4096 labels."); + struct friend_adv { uint16_t app_idx; - bool seg; + struct { + /* CONFIG_BT_MESH_LABEL_COUNT max value is 4096. */ + uint16_t uuidx:15, + seg:1; + }; }; NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BT_MESH_ADV_DATA_SIZE, @@ -309,6 +316,7 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) if (empty_idx != INT_MAX) { frnd->sub_list[empty_idx] = addr; + LOG_DBG("%04x added %04x to subscription list", frnd->lpn, addr); } else { LOG_WRN("No space in friend subscription list"); } @@ -320,6 +328,7 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { + LOG_DBG("%04x removed %04x from subscription list", frnd->lpn, addr); frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED; return; } @@ -370,6 +379,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta *meta) { uint16_t app_idx = FRIEND_ADV(buf)->app_idx; + uint16_t uuidx = FRIEND_ADV(buf)->uuidx; struct bt_mesh_net_rx net = { .ctx = { .app_idx = app_idx, @@ -393,10 +403,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, meta->crypto.aszmic = 0; if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) { - meta->crypto.ad = bt_mesh_va_label_get(meta->crypto.dst); - if (!meta->crypto.ad) { - return -ENOENT; - } + meta->crypto.ad = bt_mesh_va_get_uuid_by_idx(uuidx); } else { meta->crypto.ad = NULL; } @@ -1504,11 +1511,26 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, * when encrypting in transport and network. */ FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx; + + /* When reencrypting a virtual address message, we need to know uuid as well. */ + if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { + uint16_t uuidx; + int err; + + err = bt_mesh_va_get_idx_by_uuid(tx->ctx->uuid, &uuidx); + if (err) { + net_buf_unref(buf); + return; + } + + FRIEND_ADV(buf)->uuidx = uuidx; + } } enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - LOG_DBG("Queued message for LPN 0x%04x", frnd->lpn); + LOG_DBG("Queued message for LPN 0x%04x, dst: %04x, uuid: %p", frnd->lpn, tx->ctx->addr, + tx->ctx->uuid); } static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, diff --git a/subsys/bluetooth/mesh/lpn.c b/subsys/bluetooth/mesh/lpn.c index 03ff672338f3..2b655f729f31 100644 --- a/subsys/bluetooth/mesh/lpn.c +++ b/subsys/bluetooth/mesh/lpn.c @@ -966,7 +966,7 @@ void bt_mesh_lpn_group_add(uint16_t group) sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD); } -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) +void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count) { int i; diff --git a/subsys/bluetooth/mesh/lpn.h b/subsys/bluetooth/mesh/lpn.h index 7d909e06d0b9..6fbea59b975b 100644 --- a/subsys/bluetooth/mesh/lpn.h +++ b/subsys/bluetooth/mesh/lpn.h @@ -45,7 +45,7 @@ static inline bool bt_mesh_lpn_waiting_update(void) void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); void bt_mesh_lpn_group_add(uint16_t group); -void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count); +void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count); void bt_mesh_lpn_disable(bool force); void bt_mesh_lpn_friendship_end(void); diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index ef4eec6f6a77..771aad9b9460 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -30,6 +30,7 @@ #include "settings.h" #include "cfg.h" #include "solicitation.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL #include diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 1501c88217b1..4cacf8d526c8 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -35,6 +35,7 @@ #include "settings.h" #include "heartbeat.h" #include "transport.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL #include @@ -59,20 +60,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport); /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT -struct virtual_addr { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - -/* Virtual Address information for persistent storage. */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - #define ACK_DELAY(seg_n) \ (MIN(2 * seg_n + 1, BT_MESH_SAR_RX_ACK_DELAY_INC_X2) * \ BT_MESH_SAR_RX_SEG_INT_MS / 2) @@ -131,8 +118,6 @@ static struct seg_rx { K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); -static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; - 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) @@ -652,7 +637,7 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k }; if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - crypto.ad = bt_mesh_va_label_get(tx->ctx->addr); + crypto.ad = tx->ctx->uuid; } return bt_mesh_app_encrypt(key, &crypto, msg); @@ -759,15 +744,35 @@ struct decrypt_ctx { static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { - const struct decrypt_ctx *ctx = cb_data; + struct decrypt_ctx *ctx = cb_data; + int err; - if (ctx->seg) { - seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); - } + ctx->crypto.ad = NULL; + + do { + if (ctx->seg) { + seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); + } - net_buf_simple_reset(ctx->sdu); + 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); - return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + 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, @@ -794,10 +799,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst); - } - 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) { @@ -805,6 +806,8 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } + rx->ctx.uuid = ctx.crypto.ad; + LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx); (void)bt_mesh_model_recv(&rx->ctx, sdu); @@ -1683,11 +1686,6 @@ void bt_mesh_rx_reset(void) } } -static void store_va_label(void) -{ - bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); -} - void bt_mesh_trans_reset(void) { int i; @@ -1700,18 +1698,8 @@ void bt_mesh_trans_reset(void) seg_tx_reset(&seg_tx[i]); } - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref) { - virtual_addrs[i].ref = 0U; - virtual_addrs[i].changed = 1U; - } - } - bt_mesh_rpl_clear(); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } + bt_mesh_va_clear(); } void bt_mesh_trans_init(void) @@ -1727,199 +1715,3 @@ void bt_mesh_trans_init(void) k_work_init_delayable(&seg_rx[i].discard, seg_discard); } } - -static inline void va_store(struct virtual_addr *store) -{ - store->changed = 1U; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } -} - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - int err; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (!virtual_addrs[i].ref) { - if (!va) { - va = &virtual_addrs[i]; - } - - continue; - } - - if (!memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - *addr = virtual_addrs[i].addr; - virtual_addrs[i].ref++; - va_store(&virtual_addrs[i]); - return STATUS_SUCCESS; - } - } - - if (!va) { - return STATUS_INSUFF_RESOURCES; - } - - memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); - err = bt_mesh_virtual_addr(uuid, &va->addr); - if (err) { - va->addr = BT_MESH_ADDR_UNASSIGNED; - return STATUS_UNSPECIFIED; - } - - va->ref = 1; - va_store(va); - - *addr = va->addr; - - return STATUS_SUCCESS; -} - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - va = &virtual_addrs[i]; - break; - } - } - - if (!va) { - return STATUS_CANNOT_REMOVE; - } - - va->ref--; - if (addr) { - *addr = va->addr; - } - - va_store(va); - return STATUS_SUCCESS; -} - -uint8_t *bt_mesh_va_label_get(uint16_t addr) -{ - int i; - - LOG_DBG("addr 0x%04x", addr); - - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) { - LOG_DBG("Found Label UUID for 0x%04x: %s", addr, - bt_hex(virtual_addrs[i].uuid, 16)); - return virtual_addrs[i].uuid; - } - } - - LOG_WRN("No matching Label UUID for 0x%04x", addr); - - return NULL; -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static struct virtual_addr *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; - } - - return &virtual_addrs[index]; -} - -static int va_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct va_val va; - struct virtual_addr *lab; - uint16_t index; - int err; - - if (!name) { - LOG_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - index = strtol(name, NULL, 16); - - if (len_rd == 0) { - LOG_WRN("Mesh Virtual Address length = 0"); - return 0; - } - - err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); - if (err) { - LOG_ERR("Failed to set \'virtual address\'"); - return err; - } - - if (va.ref == 0) { - LOG_WRN("Ignore Mesh Virtual Address ref = 0"); - return 0; - } - - lab = bt_mesh_va_get(index); - if (lab == NULL) { - LOG_WRN("Out of labels buffers"); - return -ENOBUFS; - } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); - - return 0; -} - -BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -void bt_mesh_va_pending_store(void) -{ - struct virtual_addr *lab; - struct va_val va; - char path[18]; - uint16_t i; - int err; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - err = settings_delete(path); - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - err = settings_save_one(path, &va, sizeof(va)); - } - - if (err) { - LOG_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} -#else -void bt_mesh_va_pending_store(void) -{ - /* Do nothing. */ -} -#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index ec540bd118a0..2ac840d3923c 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -101,13 +101,4 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx); void bt_mesh_trans_init(void); - void bt_mesh_trans_reset(void); - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr); - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr); - -uint8_t *bt_mesh_va_label_get(uint16_t addr); - -void bt_mesh_va_pending_store(void); diff --git a/subsys/bluetooth/mesh/transport_legacy.c b/subsys/bluetooth/mesh/transport_legacy.c index f619473c606e..c63ad1dac85d 100644 --- a/subsys/bluetooth/mesh/transport_legacy.c +++ b/subsys/bluetooth/mesh/transport_legacy.c @@ -34,6 +34,7 @@ #include "settings.h" #include "heartbeat.h" #include "transport.h" +#include "va.h" #define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL #include @@ -78,20 +79,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport); /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT -struct virtual_addr { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - -/* Virtual Address information for persistent storage. */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - static struct seg_tx { struct bt_mesh_subnet *sub; void *seg[BT_MESH_TX_SEG_MAX]; @@ -138,8 +125,6 @@ static struct seg_rx { K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); -static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; - 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) @@ -613,7 +598,10 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k }; if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) { - crypto.ad = bt_mesh_va_label_get(tx->ctx->addr); + crypto.ad = tx->ctx->uuid; + if (crypto.ad == NULL) { + return -ENOENT; + } } return bt_mesh_app_encrypt(key, &crypto, msg); @@ -720,15 +708,35 @@ struct decrypt_ctx { static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key, void *cb_data) { - const struct decrypt_ctx *ctx = cb_data; + struct decrypt_ctx *ctx = cb_data; + int err; - if (ctx->seg) { - seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic); - } + 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); - 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 bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu); + return err; } static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, @@ -755,10 +763,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic, return 0; } - if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) { - ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst); - } - 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) { @@ -1625,11 +1629,6 @@ void bt_mesh_rx_reset(void) } } -static void store_va_label(void) -{ - bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); -} - void bt_mesh_trans_reset(void) { int i; @@ -1642,18 +1641,8 @@ void bt_mesh_trans_reset(void) seg_tx_reset(&seg_tx[i]); } - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref) { - virtual_addrs[i].ref = 0U; - virtual_addrs[i].changed = 1U; - } - } - bt_mesh_rpl_clear(); - - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } + bt_mesh_va_clear(); } void bt_mesh_trans_init(void) @@ -1668,199 +1657,3 @@ void bt_mesh_trans_init(void) k_work_init_delayable(&seg_rx[i].ack, seg_ack); } } - -static inline void va_store(struct virtual_addr *store) -{ - store->changed = 1U; - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - store_va_label(); - } -} - -uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - int err; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (!virtual_addrs[i].ref) { - if (!va) { - va = &virtual_addrs[i]; - } - - continue; - } - - if (!memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - *addr = virtual_addrs[i].addr; - virtual_addrs[i].ref++; - va_store(&virtual_addrs[i]); - return STATUS_SUCCESS; - } - } - - if (!va) { - return STATUS_INSUFF_RESOURCES; - } - - memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); - err = bt_mesh_virtual_addr(uuid, &va->addr); - if (err) { - va->addr = BT_MESH_ADDR_UNASSIGNED; - return STATUS_UNSPECIFIED; - } - - va->ref = 1; - va_store(va); - - *addr = va->addr; - - return STATUS_SUCCESS; -} - -uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) -{ - struct virtual_addr *va = NULL; - - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - va = &virtual_addrs[i]; - break; - } - } - - if (!va) { - return STATUS_CANNOT_REMOVE; - } - - va->ref--; - if (addr) { - *addr = va->addr; - } - - va_store(va); - return STATUS_SUCCESS; -} - -uint8_t *bt_mesh_va_label_get(uint16_t addr) -{ - int i; - - LOG_DBG("addr 0x%04x", addr); - - for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) { - LOG_DBG("Found Label UUID for 0x%04x: %s", addr, - bt_hex(virtual_addrs[i].uuid, 16)); - return virtual_addrs[i].uuid; - } - } - - LOG_WRN("No matching Label UUID for 0x%04x", addr); - - return NULL; -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static struct virtual_addr *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; - } - - return &virtual_addrs[index]; -} - -static int va_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct va_val va; - struct virtual_addr *lab; - uint16_t index; - int err; - - if (!name) { - LOG_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - index = strtol(name, NULL, 16); - - if (len_rd == 0) { - LOG_WRN("Mesh Virtual Address length = 0"); - return 0; - } - - err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); - if (err) { - LOG_ERR("Failed to set \'virtual address\'"); - return err; - } - - if (va.ref == 0) { - LOG_WRN("Ignore Mesh Virtual Address ref = 0"); - return 0; - } - - lab = bt_mesh_va_get(index); - if (lab == NULL) { - LOG_WRN("Out of labels buffers"); - return -ENOBUFS; - } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); - - return 0; -} - -BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -void bt_mesh_va_pending_store(void) -{ - struct virtual_addr *lab; - struct va_val va; - char path[18]; - uint16_t i; - int err; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - err = settings_delete(path); - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - err = settings_save_one(path, &va, sizeof(va)); - } - - if (err) { - LOG_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} -#else -void bt_mesh_va_pending_store(void) -{ - /* Do nothing. */ -} -#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/subsys/bluetooth/mesh/va.c b/subsys/bluetooth/mesh/va.c new file mode 100644 index 000000000000..0392208951ad --- /dev/null +++ b/subsys/bluetooth/mesh/va.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "common/bt_str.h" + +#include "va.h" +#include "foundation.h" +#include "msg.h" +#include "net.h" +#include "crypto.h" +#include "settings.h" + +#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_va); + +static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; + +/* Virtual Address information for persistent storage. */ +struct va_val { + uint16_t ref; + uint16_t addr; + uint8_t uuid[16]; +} __packed; + +static void va_store(struct bt_mesh_va *store) +{ + store->changed = 1U; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); + } +} + +uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry) +{ + struct bt_mesh_va *va = NULL; + int err; + + for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (!virtual_addrs[i].ref) { + if (!va) { + va = &virtual_addrs[i]; + } + + continue; + } + + if (!memcmp(uuid, virtual_addrs[i].uuid, + ARRAY_SIZE(virtual_addrs[i].uuid))) { + if (entry) { + *entry = &virtual_addrs[i]; + } + virtual_addrs[i].ref++; + va_store(&virtual_addrs[i]); + return STATUS_SUCCESS; + } + } + + if (!va) { + return STATUS_INSUFF_RESOURCES; + } + + memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid)); + err = bt_mesh_virtual_addr(uuid, &va->addr); + if (err) { + va->addr = BT_MESH_ADDR_UNASSIGNED; + return STATUS_UNSPECIFIED; + } + + va->ref = 1; + va_store(va); + + if (entry) { + *entry = va; + } + + return STATUS_SUCCESS; +} + +uint8_t bt_mesh_va_del(const uint8_t *uuid) +{ + struct bt_mesh_va *va; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return STATUS_CANNOT_REMOVE; + } + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + + if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) { + return STATUS_CANNOT_REMOVE; + } + + va->ref--; + va_store(va); + + return STATUS_SUCCESS; +} + +const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr) +{ + int i = 0; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return NULL; + } + + if (uuid != NULL) { + struct bt_mesh_va *va; + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + i = ARRAY_INDEX(virtual_addrs, va); + } + + for (; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref && + (virtual_addrs[i].addr == addr || addr == BT_MESH_ADDR_UNASSIGNED)) { + if (!uuid) { + LOG_DBG("Found Label UUID for 0x%04x: %s", addr, + bt_hex(virtual_addrs[i].uuid, 16)); + + if (retaddr) { + *retaddr = virtual_addrs[i].addr; + } + + return virtual_addrs[i].uuid; + } else if (uuid == virtual_addrs[i].uuid) { + uuid = NULL; + } + } + } + + LOG_WRN("No matching Label UUID for 0x%04x", addr); + + return NULL; +} + +bool bt_mesh_va_collision_check(uint16_t addr) +{ + size_t count = 0; + const uint8_t *uuid = NULL; + + do { + uuid = bt_mesh_va_uuid_get(addr, uuid, NULL); + } while (uuid && ++count); + + return count > 1; +} + +const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref && !memcmp(virtual_addrs[i].uuid, uuid, 16)) { + return &virtual_addrs[i]; + } + } + + return NULL; +} + +static struct bt_mesh_va *va_get_by_idx(uint16_t index) +{ + if (index >= ARRAY_SIZE(virtual_addrs)) { + return NULL; + } + + return &virtual_addrs[index]; +} + +const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx) +{ + struct bt_mesh_va *va; + + va = va_get_by_idx(idx); + return (va && va->ref > 0) ? va->uuid : NULL; +} + +int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx) +{ + struct bt_mesh_va *va; + + if (CONFIG_BT_MESH_LABEL_COUNT == 0) { + return -ENOENT; + } + + va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid); + + if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) { + return -ENOENT; + } + + *uuidx = ARRAY_INDEX(virtual_addrs, va); + return 0; +} + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +static int va_set(const char *name, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + struct va_val va; + struct bt_mesh_va *lab; + uint16_t index; + int err; + + if (!name) { + LOG_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + index = strtol(name, NULL, 16); + + if (len_rd == 0) { + LOG_WRN("Mesh Virtual Address length = 0"); + return 0; + } + + err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va)); + if (err) { + LOG_ERR("Failed to set \'virtual address\'"); + return err; + } + + if (va.ref == 0) { + LOG_WRN("Ignore Mesh Virtual Address ref = 0"); + return 0; + } + + lab = va_get_by_idx(index); + if (lab == NULL) { + LOG_WRN("Out of labels buffers"); + return -ENOBUFS; + } + + memcpy(lab->uuid, va.uuid, 16); + lab->addr = va.addr; + lab->ref = va.ref; + + LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref); + + return 0; +} + +BT_MESH_SETTINGS_DEFINE(va, "Va", va_set); + +#define IS_VA_DEL(_label) ((_label)->ref == 0) +void bt_mesh_va_pending_store(void) +{ + struct bt_mesh_va *lab; + struct va_val va; + char path[18]; + uint16_t i; + int err; + + for (i = 0; (lab = va_get_by_idx(i)) != NULL; i++) { + if (!lab->changed) { + continue; + } + + lab->changed = 0U; + + snprintk(path, sizeof(path), "bt/mesh/Va/%x", i); + + if (IS_VA_DEL(lab)) { + err = settings_delete(path); + } else { + va.ref = lab->ref; + va.addr = lab->addr; + memcpy(va.uuid, lab->uuid, 16); + + err = settings_save_one(path, &va, sizeof(va)); + } + + if (err) { + LOG_ERR("Failed to %s %s value (err %d)", + IS_VA_DEL(lab) ? "delete" : "store", path, err); + } else { + LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path); + } + } +} +#else +void bt_mesh_va_pending_store(void) +{ + /* Do nothing. */ +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ + +void bt_mesh_va_clear(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { + if (virtual_addrs[i].ref) { + virtual_addrs[i].ref = 0U; + virtual_addrs[i].changed = 1U; + } + } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); + } +} diff --git a/subsys/bluetooth/mesh/va.h b/subsys/bluetooth/mesh/va.h new file mode 100644 index 000000000000..958b99af6c0d --- /dev/null +++ b/subsys/bluetooth/mesh/va.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** Virtual address entry. */ +struct bt_mesh_va { + uint16_t ref:15, + changed:1; + uint16_t addr; + uint8_t uuid[16]; +}; + +/** @brief Store Label UUID. + * + * @param uuid Label UUID to be stored. + * @param entry Pointer to a memory where a new or updated entry will be stored, or NULL. + * + * @return STATUS_SUCCESS if entry is stored or updated, error code otherwise. + */ +uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry); + +/** @brief Delete Label UUID. + * + * @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid + * pointer. + * + * @param uuid Label UUID to delete. + * + * @return STATUS_SUCCESS if entry is deleted, error code otherwise. + */ +uint8_t bt_mesh_va_del(const uint8_t *uuid); + +/** @brief Find virtual address entry by Label UUID. + * + * @c uuid can be a user data. + * + * @param uuid pointer to memory with Label UUID to be found. + * + * @return Pointer to a valid entry, NULL otherwise. + */ +const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid); + +/** @brief Check if there are more than one Label UUID which hash has the specificed virtual + * address. + * + * @param addr Virtual address to check + * + * @return True if there is collision, false otherwise. + */ +bool bt_mesh_va_collision_check(uint16_t addr); + +/* Needed for storing va as indexes in persistent storage. */ +/** @brief Get Label UUID by index. + * + * @param idx Index of virtual address entry. + * + * @return Pointer to a valid Label UUID, or NULL if entry is not found. + */ +const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx); + +/** @brief Get virtual address entry index by Label UUID. + * + * @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid + * pointer. + * + * @param uuid Label UUID which index to find + * @param uuidx Pointer to a memory where to store index. + * + * @return 0 if entry is found, error code otherwise. + */ +int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx); + +/** @brief Store pending virtual address entries in the persistent storage.*/ +void bt_mesh_va_pending_store(void); + +/** @brief Remove all stored virtual addresses and remove them from the persistent storage. */ +void bt_mesh_va_clear(void); diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.c b/tests/bsim/bluetooth/mesh/src/mesh_test.c index 583e8eb86a59..cbbc7ac28a7e 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.c +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.c @@ -15,6 +15,8 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); +#include "common/bt_str.h" + /* Max number of messages that can be pending on RX at the same time */ #define RECV_QUEUE_SIZE 32 @@ -303,7 +305,7 @@ static struct bt_mesh_test_msg *blocking_recv(k_timeout_t timeout) return k_queue_get(&recv, timeout); } -int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout) +int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout) { struct bt_mesh_test_msg *msg = blocking_recv(timeout); @@ -321,6 +323,19 @@ int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout) return -EINVAL; } + if (BT_MESH_ADDR_IS_VIRTUAL(msg->ctx.recv_dst) && + ((uuid != NULL && msg->ctx.uuid == NULL) || + (uuid == NULL && msg->ctx.uuid != NULL) || + memcmp(uuid, msg->ctx.uuid, 16))) { + LOG_ERR("Recv: Label UUID mismatch for virtual address 0x%04x"); + if (uuid && msg->ctx.uuid) { + LOG_ERR("Got: %s", bt_hex(msg->ctx.uuid, 16)); + LOG_ERR("Expected: %s", bt_hex(uuid, 16)); + } + + return -EINVAL; + } + k_mem_slab_free(&msg_pool, (void **)&msg); return 0; @@ -390,7 +405,7 @@ static void tx_ended(int err, void *data) k_sem_give(&send_ctx->sem); } -int bt_mesh_test_send_async(uint16_t addr, size_t len, +int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, const struct bt_mesh_send_cb *send_cb, void *cb_data) @@ -403,6 +418,7 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len, test_send_ctx.addr = addr; test_send_ctx.send_rel = (flags & FORCE_SEGMENTATION); test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT; + test_send_ctx.uuid = uuid; BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_1, BT_MESH_TX_SDU_MAX); bt_mesh_model_msg_init(&buf, TEST_MSG_OP_1); @@ -441,11 +457,11 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len, return 0; } -int bt_mesh_test_send(uint16_t addr, size_t len, +int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, k_timeout_t timeout) { if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - return bt_mesh_test_send_async(addr, len, flags, NULL, NULL); + return bt_mesh_test_send_async(addr, uuid, len, flags, NULL, NULL); } static const struct bt_mesh_send_cb send_cb = { @@ -457,7 +473,7 @@ int bt_mesh_test_send(uint16_t addr, size_t len, int err; k_sem_init(&send_ctx.sem, 0, 1); - err = bt_mesh_test_send_async(addr, len, flags, &send_cb, &send_ctx); + err = bt_mesh_test_send_async(addr, uuid, len, flags, &send_cb, &send_ctx); if (err) { return err; } diff --git a/tests/bsim/bluetooth/mesh/src/mesh_test.h b/tests/bsim/bluetooth/mesh/src/mesh_test.h index ca28964dce39..d36f5cddeaff 100644 --- a/tests/bsim/bluetooth/mesh/src/mesh_test.h +++ b/tests/bsim/bluetooth/mesh/src/mesh_test.h @@ -141,13 +141,13 @@ void bt_mesh_test_timeout(bs_time_t HW_device_time); void bt_mesh_device_setup(const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp); -int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout); +int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout); int bt_mesh_test_recv_msg(struct bt_mesh_test_msg *msg, k_timeout_t timeout); int bt_mesh_test_recv_clear(void); -int bt_mesh_test_send(uint16_t addr, size_t len, +int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, k_timeout_t timeout); -int bt_mesh_test_send_async(uint16_t addr, size_t len, +int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len, enum bt_mesh_test_send_flags flags, const struct bt_mesh_send_cb *send_cb, void *cb_data); diff --git a/tests/bsim/bluetooth/mesh/src/test_friendship.c b/tests/bsim/bluetooth/mesh/src/test_friendship.c index 3411be4b5c6e..4e54aa74af69 100644 --- a/tests/bsim/bluetooth/mesh/src/test_friendship.c +++ b/tests/bsim/bluetooth/mesh/src/test_friendship.c @@ -6,6 +6,7 @@ #include "mesh_test.h" #include "mesh/net.h" #include "mesh/transport.h" +#include "mesh/va.h" #include #include "argparse.h" @@ -156,7 +157,7 @@ static void test_friend_msg(void) /* Send unsegmented message from friend to LPN: */ LOG_INF("Sending unsegmented message"); - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_SECONDS(1)), "Unseg send failed"); @@ -164,7 +165,7 @@ static void test_friend_msg(void) friend_wait_for_polls(2); /* Send segmented message */ - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 13, 0, + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 13, 0, K_SECONDS(1)), "Unseg send failed"); @@ -178,23 +179,23 @@ static void test_friend_msg(void) * transport and network parts of the second packet. * Ensures coverage for the regression reported in #32033. */ - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)), "Unseg send failed"); - ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), + ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)), "Unseg send failed"); /* Two messages require 2 polls plus the "no more messages" msg */ friend_wait_for_polls(3); - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(10)), + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(10)), "Receive from LPN failed"); /* Receive a segmented message from the LPN. LPN should poll for the ack * after sending the segments. */ - ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_SECONDS(10))); /* 4 polls (2 if legacy transport layer is used): * - The first one triggered manually by transport when sending segmented message; * - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages); @@ -227,13 +228,13 @@ static void test_friend_overflow(void) /* Fill the queue */ for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) { - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); } /* Add one more message, which should overflow the queue and cause the * first message to be discarded. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -246,12 +247,12 @@ static void test_friend_overflow(void) /* Make room in the Friend Queue for only one unsegmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 1), 0, K_SECONDS(1)), - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); /* This message should preempt the segmented one. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -266,17 +267,17 @@ static void test_friend_overflow(void) * message won't preempt this segmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2), 0, K_SECONDS(1)); - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); /* This segmented message should preempt the previous segmented message. */ bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), - BT_MESH_SDU_UNSEG_MAX * + NULL, BT_MESH_SDU_UNSEG_MAX * (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2), 0, K_SECONDS(1)); /* This message should fit in Friend Queue as well. */ - bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT); + bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(35)), @@ -295,7 +296,7 @@ static void test_friend_overflow(void) */ static void test_friend_group(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; bt_mesh_test_setup(); @@ -306,7 +307,7 @@ static void test_friend_group(void) "Friendship not established"); bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED); - ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr)); + ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va)); /* The other mesh device will send its messages in the first poll */ ASSERT_OK(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, @@ -317,10 +318,10 @@ static void test_friend_group(void) bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED); /* Send a group message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Send a virtual message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Wait for the LPN to poll for each message, then for adding the @@ -331,7 +332,7 @@ static void test_friend_group(void) /* Send a group message to an address the LPN added after the friendship * was established. */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(10)); @@ -410,7 +411,7 @@ static void test_lpn_msg_frnd(void) /* Receive unsegmented message */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1)), "Failed to receive message"); /* Give friend time to prepare the message */ @@ -418,7 +419,7 @@ static void test_lpn_msg_frnd(void) /* Receive segmented message */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); - ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, K_SECONDS(2)), + ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, NULL, K_SECONDS(2)), "Failed to receive message"); /* Give friend time to prepare the messages */ @@ -427,10 +428,10 @@ static void test_lpn_msg_frnd(void) /* Receive two unsegmented messages */ ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr, - K_SECONDS(2)), + NULL, K_SECONDS(2)), "Failed to receive message"); ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr, - K_SECONDS(2)), + NULL, K_SECONDS(2)), "Failed to receive message"); k_sleep(K_SECONDS(3)); @@ -438,7 +439,7 @@ static void test_lpn_msg_frnd(void) /* Send an unsegmented message to the friend. * Should not be affected by the LPN mode at all. */ - ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 5, 0, K_MSEC(500)), + ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 5, 0, K_MSEC(500)), "Send to friend failed"); k_sleep(K_SECONDS(5)); @@ -446,7 +447,7 @@ static void test_lpn_msg_frnd(void) /* Send a segmented message to the friend. Should trigger a poll for the * ack. */ - ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 15, 0, K_SECONDS(5)), + ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 15, 0, K_SECONDS(5)), "Send to friend failed"); PASS(); @@ -472,17 +473,18 @@ static void test_lpn_msg_mesh(void) /* Send an unsegmented message to a third mesh node. * Should not be affected by the LPN mode at all. */ - ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 5, 0, K_NO_WAIT), "Send to mesh failed"); + ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_NO_WAIT), + "Send to mesh failed"); /* Receive an unsegmented message back */ - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_FOREVER)); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER)); /* Send a segmented message to the mesh node. */ - ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 15, 0, K_FOREVER), + ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 15, 0, K_FOREVER), "Send to other failed"); /* Receive a segmented message back */ - ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_FOREVER)); + ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER)); /* Send an unsegmented message with friend credentials to a third mesh * node. The friend shall relay it. @@ -664,6 +666,7 @@ static void test_lpn_overflow(void) static void test_lpn_group(void) { struct bt_mesh_test_msg msg; + const struct bt_mesh_va *va; uint16_t vaddr; uint8_t status = 0; int err; @@ -683,6 +686,10 @@ static void test_lpn_group(void) FAIL("VA addr add failed with err %d status 0x%x", err, status); } + va = bt_mesh_va_find(test_va_uuid); + ASSERT_TRUE(va != NULL); + ASSERT_EQUAL(vaddr, va->addr); + bt_mesh_lpn_set(true); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED, K_SECONDS(5)), "LPN not established"); @@ -693,7 +700,7 @@ static void test_lpn_group(void) * start up first. */ k_sleep(K_MSEC(10)); - ASSERT_OK(bt_mesh_test_send(other_cfg.addr, 5, 0, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_SECONDS(1))); k_sleep(K_SECONDS(5)); ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); @@ -706,7 +713,8 @@ static void test_lpn_group(void) } ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1))); - if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != other_cfg.addr) { + if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != other_cfg.addr || + msg.ctx.uuid != va->uuid) { FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr, msg.ctx.recv_dst); } @@ -722,7 +730,7 @@ static void test_lpn_group(void) } ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1))); - if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != friend_cfg.addr) { + if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != friend_cfg.addr) { FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr, msg.ctx.recv_dst); } @@ -763,6 +771,7 @@ static void test_lpn_group(void) static void test_lpn_loopback(void) { struct bt_mesh_test_msg msg; + const struct bt_mesh_va *va; uint16_t vaddr; uint8_t status = 0; int err; @@ -782,6 +791,10 @@ static void test_lpn_loopback(void) FAIL("VA addr add failed with err %d status 0x%x", err, status); } + va = bt_mesh_va_find(test_va_uuid); + ASSERT_TRUE(va != NULL); + ASSERT_EQUAL(vaddr, va->addr); + bt_mesh_lpn_set(true); ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED, K_SECONDS(5)), @@ -791,12 +804,16 @@ static void test_lpn_loopback(void) k_sleep(K_SECONDS(1)); /* Loopback on unicast, shouldn't even leave the device */ - ASSERT_OK(bt_mesh_test_send_async(cfg->addr, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(cfg->addr, NULL, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1))); /* Loopback on group address, should not come back from the friend */ - ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, NULL, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, NULL, K_SECONDS(1))); + + /* Loopback on virtual address, should not come back from the friend */ + ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1))); ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); err = bt_mesh_test_recv_msg(&msg, K_SECONDS(2)); @@ -805,8 +822,8 @@ static void test_lpn_loopback(void) } /* Loopback on virtual address, should not come back from the friend */ - ASSERT_OK(bt_mesh_test_send_async(vaddr, 5, 0, NULL, NULL)); - ASSERT_OK(bt_mesh_test_recv(5, vaddr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL)); + ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1))); k_sleep(K_SECONDS(2)); @@ -844,27 +861,32 @@ static void test_other_msg(void) } /* Receive an unsegmented message from the LPN. */ - ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); /* Minor delay that allows LPN's adv to complete sending. */ k_sleep(K_SECONDS(2)); /* Send an unsegmented message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 5, 0, K_NO_WAIT), "Failed to send to LPN"); + ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 5, 0, K_NO_WAIT), + "Failed to send to LPN"); /* Receive a segmented message from the LPN. */ - ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); /* Minor delay that allows LPN's adv to complete sending. */ k_sleep(K_SECONDS(2)); /* Send a segmented message to the friend. */ - ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 15, 0, K_FOREVER), "Send to LPN failed"); + ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 15, 0, K_FOREVER), + "Send to LPN failed"); /* Receive an unsegmented message from the LPN, originally sent with * friend credentials. */ - ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, K_FOREVER), "Failed to receive from LPN"); + ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, NULL, K_FOREVER), + "Failed to receive from LPN"); PASS(); } @@ -874,20 +896,20 @@ static void test_other_msg(void) */ static void test_other_group(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr)); + ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va)); /* Wait for LPN to send us a message after establishing the friendship */ - ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1))); + ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1))); /* Send a group message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); /* Send a virtual message to the LPN */ - ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)), "Failed to send to LPN"); PASS(); diff --git a/tests/bsim/bluetooth/mesh/src/test_iv_index.c b/tests/bsim/bluetooth/mesh/src/test_iv_index.c index 8c0dde73071c..466f0fb7b56b 100644 --- a/tests/bsim/bluetooth/mesh/src/test_iv_index.c +++ b/tests/bsim/bluetooth/mesh/src/test_iv_index.c @@ -134,7 +134,8 @@ static void test_ivu_deferring(void) atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; - ASSERT_OK(bt_mesh_test_send_async(0x0002, 20, FORCE_SEGMENTATION, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(0x0002, NULL, 20, FORCE_SEGMENTATION, &async_send_cb, + &sem)); ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE)); ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)); diff --git a/tests/bsim/bluetooth/mesh/src/test_scanner.c b/tests/bsim/bluetooth/mesh/src/test_scanner.c index aaccd84cec48..12557b7e1b2a 100644 --- a/tests/bsim/bluetooth/mesh/src/test_scanner.c +++ b/tests/bsim/bluetooth/mesh/src/test_scanner.c @@ -185,7 +185,7 @@ static void test_rx_invalid_packet(void) } /* Verify that test data is received correct. */ - err = bt_mesh_test_recv(10, cfg->addr, K_SECONDS(10)); + err = bt_mesh_test_recv(10, cfg->addr, NULL, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed receiving with valid ad_type"); PASS(); diff --git a/tests/bsim/bluetooth/mesh/src/test_transport.c b/tests/bsim/bluetooth/mesh/src/test_transport.c index a6be16c58c9a..8da83c0df3b2 100644 --- a/tests/bsim/bluetooth/mesh/src/test_transport.c +++ b/tests/bsim/bluetooth/mesh/src/test_transport.c @@ -6,8 +6,18 @@ #include "mesh_test.h" #include "mesh/net.h" #include "mesh/transport.h" +#include "mesh/va.h" #include +#include "mesh/crypto.h" + +#define LOG_MODULE_NAME test_transport + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include "common/bt_str.h" + /* * Transport layer tests: * This file contains tests for sending and receiving messages end-to-end in @@ -121,7 +131,7 @@ static void test_tx_unicast(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(rx_cfg.addr, test_vector[i].len, + err = bt_mesh_test_send(rx_cfg.addr, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -138,7 +148,7 @@ static void test_tx_group(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len, + err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -150,19 +160,19 @@ static void test_tx_group(void) */ static void test_tx_va(void) { - uint16_t virtual_addr; + const struct bt_mesh_va *va; int err; bt_mesh_test_setup(); - err = bt_mesh_va_add(test_va_uuid, &virtual_addr); + err = bt_mesh_va_add(test_va_uuid, &va); ASSERT_OK_MSG(err, "Virtual addr add failed (err %d)", err); /* Wait for the receiver to subscribe on address. */ k_sleep(K_SECONDS(1)); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(virtual_addr, test_vector[i].len, + err = bt_mesh_test_send(va->addr, va->uuid, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed sending vector %d", i); } @@ -179,10 +189,10 @@ static void test_tx_loopback(void) bt_mesh_test_setup(); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(cfg->addr, test_vector[i].len, test_vector[i].flags, + err = bt_mesh_test_send(cfg->addr, NULL, test_vector[i].len, test_vector[i].flags, K_NO_WAIT); ASSERT_OK_MSG(err, "Failed sending vector %d", i); - bt_mesh_test_recv(test_vector[i].len, cfg->addr, K_SECONDS(1)); + bt_mesh_test_recv(test_vector[i].len, cfg->addr, NULL, K_SECONDS(1)); if (test_stats.received != i + 1) { FAIL("Didn't receive message %d", i); @@ -219,10 +229,10 @@ static void test_tx_unknown_app(void) test_send_ctx.app_idx = 1; - ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 5, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 5, 0, K_SECONDS(1)), "Failed sending unsegmented"); - ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 25, 0, K_SECONDS(1)), + ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 25, 0, K_SECONDS(1)), "Failed sending segmented"); PASS(); @@ -247,7 +257,7 @@ static void test_tx_loopback_group(void) err, status); for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { - err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len, + err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len, test_vector[i].flags, K_SECONDS(20)); @@ -255,7 +265,7 @@ static void test_tx_loopback_group(void) k_sleep(K_SECONDS(1)); ASSERT_OK_MSG(bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR, - K_SECONDS(1)), + NULL, K_SECONDS(1)), "Failed receiving loopback %d", i); if (test_stats.received != i + 1) { @@ -277,11 +287,11 @@ static void test_tx_seg_block(void) bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT)); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT)); /* Send some more to the same address before the first is finished. */ - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT)); - ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT)); + ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_SECONDS(10))); if (test_stats.sent != 3) { FAIL("Not all messages completed (%u/3)", test_stats.sent); @@ -303,10 +313,10 @@ static void test_tx_seg_concurrent(void) k_sem_init(&sem, 0, 1); bt_mesh_test_setup(); - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 20, 0, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 20, 0, &async_send_cb, &sem)); /* Send some more to the same address before the first is finished. */ - ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, 20, 0, K_SECONDS(10))); + ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, NULL, 20, 0, K_SECONDS(10))); /* Ensure that the first message finishes as well */ ASSERT_OK(k_sem_take(&sem, K_SECONDS(1))); @@ -336,7 +346,7 @@ static void test_tx_seg_ivu(void) iv_index = BT_MESH_NET_IVI_TX; - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb, + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb, &sem)); /* Start IV update */ bt_mesh_iv_update(); @@ -347,7 +357,7 @@ static void test_tx_seg_ivu(void) k_sem_take(&sem, K_SECONDS(20)); - ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb, + ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb, &sem)); /* End IV update */ @@ -377,7 +387,7 @@ static void test_tx_seg_fail(void) bt_mesh_test_setup(); expected_send_err = -ETIMEDOUT; - ASSERT_OK(bt_mesh_test_send_async(0x0fff, 20, 0, &async_send_cb, &sem)); + ASSERT_OK(bt_mesh_test_send_async(0x0fff, NULL, 20, 0, &async_send_cb, &sem)); ASSERT_OK(k_sem_take(&sem, K_SECONDS(10))); PASS(); @@ -396,7 +406,7 @@ static void test_rx_unicast(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, cfg->addr, - K_SECONDS(10)); + NULL, K_SECONDS(10)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -418,7 +428,7 @@ static void test_rx_group(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR, - K_SECONDS(20)); + NULL, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -441,7 +451,7 @@ static void test_rx_va(void) for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { err = bt_mesh_test_recv(test_vector[i].len, virtual_addr, - K_SECONDS(20)); + test_va_uuid, K_SECONDS(20)); ASSERT_OK_MSG(err, "Failed receiving vector %d", i); } @@ -471,9 +481,9 @@ static void test_rx_seg_block(void) { bt_mesh_test_setup(); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); PASS(); } @@ -496,8 +506,8 @@ static void test_rx_seg_concurrent(void) * Note: The receive order is technically irrelevant, but the test_recv * function fails if the order is wrong. */ - ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, NULL, K_SECONDS(2)), "RX fail"); PASS(); } @@ -509,8 +519,8 @@ static void test_rx_seg_ivu(void) bt_mesh_test_setup(); rx_sar_conf(); - ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail"); - ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail"); + ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail"); PASS(); } From 98f27db189736390b87e335817a5ac66bd4c7159 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 19:05:19 +0200 Subject: [PATCH 0290/2042] tests: bsim: bluetooth: mesh: Test persistent storage of virtual addrs Test that: - virtual addresses in subscription list and publication states are stored and restored correctly - virtual addresses with collisions are stored and restored correctly Signed-off-by: Pavel Vasilyev --- tests/bsim/bluetooth/mesh/overlay_pst.conf | 2 +- tests/bsim/bluetooth/mesh/prj.conf | 2 +- tests/bsim/bluetooth/mesh/prj_mesh1d1.conf | 2 +- .../bluetooth/mesh/src/test_persistence.c | 88 +++++++++++++++---- 4 files changed, 75 insertions(+), 19 deletions(-) diff --git a/tests/bsim/bluetooth/mesh/overlay_pst.conf b/tests/bsim/bluetooth/mesh/overlay_pst.conf index 87fa5b6c40e7..a79faccee23f 100644 --- a/tests/bsim/bluetooth/mesh/overlay_pst.conf +++ b/tests/bsim/bluetooth/mesh/overlay_pst.conf @@ -7,7 +7,7 @@ CONFIG_BT_PERIPHERAL=y CONFIG_BT_MESH_GATT_PROXY=y CONFIG_BT_MESH_PB_GATT=y -CONFIG_BT_MESH_MODEL_GROUP_COUNT=2 +CONFIG_BT_MESH_MODEL_GROUP_COUNT=4 CONFIG_BT_MESH_CDB_NODE_COUNT=3 CONFIG_BT_MESH_CDB_SUBNET_COUNT=2 CONFIG_BT_MESH_SUBNET_COUNT=2 diff --git a/tests/bsim/bluetooth/mesh/prj.conf b/tests/bsim/bluetooth/mesh/prj.conf index ab15e1a136c7..2e55a6a588bc 100644 --- a/tests/bsim/bluetooth/mesh/prj.conf +++ b/tests/bsim/bluetooth/mesh/prj.conf @@ -33,7 +33,7 @@ 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=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 diff --git a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf index 769848ad634b..302ff522c131 100644 --- a/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf +++ b/tests/bsim/bluetooth/mesh/prj_mesh1d1.conf @@ -34,7 +34,7 @@ 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=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 diff --git a/tests/bsim/bluetooth/mesh/src/test_persistence.c b/tests/bsim/bluetooth/mesh/src/test_persistence.c index a054a423f40a..e5391d1c770b 100644 --- a/tests/bsim/bluetooth/mesh/src/test_persistence.c +++ b/tests/bsim/bluetooth/mesh/src/test_persistence.c @@ -53,6 +53,9 @@ static uint8_t test_prov_devkey[16] = { 0x11 }; #define TEST_VA_1_ADDR 0x8700 #define TEST_VA_1_UUID (uint8_t[16]) { 0xdf, 0xca, 0xa3, 0x54, 0x23, 0xfa, 0x33, 0xed, \ 0x1a, 0xbe, 0xa0, 0xaa, 0xbd, 0xfa, 0x0f, 0xaf } +#define TEST_VA_1_ADDR_COL 0x8700 +#define TEST_VA_1_UUID_COL (uint8_t[16]) { 0x01, 0xcc, 0x74, 0x51, 0x71, 0x9e, 0x56, 0x71, \ + 0x5b, 0x8a, 0x18, 0xaf, 0x13, 0x86, 0x0e, 0x4a } #define TEST_APPKEY_0_IDX 0x12 #define TEST_APPKEY_0_KEY { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \ @@ -81,6 +84,26 @@ static uint8_t test_prov_devkey[16] = { 0x11 }; .transmit = BT_MESH_TRANSMIT(2, 20), \ } +#define TEST_MOD_PUB_PARAMS_2 { \ + .addr = TEST_GROUP_1, \ + .uuid = NULL, \ + .app_idx = TEST_APPKEY_1_IDX, \ + .cred_flag = false, \ + .ttl = 3, \ + .period = BT_MESH_PUB_PERIOD_10SEC(3), \ + .transmit = BT_MESH_TRANSMIT(3, 20), \ + } + +#define TEST_VND_MOD_PUB_PARAMS_2 { \ + .addr = TEST_VA_1_ADDR, \ + .uuid = TEST_VA_1_UUID, \ + .app_idx = TEST_APPKEY_0_IDX, \ + .cred_flag = false, \ + .ttl = 3, \ + .period = BT_MESH_PUB_PERIOD_10SEC(2), \ + .transmit = BT_MESH_TRANSMIT(3, 20), \ + } + #define DISABLED_MOD_PUB_PARAMS { \ .addr = 0, \ .uuid = NULL, \ @@ -119,7 +142,8 @@ static const struct access_cfg access_cfgs[][2] = { { .pub_params = TEST_MOD_PUB_PARAMS, .appkeys_count = 2, .appkeys = { TEST_APPKEY_0_IDX, TEST_APPKEY_1_IDX }, - .subs_count = 2, .subs = { TEST_GROUP_0, TEST_VA_0_ADDR }, + .subs_count = 4, .subs = { TEST_GROUP_0, TEST_VA_0_ADDR, TEST_VA_1_ADDR, + TEST_VA_1_ADDR /* collision */ }, .mod_data_len = sizeof(test_mod_data), }, @@ -127,7 +151,8 @@ static const struct access_cfg access_cfgs[][2] = { { .pub_params = TEST_VND_MOD_PUB_PARAMS, .appkeys_count = 2, .appkeys = { TEST_APPKEY_0_IDX, TEST_APPKEY_1_IDX }, - .subs_count = 2, .subs = { TEST_GROUP_0, TEST_VA_0_ADDR }, + .subs_count = 4, .subs = { TEST_GROUP_0, TEST_VA_0_ADDR, TEST_VA_1_ADDR, + TEST_VA_1_ADDR /* collision */ }, .mod_data_len = sizeof(vnd_test_mod_data), }, }, @@ -135,7 +160,7 @@ static const struct access_cfg access_cfgs[][2] = { [NEW_SUBS] = { /* SIG model. */ { - .pub_params = TEST_MOD_PUB_PARAMS, + .pub_params = TEST_MOD_PUB_PARAMS_2, .appkeys_count = 2, .appkeys = { TEST_APPKEY_0_IDX, TEST_APPKEY_1_IDX }, .subs_count = 1, .subs = { TEST_GROUP_0 }, .mod_data_len = sizeof(test_mod_data), @@ -143,7 +168,7 @@ static const struct access_cfg access_cfgs[][2] = { /* Vendor model. */ { - .pub_params = TEST_VND_MOD_PUB_PARAMS, + .pub_params = TEST_VND_MOD_PUB_PARAMS_2, .appkeys_count = 2, .appkeys = { TEST_APPKEY_0_IDX, TEST_APPKEY_1_IDX }, .subs_count = 1, .subs = { TEST_VA_0_ADDR }, .mod_data_len = sizeof(vnd_test_mod_data), @@ -533,12 +558,23 @@ static void node_configure(void) FAIL("Mod sub add failed (err %d, status %u)", err, status); } - err = bt_mesh_cfg_cli_mod_sub_va_add(test_netkey_idx, TEST_ADDR, TEST_ADDR, TEST_VA_0_UUID, - TEST_MOD_ID, &va, &status); - if (err || status) { - FAIL("Mod sub add failed (err %d, status %u)", err, status); + struct { + const uint8_t *uuid; + uint16_t addr; + } va_subs[] = { + { .uuid = TEST_VA_0_UUID, .addr = TEST_VA_0_ADDR, }, + { .uuid = TEST_VA_1_UUID, .addr = TEST_VA_1_ADDR, }, + { .uuid = TEST_VA_1_UUID_COL, .addr = TEST_VA_1_ADDR, }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(va_subs); i++) { + err = bt_mesh_cfg_cli_mod_sub_va_add(test_netkey_idx, TEST_ADDR, TEST_ADDR, + va_subs[i].uuid, TEST_MOD_ID, &va, &status); + if (err || status) { + FAIL("Mod sub add failed (err %d, status %u)", err, status); + } + ASSERT_EQUAL(va_subs[i].addr, va); } - ASSERT_EQUAL(TEST_VA_0_ADDR, va); memcpy(&pub_params, &(struct bt_mesh_cfg_cli_mod_pub)TEST_MOD_PUB_PARAMS, sizeof(struct bt_mesh_cfg_cli_mod_pub)); @@ -571,15 +607,16 @@ static void node_configure(void) FAIL("Mod sub add failed (err %d, status %u)", err, status); } - err = bt_mesh_cfg_cli_mod_sub_va_add_vnd(test_netkey_idx, TEST_ADDR, TEST_ADDR, - TEST_VA_0_UUID, TEST_VND_MOD_ID, - TEST_VND_COMPANY_ID, &va, &status); - if (err || status) { - FAIL("Mod sub add failed (err %d, status %u)", err, status); + for (size_t i = 0; i < ARRAY_SIZE(va_subs); i++) { + err = bt_mesh_cfg_cli_mod_sub_va_add_vnd(test_netkey_idx, TEST_ADDR, TEST_ADDR, + va_subs[i].uuid, TEST_VND_MOD_ID, + TEST_VND_COMPANY_ID, &va, &status); + if (err || status) { + FAIL("Mod sub add failed (err %d, status %u)", err, status); + } + ASSERT_EQUAL(va_subs[i].addr, va); } - ASSERT_EQUAL(TEST_VA_0_ADDR, va); - memcpy(&pub_params, &(struct bt_mesh_cfg_cli_mod_pub)TEST_VND_MOD_PUB_PARAMS, sizeof(struct bt_mesh_cfg_cli_mod_pub)); err = bt_mesh_cfg_cli_mod_pub_set_vnd(test_netkey_idx, TEST_ADDR, TEST_ADDR, @@ -696,6 +733,7 @@ static void test_access_data_load(void) static void test_access_sub_overwrite(void) { + struct bt_mesh_cfg_cli_mod_pub pub_params; uint16_t va; uint8_t status; int err; @@ -713,6 +751,15 @@ static void test_access_sub_overwrite(void) FAIL("Mod sub overwrite failed (err %d, status %u)", err, status); } + memcpy(&pub_params, &(struct bt_mesh_cfg_cli_mod_pub)TEST_MOD_PUB_PARAMS_2, + sizeof(struct bt_mesh_cfg_cli_mod_pub)); + err = bt_mesh_cfg_cli_mod_pub_set(test_netkey_idx, TEST_ADDR, TEST_ADDR, TEST_MOD_ID, + &pub_params, &status); + if (err || status) { + FAIL("Mod pub set failed (err %d, status %u)", err, status); + } + + /* Vendor model. */ err = bt_mesh_cfg_cli_mod_sub_va_overwrite_vnd(test_netkey_idx, TEST_ADDR, TEST_ADDR, TEST_VA_0_UUID, TEST_VND_MOD_ID, TEST_VND_COMPANY_ID, &va, &status); @@ -721,6 +768,15 @@ static void test_access_sub_overwrite(void) } ASSERT_EQUAL(TEST_VA_0_ADDR, va); + memcpy(&pub_params, &(struct bt_mesh_cfg_cli_mod_pub)TEST_VND_MOD_PUB_PARAMS_2, + sizeof(struct bt_mesh_cfg_cli_mod_pub)); + err = bt_mesh_cfg_cli_mod_pub_set_vnd(test_netkey_idx, TEST_ADDR, TEST_ADDR, + TEST_VND_MOD_ID, TEST_VND_COMPANY_ID, &pub_params, + &status); + if (err || status) { + FAIL("Mod pub set failed (err %d, status %u)", err, status); + } + k_sleep(K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT)); PASS(); From 45369f78ede05a9d2836e8118119a6846caf1a54 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 19:07:06 +0200 Subject: [PATCH 0291/2042] tests: bsim: bluetooth: mesh: Test tran to virtual addr with collision Test that transport layer correctly encrypts and decrypts messages to virtual addresses with collision. Signed-off-by: Pavel Vasilyev --- .../bsim/bluetooth/mesh/src/test_transport.c | 76 +++++++++++++++++++ .../tests_scripts/transport/va_collision.sh | 11 +++ 2 files changed, 87 insertions(+) create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh diff --git a/tests/bsim/bluetooth/mesh/src/test_transport.c b/tests/bsim/bluetooth/mesh/src/test_transport.c index 8da83c0df3b2..cb1e33fc8489 100644 --- a/tests/bsim/bluetooth/mesh/src/test_transport.c +++ b/tests/bsim/bluetooth/mesh/src/test_transport.c @@ -57,6 +57,18 @@ static const struct bt_mesh_test_cfg rx_cfg = { static int expected_send_err; +static uint8_t test_va_col_uuid[][16] = { + { + 0xe3, 0x94, 0xe7, 0xc1, 0xc5, 0x14, 0x72, 0x11, + 0x68, 0x36, 0x19, 0x30, 0x99, 0x34, 0x53, 0x62 + }, + { + 0x5e, 0x49, 0x5a, 0xd9, 0x44, 0xdf, 0xae, 0xc0, + 0x62, 0xd8, 0x0d, 0xed, 0x16, 0x82, 0xd1, 0x7d + }, +}; +static const uint16_t test_va_col_addr = 0x809D; + static void test_tx_init(void) { bt_mesh_test_cfg_set(&tx_cfg, WAIT_TIME); @@ -180,6 +192,37 @@ static void test_tx_va(void) PASS(); } +/** Test sending the test vector using virtual addresses with collision. + */ +static void test_tx_va_collision(void) +{ + const struct bt_mesh_va *va[ARRAY_SIZE(test_va_col_uuid)]; + int err; + + bt_mesh_test_setup(); + + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + err = bt_mesh_va_add(test_va_col_uuid[i], &va[i]); + ASSERT_OK_MSG(err, "Virtual addr add failed (err %d)", err); + ASSERT_EQUAL(test_va_col_addr, va[i]->addr); + } + + /* Wait for the receiver to subscribe on address. */ + k_sleep(K_SECONDS(1)); + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + for (int j = 0; j < ARRAY_SIZE(test_va_col_uuid); j++) { + LOG_INF("Sending msg #%d to %s addr", i, (j == 0 ? "first" : "second")); + + err = bt_mesh_test_send(test_va_col_addr, va[j]->uuid, test_vector[i].len, + test_vector[i].flags, K_SECONDS(20)); + ASSERT_OK_MSG(err, "Failed sending vector %d", i); + } + } + + PASS(); +} + /** Test sending of messages to own unicast address using the test vector. */ static void test_tx_loopback(void) @@ -458,6 +501,36 @@ static void test_rx_va(void) PASS(); } +/** @brief Receive the test vector using virtual addresses with collision. + */ +static void test_rx_va_collision(void) +{ + uint16_t virtual_addr; + uint8_t status; + int err; + + bt_mesh_test_setup(); + + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + err = bt_mesh_cfg_cli_mod_sub_va_add(0, cfg->addr, cfg->addr, test_va_col_uuid[i], + TEST_MOD_ID, &virtual_addr, &status); + ASSERT_OK_MSG(err || status, "Sub add failed (err %d, status %u)", err, status); + ASSERT_EQUAL(test_va_col_addr, virtual_addr); + } + + for (int i = 0; i < ARRAY_SIZE(test_vector); i++) { + for (int j = 0; j < ARRAY_SIZE(test_va_col_uuid); j++) { + LOG_INF("Recv msg #%d from %s addr", i, (j == 0 ? "first" : "second")); + + err = bt_mesh_test_recv(test_vector[i].len, test_va_col_addr, + test_va_col_uuid[j], K_SECONDS(20)); + ASSERT_OK_MSG(err, "Failed receiving vector %d", i); + } + } + + PASS(); +} + /** @brief Verify that this device doesn't receive any messages. */ static void test_rx_none(void) @@ -538,6 +611,7 @@ static const struct bst_test_instance test_connect[] = { TEST_CASE(tx, unicast, "Transport: send to unicast addr"), TEST_CASE(tx, group, "Transport: send to group addr"), TEST_CASE(tx, va, "Transport: send to virtual addr"), + TEST_CASE(tx, va_collision, "Transport: send to virtual addr"), TEST_CASE(tx, loopback, "Transport: send loopback"), TEST_CASE(tx, loopback_group, "Transport: send loopback and group"), TEST_CASE(tx, unknown_app, "Transport: send with unknown app key"), @@ -549,10 +623,12 @@ static const struct bst_test_instance test_connect[] = { TEST_CASE(rx, unicast, "Transport: receive on unicast addr"), TEST_CASE(rx, group, "Transport: receive on group addr"), TEST_CASE(rx, va, "Transport: receive on virtual addr"), + TEST_CASE(rx, va_collision, "Transport: receive on virtual addr"), TEST_CASE(rx, none, "Transport: receive no messages"), TEST_CASE(rx, seg_block, "Transport: receive blocked segmented"), TEST_CASE(rx, seg_concurrent, "Transport: receive concurrent segmented"), TEST_CASE(rx, seg_ivu, "Transport: receive segmented during IV update"), + BSTEST_END_MARKER }; diff --git a/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh new file mode 100755 index 000000000000..9259b02f5ffd --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/transport/va_collision.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +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 From 6bb97cc417773866d822c4b78761aabe46f665cc Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 14 May 2023 19:08:37 +0200 Subject: [PATCH 0292/2042] tests: bsim: bluetooth: mesh: Test friendship subs virtual addrs coll Test that LPN correctly sends Friend Subscription List Add and Remove messages to Friend when subscribed and unsubscribed to virtual addresses wirth collision. Signed-off-by: Pavel Vasilyev --- .../bsim/bluetooth/mesh/src/test_friendship.c | 204 +++++++++++++++++- .../friendship/msg_va_collision.sh | 30 +++ 2 files changed, 233 insertions(+), 1 deletion(-) create mode 100755 tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh diff --git a/tests/bsim/bluetooth/mesh/src/test_friendship.c b/tests/bsim/bluetooth/mesh/src/test_friendship.c index 4e54aa74af69..64942e7f3409 100644 --- a/tests/bsim/bluetooth/mesh/src/test_friendship.c +++ b/tests/bsim/bluetooth/mesh/src/test_friendship.c @@ -23,7 +23,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); */ #define GROUP_ADDR 0xc000 -#define WAIT_TIME 60 /*seconds*/ +#define WAIT_TIME 70 /*seconds*/ #define LPN_ADDR_START 0x0003 #define POLL_TIMEOUT_MS (100 * CONFIG_BT_MESH_LPN_POLL_TIMEOUT) @@ -39,6 +39,14 @@ static const struct bt_mesh_test_cfg other_cfg = { }; static struct bt_mesh_test_cfg lpn_cfg; +static uint8_t test_va_col_uuid[][16] = { + { 0xe3, 0x94, 0xe7, 0xc1, 0xc5, 0x14, 0x72, 0x11, + 0x68, 0x36, 0x19, 0x30, 0x99, 0x34, 0x53, 0x62 }, + { 0x5e, 0x49, 0x5a, 0xd9, 0x44, 0xdf, 0xae, 0xc0, + 0x62, 0xd8, 0x0d, 0xed, 0x16, 0x82, 0xd1, 0x7d }, +}; +static uint16_t test_va_col_addr = 0x809D; + static void test_common_init(const struct bt_mesh_test_cfg *cfg) { bt_mesh_test_friendship_init(CONFIG_BT_MESH_FRIEND_LPN_COUNT); @@ -358,6 +366,79 @@ static void test_friend_no_est(void) PASS(); } +/** Send messages to 2 virtual addresses with collision and check that LPN correctly polls them. + */ +static void test_friend_va_collision(void) +{ + const struct bt_mesh_va *va[2]; + + bt_mesh_test_setup(); + + bt_mesh_friend_set(BT_MESH_FEATURE_ENABLED); + + ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_ESTABLISHED, + K_SECONDS(5)), + "Friendship not established"); + bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED); + + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + ASSERT_OK(bt_mesh_va_add(test_va_col_uuid[i], &va[i])); + ASSERT_EQUAL(test_va_col_addr, va[i]->addr); + } + + bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(10)); + + LOG_INF("Step 1: Sending msgs to LPN."); + + /* LPN shall receive the first 2 messages. */ + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + /* Send a message to the first virtual address. LPN should receive it. */ + ASSERT_OK_MSG(bt_mesh_test_send(test_va_col_addr, va[i]->uuid, 5, 0, K_SECONDS(1)), + "Failed to send to LPN"); + } + /* One poll per message + Friend Update with md == 0 */ + friend_wait_for_polls(3); + + LOG_INF("Let LPN unsubscribe from the first address."); + + /* Manual poll by LPN test case after removing the first Label UUID from subscription. */ + friend_wait_for_polls(1); + + LOG_INF("Step 2: Sending msgs to LPN."); + + /* Friend will send both messages as the virtual address is the same, but LPN shall + * receive only the second message. + */ + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + ASSERT_OK_MSG(bt_mesh_test_send(test_va_col_addr, va[i]->uuid, 5, 0, K_SECONDS(1)), + "Failed to send to LPN"); + } + /* One poll per message + Friend Update with md == 0 */ + friend_wait_for_polls(3); + + LOG_INF("Let LPN unsubscribe from the second address."); + + /* Manual poll by LPN test case after removing the second Label UUID from subscription. + * After this step, the virtual address shall be removed from the subscription list. + */ + friend_wait_for_polls(1); + + LOG_INF("Step 3: Sending msgs to LPN."); + + /* Friend shall not send the messages to LPN because it is not subscribed to any virtual + * address. + */ + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + ASSERT_OK_MSG(bt_mesh_test_send(test_va_col_addr, va[i]->uuid, 5, 0, K_SECONDS(1)), + "Failed to send to LPN"); + } + /* Shall be only one Friend Poll as the Friend Queue is empty. */ + friend_wait_for_polls(1); + + PASS(); +} + + /* LPN test functions */ /** Enable the LPN role, and verify that the friendship is established. @@ -954,6 +1035,125 @@ static void test_lpn_term_cb_check(void) PASS(); } +/** Test that LPN sends only one Subscription List Add and only one Subscription List Remove message + * to Friend when LPN is subscribed to 2 virtual addresses with collision. + */ +static void test_lpn_va_collision(void) +{ + struct bt_mesh_test_msg msg; + const struct bt_mesh_va *va[2]; + uint16_t vaddr; + uint8_t status = 0; + int err; + + bt_mesh_test_setup(); + + /* Subscripbe LPN on both virtual address with collision. */ + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + err = bt_mesh_cfg_cli_mod_sub_va_add(0, cfg->addr, cfg->addr, test_va_col_uuid[i], + TEST_MOD_ID, &vaddr, &status); + if (err || status) { + FAIL("VA addr add failed with err %d status 0x%x", err, status); + } + + ASSERT_EQUAL(test_va_col_addr, vaddr); + + va[i] = bt_mesh_va_find(test_va_col_uuid[i]); + ASSERT_TRUE(va[i] != NULL); + ASSERT_EQUAL(vaddr, va[i]->addr); + } + + bt_mesh_lpn_set(true); + ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED, + K_SECONDS(5)), "LPN not established"); + bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_LPN_POLLED); + + LOG_INF("Step 1: Waiting for msgs from Friend"); + + /* Let Friend prepare messages and the poll them. */ + k_sleep(K_SECONDS(3)); + ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); + /* LPN shall receive both messages. */ + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(10))); + if (msg.ctx.recv_dst != va[i]->addr || + msg.ctx.uuid != va[i]->uuid || + msg.ctx.addr != friend_cfg.addr) { + FAIL("Unexpected message: 0x%04x -> 0x%04x, uuid: %p", msg.ctx.addr, + msg.ctx.recv_dst, msg.ctx.uuid); + } + } + /* Wait for the extra poll timeout in friend_wait_for_polls(). */ + k_sleep(K_SECONDS(3)); + + LOG_INF("Unsubscribing from the first address."); + + /* Remove the first virtual address from subscription and poll messages from Friend. This + * call shall not generate Friend Subscription List Remove message because LPN is still + * subscribed to another Label UUID with the same virtual address. + */ + err = bt_mesh_cfg_cli_mod_sub_va_del(0, cfg->addr, cfg->addr, test_va_col_uuid[0], + TEST_MOD_ID, &vaddr, &status); + if (err || status) { + FAIL("Virtual addr add failed with err %d status 0x%x", err, status); + } + ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); + /* Wait for the extra poll timeout in friend_wait_for_polls(). */ + k_sleep(K_SECONDS(3)); + + LOG_INF("Step 2: Waiting for msgs from Friend"); + + /* LPN will still receive both messages as the virtual address is the same for both Label + * UUIDs, but the first message shall not be decrypted and shall be dropped. + */ + ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); + ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1))); + if (msg.ctx.recv_dst != va[1]->addr || msg.ctx.uuid != va[1]->uuid || + msg.ctx.addr != friend_cfg.addr) { + FAIL("Unexpected message: 0x%04x -> 0x%04x, uuid: %p", msg.ctx.addr, + msg.ctx.recv_dst, msg.ctx.uuid); + } + + /* Check that there are no more messages from Friend. */ + err = bt_mesh_test_recv_msg(&msg, K_SECONDS(1)); + if (!err) { + FAIL("Unexpected message: 0x%04x -> 0x%04x, uuid: %p", msg.ctx.addr, + msg.ctx.recv_dst, msg.ctx.uuid); + } + /* Wait for the extra poll timeout in friend_wait_for_polls(). */ + k_sleep(K_SECONDS(3)); + + LOG_INF("Unsubscribing from the second address."); + + /* Unsubscribe from the second address. Now there are no subscriptions to the same virtual + * address. LPN shall send Subscription List Remove message. + */ + err = bt_mesh_cfg_cli_mod_sub_va_del(0, cfg->addr, cfg->addr, test_va_col_uuid[1], + TEST_MOD_ID, &vaddr, &status); + if (err || status) { + FAIL("Virtual addr del failed with err %d status 0x%x", err, status); + } + ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); + /* Wait for the extra poll timeout in friend_wait_for_polls(). */ + k_sleep(K_SECONDS(3)); + + LOG_INF("Step 3: Waiting for msgs from Friend"); + + /* As now there shall be no virtual addresses in the subscription list, Friend Queue shall + * be empty. + */ + ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed"); + for (int i = 0; i < ARRAY_SIZE(test_va_col_uuid); i++) { + err = bt_mesh_test_recv_msg(&msg, K_SECONDS(1)); + if (!err) { + FAIL("Unexpected message: 0x%04x -> 0x%04x, uuid: %p", msg.ctx.addr, + msg.ctx.recv_dst, msg.ctx.uuid); + } + } + + PASS(); +} + #define TEST_CASE(role, name, description) \ { \ .test_id = "friendship_" #role "_" #name, \ @@ -970,6 +1170,7 @@ static const struct bst_test_instance test_connect[] = { TEST_CASE(friend, overflow, "Friend: message queue overflow"), TEST_CASE(friend, group, "Friend: send to group addrs"), TEST_CASE(friend, no_est, "Friend: do not establish friendship"), + TEST_CASE(friend, va_collision, "Friend: send to virtual addrs with collision"), TEST_CASE(lpn, est, "LPN: establish friendship"), TEST_CASE(lpn, msg_frnd, "LPN: message exchange with friend"), @@ -981,6 +1182,7 @@ static const struct bst_test_instance test_connect[] = { TEST_CASE(lpn, loopback, "LPN: send to loopback addrs"), TEST_CASE(lpn, disable, "LPN: disable LPN"), TEST_CASE(lpn, term_cb_check, "LPN: no terminate cb trigger"), + TEST_CASE(lpn, va_collision, "LPN: receive on virtual addrs with collision"), TEST_CASE(other, msg, "Other mesh device: message exchange"), TEST_CASE(other, group, "Other mesh device: send to group addrs"), 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 new file mode 100755 index 000000000000..a1f0d1863238 --- /dev/null +++ b/tests/bsim/bluetooth/mesh/tests_scripts/friendship/msg_va_collision.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source $(dirname "${BASH_SOURCE[0]}")/../../_mesh_test.sh + +# Test that LPN sends only one Subscription List Add and only one Subscription List Remove message +# to Friend when LPN is subscribed to 2 virtual addresses with collision. +# Test scenario: +# 1. LPN subscribes a model to 2 virtual addresses with collision and sends single Friend +# Subscription List Add message to its friend. +# 2. Step 1: +# 2.1. Friend sends a message to each virtual address, LPN receives both messages. +# 3. Step 2: +# 3.1. LPN unsubscribes from one of the virtual addresses. At this step no Friend Subscription +# Remove messages are sent from LPN to its friend. +# 3.2. Friend sends a message to each virtual address. LPN receives both, but successfully decrypts +# only one message, which it is still subscribed to. +# 4. Step 3: +# 4.1. LPN unsubscribes from the second virtual address and sends Friend Subscription Remove message +# to its friend. +# 4.2. Friend sends a message to each virtual address, but non of them are received by LPN. +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 From 47e3c5386ab4b58ea8b8b58c513f72098c80b80a Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 1 Jun 2023 14:59:45 +0200 Subject: [PATCH 0293/2042] Bluetooth: Mesh: Add option to disable Label UUIDs recovery After adding support for virtual addresses with collision (where two Label UUIDs have the same virtual address), the format of the data in the persistent storage with the Label UUIDs which a model is subscribed to or publishes to has been changed. The recovery code is added and the Label UUIDs will be recovered by picking first Label UUID matching to the virtual address in the subscription list or model publication. This options can disable the recovery code and save some flash if the recovery is not required (e.g. virtual address support wasn't enabled before this option was added, or the devices were unprovisioned before upgrading to the version with this option). Making this option as deprecated to be able to drop support of this option and remove the recovery code eventually. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 15 ++++++++++++++ subsys/bluetooth/mesh/access.c | 38 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 84683871c4ee..4f2438b9bbe5 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -347,6 +347,21 @@ config BT_MESH_LABEL_COUNT help This option specifies how many Label UUIDs can be stored. +config BT_MESH_LABEL_NO_RECOVER + bool "[DEPRECATED] Don't recover Label UUIDs from groups address subscription list" + select DEPRECATED + depends on BT_MESH_LABEL_COUNT > 0 + help + After adding support for virtual addresses with collision (where two Label UUIDs have the + same virtual address), the format of the data in the persistent storage with the Label + UUIDs which a model is subscribed to or publishes to has been changed. The recovery + code is added and the Label UUIDs will be recovered by picking first Label UUID matching + to the virtual address in the subscription list or model publication. This options can + disable the recovery code and save some flash if the recovery is not required (e.g. + virtual address support wasn't enabled before this option was added, or the devices were + unprovisioned before upgrading to the version with this option). The option is marked as + deprecated to remove the recovery code eventually. + config BT_MESH_CRPL int "Maximum capacity of the replay protection list" default 10 diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 483e7dcc0283..6e577768d98c 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -1650,7 +1650,7 @@ static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd, LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0])); -#if CONFIG_BT_MESH_LABEL_COUNT > 0 +#if !IS_ENABLED(CONFIG_BT_MESH_LABEL_NO_RECOVER) && (CONFIG_BT_MESH_LABEL_COUNT > 0) /* If uuids[0] is NULL, then either the model is not subscribed to virtual addresses or * uuids are not yet recovered. */ @@ -1739,25 +1739,27 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd, return 0; } - err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub.base)); - if (!err) { - /* Recover from implementation where uuid was not stored for virtual address. It - * is safe to pick first matched label because previously the stack wasn't able - * to store virtual addresses with collisions. - */ - if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { - mod->pub->uuid = bt_mesh_va_uuid_get(pub.base.addr, NULL, NULL); - } + if (!IS_ENABLED(CONFIG_BT_MESH_LABEL_NO_RECOVER)) { + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub.base)); + if (!err) { + /* Recover from implementation where uuid was not stored for virtual + * address. It is safe to pick first matched label because previously the + * stack wasn't able to store virtual addresses with collisions. + */ + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { + mod->pub->uuid = bt_mesh_va_uuid_get(pub.base.addr, NULL, NULL); + } - goto pub_base_set; - } else { - err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); - if (err) { - LOG_ERR("Failed to set \'model-pub\'"); - return err; + goto pub_base_set; } } + err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub)); + if (err) { + LOG_ERR("Failed to set \'model-pub\'"); + return err; + } + if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) { mod->pub->uuid = bt_mesh_va_get_uuid_by_idx(pub.uuidx); } @@ -2008,9 +2010,7 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) (void)bt_mesh_va_get_idx_by_uuid(mod->pub->uuid, &pub.uuidx); } - err = settings_save_one(path, &pub, - BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr) ? sizeof(pub) : - sizeof(pub.base)); + err = settings_save_one(path, &pub, sizeof(pub)); } if (err) { From 6c10da79570ad15b65b254e4f7f6b7740de03ae0 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Sun, 4 Dec 2022 00:46:56 -0600 Subject: [PATCH 0294/2042] drivers: sensor: introduce driver for TCN75A temperature sensor Add driver for TCN75A temperature sensor. The following features are supported: - TCN75A oneshot mode, which allows single shot conversions with lower power consumtion - Resolution selection, up to 12 bit resolution (9 bit default) - Triggering based on temperatue thresholds. If the TCN75A exits a set threshold range, the application can be notified via a callback. Signed-off-by: Daniel DeGrasse --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/tcn75a/CMakeLists.txt | 6 + drivers/sensor/tcn75a/Kconfig | 50 ++++++ drivers/sensor/tcn75a/tcn75a.c | 135 ++++++++++++++ drivers/sensor/tcn75a/tcn75a.h | 83 +++++++++ drivers/sensor/tcn75a/tcn75a_trigger.c | 203 ++++++++++++++++++++++ dts/bindings/sensor/microchip,tcn75a.yaml | 42 +++++ 8 files changed, 521 insertions(+) create mode 100644 drivers/sensor/tcn75a/CMakeLists.txt create mode 100644 drivers/sensor/tcn75a/Kconfig create mode 100644 drivers/sensor/tcn75a/tcn75a.c create mode 100644 drivers/sensor/tcn75a/tcn75a.h create mode 100644 drivers/sensor/tcn75a/tcn75a_trigger.c create mode 100644 dts/bindings/sensor/microchip,tcn75a.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index d13ac7e56eb4..4aac5ac9f2ed 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -120,6 +120,7 @@ add_subdirectory_ifdef(CONFIG_SX9500 sx9500) add_subdirectory_ifdef(CONFIG_TACH_IT8XXX2 ite_tach_it8xxx2) add_subdirectory_ifdef(CONFIG_TACH_NPCX nuvoton_tach_npcx) add_subdirectory_ifdef(CONFIG_TACH_XEC mchp_tach_xec) +add_subdirectory_ifdef(CONFIG_TCN75A tcn75a) add_subdirectory_ifdef(CONFIG_TCS3400 tcs3400) add_subdirectory_ifdef(CONFIG_TEMP_KINETIS nxp_kinetis_temp) add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 838bdf1a988c..a91ea8824bd0 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -178,6 +178,7 @@ source "drivers/sensor/stm32_vbat/Kconfig" source "drivers/sensor/stm32_vref/Kconfig" source "drivers/sensor/stts751/Kconfig" source "drivers/sensor/sx9500/Kconfig" +source "drivers/sensor/tcn75a/Kconfig" source "drivers/sensor/tcs3400/Kconfig" source "drivers/sensor/th02/Kconfig" source "drivers/sensor/ti_hdc/Kconfig" diff --git a/drivers/sensor/tcn75a/CMakeLists.txt b/drivers/sensor/tcn75a/CMakeLists.txt new file mode 100644 index 000000000000..51bfb4b3ae6d --- /dev/null +++ b/drivers/sensor/tcn75a/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(tcn75a.c) +zephyr_library_sources_ifdef(CONFIG_TCN75A_TRIGGER tcn75a_trigger.c) diff --git a/drivers/sensor/tcn75a/Kconfig b/drivers/sensor/tcn75a/Kconfig new file mode 100644 index 000000000000..7a7c37572be4 --- /dev/null +++ b/drivers/sensor/tcn75a/Kconfig @@ -0,0 +1,50 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +config TCN75A + bool "TCN75A Ambient Temperature Sensor" + default y + depends on DT_HAS_MICROCHIP_TCN75A_ENABLED + select I2C + help + Enable TCN75A ambient temperature to digital converter + +if TCN75A + +choice + prompt "TCN75A Trigger mode" + default TCN75A_TRIGGER_NONE + +config TCN75A_TRIGGER_NONE + bool "No trigger" + +config TCN75A_TRIGGER_OWN_THREAD + bool "Use own thread" + select TCN75A_TRIGGER + +config TCN75A_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + select TCN75A_TRIGGER + +endchoice + +config TCN75A_TRIGGER + bool + help + Enable interrupt based trigger support for TCN75A. Requires that + the sensor be set to continuous sample mode. + +if TCN75A_TRIGGER_OWN_THREAD + +config TCN75A_THREAD_PRIORITY + int "Own thread priority" + default 10 + +config TCN75A_THREAD_STACK_SIZE + int "Own thread stack size" + default 1024 + +endif # TCN75A_TRIGGER_OWN_THREAD + + +endif # TCN75A diff --git a/drivers/sensor/tcn75a/tcn75a.c b/drivers/sensor/tcn75a/tcn75a.c new file mode 100644 index 000000000000..c9594efcfa74 --- /dev/null +++ b/drivers/sensor/tcn75a/tcn75a.c @@ -0,0 +1,135 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_tcn75a + +#include +LOG_MODULE_REGISTER(tcn75a, CONFIG_SENSOR_LOG_LEVEL); + +#include "tcn75a.h" + +int tcn75a_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct tcn75a_config *config = dev->config; + struct tcn75a_data *data = dev->data; + int ret; + uint8_t temp_reg = TCN75A_TEMP_REG; + uint8_t rx_buf[2]; + uint8_t adc_conf[2] = {TCN75A_CONFIG_REG, 0x0}; + /* This sensor only supports ambient temperature */ + if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_AMBIENT_TEMP)) { + return -ENOTSUP; + } + + if (config->oneshot_mode) { + /* Oneshot mode, requires one shot bit to be set in config register */ + adc_conf[1] = TCN75A_CONFIG_ONEDOWN; + ret = i2c_write_dt(&config->i2c_spec, adc_conf, 2); + if (ret < 0) { + return ret; + } + } + + /* Fetch a sample from the 2 byte ambient temperature register */ + ret = i2c_write_read_dt(&config->i2c_spec, &temp_reg, sizeof(temp_reg), + rx_buf, sizeof(rx_buf)); + if (ret < 0) { + return ret; + } + + data->temp_sample = sys_get_be16(rx_buf); + LOG_DBG("Raw sample: 0x%04x", data->temp_sample); + + return ret; +} + +static int tcn75a_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct tcn75a_data *data = dev->data; + uint32_t temp_lsb; + + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + + /* Convert fixed point to sensor value */ + val->val1 = data->temp_sample >> TCN75A_TEMP_MSB_POS; + temp_lsb = (data->temp_sample & TCN75A_TEMP_LSB_MASK); + val->val2 = TCN75A_FIXED_PT_TO_SENSOR(temp_lsb); + return 0; +} + +static const struct sensor_driver_api tcn75a_api = { + .sample_fetch = &tcn75a_sample_fetch, + .channel_get = &tcn75a_channel_get, +#ifdef CONFIG_TCN75A_TRIGGER + .attr_get = &tcn75a_attr_get, + .attr_set = &tcn75a_attr_set, + .trigger_set = &tcn75a_trigger_set, +#endif +}; + +static int tcn75a_init(const struct device *dev) +{ + const struct tcn75a_config *config = dev->config; + uint8_t adc_conf[2] = {TCN75A_CONFIG_REG, 0x0}; + + if (!i2c_is_ready_dt(&config->i2c_spec)) { + LOG_ERR("I2C bus is not ready"); + return -ENODEV; + } + + /* Set user selected resolution */ + adc_conf[1] |= TCN75A_CONFIG_RES(config->resolution); + + if (config->oneshot_mode) { + if (adc_conf[1] != 0) { + /* Oneshot mode only supports 9 bit resolution */ + LOG_ERR("Oneshot mode requires 9 bit resolution"); + return -ENODEV; + } + adc_conf[1] |= TCN75A_CONFIG_SHUTDOWN; + } + +#ifdef CONFIG_TCN75A_TRIGGER + /* If user supplies an ALERT gpio, assume they want trigger support. */ + if (config->alert_gpios.port != NULL) { + int ret; + + if (config->oneshot_mode) { + LOG_ERR("Oneshot mode not supported with trigger"); + return -ENODEV; + } + + ret = tcn75a_trigger_init(dev); + if (ret < 0) { + return ret; + } + } +#endif + + return i2c_write_dt(&config->i2c_spec, adc_conf, 2); +} + +#ifdef CONFIG_TCN75A_TRIGGER +#define TCN75A_TRIGGER(n) .alert_gpios = GPIO_DT_SPEC_INST_GET_OR(n, alert_gpios, {}), +#else +#define TCN75A_TRIGGER(n) +#endif + +#define TCN75A_INIT(n) \ + static struct tcn75a_data tcn75a_data_##n; \ + static const struct tcn75a_config tcn75a_config_##n = { \ + .i2c_spec = I2C_DT_SPEC_INST_GET(n), \ + .resolution = DT_INST_ENUM_IDX(n, resolution), \ + .oneshot_mode = DT_INST_PROP(n, oneshot_mode), \ + TCN75A_TRIGGER(n) \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(n, &tcn75a_init, NULL, &tcn75a_data_##n, &tcn75a_config_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &tcn75a_api); + +DT_INST_FOREACH_STATUS_OKAY(TCN75A_INIT) diff --git a/drivers/sensor/tcn75a/tcn75a.h b/drivers/sensor/tcn75a/tcn75a.h new file mode 100644 index 000000000000..56b0a9a71250 --- /dev/null +++ b/drivers/sensor/tcn75a/tcn75a.h @@ -0,0 +1,83 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _DRIVERS_SENSOR_TCN75A_H_ +#define _DRIVERS_SENSOR_TCN75A_H_ + +#include +#include +#include +#include + +#define TCN75A_TEMP_REG 0x0 +#define TCN75A_CONFIG_REG 0x1 +#define TCN75A_THYST_REG 0x2 +#define TCN75A_TSET_REG 0x3 + +/* TCN75A TEMP register constants */ +#define TCN75A_TEMP_MSB_POS 8 +#define TCN75A_TEMP_MSB_MASK 0xFF00 +#define TCN75A_TEMP_LSB_MASK 0xFF +#define TCN75A_TEMP_LSB_POS 0 + +/* TCN75A CONFIG register constants */ +#define TCN75A_CONFIG_ONEDOWN BIT(7) +#define TCN75A_CONFIG_RES(x) (((x) & 0x3) << 5) +#define TCN75A_CONFIG_INT_EN 0x2 +#define TCN75A_CONFIG_SHUTDOWN 0x1 + +struct tcn75a_config { + struct i2c_dt_spec i2c_spec; + bool oneshot_mode; + uint8_t resolution; +#ifdef CONFIG_TCN75A_TRIGGER + struct gpio_dt_spec alert_gpios; +#endif +}; + +struct tcn75a_data { + uint16_t temp_sample; +#ifdef CONFIG_TCN75A_TRIGGER + const struct device *dev; + struct gpio_callback gpio_cb; + sensor_trigger_handler_t sensor_cb; + const struct sensor_trigger *sensor_trig; +#endif +#ifdef CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD + struct k_work work; +#endif +#ifdef CONFIG_TCN75A_TRIGGER_OWN_THREAD + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TCN75A_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem trig_sem; +#endif +}; + +/* Helpers to convert from TCN75A temperature fixed point format + * to sensor val2 format. When the LSB of the TCN75A temperature sample + * is treated as an integer, the format to convert to sensor val2 is + * FIXED_POINT_VAL * 3906.25 + */ +#define TCN75A_FIXED_PT_TO_SENSOR(x) (((x)*3906) + ((x) >> 2)) +/* This conversion is imprecise, but because the 4 least significant bits + * of the temperature register aren't used, it doesn't matter. + */ +#define TCN75A_SENSOR_TO_FIXED_PT(x) ((x) / 3906) + +#ifdef CONFIG_TCN75A_TRIGGER + +int tcn75a_trigger_init(const struct device *dev); +int tcn75a_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + struct sensor_value *val); + +int tcn75a_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + const struct sensor_value *val); +int tcn75a_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +#endif +int tcn75a_sample_fetch(const struct device *dev, enum sensor_channel chan); + +#endif /* _DRIVERS_SENSOR_TCN75A_H_ */ diff --git a/drivers/sensor/tcn75a/tcn75a_trigger.c b/drivers/sensor/tcn75a/tcn75a_trigger.c new file mode 100644 index 000000000000..90f6932a9e04 --- /dev/null +++ b/drivers/sensor/tcn75a/tcn75a_trigger.c @@ -0,0 +1,203 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_DECLARE(tcn75a, CONFIG_SENSOR_LOG_LEVEL); + +#include "tcn75a.h" + +int tcn75a_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct tcn75a_config *config = dev->config; + struct tcn75a_data *data = dev->data; + int ret; + + if (trig->type != SENSOR_TRIG_THRESHOLD) { + return -ENOTSUP; + } + + if ((trig->chan != SENSOR_CHAN_ALL) && (trig->chan != SENSOR_CHAN_AMBIENT_TEMP)) { + return -ENOTSUP; + } + + data->sensor_cb = handler; + data->sensor_trig = trig; + + /* TCN75A starts in comparator mode by default, switch it to + * use interrupt mode. + */ + ret = i2c_reg_update_byte_dt(&config->i2c_spec, TCN75A_CONFIG_REG, TCN75A_CONFIG_INT_EN, + TCN75A_CONFIG_INT_EN); + if (ret < 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->alert_gpios, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + return ret; + } + + return ret; +} + +int tcn75a_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + const struct sensor_value *val) +{ + const struct tcn75a_config *config = dev->config; + uint8_t tx_buf[3]; + + if ((chan != SENSOR_CHAN_AMBIENT_TEMP) && (chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_LOWER_THRESH: + tx_buf[0] = TCN75A_THYST_REG; + break; + case SENSOR_ATTR_UPPER_THRESH: + tx_buf[0] = TCN75A_TSET_REG; + break; + default: + return -ENOTSUP; + } + + /* Convert sensor val to fixed point */ + tx_buf[1] = (uint8_t)val->val1; + tx_buf[2] = TCN75A_SENSOR_TO_FIXED_PT(val->val2); + + LOG_DBG("Writing 0x%02X to limit reg %s", *(uint16_t *)(tx_buf + 1), + tx_buf[0] == TCN75A_THYST_REG ? "THYST" : "TSET"); + + return i2c_write_dt(&config->i2c_spec, tx_buf, 3); +} + +int tcn75a_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, + struct sensor_value *val) +{ + const struct tcn75a_config *config = dev->config; + uint8_t config_reg; + uint8_t rx_buf[2]; + uint16_t limit, temp_lsb; + int ret; + + if ((chan != SENSOR_CHAN_AMBIENT_TEMP) && (chan != SENSOR_CHAN_ALL)) { + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_LOWER_THRESH: + config_reg = TCN75A_THYST_REG; + break; + case SENSOR_ATTR_UPPER_THRESH: + config_reg = TCN75A_TSET_REG; + break; + default: + return -ENOTSUP; + } + + ret = i2c_write_read_dt(&config->i2c_spec, &config_reg, 1, rx_buf, 2); + if (ret < 0) { + return ret; + } + + limit = sys_get_be16(rx_buf); + + LOG_DBG("Read 0x%02X from %s", limit, config_reg == TCN75A_THYST_REG ? "THYST" : "TSET"); + + /* Convert fixed point to sensor value */ + val->val1 = limit >> TCN75A_TEMP_MSB_POS; + temp_lsb = (limit & TCN75A_TEMP_LSB_MASK); + val->val2 = TCN75A_FIXED_PT_TO_SENSOR(temp_lsb); + + return ret; +} + +static void tcn75a_handle_int(const struct device *dev) +{ + struct tcn75a_data *data = dev->data; + /* Note that once the temperature rises + * above T_SET, the sensor will not trigger another interrupt until + * it falls below T_HYST (or vice versa for falling below T_HYST). + * + * Reading from any register will de-assert the interrupt. + */ + + if (data->sensor_cb) { + data->sensor_cb(dev, data->sensor_trig); + } +} + +static void tcn75a_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pin_mask) +{ + struct tcn75a_data *data = CONTAINER_OF(cb, struct tcn75a_data, gpio_cb); + const struct tcn75a_config *config = data->dev->config; + + if ((pin_mask & BIT(config->alert_gpios.pin)) == 0U) { + return; + } + +#if defined(CONFIG_TCN75A_TRIGGER_OWN_THREAD) + k_sem_give(&data->trig_sem); +#elif defined(CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +#ifdef CONFIG_TCN75A_TRIGGER_OWN_THREAD +static void tcn75a_thread_main(struct tcn75a_data *data) +{ + while (true) { + k_sem_take(&data->trig_sem, K_FOREVER); + tcn75a_handle_int(data->dev); + } +} +#endif + +#ifdef CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD +static void tcn75a_work_handler(struct k_work *work) +{ + struct tcn75a_data *data = CONTAINER_OF(work, struct tcn75a_data, work); + + tcn75a_handle_int(data->dev); +} +#endif + +int tcn75a_trigger_init(const struct device *dev) +{ + const struct tcn75a_config *config = dev->config; + struct tcn75a_data *data = dev->data; + int ret; + + /* Save config pointer */ + data->dev = dev; + + if (!gpio_is_ready_dt(&config->alert_gpios)) { + LOG_ERR("alert GPIO device is not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->alert_gpios, GPIO_INPUT); + if (ret < 0) { + return ret; + } + + gpio_init_callback(&data->gpio_cb, tcn75a_gpio_callback, BIT(config->alert_gpios.pin)); + + ret = gpio_add_callback(config->alert_gpios.port, &data->gpio_cb); + +#if defined(CONFIG_TCN75A_TRIGGER_OWN_THREAD) + k_sem_init(&data->trig_sem, 0, K_SEM_MAX_LIMIT); + k_thread_create(&data->thread, data->thread_stack, CONFIG_TCN75A_THREAD_STACK_SIZE, + (k_thread_entry_t)tcn75a_thread_main, data, NULL, NULL, + K_PRIO_COOP(CONFIG_TCN75A_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD) + data->work.handler = tcn75a_work_handler; +#endif + + return ret; +} diff --git a/dts/bindings/sensor/microchip,tcn75a.yaml b/dts/bindings/sensor/microchip,tcn75a.yaml new file mode 100644 index 000000000000..ab635dd203ea --- /dev/null +++ b/dts/bindings/sensor/microchip,tcn75a.yaml @@ -0,0 +1,42 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +description: TCN75A ambient temperature sensor + +compatible: "microchip,tcn75a" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + alert-gpios: + type: phandle-array + description: | + ALERT pin + This pin defaults to active low when produced by the sensor. + The property value should ensure the gpio flags properly describe + the signal that is presented to the driver. Required in order to use + triggering support. + + resolution: + type: string + default: "9-bit" + enum: + - "9-bit" + - "10-bit" + - "11-bit" + - "12-bit" + description: | + Sensor resolution. Higher resolutions will result in longer conversion + times. Note: datasheet's claim about the ambient temperature register: + > When the 0.5°C, 0.25°C or 0.125°C resolutions are selected, + > bit 6, bit 7 or bit 8 will remain clear <0>, + > respectively. + appears to be incorrect. Only conversion times seem to be affected by + resolution selection. + + oneshot-mode: + type: boolean + description: | + Oneshot sampling mode. Reduces power consumption, but disables triggering + feature as well as high resolution sampling. Only supported with 9 bit + resolution. From d3828418c09b2f35463da841a893798bc4ab9ce7 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Sun, 14 May 2023 00:42:42 -0500 Subject: [PATCH 0295/2042] tests: drivers: build_all: add TCN75A to sensor build test Add TCN75A temperature sensor to sensor build all test, along with configuration setting to enable driver to use a separate thread for triggering Signed-off-by: Daniel DeGrasse --- tests/drivers/build_all/sensor/i2c.dtsi | 6 ++++++ tests/drivers/build_all/sensor/sensors_trigger_global.conf | 1 + tests/drivers/build_all/sensor/sensors_trigger_none.conf | 1 + tests/drivers/build_all/sensor/sensors_trigger_own.conf | 1 + 4 files changed, 9 insertions(+) diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 4023fc88ffd6..454712b74fe7 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -745,3 +745,9 @@ test_i2c_tcs3400: tcs3400@72 { reg = <0x72>; int-gpios = <&test_gpio 0 0>; }; + +test_tcn75a: tcn75a@73 { + compatible = "microchip,tcn75a"; + reg = <0x73>; + alert-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 ac5299f78d48..28b1663f1bce 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -44,6 +44,7 @@ CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD=y CONFIG_SM351LT_TRIGGER_GLOBAL_THREAD=y CONFIG_STTS751_TRIGGER_GLOBAL_THREAD=y CONFIG_SX9500_TRIGGER_GLOBAL_THREAD=y +CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD=y CONFIG_TMD2620_TRIGGER_GLOBAL_THREAD=y CONFIG_TMP007_TRIGGER_GLOBAL_THREAD=y CONFIG_VCNL4040_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 1653cb486c03..6fffb6ef623a 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -44,6 +44,7 @@ CONFIG_SHT3XD_TRIGGER_NONE=y CONFIG_SM351LT_TRIGGER_NONE=y CONFIG_STTS751_TRIGGER_NONE=y CONFIG_SX9500_TRIGGER_NONE=y +CONFIG_TCN75A_TRIGGER_NONE=y CONFIG_TMD2620_TRIGGER_NONE=y CONFIG_TMP007_TRIGGER_NONE=y CONFIG_VCNL4040_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 83c5680648ec..f3bb63056727 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -42,6 +42,7 @@ CONFIG_SHT3XD_TRIGGER_OWN_THREAD=y CONFIG_SM351LT_TRIGGER_OWN_THREAD=y CONFIG_STTS751_TRIGGER_OWN_THREAD=y CONFIG_SX9500_TRIGGER_OWN_THREAD=y +CONFIG_TCN75A_TRIGGER_OWN_THREAD=y CONFIG_TMP007_TRIGGER_OWN_THREAD=y CONFIG_VCNL4040_TRIGGER_OWN_THREAD=y CONFIG_WSEN_HIDS_TRIGGER_OWN_THREAD=y From 7993e7d1b09b5bd9cb3383dada84151cde6e64f3 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Sun, 14 May 2023 14:13:34 -0500 Subject: [PATCH 0296/2042] samples: sensor: thermometer: add trigger support to sample Add optional trigger support to sample. If the selected temperature sensor supports triggering using the AMBIENT_TEMP channel, then temperature thresholds will be set for +0.5 and +1.5 degrees celsius above ambient temperature. Sample overlays are provided for the FRDM_K22F board to demonstrate enabling this feature. Signed-off-by: Daniel DeGrasse --- samples/sensor/thermometer/README.rst | 32 ++++-- .../sensor/thermometer/boards/frdm_k22f.conf | 2 + .../thermometer/boards/frdm_k22f.overlay | 24 +++++ samples/sensor/thermometer/sample.yaml | 2 +- samples/sensor/thermometer/src/main.c | 98 +++++++++++++++++-- 5 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 samples/sensor/thermometer/boards/frdm_k22f.conf create mode 100644 samples/sensor/thermometer/boards/frdm_k22f.overlay diff --git a/samples/sensor/thermometer/README.rst b/samples/sensor/thermometer/README.rst index 4fe7e6b29838..e37ad7b016b0 100644 --- a/samples/sensor/thermometer/README.rst +++ b/samples/sensor/thermometer/README.rst @@ -39,17 +39,31 @@ alias named ``ambient-temp0`` to link to the node. See the overlay used for the ``nrf52840dk_nrf52840`` board within this sample: ``boards/nrf52840dk_nrf52840.overlay`` + +Temperature Alert +================= + +If the attached sensor supports alerts when the temperature drifts above or +below a threshold, the sample will enable the sensor's trigger functionality. +This will require the sensor's TRIGGER KConfig setting to be enabled. An +example of this setup is provided for the ``frdm_k22f`` board, using +``boards/frdm_k22f.conf``. + Sample Output ============= .. code-block:: console - *** Booting Zephyr OS build zephyr-v3.3.0-1205-g118f73e12a70 *** - Thermometer Example (arm) - Temperature device is 0x6150, name is mcp9700a - Temperature is 24.0°C - Temperature is 24.1°C - Temperature is 24.2°C - Temperature is 24.1°C - Temperature is 24.0°C - Temperature is 24.1°C + *** Booting Zephyr OS build zephyr-v3.3.0-2354-gb4f4bd1f1c22 *** + Thermometer Example (arm) + Temperature device is 0x525c, name is tcn75a@48 + Set temperature lower limit to 25.5°C + Set temperature upper limit to 26.5°C + Enabled sensor threshold triggers + Temperature is 25.0°C + Temperature is 25.0°C + Temperature is 25.0°C + Temperature is 25.0°C + Temperature is 25.5°C + Temperature above threshold: 26.5°C + Temperature is 26.5°C diff --git a/samples/sensor/thermometer/boards/frdm_k22f.conf b/samples/sensor/thermometer/boards/frdm_k22f.conf new file mode 100644 index 000000000000..015ae0095ae6 --- /dev/null +++ b/samples/sensor/thermometer/boards/frdm_k22f.conf @@ -0,0 +1,2 @@ +# Enable trigger support +CONFIG_TCN75A_TRIGGER_GLOBAL_THREAD=y diff --git a/samples/sensor/thermometer/boards/frdm_k22f.overlay b/samples/sensor/thermometer/boards/frdm_k22f.overlay new file mode 100644 index 000000000000..8124dce61797 --- /dev/null +++ b/samples/sensor/thermometer/boards/frdm_k22f.overlay @@ -0,0 +1,24 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + ambient-temp0 = &temp_sensor; + }; +}; + +/* + * Note- TCN75A is not present on the FRDM-K22F eval board, and must be + * wired to i2c0 and PTC2 externally + */ +&i2c0 { + temp_sensor: tcn75a@48 { + reg = <0x48>; + compatible = "microchip,tcn75a"; + alert-gpios = <&gpioc 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + resolution = "10-bit"; + }; +}; diff --git a/samples/sensor/thermometer/sample.yaml b/samples/sensor/thermometer/sample.yaml index 5f5f12dda146..64a4de64380c 100644 --- a/samples/sensor/thermometer/sample.yaml +++ b/samples/sensor/thermometer/sample.yaml @@ -6,4 +6,4 @@ tests: harness: sensor integration_platforms: - nrf52840dk_nrf52840 - platform_allow: nrf52840dk_nrf52840 + platform_allow: nrf52840dk_nrf52840 frdm_k22f diff --git a/samples/sensor/thermometer/src/main.c b/samples/sensor/thermometer/src/main.c index 7175ee612c83..e561223e6f38 100644 --- a/samples/sensor/thermometer/src/main.c +++ b/samples/sensor/thermometer/src/main.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2016 ARM Ltd. * Copyright (c) 2023 FTP Technologies + * Copyright (c) 2023 Daniel DeGrasse * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,11 +10,58 @@ #include #include +static double high_temp; +static double low_temp; + +int read_temperature(const struct device *dev, struct sensor_value *val) +{ + int ret; + + ret = sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP); + if (ret < 0) { + printf("Could not fetch temperature: %d\n", ret); + return ret; + } + + ret = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, val); + if (ret < 0) { + printf("Could not get temperature: %d\n", ret); + } + return ret; +} + +void temp_alert_handler(const struct device *dev, const struct sensor_trigger *trig) +{ + int ret; + struct sensor_value value; + double temp; + + /* Read sensor value */ + ret = read_temperature(dev, &value); + if (ret < 0) { + printf("Reading temperature failed: %d\n", ret); + return; + } + temp = sensor_value_to_double(&value); + if (temp <= low_temp) { + printf("Temperature below threshold: %0.1f°C\n", temp); + } else if (temp >= high_temp) { + printf("Temperature above threshold: %0.1f°C\n", temp); + } else { + printf("Error: temperature alert triggered without valid condition\n"); + } +} + int main(void) { const struct device *const dev = DEVICE_DT_GET(DT_ALIAS(ambient_temp0)); struct sensor_value value; + double temp; int ret; + const struct sensor_trigger trig = { + .chan = SENSOR_CHAN_AMBIENT_TEMP, + .type = SENSOR_TRIG_THRESHOLD, + }; printf("Thermometer Example (%s)\n", CONFIG_ARCH); @@ -24,16 +72,50 @@ int main(void) printf("Temperature device is %p, name is %s\n", dev, dev->name); - while (1) { - ret = sensor_sample_fetch(dev); - if (ret != 0) { - printf("Sensor fetch failed: %d\n", ret); - break; - } + /* First, fetch a sensor sample to use for sensor thresholds */ + ret = read_temperature(dev, &value); + if (ret != 0) { + printf("Failed to read temperature: %d\n", ret); + return ret; + } + temp = sensor_value_to_double(&value); - ret = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &value); + /* Set thresholds to +0.5 and +1.5 °C from ambient */ + low_temp = temp + 0.5; + ret = sensor_value_from_double(&value, low_temp); + if (ret != 0) { + printf("Failed to convert low threshold to sensor value: %d\n", ret); + return ret; + } + ret = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, + SENSOR_ATTR_LOWER_THRESH, &value); + if (ret == 0) { + /* This sensor supports threshold triggers */ + printf("Set temperature lower limit to %0.1f°C\n", low_temp); + } + + high_temp = temp + 1.5; + ret = sensor_value_from_double(&value, high_temp); + if (ret != 0) { + printf("Failed to convert low threshold to sensor value: %d\n", ret); + return ret; + } + ret = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP, + SENSOR_ATTR_UPPER_THRESH, &value); + if (ret == 0) { + /* This sensor supports threshold triggers */ + printf("Set temperature upper limit to %0.1f°C\n", high_temp); + } + + ret = sensor_trigger_set(dev, &trig, temp_alert_handler); + if (ret == 0) { + printf("Enabled sensor threshold triggers\n"); + } + + while (1) { + ret = read_temperature(dev, &value); if (ret != 0) { - printf("Sensor get failed: %d\n", ret); + printf("Failed to read temperature: %d\n", ret); break; } From 88f4353ce133a6bc46026084b726f1efb366f763 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Thu, 18 May 2023 12:52:41 +0200 Subject: [PATCH 0297/2042] dts: bindings: interrupt-controller: GIC: Update description When the GIC driver was originally introduced, it was only used on Cortex-R SoCs. However, this is not the case anymore. Update the description to reflect that this driver is not specific to Cortex-R. Signed-off-by: Piotr Wojnarowski --- dts/bindings/interrupt-controller/arm,gic.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/interrupt-controller/arm,gic.yaml b/dts/bindings/interrupt-controller/arm,gic.yaml index 5dae97f34219..edca13ba6db5 100644 --- a/dts/bindings/interrupt-controller/arm,gic.yaml +++ b/dts/bindings/interrupt-controller/arm,gic.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2018 Marvell # SPDX-License-Identifier: Apache-2.0 -description: ARMv7-R Generic Interrupt Controller +description: ARM Generic Interrupt Controller compatible: "arm,gic" From 2f5ac45e53775bb57dcd9a5ee30992e44d95a9eb Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:35:23 +0200 Subject: [PATCH 0298/2042] dts: bindings: interrupt-controller: GIC: Allow specifying version in DT Currently, only the presence of a GIC is reflected in the device tree, and its version must be set separately in each SoC's Kconfig. This patch adds separate bindings for each GIC version whose presence in the device tree automatically enables the corresponding Kconfig symbol. Signed-off-by: Piotr Wojnarowski --- drivers/interrupt_controller/Kconfig.gic | 18 +++++++++++++++--- .../interrupt-controller/arm,gic-v1.yaml | 7 +++++++ .../interrupt-controller/arm,gic-v2.yaml | 7 +++++++ .../interrupt-controller/arm,gic-v3.yaml | 7 +++++++ 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 dts/bindings/interrupt-controller/arm,gic-v1.yaml create mode 100644 dts/bindings/interrupt-controller/arm,gic-v2.yaml create mode 100644 dts/bindings/interrupt-controller/arm,gic-v3.yaml diff --git a/drivers/interrupt_controller/Kconfig.gic b/drivers/interrupt_controller/Kconfig.gic index 483e3a5e73bb..bab59a6ee37d 100644 --- a/drivers/interrupt_controller/Kconfig.gic +++ b/drivers/interrupt_controller/Kconfig.gic @@ -8,26 +8,38 @@ if CPU_CORTEX config GIC bool +# Selecting these symbols directly is deprecated: the GIC architecture version +# should be specified by adding the appropriate compat (for example arm,gic-v2) +# to the DT. config GIC_V1 - bool + def_bool DT_HAS_ARM_GIC_V1_ENABLED select GIC + select DEPRECATED if !DT_HAS_ARM_GIC_V1_ENABLED help The ARM Generic Interrupt Controller v1 (e.g. PL390) works with the ARM Cortex-family processors. + Selecting this symbol directly is deprecated. Please add the arm,gic-v1 + compatible to the GIC node in your DT and remove the direct selection. config GIC_V2 - bool + def_bool DT_HAS_ARM_GIC_V2_ENABLED select GIC + select DEPRECATED if !DT_HAS_ARM_GIC_V2_ENABLED help The ARM Generic Interrupt Controller v2 (e.g. GIC-400) works with the ARM Cortex-family processors. + Selecting this symbol directly is deprecated. Please add the arm,gic-v2 + compatible to the GIC node in your DT and remove the direct selection. config GIC_V3 - bool + def_bool DT_HAS_ARM_GIC_V3_ENABLED select GIC + select DEPRECATED if !DT_HAS_ARM_GIC_V3_ENABLED help The ARM Generic Interrupt Controller v3 (e.g. GIC-500 and GIC-600) works with the ARM Cortex-family processors. + Selecting this symbol directly is deprecated. Please add the arm,gic-v3 + compatible to the GIC node in your DT and remove the direct selection. config GIC_VER int diff --git a/dts/bindings/interrupt-controller/arm,gic-v1.yaml b/dts/bindings/interrupt-controller/arm,gic-v1.yaml new file mode 100644 index 000000000000..aae5bbbed0cf --- /dev/null +++ b/dts/bindings/interrupt-controller/arm,gic-v1.yaml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +description: ARM Generic Interrupt Controller v1 + +compatible: arm,gic-v1 + +include: arm,gic.yaml diff --git a/dts/bindings/interrupt-controller/arm,gic-v2.yaml b/dts/bindings/interrupt-controller/arm,gic-v2.yaml new file mode 100644 index 000000000000..a5e294efea37 --- /dev/null +++ b/dts/bindings/interrupt-controller/arm,gic-v2.yaml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +description: ARM Generic Interrupt Controller v2 + +compatible: arm,gic-v2 + +include: arm,gic.yaml diff --git a/dts/bindings/interrupt-controller/arm,gic-v3.yaml b/dts/bindings/interrupt-controller/arm,gic-v3.yaml new file mode 100644 index 000000000000..8fc5851d62cf --- /dev/null +++ b/dts/bindings/interrupt-controller/arm,gic-v3.yaml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +description: ARM Generic Interrupt Controller v3 + +compatible: arm,gic-v3 + +include: arm,gic.yaml From 678d3f6b0308d30a9a0fa913a90e2f799f76ad9b Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Fri, 2 Jun 2023 15:17:57 +0200 Subject: [PATCH 0299/2042] doc: release: 3.5: Add working release notes file Add a base working release notes file for the Zephyr 3.5 release. Signed-off-by: Piotr Wojnarowski --- doc/releases/release-notes-3.5.rst | 255 +++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 doc/releases/release-notes-3.5.rst diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst new file mode 100644 index 000000000000..d569682b8685 --- /dev/null +++ b/doc/releases/release-notes-3.5.rst @@ -0,0 +1,255 @@ +:orphan: + +.. _zephyr_3.5: + +Zephyr 3.5.0 (Working Draft) +############################ + +We are pleased to announce the release of Zephyr version 3.5.0. + +Major enhancements with this release include: + +The following sections provide detailed lists of changes by component. + +Security Vulnerability Related +****************************** + +API Changes +*********** + +Changes in this release +======================= + +Removed APIs in this release +============================ + +Deprecated in this release +========================== + +Stable API changes in this release +================================== + +New APIs in this release +======================== + +Kernel +****** + +Architectures +************* + +* ARM + +* ARM + +* ARM64 + +* RISC-V + +* Xtensa + +Bluetooth +********* + +* Audio + +* Direction Finding + +* Host + +* Mesh + +* Controller + +* HCI Driver + +Boards & SoC Support +******************** + +* Added support for these SoC series: + +* Removed support for these SoC series: + +* Made these changes in other SoC series: + +* Added support for these ARC boards: + +* Added support for these ARM boards: + +* Added support for these ARM64 boards: + +* Added support for these RISC-V boards: + +* Added support for these X86 boards: + +* Added support for these Xtensa boards: + +* Made these changes for ARC boards: + +* Made these changes for ARM boards: + +* Made these changes for ARM64 boards: + +* Made these changes for RISC-V boards: + +* Made these changes for X86 boards: + +* Made these changes for Xtensa boards: + +* Removed support for these ARC boards: + +* Removed support for these ARM boards: + +* Removed support for these ARM64 boards: + +* Removed support for these RISC-V boards: + +* Removed support for these X86 boards: + +* Removed support for these Xtensa boards: + +* Made these changes in other boards: + +* Added support for these following shields: + +Build system and infrastructure +******************************* + +Drivers and Sensors +******************* + +* ADC + +* Battery-backed RAM + +* CAN + +* Clock control + +* Counter + +* Crypto + +* DAC + +* DFU + +* Disk + +* Display + +* DMA + +* EEPROM + +* Entropy + +* ESPI + +* Ethernet + +* Flash + +* FPGA + +* Fuel Gauge + +* GPIO + +* hwinfo + +* I2C + +* I2S + +* I3C + +* IEEE 802.15.4 + +* Interrupt Controller + +* IPM + +* KSCAN + +* LED + +* MBOX + +* MEMC + +* PCIE + +* PECI + +Trusted Firmware-M +****************** +* Pin control + +* PWM + +* Power domain + +* Regulators + +* Reset + +* SDHC + +* Sensor + +* Serial + +* SPI + +* Timer + +* USB + +* W1 + +* Watchdog + +* WiFi + +Networking +********** + +USB +*** + +Devicetree +********** + +Libraries / Subsystems +********************** + +HALs +**** + +MCUboot +******* + +Storage +******* + +Trusted Firmware-M +****************** + +zcbor +***** + +Documentation +************* + +Tests and Samples +***************** + +Issue Related Items +******************* + +Known Issues +============ + +Addressed issues +================ From f2b5ebf09854e20ed59340d304f5bd2d4dce021d Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Fri, 2 Jun 2023 15:19:04 +0200 Subject: [PATCH 0300/2042] doc: release: 3.5: Add note on GIC version selection in DT Add a note that explains that the GIC version is now specified in the DT and not Kconfig. Signed-off-by: Piotr Wojnarowski --- doc/releases/release-notes-3.5.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index d569682b8685..c532ff873e5c 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -26,6 +26,12 @@ Removed APIs in this release Deprecated in this release ========================== +* Setting the GIC architecture version by selecting + :kconfig:option:`CONFIG_GIC_V1`, :kconfig:option:`CONFIG_GIC_V2` and + :kconfig:option:`CONFIG_GIC_V3` directly in Kconfig has been deprecated. + The GIC version should now be specified by adding the appropriate compatible, for + example :dtcompatible:`arm,gic-v2`, to the GIC node in the device tree. + Stable API changes in this release ================================== @@ -168,6 +174,8 @@ Drivers and Sensors * Interrupt Controller + * GIC: Architecture version selection is now based on the device tree + * IPM * KSCAN From 95c1a7e83f1dce26c5e1e79ac8bec00ba641a487 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:46:50 +0200 Subject: [PATCH 0301/2042] soc: arm: xilinx_zynq7000: Move GIC version to DT Move the GIC version to the device tree for xilinx_zynq7000 to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/xilinx/zynq7000.dtsi | 2 +- soc/arm/xilinx_zynq7000/xc7zxxx/Kconfig.series | 1 - soc/arm/xilinx_zynq7000/xc7zxxxs/Kconfig.series | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dts/arm/xilinx/zynq7000.dtsi b/dts/arm/xilinx/zynq7000.dtsi index dfc62feef95f..cbbc8eecaba8 100644 --- a/dts/arm/xilinx/zynq7000.dtsi +++ b/dts/arm/xilinx/zynq7000.dtsi @@ -40,7 +40,7 @@ }; gic: interrupt-controller@f8f01000 { - compatible = "arm,gic"; + compatible = "arm,gic-v1", "arm,gic"; status = "okay"; reg = <0xf8f01000 0x1000>, <0xf8f00100 0x100>; diff --git a/soc/arm/xilinx_zynq7000/xc7zxxx/Kconfig.series b/soc/arm/xilinx_zynq7000/xc7zxxx/Kconfig.series index 4b6217d99236..5a2f0966aadc 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxx/Kconfig.series +++ b/soc/arm/xilinx_zynq7000/xc7zxxx/Kconfig.series @@ -8,7 +8,6 @@ config SOC_SERIES_XILINX_XC7ZXXX select SOC_FAMILY_XILINX_ZYNQ7000 select ARM select CPU_CORTEX_A9 - select GIC_V1 select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER help Enable support for the Xilinx Zynq-7000 (XC7Zxxx) diff --git a/soc/arm/xilinx_zynq7000/xc7zxxxs/Kconfig.series b/soc/arm/xilinx_zynq7000/xc7zxxxs/Kconfig.series index 3b00ae321397..3045a8560162 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxxs/Kconfig.series +++ b/soc/arm/xilinx_zynq7000/xc7zxxxs/Kconfig.series @@ -8,7 +8,6 @@ config SOC_SERIES_XILINX_XC7ZXXXS select SOC_FAMILY_XILINX_ZYNQ7000 select ARM select CPU_CORTEX_A9 - select GIC_V1 select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER help Enable support for the Xilinx Zynq-7000S (XC7ZxxxS) From bca43d3eafd30b8fe0ce4fe090b572572d09361f Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:51:56 +0200 Subject: [PATCH 0302/2042] soc: arm: nxp_s32: Move GIC version to DT Move the GIC version to the device tree for nxp_s32 to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/nxp/nxp_s32z27x_r52.dtsi | 2 +- soc/arm/nxp_s32/s32ze/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index fdbdeaae4da9..3d083083b911 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -81,7 +81,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@47800000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x47800000 0x10000>, <0x47900000 0x80000>; interrupt-controller; diff --git a/soc/arm/nxp_s32/s32ze/Kconfig.series b/soc/arm/nxp_s32/s32ze/Kconfig.series index cb60a3e75d77..863a4cbd6d0d 100644 --- a/soc/arm/nxp_s32/s32ze/Kconfig.series +++ b/soc/arm/nxp_s32/s32ze/Kconfig.series @@ -10,7 +10,6 @@ config SOC_SERIES_S32ZE_R52 select CPU_CORTEX_R52 select CPU_HAS_DCLS select CPU_HAS_ARM_MPU - select GIC_V3 select GIC_SINGLE_SECURITY_STATE select VFP_DP_D16 select PLATFORM_SPECIFIC_INIT From 48ba2aec6a530850110883e91e9d34289d9c2f5f Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 21:47:25 +0200 Subject: [PATCH 0303/2042] soc: arm: cyclonev: Move GIC version to DT Move the GIC version to the device tree for cyclonev to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/intel_socfpga_std/socfpga.dtsi | 2 +- soc/arm/intel_socfpga_std/cyclonev/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm/intel_socfpga_std/socfpga.dtsi b/dts/arm/intel_socfpga_std/socfpga.dtsi index c0606995470e..e2e852a47911 100644 --- a/dts/arm/intel_socfpga_std/socfpga.dtsi +++ b/dts/arm/intel_socfpga_std/socfpga.dtsi @@ -39,7 +39,7 @@ }; intc: intc@fffed000 { - compatible = "arm,gic"; + compatible = "arm,gic-v1", "arm,gic"; #interrupt-cells = <4>; interrupt-controller; reg = <0xfffed000 0x1000>, diff --git a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series index 304788d0ee94..cb0dc6984e39 100644 --- a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series +++ b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series @@ -7,7 +7,6 @@ config SOC_SERIES_CYCLONE5 bool "Intel SoC FPGA Cyclone5 Series" select ARM select CPU_CORTEX_A9 - select GIC_V1 select SOC_FAMILY_INTEL_SOCFPGA_STD select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER select HAS_SPI_DW if SPI From 0835a99fac0498c01606d47160ed3d5d5f40f1aa Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 21:49:07 +0200 Subject: [PATCH 0304/2042] soc: arm: renesas_rcar: Move GIC version to DT Move the GIC version to the device tree for renesas_rcar to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/renesas/gen3/rcar_gen3_cr7.dtsi | 2 +- soc/arm/renesas_rcar/gen3/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm/renesas/gen3/rcar_gen3_cr7.dtsi b/dts/arm/renesas/gen3/rcar_gen3_cr7.dtsi index 49783f68077c..549443ee9950 100644 --- a/dts/arm/renesas/gen3/rcar_gen3_cr7.dtsi +++ b/dts/arm/renesas/gen3/rcar_gen3_cr7.dtsi @@ -31,7 +31,7 @@ }; gic: interrupt-controller@f1110000 { - compatible = "arm,gic"; + compatible = "arm,gic-v2", "arm,gic"; reg = <0xf1110000 0x1000>, <0xf1120000 0x20000>, <0xf1140000 0x20000>, diff --git a/soc/arm/renesas_rcar/gen3/Kconfig.series b/soc/arm/renesas_rcar/gen3/Kconfig.series index 966bbbb30e0b..717f9881bf92 100644 --- a/soc/arm/renesas_rcar/gen3/Kconfig.series +++ b/soc/arm/renesas_rcar/gen3/Kconfig.series @@ -6,7 +6,6 @@ config SOC_SERIES_RCAR_GEN3 select ARM select CPU_CORTEX_R7 select PLATFORM_SPECIFIC_INIT - select GIC_V2 select CPU_HAS_DCLS select SOC_FAMILY_RCAR select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL From fc29f73a29cf6a7c03f05146a8555801086e5347 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 21:50:52 +0200 Subject: [PATCH 0305/2042] soc: arm: xilinx_zynqmp: Move GIC version to DT Move the GIC version to the device tree for xilinx_zynqmp to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/xilinx/zynqmp_rpu.dtsi | 2 +- soc/arm/xilinx_zynqmp/Kconfig.soc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm/xilinx/zynqmp_rpu.dtsi b/dts/arm/xilinx/zynqmp_rpu.dtsi index 57e21ce4e5de..88fd4d701414 100644 --- a/dts/arm/xilinx/zynqmp_rpu.dtsi +++ b/dts/arm/xilinx/zynqmp_rpu.dtsi @@ -22,7 +22,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@f9000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v1", "arm,gic"; reg = <0xf9000000 0x1000>, <0xf9001000 0x100>; interrupt-controller; diff --git a/soc/arm/xilinx_zynqmp/Kconfig.soc b/soc/arm/xilinx_zynqmp/Kconfig.soc index 04611379b239..6d80f61c68ea 100644 --- a/soc/arm/xilinx_zynqmp/Kconfig.soc +++ b/soc/arm/xilinx_zynqmp/Kconfig.soc @@ -7,7 +7,6 @@ config SOC_XILINX_ZYNQMP_RPU select ARM select CPU_CORTEX_R5 select SOC_XILINX_ZYNQMP - select GIC_V1 select PLATFORM_SPECIFIC_INIT select CPU_HAS_ARM_MPU select VFP_DP_D16 From ff9fe7271a0934a19d64ee0ae7310f389b720f9b Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:57:03 +0200 Subject: [PATCH 0306/2042] soc: arm64: fvp_aemv8: Move GIC version to DT Move the GIC version to the device tree for fvp_aemv8{a,r} to improve readability Signed-off-by: Piotr Wojnarowski --- boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts | 2 +- dts/arm64/fvp/fvp-aemv8r.dtsi | 2 +- soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc | 1 - soc/arm64/arm/fvp_aemv8a/Kconfig.soc | 1 - soc/arm64/arm/fvp_aemv8r/Kconfig.soc | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts index c089a959fa17..e5ba322f91cd 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts +++ b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a.dts @@ -80,7 +80,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@2f000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x2f000000 0x10000>, // GICD <0x2f100000 0x200000>; // GICR interrupt-controller; diff --git a/dts/arm64/fvp/fvp-aemv8r.dtsi b/dts/arm64/fvp/fvp-aemv8r.dtsi index a03906f29a4b..5af99a25eb1a 100644 --- a/dts/arm64/fvp/fvp-aemv8r.dtsi +++ b/dts/arm64/fvp/fvp-aemv8r.dtsi @@ -60,7 +60,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@af000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0xaf000000 0x10000>, <0xaf100000 0x200000>; interrupt-controller; diff --git a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc index 3b6441c707b1..53f5f3a0bac9 100644 --- a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc +++ b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc @@ -10,7 +10,6 @@ config SOC_FVP_AEMV8R_AARCH32 select CPU_CORTEX_R52 select CPU_HAS_ARM_MPU select CPU_HAS_MPU - select GIC_V3 select GIC_SINGLE_SECURITY_STATE select PLATFORM_SPECIFIC_INIT diff --git a/soc/arm64/arm/fvp_aemv8a/Kconfig.soc b/soc/arm64/arm/fvp_aemv8a/Kconfig.soc index b73bf3a6e6e1..9dec51555816 100644 --- a/soc/arm64/arm/fvp_aemv8a/Kconfig.soc +++ b/soc/arm64/arm/fvp_aemv8a/Kconfig.soc @@ -8,6 +8,5 @@ choice config SOC_FVP_BASE_REVC_2XAEMV8A bool "ARM FVP Base RevC 2xAEMv8A AArch64 simulation" select CPU_CORTEX_A53 - select GIC_V3 endchoice diff --git a/soc/arm64/arm/fvp_aemv8r/Kconfig.soc b/soc/arm64/arm/fvp_aemv8r/Kconfig.soc index 2888995c8de4..724c37b11820 100644 --- a/soc/arm64/arm/fvp_aemv8r/Kconfig.soc +++ b/soc/arm64/arm/fvp_aemv8r/Kconfig.soc @@ -9,7 +9,6 @@ config SOC_FVP_AEMV8R_AARCH64 bool "ARM FVP AEMv8R aarch64 simulation" select CPU_CORTEX_R82 select CPU_HAS_MPU - select GIC_V3 select GIC_SINGLE_SECURITY_STATE endchoice From 03aa363a6c7e814b2305c0645ca6e788efe07f86 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:58:26 +0200 Subject: [PATCH 0307/2042] soc: arm64: viper: Move GIC version to DT Move the GIC version to the device tree for viper to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm/broadcom/viper-a72.dtsi | 2 +- dts/arm64/broadcom/viper-a72.dtsi | 2 +- soc/arm64/bcm_vk/viper/Kconfig.soc | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dts/arm/broadcom/viper-a72.dtsi b/dts/arm/broadcom/viper-a72.dtsi index 2d3148032931..d7a3ea35fe1a 100644 --- a/dts/arm/broadcom/viper-a72.dtsi +++ b/dts/arm/broadcom/viper-a72.dtsi @@ -36,7 +36,7 @@ soc { gic: interrupt-controller@42700000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x42700000 0x010000>, <0x42780000 0x600000>; interrupt-controller; diff --git a/dts/arm64/broadcom/viper-a72.dtsi b/dts/arm64/broadcom/viper-a72.dtsi index 451446325880..698bd9158481 100644 --- a/dts/arm64/broadcom/viper-a72.dtsi +++ b/dts/arm64/broadcom/viper-a72.dtsi @@ -36,7 +36,7 @@ soc { gic: interrupt-controller@42700000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x42700000 0x010000>, <0x42780000 0x600000>; interrupt-controller; diff --git a/soc/arm64/bcm_vk/viper/Kconfig.soc b/soc/arm64/bcm_vk/viper/Kconfig.soc index 9a7dc23f5224..592a788f7299 100644 --- a/soc/arm64/bcm_vk/viper/Kconfig.soc +++ b/soc/arm64/bcm_vk/viper/Kconfig.soc @@ -10,6 +10,5 @@ config SOC_BCM58402_A72 select ARM64 select CPU_CORTEX_A72 select ARM_ARCH_TIMER - select GIC_V3 endchoice From 184440239ecc65d41d16b700a5cf0f84f2972307 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 18:00:43 +0200 Subject: [PATCH 0308/2042] soc: arm64: mimx9: Move GIC version to DT Move the GIC version to the device tree for mimx9 to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/nxp/nxp_mimx93_a55.dtsi | 2 +- soc/arm64/nxp_imx/mimx9/Kconfig.soc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index 48a8434ff687..1e73bff224fb 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -52,7 +52,7 @@ }; gic: interrupt-controller@48000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x48000000 0x10000>, /* GIC Dist */ <0x48040000 0xc0000>; /* GICR (RD_base + SGI_base) */ interrupt-controller; diff --git a/soc/arm64/nxp_imx/mimx9/Kconfig.soc b/soc/arm64/nxp_imx/mimx9/Kconfig.soc index 1d20d5be5b8c..0a091196cfb7 100644 --- a/soc/arm64/nxp_imx/mimx9/Kconfig.soc +++ b/soc/arm64/nxp_imx/mimx9/Kconfig.soc @@ -10,7 +10,6 @@ config SOC_MIMX93_A55 select ARM64 select CPU_CORTEX_A55 select ARM_ARCH_TIMER - select GIC_V3 select HAS_MCUX if CLOCK_CONTROL select HAS_MCUX_CCM if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL From 7626426f2770c8bf7b10622139329de9538472bd Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 18:02:06 +0200 Subject: [PATCH 0309/2042] soc: arm64: qemu: Move GIC version to DT Move the GIC version to the device tree for the QEMU platforms to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/qemu/qemu-virt-a53.dtsi | 2 +- dts/arm64/qemu/qemu-virt-arm64.dtsi | 2 +- soc/arm64/qemu_cortex_a53/Kconfig.soc | 1 - soc/arm64/qemu_virt_arm64/Kconfig.soc | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dts/arm64/qemu/qemu-virt-a53.dtsi b/dts/arm64/qemu/qemu-virt-a53.dtsi index 3eeef309a206..1839c2726a1c 100644 --- a/dts/arm64/qemu/qemu-virt-a53.dtsi +++ b/dts/arm64/qemu/qemu-virt-a53.dtsi @@ -66,7 +66,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@8000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x00 0x8000000 0x00 0x010000>, <0x00 0x80a0000 0x00 0xf60000>; interrupt-controller; diff --git a/dts/arm64/qemu/qemu-virt-arm64.dtsi b/dts/arm64/qemu/qemu-virt-arm64.dtsi index bbd5fca560c4..0460c70f0738 100644 --- a/dts/arm64/qemu/qemu-virt-arm64.dtsi +++ b/dts/arm64/qemu/qemu-virt-arm64.dtsi @@ -66,7 +66,7 @@ interrupt-parent = <&gic>; gic: interrupt-controller@8000000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x00 0x8000000 0x00 0x010000>, <0x00 0x80a0000 0x00 0xf60000>; interrupt-controller; diff --git a/soc/arm64/qemu_cortex_a53/Kconfig.soc b/soc/arm64/qemu_cortex_a53/Kconfig.soc index 23b6e7481f6a..4aac3e811b5f 100644 --- a/soc/arm64/qemu_cortex_a53/Kconfig.soc +++ b/soc/arm64/qemu_cortex_a53/Kconfig.soc @@ -5,4 +5,3 @@ config SOC_QEMU_CORTEX_A53 bool "QEMU virt platform (cortex-a53)" select ARM64 select CPU_CORTEX_A53 - select GIC_V3 diff --git a/soc/arm64/qemu_virt_arm64/Kconfig.soc b/soc/arm64/qemu_virt_arm64/Kconfig.soc index 077e108299d1..109e8e3270a3 100644 --- a/soc/arm64/qemu_virt_arm64/Kconfig.soc +++ b/soc/arm64/qemu_virt_arm64/Kconfig.soc @@ -6,4 +6,3 @@ config SOC_QEMU_VIRT_ARM64 select ARM64 select CPU_CORTEX_A select ARMV8_A - select GIC_V3 From 7908d7556c61b7cba664cb6cc838e0cf71847e12 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 18:05:40 +0200 Subject: [PATCH 0310/2042] soc: arm64: nxp_imx: Move GIC version to DT Move the GIC version to the device tree for nxp_imx to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/nxp/nxp_mimx8mm_a53.dtsi | 2 +- dts/arm64/nxp/nxp_mimx8mn_a53.dtsi | 2 +- dts/arm64/nxp/nxp_mimx8mp_a53.dtsi | 2 +- soc/arm64/nxp_imx/mimx8m/Kconfig.soc | 3 --- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi b/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi index c64e44139565..605729969db6 100644 --- a/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi +++ b/dts/arm64/nxp/nxp_mimx8mm_a53.dtsi @@ -64,7 +64,7 @@ }; gic: interrupt-controller@38800000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x38800000 0x10000>, /* GIC Dist */ <0x38880000 0xc0000>; /* GICR (RD_base + SGI_base) */ interrupt-controller; diff --git a/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi b/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi index 1c6a6bdc368c..d76cc40438e1 100644 --- a/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi +++ b/dts/arm64/nxp/nxp_mimx8mn_a53.dtsi @@ -64,7 +64,7 @@ }; gic: interrupt-controller@38800000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x38800000 0x10000>, /* GIC Dist */ <0x38880000 0xc0000>; /* GICR (RD_base + SGI_base) */ interrupt-controller; diff --git a/dts/arm64/nxp/nxp_mimx8mp_a53.dtsi b/dts/arm64/nxp/nxp_mimx8mp_a53.dtsi index ba6eca8723a1..6ca0b3159d35 100644 --- a/dts/arm64/nxp/nxp_mimx8mp_a53.dtsi +++ b/dts/arm64/nxp/nxp_mimx8mp_a53.dtsi @@ -57,7 +57,7 @@ }; gic: interrupt-controller@38800000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x38800000 0x10000>, /* GIC Dist */ <0x38880000 0xc0000>; /* GICR (RD_base + SGI_base) */ interrupt-controller; diff --git a/soc/arm64/nxp_imx/mimx8m/Kconfig.soc b/soc/arm64/nxp_imx/mimx8m/Kconfig.soc index 56aef3c0ccd9..03c8361c8b24 100644 --- a/soc/arm64/nxp_imx/mimx8m/Kconfig.soc +++ b/soc/arm64/nxp_imx/mimx8m/Kconfig.soc @@ -10,7 +10,6 @@ config SOC_MIMX8MM_A53 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER - select GIC_V3 select HAS_MCUX if CLOCK_CONTROL select HAS_MCUX_CCM if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL @@ -20,7 +19,6 @@ config SOC_MIMX8MP_A53 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER - select GIC_V3 select HAS_MCUX if CLOCK_CONTROL select HAS_MCUX_CCM if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL @@ -30,7 +28,6 @@ config SOC_MIMX8MN_A53 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER - select GIC_V3 select HAS_MCUX if CLOCK_CONTROL select HAS_MCUX_CCM if CLOCK_CONTROL select HAS_MCUX_IOMUXC if PINCTRL From 2ba2e1dc3a925f6e70cd2ca47abdc26fcc6df4ba Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 17:47:18 +0200 Subject: [PATCH 0311/2042] soc: arm64: intel_socfpga: Move GIC version to DT Move the GIC version to the device tree for intel_socfpga to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/intel/intel_socfpga_agilex.dtsi | 2 +- soc/arm64/intel_socfpga/agilex/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/intel/intel_socfpga_agilex.dtsi b/dts/arm64/intel/intel_socfpga_agilex.dtsi index 25ccb268ce7b..14174e5a4462 100644 --- a/dts/arm64/intel/intel_socfpga_agilex.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex.dtsi @@ -41,7 +41,7 @@ }; gic: interrupt-controller@fffc1000 { - compatible = "arm,gic"; + compatible = "arm,gic-v2", "arm,gic"; reg = <0xfffc1000 0x1000>, <0xfffc2000 0x2000>; interrupt-controller; diff --git a/soc/arm64/intel_socfpga/agilex/Kconfig.series b/soc/arm64/intel_socfpga/agilex/Kconfig.series index e4aeb5ebb919..f1266db5baef 100644 --- a/soc/arm64/intel_socfpga/agilex/Kconfig.series +++ b/soc/arm64/intel_socfpga/agilex/Kconfig.series @@ -5,7 +5,6 @@ config SOC_SERIES_AGILEX bool "Intel SoC FPGA Agilex Series" select ARM64 select CPU_CORTEX_A53 - select GIC_V2 select SOC_FAMILY_INTEL_SOCFPGA help Enable support for Intel SoC FPGA Series From 0e537bc04e009f9a814b4e527158a1ff6d94f7a2 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Tue, 16 May 2023 12:45:22 +0200 Subject: [PATCH 0312/2042] soc: arm64: rk3399: Move GIC version to DT Move the GIC version to the device tree for rk3399 to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/rockchip/rk3399.dtsi | 2 +- soc/arm64/rockchip/rk3399/Kconfig.soc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/rockchip/rk3399.dtsi b/dts/arm64/rockchip/rk3399.dtsi index 932d6f0cc955..fadaa0a40c7f 100644 --- a/dts/arm64/rockchip/rk3399.dtsi +++ b/dts/arm64/rockchip/rk3399.dtsi @@ -50,7 +50,7 @@ gic: interrupt-controller@fee00000 { #address-cells = <1>; - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0xfee00000 0x10000>, /* GICD */ <0xfef00000 0xc0000>, /* GICR */ <0xfff00000 0x10000>, /* GICC */ diff --git a/soc/arm64/rockchip/rk3399/Kconfig.soc b/soc/arm64/rockchip/rk3399/Kconfig.soc index 97d41254fb55..8a9382b43ca0 100644 --- a/soc/arm64/rockchip/rk3399/Kconfig.soc +++ b/soc/arm64/rockchip/rk3399/Kconfig.soc @@ -13,6 +13,5 @@ config SOC_RK3399 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER - select GIC_V3 endchoice From 6b004bc1b9327006ba7fca269937c8f0856c0591 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Tue, 16 May 2023 12:46:01 +0200 Subject: [PATCH 0313/2042] soc: arm64: am6x: Move GIC version to DT Move the GIC version to the device tree for am6x to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/ti/ti_am62x_a53.dtsi | 2 +- soc/arm64/ti_sitara/am6x/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/ti/ti_am62x_a53.dtsi b/dts/arm64/ti/ti_am62x_a53.dtsi index 4a18ebbd86fc..183095dd8d0e 100644 --- a/dts/arm64/ti/ti_am62x_a53.dtsi +++ b/dts/arm64/ti/ti_am62x_a53.dtsi @@ -43,7 +43,7 @@ }; gic: interrupt-controller@1800000 { - compatible = "arm,gic"; + compatible = "arm,gic-v3", "arm,gic"; reg = <0x01800000 0x10000>, /* GICD */ <0x01880000 0xc0000>; /* GICR */ interrupt-controller; diff --git a/soc/arm64/ti_sitara/am6x/Kconfig.series b/soc/arm64/ti_sitara/am6x/Kconfig.series index 81f13ee6fffd..54da4e341663 100644 --- a/soc/arm64/ti_sitara/am6x/Kconfig.series +++ b/soc/arm64/ti_sitara/am6x/Kconfig.series @@ -7,6 +7,5 @@ config SOC_SERIES_AM6X_A53 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER - select GIC_V3 help Enable support for AM6X A53 Series. From bc8b234d9c9206a76a8502fdb3227d6aecdd0587 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 21:51:32 +0200 Subject: [PATCH 0314/2042] soc: arm64: ls1046a: Move GIC version to DT Move the GIC version to the device tree for ls1046a to improve readability Signed-off-by: Piotr Wojnarowski --- dts/arm64/nxp/nxp_ls1046a.dtsi | 2 +- soc/arm64/nxp_layerscape/ls1046a/Kconfig.soc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/nxp/nxp_ls1046a.dtsi b/dts/arm64/nxp/nxp_ls1046a.dtsi index 045cb4d2b89b..153317fe23c2 100644 --- a/dts/arm64/nxp/nxp_ls1046a.dtsi +++ b/dts/arm64/nxp/nxp_ls1046a.dtsi @@ -38,7 +38,7 @@ }; gic: interrupt-controller@1410000 { - compatible = "arm,gic"; + compatible = "arm,gic-v2", "arm,gic"; reg = <0x01410000 0x10000>, /* GICD */ <0x0142f000 0x1000>; /* GICC */ interrupt-controller; diff --git a/soc/arm64/nxp_layerscape/ls1046a/Kconfig.soc b/soc/arm64/nxp_layerscape/ls1046a/Kconfig.soc index 771024c8798e..5b17567970db 100644 --- a/soc/arm64/nxp_layerscape/ls1046a/Kconfig.soc +++ b/soc/arm64/nxp_layerscape/ls1046a/Kconfig.soc @@ -13,6 +13,5 @@ config SOC_LS1046A select ARM64 select CPU_CORTEX_A72 select ARM_ARCH_TIMER - select GIC_V2 endchoice From 562716d70993b194e650b8c0a120c482e1757161 Mon Sep 17 00:00:00 2001 From: Piotr Wojnarowski Date: Wed, 17 May 2023 18:05:07 +0200 Subject: [PATCH 0315/2042] soc: arm64: xenvm: Move GIC version to DT Move the GIC version to the device tree for xenvm to improve readability Signed-off-by: Piotr Wojnarowski --- boards/arm64/xenvm/Kconfig | 8 -------- boards/arm64/xenvm/xenvm.dts | 2 +- boards/arm64/xenvm/xenvm_gicv3.dts | 1 + boards/arm64/xenvm/xenvm_gicv3_defconfig | 3 --- soc/arm64/xenvm/Kconfig.soc | 2 -- 5 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 boards/arm64/xenvm/Kconfig diff --git a/boards/arm64/xenvm/Kconfig b/boards/arm64/xenvm/Kconfig deleted file mode 100644 index d6735af0283e..000000000000 --- a/boards/arm64/xenvm/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2022 Arm Limited (or its affiliates). All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -config XENVM_USE_GIC_V3 - bool "Xen VM using GICv3" - depends on BOARD_XENVM - help - Configure Xen VM to use GICv3 instead of default GICv2. diff --git a/boards/arm64/xenvm/xenvm.dts b/boards/arm64/xenvm/xenvm.dts index 006078238866..fb6daa3656ab 100644 --- a/boards/arm64/xenvm/xenvm.dts +++ b/boards/arm64/xenvm/xenvm.dts @@ -52,7 +52,7 @@ }; gic: interrupt-controller@3001000 { - compatible = "arm,gic"; + compatible = "arm,gic-v2", "arm,gic"; #interrupt-cells = <0x04>; #address-cells = <0x00>; interrupt-controller; diff --git a/boards/arm64/xenvm/xenvm_gicv3.dts b/boards/arm64/xenvm/xenvm_gicv3.dts index c3af22c178f4..dbf7e0dd33c0 100644 --- a/boards/arm64/xenvm/xenvm_gicv3.dts +++ b/boards/arm64/xenvm/xenvm_gicv3.dts @@ -6,5 +6,6 @@ #include "xenvm.dts" &gic { + compatible = "arm,gic-v3", "arm,gic"; reg = <0x00 0x3001000 0x00 0x10000 0x00 0x3020000 0x00 0x1000000>; }; diff --git a/boards/arm64/xenvm/xenvm_gicv3_defconfig b/boards/arm64/xenvm/xenvm_gicv3_defconfig index b5b63987b498..9bff11a2edb8 100644 --- a/boards/arm64/xenvm/xenvm_gicv3_defconfig +++ b/boards/arm64/xenvm/xenvm_gicv3_defconfig @@ -1,9 +1,6 @@ CONFIG_SOC_XENVM=y CONFIG_BOARD_XENVM=y -# Use GICv3 -CONFIG_XENVM_USE_GIC_V3=y - # Enable UART driver CONFIG_SERIAL=y diff --git a/soc/arm64/xenvm/Kconfig.soc b/soc/arm64/xenvm/Kconfig.soc index 904f21dfedd5..a1c19c27a4c9 100644 --- a/soc/arm64/xenvm/Kconfig.soc +++ b/soc/arm64/xenvm/Kconfig.soc @@ -5,8 +5,6 @@ config SOC_XENVM bool "Xen virtual machine on aarch64" select ARM64 select ARM_ARCH_TIMER - select GIC_V3 if XENVM_USE_GIC_V3 - select GIC_V2 if !XENVM_USE_GIC_V3 select CPU_CORTEX_A72 config XEN_INITIAL_DOMAIN From 817f635a37a9ace16f8289fe1ce010bad9956a76 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 9 Jun 2023 15:31:06 +0200 Subject: [PATCH 0316/2042] boards: arm: pinetime_devkit0: use gpio-hog for key-out Now that we have GPIO hogs, there's no need for custom board init code to just configure GPIOs. The objective of this patch is also to reduce usage of SYS_INIT to eventually help on improving the status of system initialization (e.g. devices, sys_inits, etc.). Signed-off-by: Gerard Marull-Paretas --- boards/arm/pinetime_devkit0/CMakeLists.txt | 7 ---- .../misc/pine64,pinetime-key-out.yaml | 15 ------- boards/arm/pinetime_devkit0/key_out.c | 39 ------------------- .../arm/pinetime_devkit0/pinetime_devkit0.dts | 10 +++-- 4 files changed, 6 insertions(+), 65 deletions(-) delete mode 100644 boards/arm/pinetime_devkit0/CMakeLists.txt delete mode 100644 boards/arm/pinetime_devkit0/dts/bindings/misc/pine64,pinetime-key-out.yaml delete mode 100644 boards/arm/pinetime_devkit0/key_out.c diff --git a/boards/arm/pinetime_devkit0/CMakeLists.txt b/boards/arm/pinetime_devkit0/CMakeLists.txt deleted file mode 100644 index 6bfe8fe54f37..000000000000 --- a/boards/arm/pinetime_devkit0/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2021 Casper Meijn -# SPDX-License-Identifier: Apache-2.0 - -description: | - Key out definition for PineTime. This pin needs to be high before the button (key_in) becomes - available. - -compatible: "pine64,pinetime-key-out" - -include: base.yaml - -properties: - gpios: - type: phandle-array - required: true diff --git a/boards/arm/pinetime_devkit0/key_out.c b/boards/arm/pinetime_devkit0/key_out.c deleted file mode 100644 index db8f3506f934..000000000000 --- a/boards/arm/pinetime_devkit0/key_out.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2021 Casper Meijn - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -LOG_MODULE_REGISTER(pine64_pinetime_key_out); - -#define KEY_OUT_NODE DT_PATH(key_out) - -#if DT_NODE_HAS_STATUS(KEY_OUT_NODE, okay) - -static const struct gpio_dt_spec key_out = GPIO_DT_SPEC_GET(KEY_OUT_NODE, gpios); - -static int pinetime_key_out_init(void) -{ - int ret; - - if (!device_is_ready(key_out.port)) { - LOG_ERR("key out gpio device %s is not ready", - key_out.port->name); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&key_out, GPIO_OUTPUT_ACTIVE); - if (ret != 0) { - LOG_ERR("failed to configure %s pin %d (err %d)", - key_out.port->name, key_out.pin, ret); - return ret; - } - - return 0; -} - -SYS_INIT(pinetime_key_out_init, POST_KERNEL, 99); -#endif diff --git a/boards/arm/pinetime_devkit0/pinetime_devkit0.dts b/boards/arm/pinetime_devkit0/pinetime_devkit0.dts index 2ab46733ec0a..55b16ecc79ee 100644 --- a/boards/arm/pinetime_devkit0/pinetime_devkit0.dts +++ b/boards/arm/pinetime_devkit0/pinetime_devkit0.dts @@ -65,10 +65,6 @@ label = "Key in"; }; }; - key_out { - compatible = "pine64,pinetime-key-out"; - gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; - }; vbatt { compatible = "voltage-divider"; @@ -88,6 +84,12 @@ &gpio0 { status = "okay"; + + key-out { + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &uart0 { From c7af24a065da3875240b742215e58e96fdb19850 Mon Sep 17 00:00:00 2001 From: Sahaj Sarup Date: Mon, 5 Jun 2023 12:40:44 +0530 Subject: [PATCH 0317/2042] drivers: i2c: target: Virtual EEPROM add ability to change i2c address This patch adds the ability to change virtual i2c eeprom target address at runtime using a single function. Added CONFIG_I2C_EEPROM_TARGET_RUNTIME_ADDR as an optional Kconfig. Signed-off-by: Sahaj Sarup --- drivers/i2c/target/Kconfig.eeprom | 6 ++++++ drivers/i2c/target/eeprom_target.c | 19 +++++++++++++++++++ include/zephyr/drivers/i2c/target/eeprom.h | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/drivers/i2c/target/Kconfig.eeprom b/drivers/i2c/target/Kconfig.eeprom index 34e2e82274eb..ce2120b10832 100644 --- a/drivers/i2c/target/Kconfig.eeprom +++ b/drivers/i2c/target/Kconfig.eeprom @@ -7,3 +7,9 @@ config I2C_EEPROM_TARGET bool "I2C Target EEPROM driver" help Enable virtual I2C Target EEPROM driver + +config I2C_EEPROM_TARGET_RUNTIME_ADDR + bool "Set I2C Target EEPROM Address at Runtime" + depends on I2C_EEPROM_TARGET + help + Enable changing virtual I2C Target EEPROM device address at runtime diff --git a/drivers/i2c/target/eeprom_target.c b/drivers/i2c/target/eeprom_target.c index e7afe63856b4..b1fc2c2a0b21 100644 --- a/drivers/i2c/target/eeprom_target.c +++ b/drivers/i2c/target/eeprom_target.c @@ -59,6 +59,25 @@ int eeprom_target_read(const struct device *dev, uint8_t *eeprom_data, return 0; } +#ifdef CONFIG_I2C_EEPROM_TARGET_RUNTIME_ADDR +int eeprom_target_set_addr(const struct device *dev, uint8_t addr) +{ + const struct i2c_eeprom_target_config *cfg = dev->config; + struct i2c_eeprom_target_data *data = dev->data; + int ret; + + ret = i2c_target_unregister(cfg->bus.bus, &data->config); + if (ret) { + LOG_DBG("eeprom target failed to unregister"); + return ret; + } + + data->config.address = addr; + + return i2c_target_register(cfg->bus.bus, &data->config); +} +#endif /* CONFIG_I2C_EEPROM_TARGET_RUNTIME_ADDR */ + static int eeprom_target_write_requested(struct i2c_target_config *config) { struct i2c_eeprom_target_data *data = CONTAINER_OF(config, diff --git a/include/zephyr/drivers/i2c/target/eeprom.h b/include/zephyr/drivers/i2c/target/eeprom.h index 2d2a554a7f3c..5dfde70d16ac 100644 --- a/include/zephyr/drivers/i2c/target/eeprom.h +++ b/include/zephyr/drivers/i2c/target/eeprom.h @@ -45,6 +45,19 @@ int eeprom_target_program(const struct device *dev, const uint8_t *eeprom_data, int eeprom_target_read(const struct device *dev, uint8_t *eeprom_data, unsigned int offset); +/** + * @brief Change the address of eeprom taget at runtime + * + * @param dev Pointer to the device structure for the driver instance. + * @param addr New address to assign to the eeprom target devide + * + * @retval 0 Is successful + * @retval -EINVAL If parameters are invalid + * @retval -EIO General input / output error during i2c_taget_register + * @retval -ENOSYS If target mode is not implemented + */ +int eeprom_target_set_addr(const struct device *dev, uint8_t addr); + /** * @} */ From 7c1c619c61c9dfe91c9885e184e1bc4d0b060492 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 15 May 2023 15:25:50 +0200 Subject: [PATCH 0318/2042] boards: sparkfun_thing_plus_nrf9160: Always enable GPIO The GPIO driver is required by this board's initialization code (board.c), so it is forced to be enabled always for the board Kconfig, not only enabled by default (in defconfig). Fixes: #57890 Signed-off-by: Joakim Andersson --- boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.board | 8 ++++++++ .../sparkfun_thing_plus_nrf9160_defconfig | 3 --- .../sparkfun_thing_plus_nrf9160_ns_defconfig | 3 --- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.board b/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.board index 923c1cd36f37..504107a7b2cb 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.board +++ b/boards/arm/sparkfun_thing_plus_nrf9160/Kconfig.board @@ -8,8 +8,16 @@ if SOC_NRF9160_SICA config BOARD_SPARKFUN_THING_PLUS_NRF9160 bool "Sparkfun nRF9160 Thing Plus" + # The GPIO driver is required by this board's initialization code + # (board.c), so it is forced here to be enabled always, not only + # enabled by default (in defconfig). + select GPIO config BOARD_SPARKFUN_THING_PLUS_NRF9160_NS bool "Sparkfun nRF9160 Thing Plus non-secure" + # The GPIO driver is required by this board's initialization code + # (board.c), so it is forced here to be enabled always, not only + # enabled by default (in defconfig). + select GPIO endif # SOC_NRF9160_SICA diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig index 6c5fdd1cdd9e..e53eb77c6513 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_defconfig @@ -13,9 +13,6 @@ CONFIG_ARM_TRUSTZONE_M=y # Hardware stack protection CONFIG_HW_STACK_PROTECTION=y -# enable GPIO -CONFIG_GPIO=y - # Enable uart driver CONFIG_SERIAL=y diff --git a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig index 7386d5b08831..f2e6c1026c77 100644 --- a/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig +++ b/boards/arm/sparkfun_thing_plus_nrf9160/sparkfun_thing_plus_nrf9160_ns_defconfig @@ -16,9 +16,6 @@ CONFIG_TRUSTED_EXECUTION_NONSECURE=y # Hardware stack protection CONFIG_HW_STACK_PROTECTION=y -# enable GPIO -CONFIG_GPIO=y - # Enable uart driver CONFIG_SERIAL=y From 2d7c5f16627b46d6558e85f6f28291ff3a604ba5 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 13 Jun 2023 10:40:50 +0200 Subject: [PATCH 0319/2042] boards: efm32*: use gpio-hogs to enable board controller Remove custom board initialization code in charge of enabling board controller with simple gpio-hogs. Signed-off-by: Gerard Marull-Paretas --- boards/arm/efm32gg_stk3701a/board.c | 13 +----- boards/arm/efm32gg_stk3701a/board.h | 4 -- .../arm/efm32gg_stk3701a/efm32gg_stk3701a.dts | 6 +++ boards/arm/efm32hg_slstk3400a/CMakeLists.txt | 6 --- boards/arm/efm32hg_slstk3400a/board.c | 32 --------------- boards/arm/efm32hg_slstk3400a/board.h | 14 ------- .../efm32hg_slstk3400a/efm32hg_slstk3400a.dts | 6 +++ boards/arm/efm32pg_stk3401a/CMakeLists.txt | 6 --- boards/arm/efm32pg_stk3401a/board.c | 32 --------------- boards/arm/efm32pg_stk3401a/board.h | 14 ------- .../efm32pg_stk3401a_common.dtsi | 6 +++ boards/arm/efm32pg_stk3402a/CMakeLists.txt | 6 --- boards/arm/efm32pg_stk3402a/board.c | 32 --------------- boards/arm/efm32pg_stk3402a/board.h | 14 ------- .../efm32pg_stk3402a_common.dtsi | 6 +++ boards/arm/efm32wg_stk3800/CMakeLists.txt | 6 --- boards/arm/efm32wg_stk3800/board.c | 31 -------------- boards/arm/efm32wg_stk3800/board.h | 14 ------- .../arm/efm32wg_stk3800/efm32wg_stk3800.dts | 6 +++ boards/arm/efr32_radio/CMakeLists.txt | 6 --- boards/arm/efr32_radio/board.c | 41 ------------------- boards/arm/efr32_radio/efr32_radio.dtsi | 6 +++ .../arm/efr32_radio/efr32_radio_brd4180a.dts | 6 +++ .../arm/efr32_radio/efr32_radio_brd4187c.dts | 6 +++ 24 files changed, 49 insertions(+), 270 deletions(-) delete mode 100644 boards/arm/efm32hg_slstk3400a/CMakeLists.txt delete mode 100644 boards/arm/efm32hg_slstk3400a/board.c delete mode 100644 boards/arm/efm32hg_slstk3400a/board.h delete mode 100644 boards/arm/efm32pg_stk3401a/CMakeLists.txt delete mode 100644 boards/arm/efm32pg_stk3401a/board.c delete mode 100644 boards/arm/efm32pg_stk3401a/board.h delete mode 100644 boards/arm/efm32pg_stk3402a/CMakeLists.txt delete mode 100644 boards/arm/efm32pg_stk3402a/board.c delete mode 100644 boards/arm/efm32pg_stk3402a/board.h delete mode 100644 boards/arm/efm32wg_stk3800/CMakeLists.txt delete mode 100644 boards/arm/efm32wg_stk3800/board.c delete mode 100644 boards/arm/efm32wg_stk3800/board.h delete mode 100644 boards/arm/efr32_radio/board.c diff --git a/boards/arm/efm32gg_stk3701a/board.c b/boards/arm/efm32gg_stk3701a/board.c index 0096cf11bc92..11dad370f789 100644 --- a/boards/arm/efm32gg_stk3701a/board.c +++ b/boards/arm/efm32gg_stk3701a/board.c @@ -13,20 +13,9 @@ static int efm32gg_stk3701a_init(void) { +#ifdef CONFIG_ETH_GECKO const struct device *cur_dev; - - /* Enable the board controller to be able to use the serial port */ - cur_dev = DEVICE_DT_GET(BC_ENABLE_GPIO_NODE); - if (!device_is_ready(cur_dev)) { - printk("Board controller gpio port is not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(cur_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT); - gpio_pin_set(cur_dev, BC_ENABLE_GPIO_PIN, 1); - -#ifdef CONFIG_ETH_GECKO /* Enable the ethernet PHY power */ cur_dev = DEVICE_DT_GET(ETH_PWR_ENABLE_GPIO_NODE); if (!device_is_ready(cur_dev)) { diff --git a/boards/arm/efm32gg_stk3701a/board.h b/boards/arm/efm32gg_stk3701a/board.h index eded04c5ba2c..e76e798ce510 100644 --- a/boards/arm/efm32gg_stk3701a/board.h +++ b/boards/arm/efm32gg_stk3701a/board.h @@ -8,10 +8,6 @@ #ifndef __INC_BOARD_H #define __INC_BOARD_H -/* This pin is used to enable the serial port using the board controller */ -#define BC_ENABLE_GPIO_NODE DT_NODELABEL(gpioe) -#define BC_ENABLE_GPIO_PIN 1 - /* Ethernet specific pins */ #ifdef CONFIG_ETH_GECKO #define ETH_PWR_ENABLE_GPIO_NODE DT_NODELABEL(gpioi) diff --git a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts index 017cc90759ce..41f54a4d910d 100644 --- a/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts +++ b/boards/arm/efm32gg_stk3701a/efm32gg_stk3701a.dts @@ -116,6 +116,12 @@ &gpioe { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpiof { diff --git a/boards/arm/efm32hg_slstk3400a/CMakeLists.txt b/boards/arm/efm32hg_slstk3400a/CMakeLists.txt deleted file mode 100644 index a7a82c8b6084..000000000000 --- a/boards/arm/efm32hg_slstk3400a/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_UART_GECKO) - zephyr_library() - zephyr_library_sources(board.c) -endif() diff --git a/boards/arm/efm32hg_slstk3400a/board.c b/boards/arm/efm32hg_slstk3400a/board.c deleted file mode 100644 index ae69f6ee5d28..000000000000 --- a/boards/arm/efm32hg_slstk3400a/board.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018 Marcio Montenegro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "board.h" -#include -#include - -static int efm32hg_slstk3400a_init(void) -{ - const struct device *bce_dev; /* Board Controller Enable Gpio Device */ - - - /* Enable the board controller to be able to use the serial port */ - bce_dev = DEVICE_DT_GET(BC_ENABLE_GPIO_NODE); - - if (!device_is_ready(bce_dev)) { - printk("Board controller gpio port is not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(efm32hg_slstk3400a_init, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/efm32hg_slstk3400a/board.h b/boards/arm/efm32hg_slstk3400a/board.h deleted file mode 100644 index 73932b978e9f..000000000000 --- a/boards/arm/efm32hg_slstk3400a/board.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2018 Marcio Montenegro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -/* This pin is used to enable the serial port using the board controller */ -#define BC_ENABLE_GPIO_NODE DT_NODELABEL(gpioa) -#define BC_ENABLE_GPIO_PIN 9 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts b/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts index c86cda085cc8..25a28cc3a4a2 100644 --- a/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts +++ b/boards/arm/efm32hg_slstk3400a/efm32hg_slstk3400a.dts @@ -60,6 +60,12 @@ &gpioa { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpioc { diff --git a/boards/arm/efm32pg_stk3401a/CMakeLists.txt b/boards/arm/efm32pg_stk3401a/CMakeLists.txt deleted file mode 100644 index a7a82c8b6084..000000000000 --- a/boards/arm/efm32pg_stk3401a/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_UART_GECKO) - zephyr_library() - zephyr_library_sources(board.c) -endif() diff --git a/boards/arm/efm32pg_stk3401a/board.c b/boards/arm/efm32pg_stk3401a/board.c deleted file mode 100644 index a2677965a4ae..000000000000 --- a/boards/arm/efm32pg_stk3401a/board.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2020 Rafael Dias Menezes - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "board.h" -#include -#include - -static int efm32pg_stk3401a_init(void) -{ - const struct device *bce_dev; /* Board Controller Enable Gpio Device */ - - - /* Enable the board controller to be able to use the serial port */ - bce_dev = DEVICE_DT_GET(BC_ENABLE_GPIO_NODE); - - if (!device_is_ready(bce_dev)) { - printk("Board controller gpio port is not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(efm32pg_stk3401a_init, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/efm32pg_stk3401a/board.h b/boards/arm/efm32pg_stk3401a/board.h deleted file mode 100644 index f88ee79edd2b..000000000000 --- a/boards/arm/efm32pg_stk3401a/board.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -/* This pin is used to enable the serial port using the board controller */ -#define BC_ENABLE_GPIO_NODE DT_NODELABEL(gpioa) -#define BC_ENABLE_GPIO_PIN 5 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi index 93585bd0d814..b59d45931eac 100644 --- a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi +++ b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi @@ -86,6 +86,12 @@ &gpioa { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpiob { diff --git a/boards/arm/efm32pg_stk3402a/CMakeLists.txt b/boards/arm/efm32pg_stk3402a/CMakeLists.txt deleted file mode 100644 index a7a82c8b6084..000000000000 --- a/boards/arm/efm32pg_stk3402a/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_UART_GECKO) - zephyr_library() - zephyr_library_sources(board.c) -endif() diff --git a/boards/arm/efm32pg_stk3402a/board.c b/boards/arm/efm32pg_stk3402a/board.c deleted file mode 100644 index 8809b013920c..000000000000 --- a/boards/arm/efm32pg_stk3402a/board.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "board.h" -#include -#include - -static int efm32pg_stk3402a_init(void) -{ - const struct device *bce_dev; /* Board Controller Enable Gpio Device */ - - - /* Enable the board controller to be able to use the serial port */ - bce_dev = DEVICE_DT_GET(BC_ENABLE_GPIO_NODE); - - if (!device_is_ready(bce_dev)) { - printk("Board controller gpio port is not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(efm32pg_stk3402a_init, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/efm32pg_stk3402a/board.h b/boards/arm/efm32pg_stk3402a/board.h deleted file mode 100644 index f88ee79edd2b..000000000000 --- a/boards/arm/efm32pg_stk3402a/board.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -/* This pin is used to enable the serial port using the board controller */ -#define BC_ENABLE_GPIO_NODE DT_NODELABEL(gpioa) -#define BC_ENABLE_GPIO_PIN 5 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi index b3b4321485d0..d862a0da5b77 100644 --- a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi +++ b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi @@ -107,6 +107,12 @@ &gpioa { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpiob { diff --git a/boards/arm/efm32wg_stk3800/CMakeLists.txt b/boards/arm/efm32wg_stk3800/CMakeLists.txt deleted file mode 100644 index a7a82c8b6084..000000000000 --- a/boards/arm/efm32wg_stk3800/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_UART_GECKO) - zephyr_library() - zephyr_library_sources(board.c) -endif() diff --git a/boards/arm/efm32wg_stk3800/board.c b/boards/arm/efm32wg_stk3800/board.c deleted file mode 100644 index acf9406da610..000000000000 --- a/boards/arm/efm32wg_stk3800/board.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2017 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "board.h" -#include -#include - -static int efm32wg_stk3800_init(void) -{ - const struct device *bce_dev; /* Board Controller Enable Gpio Device */ - - - /* Enable the board controller to be able to use the serial port */ - bce_dev = DEVICE_DT_GET(BC_ENABLE_GPIO_NODE); - - if (!device_is_ready(bce_dev)) { - printk("Board controller gpio port not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(bce_dev, BC_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(efm32wg_stk3800_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/efm32wg_stk3800/board.h b/boards/arm/efm32wg_stk3800/board.h deleted file mode 100644 index 8fefb9470141..000000000000 --- a/boards/arm/efm32wg_stk3800/board.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2017 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -/* This pin is used to enable the serial port using the board controller */ -#define BC_ENABLE_GPIO_NODE DT_NODELABEL(gpiof) -#define BC_ENABLE_GPIO_PIN 7 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts b/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts index 99f42c1f6c8c..e955a281bb3c 100644 --- a/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts +++ b/boards/arm/efm32wg_stk3800/efm32wg_stk3800.dts @@ -71,6 +71,12 @@ &gpiof { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &uart0 { diff --git a/boards/arm/efr32_radio/CMakeLists.txt b/boards/arm/efr32_radio/CMakeLists.txt index 28383c1429d6..77a7880c491c 100644 --- a/boards/arm/efr32_radio/CMakeLists.txt +++ b/boards/arm/efr32_radio/CMakeLists.txt @@ -1,8 +1,2 @@ # SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_UART_GECKO) - zephyr_library() - zephyr_library_sources(board.c) -endif() - zephyr_include_directories(.) diff --git a/boards/arm/efr32_radio/board.c b/boards/arm/efr32_radio/board.c deleted file mode 100644 index d6ac8237b78d..000000000000 --- a/boards/arm/efr32_radio/board.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2018 Christian Taedcke - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -/* This pin is used to enable the serial port using the board controller */ -#if defined(CONFIG_BOARD_EFR32_RADIO_BRD4180A) -#define VCOM_ENABLE_GPIO_NODE DT_NODELABEL(gpiod) -#define VCOM_ENABLE_GPIO_PIN 4 -#elif defined(CONFIG_BOARD_EFR32_RADIO_BRD4187C) -#define VCOM_ENABLE_GPIO_NODE DT_NODELABEL(gpiob) -#define VCOM_ENABLE_GPIO_PIN 0 -#else -#define VCOM_ENABLE_GPIO_NODE DT_NODELABEL(gpioa) -#define VCOM_ENABLE_GPIO_PIN 5 -#endif - -static int efr32_radio_init(void) -{ - const struct device *vce_dev; /* Virtual COM Port Enable GPIO Device */ - - - /* Enable the board controller to be able to use the serial port */ - vce_dev = DEVICE_DT_GET(VCOM_ENABLE_GPIO_NODE); - if (!device_is_ready(vce_dev)) { - printk("Virtual COM Port Enable device is not ready!\n"); - return -ENODEV; - } - - gpio_pin_configure(vce_dev, VCOM_ENABLE_GPIO_PIN, GPIO_OUTPUT_HIGH); - - return 0; -} - -/* needs to be done after GPIO driver init */ -SYS_INIT(efr32_radio_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/efr32_radio/efr32_radio.dtsi b/boards/arm/efr32_radio/efr32_radio.dtsi index 117883677638..584799ef33f3 100644 --- a/boards/arm/efr32_radio/efr32_radio.dtsi +++ b/boards/arm/efr32_radio/efr32_radio.dtsi @@ -93,6 +93,12 @@ &gpioa { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpiob { diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts index 550d298cb172..a65dee27e907 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts @@ -90,6 +90,12 @@ &gpiod { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <4 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &wdog0 { diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts index 30125b93b663..cebc0919d12a 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts @@ -76,6 +76,12 @@ &gpiob { status = "okay"; + + board-controller-enable { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>; + output-high; + }; }; &gpioc { From ce3317d03e46e1a218af3e712383d9216c48a992 Mon Sep 17 00:00:00 2001 From: Ingar Kulbrandstad Date: Wed, 7 Jun 2023 12:26:43 +0200 Subject: [PATCH 0320/2042] Bluetooth: Mesh: Updated ACL configuration settings Setting default value for BT_BUF_ACL_TX/RX_SIZE and BT_CTLR_DATA_LENGTH_MAX to 37, as this will process the incoming data the most efficient way. When GATT is enable BT_BUF_ACL_RX_SIZE does not have to be 73, as this will just give segmented messages for the public keys exchange during provisioning. Signed-off-by: Ingar Kulbrandstad --- subsys/bluetooth/common/Kconfig | 5 ++--- subsys/bluetooth/controller/Kconfig | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 266f7201c7e0..d72ce90afa69 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -9,6 +9,7 @@ menu "Bluetooth buffer configuration" config BT_BUF_ACL_TX_SIZE int "Maximum supported ACL size for outgoing data" range 27 65535 + default 37 if BT_MESH_GATT default 27 help Maximum supported ACL size of data packets sent from the Host to the @@ -48,11 +49,9 @@ config BT_BUF_ACL_TX_COUNT config BT_BUF_ACL_RX_SIZE int "Maximum supported ACL size for incoming data" default 200 if BT_BREDR - # Mesh Proxy Recommended: 64 Pkey + 2 Bytes Mesh header. - # Overhead: ATT Write command Header (3) in an L2CAP PDU (4). - default 73 if BT_MESH_GATT default 70 if BT_EATT default 69 if BT_SMP + default 37 if BT_MESH_GATT default 27 range 70 65535 if BT_EATT range 69 65535 if BT_SMP diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index d4345012ffef..4cc413ea03cb 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -456,6 +456,7 @@ config BT_CTLR_DATA_LENGTH config BT_CTLR_DATA_LENGTH_MAX int "Maximum data length supported" depends on BT_CTLR_DATA_LENGTH + default BT_BUF_ACL_RX_SIZE if BT_BUF_ACL_RX_SIZE < 251 default 27 range 27 BT_BUF_ACL_RX_SIZE if BT_BUF_ACL_RX_SIZE < 251 range 27 251 From 6bfa52afe5e6036052ef0d7f0da735bf5680e99e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:05 +0200 Subject: [PATCH 0321/2042] net: l2: ieee802154: fix CSMA/CA configuration ranges The allowable ranges of several CSMA/CA-related settings were not conforming to the standard, see IEEE 802.15.4-2020, section 8.4.3.1, table 8-94 (MAC PIB attributes). This change fixes the ranges. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/Kconfig.radio | 17 +++++++++-------- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 3 +++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/subsys/net/l2/ieee802154/Kconfig.radio b/subsys/net/l2/ieee802154/Kconfig.radio index 180e87377867..4f4175120906 100644 --- a/subsys/net/l2/ieee802154/Kconfig.radio +++ b/subsys/net/l2/ieee802154/Kconfig.radio @@ -11,11 +11,11 @@ config NET_L2_IEEE802154_RADIO_DFLT_TX_POWER If wrongly set, it will silently fail. config NET_L2_IEEE802154_RADIO_TX_RETRIES - int "Radio Transmission attempts" + int "Radio Retransmission attempts" default 3 - range 1 7 + range 0 7 help - Number of transmission attempts radio driver should do, before + Number of re-transmission attempts radio driver should do, before replying it could not send the packet (MAC PIB attribute: macMaxFrameRetries). @@ -45,24 +45,25 @@ if NET_L2_IEEE802154_RADIO_CSMA_CA config NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO int "CSMA maximum backoffs" default 4 - range 1 5 + range 0 5 help The maximum number of backoffs the CSMA-CA algorithm will attempt before declaring a channel access failure (MAC PIB attribute: - maxMaxCSMABackoffs). + macMaxCSMABackoffs). config NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE int "CSMA MAC minimum backoff exponent" default 3 - range 1 8 + range 0 8 help The minimum value of the backoff exponent (BE) in the CSMA-CA - algorithm (MAC PIB attribute: macMinBe). + algorithm (MAC PIB attribute: macMinBe). This setting must be less + than or equal NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE. config NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE int "CSMA MAC maximum backoff exponent" default 5 - range 1 8 + range 3 8 help The maximum value of the backoff exponent (BE) in the CSMA-CA algorithm (MAC PIB attribute: macMaxBe). diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index befc0f648443..57ff108cc4e3 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -48,6 +48,9 @@ static inline int csma_ca_radio_send(struct net_if *iface, while (1) { if (!ieee802154_cca(iface)) { break; + } else if (ret != -EBUSY) { + /* CCA exited with failure code. */ + return -EIO; } be = MIN(be + 1, max_be); From f08b70549f07aa672e35c7a4cf77131f6216211d Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 31 May 2023 13:42:44 +0200 Subject: [PATCH 0322/2042] net: l2: ieee802154: radio: fix aloha algorithm The ALOHA algorithm had two minor implementation errors: - The number of retransmissions was off by one. - Retransmissions are only allowed when acknowledgement is requested otherwise it is to be assumed that the transmission was successful. - prepare_for_ack() has side effects and must be called before each retransmission. Signed-off-by: Florian Grandel --- .../l2/ieee802154/ieee802154_radio_aloha.c | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c index 36b28a4edc59..3eae9f84945c 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c @@ -2,6 +2,8 @@ * Copyright (c) 2016 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 + * + * All references to the spec refer to IEEE 802.15.4-2020. */ #include @@ -20,15 +22,27 @@ static inline int aloha_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) { - uint8_t retries = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES; + /* See section 6.7.4.4 - Retransmissions. */ + uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; struct ieee802154_context *ctx = net_if_l2_data(iface); - bool ack_required = prepare_for_ack(ctx, pkt, frag); + bool ack_required; int ret = -EIO; NET_DBG("frag %p", frag); - while (retries) { - retries--; + while (remaining_attempts) { + remaining_attempts--; + + ack_required = prepare_for_ack(ctx, pkt, frag); + + if (!ack_required) { + /* See section 6.7.4.4: "A device that sends a frame with the AR field set + * to indicate no acknowledgment requested may assume that the transmission + * was successfully received and shall not perform the retransmission + * procedure." + */ + remaining_attempts = 0; + } ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, frag); From 5827066ca9a04d12b749221229f4f1ea014d4c53 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:29:19 +0200 Subject: [PATCH 0323/2042] net: l2: ieee802154: radio: fix csma/ca algorithm The CSMA/CA algorithm had multiple issues: - Timing of backoff periods depends on the PHY's symbol rate and other PHY-specific settings. We introduce a preliminary solution that works with current drivers. A fully standard-compliant long-term solution has already been conceptualized but requires further pre-conditions, see #50336 (issuecomment-1251122582). - We enforce the condition defined in the standard that macMinBe must be less than or equal macMaxBe. - According to the standard a CSMA/CA failure should lead to immediate abortion of the transmission attempt, no matter how many retransmissions have been configured. - The number of retransmissions was off by one. It is now used as defined in the standard algorithm. - Retransmissions are only allowed when acknowledgement is requested in the packet. - prepare_for_ack() has side effects and must be called before each retransmission. We also replace variables by constants where possible. The function was renamed as it represents unslotted CSMA/CA and does not support other CSMA/CA modes. These may be introduced in the future. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 9 +++ include/zephyr/net/ieee802154_radio.h | 56 +++++++++++++- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 75 +++++++++++++------ 3 files changed, 117 insertions(+), 23 deletions(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index c17646840571..be6241912917 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -50,6 +51,14 @@ extern "C" { /* See IEEE 802.15.4-2020, section 7.3.5 */ #define IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED IEEE802154_BROADCAST_ADDRESS +/* MAC PIB attribute aUnitBackoffPeriod, see section 8.4.2, table 8-93, in symbol periods, valid for + * all PHYs except SUN PHY in the 920 MHz band. + */ +#define IEEE802154_A_UNIT_BACKOFF_PERIOD(turnaround_time) \ + (turnaround_time + IEEE802154_PHY_A_CCA_TIME) +#define IEEE802154_A_UNIT_BACKOFF_PERIOD_US(turnaround_time, symbol_period) \ + (IEEE802154_A_UNIT_BACKOFF_PERIOD(turnaround_time) * symbol_period) + struct ieee802154_security_ctx { uint32_t frame_counter; struct cipher_ctx enc; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 41a906112ee7..c599be9b9c0b 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -7,15 +7,19 @@ /** * @file * @brief Public IEEE 802.15.4 Radio API + * + * All references to the spec refer to IEEE 802.15.4-2020. */ #ifndef ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_H_ #define ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_H_ #include +#include #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -26,6 +30,54 @@ extern "C" { * @{ */ +/* See section 6.1: "Some of the timing parameters in definition of the MAC are in units of PHY + * symbols. For PHYs that have multiple symbol periods, the duration to be used for the MAC + * parameters is defined in that PHY clause." + */ +#define IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_US 20U /* see section 19.1, table 19-1 */ +#define IEEE802154_PHY_OQPSK_2450MHZ_SYMBOL_PERIOD_US 16U /* see section 12.3.3 */ + +/* TODO: Get PHY-specific symbol period from radio API. Requires an attribute getter, see + * https://github.com/zephyrproject-rtos/zephyr/issues/50336#issuecomment-1251122582. + * For now we assume PHYs that current drivers actually implement. + */ +#define IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy) \ + ((is_subg_phy) ? IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_US \ + : IEEE802154_PHY_OQPSK_2450MHZ_SYMBOL_PERIOD_US) + +/* The inverse of the symbol period as defined in section 6.1. This is not necessarily the true + * physical symbol period, so take care to use this macro only when either the symbol period used + * for MAC timing is the same as the physical symbol period or if you actually mean the MAC timing + * symbol period. + */ +#define IEEE802154_PHY_SYMBOLS_PER_SECOND(symbol_period) (USEC_PER_SEC / symbol_period) + +/* see section 19.2.4 */ +#define IEEE802154_PHY_SUN_FSK_PHR_LEN 2 + +/* Default PHY PIB attribute aTurnaroundTime, in PHY symbols, see section 11.3, table 11-1. */ +#define IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT 12U + +/* PHY PIB attribute aTurnaroundTime for SUN, RS-GFSK, TVWS, and LECIM FSK PHY, + * in PHY symbols, see section 11.3, table 11-1. + */ +#define IEEE802154_PHY_A_TURNAROUND_TIME_1MS(symbol_period) \ + DIV_ROUND_UP(USEC_PER_MSEC, symbol_period) + +/* TODO: Get PHY-specific turnaround time from radio API, see + * https://github.com/zephyrproject-rtos/zephyr/issues/50336#issuecomment-1251122582. + * For now we assume PHYs that current drivers actually implement. + */ +#define IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy) \ + ((is_subg_phy) \ + ? IEEE802154_PHY_A_TURNAROUND_TIME_1MS(IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy)) \ + : IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT) + +/* PHY PIB attribute aCcaTime, in PHY symbols, all PHYs except for SUN O-QPSK, + * see section 11.3, table 11-1. + */ +#define IEEE802154_PHY_A_CCA_TIME 8U + /** * @brief IEEE 802.15.4 Channel assignments * @@ -35,7 +87,7 @@ extern "C" { * - Channels 1-10 are for 906 to 924 MHz with 2 MHz channel spacing. * - Channels 11-26 are for 2405 to 2530 MHz with 5 MHz channel spacing. * - * For more information, please refer to 802.15.4-2015 Section 10.1.2.2. + * For more information, please refer to section 10.1.3. */ enum ieee802154_channel { IEEE802154_SUB_GHZ_CHANNEL_MIN = 0, @@ -142,7 +194,7 @@ enum ieee802154_config_type { * determine whether to set the bit or not based on the information * provided with ``IEEE802154_CONFIG_ACK_FPB`` config and FPB address * matching mode specified. Otherwise, Frame Pending bit should be set - * to ``1`` (see IEEE Std 802.15.4-2006, 7.2.2.3.1). + * to ``1`` (see section 6.7.3). */ IEEE802154_CONFIG_AUTO_ACK_FPB, diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index 57ff108cc4e3..708cad22fc67 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -2,6 +2,8 @@ * Copyright (c) 2016 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 + * + * All references to the spec refer to IEEE 802.15.4-2020. */ #include @@ -9,6 +11,7 @@ LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include #include +#include #include #include @@ -20,47 +23,77 @@ LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include "ieee802154_utils.h" #include "ieee802154_radio_utils.h" -static inline int csma_ca_radio_send(struct net_if *iface, - struct net_pkt *pkt, - struct net_buf *frag) +BUILD_ASSERT(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE <= + CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE, + "The CSMA/CA min backoff exponent must be less or equal max backoff exponent."); + +/* See section 6.2.5.1. */ +static inline int unslotted_csma_ca_radio_send(struct net_if *iface, struct net_pkt *pkt, + struct net_buf *frag) { - const uint8_t max_bo = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; - const uint8_t max_be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE; - uint8_t retries = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES; - struct ieee802154_context *ctx = net_if_l2_data(iface); - bool ack_required = prepare_for_ack(ctx, pkt, frag); uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE; + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint32_t symbol_period, turnaround_time; + uint8_t remaining_attempts; + bool ack_required; + bool is_subg_phy; uint8_t nb = 0U; - int ret = -EIO; + int ret; NET_DBG("frag %p", frag); -loop: - while (retries) { - retries--; + is_subg_phy = ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ; + /* TODO: Move symbol period calculation to radio driver. */ + symbol_period = IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy); + turnaround_time = IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy); - if (be) { - uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1); + /* See section 6.7.4.4 - Retransmissions. */ + remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; - k_busy_wait(bo_n * 20U); - } + while (remaining_attempts) { + remaining_attempts--; while (1) { - if (!ieee802154_cca(iface)) { + if (be) { + uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1); + + /* TODO: k_busy_wait() is too inaccurate on many platforms, the + * radio API should expose a precise radio clock instead (which may + * fall back to k_busy_wait() if the radio does not have a clock). + */ + k_busy_wait(bo_n * IEEE802154_A_UNIT_BACKOFF_PERIOD_US( + turnaround_time, symbol_period)); + } + + ret = ieee802154_cca(iface); + if (ret == 0) { + /* Channel is idle -> CSMA Success */ break; } else if (ret != -EBUSY) { /* CCA exited with failure code. */ return -EIO; } - be = MIN(be + 1, max_be); + /* Channel is not idle -> CSMA Backoff */ + be = MIN(be + 1, CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE); nb++; - if (nb > max_bo) { - goto loop; + if (nb > CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO) { + return -EIO; } } + ack_required = prepare_for_ack(ctx, pkt, frag); + + if (!ack_required) { + /* See section 6.7.4.4: "A device that sends a frame with the AR field set + * to indicate no acknowledgment requested may assume that the transmission + * was successfully received and shall not perform the retransmission + * procedure." + */ + remaining_attempts = 0; + } + ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, frag); if (ret) { @@ -90,7 +123,7 @@ static enum net_verdict csma_ca_radio_handle_ack(struct net_if *iface, } /* Declare the public Radio driver function used by the HW drivers */ -FUNC_ALIAS(csma_ca_radio_send, +FUNC_ALIAS(unslotted_csma_ca_radio_send, ieee802154_radio_send, int); FUNC_ALIAS(csma_ca_radio_handle_ack, From ffcae5f0297189ff8591deff91ac11d5dc7fb439 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 2 Jun 2023 19:34:52 +0200 Subject: [PATCH 0324/2042] net: l2: ieee802154: separate CCA and retransmission The IEEE 802.15.4 standard clearly separates clear channel assessment from retransmission. This separation of concern was not represented in the current channel access vs. retransmission implementation which resulted in considerable duplication of code and logic. This change removes the duplication of logic and encapsulates the resulting functions in a private API that may only be used from within Zephyr's native L2 layer. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/Kconfig.radio | 24 ++-- subsys/net/l2/ieee802154/ieee802154.c | 124 +++++++++++++++++- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 2 +- subsys/net/l2/ieee802154/ieee802154_priv.h | 100 ++++++++++++++ .../l2/ieee802154/ieee802154_radio_aloha.c | 69 +--------- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 114 ++++------------ .../l2/ieee802154/ieee802154_radio_utils.h | 95 -------------- tests/net/ieee802154/l2/src/ieee802154_test.c | 9 +- 8 files changed, 276 insertions(+), 261 deletions(-) create mode 100644 subsys/net/l2/ieee802154/ieee802154_priv.h delete mode 100644 subsys/net/l2/ieee802154/ieee802154_radio_utils.h diff --git a/subsys/net/l2/ieee802154/Kconfig.radio b/subsys/net/l2/ieee802154/Kconfig.radio index 4f4175120906..dc21255898fa 100644 --- a/subsys/net/l2/ieee802154/Kconfig.radio +++ b/subsys/net/l2/ieee802154/Kconfig.radio @@ -20,24 +20,28 @@ config NET_L2_IEEE802154_RADIO_TX_RETRIES macMaxFrameRetries). choice - prompt "Radio protocol" + prompt "Radio channel access protocol" default NET_L2_IEEE802154_RADIO_CSMA_CA help - Select which radio protocol to use. + Select which medium access protocol to use. config NET_L2_IEEE802154_RADIO_CSMA_CA - bool "IEEE 802.15.4 CSMA-CA radio protocol" + bool "IEEE 802.15.4 unslotted CSMA-CA medium access protocol" help - Use CSMA-CA mechanism to transmit packets. This is the most common - way of transmitting packets and fits most of all the usage. - At least until the version 2011 of the specification. + Use CSMA-CA mechanism (listen-before-talk with exponential backoff) + to transmit packets. This is the most common way of mediating radio + channel access and fits most usage scenarios (see IEEE 802.15.4-2020, + sections 6.2.5.1 and 10.2.8). config NET_L2_IEEE802154_RADIO_ALOHA - bool "IEEE 802.15.4 Aloha radio protocol" + bool "IEEE 802.15.4 Aloha medium access protocol (CCA mode 4)" help - Use Aloha mechanism to transmit packets. This is a simplistic - way of transmitting packets and fits contexts where radio spectrum - is not too heavily loaded. + Use Aloha mechanism (send without any clear channel assessment) to + transmit packets. This is a simplistic way of transmitting packets + and fits low duty-cycle contexts where the radio spectrum is not + too heavily loaded (see IEEE 802.15.4-2020, section 10.2.8). The + current implementation does not randomize channel access. + endchoice if NET_L2_IEEE802154_RADIO_CSMA_CA diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 4cf4eac03c3a..ee8f3356fe85 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -36,12 +36,10 @@ LOG_MODULE_REGISTER(net_ieee802154, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include "ieee802154_frame.h" #include "ieee802154_mgmt_priv.h" -#include "ieee802154_radio_utils.h" +#include "ieee802154_priv.h" #include "ieee802154_security.h" #include "ieee802154_utils.h" -#include - #define BUF_TIMEOUT K_MSEC(50) NET_BUF_POOL_DEFINE(tx_frame_buf_pool, 1, IEEE802154_MTU, 8, NULL); @@ -96,6 +94,126 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 #define ieee802154_acknowledge(...) #endif /* CONFIG_NET_L2_IEEE802154_ACK_REPLY */ +inline bool ieee802154_prepare_for_ack(struct ieee802154_context *ctx, struct net_pkt *pkt, + struct net_buf *frag) +{ + /* TODO: Only execute when the driver does not handle ACK itself. */ + if (ieee802154_is_ar_flag_set(frag)) { + struct ieee802154_fcf_seq *fs; + + fs = (struct ieee802154_fcf_seq *)frag->data; + + ctx->ack_seq = fs->sequence; + ctx->ack_received = false; + k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); + + return true; + } + + return false; +} + +enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, struct net_pkt *pkt) +{ + struct ieee802154_context *ctx = net_if_l2_data(iface); + + /* TODO: Only execute when the driver does not handle ACK itself. */ + + /* TODO: ACK/Retransmission has nothing to do with CSMA/CA - this + * is about retransmission. + */ + if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && + ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { + return NET_OK; + } + + if (pkt->buffer->len == IEEE802154_ACK_PKT_LENGTH) { + uint8_t len = IEEE802154_ACK_PKT_LENGTH; + struct ieee802154_fcf_seq *fs; + + fs = ieee802154_validate_fc_seq(net_pkt_data(pkt), NULL, &len); + if (!fs || fs->sequence != ctx->ack_seq) { + return NET_CONTINUE; + } + + ctx->ack_received = true; + k_sem_give(&ctx->ack_lock); + + /* TODO: Release packet in L2 as we're taking ownership. */ + return NET_OK; + } + + return NET_CONTINUE; +} + +inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) +{ + struct ieee802154_context *ctx = net_if_l2_data(iface); + + if (!ack_required || (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { + return 0; + } + + if (k_sem_take(&ctx->ack_lock, K_MSEC(10)) == 0) { + /* We reinit the semaphore in case ieee802154_handle_ack() + * got called multiple times. + */ + k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); + } + + ctx->ack_seq = 0U; + + return ctx->ack_received ? 0 : -ETIME; +} + +int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) +{ + struct ieee802154_context *ctx = net_if_l2_data(iface); + + bool ack_required; + int ret; + + NET_DBG("frag %p", frag); + + /* See section 6.7.4.4 - Retransmissions. */ + for (uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; + remaining_attempts > 0; remaining_attempts--) { + ret = ieee802154_wait_for_clear_channel(iface); + if (ret != 0) { + NET_WARN("Clear channel assessment failed: dropping fragment %p on " + "interface %p.", + frag, iface); + return ret; + } + + ack_required = ieee802154_prepare_for_ack(ctx, pkt, frag); + + ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, frag); + if (ret) { + /* Unknown transmission failure. */ + return ret; + } + + if (!ack_required) { + /* See section 6.7.4.4: "A device that sends a frame with the AR field set + * to indicate no acknowledgment requested may assume that the transmission + * was successfully received and shall not perform the retransmission + * procedure." + */ + return 0; + } + + + ret = ieee802154_wait_for_ack(iface, ack_required); + if (ret == 0) { + /* ACK received - transmission is successful. */ + return 0; + } + } + + return -EIO; +} + static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool comp, enum ieee802154_addressing_mode mode, struct ieee802154_address_field *ll) diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index 650bdc5ac9ac..1bc7c875433f 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -25,9 +25,9 @@ LOG_MODULE_REGISTER(net_ieee802154_mgmt, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include "ieee802154_frame.h" #include "ieee802154_mgmt_priv.h" +#include "ieee802154_priv.h" #include "ieee802154_security.h" #include "ieee802154_utils.h" -#include "ieee802154_radio_utils.h" /** * Implements (part of) the MLME-BEACON.notify primitive, see section 8.2.5.2. diff --git a/subsys/net/l2/ieee802154/ieee802154_priv.h b/subsys/net/l2/ieee802154/ieee802154_priv.h new file mode 100644 index 000000000000..c1d63fb84217 --- /dev/null +++ b/subsys/net/l2/ieee802154/ieee802154_priv.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Private IEEE 802.15.4 low level L2 helper utilities + * + * These utilities are internal to the native IEEE 802.15.4 L2 + * stack and must not be included and used elsewhere. + * + * All references to the spec refer to IEEE 802.15.4-2020. + */ + +#ifndef __IEEE802154_PRIV_H__ +#define __IEEE802154_PRIV_H__ + +#include +#include +#include + +/** + * @brief Sends the given fragment respecting the configured IEEE 802.15.4 access arbitration + * algorithm (CSMA/CA, ALOHA, etc.) and re-transmission protocol. See sections 6.2.5 (random + * access methods) and 6.7.4.4 (retransmissions). + * + * This function checks for and supports both, software and hardware access arbitration and + * acknowledgment depending on driver capabilities. + * + * @param iface A valid pointer on a network interface to send from + * @param pkt A valid pointer on a packet to send + * @param frag The fragment to be sent + * + * @return 0 on success, negative value otherwise + */ +int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag); + +/** + * @brief This function implements the configured channel access algorithm (CSMA/CA, ALOHA, + * etc.). Currently only one implementation of this function may be compiled into the + * source code. The implementation will be selected via Kconfig variables (see + * @ref NET_L2_IEEE802154_RADIO_CSMA_CA and @ref NET_L2_IEEE802154_RADIO_ALOHA). + * + * This method will be called by ieee802154_radio_send() to determine if and when the + * radio channel is clear to send. It blocks the thread during backoff if the selected + * algorithm implements a backoff strategy. + * + * See sections 6.2.5 and 10.2.8. + * + * @param iface A valid pointer on a network interface to assesss + * + * @return 0 if the channel is clear to send, -EBUSY if a timeout was reached while waiting for + * a clear channel, other negative values to signal internal error conditions. + */ +int ieee802154_wait_for_clear_channel(struct net_if *iface); + +/** + * @brief Checks whether the given packet requires acknowledgment, and if so, prepares ACK + * reception on the TX path, i.e. sets up the necessary internal state before a transmission. + * + * This function has side effects and must be called before each individual transmission + * attempt. + * + * This function checks for and supports both, software and hardware acknowlegement, + * depending on driver capabilities. + * + * See sections 6.7.4.1 through 6.7.4.3. + * + * @param ctx A valid pointer to the IEEE 802.15.4 context + * @param pkt A valid pointer on a packet to send + * @param frag The fragment that needs to be acknowledged + * + * @return true if the given packet requires acknowlegement, false otherwise. + */ +bool ieee802154_prepare_for_ack(struct ieee802154_context *ctx, struct net_pkt *pkt, + struct net_buf *frag); + +/** + * @brief Waits for ACK reception on the TX path with standard compliant timeout settings, i.e. + * listens for incoming packages with the correct attributes and sequence number, see + * section 6.7.4.4 (retransmissions). + * + * This function has side effects and must be called after each transmission attempt if (and only + * if) @ref ieee802154_prepare_for_ack() had been called before. + * + * This function checks for and supports both, software and hardware acknowlegement, depending on + * driver capabilities. + * + * @param iface A valid pointer on the network the packet was transmitted to + * @param ack_required The return value from the corresponding call to + * @ref ieee802154_prepare_for_ack() + * + * @return 0 if no ACK was required or the exected ACK was received in time, -EIO if the expected + * ACK was not received within the standard compliant timeout. + */ +int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required); + +#endif /* __IEEE802154_PRIV_H__ */ diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c index 3eae9f84945c..edbcff82db8f 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_aloha.c @@ -9,72 +9,17 @@ #include LOG_MODULE_REGISTER(net_ieee802154_aloha, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); -#include #include -#include +#include "ieee802154_priv.h" -#include "ieee802154_frame.h" -#include "ieee802154_utils.h" -#include "ieee802154_radio_utils.h" - -static inline int aloha_radio_send(struct net_if *iface, - struct net_pkt *pkt, - struct net_buf *frag) +static inline int aloha_channel_access(struct net_if *iface) { - /* See section 6.7.4.4 - Retransmissions. */ - uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; - struct ieee802154_context *ctx = net_if_l2_data(iface); - bool ack_required; - int ret = -EIO; - - NET_DBG("frag %p", frag); - - while (remaining_attempts) { - remaining_attempts--; - - ack_required = prepare_for_ack(ctx, pkt, frag); - - if (!ack_required) { - /* See section 6.7.4.4: "A device that sends a frame with the AR field set - * to indicate no acknowledgment requested may assume that the transmission - * was successfully received and shall not perform the retransmission - * procedure." - */ - remaining_attempts = 0; - } - - ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, - pkt, frag); - if (ret) { - continue; - } - - ret = wait_for_ack(iface, ack_required); - if (!ret) { - break; - } - } + ARG_UNUSED(iface); - return ret; + /* CCA Mode 4: ALOHA. CCA shall always report an idle medium, see section 10.2.8. */ + return 0; } -static enum net_verdict aloha_radio_handle_ack(struct net_if *iface, - struct net_pkt *pkt) -{ - struct ieee802154_context *ctx = net_if_l2_data(iface); - - if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && - ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { - return NET_OK; - } - - return handle_ack(ctx, pkt); -} - -/* Declare the public Radio driver function used by the HW drivers */ -FUNC_ALIAS(aloha_radio_send, - ieee802154_radio_send, int); - -FUNC_ALIAS(aloha_radio_handle_ack, - ieee802154_radio_handle_ack, enum net_verdict); +/* Declare the public channel access algorithm function used by L2. */ +FUNC_ALIAS(aloha_channel_access, ieee802154_wait_for_clear_channel, int); diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index 708cad22fc67..fc43fca9dd3b 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -9,122 +9,64 @@ #include LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); -#include -#include #include - -#include +#include +#include #include +#include -#include #include +#include -#include "ieee802154_frame.h" +#include "ieee802154_priv.h" #include "ieee802154_utils.h" -#include "ieee802154_radio_utils.h" BUILD_ASSERT(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE <= CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE, "The CSMA/CA min backoff exponent must be less or equal max backoff exponent."); /* See section 6.2.5.1. */ -static inline int unslotted_csma_ca_radio_send(struct net_if *iface, struct net_pkt *pkt, - struct net_buf *frag) +static inline int unslotted_csma_ca_channel_access(struct net_if *iface) { uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE; - struct ieee802154_context *ctx = net_if_l2_data(iface); uint32_t symbol_period, turnaround_time; - uint8_t remaining_attempts; - bool ack_required; bool is_subg_phy; - uint8_t nb = 0U; - int ret; - - NET_DBG("frag %p", frag); is_subg_phy = ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ; /* TODO: Move symbol period calculation to radio driver. */ symbol_period = IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy); turnaround_time = IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy); - /* See section 6.7.4.4 - Retransmissions. */ - remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; + for (uint8_t nb = 0U; nb <= CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; nb++) { + int ret; - while (remaining_attempts) { - remaining_attempts--; + if (be) { + uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1); - while (1) { - if (be) { - uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1); - - /* TODO: k_busy_wait() is too inaccurate on many platforms, the - * radio API should expose a precise radio clock instead (which may - * fall back to k_busy_wait() if the radio does not have a clock). - */ - k_busy_wait(bo_n * IEEE802154_A_UNIT_BACKOFF_PERIOD_US( - turnaround_time, symbol_period)); - } - - ret = ieee802154_cca(iface); - if (ret == 0) { - /* Channel is idle -> CSMA Success */ - break; - } else if (ret != -EBUSY) { - /* CCA exited with failure code. */ - return -EIO; - } - - /* Channel is not idle -> CSMA Backoff */ - be = MIN(be + 1, CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE); - nb++; - - if (nb > CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO) { - return -EIO; - } - } - - ack_required = prepare_for_ack(ctx, pkt, frag); - - if (!ack_required) { - /* See section 6.7.4.4: "A device that sends a frame with the AR field set - * to indicate no acknowledgment requested may assume that the transmission - * was successfully received and shall not perform the retransmission - * procedure." + /* TODO: k_busy_wait() is too inaccurate on many platforms, the + * radio API should expose a precise radio clock instead (which may + * fall back to k_busy_wait() if the radio does not have a clock). */ - remaining_attempts = 0; + k_busy_wait(bo_n * IEEE802154_A_UNIT_BACKOFF_PERIOD_US(turnaround_time, + symbol_period)); } - ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, - pkt, frag); - if (ret) { - continue; + ret = ieee802154_cca(iface); + if (ret == 0) { + /* Channel is idle -> CSMA Success */ + return 0; + } else if (ret != -EBUSY) { + /* CCA exited with failure code -> CSMA Abort */ + return -EIO; } - ret = wait_for_ack(iface, ack_required); - if (!ret) { - break; - } - } - - return ret; -} - -static enum net_verdict csma_ca_radio_handle_ack(struct net_if *iface, - struct net_pkt *pkt) -{ - struct ieee802154_context *ctx = net_if_l2_data(iface); - - if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && - ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { - return NET_OK; + /* Channel is busy -> CSMA Backoff */ + be = MIN(be + 1, CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE); } - return handle_ack(ctx, pkt); + /* Channel is still busy after max backoffs -> CSMA Failure */ + return -EBUSY; } -/* Declare the public Radio driver function used by the HW drivers */ -FUNC_ALIAS(unslotted_csma_ca_radio_send, - ieee802154_radio_send, int); - -FUNC_ALIAS(csma_ca_radio_handle_ack, - ieee802154_radio_handle_ack, enum net_verdict); +/* Declare the public channel access algorithm function used by L2. */ +FUNC_ALIAS(unslotted_csma_ca_channel_access, ieee802154_wait_for_clear_channel, int); diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_utils.h b/subsys/net/l2/ieee802154/ieee802154_radio_utils.h deleted file mode 100644 index 1c1b4a12de50..000000000000 --- a/subsys/net/l2/ieee802154/ieee802154_radio_utils.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief IEEE 802.15.4 low level radio helper utilities - * - * All references to the spec refer to IEEE 802.15.4-2020. - */ - -#ifndef __IEEE802154_RADIO_UTILS_H__ -#define __IEEE802154_RADIO_UTILS_H__ - -#include "ieee802154_utils.h" - -/** - * @brief Radio driver sending function that radio drivers should implement - * - * @param iface A valid pointer on a network interface to send from - * @param pkt A valid pointer on a packet to send - * - * @return 0 on success, negative value otherwise - */ -extern int ieee802154_radio_send(struct net_if *iface, - struct net_pkt *pkt, - struct net_buf *frag); - -static inline bool prepare_for_ack(struct ieee802154_context *ctx, - struct net_pkt *pkt, - struct net_buf *frag) -{ - if (ieee802154_is_ar_flag_set(frag)) { - struct ieee802154_fcf_seq *fs; - - fs = (struct ieee802154_fcf_seq *)frag->data; - - ctx->ack_seq = fs->sequence; - ctx->ack_received = false; - k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); - - return true; - } - - return false; -} - -static inline int wait_for_ack(struct net_if *iface, - bool ack_required) -{ - struct ieee802154_context *ctx = net_if_l2_data(iface); - - - if (!ack_required || - (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { - return 0; - } - - if (k_sem_take(&ctx->ack_lock, K_MSEC(10)) == 0) { - /* - * We reinit the semaphore in case handle_ack() - * got called multiple times. - */ - k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); - } - - ctx->ack_seq = 0U; - - return ctx->ack_received ? 0 : -EIO; -} - -static inline int handle_ack(struct ieee802154_context *ctx, - struct net_pkt *pkt) -{ - if (pkt->buffer->len == IEEE802154_ACK_PKT_LENGTH) { - uint8_t len = IEEE802154_ACK_PKT_LENGTH; - struct ieee802154_fcf_seq *fs; - - fs = ieee802154_validate_fc_seq(net_pkt_data(pkt), NULL, &len); - if (!fs || fs->sequence != ctx->ack_seq) { - return NET_CONTINUE; - } - - ctx->ack_received = true; - k_sem_give(&ctx->ack_lock); - - return NET_OK; - } - - return NET_CONTINUE; -} - -#endif /* __IEEE802154_RADIO_UTILS_H__ */ diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index b7f4a3d55229..69ab7d68c15c 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(net_ieee802154_test, LOG_LEVEL_DBG); #include #include #include +#include #include #include #include @@ -22,7 +23,7 @@ LOG_MODULE_REGISTER(net_ieee802154_test, LOG_LEVEL_DBG); #include "net_private.h" #include -#include +#include #include struct ieee802154_pkt_test { @@ -456,7 +457,7 @@ static bool test_wait_for_ack(struct ieee802154_pkt_test *t) goto out; } - ack_required = prepare_for_ack(ctx, tx_pkt, tx_pkt->frags); + ack_required = ieee802154_prepare_for_ack(ctx, tx_pkt, tx_pkt->frags); if (!ack_required) { NET_ERR("*** Expected AR flag to be set\n"); goto release_tx_pkt; @@ -481,12 +482,12 @@ static bool test_wait_for_ack(struct ieee802154_pkt_test *t) pkt_hexdump(net_pkt_data(ack_pkt), net_pkt_get_len(ack_pkt)); - if (handle_ack(ctx, ack_pkt) != NET_OK) { + if (ieee802154_radio_handle_ack(iface, ack_pkt) != NET_OK) { NET_ERR("*** Ack frame was not handled.\n"); goto release_ack_pkt; } - if (wait_for_ack(iface, ack_required) != 0) { + if (ieee802154_wait_for_ack(iface, ack_required) != 0) { NET_ERR("*** Ack frame was not recorded.\n"); goto release_ack_pkt; } From 1ee4d3ed774862e33f657e6b159f4c5aa707bd63 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 2 Jun 2023 19:56:49 +0200 Subject: [PATCH 0325/2042] net: l2: ieee802154: document L1/L2 sep. of concerns The method ieee802154_radio_handle_ack() does not belong to the PHY/radio layer but to the L2 layer. It is a callback called from the radio layer into the L2 layer and to be implemented by all L2 stacks. This is the same pattern as is used for ieee802154_init(). The '_radio_' infix in this function is therefore confusing and conceptually wrong. This change fixes the naming inconsistency and extensively documents its rationale. It is assumed that the change can be made without prior deprecation of the existing method as in the rare cases where users have implemented custom radio drivers these will break in obvious ways and can easily be fixed. Nevertheless such a rename would not be justified on its own if it were not for an important conceptual reason: The renamed function represents a generic "inversion-of-control" pattern which will become important in the TSCH context: It allows for clean separation of concerns between the PHY/radio driver layer and the MAC/L2 layer even in situations where the radio driver needs to be involved for performance or deterministic timing reasons. This "inversion-of-control" pattern can be applied to negotiate timing sensitive reception and transmission windows, it let's the L2 layer deterministically timestamp information elements just-in-time with internal radio timer counter values, etc. Signed-off-by: Florian Grandel --- doc/connectivity/networking/api/net_l2.rst | 72 ++++++++++++++----- drivers/ieee802154/ieee802154_b91.c | 2 +- drivers/ieee802154/ieee802154_cc1200.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 +- include/zephyr/net/ieee802154_radio.h | 35 ++++++--- modules/openthread/platform/radio.c | 3 +- samples/net/wpan_serial/src/main.c | 2 +- samples/net/wpanusb/src/wpanusb.c | 2 +- subsys/net/l2/ieee802154/ieee802154.c | 2 +- tests/net/ieee802154/l2/src/ieee802154_test.c | 2 +- tests/subsys/openthread/radio_test.c | 2 +- 17 files changed, 95 insertions(+), 43 deletions(-) diff --git a/doc/connectivity/networking/api/net_l2.rst b/doc/connectivity/networking/api/net_l2.rst index 7fd43f812d81..1bf5249e5c2b 100644 --- a/doc/connectivity/networking/api/net_l2.rst +++ b/doc/connectivity/networking/api/net_l2.rst @@ -113,8 +113,8 @@ IEEE 802.15.4 device driver =========================== Device drivers for IEEE 802.15.4 L2 work basically the same as for -Ethernet. What has been described above, especially for ``recv()``, applies -here as well. There are two specific differences however: +Ethernet. What has been described above, especially for ``recv()``, applies +here as well. There are two specific differences however: - It requires a dedicated device driver API: :c:struct:`ieee802154_radio_api`, which overloads :c:struct:`net_if_api`. This is because 802.15.4 L2 needs more from the device @@ -123,24 +123,58 @@ here as well. There are two specific differences however: IEEE 802.15.4 device driver must provide a valid pointer on such relevantly filled-in API structure. -- Sending a packet is slightly different than in Ethernet. IEEE 802.15.4 sends - relatively small frames, 127 bytes all inclusive: frame header, - payload and frame checksum. Buffers are meant to fit such - frame size limitation. But a buffer containing an IPv6/UDP packet - might have more than one fragment. IEEE 802.15.4 drivers - handle only one buffer at a time. This is why the +- Sending a packet is slightly different than in Ethernet. Most IEEE 802.15.4 + PHYs support relatively small frames only, 127 bytes all inclusive: frame + header, payload and frame checksum. Buffers to be sent over the radio will + often not fit this frame size limitation, e.g. a buffer containing an IPv6 + packet will often have to be split into several fragments and IP6 packet headers + and fragments need to be compressed using a protocol like 6LoWPAN before being + passed on to the radio driver. Additionally the IEEE 802.15.4 standard defines + medium access (e.g. CSMA/CA), frame retransmission, encryption and other pre- + processing procedures (e.g. addition of information elements) that individual + radio drivers should not have to care about. This is why the :c:struct:`ieee802154_radio_api` requires a tx function pointer which differs - from the :c:struct:`net_if_api` send function pointer. - Instead, the IEEE 802.15.4 L2, provides a generic - :c:func:`ieee802154_radio_send` meant to be given as - :c:type:`net_if` send function. It turn, the implementation - of :c:func:`ieee802154_radio_send` will ensure the same behavior: - sending one buffer at a time through :c:type:`ieee802154_radio_api` tx - function, and unreferencing the network packet - only when all the transmission were successful. - -Each IEEE 802.15.4 device driver, in the end, will need to call -``NET_DEVICE_INIT_INSTANCE()`` that way: + from the :c:struct:`net_if_api` send function pointer. Zephyr's native + IEEE 802.15.4 L2 implementation provides a generic :c:func:`ieee802154_send` + instead, meant to be given as :c:type:`net_if` send function. The implementation + of :c:func:`ieee802154_send` takes care of IEEE 802.15.4 standard packet + preparation procedures, splitting the packet into possibly compressed, + encrypted and otherwise pre-processed fragment buffers, sending one buffer + at a time through :c:type:`ieee802154_radio_api` tx function and unreferencing + the network packet only when the transmission as a whole was either successful + or failed. + +Interaction between IEEE 802.15.4 radio device drivers and L2 is bidirectional: + +- L2 -> L1: Methods as :c:func:`ieee802154_send` and several IEEE 802.15.4 net + management calls will call into the driver, e.g. to send a packet over the + radio link or re-configure the driver at runtime. These incoming calls will + all be handled by the methods in the :c:type:`ieee802154_radio_api`. + +- L1 -> L2: There are several situations in which the driver needs to initiate + calls into the L2/MAC layer. Zephyr's IEEE 802.15.4 L1 -> L2 adaptation API + employs an "inversion-of-control" pattern in such cases avoids duplication of + complex logic across independent driver implementations and ensures + implementation agnostic loose coupling and clean separation of concerns between + MAC (L2) and PHY (L1) whenever reverse information transfer or close co-operation + between hardware and L2 is required. During driver initialization, for example, + the driver calls :c:func:`ieee802154_init` to pass the interface's MAC address + as well as other hardware-related configuration to L2. Similarly, drivers may + indicate performance or timing critical radio events to L2 that require close + integration with the hardware (e.g. :c:func:`ieee802154_handle_ack`). Calls + from L1 into L2 are not implemented as methods in :c:type:`ieee802154_radio_api` + but are standalone functions declared and documented as such in + :zephyr_file:`include/zephyr/net/ieee802154_radio.h`. The API documentation will + clearly state which functions must be implemented by all L2 stacks as part + of the L1 -> L2 "inversion-of-control" adaptation API. + +Note: Standalone functions in :zephyr_file:`include/zephyr/net/ieee802154_radio.h` +that are not explicitly documented as callbacks are considered to be helper functions +within the PHY (L1) layer implemented independently of any specific L2 stack, see for +example :c:func:`ieee802154_is_ar_flag_set`. + +As all net interfaces, IEEE 802.15.4 device driver implementations will have to call +``NET_DEVICE_INIT_INSTANCE()`` in the end: .. code-block:: c diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index 14f79db01c18..04d4396e7600 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -227,7 +227,7 @@ static void b91_handle_ack(void) net_pkt_cursor_init(ack_pkt); /* handle ack */ - if (ieee802154_radio_handle_ack(data.iface, ack_pkt) != NET_OK) { + if (ieee802154_handle_ack(data.iface, ack_pkt) != NET_OK) { LOG_INF("ACK packet not handled - releasing."); } diff --git a/drivers/ieee802154/ieee802154_cc1200.c b/drivers/ieee802154/ieee802154_cc1200.c index fabbd1fe1061..7f9efa302ccd 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -486,7 +486,7 @@ static void cc1200_rx(void *arg) goto out; } - if (ieee802154_radio_handle_ack(cc1200->iface, pkt) == NET_OK) { + if (ieee802154_handle_ack(cc1200->iface, pkt) == NET_OK) { LOG_DBG("ACK packet handled"); goto out; } diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index 417d208c1d58..0bf1ce728a21 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -637,7 +637,7 @@ static void cc2520_rx(void *arg) goto out; } - if (ieee802154_radio_handle_ack(cc2520->iface, pkt) == NET_OK) { + if (ieee802154_handle_ack(cc2520->iface, pkt) == NET_OK) { LOG_DBG("ACK packet handled"); goto out; } diff --git a/drivers/ieee802154/ieee802154_dw1000.c b/drivers/ieee802154/ieee802154_dw1000.c index efeded45734b..421f66cb99e5 100644 --- a/drivers/ieee802154/ieee802154_dw1000.c +++ b/drivers/ieee802154/ieee802154_dw1000.c @@ -491,7 +491,7 @@ static inline void dwt_irq_handle_rx(const struct device *dev, uint32_t sys_stat flags_to_clear |= DWT_SYS_STATUS_AAT; } - if (ieee802154_radio_handle_ack(ctx->iface, pkt) == NET_OK) { + if (ieee802154_handle_ack(ctx->iface, pkt) == NET_OK) { LOG_INF("ACK packet handled"); goto rx_out_unref_pkt; } diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index b68cd49b81c1..abecf68e25f1 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -606,7 +606,7 @@ static void handle_ack(struct kw41z_context *kw41z, uint8_t seq_number) net_pkt_cursor_init(ack_pkt); - if (ieee802154_radio_handle_ack(kw41z->iface, ack_pkt) != NET_OK) { + if (ieee802154_handle_ack(kw41z->iface, ack_pkt) != NET_OK) { LOG_INF("ACK packet not handled - releasing."); } diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index 110d0df04b32..0cb1c318a50f 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -581,7 +581,7 @@ static inline void mcr20a_rx(const struct device *dev, uint8_t len) goto out; } - if (ieee802154_radio_handle_ack(mcr20a->iface, pkt) == NET_OK) { + if (ieee802154_handle_ack(mcr20a->iface, pkt) == NET_OK) { LOG_DBG("ACK packet handled"); goto out; } diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 426d90578a62..bef2f3f35ea5 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -412,7 +412,7 @@ static int handle_ack(struct nrf5_802154_data *nrf5_radio) net_pkt_cursor_init(ack_pkt); - if (ieee802154_radio_handle_ack(nrf5_radio->iface, ack_pkt) != NET_OK) { + if (ieee802154_handle_ack(nrf5_radio->iface, ack_pkt) != NET_OK) { LOG_INF("ACK packet not handled - releasing."); } diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index 8e8947e56beb..c8853e49ed3b 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -629,7 +629,7 @@ static void rf2xx_handle_ack(struct rf2xx_context *ctx, struct net_buf *frag) net_pkt_cursor_init(&rf2xx_ack_pkt); - if (ieee802154_radio_handle_ack(ctx->iface, &rf2xx_ack_pkt) != NET_OK) { + if (ieee802154_handle_ack(ctx->iface, &rf2xx_ack_pkt) != NET_OK) { LOG_INF("ACK packet not handled."); } } diff --git a/drivers/ieee802154/ieee802154_uart_pipe.c b/drivers/ieee802154/ieee802154_uart_pipe.c index 522e92c9cf98..158097e2ad2d 100644 --- a/drivers/ieee802154/ieee802154_uart_pipe.c +++ b/drivers/ieee802154/ieee802154_uart_pipe.c @@ -154,7 +154,7 @@ static uint8_t *upipe_rx(uint8_t *buf, size_t *off) } #endif - if (ieee802154_radio_handle_ack(upipe->iface, pkt) == NET_OK) { + if (ieee802154_handle_ack(upipe->iface, pkt) == NET_OK) { LOG_DBG("ACK packet handled"); goto out; } diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index c599be9b9c0b..d877e3c7a2d8 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -455,26 +455,45 @@ static inline bool ieee802154_is_ar_flag_set(struct net_buf *frag) } /** - * @brief Radio driver ACK handling function that hw drivers should use + * @brief Radio driver ACK handling callback into L2 that radio + * drivers must call when receiving an ACK package. * - * @details ACK handling requires fast handling and thus such function - * helps to hook directly the hw drivers to the radio driver. + * @details The IEEE 802.15.4 standard prescribes generic procedures for ACK + * handling on L2 (MAC) level. L2 stacks therefore have to provides a + * fast and re-usable generic implementation of this callback for + * radio drivers to call when receiving an ACK packet. + * + * Note: This function is part of Zephyr's 802.15.4 stack L1 -> L2 + * "inversion-of-control" adaptation API and must be implemented by + * all IEEE 802.15.4 L2 stacks. * * @param iface A valid pointer on a network interface that received the packet * @param pkt A valid pointer on a packet to check * - * @return NET_OK if it was handled, NET_CONTINUE otherwise + * @return NET_OK if L2 handles the ACK package, NET_CONTINUE or NET_DROP otherwise. + * + * Note: Deviating from other functions in the net stack returning net_verdict, + * this function will not unref the package even if it returns NET_OK. + * + * TODO: Fix this deviating behavior. */ -extern enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, - struct net_pkt *pkt); +extern enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt); /** - * @brief Initialize L2 stack for a given interface + * @brief Radio driver initialization callback into L2 called by radio drivers + * to initialize the active L2 stack for a given interface. + * + * @details Radio drivers must call this function as part of their own + * initialization routine. + * + * Note: This function is part of Zephyr's 802.15.4 stack L1 -> L2 + * "inversion-of-control" adaptation API and must be implemented by + * all IEEE 802.15.4 L2 stacks. * * @param iface A valid pointer on a network interface */ #ifndef CONFIG_IEEE802154_RAW_MODE -void ieee802154_init(struct net_if *iface); +extern void ieee802154_init(struct net_if *iface); #else #define ieee802154_init(_iface_) #endif /* CONFIG_IEEE802154_RAW_MODE */ diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 582a1cff5c62..523d49bd8aa0 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -154,8 +154,7 @@ void energy_detected(const struct device *dev, int16_t max_ed) } } -enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, - struct net_pkt *pkt) +enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt) { ARG_UNUSED(iface); diff --git a/samples/net/wpan_serial/src/main.c b/samples/net/wpan_serial/src/main.c index 196c25f2ef90..33ac597ef91d 100644 --- a/samples/net/wpan_serial/src/main.c +++ b/samples/net/wpan_serial/src/main.c @@ -521,7 +521,7 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) return 0; } -enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, struct net_pkt *pkt) +enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt) { return NET_CONTINUE; } diff --git a/samples/net/wpanusb/src/wpanusb.c b/samples/net/wpanusb/src/wpanusb.c index 5f80bfc9ccb4..a4e1f88403f3 100644 --- a/samples/net/wpanusb/src/wpanusb.c +++ b/samples/net/wpanusb/src/wpanusb.c @@ -414,7 +414,7 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) return ret; } -enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, struct net_pkt *pkt) +enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt) { return NET_CONTINUE; } diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index ee8f3356fe85..290a9b1aaee0 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -113,7 +113,7 @@ inline bool ieee802154_prepare_for_ack(struct ieee802154_context *ctx, struct ne return false; } -enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, struct net_pkt *pkt) +enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt) { struct ieee802154_context *ctx = net_if_l2_data(iface); diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index 69ab7d68c15c..570ab1268a5d 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -482,7 +482,7 @@ static bool test_wait_for_ack(struct ieee802154_pkt_test *t) pkt_hexdump(net_pkt_data(ack_pkt), net_pkt_get_len(ack_pkt)); - if (ieee802154_radio_handle_ack(iface, ack_pkt) != NET_OK) { + if (ieee802154_handle_ack(iface, ack_pkt) != NET_OK) { NET_ERR("*** Ack frame was not handled.\n"); goto release_ack_pkt; } diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index d791f964f097..c7837016927d 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -245,7 +245,7 @@ static void create_ack_frame(void) net_pkt_set_ieee802154_rssi_dbm(packet, rssi); net_pkt_set_ieee802154_lqi(packet, lqi); - zassert_equal(ieee802154_radio_handle_ack(NULL, packet), NET_OK, "Handling ack failed."); + zassert_equal(ieee802154_handle_ack(NULL, packet), NET_OK, "Handling ack failed."); net_pkt_unref(packet); } From f96b620d1283b7b60764914c37043c7e0d3614c4 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 3 Jun 2023 14:38:36 +0200 Subject: [PATCH 0326/2042] net: l2: ieee802154: properly handle TX HW capabilities The existing calls to ieee802154_radio_send() and soft MAC ACK handling were inconsistent and/or not properly integrated with more recent radio driver capabilities as CSMA/CA and ACK in hardware. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 8 ++ drivers/ieee802154/ieee802154_cc2520.c | 1 + include/zephyr/net/ieee802154_radio.h | 33 +++++++-- subsys/net/l2/ieee802154/ieee802154.c | 73 ++++++++++--------- subsys/net/l2/ieee802154/ieee802154_priv.h | 5 +- tests/net/ieee802154/l2/src/ieee802154_test.c | 3 +- 6 files changed, 77 insertions(+), 46 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 7e76bd2e2acf..1ee58e15fbba 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -361,12 +361,20 @@ static int ieee802154_cc13xx_cc26xx_tx(const struct device *dev, } if (drv_data->cmd_ieee_csma.status != IEEE_DONE_OK) { + /* TODO: According to IEEE 802.15.4 CSMA/CA failure + * fails TX immediately and should not trigger + * attempt (which is reserved for ACK timeouts). + */ LOG_DBG("Channel access failure (0x%x)", drv_data->cmd_ieee_csma.status); continue; } if (drv_data->cmd_ieee_tx.status != IEEE_DONE_OK) { + /* TODO: According to IEEE 802.15.4 transmission failure + * fails TX immediately and should not trigger + * attempt (which is reserved for ACK timeouts). + */ LOG_DBG("Transmit failed (0x%x)", drv_data->cmd_ieee_tx.status); continue; diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index 0bf1ce728a21..54e62695af68 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -817,6 +817,7 @@ static int cc2520_tx(const struct device *dev, goto error; } + /* TODO: Implement standard conforming CSMA/CA or use the soft MAC's default. */ k_sem_take(&cc2520->tx_sync, K_MSEC(10)); retry--; diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index d877e3c7a2d8..06f052174f43 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -165,13 +165,22 @@ enum ieee802154_tx_mode { /** Perform CCA before packet transmission. */ IEEE802154_TX_MODE_CCA, - /** Perform full CSMA CA procedure before packet transmission. */ + /** + * Perform full CSMA CA procedure before packet transmission. + * Requires IEEE802154_HW_CSMA capability. + */ IEEE802154_TX_MODE_CSMA_CA, - /** Transmit packet in the future, at specified time, no CCA. */ + /** + * Transmit packet in the future, at specified time, no CCA. + * Requires IEEE802154_HW_TXTIME capability. + */ IEEE802154_TX_MODE_TXTIME, - /** Transmit packet in the future, perform CCA before transmission. */ + /** + * Transmit packet in the future, perform CCA before transmission. + * Requires IEEE802154_HW_TXTIME capability. + */ IEEE802154_TX_MODE_TXTIME_CCA, }; @@ -195,12 +204,14 @@ enum ieee802154_config_type { * provided with ``IEEE802154_CONFIG_ACK_FPB`` config and FPB address * matching mode specified. Otherwise, Frame Pending bit should be set * to ``1`` (see section 6.7.3). + * Requires IEEE802154_HW_TX_RX_ACK capability. */ IEEE802154_CONFIG_AUTO_ACK_FPB, /** Indicates whether to set ACK Frame Pending bit for specific address * or not. Disabling the Frame Pending bit with no address provided * (NULL pointer) should disable it for all enabled addresses. + * Requires IEEE802154_HW_TX_RX_ACK capability. */ IEEE802154_CONFIG_ACK_FPB, @@ -227,8 +238,9 @@ enum ieee802154_config_type { IEEE802154_CONFIG_FRAME_COUNTER_IF_LARGER, - /** Configure a radio reception slot. This can be used for any scheduler reception, e.g.: + /** Configure a radio reception slot. This can be used for any scheduled reception, e.g.: * Zigbee GP device, CSL, TSCH, etc. + * Requires IEEE802154_HW_RXTIME capability. */ IEEE802154_CONFIG_RX_SLOT, @@ -380,7 +392,7 @@ struct ieee802154_radio_api { /** Set current channel, channel is in CPU byte order. */ int (*set_channel)(const struct device *dev, uint16_t channel); - /** Set/Unset filters (for IEEE802154_HW_FILTER ) */ + /** Set/Unset filters. Requires IEEE802154_HW_FILTER capability. */ int (*filter)(const struct device *dev, bool set, enum ieee802154_filter_type type, @@ -410,24 +422,31 @@ struct ieee802154_radio_api { enum ieee802154_config_type type, const struct ieee802154_config *config); - /** Get the available amount of Sub-GHz channels */ + /** + * Get the available amount of Sub-GHz channels + * TODO: Replace with a combination of channel page and channel attributes. + */ uint16_t (*get_subg_channel_count)(const struct device *dev); /** Run an energy detection scan. * Note: channel must be set prior to request this function. * duration parameter is in ms. + * Requires IEEE802154_HW_ENERGY_SCAN capability. */ int (*ed_scan)(const struct device *dev, uint16_t duration, energy_scan_done_cb_t done_cb); - /** Get the current radio time in microseconds */ + /** Get the current radio time in microseconds + * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. + */ uint64_t (*get_time)(const struct device *dev); /** Get the current accuracy, in units of ± ppm, of the clock used for * scheduling delayed receive or transmit radio operations. * Note: Implementations may optimize this value based on operational * conditions (i.e.: temperature). + * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. */ uint8_t (*get_sch_acc)(const struct device *dev); }; diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 290a9b1aaee0..5573c1b1e6ad 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -94,14 +94,18 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 #define ieee802154_acknowledge(...) #endif /* CONFIG_NET_L2_IEEE802154_ACK_REPLY */ -inline bool ieee802154_prepare_for_ack(struct ieee802154_context *ctx, struct net_pkt *pkt, +inline bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) { - /* TODO: Only execute when the driver does not handle ACK itself. */ - if (ieee802154_is_ar_flag_set(frag)) { - struct ieee802154_fcf_seq *fs; + bool ack_required = ieee802154_is_ar_flag_set(frag); + + if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { + return ack_required; + } - fs = (struct ieee802154_fcf_seq *)frag->data; + if (ack_required) { + struct ieee802154_fcf_seq *fs = (struct ieee802154_fcf_seq *)frag->data; + struct ieee802154_context *ctx = net_if_l2_data(iface); ctx->ack_seq = fs->sequence; ctx->ack_received = false; @@ -117,13 +121,9 @@ enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt { struct ieee802154_context *ctx = net_if_l2_data(iface); - /* TODO: Only execute when the driver does not handle ACK itself. */ - - /* TODO: ACK/Retransmission has nothing to do with CSMA/CA - this - * is about retransmission. - */ - if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && - ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { + if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { + __ASSERT_NO_MSG(ctx->ack_seq == 0U); + /* TODO: Release packet in L2 as we're taking ownership. */ return NET_OK; } @@ -151,6 +151,7 @@ inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) struct ieee802154_context *ctx = net_if_l2_data(iface); if (!ack_required || (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { + __ASSERT_NO_MSG(ctx->ack_seq == 0U); return 0; } @@ -168,29 +169,40 @@ inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) { - struct ieee802154_context *ctx = net_if_l2_data(iface); - - bool ack_required; + bool hw_csma, ack_required; int ret; NET_DBG("frag %p", frag); - /* See section 6.7.4.4 - Retransmissions. */ + hw_csma = IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && + ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA; + + + /* Media access (CSMA, ALOHA, ...) and retransmission, see section 6.7.4.4. */ for (uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; remaining_attempts > 0; remaining_attempts--) { - ret = ieee802154_wait_for_clear_channel(iface); - if (ret != 0) { - NET_WARN("Clear channel assessment failed: dropping fragment %p on " - "interface %p.", - frag, iface); - return ret; + if (!hw_csma) { + ret = ieee802154_wait_for_clear_channel(iface); + if (ret != 0) { + NET_WARN("Clear channel assessment failed: dropping fragment %p on " + "interface %p.", + frag, iface); + return ret; + } } - ack_required = ieee802154_prepare_for_ack(ctx, pkt, frag); + /* No-op in case the driver has IEEE802154_HW_TX_RX_ACK capability. */ + ack_required = ieee802154_prepare_for_ack(iface, pkt, frag); - ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, frag); + /* TX including: + * - CSMA/CA in case the driver has IEEE802154_HW_CSMA capability, + * - waiting for ACK in case the driver has IEEE802154_HW_TX_RX_ACK capability. + */ + ret = ieee802154_tx( + iface, hw_csma ? IEEE802154_TX_MODE_CSMA_CA : IEEE802154_TX_MODE_DIRECT, + pkt, frag); if (ret) { - /* Unknown transmission failure. */ + /* Transmission failure. */ return ret; } @@ -204,6 +216,7 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ } + /* No-op in case the driver has IEEE802154_HW_TX_RX_ACK capability. */ ret = ieee802154_wait_for_ack(iface, ack_required); if (ret == 0) { /* ACK received - transmission is successful. */ @@ -517,15 +530,7 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) return -EINVAL; } - if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && - ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) { - /* CSMA in hardware */ - ret = ieee802154_tx(iface, IEEE802154_TX_MODE_CSMA_CA, pkt, frame_buf); - } else { - /* Media access (direct, CSMA, ALOHA, ...) in software */ - ret = ieee802154_radio_send(iface, pkt, frame_buf); - } - + ret = ieee802154_radio_send(iface, pkt, frame_buf); if (ret) { return ret; } diff --git a/subsys/net/l2/ieee802154/ieee802154_priv.h b/subsys/net/l2/ieee802154/ieee802154_priv.h index c1d63fb84217..707f86893a9c 100644 --- a/subsys/net/l2/ieee802154/ieee802154_priv.h +++ b/subsys/net/l2/ieee802154/ieee802154_priv.h @@ -68,14 +68,13 @@ int ieee802154_wait_for_clear_channel(struct net_if *iface); * * See sections 6.7.4.1 through 6.7.4.3. * - * @param ctx A valid pointer to the IEEE 802.15.4 context + * @param iface A valid pointer on the network the packet will be transmitted to * @param pkt A valid pointer on a packet to send * @param frag The fragment that needs to be acknowledged * * @return true if the given packet requires acknowlegement, false otherwise. */ -bool ieee802154_prepare_for_ack(struct ieee802154_context *ctx, struct net_pkt *pkt, - struct net_buf *frag); +bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag); /** * @brief Waits for ACK reception on the TX path with standard compliant timeout settings, i.e. diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index 570ab1268a5d..2e5e683f4b8e 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -443,7 +443,6 @@ static bool test_ns_sending(struct ieee802154_pkt_test *t, bool with_short_addr) static bool test_wait_for_ack(struct ieee802154_pkt_test *t) { - struct ieee802154_context *ctx = net_if_l2_data(iface); struct ieee802154_mpdu mpdu; struct net_pkt *ack_pkt; struct net_pkt *tx_pkt; @@ -457,7 +456,7 @@ static bool test_wait_for_ack(struct ieee802154_pkt_test *t) goto out; } - ack_required = ieee802154_prepare_for_ack(ctx, tx_pkt, tx_pkt->frags); + ack_required = ieee802154_prepare_for_ack(iface, tx_pkt, tx_pkt->frags); if (!ack_required) { NET_ERR("*** Expected AR flag to be set\n"); goto release_tx_pkt; From 7571be32610f739e3a437d42a5461f9fec85db48 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 3 Jun 2023 19:31:31 +0200 Subject: [PATCH 0327/2042] net: l2: ieee802154: deprecate NET_L2_IEEE802154_ACK_REPLY Acknowledgment is mandatory if legitimately requested by the package's "ACK requested" flag. The L2 layer will have to ensure that compliant ACK packages will always be sent out automatically as required by the standard. For IEEE 802.15.4 compliance, the NET_L2_IEEE802154_ACK_REPLY option is therefore being deprecated. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_b91.c | 4 +-- drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 6 ++-- .../ieee802154_cc13xx_cc26xx_subg.c | 6 +++- drivers/ieee802154/ieee802154_cc2520.c | 7 ++--- drivers/ieee802154/ieee802154_dw1000.c | 7 +++-- drivers/ieee802154/ieee802154_kw41z.c | 10 ++---- drivers/ieee802154/ieee802154_mcr20a.c | 7 ++--- drivers/ieee802154/ieee802154_nrf5.c | 1 + drivers/ieee802154/ieee802154_rf2xx.c | 2 ++ include/zephyr/net/ieee802154_radio.h | 30 +++++++++++------- subsys/net/l2/ieee802154/Kconfig | 12 ++----- subsys/net/l2/ieee802154/ieee802154.c | 31 +++++++++++++------ subsys/net/l2/ieee802154/ieee802154_frame.c | 2 -- subsys/net/l2/ieee802154/ieee802154_frame.h | 2 -- tests/net/all/prj.conf | 1 - tests/net/ieee802154/l2/prj.conf | 1 - 16 files changed, 67 insertions(+), 62 deletions(-) diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index 04d4396e7600..8361d3e8aa24 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -403,8 +403,8 @@ static enum ieee802154_hw_caps b91_get_capabilities(const struct device *dev) { ARG_UNUSED(dev); - return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | - IEEE802154_HW_FILTER | IEEE802154_HW_TX_RX_ACK; + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_FILTER | + IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_RX_TX_ACK; } /* API implementation: cca */ diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 1ee58e15fbba..71675ae9a90b 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -122,9 +122,9 @@ static void client_event_callback(RF_Handle h, RF_ClientEvent event, void *arg) static enum ieee802154_hw_caps ieee802154_cc13xx_cc26xx_get_capabilities(const struct device *dev) { - return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | - IEEE802154_HW_FILTER | IEEE802154_HW_TX_RX_ACK | - IEEE802154_HW_CSMA; + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_FILTER | + IEEE802154_HW_RX_TX_ACK | IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_CSMA | + IEEE802154_HW_RETRANSMISSION; } static int ieee802154_cc13xx_cc26xx_cca(const struct device *dev) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 958c397b3e61..b190bdc6e5d4 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -548,7 +548,6 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, continue; } - /* TODO: handle RX acknowledgment */ r = 0; goto out; @@ -612,6 +611,11 @@ static void ieee802154_cc13xx_cc26xx_subg_rx_done( ? IEEE802154_MAC_RSSI_DBM_UNDEFINED : rssi); + if (ieee802154_handle_ack(drv_data->iface, pkt) == NET_OK) { + net_pkt_unref(pkt); + continue; + } + if (net_recv_data(drv_data->iface, pkt)) { LOG_WRN("Packet dropped"); net_pkt_unref(pkt); diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index 54e62695af68..1b9183b8ccaa 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -667,10 +667,9 @@ static void cc2520_rx(void *arg) *******************/ static enum ieee802154_hw_caps cc2520_get_capabilities(const struct device *dev) { - /* ToDo: Add support for IEEE802154_HW_PROMISC */ - return IEEE802154_HW_FCS | - IEEE802154_HW_2_4_GHZ | - IEEE802154_HW_FILTER; + /* TODO: Add support for IEEE802154_HW_PROMISC */ + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_FILTER | + IEEE802154_HW_RX_TX_ACK; } static int cc2520_cca(const struct device *dev) diff --git a/drivers/ieee802154/ieee802154_dw1000.c b/drivers/ieee802154/ieee802154_dw1000.c index 421f66cb99e5..eca3cf794ec2 100644 --- a/drivers/ieee802154/ieee802154_dw1000.c +++ b/drivers/ieee802154/ieee802154_dw1000.c @@ -624,9 +624,10 @@ static void dwt_gpio_callback(const struct device *dev, static enum ieee802154_hw_caps dwt_get_capabilities(const struct device *dev) { - return IEEE802154_HW_FCS | - IEEE802154_HW_2_4_GHZ | /* FIXME: add IEEE802154_HW_UWB_PHY */ - IEEE802154_HW_FILTER; + /* TODO: Add channel page attribute with channel page four. */ + /* TODO: Implement HW-supported AUTOACK + frame pending bit handling. */ + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_FILTER | + IEEE802154_HW_TXTIME; } static uint32_t dwt_get_pkt_duration_ns(struct dwt_context *ctx, uint8_t psdu_len) diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index abecf68e25f1..3720ec0fd53a 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -359,10 +359,8 @@ static void kw41z_tmr3_disable(void) static enum ieee802154_hw_caps kw41z_get_capabilities(const struct device *dev) { - return IEEE802154_HW_FCS | - IEEE802154_HW_2_4_GHZ | - IEEE802154_HW_FILTER | - IEEE802154_HW_TX_RX_ACK; + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_FILTER | + IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_RX_TX_ACK; } static int kw41z_cca(const struct device *dev) @@ -666,10 +664,6 @@ static int kw41z_tx(const struct device *dev, enum ieee802154_tx_mode mode, /* Clear all IRQ flags */ ZLL->IRQSTS = ZLL->IRQSTS; - /* - * Current Zephyr 802.15.4 stack doesn't support ACK offload - */ - /* Perform automatic reception of ACK frame, if required */ if (ieee802154_is_ar_flag_set(frag)) { tx_timeout = kw41z->tx_warmup_time + KW41Z_SHR_PHY_TIME + diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index 0cb1c318a50f..368534e5a5ba 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -581,6 +581,7 @@ static inline void mcr20a_rx(const struct device *dev, uint8_t len) goto out; } + /* TODO: ieee802154_handle_ack() expects an ACK package. */ if (ieee802154_handle_ack(mcr20a->iface, pkt) == NET_OK) { LOG_DBG("ACK packet handled"); goto out; @@ -853,10 +854,8 @@ static int mcr20a_set_cca_mode(const struct device *dev, uint8_t mode) static enum ieee802154_hw_caps mcr20a_get_capabilities(const struct device *dev) { - return IEEE802154_HW_FCS | - IEEE802154_HW_2_4_GHZ | - IEEE802154_HW_TX_RX_ACK | - IEEE802154_HW_FILTER; + return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_TX_RX_ACK | + IEEE802154_HW_RX_TX_ACK | IEEE802154_HW_FILTER; } /* Note: CCA before TX is enabled by default */ diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index bef2f3f35ea5..f11c1953c2c7 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -224,6 +224,7 @@ static void nrf5_get_capabilities_at_boot(void) ((caps & NRF_802154_CAPABILITY_CSMA) ? IEEE802154_HW_CSMA : 0UL) | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_TX_RX_ACK | + IEEE802154_HW_RX_TX_ACK | IEEE802154_HW_ENERGY_SCAN | ((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? IEEE802154_HW_TXTIME : 0UL) | ((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? IEEE802154_HW_RXTIME : 0UL) | diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index c8853e49ed3b..ed2cacc17dac 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -365,7 +365,9 @@ static enum ieee802154_hw_caps rf2xx_get_capabilities(const struct device *dev) IEEE802154_HW_PROMISC | IEEE802154_HW_FILTER | IEEE802154_HW_CSMA | + IEEE802154_HW_RETRANSMISSION | IEEE802154_HW_TX_RX_ACK | + IEEE802154_HW_RX_TX_ACK | (ctx->trx_model == RF2XX_TRX_MODEL_212 ? IEEE802154_HW_SUB_GHZ : IEEE802154_HW_2_4_GHZ); diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 06f052174f43..ec8e7f4ae340 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -97,18 +97,24 @@ enum ieee802154_channel { }; enum ieee802154_hw_caps { - IEEE802154_HW_FCS = BIT(0), /* Frame Check-Sum supported */ - IEEE802154_HW_PROMISC = BIT(1), /* Promiscuous mode supported */ - IEEE802154_HW_FILTER = BIT(2), /* Filter PAN ID, long/short addr */ - IEEE802154_HW_CSMA = BIT(3), /* CSMA-CA supported */ - IEEE802154_HW_2_4_GHZ = BIT(4), /* 2.4Ghz radio supported */ - IEEE802154_HW_TX_RX_ACK = BIT(5), /* Handles ACK request on TX */ - IEEE802154_HW_SUB_GHZ = BIT(6), /* Sub-GHz radio supported */ - IEEE802154_HW_ENERGY_SCAN = BIT(7), /* Energy scan supported */ - IEEE802154_HW_TXTIME = BIT(8), /* TX at specified time supported */ - IEEE802154_HW_SLEEP_TO_TX = BIT(9), /* TX directly from sleep supported */ - IEEE802154_HW_TX_SEC = BIT(10), /* TX security handling supported */ - IEEE802154_HW_RXTIME = BIT(11), /* RX at specified time supported */ + IEEE802154_HW_FCS = BIT(0), /* Frame Check-Sum supported */ + IEEE802154_HW_PROMISC = BIT(1), /* Promiscuous mode supported */ + IEEE802154_HW_FILTER = BIT(2), /* Filter PAN ID, long/short addr */ + IEEE802154_HW_CSMA = BIT(3), /* Executes CSMA-CA procedure on TX */ + IEEE802154_HW_RETRANSMISSION = BIT(4), /* Handles retransmission on TX ACK timeout */ + IEEE802154_HW_TX_RX_ACK = BIT(5), /* Waits for ACK on TX if AR bit is set in TX pkt */ + IEEE802154_HW_RX_TX_ACK = BIT(6), /* Sends ACK on RX if AR bit is set in RX pkt */ + IEEE802154_HW_ENERGY_SCAN = BIT(7), /* Energy scan supported */ + IEEE802154_HW_TXTIME = BIT(8), /* TX at specified time supported */ + IEEE802154_HW_SLEEP_TO_TX = BIT(9), /* TX directly from sleep supported */ + IEEE802154_HW_TX_SEC = BIT(10), /* TX security handling supported */ + IEEE802154_HW_RXTIME = BIT(11), /* RX at specified time supported */ + IEEE802154_HW_2_4_GHZ = BIT(12), /* 2.4Ghz radio supported + * TODO: Replace with channel page attribute. + */ + IEEE802154_HW_SUB_GHZ = BIT(13), /* Sub-GHz radio supported + * TODO: Replace with channel page attribute. + */ }; enum ieee802154_filter_type { diff --git a/subsys/net/l2/ieee802154/Kconfig b/subsys/net/l2/ieee802154/Kconfig index aed2648b2af4..8239d00efa89 100644 --- a/subsys/net/l2/ieee802154/Kconfig +++ b/subsys/net/l2/ieee802154/Kconfig @@ -65,17 +65,9 @@ config NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET_TX endchoice -# TODO: For IEEE 802.15.4 compliance, this option will be removed in the future. -# Acknowledgment is mandatory if requested by the package's "ACK requested" -# flag. Drivers with hardware ACK support and otherwise the L2 layer will -# have to ensure that compliant ACK packages will always be sent out automatically -# as required by the standard. config NET_L2_IEEE802154_ACK_REPLY - bool "IEEE 802.15.4 ACK reply logic" - help - Enable sending of ACK replies when receiving packages that request - ACK. Note that if the HW driver has an AUTOACK feature, this should be - disabled to avoid duplicate ACK packages. + bool + select DEPRECATED choice prompt "Device features level support" diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 5573c1b1e6ad..c8b19c9478e3 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -67,11 +67,14 @@ static inline void pkt_hexdump(const char *title, struct net_pkt *pkt, bool in) #define pkt_hexdump(...) #endif /* CONFIG_NET_DEBUG_L2_IEEE802154_DISPLAY_PACKET */ -#ifdef CONFIG_NET_L2_IEEE802154_ACK_REPLY static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee802154_mpdu *mpdu) { struct net_pkt *pkt; + if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_RX_TX_ACK) { + return; + } + if (!mpdu->mhr.fs->fc.ar) { return; } @@ -90,9 +93,6 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 return; } -#else -#define ieee802154_acknowledge(...) -#endif /* CONFIG_NET_L2_IEEE802154_ACK_REPLY */ inline bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) @@ -132,7 +132,8 @@ enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt struct ieee802154_fcf_seq *fs; fs = ieee802154_validate_fc_seq(net_pkt_data(pkt), NULL, &len); - if (!fs || fs->sequence != ctx->ack_seq) { + if (!fs || fs->fc.frame_type != IEEE802154_FRAME_TYPE_ACK || + fs->sequence != ctx->ack_seq) { return NET_CONTINUE; } @@ -169,18 +170,26 @@ inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) { + uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; bool hw_csma, ack_required; int ret; NET_DBG("frag %p", frag); + if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_RETRANSMISSION) { + /* A driver that claims retransmission capability must also be able + * to wait for ACK frames otherwise it could not decide whether or + * not retransmission is required in a standard conforming way. + */ + __ASSERT_NO_MSG(ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK); + remaining_attempts = 1; + } + hw_csma = IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA; - /* Media access (CSMA, ALOHA, ...) and retransmission, see section 6.7.4.4. */ - for (uint8_t remaining_attempts = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES + 1; - remaining_attempts > 0; remaining_attempts--) { + while (remaining_attempts) { if (!hw_csma) { ret = ieee802154_wait_for_clear_channel(iface); if (ret != 0) { @@ -196,7 +205,9 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ /* TX including: * - CSMA/CA in case the driver has IEEE802154_HW_CSMA capability, - * - waiting for ACK in case the driver has IEEE802154_HW_TX_RX_ACK capability. + * - waiting for ACK in case the driver has IEEE802154_HW_TX_RX_ACK capability, + * - retransmission on ACK timeout in case the driver has + * IEEE802154_HW_RETRANSMISSION capability. */ ret = ieee802154_tx( iface, hw_csma ? IEEE802154_TX_MODE_CSMA_CA : IEEE802154_TX_MODE_DIRECT, @@ -222,6 +233,8 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ /* ACK received - transmission is successful. */ return 0; } + + remaining_attempts--; } return -EIO; diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 9f8f0ef749da..de9e9cc87698 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -903,7 +903,6 @@ void ieee802154_mac_cmd_finalize(struct net_pkt *pkt, enum ieee802154_cfi type) #endif /* CONFIG_NET_L2_IEEE802154_RFD */ -#ifdef CONFIG_NET_L2_IEEE802154_ACK_REPLY bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint8_t seq) { uint8_t *p_buf = net_pkt_data(pkt); @@ -925,7 +924,6 @@ bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint return true; } -#endif /* CONFIG_NET_L2_IEEE802154_ACK_REPLY */ #ifdef CONFIG_NET_L2_IEEE802154_SECURITY bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt, diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.h b/subsys/net/l2/ieee802154/ieee802154_frame.h index a4051da6b000..b69fa60ec78a 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.h +++ b/subsys/net/l2/ieee802154/ieee802154_frame.h @@ -490,9 +490,7 @@ static inline struct ieee802154_command *ieee802154_get_mac_command(struct net_p return (struct ieee802154_command *)(pkt->frags->data + pkt->frags->len); } -#ifdef CONFIG_NET_L2_IEEE802154_ACK_REPLY bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint8_t seq); -#endif #ifdef CONFIG_NET_L2_IEEE802154_SECURITY bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt, diff --git a/tests/net/all/prj.conf b/tests/net/all/prj.conf index cc8d19cfedc5..bb40e71fca18 100644 --- a/tests/net/all/prj.conf +++ b/tests/net/all/prj.conf @@ -80,7 +80,6 @@ CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO=4 CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE=3 CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE=5 CONFIG_NET_L2_IEEE802154=y -CONFIG_NET_L2_IEEE802154_ACK_REPLY=y CONFIG_NET_L2_IEEE802154_RFD=y CONFIG_NET_L2_IEEE802154_SHELL=y CONFIG_NET_L2_IEEE802154_FRAGMENT=y diff --git a/tests/net/ieee802154/l2/prj.conf b/tests/net/ieee802154/l2/prj.conf index 362634faf240..7d6dbc936b6d 100644 --- a/tests/net/ieee802154/l2/prj.conf +++ b/tests/net/ieee802154/l2/prj.conf @@ -11,7 +11,6 @@ CONFIG_NET_LOG=y CONFIG_NET_L2_IEEE802154=y CONFIG_NET_L2_IEEE802154_SECURITY=y CONFIG_NET_L2_IEEE802154_SECURITY_CRYPTO_DEV_NAME="CRYPTO_MTLS" -CONFIG_NET_L2_IEEE802154_ACK_REPLY=y CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_PACKET=y From 267db64f39a74b065ef9150b3bd9c8856e7de8a6 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 3 Jun 2023 21:46:13 +0200 Subject: [PATCH 0328/2042] net: l2: ieee802154: fix acknowledgment procedure The ACK procedure had the following issues: - MAC commands were not acknowledged. - When the package is a broadcast package the package must not be acknowledged. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 2 +- subsys/net/l2/ieee802154/ieee802154.c | 57 +++++++++++++++---- subsys/net/l2/ieee802154/ieee802154_frame.c | 2 +- tests/net/ieee802154/l2/src/ieee802154_test.c | 10 +++- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index be6241912917..422c2ea64d51 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -95,7 +95,7 @@ struct ieee802154_context { int16_t tx_power; enum net_l2_flags flags; - uint8_t sequence; + uint8_t sequence; /* see section 8.4.3.1, table 8-94, macDsn */ uint8_t _unused : 6; diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index c8b19c9478e3..c2ad77cc31e7 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -22,6 +22,7 @@ LOG_MODULE_REGISTER(net_ieee802154, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include #include #include +#include #ifdef CONFIG_NET_6LO #include "ieee802154_6lo.h" @@ -362,8 +363,10 @@ static bool ieeee802154_check_dst_addr(struct net_if *iface, struct ieee802154_m static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pkt) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; + enum net_verdict verdict = NET_DROP; + struct ieee802154_fcf_seq *fs; struct ieee802154_mpdu mpdu; - enum net_verdict verdict; + bool is_broadcast; size_t hdr_len; /* The IEEE 802.15.4 stack assumes that drivers provide a single-fragment package. */ @@ -379,15 +382,18 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk return NET_DROP; } - if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_ACK) { + fs = mpdu.mhr.fs; + + if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_ACK) { return NET_DROP; } - if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) { + if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_BEACON) { verdict = ieee802154_handle_beacon(iface, &mpdu, net_pkt_ieee802154_lqi(pkt)); if (verdict == NET_OK) { net_pkt_unref(pkt); } + /* Beacons must not be acknowledged, see section 6.7.4.1. */ return verdict; } @@ -395,17 +401,37 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk return NET_DROP; } - if (mpdu.mhr.fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) { + if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) { verdict = ieee802154_handle_mac_command(iface, &mpdu); - if (verdict == NET_OK) { - net_pkt_unref(pkt); + if (verdict != NET_OK) { + return verdict; } - return verdict; } - /* At this point the frame has to be a data frame. */ + /* At this point the frame is either a MAC command or a data frame + * which may have to be acknowledged, see section 6.7.4.1. + */ + + is_broadcast = false; + + if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) { + struct ieee802154_address_field *dst_addr = mpdu.mhr.dst_addr; + uint16_t short_dst_addr; + + short_dst_addr = fs->fc.pan_id_comp ? dst_addr->comp.addr.short_addr + : dst_addr->plain.addr.short_addr; + is_broadcast = short_dst_addr == IEEE802154_BROADCAST_ADDRESS; + } + + /* Frames that are broadcast must not be acknowledged, see section 6.7.2. */ + if (!is_broadcast) { + ieee802154_acknowledge(iface, &mpdu); + } - ieee802154_acknowledge(iface, &mpdu); + if (fs->fc.frame_type == IEEE802154_FRAME_TYPE_MAC_COMMAND) { + net_pkt_unref(pkt); + return verdict; + } if (!ieee802154_decipher_data_frame(iface, pkt, &mpdu)) { return NET_DROP; @@ -415,10 +441,10 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk * packet handling as it will mangle the package header to comply with upper * network layers' (POSIX) requirement to represent network addresses in big endian. */ - swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), mpdu.mhr.fs->fc.pan_id_comp, - mpdu.mhr.fs->fc.src_addr_mode, mpdu.mhr.src_addr); + swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), fs->fc.pan_id_comp, fs->fc.src_addr_mode, + mpdu.mhr.src_addr); - swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false, mpdu.mhr.fs->fc.dst_addr_mode, + swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false, fs->fc.dst_addr_mode, mpdu.mhr.dst_addr); net_pkt_set_ll_proto_type(pkt, ETH_P_IEEE802154); @@ -603,6 +629,13 @@ void ieee802154_init(struct net_if *iface) /* no need to lock the context here as it has * not been published yet. */ + + /* See section 6.7.1 - Transmission: "Each device shall initialize its data sequence number + * (DSN) to a random value and store its current DSN value in the MAC PIB attribute macDsn + * [...]." + */ + ctx->sequence = sys_rand32_get() & 0xFF; + ctx->channel = IEEE802154_NO_CHANNEL; ctx->flags = NET_L2_MULTICAST; if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_PROMISC) { diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index de9e9cc87698..ee1405e7ddcb 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -870,7 +870,7 @@ struct net_pkt *ieee802154_create_mac_cmd_frame(struct net_if *iface, enum ieee8 &p_buf, type == IEEE802154_CFI_BEACON_REQUEST ? false : ctx->ack_requested); fs->fc.frame_type = IEEE802154_FRAME_TYPE_MAC_COMMAND; - fs->sequence = ctx->sequence; + fs->sequence = ctx->sequence++; if (!cfi_to_fs_settings(type, fs, params)) { goto error; diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index 2e5e683f4b8e..c5df0e1c35f4 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -241,7 +241,7 @@ static struct net_pkt *get_data_pkt_with_ar(void) 0x61, 0xd8, /* FCF with AR bit set */ 0x16, /* Sequence */ 0xcd, 0xab, /* Destination PAN */ - 0xff, 0xff, /* Destination Address */ + 0x78, 0x56, /* Destination Address */ 0xc2, 0xa3, 0x9e, 0x00, 0x00, 0x4b, 0x12, 0x00, /* Source Address */ /* IEEE 802.15.4 MAC Payload */ 0x7b, 0x39, /* IPHC header, SAM: compressed, DAM: 48-bits inline */ @@ -1047,9 +1047,13 @@ static bool test_recv_and_send_ack_reply(struct ieee802154_pkt_test *t) goto release_fd; } + if (set_up_short_addr(iface, ctx)) { + goto release_fd; + } + rx_pkt = get_data_pkt_with_ar(); if (!rx_pkt) { - goto release_fd; + goto reset_short_addr; } if (net_recv_data(iface, rx_pkt) < 0) { @@ -1118,6 +1122,8 @@ static bool test_recv_and_send_ack_reply(struct ieee802154_pkt_test *t) current_pkt->frags = NULL; release_rx_pkt: net_pkt_unref(rx_pkt); +reset_short_addr: + tear_down_short_addr(iface, ctx); release_fd: close(fd); out: From f32fae07f299aa3264ec736517baceacc5398e43 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 3 Jun 2023 23:05:24 +0200 Subject: [PATCH 0329/2042] net: l2: ieee802154: fix endianness bug The PAN ID in IEEE 802.15.4 frames is little endian while in the IEEE 802.15.4 context it is kept in CPU byte order. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index c2ad77cc31e7..16afbe59ada6 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -318,7 +318,7 @@ static bool ieeee802154_check_dst_addr(struct net_if *iface, struct ieee802154_m * macPanId or shall be the broadcast PAN ID. */ if (!(dst_plain->pan_id == IEEE802154_BROADCAST_PAN_ID || - dst_plain->pan_id == ctx->pan_id)) { + dst_plain->pan_id == sys_cpu_to_le16(ctx->pan_id))) { LOG_DBG("Frame PAN ID does not match!"); return false; } From bee43bd972d2174ca624f08207bc8ed92c8f9edb Mon Sep 17 00:00:00 2001 From: Victor Chavez Date: Sat, 15 Apr 2023 09:31:33 +0200 Subject: [PATCH 0330/2042] logging: Fixed BLE backend buffer size independent of MTU The BLE backend has a bug that when the MTU size is less than the buffer the notification always fails and does not allow to flush the buffer. This fix checks for the MTU size of the current connection and adjusts it. In addition, the buffer size is no longer settable by the user and depends on the transmission size of MTU set with CONFIG_BT_L2CAP_TX_MTU. Signed-off-by: Victor Chavez --- samples/subsys/logging/ble_backend/README.rst | 3 + samples/subsys/logging/ble_backend/prj.conf | 1 - subsys/logging/backends/Kconfig.ble | 11 --- subsys/logging/backends/log_backend_ble.c | 67 +++++++++++++++++-- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/samples/subsys/logging/ble_backend/README.rst b/samples/subsys/logging/ble_backend/README.rst index 6c12071cae07..2c3726dc0bf1 100644 --- a/samples/subsys/logging/ble_backend/README.rst +++ b/samples/subsys/logging/ble_backend/README.rst @@ -10,6 +10,9 @@ Sample that demonstrates how to setup and use the BLE Logging backend. The BLE Logger uses the NRF Connect SDK NUS service as UUID to make it compatible with already existing apps to debug BLE connections over UART. +The notification size of the ble backend buffer is dependent on the +transmission size of the mtu set with `CONFIG_BT_L2CAP_TX_MTU`. Be sure +to change this configuration to increase the logger throughput over BLE. Requirements ************ diff --git a/samples/subsys/logging/ble_backend/prj.conf b/samples/subsys/logging/ble_backend/prj.conf index 4a1ab5099b05..f98016410b98 100644 --- a/samples/subsys/logging/ble_backend/prj.conf +++ b/samples/subsys/logging/ble_backend/prj.conf @@ -8,4 +8,3 @@ CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=2048 # Uncomment to use the maximum buffer size # CONFIG_BT_L2CAP_TX_MTU=600 # CONFIG_BT_BUF_ACL_RX_SIZE=600 -# CONFIG_LOG_BACKEND_BLE_BUF_SIZE=512 diff --git a/subsys/logging/backends/Kconfig.ble b/subsys/logging/backends/Kconfig.ble index b2ae6901fe20..016573c0f7ba 100644 --- a/subsys/logging/backends/Kconfig.ble +++ b/subsys/logging/backends/Kconfig.ble @@ -16,17 +16,6 @@ config LOG_BACKEND_BLE if LOG_BACKEND_BLE -config LOG_BACKEND_BLE_BUF_SIZE - int "BLE Logger Backend Buffer size" - range 20 512 - default 20 - help - Maximum buffer size that can be transmitted over the BLE Logger - notification characteristic. The minimum size is 20 for the smallest - MTU packet. Be sure to increase the MTU size in your application to use - bigger values. - Both BT_L2CAP_TX_MTU and BT_BUF_ACL_RX_SIZE will need to be increased. - backend = BLE backend-str = ble source "subsys/logging/Kconfig.template.log_format_config" diff --git a/subsys/logging/backends/log_backend_ble.c b/subsys/logging/backends/log_backend_ble.c index 626b7fdff64a..9487dc72b717 100644 --- a/subsys/logging/backends/log_backend_ble.c +++ b/subsys/logging/backends/log_backend_ble.c @@ -7,16 +7,24 @@ #include #include #include +#include #include -static uint8_t output_buf[CONFIG_LOG_BACKEND_BLE_BUF_SIZE]; +#define ATT_NOTIFY_SIZE 3 +#define LOG_BACKEND_BLE_BUF_SIZE (CONFIG_BT_L2CAP_TX_MTU - ATT_NOTIFY_SIZE) + +static uint8_t output_buf[LOG_BACKEND_BLE_BUF_SIZE]; static bool panic_mode; static uint32_t log_format_current = CONFIG_LOG_BACKEND_BLE_OUTPUT_DEFAULT; static logger_backend_ble_hook user_hook; static bool first_enable; static void *user_ctx; +static struct bt_conn *ble_backend_conn; + /* Forward declarations*/ -const struct log_backend *log_backend_ble_get(void); +static const struct log_backend *log_backend_ble_get(void); +static void log_backend_ble_connect(struct bt_conn *conn, uint8_t err); +static void log_backend_ble_disconnect(struct bt_conn *conn, uint8_t reason); /** * @brief Callback for the subscription to the ble logger notification characteristic @@ -39,6 +47,13 @@ static void log_notify_changed(const struct bt_gatt_attr *attr, uint16_t value); #define LOGGER_RX_SERVICE_UUID \ BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0x6E400002, 0xB5A3, 0xF393, 0xE0A9, 0xE50E24DCCA9E)) +BT_CONN_CB_DEFINE(log_backend_ble) = { + .connected = log_backend_ble_connect, + .disconnected = log_backend_ble_disconnect, + .le_param_req = NULL, + .le_param_updated = NULL +}; + /** * @brief BLE Service that represents this backend * @note Only transmission characteristic is used. The RX characteristic @@ -63,6 +78,20 @@ void logger_backend_ble_set_hook(logger_backend_ble_hook hook, void *ctx) user_ctx = ctx; } +static void log_backend_ble_connect(struct bt_conn *conn, uint8_t err) +{ + if (err == 0) { + ble_backend_conn = conn; + } +} + +static void log_backend_ble_disconnect(struct bt_conn *conn, uint8_t reason) +{ + ARG_UNUSED(conn); + ARG_UNUSED(reason); + ble_backend_conn = NULL; +} + void log_notify_changed(const struct bt_gatt_attr *attr, uint16_t value) { ARG_UNUSED(attr); @@ -86,19 +115,41 @@ void log_notify_changed(const struct bt_gatt_attr *attr, uint16_t value) static int line_out(uint8_t *data, size_t length, void *output_ctx) { - const int notify_res = bt_gatt_notify(NULL, log_characteristic, data, length); + ARG_UNUSED(output_ctx); + const uint16_t mtu_size = bt_gatt_get_mtu(ble_backend_conn); + const uint16_t attr_data_len = mtu_size - ATT_NOTIFY_SIZE; + uint16_t notify_len; - if (notify_res == 0) { - return length; + if (attr_data_len < LOG_BACKEND_BLE_BUF_SIZE) { + notify_len = attr_data_len; } else { - return 0; + notify_len = LOG_BACKEND_BLE_BUF_SIZE; } + + struct bt_gatt_notify_params notify_param = { + .uuid = NULL, + .attr = log_characteristic, + .data = data, + .len = notify_len, + .func = NULL, + .user_data = NULL, + #if defined(CONFIG_BT_EATT) + .chan_opt = BT_ATT_CHAN_OPT_NONE + #endif + }; + + const int notify_res = bt_gatt_notify_cb(ble_backend_conn, ¬ify_param); + /* ignore notification result and continue sending msg*/ + ARG_UNUSED(notify_res); + + return length; } LOG_OUTPUT_DEFINE(log_output_ble, line_out, output_buf, sizeof(output_buf)); static void process(const struct log_backend *const backend, union log_msg_generic *msg) { + ARG_UNUSED(backend); uint32_t flags = LOG_OUTPUT_FLAG_FORMAT_SYSLOG | LOG_OUTPUT_FLAG_TIMESTAMP; if (panic_mode) { @@ -112,17 +163,20 @@ static void process(const struct log_backend *const backend, union log_msg_gener 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 void init_ble(struct log_backend const *const backend) { + ARG_UNUSED(backend); log_backend_deactivate(log_backend_ble_get()); } static void panic(struct log_backend const *const backend) { + ARG_UNUSED(backend); panic_mode = true; } @@ -136,6 +190,7 @@ static void panic(struct log_backend const *const backend) */ static int backend_ready(const struct log_backend *const backend) { + ARG_UNUSED(backend); return -EACCES; } From 07f2c7a1df09ab5baad58b86acdcee06f13a0564 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Sat, 27 May 2023 01:32:32 +0000 Subject: [PATCH 0331/2042] west: sign.py: give rimage a key placeholder when there's none rimage always requires a key argument even when it does not use it. Some configurations (IMX) use rimage only for "stitching" the image but not for signing. These were failing to build directly from west with pretty cryptic stack trace, see below. This has never been a problem for the SOF project because it has always worked around this rimage limitation by providing a bogus -k argument - very much like the one added by this commit. ``` File "zephyrproject/zephyr/scripts/west_commands/sign.py", in sign extra_ri_args += [ '-k', str(sof_src_dir / 'keys' / cmake_default_key) ] TypeError: unsupported operand type(s) for /: 'PosixPath' and 'NoneType' ninja: build stopped: subcommand failed. ``` Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index 87b734feca27..e57b8800b4e2 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -522,7 +522,8 @@ def sign(self, command, build_dir, build_conf, formats): sign_config_extra_args = config_get_words(command.config, 'rimage.extra-args', []) if '-k' not in sign_config_extra_args + args.tool_args: - cmake_default_key = cache.get('RIMAGE_SIGN_KEY') + # rimage requires a key argument even when it does not sign + 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 '-c' not in sign_config_extra_args + args.tool_args: From 0ef6454c6fc7cb983bc39b7ee7697e3ec3012d8d Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Fri, 5 May 2023 16:10:10 +0300 Subject: [PATCH 0332/2042] drivers: gpio_rcar: add memory mapping to driver Add memory mapping to driver in order to use driver with platforms based on Cortex A with enabled MMU. Signed-off-by: Mykola Kvach --- drivers/gpio/gpio_rcar.c | 166 +++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 87 deletions(-) diff --git a/drivers/gpio/gpio_rcar.c b/drivers/gpio/gpio_rcar.c index 959df4960e92..820db5fc76cf 100644 --- a/drivers/gpio/gpio_rcar.c +++ b/drivers/gpio/gpio_rcar.c @@ -20,10 +20,14 @@ typedef void (*init_func_t)(const struct device *dev); +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct gpio_rcar_cfg *)(_dev)->config) +#define DEV_DATA(_dev) ((struct gpio_rcar_data *)(_dev)->data) + struct gpio_rcar_cfg { struct gpio_driver_config common; - uint32_t reg_addr; - int reg_size; + DEVICE_MMIO_NAMED_ROM(reg_base); init_func_t init_func; const struct device *clock_dev; struct rcar_cpg_clk mod_clk; @@ -31,6 +35,7 @@ struct gpio_rcar_cfg { struct gpio_rcar_data { struct gpio_driver_data common; + DEVICE_MMIO_NAMED_RAM(reg_base); sys_slist_t cb; }; @@ -48,22 +53,20 @@ struct gpio_rcar_data { #define OUTDTSEL 0x40 /* Output Data Select Register */ #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ -static inline uint32_t gpio_rcar_read(const struct gpio_rcar_cfg *config, - uint32_t offs) +static inline uint32_t gpio_rcar_read(const struct device *dev, uint32_t offs) { - return sys_read32(config->reg_addr + offs); + return sys_read32(DEVICE_MMIO_NAMED_GET(dev, reg_base) + offs); } -static inline void gpio_rcar_write(const struct gpio_rcar_cfg *config, - uint32_t offs, uint32_t value) +static inline void gpio_rcar_write(const struct device *dev, uint32_t offs, uint32_t value) { - sys_write32(value, config->reg_addr + offs); + sys_write32(value, DEVICE_MMIO_NAMED_GET(dev, reg_base) + offs); } -static void gpio_rcar_modify_bit(const struct gpio_rcar_cfg *config, +static void gpio_rcar_modify_bit(const struct device *dev, uint32_t offs, int bit, bool value) { - uint32_t tmp = gpio_rcar_read(config, offs); + uint32_t tmp = gpio_rcar_read(dev, offs); if (value) { tmp |= BIT(bit); @@ -71,28 +74,27 @@ static void gpio_rcar_modify_bit(const struct gpio_rcar_cfg *config, tmp &= ~BIT(bit); } - gpio_rcar_write(config, offs, tmp); + gpio_rcar_write(dev, offs, tmp); } static void gpio_rcar_port_isr(const struct device *dev) { - const struct gpio_rcar_cfg *config = dev->config; struct gpio_rcar_data *data = dev->data; uint32_t pending, fsb, mask; - pending = gpio_rcar_read(config, INTDT); - mask = gpio_rcar_read(config, INTMSK); + pending = gpio_rcar_read(dev, INTDT); + mask = gpio_rcar_read(dev, INTMSK); - while ((pending = gpio_rcar_read(config, INTDT) & - gpio_rcar_read(config, INTMSK))) { + while ((pending = gpio_rcar_read(dev, INTDT) & + gpio_rcar_read(dev, INTMSK))) { fsb = find_lsb_set(pending) - 1; gpio_fire_callbacks(&data->cb, dev, BIT(fsb)); - gpio_rcar_write(config, INTCLR, BIT(fsb)); + gpio_rcar_write(dev, INTCLR, BIT(fsb)); } } static void gpio_rcar_config_general_input_output_mode( - const struct gpio_rcar_cfg *config, + const struct device *dev, uint32_t gpio, bool output) { @@ -102,25 +104,23 @@ static void gpio_rcar_config_general_input_output_mode( */ /* Configure positive logic in POSNEG */ - gpio_rcar_modify_bit(config, POSNEG, gpio, false); + gpio_rcar_modify_bit(dev, POSNEG, gpio, false); /* Select "General Input/Output Mode" in IOINTSEL */ - gpio_rcar_modify_bit(config, IOINTSEL, gpio, false); + gpio_rcar_modify_bit(dev, IOINTSEL, gpio, false); /* Select Input Mode or Output Mode in INOUTSEL */ - gpio_rcar_modify_bit(config, INOUTSEL, gpio, output); + gpio_rcar_modify_bit(dev, INOUTSEL, gpio, output); /* Select General Output Register to output data in OUTDTSEL */ if (output) { - gpio_rcar_modify_bit(config, OUTDTSEL, gpio, false); + gpio_rcar_modify_bit(dev, OUTDTSEL, gpio, false); } } static int gpio_rcar_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { - const struct gpio_rcar_cfg *config = dev->config; - if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) { /* Pin cannot be configured as input and output */ return -ENOTSUP; @@ -131,13 +131,13 @@ static int gpio_rcar_configure(const struct device *dev, if (flags & GPIO_OUTPUT) { if (flags & GPIO_OUTPUT_INIT_HIGH) { - gpio_rcar_modify_bit(config, OUTDT, pin, true); + gpio_rcar_modify_bit(dev, OUTDT, pin, true); } else if (flags & GPIO_OUTPUT_INIT_LOW) { - gpio_rcar_modify_bit(config, OUTDT, pin, false); + gpio_rcar_modify_bit(dev, OUTDT, pin, false); } - gpio_rcar_config_general_input_output_mode(config, pin, true); + gpio_rcar_config_general_input_output_mode(dev, pin, true); } else { - gpio_rcar_config_general_input_output_mode(config, pin, false); + gpio_rcar_config_general_input_output_mode(dev, pin, false); } return 0; @@ -146,9 +146,7 @@ static int gpio_rcar_configure(const struct device *dev, static int gpio_rcar_port_get_raw(const struct device *dev, gpio_port_value_t *value) { - const struct gpio_rcar_cfg *config = dev->config; - - *value = gpio_rcar_read(config, INDT); + *value = gpio_rcar_read(dev, INDT); return 0; } @@ -156,12 +154,11 @@ static int gpio_rcar_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, gpio_port_value_t value) { - const struct gpio_rcar_cfg *config = dev->config; uint32_t port_val; - port_val = gpio_rcar_read(config, OUTDT); + port_val = gpio_rcar_read(dev, OUTDT); port_val = (port_val & ~mask) | (value & mask); - gpio_rcar_write(config, OUTDT, port_val); + gpio_rcar_write(dev, OUTDT, port_val); return 0; } @@ -169,12 +166,11 @@ static int gpio_rcar_port_set_masked_raw(const struct device *dev, static int gpio_rcar_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) { - const struct gpio_rcar_cfg *config = dev->config; uint32_t port_val; - port_val = gpio_rcar_read(config, OUTDT); + port_val = gpio_rcar_read(dev, OUTDT); port_val |= pins; - gpio_rcar_write(config, OUTDT, port_val); + gpio_rcar_write(dev, OUTDT, port_val); return 0; } @@ -182,12 +178,11 @@ static int gpio_rcar_port_set_bits_raw(const struct device *dev, static int gpio_rcar_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) { - const struct gpio_rcar_cfg *config = dev->config; uint32_t port_val; - port_val = gpio_rcar_read(config, OUTDT); + port_val = gpio_rcar_read(dev, OUTDT); port_val &= ~pins; - gpio_rcar_write(config, OUTDT, port_val); + gpio_rcar_write(dev, OUTDT, port_val); return 0; } @@ -195,12 +190,11 @@ static int gpio_rcar_port_clear_bits_raw(const struct device *dev, static int gpio_rcar_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) { - const struct gpio_rcar_cfg *config = dev->config; uint32_t port_val; - port_val = gpio_rcar_read(config, OUTDT); + port_val = gpio_rcar_read(dev, OUTDT); port_val ^= pins; - gpio_rcar_write(config, OUTDT, port_val); + gpio_rcar_write(dev, OUTDT, port_val); return 0; } @@ -210,35 +204,33 @@ static int gpio_rcar_pin_interrupt_configure(const struct device *dev, enum gpio_int_mode mode, enum gpio_int_trig trig) { - const struct gpio_rcar_cfg *config = dev->config; - if (mode == GPIO_INT_MODE_DISABLED) { return -ENOTSUP; } /* Configure positive or negative logic in POSNEG */ - gpio_rcar_modify_bit(config, POSNEG, pin, + gpio_rcar_modify_bit(dev, POSNEG, pin, (trig == GPIO_INT_TRIG_LOW)); /* Configure edge or level trigger in EDGLEVEL */ if (mode == GPIO_INT_MODE_EDGE) { - gpio_rcar_modify_bit(config, EDGLEVEL, pin, true); + gpio_rcar_modify_bit(dev, EDGLEVEL, pin, true); } else { - gpio_rcar_modify_bit(config, EDGLEVEL, pin, false); + gpio_rcar_modify_bit(dev, EDGLEVEL, pin, false); } if (trig == GPIO_INT_TRIG_BOTH) { - gpio_rcar_modify_bit(config, BOTHEDGE, pin, true); + gpio_rcar_modify_bit(dev, BOTHEDGE, pin, true); } - gpio_rcar_modify_bit(config, IOINTSEL, pin, true); + gpio_rcar_modify_bit(dev, IOINTSEL, pin, true); if (mode == GPIO_INT_MODE_EDGE) { /* Write INTCLR in case of edge trigger */ - gpio_rcar_write(config, INTCLR, BIT(pin)); + gpio_rcar_write(dev, INTCLR, BIT(pin)); } - gpio_rcar_write(config, MSKCLR, BIT(pin)); + gpio_rcar_write(dev, MSKCLR, BIT(pin)); return 0; } @@ -259,6 +251,7 @@ static int gpio_rcar_init(const struct device *dev) return ret; } + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE); config->init_func(dev); return 0; } @@ -284,41 +277,40 @@ static const struct gpio_driver_api gpio_rcar_driver_api = { }; /* Device Instantiation */ -#define GPIO_RCAR_INIT(n) \ - static void gpio_rcar_##n##_init(const struct device *dev); \ - static const struct gpio_rcar_cfg gpio_rcar_cfg_##n = { \ - .common = { \ - .port_pin_mask = \ - GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ - }, \ - .reg_addr = DT_INST_REG_ADDR(n), \ - .reg_size = DT_INST_REG_SIZE(n), \ - .init_func = gpio_rcar_##n##_init, \ - .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ - .mod_clk.module = \ - DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ - .mod_clk.domain = \ - DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \ - }; \ - static struct gpio_rcar_data gpio_rcar_data_##n; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - gpio_rcar_init, \ - NULL, \ - &gpio_rcar_data_##n, \ - &gpio_rcar_cfg_##n, \ - PRE_KERNEL_1, \ - CONFIG_GPIO_INIT_PRIORITY, \ - &gpio_rcar_driver_api \ - ); \ - static void gpio_rcar_##n##_init(const struct device *dev) \ - { \ - IRQ_CONNECT(DT_INST_IRQN(n), \ - 0, \ - gpio_rcar_port_isr, \ - DEVICE_DT_INST_GET(n), 0); \ - \ - irq_enable(DT_INST_IRQN(n)); \ +#define GPIO_RCAR_INIT(n) \ + static void gpio_rcar_##n##_init(const struct device *dev); \ + static const struct gpio_rcar_cfg gpio_rcar_cfg_##n = { \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ + .common = { \ + .port_pin_mask = \ + GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .init_func = gpio_rcar_##n##_init, \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .mod_clk.module = \ + DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ + .mod_clk.domain = \ + DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain), \ + }; \ + static struct gpio_rcar_data gpio_rcar_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + gpio_rcar_init, \ + NULL, \ + &gpio_rcar_data_##n, \ + &gpio_rcar_cfg_##n, \ + PRE_KERNEL_1, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_rcar_driver_api \ + ); \ + static void gpio_rcar_##n##_init(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + 0, \ + gpio_rcar_port_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ } DT_INST_FOREACH_STATUS_OKAY(GPIO_RCAR_INIT) From 178130a33691cf1af347ca856709ee0c289e7eb7 Mon Sep 17 00:00:00 2001 From: Cyril Fougeray Date: Thu, 8 Jun 2023 16:46:06 +0200 Subject: [PATCH 0333/2042] rtio: fix unused warning unused args Signed-off-by: Cyril Fougeray --- include/zephyr/rtio/rtio.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index 33e9243f0ab5..c017d06ad883 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -1014,8 +1014,6 @@ static inline uint32_t rtio_cqe_compute_flags(struct rtio_iodev_sqe *iodev_sqe) { uint32_t flags = 0; - ARG_UNUSED(iodev_sqe); - #ifdef CONFIG_RTIO_SYS_MEM_BLOCKS if (iodev_sqe->sqe.op == RTIO_OP_RX && iodev_sqe->sqe.flags & RTIO_SQE_MEMPOOL_BUFFER) { struct rtio *r = iodev_sqe->r; @@ -1026,6 +1024,8 @@ static inline uint32_t rtio_cqe_compute_flags(struct rtio_iodev_sqe *iodev_sqe) flags = RTIO_CQE_FLAG_PREP_MEMPOOL(blk_index, blk_count); } +#else + ARG_UNUSED(iodev_sqe); #endif return flags; @@ -1202,7 +1202,10 @@ static inline int rtio_sqe_rx_buf(const struct rtio_iodev_sqe *iodev_sqe, uint32 return -ENOMEM; } +#else + ARG_UNUSED(max_buf_len); #endif + if (sqe->buf_len < min_buf_len) { return -ENOMEM; } @@ -1236,6 +1239,10 @@ static inline void z_impl_rtio_release_buffer(struct rtio *r, void *buff, uint32 } rtio_block_pool_free(r->block_pool, buff, buff_len); +#else + ARG_UNUSED(r); + ARG_UNUSED(buff); + ARG_UNUSED(buff_len); #endif } From 547a342618f4afd73663f7e92bcf3ce1a4008d0f Mon Sep 17 00:00:00 2001 From: Cyril Fougeray Date: Thu, 8 Jun 2023 16:46:14 +0200 Subject: [PATCH 0334/2042] flash: fix unused warning unused args Signed-off-by: Cyril Fougeray --- include/zephyr/drivers/flash.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/drivers/flash.h b/include/zephyr/drivers/flash.h index df2402c1a860..de5e7c2116e0 100644 --- a/include/zephyr/drivers/flash.h +++ b/include/zephyr/drivers/flash.h @@ -484,6 +484,11 @@ static inline int z_impl_flash_ex_op(const struct device *dev, uint16_t code, return api->ex_op(dev, code, in, out); #else + ARG_UNUSED(dev); + ARG_UNUSED(code); + ARG_UNUSED(in); + ARG_UNUSED(out); + return -ENOSYS; #endif /* CONFIG_FLASH_EX_OP_ENABLED */ } From 55c7f7aeaf0f1dc243cf43d714411934542f016c Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Tue, 13 Jun 2023 19:04:09 -0500 Subject: [PATCH 0335/2042] boards: mg100: fix SD card device tree definition Replace obsolete compatible fields. Signed-off-by: Ryan Erickson --- boards/arm/mg100/mg100.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/boards/arm/mg100/mg100.dts b/boards/arm/mg100/mg100.dts index 16e4c4a9fb6e..a605c4131ebe 100644 --- a/boards/arm/mg100/mg100.dts +++ b/boards/arm/mg100/mg100.dts @@ -130,9 +130,14 @@ pinctrl-names = "default", "sleep"; cs-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; sdhc0: sdhc@0 { - compatible = "zephyr,mmc-spi-slot"; + compatible = "zephyr,sdhc-spi-slot"; + status = "okay"; reg = <0>; spi-max-frequency = <8000000>; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; }; }; From 53843c646423c5b00d7c5ec8fb652d8d5a886008 Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Tue, 13 Jun 2023 19:05:13 -0500 Subject: [PATCH 0336/2042] samples: fat_fs: Add support for MG100 board Add overlay so the sample can be built for the MG100. Signed-off-by: Ryan Erickson --- samples/subsys/fs/fat_fs/boards/mg100.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 samples/subsys/fs/fat_fs/boards/mg100.conf diff --git a/samples/subsys/fs/fat_fs/boards/mg100.conf b/samples/subsys/fs/fat_fs/boards/mg100.conf new file mode 100644 index 000000000000..83ac43fc39ff --- /dev/null +++ b/samples/subsys/fs/fat_fs/boards/mg100.conf @@ -0,0 +1,2 @@ +CONFIG_SPI=y +CONFIG_DISK_DRIVER_SDMMC=y From a6615ac11fdd6188d07e59089cf2da7758ddcd39 Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 13 Jun 2023 12:43:04 +0200 Subject: [PATCH 0337/2042] drivers: timer: add z_nrf_rtc_timer_exact_set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function `z_nrf_rtc_timer_exact_set` is added to allow setting compare channel without possible creeping of cc val. Signed-off-by: Andrzej Kuroś --- drivers/timer/nrf_rtc_timer.c | 59 +++++++++++++++----- include/zephyr/drivers/timer/nrf_rtc_timer.h | 31 ++++++++++ 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index a60c920b383e..8ec987801999 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -232,9 +232,20 @@ uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t) * @param[in] chan A channel for which a new CC value is to be set. * * @param[in] req_cc Requested CC register value to be set. + * + * @param[in] exact Use @c false to allow CC adjustment if @c req_cc value is + * close to the current value of the timer. + * Use @c true to disallow CC adjustment. The function can + * fail with -EINVAL result if @p req_cc is too close to the + * current value. + * + * @retval 0 The requested CC has been set successfully. + * @retval -EINVAL The requested CC value could not be reliably set. */ -static void set_alarm(int32_t chan, uint32_t req_cc) +static int set_alarm(int32_t chan, uint32_t req_cc, bool exact) { + int ret = 0; + /* Ensure that the value exposed in this driver API is consistent with * assumptions of this function. */ @@ -301,9 +312,16 @@ static void set_alarm(int32_t chan, uint32_t req_cc) now = counter(); if (counter_sub(now, req_cc) > COUNTER_HALF_SPAN) { event_clear(chan); + if (exact) { + ret = -EINVAL; + break; + } } else { break; } + } else if (exact) { + ret = -EINVAL; + break; } cc_val = now + cc_inc; @@ -312,11 +330,13 @@ static void set_alarm(int32_t chan, uint32_t req_cc) break; } } + + return ret; } static int compare_set_nolocks(int32_t chan, uint64_t target_time, z_nrf_rtc_timer_compare_handler_t handler, - void *user_data) + void *user_data, bool exact) { int ret = 0; uint32_t cc_value = absolute_time_to_cc(target_time); @@ -332,29 +352,33 @@ static int compare_set_nolocks(int32_t chan, uint64_t target_time, /* Target time is valid and is different than currently set. * Set CC value. */ - set_alarm(chan, cc_value); + ret = set_alarm(chan, cc_value, exact); } - } else { + } else if (!exact) { /* Force ISR handling when exiting from critical section. */ atomic_or(&force_isr_mask, BIT(chan)); + } else { + ret = -EINVAL; } - cc_data[chan].target_time = target_time; - cc_data[chan].callback = handler; - cc_data[chan].user_context = user_data; + if (ret == 0) { + cc_data[chan].target_time = target_time; + cc_data[chan].callback = handler; + cc_data[chan].user_context = user_data; + } return ret; } static int compare_set(int32_t chan, uint64_t target_time, z_nrf_rtc_timer_compare_handler_t handler, - void *user_data) + void *user_data, bool exact) { bool key; key = compare_int_lock(chan); - int ret = compare_set_nolocks(chan, target_time, handler, user_data); + int ret = compare_set_nolocks(chan, target_time, handler, user_data, exact); compare_int_unlock(chan, key); @@ -367,7 +391,16 @@ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time, { __ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT); - return compare_set(chan, target_time, handler, user_data); + return compare_set(chan, target_time, handler, user_data, false); +} + +int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time, + z_nrf_rtc_timer_compare_handler_t handler, + void *user_data) +{ + __ASSERT_NO_MSG(chan > 0 && chan < CHAN_COUNT); + + return compare_set(chan, target_time, handler, user_data, true); } void z_nrf_rtc_timer_abort(int32_t chan) @@ -448,7 +481,7 @@ static void sys_clock_timeout_handler(int32_t chan, * so it won't get preempted by the interrupt. */ compare_set(chan, last_count + CYC_PER_TICK, - sys_clock_timeout_handler, NULL); + sys_clock_timeout_handler, NULL, false); } sys_clock_announce(dticks); @@ -644,7 +677,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) uint64_t target_time = cyc + last_count; - compare_set(0, target_time, sys_clock_timeout_handler, NULL); + compare_set(0, target_time, sys_clock_timeout_handler, NULL, false); } uint32_t sys_clock_elapsed(void) @@ -722,7 +755,7 @@ static int sys_clock_driver_init(void) uint32_t initial_timeout = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? MAX_CYCLES : CYC_PER_TICK; - compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL); + compare_set(0, initial_timeout, sys_clock_timeout_handler, NULL, false); z_nrf_clock_control_lf_on(mode); diff --git a/include/zephyr/drivers/timer/nrf_rtc_timer.h b/include/zephyr/drivers/timer/nrf_rtc_timer.h index b11f201386e6..c5992bee4bdd 100644 --- a/include/zephyr/drivers/timer/nrf_rtc_timer.h +++ b/include/zephyr/drivers/timer/nrf_rtc_timer.h @@ -127,11 +127,42 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan); * @retval 0 if the compare channel was set successfully. * @retval -EINVAL if provided target time was further than * @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future. + * + * @sa @ref z_nrf_rtc_timer_exact_set */ int z_nrf_rtc_timer_set(int32_t chan, uint64_t target_time, z_nrf_rtc_timer_compare_handler_t handler, void *user_data); +/** @brief Try to set compare channel exactly to given value. + * + * @note This function is similar to @ref z_nrf_rtc_timer_set, but the compare + * channel will be set to expected value only when it can be guaranteed that + * the hardware event will be generated exactly at expected @c target_time in + * the future. If the @c target_time is in the past or so close in the future + * that the reliable generation of event would require adjustment of compare + * value (as would @ref z_nrf_rtc_timer_set function do), neither the hardware + * event nor interrupt will be generated and the function fails. + * + * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + * + * @param target_time Absolute target time in ticks. + * + * @param handler User function called in the context of the RTC interrupt. + * + * @param user_data Data passed to the handler. + * + * @retval 0 if the compare channel was set successfully. + * @retval -EINVAL if provided target time was further than + * @c NRF_RTC_TIMER_MAX_SCHEDULE_SPAN ticks in the future + * or the target time is in the past or is so close in the future that + * event generation could not be guaranteed without adjusting + * compare value of that channel. + */ +int z_nrf_rtc_timer_exact_set(int32_t chan, uint64_t target_time, + z_nrf_rtc_timer_compare_handler_t handler, + void *user_data); + /** @brief Abort a timer requested with @ref z_nrf_rtc_timer_set. * * If an abort operation is performed too late it is still possible for an event From 99751b1d98cfe8a6daaa765f46894b1666478a7f Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Mon, 29 May 2023 23:04:48 +0200 Subject: [PATCH 0338/2042] drivers: led: Add lp5569 led controller driver Add a minimal driver for the ti lp5569 led controller. The driver supports multiple instances. Commands on|off|set_brightness are supported. Signed-off-by: Jonas Remmert --- drivers/led/CMakeLists.txt | 1 + drivers/led/Kconfig | 1 + drivers/led/Kconfig.lp5569 | 11 +++ drivers/led/lp5569.c | 121 ++++++++++++++++++++++++++++++++ dts/bindings/led/ti,lp5569.yaml | 5 ++ 5 files changed, 139 insertions(+) create mode 100644 drivers/led/Kconfig.lp5569 create mode 100644 drivers/led/lp5569.c create mode 100644 dts/bindings/led/ti,lp5569.yaml diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index c9a7478286dd..e018acb0cae0 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_LED_XEC led_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_LP3943 lp3943.c) zephyr_library_sources_ifdef(CONFIG_LP503X lp503x.c) zephyr_library_sources_ifdef(CONFIG_LP5562 lp5562.c) +zephyr_library_sources_ifdef(CONFIG_LP5569 lp5569.c) zephyr_library_sources_ifdef(CONFIG_PCA9633 pca9633.c) zephyr_library_sources_ifdef(CONFIG_TLC59108 tlc59108.c) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 7c4f5ced0864..bf606b6e91b2 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -31,6 +31,7 @@ source "drivers/led/Kconfig.ht16k33" source "drivers/led/Kconfig.lp3943" source "drivers/led/Kconfig.lp503x" source "drivers/led/Kconfig.lp5562" +source "drivers/led/Kconfig.lp5569" source "drivers/led/Kconfig.pca9633" source "drivers/led/Kconfig.pwm" source "drivers/led/Kconfig.tlc59108" diff --git a/drivers/led/Kconfig.lp5569 b/drivers/led/Kconfig.lp5569 new file mode 100644 index 000000000000..1090993399ad --- /dev/null +++ b/drivers/led/Kconfig.lp5569 @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Phytec Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +config LP5569 + bool "LP5569 LED driver" + default y + depends on DT_HAS_TI_LP5569_ENABLED + select I2C + help + Enable LED driver for LP5569. LP5569 LED driver has 9 channels. + Each channel can drive up to 25.5 mA per LED. diff --git a/drivers/led/lp5569.c b/drivers/led/lp5569.c new file mode 100644 index 000000000000..f3f196785df8 --- /dev/null +++ b/drivers/led/lp5569.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023 Phytec Messtechnik GmbH. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_lp5569 + +/** + * @file + * @brief LP5569 LED controller + * + * The LP5569 is a 9-channel LED driver that communicates over I2C. + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(lp5569, CONFIG_LED_LOG_LEVEL); + +#define LP5569_NUM_LEDS 9 + +/* General Registers */ +#define LP5569_CONFIG 0x00 +#define LP5569_CHIP_EN BIT(6) + +#define LP5569_MISC 0x2F +#define LP5569_POWERSAVE_EN BIT(5) + +/* PWM base Register for controlling the duty-cycle */ +#define LP5569_LED0_PWM 0x16 + +struct lp5569_config { + struct i2c_dt_spec bus; +}; + +static int lp5569_led_set_brightness(const struct device *dev, uint32_t led, + uint8_t brightness) +{ + const struct lp5569_config *config = dev->config; + uint8_t val; + int ret; + + if (led >= LP5569_NUM_LEDS || brightness > 100) { + return -EINVAL; + } + + /* Map 0-100 % to 0-255 pwm register value */ + val = brightness * 255 / 100; + + ret = i2c_reg_write_byte_dt(&config->bus, LP5569_LED0_PWM + led, val); + if (ret < 0) { + LOG_ERR("LED reg update failed"); + return ret; + } + + return 0; +} + +static inline int lp5569_led_on(const struct device *dev, uint32_t led) +{ + /* Set LED brightness to 100 % */ + return lp5569_led_set_brightness(dev, led, 100); +} + +static inline int lp5569_led_off(const struct device *dev, uint32_t led) +{ + /* Set LED brightness to 0 % */ + return lp5569_led_set_brightness(dev, led, 0); +} + +static int lp5569_init(const struct device *dev) +{ + const struct lp5569_config *config = dev->config; + int ret; + + if (!i2c_is_ready_dt(&config->bus)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + ret = i2c_reg_write_byte_dt(&config->bus, LP5569_CONFIG, + LP5569_CHIP_EN); + if (ret < 0) { + LOG_ERR("Enable LP5569 failed"); + return ret; + } + + ret = i2c_reg_write_byte_dt(&config->bus, LP5569_MISC, + LP5569_POWERSAVE_EN); + if (ret < 0) { + LOG_ERR("LED reg update failed"); + return ret; + } + + return 0; +} + + +static const struct led_driver_api lp5569_led_api = { + .set_brightness = lp5569_led_set_brightness, + .on = lp5569_led_on, + .off = lp5569_led_off, +}; + +#define LP5569_DEFINE(id) \ + static const struct lp5569_config lp5569_config_##id = { \ + .bus = I2C_DT_SPEC_INST_GET(id), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(id, &lp5569_init, \ + NULL, \ + NULL, \ + &lp5569_config_##id, POST_KERNEL, \ + CONFIG_LED_INIT_PRIORITY, \ + &lp5569_led_api); + +DT_INST_FOREACH_STATUS_OKAY(LP5569_DEFINE) diff --git a/dts/bindings/led/ti,lp5569.yaml b/dts/bindings/led/ti,lp5569.yaml new file mode 100644 index 000000000000..1d84ba257c53 --- /dev/null +++ b/dts/bindings/led/ti,lp5569.yaml @@ -0,0 +1,5 @@ +description: TI LP5569 LED + +compatible: "ti,lp5569" + +include: i2c-device.yaml From 49707dfca243f5108ff2fdd0f9d722d75038a0c4 Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Mon, 29 May 2023 23:08:16 +0200 Subject: [PATCH 0339/2042] drivers: led: add power management for ti lp5569 Adding device power management for the ti lp5569 led controller driver. Allow the option to either use device power managemnt while keeping the voltage on or to use device power management including using e.g. a voltage domain that controls the led controller voltage on-demand. Signed-off-by: Jonas Remmert --- drivers/led/lp5569.c | 53 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/led/lp5569.c b/drivers/led/lp5569.c index f3f196785df8..e469c22574e3 100644 --- a/drivers/led/lp5569.c +++ b/drivers/led/lp5569.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -72,7 +73,7 @@ static inline int lp5569_led_off(const struct device *dev, uint32_t led) return lp5569_led_set_brightness(dev, led, 0); } -static int lp5569_init(const struct device *dev) +static int lp5569_enable(const struct device *dev) { const struct lp5569_config *config = dev->config; int ret; @@ -99,6 +100,52 @@ static int lp5569_init(const struct device *dev) return 0; } +static int lp5569_init(const struct device *dev) +{ + /* If the device is behind a power domain, it will start in + * PM_DEVICE_STATE_OFF. + */ + if (pm_device_on_power_domain(dev)) { + pm_device_init_off(dev); + LOG_INF("Init %s as PM_DEVICE_STATE_OFF", dev->name); + return 0; + } + + return lp5569_enable(dev); +} + +#ifdef CONFIG_PM_DEVICE +static int lp5569_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct lp5569_config *config = dev->config; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_TURN_ON: + case PM_DEVICE_ACTION_RESUME: + ret = lp5569_enable(dev); + if (ret < 0) { + LOG_ERR("Enable LP5569 failed"); + return ret; + } + break; + case PM_DEVICE_ACTION_TURN_OFF: + case PM_DEVICE_ACTION_SUSPEND: + ret = i2c_reg_update_byte_dt(&config->bus, LP5569_CONFIG, + LP5569_CHIP_EN, 0); + if (ret < 0) { + LOG_ERR("Disable LP5569 failed"); + return ret; + } + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ static const struct led_driver_api lp5569_led_api = { .set_brightness = lp5569_led_set_brightness, @@ -111,8 +158,10 @@ static const struct led_driver_api lp5569_led_api = { .bus = I2C_DT_SPEC_INST_GET(id), \ }; \ \ + PM_DEVICE_DT_INST_DEFINE(id, lp5569_pm_action); \ + \ DEVICE_DT_INST_DEFINE(id, &lp5569_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(id), \ NULL, \ &lp5569_config_##id, POST_KERNEL, \ CONFIG_LED_INIT_PRIORITY, \ From 22e7edbbab1d88209cc1ac664f7f853956041f1a Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Tue, 23 May 2023 00:31:37 +0200 Subject: [PATCH 0340/2042] samples: drivers: led: add a sample for ti lp5569 Add a sample for the ti lp5569 led controller driver. Signed-off-by: Jonas Remmert --- samples/drivers/led_lp5569/CMakeLists.txt | 9 +++ samples/drivers/led_lp5569/README.rst | 36 +++++++++++ .../boards/nrf52840dk_nrf52840.overlay | 11 ++++ samples/drivers/led_lp5569/prj.conf | 2 + samples/drivers/led_lp5569/sample.yaml | 7 ++ samples/drivers/led_lp5569/src/main.c | 64 +++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 samples/drivers/led_lp5569/CMakeLists.txt create mode 100644 samples/drivers/led_lp5569/README.rst create mode 100644 samples/drivers/led_lp5569/boards/nrf52840dk_nrf52840.overlay create mode 100644 samples/drivers/led_lp5569/prj.conf create mode 100644 samples/drivers/led_lp5569/sample.yaml create mode 100644 samples/drivers/led_lp5569/src/main.c diff --git a/samples/drivers/led_lp5569/CMakeLists.txt b/samples/drivers/led_lp5569/CMakeLists.txt new file mode 100644 index 000000000000..3e9fb70a0b05 --- /dev/null +++ b/samples/drivers/led_lp5569/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(led_lp5569) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/led_lp5569/README.rst b/samples/drivers/led_lp5569/README.rst new file mode 100644 index 000000000000..c7679972f1db --- /dev/null +++ b/samples/drivers/led_lp5569/README.rst @@ -0,0 +1,36 @@ +.. _lp5569: + +LP5569: 9-Channel LED Controller +################################ + +Overview +******** + +This sample controls 9 LEDs connected to an LP5569 driver. The sample turns +all LEDs on and switches all LEDs off again within a one second interval. + +Building and Running +******************** + +Build the application for the :ref:`nrf52840dk_nrf52840` board, and connect +a LP5569 LED controller on the bus I2C0 at the address 0x32. + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/led_lp5569 + :board: nrf52840dk_nrf52840 + :goals: build + :compact: + +For flashing the application, refer to the Flashing section of the +:ref:`nrf52840dk_nrf52840` board documentation. + +.. code-block:: none + + *** Booting Zephyr OS build zephyr-v3.3.0 *** + [00:00:00.361,694] app: Found LED device lp5569@32 + [00:00:00.361,694] app: Testing 9 LEDs .. + +References +********** + +- LP5569 Datasheet: https://www.ti.com/product/de-de/LP5569 diff --git a/samples/drivers/led_lp5569/boards/nrf52840dk_nrf52840.overlay b/samples/drivers/led_lp5569/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 000000000000..3aa26205ed23 --- /dev/null +++ b/samples/drivers/led_lp5569/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&i2c0 { + status = "okay"; + clock-frequency = ; + + lp5569@32 { + compatible = "ti,lp5569"; + reg = <0x32>; + }; +}; diff --git a/samples/drivers/led_lp5569/prj.conf b/samples/drivers/led_lp5569/prj.conf new file mode 100644 index 000000000000..df85f3b69dfb --- /dev/null +++ b/samples/drivers/led_lp5569/prj.conf @@ -0,0 +1,2 @@ +CONFIG_LOG=y +CONFIG_LED=y diff --git a/samples/drivers/led_lp5569/sample.yaml b/samples/drivers/led_lp5569/sample.yaml new file mode 100644 index 000000000000..40d8f24ace17 --- /dev/null +++ b/samples/drivers/led_lp5569/sample.yaml @@ -0,0 +1,7 @@ +sample: + description: Demonstration of the LP5569 LED driver + name: LP5569 sample +tests: + sample.drivers.led.lp5569: + platform_allow: nrf52840dk_nrf52840 + tags: led diff --git a/samples/drivers/led_lp5569/src/main.c b/samples/drivers/led_lp5569/src/main.c new file mode 100644 index 000000000000..fe18d5ee280a --- /dev/null +++ b/samples/drivers/led_lp5569/src/main.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Phytec Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(app, CONFIG_LED_LOG_LEVEL); + +#define NUM_LEDS 9 +#define DELAY_TIME_ON K_MSEC(1000) +#define DELAY_TIME_BREATHING K_MSEC(20) + +int main(void) +{ + const struct device *const led_dev = DEVICE_DT_GET_ANY(ti_lp5569); + int i, ret; + + if (!led_dev) { + LOG_ERR("No device with compatible ti,lp5569 found"); + return 0; + } else if (!device_is_ready(led_dev)) { + LOG_ERR("LED device %s not ready", led_dev->name); + return 0; + } + + LOG_INF("Found LED device %s", led_dev->name); + + /* + * Display a continuous pattern that turns on 9 LEDs at 1 s one by + * one until it reaches the end and turns off LEDs in reverse order. + */ + + LOG_INF("Testing 9 LEDs .."); + + while (1) { + /* Turn on LEDs one by one */ + for (i = 0; i < NUM_LEDS; i++) { + ret = led_on(led_dev, i); + if (ret) { + return ret; + } + + k_sleep(DELAY_TIME_ON); + } + + /* Turn all LEDs off slowly to demonstrate set_brightness */ + for (i = 0; i <= 100; i++) { + for (int j = 0; j < NUM_LEDS; j++) { + ret = led_set_brightness(led_dev, j, 100 - i); + if (ret) { + return ret; + } + } + + k_sleep(DELAY_TIME_BREATHING); + } + } + return 0; +} From e396f69afd261c80a420b8034293b672e8e01d72 Mon Sep 17 00:00:00 2001 From: Jonas Remmert Date: Tue, 23 May 2023 00:34:25 +0200 Subject: [PATCH 0341/2042] tests: driver: build_all: add lp5569 to tests Add LED controller driver to list of tests. Signed-off-by: Jonas Remmert --- tests/drivers/build_all/led/app.overlay | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/drivers/build_all/led/app.overlay b/tests/drivers/build_all/led/app.overlay index 22f119765bc3..63a870f51c6c 100644 --- a/tests/drivers/build_all/led/app.overlay +++ b/tests/drivers/build_all/led/app.overlay @@ -69,6 +69,11 @@ compatible = "ti,tlc59108"; reg = <0x6>; }; + + lp5569@5 { + compatible = "ti,lp5569"; + reg = <0x7>; + }; }; }; }; From 3c9f3b7849c2e290819e7a558a5d05c771c38467 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Fri, 16 Jun 2023 01:05:49 +0530 Subject: [PATCH 0342/2042] net: websockets: do not close tcp socket in websocket The websocket_connect api expects connected tcp socket, do not close the user supplied socket so that the caller can re-use it if needed. Signed-off-by: Saravanan Sekar --- subsys/net/lib/websocket/websocket.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index 86b4e4127d61..5e5eee5fb2c4 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -425,8 +425,6 @@ static int websocket_interal_disconnect(struct websocket_context *ctx) NET_ERR("[%p] Failed to send close message (err %d).", ctx, ret); } - ret = close(ctx->real_sock); - websocket_context_unref(ctx); return ret; From c05de187812a6e85c571f696773119875423188b Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Sat, 17 Jun 2023 02:27:45 +0530 Subject: [PATCH 0343/2042] doc: websocket: update websocket_disconnect api Do not close the user supplied socket so that the caller can re-use it if needed. Signed-off-by: Saravanan Sekar --- doc/connectivity/networking/api/websocket.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/connectivity/networking/api/websocket.rst b/doc/connectivity/networking/api/websocket.rst index c7422fbca68a..f803e7b2ef87 100644 --- a/doc/connectivity/networking/api/websocket.rst +++ b/doc/connectivity/networking/api/websocket.rst @@ -62,7 +62,8 @@ If normal BSD socket functions are used, then currently only TEXT data 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. +When done, the Websocket transport socket must be closed. User should handle +the lifecycle(close/re-use) of tcp socket after websocket_disconnect. .. code-block:: c From bdb26cfe02be9a42a70479d48144d92f4c151eb4 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Sat, 17 Jun 2023 02:49:38 +0530 Subject: [PATCH 0344/2042] net: mqtt: close tcp socket after websocket_disconnect websocket_disconnect api does not closes mqtt's tcp socket, so tcp socket must be closed after done. Signed-off-by: Saravanan Sekar --- .../net/lib/mqtt/mqtt_transport_websocket.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/mqtt/mqtt_transport_websocket.c b/subsys/net/lib/mqtt/mqtt_transport_websocket.c index a4f8b477d1bb..bf00423bb2c9 100644 --- a/subsys/net/lib/mqtt/mqtt_transport_websocket.c +++ b/subsys/net/lib/mqtt/mqtt_transport_websocket.c @@ -168,7 +168,24 @@ int mqtt_client_websocket_read(struct mqtt_client *client, uint8_t *data, int mqtt_client_websocket_disconnect(struct mqtt_client *client) { + int ret; + NET_INFO("Closing socket %d", client->transport.websocket.sock); - return websocket_disconnect(client->transport.websocket.sock); + ret = websocket_disconnect(client->transport.websocket.sock); + if (ret < 0) { + NET_ERR("Websocket disconnect failed (%d)", ret); + return ret; + } + + if (client->transport.type == MQTT_TRANSPORT_NON_SECURE_WEBSOCKET) { + ret = mqtt_client_tcp_disconnect(client); + } +#if defined(CONFIG_MQTT_LIB_TLS) + else if (client->transport.type == MQTT_TRANSPORT_SECURE_WEBSOCKET) { + ret = mqtt_client_tls_disconnect(client); + } +#endif + + return ret; } From 026d476a84777b959ee0da2bc963fbbcb2e70665 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Sun, 18 Jun 2023 03:16:56 +0530 Subject: [PATCH 0345/2042] samples: websocket_client: close tcp socket after websocket_disconnect websocket_disconnect api does not closes user tcp socket, so tcp socket must be closed after done. Signed-off-by: Saravanan Sekar --- samples/net/sockets/websocket_client/src/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/samples/net/sockets/websocket_client/src/main.c b/samples/net/sockets/websocket_client/src/main.c index d165f524c579..f58e6d47b416 100644 --- a/samples/net/sockets/websocket_client/src/main.c +++ b/samples/net/sockets/websocket_client/src/main.c @@ -431,10 +431,18 @@ int main(void) close(websock4); } + if (sock4 >= 0) { + close(sock4); + } + if (websock6 >= 0) { close(websock6); } + if (sock6 >= 0) { + close(sock6); + } + k_sleep(K_FOREVER); return 0; } From 0f3af43330b0099ace3b10b71284ca2f119e1049 Mon Sep 17 00:00:00 2001 From: Christian Tenllado Date: Fri, 12 May 2023 09:53:38 +0200 Subject: [PATCH 0346/2042] include: posix: signal: add sig_atomic_t type This commit adds the definition of sig_atomic_t to the posix/signal.h file. The definition was copied from the file modules/lib/picolibc/newlib/libc/include/signal.h. The problem of the missing definition arose when I tried to compile a lua module for the 3.3.0 version of zephyr. Adding this definition solves the problem. Signed-off-by: Christian Tenllado --- include/zephyr/posix/signal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 833afb0e60db..88b137e7547a 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -24,6 +24,8 @@ extern "C" { #define SIGEV_THREAD 3 #endif +typedef int sig_atomic_t; /* Atomic entity type (ANSI) */ + typedef union sigval { int sival_int; void *sival_ptr; From a322e4d20d1e6f602994f14935720344040782cd Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Fri, 16 Jun 2023 12:40:56 +0200 Subject: [PATCH 0347/2042] Bluetooth: Mesh: clarification about adv local identity BT_ID_DEFAULT is hardcoded in mesh. Added clarification about the necessity of another local identity allocation for BLE if it coexists with mesh. Signed-off-by: Aleksandr Khromykh --- doc/connectivity/bluetooth/api/mesh/core.rst | 8 ++++++++ subsys/bluetooth/mesh/pb_gatt_srv.c | 2 ++ subsys/bluetooth/mesh/proxy_srv.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index e27f29a31350..d689c71fcb13 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -108,6 +108,14 @@ This means that the system workqueue is blocked for the time it takes to store the stack's configuration. It is not recommended to disable this option as this will make the device non-responsive for a noticeable amount of time. +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 +configure another local identity for Bluetooth LE purposes before starting the communication. + API reference ************** diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c index e15ba74c02dc..d5ad2f9711d1 100644 --- a/subsys/bluetooth/mesh/pb_gatt_srv.c +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -274,6 +274,7 @@ int bt_mesh_pb_gatt_srv_adv_start(void) } struct bt_le_adv_param fast_adv_param = { + .id = BT_ID_DEFAULT, .options = ADV_OPT_PROV, ADV_FAST_INT, }; @@ -286,6 +287,7 @@ int bt_mesh_pb_gatt_srv_adv_start(void) if (elapsed_time > FAST_ADV_TIME) { struct bt_le_adv_param slow_adv_param = { + .id = BT_ID_DEFAULT, .options = ADV_OPT_PROV, ADV_SLOW_INT, }; diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 8ff026fb991d..76e994c132b1 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -495,10 +495,12 @@ static int enc_id_adv(struct bt_mesh_subnet *sub, uint8_t type, uint8_t hash[16], int32_t duration) { struct bt_le_adv_param slow_adv_param = { + .id = BT_ID_DEFAULT, .options = ADV_OPT_PROXY, ADV_SLOW_INT, }; struct bt_le_adv_param fast_adv_param = { + .id = BT_ID_DEFAULT, .options = ADV_OPT_PROXY, ADV_FAST_INT, }; @@ -595,6 +597,7 @@ static int priv_net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) { struct bt_le_adv_param slow_adv_param = { + .id = BT_ID_DEFAULT, .options = ADV_OPT_PROXY, ADV_SLOW_INT, }; From 5ac063d79374183df756334c3302733c70237666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Grochala?= Date: Fri, 16 Jun 2023 08:01:37 +0200 Subject: [PATCH 0348/2042] bluetooth: controller: Fix build with BT_HCI_VS_EXT disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing error: undefined reference to 'vs_set_min_used_chans' when building with 'BT_HCI_VS_EXT' option disabled. Signed-off-by: Michał Grochala --- subsys/bluetooth/controller/hci/hci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 2b3abb22b7af..de70a3567057 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -5458,6 +5458,12 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, vs_read_tx_power_level(cmd, evt); break; #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */ + +#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) + case BT_OCF(BT_HCI_OP_VS_SET_MIN_NUM_USED_CHANS): + vs_set_min_used_chans(cmd, evt); + break; +#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ #endif /* CONFIG_BT_HCI_VS_EXT */ #if defined(CONFIG_BT_HCI_MESH_EXT) @@ -5466,12 +5472,6 @@ int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd, break; #endif /* CONFIG_BT_HCI_MESH_EXT */ -#if defined(CONFIG_BT_CTLR_MIN_USED_CHAN) && defined(CONFIG_BT_PERIPHERAL) - case BT_OCF(BT_HCI_OP_VS_SET_MIN_NUM_USED_CHANS): - vs_set_min_used_chans(cmd, evt); - break; -#endif /* CONFIG_BT_CTLR_MIN_USED_CHAN && CONFIG_BT_PERIPHERAL */ - default: return -EINVAL; } From 890363a6fb046b34042de9cce00794b652ca13b2 Mon Sep 17 00:00:00 2001 From: Guy Morand Date: Thu, 30 Mar 2023 11:22:52 +0200 Subject: [PATCH 0349/2042] drivers: led: Add lumissil is31fl3216a driver The IS31FL3216A is a fun light LED controller. The LED current of each channel can be set in 256 steps by adjusting the PWM duty cycle through an I2C interface. Signed-off-by: Guy Morand --- drivers/led/CMakeLists.txt | 1 + drivers/led/Kconfig | 1 + drivers/led/Kconfig.is31fl3216a | 11 ++ drivers/led/is31fl3216a.c | 240 +++++++++++++++++++++++++ dts/bindings/led/issi,is31fl3216a.yaml | 9 + 5 files changed, 262 insertions(+) create mode 100644 drivers/led/Kconfig.is31fl3216a create mode 100644 drivers/led/is31fl3216a.c create mode 100644 dts/bindings/led/issi,is31fl3216a.yaml diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index e018acb0cae0..018a2f362d8c 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/led.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c) +zephyr_library_sources_ifdef(CONFIG_IS31FL3216A is31fl3216a.c) zephyr_library_sources_ifdef(CONFIG_LED_GPIO led_gpio.c) zephyr_library_sources_ifdef(CONFIG_LED_PWM led_pwm.c) zephyr_library_sources_ifdef(CONFIG_LED_XEC led_mchp_xec.c) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index bf606b6e91b2..293d6347946f 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -28,6 +28,7 @@ config LED_SHELL source "drivers/led/Kconfig.gpio" source "drivers/led/Kconfig.ht16k33" +source "drivers/led/Kconfig.is31fl3216a" source "drivers/led/Kconfig.lp3943" source "drivers/led/Kconfig.lp503x" source "drivers/led/Kconfig.lp5562" diff --git a/drivers/led/Kconfig.is31fl3216a b/drivers/led/Kconfig.is31fl3216a new file mode 100644 index 000000000000..ef6481bdb807 --- /dev/null +++ b/drivers/led/Kconfig.is31fl3216a @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Endor AG +# SPDX-License-Identifier: Apache-2.0 + +config IS31FL3216A + bool "IS31FL3216A LED driver" + default y + depends on DT_HAS_ISSI_IS31FL3216A_ENABLED + select I2C + help + Enable LED driver for Lumissil Microsystems (a division of ISSI) + IS31FL3216A. This chip supports up to 16 PWM controlled LEDs. diff --git a/drivers/led/is31fl3216a.c b/drivers/led/is31fl3216a.c new file mode 100644 index 000000000000..b5b6ead10e68 --- /dev/null +++ b/drivers/led/is31fl3216a.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2023 Endor AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT issi_is31fl3216a + +#include +#include +#include + +#define IS31FL3216A_REG_CONFIG 0x00 +#define IS31FL3216A_REG_CTL_1 0x01 +#define IS31FL3216A_REG_CTL_2 0x02 +#define IS31FL3216A_REG_LIGHT_EFFECT 0x03 +#define IS31FL3216A_REG_CHANNEL_CONFIG 0x04 +#define IS31FL3216A_REG_GPIO_CONFIG 0x05 +#define IS31FL3216A_REG_OUTPUT_PORT 0x06 +#define IS31FL3216A_REG_INT_CONTROL 0x07 +#define IS31FL3216A_REG_ADC_SAMPLE_RATE 0x09 +#define IS31FL3216A_REG_PWM_FIRST 0x10 +#define IS31FL3216A_REG_PWM_LAST 0x1F +#define IS31FL3216A_REG_UPDATE 0xB0 +#define IS31FL3216A_REG_FRAME_DELAY 0xB6 +#define IS31FL3216A_REG_FRAME_START 0xB7 + +#define IS31FL3216A_MAX_LEDS 16 + +LOG_MODULE_REGISTER(is31fl3216a, CONFIG_LED_LOG_LEVEL); + +struct is31fl3216a_cfg { + struct i2c_dt_spec i2c; +}; + +static int is31fl3216a_write_buffer(const struct i2c_dt_spec *i2c, + const uint8_t *buffer, uint32_t num_bytes) +{ + int status; + + status = i2c_write_dt(i2c, buffer, num_bytes); + if (status < 0) { + LOG_ERR("Could not write buffer: %i", status); + return status; + } + + return 0; +} + +static int is31fl3216a_write_reg(const struct i2c_dt_spec *i2c, uint8_t reg, + uint8_t val) +{ + uint8_t buffer[2] = {reg, val}; + + return is31fl3216a_write_buffer(i2c, buffer, sizeof(buffer)); +} + +static int is31fl3216a_update_pwm(const struct i2c_dt_spec *i2c) +{ + return is31fl3216a_write_reg(i2c, IS31FL3216A_REG_UPDATE, 0); +} + +static uint8_t is31fl3216a_brightness_to_pwm(uint8_t brightness) +{ + return (0xFFU * brightness) / 100; +} + +static int is31fl3216a_led_write_channels(const struct device *dev, + uint32_t start_channel, + uint32_t num_channels, + const uint8_t *buf) +{ + const struct is31fl3216a_cfg *config = dev->config; + uint8_t i2c_buffer[IS31FL3216A_MAX_LEDS + 1]; + int status; + int i; + + if (num_channels == 0) { + return 0; + } + + if (start_channel + num_channels > IS31FL3216A_MAX_LEDS) { + return -EINVAL; + } + + /* Invert channels, last register is channel 0 */ + i2c_buffer[0] = IS31FL3216A_REG_PWM_LAST - start_channel - + (num_channels - 1); + for (i = 0; i < num_channels; i++) { + if (buf[num_channels - i - 1] > 100) { + return -EINVAL; + } + i2c_buffer[i + 1] = is31fl3216a_brightness_to_pwm( + buf[num_channels - i - 1]); + } + + status = is31fl3216a_write_buffer(&config->i2c, i2c_buffer, + num_channels + 1); + if (status < 0) { + return status; + } + + return is31fl3216a_update_pwm(&config->i2c); +} + +static int is31fl3216a_led_set_brightness(const struct device *dev, + uint32_t led, uint8_t value) +{ + const struct is31fl3216a_cfg *config = dev->config; + uint8_t pwm_reg = IS31FL3216A_REG_PWM_LAST - led; + int status; + uint8_t pwm_value; + + if (led > IS31FL3216A_MAX_LEDS - 1 || value > 100) { + return -EINVAL; + } + + pwm_value = is31fl3216a_brightness_to_pwm(value); + status = is31fl3216a_write_reg(&config->i2c, pwm_reg, pwm_value); + if (status < 0) { + return status; + } + + return is31fl3216a_update_pwm(&config->i2c); +} + +static int is31fl3216a_led_on(const struct device *dev, uint32_t led) +{ + return is31fl3216a_led_set_brightness(dev, led, 100); +} + +static int is31fl3216a_led_off(const struct device *dev, uint32_t led) +{ + return is31fl3216a_led_set_brightness(dev, led, 0); +} + +static int is31fl3216a_init_registers(const struct i2c_dt_spec *i2c) +{ + int i; + int status; + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_CTL_1, 0xFF); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_CTL_2, 0xFF); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_LIGHT_EFFECT, 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_CHANNEL_CONFIG, + 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_GPIO_CONFIG, 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_OUTPUT_PORT, 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_INT_CONTROL, 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_ADC_SAMPLE_RATE, + 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_FRAME_DELAY, 0x00); + if (status < 0) { + return status; + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_FRAME_START, 0x00); + if (status < 0) { + return status; + } + + for (i = IS31FL3216A_REG_PWM_FIRST; + i <= IS31FL3216A_REG_PWM_LAST; + i++) { + status = is31fl3216a_write_reg(i2c, i, 0); + if (status < 0) { + return status; + } + } + + status = is31fl3216a_write_reg(i2c, IS31FL3216A_REG_UPDATE, 0); + if (status < 0) { + return status; + } + + return is31fl3216a_write_reg(i2c, IS31FL3216A_REG_CONFIG, 0x00); +} + +static int is31fl3216a_init(const struct device *dev) +{ + const struct is31fl3216a_cfg *config = dev->config; + + LOG_DBG("Initializing @0x%x...", config->i2c.addr); + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + return is31fl3216a_init_registers(&config->i2c); +} + +static const struct led_driver_api is31fl3216a_led_api = { + .set_brightness = is31fl3216a_led_set_brightness, + .on = is31fl3216a_led_on, + .off = is31fl3216a_led_off, + .write_channels = is31fl3216a_led_write_channels +}; + +#define IS31FL3216A_INIT(id) \ + static const struct is31fl3216a_cfg is31fl3216a_##id##_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(id), \ + }; \ + DEVICE_DT_INST_DEFINE(id, &is31fl3216a_init, NULL, NULL, \ + &is31fl3216a_##id##_cfg, POST_KERNEL, \ + CONFIG_LED_INIT_PRIORITY, &is31fl3216a_led_api); + +DT_INST_FOREACH_STATUS_OKAY(IS31FL3216A_INIT) diff --git a/dts/bindings/led/issi,is31fl3216a.yaml b/dts/bindings/led/issi,is31fl3216a.yaml new file mode 100644 index 000000000000..c010ae71829d --- /dev/null +++ b/dts/bindings/led/issi,is31fl3216a.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Endor AG +# SPDX-License-Identifier: Apache-2.0 + +description: | + is31fl3216a LED driver for Lumissil Microsystems (a division of ISSI) + +compatible: "issi,is31fl3216a" + +include: i2c-device.yaml From d87d934e75fcc21fd4cd531c28a44c3ba182d3b4 Mon Sep 17 00:00:00 2001 From: Guy Morand Date: Wed, 3 May 2023 14:43:53 +0200 Subject: [PATCH 0350/2042] samples: Add is31fl3216a LED sample This demonstrates and tests is31fl3216a driver functionality. Signed-off-by: Guy Morand --- .../drivers/led_is31fl3216a/CMakeLists.txt | 9 ++ samples/drivers/led_is31fl3216a/README.rst | 42 +++++++ .../boards/arduino_i2c.overlay | 19 ++++ .../boards/lpcxpresso55s28.overlay | 15 +++ samples/drivers/led_is31fl3216a/prj.conf | 2 + samples/drivers/led_is31fl3216a/sample.yaml | 8 ++ samples/drivers/led_is31fl3216a/src/main.c | 105 ++++++++++++++++++ 7 files changed, 200 insertions(+) create mode 100644 samples/drivers/led_is31fl3216a/CMakeLists.txt create mode 100644 samples/drivers/led_is31fl3216a/README.rst create mode 100644 samples/drivers/led_is31fl3216a/boards/arduino_i2c.overlay create mode 100644 samples/drivers/led_is31fl3216a/boards/lpcxpresso55s28.overlay create mode 100644 samples/drivers/led_is31fl3216a/prj.conf create mode 100644 samples/drivers/led_is31fl3216a/sample.yaml create mode 100644 samples/drivers/led_is31fl3216a/src/main.c diff --git a/samples/drivers/led_is31fl3216a/CMakeLists.txt b/samples/drivers/led_is31fl3216a/CMakeLists.txt new file mode 100644 index 000000000000..055c5ef1f152 --- /dev/null +++ b/samples/drivers/led_is31fl3216a/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(led_is31fl3216a) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/led_is31fl3216a/README.rst b/samples/drivers/led_is31fl3216a/README.rst new file mode 100644 index 000000000000..fb3c2353dd5f --- /dev/null +++ b/samples/drivers/led_is31fl3216a/README.rst @@ -0,0 +1,42 @@ +.. _is31fl3216a: + +is31fl3216a: 16 channels PWD LEDs controller +############################################ + +Overview +******** + +This sample controls up to 16 LEDs connected to a is31fl3216a driver. + +Each LED is gradually pulsed until it reach 100% of luminosity and gradually +turned off again. + +Once each LED was pulsed, multiple LEDs are pulse simultaneously using the +``write_channels`` LED API. + +Test pattern +============ + +For each LED: +- Increase the luminosity until 100% is reached +- Decrease the luminosity until completely turned off + +- Increase the luminosity of LEDs 2 to 4 until 100% is reached +- Decrease the luminosity of LEDs 2 to 4 until completely turned off + +Building and Running +******************** + +This sample can be built and executed when the devicetree has an I2C device node +with compatible :dtcompatible:`issi,is31fl3216a` enabled, along with the relevant +bus controller node also being enabled. + +As an example this sample provides a DTS overlay for the :ref:`lpcxpresso55s28` +board (:file:`boards/lpcxpresso55s28.overlay`). It assumes that a I2C +_is31fl3216a LED driver (with 16 LEDs wired) is connected to the I2C bus at +address 0x74. + +References +********** + +- is31fl3216a: https://lumissil.com/assets/pdf/core/IS31FL3216A_DS.pdf diff --git a/samples/drivers/led_is31fl3216a/boards/arduino_i2c.overlay b/samples/drivers/led_is31fl3216a/boards/arduino_i2c.overlay new file mode 100644 index 000000000000..bff4b0ccdbde --- /dev/null +++ b/samples/drivers/led_is31fl3216a/boards/arduino_i2c.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Endor AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Example configuration of a is31fl3216a device on an Arduino I2C bus. + * + * Device address 0x74 is assumed. Your device may have a different + * address; check your device documentation if unsure. + */ +&arduino_i2c { + status = "okay"; + is31fl3216a@74 { + compatible = "issi,is31fl3216a"; + reg = <0x74>; + }; +}; diff --git a/samples/drivers/led_is31fl3216a/boards/lpcxpresso55s28.overlay b/samples/drivers/led_is31fl3216a/boards/lpcxpresso55s28.overlay new file mode 100644 index 000000000000..fdea50c98b71 --- /dev/null +++ b/samples/drivers/led_is31fl3216a/boards/lpcxpresso55s28.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Endor AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&flexcomm4 { + status = "okay"; + is31fl3216a@74 { + compatible = "issi,is31fl3216a"; + reg = <0x74>; + }; +}; diff --git a/samples/drivers/led_is31fl3216a/prj.conf b/samples/drivers/led_is31fl3216a/prj.conf new file mode 100644 index 000000000000..df85f3b69dfb --- /dev/null +++ b/samples/drivers/led_is31fl3216a/prj.conf @@ -0,0 +1,2 @@ +CONFIG_LOG=y +CONFIG_LED=y diff --git a/samples/drivers/led_is31fl3216a/sample.yaml b/samples/drivers/led_is31fl3216a/sample.yaml new file mode 100644 index 000000000000..fea755930120 --- /dev/null +++ b/samples/drivers/led_is31fl3216a/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: Demonstration of the is31fl3216a LED driver + name: is31fl3216a sample +tests: + sample.drivers.led.is31fl3216a: + filter: dt_compat_enabled("issi,is31fl3216a") + tags: LED + depends_on: i2c diff --git a/samples/drivers/led_is31fl3216a/src/main.c b/samples/drivers/led_is31fl3216a/src/main.c new file mode 100644 index 000000000000..ce56642a76e2 --- /dev/null +++ b/samples/drivers/led_is31fl3216a/src/main.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Endor AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL); + +#define MAX_BRIGHTNESS 100 +#define LAST_LED 15 + +#define SLEEP_DELAY_MS 100 +#define FADE_DELAY_MS 10 +#define WRITE_CHANNELS_LEDS_COUNT 3 +#define WRITE_CHANNELS_LED_START 2 + +static void pulse_led(int led, const struct device *const dev) +{ + int status; + uint8_t percent; + + for (percent = 1 ; percent <= MAX_BRIGHTNESS ; percent++) { + status = led_set_brightness(dev, led, percent); + if (status) { + LOG_ERR("Could not change brightness: %i", status); + return; + } + k_msleep(FADE_DELAY_MS); + } + k_msleep(SLEEP_DELAY_MS); + for (percent = MAX_BRIGHTNESS; + percent <= MAX_BRIGHTNESS; percent--) { + status = led_set_brightness(dev, led, percent); + if (status) { + LOG_ERR("Could not change brightness: %i", status); + return; + } + k_msleep(FADE_DELAY_MS); + } +} + +static void pulse_leds(const struct device *const dev) +{ + int status; + uint8_t brightness[WRITE_CHANNELS_LEDS_COUNT]; + uint8_t percent; + + for (percent = 1; percent <= MAX_BRIGHTNESS; percent++) { + memset(brightness, percent, sizeof(brightness)); + status = led_write_channels(dev, WRITE_CHANNELS_LED_START, + WRITE_CHANNELS_LEDS_COUNT, + brightness); + if (status) { + LOG_ERR("Could not change brightness: %i", status); + return; + } + k_msleep(FADE_DELAY_MS); + } + k_msleep(SLEEP_DELAY_MS); + for (percent = MAX_BRIGHTNESS; + percent <= MAX_BRIGHTNESS; percent--) { + memset(brightness, percent, sizeof(brightness)); + status = led_write_channels(dev, WRITE_CHANNELS_LED_START, + WRITE_CHANNELS_LEDS_COUNT, + brightness); + if (status) { + LOG_ERR("Could not change brightness: %i", status); + return; + } + k_msleep(FADE_DELAY_MS); + } +} + +int main(void) +{ + int led; + const struct device *const is31fl3216a = + DEVICE_DT_GET_ANY(issi_is31fl3216a); + + if (!is31fl3216a) { + LOG_ERR("No device with compatible issi,is31fl3216a found"); + return 0; + } else if (!device_is_ready(is31fl3216a)) { + LOG_ERR("LED controller %s is not ready", is31fl3216a->name); + return 0; + } + + LOG_INF("Found LED controller %s", is31fl3216a->name); + for (;;) { + LOG_INF("Pulsing single LED"); + for (led = 0 ; led <= LAST_LED ; led++) { + pulse_led(led, is31fl3216a); + } + LOG_INF("Pulsing multiple LEDs"); + pulse_leds(is31fl3216a); + } + + return 0; +} From d7964cd212bb3bfbd6c60737b385764f21c780cc Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 31 May 2023 12:52:54 +0100 Subject: [PATCH 0351/2042] drivers: mfd: npm1300: Initial version Added an MFD driver for the nPM1300. This driver has register access helper functions that can be used by subsystems. This will avoid each subsystem having to duplicate the register access code. Signed-off-by: Andy Sinclair --- doc/_doxygen/groups.dox | 6 ++ drivers/mfd/CMakeLists.txt | 1 + drivers/mfd/Kconfig | 1 + drivers/mfd/Kconfig.npm1300 | 10 +++ drivers/mfd/mfd_npm1300.c | 122 +++++++++++++++++++++++++++ include/zephyr/drivers/mfd/npm1300.h | 96 +++++++++++++++++++++ 6 files changed, 236 insertions(+) create mode 100644 drivers/mfd/Kconfig.npm1300 create mode 100644 drivers/mfd/mfd_npm1300.c create mode 100644 include/zephyr/drivers/mfd/npm1300.h diff --git a/doc/_doxygen/groups.dox b/doc/_doxygen/groups.dox index ddc0c1c36400..cd4efcd62946 100644 --- a/doc/_doxygen/groups.dox +++ b/doc/_doxygen/groups.dox @@ -22,6 +22,12 @@ @{ @} +@brief Multi Function Device Drivers APIs +@defgroup mfd_interfaces Multi Function Device Drivers APIs +@ingroup io_interfaces +@{ +@} + @brief Testing @defgroup testing Testing @{ diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index 6719916cc1b4..d7071a6af95b 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -3,4 +3,5 @@ zephyr_library() +zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 42ac815e55b7..64a166c7cc78 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,6 +18,7 @@ config MFD_INIT_PRIORITY help Multi-function devices initialization priority. +source "drivers/mfd/Kconfig.npm1300" source "drivers/mfd/Kconfig.npm6001" endif # MFD diff --git a/drivers/mfd/Kconfig.npm1300 b/drivers/mfd/Kconfig.npm1300 new file mode 100644 index 000000000000..cc3eb0ef3033 --- /dev/null +++ b/drivers/mfd/Kconfig.npm1300 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX -License-Identifier: Apache-2.0 + +config MFD_NPM1300 + bool "nPM1300 PMIC multi-function device driver" + default y + depends on DT_HAS_NORDIC_NPM1300_ENABLED + select I2C + help + Enable the Nordic nPM1300 PMIC multi-function device driver diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c new file mode 100644 index 000000000000..34b03b85bc43 --- /dev/null +++ b/drivers/mfd/mfd_npm1300.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_npm1300 + +#include + +#include +#include +#include + +struct mfd_npm1300_config { + struct i2c_dt_spec i2c; +}; + +struct mfd_npm1300_data { + struct k_mutex mutex; +}; + +static int mfd_npm1300_init(const struct device *dev) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + + if (!i2c_is_ready_dt(&config->i2c)) { + return -ENODEV; + } + + k_mutex_init(&mfd_data->mutex); + + return 0; +} + +int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data, + size_t len) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) +{ + return mfd_npm1300_reg_read_burst(dev, base, offset, data, 1U); +} + +int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset, data}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, + uint8_t data2) +{ + const struct mfd_npm1300_config *config = dev->config; + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t buff[] = {base, offset, data1, data2}; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, + uint8_t mask) +{ + struct mfd_npm1300_data *mfd_data = dev->data; + uint8_t reg; + int ret; + + k_mutex_lock(&mfd_data->mutex, K_FOREVER); + + ret = mfd_npm1300_reg_read(dev, base, offset, ®); + + if (ret == 0) { + reg = (reg & ~mask) | (data & mask); + ret = mfd_npm1300_reg_write(dev, base, offset, reg); + } + + k_mutex_unlock(&mfd_data->mutex); + + return ret; +} + +#define MFD_NPM1300_DEFINE(inst) \ + static struct mfd_npm1300_data data_##inst; \ + \ + static const struct mfd_npm1300_config config##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_npm1300_init, NULL, &data_##inst, &config##inst, \ + POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_NPM1300_DEFINE) diff --git a/include/zephyr/drivers/mfd/npm1300.h b/include/zephyr/drivers/mfd/npm1300.h new file mode 100644 index 000000000000..372ab725ed9d --- /dev/null +++ b/include/zephyr/drivers/mfd/npm1300.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup mdf_interface_npm1300 MFD NPM1300 Interface + * @ingroup mfd_interfaces + * @{ + */ + +#include +#include + +#include + +/** + * @brief Read multiple registers from npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data Pointer to buffer for received data + * @param len Number of bytes to read + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt()) + */ +int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, + void *data, size_t len); + +/** + * @brief Read single register from npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data Pointer to buffer for received data + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt()) + */ +int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data); + +/** + * @brief Write single register to npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data data to write + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data); + +/** + * @brief Write two registers to npm1300 + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data1 first byte of data to write + * @param data2 second byte of data to write + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, + uint8_t data2); + +/** + * @brief Update selected bits in npm1300 register + * + * @param dev npm1300 mfd device + * @param base Register base address (bits 15..8 of 16-bit address) + * @param offset Register offset address (bits 7..0 of 16-bit address) + * @param data data to write + * @param mask mask of bits to be modified + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_read_dt(), i2c_write_dt()) + */ +int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, + uint8_t mask); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_NPM1300_H_ */ From 5e6f82c872c548a436bf26adfd49cc5df76e5f1e Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 31 May 2023 13:10:52 +0100 Subject: [PATCH 0352/2042] drivers: regulator: npm1300: Now uses MFD register access functions Local register read/write functions have been removed and replaced with calls to the new MFD functions. Signed-off-by: Andy Sinclair --- drivers/regulator/Kconfig.npm1300 | 1 + drivers/regulator/regulator_npm1300.c | 138 ++++++++++---------------- 2 files changed, 55 insertions(+), 84 deletions(-) diff --git a/drivers/regulator/Kconfig.npm1300 b/drivers/regulator/Kconfig.npm1300 index fe424b7cf77a..a003f90f7a9f 100644 --- a/drivers/regulator/Kconfig.npm1300 +++ b/drivers/regulator/Kconfig.npm1300 @@ -6,6 +6,7 @@ config REGULATOR_NPM1300 default y depends on DT_HAS_NORDIC_NPM1300_REGULATOR_ENABLED select I2C + select MFD help Enable the Nordic nPM1300 PMIC regulator driver diff --git a/drivers/regulator/regulator_npm1300.c b/drivers/regulator/regulator_npm1300.c index 1a245fd6fd1c..7f05e12b5b3e 100644 --- a/drivers/regulator/regulator_npm1300.c +++ b/drivers/regulator/regulator_npm1300.c @@ -9,10 +9,9 @@ #include #include -#include #include +#include #include -#include #include #include @@ -59,14 +58,12 @@ enum npm1300_gpio_type { #define LDSW_OFFSET_VOUTSEL 0x0CU struct regulator_npm1300_pconfig { - struct i2c_dt_spec i2c; struct gpio_dt_spec dvs_state_pins[5]; - uint8_t pad_val; }; struct regulator_npm1300_config { struct regulator_common_config common; - const struct device *p; + const struct device *mfd; uint8_t source; int32_t retention_uv; struct gpio_dt_spec enable_gpios; @@ -81,50 +78,6 @@ struct regulator_npm1300_data { /* Linear range for output voltage, common for all bucks and LDOs on this device */ static const struct linear_range buckldo_range = LINEAR_RANGE_INIT(1000000, 100000, 0U, 23U); -/* Read multiple registers from specified address */ -static int reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data, - size_t len) -{ - const struct regulator_npm1300_config *config = dev->config; - const struct regulator_npm1300_pconfig *pconfig = config->p->config; - uint8_t buff[] = {base, offset}; - - return i2c_write_read_dt(&pconfig->i2c, buff, sizeof(buff), data, len); -} - -static int reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) -{ - return reg_read_burst(dev, base, offset, data, 1U); -} - -/* Write single register to specified address */ -static int reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) -{ - const struct regulator_npm1300_config *config = dev->config; - const struct regulator_npm1300_pconfig *pconfig = config->p->config; - uint8_t buff[] = {base, offset, data}; - - return i2c_write_dt(&pconfig->i2c, buff, sizeof(buff)); -} - -/* Modify bits in single register */ -static int reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, - uint8_t mask) -{ - uint8_t reg; - int ret; - - ret = reg_read(dev, base, offset, ®); - - if (ret < 0) { - return ret; - } - - reg = (reg & ~mask) | (data & mask); - - return reg_write(dev, base, offset, reg); -} - unsigned int regulator_npm1300_count_voltages(const struct device *dev) { const struct regulator_npm1300_config *config = dev->config; @@ -179,11 +132,13 @@ static int retention_set_voltage(const struct device *dev, int32_t retention_uv) return ret; } - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_VOUT_RET + (chan * 2U), idx); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_VOUT_RET + (chan * 2U), + idx); } static int buck_set_voltage(const struct device *dev, uint8_t chan, int32_t min_uv, int32_t max_uv) { + const struct regulator_npm1300_config *config = dev->config; uint8_t mask; uint16_t idx; int ret; @@ -194,7 +149,8 @@ static int buck_set_voltage(const struct device *dev, uint8_t chan, int32_t min_ return ret; } - ret = reg_write(dev, BUCK_BASE, BUCK_OFFSET_VOUT_NORM + (chan * 2U), idx); + ret = mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_VOUT_NORM + (chan * 2U), + idx); if (ret < 0) { return ret; @@ -202,11 +158,12 @@ static int buck_set_voltage(const struct device *dev, uint8_t chan, int32_t min_ /* Enable SW control of buck output */ mask = BIT(chan); - return reg_update(dev, BUCK_BASE, BUCK_OFFSET_SW_CTRL, mask, mask); + return mfd_npm1300_reg_update(config->mfd, BUCK_BASE, BUCK_OFFSET_SW_CTRL, mask, mask); } static int ldo_set_voltage(const struct device *dev, uint8_t chan, int32_t min_uv, int32_t max_uv) { + const struct regulator_npm1300_config *config = dev->config; uint16_t idx; int ret; @@ -216,7 +173,7 @@ static int ldo_set_voltage(const struct device *dev, uint8_t chan, int32_t min_u return ret; } - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_VOUTSEL + chan, idx); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_VOUTSEL + chan, idx); } int regulator_npm1300_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) @@ -239,11 +196,12 @@ int regulator_npm1300_set_voltage(const struct device *dev, int32_t min_uv, int3 static int buck_get_voltage(const struct device *dev, uint8_t chan, int32_t *volt_uv) { + const struct regulator_npm1300_config *config = dev->config; uint8_t sel; uint8_t idx; int ret; - ret = reg_read(dev, BUCK_BASE, BUCK_OFFSET_SW_CTRL, &sel); + ret = mfd_npm1300_reg_read(config->mfd, BUCK_BASE, BUCK_OFFSET_SW_CTRL, &sel); if (ret < 0) { return ret; @@ -251,10 +209,12 @@ static int buck_get_voltage(const struct device *dev, uint8_t chan, int32_t *vol if ((sel >> chan) & 1U) { /* SW control */ - ret = reg_read(dev, BUCK_BASE, BUCK_OFFSET_VOUT_NORM + (chan * 2U), &idx); + ret = mfd_npm1300_reg_read(config->mfd, BUCK_BASE, + BUCK_OFFSET_VOUT_NORM + (chan * 2U), &idx); } else { /* VSET pin control */ - ret = reg_read(dev, BUCK_BASE, BUCK_OFFSET_VOUT_STAT + chan, &idx); + ret = mfd_npm1300_reg_read(config->mfd, BUCK_BASE, BUCK_OFFSET_VOUT_STAT + chan, + &idx); } if (ret < 0) { @@ -266,10 +226,11 @@ static int buck_get_voltage(const struct device *dev, uint8_t chan, int32_t *vol static int ldo_get_voltage(const struct device *dev, uint8_t chan, int32_t *volt_uv) { + const struct regulator_npm1300_config *config = dev->config; uint8_t idx; int ret; - ret = reg_read(dev, LDSW_BASE, LDSW_OFFSET_VOUTSEL + chan, &idx); + ret = mfd_npm1300_reg_read(config->mfd, LDSW_BASE, LDSW_OFFSET_VOUTSEL + chan, &idx); if (ret < 0) { return ret; @@ -298,11 +259,15 @@ int regulator_npm1300_get_voltage(const struct device *dev, int32_t *volt_uv) static int set_buck_mode(const struct device *dev, uint8_t chan, regulator_mode_t mode) { + const struct regulator_npm1300_config *config = dev->config; + switch (mode) { case NPM1300_BUCK_MODE_PWM: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_PWM_SET + (chan * 2U), 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, + BUCK_OFFSET_PWM_SET + (chan * 2U), 1U); case NPM1300_BUCK_MODE_AUTO: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_PWM_CLR + (chan * 2U), 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, + BUCK_OFFSET_PWM_CLR + (chan * 2U), 1U); default: return -ENOTSUP; } @@ -310,11 +275,13 @@ static int set_buck_mode(const struct device *dev, uint8_t chan, regulator_mode_ static int set_ldsw_mode(const struct device *dev, uint8_t chan, regulator_mode_t mode) { + const struct regulator_npm1300_config *config = dev->config; + switch (mode) { case NPM1300_LDSW_MODE_LDO: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_LDOSEL + chan, 1U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_LDOSEL + chan, 1U); case NPM1300_LDSW_MODE_LDSW: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_LDOSEL + chan, 0U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_LDOSEL + chan, 0U); default: return -ENOTSUP; } @@ -344,13 +311,13 @@ int regulator_npm1300_enable(const struct device *dev) switch (config->source) { case NPM1300_SOURCE_BUCK1: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_EN_SET, 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_EN_SET, 1U); case NPM1300_SOURCE_BUCK2: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_EN_SET + 2U, 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_EN_SET + 2U, 1U); case NPM1300_SOURCE_LDO1: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_EN_SET, 1U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_EN_SET, 1U); case NPM1300_SOURCE_LDO2: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_EN_SET + 2U, 1U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_EN_SET + 2U, 1U); default: return 0; } @@ -362,13 +329,13 @@ int regulator_npm1300_disable(const struct device *dev) switch (config->source) { case NPM1300_SOURCE_BUCK1: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_EN_CLR, 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_EN_CLR, 1U); case NPM1300_SOURCE_BUCK2: - return reg_write(dev, BUCK_BASE, BUCK_OFFSET_EN_CLR + 2U, 1U); + return mfd_npm1300_reg_write(config->mfd, BUCK_BASE, BUCK_OFFSET_EN_CLR + 2U, 1U); case NPM1300_SOURCE_LDO1: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_EN_CLR, 1U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_EN_CLR, 1U); case NPM1300_SOURCE_LDO2: - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_EN_CLR + 2U, 1U); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_EN_CLR + 2U, 1U); default: return 0; } @@ -377,6 +344,7 @@ int regulator_npm1300_disable(const struct device *dev) static int regulator_npm1300_set_buck_pin_ctrl(const struct device *dev, uint8_t chan, uint8_t pin, uint8_t inv, enum npm1300_gpio_type type) { + const struct regulator_npm1300_config *config = dev->config; uint8_t ctrl; uint8_t mask; @@ -397,11 +365,14 @@ static int regulator_npm1300_set_buck_pin_ctrl(const struct device *dev, uint8_t switch (type) { case NPM1300_GPIO_TYPE_ENABLE: - return reg_update(dev, BUCK_BASE, BUCK_OFFSET_EN_CTRL, ctrl, mask); + return mfd_npm1300_reg_update(config->mfd, BUCK_BASE, BUCK_OFFSET_EN_CTRL, ctrl, + mask); case NPM1300_GPIO_TYPE_PWM: - return reg_update(dev, BUCK_BASE, BUCK_OFFSET_PWM_CTRL, ctrl, mask); + return mfd_npm1300_reg_update(config->mfd, BUCK_BASE, BUCK_OFFSET_PWM_CTRL, ctrl, + mask); case NPM1300_GPIO_TYPE_RETENTION: - return reg_update(dev, BUCK_BASE, BUCK_OFFSET_VRET_CTRL, ctrl, mask); + return mfd_npm1300_reg_update(config->mfd, BUCK_BASE, BUCK_OFFSET_VRET_CTRL, ctrl, + mask); default: return -ENOTSUP; } @@ -410,6 +381,7 @@ static int regulator_npm1300_set_buck_pin_ctrl(const struct device *dev, uint8_t static int regulator_npm1300_set_ldsw_pin_ctrl(const struct device *dev, uint8_t chan, uint8_t pin, uint8_t inv, enum npm1300_gpio_type type) { + const struct regulator_npm1300_config *config = dev->config; uint8_t ctrl; if (type != NPM1300_GPIO_TYPE_ENABLE) { @@ -418,7 +390,7 @@ static int regulator_npm1300_set_ldsw_pin_ctrl(const struct device *dev, uint8_t ctrl = (pin + 1U) | (inv << 3U); - return reg_write(dev, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, type); + return mfd_npm1300_reg_write(config->mfd, LDSW_BASE, LDSW_OFFSET_GPISEL + chan, type); } int regulator_npm1300_set_pin_ctrl(const struct device *dev, const struct gpio_dt_spec *spec, @@ -501,7 +473,7 @@ int regulator_npm1300_init(const struct device *dev) const struct regulator_npm1300_config *config = dev->config; int ret = 0; - if (!device_is_ready(config->p)) { + if (!device_is_ready(config->mfd)) { return -ENODEV; } @@ -546,12 +518,12 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab .get_voltage = regulator_npm1300_get_voltage, .set_mode = regulator_npm1300_set_mode}; -#define REGULATOR_NPM1300_DEFINE(node_id, id, _source, parent) \ +#define REGULATOR_NPM1300_DEFINE(node_id, id, _source) \ static struct regulator_npm1300_data data_##id; \ \ static const struct regulator_npm1300_config config_##id = { \ .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \ - .p = parent, \ + .mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \ .source = _source, \ .retention_uv = DT_PROP_OR(node_id, retention_microvolt, 0), \ .enable_gpios = GPIO_DT_SPEC_GET_OR(node_id, enable_gpios, {0}), \ @@ -561,15 +533,13 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab DEVICE_DT_DEFINE(node_id, regulator_npm1300_init, NULL, &data_##id, &config_##id, \ POST_KERNEL, CONFIG_REGULATOR_NPM1300_INIT_PRIORITY, &api); -#define REGULATOR_NPM1300_DEFINE_COND(inst, child, source, parent) \ +#define REGULATOR_NPM1300_DEFINE_COND(inst, child, source) \ COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ - (REGULATOR_NPM1300_DEFINE(DT_INST_CHILD(inst, child), child##inst, source, \ - parent)), \ + (REGULATOR_NPM1300_DEFINE(DT_INST_CHILD(inst, child), child##inst, source)), \ ()) #define REGULATOR_NPM1300_DEFINE_ALL(inst) \ static const struct regulator_npm1300_pconfig config_##inst = { \ - .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ .dvs_state_pins = {GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 0, {0}), \ GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 1, {0}), \ GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 2, {0}), \ @@ -580,9 +550,9 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab POST_KERNEL, CONFIG_REGULATOR_NPM1300_COMMON_INIT_PRIORITY, \ &parent_api); \ \ - REGULATOR_NPM1300_DEFINE_COND(inst, buck1, NPM1300_SOURCE_BUCK1, DEVICE_DT_INST_GET(inst)) \ - REGULATOR_NPM1300_DEFINE_COND(inst, buck2, NPM1300_SOURCE_BUCK2, DEVICE_DT_INST_GET(inst)) \ - REGULATOR_NPM1300_DEFINE_COND(inst, ldo1, NPM1300_SOURCE_LDO1, DEVICE_DT_INST_GET(inst)) \ - REGULATOR_NPM1300_DEFINE_COND(inst, ldo2, NPM1300_SOURCE_LDO2, DEVICE_DT_INST_GET(inst)) + REGULATOR_NPM1300_DEFINE_COND(inst, buck1, NPM1300_SOURCE_BUCK1) \ + REGULATOR_NPM1300_DEFINE_COND(inst, buck2, NPM1300_SOURCE_BUCK2) \ + REGULATOR_NPM1300_DEFINE_COND(inst, ldo1, NPM1300_SOURCE_LDO1) \ + REGULATOR_NPM1300_DEFINE_COND(inst, ldo2, NPM1300_SOURCE_LDO2) DT_INST_FOREACH_STATUS_OKAY(REGULATOR_NPM1300_DEFINE_ALL) From b31f60470f8c4df1f7d37d36f026e5f787a7b978 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 2 Jun 2023 09:12:40 +0100 Subject: [PATCH 0353/2042] drivers: sensor: npm1300_charger: use MFD register functions Local register read/write functions have been removed and replaced with calls to the new MFD functions. Signed-off-by: Andy Sinclair --- drivers/sensor/npm1300_charger/Kconfig | 1 + .../sensor/npm1300_charger/npm1300_charger.c | 79 ++++++------------- 2 files changed, 26 insertions(+), 54 deletions(-) diff --git a/drivers/sensor/npm1300_charger/Kconfig b/drivers/sensor/npm1300_charger/Kconfig index 12a3e6937cf5..abafa5309504 100644 --- a/drivers/sensor/npm1300_charger/Kconfig +++ b/drivers/sensor/npm1300_charger/Kconfig @@ -7,6 +7,7 @@ config NPM1300_CHARGER default y depends on DT_HAS_NORDIC_NPM1300_CHARGER_ENABLED select I2C + select MFD select REQUIRES_FULL_LIBC help Enable NPM1300 charger driver. diff --git a/drivers/sensor/npm1300_charger/npm1300_charger.c b/drivers/sensor/npm1300_charger/npm1300_charger.c index 8a5ff935777d..b7d52fc5e65c 100644 --- a/drivers/sensor/npm1300_charger/npm1300_charger.c +++ b/drivers/sensor/npm1300_charger/npm1300_charger.c @@ -6,14 +6,14 @@ #define DT_DRV_COMPAT nordic_npm1300_charger #include -#include #include +#include #include #include #include struct npm1300_charger_config { - struct i2c_dt_spec i2c; + const struct device *mfd; int32_t term_microvolt; int32_t term_warm_microvolt; int32_t current_microamp; @@ -103,39 +103,6 @@ static const struct linear_range discharge_limit_range = LINEAR_RANGE_INIT(26809 static const struct linear_range vbus_current_ranges[] = { LINEAR_RANGE_INIT(100000, 0, 1U, 1U), LINEAR_RANGE_INIT(500000, 100000, 5U, 15U)}; -/* Read multiple registers from specified address */ -static int reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data, - size_t len) -{ - const struct npm1300_charger_config *const config = dev->config; - uint8_t buff[] = {base, offset}; - - return i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len); -} - -static int reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) -{ - return reg_read_burst(dev, base, offset, data, 1U); -} - -/* Write single register to specified address */ -static int reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) -{ - const struct npm1300_charger_config *const config = dev->config; - uint8_t buff[] = {base, offset, data}; - - return i2c_write_dt(&config->i2c, buff, sizeof(buff)); -} - -static int reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, - uint8_t data2) -{ - const struct npm1300_charger_config *const config = dev->config; - uint8_t buff[] = {base, offset, data1, data2}; - - return i2c_write_dt(&config->i2c, buff, sizeof(buff)); -} - static void calc_temp(const struct npm1300_charger_config *const config, uint16_t code, struct sensor_value *valp) { @@ -228,24 +195,26 @@ int npm1300_charger_channel_get(const struct device *dev, enum sensor_channel ch int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel chan) { + const struct npm1300_charger_config *const config = dev->config; struct npm1300_charger_data *data = dev->data; struct adc_results_t results; bool last_vbus; int ret; /* Read charge status and error reason */ - ret = reg_read(dev, CHGR_BASE, CHGR_OFFSET_CHG_STAT, &data->status); + ret = mfd_npm1300_reg_read(config->mfd, CHGR_BASE, CHGR_OFFSET_CHG_STAT, &data->status); if (ret != 0) { return ret; } - ret = reg_read(dev, CHGR_BASE, CHGR_OFFSET_ERR_REASON, &data->error); + ret = mfd_npm1300_reg_read(config->mfd, CHGR_BASE, CHGR_OFFSET_ERR_REASON, &data->error); if (ret != 0) { return ret; } /* Read adc results */ - ret = reg_read_burst(dev, ADC_BASE, ADC_OFFSET_RESULTS, &results, sizeof(results)); + ret = mfd_npm1300_reg_read_burst(config->mfd, ADC_BASE, ADC_OFFSET_RESULTS, &results, + sizeof(results)); if (ret != 0) { return ret; } @@ -256,26 +225,26 @@ int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel c data->ibat_stat = results.ibat_stat; /* Trigger temperature measurement */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); if (ret != 0) { return ret; } /* Trigger current and voltage measurement */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U); if (ret != 0) { return ret; } /* Read vbus status, and set SW current limit on new vbus detection */ last_vbus = (data->vbus_stat & 1U) != 0U; - ret = reg_read(dev, VBUS_BASE, VBUS_OFFSET_STATUS, &data->vbus_stat); + ret = mfd_npm1300_reg_read(config->mfd, VBUS_BASE, VBUS_OFFSET_STATUS, &data->vbus_stat); if (ret != 0) { return ret; } if (!last_vbus && ((data->vbus_stat & 1U) != 0U)) { - ret = reg_write(dev, VBUS_BASE, VBUS_OFFSET_TASK_UPDATE, 1U); + ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_TASK_UPDATE, 1U); if (ret != 0) { return ret; @@ -291,12 +260,13 @@ int npm1300_charger_init(const struct device *dev) uint16_t idx; int ret; - if (!i2c_is_ready_dt(&config->i2c)) { + if (!device_is_ready(config->mfd)) { return -ENODEV; } /* Configure thermistor */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_NTCR_SEL, config->thermistor_idx + 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_NTCR_SEL, + config->thermistor_idx + 1U); if (ret != 0) { return ret; } @@ -308,7 +278,7 @@ int npm1300_charger_init(const struct device *dev) if (ret == -EINVAL) { return ret; } - ret = reg_write(dev, CHGR_BASE, CHGR_OFFSET_VTERM, idx); + ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_VTERM, idx); if (ret != 0) { return ret; } @@ -320,7 +290,7 @@ int npm1300_charger_init(const struct device *dev) return ret; } - ret = reg_write(dev, CHGR_BASE, CHGR_OFFSET_VTERM_R, idx); + ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_VTERM_R, idx); if (ret != 0) { return ret; } @@ -333,7 +303,7 @@ int npm1300_charger_init(const struct device *dev) return ret; } - ret = reg_write2(dev, CHGR_BASE, CHGR_OFFSET_ISET, idx / 2U, idx & 1U); + ret = mfd_npm1300_reg_write2(config->mfd, CHGR_BASE, CHGR_OFFSET_ISET, idx / 2U, idx & 1U); if (ret != 0) { return ret; } @@ -346,7 +316,8 @@ int npm1300_charger_init(const struct device *dev) return ret; } - ret = reg_write2(dev, CHGR_BASE, CHGR_OFFSET_ISET_DISCHG, idx / 2U, idx & 1U); + ret = mfd_npm1300_reg_write2(config->mfd, CHGR_BASE, CHGR_OFFSET_ISET_DISCHG, idx / 2U, + idx & 1U); if (ret != 0) { return ret; } @@ -358,32 +329,32 @@ int npm1300_charger_init(const struct device *dev) if (ret == -EINVAL) { return ret; } - ret = reg_write(dev, VBUS_BASE, VBUS_OFFSET_ILIM, idx); + ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIM, idx); if (ret != 0) { return ret; } /* Enable current measurement */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_IBAT_EN, 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_IBAT_EN, 1U); if (ret != 0) { return ret; } /* Trigger current and voltage measurement */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_VBAT, 1U); if (ret != 0) { return ret; } /* Trigger temperature measurement */ - ret = reg_write(dev, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_TEMP, 1U); if (ret != 0) { return ret; } /* Enable charging if configured */ if (config->charging_enable) { - ret = reg_write(dev, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U); + ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U); if (ret != 0) { return ret; } @@ -401,7 +372,7 @@ static const struct sensor_driver_api npm1300_charger_battery_driver_api = { static struct npm1300_charger_data npm1300_charger_data_##n; \ \ static const struct npm1300_charger_config npm1300_charger_config_##n = { \ - .i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(n)), \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ .term_microvolt = DT_INST_PROP(n, term_microvolt), \ .term_warm_microvolt = \ DT_INST_PROP_OR(n, term_warm_microvolt, DT_INST_PROP(n, term_microvolt)), \ From 68589ca0f1d0af789bf1853c6a296d39fe5ebfe1 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 2 Jun 2023 09:23:18 +0100 Subject: [PATCH 0354/2042] drivers: gpio: npm1300: Use MFD register functions Local register read/write functions have been removed and replaced with calls to the new MFD functions. Signed-off-by: Andy Sinclair --- drivers/gpio/Kconfig.npm1300 | 1 + drivers/gpio/gpio_npm1300.c | 75 +++++++++++++++--------------------- drivers/mfd/mfd_npm1300.c | 30 ++------------- 3 files changed, 35 insertions(+), 71 deletions(-) diff --git a/drivers/gpio/Kconfig.npm1300 b/drivers/gpio/Kconfig.npm1300 index 6123956694a6..6f419c97d1e2 100644 --- a/drivers/gpio/Kconfig.npm1300 +++ b/drivers/gpio/Kconfig.npm1300 @@ -6,6 +6,7 @@ config GPIO_NPM1300 default y depends on DT_HAS_NORDIC_NPM1300_GPIO_ENABLED select I2C + select MFD help Enable the nPM1300 GPIO driver. diff --git a/drivers/gpio/gpio_npm1300.c b/drivers/gpio/gpio_npm1300.c index 4580b40a9530..76850cf59f2f 100644 --- a/drivers/gpio/gpio_npm1300.c +++ b/drivers/gpio/gpio_npm1300.c @@ -9,12 +9,10 @@ #include #include -#include +#include #include #include #include -#include -#include /* nPM1300 GPIO base address */ #define NPM_GPIO_BASE 0x06U @@ -44,36 +42,20 @@ struct gpio_npm1300_config { struct gpio_driver_config common; - struct i2c_dt_spec bus; + const struct device *mfd; }; struct gpio_npm1300_data { struct gpio_driver_data common; }; -/* Write single register to specified address */ -static int reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) -{ - const struct gpio_npm1300_config *config = dev->config; - uint8_t buff[] = {base, offset, data}; - - return i2c_write_dt(&config->bus, buff, sizeof(buff)); -} - -static int reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) -{ - const struct gpio_npm1300_config *config = dev->config; - uint8_t buff[] = {base, offset}; - - return i2c_write_read_dt(&config->bus, buff, sizeof(buff), data, 1U); -} - static int gpio_npm1300_port_get_raw(const struct device *dev, uint32_t *value) { + const struct gpio_npm1300_config *config = dev->config; int ret; uint8_t data; - ret = reg_read(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_STATUS, &data); + ret = mfd_npm1300_reg_read(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_STATUS, &data); if (ret < 0) { return ret; @@ -87,16 +69,19 @@ static int gpio_npm1300_port_get_raw(const struct device *dev, uint32_t *value) static int gpio_npm1300_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, gpio_port_value_t value) { + const struct gpio_npm1300_config *config = dev->config; int ret = 0; for (size_t idx = 0; idx < NPM1300_GPIO_PINS; idx++) { if ((mask & BIT(idx)) != 0U) { if ((value & BIT(idx)) != 0U) { - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + idx, - NPM1300_GPIO_GPOLOGIC1); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, + NPM_GPIO_OFFSET_MODE + idx, + NPM1300_GPIO_GPOLOGIC1); } else { - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + idx, - NPM1300_GPIO_GPOLOGIC0); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, + NPM_GPIO_OFFSET_MODE + idx, + NPM1300_GPIO_GPOLOGIC0); } if (ret != 0U) { return ret; @@ -120,6 +105,7 @@ static int gpio_npm1300_port_clear_bits_raw(const struct device *dev, gpio_port_ static inline int gpio_npm1300_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { + const struct gpio_npm1300_config *config = dev->config; int ret = 0; if (k_is_in_isr()) { @@ -132,14 +118,14 @@ static inline int gpio_npm1300_configure(const struct device *dev, gpio_pin_t pi /* Configure mode */ if ((flags & GPIO_INPUT) != 0U) { - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, - NPM1300_GPIO_GPIINPUT); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, + NPM1300_GPIO_GPIINPUT); } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, - NPM1300_GPIO_GPOLOGIC1); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, + NPM1300_GPIO_GPOLOGIC1); } else if ((flags & GPIO_OUTPUT) != 0U) { - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, - NPM1300_GPIO_GPOLOGIC0); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, + NPM1300_GPIO_GPOLOGIC0); } if (ret < 0) { @@ -147,33 +133,34 @@ static inline int gpio_npm1300_configure(const struct device *dev, gpio_pin_t pi } /* Configure open drain */ - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_OPENDRAIN + pin, - !!(flags & GPIO_SINGLE_ENDED)); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_OPENDRAIN + pin, + !!(flags & GPIO_SINGLE_ENDED)); if (ret < 0) { return ret; } /* Configure pulls */ - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_PULLUP + pin, !!(flags & GPIO_PULL_UP)); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_PULLUP + pin, + !!(flags & GPIO_PULL_UP)); if (ret < 0) { return ret; } - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_PULLDOWN + pin, - !!(flags & GPIO_PULL_DOWN)); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_PULLDOWN + pin, + !!(flags & GPIO_PULL_DOWN)); if (ret < 0) { return ret; } /* Configure drive strength and debounce */ - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_DRIVE + pin, - !!(flags & NPM1300_GPIO_DRIVE_6MA)); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_DRIVE + pin, + !!(flags & NPM1300_GPIO_DRIVE_6MA)); if (ret < 0) { return ret; } - ret = reg_write(dev, NPM_GPIO_BASE, NPM_GPIO_OFFSET_DEBOUNCE + pin, - !!(flags & NPM1300_GPIO_DEBOUNCE_ON)); + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_DEBOUNCE + pin, + !!(flags & NPM1300_GPIO_DEBOUNCE_ON)); return ret; } @@ -217,7 +204,7 @@ static int gpio_npm1300_init(const struct device *dev) { const struct gpio_npm1300_config *config = dev->config; - if (!device_is_ready(config->bus.bus)) { + if (!device_is_ready(config->mfd)) { return -ENODEV; } @@ -230,9 +217,9 @@ static int gpio_npm1300_init(const struct device *dev) { \ .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ }, \ - .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(n))}; \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n))}; \ \ - static struct gpio_npm1300_data gpio_npm1300_data##n; \ + static struct gpio_npm1300_data gpio_npm1300_data##n; \ \ DEVICE_DT_INST_DEFINE(n, &gpio_npm1300_init, NULL, &gpio_npm1300_data##n, \ &gpio_npm1300_config##n, POST_KERNEL, \ diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index 34b03b85bc43..57b10201308d 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -37,17 +37,9 @@ int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t o size_t len) { const struct mfd_npm1300_config *config = dev->config; - struct mfd_npm1300_data *mfd_data = dev->data; uint8_t buff[] = {base, offset}; - int ret; - - k_mutex_lock(&mfd_data->mutex, K_FOREVER); - - ret = i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len); - - k_mutex_unlock(&mfd_data->mutex); - return ret; + return i2c_write_read_dt(&config->i2c, buff, sizeof(buff), data, len); } int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, uint8_t *data) @@ -58,34 +50,18 @@ int mfd_npm1300_reg_read(const struct device *dev, uint8_t base, uint8_t offset, int mfd_npm1300_reg_write(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data) { const struct mfd_npm1300_config *config = dev->config; - struct mfd_npm1300_data *mfd_data = dev->data; uint8_t buff[] = {base, offset, data}; - int ret; - - k_mutex_lock(&mfd_data->mutex, K_FOREVER); - ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); - - k_mutex_unlock(&mfd_data->mutex); - - return ret; + return i2c_write_dt(&config->i2c, buff, sizeof(buff)); } int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data1, uint8_t data2) { const struct mfd_npm1300_config *config = dev->config; - struct mfd_npm1300_data *mfd_data = dev->data; uint8_t buff[] = {base, offset, data1, data2}; - int ret; - k_mutex_lock(&mfd_data->mutex, K_FOREVER); - - ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); - - k_mutex_unlock(&mfd_data->mutex); - - return ret; + return i2c_write_dt(&config->i2c, buff, sizeof(buff)); } int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, From 12e8de71b1748b533dd1f48062e1d69792b7e510 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 19 Jun 2023 10:19:37 +0100 Subject: [PATCH 0355/2042] scripts: build: parse_syscalls: Fix duplicate paths on windows Fixes an issue on windows where there would be many permutations of paths with different folder separators by converting to posix-style path separators. Issue was introduced by https://github.com/zephyrproject-rtos/zephyr/pull/58351 Signed-off-by: Jamie McCrae --- 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 c9c259980119..636404950dbf 100644 --- a/scripts/build/parse_syscalls.py +++ b/scripts/build/parse_syscalls.py @@ -29,6 +29,7 @@ import argparse import os import json +from pathlib import PurePath regex_flags = re.MULTILINE | re.VERBOSE @@ -101,6 +102,8 @@ def analyze_headers(include_dir, scan_dir, file_list): 'common.h'))): continue + path = PurePath(os.path.normpath(path)).as_posix() + if path not in syscall_files: if include_dir and base_path in include_dir: syscall_files[path] = {"emit" : True} From 9c2d1c8e99159293961f6d39a64ce519fac103a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Wed, 14 Jun 2023 09:59:52 +0200 Subject: [PATCH 0356/2042] scripts: logging: dictionary: Fix database generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed that not all strings were put into database. That is because algorithm was searching for any null terminated byte arrays in the section (e.g. rodata) and then attempting to decode it to string. However, section may contain other static const variable and if a string is preceded by a variable that has non-printable bytes and no zero at the end then algorithm was picking a candidate that started with non-printable characters followed by the string. Such candidate was discarded because it was not a valid string. Algorithm is changed to treat as string candidate any sequences that contains printable bytes followed by 0. Signed-off-by: Krzysztof Chruściński --- scripts/logging/dictionary/database_gen.py | 125 ++++++++------------- 1 file changed, 49 insertions(+), 76 deletions(-) diff --git a/scripts/logging/dictionary/database_gen.py b/scripts/logging/dictionary/database_gen.py index e1a6e672af48..1737186793d8 100755 --- a/scripts/logging/dictionary/database_gen.py +++ b/scripts/logging/dictionary/database_gen.py @@ -378,97 +378,70 @@ def extract_string_variables(elf): return strings - def try_decode_string(str_maybe): """Check if it is a printable string""" for encoding in STR_ENCODINGS: try: - decoded_str = str_maybe.decode(encoding) - - # Check if string is printable according to Python - # since the parser (written in Python) will need to - # print the string. - # - # Note that '\r' and '\n' are not included in - # string.printable so they need to be checked separately. - printable = True - for one_char in decoded_str: - if (one_char not in string.printable - and one_char not in ACCEPTABLE_ESCAPE_CHARS): - printable = False - break - - if printable: - return decoded_str + return str_maybe.decode(encoding) except UnicodeDecodeError: pass return None +def is_printable(b): + # Check if string is printable according to Python + # since the parser (written in Python) will need to + # print the string. + # + # Note that '\r' and '\n' are not included in + # string.printable so they need to be checked separately. + return (b in string.printable) or (b in ACCEPTABLE_ESCAPE_CHARS) def extract_strings_in_one_section(section, str_mappings): """Extract NULL-terminated strings in one ELF section""" - bindata = section['data'] - - if len(bindata) < 2: - # Can't have a NULL-terminated string with fewer than 2 bytes. - return str_mappings - + data = section['data'] idx = 0 - - # If first byte is not NULL, it may be a string. - if bindata[0] == 0: - start = None - else: - start = 0 - - while idx < len(bindata): - if start is None: - if bindata[idx] == 0: - # Skip NULL bytes to find next string - idx += 1 - else: - # Beginning of possible string + start = None + for x in data: + if is_printable(chr(x)): + # Printable character, potential part of string + if start is None: + # Beginning of potential string start = idx - idx += 1 - else: - if bindata[idx] != 0: - # Skipping till next NULL byte for possible string - idx += 1 - else: - # End of possible string - end = idx - - if start != end: - str_maybe = bindata[start:end] - decoded_str = try_decode_string(str_maybe) - - # Only store readable string - if decoded_str is not None: - addr = section['start'] + start - - if addr not in str_mappings: - str_mappings[addr] = decoded_str - - # Decoded string may contain un-printable characters - # (e.g. extended ASC-II characters) or control - # characters (e.g. '\r' or '\n'), so simply print - # the byte string instead. - logger.debug('Found string via extraction at ' + PTR_FMT + ': %s', - addr, str_maybe) - - # GCC-based toolchain will reuse the NULL character - # for empty strings. There is no way to know which - # one is being reused, so just treat all NULL character - # at the end of legitimate strings as empty strings. - null_addr = section['start'] + end - str_mappings[null_addr] = '' - - logger.debug('Found null string via extraction at ' + PTR_FMT, - null_addr) - + elif x == 0: + # End of possible string + if start is not None: + # Found potential string + str_maybe = data[start : idx] + decoded_str = try_decode_string(str_maybe) + + if decoded_str is not None: + addr = section['start'] + start + + if addr not in str_mappings: + str_mappings[addr] = decoded_str + + # Decoded string may contain un-printable characters + # (e.g. extended ASC-II characters) or control + # characters (e.g. '\r' or '\n'), so simply print + # the byte string instead. + logger.debug('Found string via extraction at ' + PTR_FMT + ': %s', + addr, str_maybe) + + # GCC-based toolchain will reuse the NULL character + # for empty strings. There is no way to know which + # one is being reused, so just treat all NULL character + # at the end of legitimate strings as empty strings. + null_addr = section['start'] + idx + str_mappings[null_addr] = '' + + logger.debug('Found null string via extraction at ' + PTR_FMT, + null_addr) start = None - idx += 1 + else: + # Non-printable byte, remove start location + start = None + idx += 1 return str_mappings From 9748250e7295495a18da29b4aa65eaf3eafc46e1 Mon Sep 17 00:00:00 2001 From: Maciej Baczmanski Date: Mon, 19 Jun 2023 10:55:28 +0200 Subject: [PATCH 0357/2042] dts: vendor-prefixes: Add OpenThread.io vendor prefix Added OpenThread.io vendor prefix to enable `openthread,config` dts binding for additional OpenThread configurations. Signed-off-by: Maciej Baczmanski --- 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 755436d5490d..c7bcb10eabbc 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -439,6 +439,7 @@ opalkelly Opal Kelly Incorporated opencores OpenCores.org openisa open-isa.org openrisc OpenRISC.io +openthread OpenThread.io option Option NV oranth Shenzhen Oranth Technology Co., Ltd. ORCL Oracle Corporation From 327eb119b6bc3166b2e623792567e9831f4385d7 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 31 May 2023 14:09:21 +0200 Subject: [PATCH 0358/2042] Bluetooth: Mesh: add tf-m support for ble mesh This PR adds ability to build mesh with tf-m psa for platforms those support tf-m. Signed-off-by: Aleksandr Khromykh --- include/zephyr/bluetooth/mesh/keys.h | 4 +-- ...nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf | 33 +++++++++++++++++++ samples/bluetooth/hci_rpmsg/sample.yaml | 7 ++++ samples/bluetooth/mesh/CMakeLists.txt | 6 ++++ samples/bluetooth/mesh/README.rst | 6 ++++ .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 3 ++ samples/bluetooth/mesh/microbit_gatt.conf | 1 - samples/bluetooth/mesh/prj.conf | 1 - samples/bluetooth/mesh/sample.yaml | 1 + samples/bluetooth/mesh_demo/CMakeLists.txt | 6 ++++ samples/bluetooth/mesh_demo/README.rst | 6 ++++ .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 3 ++ samples/bluetooth/mesh_demo/prj.conf | 10 +++++- samples/bluetooth/mesh_demo/sample.yaml | 1 + .../bluetooth/mesh_provisioner/CMakeLists.txt | 6 ++++ samples/bluetooth/mesh_provisioner/README.rst | 6 ++++ .../boards/nrf5340dk_nrf5340_cpuapp_ns.conf | 3 ++ samples/bluetooth/mesh_provisioner/prj.conf | 10 +++++- .../bluetooth/mesh_provisioner/sample.yaml | 1 + subsys/bluetooth/mesh/CMakeLists.txt | 14 ++++++-- subsys/bluetooth/mesh/Kconfig | 14 ++++++-- subsys/bluetooth/mesh/keys.h | 2 +- 22 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf create mode 100644 samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf create mode 100644 samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf create mode 100644 samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf diff --git a/include/zephyr/bluetooth/mesh/keys.h b/include/zephyr/bluetooth/mesh/keys.h index db2a2ca45a93..73e0a8a2a938 100644 --- a/include/zephyr/bluetooth/mesh/keys.h +++ b/include/zephyr/bluetooth/mesh/keys.h @@ -12,7 +12,7 @@ #define ZEPHYR_INCLUDE_BLUETOOTH_MESH_KEYS_H_ #include -#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA || defined CONFIG_BT_MESH_USES_TFM_PSA #include #endif @@ -20,7 +20,7 @@ extern "C" { #endif -#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA || defined CONFIG_BT_MESH_USES_TFM_PSA /** The structure that keeps representation of key. */ struct bt_mesh_key { diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf new file mode 100644 index 000000000000..37e29435d49b --- /dev/null +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf @@ -0,0 +1,33 @@ +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y + +CONFIG_HEAP_MEM_POOL_SIZE=8192 + +CONFIG_MAIN_STACK_SIZE=512 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +CONFIG_BT_HCI_RAW_RESERVE=1 +CONFIG_BT_MAX_CONN=16 + + +# 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 + +# Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Disable unused Bluetooth features +CONFIG_BT_CTLR_DUP_FILTER_LEN=0 +CONFIG_BT_CTLR_LE_ENC=n +CONFIG_BT_CTLR_LE_PING=n +CONFIG_BT_DATA_LEN_UPDATE=n +CONFIG_BT_PHY_UPDATE=n +CONFIG_BT_CTLR_MIN_USED_CHAN=n +CONFIG_BT_CTLR_PRIVACY=n + +CONFIG_BT_OBSERVER=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_EXT_ADV=y diff --git a/samples/bluetooth/hci_rpmsg/sample.yaml b/samples/bluetooth/hci_rpmsg/sample.yaml index 3623dbb53f5b..3330002a59d1 100644 --- a/samples/bluetooth/hci_rpmsg/sample.yaml +++ b/samples/bluetooth/hci_rpmsg/sample.yaml @@ -82,3 +82,10 @@ tests: platform_allow: nrf5340dk_nrf5340_cpunet integration_platforms: - nrf5340dk_nrf5340_cpunet + sample.bluetooth.hci_rpmsg.mesh.bt_ll_sw_split: + harness: bluetooth + tags: bluetooth + extra_args: CONF_FILE="nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf" + platform_allow: nrf5340dk_nrf5340_cpunet + integration_platforms: + - nrf5340dk_nrf5340_cpunet diff --git a/samples/bluetooth/mesh/CMakeLists.txt b/samples/bluetooth/mesh/CMakeLists.txt index 40b69cf15d40..6ee28b12d488 100644 --- a/samples/bluetooth/mesh/CMakeLists.txt +++ b/samples/bluetooth/mesh/CMakeLists.txt @@ -13,3 +13,9 @@ if (BOARD STREQUAL bbc_microbit) else() target_sources(app PRIVATE src/board.c) endif() + +if (CONFIG_BUILD_WITH_TFM) + target_include_directories(app PRIVATE + $/install/interface/include + ) +endif() diff --git a/samples/bluetooth/mesh/README.rst b/samples/bluetooth/mesh/README.rst index 5b1b7ab250d3..c30bb48adae3 100644 --- a/samples/bluetooth/mesh/README.rst +++ b/samples/bluetooth/mesh/README.rst @@ -44,6 +44,12 @@ For other boards, build and flash the application as follows: Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. +To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application +must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +application may be used. Build this sample with configuration +:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +to enable mesh support. + Interacting with the sample *************************** diff --git a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf new file mode 100644 index 000000000000..c638a292c910 --- /dev/null +++ b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -0,0 +1,3 @@ +# Known issue: non secure platforms do not work with settings subsystem. +CONFIG_SETTINGS=n +CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh/microbit_gatt.conf b/samples/bluetooth/mesh/microbit_gatt.conf index 714dfb4969c1..21ebb1608828 100644 --- a/samples/bluetooth/mesh/microbit_gatt.conf +++ b/samples/bluetooth/mesh/microbit_gatt.conf @@ -13,7 +13,6 @@ CONFIG_BT_MESH_PB_ADV=n CONFIG_BT=y CONFIG_BT_DEVICE_NAME="Zephyr Mesh" -CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_RX_STACK_SIZE=1400 CONFIG_BT_L2CAP_TX_BUF_COUNT=5 CONFIG_BT_EXT_ADV=n diff --git a/samples/bluetooth/mesh/prj.conf b/samples/bluetooth/mesh/prj.conf index cd8819616be4..9c8daad91316 100644 --- a/samples/bluetooth/mesh/prj.conf +++ b/samples/bluetooth/mesh/prj.conf @@ -8,7 +8,6 @@ CONFIG_SETTINGS=y CONFIG_HWINFO=y CONFIG_BT=y -CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_L2CAP_TX_BUF_COUNT=5 CONFIG_BT_PERIPHERAL=y CONFIG_BT_OBSERVER=y diff --git a/samples/bluetooth/mesh/sample.yaml b/samples/bluetooth/mesh/sample.yaml index 799d69bde371..cbb474cd92f2 100644 --- a/samples/bluetooth/mesh/sample.yaml +++ b/samples/bluetooth/mesh/sample.yaml @@ -7,6 +7,7 @@ tests: - bbc_microbit - qemu_x86 - nrf52840dk_nrf52840 + - nrf5340dk_nrf5340_cpuapp_ns integration_platforms: - qemu_x86 tags: bluetooth diff --git a/samples/bluetooth/mesh_demo/CMakeLists.txt b/samples/bluetooth/mesh_demo/CMakeLists.txt index c4c6ce298d65..07736d6c12e1 100644 --- a/samples/bluetooth/mesh_demo/CMakeLists.txt +++ b/samples/bluetooth/mesh_demo/CMakeLists.txt @@ -12,3 +12,9 @@ target_sources_ifdef(CONFIG_BOARD_BBC_MICROBIT app PRIVATE src/microbit.c) if(NODE_ADDR) zephyr_compile_definitions(NODE_ADDR=${NODE_ADDR}) endif() + +if (CONFIG_BUILD_WITH_TFM) + target_include_directories(app PRIVATE + $/install/interface/include + ) +endif() diff --git a/samples/bluetooth/mesh_demo/README.rst b/samples/bluetooth/mesh_demo/README.rst index ca2735caa781..52a786c164d6 100644 --- a/samples/bluetooth/mesh_demo/README.rst +++ b/samples/bluetooth/mesh_demo/README.rst @@ -54,3 +54,9 @@ For other boards, build and flash the application as follows: Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. + +To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application +must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +application may be used. Build this sample with configuration +:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +to enable mesh support. diff --git a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf new file mode 100644 index 000000000000..c638a292c910 --- /dev/null +++ b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -0,0 +1,3 @@ +# 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/prj.conf b/samples/bluetooth/mesh_demo/prj.conf index 144e9440a9c3..1fe22df04ef2 100644 --- a/samples/bluetooth/mesh_demo/prj.conf +++ b/samples/bluetooth/mesh_demo/prj.conf @@ -2,10 +2,18 @@ CONFIG_MAIN_STACK_SIZE=512 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_BT=y -CONFIG_BT_TINYCRYPT_ECC=y CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y +CONFIG_BT_CTLR_DUP_FILTER_LEN=0 +CONFIG_BT_CTLR_LE_ENC=n +CONFIG_BT_CTLR_LE_PING=n +CONFIG_BT_DATA_LEN_UPDATE=n +CONFIG_BT_PHY_UPDATE=n +CONFIG_BT_CTLR_MIN_USED_CHAN=n +CONFIG_BT_CTLR_PRIVACY=n +CONFIG_BT_CTLR_CHAN_SEL_2=n + CONFIG_BT_MESH=y CONFIG_BT_MESH_RELAY=y CONFIG_BT_MESH_SUBNET_COUNT=1 diff --git a/samples/bluetooth/mesh_demo/sample.yaml b/samples/bluetooth/mesh_demo/sample.yaml index c48d3ae15fb0..adcb1af05cb4 100644 --- a/samples/bluetooth/mesh_demo/sample.yaml +++ b/samples/bluetooth/mesh_demo/sample.yaml @@ -7,6 +7,7 @@ tests: - bbc_microbit - qemu_x86 - nrf52840dk_nrf52840 + - nrf5340dk_nrf5340_cpuapp_ns integration_platforms: - qemu_x86 - bbc_microbit diff --git a/samples/bluetooth/mesh_provisioner/CMakeLists.txt b/samples/bluetooth/mesh_provisioner/CMakeLists.txt index e0d490e04bea..7b22bd0fe14c 100644 --- a/samples/bluetooth/mesh_provisioner/CMakeLists.txt +++ b/samples/bluetooth/mesh_provisioner/CMakeLists.txt @@ -7,3 +7,9 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(mesh_provisioner) target_sources(app PRIVATE src/main.c) + +if (CONFIG_BUILD_WITH_TFM) + target_include_directories(app PRIVATE + $/install/interface/include + ) +endif() diff --git a/samples/bluetooth/mesh_provisioner/README.rst b/samples/bluetooth/mesh_provisioner/README.rst index c7b7bc5f8617..4769ae09f17d 100644 --- a/samples/bluetooth/mesh_provisioner/README.rst +++ b/samples/bluetooth/mesh_provisioner/README.rst @@ -52,3 +52,9 @@ For other boards, build and flash the application as follows: Refer to your :ref:`board's documentation ` for alternative flash instructions if your board doesn't support the ``flash`` target. + +To run the application on an :ref:`nrf5340dk_nrf5340`, a Bluetooth controller application +must also run on the network core. The :ref:`bluetooth-hci-rpmsg-sample` sample +application may be used. Build this sample with configuration +:zephyr_file:`samples/bluetooth/hci_rpmg/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf` +to enable mesh support. diff --git a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf new file mode 100644 index 000000000000..c638a292c910 --- /dev/null +++ b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -0,0 +1,3 @@ +# 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/prj.conf b/samples/bluetooth/mesh_provisioner/prj.conf index 8e58221fe175..3b40d2c2c7b9 100644 --- a/samples/bluetooth/mesh_provisioner/prj.conf +++ b/samples/bluetooth/mesh_provisioner/prj.conf @@ -5,11 +5,19 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_MAIN_THREAD_PRIORITY=-2 CONFIG_BT=y -CONFIG_BT_TINYCRYPT_ECC=y #CONFIG_BT_DEBUG_LOG=y CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y +CONFIG_BT_CTLR_DUP_FILTER_LEN=0 +CONFIG_BT_CTLR_LE_ENC=n +CONFIG_BT_CTLR_LE_PING=n +CONFIG_BT_DATA_LEN_UPDATE=n +CONFIG_BT_PHY_UPDATE=n +CONFIG_BT_CTLR_MIN_USED_CHAN=n +CONFIG_BT_CTLR_PRIVACY=n +CONFIG_BT_CTLR_CHAN_SEL_2=n + CONFIG_BT_MESH=y CONFIG_BT_MESH_SUBNET_COUNT=1 CONFIG_BT_MESH_APP_KEY_COUNT=1 diff --git a/samples/bluetooth/mesh_provisioner/sample.yaml b/samples/bluetooth/mesh_provisioner/sample.yaml index 7fc159741fd1..abaaf79aae31 100644 --- a/samples/bluetooth/mesh_provisioner/sample.yaml +++ b/samples/bluetooth/mesh_provisioner/sample.yaml @@ -6,6 +6,7 @@ tests: platform_allow: - qemu_x86 - nrf52840dk_nrf52840 + - nrf5340dk_nrf5340_cpuapp_ns integration_platforms: - qemu_x86 tags: bluetooth diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index a1a5b1de93a2..df97ee49d0ff 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -120,8 +120,16 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV sol_pdu_rpl_srv.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_USES_TINYCRYPT crypto_tc.c) - -zephyr_library_sources_ifdef(CONFIG_BT_MESH_USES_MBEDTLS_PSA crypto_psa.c) +if (CONFIG_BT_MESH_USES_TINYCRYPT) + zephyr_library_sources(crypto_tc.c) +else() + zephyr_library_sources(crypto_psa.c) +endif() zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) + +if (CONFIG_BUILD_WITH_TFM) + target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE + $/install/interface/include + ) +endif() diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 4f2438b9bbe5..3a2a35b28385 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -15,6 +15,7 @@ if BT_MESH choice BT_MESH_CRYPTO_LIB prompt "Crypto library selection for mesh security" + default BT_MESH_USES_TFM_PSA if BUILD_WITH_TFM default BT_MESH_USES_TINYCRYPT config BT_MESH_USES_TINYCRYPT @@ -53,9 +54,18 @@ config BT_MESH_USES_MBEDTLS_PSA on Zephyr's settings subsystem. Not possible to use for embedded devices yet. +config BT_MESH_USES_TFM_PSA + bool "Use TF-M PSA [EXPERIMENTAL]" + select EXPERIMENTAL + depends on BUILD_WITH_TFM + help + Use TF-M that implements PSA security framework. Support of TF-M is + experimental. It is only possible to use with platforms that TF-M supports. + For more platform details see TF-M documentation. + endchoice -if BT_MESH_USES_MBEDTLS_PSA +if BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET int "Offset of BLE Mesh key id range regarding PSA_KEY_ID_USER_MIN" @@ -69,7 +79,7 @@ config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET for each application key, and two ids for the device key and device key candidate. It should consider the Mesh Configuration Database instances if database enabled. -endif # BT_MESH_USES_MBEDTLS_PSA +endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA # Virtual option enabled whenever Generic Provisioning layer is needed config BT_MESH_PROV diff --git a/subsys/bluetooth/mesh/keys.h b/subsys/bluetooth/mesh/keys.h index f9a559a1c873..a72236e46783 100644 --- a/subsys/bluetooth/mesh/keys.h +++ b/subsys/bluetooth/mesh/keys.h @@ -13,7 +13,7 @@ enum bt_mesh_key_type { BT_MESH_KEY_TYPE_DEV }; -#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA +#if defined CONFIG_BT_MESH_USES_MBEDTLS_PSA || defined CONFIG_BT_MESH_USES_TFM_PSA int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16], struct bt_mesh_key *out); int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in); From df0e03c5512c03f4e3e641cc37641abb1f76082b Mon Sep 17 00:00:00 2001 From: Jon Neal Date: Tue, 13 Jun 2023 09:56:09 -0400 Subject: [PATCH 0359/2042] boards: efr32 thunderboard: correct high freq osc frequency The efr32bg22 thunderboard has a 38.4MHz high frequency oscillator. This is default for these micros, as the core runs at 76.8MHz. The default frequency was incorrectly set to 40MHz. Signed-off-by: Jon Neal --- boards/arm/efr32_thunderboard/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/efr32_thunderboard/Kconfig.defconfig b/boards/arm/efr32_thunderboard/Kconfig.defconfig index df366db88b1f..35059d030c84 100644 --- a/boards/arm/efr32_thunderboard/Kconfig.defconfig +++ b/boards/arm/efr32_thunderboard/Kconfig.defconfig @@ -18,7 +18,7 @@ config BOARD endif # BOARD_EFR32BG27_BRD2602A config CMU_HFXO_FREQ - default 40000000 + default 38400000 config CMU_LFXO_FREQ default 32768 From 9fd9c9dd4ff647ced8c67a0be18534d8f64b1b20 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 19 Jun 2023 19:35:22 -0400 Subject: [PATCH 0360/2042] doc: sensing: fix structure and remove top doxygen reference Move sections out of the Overview section and put API documentation in one section without bullets, which was causing duplication in headers and text. This also fixes the issue with PDF generation which is currently blocking publication of HTML pages on docs.zephyrproject.org. Signed-off-by: Anas Nashif --- doc/services/sensing/index.rst | 42 ++++++++-------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/doc/services/sensing/index.rst b/doc/services/sensing/index.rst index bc54598dc25c..99fdc48d6b70 100644 --- a/doc/services/sensing/index.rst +++ b/doc/services/sensing/index.rst @@ -52,7 +52,7 @@ The diagram below illustrates how the Sensing Subsystem integrates with up-layer :alt: Unified Zephyr sensing architecture. Configurability -=============== +*************** * Reusable and configurable standalone subsystem. * Based on Zephyr existing low-level Sensor API (reuse 100+ existing sensor device drivers) @@ -62,7 +62,7 @@ Configurability protocols (MQTT, HID or Private, all configurable) Main Features -============= +************* * Scope * Focus on framework for sensor fusion, multiple clients, arbitration, data sampling, timing @@ -84,28 +84,6 @@ Main Features * Configurable Via Device Tree -API Design -********** - -API Organization -================ - -* Sensing Subsystem - * Sensor Types - - .. doxygengroup:: sensing_sensor_types - - * Data Types - - .. doxygengroup:: sensing_datatypes - - * Sensing Subsystem API - - .. doxygengroup:: sensing_api - - * Sensing Sensor API - - .. doxygengroup:: sensing_sensor Below diagram shows the API position and scope: @@ -118,7 +96,7 @@ Below diagram shows the API position and scope: Major Flows -========================= +*********** * Sensor Configuration Flow @@ -133,7 +111,7 @@ Major Flows :alt: Sensor Data Flow (App receive hinge angel data through data event callback example). Sensor Types And Instance -========================= +************************* The ``Sensing Subsystem`` supports multiple instances of the same sensor type, there're two methods for Applications to identify and open an unique sensor instance: @@ -171,7 +149,7 @@ sensor(s). See :zephyr_file:`include/zephyr/sensing/sensing_sensor_types.h` Sensor Instance Handler -========================= +*********************** Clients using a :c:type:`sensing_sensor_handle_t` type handler to handle a opened sensor instance, and all subsequent operations on this sensor instance need use this handler, @@ -201,7 +179,7 @@ to it's reporter sensors. Application(s) need to call :c:func:`sensing_open_sensor` to explicitly open the sensor instance. Sensor Sample Value -================================== +******************* * Data Structure @@ -268,7 +246,7 @@ See the example :zephyr_file:`samples/subsys/sensing/simple/boards/native_posix. API Reference ************* -Sensing -======== - -.. doxygengroup:: sensing +.. doxygengroup:: sensing_sensor_types +.. doxygengroup:: sensing_datatypes +.. doxygengroup:: sensing_api +.. doxygengroup:: sensing_sensor From 231c0136a7035400ec40ef99d2ecd8cf3e0f8c5c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 14 Jun 2023 15:15:34 +0200 Subject: [PATCH 0361/2042] manifest: Update bsim to 2.2.1 Update the bsim top manifest repo and all its subrepos to bsim release 2.2.1. Signed-off-by: Alberto Escolar Piedras --- west.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/west.yml b/west.yml index 72c863a6dd5a..215cc46f50ba 100644 --- a/west.yml +++ b/west.yml @@ -31,7 +31,7 @@ manifest: projects: - name: bsim repo-path: babblesim-manifest - revision: 908ffde6298a937c6549dbfa843a62caab26bfc5 + revision: 384a091445c57b44ac8cbd18ebd245b47c71db94 path: tools/bsim groups: - babblesim @@ -39,7 +39,7 @@ manifest: remote: babblesim repo-path: base.git path: tools/bsim/components - revision: 02838ca04c4562e68dc876196828d8121679e537 + revision: 19d62424c0802c6c9fc15528febe666e40f372a1 groups: - babblesim - name: babblesim_ext_2G4_libPhyComv1 @@ -53,7 +53,7 @@ manifest: remote: babblesim repo-path: ext_2G4_phy_v1.git path: tools/bsim/components/ext_2G4_phy_v1 - revision: cf2d86e736efac4f12fad5093ed2da2c5b406156 + revision: d47c6dd90035b41b14f6921785ccb7b8484868e2 groups: - babblesim - name: babblesim_ext_2G4_channel_NtNcable @@ -67,7 +67,7 @@ manifest: remote: babblesim repo-path: ext_2G4_channel_multiatt.git path: tools/bsim/components/ext_2G4_channel_multiatt - revision: e09bc2d14b1975f969ad19c6ed23eb20e5dc3d09 + revision: bde72a57384dde7a4310bcf3843469401be93074 groups: - babblesim - name: babblesim_ext_2G4_modem_magic @@ -81,7 +81,7 @@ manifest: remote: babblesim repo-path: ext_2G4_modem_BLE_simple.git path: tools/bsim/components/ext_2G4_modem_BLE_simple - revision: ce975a3259fd0dd761d371b60435242d54794bad + revision: 809ab073159c9ab6686c2fea5749b0702e0909f7 groups: - babblesim - name: babblesim_ext_2G4_device_burst_interferer From 0bc6860b42e413f0f2f555881d0443d89560343e Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Mon, 19 Jun 2023 14:57:41 +0200 Subject: [PATCH 0362/2042] arm64: Remove ARCH_IRQ_DIRECT_CONNECT There is no support for direct IRQs on ARM64. Remove the macro. Signed-off-by: Carlo Caione --- include/zephyr/arch/arm64/irq.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/zephyr/arch/arm64/irq.h b/include/zephyr/arch/arm64/irq.h index 081d4c0d699d..fc89fddda817 100644 --- a/include/zephyr/arch/arm64/irq.h +++ b/include/zephyr/arch/arm64/irq.h @@ -88,12 +88,6 @@ extern void z_arm64_interrupt_init(void); z_arm64_irq_priority_set(irq_p, priority_p, flags_p); \ } -#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_arm64_irq_priority_set(irq_p, priority_p, flags_p); \ -} - #endif /* _ASMLANGUAGE */ #ifdef __cplusplus From 0adfe5531ede67be7b8022a8821b56d9ba60d096 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Jun 2023 15:42:54 +0300 Subject: [PATCH 0363/2042] drivers: gsm_ppp: Fix possible NULL pointer dereference Assign api value after NULL check. Signed-off-by: Andrei Emeltchenko --- drivers/modem/gsm_ppp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/modem/gsm_ppp.c b/drivers/modem/gsm_ppp.c index 7eca5f669c92..a22aac6132ec 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -615,7 +615,7 @@ static struct net_if *ppp_net_if(void) static void set_ppp_carrier_on(struct gsm_modem *gsm) { const struct device *ppp_dev = device_get_binding(CONFIG_NET_PPP_DRV_NAME); - const struct ppp_api *api = (const struct ppp_api *)ppp_dev->api; + const struct ppp_api *api; struct net_if *iface = gsm->iface; int ret; @@ -624,6 +624,8 @@ static void set_ppp_carrier_on(struct gsm_modem *gsm) return; } + api = (const struct ppp_api *)ppp_dev->api; + ret = api->start(ppp_dev); if (ret < 0) { From d644bebd9365cef33ac52cc727f537f918ec7692 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Fri, 16 Jun 2023 13:00:06 +0200 Subject: [PATCH 0364/2042] drivers/entropy/gecko_trng: select the correct RNGOUT_FIFO_MEM_BASE This commit introduces a preprocessor checking mechanism for selecting the correct RNGOUT FIFO memory base address depending on whether SL_TRUSTZONE is used. Fixes #59197. Signed-off-by: Filip Kokosinski --- drivers/entropy/entropy_gecko_trng.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/entropy/entropy_gecko_trng.c b/drivers/entropy/entropy_gecko_trng.c index 18da6d8165e7..281229b82122 100644 --- a/drivers/entropy/entropy_gecko_trng.c +++ b/drivers/entropy/entropy_gecko_trng.c @@ -12,16 +12,30 @@ #include "em_cmu.h" #if defined(CONFIG_CRYPTO_ACC_GECKO_TRNG) + +/* + * Select the correct Crypto ACC FIFO memory base address. + * + * Problem: Gecko SDK doesn't provide macros that check if SL_TRUSTZONE is used or not for Crypto + * ACC RNGOUT FIFO memory base address, like it does for register address definitions. + * + * Solution: Check which register base address is used for the Crypto ACC peripheral and select an + * appropriate FIFO memory base address. + */ +#if (CRYPTOACC_BASE == CRYPTOACC_S_BASE) +#define S2_FIFO_BASE CRYPTOACC_RNGOUT_FIFO_S_MEM_BASE +#else +#define S2_FIFO_BASE CRYPTOACC_RNGOUT_FIFO_MEM_BASE +#endif + /** * Series 2 SoCs have different TRNG register definitions */ #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) /* xG22 */ -#define S2_FIFO_BASE (CRYPTOACC_RNGOUT_FIFO_S_MEM_BASE) #define S2_FIFO_LEVEL (CRYPTOACC_RNGCTRL->FIFOLEVEL) #define S2_CTRL (CRYPTOACC_RNGCTRL->RNGCTRL) #define S2_CTRL_ENABLE (CRYPTOACC_RNGCTRL_ENABLE) #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) /* xG27 */ -#define S2_FIFO_BASE (CRYPTOACC_RNGOUT_FIFO_S_MEM_BASE) #define S2_FIFO_LEVEL (CRYPTOACC->NDRNG_FIFOLEVEL) #define S2_CTRL (CRYPTOACC->NDRNG_CONTROL) #define S2_CTRL_ENABLE (CRYPTOACC_NDRNG_CONTROL_ENABLE) From beaa5e98a6e7ed5c5aaf195efe19e97393ace072 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 7 Jun 2023 16:57:15 +0200 Subject: [PATCH 0365/2042] tests: i2c: i2c_slave_api add comment for nucleo_f091rc Adds comment for overlays for nucleo_f091rc in i2c_slave_api test case. Signed-off-by: Marc Desvaux --- .../i2c/i2c_target_api/boards/nucleo_f091rc.overlay | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f091rc.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f091rc.overlay index 12ce645b5115..6ca9868d7341 100644 --- a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f091rc.overlay +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f091rc.overlay @@ -1,5 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 */ +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN10:5 PB8 CN10:3 + * i2c2 PA12 CN10:12 PA11 CN10:14 + * + * Short Pin PB9 to PA12, and PB8 to PA11, for the test to pass. + */ + &i2c1 { eeprom0: eeprom@54 { compatible = "zephyr,i2c-target-eeprom"; From 427f5ef1eedd4acfb7d6539fdb348271855080cf Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 19 Jun 2023 13:42:44 +0200 Subject: [PATCH 0366/2042] tests: drivers: i2c: i2c_target_api add nucleo_f429zi Adds nucleo_f429zi in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index eb14ff445bcf..7b75c8d9b621 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -14,6 +14,7 @@ tests: - stm32f072b_disco - nucleo_g071rb - nucleo_f207zg + - nucleo_f429zi - rpi_pico integration_platforms: - nucleo_f091rc From 4c977c5df697ee2f8438136fa744f9733177146f Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 9 Jun 2023 14:44:03 +0200 Subject: [PATCH 0367/2042] boards: arm: nucleo_f429zi: add i2c2 Adds i2c2 on nucleo_f429zi to use the i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- boards/arm/nucleo_f429zi/nucleo_f429zi.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/nucleo_f429zi/nucleo_f429zi.dts b/boards/arm/nucleo_f429zi/nucleo_f429zi.dts index 8014a839e6c3..9fce1d895f02 100644 --- a/boards/arm/nucleo_f429zi/nucleo_f429zi.dts +++ b/boards/arm/nucleo_f429zi/nucleo_f429zi.dts @@ -108,6 +108,13 @@ clock-frequency = ; }; +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + &spi1 { pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; pinctrl-names = "default"; From eecf1ed84be0d0b5711c50fdd6326b28628f5e5b Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 9 Jun 2023 14:52:44 +0200 Subject: [PATCH 0368/2042] tests: drivers: i2c: i2c_target_api add nucleo_f429zi Adds necessary overlay nucleo_f429zi in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_f429zi.conf | 2 ++ .../boards/nucleo_f429zi.overlay | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.conf new file mode 100644 index 000000000000..34b2571d1251 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.overlay new file mode 100644 index 000000000000..fc88c69010bf --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f429zi.overlay @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN7:4 PB8 CN7:2 + * i2c2 PB11 CN10:34 PB10 CN10:32 + * + * Short Pin PB9 to PB11, and PB8 to PB10, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From cd4bfc8c437d1830ade5b500bb2bff2f46c31c6e Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 19 Jun 2023 12:28:27 +0200 Subject: [PATCH 0369/2042] doc: Bluetooth: Mesh: add link to adv id subclause PR adds link to advertisement identity coexistence subclause. Signed-off-by: Aleksandr Khromykh --- doc/connectivity/bluetooth/api/mesh/core.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index d689c71fcb13..19166b65a09b 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -108,6 +108,8 @@ This means that the system workqueue is blocked for the time it takes to store the stack's configuration. It is not recommended to disable this option as this will make the device non-responsive for a noticeable amount of time. +.. _bluetooth_mesh_adv_identity: + Advertisement identity ********************** From a13157f997b084c62a01aba1e46e2aa0a46a64d9 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 19 Jun 2023 16:32:05 +0200 Subject: [PATCH 0370/2042] Bluetooth: Mesh: fix missed old encryption in dfu metadata PR fixes the old internal encryption api usage for dfu metadata. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/dfu_metadata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/mesh/dfu_metadata.c b/subsys/bluetooth/mesh/dfu_metadata.c index f36198b1671c..11bcd975521a 100644 --- a/subsys/bluetooth/mesh/dfu_metadata.c +++ b/subsys/bluetooth/mesh/dfu_metadata.c @@ -77,7 +77,7 @@ int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, int err; struct bt_mesh_sg sg = {.data = buf->data, .len = buf->len}; - err = bt_mesh_aes_cmac(key, &sg, 1, mac); + err = bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); if (err) { return err; } From a8b28f13c195a00bdf50f5c24092981124664ed9 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 2 Jun 2023 12:26:23 +0300 Subject: [PATCH 0371/2042] soc: intel_adsp: cavs: add simple IMR functionality Add simple mechanism to load the image from IMR memory. Basically we are only setting a flag in power off for the next boot to jump to existing image in IMR. Signed-off-by: Jaska Uimonen --- dts/xtensa/intel/intel_adsp_cavs25.dtsi | 7 ++++ .../include/intel_tgl_adsp/adsp_imr_layout.h | 39 +++++++++++++++++++ .../cavs/include/intel_tgl_adsp/adsp_memory.h | 3 ++ soc/xtensa/intel_adsp/cavs/power.c | 15 +++++++ 4 files changed, 64 insertions(+) create mode 100644 soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_imr_layout.h diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index d9d839b92f9b..02142c30b63a 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -97,6 +97,13 @@ wovcro-supported; }; + IMR1: memory@0xb0000000 { + compatible = "intel,adsp-imr"; + reg = <0xB0000000 DT_SIZE_M(16)>; + block-size = <0x1000>; + zephyr,memory-region = "IMR1"; + }; + soc { shim: shim@71f00 { compatible = "intel,adsp-shim"; diff --git a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_imr_layout.h b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_imr_layout.h new file mode 100644 index 000000000000..37fd8d75fd38 --- /dev/null +++ b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_imr_layout.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_SOC_INTEL_ADSP_TGL_IMR_LAYOUT_H_ +#define ZEPHYR_SOC_INTEL_ADSP_TGL_IMR_LAYOUT_H_ + +/* These structs and macros are from the ROM code header + * on cAVS platforms, please keep them immutable. + * + * The ROM structs and code is lifted from: + * https://github.com/thesofproject/sof + * 6c0db22c65 - platform: cavs: configure resume from IMR + */ + +/* + * A magic that tells ROM to jump to imr_restore_vector instead of normal boot + */ +#define ADSP_IMR_MAGIC_VALUE 0x02468ACE + +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); +}; + +struct imr_state { + struct imr_header header; + uint8_t reserved[0x1000 - sizeof(struct imr_header)]; +}; + +struct imr_layout { + uint8_t css_reserved[0x1000]; + struct imr_state imr_state; +}; + +#endif /* ZEPHYR_SOC_INTEL_ADSP_TGL_IMR_LAYOUT_H_ */ diff --git a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h index b989dd261885..ed10a5d13679 100644 --- a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h +++ b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/adsp_memory.h @@ -29,6 +29,9 @@ #define HPSRAM_SEGMENTS (HPSRAM_EBB_COUNT + EBB_SEG_SIZE - 1) / EBB_SEG_SIZE #define HPSRAM_MEMMASK(idx) ((1ULL << (HPSRAM_EBB_COUNT - EBB_SEG_SIZE * idx)) - 1) +/* L3 region (IMR), located in host memory */ +#define L3_MEM_BASE_ADDR (DT_REG_ADDR(DT_NODELABEL(imr1))) + /* The rimage tool produces two blob addresses we need to find: one is * our bootloader code block which starts at its entry point, the * other is the "manifest" containing the HP-SRAM data to unpack, diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index ea8987814617..e05df97c6e72 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "soc.h" @@ -47,6 +48,11 @@ LOG_MODULE_REGISTER(soc); #define ALL_USED_INT_LEVELS_MASK (L2_INTERRUPT_MASK | L3_INTERRUPT_MASK) +/* + * @biref FW entry point called by ROM during normal boot flow + */ +extern void rom_entry(void); + struct core_state { uint32_t intenable; }; @@ -82,6 +88,15 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) sys_cache_data_flush_and_invd_all(); if (cpu == 0) { uint32_t hpsram_mask[HPSRAM_SEGMENTS]; + + struct imr_header hdr = { + .adsp_imr_magic = ADSP_IMR_MAGIC_VALUE, + .imr_restore_vector = rom_entry, + }; + struct imr_layout *imr_layout = + arch_xtensa_uncached_ptr((struct imr_layout *)L3_MEM_BASE_ADDR); + imr_layout->imr_state.header = hdr; + /* turn off all HPSRAM banks - get a full bitmap */ for (int i = 0; i < HPSRAM_SEGMENTS; i++) hpsram_mask[i] = HPSRAM_MEMMASK(i); From 78d3f2a6a0c05935a91e433318bb0dbdb806a1a6 Mon Sep 17 00:00:00 2001 From: Michael Grand Date: Thu, 8 Jun 2023 14:15:27 +0200 Subject: [PATCH 0372/2042] stm32,i2c: Fix large I2C transactions on I2C V1 Previous commit added support of large transactions on I2C v2, this commit implements some changes to also add support of large transactions on I2C v1. Some refactoring is also done to put the code in the right source files. Fixes zephyrproject-rtos#58866 Signed-off-by: Michael Grand --- drivers/i2c/i2c_ll_stm32.c | 52 +------------------------------- drivers/i2c/i2c_ll_stm32.h | 9 ++---- drivers/i2c/i2c_ll_stm32_v1.c | 22 +++++++++++--- drivers/i2c/i2c_ll_stm32_v2.c | 57 ++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index bbf255923772..eab774241ad1 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -93,56 +93,6 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) return ret; } -static inline int -i2c_stm32_transaction(const struct device *dev, - struct i2c_msg msg, uint8_t *next_msg_flags, - uint16_t periph) -{ - /* - * Perform a I2C transaction, while taking into account the STM32 I2C - * peripheral has a limited maximum chunk size. Take appropriate action - * if the message to send exceeds that limit. - * - * The last chunk of a transmission uses this function's next_msg_flags - * parameter for its backend calls (_write/_read). Any previous chunks - * use a copy of the current message's flags, with the STOP and RESTART - * bits turned off. This will cause the backend to use reload-mode, - * which will make the combination of all chunks to look like one big - * transaction on the wire. - */ - const uint32_t i2c_stm32_maxchunk = 255U; - const uint8_t saved_flags = msg.flags; - uint8_t combine_flags = - saved_flags & ~(I2C_MSG_STOP | I2C_MSG_RESTART); - uint8_t *flagsp = NULL; - uint32_t rest = msg.len; - int ret = 0; - - do { /* do ... while to allow zero-length transactions */ - if (msg.len > i2c_stm32_maxchunk) { - msg.len = i2c_stm32_maxchunk; - msg.flags &= ~I2C_MSG_STOP; - flagsp = &combine_flags; - } else { - msg.flags = saved_flags; - flagsp = next_msg_flags; - } - if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { - ret = stm32_i2c_msg_write(dev, &msg, flagsp, periph); - } else { - ret = stm32_i2c_msg_read(dev, &msg, flagsp, periph); - } - if (ret < 0) { - break; - } - rest -= msg.len; - msg.buf += msg.len; - msg.len = rest; - } while (rest > 0U); - - return ret; -} - #define OPERATION(msg) (((struct i2c_msg *) msg)->flags & I2C_MSG_RW_MASK) static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, @@ -220,7 +170,7 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, next = current + 1; next_msg_flags = &(next->flags); } - ret = i2c_stm32_transaction(dev, *current, next_msg_flags, slave); + ret = stm32_i2c_transaction(dev, *current, next_msg_flags, slave); if (ret < 0) { break; } diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h index a98991f218ca..1db22236043b 100644 --- a/drivers/i2c/i2c_ll_stm32.h +++ b/drivers/i2c/i2c_ll_stm32.h @@ -80,12 +80,9 @@ struct i2c_stm32_data { #endif }; -int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, - uint8_t *flg, - uint16_t sadr); -int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, - uint8_t *flg, - uint16_t sadr); +int32_t stm32_i2c_transaction(const struct device *dev, + struct i2c_msg msg, uint8_t *next_msg_flags, + uint16_t periph); int32_t stm32_i2c_configure_timing(const struct device *dev, uint32_t clk); int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config); diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index 9a64fc7fcc17..d0a0131858fe 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -613,7 +613,7 @@ void stm32_i2c_error_isr(void *arg) stm32_i2c_master_mode_end(dev); } -int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, +static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t saddr) { struct i2c_stm32_data *data = dev->data; @@ -632,7 +632,7 @@ int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, return msg_end(dev, next_msg_flags, __func__); } -int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, +static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t saddr) { const struct i2c_stm32_config *cfg = dev->config; @@ -706,7 +706,7 @@ static int stm32_i2c_wait_timeout(uint16_t *timeout) } } -int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, +static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t saddr) { const struct i2c_stm32_config *cfg = dev->config; @@ -804,7 +804,7 @@ int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, return res; } -int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, +static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t saddr) { const struct i2c_stm32_config *cfg = dev->config; @@ -986,3 +986,17 @@ int32_t stm32_i2c_configure_timing(const struct device *dev, uint32_t clock) return 0; } + +int stm32_i2c_transaction(const struct device *dev, + struct i2c_msg msg, uint8_t *next_msg_flags, + uint16_t periph) +{ + int ret; + + if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { + ret = stm32_i2c_msg_write(dev, &msg, next_msg_flags, periph); + } else { + ret = stm32_i2c_msg_read(dev, &msg, next_msg_flags, periph); + } + return ret; +} diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index 939c4961e7cc..ea2e626f8ecd 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -427,7 +427,7 @@ void stm32_i2c_error_isr(void *arg) } #endif -int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, +static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t slave) { const struct i2c_stm32_config *cfg = dev->config; @@ -485,7 +485,7 @@ int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, return -EIO; } -int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, +static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t slave) { const struct i2c_stm32_config *cfg = dev->config; @@ -607,7 +607,7 @@ static inline int msg_done(const struct device *dev, return 0; } -int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, +static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t slave) { const struct i2c_stm32_config *cfg = dev->config; @@ -637,7 +637,7 @@ int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg, return msg_done(dev, msg->flags); } -int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, +static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, uint8_t *next_msg_flags, uint16_t slave) { const struct i2c_stm32_config *cfg = dev->config; @@ -738,3 +738,52 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock) return 0; } + +int stm32_i2c_transaction(const struct device *dev, + struct i2c_msg msg, uint8_t *next_msg_flags, + uint16_t periph) +{ + /* + * Perform a I2C transaction, while taking into account the STM32 I2C V2 + * peripheral has a limited maximum chunk size. Take appropriate action + * if the message to send exceeds that limit. + * + * The last chunk of a transmission uses this function's next_msg_flags + * parameter for its backend calls (_write/_read). Any previous chunks + * use a copy of the current message's flags, with the STOP and RESTART + * bits turned off. This will cause the backend to use reload-mode, + * which will make the combination of all chunks to look like one big + * transaction on the wire. + */ + const uint32_t i2c_stm32_maxchunk = 255U; + const uint8_t saved_flags = msg.flags; + uint8_t combine_flags = + saved_flags & ~(I2C_MSG_STOP | I2C_MSG_RESTART); + uint8_t *flagsp = NULL; + uint32_t rest = msg.len; + int ret = 0; + + do { /* do ... while to allow zero-length transactions */ + if (msg.len > i2c_stm32_maxchunk) { + msg.len = i2c_stm32_maxchunk; + msg.flags &= ~I2C_MSG_STOP; + flagsp = &combine_flags; + } else { + msg.flags = saved_flags; + flagsp = next_msg_flags; + } + if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) { + ret = stm32_i2c_msg_write(dev, &msg, flagsp, periph); + } else { + ret = stm32_i2c_msg_read(dev, &msg, flagsp, periph); + } + if (ret < 0) { + break; + } + rest -= msg.len; + msg.buf += msg.len; + msg.len = rest; + } while (rest > 0U); + + return ret; +} From 1f1e51ad6b8274502ba4f7d66c9abe6a15402df1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 10:56:18 +0200 Subject: [PATCH 0373/2042] Bluetooth: Shell: Fix typo in disconnected A callback function had a typo where disconencted should have been disconnected. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 85dea6de0ede..f7a9773bd97f 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -586,7 +586,7 @@ static void connected(struct bt_conn *conn, uint8_t err) } } -static void disconencted_set_new_default_conn_cb(struct bt_conn *conn, void *user_data) +static void disconnected_set_new_default_conn_cb(struct bt_conn *conn, void *user_data) { struct bt_conn_info info; @@ -622,7 +622,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) default_conn = NULL; /* If we are connected to other devices, set one of them as default */ - bt_conn_foreach(BT_CONN_TYPE_LE, disconencted_set_new_default_conn_cb, NULL); + bt_conn_foreach(BT_CONN_TYPE_LE, disconnected_set_new_default_conn_cb, NULL); } } From 17537564d471d50c38038f1db2c5dea1f866f218 Mon Sep 17 00:00:00 2001 From: Nicolas Granger Date: Mon, 19 Jun 2023 15:24:44 +0200 Subject: [PATCH 0374/2042] boards: shields: Fix naming scheme for shield node labels Replaced incorrect names with correct ones. Fixes: #50526 Signed-off-by: Nicolas Granger --- .../shields/x_nucleo_iks01a2/boards/stm32mp157c_dk2.overlay | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/shields/x_nucleo_iks01a2/boards/stm32mp157c_dk2.overlay b/boards/shields/x_nucleo_iks01a2/boards/stm32mp157c_dk2.overlay index a560b19ea4c4..9fbf9eef3279 100644 --- a/boards/shields/x_nucleo_iks01a2/boards/stm32mp157c_dk2.overlay +++ b/boards/shields/x_nucleo_iks01a2/boards/stm32mp157c_dk2.overlay @@ -10,11 +10,11 @@ */ &arduino_i2c { - lsm303agr-magn_x_nucleo_iks01a2: lsm303agr-magn@1e { + lsm303agr_magn_1e_x_nucleo_iks01a2: lsm303agr-magn@1e { /delete-property/ irq-gpios; /* A3 */ }; - lsm303agr-accel_x_nucleo_iks01a2: lsm303agr-accel@19 { + lsm303agr_accel_19_x_nucleo_iks01a2: lsm303agr-accel@19 { /delete-property/ irq-gpios; /* A3 */ }; }; From 175abfbb715621c9e86f9aaa9919126564412dc1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 20 Jun 2023 09:14:00 +0200 Subject: [PATCH 0375/2042] nrf52_bsim: Give better description on test not yet passed When a bs_test is stopped before it passes, the current description is not informative enough. Improve it. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/bstests_entry.c | 8 ++++++++ boards/posix/nrf52_bsim/main.c | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/boards/posix/nrf52_bsim/bstests_entry.c b/boards/posix/nrf52_bsim/bstests_entry.c index 1f1208b9de20..ee61811ee3d3 100644 --- a/boards/posix/nrf52_bsim/bstests_entry.c +++ b/boards/posix/nrf52_bsim/bstests_entry.c @@ -233,5 +233,13 @@ uint8_t bst_delete(void) test_list_top = tmp; } + if (bst_result == In_progress) { + bs_trace_raw_time(2, "TESTCASE NOT PASSED at exit (test return " + "(%u) indicates it was still in progress)\n", bst_result); + } else if (bst_result != Passed) { + bs_trace_raw_time(2, "The TESTCASE FAILED (test return code %u)\n", + bst_result); + } + return bst_result; } diff --git a/boards/posix/nrf52_bsim/main.c b/boards/posix/nrf52_bsim/main.c index 42a473676f9e..df402c12241f 100644 --- a/boards/posix/nrf52_bsim/main.c +++ b/boards/posix/nrf52_bsim/main.c @@ -39,10 +39,6 @@ uint8_t inner_main_clean_up(int exit_code) uint8_t bst_result = bst_delete(); - if (bst_result != 0U) { - bs_trace_raw_time(2, "main: The TESTCASE FAILED with return " - "code %u\n", bst_result); - } return BS_MAX(bst_result, max_exit_code); } From 585063606a13437608a2e87f3602bf29ac3f8707 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 15:19:46 +0200 Subject: [PATCH 0376/2042] tests: portability cmsis_rtosv2: Fix buffer aligment The kernel requires the buffer to be word aligned. Instead of assuming the word size is 32bits, lets align the buffer to the size of a pointer, which should match the word size (and which is the check the kernel performs). Signed-off-by: Alberto Escolar Piedras --- tests/subsys/portability/cmsis_rtos_v2/src/mempool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c index 662afb44b927..1af17988e7ee 100644 --- a/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c +++ b/tests/subsys/portability/cmsis_rtos_v2/src/mempool.c @@ -16,7 +16,7 @@ struct mem_block { int member2; }; -static char __aligned(4) sample_mem[sizeof(struct mem_block) * MAX_BLOCKS]; +static char __aligned(sizeof(void *)) sample_mem[sizeof(struct mem_block) * MAX_BLOCKS]; static const osMemoryPoolAttr_t mp_attrs = { .name = "TestMempool", .attr_bits = 0, From e59f6a8135a4e7a1c2463d6bed1f5ac8e7c33cca Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 15:27:05 +0200 Subject: [PATCH 0377/2042] portability cmsis_rtosv2: Check return of k_mem_slab_init() Instead of trusting blindly that k_mem_slab_init() will succeed, let's check it, and handle failures appropriately. Otherwise, a buffer of garbage will be passed around, leading to misterious failures later on. Signed-off-by: Alberto Escolar Piedras --- subsys/portability/cmsis_rtos_v2/mempool.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/subsys/portability/cmsis_rtos_v2/mempool.c b/subsys/portability/cmsis_rtos_v2/mempool.c index 7865c890b1ca..0003af990aa1 100644 --- a/subsys/portability/cmsis_rtos_v2/mempool.c +++ b/subsys/portability/cmsis_rtos_v2/mempool.c @@ -68,7 +68,15 @@ osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size, mslab->is_dynamic_allocation = FALSE; } - k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count); + int rc = k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count); + + if (rc != 0) { + k_mem_slab_free(&cv2_mem_slab, (void *) &mslab); + if (attr->mp_mem == NULL) { + k_free(mslab->pool); + } + return NULL; + } if (attr->name == NULL) { strncpy(mslab->name, init_mslab_attrs.name, From 6c9a360647c8a1947c3b2eb7ba40c836810810aa Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 16 Jun 2023 13:43:59 +0200 Subject: [PATCH 0378/2042] drivers: intel_adsp_gpdma: Fix typo in reg name The correct short name for Dynamic Clock Gating Disable register is DCGD, not DGCD. Signed-off-by: Serhiy Katsyuba --- drivers/dma/dma_intel_adsp_gpdma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dma_intel_adsp_gpdma.c b/drivers/dma/dma_intel_adsp_gpdma.c index be24c302a646..219cec7fad30 100644 --- a/drivers/dma/dma_intel_adsp_gpdma.c +++ b/drivers/dma/dma_intel_adsp_gpdma.c @@ -11,7 +11,7 @@ #define GPDMA_CTL_OFFSET 0x0004 #define GPDMA_CTL_FDCGB BIT(0) -#define GPDMA_CTL_DGCD BIT(30) +#define GPDMA_CTL_DCGD BIT(30) /* TODO make device tree defined? */ #define GPDMA_CHLLPC_OFFSET(channel) (0x0010 + channel*0x10) @@ -247,7 +247,7 @@ static void intel_adsp_gpdma_clock_enable(const struct device *dev) uint32_t val; if (IS_ENABLED(CONFIG_SOC_SERIES_INTEL_ACE)) { - val = sys_read32(reg) | GPDMA_CTL_DGCD; + val = sys_read32(reg) | GPDMA_CTL_DCGD; } else { val = GPDMA_CTL_FDCGB; } @@ -261,7 +261,7 @@ static void intel_adsp_gpdma_clock_disable(const struct device *dev) #ifdef CONFIG_SOC_SERIES_INTEL_ACE const struct intel_adsp_gpdma_cfg *const dev_cfg = dev->config; uint32_t reg = dev_cfg->shim + GPDMA_CTL_OFFSET; - uint32_t val = sys_read32(reg) & ~GPDMA_CTL_DGCD; + uint32_t val = sys_read32(reg) & ~GPDMA_CTL_DCGD; sys_write32(val, reg); #endif From c8e0022d4b05fee10a016622b126f4912a81ff46 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 19 Jun 2023 16:19:46 -0400 Subject: [PATCH 0379/2042] drivers: rtc: mc146818: fix y2k bug That's correct. We are still fixing the Y2K bug in 2023 \o/ * write century to RAM register 0x32 * ensure year register is in [0,99] (inclusive) Aside from that, there were a few other errors in the driver. * translate epoch-centric RTC API year to begin at 1900 * fix off-by-one error with month limit * fix off-by-one error with wday * fix off-by-one-hundred error with year limit * adjust timeptr values in rtc_mc146818_validate_time() * adjust timeptr values in rtc_mc146818_validate_alarm() With the above, the testsuite passes! Signed-off-by: Christopher Friedt --- drivers/rtc/rtc_mc146818.c | 42 ++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c index 3f4530c750e4..58177b10c866 100644 --- a/drivers/rtc/rtc_mc146818.c +++ b/drivers/rtc/rtc_mc146818.c @@ -34,6 +34,9 @@ #define RTC_MONTH 0x08 #define RTC_YEAR 0x09 +/* Y2K Bugfix */ +#define RTC_CENTURY 0x32 + /* Alarm time indices in RTC RAM */ #define RTC_ALARM_SEC 0x01 #define RTC_ALARM_MIN 0x03 @@ -106,10 +109,10 @@ #define MIN_WDAY 1 #define MAX_MDAY 31 #define MIN_MDAY 1 -#define MAX_MON 11 -#define MIN_MON 0 +#define MAX_MON 12 +#define MIN_MON 1 #define MIN_YEAR_DIFF 0 /* YEAR - 1900 */ -#define MAX_YEAR_DIFF 199 /* YEAR - 1900 */ +#define MAX_YEAR_DIFF 99 /* YEAR - 1999 */ struct rtc_mc146818_data { struct k_spinlock lock; @@ -149,16 +152,16 @@ static bool rtc_mc146818_validate_time(const struct rtc_time *timeptr) if (timeptr->tm_hour < MIN_HOUR || timeptr->tm_hour > MAX_HOUR) { return false; } - if (timeptr->tm_wday < MIN_WDAY || timeptr->tm_wday > MAX_WDAY) { + if (timeptr->tm_wday + 1 < MIN_WDAY || timeptr->tm_wday + 1 > MAX_WDAY) { return false; } if (timeptr->tm_mday < MIN_MDAY || timeptr->tm_mday > MAX_MDAY) { return false; } - if (timeptr->tm_mon < MIN_MON || timeptr->tm_mon > MAX_MON) { + if (timeptr->tm_mon + 1 < MIN_MON || timeptr->tm_mon + 1 > MAX_MON) { return false; } - if (timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF) { + if (timeptr->tm_year - 70 < MIN_YEAR_DIFF || timeptr->tm_year - 70 > MAX_YEAR_DIFF) { return false; } return true; @@ -168,6 +171,8 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time { struct rtc_mc146818_data * const dev_data = dev->data; uint8_t value; + int year; + int cent; int ret; k_spinlock_key_t key = k_spin_lock(&dev_data->lock); @@ -186,6 +191,9 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time value = rtc_read(RTC_DATA); rtc_write(RTC_DATA, value | RTC_UCI_BIT); + year = (1970 + timeptr->tm_year) % 100; + cent = (1970 + timeptr->tm_year) / 100; + if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { rtc_write(RTC_SEC, (uint8_t)bin2bcd(timeptr->tm_sec)); rtc_write(RTC_MIN, (uint8_t)bin2bcd(timeptr->tm_min)); @@ -193,7 +201,8 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time rtc_write(RTC_WDAY, (uint8_t)bin2bcd(timeptr->tm_wday)); rtc_write(RTC_MDAY, (uint8_t)bin2bcd(timeptr->tm_mday)); rtc_write(RTC_MONTH, (uint8_t)bin2bcd(timeptr->tm_mon + 1)); - rtc_write(RTC_YEAR, (uint8_t)bin2bcd(timeptr->tm_year)); + rtc_write(RTC_YEAR, (uint8_t)bin2bcd(year)); + rtc_write(RTC_CENTURY, (uint8_t)bin2bcd(cent)); } else { rtc_write(RTC_SEC, (uint8_t)timeptr->tm_sec); rtc_write(RTC_MIN, (uint8_t)timeptr->tm_min); @@ -201,7 +210,8 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time rtc_write(RTC_WDAY, (uint8_t)timeptr->tm_wday); rtc_write(RTC_MDAY, (uint8_t)timeptr->tm_mday); rtc_write(RTC_MONTH, (uint8_t)timeptr->tm_mon + 1); - rtc_write(RTC_YEAR, (uint8_t)timeptr->tm_year); + rtc_write(RTC_YEAR, year); + rtc_write(RTC_CENTURY, cent); } if (timeptr->tm_isdst == 1) { @@ -221,6 +231,8 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim { struct rtc_mc146818_data * const dev_data = dev->data; int ret; + uint8_t cent; + uint8_t year; uint8_t value; k_spinlock_key_t key = k_spin_lock(&dev_data->lock); @@ -239,16 +251,18 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim while (rtc_read(RTC_UIP) & RTC_UIP_BIT) { continue; } - timeptr->tm_year = rtc_read(RTC_YEAR); + cent = rtc_read(RTC_CENTURY); + year = rtc_read(RTC_YEAR); timeptr->tm_mon = rtc_read(RTC_MONTH) - 1; timeptr->tm_mday = rtc_read(RTC_MDAY); - timeptr->tm_wday = rtc_read(RTC_WDAY); + timeptr->tm_wday = rtc_read(RTC_WDAY) - 1; timeptr->tm_hour = rtc_read(RTC_HOUR); timeptr->tm_min = rtc_read(RTC_MIN); timeptr->tm_sec = rtc_read(RTC_SEC); if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { - timeptr->tm_year = bcd2bin(timeptr->tm_year); + year = bcd2bin(year); + cent = bcd2bin(cent); timeptr->tm_mon = bcd2bin(timeptr->tm_mon); timeptr->tm_mday = bcd2bin(timeptr->tm_mday); timeptr->tm_wday = bcd2bin(timeptr->tm_wday); @@ -257,6 +271,8 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim timeptr->tm_sec = bcd2bin(timeptr->tm_sec); } + timeptr->tm_year = 100 * (int)cent + year - 1970; + timeptr->tm_nsec = 0; timeptr->tm_yday = 0; value = rtc_read(RTC_DATA); @@ -296,7 +312,7 @@ static bool rtc_mc146818_validate_alarm(const struct rtc_time *timeptr, uint32_t } if ((mask & RTC_ALARM_TIME_MASK_MONTH) && - (timeptr->tm_mon < MIN_WDAY || timeptr->tm_mon > MAX_WDAY)) { + (timeptr->tm_mon + 1 < MIN_WDAY || timeptr->tm_mon + 1 > MAX_WDAY)) { return false; } @@ -306,7 +322,7 @@ static bool rtc_mc146818_validate_alarm(const struct rtc_time *timeptr, uint32_t } if ((mask & RTC_ALARM_TIME_MASK_YEAR) && - (timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF)) { + (timeptr->tm_year - 70 < MIN_YEAR_DIFF || timeptr->tm_year - 70 > MAX_YEAR_DIFF)) { return false; } From 3e71797ba229121413103e787a49630bc06520ef Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 19 Jun 2023 12:23:53 +0100 Subject: [PATCH 0380/2042] mgmt: mcumgr: grp: img_mgmt: Fix missing define Fixes a missing define which causes a build failure. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 953c3776c4c9..66df020bfc6f 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -426,7 +426,9 @@ img_mgmt_upload(struct smp_streamer *ctxt) bool data_match = false; #endif -#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) || defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) +#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) || \ +defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) || \ +defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) enum mgmt_cb_return status; int32_t ret_rc; uint16_t ret_group; From a24eec238819de8de7df024632ca3704aeb84247 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 19 Jun 2023 11:47:46 +0200 Subject: [PATCH 0381/2042] bsim boards: doc: Fix around printk backend The printk backend for the bsim boards and native_posix was merged into a single backend reusable for all POSIX arch boards. Correct the bsim board documentation so it does not refer to the old backend anymore. Signed-off-by: Alberto Escolar Piedras --- boards/posix/doc/bsim_boards_design.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index 9fe31afdc566..3c12f0e6acb3 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -225,15 +225,14 @@ which relies on the bs_trace API. Instead, for tracing the bs_trace API should be used directly. The same applies to other Zephyr APIs, including the entropy API, etc. -printk and posix_print backend -============================== - -The bsim board provides a very simple backend for Zephyr's :c:func:`printk()`, -which simply routes the printk strings to the bs_trace bsim API. -So printk messages are printed in the console (stdout) together with all -other device messages. -The board also provides the posix_print API which is expected by the posix ARCH -and soc inf code, and which is based on the same bs_trace API. +posix_print backend +=================== + +The bsim board provides a backend for the posix_print API which is expected by the posix ARCH +and soc inf (POSIX) code. +It simply routes the printk strings to the bs_trace bsim API. +Any message printed to the posix_print API, which is also the default printk backend, +will be printed to the console (stdout) together with all other device messages. .. _bsim_boards_bs_tests: From c345f95134c8a1ecca86d1c1496e4ed6e322754b Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Thu, 8 Jun 2023 19:47:36 +0300 Subject: [PATCH 0382/2042] boards: rpi_pico: Fixed openocd invocation Pass openocd "cmsis-dap.cfg" instead of the obsolete "picoprobe.cfg". Signed-off-by: Yonatan Schachter --- boards/arm/rpi_pico/board.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake index 0427e9e50910..07a128fad7bf 100644 --- a/boards/arm/rpi_pico/board.cmake +++ b/boards/arm/rpi_pico/board.cmake @@ -14,7 +14,7 @@ # in the openocd interface configuration file. # The setting is store to CMakeCache.txt. if ("${RPI_PICO_DEBUG_ADAPTER}" STREQUAL "") - set(RPI_PICO_DEBUG_ADAPTER picoprobe) + set(RPI_PICO_DEBUG_ADAPTER "cmsis-dap") endif() board_runner_args(openocd --cmd-pre-init "source [find interface/${RPI_PICO_DEBUG_ADAPTER}.cfg]") From a75e9f5a669d80d266539de8dd9340cc28ff53cf Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Fri, 9 Jun 2023 12:59:52 +0300 Subject: [PATCH 0383/2042] boards: arm: rpi_pico: Updated doc Updated the documentation of the rpi_pico board regarding the use of OpenOCD. Signed-off-by: Yonatan Schachter --- boards/arm/rpi_pico/doc/index.rst | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst index 074de00d8179..ee01585663d1 100644 --- a/boards/arm/rpi_pico/doc/index.rst +++ b/boards/arm/rpi_pico/doc/index.rst @@ -169,13 +169,13 @@ Create a file in /etc/udev.rules.d with any name, and write the line below. .. code-block:: bash - ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="660", GROUP="plugdev", TAG+="uaccess" + 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 has an SWD interface that can be used to program and debug the on board RP2040. This interface can be utilized by OpenOCD. -However, to use it with the RP2040, a `fork of OpenOCD supporting RP2040`_ is needed. +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. @@ -244,10 +244,6 @@ Using OpenOCD Install OpenOCD as described for flashing the board. -.. note:: - `fork of OpenOCD supporting RP2040`_ does not provide ZephyrRTOS enhancement. - (No RTOS awareness. Thus, can't recognize threads.) - Here is an example for debugging the :ref:`blinky-sample` application. .. zephyr-app-commands:: @@ -284,9 +280,6 @@ You can then start debugging the board. .. target-notes:: -.. _fork of OpenOCD supporting RP2040: - https://github.com/raspberrypi/openocd - .. _pico_setup.sh: https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh From f3668dfdff443f407f8717fb66a9b90e81550754 Mon Sep 17 00:00:00 2001 From: Oleh Lozynskyy Date: Mon, 27 Mar 2023 17:59:39 +0200 Subject: [PATCH 0384/2042] drivers: sensor: bq274xx: rename status to ret Shorten lines lengths. ret is a more common return variable name. Signed-off-by: Oleh Lozynskyy --- drivers/sensor/bq274xx/bq274xx.c | 266 +++++++++++------------ drivers/sensor/bq274xx/bq274xx_trigger.c | 50 ++--- 2 files changed, 158 insertions(+), 158 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 6266bc2d88d1..702a25586070 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -33,11 +33,11 @@ static int bq274xx_command_reg_read(const struct device *dev, uint8_t reg_addr, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data[2]; - int status; + int ret; - status = i2c_burst_read_dt(&config->i2c, reg_addr, + ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, 2); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; } @@ -52,14 +52,14 @@ static int bq274xx_control_reg_write(const struct device *dev, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; - int status = 0; + int ret = 0; reg_addr = BQ274XX_COMMAND_CONTROL_LOW; i2c_data = (uint8_t)((subcommand)&0x00FF); - status = i2c_reg_write_byte_dt(&config->i2c, reg_addr, + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write into control low register"); return -EIO; } @@ -69,9 +69,9 @@ static int bq274xx_control_reg_write(const struct device *dev, reg_addr = BQ274XX_COMMAND_CONTROL_HIGH; i2c_data = (uint8_t)((subcommand >> 8) & 0x00FF); - status = i2c_reg_write_byte_dt(&config->i2c, reg_addr, + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write into control high register"); return -EIO; } @@ -84,14 +84,14 @@ static int bq274xx_command_reg_write(const struct device *dev, uint8_t command, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; - int status = 0; + int ret = 0; reg_addr = command; i2c_data = data; - status = i2c_reg_write_byte_dt(&config->i2c, reg_addr, + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write into control register"); return -EIO; } @@ -104,13 +104,13 @@ static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data; - int status = 0; + int ret = 0; i2c_data = BQ274XX_EXTENDED_BLOCKDATA_START + offset; - status = i2c_burst_read_dt(&config->i2c, i2c_data, + ret = i2c_burst_read_dt(&config->i2c, i2c_data, data, bytes); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read block"); return -EIO; } @@ -122,19 +122,19 @@ static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) { - int status; + int ret; - status = + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_DEVICE_TYPE); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to write control register"); return -EIO; } - status = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_CONTROL_LOW, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_CONTROL_LOW, val); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; } @@ -229,133 +229,133 @@ static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *bq274xx = dev->data; - int status = 0; + int ret = 0; if (!bq274xx->configured) { - status = bq274xx_gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); - if (status < 0) { - return status; + if (ret < 0) { + return ret; } } switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_VOLTAGE, &bq274xx->voltage); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; } break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - status = bq274xx_command_reg_read(dev, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVG_CURRENT, &bq274xx->avg_current); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; } break; case SENSOR_CHAN_GAUGE_TEMP: - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_INT_TEMP, &bq274xx->internal_temperature); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; } break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - status = bq274xx_command_reg_read(dev, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_STDBY_CURRENT, &bq274xx->stdby_current); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; } break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - status = bq274xx_command_reg_read(dev, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_MAX_CURRENT, &bq274xx->max_load_current); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; } break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - status = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOC, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOC, &bq274xx->state_of_charge); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; } break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_FULL_CAPACITY, &bq274xx->full_charge_capacity); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); return -EIO; } break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_REM_CAPACITY, &bq274xx->remaining_charge_capacity); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); return -EIO; } break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - status = bq274xx_command_reg_read(dev, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_NOM_CAPACITY, &bq274xx->nom_avail_capacity); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); return -EIO; } break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - status = + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVAIL_CAPACITY, &bq274xx->full_avail_capacity); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read full available capacity"); return -EIO; } break; case SENSOR_CHAN_GAUGE_AVG_POWER: - status = bq274xx_command_reg_read(dev, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVG_POWER, &bq274xx->avg_power); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; } break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - status = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOH, + ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOH, &bq274xx->state_of_health); bq274xx->state_of_health = (bq274xx->state_of_health) & 0x00FF; - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read state of health"); return -EIO; } @@ -376,7 +376,7 @@ static int bq274xx_sample_fetch(const struct device *dev, static int bq274xx_gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int status = 0; + int ret = 0; uint16_t id; if (!device_is_ready(config->i2c.bus)) { @@ -391,8 +391,8 @@ static int bq274xx_gauge_init(const struct device *dev) } #endif - status = bq274xx_get_device_type(dev, &id); - if (status < 0) { + ret = bq274xx_get_device_type(dev, &id); + if (ret < 0) { LOG_ERR("Unable to get device ID"); return -EIO; } @@ -403,18 +403,18 @@ static int bq274xx_gauge_init(const struct device *dev) } #ifdef CONFIG_BQ274XX_TRIGGER - status = bq274xx_trigger_mode_init(dev); - if (status < 0) { + ret = bq274xx_trigger_mode_init(dev); + if (ret < 0) { LOG_ERR("Unable set up trigger mode."); - return status; + return ret; } #endif if (!config->lazy_loading) { - status = bq274xx_gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); } - return status; + return ret; } static int bq274xx_gauge_configure(const struct device *dev) @@ -422,7 +422,7 @@ static int bq274xx_gauge_configure(const struct device *dev) const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - int status = 0; + int ret = 0; uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, @@ -435,31 +435,31 @@ static int bq274xx_gauge_configure(const struct device *dev) (uint16_t)config->design_capacity / (0.1 * config->taper_current); /** Unseal the battery control register **/ - status = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } - status = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } /* Send CFG_UPDATE */ - status = bq274xx_control_reg_write(dev, + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SET_CFGUPDATE); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to set CFGUpdate"); return -EIO; } /** Step to place the Gauge into CONFIG UPDATE Mode **/ do { - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_FLAGS, &flags); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; } @@ -470,25 +470,25 @@ static int bq274xx_gauge_configure(const struct device *dev) } while (!(flags & 0x0010)); - status = bq274xx_command_reg_write(dev, + ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_CONTROL, 0x00); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to enable block data memory"); return -EIO; } /* Access State subclass */ - status = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_CLASS, + ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_CLASS, 0x52); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to update state subclass"); return -EIO; } /* Write the block offset */ - status = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_BLOCK, + ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_BLOCK, 0x00); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to update block offset"); return -EIO; } @@ -497,8 +497,8 @@ static int bq274xx_gauge_configure(const struct device *dev) block[i] = 0; } - status = bq274xx_read_data_block(dev, 0x00, block, 32); - if (status < 0) { + ret = bq274xx_read_data_block(dev, 0x00, block, 32); + if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; } @@ -510,9 +510,9 @@ static int bq274xx_gauge_configure(const struct device *dev) tmp_checksum = 255 - tmp_checksum; /* Read the block checksum */ - status = i2c_reg_read_byte_dt(&config->i2c, + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXTENDED_CHECKSUM, &checksum_old); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to read block checksum"); return -EIO; } @@ -526,65 +526,65 @@ static int bq274xx_gauge_configure(const struct device *dev) taperrate_msb = taperrate >> 8; taperrate_lsb = taperrate & 0x00FF; - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_HIGH, designcap_msb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write designCAP MSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_LOW, designcap_lsb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write designCAP LSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_HIGH, designenergy_msb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write designEnergy MSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_LOW, designenergy_lsb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write designEnergy LSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_HIGH, terminatevolt_msb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write terminateVolt MSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW, terminatevolt_lsb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write terminateVolt LSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_HIGH, taperrate_msb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write taperRate MSB"); return -EIO; } - status = i2c_reg_write_byte_dt(&config->i2c, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_LOW, taperrate_lsb); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to write taperRate LSB"); return -EIO; } @@ -593,8 +593,8 @@ static int bq274xx_gauge_configure(const struct device *dev) block[i] = 0; } - status = bq274xx_read_data_block(dev, 0x00, block, 32); - if (status < 0) { + ret = bq274xx_read_data_block(dev, 0x00, block, 32); + if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; } @@ -605,29 +605,29 @@ static int bq274xx_gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - status = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_CHECKSUM, + ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_CHECKSUM, checksum_new); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to update new checksum"); return -EIO; } tmp_checksum = 0; - status = i2c_reg_read_byte_dt(&config->i2c, + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXTENDED_CHECKSUM, &tmp_checksum); - if (status < 0) { + if (ret < 0) { LOG_ERR("Failed to read checksum"); return -EIO; } - status = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_BAT_INSERT); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_BAT_INSERT); + if (ret < 0) { LOG_ERR("Unable to configure BAT Detect"); return -EIO; } - status = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SOFT_RESET); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SOFT_RESET); + if (ret < 0) { LOG_ERR("Failed to soft reset the gauge"); return -EIO; } @@ -635,9 +635,9 @@ static int bq274xx_gauge_configure(const struct device *dev) flags = 0; /* Poll Flags */ do { - status = bq274xx_command_reg_read( + ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_FLAGS, &flags); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; } @@ -648,8 +648,8 @@ static int bq274xx_gauge_configure(const struct device *dev) } while (flags & 0x0010); /* Seal the gauge */ - status = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); + if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return -EIO; } @@ -662,37 +662,37 @@ static int bq274xx_gauge_configure(const struct device *dev) #ifdef CONFIG_BQ274XX_PM static int bq274xx_enter_shutdown_mode(const struct device *dev) { - int status; + int ret; - status = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { LOG_ERR("Unable to unseal the battery"); - return status; + return ret; } - status = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { LOG_ERR("Unable to unseal the battery"); - return status; + return ret; } - status = bq274xx_control_reg_write(dev, + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN_ENABLE); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); - return status; + return ret; } - status = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN); + if (ret < 0) { LOG_ERR("Unable to enter shutdown mode"); - return status; + return ret; } - status = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); - if (status < 0) { + ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); + if (ret < 0) { LOG_ERR("Failed to seal the gauge"); - return status; + return ret; } return 0; @@ -701,36 +701,36 @@ static int bq274xx_enter_shutdown_mode(const struct device *dev) static int bq274xx_exit_shutdown_mode(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int status = 0; + int ret = 0; - status = gpio_pin_configure_dt(&config->int_gpios, + ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_OUTPUT | GPIO_OPEN_DRAIN); - if (status < 0) { + if (ret < 0) { LOG_ERR("Unable to configure interrupt pin to output and open drain"); - return status; + return ret; } - status = gpio_pin_set_dt(&config->int_gpios, 0); - if (status < 0) { + ret = gpio_pin_set_dt(&config->int_gpios, 0); + if (ret < 0) { LOG_ERR("Unable to set interrupt pin to low"); - return status; + return ret; } k_msleep(PIN_DELAY_TIME); - status = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); - if (status < 0) { + ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); + if (ret < 0) { LOG_ERR("Unable to configure interrupt pin to input"); - return status; + return ret; } if (!config->lazy_loading) { k_msleep(INIT_TIME); - status = bq274xx_gauge_configure(dev); - if (status < 0) { + ret = bq274xx_gauge_configure(dev); + if (ret < 0) { LOG_ERR("Unable to configure bq274xx gauge"); - return status; + return ret; } } diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 6bb7207b8708..3fba419d4867 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -69,7 +69,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - int status = 0; + int ret = 0; data->dev = dev; @@ -86,10 +86,10 @@ int bq274xx_trigger_mode_init(const struct device *dev) k_work_init(&data->work, bq274xx_work_handler); #endif - status = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); - if (status < 0) { + ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); + if (ret < 0) { LOG_ERR("Unable to configure interrupt pin to input"); - return status; + return ret; } gpio_init_callback(&data->ready_callback, bq274xx_ready_callback_handler, @@ -104,7 +104,7 @@ int bq274xx_trigger_set(const struct device *dev, { const struct bq274xx_config *config = dev->config; struct bq274xx_data *data = dev->data; - int status; + int ret; #ifdef CONFIG_BQ274XX_PM enum pm_device_state state; @@ -128,35 +128,35 @@ int bq274xx_trigger_set(const struct device *dev, data->ready_trig = trig; if (handler) { - status = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); - if (status < 0) { - LOG_ERR("Unable to configure interrupt pin to input (%d)", status); - return status; + ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Unable to configure interrupt pin to input (%d)", ret); + return ret; } - status = gpio_add_callback(config->int_gpios.port, &data->ready_callback); - if (status < 0) { - LOG_ERR("Unable to add interrupt callback (%d)", status); - return status; + ret = gpio_add_callback(config->int_gpios.port, &data->ready_callback); + if (ret < 0) { + LOG_ERR("Unable to add interrupt callback (%d)", ret); + return ret; } - status = gpio_pin_interrupt_configure_dt(&config->int_gpios, + ret = gpio_pin_interrupt_configure_dt(&config->int_gpios, GPIO_INT_EDGE_TO_ACTIVE); - if (status < 0) { - LOG_ERR("Unable to configure interrupt (%d)", status); - return status; + if (ret < 0) { + LOG_ERR("Unable to configure interrupt (%d)", ret); + return ret; } } else { - status = gpio_remove_callback(config->int_gpios.port, &data->ready_callback); - if (status < 0) { - LOG_ERR("Unable to remove interrupt callback (%d)", status); - return status; + ret = gpio_remove_callback(config->int_gpios.port, &data->ready_callback); + if (ret < 0) { + LOG_ERR("Unable to remove interrupt callback (%d)", ret); + return ret; } - status = gpio_pin_interrupt_configure_dt(&config->int_gpios, GPIO_INT_DISABLE); - if (status < 0) { - LOG_ERR("Unable to configure interrupt (%d)", status); - return status; + ret = gpio_pin_interrupt_configure_dt(&config->int_gpios, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("Unable to configure interrupt (%d)", ret); + return ret; } } From 765698e3a2ad09086fa9db96f77475d3165c2e79 Mon Sep 17 00:00:00 2001 From: Oleh Lozynskyy Date: Mon, 27 Mar 2023 18:08:34 +0200 Subject: [PATCH 0385/2042] drivers: sensor: bq274xx: rename bq274xx to data Shorten lines lengths. data is a common driver data struct point name. Signed-off-by: Oleh Lozynskyy --- drivers/sensor/bq274xx/bq274xx.c | 74 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 702a25586070..00c1a6aee19b 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -151,71 +151,71 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { - struct bq274xx_data *bq274xx = dev->data; + struct bq274xx_data *data = dev->data; float int_temp; switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - val->val1 = ((bq274xx->voltage / 1000)); - val->val2 = ((bq274xx->voltage % 1000) * 1000U); + val->val1 = ((data->voltage / 1000)); + val->val2 = ((data->voltage % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - val->val1 = ((bq274xx->avg_current / 1000)); - val->val2 = ((bq274xx->avg_current % 1000) * 1000U); + val->val1 = ((data->avg_current / 1000)); + val->val2 = ((data->avg_current % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - val->val1 = ((bq274xx->stdby_current / 1000)); - val->val2 = ((bq274xx->stdby_current % 1000) * 1000U); + val->val1 = ((data->stdby_current / 1000)); + val->val2 = ((data->stdby_current % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - val->val1 = ((bq274xx->max_load_current / 1000)); - val->val2 = ((bq274xx->max_load_current % 1000) * 1000U); + val->val1 = ((data->max_load_current / 1000)); + val->val2 = ((data->max_load_current % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_TEMP: - int_temp = (bq274xx->internal_temperature * 0.1f); + 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; break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - val->val1 = bq274xx->state_of_charge; + val->val1 = data->state_of_charge; val->val2 = 0; break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - val->val1 = bq274xx->state_of_health; + val->val1 = data->state_of_health; val->val2 = 0; break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - val->val1 = (bq274xx->full_charge_capacity / 1000); - val->val2 = ((bq274xx->full_charge_capacity % 1000) * 1000U); + val->val1 = (data->full_charge_capacity / 1000); + val->val2 = ((data->full_charge_capacity % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - val->val1 = (bq274xx->remaining_charge_capacity / 1000); + val->val1 = (data->remaining_charge_capacity / 1000); val->val2 = - ((bq274xx->remaining_charge_capacity % 1000) * 1000U); + ((data->remaining_charge_capacity % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - val->val1 = (bq274xx->nom_avail_capacity / 1000); - val->val2 = ((bq274xx->nom_avail_capacity % 1000) * 1000U); + val->val1 = (data->nom_avail_capacity / 1000); + val->val2 = ((data->nom_avail_capacity % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - val->val1 = (bq274xx->full_avail_capacity / 1000); - val->val2 = ((bq274xx->full_avail_capacity % 1000) * 1000U); + val->val1 = (data->full_avail_capacity / 1000); + val->val2 = ((data->full_avail_capacity % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_AVG_POWER: - val->val1 = (bq274xx->avg_power / 1000); - val->val2 = ((bq274xx->avg_power % 1000) * 1000U); + val->val1 = (data->avg_power / 1000); + val->val2 = ((data->avg_power % 1000) * 1000U); break; default: @@ -228,10 +228,10 @@ static int bq274xx_channel_get(const struct device *dev, static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { - struct bq274xx_data *bq274xx = dev->data; + struct bq274xx_data *data = dev->data; int ret = 0; - if (!bq274xx->configured) { + if (!data->configured) { ret = bq274xx_gauge_configure(dev); if (ret < 0) { @@ -242,7 +242,7 @@ static int bq274xx_sample_fetch(const struct device *dev, switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: ret = bq274xx_command_reg_read( - dev, BQ274XX_COMMAND_VOLTAGE, &bq274xx->voltage); + dev, BQ274XX_COMMAND_VOLTAGE, &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; @@ -252,7 +252,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_AVG_CURRENT: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVG_CURRENT, - &bq274xx->avg_current); + &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; @@ -262,7 +262,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_TEMP: ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_INT_TEMP, - &bq274xx->internal_temperature); + &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; @@ -272,7 +272,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_STDBY_CURRENT: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_STDBY_CURRENT, - &bq274xx->stdby_current); + &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; @@ -282,7 +282,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_MAX_CURRENT, - &bq274xx->max_load_current); + &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; @@ -291,7 +291,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOC, - &bq274xx->state_of_charge); + &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; @@ -301,7 +301,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_FULL_CAPACITY, - &bq274xx->full_charge_capacity); + &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); return -EIO; @@ -311,7 +311,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: ret = bq274xx_command_reg_read( dev, BQ274XX_COMMAND_REM_CAPACITY, - &bq274xx->remaining_charge_capacity); + &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); return -EIO; @@ -321,7 +321,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_NOM_CAPACITY, - &bq274xx->nom_avail_capacity); + &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); return -EIO; @@ -332,7 +332,7 @@ static int bq274xx_sample_fetch(const struct device *dev, ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVAIL_CAPACITY, - &bq274xx->full_avail_capacity); + &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); return -EIO; @@ -342,7 +342,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_AVG_POWER: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_AVG_POWER, - &bq274xx->avg_power); + &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; @@ -351,9 +351,9 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOH, - &bq274xx->state_of_health); + &data->state_of_health); - bq274xx->state_of_health = (bq274xx->state_of_health) & 0x00FF; + data->state_of_health = (data->state_of_health) & 0x00FF; if (ret < 0) { LOG_ERR("Failed to read state of health"); From 0f37378a9582bac6415c9a074cec48ce77a17f78 Mon Sep 17 00:00:00 2001 From: Oleh Lozynskyy Date: Mon, 27 Mar 2023 18:13:28 +0200 Subject: [PATCH 0386/2042] drivers: sensor: bq274xx: remove bq274xx prefixes Shorten lines lengths. Remove bq274xx prefixes from static function names. Removes repetition of bq274xx in logging. Signed-off-by: Oleh Lozynskyy --- drivers/sensor/bq274xx/bq274xx.c | 118 +++++++++++------------ drivers/sensor/bq274xx/bq274xx_trigger.c | 18 ++-- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 00c1a6aee19b..46592fb19d45 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -26,9 +26,9 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* Time it takes device to initialize before doing any configuration */ #define INIT_TIME 100U -static int bq274xx_gauge_configure(const struct device *dev); +static int gauge_configure(const struct device *dev); -static int bq274xx_command_reg_read(const struct device *dev, uint8_t reg_addr, +static int command_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { const struct bq274xx_config *config = dev->config; @@ -47,7 +47,7 @@ static int bq274xx_command_reg_read(const struct device *dev, uint8_t reg_addr, return 0; } -static int bq274xx_control_reg_write(const struct device *dev, +static int control_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; @@ -79,7 +79,7 @@ static int bq274xx_control_reg_write(const struct device *dev, return 0; } -static int bq274xx_command_reg_write(const struct device *dev, uint8_t command, +static int command_reg_write(const struct device *dev, uint8_t command, uint8_t data) { const struct bq274xx_config *config = dev->config; @@ -99,7 +99,7 @@ static int bq274xx_command_reg_write(const struct device *dev, uint8_t command, return 0; } -static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, +static int read_data_block(const struct device *dev, uint8_t offset, uint8_t *data, uint8_t bytes) { const struct bq274xx_config *config = dev->config; @@ -120,18 +120,18 @@ static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, return 0; } -static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) +static int get_device_type(const struct device *dev, uint16_t *val) { int ret; ret = - bq274xx_control_reg_write(dev, BQ274XX_CONTROL_DEVICE_TYPE); + control_reg_write(dev, BQ274XX_CONTROL_DEVICE_TYPE); if (ret < 0) { LOG_ERR("Unable to write control register"); return -EIO; } - ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_CONTROL_LOW, + ret = command_reg_read(dev, BQ274XX_COMMAND_CONTROL_LOW, val); if (ret < 0) { @@ -147,7 +147,7 @@ static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) * * @return -ENOTSUP for unsupported channels */ -static int bq274xx_channel_get(const struct device *dev, +static int channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { @@ -225,14 +225,14 @@ static int bq274xx_channel_get(const struct device *dev, return 0; } -static int bq274xx_sample_fetch(const struct device *dev, +static int sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; int ret = 0; if (!data->configured) { - ret = bq274xx_gauge_configure(dev); + ret = gauge_configure(dev); if (ret < 0) { return ret; @@ -241,7 +241,7 @@ static int bq274xx_sample_fetch(const struct device *dev, switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_VOLTAGE, &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); @@ -250,7 +250,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - ret = bq274xx_command_reg_read(dev, + ret = command_reg_read(dev, BQ274XX_COMMAND_AVG_CURRENT, &data->avg_current); if (ret < 0) { @@ -260,7 +260,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_TEMP: - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_INT_TEMP, &data->internal_temperature); if (ret < 0) { @@ -270,7 +270,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - ret = bq274xx_command_reg_read(dev, + ret = command_reg_read(dev, BQ274XX_COMMAND_STDBY_CURRENT, &data->stdby_current); if (ret < 0) { @@ -280,7 +280,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - ret = bq274xx_command_reg_read(dev, + ret = command_reg_read(dev, BQ274XX_COMMAND_MAX_CURRENT, &data->max_load_current); if (ret < 0) { @@ -290,7 +290,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOC, + ret = command_reg_read(dev, BQ274XX_COMMAND_SOC, &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); @@ -299,7 +299,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_FULL_CAPACITY, &data->full_charge_capacity); if (ret < 0) { @@ -309,7 +309,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_REM_CAPACITY, &data->remaining_charge_capacity); if (ret < 0) { @@ -319,7 +319,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - ret = bq274xx_command_reg_read(dev, + ret = command_reg_read(dev, BQ274XX_COMMAND_NOM_CAPACITY, &data->nom_avail_capacity); if (ret < 0) { @@ -330,7 +330,7 @@ static int bq274xx_sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: ret = - bq274xx_command_reg_read(dev, + command_reg_read(dev, BQ274XX_COMMAND_AVAIL_CAPACITY, &data->full_avail_capacity); if (ret < 0) { @@ -340,7 +340,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_POWER: - ret = bq274xx_command_reg_read(dev, + ret = command_reg_read(dev, BQ274XX_COMMAND_AVG_POWER, &data->avg_power); if (ret < 0) { @@ -350,7 +350,7 @@ static int bq274xx_sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - ret = bq274xx_command_reg_read(dev, BQ274XX_COMMAND_SOH, + ret = command_reg_read(dev, BQ274XX_COMMAND_SOH, &data->state_of_health); data->state_of_health = (data->state_of_health) & 0x00FF; @@ -373,7 +373,7 @@ static int bq274xx_sample_fetch(const struct device *dev, * * @return 0 for success */ -static int bq274xx_gauge_init(const struct device *dev) +static int gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; int ret = 0; @@ -391,7 +391,7 @@ static int bq274xx_gauge_init(const struct device *dev) } #endif - ret = bq274xx_get_device_type(dev, &id); + ret = get_device_type(dev, &id); if (ret < 0) { LOG_ERR("Unable to get device ID"); return -EIO; @@ -411,13 +411,13 @@ static int bq274xx_gauge_init(const struct device *dev) #endif if (!config->lazy_loading) { - ret = bq274xx_gauge_configure(dev); + ret = gauge_configure(dev); } return ret; } -static int bq274xx_gauge_configure(const struct device *dev) +static int gauge_configure(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; @@ -435,20 +435,20 @@ static int bq274xx_gauge_configure(const struct device *dev) (uint16_t)config->design_capacity / (0.1 * config->taper_current); /** Unseal the battery control register **/ - ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } - ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } /* Send CFG_UPDATE */ - ret = bq274xx_control_reg_write(dev, + ret = control_reg_write(dev, BQ274XX_CONTROL_SET_CFGUPDATE); if (ret < 0) { LOG_ERR("Unable to set CFGUpdate"); @@ -457,7 +457,7 @@ static int bq274xx_gauge_configure(const struct device *dev) /** Step to place the Gauge into CONFIG UPDATE Mode **/ do { - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); @@ -470,7 +470,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } while (!(flags & 0x0010)); - ret = bq274xx_command_reg_write(dev, + ret = command_reg_write(dev, BQ274XX_EXTENDED_DATA_CONTROL, 0x00); if (ret < 0) { LOG_ERR("Failed to enable block data memory"); @@ -478,7 +478,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } /* Access State subclass */ - ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_CLASS, + ret = command_reg_write(dev, BQ274XX_EXTENDED_DATA_CLASS, 0x52); if (ret < 0) { LOG_ERR("Failed to update state subclass"); @@ -486,7 +486,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } /* Write the block offset */ - ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_DATA_BLOCK, + ret = command_reg_write(dev, BQ274XX_EXTENDED_DATA_BLOCK, 0x00); if (ret < 0) { LOG_ERR("Failed to update block offset"); @@ -497,7 +497,7 @@ static int bq274xx_gauge_configure(const struct device *dev) block[i] = 0; } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); + ret = read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; @@ -593,7 +593,7 @@ static int bq274xx_gauge_configure(const struct device *dev) block[i] = 0; } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); + ret = read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; @@ -605,7 +605,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - ret = bq274xx_command_reg_write(dev, BQ274XX_EXTENDED_CHECKSUM, + ret = command_reg_write(dev, BQ274XX_EXTENDED_CHECKSUM, checksum_new); if (ret < 0) { LOG_ERR("Failed to update new checksum"); @@ -620,13 +620,13 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_BAT_INSERT); + ret = control_reg_write(dev, BQ274XX_CONTROL_BAT_INSERT); if (ret < 0) { LOG_ERR("Unable to configure BAT Detect"); return -EIO; } - ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SOFT_RESET); + ret = control_reg_write(dev, BQ274XX_CONTROL_SOFT_RESET); if (ret < 0) { LOG_ERR("Failed to soft reset the gauge"); return -EIO; @@ -635,7 +635,7 @@ static int bq274xx_gauge_configure(const struct device *dev) flags = 0; /* Poll Flags */ do { - ret = bq274xx_command_reg_read( + ret = command_reg_read( dev, BQ274XX_COMMAND_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); @@ -648,7 +648,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } while (flags & 0x0010); /* Seal the gauge */ - ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); + ret = control_reg_write(dev, BQ274XX_CONTROL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return -EIO; @@ -660,36 +660,36 @@ static int bq274xx_gauge_configure(const struct device *dev) } #ifdef CONFIG_BQ274XX_PM -static int bq274xx_enter_shutdown_mode(const struct device *dev) +static int enter_shutdown_mode(const struct device *dev) { int ret; - ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = bq274xx_control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = bq274xx_control_reg_write(dev, + ret = control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN_ENABLE); if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); return ret; } - ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN); + ret = control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN); if (ret < 0) { LOG_ERR("Unable to enter shutdown mode"); return ret; } - ret = bq274xx_control_reg_write(dev, BQ274XX_CONTROL_SEALED); + ret = control_reg_write(dev, BQ274XX_CONTROL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return ret; @@ -698,7 +698,7 @@ static int bq274xx_enter_shutdown_mode(const struct device *dev) return 0; } -static int bq274xx_exit_shutdown_mode(const struct device *dev) +static int exit_shutdown_mode(const struct device *dev) { const struct bq274xx_config *const config = dev->config; int ret = 0; @@ -727,7 +727,7 @@ static int bq274xx_exit_shutdown_mode(const struct device *dev) if (!config->lazy_loading) { k_msleep(INIT_TIME); - ret = bq274xx_gauge_configure(dev); + ret = gauge_configure(dev); if (ret < 0) { LOG_ERR("Unable to configure bq274xx gauge"); return ret; @@ -737,17 +737,17 @@ static int bq274xx_exit_shutdown_mode(const struct device *dev) return 0; } -static int bq274xx_pm_action(const struct device *dev, +static int pm_action(const struct device *dev, enum pm_device_action action) { int ret; switch (action) { case PM_DEVICE_ACTION_TURN_OFF: - ret = bq274xx_enter_shutdown_mode(dev); + ret = enter_shutdown_mode(dev); break; case PM_DEVICE_ACTION_RESUME: - ret = bq274xx_exit_shutdown_mode(dev); + ret = exit_shutdown_mode(dev); break; default: ret = -ENOTSUP; @@ -759,8 +759,8 @@ static int bq274xx_pm_action(const struct device *dev, #endif /* CONFIG_BQ274XX_PM */ static const struct sensor_driver_api bq274xx_battery_driver_api = { - .sample_fetch = bq274xx_sample_fetch, - .channel_get = bq274xx_channel_get, + .sample_fetch = sample_fetch, + .channel_get = channel_get, #ifdef CONFIG_BQ274XX_TRIGGER .trigger_set = bq274xx_trigger_set, #endif @@ -769,12 +769,12 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) #define BQ274XX_INT_CFG(index) \ .int_gpios = GPIO_DT_SPEC_INST_GET(index, int_gpios), -#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) \ - PM_DEVICE_DT_INST_DEFINE(index, bq274xx_pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) \ + PM_DEVICE_DT_INST_DEFINE(index, pm_action) #define PM_BQ274XX_DT_INST_GET(index) PM_DEVICE_DT_INST_GET(index) #else #define BQ274XX_INT_CFG(index) -#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) #define PM_BQ274XX_DT_INST_GET(index) NULL #endif @@ -791,9 +791,9 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ - PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action); \ + PM_BQ274XX_DT_INST_DEFINE(index, pm_action); \ \ - SENSOR_DEVICE_DT_INST_DEFINE(index, &bq274xx_gauge_init, \ + SENSOR_DEVICE_DT_INST_DEFINE(index, &gauge_init, \ PM_BQ274XX_DT_INST_GET(index), \ &bq274xx_driver_##index, \ &bq274xx_config_##index, POST_KERNEL, \ diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 3fba419d4867..c9bd05a141ea 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(bq274xx, CONFIG_SENSOR_LOG_LEVEL); -static void bq274xx_handle_interrupts(const struct device *dev) +static void handle_interrupts(const struct device *dev) { struct bq274xx_data *data = dev->data; @@ -31,25 +31,25 @@ static void bq274xx_handle_interrupts(const struct device *dev) static K_KERNEL_STACK_DEFINE(bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE); static struct k_thread bq274xx_thread; -static void bq274xx_thread_main(struct bq274xx_data *data) +static void thread_main(struct bq274xx_data *data) { while (1) { k_sem_take(&data->sem, K_FOREVER); - bq274xx_handle_interrupts(data->dev); + handle_interrupts(data->dev); } } #endif #ifdef CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD -static void bq274xx_work_handler(struct k_work *work) +static void work_handler(struct k_work *work) { struct bq274xx_data *data = CONTAINER_OF(work, struct bq274xx_data, work); - bq274xx_handle_interrupts(data->dev); + handle_interrupts(data->dev); } #endif -static void bq274xx_ready_callback_handler(const struct device *port, +static void ready_callback_handler(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { @@ -78,12 +78,12 @@ int bq274xx_trigger_mode_init(const struct device *dev) k_thread_create(&bq274xx_thread, bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE, - (k_thread_entry_t)bq274xx_thread_main, + (k_thread_entry_t)thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_BQ274XX_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD) - k_work_init(&data->work, bq274xx_work_handler); + k_work_init(&data->work, work_handler); #endif ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); @@ -92,7 +92,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) return ret; } gpio_init_callback(&data->ready_callback, - bq274xx_ready_callback_handler, + ready_callback_handler, BIT(config->int_gpios.pin)); return 0; From 845d880773955161ac31b0d41f388dcb2b2a5f4b Mon Sep 17 00:00:00 2001 From: Oleh Lozynskyy Date: Mon, 27 Mar 2023 18:23:25 +0200 Subject: [PATCH 0387/2042] drivers: sensor: bq274xx: shorten macro names Shorten lines lengths. Signed-off-by: Oleh Lozynskyy --- drivers/sensor/bq274xx/bq274xx.c | 124 +++++++++++++++---------------- drivers/sensor/bq274xx/bq274xx.h | 112 ++++++++++++++-------------- 2 files changed, 118 insertions(+), 118 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 46592fb19d45..30f1d3ed023c 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); static int gauge_configure(const struct device *dev); -static int command_reg_read(const struct device *dev, uint8_t reg_addr, +static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { const struct bq274xx_config *config = dev->config; @@ -47,14 +47,14 @@ static int command_reg_read(const struct device *dev, uint8_t reg_addr, return 0; } -static int control_reg_write(const struct device *dev, +static int ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; int ret = 0; - reg_addr = BQ274XX_COMMAND_CONTROL_LOW; + reg_addr = BQ274XX_CMD_CONTROL_LOW; i2c_data = (uint8_t)((subcommand)&0x00FF); ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, @@ -66,7 +66,7 @@ static int control_reg_write(const struct device *dev, k_msleep(BQ274XX_SUBCLASS_DELAY); - reg_addr = BQ274XX_COMMAND_CONTROL_HIGH; + reg_addr = BQ274XX_CMD_CONTROL_HIGH; i2c_data = (uint8_t)((subcommand >> 8) & 0x00FF); ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, @@ -79,7 +79,7 @@ static int control_reg_write(const struct device *dev, return 0; } -static int command_reg_write(const struct device *dev, uint8_t command, +static int cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data) { const struct bq274xx_config *config = dev->config; @@ -106,7 +106,7 @@ static int read_data_block(const struct device *dev, uint8_t offset, uint8_t i2c_data; int ret = 0; - i2c_data = BQ274XX_EXTENDED_BLOCKDATA_START + offset; + i2c_data = BQ274XX_EXT_BLKDAT_START + offset; ret = i2c_burst_read_dt(&config->i2c, i2c_data, data, bytes); @@ -125,13 +125,13 @@ static int get_device_type(const struct device *dev, uint16_t *val) int ret; ret = - control_reg_write(dev, BQ274XX_CONTROL_DEVICE_TYPE); + ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); if (ret < 0) { LOG_ERR("Unable to write control register"); return -EIO; } - ret = command_reg_read(dev, BQ274XX_COMMAND_CONTROL_LOW, + ret = cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); if (ret < 0) { @@ -241,8 +241,8 @@ static int sample_fetch(const struct device *dev, switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - ret = command_reg_read( - dev, BQ274XX_COMMAND_VOLTAGE, &data->voltage); + ret = cmd_reg_read( + dev, BQ274XX_CMD_VOLTAGE, &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; @@ -250,8 +250,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - ret = command_reg_read(dev, - BQ274XX_COMMAND_AVG_CURRENT, + ret = cmd_reg_read(dev, + BQ274XX_CMD_AVG_CURRENT, &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); @@ -260,8 +260,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_TEMP: - ret = command_reg_read( - dev, BQ274XX_COMMAND_INT_TEMP, + ret = cmd_reg_read( + dev, BQ274XX_CMD_INT_TEMP, &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); @@ -270,8 +270,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - ret = command_reg_read(dev, - BQ274XX_COMMAND_STDBY_CURRENT, + ret = cmd_reg_read(dev, + BQ274XX_CMD_STDBY_CURRENT, &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); @@ -280,8 +280,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - ret = command_reg_read(dev, - BQ274XX_COMMAND_MAX_CURRENT, + ret = cmd_reg_read(dev, + BQ274XX_CMD_MAX_CURRENT, &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); @@ -290,7 +290,7 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - ret = command_reg_read(dev, BQ274XX_COMMAND_SOC, + ret = cmd_reg_read(dev, BQ274XX_CMD_SOC, &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); @@ -299,8 +299,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - ret = command_reg_read( - dev, BQ274XX_COMMAND_FULL_CAPACITY, + ret = cmd_reg_read( + dev, BQ274XX_CMD_FULL_CAPACITY, &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); @@ -309,8 +309,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - ret = command_reg_read( - dev, BQ274XX_COMMAND_REM_CAPACITY, + ret = cmd_reg_read( + dev, BQ274XX_CMD_REM_CAPACITY, &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); @@ -319,8 +319,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - ret = command_reg_read(dev, - BQ274XX_COMMAND_NOM_CAPACITY, + ret = cmd_reg_read(dev, + BQ274XX_CMD_NOM_CAPACITY, &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); @@ -330,8 +330,8 @@ static int sample_fetch(const struct device *dev, case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: ret = - command_reg_read(dev, - BQ274XX_COMMAND_AVAIL_CAPACITY, + cmd_reg_read(dev, + BQ274XX_CMD_AVAIL_CAPACITY, &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); @@ -340,8 +340,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_POWER: - ret = command_reg_read(dev, - BQ274XX_COMMAND_AVG_POWER, + ret = cmd_reg_read(dev, + BQ274XX_CMD_AVG_POWER, &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); @@ -350,7 +350,7 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - ret = command_reg_read(dev, BQ274XX_COMMAND_SOH, + ret = cmd_reg_read(dev, BQ274XX_CMD_SOH, &data->state_of_health); data->state_of_health = (data->state_of_health) & 0x00FF; @@ -435,21 +435,21 @@ static int gauge_configure(const struct device *dev) (uint16_t)config->design_capacity / (0.1 * config->taper_current); /** Unseal the battery control register **/ - ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } - ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } /* Send CFG_UPDATE */ - ret = control_reg_write(dev, - BQ274XX_CONTROL_SET_CFGUPDATE); + ret = ctrl_reg_write(dev, + BQ274XX_CTRL_SET_CFGUPDATE); if (ret < 0) { LOG_ERR("Unable to set CFGUpdate"); return -EIO; @@ -457,8 +457,8 @@ static int gauge_configure(const struct device *dev) /** Step to place the Gauge into CONFIG UPDATE Mode **/ do { - ret = command_reg_read( - dev, BQ274XX_COMMAND_FLAGS, &flags); + ret = cmd_reg_read( + dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -470,15 +470,15 @@ static int gauge_configure(const struct device *dev) } while (!(flags & 0x0010)); - ret = command_reg_write(dev, - BQ274XX_EXTENDED_DATA_CONTROL, 0x00); + ret = cmd_reg_write(dev, + BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { LOG_ERR("Failed to enable block data memory"); return -EIO; } /* Access State subclass */ - ret = command_reg_write(dev, BQ274XX_EXTENDED_DATA_CLASS, + ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); if (ret < 0) { LOG_ERR("Failed to update state subclass"); @@ -486,7 +486,7 @@ static int gauge_configure(const struct device *dev) } /* Write the block offset */ - ret = command_reg_write(dev, BQ274XX_EXTENDED_DATA_BLOCK, + ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); if (ret < 0) { LOG_ERR("Failed to update block offset"); @@ -511,7 +511,7 @@ static int gauge_configure(const struct device *dev) /* Read the block checksum */ ret = i2c_reg_read_byte_dt(&config->i2c, - BQ274XX_EXTENDED_CHECKSUM, &checksum_old); + BQ274XX_EXT_CHECKSUM, &checksum_old); if (ret < 0) { LOG_ERR("Unable to read block checksum"); return -EIO; @@ -527,7 +527,7 @@ static int gauge_configure(const struct device *dev) taperrate_lsb = taperrate & 0x00FF; ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_HIGH, + BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, designcap_msb); if (ret < 0) { LOG_ERR("Failed to write designCAP MSB"); @@ -535,7 +535,7 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_LOW, + BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, designcap_lsb); if (ret < 0) { LOG_ERR("Failed to write designCAP LSB"); @@ -543,7 +543,7 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_HIGH, + BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, designenergy_msb); if (ret < 0) { LOG_ERR("Failed to write designEnergy MSB"); @@ -551,7 +551,7 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_LOW, + BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, designenergy_lsb); if (ret < 0) { LOG_ERR("Failed to write designEnergy LSB"); @@ -559,14 +559,14 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_HIGH, + BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, terminatevolt_msb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW, + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, terminatevolt_lsb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt LSB"); @@ -574,7 +574,7 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_HIGH, + BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, taperrate_msb); if (ret < 0) { LOG_ERR("Failed to write taperRate MSB"); @@ -582,7 +582,7 @@ static int gauge_configure(const struct device *dev) } ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_LOW, + BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); if (ret < 0) { LOG_ERR("Failed to write taperRate LSB"); @@ -605,7 +605,7 @@ static int gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - ret = command_reg_write(dev, BQ274XX_EXTENDED_CHECKSUM, + ret = cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); if (ret < 0) { LOG_ERR("Failed to update new checksum"); @@ -614,19 +614,19 @@ static int gauge_configure(const struct device *dev) tmp_checksum = 0; ret = i2c_reg_read_byte_dt(&config->i2c, - BQ274XX_EXTENDED_CHECKSUM, &tmp_checksum); + BQ274XX_EXT_CHECKSUM, &tmp_checksum); if (ret < 0) { LOG_ERR("Failed to read checksum"); return -EIO; } - ret = control_reg_write(dev, BQ274XX_CONTROL_BAT_INSERT); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); if (ret < 0) { LOG_ERR("Unable to configure BAT Detect"); return -EIO; } - ret = control_reg_write(dev, BQ274XX_CONTROL_SOFT_RESET); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); if (ret < 0) { LOG_ERR("Failed to soft reset the gauge"); return -EIO; @@ -635,8 +635,8 @@ static int gauge_configure(const struct device *dev) flags = 0; /* Poll Flags */ do { - ret = command_reg_read( - dev, BQ274XX_COMMAND_FLAGS, &flags); + ret = cmd_reg_read( + dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -648,7 +648,7 @@ static int gauge_configure(const struct device *dev) } while (flags & 0x0010); /* Seal the gauge */ - ret = control_reg_write(dev, BQ274XX_CONTROL_SEALED); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return -EIO; @@ -664,32 +664,32 @@ static int enter_shutdown_mode(const struct device *dev) { int ret; - ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = control_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = control_reg_write(dev, - BQ274XX_CONTROL_SHUTDOWN_ENABLE); + ret = ctrl_reg_write(dev, + BQ274XX_CTRL_SHUTDOWN_ENABLE); if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); return ret; } - ret = control_reg_write(dev, BQ274XX_CONTROL_SHUTDOWN); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN); if (ret < 0) { LOG_ERR("Unable to enter shutdown mode"); return ret; } - ret = control_reg_write(dev, BQ274XX_CONTROL_SEALED); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return ret; diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index bd099f04014c..67b312c805f4 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -15,66 +15,66 @@ #define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ /*** Standard Commands ***/ -#define BQ274XX_COMMAND_CONTROL_LOW 0x00 /* Control() low register */ -#define BQ274XX_COMMAND_CONTROL_HIGH 0x01 /* Control() high register */ -#define BQ274XX_COMMAND_TEMP 0x02 /* Temperature() */ -#define BQ274XX_COMMAND_VOLTAGE 0x04 /* Voltage() */ -#define BQ274XX_COMMAND_FLAGS 0x06 /* Flags() */ -#define BQ274XX_COMMAND_NOM_CAPACITY 0x08 /* NominalAvailableCapacity() */ -#define BQ274XX_COMMAND_AVAIL_CAPACITY 0x0A /* FullAvailableCapacity() */ -#define BQ274XX_COMMAND_REM_CAPACITY 0x0C /* RemainingCapacity() */ -#define BQ274XX_COMMAND_FULL_CAPACITY 0x0E /* FullChargeCapacity() */ -#define BQ274XX_COMMAND_AVG_CURRENT 0x10 /* AverageCurrent() */ -#define BQ274XX_COMMAND_STDBY_CURRENT 0x12 /* StandbyCurrent() */ -#define BQ274XX_COMMAND_MAX_CURRENT 0x14 /* MaxLoadCurrent() */ -#define BQ274XX_COMMAND_AVG_POWER 0x18 /* AveragePower() */ -#define BQ274XX_COMMAND_SOC 0x1C /* StateOfCharge() */ -#define BQ274XX_COMMAND_INT_TEMP 0x1E /* InternalTemperature() */ -#define BQ274XX_COMMAND_SOH 0x20 /* StateOfHealth() */ -#define BQ274XX_COMMAND_REM_CAP_UNFL 0x28 /* RemainingCapacityUnfiltered() */ -#define BQ274XX_COMMAND_REM_CAP_FIL 0x2A /* RemainingCapacityFiltered() */ -#define BQ274XX_COMMAND_FULL_CAP_UNFL 0x2C /* FullChargeCapacityUnfiltered() */ -#define BQ274XX_COMMAND_FULL_CAP_FIL 0x2E /* FullChargeCapacityFiltered() */ -#define BQ274XX_COMMAND_SOC_UNFL 0x30 /* StateOfChargeUnfiltered() */ +#define BQ274XX_CMD_CONTROL_LOW 0x00 /* Control() low register */ +#define BQ274XX_CMD_CONTROL_HIGH 0x01 /* Control() high register */ +#define BQ274XX_CMD_TEMP 0x02 /* Temperature() */ +#define BQ274XX_CMD_VOLTAGE 0x04 /* Voltage() */ +#define BQ274XX_CMD_FLAGS 0x06 /* Flags() */ +#define BQ274XX_CMD_NOM_CAPACITY 0x08 /* NominalAvailableCapacity() */ +#define BQ274XX_CMD_AVAIL_CAPACITY 0x0A /* FullAvailableCapacity() */ +#define BQ274XX_CMD_REM_CAPACITY 0x0C /* RemainingCapacity() */ +#define BQ274XX_CMD_FULL_CAPACITY 0x0E /* FullChargeCapacity() */ +#define BQ274XX_CMD_AVG_CURRENT 0x10 /* AverageCurrent() */ +#define BQ274XX_CMD_STDBY_CURRENT 0x12 /* StandbyCurrent() */ +#define BQ274XX_CMD_MAX_CURRENT 0x14 /* MaxLoadCurrent() */ +#define BQ274XX_CMD_AVG_POWER 0x18 /* AveragePower() */ +#define BQ274XX_CMD_SOC 0x1C /* StateOfCharge() */ +#define BQ274XX_CMD_INT_TEMP 0x1E /* InternalTemperature() */ +#define BQ274XX_CMD_SOH 0x20 /* StateOfHealth() */ +#define BQ274XX_CMD_REM_CAP_UNFL 0x28 /* RemainingCapacityUnfiltered() */ +#define BQ274XX_CMD_REM_CAP_FIL 0x2A /* RemainingCapacityFiltered() */ +#define BQ274XX_CMD_FULL_CAP_UNFL 0x2C /* FullChargeCapacityUnfiltered() */ +#define BQ274XX_CMD_FULL_CAP_FIL 0x2E /* FullChargeCapacityFiltered() */ +#define BQ274XX_CMD_SOC_UNFL 0x30 /* StateOfChargeUnfiltered() */ /*** Control Sub-Commands ***/ -#define BQ274XX_CONTROL_STATUS 0x0000 -#define BQ274XX_CONTROL_DEVICE_TYPE 0x0001 -#define BQ274XX_CONTROL_FW_VERSION 0x0002 -#define BQ274XX_CONTROL_DM_CODE 0x0004 -#define BQ274XX_CONTROL_PREV_MACWRITE 0x0007 -#define BQ274XX_CONTROL_CHEM_ID 0x0008 -#define BQ274XX_CONTROL_BAT_INSERT 0x000C -#define BQ274XX_CONTROL_BAT_REMOVE 0x000D -#define BQ274XX_CONTROL_SET_HIBERNATE 0x0011 -#define BQ274XX_CONTROL_CLEAR_HIBERNATE 0x0012 -#define BQ274XX_CONTROL_SET_CFGUPDATE 0x0013 -#define BQ274XX_CONTROL_SHUTDOWN_ENABLE 0x001B -#define BQ274XX_CONTROL_SHUTDOWN 0x001C -#define BQ274XX_CONTROL_SEALED 0x0020 -#define BQ274XX_CONTROL_PULSE_SOC_INT 0x0023 -#define BQ274XX_CONTROL_RESET 0x0041 -#define BQ274XX_CONTROL_SOFT_RESET 0x0042 -#define BQ274XX_CONTROL_EXIT_CFGUPDATE 0x0043 -#define BQ274XX_CONTROL_EXIT_RESIM 0x0044 +#define BQ274XX_CTRL_STATUS 0x0000 +#define BQ274XX_CTRL_DEVICE_TYPE 0x0001 +#define BQ274XX_CTRL_FW_VERSION 0x0002 +#define BQ274XX_CTRL_DM_CODE 0x0004 +#define BQ274XX_CTRL_PREV_MACWRITE 0x0007 +#define BQ274XX_CTRL_CHEM_ID 0x0008 +#define BQ274XX_CTRL_BAT_INSERT 0x000C +#define BQ274XX_CTRL_BAT_REMOVE 0x000D +#define BQ274XX_CTRL_SET_HIBERNATE 0x0011 +#define BQ274XX_CTRL_CLEAR_HIBERNATE 0x0012 +#define BQ274XX_CTRL_SET_CFGUPDATE 0x0013 +#define BQ274XX_CTRL_SHUTDOWN_ENABLE 0x001B +#define BQ274XX_CTRL_SHUTDOWN 0x001C +#define BQ274XX_CTRL_SEALED 0x0020 +#define BQ274XX_CTRL_PULSE_SOC_INT 0x0023 +#define BQ274XX_CTRL_RESET 0x0041 +#define BQ274XX_CTRL_SOFT_RESET 0x0042 +#define BQ274XX_CTRL_EXIT_CFGUPDATE 0x0043 +#define BQ274XX_CTRL_EXIT_RESIM 0x0044 /*** Extended Data Commands ***/ -#define BQ274XX_EXTENDED_OPCONFIG 0x3A /* OpConfig() */ -#define BQ274XX_EXTENDED_CAPACITY 0x3C /* DesignCapacity() */ -#define BQ274XX_EXTENDED_DATA_CLASS 0x3E /* DataClass() */ -#define BQ274XX_EXTENDED_DATA_BLOCK 0x3F /* DataBlock() */ -#define BQ274XX_EXTENDED_BLOCKDATA_START 0x40 /* BlockData_start() */ -#define BQ274XX_EXTENDED_BLOCKDATA_END 0x5F /* BlockData_end() */ -#define BQ274XX_EXTENDED_CHECKSUM 0x60 /* BlockDataCheckSum() */ -#define BQ274XX_EXTENDED_DATA_CONTROL 0x61 /* BlockDataControl() */ -#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_HIGH 0x4A /* BlockData */ -#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_LOW 0x4B -#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_HIGH 0x4C -#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_LOW 0x4D -#define BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_HIGH 0x50 -#define BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW 0x51 -#define BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_HIGH 0x5B -#define BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_LOW 0x5C +#define BQ274XX_EXT_OPCONFIG 0x3A /* OpConfig() */ +#define BQ274XX_EXT_CAPACITY 0x3C /* DesignCapacity() */ +#define BQ274XX_EXT_DATA_CLASS 0x3E /* DataClass() */ +#define BQ274XX_EXT_DATA_BLOCK 0x3F /* DataBlock() */ +#define BQ274XX_EXT_BLKDAT_START 0x40 /* BlockData_start() */ +#define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ +#define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ +#define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ +#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH 0x4A /* BlockData */ +#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW 0x4B +#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH 0x4C +#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW 0x4D +#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH 0x50 +#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW 0x51 +#define BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH 0x5B +#define BQ274XX_EXT_BLKDAT_TAPERRATE_LOW 0x5C #define BQ274XX_DELAY 1000 From 264d3f0b1aabcf4fb93770ed93078d4e294e6463 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Wed, 7 Jun 2023 00:21:34 +1000 Subject: [PATCH 0388/2042] drivers: sensor: bq274xx: apply clang format Fix unnecessarily broken lines. Also make logging sentences more concise. Signed-off-by: Nick Ward --- drivers/sensor/bq274xx/bq274xx.c | 192 +++++++++-------------- drivers/sensor/bq274xx/bq274xx.h | 106 ++++++------- drivers/sensor/bq274xx/bq274xx_trigger.c | 30 ++-- 3 files changed, 142 insertions(+), 186 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 30f1d3ed023c..5342fcb245c4 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -20,23 +20,24 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); -#define BQ274XX_SUBCLASS_DELAY 5 /* subclass 64 & 82 needs 5ms delay */ +/* subclass 64 & 82 needs 5ms delay */ +#define BQ274XX_SUBCLASS_DELAY 5 + /* Time to set pin in order to exit shutdown mode */ -#define PIN_DELAY_TIME 1U +#define PIN_DELAY_TIME 1U + /* Time it takes device to initialize before doing any configuration */ -#define INIT_TIME 100U +#define INIT_TIME 100U static int gauge_configure(const struct device *dev); -static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, - int16_t *val) +static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data[2]; int ret; - ret = i2c_burst_read_dt(&config->i2c, reg_addr, - i2c_data, 2); + ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, 2); if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; @@ -47,8 +48,7 @@ static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, return 0; } -static int ctrl_reg_write(const struct device *dev, - uint16_t subcommand) +static int ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; @@ -57,8 +57,7 @@ static int ctrl_reg_write(const struct device *dev, reg_addr = BQ274XX_CMD_CONTROL_LOW; i2c_data = (uint8_t)((subcommand)&0x00FF); - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, - i2c_data); + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); if (ret < 0) { LOG_ERR("Failed to write into control low register"); return -EIO; @@ -69,8 +68,7 @@ static int ctrl_reg_write(const struct device *dev, reg_addr = BQ274XX_CMD_CONTROL_HIGH; i2c_data = (uint8_t)((subcommand >> 8) & 0x00FF); - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, - i2c_data); + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); if (ret < 0) { LOG_ERR("Failed to write into control high register"); return -EIO; @@ -79,8 +77,7 @@ static int ctrl_reg_write(const struct device *dev, return 0; } -static int cmd_reg_write(const struct device *dev, uint8_t command, - uint8_t data) +static int cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; @@ -89,8 +86,7 @@ static int cmd_reg_write(const struct device *dev, uint8_t command, reg_addr = command; i2c_data = data; - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, - i2c_data); + ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); if (ret < 0) { LOG_ERR("Failed to write into control register"); return -EIO; @@ -100,7 +96,7 @@ static int cmd_reg_write(const struct device *dev, uint8_t command, } static int read_data_block(const struct device *dev, uint8_t offset, - uint8_t *data, uint8_t bytes) + uint8_t *data, uint8_t bytes) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data; @@ -108,8 +104,7 @@ static int read_data_block(const struct device *dev, uint8_t offset, i2c_data = BQ274XX_EXT_BLKDAT_START + offset; - ret = i2c_burst_read_dt(&config->i2c, i2c_data, - data, bytes); + ret = i2c_burst_read_dt(&config->i2c, i2c_data, data, bytes); if (ret < 0) { LOG_ERR("Failed to read block"); return -EIO; @@ -124,15 +119,13 @@ static int get_device_type(const struct device *dev, uint16_t *val) { int ret; - ret = - ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); if (ret < 0) { LOG_ERR("Unable to write control register"); return -EIO; } - ret = cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, - val); + ret = cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); if (ret < 0) { LOG_ERR("Unable to read register"); @@ -147,9 +140,8 @@ static int get_device_type(const struct device *dev, uint16_t *val) * * @return -ENOTSUP for unsupported channels */ -static int channel_get(const struct device *dev, - enum sensor_channel chan, - struct sensor_value *val) +static int channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { struct bq274xx_data *data = dev->data; float int_temp; @@ -199,8 +191,7 @@ static int channel_get(const struct device *dev, case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: val->val1 = (data->remaining_charge_capacity / 1000); - val->val2 = - ((data->remaining_charge_capacity % 1000) * 1000U); + val->val2 = ((data->remaining_charge_capacity % 1000) * 1000U); break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: @@ -225,8 +216,7 @@ static int channel_get(const struct device *dev, return 0; } -static int sample_fetch(const struct device *dev, - enum sensor_channel chan) +static int sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; int ret = 0; @@ -241,8 +231,7 @@ static int sample_fetch(const struct device *dev, switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - ret = cmd_reg_read( - dev, BQ274XX_CMD_VOLTAGE, &data->voltage); + ret = cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; @@ -250,9 +239,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - ret = cmd_reg_read(dev, - BQ274XX_CMD_AVG_CURRENT, - &data->avg_current); + ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, + &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; @@ -260,9 +248,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_TEMP: - ret = cmd_reg_read( - dev, BQ274XX_CMD_INT_TEMP, - &data->internal_temperature); + ret = cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, + &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; @@ -270,9 +257,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - ret = cmd_reg_read(dev, - BQ274XX_CMD_STDBY_CURRENT, - &data->stdby_current); + ret = cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, + &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; @@ -280,9 +266,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - ret = cmd_reg_read(dev, - BQ274XX_CMD_MAX_CURRENT, - &data->max_load_current); + ret = cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, + &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; @@ -290,8 +275,7 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOC, - &data->state_of_charge); + ret = cmd_reg_read(dev, BQ274XX_CMD_SOC, &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; @@ -299,9 +283,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - ret = cmd_reg_read( - dev, BQ274XX_CMD_FULL_CAPACITY, - &data->full_charge_capacity); + ret = cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, + &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); return -EIO; @@ -309,9 +292,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - ret = cmd_reg_read( - dev, BQ274XX_CMD_REM_CAPACITY, - &data->remaining_charge_capacity); + ret = cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, + &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); return -EIO; @@ -319,9 +301,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - ret = cmd_reg_read(dev, - BQ274XX_CMD_NOM_CAPACITY, - &data->nom_avail_capacity); + ret = cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, + &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); return -EIO; @@ -329,10 +310,8 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - ret = - cmd_reg_read(dev, - BQ274XX_CMD_AVAIL_CAPACITY, - &data->full_avail_capacity); + ret = cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, + &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); return -EIO; @@ -340,9 +319,7 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_AVG_POWER: - ret = cmd_reg_read(dev, - BQ274XX_CMD_AVG_POWER, - &data->avg_power); + ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; @@ -350,8 +327,7 @@ static int sample_fetch(const struct device *dev, break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOH, - &data->state_of_health); + ret = cmd_reg_read(dev, BQ274XX_CMD_SOH, &data->state_of_health); data->state_of_health = (data->state_of_health) & 0x00FF; @@ -426,13 +402,11 @@ static int gauge_configure(const struct device *dev) uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, - terminatevolt_msb, terminatevolt_lsb, taperrate_msb, - taperrate_lsb; + terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; uint8_t block[32]; designenergy_mwh = (uint16_t)3.7 * config->design_capacity; - taperrate = - (uint16_t)config->design_capacity / (0.1 * config->taper_current); + taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); /** Unseal the battery control register **/ ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); @@ -448,8 +422,7 @@ static int gauge_configure(const struct device *dev) } /* Send CFG_UPDATE */ - ret = ctrl_reg_write(dev, - BQ274XX_CTRL_SET_CFGUPDATE); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); if (ret < 0) { LOG_ERR("Unable to set CFGUpdate"); return -EIO; @@ -457,8 +430,7 @@ static int gauge_configure(const struct device *dev) /** Step to place the Gauge into CONFIG UPDATE Mode **/ do { - ret = cmd_reg_read( - dev, BQ274XX_CMD_FLAGS, &flags); + ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -470,24 +442,21 @@ static int gauge_configure(const struct device *dev) } while (!(flags & 0x0010)); - ret = cmd_reg_write(dev, - BQ274XX_EXT_DATA_CONTROL, 0x00); + ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { LOG_ERR("Failed to enable block data memory"); return -EIO; } /* Access State subclass */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, - 0x52); + ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); if (ret < 0) { LOG_ERR("Failed to update state subclass"); return -EIO; } /* Write the block offset */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, - 0x00); + ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); if (ret < 0) { LOG_ERR("Failed to update block offset"); return -EIO; @@ -510,8 +479,7 @@ static int gauge_configure(const struct device *dev) tmp_checksum = 255 - tmp_checksum; /* Read the block checksum */ - ret = i2c_reg_read_byte_dt(&config->i2c, - BQ274XX_EXT_CHECKSUM, &checksum_old); + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &checksum_old); if (ret < 0) { LOG_ERR("Unable to read block checksum"); return -EIO; @@ -526,64 +494,56 @@ static int gauge_configure(const struct device *dev) taperrate_msb = taperrate >> 8; taperrate_lsb = taperrate & 0x00FF; - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, - designcap_msb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, + designcap_msb); if (ret < 0) { LOG_ERR("Failed to write designCAP MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, - designcap_lsb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, + designcap_lsb); if (ret < 0) { LOG_ERR("Failed to write designCAP LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, - designenergy_msb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, + designenergy_msb); if (ret < 0) { LOG_ERR("Failed to write designEnergy MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, - designenergy_lsb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, + designenergy_lsb); if (ret < 0) { LOG_ERR("Failed to write designEnergy LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, - terminatevolt_msb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, + terminatevolt_msb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt MSB"); return -EIO; } ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, - terminatevolt_lsb); + terminatevolt_lsb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, - taperrate_msb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, + taperrate_msb); if (ret < 0) { LOG_ERR("Failed to write taperRate MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, - taperrate_lsb); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); if (ret < 0) { LOG_ERR("Failed to write taperRate LSB"); return -EIO; @@ -605,16 +565,14 @@ static int gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - ret = cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, - checksum_new); + ret = cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); if (ret < 0) { LOG_ERR("Failed to update new checksum"); return -EIO; } tmp_checksum = 0; - ret = i2c_reg_read_byte_dt(&config->i2c, - BQ274XX_EXT_CHECKSUM, &tmp_checksum); + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &tmp_checksum); if (ret < 0) { LOG_ERR("Failed to read checksum"); return -EIO; @@ -635,8 +593,7 @@ static int gauge_configure(const struct device *dev) flags = 0; /* Poll Flags */ do { - ret = cmd_reg_read( - dev, BQ274XX_CMD_FLAGS, &flags); + ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -676,8 +633,7 @@ static int enter_shutdown_mode(const struct device *dev) return ret; } - ret = ctrl_reg_write(dev, - BQ274XX_CTRL_SHUTDOWN_ENABLE); + ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN_ENABLE); if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); return ret; @@ -703,8 +659,7 @@ static int exit_shutdown_mode(const struct device *dev) const struct bq274xx_config *const config = dev->config; int ret = 0; - ret = gpio_pin_configure_dt(&config->int_gpios, - GPIO_OUTPUT | GPIO_OPEN_DRAIN); + ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_OUTPUT | GPIO_OPEN_DRAIN); if (ret < 0) { LOG_ERR("Unable to configure interrupt pin to output and open drain"); return ret; @@ -737,8 +692,7 @@ static int exit_shutdown_mode(const struct device *dev) return 0; } -static int pm_action(const struct device *dev, - enum pm_device_action action) +static int pm_action(const struct device *dev, enum pm_device_action action) { int ret; @@ -767,9 +721,9 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { }; #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) -#define BQ274XX_INT_CFG(index) \ +#define BQ274XX_INT_CFG(index) \ .int_gpios = GPIO_DT_SPEC_INST_GET(index, int_gpios), -#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) \ +#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) \ PM_DEVICE_DT_INST_DEFINE(index, pm_action) #define PM_BQ274XX_DT_INST_GET(index) PM_DEVICE_DT_INST_GET(index) #else @@ -791,9 +745,9 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ - PM_BQ274XX_DT_INST_DEFINE(index, pm_action); \ + PM_BQ274XX_DT_INST_DEFINE(index, pm_action); \ \ - SENSOR_DEVICE_DT_INST_DEFINE(index, &gauge_init, \ + SENSOR_DEVICE_DT_INST_DEFINE(index, &gauge_init, \ PM_BQ274XX_DT_INST_GET(index), \ &bq274xx_driver_##index, \ &bq274xx_config_##index, POST_KERNEL, \ diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index 67b312c805f4..96bb9e83edf8 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -12,69 +12,69 @@ /*** General Constant ***/ #define BQ274XX_UNSEAL_KEY 0x8000 /* Secret code to unseal the BQ27441-G1A */ -#define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ +#define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ /*** Standard Commands ***/ -#define BQ274XX_CMD_CONTROL_LOW 0x00 /* Control() low register */ -#define BQ274XX_CMD_CONTROL_HIGH 0x01 /* Control() high register */ -#define BQ274XX_CMD_TEMP 0x02 /* Temperature() */ -#define BQ274XX_CMD_VOLTAGE 0x04 /* Voltage() */ -#define BQ274XX_CMD_FLAGS 0x06 /* Flags() */ -#define BQ274XX_CMD_NOM_CAPACITY 0x08 /* NominalAvailableCapacity() */ +#define BQ274XX_CMD_CONTROL_LOW 0x00 /* Control() low register */ +#define BQ274XX_CMD_CONTROL_HIGH 0x01 /* Control() high register */ +#define BQ274XX_CMD_TEMP 0x02 /* Temperature() */ +#define BQ274XX_CMD_VOLTAGE 0x04 /* Voltage() */ +#define BQ274XX_CMD_FLAGS 0x06 /* Flags() */ +#define BQ274XX_CMD_NOM_CAPACITY 0x08 /* NominalAvailableCapacity() */ #define BQ274XX_CMD_AVAIL_CAPACITY 0x0A /* FullAvailableCapacity() */ -#define BQ274XX_CMD_REM_CAPACITY 0x0C /* RemainingCapacity() */ -#define BQ274XX_CMD_FULL_CAPACITY 0x0E /* FullChargeCapacity() */ -#define BQ274XX_CMD_AVG_CURRENT 0x10 /* AverageCurrent() */ -#define BQ274XX_CMD_STDBY_CURRENT 0x12 /* StandbyCurrent() */ -#define BQ274XX_CMD_MAX_CURRENT 0x14 /* MaxLoadCurrent() */ -#define BQ274XX_CMD_AVG_POWER 0x18 /* AveragePower() */ -#define BQ274XX_CMD_SOC 0x1C /* StateOfCharge() */ -#define BQ274XX_CMD_INT_TEMP 0x1E /* InternalTemperature() */ -#define BQ274XX_CMD_SOH 0x20 /* StateOfHealth() */ -#define BQ274XX_CMD_REM_CAP_UNFL 0x28 /* RemainingCapacityUnfiltered() */ -#define BQ274XX_CMD_REM_CAP_FIL 0x2A /* RemainingCapacityFiltered() */ -#define BQ274XX_CMD_FULL_CAP_UNFL 0x2C /* FullChargeCapacityUnfiltered() */ -#define BQ274XX_CMD_FULL_CAP_FIL 0x2E /* FullChargeCapacityFiltered() */ -#define BQ274XX_CMD_SOC_UNFL 0x30 /* StateOfChargeUnfiltered() */ +#define BQ274XX_CMD_REM_CAPACITY 0x0C /* RemainingCapacity() */ +#define BQ274XX_CMD_FULL_CAPACITY 0x0E /* FullChargeCapacity() */ +#define BQ274XX_CMD_AVG_CURRENT 0x10 /* AverageCurrent() */ +#define BQ274XX_CMD_STDBY_CURRENT 0x12 /* StandbyCurrent() */ +#define BQ274XX_CMD_MAX_CURRENT 0x14 /* MaxLoadCurrent() */ +#define BQ274XX_CMD_AVG_POWER 0x18 /* AveragePower() */ +#define BQ274XX_CMD_SOC 0x1C /* StateOfCharge() */ +#define BQ274XX_CMD_INT_TEMP 0x1E /* InternalTemperature() */ +#define BQ274XX_CMD_SOH 0x20 /* StateOfHealth() */ +#define BQ274XX_CMD_REM_CAP_UNFL 0x28 /* RemainingCapacityUnfiltered() */ +#define BQ274XX_CMD_REM_CAP_FIL 0x2A /* RemainingCapacityFiltered() */ +#define BQ274XX_CMD_FULL_CAP_UNFL 0x2C /* FullChargeCapacityUnfiltered() */ +#define BQ274XX_CMD_FULL_CAP_FIL 0x2E /* FullChargeCapacityFiltered() */ +#define BQ274XX_CMD_SOC_UNFL 0x30 /* StateOfChargeUnfiltered() */ /*** Control Sub-Commands ***/ -#define BQ274XX_CTRL_STATUS 0x0000 -#define BQ274XX_CTRL_DEVICE_TYPE 0x0001 -#define BQ274XX_CTRL_FW_VERSION 0x0002 -#define BQ274XX_CTRL_DM_CODE 0x0004 -#define BQ274XX_CTRL_PREV_MACWRITE 0x0007 -#define BQ274XX_CTRL_CHEM_ID 0x0008 -#define BQ274XX_CTRL_BAT_INSERT 0x000C -#define BQ274XX_CTRL_BAT_REMOVE 0x000D -#define BQ274XX_CTRL_SET_HIBERNATE 0x0011 +#define BQ274XX_CTRL_STATUS 0x0000 +#define BQ274XX_CTRL_DEVICE_TYPE 0x0001 +#define BQ274XX_CTRL_FW_VERSION 0x0002 +#define BQ274XX_CTRL_DM_CODE 0x0004 +#define BQ274XX_CTRL_PREV_MACWRITE 0x0007 +#define BQ274XX_CTRL_CHEM_ID 0x0008 +#define BQ274XX_CTRL_BAT_INSERT 0x000C +#define BQ274XX_CTRL_BAT_REMOVE 0x000D +#define BQ274XX_CTRL_SET_HIBERNATE 0x0011 #define BQ274XX_CTRL_CLEAR_HIBERNATE 0x0012 -#define BQ274XX_CTRL_SET_CFGUPDATE 0x0013 +#define BQ274XX_CTRL_SET_CFGUPDATE 0x0013 #define BQ274XX_CTRL_SHUTDOWN_ENABLE 0x001B -#define BQ274XX_CTRL_SHUTDOWN 0x001C -#define BQ274XX_CTRL_SEALED 0x0020 -#define BQ274XX_CTRL_PULSE_SOC_INT 0x0023 -#define BQ274XX_CTRL_RESET 0x0041 -#define BQ274XX_CTRL_SOFT_RESET 0x0042 -#define BQ274XX_CTRL_EXIT_CFGUPDATE 0x0043 -#define BQ274XX_CTRL_EXIT_RESIM 0x0044 +#define BQ274XX_CTRL_SHUTDOWN 0x001C +#define BQ274XX_CTRL_SEALED 0x0020 +#define BQ274XX_CTRL_PULSE_SOC_INT 0x0023 +#define BQ274XX_CTRL_RESET 0x0041 +#define BQ274XX_CTRL_SOFT_RESET 0x0042 +#define BQ274XX_CTRL_EXIT_CFGUPDATE 0x0043 +#define BQ274XX_CTRL_EXIT_RESIM 0x0044 /*** Extended Data Commands ***/ -#define BQ274XX_EXT_OPCONFIG 0x3A /* OpConfig() */ -#define BQ274XX_EXT_CAPACITY 0x3C /* DesignCapacity() */ -#define BQ274XX_EXT_DATA_CLASS 0x3E /* DataClass() */ -#define BQ274XX_EXT_DATA_BLOCK 0x3F /* DataBlock() */ -#define BQ274XX_EXT_BLKDAT_START 0x40 /* BlockData_start() */ -#define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ -#define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ -#define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH 0x4A /* BlockData */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW 0x4B -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH 0x4C -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW 0x4D +#define BQ274XX_EXT_OPCONFIG 0x3A /* OpConfig() */ +#define BQ274XX_EXT_CAPACITY 0x3C /* DesignCapacity() */ +#define BQ274XX_EXT_DATA_CLASS 0x3E /* DataClass() */ +#define BQ274XX_EXT_DATA_BLOCK 0x3F /* DataBlock() */ +#define BQ274XX_EXT_BLKDAT_START 0x40 /* BlockData_start() */ +#define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ +#define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ +#define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ +#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH 0x4A /* BlockData */ +#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW 0x4B +#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH 0x4C +#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW 0x4D #define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH 0x50 -#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW 0x51 -#define BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH 0x5B -#define BQ274XX_EXT_BLKDAT_TAPERRATE_LOW 0x5C +#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW 0x51 +#define BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH 0x5B +#define BQ274XX_EXT_BLKDAT_TAPERRATE_LOW 0x5C #define BQ274XX_DELAY 1000 diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index c9bd05a141ea..658fef2f72cc 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -49,11 +49,11 @@ static void work_handler(struct k_work *work) } #endif -static void ready_callback_handler(const struct device *port, - struct gpio_callback *cb, - gpio_port_pins_t pins) +static void ready_callback_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) { - struct bq274xx_data *data = CONTAINER_OF(cb, struct bq274xx_data, ready_callback); + struct bq274xx_data *data = CONTAINER_OF(cb, struct bq274xx_data, + ready_callback); ARG_UNUSED(port); ARG_UNUSED(pins); @@ -88,7 +88,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); if (ret < 0) { - LOG_ERR("Unable to configure interrupt pin to input"); + LOG_ERR("Unable to configure interrupt pin"); return ret; } gpio_init_callback(&data->ready_callback, @@ -120,7 +120,7 @@ int bq274xx_trigger_set(const struct device *dev, } if (!device_is_ready(config->int_gpios.port)) { - LOG_ERR("GPIO device pointer is not ready to be used"); + LOG_ERR("GPIO device is not ready"); return -ENODEV; } @@ -130,32 +130,34 @@ int bq274xx_trigger_set(const struct device *dev, if (handler) { ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); if (ret < 0) { - LOG_ERR("Unable to configure interrupt pin to input (%d)", ret); + LOG_ERR("Unable to configure interrupt pin: %d", ret); return ret; } - ret = gpio_add_callback(config->int_gpios.port, &data->ready_callback); + ret = gpio_add_callback(config->int_gpios.port, + &data->ready_callback); if (ret < 0) { - LOG_ERR("Unable to add interrupt callback (%d)", ret); + LOG_ERR("Unable to add interrupt callback: %d", ret); return ret; } ret = gpio_pin_interrupt_configure_dt(&config->int_gpios, - GPIO_INT_EDGE_TO_ACTIVE); + GPIO_INT_EDGE_TO_ACTIVE); if (ret < 0) { - LOG_ERR("Unable to configure interrupt (%d)", ret); + LOG_ERR("Unable to configure interrupt: %d", ret); return ret; } } else { - ret = gpio_remove_callback(config->int_gpios.port, &data->ready_callback); + ret = gpio_remove_callback(config->int_gpios.port, + &data->ready_callback); if (ret < 0) { - LOG_ERR("Unable to remove interrupt callback (%d)", ret); + LOG_ERR("Unable to remove interrupt callback: %d", ret); return ret; } ret = gpio_pin_interrupt_configure_dt(&config->int_gpios, GPIO_INT_DISABLE); if (ret < 0) { - LOG_ERR("Unable to configure interrupt (%d)", ret); + LOG_ERR("Unable to disable interrupt: %d", ret); return ret; } } From 49ff2a5add4527b5fc319fd66574dcc55b078a2e Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Tue, 6 Jun 2023 09:08:20 +1000 Subject: [PATCH 0389/2042] drivers: sensor: bmm150: fix soft reset Bit 7 and 1 is 0x82 not 0x81. Signed-off-by: Nick Ward --- drivers/sensor/bmm150/bmm150.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/bmm150/bmm150.h b/drivers/sensor/bmm150/bmm150.h index f96fcb948da6..7e954d7882c8 100644 --- a/drivers/sensor/bmm150/bmm150.h +++ b/drivers/sensor/bmm150/bmm150.h @@ -82,8 +82,8 @@ extern const struct bmm150_bus_io bmm150_bus_io_i2c; #define BMM150_REG_POWER 0x4B #define BMM150_MASK_POWER_CTL BIT(0) -#define BMM150_MASK_SOFT_RESET (BIT(1) | BIT(7)) -#define BMM150_SOFT_RESET 0x81 +#define BMM150_MASK_SOFT_RESET (BIT(7) | BIT(1)) +#define BMM150_SOFT_RESET BMM150_MASK_SOFT_RESET #define BMM150_REG_OPMODE_ODR 0x4C #define BMM150_MASK_OPMODE (BIT(2) | BIT(1)) From ce9eb7a353303520ba22d48b1358606cf1eddc17 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 4 Jun 2023 00:28:38 +1000 Subject: [PATCH 0390/2042] drivers: sensor: bmm150: improve initialisation Update driver with low level power control and OpMode functions to better represent operations used in power mode transition diagram Figure 2 from the datasheet. This also prepares the driver for use of these functions for PM actions. Extend the soft reset at initialisation to a full POR. Add defines for maximum POR time and start up time. Signed-off-by: Nick Ward --- drivers/sensor/bmm150/bmm150.c | 121 ++++++++++++++++++--------------- drivers/sensor/bmm150/bmm150.h | 15 ++-- 2 files changed, 74 insertions(+), 62 deletions(-) diff --git a/drivers/sensor/bmm150/bmm150.c b/drivers/sensor/bmm150/bmm150.c index 697588c3e87c..aa748a0906f5 100644 --- a/drivers/sensor/bmm150/bmm150.c +++ b/drivers/sensor/bmm150/bmm150.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2023 FTP Technologies * * SPDX-License-Identifier: Apache-2.0 */ @@ -80,41 +81,22 @@ int bmm150_reg_update_byte(const struct device *dev, uint8_t reg, return ret; } -static int bmm150_set_power_mode(const struct device *dev, - enum bmm150_power_modes mode, - int state) +/* Power control = 'bit' */ +static int bmm150_power_control(const struct device *dev, uint8_t bit) { - switch (mode) { - case BMM150_POWER_MODE_SUSPEND: - if (bmm150_reg_update_byte(dev, - BMM150_REG_POWER, - BMM150_MASK_POWER_CTL, - !state) < 0) { - return -EIO; - } - k_busy_wait(USEC_PER_MSEC * 5U); - - return 0; - case BMM150_POWER_MODE_SLEEP: - return bmm150_reg_update_byte(dev, - BMM150_REG_OPMODE_ODR, - BMM150_MASK_OPMODE, - BMM150_MODE_SLEEP << - BMM150_SHIFT_OPMODE); - break; - case BMM150_POWER_MODE_NORMAL: - return bmm150_reg_update_byte(dev, - BMM150_REG_OPMODE_ODR, - BMM150_MASK_OPMODE, - BMM150_MODE_NORMAL << - BMM150_SHIFT_OPMODE); - break; - } - - return -ENOTSUP; + return bmm150_reg_update_byte(dev, BMM150_REG_POWER, + BMM150_MASK_POWER_CTL, bit); +} +/* OpMode = 'mode' */ +static int bmm150_opmode(const struct device *dev, uint8_t mode) +{ + return bmm150_reg_update_byte(dev, BMM150_REG_OPMODE_ODR, + BMM150_MASK_OPMODE, + mode << BMM150_SHIFT_OPMODE); } + static int bmm150_set_odr(const struct device *dev, uint8_t val) { uint8_t i; @@ -515,33 +497,63 @@ static const struct sensor_driver_api bmm150_api_funcs = { .channel_get = bmm150_channel_get, }; -static int bmm150_init_chip(const struct device *dev) +static int bmm150_full_por(const struct device *dev) { - struct bmm150_data *data = dev->data; - uint8_t chip_id; - struct bmm150_preset preset; + int ret; - /* Soft reset chip */ - if (bmm150_reg_update_byte(dev, BMM150_REG_POWER, BMM150_MASK_SOFT_RESET, - BMM150_SOFT_RESET) < 0) { - LOG_ERR("failed reset chip"); - goto err_poweroff; + /* Ensure we are not in suspend mode so soft reset is not ignored */ + ret = bmm150_power_control(dev, 1); + if (ret != 0) { + LOG_ERR("failed to ensure not in suspend mode: %d", ret); + return ret; } - /* Sleep for 1ms after software reset */ - k_sleep(K_MSEC(1)); + k_sleep(BMM150_START_UP_TIME); - /* Suspend mode to sleep mode */ - if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 0) - < 0) { - LOG_ERR("failed to bring up device from suspend mode"); - return -EIO; + /* Soft reset always brings the device into sleep mode */ + ret = bmm150_reg_update_byte(dev, BMM150_REG_POWER, + BMM150_MASK_SOFT_RESET, + BMM150_SOFT_RESET); + if (ret != 0) { + LOG_ERR("failed soft reset: %d", ret); + return ret; } - /* Sleep for 3ms from suspend to sleep mode */ - k_sleep(K_MSEC(3)); + /* + * To perform full POR (after soft reset), bring the device into suspend + * mode then back into sleep mode, see datasheet section 5.6 + */ + ret = bmm150_power_control(dev, 0); + if (ret != 0) { + LOG_ERR("failed to enter suspend mode: %d", ret); + return ret; + } + + k_sleep(BMM150_POR_TIME); + + /* Full POR - back into sleep mode */ + ret = bmm150_power_control(dev, 1); + if (ret != 0) { + LOG_ERR("failed to go back into sleep mode: %d", ret); + return ret; + } + + k_sleep(BMM150_START_UP_TIME); - /* Read chip ID */ + return 0; +} + +static int bmm150_init_chip(const struct device *dev) +{ + struct bmm150_data *data = dev->data; + struct bmm150_preset preset; + uint8_t chip_id; + + if (bmm150_full_por(dev) != 0) { + goto err_poweroff; + } + + /* Read chip ID (can only be read in sleep mode)*/ if (bmm150_reg_read(dev, BMM150_REG_CHIP_ID, &chip_id, 1) < 0) { LOG_ERR("failed reading chip id"); goto err_poweroff; @@ -574,9 +586,8 @@ static int bmm150_init_chip(const struct device *dev) } /* Set chip normal mode */ - if (bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 1) - < 0) { - LOG_ERR("failed to power on device"); + if (bmm150_opmode(dev, BMM150_MODE_NORMAL) < 0) { + LOG_ERR("failed to enter normal mode"); } /* Reads the trim registers of the sensor */ @@ -603,8 +614,8 @@ static int bmm150_init_chip(const struct device *dev) return 0; err_poweroff: - bmm150_set_power_mode(dev, BMM150_POWER_MODE_NORMAL, 0); - bmm150_set_power_mode(dev, BMM150_POWER_MODE_SUSPEND, 1); + (void)bmm150_power_control(dev, 0); /* Suspend */ + return -EIO; } diff --git a/drivers/sensor/bmm150/bmm150.h b/drivers/sensor/bmm150/bmm150.h index 7e954d7882c8..5ea8fb67ab50 100644 --- a/drivers/sensor/bmm150/bmm150.h +++ b/drivers/sensor/bmm150/bmm150.h @@ -2,6 +2,7 @@ /* * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2023 FTP Technologies * * SPDX-License-Identifier: Apache-2.0 */ @@ -116,7 +117,7 @@ extern const struct bmm150_bus_io bmm150_bus_io_i2c; #define BMM150_REG_INT_DRDY 0x4E #define BMM150_MASK_DRDY_EN BIT(7) #define BMM150_SHIFT_DRDY_EN 7 -#define BMM150_DRDY_INT3 BIT(6) +#define BMM150_DRDY_INT3 BIT(6) #define BMM150_MASK_DRDY_Z_EN BIT(5) #define BMM150_MASK_DRDY_Y_EN BIT(4) #define BMM150_MASK_DRDY_X_EN BIT(3) @@ -164,12 +165,6 @@ struct bmm150_data { int sample_x, sample_y, sample_z; }; -enum bmm150_power_modes { - BMM150_POWER_MODE_SUSPEND, - BMM150_POWER_MODE_SLEEP, - BMM150_POWER_MODE_NORMAL -}; - enum bmm150_axis { BMM150_AXIS_X, BMM150_AXIS_Y, @@ -196,6 +191,12 @@ enum bmm150_presets { #define BMM150_DEFAULT_PRESET BMM150_HIGH_ACCURACY_PRESET #endif +/* Power On Reset time - from OFF to Suspend (Max) */ +#define BMM150_POR_TIME K_MSEC(1) + +/* Start-Up Time - from suspend to sleep (Max) */ +#define BMM150_START_UP_TIME K_MSEC(3) + int bmm150_reg_update_byte(const struct device *dev, uint8_t reg, uint8_t mask, uint8_t value); From e0cdb0178c719ff7deee5ff7798b1074d306bc90 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Fri, 2 Jun 2023 17:52:49 +1000 Subject: [PATCH 0391/2042] drivers: sensor: bmm150: add PM Add PM Signed-off-by: Nick Ward --- drivers/sensor/bmm150/bmm150.c | 40 +++++++++++++++++++++++++++++++++- drivers/sensor/bmm150/bmm150.h | 1 + 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/sensor/bmm150/bmm150.c b/drivers/sensor/bmm150/bmm150.c index aa748a0906f5..ae1a09657e08 100644 --- a/drivers/sensor/bmm150/bmm150.c +++ b/drivers/sensor/bmm150/bmm150.c @@ -619,6 +619,40 @@ static int bmm150_init_chip(const struct device *dev) return -EIO; } +#ifdef CONFIG_PM_DEVICE +static int pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Need to enter sleep mode before setting OpMode to normal */ + ret = bmm150_power_control(dev, 1); + if (ret != 0) { + LOG_ERR("failed to enter sleep mode: %d", ret); + } + + k_sleep(BMM150_START_UP_TIME); + + ret |= bmm150_opmode(dev, BMM150_MODE_NORMAL); + if (ret != 0) { + LOG_ERR("failed to enter normal mode: %d", ret); + } + break; + case PM_DEVICE_ACTION_SUSPEND: + ret = bmm150_power_control(dev, 0); /* Suspend */ + if (ret != 0) { + LOG_ERR("failed to enter suspend mode: %d", ret); + } + break; + default: + return -ENOTSUP; + } + + return ret; +} +#endif + static int bmm150_init(const struct device *dev) { int err = 0; @@ -661,8 +695,12 @@ static int bmm150_init(const struct device *dev) static const struct bmm150_config bmm150_config_##inst = { \ BMM150_BUS_CFG(inst) \ }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, pm_action); \ + \ SENSOR_DEVICE_DT_INST_DEFINE(inst, \ - bmm150_init, NULL, \ + bmm150_init, \ + PM_DEVICE_DT_INST_GET(inst), \ &bmm150_data_##inst, \ &bmm150_config_##inst, \ POST_KERNEL, \ diff --git a/drivers/sensor/bmm150/bmm150.h b/drivers/sensor/bmm150/bmm150.h index 5ea8fb67ab50..d00497354a48 100644 --- a/drivers/sensor/bmm150/bmm150.h +++ b/drivers/sensor/bmm150/bmm150.h @@ -60,6 +60,7 @@ extern const struct bmm150_bus_io bmm150_bus_io_i2c; #include #include #include +#include #include #include #include From 234fec579a9b856b3e02b24d7787e6de1bfa6b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Stenberg?= Date: Tue, 14 Feb 2023 14:48:37 +0100 Subject: [PATCH 0392/2042] scripts: gen_relocate_app.py: Give sections unique names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code_relocation feature creates generic section names that sometimes conflict with already existing names. This patch adds a '_reloc_' word to the created names to reduce the risk of conflict. This solves #54785. Signed-off-by: Björn Stenberg --- arch/arm/core/aarch32/mpu/arm_core_mpu.c | 8 ++--- scripts/build/gen_relocate_app.py | 32 +++++++++---------- .../code_relocation/src/test_file1.c | 32 +++++++++---------- .../code_relocation/src/test_file3.c | 8 ++--- .../code_relocation/src/test_file4.c | 16 +++++----- .../code_relocation/src/test_file5.c | 16 +++++----- .../code_relocation/test_lib/test_lib1.c | 24 +++++++------- 7 files changed, 68 insertions(+), 68 deletions(-) diff --git a/arch/arm/core/aarch32/mpu/arm_core_mpu.c b/arch/arm/core/aarch32/mpu/arm_core_mpu.c index bc913557d118..2fb0f141125b 100644 --- a/arch/arm/core/aarch32/mpu/arm_core_mpu.c +++ b/arch/arm/core/aarch32/mpu/arm_core_mpu.c @@ -58,8 +58,8 @@ uint32_t z_arm_mpu_stack_guard_and_fpu_adjust(struct k_thread *thread); #endif #if defined(CONFIG_CODE_DATA_RELOCATION_SRAM) -extern char __ram_text_start[]; -extern char __ram_text_size[]; +extern char __ram_text_reloc_start[]; +extern char __ram_text_reloc_size[]; #endif static const struct z_arm_mpu_partition static_regions[] = { @@ -92,8 +92,8 @@ static const struct z_arm_mpu_partition static_regions[] = { #if defined(CONFIG_CODE_DATA_RELOCATION_SRAM) { /* RAM area for relocated text */ - .start = (uint32_t)&__ram_text_start, - .size = (uint32_t)&__ram_text_size, + .start = (uint32_t)&__ram_text_reloc_start, + .size = (uint32_t)&__ram_text_reloc_size, .attr = K_MEM_PARTITION_P_RX_U_RX, }, #endif /* CONFIG_CODE_DATA_RELOCATION_SRAM */ diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 375f744107c8..1e3067c34312 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -101,7 +101,7 @@ class OutputSection(NamedTuple): """ SECTION_LOAD_MEMORY_SEQ = """ - __{0}_{1}_rom_start = LOADADDR(_{2}_{3}_SECTION_NAME); + __{0}_{1}_rom_start = LOADADDR(.{0}_{1}_reloc); """ LOAD_ADDRESS_LOCATION_FLASH = """ @@ -135,33 +135,33 @@ class OutputSection(NamedTuple): /* Linker section for memory region {2} for {3} section */ - SECTION_PROLOGUE(_{2}_{3}_SECTION_NAME,,) + SECTION_PROLOGUE(.{0}_{1}_reloc,,) {{ . = ALIGN(4); {4} . = ALIGN(4); }} {5} - __{0}_{1}_end = .; - __{0}_{1}_start = ADDR(_{2}_{3}_SECTION_NAME); - __{0}_{1}_size = SIZEOF(_{2}_{3}_SECTION_NAME); + __{0}_{1}_reloc_end = .; + __{0}_{1}_reloc_start = ADDR(.{0}_{1}_reloc); + __{0}_{1}_reloc_size = __{0}_{1}_reloc_end - __{0}_{1}_reloc_start; """ LINKER_SECTION_SEQ_MPU = """ /* Linker section for memory region {2} for {3} section */ - SECTION_PROLOGUE(_{2}_{3}_SECTION_NAME,,) + SECTION_PROLOGUE(.{0}_{1}_reloc,,) {{ - __{0}_{1}_start = .; + __{0}_{1}_reloc_start = .; {4} #if {6} . = ALIGN({6}); #else - MPU_ALIGN(__{0}_{1}_size); + MPU_ALIGN(__{0}_{1}_reloc_size); #endif - __{0}_{1}_end = .; + __{0}_{1}_reloc_end = .; }} {5} - __{0}_{1}_size = __{0}_{1}_end - __{0}_{1}_start; + __{0}_{1}_reloc_size = __{0}_{1}_reloc_end - __{0}_{1}_reloc_start; """ SOURCE_CODE_INCLUDES = """ @@ -173,9 +173,9 @@ class OutputSection(NamedTuple): """ EXTERN_LINKER_VAR_DECLARATION = """ -extern char __{0}_{1}_start[]; +extern char __{0}_{1}_reloc_start[]; extern char __{0}_{1}_rom_start[]; -extern char __{0}_{1}_size[]; +extern char __{0}_{1}_reloc_size[]; """ @@ -194,14 +194,14 @@ class OutputSection(NamedTuple): """ MEMCPY_TEMPLATE = """ - z_early_memcpy(&__{0}_{1}_start, &__{0}_{1}_rom_start, - (size_t) &__{0}_{1}_size); + z_early_memcpy(&__{0}_{1}_reloc_start, &__{0}_{1}_rom_start, + (size_t) &__{0}_{1}_reloc_size); """ MEMSET_TEMPLATE = """ - z_early_memset(&__{0}_bss_start, 0, - (size_t) &__{0}_bss_size); + z_early_memset(&__{0}_bss_reloc_start, 0, + (size_t) &__{0}_bss_reloc_size); """ diff --git a/tests/application_development/code_relocation/src/test_file1.c b/tests/application_development/code_relocation/src/test_file1.c index ff4f537ec029..1e1cbafb54f9 100644 --- a/tests/application_development/code_relocation/src/test_file1.c +++ b/tests/application_development/code_relocation/src/test_file1.c @@ -29,14 +29,14 @@ void function_in_custom_section(void); ZTEST(code_relocation, test_function_in_sram2) { - extern uintptr_t __sram2_text_start; - extern uintptr_t __sram2_text_end; - extern uintptr_t __sram2_data_start; - extern uintptr_t __sram2_data_end; - extern uintptr_t __sram2_bss_start; - extern uintptr_t __sram2_bss_end; - extern uintptr_t __sram2_rodata_start; - extern uintptr_t __sram2_rodata_end; + extern uintptr_t __sram2_text_reloc_start; + extern uintptr_t __sram2_text_reloc_end; + extern uintptr_t __sram2_data_reloc_start; + extern uintptr_t __sram2_data_reloc_end; + extern uintptr_t __sram2_bss_reloc_start; + extern uintptr_t __sram2_bss_reloc_end; + extern uintptr_t __sram2_rodata_reloc_start; + extern uintptr_t __sram2_rodata_reloc_end; extern uintptr_t __custom_section_start; extern uintptr_t __custom_section_end; @@ -47,20 +47,20 @@ ZTEST(code_relocation, test_function_in_sram2) printk("Address of var_sram2_bss %p\n\n", &var_sram2_bss); zassert_between_inclusive((uintptr_t)&var_sram2_data, - (uintptr_t)&__sram2_data_start, - (uintptr_t)&__sram2_data_end, + (uintptr_t)&__sram2_data_reloc_start, + (uintptr_t)&__sram2_data_reloc_end, "var_sram2_data not in sram2 region"); zassert_between_inclusive((uintptr_t)&k_sem_give, - (uintptr_t)&__sram2_text_start, - (uintptr_t)&__sram2_text_end, + (uintptr_t)&__sram2_text_reloc_start, + (uintptr_t)&__sram2_text_reloc_end, "k_sem_give not in sram_text region"); zassert_between_inclusive((uintptr_t)&var_sram2_rodata, - (uintptr_t)&__sram2_rodata_start, - (uintptr_t)&__sram2_rodata_end, + (uintptr_t)&__sram2_rodata_reloc_start, + (uintptr_t)&__sram2_rodata_reloc_end, "var_sram2_rodata not in sram2_rodata region"); zassert_between_inclusive((uintptr_t)&var_sram2_bss, - (uintptr_t)&__sram2_bss_start, - (uintptr_t)&__sram2_bss_end, + (uintptr_t)&__sram2_bss_reloc_start, + (uintptr_t)&__sram2_bss_reloc_end, "var_sram2_bss not in sram2_bss region"); /* Print values from sram */ diff --git a/tests/application_development/code_relocation/src/test_file3.c b/tests/application_development/code_relocation/src/test_file3.c index e7c26773c3ce..c9ca6f911e47 100644 --- a/tests/application_development/code_relocation/src/test_file3.c +++ b/tests/application_development/code_relocation/src/test_file3.c @@ -15,8 +15,8 @@ ZTEST(code_relocation, test_function_in_split_multiple) { extern uintptr_t __data_start; extern uintptr_t __data_end; - extern uintptr_t __sram2_bss_start; - extern uintptr_t __sram2_bss_end; + extern uintptr_t __sram2_bss_reloc_start; + extern uintptr_t __sram2_bss_reloc_end; printk("Address of var_file3_sram_data %p\n", &var_file3_sram_data); printk("Address of var_file3_sram2_bss %p\n\n", &var_file3_sram2_bss); @@ -26,7 +26,7 @@ ZTEST(code_relocation, test_function_in_split_multiple) (uintptr_t)&__data_end, "var_file3_sram_data not in sram_data region"); zassert_between_inclusive((uintptr_t)&var_file3_sram2_bss, - (uintptr_t)&__sram2_bss_start, - (uintptr_t)&__sram2_bss_end, + (uintptr_t)&__sram2_bss_reloc_start, + (uintptr_t)&__sram2_bss_reloc_end, "var_file3_sram2_bss not in sram2_bss region"); } diff --git a/tests/application_development/code_relocation/src/test_file4.c b/tests/application_development/code_relocation/src/test_file4.c index 19d9a6f29b33..679744d23873 100644 --- a/tests/application_development/code_relocation/src/test_file4.c +++ b/tests/application_development/code_relocation/src/test_file4.c @@ -13,20 +13,20 @@ __in_section(bss, sram2, var) uint32_t var_file4_sram2_bss; ZTEST(code_relocation, test_function_genex_relocate_1) { - extern uintptr_t __sram2_data_start; - extern uintptr_t __sram2_data_end; - extern uintptr_t __sram2_bss_start; - extern uintptr_t __sram2_bss_end; + extern uintptr_t __sram2_data_reloc_start; + extern uintptr_t __sram2_data_reloc_end; + extern uintptr_t __sram2_bss_reloc_start; + extern uintptr_t __sram2_bss_reloc_end; printk("Address of var_file4_sram2_data %p\n", &var_file4_sram2_data); printk("Address of var_file4_sram2_bss %p\n\n", &var_file4_sram2_bss); zassert_between_inclusive((uintptr_t)&var_file4_sram2_data, - (uintptr_t)&__sram2_data_start, - (uintptr_t)&__sram2_data_end, + (uintptr_t)&__sram2_data_reloc_start, + (uintptr_t)&__sram2_data_reloc_end, "var_file4_sram2_data not in sram2_data region"); zassert_between_inclusive((uintptr_t)&var_file4_sram2_bss, - (uintptr_t)&__sram2_bss_start, - (uintptr_t)&__sram2_bss_end, + (uintptr_t)&__sram2_bss_reloc_start, + (uintptr_t)&__sram2_bss_reloc_end, "var_file4_sram2_bss not in sram2_bss region"); } diff --git a/tests/application_development/code_relocation/src/test_file5.c b/tests/application_development/code_relocation/src/test_file5.c index b06004dc3492..6d3ca7d91765 100644 --- a/tests/application_development/code_relocation/src/test_file5.c +++ b/tests/application_development/code_relocation/src/test_file5.c @@ -13,20 +13,20 @@ __in_section(bss, sram2, var) uint32_t var_file5_sram2_bss; ZTEST(code_relocation, test_function_genex_relocate_2) { - extern uintptr_t __sram2_data_start; - extern uintptr_t __sram2_data_end; - extern uintptr_t __sram2_bss_start; - extern uintptr_t __sram2_bss_end; + extern uintptr_t __sram2_data_reloc_start; + extern uintptr_t __sram2_data_reloc_end; + extern uintptr_t __sram2_bss_reloc_start; + extern uintptr_t __sram2_bss_reloc_end; printk("Address of var_file5_sram2_data %p\n", &var_file5_sram2_data); printk("Address of var_file5_sram2_bss %p\n\n", &var_file5_sram2_bss); zassert_between_inclusive((uintptr_t)&var_file5_sram2_data, - (uintptr_t)&__sram2_data_start, - (uintptr_t)&__sram2_data_end, + (uintptr_t)&__sram2_data_reloc_start, + (uintptr_t)&__sram2_data_reloc_end, "var_file5_sram2_data not in sram2_data region"); zassert_between_inclusive((uintptr_t)&var_file5_sram2_bss, - (uintptr_t)&__sram2_bss_start, - (uintptr_t)&__sram2_bss_end, + (uintptr_t)&__sram2_bss_reloc_start, + (uintptr_t)&__sram2_bss_reloc_end, "var_file5_sram2_bss not in sram2_bss region"); } diff --git a/tests/application_development/code_relocation/test_lib/test_lib1.c b/tests/application_development/code_relocation/test_lib/test_lib1.c index d0b693102a8e..a2bdd59c9ae8 100644 --- a/tests/application_development/code_relocation/test_lib/test_lib1.c +++ b/tests/application_development/code_relocation/test_lib/test_lib1.c @@ -16,28 +16,28 @@ extern void relocated_helper(void); void relocated_library(void) { - extern uintptr_t __sram2_text_start; - extern uintptr_t __sram2_text_end; - extern uintptr_t __sram2_data_start; - extern uintptr_t __sram2_data_end; - extern uintptr_t __sram2_bss_start; - extern uintptr_t __sram2_bss_end; + extern uintptr_t __sram2_text_reloc_start; + extern uintptr_t __sram2_text_reloc_end; + extern uintptr_t __sram2_data_reloc_start; + extern uintptr_t __sram2_data_reloc_end; + extern uintptr_t __sram2_bss_reloc_start; + extern uintptr_t __sram2_bss_reloc_end; printk("Address of var_lib1_sram2_data %p\n", &var_lib1_sram2_data); printk("Address of var_lib1_sram2_bss %p\n", &var_lib1_sram2_bss); printk("Address of relocated_lib_helper %p\n\n", &relocated_helper); zassert_between_inclusive((uintptr_t)&var_lib1_sram2_data, - (uintptr_t)&__sram2_data_start, - (uintptr_t)&__sram2_data_end, + (uintptr_t)&__sram2_data_reloc_start, + (uintptr_t)&__sram2_data_reloc_end, "var_lib1_sram2_data not in sram2_data region"); zassert_between_inclusive((uintptr_t)&var_lib1_sram2_bss, - (uintptr_t)&__sram2_bss_start, - (uintptr_t)&__sram2_bss_end, + (uintptr_t)&__sram2_bss_reloc_start, + (uintptr_t)&__sram2_bss_reloc_end, "var_lib1_sram2_bss not in sram2_bss region"); zassert_between_inclusive((uintptr_t)&relocated_helper, - (uintptr_t)&__sram2_text_start, - (uintptr_t)&__sram2_text_end, + (uintptr_t)&__sram2_text_reloc_start, + (uintptr_t)&__sram2_text_reloc_end, "relocated_helper not in sram2_text region"); relocated_helper(); } From 5a07588ae485e23366af05f218a023457986e6dc Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 15:58:39 +0200 Subject: [PATCH 0393/2042] kernel: Explicitly define the main prototype if C++ If the embedded application has a main(), Zephyr requires it to have a signature with C linkage (no C++ name mangling). Otherwise Zephyr's init will not call it, but will call the default weak stub. But, when building with clang/llvm, when we build calling the compiler with --frestanding (for ex if CONFIG_MINIMAL_LIBC is set), the compiler will mangle the main() symbol name. This is not incorrect behavior from the compiler, as, in principle, in a freestanding environment main() does not have a special meaning. gcc is still not mangling it when called with --frestanding. To avoid this issue, we define explicitly the main linkage as extern C, in a header the application will always include. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/types.h b/include/zephyr/types.h index 80e80d4de749..7e5e87b2ce33 100644 --- a/include/zephyr/types.h +++ b/include/zephyr/types.h @@ -29,6 +29,11 @@ typedef union { void (*thepfunc)(void); } z_max_align_t; +#ifdef __cplusplus +/* Zephyr requires an int main(void) signature with C linkage for the application main if present */ +extern int main(void); +#endif + #ifdef __cplusplus } #endif From e3f0d402f94b90e234e4cad82435b1bf1bdf44a9 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 20 Jun 2023 07:04:13 -0400 Subject: [PATCH 0394/2042] ci: doc: upload build log for debugging When PDF build fails, we want to see what cmaused the failure, so upload the log for later analysis. Signed-off-by: Anas Nashif --- .github/workflows/doc-build.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 466f9c8afbda..7048365d850e 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -156,6 +156,7 @@ jobs: west init -l . - name: build-docs + continue-on-error: true run: | if [[ "$GITHUB_REF" =~ "refs/tags/v" ]]; then DOC_TAG="release" @@ -166,7 +167,11 @@ jobs: DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -j auto" LATEXMKOPTS="-quiet -halt-on-error" make -C doc pdf - name: upload-build + if: always() uses: actions/upload-artifact@v3 with: name: pdf-output - path: doc/_build/latex/zephyr.pdf + if-no-files-found: ignore + path: | + doc/_build/latex/zephyr.pdf + doc/_build/latex/zephyr.log From 294e0ddee7aeb7eaccd098935827843ec26d9d9d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 20 Jun 2023 07:40:13 -0400 Subject: [PATCH 0395/2042] ci: doc-build: set shell as bash Specify the shell variant being used in the workflow step. Signed-off-by: Anas Nashif --- .github/workflows/doc-build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 7048365d850e..198a6b6b5ced 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -71,6 +71,7 @@ jobs: west init -l . - name: build-docs + shell: bash run: | if [[ "$GITHUB_REF" =~ "refs/tags/v" ]]; then DOC_TAG="release" @@ -156,6 +157,7 @@ jobs: west init -l . - name: build-docs + shell: bash continue-on-error: true run: | if [[ "$GITHUB_REF" =~ "refs/tags/v" ]]; then From ae114855f90405b886bbb98935db1b50432740cc Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 20 Jun 2023 08:46:04 -0400 Subject: [PATCH 0396/2042] ci: doc-build: use customer runner Apparently the PDF build needs more resources, otherwise we end up aborting the build too early. Signed-off-by: Anas Nashif --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 198a6b6b5ced..8d86b1033591 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -117,7 +117,7 @@ jobs: doc-build-pdf: name: "Documentation Build (PDF)" if: github.event_name != 'pull_request' - runs-on: ubuntu-22.04 + runs-on: zephyr-runner-linux-x64-4xlarge container: texlive/texlive:latest timeout-minutes: 60 concurrency: From e2e3dc0771188f2a01e3aaa792f81e6c6a611eb6 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 20 Jun 2023 16:55:31 +0300 Subject: [PATCH 0397/2042] dts: xtensa: intel: add imr entry to cavs25_tgph Add similar imr definition to cavs25_tpgh as in cavs25. Signed-off-by: Jaska Uimonen --- dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi index 246c026f7446..6cdd0e4c887c 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi @@ -83,6 +83,13 @@ wovcro-supported; }; + IMR1: memory@0xb0000000 { + compatible = "intel,adsp-imr"; + reg = <0xB0000000 DT_SIZE_M(16)>; + block-size = <0x1000>; + zephyr,memory-region = "IMR1"; + }; + soc { shim: shim@71f00 { compatible = "intel,adsp-shim"; From faadbc42eedcfa941a048311187986ce299812ca Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Fri, 2 Jun 2023 15:08:46 +0200 Subject: [PATCH 0398/2042] mm_drv: tlb: Fix mapped page in bank calculation The initial implementation was broken during improvements. There was incorrect assumption that all pages are unmapped at initials state. In reality at the beginning whole memory is powered on, so we should mark all pages as mapped. Later in initialization code unused pages are unmapped and if after this some banks become empty (all pages unmapped), the power is switched off. Signed-off-by: Jaroslaw Stelter --- drivers/mm/mm_drv_bank.c | 14 ++++++-------- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 4 ++-- include/zephyr/drivers/mm/mm_drv_bank.h | 6 +++++- tests/drivers/mm/sys_mm_drv_bank/src/main.c | 7 ++++++- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/mm/mm_drv_bank.c b/drivers/mm/mm_drv_bank.c index 14b4b40613ae..af3ced8171d7 100644 --- a/drivers/mm/mm_drv_bank.c +++ b/drivers/mm/mm_drv_bank.c @@ -15,24 +15,22 @@ */ #include - +#include #include #include void sys_mm_drv_bank_init(struct mem_drv_bank *bank, uint32_t bank_pages) { - bank->unmapped_pages = bank_pages; - bank->mapped_pages = 0; - bank->max_mapped_pages = 0; + bank->unmapped_pages = 0; + bank->mapped_pages = bank_pages; + bank->max_mapped_pages = bank_pages; } uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) { bank->unmapped_pages--; bank->mapped_pages++; - if (bank->mapped_pages > bank->max_mapped_pages) { - bank->max_mapped_pages = bank->mapped_pages; - } + __ASSERT_NO_MSG(bank->mapped_pages <= bank->max_mapped_pages); return bank->mapped_pages; } @@ -40,7 +38,7 @@ uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank) { bank->unmapped_pages++; bank->mapped_pages--; - + __ASSERT_NO_MSG(bank->unmapped_pages <= bank->max_mapped_pages); return bank->unmapped_pages; } diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index 504b51e6e5a0..c75c3d9f0fd7 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -378,7 +378,7 @@ int sys_mm_drv_unmap_page(void *virt) sys_mm_drv_report_page_usage(); #endif - if (sys_mm_drv_bank_page_unmapped(&hpsram_bank[bank_idx]) == 0) { + if (sys_mm_drv_bank_page_unmapped(&hpsram_bank[bank_idx]) == SRAM_BANK_PAGE_NUM) { sys_mm_drv_hpsram_pwr(bank_idx, false, false); } } @@ -649,7 +649,7 @@ static int sys_mm_drv_mm_init(const struct device *dev) */ for (int i = 0; i < L2_SRAM_BANK_NUM; i++) { sys_mm_drv_bank_init(&hpsram_bank[i], - SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE); + SRAM_BANK_PAGE_NUM); } #ifdef CONFIG_SOC_INTEL_COMM_WIDGET used_pages = L2_SRAM_BANK_NUM * SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE; diff --git a/include/zephyr/drivers/mm/mm_drv_bank.h b/include/zephyr/drivers/mm/mm_drv_bank.h index 1b53e9c21319..9e1a51ebcbf1 100644 --- a/include/zephyr/drivers/mm/mm_drv_bank.h +++ b/include/zephyr/drivers/mm/mm_drv_bank.h @@ -21,6 +21,8 @@ #include #include +#define SRAM_BANK_PAGE_NUM (SRAM_BANK_SIZE / CONFIG_MM_DRV_PAGE_SIZE) + struct mem_drv_bank { uint32_t unmapped_pages; uint32_t mapped_pages; @@ -32,7 +34,9 @@ struct mem_drv_bank { * * The driver may wish to track various information about the memory banks * that it uses. This routine will initialize a generic structure containing - * that information. + * that information. Since at the power on all memory banks are switched on + * it will start with all pages mapped. In next phase of driver initialization + * unused pages will be unmapped. * * @param bank Pointer to the memory bank structure used for tracking * @param bank_pages Number of pages in the memory bank diff --git a/tests/drivers/mm/sys_mm_drv_bank/src/main.c b/tests/drivers/mm/sys_mm_drv_bank/src/main.c index 786c24f662da..9c834c5efa5c 100644 --- a/tests/drivers/mm/sys_mm_drv_bank/src/main.c +++ b/tests/drivers/mm/sys_mm_drv_bank/src/main.c @@ -34,10 +34,15 @@ ZTEST(sys_mm_bank_api, test_sys_mm_drv_bank) struct sys_memory_stats stats; struct sys_memory_stats expected; uint32_t count; + uint32_t index; /* Verify that the initialization routine works as expected. */ - + /* It set mapped state for all pages */ sys_mm_drv_bank_init(&bank_data, BANK_PAGES); + /* Now unmap all pages */ + for (index = 0; index < BANK_PAGES; index++) { + sys_mm_drv_bank_page_unmapped(&bank_data); + } expected.free_bytes = EXPECTED(BANK_PAGES); expected.allocated_bytes = EXPECTED(0); From 5e4e6bc4860b99f8fa7b9bc6a9503a2139d261e4 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 9 May 2023 11:14:26 +0200 Subject: [PATCH 0399/2042] drivers/pcie: Add Virtual Channel configuration support Basic support of VC capability, where a driver can enable VC and map its traffic classes. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/CMakeLists.txt | 2 +- drivers/pcie/host/vc.c | 57 ++++++++++++++ drivers/pcie/host/vc.h | 123 +++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 drivers/pcie/host/vc.c create mode 100644 drivers/pcie/host/vc.h diff --git a/drivers/pcie/host/CMakeLists.txt b/drivers/pcie/host/CMakeLists.txt index 8426226bf445..5dbe9540817e 100644 --- a/drivers/pcie/host/CMakeLists.txt +++ b/drivers/pcie/host/CMakeLists.txt @@ -1,6 +1,6 @@ zephyr_library() -zephyr_library_sources(pcie.c) +zephyr_library_sources(pcie.c vc.c) zephyr_library_sources_ifdef(CONFIG_PCIE_CONTROLLER controller.c) zephyr_library_sources_ifdef(CONFIG_PCIE_ECAM pcie_ecam.c) zephyr_library_sources_ifdef(CONFIG_PCIE_MSI msi.c) diff --git a/drivers/pcie/host/vc.c b/drivers/pcie/host/vc.c new file mode 100644 index 000000000000..9926f7534859 --- /dev/null +++ b/drivers/pcie/host/vc.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include +#include + +#include "vc.h" + +uint32_t pcie_vc_cap_lookup(pcie_bdf_t bdf, struct pcie_vc_regs *regs) +{ + uint32_t base; + + base = pcie_get_ext_cap(bdf, PCIE_EXT_CAP_ID_VC); + if (base == 0) { + base = pcie_get_ext_cap(bdf, PCIE_EXT_CAP_ID_MFVC_VC); + if (base == 0) { + return 0; + } + } + + regs->cap_reg_1.raw = pcie_conf_read(bdf, base + + PCIE_VC_CAP_REG_1_OFFSET); + regs->cap_reg_2.raw = pcie_conf_read(bdf, base + + PCIE_VC_CAP_REG_2_OFFSET); + regs->ctrl_reg.raw = pcie_conf_read(bdf, base + + PCIE_VC_CTRL_STATUS_REG_OFFSET); + + return base; +} + +void pcie_vc_load_resources_regs(pcie_bdf_t bdf, + uint32_t base, + struct pcie_vc_resource_regs *regs, + int nb_regs) +{ + int idx; + + for (idx = 0; idx < nb_regs; idx++) { + regs->cap_reg.raw = + pcie_conf_read(bdf, base + + PCIE_VC_RES_CAP_REG_OFFSET(idx)); + regs->ctrl_reg.raw = + pcie_conf_read(bdf, base + + PCIE_VC_RES_CTRL_REG_OFFSET(idx)); + regs->status_reg.raw = + pcie_conf_read(bdf, base + + PCIE_VC_RES_STATUS_REG_OFFSET(idx)); + regs++; + } +} diff --git a/drivers/pcie/host/vc.h b/drivers/pcie/host/vc.h new file mode 100644 index 000000000000..c765f8e5ca22 --- /dev/null +++ b/drivers/pcie/host/vc.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PCIE_HOST_VC_H_ +#define ZEPHYR_DRIVERS_PCIE_HOST_VC_H_ + +#define PCIE_VC_MAX_COUNT 8 + +#define PCIE_VC_CAP_REG_1_OFFSET 0x04U +#define PCIE_VC_CAP_REG_2_OFFSET 0x08U +#define PCIE_VC_CTRL_STATUS_REG_OFFSET 0x0CU + +/** Virtual Channel capability and control Registers */ +struct pcie_vc_regs { + union { + struct { + /** Virtual Channel Count */ + uint32_t vc_count : 3; + uint32_t _reserved1 : 1; + /** Low Priority Virtual Channel Count */ + uint32_t lpvc_count : 3; + uint32_t _reserved2 : 1; + /** Reference Clock */ + uint32_t reference_clock : 2; + /** Port Arbitration Table Entry Size */ + uint32_t pat_entry_size : 3; + uint32_t _reserved3 : 19; + }; + uint32_t raw; + } cap_reg_1; + + union { + struct { + /** Virtual Channel Arbitration Capability */ + uint32_t vca_cap : 8; + uint32_t _reserved1 : 16; + /** Virtual Channel Arbitration Table Offset */ + uint32_t vca_table_offset : 8; + }; + uint32_t raw; + } cap_reg_2; + + union { + struct { + /** Load Virtual Channel Arbitration Table */ + uint32_t load_vca_table : 1; + /** Virtual Channel Arbitration Select */ + uint32_t vca_select : 3; + uint32_t _reserved1 : 12; + /** Virtual Channel Arbitration Table Status */ + uint32_t vca_table_status : 1; + uint32_t _reserved2 : 15; + }; + uint32_t raw; + } ctrl_reg; +}; + +#define PCIE_VC_RES_CAP_REG_OFFSET(_vc) (0x10U + _vc * 0X0CU) +#define PCIE_VC_RES_CTRL_REG_OFFSET(_vc) (0x14U + _vc * 0X0CU) +#define PCIE_VC_RES_STATUS_REG_OFFSET(_vc) (0x18U + _vc * 0X0CU) + +/** Virtual Channel Resource Registers */ +struct pcie_vc_resource_regs { + union { + struct { + /** Port Arbitration Capability */ + uint32_t pa_cap : 8; + uint32_t _reserved1 : 6; + uint32_t undefined : 1; + /** Reject Snoop Transactions */ + uint32_t rst : 1; + /** Maximum Time Slots */ + uint32_t max_time_slots : 7; + uint32_t _reserved2 : 1; + /** Port Arbitration Table Offset */ + uint32_t pa_table_offset : 8; + }; + uint32_t raw; + } cap_reg; + + union { + struct { + /** Traffic Class to Virtual Channel Map */ + uint32_t tc_vc_map : 8; + uint32_t _reserved1 : 8; + /** Load Port Arbitration Table */ + uint32_t load_pa_table : 1; + /** Port Arbitration Select */ + uint32_t pa_select : 3; + uint32_t _reserved2 : 4; + /** Virtual Channel ID */ + uint32_t vc_id : 3; + uint32_t _reserved3 : 4; + /** Virtual Channel Enable */ + uint32_t vc_enable : 1; + }; + uint32_t raw; + } ctrl_reg; + + union { + struct { + uint32_t _reserved1 : 16; + /** Port Arbitration Table Status */ + uint32_t pa_table_status : 1; + /** Virtual Channel Negociation Pending */ + uint32_t vc_negocation_pending : 1; + uint32_t _reserved2 : 14; + }; + uint32_t raw; + } status_reg; +}; + +uint32_t pcie_vc_cap_lookup(pcie_bdf_t bdf, struct pcie_vc_regs *regs); + +void pcie_vc_load_resources_regs(pcie_bdf_t bdf, + uint32_t base, + struct pcie_vc_resource_regs *regs, + int nb_regs); + +#endif /* ZEPHYR_DRIVERS_PCIE_HOST_VC_H_ */ From 6a1e19cf8659a0ab7b847e2cdc1c8bd8fa28ff3b Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Tue, 9 May 2023 11:16:02 +0200 Subject: [PATCH 0400/2042] drivers/pcie: Add virtual channel details output to shell module Helps to see how many VCs are supported and the related ressources. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/shell.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/pcie/host/shell.c b/drivers/pcie/host/shell.c index d5b201734e15..a6b713bf181f 100644 --- a/drivers/pcie/host/shell.c +++ b/drivers/pcie/host/shell.c @@ -14,6 +14,8 @@ #include +#include "vc.h" + struct pcie_cap_id_to_str { uint32_t id; char *str; @@ -200,6 +202,42 @@ static void show_capabilities(const struct shell *sh, pcie_bdf_t bdf) } } +static void show_vc(const struct shell *sh, pcie_bdf_t bdf) +{ + uint32_t base; + struct pcie_vc_regs regs; + struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT]; + int idx; + + base = pcie_vc_cap_lookup(bdf, ®s); + if (base == 0) { + return; + } + + shell_fprintf(sh, SHELL_NORMAL, + " VC exposed : VC/LPVC count: %u/%u, " + "PAT entry size 0x%x, VCA cap 0x%x, " + "VCA table Offset 0x%x\n", + regs.cap_reg_1.vc_count + 1, + regs.cap_reg_1.lpvc_count, + regs.cap_reg_1.pat_entry_size, + regs.cap_reg_2.vca_cap, + regs.cap_reg_2.vca_table_offset); + + pcie_vc_load_resources_regs(bdf, base, res_regs, + regs.cap_reg_1.vc_count + 1); + + for (idx = 0; idx < regs.cap_reg_1.vc_count + 1; idx++) { + shell_fprintf(sh, SHELL_NORMAL, + " VC %d - PA Cap 0x%x, RST %u," + "Max TS %u PAT offset 0x%x\n", + idx, res_regs[idx].cap_reg.pa_cap, + res_regs[idx].cap_reg.rst, + res_regs[idx].cap_reg.max_time_slots, + res_regs[idx].cap_reg.pa_table_offset); + } +} + static void pcie_dump(const struct shell *sh, pcie_bdf_t bdf) { for (int i = 0; i < 16; i++) { @@ -289,6 +327,7 @@ static void show(const struct shell *sh, pcie_bdf_t bdf, bool details, bool dump if (details) { show_capabilities(sh, bdf); + show_vc(sh, bdf); } if (dump) { From 0c9e762cee8dca578e429fd41fe7b583be491213 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Sun, 28 May 2023 12:09:05 +0200 Subject: [PATCH 0401/2042] drivers/pcie: Add VC/TC mapping and VC enablement Note that only the the hardware round robin port arbitration capability is being used. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/shell.c | 1 + drivers/pcie/host/vc.c | 121 ++++++++++++++++++++++++++++++- drivers/pcie/host/vc.h | 9 ++- include/zephyr/drivers/pcie/vc.h | 95 ++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 include/zephyr/drivers/pcie/vc.h diff --git a/drivers/pcie/host/shell.c b/drivers/pcie/host/shell.c index a6b713bf181f..a0d36db62696 100644 --- a/drivers/pcie/host/shell.c +++ b/drivers/pcie/host/shell.c @@ -14,6 +14,7 @@ #include +#include #include "vc.h" struct pcie_cap_id_to_str { diff --git a/drivers/pcie/host/vc.c b/drivers/pcie/host/vc.c index 9926f7534859..8b9273c1cc9a 100644 --- a/drivers/pcie/host/vc.c +++ b/drivers/pcie/host/vc.c @@ -6,9 +6,7 @@ #include -#include - -#include +#include #include #include "vc.h" @@ -55,3 +53,120 @@ void pcie_vc_load_resources_regs(pcie_bdf_t bdf, regs++; } } + +static int get_vc_registers(pcie_bdf_t bdf, + struct pcie_vc_regs *regs, + struct pcie_vc_resource_regs *res_regs) +{ + uint32_t base; + + base = pcie_vc_cap_lookup(bdf, regs); + if (base == 0) { + return -ENOTSUP; + } + + if (regs->cap_reg_1.vc_count == 0) { + /* Having only VC0 is like having no real VC */ + return -ENOTSUP; + } + + pcie_vc_load_resources_regs(bdf, base, res_regs, + regs->cap_reg_1.vc_count + 1); + + return 0; +} + + +int pcie_vc_enable(pcie_bdf_t bdf) +{ + struct pcie_vc_regs regs; + struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT]; + int idx; + + if (get_vc_registers(bdf, ®s, res_regs) != 0) { + return -ENOTSUP; + } + + /* We do not touch VC0: it is always on */ + for (idx = 1; idx < regs.cap_reg_1.vc_count + 1; idx++) { + if (idx > 0 && res_regs[idx].ctrl_reg.vc_enable == 1) { + /* + * VC has not been disabled properly, if at all? + */ + return -EALREADY; + } + + res_regs[idx].ctrl_reg.vc_enable = 1; + } + + return 0; +} + +int pcie_vc_disable(pcie_bdf_t bdf) +{ + struct pcie_vc_regs regs; + struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT]; + int idx; + + if (get_vc_registers(bdf, ®s, res_regs) != 0) { + return -ENOTSUP; + } + + /* We do not touch VC0: it is always on */ + for (idx = 1; idx < regs.cap_reg_1.vc_count + 1; idx++) { + /* Let's wait for the pending negotiation to end */ + while (res_regs[idx].status_reg.vc_negocation_pending == 1) { + k_msleep(10); + } + + res_regs[idx].ctrl_reg.vc_enable = 0; + } + + return 0; +} + +int pcie_vc_map_tc(pcie_bdf_t bdf, struct pcie_vctc_map *map) +{ + struct pcie_vc_regs regs; + struct pcie_vc_resource_regs res_regs[PCIE_VC_MAX_COUNT]; + int idx; + uint8_t tc_mapped = 0; + + if (get_vc_registers(bdf, ®s, res_regs) != 0) { + return -ENOTSUP; + } + + /* Map must relate to the actual VC count */ + if (regs.cap_reg_1.vc_count != map->vc_count) { + return -EINVAL; + } + + /* Veryfying that map is sane */ + for (idx = 0; idx < map->vc_count; idx++) { + if (idx == 0 && !(map->vc_tc[idx] & PCIE_VC_SET_TC0)) { + /* TC0 is on VC0 and cannot be unset */ + return -EINVAL; + } + + /* Each TC must appear only once in the map */ + if (tc_mapped & map->vc_tc[idx]) { + return -EINVAL; + } + + tc_mapped |= map->vc_tc[idx]; + } + + for (idx = 0; idx < regs.cap_reg_1.vc_count + 1; idx++) { + /* Let's just set the VC ID to related index for now */ + if (idx > 0) { + res_regs[idx].ctrl_reg.vc_id = idx; + } + + /* Currently, only HW round robin is used */ + res_regs[idx].ctrl_reg.pa_select = PCIE_VC_PA_RR; + + res_regs[idx].ctrl_reg.tc_vc_map = map->vc_tc[idx]; + } + + return 0; +} diff --git a/drivers/pcie/host/vc.h b/drivers/pcie/host/vc.h index c765f8e5ca22..78a9e51722cf 100644 --- a/drivers/pcie/host/vc.h +++ b/drivers/pcie/host/vc.h @@ -7,8 +7,6 @@ #ifndef ZEPHYR_DRIVERS_PCIE_HOST_VC_H_ #define ZEPHYR_DRIVERS_PCIE_HOST_VC_H_ -#define PCIE_VC_MAX_COUNT 8 - #define PCIE_VC_CAP_REG_1_OFFSET 0x04U #define PCIE_VC_CAP_REG_2_OFFSET 0x08U #define PCIE_VC_CTRL_STATUS_REG_OFFSET 0x0CU @@ -62,6 +60,13 @@ struct pcie_vc_regs { #define PCIE_VC_RES_CTRL_REG_OFFSET(_vc) (0x14U + _vc * 0X0CU) #define PCIE_VC_RES_STATUS_REG_OFFSET(_vc) (0x18U + _vc * 0X0CU) +#define PCIE_VC_PA_RR BIT(0) +#define PCIE_VC_PA_WRR BIT(1) +#define PCIE_VC_PA_WRR64 BIT(2) +#define PCIE_VC_PA_WRR128 BIT(3) +#define PCIE_VC_PA_TMWRR128 BIT(4) +#define PCIE_VC_PA_WRR256 BIT(5) + /** Virtual Channel Resource Registers */ struct pcie_vc_resource_regs { union { diff --git a/include/zephyr/drivers/pcie/vc.h b/include/zephyr/drivers/pcie/vc.h new file mode 100644 index 000000000000..a0438d2a7dfa --- /dev/null +++ b/include/zephyr/drivers/pcie/vc.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_ + +/** + * @brief PCIe Virtual Channel Host Interface + * @defgroup pcie_vc_host_interface PCIe Virtual Channel Host Interface + * @ingroup pcie_host_interface + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include + +/* + * 1 default VC + 7 extended VCs + */ +#define PCIE_VC_MAX_COUNT 8U + +#define PCIE_VC_SET_TC0 BIT(0) +#define PCIE_VC_SET_TC1 BIT(1) +#define PCIE_VC_SET_TC2 BIT(2) +#define PCIE_VC_SET_TC3 BIT(3) +#define PCIE_VC_SET_TC4 BIT(4) +#define PCIE_VC_SET_TC5 BIT(5) +#define PCIE_VC_SET_TC6 BIT(6) +#define PCIE_VC_SET_TC7 BIT(7) + +struct pcie_vctc_map { + /* + * Map the TCs for each VC by setting bits relevantly + * Note: one bit cannot be set more than once among the VCs + */ + uint8_t vc_tc[PCIE_VC_MAX_COUNT]; + /* + * Number of VCs being addressed + */ + int vc_count; +}; + +/** + * @brief Enable PCIe Virtual Channel handling + * @param bdf the target PCI endpoint + * @return 0 on success, a negative error code otherwise + * + * Note: Not being able to enable such feature is a non-fatal error + * and any code using it should behave accordingly (displaying some info, + * and ignoring it for instance). + */ +int pcie_vc_enable(pcie_bdf_t bdf); + +/** + * @brief Disable PCIe Virtual Channel handling + * @param bdf the target PCI endpoint + * @return 0 on success, a negative error code otherwise + */ +int pcie_vc_disable(pcie_bdf_t bdf); + +/** + * @brief Map PCIe TC/VC + * @param bdf the target PCI endpoint + * @param map the tc/vc map to apply + * @return 0 on success, a negative error code otherwise + * + * Note: VC must be disabled prior to call this function and + * enabled afterward in order for the endpoint to take advandage of the map. + * + * Note: Not being able to enable such feature is a non-fatal error + * and any code using it should behave accordingly (displaying some info, + * and ignoring it for instance). + */ +int pcie_vc_map_tc(pcie_bdf_t bdf, struct pcie_vctc_map *map); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_PCIE_VC_H_ */ From fbb55d1d5e198ec17365c694aec60b9b867dcfdc Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 19 Apr 2023 13:45:07 +0200 Subject: [PATCH 0402/2042] adsp: dmic: Moved registers definitions to a separate file Moved dmic register definitions to a separate file dmic_regs.h and added their description. Platform-dependent registers definitions are placed in separate files. Used standard macros FIELD_PREP, FIELD_GET in operations on registers. Signed-off-by: Adrian Warecki --- drivers/dai/intel/dmic/dmic.c | 126 +++---- drivers/dai/intel/dmic/dmic.h | 362 ------------------ drivers/dai/intel/dmic/dmic_nhlt.c | 203 +++++----- drivers/dai/intel/dmic/dmic_regs.h | 461 +++++++++++++++++++++++ drivers/dai/intel/dmic/dmic_regs_ace1x.h | 29 ++ drivers/dai/intel/dmic/dmic_regs_ace2x.h | 72 ++++ 6 files changed, 742 insertions(+), 511 deletions(-) create mode 100644 drivers/dai/intel/dmic/dmic_regs.h create mode 100644 drivers/dai/intel/dmic/dmic_regs_ace1x.h create mode 100644 drivers/dai/intel/dmic/dmic_regs_ace2x.h diff --git a/drivers/dai/intel/dmic/dmic.c b/drivers/dai/intel/dmic/dmic.c index c0622a59bc5f..4651eb16c763 100644 --- a/drivers/dai/intel/dmic/dmic.c +++ b/drivers/dai/intel/dmic/dmic.c @@ -22,6 +22,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include "dmic.h" +#include "dmic_regs.h" /* Base addresses (in PDM scope) of 2ch PDM controllers and coefficient RAM. */ static const uint32_t base[4] = {PDM0, PDM1, PDM2, PDM3}; @@ -139,14 +140,14 @@ static inline void dai_dmic_claim_ownership(const struct dai_intel_dmic *dmic) { /* DMIC Owner Select to DSP */ sys_write32(sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | - DMICLCTL_OSEL(0x3), dmic->shim_base + DMICLCTL_OFFSET); + FIELD_PREP(DMICLCTL_OSEL, 0x3), dmic->shim_base + DMICLCTL_OFFSET); } static inline void dai_dmic_release_ownership(const struct dai_intel_dmic *dmic) { /* DMIC Owner Select back to Host CPU + DSP */ sys_write32(sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & - ~DMICLCTL_OSEL(0x0), dmic->shim_base + DMICLCTL_OFFSET); + ~DMICLCTL_OSEL, dmic->shim_base + DMICLCTL_OFFSET); } #else /* CONFIG_DAI_DMIC_HAS_OWNERSHIP */ @@ -172,7 +173,7 @@ static inline void dai_dmic_set_sync_period(uint32_t period, const struct dai_in uint32_t base = dai_dmic_base(dmic); /* DMIC Change sync period */ #ifdef CONFIG_SOC_INTEL_ACE20_LNL - sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPRD(val), + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | FIELD_PREP(DMICSYNC_SYNCPRD, val), base + DMICSYNC_OFFSET); sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPU, base + DMICSYNC_OFFSET); @@ -182,7 +183,7 @@ static inline void dai_dmic_set_sync_period(uint32_t period, const struct dai_in sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, base + DMICSYNC_OFFSET); #else /* All other CAVS and ACE platforms */ - sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_SYNCPRD(val), + sys_write32(sys_read32(base + DMICSYNC_OFFSET) | FIELD_PREP(DMICSYNC_SYNCPRD, val), base + DMICSYNC_OFFSET); sys_write32(sys_read32(base + DMICSYNC_OFFSET) | DMICSYNC_CMDSYNC, base + DMICSYNC_OFFSET); @@ -193,7 +194,7 @@ static inline void dai_dmic_clear_sync_period(const struct dai_intel_dmic *dmic) { uint32_t base = dai_dmic_base(dmic); /* DMIC Clean sync period */ - sys_write32(sys_read32(base + DMICSYNC_OFFSET) & ~DMICSYNC_SYNCPRD(0x0000), + sys_write32(sys_read32(base + DMICSYNC_OFFSET) & ~DMICSYNC_SYNCPRD, base + DMICSYNC_OFFSET); sys_write32(sys_read32(base + DMICSYNC_OFFSET) & ~DMICSYNC_CMDSYNC, base + DMICSYNC_OFFSET); @@ -239,13 +240,13 @@ static void dai_dmic_stop_fifo_packers(struct dai_intel_dmic *dmic, switch (fifo_index) { case 0: dai_dmic_update_bits(dmic, OUTCONTROL0, - OUTCONTROL0_SIP_BIT | OUTCONTROL0_FINIT_BIT, - OUTCONTROL0_FINIT_BIT); + OUTCONTROL_SIP | OUTCONTROL_FINIT, + OUTCONTROL_FINIT); break; case 1: dai_dmic_update_bits(dmic, OUTCONTROL1, - OUTCONTROL1_SIP_BIT | OUTCONTROL1_FINIT_BIT, - OUTCONTROL1_FINIT_BIT); + OUTCONTROL_SIP | OUTCONTROL_FINIT, + OUTCONTROL_FINIT); break; } } @@ -264,13 +265,13 @@ static void dai_dmic_irq_handler(const void *data) val1 = dai_dmic_read(dmic, OUTSTAT1); LOG_DBG("dmic_irq_handler(), OUTSTAT0 = 0x%x, OUTSTAT1 = 0x%x", val0, val1); - if (val0 & OUTSTAT0_ROR_BIT) { + if (val0 & OUTSTAT_ROR) { LOG_ERR("dmic_irq_handler(): full fifo A or PDM overrun"); dai_dmic_write(dmic, OUTSTAT0, val0); dai_dmic_stop_fifo_packers(dmic, 0); } - if (val1 & OUTSTAT1_ROR_BIT) { + if (val1 & OUTSTAT_ROR) { LOG_ERR("dmic_irq_handler(): full fifo B or PDM overrun"); dai_dmic_write(dmic, OUTSTAT1, val1); dai_dmic_stop_fifo_packers(dmic, 1); @@ -281,10 +282,10 @@ static inline void dai_dmic_dis_clk_gating(const struct dai_intel_dmic *dmic) { /* Disable DMIC clock gating */ #ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ - sys_write32((sys_read32(dmic->vshim_base + DMICLCTL_OFFSET) | DMIC_DCGD), - dmic->vshim_base + DMICLCTL_OFFSET); + sys_write32((sys_read32(dmic->vshim_base + DMICLVSCTL_OFFSET) | DMICLVSCTL_DCGD), + dmic->vshim_base + DMICLVSCTL_OFFSET); #else - sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMIC_DCGD), + sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMICLCTL_DCGD), dmic->shim_base + DMICLCTL_OFFSET); #endif } @@ -293,10 +294,10 @@ static inline void dai_dmic_en_clk_gating(const struct dai_intel_dmic *dmic) { /* Enable DMIC clock gating */ #ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ - sys_write32((sys_read32(dmic->vshim_base + DMICLCTL_OFFSET) & ~DMIC_DCGD), - dmic->vshim_base + DMICLCTL_OFFSET); + sys_write32((sys_read32(dmic->vshim_base + DMICLVSCTL_OFFSET) & ~DMICLVSCTL_DCGD), + dmic->vshim_base + DMICLVSCTL_OFFSET); #else - sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & ~DMIC_DCGD), + sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & ~DMICLCTL_DCGD), dmic->shim_base + DMICLCTL_OFFSET); #endif @@ -413,12 +414,12 @@ static int dai_timestamp_dmic_start(const struct device *dev, struct dai_ts_cfg /* First point CDMAS to GPDMA channel that is used by DMIC * also clear NTK to be sure there is no old timestamp. */ - cdmas = TS_LOCAL_TSCTRL_CDMAS(cfg->dma_chan_index + + cdmas = FIELD_PREP(TS_LOCAL_TSCTRL_CDMAS, cfg->dma_chan_index + cfg->dma_chan_count * cfg->dma_id); - sys_write32(TS_LOCAL_TSCTRL_NTK_BIT | cdmas, addr); + sys_write32(TS_LOCAL_TSCTRL_NTK | cdmas, addr); /* Request on demand timestamp */ - sys_write32(TS_LOCAL_TSCTRL_ODTS_BIT | cdmas, addr); + sys_write32(TS_LOCAL_TSCTRL_ODTS | cdmas, addr); return 0; } @@ -426,8 +427,7 @@ static int dai_timestamp_dmic_start(const struct device *dev, struct dai_ts_cfg static int dai_timestamp_dmic_stop(const struct device *dev, struct dai_ts_cfg *cfg) { /* Clear NTK and write zero to CDMAS */ - sys_write32(TS_LOCAL_TSCTRL_NTK_BIT, - TS_DMIC_LOCAL_TSCTRL); + sys_write32(TS_LOCAL_TSCTRL_NTK, TS_DMIC_LOCAL_TSCTRL); return 0; } @@ -439,7 +439,7 @@ static int dai_timestamp_dmic_get(const struct device *dev, struct dai_ts_cfg *c uint32_t ntk; /* Read SSP timestamp registers */ - ntk = sys_read32(tsctrl) & TS_LOCAL_TSCTRL_NTK_BIT; + ntk = sys_read32(tsctrl) & TS_LOCAL_TSCTRL_NTK; if (!ntk) goto out; @@ -450,7 +450,7 @@ static int dai_timestamp_dmic_get(const struct device *dev, struct dai_ts_cfg *c tsd->sample = sys_read64(TS_DMIC_LOCAL_SAMPLE); /* Clear NTK to enable successive timestamps */ - sys_write32(TS_LOCAL_TSCTRL_NTK_BIT, tsctrl); + sys_write32(TS_LOCAL_TSCTRL_NTK, tsctrl); out: tsd->walclk_rate = cfg->walclk_rate; @@ -514,28 +514,28 @@ static void dai_dmic_gain_ramp(struct dai_intel_dmic *dmic) if (dmic->startcount == DMIC_UNMUTE_CIC) dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_MIC_MUTE_BIT, 0); + CIC_CONTROL_MIC_MUTE, 0); if (dmic->startcount == DMIC_UNMUTE_FIR) { switch (dmic->dai_config_params.dai_index) { case 0: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_A, - FIR_CONTROL_A_MUTE_BIT, 0); + FIR_CONTROL_MUTE, 0); break; case 1: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_B, - FIR_CONTROL_B_MUTE_BIT, 0); + FIR_CONTROL_MUTE, 0); break; } } switch (dmic->dai_config_params.dai_index) { case 0: - val = OUT_GAIN_LEFT_A_GAIN(gval); + val = FIELD_PREP(OUT_GAIN, gval); dai_dmic_write(dmic, base[i] + OUT_GAIN_LEFT_A, val); dai_dmic_write(dmic, base[i] + OUT_GAIN_RIGHT_A, val); break; case 1: - val = OUT_GAIN_LEFT_B_GAIN(gval); + val = FIELD_PREP(OUT_GAIN, gval); dai_dmic_write(dmic, base[i] + OUT_GAIN_LEFT_B, val); dai_dmic_write(dmic, base[i] + OUT_GAIN_RIGHT_B, val); break; @@ -576,8 +576,8 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic) dai_dmic_update_bits( dmic, OUTCONTROL0, - OUTCONTROL0_FINIT_BIT | OUTCONTROL0_SIP_BIT, - OUTCONTROL0_SIP_BIT); + OUTCONTROL_FINIT | OUTCONTROL_SIP, + OUTCONTROL_SIP); break; case 1: LOG_INF("dmic_start(), dmic->fifo_b"); @@ -585,14 +585,14 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic) * Start FIFO B packer. */ dai_dmic_update_bits(dmic, OUTCONTROL1, - OUTCONTROL1_FINIT_BIT | OUTCONTROL1_SIP_BIT, - OUTCONTROL1_SIP_BIT); + OUTCONTROL_FINIT | OUTCONTROL_SIP, + OUTCONTROL_SIP); } for (i = 0; i < CONFIG_DAI_DMIC_HW_CONTROLLERS; i++) { #ifdef CONFIG_SOC_SERIES_INTEL_ACE dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_SOFT_RESET_BIT, 0); + CIC_CONTROL_SOFT_RESET, 0); LOG_INF("dmic_start(), cic 0x%08x", dai_dmic_read(dmic, base[i] + CIC_CONTROL)); @@ -611,41 +611,41 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic) */ if (mic_a && mic_b) { dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_CIC_START_A_BIT | - CIC_CONTROL_CIC_START_B_BIT, - CIC_CONTROL_CIC_START_A(1) | - CIC_CONTROL_CIC_START_B(1)); + CIC_CONTROL_CIC_START_A | + CIC_CONTROL_CIC_START_B, + FIELD_PREP(CIC_CONTROL_CIC_START_A, 1) | + FIELD_PREP(CIC_CONTROL_CIC_START_B, 1)); dai_dmic_update_bits(dmic, base[i] + MIC_CONTROL, - MIC_CONTROL_PDM_EN_A_BIT | - MIC_CONTROL_PDM_EN_B_BIT, - MIC_CONTROL_PDM_EN_A(1) | - MIC_CONTROL_PDM_EN_B(1)); + MIC_CONTROL_PDM_EN_A | + MIC_CONTROL_PDM_EN_B, + FIELD_PREP(MIC_CONTROL_PDM_EN_A, 1) | + FIELD_PREP(MIC_CONTROL_PDM_EN_B, 1)); } else if (mic_a) { dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_CIC_START_A_BIT, - CIC_CONTROL_CIC_START_A(1)); + CIC_CONTROL_CIC_START_A, + FIELD_PREP(CIC_CONTROL_CIC_START_A, 1)); dai_dmic_update_bits(dmic, base[i] + MIC_CONTROL, - MIC_CONTROL_PDM_EN_A_BIT, - MIC_CONTROL_PDM_EN_A(1)); + MIC_CONTROL_PDM_EN_A, + FIELD_PREP(MIC_CONTROL_PDM_EN_A, 1)); } else if (mic_b) { dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_CIC_START_B_BIT, - CIC_CONTROL_CIC_START_B(1)); + CIC_CONTROL_CIC_START_B, + FIELD_PREP(CIC_CONTROL_CIC_START_B, 1)); dai_dmic_update_bits(dmic, base[i] + MIC_CONTROL, - MIC_CONTROL_PDM_EN_B_BIT, - MIC_CONTROL_PDM_EN_B(1)); + MIC_CONTROL_PDM_EN_B, + FIELD_PREP(MIC_CONTROL_PDM_EN_B, 1)); } switch (dmic->dai_config_params.dai_index) { case 0: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_A, - FIR_CONTROL_A_START_BIT, - FIR_CONTROL_A_START(fir_a)); + FIR_CONTROL_START, + FIELD_PREP(FIR_CONTROL_START, fir_a)); break; case 1: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_B, - FIR_CONTROL_B_START_BIT, - FIR_CONTROL_B_START(fir_b)); + FIR_CONTROL_START, + FIELD_PREP(FIR_CONTROL_START, fir_b)); break; } } @@ -656,7 +656,7 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic) */ for (i = 0; i < CONFIG_DAI_DMIC_HW_CONTROLLERS; i++) { dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_SOFT_RESET_BIT, 0); + CIC_CONTROL_SOFT_RESET, 0); LOG_INF("dmic_start(), cic 0x%08x", dai_dmic_read(dmic, base[i] + CIC_CONTROL)); @@ -704,21 +704,21 @@ static void dai_dmic_stop(struct dai_intel_dmic *dmic, bool stop_is_pause) /* Don't stop CIC yet if one FIFO remains active */ if (dai_dmic_global.active_fifos_mask == 0) { dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL, - CIC_CONTROL_SOFT_RESET_BIT | - CIC_CONTROL_MIC_MUTE_BIT, - CIC_CONTROL_SOFT_RESET_BIT | - CIC_CONTROL_MIC_MUTE_BIT); + CIC_CONTROL_SOFT_RESET | + CIC_CONTROL_MIC_MUTE, + CIC_CONTROL_SOFT_RESET | + CIC_CONTROL_MIC_MUTE); } switch (dmic->dai_config_params.dai_index) { case 0: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_A, - FIR_CONTROL_A_MUTE_BIT, - FIR_CONTROL_A_MUTE_BIT); + FIR_CONTROL_MUTE, + FIR_CONTROL_MUTE); break; case 1: dai_dmic_update_bits(dmic, base[i] + FIR_CONTROL_B, - FIR_CONTROL_B_MUTE_BIT, - FIR_CONTROL_B_MUTE_BIT); + FIR_CONTROL_MUTE, + FIR_CONTROL_MUTE); break; } } diff --git a/drivers/dai/intel/dmic/dmic.h b/drivers/dai/intel/dmic/dmic.h index 481b369fc88d..da1b486938d4 100644 --- a/drivers/dai/intel/dmic/dmic.h +++ b/drivers/dai/intel/dmic/dmic.h @@ -9,21 +9,6 @@ #include -/* bit operations macros */ -#define MASK(b_hi, b_lo) \ - (((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL) << (b_lo)) - -#define SET_BIT(b, x) (((x) & 1) << (b)) - -#define SET_BITS(b_hi, b_lo, x) \ - (((x) & ((1ULL << ((b_hi) - (b_lo) + 1ULL)) - 1ULL)) << (b_lo)) - -#define GET_BIT(b, x) \ - (((x) & (1ULL << (b))) >> (b)) - -#define GET_BITS(b_hi, b_lo, x) \ - (((x) & MASK(b_hi, b_lo)) >> (b_lo)) - /* The microphones create a low frequecy thump sound when clock is enabled. * The unmute linear gain ramp chacteristic is defined here. * NOTE: Do not set any of these to 0. @@ -32,71 +17,6 @@ #define DMIC_UNMUTE_CIC 1 /* Unmute CIC at 1 ms */ #define DMIC_UNMUTE_FIR 2 /* Unmute FIR at 2 ms */ -/* DMIC timestamping registers */ -#define TS_DMIC_LOCAL_TSCTRL_OFFSET 0x000 -#define TS_DMIC_LOCAL_OFFS_OFFSET 0x004 -#define TS_DMIC_LOCAL_SAMPLE_OFFSET 0x008 -#define TS_DMIC_LOCAL_WALCLK_OFFSET 0x010 -#define TS_DMIC_TSCC_OFFSET 0x018 - -/* Timestamping */ -#define TIMESTAMP_BASE 0x00071800 - -#define TS_DMIC_LOCAL_TSCTRL (TIMESTAMP_BASE + TS_DMIC_LOCAL_TSCTRL_OFFSET) -#define TS_DMIC_LOCAL_OFFS (TIMESTAMP_BASE + TS_DMIC_LOCAL_OFFS_OFFSET) -#define TS_DMIC_LOCAL_SAMPLE (TIMESTAMP_BASE + TS_DMIC_LOCAL_SAMPLE_OFFSET) -#define TS_DMIC_LOCAL_WALCLK (TIMESTAMP_BASE + TS_DMIC_LOCAL_WALCLK_OFFSET) -#define TS_DMIC_TSCC (TIMESTAMP_BASE + TS_DMIC_TSCC_OFFSET) - -#define TS_LOCAL_TSCTRL_NTK_BIT BIT(31) -#define TS_LOCAL_TSCTRL_IONTE_BIT BIT(30) -#define TS_LOCAL_TSCTRL_SIP_BIT BIT(8) -#define TS_LOCAL_TSCTRL_HHTSE_BIT BIT(7) -#define TS_LOCAL_TSCTRL_ODTS_BIT BIT(5) -#define TS_LOCAL_TSCTRL_CDMAS(x) SET_BITS(4, 0, x) -#define TS_LOCAL_OFFS_FRM GET_BITS(15, 12) -#define TS_LOCAL_OFFS_CLK GET_BITS(11, 0) - -/* Digital Mic Shim Registers */ -#define DMICLCTL_OFFSET 0x04 -#define DMICIPPTR_OFFSET 0x08 - -#ifdef CONFIG_SOC_INTEL_ACE20_LNL -#define DMICSYNC_OFFSET 0x1C - -#define DMICLCTL_SPA BIT(16) -#define DMICLCTL_CPA BIT(23) -#define DMICLCTL_OFLEN BIT(4) - -/* DMIC disable clock gating */ -#define DMIC_DCGD BIT(30) - -/* DMIC Command Sync */ -#define DMICSYNC_CMDSYNC BIT(24) -/* DMIC Sync Go */ -#define DMICSYNC_SYNCGO BIT(23) -#define DMICSYNC_SYNCPU BIT(20) -/* DMIC Sync Period */ -#define DMICSYNC_SYNCPRD(x) SET_BITS(19, 0, x) -#define DMICXPCMSyCM_OFFSET 0x16 -#else /* All other CAVS and ACE platforms */ -#define DMICSYNC_OFFSET 0x0C -/* DMIC power ON bit */ -#define DMICLCTL_SPA BIT(0) -#define DMICLCTL_CPA BIT(8) -/* DMIC Owner Select */ -#define DMICLCTL_OSEL(x) SET_BITS(25, 24, x) -/* DMIC disable clock gating */ -#define DMIC_DCGD BIT(30) - -/* DMIC Command Sync */ -#define DMICSYNC_CMDSYNC BIT(16) -/* DMIC Sync Go */ -#define DMICSYNC_SYNCGO BIT(24) -/* DMIC Sync Period */ -#define DMICSYNC_SYNCPRD(x) SET_BITS(14, 0, x) -#endif - /* Parameters used in modes computation */ #define DMIC_HW_BITS_CIC 26 #define DMIC_HW_BITS_FIR_COEF 20 @@ -119,232 +39,6 @@ #define DMIC_HW_DUTY_MIN 20 /* Note: Practical min value */ #define DMIC_HW_DUTY_MAX 80 /* Note: Practical max value */ -/* DMIC register offsets */ - -/* Global registers */ -#define OUTCONTROL0 0x0000 -#define OUTSTAT0 0x0004 -#define OUTDATA0 0x0008 -#define OUTCONTROL1 0x0100 -#define OUTSTAT1 0x0104 -#define OUTDATA1 0x0108 -#define PDM0 0x1000 -#define PDM0_COEFFICIENT_A 0x1400 -#define PDM0_COEFFICIENT_B 0x1800 -#define PDM1 0x2000 -#define PDM1_COEFFICIENT_A 0x2400 -#define PDM1_COEFFICIENT_B 0x2800 -#define PDM2 0x3000 -#define PDM2_COEFFICIENT_A 0x3400 -#define PDM2_COEFFICIENT_B 0x3800 -#define PDM3 0x4000 -#define PDM3_COEFFICIENT_A 0x4400 -#define PDM3_COEFFICIENT_B 0x4800 -#define PDM_COEF_RAM_A_LENGTH 0x0400 -#define PDM_COEF_RAM_B_LENGTH 0x0400 - -/* Local registers in each PDMx */ -#define CIC_CONTROL 0x000 -#define CIC_CONFIG 0x004 -#define MIC_CONTROL 0x00c -#define FIR_CONTROL_A 0x020 -#define FIR_CONFIG_A 0x024 -#define DC_OFFSET_LEFT_A 0x028 -#define DC_OFFSET_RIGHT_A 0x02c -#define OUT_GAIN_LEFT_A 0x030 -#define OUT_GAIN_RIGHT_A 0x034 -#define FIR_CONTROL_B 0x040 -#define FIR_CONFIG_B 0x044 -#define DC_OFFSET_LEFT_B 0x048 -#define DC_OFFSET_RIGHT_B 0x04c -#define OUT_GAIN_LEFT_B 0x050 -#define OUT_GAIN_RIGHT_B 0x054 -#define PDM_REG_END 0x058 - -/* Register bits */ - -/* OUTCONTROLx IPM bit fields style */ -#define OUTCONTROL0_BFTH_MAX 4 /* Max depth 16 */ - -/* OUTCONTROL0 bits */ -#define OUTCONTROL0_TIE_BIT BIT(27) -#define OUTCONTROL0_SIP_BIT BIT(26) -#define OUTCONTROL0_FINIT_BIT BIT(25) -#define OUTCONTROL0_FCI_BIT BIT(24) -#define OUTCONTROL0_TIE(x) SET_BIT(27, x) -#define OUTCONTROL0_SIP(x) SET_BIT(26, x) -#define OUTCONTROL0_FINIT(x) SET_BIT(25, x) -#define OUTCONTROL0_FCI(x) SET_BIT(24, x) -#define OUTCONTROL0_BFTH(x) SET_BITS(23, 20, x) -#define OUTCONTROL0_OF(x) SET_BITS(19, 18, x) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -#define OUTCONTROL0_IPM(x) SET_BITS(17, 15, x) -#else -#define OUTCONTROL0_IPM(x) SET_BITS(17, 16, x) -#endif -#define OUTCONTROL0_IPM_SOURCE_1(x) SET_BITS(14, 13, x) -#define OUTCONTROL0_IPM_SOURCE_2(x) SET_BITS(12, 11, x) -#define OUTCONTROL0_IPM_SOURCE_3(x) SET_BITS(10, 9, x) -#define OUTCONTROL0_IPM_SOURCE_4(x) SET_BITS(8, 7, x) -#define OUTCONTROL0_IPM_SOURCE_MODE(x) SET_BIT(6, x) -#define OUTCONTROL0_TH(x) SET_BITS(5, 0, x) -#define OUTCONTROL0_TIE_GET(x) GET_BIT(27, x) -#define OUTCONTROL0_SIP_GET(x) GET_BIT(26, x) -#define OUTCONTROL0_FINIT_GET(x) GET_BIT(25, x) -#define OUTCONTROL0_FCI_GET(x) GET_BIT(24, x) -#define OUTCONTROL0_BFTH_GET(x) GET_BITS(23, 20, x) -#define OUTCONTROL0_OF_GET(x) GET_BITS(19, 18, x) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -#define OUTCONTROL0_IPM_GET(x) GET_BITS(17, 15, x) -#else -#define OUTCONTROL0_IPM_GET(x) GET_BITS(17, 16, x) -#endif -#define OUTCONTROL0_IPM_SOURCE_1_GET(x) GET_BITS(14, 13, x) -#define OUTCONTROL0_IPM_SOURCE_2_GET(x) GET_BITS(12, 11, x) -#define OUTCONTROL0_IPM_SOURCE_3_GET(x) GET_BITS(10, 9, x) -#define OUTCONTROL0_IPM_SOURCE_4_GET(x) GET_BITS(8, 7, x) -#define OUTCONTROL0_IPM_SOURCE_MODE_GET(x) GET_BIT(6, x) -#define OUTCONTROL0_TH_GET(x) GET_BITS(5, 0, x) - -/* OUTCONTROL1 bits */ -#define OUTCONTROL1_TIE_BIT BIT(27) -#define OUTCONTROL1_SIP_BIT BIT(26) -#define OUTCONTROL1_FINIT_BIT BIT(25) -#define OUTCONTROL1_FCI_BIT BIT(24) -#define OUTCONTROL1_TIE(x) SET_BIT(27, x) -#define OUTCONTROL1_SIP(x) SET_BIT(26, x) -#define OUTCONTROL1_FINIT(x) SET_BIT(25, x) -#define OUTCONTROL1_FCI(x) SET_BIT(24, x) -#define OUTCONTROL1_BFTH(x) SET_BITS(23, 20, x) -#define OUTCONTROL1_OF(x) SET_BITS(19, 18, x) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -#define OUTCONTROL1_IPM(x) SET_BITS(17, 15, x) -#else -#define OUTCONTROL1_IPM(x) SET_BITS(17, 16, x) -#endif -#define OUTCONTROL1_IPM_SOURCE_1(x) SET_BITS(14, 13, x) -#define OUTCONTROL1_IPM_SOURCE_2(x) SET_BITS(12, 11, x) -#define OUTCONTROL1_IPM_SOURCE_3(x) SET_BITS(10, 9, x) -#define OUTCONTROL1_IPM_SOURCE_4(x) SET_BITS(8, 7, x) -#define OUTCONTROL1_IPM_SOURCE_MODE(x) SET_BIT(6, x) -#define OUTCONTROL1_TH(x) SET_BITS(5, 0, x) -#define OUTCONTROL1_TIE_GET(x) GET_BIT(27, x) -#define OUTCONTROL1_SIP_GET(x) GET_BIT(26, x) -#define OUTCONTROL1_FINIT_GET(x) GET_BIT(25, x) -#define OUTCONTROL1_FCI_GET(x) GET_BIT(24, x) -#define OUTCONTROL1_BFTH_GET(x) GET_BITS(23, 20, x) -#define OUTCONTROL1_OF_GET(x) GET_BITS(19, 18, x) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -#define OUTCONTROL1_IPM_GET(x) GET_BITS(17, 15, x) -#else -#define OUTCONTROL1_IPM_GET(x) GET_BITS(17, 16, x) -#endif -#define OUTCONTROL1_IPM_SOURCE_1_GET(x) GET_BITS(14, 13, x) -#define OUTCONTROL1_IPM_SOURCE_2_GET(x) GET_BITS(12, 11, x) -#define OUTCONTROL1_IPM_SOURCE_3_GET(x) GET_BITS(10, 9, x) -#define OUTCONTROL1_IPM_SOURCE_4_GET(x) GET_BITS(8, 7, x) -#define OUTCONTROL1_IPM_SOURCE_MODE_GET(x) GET_BIT(6, x) -#define OUTCONTROL1_TH_GET(x) GET_BITS(5, 0, x) - -#define OUTCONTROLX_IPM_NUMSOURCES 4 - - -/* OUTSTAT0 bits */ -#define OUTSTAT0_AFE_BIT BIT(31) -#define OUTSTAT0_ASNE_BIT BIT(29) -#define OUTSTAT0_RFS_BIT BIT(28) -#define OUTSTAT0_ROR_BIT BIT(27) -#define OUTSTAT0_FL_MASK MASK(6, 0) - -/* OUTSTAT1 bits */ -#define OUTSTAT1_AFE_BIT BIT(31) -#define OUTSTAT1_ASNE_BIT BIT(29) -#define OUTSTAT1_RFS_BIT BIT(28) -#define OUTSTAT1_ROR_BIT BIT(27) -#define OUTSTAT1_FL_MASK MASK(6, 0) - -/* CIC_CONTROL bits */ -#define CIC_CONTROL_SOFT_RESET_BIT BIT(16) -#define CIC_CONTROL_CIC_START_B_BIT BIT(15) -#define CIC_CONTROL_CIC_START_A_BIT BIT(14) -#define CIC_CONTROL_MIC_B_POLARITY_BIT BIT(3) -#define CIC_CONTROL_MIC_A_POLARITY_BIT BIT(2) -#define CIC_CONTROL_MIC_MUTE_BIT BIT(1) -#define CIC_CONTROL_STEREO_MODE_BIT BIT(0) - -#define CIC_CONTROL_SOFT_RESET(x) SET_BIT(16, x) -#define CIC_CONTROL_CIC_START_B(x) SET_BIT(15, x) -#define CIC_CONTROL_CIC_START_A(x) SET_BIT(14, x) -#define CIC_CONTROL_MIC_B_POLARITY(x) SET_BIT(3, x) -#define CIC_CONTROL_MIC_A_POLARITY(x) SET_BIT(2, x) -#define CIC_CONTROL_MIC_MUTE(x) SET_BIT(1, x) -#define CIC_CONTROL_STEREO_MODE(x) SET_BIT(0, x) - -#define CIC_CONTROL_SOFT_RESET_GET(x) GET_BIT(16, x) -#define CIC_CONTROL_CIC_START_B_GET(x) GET_BIT(15, x) -#define CIC_CONTROL_CIC_START_A_GET(x) GET_BIT(14, x) -#define CIC_CONTROL_MIC_B_POLARITY_GET(x) GET_BIT(3, x) -#define CIC_CONTROL_MIC_A_POLARITY_GET(x) GET_BIT(2, x) -#define CIC_CONTROL_MIC_MUTE_GET(x) GET_BIT(1, x) -#define CIC_CONTROL_STEREO_MODE_GET(x) GET_BIT(0, x) - -/* CIC_CONFIG bits */ -#define CIC_CONFIG_CIC_SHIFT(x) SET_BITS(27, 24, x) -#define CIC_CONFIG_COMB_COUNT(x) SET_BITS(15, 8, x) - -/* CIC_CONFIG masks */ -#define CIC_CONFIG_CIC_SHIFT_MASK MASK(27, 24) -#define CIC_CONFIG_COMB_COUNT_MASK MASK(15, 8) - -#define CIC_CONFIG_CIC_SHIFT_GET(x) GET_BITS(27, 24, x) -#define CIC_CONFIG_COMB_COUNT_GET(x) GET_BITS(15, 8, x) - -/* MIC_CONTROL bits */ -#define MIC_CONTROL_PDM_EN_B_BIT BIT(1) -#define MIC_CONTROL_PDM_EN_A_BIT BIT(0) -#define MIC_CONTROL_PDM_CLKDIV(x) SET_BITS(15, 8, x) -#define MIC_CONTROL_PDM_SKEW(x) SET_BITS(7, 4, x) -#define MIC_CONTROL_CLK_EDGE(x) SET_BIT(3, x) -#define MIC_CONTROL_PDM_EN_B(x) SET_BIT(1, x) -#define MIC_CONTROL_PDM_EN_A(x) SET_BIT(0, x) - -/* MIC_CONTROL masks */ -#define MIC_CONTROL_PDM_CLKDIV_MASK MASK(15, 8) - -#define MIC_CONTROL_PDM_CLKDIV_GET(x) GET_BITS(15, 8, x) -#define MIC_CONTROL_PDM_SKEW_GET(x) GET_BITS(7, 4, x) -#define MIC_CONTROL_PDM_CLK_EDGE_GET(x) GET_BIT(3, x) -#define MIC_CONTROL_PDM_EN_B_GET(x) GET_BIT(1, x) -#define MIC_CONTROL_PDM_EN_A_GET(x) GET_BIT(0, x) - -/* FIR_CONTROL_A bits */ -#define FIR_CONTROL_A_START_BIT BIT(7) -#define FIR_CONTROL_A_ARRAY_START_EN_BIT BIT(6) -#define FIR_CONTROL_A_PERIODIC_START_EN_BIT BIT(5) -#define FIR_CONTROL_A_MUTE_BIT BIT(1) -#define FIR_CONTROL_A_START(x) SET_BIT(7, x) -#define FIR_CONTROL_A_ARRAY_START_EN(x) SET_BIT(6, x) -#define FIR_CONTROL_A_PERIODIC_START_EN(x) SET_BIT(5, x) -#define FIR_CONTROL_A_DCCOMP(x) SET_BIT(4, x) -#define FIR_CONTROL_A_MUTE(x) SET_BIT(1, x) -#define FIR_CONTROL_A_STEREO(x) SET_BIT(0, x) - -#define FIR_CONTROL_A_START_GET(x) GET_BIT(7, x) -#define FIR_CONTROL_A_ARRAY_START_EN_GET(x) GET_BIT(6, x) -#define FIR_CONTROL_A_PERIODIC_START_EN_GET(x) GET_BIT(5, x) -#define FIR_CONTROL_A_DCCOMP_GET(x) GET_BIT(4, x) -#define FIR_CONTROL_A_MUTE_GET(x) GET_BIT(1, x) -#define FIR_CONTROL_A_STEREO_GET(x) GET_BIT(0, x) - -/* FIR_CONFIG_A bits */ -#define FIR_CONFIG_A_FIR_DECIMATION(x) SET_BITS(20, 16, x) -#define FIR_CONFIG_A_FIR_SHIFT(x) SET_BITS(11, 8, x) -#define FIR_CONFIG_A_FIR_LENGTH(x) SET_BITS(7, 0, x) - -#define FIR_CONFIG_A_FIR_DECIMATION_GET(x) GET_BITS(20, 16, x) -#define FIR_CONFIG_A_FIR_SHIFT_GET(x) GET_BITS(11, 8, x) -#define FIR_CONFIG_A_FIR_LENGTH_GET(x) GET_BITS(7, 0, x) - /* DC offset compensation time constants */ #define DCCOMP_TC0 0 #define DCCOMP_TC1 1 @@ -355,62 +49,6 @@ #define DCCOMP_TC6 6 #define DCCOMP_TC7 7 -/* DC_OFFSET_LEFT_A bits */ -#define DC_OFFSET_LEFT_A_DC_OFFS(x) SET_BITS(21, 0, x) - -/* DC_OFFSET_RIGHT_A bits */ -#define DC_OFFSET_RIGHT_A_DC_OFFS(x) SET_BITS(21, 0, x) - -/* OUT_GAIN_LEFT_A bits */ -#define OUT_GAIN_LEFT_A_GAIN(x) SET_BITS(19, 0, x) - -/* OUT_GAIN_RIGHT_A bits */ -#define OUT_GAIN_RIGHT_A_GAIN(x) SET_BITS(19, 0, x) - -/* FIR_CONTROL_B bits */ -#define FIR_CONTROL_B_START_BIT BIT(7) -#define FIR_CONTROL_B_ARRAY_START_EN_BIT BIT(6) -#define FIR_CONTROL_B_PERIODIC_START_EN_BIT BIT(5) -#define FIR_CONTROL_B_MUTE_BIT BIT(1) -#define FIR_CONTROL_B_START(x) SET_BIT(7, x) -#define FIR_CONTROL_B_ARRAY_START_EN(x) SET_BIT(6, x) -#define FIR_CONTROL_B_PERIODIC_START_EN(x) SET_BIT(5, x) -#define FIR_CONTROL_B_DCCOMP(x) SET_BIT(4, x) -#define FIR_CONTROL_B_MUTE(x) SET_BIT(1, x) -#define FIR_CONTROL_B_STEREO(x) SET_BIT(0, x) - -#define FIR_CONTROL_B_START_GET(x) GET_BIT(7, x) -#define FIR_CONTROL_B_ARRAY_START_EN_GET(x) GET_BIT(6, x) -#define FIR_CONTROL_B_PERIODIC_START_EN_GET(x) GET_BIT(5, x) -#define FIR_CONTROL_B_DCCOMP_GET(x) GET_BIT(4, x) -#define FIR_CONTROL_B_MUTE_GET(x) GET_BIT(1, x) -#define FIR_CONTROL_B_STEREO_GET(x) GET_BIT(0, x) - -/* FIR_CONFIG_B bits */ -#define FIR_CONFIG_B_FIR_DECIMATION(x) SET_BITS(20, 16, x) -#define FIR_CONFIG_B_FIR_SHIFT(x) SET_BITS(11, 8, x) -#define FIR_CONFIG_B_FIR_LENGTH(x) SET_BITS(7, 0, x) - -#define FIR_CONFIG_B_FIR_DECIMATION_GET(x) GET_BITS(20, 16, x) -#define FIR_CONFIG_B_FIR_SHIFT_GET(x) GET_BITS(11, 8, x) -#define FIR_CONFIG_B_FIR_LENGTH_GET(x) GET_BITS(7, 0, x) - -/* DC_OFFSET_LEFT_B bits */ -#define DC_OFFSET_LEFT_B_DC_OFFS(x) SET_BITS(21, 0, x) - -/* DC_OFFSET_RIGHT_B bits */ -#define DC_OFFSET_RIGHT_B_DC_OFFS(x) SET_BITS(21, 0, x) - -/* OUT_GAIN_LEFT_B bits */ -#define OUT_GAIN_LEFT_B_GAIN(x) SET_BITS(19, 0, x) - -/* OUT_GAIN_RIGHT_B bits */ -#define OUT_GAIN_RIGHT_B_GAIN(x) SET_BITS(19, 0, x) - -/* FIR coefficients */ -#define FIR_COEF_A(x) SET_BITS(19, 0, x) -#define FIR_COEF_B(x) SET_BITS(19, 0, x) - /* Used for scaling FIR coefficients for HW */ #define DMIC_HW_FIR_COEF_MAX ((1 << (DMIC_HW_BITS_FIR_COEF - 1)) - 1) #define DMIC_HW_FIR_COEF_Q (DMIC_HW_BITS_FIR_COEF - 1) diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 8bff02b2860c..c9b00a204261 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -14,6 +14,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include "dmic.h" +#include "dmic_regs.h" extern struct dai_dmic_global_shared dai_dmic_global; @@ -43,7 +44,7 @@ static int dai_ipm_source_to_enable(struct dai_intel_dmic *dmic, if (*count < pdm_count) { (*count)++; - mic_swap = MIC_CONTROL_PDM_CLK_EDGE_GET(pdm_cfg[source_pdm]->mic_control); + mic_swap = FIELD_GET(MIC_CONTROL_CLK_EDGE, pdm_cfg[source_pdm]->mic_control); if (stereo) dmic->enable[source_pdm] = 0x3; /* PDMi MIC A and B */ else @@ -65,7 +66,7 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, int n; bool stereo_pdm; - switch (OUTCONTROL0_OF_GET(outcontrol_val)) { + switch (FIELD_GET(OUTCONTROL_OF, outcontrol_val)) { case 0: case 1: dmic->dai_config_params.format = DAI_DMIC_FRAME_S16_LE; @@ -80,42 +81,42 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, return -EINVAL; } - num_pdm = OUTCONTROL0_IPM_GET(outcontrol_val); + num_pdm = FIELD_GET(OUTCONTROL_IPM, outcontrol_val); if (num_pdm > CONFIG_DAI_DMIC_HW_CONTROLLERS) { LOG_ERR("nhlt_dmic_dai_params_get(): Illegal IPM PDM controllers count %d", num_pdm); return -EINVAL; } - stereo_pdm = OUTCONTROL0_IPM_SOURCE_MODE_GET(outcontrol_val); + stereo_pdm = FIELD_GET(OUTCONTROL_IPM_SOURCE_MODE, outcontrol_val); dmic->dai_config_params.channels = (stereo_pdm + 1) * num_pdm; for (n = 0; n < CONFIG_DAI_DMIC_HW_CONTROLLERS; n++) dmic->enable[n] = 0; n = 0; - source_pdm = OUTCONTROL0_IPM_SOURCE_1_GET(outcontrol_val); + source_pdm = FIELD_GET(OUTCONTROL_IPM_SOURCE_1, outcontrol_val); ret = dai_ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm); if (ret) { LOG_ERR("nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_1"); return -EINVAL; } - source_pdm = OUTCONTROL0_IPM_SOURCE_2_GET(outcontrol_val); + source_pdm = FIELD_GET(OUTCONTROL_IPM_SOURCE_2, outcontrol_val); ret = dai_ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm); if (ret) { LOG_ERR("nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_2"); return -EINVAL; } - source_pdm = OUTCONTROL0_IPM_SOURCE_3_GET(outcontrol_val); + source_pdm = FIELD_GET(OUTCONTROL_IPM_SOURCE_3, outcontrol_val); ret = dai_ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm); if (ret) { LOG_ERR("nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_3"); return -EINVAL; } - source_pdm = OUTCONTROL0_IPM_SOURCE_4_GET(outcontrol_val); + source_pdm = FIELD_GET(OUTCONTROL_IPM_SOURCE_4, outcontrol_val); ret = dai_ipm_source_to_enable(dmic, pdm_cfg, &n, num_pdm, stereo_pdm, source_pdm); if (ret) { LOG_ERR("nhlt_dmic_dai_params_get(): Illegal IPM_SOURCE_4"); @@ -133,7 +134,7 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, int fir_stereo[2]; int mic_swap; - switch (OUTCONTROL0_OF_GET(outcontrol[dmic->dai_config_params.dai_index])) { + switch (FIELD_GET(OUTCONTROL_OF, outcontrol[dmic->dai_config_params.dai_index])) { case 0: case 1: dmic->dai_config_params.format = DAI_DMIC_FRAME_S16_LE; @@ -146,12 +147,12 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, return -EINVAL; } - switch (OUTCONTROL0_IPM_GET(outcontrol[dmic->dai_config_params.dai_index])) { + switch (FIELD_GET(OUTCONTROL_IPM, outcontrol[dmic->dai_config_params.dai_index])) { case 0: if (!fir_cfg[0]) return -EINVAL; - fir_stereo[0] = FIR_CONTROL_A_STEREO_GET(fir_cfg[0]->fir_control); + fir_stereo[0] = FIELD_GET(FIR_CONTROL_STEREO, fir_cfg[0]->fir_control); if (fir_stereo[0]) { dmic->dai_config_params.channels = 2; dmic->enable[0] = 0x3; /* PDM0 MIC A and B */ @@ -159,7 +160,7 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, } else { dmic->dai_config_params.channels = 1; - mic_swap = MIC_CONTROL_PDM_CLK_EDGE_GET(pdm_cfg[0]->mic_control); + mic_swap = FIELD_GET(MIC_CONTROL_CLK_EDGE, pdm_cfg[0]->mic_control); dmic->enable[0] = mic_swap ? 0x2 : 0x1; /* PDM0 MIC B or MIC A */ dmic->enable[1] = 0x0; /* PDM1 */ } @@ -168,7 +169,7 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, if (!fir_cfg[1]) return -EINVAL; - fir_stereo[1] = FIR_CONTROL_A_STEREO_GET(fir_cfg[1]->fir_control); + fir_stereo[1] = FIELD_GET(FIR_CONTROL_STEREO, fir_cfg[1]->fir_control); if (fir_stereo[1]) { dmic->dai_config_params.channels = 2; dmic->enable[0] = 0x0; /* PDM0 none */ @@ -176,7 +177,7 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, } else { dmic->dai_config_params.channels = 1; dmic->enable[0] = 0x0; /* PDM0 none */ - mic_swap = MIC_CONTROL_PDM_CLK_EDGE_GET(pdm_cfg[1]->mic_control); + mic_swap = FIELD_GET(MIC_CONTROL_CLK_EDGE, pdm_cfg[1]->mic_control); dmic->enable[1] = mic_swap ? 0x2 : 0x1; /* PDM1 MIC B or MIC A */ } break; @@ -184,8 +185,8 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, if (!fir_cfg[0] || !fir_cfg[0]) return -EINVAL; - fir_stereo[0] = FIR_CONTROL_A_STEREO_GET(fir_cfg[0]->fir_control); - fir_stereo[1] = FIR_CONTROL_A_STEREO_GET(fir_cfg[1]->fir_control); + fir_stereo[0] = FIELD_GET(FIR_CONTROL_STEREO, fir_cfg[0]->fir_control); + fir_stereo[1] = FIELD_GET(FIR_CONTROL_STEREO, fir_cfg[1]->fir_control); if (fir_stereo[0] == fir_stereo[1]) { dmic->dai_config_params.channels = 4; dmic->enable[0] = 0x3; /* PDM0 MIC A and B */ @@ -269,40 +270,43 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf val = *(uint32_t *)p; out_control[n] = val; - bf1 = OUTCONTROL0_TIE_GET(val); - bf2 = OUTCONTROL0_SIP_GET(val); - bf3 = OUTCONTROL0_FINIT_GET(val); - bf4 = OUTCONTROL0_FCI_GET(val); - bf5 = OUTCONTROL0_BFTH_GET(val); - bf6 = OUTCONTROL0_OF_GET(val); - bf7 = OUTCONTROL0_IPM_GET(val); - bf8 = OUTCONTROL0_TH_GET(val); + bf1 = FIELD_GET(OUTCONTROL_TIE, val); + bf2 = FIELD_GET(OUTCONTROL_SIP, val); + bf3 = FIELD_GET(OUTCONTROL_FINIT, val); + bf4 = FIELD_GET(OUTCONTROL_FCI, val); + bf5 = FIELD_GET(OUTCONTROL_BFTH, val); + bf6 = FIELD_GET(OUTCONTROL_OF, val); + bf7 = FIELD_GET(OUTCONTROL_IPM, val); + bf8 = FIELD_GET(OUTCONTROL_TH, val); LOG_INF("dmic_set_config_nhlt(): OUTCONTROL%d = %08x", n, out_control[n]); LOG_INF(" tie=%d, sip=%d, finit=%d, fci=%d", bf1, bf2, bf3, bf4); LOG_INF(" bfth=%d, of=%d, ipm=%d, th=%d", bf5, bf6, bf7, bf8); - if (bf5 > OUTCONTROL0_BFTH_MAX) { + if (bf5 > OUTCONTROL_BFTH_MAX) { LOG_ERR("dmic_set_config_nhlt(): illegal BFTH value"); return -EINVAL; } #ifdef CONFIG_SOC_SERIES_INTEL_ACE - bf9 = OUTCONTROL0_IPM_SOURCE_1_GET(val); - bf10 = OUTCONTROL0_IPM_SOURCE_2_GET(val); - bf11 = OUTCONTROL0_IPM_SOURCE_3_GET(val); - bf12 = OUTCONTROL0_IPM_SOURCE_4_GET(val); - bf13 = OUTCONTROL0_IPM_SOURCE_MODE_GET(val); + bf9 = FIELD_GET(OUTCONTROL_IPM_SOURCE_1, val); + bf10 = FIELD_GET(OUTCONTROL_IPM_SOURCE_2, val); + bf11 = FIELD_GET(OUTCONTROL_IPM_SOURCE_3, val); + bf12 = FIELD_GET(OUTCONTROL_IPM_SOURCE_4, val); + bf13 = FIELD_GET(OUTCONTROL_IPM_SOURCE_MODE, val); LOG_INF(" ipms1=%d, ipms2=%d, ipms3=%d, ipms4=%d", bf9, bf10, bf11, bf12); LOG_INF(" ipms_mode=%d", bf13); - ref = OUTCONTROL0_TIE(bf1) | OUTCONTROL0_SIP(bf2) | OUTCONTROL0_FINIT(bf3) | - OUTCONTROL0_FCI(bf4) | OUTCONTROL0_BFTH(bf5) | OUTCONTROL0_OF(bf6) | - OUTCONTROL0_IPM(bf7) | OUTCONTROL0_IPM_SOURCE_1(bf9) | - OUTCONTROL0_IPM_SOURCE_2(bf10) | OUTCONTROL0_IPM_SOURCE_3(bf11) | - OUTCONTROL0_IPM_SOURCE_4(bf12) | OUTCONTROL0_TH(bf8) | - OUTCONTROL0_IPM_SOURCE_MODE(bf13); + ref = FIELD_PREP(OUTCONTROL_TIE, bf1) | FIELD_PREP(OUTCONTROL_SIP, bf2) | + FIELD_PREP(OUTCONTROL_FINIT, bf3) | FIELD_PREP(OUTCONTROL_FCI, bf4) | + FIELD_PREP(OUTCONTROL_BFTH, bf5) | FIELD_PREP(OUTCONTROL_OF, bf6) | + FIELD_PREP(OUTCONTROL_IPM, bf7) | FIELD_PREP(OUTCONTROL_IPM_SOURCE_1, bf9) | + FIELD_PREP(OUTCONTROL_IPM_SOURCE_2, bf10) | + FIELD_PREP(OUTCONTROL_IPM_SOURCE_3, bf11) | + FIELD_PREP(OUTCONTROL_IPM_SOURCE_4, bf12) | FIELD_PREP(OUTCONTROL_TH, bf8) | + FIELD_PREP(OUTCONTROL_IPM_SOURCE_MODE, bf13); #else - ref = OUTCONTROL0_TIE(bf1) | OUTCONTROL0_SIP(bf2) | OUTCONTROL0_FINIT(bf3) | - OUTCONTROL0_FCI(bf4) | OUTCONTROL0_BFTH(bf5) | OUTCONTROL0_OF(bf6) | - OUTCONTROL0_IPM(bf7) | OUTCONTROL0_TH(bf8); + ref = FIELD_PREP(OUTCONTROL_TIE, bf1) | FIELD_PREP(OUTCONTROL_SIP, bf2) | + FIELD_PREP(OUTCONTROL_FINIT, bf3) | FIELD_PREP(OUTCONTROL_FCI, bf4) | + FIELD_PREP(OUTCONTROL_BFTH, bf5) | FIELD_PREP(OUTCONTROL_OF, bf6) | + FIELD_PREP(OUTCONTROL_IPM, bf7) | FIELD_PREP(OUTCONTROL_TH, bf8); #endif if (ref != val) { LOG_ERR("dmic_set_config_nhlt(): illegal OUTCONTROL%d = 0x%08x", @@ -318,8 +322,8 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf */ /* Clear TIE, SIP, FCI, set FINIT, the rest of bits as such */ val = (out_control[dmic->dai_config_params.dai_index] & - ~(OUTCONTROL0_TIE_BIT | OUTCONTROL0_SIP_BIT | OUTCONTROL0_FCI_BIT)) | - OUTCONTROL0_FINIT_BIT; + ~(OUTCONTROL_TIE | OUTCONTROL_SIP | OUTCONTROL_FCI)) | + OUTCONTROL_FINIT; if (dmic->dai_config_params.dai_index == 0) dai_dmic_write(dmic, OUTCONTROL0, val); else @@ -331,7 +335,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf /* Pass 2^BFTH to plat_data fifo depth. It will be used later in DMA * configuration */ - bfth = OUTCONTROL0_BFTH_GET(val); + bfth = FIELD_GET(OUTCONTROL_BFTH, val); dmic->fifo.depth = 1 << bfth; /* Get PDMx registers */ @@ -350,7 +354,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf if (!(pdm_ctrl_mask & (1 << n))) { /* Set MIC_MUTE bit to unused PDM */ - dai_dmic_write(dmic, base[n] + CIC_CONTROL, CIC_CONTROL_MIC_MUTE(1)); + dai_dmic_write(dmic, base[n] + CIC_CONTROL, CIC_CONTROL_MIC_MUTE); continue; } @@ -360,28 +364,38 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf pdm_cfg[n] = (struct nhlt_pdm_ctrl_cfg *)p; p += sizeof(struct nhlt_pdm_ctrl_cfg); - comb_count = CIC_CONFIG_COMB_COUNT_GET(pdm_cfg[n]->cic_config); + comb_count = FIELD_GET(CIC_CONFIG_COMB_COUNT, pdm_cfg[n]->cic_config); p_mcic = comb_count + 1; - clk_div = MIC_CONTROL_PDM_CLKDIV_GET(pdm_cfg[n]->mic_control); + clk_div = FIELD_GET(MIC_CONTROL_PDM_CLKDIV, pdm_cfg[n]->mic_control); p_clkdiv = clk_div + 2; if (dai_dmic_global.active_fifos_mask == 0) { val = pdm_cfg[n]->cic_control; - bf1 = CIC_CONTROL_SOFT_RESET_GET(val); - bf2 = CIC_CONTROL_CIC_START_B_GET(val); - bf3 = CIC_CONTROL_CIC_START_A_GET(val); - bf4 = CIC_CONTROL_MIC_B_POLARITY_GET(val); - bf5 = CIC_CONTROL_MIC_A_POLARITY_GET(val); - bf6 = CIC_CONTROL_MIC_MUTE_GET(val); - bf7 = CIC_CONTROL_STEREO_MODE_GET(val); + bf1 = FIELD_GET(CIC_CONTROL_SOFT_RESET, val); + bf2 = FIELD_GET(CIC_CONTROL_CIC_START_B, val); + bf3 = FIELD_GET(CIC_CONTROL_CIC_START_A, val); + bf4 = FIELD_GET(CIC_CONTROL_MIC_B_POLARITY, val); + bf5 = FIELD_GET(CIC_CONTROL_MIC_A_POLARITY, val); + bf6 = FIELD_GET(CIC_CONTROL_MIC_MUTE, val); +#ifndef CONFIG_SOC_SERIES_INTEL_ACE + bf7 = FIELD_GET(CIC_CONTROL_STEREO_MODE, val); +#else + bf7 = -1; +#endif LOG_DBG("dmic_set_config_nhlt(): CIC_CONTROL = %08x", val); LOG_DBG(" soft_reset=%d, cic_start_b=%d, cic_start_a=%d", bf1, bf2, bf3); LOG_DBG(" mic_b_polarity=%d, mic_a_polarity=%d, mic_mute=%d", bf4, bf5, bf6); - ref = CIC_CONTROL_SOFT_RESET(bf1) | CIC_CONTROL_CIC_START_B(bf2) | - CIC_CONTROL_CIC_START_A(bf3) | CIC_CONTROL_MIC_B_POLARITY(bf4) | - CIC_CONTROL_MIC_A_POLARITY(bf5) | CIC_CONTROL_MIC_MUTE(bf6) | - CIC_CONTROL_STEREO_MODE(bf7); + ref = FIELD_PREP(CIC_CONTROL_SOFT_RESET, bf1) | + FIELD_PREP(CIC_CONTROL_CIC_START_B, bf2) | + FIELD_PREP(CIC_CONTROL_CIC_START_A, bf3) | + FIELD_PREP(CIC_CONTROL_MIC_B_POLARITY, bf4) | + FIELD_PREP(CIC_CONTROL_MIC_A_POLARITY, bf5) | + FIELD_PREP(CIC_CONTROL_MIC_MUTE, bf6) +#ifndef CONFIG_SOC_SERIES_INTEL_ACE + | FIELD_PREP(CIC_CONTROL_STEREO_MODE, bf7) +#endif + ; LOG_DBG(" stereo_mode=%d", bf7); if (ref != val) { LOG_ERR("dmic_set_config_nhlt(): illegal CIC_CONTROL = 0x%08x", @@ -390,12 +404,12 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf } /* Clear CIC_START_A and CIC_START_B */ - val = (val & ~(CIC_CONTROL_CIC_START_A_BIT | CIC_CONTROL_CIC_START_B_BIT)); + val = (val & ~(CIC_CONTROL_CIC_START_A | CIC_CONTROL_CIC_START_B)); dai_dmic_write(dmic, base[n] + CIC_CONTROL, val); LOG_DBG("dmic_set_config_nhlt(): CIC_CONTROL = %08x", val); val = pdm_cfg[n]->cic_config; - bf1 = CIC_CONFIG_CIC_SHIFT_GET(val); + bf1 = FIELD_GET(CIC_CONFIG_CIC_SHIFT, val); LOG_DBG("dmic_set_config_nhlt(): CIC_CONFIG = %08x", val); LOG_DBG(" cic_shift=%d, comb_count=%d", bf1, comb_count); @@ -404,16 +418,20 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf LOG_DBG("dmic_set_config_nhlt(): CIC_CONFIG = %08x", val); val = pdm_cfg[n]->mic_control; - bf1 = MIC_CONTROL_PDM_SKEW_GET(val); - bf2 = MIC_CONTROL_PDM_CLK_EDGE_GET(val); - bf3 = MIC_CONTROL_PDM_EN_B_GET(val); - bf4 = MIC_CONTROL_PDM_EN_A_GET(val); +#ifndef CONFIG_SOC_SERIES_INTEL_ACE + bf1 = FIELD_GET(MIC_CONTROL_PDM_SKEW, val); +#else + bf1 = -1; +#endif + bf2 = FIELD_GET(MIC_CONTROL_CLK_EDGE, val); + bf3 = FIELD_GET(MIC_CONTROL_PDM_EN_B, val); + bf4 = FIELD_GET(MIC_CONTROL_PDM_EN_A, val); LOG_DBG("dmic_set_config_nhlt(): MIC_CONTROL = %08x", val); LOG_DBG(" clkdiv=%d, skew=%d, clk_edge=%d", clk_div, bf1, bf2); LOG_DBG(" en_b=%d, en_a=%d", bf3, bf4); /* Clear PDM_EN_A and PDM_EN_B */ - val &= ~(MIC_CONTROL_PDM_EN_A_BIT | MIC_CONTROL_PDM_EN_B_BIT); + val &= ~(MIC_CONTROL_PDM_EN_A | MIC_CONTROL_PDM_EN_B); dai_dmic_write(dmic, base[n] + MIC_CONTROL, val); LOG_DBG("dmic_set_config_nhlt(): MIC_CONTROL = %08x", val); } @@ -422,12 +440,12 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf fir_cfg_a[n] = (struct nhlt_pdm_ctrl_fir_cfg *)p; p += sizeof(struct nhlt_pdm_ctrl_fir_cfg); val = fir_cfg_a[n]->fir_config; - fir_length = FIR_CONFIG_A_FIR_LENGTH_GET(val); + fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val); fir_length_a = fir_length + 1; /* Need for parsing */ - fir_decimation = FIR_CONFIG_A_FIR_DECIMATION_GET(val); + fir_decimation = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val); p_mfira = fir_decimation + 1; if (dmic->dai_config_params.dai_index == 0) { - fir_shift = FIR_CONFIG_A_FIR_SHIFT_GET(val); + fir_shift = FIELD_GET(FIR_CONFIG_FIR_SHIFT, val); LOG_DBG("dmic_set_config_nhlt(): FIR_CONFIG_A = %08x", val); LOG_DBG(" fir_decimation=%d, fir_shift=%d, fir_length=%d", fir_decimation, fir_shift, fir_length); @@ -437,19 +455,28 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf LOG_DBG("configure_registers(), FIR_CONFIG_A = %08x", val); val = fir_cfg_a[n]->fir_control; - bf1 = FIR_CONTROL_A_START_GET(val); - bf2 = FIR_CONTROL_A_ARRAY_START_EN_GET(val); - bf3 = FIR_CONTROL_A_PERIODIC_START_EN_GET(val); - bf4 = FIR_CONTROL_A_DCCOMP_GET(val); - bf5 = FIR_CONTROL_A_MUTE_GET(val); - bf6 = FIR_CONTROL_A_STEREO_GET(val); + bf1 = FIELD_GET(FIR_CONTROL_START, val); + bf2 = FIELD_GET(FIR_CONTROL_ARRAY_START_EN, val); +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + bf3 = FIELD_GET(FIR_CONTROL_PERIODIC_START_EN, val); +#else + bf3 = -1; +#endif + bf4 = FIELD_GET(FIR_CONTROL_DCCOMP, val); + bf5 = FIELD_GET(FIR_CONTROL_MUTE, val); + bf6 = FIELD_GET(FIR_CONTROL_STEREO, val); LOG_DBG("dmic_set_config_nhlt(): FIR_CONTROL_A = %08x", val); LOG_DBG(" start=%d, array_start_en=%d, periodic_start_en=%d", bf1, bf2, bf3); LOG_DBG(" dccomp=%d, mute=%d, stereo=%d", bf4, bf5, bf6); - ref = FIR_CONTROL_A_START(bf1) | FIR_CONTROL_A_ARRAY_START_EN(bf2) | - FIR_CONTROL_A_PERIODIC_START_EN(bf3) | FIR_CONTROL_A_DCCOMP(bf4) | - FIR_CONTROL_A_MUTE(bf5) | FIR_CONTROL_A_STEREO(bf6); + ref = FIELD_PREP(FIR_CONTROL_START, bf1) | + FIELD_PREP(FIR_CONTROL_ARRAY_START_EN, bf2) | +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + FIELD_PREP(FIR_CONTROL_PERIODIC_START_EN, bf3) | +#endif + FIELD_PREP(FIR_CONTROL_DCCOMP, bf4) | + FIELD_PREP(FIR_CONTROL_MUTE, bf5) | + FIELD_PREP(FIR_CONTROL_STEREO, bf6); if (ref != val) { LOG_ERR("dmic_set_config_nhlt(): illegal FIR_CONTROL = 0x%08x", @@ -458,7 +485,7 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf } /* Clear START, set MUTE */ - fir_control = (val & ~FIR_CONTROL_A_START_BIT) | FIR_CONTROL_A_MUTE_BIT; + fir_control = (val & ~FIR_CONTROL_START) | FIR_CONTROL_MUTE; dai_dmic_write(dmic, base[n] + FIR_CONTROL_A, fir_control); LOG_DBG("dmic_set_config_nhlt(): FIR_CONTROL_A = %08x", fir_control); @@ -484,12 +511,12 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf fir_cfg_b[n] = (struct nhlt_pdm_ctrl_fir_cfg *)p; p += sizeof(struct nhlt_pdm_ctrl_fir_cfg); val = fir_cfg_b[n]->fir_config; - fir_length = FIR_CONFIG_B_FIR_LENGTH_GET(val); + fir_length = FIELD_GET(FIR_CONFIG_FIR_LENGTH, val); fir_length_b = fir_length + 1; /* Need for parsing */ - fir_decimation = FIR_CONFIG_B_FIR_DECIMATION_GET(val); + fir_decimation = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val); p_mfirb = fir_decimation + 1; if (dmic->dai_config_params.dai_index == 1) { - fir_shift = FIR_CONFIG_B_FIR_SHIFT_GET(val); + fir_shift = FIELD_GET(FIR_CONFIG_FIR_SHIFT, val); LOG_DBG("dmic_set_config_nhlt(): FIR_CONFIG_B = %08x", val); LOG_DBG(" fir_decimation=%d, fir_shift=%d, fir_length=%d", fir_decimation, fir_shift, fir_length); @@ -499,19 +526,23 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf LOG_DBG("configure_registers(), FIR_CONFIG_B = %08x", val); val = fir_cfg_b[n]->fir_control; - bf1 = FIR_CONTROL_B_START_GET(val); - bf2 = FIR_CONTROL_B_ARRAY_START_EN_GET(val); - bf3 = FIR_CONTROL_B_PERIODIC_START_EN_GET(val); - bf4 = FIR_CONTROL_B_DCCOMP_GET(val); - bf5 = FIR_CONTROL_B_MUTE_GET(val); - bf6 = FIR_CONTROL_B_STEREO_GET(val); + bf1 = FIELD_GET(FIR_CONTROL_START, val); + bf2 = FIELD_GET(FIR_CONTROL_ARRAY_START_EN, val); +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + bf3 = FIELD_GET(FIR_CONTROL_PERIODIC_START_EN, val); +#else + bf3 = -1; +#endif + bf4 = FIELD_GET(FIR_CONTROL_DCCOMP, val); + bf5 = FIELD_GET(FIR_CONTROL_MUTE, val); + bf6 = FIELD_GET(FIR_CONTROL_STEREO, val); LOG_DBG("dmic_set_config_nhlt(): FIR_CONTROL_B = %08x", val); LOG_DBG(" start=%d, array_start_en=%d, periodic_start_en=%d", bf1, bf2, bf3); LOG_DBG(" dccomp=%d, mute=%d, stereo=%d", bf4, bf5, bf6); /* Clear START, set MUTE */ - fir_control = (val & ~FIR_CONTROL_B_START_BIT) | FIR_CONTROL_B_MUTE_BIT; + fir_control = (val & ~FIR_CONTROL_START) | FIR_CONTROL_MUTE; dai_dmic_write(dmic, base[n] + FIR_CONTROL_B, fir_control); LOG_DBG("dmic_set_config_nhlt(): FIR_CONTROL_B = %08x", fir_control); diff --git a/drivers/dai/intel/dmic/dmic_regs.h b/drivers/dai/intel/dmic/dmic_regs.h new file mode 100644 index 000000000000..32a260d182a6 --- /dev/null +++ b/drivers/dai/intel/dmic/dmic_regs.h @@ -0,0 +1,461 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef __INTEL_DAI_DRIVER_DMIC_REGS_H__ +#define __INTEL_DAI_DRIVER_DMIC_REGS_H__ + +/* DMIC timestamping registers */ +#define TS_DMIC_LOCAL_TSCTRL_OFFSET 0x000 +#define TS_DMIC_LOCAL_OFFS_OFFSET 0x004 +#define TS_DMIC_LOCAL_SAMPLE_OFFSET 0x008 +#define TS_DMIC_LOCAL_WALCLK_OFFSET 0x010 +#define TS_DMIC_TSCC_OFFSET 0x018 + +/* Timestamping */ +#define TIMESTAMP_BASE 0x00071800 + +/* Time Stamp Control Register */ +#define TS_DMIC_LOCAL_TSCTRL (TIMESTAMP_BASE + TS_DMIC_LOCAL_TSCTRL_OFFSET) + +/* Intersample offset Register */ +#define TS_DMIC_LOCAL_OFFS (TIMESTAMP_BASE + TS_DMIC_LOCAL_OFFS_OFFSET) + +#define TS_DMIC_LOCAL_SAMPLE (TIMESTAMP_BASE + TS_DMIC_LOCAL_SAMPLE_OFFSET) +#define TS_DMIC_LOCAL_WALCLK (TIMESTAMP_BASE + TS_DMIC_LOCAL_WALCLK_OFFSET) + +/* Time Stamp Counter Captured 64 bits */ +#define TS_DMIC_TSCC (TIMESTAMP_BASE + TS_DMIC_TSCC_OFFSET) + +/* New Timestamp Taken */ +#define TS_LOCAL_TSCTRL_NTK BIT(31) + +/* Interrupt on New Timestamp Enable */ +#define TS_LOCAL_TSCTRL_IONTE BIT(30) + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +/* DMA Type Select */ +#define TS_LOCAL_TSCTRL_DMATS GENMASK(13, 12) + +/* Capture Link Select - select which link wall clock to time stamp. */ +#define TS_LOCAL_TSCTRL_CLNKS GENMASK(11, 10) +#else /* CONFIG_SOC_SERIES_INTEL_ACE */ + +/* Automatically capture the local timestamp when the stream is started. */ +#define TS_LOCAL_TSCTRL_SIP BIT(8) + +#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ + +/* Hammock Harbor Time Stamp Enable */ +#define TS_LOCAL_TSCTRL_HHTSE BIT(7) + +/* Link Wall Clock Select */ +#define TS_LOCAL_TSCTRL_LWCS BIT(6) + +/* On Demand Time Stamp */ +#define TS_LOCAL_TSCTRL_ODTS BIT(5) + +/* Capture DMA Select */ +#define TS_LOCAL_TSCTRL_CDMAS GENMASK(4, 0) + +/* Snapshot of Audio Wall Clock Offset counter (frame offset). */ +#define TS_LOCAL_OFFS_FRM GENMASK(15, 12) + +/* Snapshot of Audio Wall Clock Offset counter (clock offset). */ +#define TS_LOCAL_OFFS_CLK GENMASK(11, 0) + + +/* DMIC register offsets */ + +/* Global registers */ + +/* Common FIFO channels register (primary & secondary) (0000 - 0FFF) + * PDM Primary Channel + */ + +/* Control registers for packers */ +#define OUTCONTROL0 0x0000 + +/* Status Register for FIFO interface */ +#define OUTSTAT0 0x0004 + +/* Data read/Write port for FIFO */ +#define OUTDATA0 0x0008 + +/* (crossed out) 000Ch LOCAL_OFFS Offset Counter + * (crossed out) 0010h LOCAL_TSC0 64-bit Wall Clock timestamp + * (crossed out) 0018h LOCAL_SAMPLE0 64-bit Sample Count + * 001Ch - 00FFh Reserved space for extensions + */ + + +/* PDM Secondary Channel */ + +/* Control registers for packers */ +#define OUTCONTROL1 0x0100 + +/* Status Register for FIFO interface */ +#define OUTSTAT1 0x0104 + +/* Data read/Write port for FIFO */ +#define OUTDATA1 0x0108 + +/* (crossed out) 010Ch LOCAL_OFFS Offset Counter + * (crossed out) 0110h LOCAL_TSC0 64-bit Wall Clock timestamp + * (crossed out) 0118h LOCAL_SAMPLE0 64-bit Sample Count + * 011Ch - 0FFFh Reserved space for extensions + */ + +#define GLOBAL_CAPABILITIES 0x200 + +#define PDM0 0x1000 +#define PDM0_COEFFICIENT_A 0x1400 +#define PDM0_COEFFICIENT_B 0x1800 + +#define PDM1 0x2000 +#define PDM1_COEFFICIENT_A 0x2400 +#define PDM1_COEFFICIENT_B 0x2800 + +#define PDM2 0x3000 +#define PDM2_COEFFICIENT_A 0x3400 +#define PDM2_COEFFICIENT_B 0x3800 + +#define PDM3 0x4000 +#define PDM3_COEFFICIENT_A 0x4400 +#define PDM3_COEFFICIENT_B 0x4800 + +#define PDM_COEF_RAM_A_LENGTH 0x0400 +#define PDM_COEF_RAM_B_LENGTH 0x0400 + +/* Local registers in each PDMx */ + +/* Control register for CIC configuration and decimator setting */ +#define CIC_CONTROL 0x000 + +/* Control of the CIC filter plus voice channel (B) FIR decimation factor */ +#define CIC_CONFIG 0x004 + +/* Microphone interface control register */ +#define MIC_CONTROL 0x00c + +/* FIR config */ + +/* Control for the FIR decimator (channel A) */ +#define FIR_CONTROL_A 0x020 + +/* Configuration of FIR decimator parameters (channel A) */ +#define FIR_CONFIG_A 0x024 + +/* DC offset for left channel */ +#define DC_OFFSET_LEFT_A 0x028 + +/* DC offset for right channel */ +#define DC_OFFSET_RIGHT_A 0x02c + +/* Gain for left channel */ +#define OUT_GAIN_LEFT_A 0x030 + +/* Gain for right channel */ +#define OUT_GAIN_RIGHT_A 0x034 + +/* Control for the FIR decimator (channel B) */ +#define FIR_CONTROL_B 0x040 + +/* Configuration of FIR decimator parameters (channel B) */ +#define FIR_CONFIG_B 0x044 + +/* DC offset for left channel */ +#define DC_OFFSET_LEFT_B 0x048 + +/* DC offset for right channel */ +#define DC_OFFSET_RIGHT_B 0x04c + +/* Gain for left channel */ +#define OUT_GAIN_LEFT_B 0x050 + +/* Gain for right channel */ +#define OUT_GAIN_RIGHT_B 0x054 + +#define PDM_COEFFICIENT_A 0x400 +#define PDM_COEFFICIENT_B 0x800 + + +/* Digital Mic Shim Registers */ + +/* Digital Microphone Link Control */ +#define DMICLCTL 0x04 + +/* Digital Microphone IP Pointer */ +#define DMICIPPTR 0x08 + + +/* OUTCONTROL0 and OUTCONTROL1 */ + +/* OUTCONTROLx IPM bit fields style */ +#define OUTCONTROL_BFTH_MAX 4 /* Max depth 16 */ + +/* Threshold Interrupt Enable */ +#define OUTCONTROL_TIE BIT(27) + +/* Start Input Packer */ +#define OUTCONTROL_SIP BIT(26) + +/* FIFO Initialize (FINIT): The software will set this bit to immediately clear FIFO pointers. */ +#define OUTCONTROL_FINIT BIT(25) + +/* Input Format Change Indicator */ +#define OUTCONTROL_FCI BIT(24) + +/* Burst FIFO Threshold */ +#define OUTCONTROL_BFTH GENMASK(23, 20) + +/* Output Format */ +#define OUTCONTROL_OF GENMASK(19, 18) + + +/* This field decides the packer mode */ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +#define OUTCONTROL_IPM GENMASK(17, 15) +#else +#define OUTCONTROL_IPM GENMASK(17, 16) +#endif + +/* Source decimator for 1st stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_1 GENMASK(14, 13) + +/* Source decimator for 2nd stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_2 GENMASK(12, 11) + +/* Source decimator for 3rd stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_3 GENMASK(10, 9) + +/* Source decimator for 4th stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_4 GENMASK(8, 7) + +/* Defines the mode of operation for all source decimator. */ +#define OUTCONTROL_IPM_SOURCE_MODE BIT(6) + +/* FIFO Trigger Threshold */ +#define OUTCONTROL_TH GENMASK(5, 0) + + +/* OUTSTAT0 and OUTSTAT1 bits */ + +/* Asynchronous FIFO is empty */ +#define OUTSTAT_AFE BIT(31) + +/* Asynchronous FIFO Not Empty */ +#define OUTSTAT_ASNE BIT(29) + +/* FIFO Service Request */ +#define OUTSTAT_RFS BIT(28) + +/* Overrun */ +#define OUTSTAT_ROR BIT(27) + + /* FIFO Level (FL): Current FIFO Level in the Asynchronous FIFO. */ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +#define OUTSTAT_FL_MASK GENMASK(8, 0) +#else +#define OUTSTAT_FL_MASK GENMASK(6, 0) +#endif + + +/* CIC_CONTROL bits */ + +/* Microphone interface reset. */ +#define CIC_CONTROL_SOFT_RESET BIT(16) + +/* When set to 1, the CIC channel B (right) is started, otherwise it is muted and idle. */ +#define CIC_CONTROL_CIC_START_B BIT(15) + +/* When set to 1, the CIC channel A (left) is started, otherwise it is muted and idle. */ +#define CIC_CONTROL_CIC_START_A BIT(14) + +/* Polarity of the microphone output. */ +#define CIC_CONTROL_MIC_B_POLARITY BIT(3) + +/* Polarity of the microphone output. */ +#define CIC_CONTROL_MIC_A_POLARITY BIT(2) + +/* Mute currently active microphones */ +#define CIC_CONTROL_MIC_MUTE BIT(1) + +#ifndef CONFIG_SOC_SERIES_INTEL_ACE +/* When set, the microphone input operates in the stereo mode */ +#define CIC_CONTROL_STEREO_MODE BIT(0) +#endif + + +/* CIC_CONFIG masks */ + +/* Number of bits for shift right in the output stage of the CIC filter to compensate the gain + * accumulated due to decimation. + */ +#define CIC_CONFIG_CIC_SHIFT GENMASK(27, 24) + +/* Period of activation of comb section in the microphone clocks minus 1 */ +#define CIC_CONFIG_COMB_COUNT GENMASK(15, 8) + + +/* MIC_CONTROL */ + +/* Clock divider used for producing the microphone clock from audio IO clock with approximately 50% + * duty cycle. + */ +#define MIC_CONTROL_PDM_CLKDIV GENMASK(15, 8) + +#ifndef CONFIG_SOC_SERIES_INTEL_ACE +/* Selects the delay of the clocks output for microphones to align the sampling point of the data + * and clock edge. + */ +#define MIC_CONTROL_PDM_SKEW GENMASK(7, 4) +#endif +/* Inverts the clock edge that will be used to sample microphone data stream. */ +#define MIC_CONTROL_CLK_EDGE BIT(3) + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +/* Indicates the PDM DMIC clock for the decimator will be sourced from external component instead + * of using the PDM DMIC clock generator output + */ +#define MIC_CONTROL_SLAVE_MODE BIT(2) +#endif + +/* Enable clock on microphone B (Right) */ +#define MIC_CONTROL_PDM_EN_B BIT(1) + +/* Enable clock on microphone A (left) */ +#define MIC_CONTROL_PDM_EN_A BIT(0) + + +/* FIR_CONTROL_A bits */ + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +/* Enable the power gating capability of the coefficient. */ +#define FIR_CONTROL_CRFPGE BIT(28) + +/* Power gating capability of the left channel */ +#define FIR_CONTROL_LDRFPGE BIT(29) + +/* Enable the power gating capability of the right channel */ +#define FIR_CONTROL_RDRFPGE BIT(30) +#endif + +/* FIR decimation filter is started. */ +#define FIR_CONTROL_START BIT(7) + +/* Array microphone control bit for synchronous start of multiple interfaces. */ +#define FIR_CONTROL_ARRAY_START_EN BIT(6) + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +/* Periodic synchronous start control of multiple PDM */ +#define FIR_CONTROL_PERIODIC_START_EN BIT(5) +#endif + +/* Automatic DC compensation enable */ +#define FIR_CONTROL_DCCOMP BIT(4) + +/* Write in the coefficient memory will mute the output for the N audio clocks */ +#define FIR_CONTROL_AUTO_MUTE BIT(2) + +/* Mute outputs of this filter and set it to zero. */ +#define FIR_CONTROL_MUTE BIT(1) + +/* Filter operates in stereo mode */ +#define FIR_CONTROL_STEREO BIT(0) + + + /* FIR_CONFIG bits */ + +/* Decimation factor of the FIR filter minus 1. */ +#define FIR_CONFIG_FIR_DECIMATION GENMASK(20, 16) + +/* Number of bits for shift right in the output stage of the CIC filter to compensate the gain + * accumulated due to decimation. + */ +#define FIR_CONFIG_FIR_SHIFT GENMASK(11, 8) + +/* The number of active taps of the FIR filter minus 1. */ +#define FIR_CONFIG_FIR_LENGTH GENMASK(7, 0) + + +/* DC_OFFSET_LEFT and DC_OFFSET_RIGHT */ + +/* Value added to the output of the FIR filter. */ +#define DC_OFFSET_DC_OFFS GENMASK(21, 0) + + +/* OUT_GAIN_LEFT and OUT_GAIN_RIGHT */ + +/* Value added to the output of the FIR filter. */ +#define OUT_GAIN GENMASK(19, 0) + +/* FIR coefficients */ +#define FIR_COEF GENMASK(19, 0) + + +/* GLOBAL_CAPABILITIES */ + +/* Nnumber of data entries supported in the PCM XCLK FIFO per FIR output. */ +#define GLOBAL_CAP_PCM_XCLK_FIFO_DEPTH GENMASK(5, 0) + +/* Port Count */ +#define GLOBAL_CAP_PORT_COUNT GENMASK(7, 6) + +/* FIR Count */ +#define GLOBAL_CAP_FIR_COUNT BIT(8) + +/* FIR max gain configuration. */ +#define GLOBAL_CAP_FIR_MAX_GAIN BIT(9) + +/* FIR A RF Depth */ +#define GLOBAL_CAP_FIR_A_RF_DEPTH GENMASK(23, 16) + +/* FIR B RF Depth */ +#define GLOBAL_CAP_FIR_B_RF_DEPTH GENMASK(31, 24) + + +/* Digital Mic Shim Registers */ +#ifdef CONFIG_SOC_INTEL_ACE20_LNL +#include "dmic_regs_ace2x.h" +#else /* All other CAVS and ACE platforms */ +/* DMIC Link Control + * + * This register controls the specific link. + */ +#define DMICLCTL_OFFSET 0x04 + +/* Set Power Active */ +#define DMICLCTL_SPA BIT(0) + +/* Current Power Active */ +#define DMICLCTL_CPA BIT(8) + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +/* Owner Select */ +#define DMICLCTL_OSEL GENMASK(25, 24) + +/* Force Clock Gating */ +#define DMICLCTL_FCG BIT(26) + +/* Master Link Clock Select */ +#define DMICLCTL_MLCS GENMASK(29, 27) +#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ + +/* Dynamic Clock Gating Disable */ +#define DMICLCTL_DCGD BIT(30) + +/* Idle Clock Gating Disable */ +#define DMICLCTL_ICGD BIT(31) + + +#ifdef CONFIG_SOC_SERIES_INTEL_ACE +#include "dmic_regs_ace1x.h" +#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ + +#endif /* !CONFIG_SOC_INTEL_ACE20_LNL */ + +#endif /* !__INTEL_DAI_DRIVER_DMIC_REGS_H__ */ diff --git a/drivers/dai/intel/dmic/dmic_regs_ace1x.h b/drivers/dai/intel/dmic/dmic_regs_ace1x.h new file mode 100644 index 000000000000..e3abbe2076bf --- /dev/null +++ b/drivers/dai/intel/dmic/dmic_regs_ace1x.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ +#define __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ + +/* Digital Microphone Synchronization */ +#define DMICSYNC_OFFSET 0x0C + +/* DMIC Sync Period */ +#define DMICSYNC_SYNCPRD GENMASK(14, 0) + +/* Sync Period Update */ +#define DMICSYNC_SYNCPU BIT(15) + +/* Command Sync */ +#define DMICSYNC_CMDSYNC BIT(16) + +/* Sync Go */ +#define DMICSYNC_SYNCGO BIT(24) + +/* Extended Sync Period */ +#define DMICSYNC_ESYNCPRD BIT(25) + +#endif /* ! __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ */ diff --git a/drivers/dai/intel/dmic/dmic_regs_ace2x.h b/drivers/dai/intel/dmic/dmic_regs_ace2x.h new file mode 100644 index 000000000000..21008599ad1f --- /dev/null +++ b/drivers/dai/intel/dmic/dmic_regs_ace2x.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef __INTEL_DAI_DRIVER_DMIC_REGS_ACE2X_H__ +#define __INTEL_DAI_DRIVER_DMIC_REGS_ACE2X_H__ + +/* DMIC Link Synchronization */ +#define DMICSYNC_OFFSET 0x1C + +/* Sync Period */ +#define DMICSYNC_SYNCPRD GENMASK(19, 0) + +/* Sync Period Update */ +#define DMICSYNC_SYNCPU BIT(20) + +/* Sync Go */ +#define DMICSYNC_SYNCGO BIT(23) + +/* Command Sync */ +#define DMICSYNC_CMDSYNC BIT(24) + + +/* DMIC Link Control */ +#define DMICLCTL_OFFSET 0x04 + +/* Set Clock Frequency */ +#define DMICLCTL_SCF GENMASK(3, 0) + +/* Offload Enable */ +#define DMICLCTL_OFLEN BIT(4) + +/* Interrupt Enable */ +#define DMICLCTL_INTEN BIT(5) + +/* Set Power Active */ +#define DMICLCTL_SPA BIT(16) + +/* Current Power Active */ +#define DMICLCTL_CPA BIT(23) + +/* Interrupt Status */ +#define DMICLCTL_INTSTS BIT(31) + + +/* Digital Microphone x Link Vendor Specific Control */ +#define DMICLVSCTL_OFFSET 0x04 + +/* Force Clock Gating */ +#define DMICLVSCTL_FCG BIT(26) + +/* Host Link Clock Select */ +#define DMICLVSCTL_MLCS GENMASK(29, 27) + +/* Dynamic Clock Gating Disable */ +#define DMICLVSCTL_DCGD BIT(30) + +/* Idle Clock Gating Disable */ +#define DMICLVSCTL_ICGD BIT(31) + + +/* Digital Microphone PCM Stream y Channel Map + * + * Offset: 12h + 02h * y + */ +#define DMICXPCMSyCM_OFFSET 0x16 +#define DMICXPCMSyCM_SIZE 0x02 + +#endif /* !__INTEL_DAI_DRIVER_DMIC_REGS_ACE2X_H__ */ From 0ee64528168bf130b3cbf32a53692bac01f79ddd Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Thu, 20 Apr 2023 16:46:24 +0200 Subject: [PATCH 0403/2042] adsp: ace: dmic: Add missing registers definitions Added definitions with description of missing registers for ace platforms. Signed-off-by: Adrian Warecki --- drivers/dai/intel/dmic/dmic_regs_ace1x.h | 101 +++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/dai/intel/dmic/dmic_regs_ace1x.h b/drivers/dai/intel/dmic/dmic_regs_ace1x.h index e3abbe2076bf..c3bb5984bffb 100644 --- a/drivers/dai/intel/dmic/dmic_regs_ace1x.h +++ b/drivers/dai/intel/dmic/dmic_regs_ace1x.h @@ -8,6 +8,46 @@ #ifndef __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ #define __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ +/* Digital Mic Shim Registers */ + +/* Digital Microphone Link Capability */ +#define DMICLCAP_OFFSET 0x00 + +/* Link Count */ +#define DMICLCAP_LCOUNT GENMASK(2, 0) + +/* Cross Link Type Sync Supported */ +#define DMICLCAP_CLTSS BIT(5) + +/* Link Synchronization Supported */ +#define DMICLCAP_LSS BIT(6) + +/* Stream Channel Mapping Supported */ +#define DMICLCAP_SCMS BIT(7) + +/* Master Link Clock Select */ +#define DMICLCAP_MLCS BIT(8) + +/* PREQ/WakeUp */ +#define DMICLCAP_PW BIT(26) + +/* Owner Select */ +#define DMICLCAP_OSEL BIT(27) + +/* Power Gating Domain */ +#define DMICLCAP_PGD GENMASK(30, 28) + + +/* Digital Microphone IP Pointer */ +#define DMICIPPTR_OFFSET 0x08 + +/* IP Pointer */ +#define DMICIPPTR_PTR GENMASK(20, 0) + +/* IP Version */ +#define DMICIPPTR_VER GENMASK(23, 21) + + /* Digital Microphone Synchronization */ #define DMICSYNC_OFFSET 0x0C @@ -26,4 +66,65 @@ /* Extended Sync Period */ #define DMICSYNC_ESYNCPRD BIT(25) + +/* Digital Microphone PCM Stream Capabilities */ +#define DMICPCMSCAP_OFFSET 0x10 + +/* Number of Input Streams Supported */ +#define DMICPCMSCAP_ISS GENMASK(3, 0) + +/* Number of Output Streams Supported */ +#define DMICPCMSCAP_OSS GENMASK(7, 4) + +/* Number of Bidirectional Streams Supported */ +#define DMICPCMSCAP_BSS GENMASK(12, 8) + + +/* Digital Microphone PCM Stream y Channel Map + * + * Offset: 12h + 02h * y + */ +#define DMICPCMSyCM_OFFSET 0x12 +#define DMICPCMSyCM_SIZE 0x02 + +/* Lowest Channel */ +#define DMICPCMSyCM_LCHAN GENMASK(3, 0) + +/* Highest Channel */ +#define DMICPCMSyCM_HCHAN GENMASK(7, 4) + +/* Stream */ +#define DMICPCMSyCM_STRM GENMASK(13, 8) + + +/* Digital Microphone PCM Stream y Channel Count + * + * Offset: 18h + 02h * y + */ +#define DMICPCMSyCHC_OFFSET 0x18 +#define DMICPCMSyCHC_SIZE 0x02 + +/* Number of Channel Supported */ +#define DMICPCMSyCHC_CS GENMASK(3, 0) + + +/* Digital Microphone Port y PDM SoundWire Map + * + * Offset: 20h + y * 02h + */ +#define DMICPyPDMSM_OFFSET 0x20 +#define DMICPyPDMSM_SIZE 0x02 + +/* Left Channel SoundWire Bus Segment */ +#define DMICPyPDMSM_LCSBS GENMASK(1, 0) + +/* Right Channel SoundWire Bus Segment */ +#define DMICPyPDMSM_RCSBS GENMASK(3, 2) + +/* SoundWire Select */ +#define DMICPyPDMSM_SNDWSEL BIT(4) + +/* Stereo */ +#define DMICPyPDMSM_STR BIT(5) + #endif /* ! __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ */ From b9e5cf5110ace2900d4f6f35dbcdeff744f54fac Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 24 Apr 2023 12:49:44 +0200 Subject: [PATCH 0404/2042] adsp: ace: ace_dfpmccu structure field description Added ace_dfpmccu structure field descriptions to make the code more readable. Signed-off-by: Adrian Warecki --- .../ace/include/intel_ace15_mtpm/adsp_shim.h | 48 +++++++++++++++++++ .../ace/include/intel_ace20_lnl/adsp_shim.h | 48 +++++++++++++++++++ 2 files changed, 96 insertions(+) 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 229e3c7d8211..a2b4c87bc15e 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 @@ -33,34 +33,82 @@ struct ace_dfpmcch { * and clock control operation for DSP FW. */ struct ace_dfpmccu { + /* Power Management / Clock Capability */ uint32_t dfpmccap; /* Offset: 0x00 */ + + /* HP RING Oscillator Clock Frequency */ uint32_t dfhrosccf; /* Offset: 0x04 */ + + /* XTAL Oscillator Clock Frequency */ uint32_t dfxosccf; /* Offset: 0x08 */ + + /* LP RING Oscillator Clock Frequency */ uint32_t dflrosccf; /* Offset: 0x0c */ + + /* Serial I/O RING Oscillator Clock Frequency */ uint32_t dfsiorosccf; /* Offset: 0x10 */ + + /* High Speed I/O RING Oscillator Clock Frequency */ uint32_t dfhsiorosccf; /* Offset: 0x14 */ + + /* Integrated PLL / ROSC Clock Frequency */ uint32_t dfipllrosccf; /* Offset: 0x18 */ + + /* Integrated RING Oscillator Clock Voltage */ uint32_t dfirosccv; /* Offset: 0x1c */ + + /* Fabric Clock Frequency Divider */ uint32_t dffbrcfd; /* Offset: 0x20 */ + + /* ACE PLL IP Pointer */ uint32_t dfapllptr; /* Offset: 0x24 */ uint32_t _unused0[20]; + + /* Clock Control */ uint32_t dfclkctl; /* Offset: 0x78 */ + + /* Clock Status */ uint32_t dfclksts; /* Offset: 0x7c */ + + /* Integrated Clock Control Register */ uint32_t dfintclkctl; /* Offset: 0x80 */ + + /* Integrated Clock Status Register */ uint32_t dfcrosts; /* Offset: 0x84 */ + + /* Integrated Clock Divider Register */ uint32_t dfcrodiv; /* Offset: 0x88 */ uint32_t _unused1[1]; + + /* Power Control */ uint16_t dfpwrctl; /* Offset: 0x90 */ + + /* Power Status */ uint16_t dfpwrsts; /* Offset: 0x92 */ uint32_t _unused2[1]; + + /* Low Power Sequencer DMA Select 0 */ uint32_t dflpsdmas0; /* Offset: 0x98 */ + + /* Low Power Sequencer DMA Select 1 */ uint32_t dflpsdmas1; /* Offset: 0x9c */ + uint32_t _unused3[1]; + + /* LDO Control */ uint32_t dfldoctl; /* Offset: 0xa4 */ uint32_t _unused4[2]; + + /* Low Power Sequencer Audio Link Hub Stream Select 0 */ uint32_t dflpsalhsso; /* Offset: 0xb0 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 1 */ uint32_t dflpsalhss1; /* Offset: 0xb4 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 2 */ uint32_t dflpsalhss2; /* Offset: 0xb8 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 3 */ uint32_t dflpsalhss3; /* Offset: 0xbc */ uint32_t _unused5[10]; }; 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 8fcdf0a7be04..363feb14fa0e 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 @@ -33,34 +33,82 @@ struct ace_dfpmcch { * and clock control operation for DSP FW. */ struct ace_dfpmccu { + /* Power Management / Clock Capability */ uint32_t dfpmccap; /* Offset: 0x00 */ + + /* HP RING Oscillator Clock Frequency */ uint32_t dfhrosccf; /* Offset: 0x04 */ + + /* XTAL Oscillator Clock Frequency */ uint32_t dfxosccf; /* Offset: 0x08 */ + + /* LP RING Oscillator Clock Frequency */ uint32_t dflrosccf; /* Offset: 0x0c */ + + /* Serial I/O RING Oscillator Clock Frequency */ uint32_t dfsiorosccf; /* Offset: 0x10 */ + + /* High Speed I/O RING Oscillator Clock Frequency */ uint32_t dfhsiorosccf; /* Offset: 0x14 */ + + /* Integrated PLL / ROSC Clock Frequency */ uint32_t dfipllrosccf; /* Offset: 0x18 */ + + /* Integrated RING Oscillator Clock Voltage */ uint32_t dfirosccv; /* Offset: 0x1c */ + + /* Fabric Clock Frequency Divider */ uint32_t dffbrcfd; /* Offset: 0x20 */ + + /* ACE PLL IP Pointer */ uint32_t dfapllptr; /* Offset: 0x24 */ uint32_t _unused0[20]; + + /* Clock Control */ uint32_t dfclkctl; /* Offset: 0x78 */ + + /* Clock Status */ uint32_t dfclksts; /* Offset: 0x7c */ + + /* Integrated Clock Control Register */ uint32_t dfintclkctl; /* Offset: 0x80 */ + + /* Integrated Clock Status Register */ uint32_t dfcrosts; /* Offset: 0x84 */ + + /* Integrated Clock Divider Register */ uint32_t dfcrodiv; /* Offset: 0x88 */ uint32_t _unused1[1]; + + /* Power Control */ uint16_t dfpwrctl; /* Offset: 0x90 */ + + /* Power Status */ uint16_t dfpwrsts; /* Offset: 0x92 */ uint32_t _unused2[1]; + + /* Low Power Sequencer DMA Select 0 */ uint32_t dflpsdmas0; /* Offset: 0x98 */ + + /* Low Power Sequencer DMA Select 1 */ uint32_t dflpsdmas1; /* Offset: 0x9c */ + uint32_t _unused3[1]; + + /* LDO Control */ uint32_t dfldoctl; /* Offset: 0xa4 */ uint32_t _unused4[2]; + + /* Low Power Sequencer Audio Link Hub Stream Select 0 */ uint32_t dflpsalhsso; /* Offset: 0xb0 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 1 */ uint32_t dflpsalhss1; /* Offset: 0xb4 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 2 */ uint32_t dflpsalhss2; /* Offset: 0xb8 */ + + /* Low Power Sequencer Audio Link Hub Stream Select 3 */ uint32_t dflpsalhss3; /* Offset: 0xbc */ uint32_t _unused5[10]; }; From 1a4bc7580bab0ecf765f74152b871084613c5cca Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 24 Apr 2023 13:02:27 +0200 Subject: [PATCH 0405/2042] adsp: Rename cpu clock related functions The word cpu was added to the names of functions, structs, types and definitions to disambiguate the names and make room in the namespace for soc clock control functions. Signed-off-by: Adrian Warecki --- drivers/clock_control/clock_control_adsp.c | 2 +- soc/xtensa/intel_adsp/common/clk.c | 28 ++++++++--------- .../intel_adsp/common/include/adsp_clk.h | 24 +++++++-------- .../clock_control/adsp_clock/src/main.c | 30 +++++++++---------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/drivers/clock_control/clock_control_adsp.c b/drivers/clock_control/clock_control_adsp.c index b9f10516d61e..adcab94b9a79 100644 --- a/drivers/clock_control/clock_control_adsp.c +++ b/drivers/clock_control/clock_control_adsp.c @@ -13,7 +13,7 @@ static int cavs_clock_ctrl_set_rate(const struct device *clk, { uint32_t freq_idx = (uint32_t)rate; - return adsp_clock_set_freq(freq_idx); + return adsp_clock_set_cpu_freq(freq_idx); } static int cavs_clock_ctrl_init(const struct device *dev) diff --git a/soc/xtensa/intel_adsp/common/clk.c b/soc/xtensa/intel_adsp/common/clk.c index 4bf76af274ba..679e04a16c2a 100644 --- a/soc/xtensa/intel_adsp/common/clk.c +++ b/soc/xtensa/intel_adsp/common/clk.c @@ -13,11 +13,11 @@ #include #include -static struct adsp_clock_info platform_clocks[CONFIG_MP_MAX_NUM_CPUS]; +static struct adsp_cpu_clock_info platform_cpu_clocks[CONFIG_MP_MAX_NUM_CPUS]; static struct k_spinlock lock; -int adsp_clock_freq_enc[] = ADSP_CLOCK_FREQ_ENC; -int adsp_clock_freq_mask[] = ADSP_CLOCK_FREQ_MASK; +int adsp_clock_freq_enc[] = ADSP_CPU_CLOCK_FREQ_ENC; +int adsp_clock_freq_mask[] = ADSP_CPU_CLOCK_FREQ_MASK; static void select_cpu_clock_hw(uint32_t freq_idx) { @@ -40,12 +40,12 @@ static void select_cpu_clock_hw(uint32_t freq_idx) ADSP_CLKCTL &= ~ADSP_CLKCTL_OSC_REQUEST_MASK | enc; } -int adsp_clock_set_freq(uint32_t freq_idx) +int adsp_clock_set_cpu_freq(uint32_t freq_idx) { k_spinlock_key_t k; int i; - if (freq_idx >= ADSP_CLOCK_FREQ_LEN) { + if (freq_idx >= ADSP_CPU_CLOCK_FREQ_LEN) { return -EINVAL; } @@ -56,7 +56,7 @@ int adsp_clock_set_freq(uint32_t freq_idx) unsigned int num_cpus = arch_num_cpus(); for (i = 0; i < num_cpus; i++) { - platform_clocks[i].current_freq = freq_idx; + platform_cpu_clocks[i].current_freq = freq_idx; } k_spin_unlock(&lock, k); @@ -64,14 +64,14 @@ int adsp_clock_set_freq(uint32_t freq_idx) return 0; } -struct adsp_clock_info *adsp_clocks_get(void) +struct adsp_cpu_clock_info *adsp_cpu_clocks_get(void) { - return platform_clocks; + return platform_cpu_clocks; } void adsp_clock_init(void) { - uint32_t platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LOWEST; + uint32_t platform_lowest_freq_idx = ADSP_CPU_CLOCK_FREQ_LOWEST; int i; #ifdef ADSP_CLOCK_HAS_WOVCRO @@ -80,14 +80,14 @@ void adsp_clock_init(void) if (ACE_DfPMCCU.dfclkctl & ACE_CLKCTL_WOVCRO) { ACE_DfPMCCU.dfclkctl = ACE_DfPMCCU.dfclkctl & ~ACE_CLKCTL_WOVCRO; } else { - platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LPRO; + platform_lowest_freq_idx = ADSP_CPU_CLOCK_FREQ_LPRO; } #else CAVS_SHIM.clkctl |= CAVS_CLKCTL_WOVCRO; if (CAVS_SHIM.clkctl & CAVS_CLKCTL_WOVCRO) { CAVS_SHIM.clkctl = CAVS_SHIM.clkctl & ~CAVS_CLKCTL_WOVCRO; } else { - platform_lowest_freq_idx = ADSP_CLOCK_FREQ_LPRO; + platform_lowest_freq_idx = ADSP_CPU_CLOCK_FREQ_LPRO; } #endif /* CONFIG_SOC_SERIES_INTEL_ACE */ #endif /* ADSP_CLOCK_HAS_WOVCRO */ @@ -95,8 +95,8 @@ void adsp_clock_init(void) unsigned int num_cpus = arch_num_cpus(); for (i = 0; i < num_cpus; i++) { - platform_clocks[i].default_freq = ADSP_CLOCK_FREQ_DEFAULT; - platform_clocks[i].current_freq = ADSP_CLOCK_FREQ_DEFAULT; - platform_clocks[i].lowest_freq = platform_lowest_freq_idx; + platform_cpu_clocks[i].default_freq = ADSP_CPU_CLOCK_FREQ_DEFAULT; + platform_cpu_clocks[i].current_freq = ADSP_CPU_CLOCK_FREQ_DEFAULT; + platform_cpu_clocks[i].lowest_freq = platform_lowest_freq_idx; } } diff --git a/soc/xtensa/intel_adsp/common/include/adsp_clk.h b/soc/xtensa/intel_adsp/common/include/adsp_clk.h index 166a0b994be4..c2c7fa2d5405 100644 --- a/soc/xtensa/intel_adsp/common/include/adsp_clk.h +++ b/soc/xtensa/intel_adsp/common/include/adsp_clk.h @@ -9,7 +9,7 @@ #include #include -struct adsp_clock_info { +struct adsp_cpu_clock_info { uint32_t default_freq; uint32_t current_freq; uint32_t lowest_freq; @@ -25,7 +25,7 @@ void adsp_clock_init(void); * * @return 0 on success, -EINVAL if freq_idx is not valid */ -int adsp_clock_set_freq(uint32_t freq_idx); +int adsp_clock_set_cpu_freq(uint32_t freq_idx); /** @brief Get list of cAVS clock information * @@ -33,7 +33,7 @@ int adsp_clock_set_freq(uint32_t freq_idx); * * @return array with clock information */ -struct adsp_clock_info *adsp_clocks_get(void); +struct adsp_cpu_clock_info *adsp_cpu_clocks_get(void); /* Device tree defined constants */ #ifdef CONFIG_SOC_SERIES_INTEL_ACE @@ -42,23 +42,23 @@ struct adsp_clock_info *adsp_clocks_get(void); #define ADSP_CLKCTL CAVS_SHIM.clkctl #endif -#define ADSP_CLOCK_FREQ_ENC DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) -#define ADSP_CLOCK_FREQ_MASK DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_mask) -#define ADSP_CLOCK_FREQ_LEN DT_PROP_LEN(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) +#define ADSP_CPU_CLOCK_FREQ_ENC DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) +#define ADSP_CPU_CLOCK_FREQ_MASK DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_mask) +#define ADSP_CPU_CLOCK_FREQ_LEN DT_PROP_LEN(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) -#define ADSP_CLOCK_FREQ_DEFAULT DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_default) -#define ADSP_CLOCK_FREQ_LOWEST DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_lowest) +#define ADSP_CPU_CLOCK_FREQ_DEFAULT DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_default) +#define ADSP_CPU_CLOCK_FREQ_LOWEST DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_lowest) -#define ADSP_CLOCK_FREQ(name) DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_clk_##name) +#define ADSP_CPU_CLOCK_FREQ(name) DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_clk_##name) #if DT_PROP(DT_NODELABEL(clkctl), wovcro_supported) #define ADSP_CLOCK_HAS_WOVCRO #endif -#define ADSP_CLOCK_FREQ_LPRO ADSP_CLOCK_FREQ(lpro) -#define ADSP_CLOCK_FREQ_HPRO ADSP_CLOCK_FREQ(hpro) +#define ADSP_CPU_CLOCK_FREQ_LPRO ADSP_CPU_CLOCK_FREQ(lpro) +#define ADSP_CPU_CLOCK_FREQ_HPRO ADSP_CPU_CLOCK_FREQ(hpro) #ifdef ADSP_CLOCK_HAS_WOVCRO -#define ADSP_CLOCK_FREQ_WOVCRO ADSP_CLOCK_FREQ(wovcro) +#define ADSP_CPU_CLOCK_FREQ_WOVCRO ADSP_CPU_CLOCK_FREQ(wovcro) #endif #endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_CLK_H_ */ diff --git a/tests/drivers/clock_control/adsp_clock/src/main.c b/tests/drivers/clock_control/adsp_clock/src/main.c index f4977c1d4fcd..c4af442d2a64 100644 --- a/tests/drivers/clock_control/adsp_clock/src/main.c +++ b/tests/drivers/clock_control/adsp_clock/src/main.c @@ -7,7 +7,7 @@ #include #include -static void check_clocks(struct adsp_clock_info *clocks, uint32_t freq_idx) +static void check_clocks(struct adsp_cpu_clock_info *clocks, uint32_t freq_idx) { int i; unsigned int num_cpus = arch_num_cpus(); @@ -19,41 +19,41 @@ static void check_clocks(struct adsp_clock_info *clocks, uint32_t freq_idx) ZTEST(adsp_clock_control, test_adsp_clock_driver) { - struct adsp_clock_info *clocks = adsp_clocks_get(); + struct adsp_cpu_clock_info *clocks = adsp_cpu_clocks_get(); zassert_not_null(clocks, ""); - adsp_clock_set_freq(ADSP_CLOCK_FREQ_LPRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_LPRO); + adsp_clock_set_cpu_freq(ADSP_CPU_CLOCK_FREQ_LPRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_LPRO); - adsp_clock_set_freq(ADSP_CLOCK_FREQ_HPRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_HPRO); + adsp_clock_set_cpu_freq(ADSP_CPU_CLOCK_FREQ_HPRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_HPRO); #ifdef ADSP_CLOCK_HAS_WOVCRO - adsp_clock_set_freq(ADSP_CLOCK_FREQ_WOVCRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_WOVCRO); + adsp_clock_set_cpu_freq(ADSP_CPU_CLOCK_FREQ_WOVCRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_WOVCRO); #endif } ZTEST(adsp_clock_control, test_adsp_clock_control) { - struct adsp_clock_info *clocks = adsp_clocks_get(); + struct adsp_cpu_clock_info *clocks = adsp_cpu_clocks_get(); const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(clkctl)); zassert_not_null(clocks, ""); clock_control_set_rate(dev, NULL, (clock_control_subsys_rate_t) - ADSP_CLOCK_FREQ_LPRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_LPRO); + ADSP_CPU_CLOCK_FREQ_LPRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_LPRO); clock_control_set_rate(dev, NULL, (clock_control_subsys_rate_t) - ADSP_CLOCK_FREQ_HPRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_HPRO); + ADSP_CPU_CLOCK_FREQ_HPRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_HPRO); #ifdef ADSP_CLOCK_HAS_WOVCRO clock_control_set_rate(dev, NULL, (clock_control_subsys_rate_t) - ADSP_CLOCK_FREQ_WOVCRO); - check_clocks(clocks, ADSP_CLOCK_FREQ_WOVCRO); + ADSP_CPU_CLOCK_FREQ_WOVCRO); + check_clocks(clocks, ADSP_CPU_CLOCK_FREQ_WOVCRO); #endif } ZTEST_SUITE(adsp_clock_control, NULL, NULL, NULL, NULL, NULL); From 64b2246dbcb988caab7b2499653b50738b70123a Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Thu, 20 Apr 2023 16:46:57 +0200 Subject: [PATCH 0406/2042] soc: adsp: clk: Add multiple clock sources support for dai Added a new function to check whether a clock source is supported by a platform and to retrieve its frequency. Signed-off-by: Adrian Warecki --- soc/xtensa/intel_adsp/common/clk.c | 39 +++++++++++++ .../intel_adsp/common/include/adsp_clk.h | 58 +++++++++++++++---- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/soc/xtensa/intel_adsp/common/clk.c b/soc/xtensa/intel_adsp/common/clk.c index 679e04a16c2a..696f05c0cc21 100644 --- a/soc/xtensa/intel_adsp/common/clk.c +++ b/soc/xtensa/intel_adsp/common/clk.c @@ -100,3 +100,42 @@ void adsp_clock_init(void) platform_cpu_clocks[i].lowest_freq = platform_lowest_freq_idx; } } + +struct adsp_clock_source_desc adsp_clk_src_info[ADSP_CLOCK_SOURCE_COUNT] = { +#ifndef CONFIG_DAI_DMIC_HW_IOCLK + [ADSP_CLOCK_SOURCE_XTAL_OSC] = { DT_PROP(DT_NODELABEL(sysclk), clock_frequency) }, +#else + /* Temporarily use the values from the configuration until set xtal frequency via ipc + * support is added. + */ + [ADSP_CLOCK_SOURCE_XTAL_OSC] = { CONFIG_DAI_DMIC_HW_IOCLK }, +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(audioclk), okay) + [ADSP_CLOCK_SOURCE_AUDIO_CARDINAL] = { DT_PROP(DT_NODELABEL(audioclk), clock_frequency) }, +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pllclk), okay) + [ADSP_CLOCK_SOURCE_AUDIO_PLL_FIXED] = { DT_PROP(DT_NODELABEL(pllclk), clock_frequency) }, +#endif + [ADSP_CLOCK_SOURCE_MLCK_INPUT] = { 0 }, +#ifdef ADSP_CLOCK_HAS_WOVCRO + [ADSP_CLOCK_SOURCE_WOV_RING_OSC] = { DT_PROP(DT_NODELABEL(sysclk), clock_frequency) }, +#endif +}; + +bool adsp_clock_source_is_supported(int source) +{ + if (source < 0 || source >= ADSP_CLOCK_SOURCE_COUNT) { + return false; + } + + return !!adsp_clk_src_info[source].frequency; +} + +uint32_t adsp_clock_source_frequency(int source) +{ + if (source < 0 || source >= ADSP_CLOCK_SOURCE_COUNT) { + return 0; + } + + return adsp_clk_src_info[source].frequency; +} diff --git a/soc/xtensa/intel_adsp/common/include/adsp_clk.h b/soc/xtensa/intel_adsp/common/include/adsp_clk.h index c2c7fa2d5405..94d2cb07c00f 100644 --- a/soc/xtensa/intel_adsp/common/include/adsp_clk.h +++ b/soc/xtensa/intel_adsp/common/include/adsp_clk.h @@ -42,23 +42,57 @@ struct adsp_cpu_clock_info *adsp_cpu_clocks_get(void); #define ADSP_CLKCTL CAVS_SHIM.clkctl #endif -#define ADSP_CPU_CLOCK_FREQ_ENC DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) -#define ADSP_CPU_CLOCK_FREQ_MASK DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_mask) -#define ADSP_CPU_CLOCK_FREQ_LEN DT_PROP_LEN(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) +#define ADSP_CPU_CLOCK_FREQ_ENC DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) +#define ADSP_CPU_CLOCK_FREQ_MASK DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_mask) +#define ADSP_CPU_CLOCK_FREQ_LEN DT_PROP_LEN(DT_NODELABEL(clkctl), adsp_clkctl_freq_enc) -#define ADSP_CPU_CLOCK_FREQ_DEFAULT DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_default) -#define ADSP_CPU_CLOCK_FREQ_LOWEST DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_lowest) +#define ADSP_CPU_CLOCK_FREQ_DEFAULT DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_default) +#define ADSP_CPU_CLOCK_FREQ_LOWEST DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_freq_lowest) -#define ADSP_CPU_CLOCK_FREQ(name) DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_clk_##name) +#define ADSP_CPU_CLOCK_FREQ(name) DT_PROP(DT_NODELABEL(clkctl), adsp_clkctl_clk_##name) -#if DT_PROP(DT_NODELABEL(clkctl), wovcro_supported) -#define ADSP_CLOCK_HAS_WOVCRO +#define ADSP_CLOCK_HAS_WOVCRO DT_PROP(DT_NODELABEL(clkctl), wovcro_supported) + +#define ADSP_CPU_CLOCK_FREQ_LPRO ADSP_CPU_CLOCK_FREQ(lpro) +#define ADSP_CPU_CLOCK_FREQ_HPRO ADSP_CPU_CLOCK_FREQ(hpro) +#if ADSP_CLOCK_HAS_WOVCRO +#define ADSP_CPU_CLOCK_FREQ_WOVCRO ADSP_CPU_CLOCK_FREQ(wovcro) +#endif + + +/* Clock sources used by dai */ +#define ADSP_CLOCK_SOURCE_XTAL_OSC 0 +#if DT_NODE_HAS_STATUS(DT_NODELABEL(audioclk), okay) +#define ADSP_CLOCK_SOURCE_AUDIO_CARDINAL 1 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(pllclk), okay) +#define ADSP_CLOCK_SOURCE_AUDIO_PLL_FIXED 2 #endif -#define ADSP_CPU_CLOCK_FREQ_LPRO ADSP_CPU_CLOCK_FREQ(lpro) -#define ADSP_CPU_CLOCK_FREQ_HPRO ADSP_CPU_CLOCK_FREQ(hpro) -#ifdef ADSP_CLOCK_HAS_WOVCRO -#define ADSP_CPU_CLOCK_FREQ_WOVCRO ADSP_CPU_CLOCK_FREQ(wovcro) +#define ADSP_CLOCK_SOURCE_MLCK_INPUT 3 +#if ADSP_CLOCK_HAS_WOVCRO +#define ADSP_CLOCK_SOURCE_WOV_RING_OSC 4 #endif +#define ADSP_CLOCK_SOURCE_COUNT 5 + +struct adsp_clock_source_desc { + uint32_t frequency; +}; + +/** @brief Check if clock source is supported + * + * @param freq Clock frequency index + * + * @return true if clock source is supported + */ +bool adsp_clock_source_is_supported(int source); + +/** @brief Get clock source frequency + * + * @param freq Clock frequency index + * + * @return frequency on success, 0 on error + */ +uint32_t adsp_clock_source_frequency(int source); #endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_CLK_H_ */ From 2958a407f8f115c70e39e15299b629dc418d0a1b Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Thu, 20 Apr 2023 16:47:55 +0200 Subject: [PATCH 0407/2042] adsp: dmic: Add source clock selection support The dmic driver has been expanded to support different clock sources. Signed-off-by: Adrian Warecki --- drivers/dai/intel/dmic/dmic.h | 4 +- drivers/dai/intel/dmic/dmic_nhlt.c | 83 +++++++++++++++++++++++++- tests/boards/intel_adsp/ssp/src/main.c | 11 ++++ 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/drivers/dai/intel/dmic/dmic.h b/drivers/dai/intel/dmic/dmic.h index da1b486938d4..896c5fa0959e 100644 --- a/drivers/dai/intel/dmic/dmic.h +++ b/drivers/dai/intel/dmic/dmic.h @@ -150,7 +150,9 @@ struct nhlt_dmic_clock_on_delay { }; struct nhlt_dmic_channel_ctrl_mask { - uint32_t channel_ctrl_mask; + uint8_t channel_ctrl_mask; + uint8_t clock_source; + uint16_t rsvd; }; struct nhlt_pdm_ctrl_mask { diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index c9b00a204261..621060a7baf6 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -13,6 +13,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include +#include #include "dmic.h" #include "dmic_regs.h" @@ -125,6 +126,68 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, return 0; } + + +/* + * @brief Set clock source used by device + * + * @param source Clock source index + */ +static inline void dai_dmic_clock_select_set(const struct dai_intel_dmic *dmic, uint32_t source) +{ + uint32_t val; +#ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ + val = sys_read32(dmic->vshim_base + DMICLVSCTL_OFFSET); + val &= ~DMICLVSCTL_MLCS; + val |= FIELD_PREP(DMICLVSCTL_MLCS, source); + sys_write32(val, dmic->vshim_base + DMICLVSCTL_OFFSET); +#else + val = sys_read32(dmic->shim_base + DMICLCTL_OFFSET); + val &= ~DMICLCTL_MLCS; + val |= FIELD_PREP(DMICLCTL_MLCS, source); + sys_write32(val, dmic->shim_base + DMICLCTL_OFFSET); +#endif +} + +/* + * @brief Get clock source used by device + * + * @return Clock source index + */ +static inline uint32_t dai_dmic_clock_select_get(const struct dai_intel_dmic *dmic) +{ + uint32_t val; +#ifdef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ + val = sys_read32(dmic->vshim_base + DMICLVSCTL_OFFSET); + return FIELD_GET(DMICLVSCTL_MLCS, val); +#else + val = sys_read32(dmic->shim_base + DMICLCTL_OFFSET); + return FIELD_GET(DMICLCTL_MLCS, val); +#endif +} + +/* + * @brief Set clock source used by device + * + * @param source Clock source index + */ +static int dai_dmic_set_clock(const struct dai_intel_dmic *dmic, const uint8_t clock_source) +{ + LOG_DBG("%s(): clock_source = %u", __func__, clock_source); + + if (!adsp_clock_source_is_supported(clock_source)) { + return -ENOTSUP; + } + +#ifndef CONFIG_SOC_INTEL_ACE20_LNL /* Ace 2.0 */ + if (clock_source && !(sys_read32(dmic->shim_base + DMICLCAP_OFFSET) & DMICLCAP_MLCS)) { + return -ENOTSUP; + } +#endif + + dai_dmic_clock_select_set(dmic, clock_source); + return 0; +} #else static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, int32_t *outcontrol, @@ -204,6 +267,11 @@ static int dai_nhlt_dmic_dai_params_get(struct dai_intel_dmic *dmic, return 0; } + +static inline int dai_dmic_set_clock(const struct dai_intel_dmic *dmic, const uint8_t clock_source) +{ + return 0; +} #endif int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cfg) @@ -213,6 +281,8 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf struct nhlt_pdm_ctrl_fir_cfg *fir_cfg_b[DMIC_HW_CONTROLLERS_MAX]; struct nhlt_pdm_fir_coeffs *fir_a[DMIC_HW_CONTROLLERS_MAX] = {NULL}; struct nhlt_pdm_fir_coeffs *fir_b[DMIC_HW_CONTROLLERS_MAX]; + struct nhlt_dmic_channel_ctrl_mask *dmic_cfg; + uint32_t out_control[DMIC_HW_FIFOS_MAX] = {0}; uint32_t channel_ctrl_mask; uint32_t fir_control; @@ -253,11 +323,17 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf p += sizeof(struct nhlt_dmic_clock_on_delay); /* Channel_ctlr_mask bits indicate the FIFOs enabled*/ - channel_ctrl_mask = ((struct nhlt_dmic_channel_ctrl_mask *)p)->channel_ctrl_mask; + dmic_cfg = (struct nhlt_dmic_channel_ctrl_mask *)p; + channel_ctrl_mask = dmic_cfg->channel_ctrl_mask; num_fifos = POPCOUNT(channel_ctrl_mask); /* Count set bits */ p += sizeof(struct nhlt_dmic_channel_ctrl_mask); LOG_DBG("dmic_set_config_nhlt(): channel_ctrl_mask = %d", channel_ctrl_mask); + /* Configure clock source */ + ret = dai_dmic_set_clock(dmic, dmic_cfg->clock_source); + if (ret) + return ret; + /* Get OUTCONTROLx configuration */ if (num_fifos < 1 || num_fifos > DMIC_HW_FIFOS_MAX) { LOG_ERR("dmic_set_config_nhlt(): illegal number of FIFOs %d", num_fifos); @@ -623,13 +699,14 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf return -EINVAL; } - dmic->dai_config_params.rate = CONFIG_DAI_DMIC_HW_IOCLK / rate_div; + dmic->dai_config_params.rate = adsp_clock_source_frequency(dmic_cfg->clock_source) / + rate_div; LOG_INF("dmic_set_config_nhlt(): rate = %d, channels = %d, format = %d", dmic->dai_config_params.rate, dmic->dai_config_params.channels, dmic->dai_config_params.format); LOG_INF("dmic_set_config_nhlt(): io_clk %u, rate_div %d", - CONFIG_DAI_DMIC_HW_IOCLK, rate_div); + adsp_clock_source_frequency(dmic_cfg->clock_source), rate_div); LOG_INF("dmic_set_config_nhlt(): enable0 %u, enable1 %u", dmic->enable[0], dmic->enable[1]); diff --git a/tests/boards/intel_adsp/ssp/src/main.c b/tests/boards/intel_adsp/ssp/src/main.c index 67d9e29f79b2..7ba608e4bbb4 100644 --- a/tests/boards/intel_adsp/ssp/src/main.c +++ b/tests/boards/intel_adsp/ssp/src/main.c @@ -407,4 +407,15 @@ static void *adsp_ssp_setup(void) return NULL; } + +bool adsp_clock_source_is_supported(int source) +{ + return true; +} + +uint32_t adsp_clock_source_frequency(int source) +{ + return 0; +} + ZTEST_SUITE(adsp_ssp, NULL, adsp_ssp_setup, NULL, NULL, NULL); From 732dd4843dc5c21f83f17d97bbafbfad8a3bf91a Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Tue, 20 Jun 2023 11:00:08 +0200 Subject: [PATCH 0408/2042] twister: pytest: Simplify interface to pytest-twister-harness Add DeviceAbstract class to default imports from pytest-twister-harness package to simplify importing DUT package, when creating tests. Signed-off-by: Grzegorz Chwierut --- doc/develop/test/pytest.rst | 10 ++++------ .../subsys/testsuite/pytest/shell/pytest/test_shell.py | 10 +++++----- .../src/twister_harness/__init__.py | 6 ++++++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index 8c6448bd96b2..48eb2cf8eda8 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -57,16 +57,14 @@ Pytest scans the given folder looking for tests, following its default 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’]``. -Two imports are important to include in .py sources: +Following import is required to include in .py sources: .. code-block:: python - import pytest # noqa # pylint: disable=unused-import - from pytest_twister_harness.device.device_abstract import DeviceAbstract + from twister_harness import Device -The first enables pytest-twister-harness plugin indirectly, as it is added with pytest. -It also gives access to ``dut`` fixture. The second is important for type checking and enabling -IDE hints for duts. The ``dut`` fixture is the core of pytest harness plugin. When used as an +It is important for type checking and enabling IDE hints for ``dut``s (objects representing +Devices Under Test). The ``dut`` fixture is the core of pytest harness plugin. When used as an argument of a test function it gives access to a DeviceAbstract type object. The fixture yields a device prepared according to the requested type (native posix, qemu, hardware, etc.). All types of devices share the same API. This allows for writing tests which are device-type-agnostic. diff --git a/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py b/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py index 8107a2afa744..a9f29326204d 100755 --- a/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py +++ b/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py @@ -5,12 +5,12 @@ import time import logging -from twister_harness.device.device_abstract import DeviceAbstract +from twister_harness import Device logger = logging.getLogger(__name__) -def wait_for_message(dut: DeviceAbstract, message, timeout=20): +def wait_for_message(dut: Device, message, timeout=20): time_started = time.time() for line in dut.iter_stdout: if line: @@ -21,7 +21,7 @@ def wait_for_message(dut: DeviceAbstract, message, timeout=20): return False -def wait_for_prompt(dut: DeviceAbstract, prompt='uart:~$', timeout=20): +def wait_for_prompt(dut: Device, prompt='uart:~$', timeout=20): time_started = time.time() while True: dut.write(b'\n') @@ -33,13 +33,13 @@ def wait_for_prompt(dut: DeviceAbstract, prompt='uart:~$', timeout=20): return False -def test_shell_print_help(dut: DeviceAbstract): +def test_shell_print_help(dut: Device): wait_for_prompt(dut) dut.write(b'help\n') assert wait_for_message(dut, "Available commands") -def test_shell_print_version(dut: DeviceAbstract): +def test_shell_print_version(dut: Device): wait_for_prompt(dut) dut.write(b'kernel version\n') assert wait_for_message(dut, "Zephyr version") diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py index 356fb95b53ec..67e2fd26b2af 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py @@ -2,4 +2,10 @@ # # SPDX-License-Identifier: Apache-2.0 +# flake8: noqa + +from twister_harness.device.device_abstract import DeviceAbstract as Device + +__all__= ['Device'] + __version__ = '0.0.1' From fb1651f2d368fb2c622f44e6fbfa2ca20c2027dd Mon Sep 17 00:00:00 2001 From: Aastha Grover Date: Tue, 20 Jun 2023 15:05:54 -0400 Subject: [PATCH 0409/2042] tests: rtio_api: update default MAX_THREAD_BYTES TO 3 This is needed on some platforms where number of k_objects created surpasses the allowed. Signed-off-by: Aastha Grover --- tests/subsys/rtio/rtio_api/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/rtio/rtio_api/prj.conf b/tests/subsys/rtio/rtio_api/prj.conf index aa4a5fcfadbf..9eaf6e7a537e 100644 --- a/tests/subsys/rtio/rtio_api/prj.conf +++ b/tests/subsys/rtio/rtio_api/prj.conf @@ -4,3 +4,4 @@ CONFIG_LOG=y CONFIG_RTIO=y CONFIG_RTIO_SYS_MEM_BLOCKS=y CONFIG_TIMING_FUNCTIONS=y +CONFIG_MAX_THREAD_BYTES=3 From 001795b24c980df3a3dfc0e7b385f93a9392d4f9 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 20 Jun 2023 10:29:27 -0700 Subject: [PATCH 0410/2042] boards: qemu_cortex_a53: move MAX_THREAD_BYTES to Kconfig This moves CONFIG_MAX_THREAD_BYTES from the board's defconfig file into the Kconfig file. This is to get rid of the cmake warning about CONFIG_MAX_THREAD_BYTES being assigned value but got the value ''. This is due to CONFIG_USERSPACE being disabled, where some tests explicitly do so. This is simply done to avoid confusion when running those tests manually. Signed-off-by: Daniel Leung --- boards/arm64/qemu_cortex_a53/Kconfig.defconfig | 3 +++ boards/arm64/qemu_cortex_a53/qemu_cortex_a53_smp_defconfig | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/boards/arm64/qemu_cortex_a53/Kconfig.defconfig b/boards/arm64/qemu_cortex_a53/Kconfig.defconfig index cbe833f42f6f..68e9da200733 100644 --- a/boards/arm64/qemu_cortex_a53/Kconfig.defconfig +++ b/boards/arm64/qemu_cortex_a53/Kconfig.defconfig @@ -9,4 +9,7 @@ config BUILD_OUTPUT_BIN config BOARD default "qemu_cortex_a53" +config MAX_THREAD_BYTES + default 3 + endif # BOARD_QEMU_CORTEX_A53 diff --git a/boards/arm64/qemu_cortex_a53/qemu_cortex_a53_smp_defconfig b/boards/arm64/qemu_cortex_a53/qemu_cortex_a53_smp_defconfig index 496e633201a0..ad9011aa3b76 100644 --- a/boards/arm64/qemu_cortex_a53/qemu_cortex_a53_smp_defconfig +++ b/boards/arm64/qemu_cortex_a53/qemu_cortex_a53_smp_defconfig @@ -29,4 +29,3 @@ CONFIG_PM_CPU_OPS=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TIMEOUT_64BIT=y -CONFIG_MAX_THREAD_BYTES=3 From 54cbf45c7407b308419f03245d21beb168cde4ab Mon Sep 17 00:00:00 2001 From: Marko Sagadin Date: Sun, 28 May 2023 09:46:53 +0200 Subject: [PATCH 0411/2042] drivers: uart: add support for serial ports on native posix Add support for communication with serial ports on native POSIX platform via UART driver API. Serial port driver supports polling API, configuration of the serial ports used via devicetree and command line options, and runtime configuration with `uart_configure`. Multiple instances of the driver are supported. Example use and configuration is also demonstrated in the `samples/drivers/uart/native_tty` sample. Closes: #56586 Signed-off-by: Marko Sagadin --- boards/posix/native_posix/doc/index.rst | 60 ++- drivers/serial/CMakeLists.txt | 5 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.native_tty | 7 + drivers/serial/uart_native_tty.c | 454 ++++++++++++++++++ .../serial/zephyr,native-tty-uart.yaml | 40 ++ .../drivers/uart/native_tty/CMakeLists.txt | 11 + samples/drivers/uart/native_tty/README.rst | 96 ++++ .../native_tty/boards/native_posix.overlay | 15 + samples/drivers/uart/native_tty/prj.conf | 1 + samples/drivers/uart/native_tty/sample.yaml | 9 + samples/drivers/uart/native_tty/src/main.c | 92 ++++ 12 files changed, 785 insertions(+), 7 deletions(-) create mode 100644 drivers/serial/Kconfig.native_tty create mode 100644 drivers/serial/uart_native_tty.c create mode 100644 dts/bindings/serial/zephyr,native-tty-uart.yaml create mode 100644 samples/drivers/uart/native_tty/CMakeLists.txt create mode 100644 samples/drivers/uart/native_tty/README.rst create mode 100644 samples/drivers/uart/native_tty/boards/native_posix.overlay create mode 100644 samples/drivers/uart/native_tty/prj.conf create mode 100644 samples/drivers/uart/native_tty/sample.yaml create mode 100644 samples/drivers/uart/native_tty/src/main.c diff --git a/boards/posix/native_posix/doc/index.rst b/boards/posix/native_posix/doc/index.rst index 94e62ed5eca6..0bfdc564756c 100644 --- a/boards/posix/native_posix/doc/index.rst +++ b/boards/posix/native_posix/doc/index.rst @@ -266,9 +266,18 @@ The following peripherals are currently provided with this board: Please refer to the section `About time in native_posix`_ for more information. -**UART** - An optional UART driver can be compiled with native_posix. - For more information refer to the section `UART`_. +**UART/Serial** + Two optional native UART drivers are available: + + **PTTY driver (UART_NATIVE_POSIX)** + With this driver, one or two Zephyr UART devices can be created. These + can be connected to the Linux process stdin/stdout or a newly created + pseudo-tty. For more information refer to the section `PTTY UART`_. + + **TTY driver (UART_NATIVE_TTY)** + An UART driver for interacting with host-attached serial port devices + (eg. USB to UART dongles). For more information refer to the section + `TTY UART`_. **Real time clock** The real time clock model provides a model of a constantly powered clock. @@ -371,8 +380,8 @@ 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. -UART -**** +PTTY UART +********* This driver can be configured with :kconfig:option:`CONFIG_UART_NATIVE_POSIX` to instantiate up to two UARTs. By default only one UART is enabled. @@ -408,6 +417,42 @@ option ``-attach_uart_cmd=<"cmd">``. Where the default command is given by Note that the default command assumes both ``xterm`` and ``screen`` are installed in the system. +.. _native_tty_uart: + +TTY UART +******** + +With this driver an application can use the polling UART API (``uart_poll_out``, +``uart_poll_in``) to write and read characters to and from a connected serial +port device. + +This driver is automatically enabled when a devicetree contains a node +with ``"zephyr,native-tty-uart"`` compatible property and ``okay`` status, such +as one below:: + + uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + serial-port = "/dev/ttyUSB0"; + current-speed = <115200>; + }; + +Interaction with serial ports can be configured in several different ways: + +* The default serial port and baud rate can be set via the device tree + properties ``serial-port`` and ``current-speed`` respectively. The + ``serial-port`` property is optional. +* Serial port and baud rate can also be set via command line options ``X_port`` + and ``X_baud`` respectively, where ``X`` is a name of a node. Command line + options override values from the devicetree. +* The rest of the configuration options such as number of data and stop bits, + parity, as well as baud rate can be set at runtime with ``uart_configure``. + +Multiple instances of such uart drivers are supported. + +The :ref:`sample-uart-native-tty` sample app provides a working example of the +driver. + Subsystems backends ******************* @@ -420,7 +465,7 @@ development by integrating more seamlessly with the host operating system: redirect any :c:func:`printk` write to the native host application's ``stdout``. - This driver is selected by default if the `UART`_ is not compiled in. + This driver is selected by default if the `PTTY UART`_ is not compiled in. Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as console backend. @@ -437,7 +482,8 @@ development by integrating more seamlessly with the host operating system: This backend can be selected with :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX` and is enabled by default unless the native_posix UART is compiled in. - In this later case, by default, the logger is set to output to the `UART`_. + In this later case, by default, the logger is set to output to the + `PTTY UART`_. **Tracing**: A backend/"bottom" for Zephyr's CTF tracing subsystem which writes the tracing diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index a860c8d1d61f..4d5967c0cacd 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -69,4 +69,9 @@ if(CONFIG_UART_NATIVE_POSIX) zephyr_library_sources(uart_native_posix.c) endif() +if(CONFIG_UART_NATIVE_TTY) + zephyr_library_compile_definitions(NO_POSIX_CHEATS) + zephyr_library_sources(uart_native_tty.c) +endif() + zephyr_library_sources_ifdef(CONFIG_SERIAL_TEST serial_test.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 38ab4a9e4155..70f0f0090169 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -218,4 +218,6 @@ source "drivers/serial/Kconfig.hostlink" source "drivers/serial/Kconfig.emul" +source "drivers/serial/Kconfig.native_tty" + endif # SERIAL diff --git a/drivers/serial/Kconfig.native_tty b/drivers/serial/Kconfig.native_tty new file mode 100644 index 000000000000..a8bcce360e58 --- /dev/null +++ b/drivers/serial/Kconfig.native_tty @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Marko Sagadin +# SPDX-License-Identifier: Apache-2.0 +config UART_NATIVE_TTY + bool "UART driver for interacting with host serial ports" + default y + depends on DT_HAS_ZEPHYR_NATIVE_TTY_UART_ENABLED + select SERIAL_HAS_DRIVER diff --git a/drivers/serial/uart_native_tty.c b/drivers/serial/uart_native_tty.c new file mode 100644 index 000000000000..3ca5a879c56b --- /dev/null +++ b/drivers/serial/uart_native_tty.c @@ -0,0 +1,454 @@ +/** + * @brief UART Driver for interacting with host serial ports + * + * @note Driver can open and send characters to the host serial ports (such as /dev/ttyUSB0 or + * /dev/ttyACM0). Only polling Uart API is implemented. Driver can be configured via devicetree, + * command line options or at runtime. + * + * To learn more see Native TYY section at: + * https://docs.zephyrproject.org/latest/boards/posix/native_posix/doc/index.html + * or + * ${ZEPHYR_BASE}/boards/posix/native_posix/doc/index.rst + * + * Copyright (c) 2023 Marko Sagadin + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include "posix_native_task.h" + +#define WARN(msg, ...) posix_print_warning(msg, ##__VA_ARGS__) +#define ERROR(msg, ...) posix_print_error_and_exit(msg, ##__VA_ARGS__) + +#define DT_DRV_COMPAT zephyr_native_tty_uart + +struct native_tty_data { + /* File descriptor used for the tty device. */ + int fd; + /* Absolute path to the tty device. */ + char *serial_port; + /* Baudrate set from the command line. If UINT32_MAX, it was not set. */ + int cmd_baudrate; + /* Serial port set from the command line. If NULL, it was not set. */ + char *cmd_serial_port; +}; + +struct native_tty_config { + struct uart_config uart_config; +}; + +struct baudrate_termios_pair { + int baudrate; + speed_t termios_baudrate; +}; + +/** + * @brief Lookup table for mapping the baud rate to the macro understood by termios. + */ +static const struct baudrate_termios_pair baudrate_lut[] = { + {1200, B1200}, {1800, B1800}, {2400, B2400}, {4800, B4800}, + {9600, B9600}, {19200, B19200}, {38400, B38400}, {57600, B57600}, + {115200, B115200}, {230400, B230400}, {460800, B460800}, {500000, B500000}, + {576000, B576000}, {921600, B921600}, {1000000, B1000000}, {1152000, B1152000}, + {1500000, B1500000}, {2000000, B2000000}, {2500000, B2500000}, {3000000, B3000000}, + {3500000, B3500000}, {4000000, B4000000}, +}; + +/** + * @brief Set given termios to defaults appropriate for communicating with serial port devices. + * + * @param ter + */ +static inline void native_tty_termios_defaults_set(struct termios *ter) +{ + /* Set terminal in "serial" mode: + * - Not canonical (no line input) + * - No signal generation from Ctr+{C|Z..} + * - No echoing + */ + ter->c_lflag &= ~(ICANON | ISIG | ECHO); + + /* No special interpretation of output bytes. + * No conversion of newline to carriage return/line feed. + */ + ter->c_oflag &= ~(OPOST | ONLCR); + + /* No software flow control. */ + ter->c_iflag &= ~(IXON | IXOFF | IXANY); + + /* No blocking, return immediately with what is available. */ + ter->c_cc[VMIN] = 0; + ter->c_cc[VTIME] = 0; + + /* No special handling of bytes on receive. */ + ter->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); + + /* - Enable reading data and ignore control lines */ + ter->c_cflag |= CREAD | CLOCAL; +} + +/** + * @brief Set the baud rate speed in the termios structure + * + * @param ter + * @param baudrate + * + * @retval 0 If successful, + * @retval -ENOTSUP If requested baud rate is not supported. + */ +static inline int native_tty_baud_speed_set(struct termios *ter, int baudrate) +{ + for (int i = 0; i < ARRAY_SIZE(baudrate_lut); i++) { + if (baudrate_lut[i].baudrate == baudrate) { + cfsetospeed(ter, baudrate_lut[i].termios_baudrate); + cfsetispeed(ter, baudrate_lut[i].termios_baudrate); + return 0; + } + } + return -ENOTSUP; +} + +/** + * @brief Set parity setting in the termios structure + * + * @param ter + * @param parity + * + * @retval 0 If successful. + * @retval -ENOTSUP If requested parity is not supported. + */ +static inline int native_tty_baud_parity_set(struct termios *ter, enum uart_config_parity parity) +{ + switch (parity) { + case UART_CFG_PARITY_NONE: + ter->c_cflag &= ~PARENB; + break; + case UART_CFG_PARITY_ODD: + ter->c_cflag |= PARENB; + ter->c_cflag |= PARODD; + break; + case UART_CFG_PARITY_EVEN: + ter->c_cflag |= PARENB; + ter->c_cflag &= ~PARODD; + break; + default: + /* Parity options mark and space (UART_CFG_PARITY_MARK and UART_CFG_PARITY_SPACE) + * are not supported on this driver. + */ + return -ENOTSUP; + } + return 0; +} + +/** + * @brief Set the number of stop bits in the termios structure + * + * @param ter + * @param stop_bits + * + * @retval 0 If successful. + * @retval -ENOTSUP If requested number of stop bits is not supported. + */ +static inline int native_tty_stop_bits_set(struct termios *ter, + enum uart_config_stop_bits stop_bits) +{ + switch (stop_bits) { + case UART_CFG_STOP_BITS_1: + ter->c_cflag &= ~CSTOPB; + break; + case UART_CFG_STOP_BITS_2: + ter->c_cflag |= CSTOPB; + break; + default: + /* Anything else is not supported in termios. */ + return -ENOTSUP; + } + return 0; +} + +/** + * @brief Set the number of data bits in the termios structure + * + * @param ter + * @param stop_bits + * + * @retval 0 If successful. + * @retval -ENOTSUP If requested number of data bits is not supported. + */ +static inline int native_tty_data_bits_set(struct termios *ter, + enum uart_config_data_bits data_bits) +{ + unsigned int data_bits_to_set; + + switch (data_bits) { + case UART_CFG_DATA_BITS_5: + data_bits_to_set = CS5; + break; + case UART_CFG_DATA_BITS_6: + data_bits_to_set = CS6; + break; + case UART_CFG_DATA_BITS_7: + data_bits_to_set = CS7; + break; + case UART_CFG_DATA_BITS_8: + data_bits_to_set = CS8; + break; + default: + /* Anything else is not supported in termios */ + return -ENOTSUP; + } + + /* Clear all bits that set the data size */ + ter->c_cflag &= ~CSIZE; + ter->c_cflag |= data_bits_to_set; + return 0; +} + +/* + * @brief Output a character towards the serial port + * + * @param dev UART device structure. + * @param out_char Character to send. + */ +static void native_tty_uart_poll_out(const struct device *dev, unsigned char out_char) +{ + struct native_tty_data *data = dev->data; + + int ret = write(data->fd, &out_char, 1); + + if (ret == -1) { + ERROR("Could not write to %s, reason: %s\n", data->serial_port, strerror(errno)); + } +} + +/** + * @brief Poll the device for input. + * + * @param dev UART device structure. + * @param p_char Pointer to a character. + * + * @retval 0 If a character arrived. + * @retval -1 If no character was available to read. + */ +static int native_tty_uart_poll_in(const struct device *dev, unsigned char *p_char) +{ + struct native_tty_data *data = dev->data; + + return read(data->fd, p_char, 1) > 0 ? 0 : -1; +} + +static int native_tty_configure(const struct device *dev, const struct uart_config *cfg) +{ + int rc, err; + int fd = ((struct native_tty_data *)dev->data)->fd; + + /* Structure used to control properties of a serial port */ + struct termios ter; + + /* Read current terminal driver settings */ + rc = tcgetattr(fd, &ter); + if (rc) { + WARN("Could not read terminal driver settings\n"); + return rc; + } + + native_tty_termios_defaults_set(&ter); + + rc = native_tty_baud_speed_set(&ter, cfg->baudrate); + if (rc) { + WARN("Could not set baudrate, as %d is not supported.\n", cfg->baudrate); + return rc; + } + + rc = native_tty_baud_parity_set(&ter, cfg->parity); + if (rc) { + WARN("Could not set parity.\n"); + return rc; + } + + rc = native_tty_stop_bits_set(&ter, cfg->stop_bits); + if (rc) { + WARN("Could not set number of data bits.\n"); + return rc; + } + + rc = native_tty_data_bits_set(&ter, cfg->data_bits); + if (rc) { + WARN("Could not set number of data bits.\n"); + return rc; + } + + if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { + WARN("Could not set flow control, any kind of hw flow control is not supported.\n"); + return -ENOTSUP; + } + + rc = tcsetattr(fd, TCSANOW, &ter); + if (rc) { + err = errno; + WARN("Could not set serial port settings, reason: %s\n", strerror(err)); + return err; + } + + /* tcsetattr returns success if ANY of the requested changes were successfully carried out, + * not if ALL were. So we need to read back the settings and check if they are equal to the + * requested ones. + */ + struct termios read_ter; + + rc = tcgetattr(fd, &read_ter); + if (rc) { + err = errno; + WARN("Could not read serial port settings, reason: %s\n", strerror(err)); + return err; + } + + if (ter.c_cflag != read_ter.c_cflag || ter.c_iflag != read_ter.c_iflag || + ter.c_oflag != read_ter.c_oflag || ter.c_lflag != read_ter.c_lflag || + ter.c_line != read_ter.c_line || ter.c_ispeed != read_ter.c_ispeed || + ter.c_ospeed != read_ter.c_ospeed || 0 != memcmp(ter.c_cc, read_ter.c_cc, NCCS)) { + WARN("Read serial port settings do not match set ones.\n"); + return -EBADE; + } + + /* Flush both input and output */ + rc = tcflush(fd, TCIOFLUSH); + if (rc) { + WARN("Could not flush serial port\n"); + return rc; + } + + return 0; +} + +static int native_tty_serial_init(const struct device *dev) +{ + struct native_tty_data *data = dev->data; + struct uart_config uart_config = ((struct native_tty_config *)dev->config)->uart_config; + + /* Default value for cmd_serial_port is NULL, this is due to the set 's' type in command + * line opts. If it is anything else then it was configured via command line. + */ + if (data->cmd_serial_port) { + data->serial_port = data->cmd_serial_port; + } + + /* Default value for cmd_baudrate is UINT32_MAX, this is due to the set 'u' type in command + * line opts. If it is anything else then it was configured via command line. + */ + if (data->cmd_baudrate != UINT32_MAX) { + uart_config.baudrate = data->cmd_baudrate; + } + + /* Serial port needs to be set either in the devicetree or provided via command line opts, + * if that is not the case, then abort. + */ + if (!data->serial_port) { + ERROR("%s: path to the serial port was not set.\n", dev->name); + } + + /* Try to open a serial port as with read/write access, also prevent serial port + * from becoming the controlling terminal. + */ + data->fd = open(data->serial_port, O_RDWR | O_NOCTTY); + if (data->fd < 0) { + ERROR("%s: failed to open serial port %s, reason: %s\n", dev->name, + data->serial_port, strerror(errno)); + } + + if (native_tty_configure(dev, &uart_config)) { + ERROR("%s: could not configure serial port %s\n", dev->name, data->serial_port); + } + + posix_print_trace("%s connected to the serial port: %s\n", dev->name, data->serial_port); + + return 0; +} + +static struct uart_driver_api native_tty_uart_driver_api = { + .poll_out = native_tty_uart_poll_out, + .poll_in = native_tty_uart_poll_in, + .configure = native_tty_configure, +}; + +#define NATIVE_TTY_INSTANCE(inst) \ + static const struct native_tty_config native_tty_##inst##_cfg = { \ + .uart_config = \ + { \ + .data_bits = UART_CFG_DATA_BITS_8, \ + .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ + .parity = UART_CFG_PARITY_NONE, \ + .stop_bits = UART_CFG_STOP_BITS_1, \ + .baudrate = DT_INST_PROP(inst, current_speed), \ + }, \ + }; \ + \ + static struct native_tty_data native_tty_##inst##_data = { \ + .serial_port = DT_INST_PROP_OR(inst, serial_port, NULL), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, native_tty_serial_init, NULL, &native_tty_##inst##_data, \ + &native_tty_##inst##_cfg, PRE_KERNEL_1, 55, \ + &native_tty_uart_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NATIVE_TTY_INSTANCE); + +#define INST_NAME(inst) DEVICE_DT_NAME(DT_DRV_INST(inst)) + + +#define NATIVE_TTY_COMMAND_LINE_OPTS(inst) \ + { \ + .option = INST_NAME(inst) "_port", \ + .name = "\"serial_port\"", \ + .type = 's', \ + .dest = &native_tty_##inst##_data.cmd_serial_port, \ + .descript = "Set a serial port for " INST_NAME(inst) " uart device, " \ + "overriding the one in devicetree.", \ + }, \ + { \ + .option = INST_NAME(inst) "_baud", \ + .name = "baudrate", \ + .type = 'u', \ + .dest = &native_tty_##inst##_data.cmd_baudrate, \ + .descript = "Set a baudrate for " INST_NAME(inst) " device, overriding the " \ + "baudrate of " STRINGIFY(DT_INST_PROP(inst, current_speed)) \ + "set in the devicetree.", \ + }, + +/** + * @brief Adds command line options for setting serial port and baud rate for each uart device. + */ +static void native_tty_add_serial_options(void) +{ + static struct args_struct_t opts[] = { + DT_INST_FOREACH_STATUS_OKAY(NATIVE_TTY_COMMAND_LINE_OPTS) ARG_TABLE_ENDMARKER}; + + native_add_command_line_opts(opts); +} + +#define NATIVE_TTY_CLEANUP(inst) \ + if (native_tty_##inst##_data.fd != 0) { \ + close(native_tty_##inst##_data.fd); \ + } + +/** + * @brief Cleans up any open serial ports on the exit. + */ +static void native_tty_cleanup_uart(void) +{ + DT_INST_FOREACH_STATUS_OKAY(NATIVE_TTY_CLEANUP); +} + +NATIVE_TASK(native_tty_add_serial_options, PRE_BOOT_1, 11); +NATIVE_TASK(native_tty_cleanup_uart, ON_EXIT, 99); diff --git a/dts/bindings/serial/zephyr,native-tty-uart.yaml b/dts/bindings/serial/zephyr,native-tty-uart.yaml new file mode 100644 index 000000000000..bcecc8da60ad --- /dev/null +++ b/dts/bindings/serial/zephyr,native-tty-uart.yaml @@ -0,0 +1,40 @@ +description: Native TTY UART + +include: uart-controller.yaml + +compatible: "zephyr,native-tty-uart" +bus: uart + +properties: + serial-port: + type: string + description: | + Full path to the serial port device, such as "/dev/ttyUSB0" or + "/dev/ttyACM0". + current-speed: + description: | + Initial baud rate setting for UART. Only a fixed set of baud rates are + selectable on these devices. + enum: + - 1200 + - 1800 + - 2400 + - 4800 + - 9600 + - 19200 + - 38400 + - 57600 + - 115200 + - 230400 + - 460800 + - 500000 + - 576000 + - 921600 + - 1000000 + - 1152000 + - 1500000 + - 2000000 + - 2500000 + - 3000000 + - 3500000 + - 4000000 diff --git a/samples/drivers/uart/native_tty/CMakeLists.txt b/samples/drivers/uart/native_tty/CMakeLists.txt new file mode 100644 index 000000000000..c0fa477a106f --- /dev/null +++ b/samples/drivers/uart/native_tty/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(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}) diff --git a/samples/drivers/uart/native_tty/README.rst b/samples/drivers/uart/native_tty/README.rst new file mode 100644 index 000000000000..deacfde80d34 --- /dev/null +++ b/samples/drivers/uart/native_tty/README.rst @@ -0,0 +1,96 @@ +.. _sample-uart-native-tty: + +Native TTY UART +############### + +Overview +******** + +This sample demonstrates the usage of the Native TTY UART driver. It uses two +UART to USB bridge dongles that are wired together, writing demo data to one +dongle and reading it from the other." + +The source code for this sample application can be found at: +:zephyr_file:`samples/drivers/uart/native-tty`. + +You can learn more about the Native TTY UART driver in the +:ref:`TTY UART ` section of the Native posix board +documentation. + +Requirements +************ + +#. Two UART to USB bridge dongles. Each dongle must have its TX pin wired to the + other dongle's RX pin. The ground connection is not needed. Both dongles must + be plugged into the host machine. +#. The DT overlay provided with the sample expects the dongles to appear as + ``/dev/ttyUSB0`` and ``/dev/ttyUSB1`` in the system. You can check what they + are in your system by running the command ``ls -l /dev/tty*``. If that is not + the case on your machine you can either change the ``serial-port`` properties + in the ``boards/native_posix.overlay`` file or using the command line options + ``-uart_port`` and ``-uart_port2``. + +Building and Running +******************** + +This application can be built and executed on Native Posix as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/uart/native_tty + :host-os: unix + :board: native_posix + :goals: run + :compact: + +Sample Output +============= + +.. code-block:: console + + uart_1 connected to pseudotty: /dev/pts/6 + uart2 connected to the serial port: /dev/ttyUSB1 + uart connected to the serial port: /dev/ttyUSB0 + *** Booting Zephyr OS build v3.4.0-rc2-97-ge586d02c137d *** + Device uart sent: "Hello from device uart, num 9" + Device uart2 received: "Hello from device uart, num 9" + Device uart sent: "Hello from device uart, num 8" + Device uart2 received: "Hello from device uart, num 8" + Device uart sent: "Hello from device uart, num 7" + Device uart2 received: "Hello from device uart, num 7" + Device uart sent: "Hello from device uart, num 6" + Device uart2 received: "Hello from device uart, num 6" + Device uart sent: "Hello from device uart, num 5" + Device uart2 received: "Hello from device uart, num 5" + Device uart sent: "Hello from device uart, num 4" + Device uart2 received: "Hello from device uart, num 4" + Device uart sent: "Hello from device uart, num 3" + Device uart2 received: "Hello from device uart, num 3" + Device uart sent: "Hello from device uart, num 2" + Device uart2 received: "Hello from device uart, num 2" + Device uart sent: "Hello from device uart, num 1" + Device uart2 received: "Hello from device uart, num 1" + Device uart sent: "Hello from device uart, num 0" + Device uart2 received: "Hello from device uart, num 0" + + Changing baudrate of both uart devices to 9600! + + Device uart sent: "Hello from device uart, num 9" + Device uart2 received: "Hello from device uart, num 9" + Device uart sent: "Hello from device uart, num 8" + Device uart2 received: "Hello from device uart, num 8" + Device uart sent: "Hello from device uart, num 7" + Device uart2 received: "Hello from device uart, num 7" + Device uart sent: "Hello from device uart, num 6" + Device uart2 received: "Hello from device uart, num 6" + Device uart sent: "Hello from device uart, num 5" + Device uart2 received: "Hello from device uart, num 5" + Device uart sent: "Hello from device uart, num 4" + Device uart2 received: "Hello from device uart, num 4" + Device uart sent: "Hello from device uart, num 3" + Device uart2 received: "Hello from device uart, num 3" + Device uart sent: "Hello from device uart, num 2" + Device uart2 received: "Hello from device uart, num 2" + Device uart sent: "Hello from device uart, num 1" + Device uart2 received: "Hello from device uart, num 1" + Device uart sent: "Hello from device uart, num 0" + Device uart2 received: "Hello from device uart, num 0" diff --git a/samples/drivers/uart/native_tty/boards/native_posix.overlay b/samples/drivers/uart/native_tty/boards/native_posix.overlay new file mode 100644 index 000000000000..24f1bd95705b --- /dev/null +++ b/samples/drivers/uart/native_tty/boards/native_posix.overlay @@ -0,0 +1,15 @@ +/ { + uart0: uart { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB0"; + }; + + uart2: uart2 { + status = "okay"; + compatible = "zephyr,native-tty-uart"; + current-speed = <115200>; + serial-port = "/dev/ttyUSB1"; + }; +}; diff --git a/samples/drivers/uart/native_tty/prj.conf b/samples/drivers/uart/native_tty/prj.conf new file mode 100644 index 000000000000..ef2861c789f8 --- /dev/null +++ b/samples/drivers/uart/native_tty/prj.conf @@ -0,0 +1 @@ +CONFIG_SERIAL=y diff --git a/samples/drivers/uart/native_tty/sample.yaml b/samples/drivers/uart/native_tty/sample.yaml new file mode 100644 index 000000000000..92263aa8c426 --- /dev/null +++ b/samples/drivers/uart/native_tty/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: Native TTY sample +tests: + sample.drivers.uart.native_tty: + build_only: true + platform_allow: native_posix + tags: + - serial + - uart diff --git a/samples/drivers/uart/native_tty/src/main.c b/samples/drivers/uart/native_tty/src/main.c new file mode 100644 index 000000000000..1714328e0dcb --- /dev/null +++ b/samples/drivers/uart/native_tty/src/main.c @@ -0,0 +1,92 @@ +/* + * @brief Native TTY UART sample + * + * Copyright (c) 2023 Marko Sagadin + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +const struct device *uart0 = DEVICE_DT_GET(DT_NODELABEL(uart0)); +const struct device *uart2 = DEVICE_DT_GET(DT_NODELABEL(uart2)); + +struct uart_config uart_cfg = { + .baudrate = 9600, + .parity = UART_CFG_PARITY_NONE, + .stop_bits = UART_CFG_STOP_BITS_1, + .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, + .data_bits = UART_CFG_DATA_BITS_8, +}; + +void send_str(const struct device *uart, char *str) +{ + int msg_len = strlen(str); + + for (int i = 0; i < msg_len; i++) { + uart_poll_out(uart, str[i]); + } + + printk("Device %s sent: \"%s\"\n", uart->name, str); +} + +void recv_str(const struct device *uart, char *str) +{ + char *head = str; + char c; + + while (!uart_poll_in(uart, &c)) { + *head++ = c; + } + *head = '\0'; + + printk("Device %s received: \"%s\"\n", uart->name, str); +} + +int main(void) +{ + int rc; + char send_buf[64]; + char recv_buf[64]; + int i = 10; + + while (i--) { + snprintf(send_buf, 64, "Hello from device %s, num %d", uart0->name, i); + send_str(uart0, send_buf); + /* Wait some time for the messages to arrive to the second uart. */ + k_sleep(K_MSEC(100)); + recv_str(uart2, recv_buf); + + k_sleep(K_MSEC(1000)); + } + + uart_cfg.baudrate = 9600; + printk("\nChanging baudrate of both uart devices to %d!\n\n", uart_cfg.baudrate); + + rc = uart_configure(uart0, &uart_cfg); + if (rc) { + printk("Could not configure device %s", uart0->name); + } + rc = uart_configure(uart2, &uart_cfg); + if (rc) { + printk("Could not configure device %s", uart2->name); + } + + i = 10; + while (i--) { + snprintf(send_buf, 64, "Hello from device %s, num %d", uart0->name, i); + send_str(uart0, send_buf); + /* Wait some time for the messages to arrive to the second uart. */ + k_sleep(K_MSEC(100)); + recv_str(uart2, recv_buf); + + k_sleep(K_MSEC(1000)); + } + + return 0; +} From 190b6321613bdf038bf28bb16211cc0b8398868f Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Mon, 19 Jun 2023 16:47:31 +0200 Subject: [PATCH 0412/2042] tests: drivers: adc: adc_api: boards: add overlays for stm32 boards Adds overlays for several STM32 boards to fix CI build failures. Signed-off-by: Guillaume Gautier --- .../adc/adc_api/boards/nucleo_f070rb.overlay | 25 +++++++++++++++++++ .../adc/adc_api/boards/nucleo_f303k8.overlay | 25 +++++++++++++++++++ .../adc/adc_api/boards/nucleo_f446ze.overlay | 25 +++++++++++++++++++ .../adc/adc_api/boards/nucleo_f767zi.overlay | 25 +++++++++++++++++++ .../adc/adc_api/boards/nucleo_g0b1re.overlay | 25 +++++++++++++++++++ .../adc_api/boards/nucleo_u575zi_q.overlay | 25 +++++++++++++++++++ .../adc_api/boards/stm32g081b_eval.overlay | 12 +++++++++ 7 files changed, 162 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_f070rb.overlay create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_f303k8.overlay create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_f446ze.overlay create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_f767zi.overlay create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_g0b1re.overlay create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_u575zi_q.overlay create mode 100644 tests/drivers/adc/adc_api/boards/stm32g081b_eval.overlay diff --git a/tests/drivers/adc/adc_api/boards/nucleo_f070rb.overlay b/tests/drivers/adc/adc_api/boards/nucleo_f070rb.overlay new file mode 100644 index 000000000000..a3e5fe6027f2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_f070rb.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 0>; + }; +}; + +&adc1 { + #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>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_f303k8.overlay b/tests/drivers/adc/adc_api/boards/nucleo_f303k8.overlay new file mode 100644 index 000000000000..33fbcb51723b --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_f303k8.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 1>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_f446ze.overlay b/tests/drivers/adc/adc_api/boards/nucleo_f446ze.overlay new file mode 100644 index 000000000000..a3e5fe6027f2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_f446ze.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 0>; + }; +}; + +&adc1 { + #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>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_f767zi.overlay b/tests/drivers/adc/adc_api/boards/nucleo_f767zi.overlay new file mode 100644 index 000000000000..a3e5fe6027f2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_f767zi.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 0>; + }; +}; + +&adc1 { + #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>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_g0b1re.overlay b/tests/drivers/adc/adc_api/boards/nucleo_g0b1re.overlay new file mode 100644 index 000000000000..a3e5fe6027f2 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_g0b1re.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 0>; + }; +}; + +&adc1 { + #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>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/nucleo_u575zi_q.overlay b/tests/drivers/adc/adc_api/boards/nucleo_u575zi_q.overlay new file mode 100644 index 000000000000..33fbcb51723b --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_u575zi_q.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 1>; + }; +}; + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/stm32g081b_eval.overlay b/tests/drivers/adc/adc_api/boards/stm32g081b_eval.overlay new file mode 100644 index 000000000000..ad7c9c2ca401 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/stm32g081b_eval.overlay @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc1 3>, <&adc1 9>; + }; +}; From 92707866d1b38fea8998a861b429ea51f4c9e85d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 11:51:36 +0200 Subject: [PATCH 0413/2042] device: s/gen_handles/gen_device_deps Rename the gen_handles script and all of its references/associated files to gen_device_deps. The new new makes things more clear, because the script just take care of generating, for each device, an array of device dependencies. While device handles are used internally to store this information, it is in reality an implementation detail. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 14 +++++++------- doc/build/cmake/build-postprocess-2.svg | 2 +- doc/build/cmake/index.rst | 10 +++++----- include/zephyr/device.h | 6 +++--- .../build/{gen_handles.py => gen_device_deps.py} | 0 5 files changed, 16 insertions(+), 16 deletions(-) rename scripts/build/{gen_handles.py => gen_device_deps.py} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6b06937f873..11a9dff03bbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -923,14 +923,14 @@ if(CONFIG_HAS_DTS) set(number_of_dynamic_devices 0) endif() - # dev_handles.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by - # gen_handles.py + # device_deps.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by + # gen_device_deps.py add_custom_command( - OUTPUT dev_handles.c + OUTPUT device_deps.c COMMAND ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/build/gen_handles.py - --output-source dev_handles.c + ${ZEPHYR_BASE}/scripts/build/gen_device_deps.py + --output-source device_deps.c --output-graphviz dev_graph.dot ${dynamic_handles} --num-dynamic-devices ${number_of_dynamic_devices} @@ -940,9 +940,9 @@ if(CONFIG_HAS_DTS) VERBATIM DEPENDS ${ZEPHYR_LINK_STAGE_EXECUTABLE} ) - set_property(GLOBAL APPEND PROPERTY GENERATED_APP_SOURCE_FILES dev_handles.c) + set_property(GLOBAL APPEND PROPERTY GENERATED_APP_SOURCE_FILES device_deps.c) - # gen_handles runs on `__device_handles_pass1` so pass this info to the linker script generator + # gen_device_deps runs on `__device_handles_pass1` so pass this info to the linker script generator list(APPEND LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE "LINKER_DEVICE_HANDLES_PASS1") endif() diff --git a/doc/build/cmake/build-postprocess-2.svg b/doc/build/cmake/build-postprocess-2.svg index 42c1e2c2cff5..83fc351acc76 100644 --- a/doc/build/cmake/build-postprocess-2.svg +++ b/doc/build/cmake/build-postprocess-2.svg @@ -1,4 +1,4 @@ -

Makefile
(various)

Makefile...
Device handles
Device handles
zephyr_pre0.elf
zephyr_pre0.elf
scripts/build/gen_handles.py
scripts/build/gen_handles.py
dev_handles.c
dev_handles.c
Viewer does not support full SVG 1.1
\ No newline at end of file +

Makefile
(various)

Makefile...
Device handles
Device handles
zephyr_pre0.elf
zephyr_pre0.elf
scripts/build/gen_device_deps.py
scripts/build/gen_device_deps.py
dev_handles.c
dev_handles.c
Viewer does not support full SVG 1.1
diff --git a/doc/build/cmake/index.rst b/doc/build/cmake/index.rst index 175412af1be4..479e044b68e2 100644 --- a/doc/build/cmake/index.rst +++ b/doc/build/cmake/index.rst @@ -245,7 +245,7 @@ Partition alignment When :ref:`devicetree` is used: Device dependencies - The *gen_handles.py* script scans the unfixed size binary to determine + The *gen_device_deps.py* script scans the unfixed size binary to determine relationships between devices that were recorded from devicetree data, and replaces the encoded relationships with values that are optimized to locate the devices actually present in the application. @@ -330,12 +330,12 @@ The following is a detailed description of the scripts used during the build pro :start-after: """ :end-before: """ -.. _gen_handles.py: +.. _gen_device_deps.py: -:zephyr_file:`scripts/build/gen_handles.py` -------------------------------------------- +:zephyr_file:`scripts/build/gen_device_deps.py` +----------------------------------------------- -.. include:: ../../../scripts/build/gen_handles.py +.. include:: ../../../scripts/build/gen_device_deps.py :start-after: """ :end-before: """ diff --git a/include/zephyr/device.h b/include/zephyr/device.h index a10afa9fe621..53a977107732 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -588,7 +588,7 @@ device_supported_handles_get(const struct device *dev, size_t *count) rv++; } /* Count supporting devices. - * Trailing NULL's can be injected by gen_handles.py due to + * Trailing NULL's can be injected by gen_device_deps.py due to * CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM */ while ((rv[i] != DEVICE_HANDLE_ENDS) && @@ -795,7 +795,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * original object file is compiled), and in a distinct pass1 section (which * will be replaced by postprocessing). * - * Before processing in gen_handles.py, the array format is: + * Before processing in gen_device_deps.py, the array format is: * { * DEVICE_ORDINAL (or DEVICE_HANDLE_NULL if not a devicetree node), * List of devicetree dependency ordinals (if any), @@ -805,7 +805,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * List of devicetree supporting ordinals (if any), * } * - * After processing in gen_handles.py, the format is updated to: + * After processing in gen_device_deps.py, the format is updated to: * { * List of existing devicetree dependency handles (if any), * DEVICE_HANDLE_SEP, diff --git a/scripts/build/gen_handles.py b/scripts/build/gen_device_deps.py similarity index 100% rename from scripts/build/gen_handles.py rename to scripts/build/gen_device_deps.py From 8bee39edffbfc889db5beeb33e76fc05b8c48414 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:10:40 +0200 Subject: [PATCH 0414/2042] device: s/device_handles/device_deps/ in linker scripts Use the "device_deps" naming scheme to emphasize we are storing device dependencies. The fact we are using device handles to store them is an implementation detail. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 4 ++-- cmake/linker_script/common/common-rom.cmake | 6 +++--- include/zephyr/device.h | 2 +- include/zephyr/linker/common-ram.ld | 4 ++-- .../linker/common-rom/common-rom-kernel-devices.ld | 4 ++-- include/zephyr/linker/device-deps.ld | 13 +++++++++++++ include/zephyr/linker/device-handles.ld | 13 ------------- scripts/build/gen_device_deps.py | 2 +- scripts/build/gen_relocate_app.py | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) create mode 100644 include/zephyr/linker/device-deps.ld delete mode 100644 include/zephyr/linker/device-handles.ld diff --git a/CMakeLists.txt b/CMakeLists.txt index 11a9dff03bbf..d295a0cf006c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -942,8 +942,8 @@ if(CONFIG_HAS_DTS) ) set_property(GLOBAL APPEND PROPERTY GENERATED_APP_SOURCE_FILES device_deps.c) - # gen_device_deps runs on `__device_handles_pass1` so pass this info to the linker script generator - list(APPEND LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE "LINKER_DEVICE_HANDLES_PASS1") + # gen_device_deps runs on `__device_deps_pass1` so pass this info to the linker script generator + list(APPEND LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE "LINKER_DEVICE_DEPS_PASS1") endif() if(CONFIG_CODE_DATA_RELOCATION) diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index 811a681a8c2f..4417d1081360 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -185,9 +185,9 @@ zephyr_iterable_section(NAME tracing_backend KVMA RAM_REGION GROUP RODATA_REGION zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT}) zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP) -zephyr_linker_section(NAME device_handles KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16) -zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass1* KEEP SORT NAME PASS LINKER_DEVICE_HANDLES_PASS1) -zephyr_linker_section_configure(SECTION device_handles INPUT .__device_handles_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_HANDLES_PASS1) +zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16) +zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1) +zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1) zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 53a977107732..0b487449914b 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -778,7 +778,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) /** @brief Linker section were device handles are placed. */ #define Z_DEVICE_HANDLES_SECTION \ - __attribute__((__section__(".__device_handles_pass1"))) + __attribute__((__section__(".__device_deps_pass1"))) #ifdef __cplusplus #define Z_DEVICE_HANDLES_EXTERN extern diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index a29839306309..269d56be46e5 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -43,9 +43,9 @@ #endif #if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) - SECTION_DATA_PROLOGUE(device_handles,,) + SECTION_DATA_PROLOGUE(device_deps,,) { -#include "device-handles.ld" +#include "device-deps.ld" } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif /* CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ diff --git a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld index 3c677cd0bad9..b7acb08d90c9 100644 --- a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld +++ b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld @@ -65,8 +65,8 @@ #endif /* CONFIG_PCIE */ #if !defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) - SECTION_DATA_PROLOGUE(device_handles,,) + SECTION_DATA_PROLOGUE(device_deps,,) { -#include +#include } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif /* !CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ diff --git a/include/zephyr/linker/device-deps.ld b/include/zephyr/linker/device-deps.ld new file mode 100644 index 000000000000..f3d848b92df2 --- /dev/null +++ b/include/zephyr/linker/device-deps.ld @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +__device_deps_start = .; +#ifdef LINKER_DEVICE_DEPS_PASS1 +KEEP(*(SORT(.__device_deps_pass1*))); +#else +KEEP(*(SORT(.__device_deps_pass2*))); +#endif /* LINKER_DEVICE_DEPS_PASS1 */ +__device_deps_end = .; diff --git a/include/zephyr/linker/device-handles.ld b/include/zephyr/linker/device-handles.ld deleted file mode 100644 index aed858981c5f..000000000000 --- a/include/zephyr/linker/device-handles.ld +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c) 2021 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -__device_handles_start = .; -#ifdef LINKER_DEVICE_HANDLES_PASS1 -KEEP(*(SORT(.__device_handles_pass1*))); -#else -KEEP(*(SORT(.__device_handles_pass2*))); -#endif /* LINKER_DEVICE_HANDLES_PASS1 */ -__device_handles_end = .; diff --git a/scripts/build/gen_device_deps.py b/scripts/build/gen_device_deps.py index 799b9139171b..bbebb554dd18 100755 --- a/scripts/build/gen_device_deps.py +++ b/scripts/build/gen_device_deps.py @@ -107,7 +107,7 @@ def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): ] ctype = ( '{:s}Z_DECL_ALIGN(device_handle_t) ' - '__attribute__((__section__(".__device_handles_pass2")))' + '__attribute__((__section__(".__device_deps_pass2")))' ).format('const ' if not dynamic_handles else '') return [ # The `extern` line pretends this was first declared in some .h diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 1e3067c34312..9082b62f8fd0 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -74,7 +74,7 @@ def for_section_named(cls, name: str): >>> SectionKind.for_section_with_name(".rodata.str1.4") - >>> SectionKind.for_section_with_name(".device_handles") + >>> SectionKind.for_section_with_name(".device_deps") None """ if ".text." in name: From e5f82cb5dc84e8cf116c3b1596f4467ee387122f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:20:56 +0200 Subject: [PATCH 0415/2042] device: hide DEVICE_HANDLE_SEP/ENDS These macros are used internally by the device dependencies functions. There's no need to expose them publicly, so prefix them with Z_ and add them under INTERNAL_HIDDEN docs section. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/device.h | 62 +++++++++++++++++--------------- scripts/build/gen_device_deps.py | 6 ++-- subsys/pm/device.c | 4 +-- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 0b487449914b..7dc154dd3e62 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -27,6 +27,26 @@ extern "C" { * @{ */ +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Flag value used in lists of device handles to separate distinct + * groups. + * + * This is the minimum value for the device_handle_t type. + */ +#define Z_DEVICE_HANDLE_SEP INT16_MIN + +/** + * @brief Flag value used in lists of device handles to indicate the end of the + * list. + * + * This is the maximum value for the device_handle_t type. + */ +#define Z_DEVICE_HANDLE_ENDS INT16_MAX + +/** @endcond */ + /** * @brief Type used to represent a "handle" for a device. * @@ -44,22 +64,6 @@ extern "C" { */ typedef int16_t device_handle_t; -/** - * @brief Flag value used in lists of device handles to separate distinct - * groups. - * - * This is the minimum value for the device_handle_t type. - */ -#define DEVICE_HANDLE_SEP INT16_MIN - -/** - * @brief Flag value used in lists of device handles to indicate the end of the - * list. - * - * This is the maximum value for the device_handle_t type. - */ -#define DEVICE_HANDLE_ENDS INT16_MAX - /** @brief Flag value used to identify an unknown device. */ #define DEVICE_HANDLE_NULL 0 @@ -500,8 +504,8 @@ device_required_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { size_t i = 0; - while ((rv[i] != DEVICE_HANDLE_ENDS) && - (rv[i] != DEVICE_HANDLE_SEP)) { + while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && + (rv[i] != Z_DEVICE_HANDLE_SEP)) { ++i; } *count = i; @@ -538,13 +542,13 @@ device_injected_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { /* Fast forward to injected devices */ while (region != 1) { - if (*rv == DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_HANDLE_SEP) { region++; } rv++; } - while ((rv[i] != DEVICE_HANDLE_ENDS) && - (rv[i] != DEVICE_HANDLE_SEP)) { + while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && + (rv[i] != Z_DEVICE_HANDLE_SEP)) { ++i; } *count = i; @@ -582,7 +586,7 @@ device_supported_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { /* Fast forward to supporting devices */ while (region != 2) { - if (*rv == DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_HANDLE_SEP) { region++; } rv++; @@ -591,7 +595,7 @@ device_supported_handles_get(const struct device *dev, size_t *count) * Trailing NULL's can be injected by gen_device_deps.py due to * CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM */ - while ((rv[i] != DEVICE_HANDLE_ENDS) && + while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && (rv[i] != DEVICE_HANDLE_NULL)) { ++i; } @@ -799,18 +803,18 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * { * DEVICE_ORDINAL (or DEVICE_HANDLE_NULL if not a devicetree node), * List of devicetree dependency ordinals (if any), - * DEVICE_HANDLE_SEP, + * Z_DEVICE_HANDLE_SEP, * List of injected dependency ordinals (if any), - * DEVICE_HANDLE_SEP, + * Z_DEVICE_HANDLE_SEP, * List of devicetree supporting ordinals (if any), * } * * After processing in gen_device_deps.py, the format is updated to: * { * List of existing devicetree dependency handles (if any), - * DEVICE_HANDLE_SEP, + * Z_DEVICE_HANDLE_SEP, * List of injected devicetree dependency handles (if any), - * DEVICE_HANDLE_SEP, + * Z_DEVICE_HANDLE_SEP, * List of existing devicetree support handles (if any), * DEVICE_HANDLE_NULL * } @@ -831,9 +835,9 @@ static inline bool z_impl_device_is_ready(const struct device *dev) DT_NODE_EXISTS(node_id), \ (DT_DEP_ORD(node_id), DT_REQUIRES_DEP_ORDS(node_id)), \ (DEVICE_HANDLE_NULL,)) /**/ \ - DEVICE_HANDLE_SEP, \ + Z_DEVICE_HANDLE_SEP, \ Z_DEVICE_EXTRA_HANDLES(__VA_ARGS__) /**/ \ - DEVICE_HANDLE_SEP, \ + Z_DEVICE_HANDLE_SEP, \ COND_CODE_1(DT_NODE_EXISTS(node_id), \ (DT_SUPPORTS_DEP_ORDS(node_id)), ()) /**/ \ } diff --git a/scripts/build/gen_device_deps.py b/scripts/build/gen_device_deps.py index bbebb554dd18..b26e9ef38e0f 100755 --- a/scripts/build/gen_device_deps.py +++ b/scripts/build/gen_device_deps.py @@ -98,12 +98,12 @@ def dev_path_str(dev): def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): handles = [ *[str(d.handle) for d in handles["depends"]], - 'DEVICE_HANDLE_SEP', + 'Z_DEVICE_HANDLE_SEP', *[str(d.handle) for d in handles["injected"]], - 'DEVICE_HANDLE_SEP', + 'Z_DEVICE_HANDLE_SEP', *[str(d.handle) for d in handles["supports"]], *(extra_support_handles * ['DEVICE_HANDLE_NULL']), - 'DEVICE_HANDLE_ENDS', + 'Z_DEVICE_HANDLE_ENDS', ] ctype = ( '{:s}Z_DECL_ALIGN(device_handle_t) ' diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 9b89a43ee200..f978d20889ec 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -128,14 +128,14 @@ static int power_domain_add_or_remove(const struct device *dev, * with the device handle. */ while (region != 2) { - if (*rv == DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_HANDLE_SEP) { region++; } rv++; } i = 0; - while (rv[i] != DEVICE_HANDLE_ENDS) { + while (rv[i] != Z_DEVICE_HANDLE_ENDS) { if (add == false) { if (rv[i] == dev_handle) { dev->pm->domain = NULL; From 4eb406e0930d11c93587aad2fc74a6614e76f8d6 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:35:14 +0200 Subject: [PATCH 0416/2042] device: s/DEVICE_HANDLE/DEVICE_DEPS/ Rename multiple internal device macros to use the DEVICE_DEPS naming, so that it is clear they belong to the device dependencies APIs. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/device.h | 80 +++++++++++++++----------------- scripts/build/gen_device_deps.py | 6 +-- subsys/pm/device.c | 4 +- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 7dc154dd3e62..01be9c311eb6 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -30,20 +30,16 @@ extern "C" { /** @cond INTERNAL_HIDDEN */ /** - * @brief Flag value used in lists of device handles to separate distinct + * @brief Flag value used in lists of device dependencies to separate distinct * groups. - * - * This is the minimum value for the device_handle_t type. */ -#define Z_DEVICE_HANDLE_SEP INT16_MIN +#define Z_DEVICE_DEPS_SEP INT16_MIN /** - * @brief Flag value used in lists of device handles to indicate the end of the - * list. - * - * This is the maximum value for the device_handle_t type. + * @brief Flag value used in lists of device dependencies to indicate the end of + * the list. */ -#define Z_DEVICE_HANDLE_ENDS INT16_MAX +#define Z_DEVICE_DEPS_ENDS INT16_MAX /** @endcond */ @@ -373,9 +369,9 @@ struct device_state { struct pm_device; #ifdef CONFIG_HAS_DYNAMIC_DEVICE_HANDLES -#define Z_DEVICE_HANDLES_CONST +#define Z_DEVICE_DEPS_CONST #else -#define Z_DEVICE_HANDLES_CONST const +#define Z_DEVICE_DEPS_CONST const #endif /** @@ -399,7 +395,7 @@ struct device { * relationship to this node. The individual sets are extracted with * dedicated API, such as device_required_handles_get(). */ - Z_DEVICE_HANDLES_CONST device_handle_t *handles; + Z_DEVICE_DEPS_CONST device_handle_t *handles; #if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__) /** @@ -504,8 +500,8 @@ device_required_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { size_t i = 0; - while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && - (rv[i] != Z_DEVICE_HANDLE_SEP)) { + while ((rv[i] != Z_DEVICE_DEPS_ENDS) && + (rv[i] != Z_DEVICE_DEPS_SEP)) { ++i; } *count = i; @@ -542,13 +538,13 @@ device_injected_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { /* Fast forward to injected devices */ while (region != 1) { - if (*rv == Z_DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_DEPS_SEP) { region++; } rv++; } - while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && - (rv[i] != Z_DEVICE_HANDLE_SEP)) { + while ((rv[i] != Z_DEVICE_DEPS_ENDS) && + (rv[i] != Z_DEVICE_DEPS_SEP)) { ++i; } *count = i; @@ -586,7 +582,7 @@ device_supported_handles_get(const struct device *dev, size_t *count) if (rv != NULL) { /* Fast forward to supporting devices */ while (region != 2) { - if (*rv == Z_DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_DEPS_SEP) { region++; } rv++; @@ -595,7 +591,7 @@ device_supported_handles_get(const struct device *dev, size_t *count) * Trailing NULL's can be injected by gen_device_deps.py due to * CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM */ - while ((rv[i] != Z_DEVICE_HANDLE_ENDS) && + while ((rv[i] != Z_DEVICE_DEPS_ENDS) && (rv[i] != DEVICE_HANDLE_NULL)) { ++i; } @@ -770,28 +766,28 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * * @param dev_id Device identifier. */ -#define Z_DEVICE_HANDLES_NAME(dev_id) _CONCAT(__devicehdl_, dev_id) +#define Z_DEVICE_DEPS_NAME(dev_id) _CONCAT(__devicehdl_, dev_id) /** - * @brief Expand extra handles with a comma in between. + * @brief Expand extra dependencies with a comma in between. * - * @param ... Extra handles + * @param ... Extra dependencies. */ -#define Z_DEVICE_EXTRA_HANDLES(...) \ +#define Z_DEVICE_EXTRA_DEPS(...) \ FOR_EACH_NONEMPTY_TERM(IDENTITY, (,), __VA_ARGS__) -/** @brief Linker section were device handles are placed. */ -#define Z_DEVICE_HANDLES_SECTION \ +/** @brief Linker section were device dependencies are placed. */ +#define Z_DEVICE_DEPS_SECTION \ __attribute__((__section__(".__device_deps_pass1"))) #ifdef __cplusplus -#define Z_DEVICE_HANDLES_EXTERN extern +#define Z_DEVICE_DEPS_EXTERN extern #else -#define Z_DEVICE_HANDLES_EXTERN +#define Z_DEVICE_DEPS_EXTERN #endif /** - * @brief Define device handles. + * @brief Define device dependencies. * * Initial build provides a record that associates the device object with its * devicetree ordinal, and provides the dependency ordinals. These are provided @@ -803,18 +799,18 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * { * DEVICE_ORDINAL (or DEVICE_HANDLE_NULL if not a devicetree node), * List of devicetree dependency ordinals (if any), - * Z_DEVICE_HANDLE_SEP, + * Z_DEVICE_DEPS_SEP, * List of injected dependency ordinals (if any), - * Z_DEVICE_HANDLE_SEP, + * Z_DEVICE_DEPS_SEP, * List of devicetree supporting ordinals (if any), * } * * After processing in gen_device_deps.py, the format is updated to: * { * List of existing devicetree dependency handles (if any), - * Z_DEVICE_HANDLE_SEP, + * Z_DEVICE_DEPS_SEP, * List of injected devicetree dependency handles (if any), - * Z_DEVICE_HANDLE_SEP, + * Z_DEVICE_DEPS_SEP, * List of existing devicetree support handles (if any), * DEVICE_HANDLE_NULL * } @@ -825,19 +821,19 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * subsequent links both wasting space and resulting in aggregate size changes * relative to pass2 when all objects will be in the same input section. */ -#define Z_DEVICE_HANDLES_DEFINE(node_id, dev_id, ...) \ - extern Z_DEVICE_HANDLES_CONST device_handle_t Z_DEVICE_HANDLES_NAME( \ +#define Z_DEVICE_DEPS_DEFINE(node_id, dev_id, ...) \ + extern Z_DEVICE_DEPS_CONST device_handle_t Z_DEVICE_DEPS_NAME( \ dev_id)[]; \ - Z_DEVICE_HANDLES_CONST Z_DECL_ALIGN(device_handle_t) \ - Z_DEVICE_HANDLES_SECTION Z_DEVICE_HANDLES_EXTERN __weak \ - Z_DEVICE_HANDLES_NAME(dev_id)[] = { \ + Z_DEVICE_DEPS_CONST Z_DECL_ALIGN(device_handle_t) \ + Z_DEVICE_DEPS_SECTION Z_DEVICE_DEPS_EXTERN __weak \ + Z_DEVICE_DEPS_NAME(dev_id)[] = { \ COND_CODE_1( \ DT_NODE_EXISTS(node_id), \ (DT_DEP_ORD(node_id), DT_REQUIRES_DEP_ORDS(node_id)), \ (DEVICE_HANDLE_NULL,)) /**/ \ - Z_DEVICE_HANDLE_SEP, \ - Z_DEVICE_EXTRA_HANDLES(__VA_ARGS__) /**/ \ - Z_DEVICE_HANDLE_SEP, \ + Z_DEVICE_DEPS_SEP, \ + Z_DEVICE_EXTRA_DEPS(__VA_ARGS__) /**/ \ + Z_DEVICE_DEPS_SEP, \ COND_CODE_1(DT_NODE_EXISTS(node_id), \ (DT_SUPPORTS_DEP_ORDS(node_id)), ()) /**/ \ } @@ -955,10 +951,10 @@ static inline bool z_impl_device_is_ready(const struct device *dev) level, prio, api, state, ...) \ Z_DEVICE_NAME_CHECK(name); \ \ - Z_DEVICE_HANDLES_DEFINE(node_id, dev_id, __VA_ARGS__); \ + Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__); \ \ Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ - prio, api, state, Z_DEVICE_HANDLES_NAME(dev_id)); \ + prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ \ Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn, level, prio) diff --git a/scripts/build/gen_device_deps.py b/scripts/build/gen_device_deps.py index b26e9ef38e0f..ba36e2dd449c 100755 --- a/scripts/build/gen_device_deps.py +++ b/scripts/build/gen_device_deps.py @@ -98,12 +98,12 @@ def dev_path_str(dev): def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): handles = [ *[str(d.handle) for d in handles["depends"]], - 'Z_DEVICE_HANDLE_SEP', + 'Z_DEVICE_DEPS_SEP', *[str(d.handle) for d in handles["injected"]], - 'Z_DEVICE_HANDLE_SEP', + 'Z_DEVICE_DEPS_SEP', *[str(d.handle) for d in handles["supports"]], *(extra_support_handles * ['DEVICE_HANDLE_NULL']), - 'Z_DEVICE_HANDLE_ENDS', + 'Z_DEVICE_DEPS_ENDS', ] ctype = ( '{:s}Z_DECL_ALIGN(device_handle_t) ' diff --git a/subsys/pm/device.c b/subsys/pm/device.c index f978d20889ec..07092889fab6 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -128,14 +128,14 @@ static int power_domain_add_or_remove(const struct device *dev, * with the device handle. */ while (region != 2) { - if (*rv == Z_DEVICE_HANDLE_SEP) { + if (*rv == Z_DEVICE_DEPS_SEP) { region++; } rv++; } i = 0; - while (rv[i] != Z_DEVICE_HANDLE_ENDS) { + while (rv[i] != Z_DEVICE_DEPS_ENDS) { if (add == false) { if (rv[i] == dev_handle) { dev->pm->domain = NULL; From 5982d83e2aefb1d0ead26fe10c8e3276283070e1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:38:30 +0200 Subject: [PATCH 0417/2042] device: s/struct device.handles/struct device.deps Rename struct device `handles` member to `deps`, in line with previous renamings in the device API. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/device.h | 20 ++++++++++---------- kernel/include/kernel_offsets.h | 2 +- subsys/pm/device.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 01be9c311eb6..6cdac05a6774 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -389,13 +389,13 @@ struct device { /** Address of the device instance private data */ void *data; /** - * Optional pointer to handles associated with the device. + * Optional pointer to dependencies associated with the device. * * This encodes a sequence of sets of device handles that have some * relationship to this node. The individual sets are extracted with * dedicated API, such as device_required_handles_get(). */ - Z_DEVICE_DEPS_CONST device_handle_t *handles; + Z_DEVICE_DEPS_CONST device_handle_t *deps; #if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__) /** @@ -495,7 +495,7 @@ typedef int (*device_visitor_callback_t)(const struct device *dev, static inline const device_handle_t * device_required_handles_get(const struct device *dev, size_t *count) { - const device_handle_t *rv = dev->handles; + const device_handle_t *rv = dev->deps; if (rv != NULL) { size_t i = 0; @@ -531,7 +531,7 @@ device_required_handles_get(const struct device *dev, size_t *count) static inline const device_handle_t * device_injected_handles_get(const struct device *dev, size_t *count) { - const device_handle_t *rv = dev->handles; + const device_handle_t *rv = dev->deps; size_t region = 0; size_t i = 0; @@ -575,7 +575,7 @@ device_injected_handles_get(const struct device *dev, size_t *count) static inline const device_handle_t * device_supported_handles_get(const struct device *dev, size_t *count) { - const device_handle_t *rv = dev->handles; + const device_handle_t *rv = dev->deps; size_t region = 0; size_t i = 0; @@ -864,16 +864,16 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param config_ Reference to device config. * @param api_ Reference to device API ops. * @param state_ Reference to device state. - * @param handles_ Reference to device handles. + * @param deps_ Reference to device dependencies. */ -#define Z_DEVICE_INIT(name_, pm_, data_, config_, api_, state_, handles_) \ +#define Z_DEVICE_INIT(name_, pm_, data_, config_, api_, state_, deps_) \ { \ .name = name_, \ .config = (config_), \ .api = (api_), \ .state = (state_), \ .data = (data_), \ - .handles = (handles_), \ + .deps = (deps_), \ IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \ } @@ -903,12 +903,12 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param ... Optional dependencies, manually specified. */ #define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ - prio, api, state, handles) \ + 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)) = \ - Z_DEVICE_INIT(name, pm, data, config, api, state, handles) + Z_DEVICE_INIT(name, pm, data, config, api, state, deps) /** * @brief Define the init entry for a device. diff --git a/kernel/include/kernel_offsets.h b/kernel/include/kernel_offsets.h index a12e15aa9e17..e7fbde67b095 100644 --- a/kernel/include/kernel_offsets.h +++ b/kernel/include/kernel_offsets.h @@ -74,7 +74,7 @@ GEN_ABSOLUTE_SYM(__z_interrupt_stack_SIZEOF, sizeof(z_interrupt_stacks[0])); /* member offsets in the device structure. Used in image post-processing */ GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_HANDLES_OFFSET, - offsetof(struct device, handles)); + offsetof(struct device, deps)); #ifdef CONFIG_PM_DEVICE GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET, diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 07092889fab6..7a3489823000 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -104,7 +104,7 @@ static int power_domain_add_or_remove(const struct device *dev, bool add) { #if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) - device_handle_t *rv = domain->handles; + device_handle_t *rv = domain->deps; device_handle_t dev_handle = -1; size_t i = 0, region = 0; From d93586f8316d205606f90213e3ad6ba711a16181 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:42:45 +0200 Subject: [PATCH 0418/2042] device: s/__devicehdl_/__devicedeps_/ Rename the device dependencies array variable to use the "deps" name, in line with latest renamings in device.h Signed-off-by: Gerard Marull-Paretas --- include/zephyr/device.h | 2 +- scripts/build/elf_parser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 6cdac05a6774..8ddb426e598f 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -766,7 +766,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * * @param dev_id Device identifier. */ -#define Z_DEVICE_DEPS_NAME(dev_id) _CONCAT(__devicehdl_, dev_id) +#define Z_DEVICE_DEPS_NAME(dev_id) _CONCAT(__devicedeps_, dev_id) /** * @brief Expand extra dependencies with a comma in between. diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index fc7733f857b6..3dcc8534fe69 100644 --- a/scripts/build/elf_parser.py +++ b/scripts/build/elf_parser.py @@ -228,7 +228,7 @@ def _on_pm(sym): ordinal_arrays = {} def _on_ordinal(sym): ordinal_arrays[sym.entry.st_value] = DeviceOrdinals(self, sym) - self._object_find_named('__devicehdl_', _on_ordinal) + self._object_find_named('__devicedeps_', _on_ordinal) # Find all device structs def _on_device(sym): From 319fbe57e16478b5bc96eb5ed3a292a2cfb5e35f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 12:57:29 +0200 Subject: [PATCH 0419/2042] device: s/HAS_DYNAMIC_DEVICE_HANDLES/DEVICE_DEPS_DYMAMIC Rename the Kconfig option to be in line with recent renamings in device handles/dependencies. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 2 +- include/zephyr/device.h | 2 +- include/zephyr/linker/common-ram.ld | 4 ++-- include/zephyr/linker/common-rom/common-rom-kernel-devices.ld | 4 ++-- kernel/Kconfig | 4 ++-- subsys/pm/Kconfig | 2 +- subsys/pm/device.c | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d295a0cf006c..16aaf46953b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -913,7 +913,7 @@ zephyr_get_include_directories_for_lang(C ) if(CONFIG_HAS_DTS) - if(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) + if(CONFIG_DEVICE_DEPS_DYNAMIC) set(dynamic_handles --dynamic-handles) endif() diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 8ddb426e598f..fc0862c5d2a6 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -368,7 +368,7 @@ struct device_state { struct pm_device; -#ifdef CONFIG_HAS_DYNAMIC_DEVICE_HANDLES +#ifdef CONFIG_DEVICE_DEPS_DYNAMIC #define Z_DEVICE_DEPS_CONST #else #define Z_DEVICE_DEPS_CONST const diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index 269d56be46e5..e354c723a2f6 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -42,12 +42,12 @@ ITERABLE_SECTION_RAM(pm_device_slots, 4) #endif -#if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) +#if defined(CONFIG_DEVICE_DEPS_DYNAMIC) SECTION_DATA_PROLOGUE(device_deps,,) { #include "device-deps.ld" } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) -#endif /* CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ +#endif /* CONFIG_DEVICE_DEPS_DYNAMIC */ ITERABLE_SECTION_RAM_GC_ALLOWED(log_mpsc_pbuf, 4) ITERABLE_SECTION_RAM(log_msg_ptr, 4) diff --git a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld index b7acb08d90c9..6b26691fa597 100644 --- a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld +++ b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld @@ -64,9 +64,9 @@ ITERABLE_SECTION_ROM(irq_alloc, 4) #endif /* CONFIG_PCIE */ -#if !defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) +#if !defined(CONFIG_DEVICE_DEPS_DYNAMIC) SECTION_DATA_PROLOGUE(device_deps,,) { #include } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) -#endif /* !CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ +#endif /* !CONFIG_DEVICE_DEPS_DYNAMIC */ diff --git a/kernel/Kconfig b/kernel/Kconfig index 6dbca69694f8..0911fe3b3243 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -969,10 +969,10 @@ endmenu menu "Device Options" -config HAS_DYNAMIC_DEVICE_HANDLES +config DEVICE_DEPS_DYNAMIC bool help - Hidden option that makes possible to manipulate device handles at + Hidden option that makes possible to manipulate device dependencies at runtime. endmenu diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 4395e7718598..359bc8a977b2 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -91,7 +91,7 @@ config PM_DEVICE_POWER_DOMAIN config PM_DEVICE_POWER_DOMAIN_DYNAMIC bool "Dynamically bind devices to a Power Pomain" depends on PM_DEVICE_POWER_DOMAIN - select HAS_DYNAMIC_DEVICE_HANDLES + select DEVICE_DEPS_DYNAMIC help Enable support for dynamically bind devices to a Power Domain. diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 7a3489823000..e520fe3e3323 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -103,7 +103,7 @@ static int power_domain_add_or_remove(const struct device *dev, const struct device *domain, bool add) { -#if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) +#if defined(CONFIG_DEVICE_DEPS_DYNAMIC) device_handle_t *rv = domain->deps; device_handle_t dev_handle = -1; size_t i = 0, region = 0; From 1ebd76ed51053851eb206e09a7f3acb5b6eaad88 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 17:04:52 +0200 Subject: [PATCH 0420/2042] pm: add prompt to DEVICE_DEPS_DYNAMIC The option can now be set by projects. This change will also allow to make it dependent on a future CONFIG_DEVICE_DEPS option. Signed-off-by: Gerard Marull-Paretas --- kernel/Kconfig | 4 ++-- subsys/pm/Kconfig | 3 +-- tests/subsys/pm/power_domain/prj.conf | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/Kconfig b/kernel/Kconfig index 0911fe3b3243..4a84f2554af2 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -970,9 +970,9 @@ endmenu menu "Device Options" config DEVICE_DEPS_DYNAMIC - bool + bool "Dynamic device dependencies" help - Hidden option that makes possible to manipulate device dependencies at + Option that makes it possible to manipulate device dependencies at runtime. endmenu diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 359bc8a977b2..240924f17bac 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -90,8 +90,7 @@ config PM_DEVICE_POWER_DOMAIN config PM_DEVICE_POWER_DOMAIN_DYNAMIC bool "Dynamically bind devices to a Power Pomain" - depends on PM_DEVICE_POWER_DOMAIN - select DEVICE_DEPS_DYNAMIC + depends on PM_DEVICE_POWER_DOMAIN && DEVICE_DEPS_DYNAMIC help Enable support for dynamically bind devices to a Power Domain. diff --git a/tests/subsys/pm/power_domain/prj.conf b/tests/subsys/pm/power_domain/prj.conf index dbcd7205791c..1f5e9efea787 100644 --- a/tests/subsys/pm/power_domain/prj.conf +++ b/tests/subsys/pm/power_domain/prj.conf @@ -1,4 +1,5 @@ CONFIG_ZTEST=y +CONFIG_DEVICE_DEPS_DYNAMIC=y CONFIG_PM=y CONFIG_PM_DEVICE=y CONFIG_POWER_DOMAIN=y From aedcc0b59d6b57dcf5e78e2c1209429d2971a712 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 16:27:03 +0200 Subject: [PATCH 0421/2042] tests: misc: check_init_priorities: check for zephyr_pre1 target zephyr_pre1 target may not always exists, e.g. if second linking pass is not needed. Signed-off-by: Gerard Marull-Paretas --- tests/misc/check_init_priorities/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/misc/check_init_priorities/CMakeLists.txt b/tests/misc/check_init_priorities/CMakeLists.txt index 2011564aed79..c5e9fec4071c 100644 --- a/tests/misc/check_init_priorities/CMakeLists.txt +++ b/tests/misc/check_init_priorities/CMakeLists.txt @@ -17,7 +17,9 @@ add_custom_target( ${output_file} DEPENDS zephyr_pre0 ) -add_dependencies(zephyr_pre1 check_init_priorities_output) +if (TARGET zephyr_pre1) + add_dependencies(zephyr_pre1 check_init_priorities_output) +endif() project(check_init_priorities) From b6d5d246b740a91d788cd9a7b05efdc2a605e876 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 17:12:55 +0200 Subject: [PATCH 0422/2042] scripts: build: gen_device_deps: s/--dynamic-handles/--dynamic-deps Align naming of the CLI option with recent changes in handles naming. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 4 ++-- scripts/build/gen_device_deps.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16aaf46953b8..386dedec5ef7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -914,7 +914,7 @@ zephyr_get_include_directories_for_lang(C if(CONFIG_HAS_DTS) if(CONFIG_DEVICE_DEPS_DYNAMIC) - set(dynamic_handles --dynamic-handles) + set(dynamic_deps --dynamic-deps) endif() if(CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC) @@ -932,7 +932,7 @@ if(CONFIG_HAS_DTS) ${ZEPHYR_BASE}/scripts/build/gen_device_deps.py --output-source device_deps.c --output-graphviz dev_graph.dot - ${dynamic_handles} + ${dynamic_deps} --num-dynamic-devices ${number_of_dynamic_devices} --kernel $ --zephyr-base ${ZEPHYR_BASE} diff --git a/scripts/build/gen_device_deps.py b/scripts/build/gen_device_deps.py index ba36e2dd449c..3f563eb466b9 100755 --- a/scripts/build/gen_device_deps.py +++ b/scripts/build/gen_device_deps.py @@ -46,8 +46,8 @@ def parse_args(): parser.add_argument("-k", "--kernel", required=True, help="Input zephyr ELF binary") - parser.add_argument("--dynamic-handles", action="store_true", - help="Indicates if device handles are dynamic") + parser.add_argument("--dynamic-deps", action="store_true", + help="Indicates if device dependencies are dynamic") parser.add_argument("-d", "--num-dynamic-devices", required=False, default=0, type=int, help="Input number of dynamic devices allowed") parser.add_argument("-o", "--output-source", required=True, @@ -95,7 +95,7 @@ def dev_path_str(dev): lines.append(' */') return lines -def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): +def c_handle_array(dev, handles, dynamic_deps, extra_support_handles=0): handles = [ *[str(d.handle) for d in handles["depends"]], 'Z_DEVICE_DEPS_SEP', @@ -108,7 +108,7 @@ def c_handle_array(dev, handles, dynamic_handles, extra_support_handles=0): ctype = ( '{:s}Z_DECL_ALIGN(device_handle_t) ' '__attribute__((__section__(".__device_deps_pass2")))' - ).format('const ' if not dynamic_handles else '') + ).format('const ' if not dynamic_deps else '') return [ # The `extern` line pretends this was first declared in some .h # file to silence "should it be static?" warnings in some @@ -159,7 +159,7 @@ def main(): extra_sups = args.num_dynamic_devices if dev.pm and dev.pm.is_power_domain else 0 lines = c_handle_comment(dev, sorted_handles) lines.extend( - c_handle_array(dev, sorted_handles, args.dynamic_handles, extra_sups) + c_handle_array(dev, sorted_handles, args.dynamic_deps, extra_sups) ) lines.extend(['']) fp.write('\n'.join(lines)) From 48b201cc53046b15b0220b074d4a8b10070c6d3f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 14 Jun 2023 14:30:41 +0200 Subject: [PATCH 0423/2042] device: make device dependencies optional Device dependencies are not always required, so make them optional via CONFIG_DEVICE_DEPS. When enabled, the gen_device_deps script will run so that dependencies are collected and part of the final image. Related APIs will be also made available. Since device dependencies are used in just a few places (power domains), disable the feature by default. When not enabled, a second linking pass will not be required. Signed-off-by: Gerard Marull-Paretas --- CMakeLists.txt | 8 ++++---- cmake/linker_script/common/common-rom.cmake | 8 +++++--- drivers/power_domain/Kconfig | 2 ++ include/zephyr/device.h | 19 +++++++++++++++---- kernel/Kconfig | 9 +++++++++ kernel/device.c | 4 ++++ kernel/include/kernel_offsets.h | 2 ++ subsys/pm/device.c | 2 ++ subsys/shell/modules/device_service.c | 5 +++++ tests/lib/devicetree/devices/prj.conf | 1 + tests/subsys/pm/power_domain/prj.conf | 1 + 11 files changed, 50 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 386dedec5ef7..f64f4cf0ff1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ set(CMAKE_EXECUTABLE_SUFFIX .elf) # into the `zephyr_final` target. # # Multiple linking stages are required in the following cases: -# - device handles structs must be generated (CONFIG_HAS_DTS=y) +# - device dependencies structs must be generated (CONFIG_DEVICE_DEPS=y) # - ISR tables must be generated (CONFIG_GEN_ISR_TABLES=y) # - Kernel objects hash tables (CONFIG_USERSPACE=y) # - Application memory partitions (CONFIG_USERSPACE=y) @@ -75,7 +75,7 @@ set(ZEPHYR_LINK_STAGE_EXECUTABLE zephyr_pre${ZEPHYR_CURRENT_LINKER_PASS}) # existing variable to allow slowly cleanup of linking stage handling. # Three stage linking active: pre0 -> pre1 -> final, this will correspond to `pre1` # Two stage linking active: pre0 -> final, this will correspond to `pre0` -if(CONFIG_USERSPACE OR CONFIG_HAS_DTS) +if(CONFIG_USERSPACE OR CONFIG_DEVICE_DEPS) set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre1) else() set(ZEPHYR_PREBUILT_EXECUTABLE zephyr_pre0) @@ -912,7 +912,7 @@ zephyr_get_include_directories_for_lang(C STRIP_PREFIX # Don't use a -I prefix ) -if(CONFIG_HAS_DTS) +if(CONFIG_DEVICE_DEPS) if(CONFIG_DEVICE_DEPS_DYNAMIC) set(dynamic_deps --dynamic-deps) endif() @@ -1177,7 +1177,7 @@ if(CONFIG_USERSPACE) ) endif() -if(CONFIG_USERSPACE OR CONFIG_HAS_DTS) +if(CONFIG_USERSPACE OR CONFIG_DEVICE_DEPS) configure_linker_script( ${ZEPHYR_CURRENT_LINKER_CMD} "${LINKER_PASS_${ZEPHYR_CURRENT_LINKER_PASS}_DEFINE}" diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index 4417d1081360..470996e470e9 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -185,9 +185,11 @@ zephyr_iterable_section(NAME tracing_backend KVMA RAM_REGION GROUP RODATA_REGION zephyr_linker_section(NAME zephyr_dbg_info KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT}) zephyr_linker_section_configure(SECTION zephyr_dbg_info INPUT ".zephyr_dbg_info" KEEP) -zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16) -zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1) -zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1) +if (CONFIG_DEVICE_DEPS) + zephyr_linker_section(NAME device_deps KVMA RAM_REGION GROUP RODATA_REGION NOINPUT ${XIP_ALIGN_WITH_INPUT} ENDALIGN 16) + zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass1* KEEP SORT NAME PASS LINKER_DEVICE_DEPS_PASS1) + zephyr_linker_section_configure(SECTION device_deps INPUT .__device_deps_pass2* KEEP SORT NAME PASS NOT LINKER_DEVICE_DEPS_PASS1) +endif() zephyr_iterable_section(NAME _static_thread_data KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index a418537c87b1..6c8563d4724d 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -18,11 +18,13 @@ config POWER_DOMAIN_GPIO depends on DT_HAS_POWER_DOMAIN_GPIO_ENABLED depends on GPIO depends on TIMEOUT_64BIT + select DEVICE_DEPS config POWER_DOMAIN_INTEL_ADSP bool "Use Intel ADSP power gating mechanisms" default y depends on DT_HAS_INTEL_ADSP_POWER_DOMAIN_ENABLED + select DEVICE_DEPS help Include Intel ADSP power domain control mechanisms diff --git a/include/zephyr/device.h b/include/zephyr/device.h index fc0862c5d2a6..b9bff1c603a7 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -388,15 +388,17 @@ struct device { struct device_state *state; /** Address of the device instance private data */ void *data; +#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__) /** * Optional pointer to dependencies associated with the device. * * This encodes a sequence of sets of device handles that have some * relationship to this node. The individual sets are extracted with - * dedicated API, such as device_required_handles_get(). + * dedicated API, such as device_required_handles_get(). Only available + * if @kconfig{CONFIG_DEVICE_DEPS} is enabled. */ Z_DEVICE_DEPS_CONST device_handle_t *deps; - +#endif /* CONFIG_DEVICE_DEPS */ #if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__) /** * Reference to the device PM resources (only available if @@ -453,6 +455,8 @@ device_from_handle(device_handle_t dev_handle) return dev; } +#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__) + /** * @brief Prototype for functions used when iterating over a set of devices. * @@ -668,6 +672,8 @@ int device_supported_foreach(const struct device *dev, device_visitor_callback_t visitor_cb, void *context); +#endif /* CONFIG_DEVICE_DEPS */ + /** * @brief Get a @ref device reference from its @ref device.name field. * @@ -760,6 +766,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev) static Z_DECL_ALIGN(struct device_state) Z_DEVICE_STATE_NAME(dev_id) \ __attribute__((__section__(".z_devstate"))) +#if defined(CONFIG_DEVICE_DEPS) || defined(__DOXYGEN__) + /** * @brief Synthesize the name of the object that holds device ordinal and * dependency data. @@ -838,6 +846,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev) (DT_SUPPORTS_DEP_ORDS(node_id)), ()) /**/ \ } +#endif /* CONFIG_DEVICE_DEPS */ + /** * @brief Maximum device name length. * @@ -873,7 +883,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) .api = (api_), \ .state = (state_), \ .data = (data_), \ - .deps = (deps_), \ + IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \ IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \ } @@ -951,7 +961,8 @@ static inline bool z_impl_device_is_ready(const struct device *dev) level, prio, api, state, ...) \ Z_DEVICE_NAME_CHECK(name); \ \ - Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__); \ + IF_ENABLED(CONFIG_DEVICE_DEPS, \ + (Z_DEVICE_DEPS_DEFINE(node_id, dev_id, __VA_ARGS__);)) \ \ Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ diff --git a/kernel/Kconfig b/kernel/Kconfig index 4a84f2554af2..e553553b1c74 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -969,8 +969,17 @@ endmenu menu "Device Options" +config DEVICE_DEPS + bool "Store device dependencies" + help + When enabled, device dependencies will be stored so that they can be + queried at runtime. Device dependencies are typically inferred from + devicetree. Enabling this option will increase ROM usage (or RAM if + dynamic device dependencies are enabled). + config DEVICE_DEPS_DYNAMIC bool "Dynamic device dependencies" + depends on DEVICE_DEPS help Option that makes it possible to manipulate device dependencies at runtime. diff --git a/kernel/device.c b/kernel/device.c index 3aa237716ad4..d5ceb615461a 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -100,6 +100,8 @@ bool z_device_is_ready(const struct device *dev) return dev->state->initialized && (dev->state->init_res == 0U); } +#ifdef CONFIG_DEVICE_DEPS + static int device_visitor(const device_handle_t *handles, size_t handle_count, device_visitor_callback_t visitor_cb, @@ -138,3 +140,5 @@ int device_supported_foreach(const struct device *dev, return device_visitor(handles, handle_count, visitor_cb, context); } + +#endif /* CONFIG_DEVICE_DEPS */ diff --git a/kernel/include/kernel_offsets.h b/kernel/include/kernel_offsets.h index e7fbde67b095..f7676438d9eb 100644 --- a/kernel/include/kernel_offsets.h +++ b/kernel/include/kernel_offsets.h @@ -73,8 +73,10 @@ GEN_OFFSET_SYM(_thread_t, tls); GEN_ABSOLUTE_SYM(__z_interrupt_stack_SIZEOF, sizeof(z_interrupt_stacks[0])); /* member offsets in the device structure. Used in image post-processing */ +#ifdef CONFIG_DEVICE_DEPS GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_HANDLES_OFFSET, offsetof(struct device, deps)); +#endif #ifdef CONFIG_PM_DEVICE GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET, diff --git a/subsys/pm/device.c b/subsys/pm/device.c index e520fe3e3323..baf37983d692 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -174,6 +174,7 @@ int pm_device_power_domain_add(const struct device *dev, return power_domain_add_or_remove(dev, domain, true); } +#ifdef CONFIG_DEVICE_DEPS struct pm_visitor_context { pm_device_action_failed_cb_t failure_cb; enum pm_device_action action; @@ -205,6 +206,7 @@ void pm_device_children_action_run(const struct device *dev, (void)device_supported_foreach(dev, pm_device_children_visitor, &visitor_context); } +#endif int pm_device_state_get(const struct device *dev, enum pm_device_state *state) diff --git a/subsys/shell/modules/device_service.c b/subsys/shell/modules/device_service.c index b0f899bbdcc5..c11c8b4a7b9d 100644 --- a/subsys/shell/modules/device_service.c +++ b/subsys/shell/modules/device_service.c @@ -27,6 +27,8 @@ static const char *get_device_name(const struct device *dev, return name; } + +#ifdef CONFIG_DEVICE_DEPS struct cmd_device_list_visitor_context { const struct shell *sh; char *buf; @@ -43,6 +45,7 @@ static int cmd_device_list_visitor(const struct device *dev, return 0; } +#endif /* CONFIG_DEVICE_DEPS */ static int cmd_device_list(const struct shell *sh, size_t argc, char **argv) @@ -77,6 +80,7 @@ static int cmd_device_list(const struct shell *sh, } shell_fprintf(sh, SHELL_NORMAL, " (%s)\n", state); +#ifdef CONFIG_DEVICE_DEPS if (!k_is_user_context()) { struct cmd_device_list_visitor_context ctx = { .sh = sh, @@ -86,6 +90,7 @@ static int cmd_device_list(const struct shell *sh, (void)device_required_foreach(dev, cmd_device_list_visitor, &ctx); } +#endif /* CONFIG_DEVICE_DEPS */ } return 0; diff --git a/tests/lib/devicetree/devices/prj.conf b/tests/lib/devicetree/devices/prj.conf index 6589a723a886..c440074560fb 100644 --- a/tests/lib/devicetree/devices/prj.conf +++ b/tests/lib/devicetree/devices/prj.conf @@ -1,3 +1,4 @@ CONFIG_ZTEST=y CONFIG_I2C=n CONFIG_ZTEST_NEW_API=y +CONFIG_DEVICE_DEPS=y diff --git a/tests/subsys/pm/power_domain/prj.conf b/tests/subsys/pm/power_domain/prj.conf index 1f5e9efea787..a6880b99dfc3 100644 --- a/tests/subsys/pm/power_domain/prj.conf +++ b/tests/subsys/pm/power_domain/prj.conf @@ -1,4 +1,5 @@ CONFIG_ZTEST=y +CONFIG_DEVICE_DEPS=y CONFIG_DEVICE_DEPS_DYNAMIC=y CONFIG_PM=y CONFIG_PM_DEVICE=y From b3f5db0c718f76560238a4e4c06bb5d8619589b9 Mon Sep 17 00:00:00 2001 From: Luca Fancellu Date: Thu, 15 Jun 2023 16:44:35 +0100 Subject: [PATCH 0424/2042] net: eth: Fix ethernet max header size on VLAN presence Currently NET_ETH_MAX_HDR_SIZE is computed as the size of the structure struct net_eth_hdr, but this does not take into account the additional 4 bytes on the ethernet frame header in the presence of VLAN, fix the issue using the size of struct net_eth_vlan_hdr when CONFIG_NET_VLAN is enabled. Signed-off-by: Luca Fancellu --- include/zephyr/net/ethernet.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 0807c2be33ec..b4fad4224dd3 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -96,8 +96,14 @@ struct net_eth_addr { #define NET_ETH_MINIMAL_FRAME_SIZE 60 #define NET_ETH_MTU 1500 -#define _NET_ETH_MAX_FRAME_SIZE (NET_ETH_MTU + sizeof(struct net_eth_hdr)) + +#if defined(CONFIG_NET_VLAN) +#define _NET_ETH_MAX_HDR_SIZE (sizeof(struct net_eth_vlan_hdr)) +#else #define _NET_ETH_MAX_HDR_SIZE (sizeof(struct net_eth_hdr)) +#endif + +#define _NET_ETH_MAX_FRAME_SIZE (NET_ETH_MTU + _NET_ETH_MAX_HDR_SIZE) /* * Extend the max frame size for DSA (KSZ8794) by one byte (to 1519) to * store tail tag. From 38a43b0eec494a0bce0d94c8c31309c9cfe67984 Mon Sep 17 00:00:00 2001 From: Luca Fancellu Date: Tue, 13 Jun 2023 11:31:05 +0100 Subject: [PATCH 0425/2042] net: config: Add VLAN identifier as network initial configuration Add a new Kconfig parameter NET_CONFIG_MY_VLAN_ID as initial network configuration to enable users to set VLAN identifier at startup. Add a new setup_vlan(...) function to setup the VLAN identifier in the device, the call have an effect only when NET_CONFIG_MY_VLAN_ID is above zero. Signed-off-by: Luca Fancellu --- subsys/net/lib/config/Kconfig | 7 +++++++ subsys/net/lib/config/init.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/subsys/net/lib/config/Kconfig b/subsys/net/lib/config/Kconfig index 528bbb6986f7..0f1e3c50544e 100644 --- a/subsys/net/lib/config/Kconfig +++ b/subsys/net/lib/config/Kconfig @@ -71,6 +71,13 @@ menuconfig NET_CONFIG_SETTINGS if NET_CONFIG_SETTINGS +config NET_CONFIG_MY_VLAN_ID + int "My VLAN identifier" + default 0 + depends on NET_VLAN + help + Use 0 here if uncertain. + if NET_IPV6 config NET_CONFIG_MY_IPV6_ADDR diff --git a/subsys/net/lib/config/init.c b/subsys/net/lib/config/init.c index e019987ca881..cd2bf711a7d5 100644 --- a/subsys/net/lib/config/init.c +++ b/subsys/net/lib/config/init.c @@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(net_config, CONFIG_NET_CONFIG_LOG_LEVEL); #include #include +#include #include #include #include @@ -111,6 +112,22 @@ static void setup_dhcpv4(struct net_if *iface) #define setup_dhcpv4(...) #endif /* CONFIG_NET_DHCPV4 */ +#if defined(CONFIG_NET_VLAN) && (CONFIG_NET_CONFIG_MY_VLAN_ID > 0) + +static void setup_vlan(struct net_if *iface) +{ + int ret = net_eth_vlan_enable(iface, CONFIG_NET_CONFIG_MY_VLAN_ID); + + if (ret < 0) { + NET_ERR("Network interface %d (%p): cannot set VLAN tag (%d)", + net_if_get_by_iface(iface), iface, ret); + } +} + +#else +#define setup_vlan(...) +#endif /* CONFIG_NET_VLAN && (CONFIG_NET_CONFIG_MY_VLAN_ID > 0) */ + #if defined(CONFIG_NET_NATIVE_IPV4) && !defined(CONFIG_NET_DHCPV4) && \ !defined(CONFIG_NET_CONFIG_MY_IPV4_ADDR) #error "You need to define an IPv4 address or enable DHCPv4!" @@ -379,6 +396,7 @@ int net_config_init_by_iface(struct net_if *iface, const char *app_info, #endif } + setup_vlan(iface); setup_ipv4(iface); setup_dhcpv4(iface); setup_ipv6(iface, flags); From 54b8044d036bb0c3f5bc0fe5772106453e1cd454 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 20 Jun 2023 17:54:39 +0530 Subject: [PATCH 0426/2042] boards: thingy53: Fix missing entry for CPUNET CPUNET uses a diffetent DTS file and the edge connector entry was missed, this causes build issue for CPUNET. Fixes 017ff78466("boards: thingy53: Update DTS files to support expansion boards"). Signed-off-by: Chaitanya Tata --- .../thingy53_nrf5340/thingy53_nrf5340_cpunet.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts index 6542d47d28e4..fedf35c8b3e1 100644 --- a/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts +++ b/boards/arm/thingy53_nrf5340/thingy53_nrf5340_cpunet.dts @@ -63,6 +63,20 @@ supply-voltage-mv = <3000>; }; + edge_connector: connector { + compatible = "nordic-thingy53-edge-connector"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <8 0 &gpio0 5 0>, /* P8, P0.05/AIN1 */ + <9 0 &gpio0 4 0>, /* P9, P0.04/AIN0 */ + <15 0 &gpio0 8 0>, /* P15, P0.08/TRACEDATA3 */ + <16 0 &gpio0 9 0>, /* P16, P0.09/TRACEDATA2 */ + <17 0 &gpio0 10 0>, /* P17, P0.10/TRACEDATA1 */ + <18 0 &gpio0 11 0>, /* P18, P0.11/TRACEDATA0 */ + <19 0 &gpio0 12 0>; /* P19, P0.12/TRACECLK */ + }; + aliases { sw0 = &button0; sw1 = &button1; From 8b9815aff643162c067d809bb2c7e25812d70c1e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:36:48 +0200 Subject: [PATCH 0427/2042] Bluetooth: IAS: Fix alert level loop The loop was supposed to set the alert level to the highest value by any device. The loop, however, only made sense if CONFIG_BT_MAX_CONN > 1. It has been modified to start from [0] instead of [1] and the initial condition was modified. Signed-off-by: Emil Gydesen --- subsys/bluetooth/services/ias/ias.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/services/ias/ias.c b/subsys/bluetooth/services/ias/ias.c index 4bbf8a3a7e31..1df53cac0984 100644 --- a/subsys/bluetooth/services/ias/ias.c +++ b/subsys/bluetooth/services/ias/ias.c @@ -41,10 +41,10 @@ static enum bt_ias_alert_lvl curr_lvl; static void set_alert_level(void) { - enum bt_ias_alert_lvl alert_level; + enum bt_ias_alert_lvl alert_level = BT_IAS_ALERT_LVL_NO_ALERT; - alert_level = devices[0].alert_level; - for (int i = 1; i < CONFIG_BT_MAX_CONN; i++) { + /* Set the alert_level as the highest requested by any device */ + for (int i = 0; i < CONFIG_BT_MAX_CONN; i++) { if (alert_level < devices[i].alert_level) { alert_level = devices[i].alert_level; } From 95cef5f3ab69d3afe93d7fc2498dd509f9847ec0 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 19 Jun 2023 14:37:04 +0300 Subject: [PATCH 0428/2042] net: lwm2m: Ensure string termination When writing string data to resources which are string types, we should count in the terminating character into the data length. Corner cases exist where LwM2M resource type is opaque but lwm2m_get_string() or lwm2m_set_string() are used to read/write the data. We must ensure string termination on those case, but terminating character must not be stored in the engine buffer or counted in the data length as this might be considered as part of the binary data. Fixes #59196 Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 8 +-- subsys/net/lib/lwm2m/lwm2m_registry.c | 53 ++++++++++++----- .../lwm2m/lwm2m_registry/src/lwm2m_registry.c | 57 +++++++++++++++++++ 3 files changed, 99 insertions(+), 19 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 222a90026c3d..378ca20b5d63 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -1149,23 +1149,23 @@ int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t bufl * * @param[in] pathstr LwM2M path string "obj/obj-inst/res(/res-inst)" * @param[out] str String buffer to copy data into - * @param[in] strlen Length of buffer + * @param[in] buflen Length of buffer * * @return 0 for success or negative in case of error. */ __deprecated -int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen); +int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen); /** * @brief Get resource (instance) value (string) * * @param[in] path LwM2M path as a struct * @param[out] str String buffer to copy data into - * @param[in] strlen Length of buffer + * @param[in] buflen Length of buffer * * @return 0 for success or negative in case of error. */ -int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t strlen); +int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen); /** * @brief Get resource (instance) value (u8) diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index cd5191c4c464..bbf0591121d6 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -436,6 +436,22 @@ int path_to_objs(const struct lwm2m_obj_path *path, struct lwm2m_engine_obj_inst return 0; } + +static bool is_string(const struct lwm2m_obj_path *path) +{ + struct lwm2m_engine_obj_field *obj_field; + int ret; + + ret = path_to_objs(path, NULL, &obj_field, NULL, NULL); + if (ret < 0 || !obj_field) { + return false; + } + if (obj_field->data_type == LWM2M_RES_TYPE_STRING) { + return true; + } + return false; +} + /* User data setter functions */ int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len, @@ -632,15 +648,8 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value break; case LWM2M_RES_TYPE_STRING: - /* check length (note: we add 1 to string length for NULL pad) */ - if (len > max_data_len - 1) { - LOG_ERR("String length %u is too long for res instance %d data", len, - path->res_id); - k_mutex_unlock(®istry_lock); - return -ENOMEM; - } - memcpy((uint8_t *)data_ptr, value, len); - ((uint8_t *)data_ptr)[len] = '\0'; + strncpy(data_ptr, value, len - 1); + ((char *)data_ptr)[len - 1] = '\0'; break; case LWM2M_RES_TYPE_U32: @@ -753,7 +762,14 @@ int lwm2m_engine_set_opaque(const char *pathstr, const char *data_ptr, uint16_t int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr) { - return lwm2m_engine_set(path, data_ptr, strlen(data_ptr)); + uint16_t len = strlen(data_ptr); + + /* String resources contain terminator as well, opaque resources don't */ + if (is_string(path)) { + len += 1; + } + + return lwm2m_engine_set(path, data_ptr, len); } int lwm2m_engine_set_string(const char *pathstr, const char *data_ptr) @@ -1134,7 +1150,8 @@ static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16 break; case LWM2M_RES_TYPE_STRING: - strncpy((uint8_t *)buf, (uint8_t *)data_ptr, buflen); + strncpy(buf, data_ptr, buflen - 1); + ((char *)buf)[buflen - 1] = '\0'; break; case LWM2M_RES_TYPE_U32: @@ -1229,12 +1246,18 @@ int lwm2m_engine_get_opaque(const char *pathstr, void *buf, uint16_t buflen) return lwm2m_get_opaque(&path, buf, buflen); } -int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t strlen) +int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen) { - return lwm2m_engine_get(path, str, strlen); + /* Ensure termination, in case resource is not a string type */ + if (!is_string(path)) { + memset(str, 0, buflen); + buflen -= 1; /* Last terminator cannot be overwritten */ + } + + return lwm2m_engine_get(path, str, buflen); } -int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen) +int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen) { struct lwm2m_obj_path path; int ret = 0; @@ -1243,7 +1266,7 @@ int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t strlen) if (ret < 0) { return ret; } - return lwm2m_get_opaque(&path, str, strlen); + return lwm2m_get_string(&path, str, buflen); } int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value) 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 7ffd17d196c6..aa927e6eb0b9 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -294,3 +294,60 @@ ZTEST(lwm2m_registry, test_callbacks) zassert_equal(ret, 0); zassert_equal(callback_checker, 0x7F); } + +ZTEST(lwm2m_registry, test_strings) +{ + int ret; + char buf[256] = {0}; + struct lwm2m_obj_path path = LWM2M_OBJ(0, 0, 0); + static const char uri[] = "coap://127.0.0.1"; + uint16_t len; + uint8_t *p; + + ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL); + zassert_equal(ret, 0); + memset(p, 0xff, len); /* Pre-fill buffer to check */ + + /* Handle strings in string resources */ + ret = lwm2m_set_string(&path, uri); + zassert_equal(ret, 0); + ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL); + zassert_equal(ret, 0); + zassert_equal(len, sizeof(uri)); + zassert_equal(p[len - 1], '\0'); /* string terminator in buffer */ + zassert_equal(p[len], 0xff); + + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(memcmp(uri, buf, sizeof(uri)), 0); + ret = lwm2m_get_string(&path, buf, sizeof(uri)); + zassert_equal(ret, 0); + ret = lwm2m_get_string(&path, buf, strlen(uri)); + zassert_equal(ret, -ENOMEM); + + /* Handle strings in opaque resources (no terminator) */ + path = LWM2M_OBJ(0, 0, 3); + ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL); + zassert_equal(ret, 0); + memset(p, 0xff, len); /* Pre-fill buffer to check */ + + ret = lwm2m_set_string(&path, uri); + zassert_equal(ret, 0); + ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL); + zassert_equal(ret, 0); + zassert_equal(len, strlen(uri)); /* No terminator counted in data length */ + zassert_equal(p[len - 1], '1'); /* Last character in buffer is not terminator */ + zassert_equal(p[len], 0xff); + memset(buf, 0xff, sizeof(buf)); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); /* get_string ensures termination */ + zassert_equal(ret, 0); + zassert_equal(memcmp(uri, buf, sizeof(uri)), 0); + ret = lwm2m_get_string(&path, buf, sizeof(uri)); + zassert_equal(ret, 0); + ret = lwm2m_get_string(&path, buf, strlen(uri)); + zassert_equal(ret, -ENOMEM); + /* Corner case: we request exactly as much is stored in opaque resource, */ + /* but because we request as a string, it must have room for terminator. */ + ret = lwm2m_get_string(&path, buf, len); + zassert_equal(ret, -ENOMEM); +} From 512371b75b6ebfd1b5653d12d62360caaba10074 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 3 Mar 2023 16:44:53 +0800 Subject: [PATCH 0429/2042] soc: arm: add support for nuvoton numaker m46x series Add initial support for nuvoton numaker m46x SoC series including basic init. Signed-off-by: cyliang tw --- dts/arm/nuvoton/m46x.dtsi | 43 +++++++++++++ modules/Kconfig.nuvoton | 52 +++++++++++++++- soc/arm/nuvoton_numaker/CMakeLists.txt | 8 +++ soc/arm/nuvoton_numaker/Kconfig | 18 ++++++ soc/arm/nuvoton_numaker/Kconfig.defconfig | 5 ++ soc/arm/nuvoton_numaker/Kconfig.soc | 5 ++ soc/arm/nuvoton_numaker/m46x/CMakeLists.txt | 5 ++ .../m46x/Kconfig.defconfig.m467 | 10 ++++ .../m46x/Kconfig.defconfig.series | 12 ++++ soc/arm/nuvoton_numaker/m46x/Kconfig.series | 15 +++++ soc/arm/nuvoton_numaker/m46x/Kconfig.soc | 13 ++++ soc/arm/nuvoton_numaker/m46x/linker.ld | 7 +++ soc/arm/nuvoton_numaker/m46x/soc.c | 60 +++++++++++++++++++ soc/arm/nuvoton_numaker/m46x/soc.h | 13 ++++ 14 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 dts/arm/nuvoton/m46x.dtsi create mode 100644 soc/arm/nuvoton_numaker/CMakeLists.txt create mode 100644 soc/arm/nuvoton_numaker/Kconfig create mode 100644 soc/arm/nuvoton_numaker/Kconfig.defconfig create mode 100644 soc/arm/nuvoton_numaker/Kconfig.soc create mode 100644 soc/arm/nuvoton_numaker/m46x/CMakeLists.txt create mode 100644 soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.m467 create mode 100644 soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.series create mode 100644 soc/arm/nuvoton_numaker/m46x/Kconfig.series create mode 100644 soc/arm/nuvoton_numaker/m46x/Kconfig.soc create mode 100644 soc/arm/nuvoton_numaker/m46x/linker.ld create mode 100644 soc/arm/nuvoton_numaker/m46x/soc.c create mode 100644 soc/arm/nuvoton_numaker/m46x/soc.h diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi new file mode 100644 index 000000000000..c87995e43de2 --- /dev/null +++ b/dts/arm/nuvoton/m46x.dtsi @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(512)>; + }; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(1024)>; + erase-block-size = <4096>; + write-block-size = <4>; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = <200000000>; + #clock-cells = <0>; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; diff --git a/modules/Kconfig.nuvoton b/modules/Kconfig.nuvoton index cdf94bf0cc59..4413c29423ee 100644 --- a/modules/Kconfig.nuvoton +++ b/modules/Kconfig.nuvoton @@ -12,9 +12,59 @@ menu "Nuvoton drivers" depends on HAS_NUMICRO_HAL config HAS_NUMICRO_UART - bool + bool "NuMicro UART" help Enable Nuvoton Universal asynchronous receiver transmitter HAL module driver endmenu + +config HAS_NUMAKER_HAL + bool + select HAS_CMSIS_CORE + depends on SOC_FAMILY_NUMAKER + +menu "Nuvoton NuMaker drivers" + depends on HAS_NUMAKER_HAL + config HAS_NUMAKER_UART + bool "NuMaker UART" + help + Enable Nuvoton Universal asynchronous receiver transmitter HAL + module driver + config HAS_NUMAKER_GPIO + bool "NuMaker GPIO" + help + Enable Nuvoton gpio HAL module driver + config HAS_NUMAKER_FMC + bool "NuMaker FMC" + help + Enable Nuvoton FMC HAL module driver + config HAS_NUMAKER_I2C + bool "NuMaker I2C" + help + Enable Nuvoton I2C HAL module driver + config HAS_NUMAKER_SPI + bool "NuMaker SPI" + help + Enable Nuvoton SPI HAL module driver + config HAS_NUMAKER_PWM + bool "NuMaker PWM" + help + Enable Nuvoton PWM HAL module driver + config HAS_NUMAKER_USBD + bool "NuMaker USB 1.1 device controller" + help + Enable Nuvoton USB 1.1 device controller HAL module driver + config HAS_NUMAKER_HSUSBD + bool "NuMaker high-speed USB 2.0 device controller" + help + Enable Nuvoton high-speed USB 2.0 device controller HAL module driver + config HAS_NUMAKER_ETH + bool "NuMaker ETH" + help + Enable Nuvoton ETH EMAC HAL module driver + config HAS_NUMAKER_CANFD + bool "NuMaker CAN FD" + help + Enable Nuvoton CAN FD HAL module driver +endmenu diff --git a/soc/arm/nuvoton_numaker/CMakeLists.txt b/soc/arm/nuvoton_numaker/CMakeLists.txt new file mode 100644 index 000000000000..ba7e2ec05334 --- /dev/null +++ b/soc/arm/nuvoton_numaker/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +# This is for access to pinctrl macros +zephyr_include_directories(common) + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm/nuvoton_numaker/Kconfig b/soc/arm/nuvoton_numaker/Kconfig new file mode 100644 index 000000000000..e9b668ec9118 --- /dev/null +++ b/soc/arm/nuvoton_numaker/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + + +config SOC_FAMILY_NUMAKER + select PLATFORM_SPECIFIC_INIT + bool + +if SOC_FAMILY_NUMAKER + +config SOC_FAMILY + string + default "nuvoton_numaker" + +source "soc/arm/nuvoton_numaker/*/Kconfig.soc" + +endif # SOC_FAMILY_NUMAKER diff --git a/soc/arm/nuvoton_numaker/Kconfig.defconfig b/soc/arm/nuvoton_numaker/Kconfig.defconfig new file mode 100644 index 000000000000..bcccdaa3c689 --- /dev/null +++ b/soc/arm/nuvoton_numaker/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/nuvoton_numaker/*/Kconfig.defconfig.series" diff --git a/soc/arm/nuvoton_numaker/Kconfig.soc b/soc/arm/nuvoton_numaker/Kconfig.soc new file mode 100644 index 000000000000..8e3ff44930a3 --- /dev/null +++ b/soc/arm/nuvoton_numaker/Kconfig.soc @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/nuvoton_numaker/*/Kconfig.series" diff --git a/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt b/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt new file mode 100644 index 000000000000..6b2126d22bdc --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) diff --git a/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.m467 b/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.m467 new file mode 100644 index 000000000000..ff94f5da53a9 --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.m467 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_M467 + +config NUM_IRQS + default 127 + +endif # SOC_M467 diff --git a/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.series b/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.series new file mode 100644 index 000000000000..8bf1440b0ae6 --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.series @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_M46X + +source "soc/arm/nuvoton_numaker/m46x/Kconfig.defconfig.m46*" + +config SOC_SERIES + default "m46x" + +endif # SOC_SERIES_M46X diff --git a/soc/arm/nuvoton_numaker/m46x/Kconfig.series b/soc/arm/nuvoton_numaker/m46x/Kconfig.series new file mode 100644 index 000000000000..61e877fbe961 --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/Kconfig.series @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_M46X + bool "Nuvoton M46X Series MCU" + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select CORTEX_M_SYSTICK + select SOC_FAMILY_NUMAKER + help + Enable support for Nuvoton M46X MCU series diff --git a/soc/arm/nuvoton_numaker/m46x/Kconfig.soc b/soc/arm/nuvoton_numaker/m46x/Kconfig.soc new file mode 100644 index 000000000000..898d23bcecee --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/Kconfig.soc @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Nuvoton M46X MCU Selection" + depends on SOC_SERIES_M46X + +config SOC_M467 + bool "M467" + select HAS_NUMAKER_HAL + +endchoice diff --git a/soc/arm/nuvoton_numaker/m46x/linker.ld b/soc/arm/nuvoton_numaker/m46x/linker.ld new file mode 100644 index 000000000000..b9a80770518a --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/nuvoton_numaker/m46x/soc.c b/soc/arm/nuvoton_numaker/m46x/soc.c new file mode 100644 index 000000000000..5637007495c0 --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/soc.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +/* Hardware and starter kit includes. */ +#include + +void z_arm_platform_init(void) +{ + SystemInit(); + + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* + * ------------------- + * Init System Clock + * ------------------- + */ + + CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk); + /* Wait for HXT clock ready */ + CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk); + + CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk); + /* Wait for LXT clock ready */ + CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk); + + /* Enable 12 MHz high-speed internal RC oscillator (HIRC) */ + CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk); + /* Wait for HIRC clock ready */ + CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); + + /* Enable 10 KHz low-speed internal RC oscillator (LIRC) */ + CLK_EnableXtalRC(CLK_PWRCTL_LIRCEN_Msk); + /* Wait for LIRC clock ready */ + CLK_WaitClockReady(CLK_STATUS_LIRCSTB_Msk); + + CLK_EnableXtalRC(CLK_PWRCTL_HIRC48EN_Msk); + /* Wait for HIRC48 clock ready */ + CLK_WaitClockReady(CLK_STATUS_HIRC48STB_Msk); + + /* Set PCLK0 and PCLK1 to HCLK/2 */ + CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2); + + /* Set core clock to 200MHz */ + CLK_SetCoreClock(200000000); + + /* + * Update System Core Clock + * User can use SystemCoreClockUpdate() to calculate SystemCoreClock. + */ + SystemCoreClockUpdate(); + + /* Lock protected registers */ + SYS_LockReg(); +} diff --git a/soc/arm/nuvoton_numaker/m46x/soc.h b/soc/arm/nuvoton_numaker/m46x/soc.h new file mode 100644 index 000000000000..dcb21b304daa --- /dev/null +++ b/soc/arm/nuvoton_numaker/m46x/soc.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_NUVOTON_M46X_SOC_H_ +#define ZEPHYR_SOC_ARM_NUVOTON_M46X_SOC_H_ + +/* Hardware and starter kit includes. */ +#include + +#endif /* ZEPHYR_SOC_ARM_NUVOTON_M46X_SOC_H_*/ From 5879810137570b5b65a17819dc826cff93a6eaf6 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 3 Mar 2023 17:27:55 +0800 Subject: [PATCH 0430/2042] drivers: pinctrl: add support for NuMaker series pinctrl Add Nuvoton numaker series pinctrl support. Signed-off-by: cyliang tw --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.numaker | 11 + drivers/pinctrl/pinctrl_numaker.c | 46 + dts/arm/nuvoton/m46x.dtsi | 9 + .../pinctrl/nuvoton,numaker-pinctrl.yaml | 80 + .../pinctrl/numaker-m46x-pinctrl.h | 2154 +++++++++++++++++ soc/arm/nuvoton_numaker/common/pinctrl_soc.h | 32 + 8 files changed, 2334 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.numaker create mode 100644 drivers/pinctrl/pinctrl_numaker.c create mode 100644 dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/numaker-m46x-pinctrl.h create mode 100644 soc/arm/nuvoton_numaker/common/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 656fc5f27d10..521f1e61c199 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -32,3 +32,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_GECKO pinctrl_gecko.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_K3 pinctrl_ti_k3.c) 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) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b16821edff8f..80551869d595 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -61,5 +61,6 @@ source "drivers/pinctrl/Kconfig.gecko" source "drivers/pinctrl/Kconfig.ti_k3" source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" +source "drivers/pinctrl/Kconfig.numaker" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.numaker b/drivers/pinctrl/Kconfig.numaker new file mode 100644 index 000000000000..ba4960ed2e26 --- /dev/null +++ b/drivers/pinctrl/Kconfig.numaker @@ -0,0 +1,11 @@ +# Nuvoton NuMaker Pin Controller configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_NUMAKER + bool "Nuvoton NuMaker pin controller driver" + default y + depends on DT_HAS_NUVOTON_NUMAKER_PINCTRL_ENABLED + help + This option enables the pin controller driver for Nuvoton NuMaker MCUs. diff --git a/drivers/pinctrl/pinctrl_numaker.c b/drivers/pinctrl/pinctrl_numaker.c new file mode 100644 index 000000000000..2799e0a43c18 --- /dev/null +++ b/drivers/pinctrl/pinctrl_numaker.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_pinctrl + +#include +#include + +/** + * Configure pin multi-function + */ +static void configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint32_t pin_mux = pin->pin_mux; + uint32_t pin_index = PIN_INDEX(pin_mux); + uint32_t port_index = PORT_INDEX(pin_mux); + uint32_t mfp_cfg = MFP_CFG(pin_mux); + + /* Get mfp_base, it should be == (&SYS->GPA_MFP0) in M467 */ + uint32_t mfp_base = DT_REG_ADDR(DT_NODELABEL(pinctrl)); + + uint32_t *GPx_MFPx = ((uint32_t *)mfp_base) + port_index * 4 + (pin_index / 4); + uint32_t pinMask = NU_MFP_MASK(pin_index); + + /* + * E.g.: SYS->GPA_MFP0 = (SYS->GPA_MFP0 & (~SYS_GPA_MFP0_PA0MFP_Msk) ) | + * SYS_GPA_MFP0_PA0MFP_SC0_CD; + */ + *GPx_MFPx = (*GPx_MFPx & (~pinMask)) | mfp_cfg; +} + +/* Pinctrl API implementation */ +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + /* Configure all peripheral devices' properties here. */ + for (uint8_t i = 0U; i < pin_cnt; i++) { + configure_pin(&pins[i]); + } + + return 0; +} diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index c87995e43de2..e06344fb7ac6 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -6,6 +6,7 @@ #include #include +#include / { cpus { @@ -36,6 +37,14 @@ clock-frequency = <200000000>; #clock-cells = <0>; }; + + soc { + pinctrl: pin-controller@40000500 { + compatible = "nuvoton,numaker-pinctrl"; + reg = <0x40000500 0xa0>; + status = "okay"; + }; + }; }; &nvic { diff --git a/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml new file mode 100644 index 000000000000..1e2d4f631d04 --- /dev/null +++ b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml @@ -0,0 +1,80 @@ +# Copyright (c) Nuvoton Technology Corp. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Pin controller is responsible for controlling pin function + selection and pin properties. For example, for example you can + use this node to set UART0 RX as pin PB12 to fulfill SYS_GPB_MFP3_PB12MFP_UART0_RXD. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as shown in this example: + + &pinctrl { + /* configuration for the uart0 "default" state */ + uart0_default: uart0_default { + /* configure PB13 as UART0 TX and PB12 as UART0 RX */ + pinmux = , ; + }; + }; + + + 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: + + #include "board-pinctrl.dtsi" + + &uart0 { + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + }; + +compatible: "nuvoton,numaker-pinctrl" + +include: + - name: base.yaml + - name: pincfg-node.yaml + child-binding: + property-allowlist: + - drive-push-pull + - drive-open-drain + - bias-disable + - bias-pull-down + - bias-pull-up + +child-binding: + description: | + Each child node defines the configuration for a particular state. + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should + be defined using pre-defined macros or, alternatively, using NVT_PINMUX + macros depending on the pinmux model used by the SoC series. + drive-strength: + type: string + default: "low" + enum: + - "low" + - "fast" + description: | + Set the driving strength of a pin. Hardware default configuration is low and + it's enough to drive most components, like as LED, CAN transceiver and so on. + slew-rate: + type: string + default: "low" + enum: + - "fast" + - "low" + description: | + Set the speed of a pin. This setting effectively limits the + slew rate of the output signal. Hardware default configuration is low. + Fast slew rate could support high speed pins, like as SPI CLK up to 50MHz. diff --git a/include/zephyr/dt-bindings/pinctrl/numaker-m46x-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/numaker-m46x-pinctrl.h new file mode 100644 index 000000000000..0df188e41a8e --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/numaker-m46x-pinctrl.h @@ -0,0 +1,2154 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_NUMAKER_M46X_PINCTRL_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_NUMAKER_M46X_PINCTRL_H + +/* Beginning of M460 BSP sys_reg.h pin-mux module copy */ + +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos (0) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos (8) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos (16) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos (24) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos (0) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos (8) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos (16) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos (24) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos (0) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos (8) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos (16) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos (24) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos (0) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos (8) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos (16) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos (24) + +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos (0) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos (8) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos (16) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos (24) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos (0) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos (8) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos (16) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos (24) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos (0) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos (8) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos (16) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos (24) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos (0) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos (8) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos (16) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos (24) + +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos (0) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos (8) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos (16) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos (24) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos (0) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos (8) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos (16) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos (24) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos (0) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos (8) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos (16) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos (24) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos (0) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos (8) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos (16) + +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos (0) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos (8) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos (16) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos (24) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos (0) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos (8) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos (16) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos (24) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos (0) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos (8) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos (16) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos (24) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos (0) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos (8) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos (16) + +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos (0) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos (8) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos (16) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos (24) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos (0) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos (8) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos (16) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos (24) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos (0) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos (8) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos (16) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos (24) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos (0) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos (8) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos (16) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos (24) + +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos (0) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos (8) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos (16) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos (24) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos (0) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos (8) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos (16) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos (24) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos (0) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos (8) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos (16) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos (24) + +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos (0) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos (8) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos (16) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos (24) +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos (0) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos (8) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos (16) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos (24) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos (0) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos (8) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos (16) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos (24) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos (0) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos (8) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos (16) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos (24) + +#define NUMAKER_SYS_GPH_MFP0_PH0MFP_Pos (0) +#define NUMAKER_SYS_GPH_MFP0_PH1MFP_Pos (8) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos (16) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos (24) +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos (0) +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos (8) +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos (16) +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos (24) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos (0) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos (8) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos (16) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos (24) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos (0) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos (8) +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos (16) +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos (24) + +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos (16) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos (24) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos (0) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos (8) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos (16) +#define NUMAKER_SYS_GPI_MFP2_PI11MFP_Pos (24) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos (0) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos (8) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos (16) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos (24) + +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos (0) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos (8) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos (16) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos (24) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos (0) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos (8) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos (16) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos (24) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos (0) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos (8) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos (16) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos (24) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos (0) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos (8) + +/* End of M460 BSP sys_reg.h pin-mux module copy */ + +/* Beginning of M460 BSP sys.h pin-mux module copy */ + +/* + *---------------------------------------------------------------------------- + * Multi-Function constant definitions. + *---------------------------------------------------------------------------- + */ + +/* PA.0 MFP */ +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_SPIM_MOSI (0x02UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_QSPI0_MOSI0 (0x03UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_SPI0_MOSI (0x04UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_SD1_DAT0 (0x05UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_SC0_CLK (0x06UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_UART0_RXD (0x07UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_UART1_nRTS (0x08UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_I2C2_SDA (0x09UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_CCAP_DATA6 (0x0aUL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_BPWM0_CH0 (0x0cUL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_EPWM0_CH5 (0x0dUL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_EQEI3_B (0x0eUL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_DAC0_ST (0x0fUL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_PSIO0_CH7 (0x11UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA0MFP_BMC19 (0x14UL << NUMAKER_SYS_GPA_MFP0_PA0MFP_Pos) + +/* PA.1 MFP */ +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_SPIM_MISO (0x02UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_QSPI0_MISO0 (0x03UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_SPI0_MISO (0x04UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_SD1_DAT1 (0x05UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_SC0_DAT (0x06UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_UART0_TXD (0x07UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_UART1_nCTS (0x08UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_I2C2_SCL (0x09UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_CCAP_DATA7 (0x0aUL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_BPWM0_CH1 (0x0cUL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_EPWM0_CH4 (0x0dUL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_EQEI3_A (0x0eUL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_DAC1_ST (0x0fUL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_PSIO0_CH6 (0x11UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA1MFP_BMC18 (0x14UL << NUMAKER_SYS_GPA_MFP0_PA1MFP_Pos) + +/* PA.2 MFP */ +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_SPIM_CLK (0x02UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_QSPI0_CLK (0x03UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_SPI0_CLK (0x04UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_SD1_DAT2 (0x05UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_SC0_RST (0x06UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_UART4_RXD (0x07UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_UART1_RXD (0x08UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_I2C1_SDA (0x09UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_I2C0_SMBSUS (0x0aUL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_BPWM0_CH2 (0x0cUL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_EPWM0_CH3 (0x0dUL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_EQEI3_INDEX (0x0eUL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_PSIO0_CH5 (0x11UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA2MFP_BMC17 (0x14UL << NUMAKER_SYS_GPA_MFP0_PA2MFP_Pos) + +/* PA.3 MFP */ +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_SPIM_SS (0x02UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_QSPI0_SS (0x03UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_SPI0_SS (0x04UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_SD1_DAT3 (0x05UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_SC0_PWR (0x06UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_UART4_TXD (0x07UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_UART1_TXD (0x08UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_I2C1_SCL (0x09UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_I2C0_SMBAL (0x0aUL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_BPWM0_CH3 (0x0cUL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_EPWM0_CH2 (0x0dUL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_EQEI0_B (0x0eUL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_EPWM1_BRAKE1 (0x0fUL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_PSIO0_CH4 (0x11UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) +#define NUMAKER_SYS_GPA_MFP0_PA3MFP_BMC16 (0x14UL << NUMAKER_SYS_GPA_MFP0_PA3MFP_Pos) + +/* PA.4 MFP */ +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_SPIM_D3 (0x02UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_QSPI0_MOSI1 (0x03UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_SPI0_I2SMCLK (0x04UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_SD1_CLK (0x05UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_SC0_nCD (0x06UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_UART0_nRTS (0x07UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_UART5_RXD (0x08UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_I2C0_SDA (0x09UL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_CAN0_RXD (0x0aUL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_UART0_RXD (0x0bUL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_BPWM0_CH4 (0x0cUL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_EPWM0_CH1 (0x0dUL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA4MFP_EQEI0_A (0x0eUL << NUMAKER_SYS_GPA_MFP1_PA4MFP_Pos) + +/* PA.5 MFP */ +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_SPIM_D2 (0x02UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_QSPI0_MISO1 (0x03UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_SPI1_I2SMCLK (0x04UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_SD1_CMD (0x05UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_SC2_nCD (0x06UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_UART0_nCTS (0x07UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_UART5_TXD (0x08UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_I2C0_SCL (0x09UL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_CAN0_TXD (0x0aUL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_UART0_TXD (0x0bUL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_BPWM0_CH5 (0x0cUL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_EPWM0_CH0 (0x0dUL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA5MFP_EQEI0_INDEX (0x0eUL << NUMAKER_SYS_GPA_MFP1_PA5MFP_Pos) + +/* PA.6 MFP */ +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_EBI_AD6 (0x02UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_EMAC0_RMII_RXERR (0x03UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_SPI1_SS (0x04UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_SD1_nCD (0x05UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_SC2_CLK (0x06UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_UART0_RXD (0x07UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_I2C1_SDA (0x08UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_QSPI1_MOSI1 (0x09UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_EPWM1_CH5 (0x0bUL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_BPWM1_CH3 (0x0cUL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_ACMP1_WLAT (0x0dUL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_TM3 (0x0eUL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_INT0 (0x0fUL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_SPI5_CLK (0x11UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_KPI_COL0 (0x12UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_SPI6_CLK (0x13UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA6MFP_BMC15 (0x14UL << NUMAKER_SYS_GPA_MFP1_PA6MFP_Pos) + +/* PA.7 MFP */ +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_EBI_AD7 (0x02UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_EMAC0_RMII_CRSDV (0x03UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_SPI1_CLK (0x04UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_SC2_DAT (0x06UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_UART0_TXD (0x07UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_I2C1_SCL (0x08UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_QSPI1_MISO1 (0x09UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_EPWM1_CH4 (0x0bUL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_BPWM1_CH2 (0x0cUL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_ACMP0_WLAT (0x0dUL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_TM2 (0x0eUL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_INT1 (0x0fUL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_SPI5_SS (0x11UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_KPI_COL1 (0x12UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_SPI6_SS (0x13UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) +#define NUMAKER_SYS_GPA_MFP1_PA7MFP_BMC14 (0x14UL << NUMAKER_SYS_GPA_MFP1_PA7MFP_Pos) + +/* PA.8 MFP */ +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_EADC1_CH4 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_EADC2_CH4 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_EBI_ALE (0x02UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_SC2_CLK (0x03UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_SPI2_MOSI (0x04UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_SD1_DAT0 (0x05UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_USCI0_CTL1 (0x06UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_UART1_RXD (0x07UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_UART7_RXD (0x08UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_BPWM0_CH3 (0x09UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_EQEI1_B (0x0aUL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_ECAP0_IC2 (0x0bUL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_I2S1_DO (0x0cUL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_TM3_EXT (0x0dUL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_INT4 (0x0fUL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA8MFP_BMC9 (0x14UL << NUMAKER_SYS_GPA_MFP2_PA8MFP_Pos) + +/* PA.9 MFP */ +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_EADC1_CH5 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_EADC2_CH5 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_EBI_MCLK (0x02UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_SC2_DAT (0x03UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_SPI2_MISO (0x04UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_SD1_DAT1 (0x05UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_USCI0_DAT1 (0x06UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_UART1_TXD (0x07UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_UART7_TXD (0x08UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_BPWM0_CH2 (0x09UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_EQEI1_A (0x0aUL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_ECAP0_IC1 (0x0bUL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_I2S1_DI (0x0cUL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_TM2_EXT (0x0dUL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_SWDH_DAT (0x0fUL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA9MFP_BMC8 (0x14UL << NUMAKER_SYS_GPA_MFP2_PA9MFP_Pos) + +/* PA.10 MFP */ +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_EADC1_CH6 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_EADC2_CH6 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_ACMP1_P0 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_EBI_nWR (0x02UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_SC2_RST (0x03UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_SPI2_CLK (0x04UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_SD1_DAT2 (0x05UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_USCI0_DAT0 (0x06UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_I2C2_SDA (0x07UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_UART6_RXD (0x08UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_BPWM0_CH1 (0x09UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_EQEI1_INDEX (0x0aUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_ECAP0_IC0 (0x0bUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_I2S1_MCLK (0x0cUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_TM1_EXT (0x0dUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_DAC0_ST (0x0eUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_SWDH_CLK (0x0fUL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_KPI_ROW5 (0x12UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA10MFP_BMC7 (0x14UL << NUMAKER_SYS_GPA_MFP2_PA10MFP_Pos) + +/* PA.11 MFP */ +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_EADC1_CH7 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_EADC2_CH7 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_ACMP0_P0 (0x01UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_EBI_nRD (0x02UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_SC2_PWR (0x03UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_SPI2_SS (0x04UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_SD1_DAT3 (0x05UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_USCI0_CLK (0x06UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_I2C2_SCL (0x07UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_UART6_TXD (0x08UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_BPWM0_CH0 (0x09UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_EPWM0_SYNC_OUT (0x0aUL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_I2S1_BCLK (0x0cUL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_TM0_EXT (0x0dUL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_DAC1_ST (0x0eUL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_KPI_ROW4 (0x12UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) +#define NUMAKER_SYS_GPA_MFP2_PA11MFP_BMC6 (0x14UL << NUMAKER_SYS_GPA_MFP2_PA11MFP_Pos) + +/* PA.12 MFP */ +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_I2S0_BCLK (0x02UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_UART4_TXD (0x03UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_I2C1_SCL (0x04UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_SPI2_SS (0x05UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_CAN0_TXD (0x06UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_SC2_PWR (0x07UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_SD1_nCD (0x08UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_SPI0_SS (0x09UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_QSPI1_MISO0 (0x0aUL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_BPWM1_CH2 (0x0bUL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_EQEI1_INDEX (0x0cUL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_ECAP3_IC0 (0x0dUL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_USB_VBUS (0x0eUL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_PSIO0_CH4 (0x11UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_SPI10_SS (0x13UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA12MFP_BMC12 (0x14UL << NUMAKER_SYS_GPA_MFP3_PA12MFP_Pos) + +/* PA.13 MFP */ +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_I2S0_MCLK (0x02UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_UART4_RXD (0x03UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_I2C1_SDA (0x04UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_SPI2_CLK (0x05UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_CAN0_RXD (0x06UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_SC2_RST (0x07UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_SPI0_CLK (0x09UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_QSPI1_MOSI0 (0x0aUL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_BPWM1_CH3 (0x0bUL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_EQEI1_A (0x0cUL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_ECAP3_IC1 (0x0dUL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_USB_D_N (0x0eUL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_PSIO0_CH5 (0x11UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_SPI10_CLK (0x13UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA13MFP_BMC13 (0x14UL << NUMAKER_SYS_GPA_MFP3_PA13MFP_Pos) + +/* PA.14 MFP */ +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_I2S0_DI (0x02UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_UART0_TXD (0x03UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_EBI_AD5 (0x04UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_SPI2_MISO (0x05UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_I2C2_SCL (0x06UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_SC2_DAT (0x07UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_SPI0_MISO (0x09UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_BPWM1_CH4 (0x0bUL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_EQEI1_B (0x0cUL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_ECAP3_IC2 (0x0dUL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_USB_D_P (0x0eUL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_I2C0_SCL (0x10UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_PSIO0_CH6 (0x11UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_SPI10_MISO (0x13UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA14MFP_BMC14 (0x14UL << NUMAKER_SYS_GPA_MFP3_PA14MFP_Pos) + +/* PA.15 MFP */ +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_GPIO (0x00UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_I2S0_DO (0x02UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_UART0_RXD (0x03UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_SPIM_MOSI (0x04UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_SPI2_MOSI (0x05UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_I2C2_SDA (0x06UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_SC2_CLK (0x07UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_SPI0_MOSI (0x09UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_BPWM1_CH5 (0x0bUL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_EPWM0_SYNC_IN (0x0cUL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_EQEI3_INDEX (0x0dUL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_USB_OTG_ID (0x0eUL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_I2C0_SDA (0x10UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_PSIO0_CH7 (0x11UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_SPI10_MOSI (0x13UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) +#define NUMAKER_SYS_GPA_MFP3_PA15MFP_BMC15 (0x14UL << NUMAKER_SYS_GPA_MFP3_PA15MFP_Pos) + +/* PB.0 MFP */ +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EADC0_CH0 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EADC1_CH8 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EADC2_CH8 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_ACMP3_N (0x01UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EBI_ADR9 (0x02UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_SD0_CMD (0x03UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_SPI2_I2SMCLK (0x04UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_USCI0_CTL0 (0x06UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_UART2_RXD (0x07UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_SPI0_I2SMCLK (0x08UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_I2C1_SDA (0x09UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_I2S1_LRCK (0x0aUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EPWM0_CH5 (0x0bUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EPWM1_CH5 (0x0cUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_EPWM0_BRAKE1 (0x0dUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_ACMP3_O (0x0eUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_QSPI0_MOSI1 (0x0fUL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_KPI_ROW3 (0x12UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_SPI4_MOSI (0x13UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB0MFP_BMC5 (0x14UL << NUMAKER_SYS_GPB_MFP0_PB0MFP_Pos) + +/* PB.1 MFP */ +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EADC0_CH1 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EADC1_CH9 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EADC2_CH9 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_ACMP3_P0 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EBI_ADR8 (0x02UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_SD0_CLK (0x03UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EMAC0_RMII_RXERR (0x04UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_SPI1_I2SMCLK (0x05UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_SPI3_I2SMCLK (0x06UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_UART2_TXD (0x07UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_I2C1_SCL (0x09UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_I2S0_LRCK (0x0aUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EPWM0_CH4 (0x0bUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EPWM1_CH4 (0x0cUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_EPWM0_BRAKE0 (0x0dUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_ACMP2_O (0x0eUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_QSPI0_MISO1 (0x0fUL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_KPI_ROW2 (0x12UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_SPI4_MISO (0x13UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB1MFP_BMC4 (0x14UL << NUMAKER_SYS_GPB_MFP0_PB1MFP_Pos) + +/* PB.2 MFP */ +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_EADC0_CH2 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_EADC1_CH10 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_ACMP0_P1 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_EBI_ADR3 (0x02UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_SD0_DAT0 (0x03UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_EMAC0_RMII_CRSDV (0x04UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_SPI1_SS (0x05UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_UART1_RXD (0x06UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_UART5_nCTS (0x07UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_SC0_PWR (0x09UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_I2S0_DO (0x0aUL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_EPWM0_CH3 (0x0bUL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_I2C1_SDA (0x0cUL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_TM3 (0x0eUL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_INT3 (0x0fUL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_PSIO0_CH7 (0x11UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_KPI_ROW1 (0x12UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_SPI4_CLK (0x13UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB2MFP_BMC3 (0x14UL << NUMAKER_SYS_GPB_MFP0_PB2MFP_Pos) + +/* PB.3 MFP */ +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_EADC0_CH3 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_EADC1_CH11 (0x01UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_ACMP0_N (0x01UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_EBI_ADR2 (0x02UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_SD0_DAT1 (0x03UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_EMAC0_RMII_RXD1 (0x04UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_SPI1_CLK (0x05UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_UART1_TXD (0x06UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_UART5_nRTS (0x07UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_SC0_RST (0x09UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_I2S0_DI (0x0aUL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_EPWM0_CH2 (0x0bUL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_I2C1_SCL (0x0cUL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_TM2 (0x0eUL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_INT2 (0x0fUL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_PSIO0_CH6 (0x11UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_KPI_ROW0 (0x12UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_SPI4_SS (0x13UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) +#define NUMAKER_SYS_GPB_MFP0_PB3MFP_BMC2 (0x14UL << NUMAKER_SYS_GPB_MFP0_PB3MFP_Pos) + +/* PB.4 MFP */ +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_EADC0_CH4 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_ACMP1_P1 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_EBI_ADR1 (0x02UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_SD0_DAT2 (0x03UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_EMAC0_RMII_RXD0 (0x04UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_SPI1_MOSI (0x05UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_I2C0_SDA (0x06UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_UART5_RXD (0x07UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_SC0_DAT (0x09UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_I2S0_MCLK (0x0aUL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_EPWM0_CH1 (0x0bUL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_UART2_RXD (0x0cUL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_TM1 (0x0eUL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_INT1 (0x0fUL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_PSIO0_CH5 (0x11UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_KPI_COL7 (0x12UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB4MFP_BMC1 (0x14UL << NUMAKER_SYS_GPB_MFP1_PB4MFP_Pos) + +/* PB.5 MFP */ +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_EADC0_CH5 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_ACMP1_N (0x01UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_EBI_ADR0 (0x02UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_SD0_DAT3 (0x03UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_EMAC0_RMII_REFCLK (0x04UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_SPI1_MISO (0x05UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_I2C0_SCL (0x06UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_UART5_TXD (0x07UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_SC0_CLK (0x09UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_I2S0_BCLK (0x0aUL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_EPWM0_CH0 (0x0bUL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_UART2_TXD (0x0cUL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_TM0 (0x0eUL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_INT0 (0x0fUL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_PSIO0_CH4 (0x11UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_KPI_COL6 (0x12UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB5MFP_BMC0 (0x14UL << NUMAKER_SYS_GPB_MFP1_PB5MFP_Pos) + +/* PB.6 MFP */ +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EADC0_CH6 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EADC2_CH14 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_ACMP2_N (0x01UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EBI_nWRH (0x02UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EMAC0_PPS (0x03UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_CAN1_RXD (0x05UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_UART1_RXD (0x06UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_SD1_CLK (0x07UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EBI_nCS1 (0x08UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_BPWM1_CH5 (0x0aUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EPWM1_BRAKE1 (0x0bUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_EPWM1_CH5 (0x0cUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_INT4 (0x0dUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_USB_VBUS_EN (0x0eUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_ACMP1_O (0x0fUL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_SPI3_MOSI (0x10UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_KPI_COL5 (0x12UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_SPI1_SS (0x13UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB6MFP_BMC31 (0x14UL << NUMAKER_SYS_GPB_MFP1_PB6MFP_Pos) + +/* PB.7 MFP */ +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EADC0_CH7 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EADC2_CH15 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_ACMP2_P0 (0x01UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EBI_nWRL (0x02UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EMAC0_RMII_TXEN (0x03UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_CAN1_TXD (0x05UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_UART1_TXD (0x06UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_SD1_CMD (0x07UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EBI_nCS0 (0x08UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_BPWM1_CH4 (0x0aUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EPWM1_BRAKE0 (0x0bUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_EPWM1_CH4 (0x0cUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_INT5 (0x0dUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_USB_VBUS_ST (0x0eUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_ACMP0_O (0x0fUL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_SPI3_MISO (0x10UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_KPI_COL4 (0x12UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_SPI1_CLK (0x13UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) +#define NUMAKER_SYS_GPB_MFP1_PB7MFP_BMC30 (0x14UL << NUMAKER_SYS_GPB_MFP1_PB7MFP_Pos) + +/* PB.8 MFP */ +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_EADC0_CH8 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_ACMP2_P1 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_EBI_ADR19 (0x02UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_EMAC0_RMII_TXD1 (0x03UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_UART0_RXD (0x05UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_UART1_nRTS (0x06UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_I2C1_SMBSUS (0x07UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_UART7_RXD (0x08UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_I2C0_SDA (0x09UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_BPWM1_CH3 (0x0aUL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_SPI3_MOSI (0x0bUL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_CAN2_RXD (0x0cUL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_INT6 (0x0dUL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_EADC2_ST (0x0eUL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB8MFP_BMC23 (0x14UL << NUMAKER_SYS_GPB_MFP2_PB8MFP_Pos) + +/* PB.9 MFP */ +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_EADC0_CH9 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_ACMP2_P2 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_EBI_ADR18 (0x02UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_EMAC0_RMII_TXD0 (0x03UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_UART0_TXD (0x05UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_UART1_nCTS (0x06UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_I2C1_SMBAL (0x07UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_UART7_TXD (0x08UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_I2C0_SCL (0x09UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_BPWM1_CH2 (0x0aUL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_SPI3_MISO (0x0bUL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_CAN2_TXD (0x0cUL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_INT7 (0x0dUL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_CCAP_HSYNC (0x0eUL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB9MFP_BMC22 (0x14UL << NUMAKER_SYS_GPB_MFP2_PB9MFP_Pos) + +/* PB.10 MFP */ +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_EADC0_CH10 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_ACMP2_P3 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_EBI_ADR17 (0x02UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_EMAC0_RMII_MDIO (0x03UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_UART0_nRTS (0x05UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_UART4_RXD (0x06UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_I2C1_SDA (0x07UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_CAN0_RXD (0x08UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_BPWM1_CH1 (0x0aUL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_SPI3_SS (0x0bUL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_CCAP_VSYNC (0x0cUL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_HSUSB_VBUS_EN (0x0eUL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB10MFP_BMC21 (0x14UL << NUMAKER_SYS_GPB_MFP2_PB10MFP_Pos) + +/* PB.11 MFP */ +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_EADC0_CH11 (0x01UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_EBI_ADR16 (0x02UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_EMAC0_RMII_MDC (0x03UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_UART0_nCTS (0x05UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_UART4_TXD (0x06UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_I2C1_SCL (0x07UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_CAN0_TXD (0x08UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_SPI0_I2SMCLK (0x09UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_BPWM1_CH0 (0x0aUL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_SPI3_CLK (0x0bUL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_CCAP_SFIELD (0x0cUL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_HSUSB_VBUS_ST (0x0eUL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) +#define NUMAKER_SYS_GPB_MFP2_PB11MFP_BMC20 (0x14UL << NUMAKER_SYS_GPB_MFP2_PB11MFP_Pos) + +/* PB.12 MFP */ +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_EADC0_CH12 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_EADC1_CH12 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_DAC0_OUT (0x01UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_ACMP0_P2 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_ACMP1_P2 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_EBI_AD15 (0x02UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_SC1_CLK (0x03UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_SPI0_MOSI (0x04UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_USCI0_CLK (0x05UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_UART0_RXD (0x06UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_UART3_nCTS (0x07UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_I2C2_SDA (0x08UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_SD0_nCD (0x09UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_CCAP_SCLK (0x0aUL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_EPWM1_CH3 (0x0bUL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_ETMC_TRACE_DATA3 (0x0cUL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_TM3_EXT (0x0dUL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_CAN3_RXD (0x0eUL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_SPI3_SS (0x10UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_PSIO0_CH3 (0x11UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_KPI_COL3 (0x12UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB12MFP_BMC29 (0x14UL << NUMAKER_SYS_GPB_MFP3_PB12MFP_Pos) + +/* PB.13 MFP */ +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_EADC0_CH13 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_EADC1_CH13 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_DAC1_OUT (0x01UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_ACMP0_P3 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_ACMP1_P3 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_EBI_AD14 (0x02UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_SC1_DAT (0x03UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_SPI0_MISO (0x04UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_USCI0_DAT0 (0x05UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_UART0_TXD (0x06UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_UART3_nRTS (0x07UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_I2C2_SCL (0x08UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_CCAP_PIXCLK (0x0aUL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_EPWM1_CH2 (0x0bUL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_ETMC_TRACE_DATA2 (0x0cUL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_TM2_EXT (0x0dUL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_CAN3_TXD (0x0eUL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_SPI3_CLK (0x10UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_PSIO0_CH2 (0x11UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_KPI_COL2 (0x12UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_SPI9_MISO (0x13UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB13MFP_BMC28 (0x14UL << NUMAKER_SYS_GPB_MFP3_PB13MFP_Pos) + +/* PB.14 MFP */ +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_EADC0_CH14 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_EADC1_CH14 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_EBI_AD13 (0x02UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_SC1_RST (0x03UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_SPI0_CLK (0x04UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_USCI0_DAT1 (0x05UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_UART0_nRTS (0x06UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_UART3_RXD (0x07UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_I2C2_SMBSUS (0x08UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_CCAP_DATA0 (0x09UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_EPWM1_CH1 (0x0bUL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_ETMC_TRACE_DATA1 (0x0cUL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_TM1_EXT (0x0dUL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_CLKO (0x0eUL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_USB_VBUS_ST (0x0fUL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_PSIO0_CH1 (0x11UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_KPI_COL1 (0x12UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB14MFP_SPI9_SS (0x13UL << NUMAKER_SYS_GPB_MFP3_PB14MFP_Pos) + +/* PB.15 MFP */ +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_GPIO (0x00UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_EADC0_CH15 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_EADC1_CH15 (0x01UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_EBI_AD12 (0x02UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_SC1_PWR (0x03UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_SPI0_SS (0x04UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_USCI0_CTL1 (0x05UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_UART0_nCTS (0x06UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_UART3_TXD (0x07UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_I2C2_SMBAL (0x08UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_CCAP_DATA1 (0x09UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_EPWM0_BRAKE1 (0x0aUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_EPWM1_CH0 (0x0bUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_ETMC_TRACE_DATA0 (0x0cUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_TM0_EXT (0x0dUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_USB_VBUS_EN (0x0eUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_HSUSB_VBUS_EN (0x0fUL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_PSIO0_CH0 (0x11UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_KPI_COL0 (0x12UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_SPI9_CLK (0x13UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) +#define NUMAKER_SYS_GPB_MFP3_PB15MFP_BMC27 (0x14UL << NUMAKER_SYS_GPB_MFP3_PB15MFP_Pos) + +/* PC.0 MFP */ +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_EBI_AD0 (0x02UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_SPIM_MOSI (0x03UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_QSPI0_MOSI0 (0x04UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_SC1_CLK (0x05UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_I2S0_LRCK (0x06UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_SPI1_SS (0x07UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_UART2_RXD (0x08UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_I2C0_SDA (0x09UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_CAN2_RXD (0x0aUL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_EPWM1_CH5 (0x0cUL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_CCAP_DATA0 (0x0dUL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_ACMP1_O (0x0eUL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_EADC1_ST (0x0fUL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_HBI_D2 (0x10UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_QSPI1_CLK (0x11UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_KPI_ROW5 (0x12UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_SPI7_MOSI (0x13UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC0MFP_BMC25 (0x14UL << NUMAKER_SYS_GPC_MFP0_PC0MFP_Pos) + +/* PC.1 MFP */ +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_EBI_AD1 (0x02UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_SPIM_MISO (0x03UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_QSPI0_MISO0 (0x04UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_SC1_DAT (0x05UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_I2S0_DO (0x06UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_SPI1_CLK (0x07UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_UART2_TXD (0x08UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_I2C0_SCL (0x09UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_CAN2_TXD (0x0aUL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_EPWM1_CH4 (0x0cUL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_CCAP_DATA1 (0x0dUL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_ACMP0_O (0x0eUL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_EADC0_ST (0x0fUL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_HBI_RWDS (0x10UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_QSPI1_SS (0x11UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_KPI_ROW4 (0x12UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_SPI7_MISO (0x13UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC1MFP_BMC24 (0x14UL << NUMAKER_SYS_GPC_MFP0_PC1MFP_Pos) + +/* PC.2 MFP */ +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_EBI_AD2 (0x02UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_SPIM_CLK (0x03UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_QSPI0_CLK (0x04UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_SC1_RST (0x05UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_I2S0_DI (0x06UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_SPI1_MOSI (0x07UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_UART2_nCTS (0x08UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_I2C0_SMBSUS (0x09UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_CAN1_RXD (0x0aUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_UART3_RXD (0x0bUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_EPWM1_CH3 (0x0cUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_CCAP_DATA2 (0x0dUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_QSPI1_MOSI0 (0x0eUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_I2C3_SDA (0x0fUL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_HBI_nRESET (0x10UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_PSIO0_CH3 (0x11UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_KPI_ROW3 (0x12UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_SPI7_CLK (0x13UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC2MFP_BMC23 (0x14UL << NUMAKER_SYS_GPC_MFP0_PC2MFP_Pos) + +/* PC.3 MFP */ +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_EBI_AD3 (0x02UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_SPIM_SS (0x03UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_QSPI0_SS (0x04UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_SC1_PWR (0x05UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_I2S0_MCLK (0x06UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_SPI1_MISO (0x07UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_UART2_nRTS (0x08UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_I2C0_SMBAL (0x09UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_CAN1_TXD (0x0aUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_UART3_TXD (0x0bUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_EPWM1_CH2 (0x0cUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_CCAP_DATA3 (0x0dUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_QSPI1_MISO0 (0x0eUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_I2C3_SCL (0x0fUL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_HBI_nCS (0x10UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_PSIO0_CH2 (0x11UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_KPI_ROW2 (0x12UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_SPI7_SS (0x13UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) +#define NUMAKER_SYS_GPC_MFP0_PC3MFP_BMC22 (0x14UL << NUMAKER_SYS_GPC_MFP0_PC3MFP_Pos) + +/* PC.4 MFP */ +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_EBI_AD4 (0x02UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_SPIM_D3 (0x03UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_QSPI0_MOSI1 (0x04UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_SC1_nCD (0x05UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_I2S0_BCLK (0x06UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_SPI1_I2SMCLK (0x07UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_UART2_RXD (0x08UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_I2C1_SDA (0x09UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_CAN0_RXD (0x0aUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_UART4_RXD (0x0bUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_EPWM1_CH1 (0x0cUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_CCAP_DATA4 (0x0dUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_QSPI1_CLK (0x0eUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_I2C3_SMBSUS (0x0fUL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_HBI_CK (0x10UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_PSIO0_CH1 (0x11UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_KPI_ROW1 (0x12UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC4MFP_BMC21 (0x14UL << NUMAKER_SYS_GPC_MFP1_PC4MFP_Pos) + +/* PC.5 MFP */ +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_EBI_AD5 (0x02UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_SPIM_D2 (0x03UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_QSPI0_MISO1 (0x04UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_UART2_TXD (0x08UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_I2C1_SCL (0x09UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_CAN0_TXD (0x0aUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_UART4_TXD (0x0bUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_EPWM1_CH0 (0x0cUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_CCAP_DATA5 (0x0dUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_QSPI1_SS (0x0eUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_I2C3_SMBAL (0x0fUL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_HBI_nCK (0x10UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_PSIO0_CH0 (0x11UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_KPI_ROW0 (0x12UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC5MFP_BMC20 (0x14UL << NUMAKER_SYS_GPC_MFP1_PC5MFP_Pos) + +/* PC.6 MFP */ +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_EBI_AD8 (0x02UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_EMAC0_RMII_RXD1 (0x03UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_SPI1_MOSI (0x04UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_UART4_RXD (0x05UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_SC2_RST (0x06UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_UART0_nRTS (0x07UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_I2C1_SMBSUS (0x08UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_UART6_RXD (0x09UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_ACMP3_WLAT (0x0aUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_EPWM1_CH3 (0x0bUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_BPWM1_CH1 (0x0cUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_CAN3_RXD (0x0dUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_TM1 (0x0eUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_INT2 (0x0fUL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_KPI_COL2 (0x12UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_SPI6_MOSI (0x13UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC6MFP_BMC25 (0x14UL << NUMAKER_SYS_GPC_MFP1_PC6MFP_Pos) + +/* PC.7 MFP */ +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_EBI_AD9 (0x02UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_EMAC0_RMII_RXD0 (0x03UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_SPI1_MISO (0x04UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_UART4_TXD (0x05UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_SC2_PWR (0x06UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_UART0_nCTS (0x07UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_I2C1_SMBAL (0x08UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_UART6_TXD (0x09UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_ACMP2_WLAT (0x0aUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_EPWM1_CH2 (0x0bUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_BPWM1_CH0 (0x0cUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_CAN3_TXD (0x0dUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_TM0 (0x0eUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_INT3 (0x0fUL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_KPI_COL3 (0x12UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_SPI6_MISO (0x13UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) +#define NUMAKER_SYS_GPC_MFP1_PC7MFP_BMC24 (0x14UL << NUMAKER_SYS_GPC_MFP1_PC7MFP_Pos) + +/* PC.8 MFP */ +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_EBI_ADR16 (0x02UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_EMAC0_RMII_REFCLK (0x03UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_I2C0_SDA (0x04UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_UART4_nCTS (0x05UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_UART1_RXD (0x08UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_EPWM1_CH1 (0x0bUL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_BPWM1_CH4 (0x0cUL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC8MFP_KPI_COL4 (0x12UL << NUMAKER_SYS_GPC_MFP2_PC8MFP_Pos) + +/* PC.9 MFP */ +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_EADC2_CH10 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_ACMP3_P1 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_EBI_ADR7 (0x02UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_UART6_nCTS (0x05UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_SPI3_SS (0x06UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_UART3_RXD (0x07UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_CAN1_RXD (0x09UL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_I2C4_SMBSUS (0x0aUL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_EPWM1_CH3 (0x0cUL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC9MFP_EADC1_ST (0x0eUL << NUMAKER_SYS_GPC_MFP2_PC9MFP_Pos) + +/* PC.10 MFP */ +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_EADC2_CH11 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_ACMP3_P2 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_EBI_ADR6 (0x02UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_UART6_nRTS (0x05UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_SPI3_CLK (0x06UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_UART3_TXD (0x07UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_CAN1_TXD (0x09UL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_I2C4_SMBAL (0x0aUL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_ECAP1_IC0 (0x0bUL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_EPWM1_CH2 (0x0cUL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC10MFP_EADC1_ST (0x0eUL << NUMAKER_SYS_GPC_MFP2_PC10MFP_Pos) + +/* PC.11 MFP */ +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_EADC2_CH12 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_ACMP3_P3 (0x01UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_EBI_ADR5 (0x02UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_UART0_RXD (0x03UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_I2C0_SDA (0x04UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_UART6_RXD (0x05UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_SPI3_MOSI (0x06UL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_I2C4_SDA (0x0aUL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_ECAP1_IC1 (0x0bUL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_EPWM1_CH1 (0x0cUL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) +#define NUMAKER_SYS_GPC_MFP2_PC11MFP_ACMP1_O (0x0eUL << NUMAKER_SYS_GPC_MFP2_PC11MFP_Pos) + +/* PC.12 MFP */ +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_EADC2_CH13 (0x01UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_EBI_ADR4 (0x02UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_UART0_TXD (0x03UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_I2C0_SCL (0x04UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_UART6_TXD (0x05UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_SPI3_MISO (0x06UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_SC0_nCD (0x09UL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_I2C4_SCL (0x0aUL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_ECAP1_IC2 (0x0bUL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_EPWM1_CH0 (0x0cUL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC12MFP_ACMP0_O (0x0eUL << NUMAKER_SYS_GPC_MFP3_PC12MFP_Pos) + +/* PC.13 MFP */ +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_EADC1_CH3 (0x01UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_EADC2_CH3 (0x01UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_EBI_ADR10 (0x02UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_SC2_nCD (0x03UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_SPI2_I2SMCLK (0x04UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_CAN1_TXD (0x05UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_USCI0_CTL0 (0x06UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_UART2_TXD (0x07UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_UART8_nCTS (0x08UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_BPWM0_CH4 (0x09UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_CLKO (0x0dUL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_EADC0_ST (0x0eUL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC13MFP_SPI9_SS (0x13UL << NUMAKER_SYS_GPC_MFP3_PC13MFP_Pos) + +/* PC.14 MFP */ +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_GPIO (0x00UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_EBI_AD11 (0x02UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_SC1_nCD (0x03UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_SPI0_I2SMCLK (0x04UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_USCI0_CTL0 (0x05UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_QSPI0_CLK (0x06UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_TRACE_SWO (0x0aUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_EPWM0_SYNC_IN (0x0bUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_ETMC_TRACE_CLK (0x0cUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_TM1 (0x0dUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_USB_VBUS_ST (0x0eUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_HSUSB_VBUS_ST (0x0fUL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_SPI9_MOSI (0x13UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) +#define NUMAKER_SYS_GPC_MFP3_PC14MFP_BMC26 (0x14UL << NUMAKER_SYS_GPC_MFP3_PC14MFP_Pos) + +/* PD.0 MFP */ +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_EBI_AD13 (0x02UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_USCI0_CLK (0x03UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_SPI0_MOSI (0x04UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_UART3_RXD (0x05UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_I2C2_SDA (0x06UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_SC2_CLK (0x07UL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_I2S1_DO (0x0aUL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_EQEI2_A (0x0cUL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_ECAP2_IC1 (0x0dUL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD0MFP_TM2 (0x0eUL << NUMAKER_SYS_GPD_MFP0_PD0MFP_Pos) + +/* PD.1 MFP */ +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_EBI_AD12 (0x02UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_USCI0_DAT0 (0x03UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_SPI0_MISO (0x04UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_UART3_TXD (0x05UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_I2C2_SCL (0x06UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_SC2_DAT (0x07UL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_I2S1_DI (0x0aUL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_EQEI2_INDEX (0x0cUL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD1MFP_ECAP2_IC0 (0x0dUL << NUMAKER_SYS_GPD_MFP0_PD1MFP_Pos) + +/* PD.2 MFP */ +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_EBI_AD11 (0x02UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_USCI0_DAT1 (0x03UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_SPI0_CLK (0x04UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_UART3_nCTS (0x05UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_SC2_RST (0x07UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_UART0_RXD (0x09UL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_I2S1_MCLK (0x0aUL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD2MFP_EQEI3_B (0x0dUL << NUMAKER_SYS_GPD_MFP0_PD2MFP_Pos) + +/* PD.3 MFP */ +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_EBI_AD10 (0x02UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_USCI0_CTL1 (0x03UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_SPI0_SS (0x04UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_UART3_nRTS (0x05UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_SC2_PWR (0x07UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_SC1_nCD (0x08UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_UART0_TXD (0x09UL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_I2S1_BCLK (0x0aUL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) +#define NUMAKER_SYS_GPD_MFP0_PD3MFP_EQEI3_A (0x0dUL << NUMAKER_SYS_GPD_MFP0_PD3MFP_Pos) + +/* PD.4 MFP */ +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_USCI0_CTL0 (0x03UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_I2C1_SDA (0x04UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_SPI1_SS (0x05UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_SC1_CLK (0x08UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_USB_VBUS_ST (0x0eUL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD4MFP_PSIO0_CH7 (0x11UL << NUMAKER_SYS_GPD_MFP1_PD4MFP_Pos) + +/* PD.5 MFP */ +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_I2C1_SCL (0x04UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_SPI1_CLK (0x05UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_SC1_DAT (0x08UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_ACMP1_O (0x0eUL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_EADC1_ST (0x0fUL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_HBI_nRESET (0x10UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD5MFP_PSIO0_CH6 (0x11UL << NUMAKER_SYS_GPD_MFP1_PD5MFP_Pos) + +/* PD.6 MFP */ +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_EBI_AD5 (0x02UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_UART1_RXD (0x03UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_I2C0_SDA (0x04UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_SPI1_MOSI (0x05UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_QSPI1_MOSI0 (0x06UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_SC1_RST (0x08UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_ACMP0_O (0x0eUL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_EADC0_ST (0x0fUL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_HBI_D0 (0x10UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD6MFP_PSIO0_CH5 (0x11UL << NUMAKER_SYS_GPD_MFP1_PD6MFP_Pos) + +/* PD.7 MFP */ +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_EBI_AD4 (0x02UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_UART1_TXD (0x03UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_I2C0_SCL (0x04UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_SPI1_MISO (0x05UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_QSPI1_MISO0 (0x06UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_CCAP_HSYNC (0x07UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_SC1_PWR (0x08UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_HBI_D1 (0x10UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) +#define NUMAKER_SYS_GPD_MFP1_PD7MFP_PSIO0_CH4 (0x11UL << NUMAKER_SYS_GPD_MFP1_PD7MFP_Pos) + +/* PD.8 MFP */ +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_EBI_AD6 (0x02UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_I2C2_SDA (0x03UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_UART2_nRTS (0x04UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_UART7_RXD (0x05UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_CAN2_RXD (0x06UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD8MFP_PSIO0_CH3 (0x11UL << NUMAKER_SYS_GPD_MFP2_PD8MFP_Pos) + +/* PD.9 MFP */ +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_EBI_AD7 (0x02UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_I2C2_SCL (0x03UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_UART2_nCTS (0x04UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_UART7_TXD (0x05UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_CAN2_TXD (0x06UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD9MFP_PSIO0_CH2 (0x11UL << NUMAKER_SYS_GPD_MFP2_PD9MFP_Pos) + +/* PD.10 MFP */ +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_EADC1_CH0 (0x01UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_EADC2_CH0 (0x01UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_EBI_nCS2 (0x02UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_UART1_RXD (0x03UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_CAN0_RXD (0x04UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_UART8_RXD (0x08UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_EQEI0_B (0x0aUL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_ECAP3_IC2 (0x0bUL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_INT7 (0x0fUL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD10MFP_SPI9_MOSI (0x13UL << NUMAKER_SYS_GPD_MFP2_PD10MFP_Pos) + +/* PD.11 MFP */ +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_EADC1_CH1 (0x01UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_EADC2_CH1 (0x01UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_EBI_nCS1 (0x02UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_UART1_TXD (0x03UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_CAN0_TXD (0x04UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_UART8_TXD (0x08UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_EQEI0_A (0x0aUL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_ECAP3_IC1 (0x0bUL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_INT6 (0x0fUL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) +#define NUMAKER_SYS_GPD_MFP2_PD11MFP_SPI9_MISO (0x13UL << NUMAKER_SYS_GPD_MFP2_PD11MFP_Pos) + +/* PD.12 MFP */ +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_EADC1_CH2 (0x01UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_EADC2_CH2 (0x01UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_EBI_nCS0 (0x02UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_CAN1_RXD (0x05UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_UART2_RXD (0x07UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_UART8_nRTS (0x08UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_BPWM0_CH5 (0x09UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_EQEI0_INDEX (0x0aUL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_ECAP3_IC0 (0x0bUL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_CLKO (0x0dUL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_EADC0_ST (0x0eUL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_INT5 (0x0fUL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD12MFP_SPI9_CLK (0x13UL << NUMAKER_SYS_GPD_MFP3_PD12MFP_Pos) + +/* PD.13 MFP */ +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_EBI_AD10 (0x02UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_SD0_nCD (0x03UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_SPI0_I2SMCLK (0x04UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_SPI1_I2SMCLK (0x05UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_QSPI1_MOSI0 (0x06UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_SC2_nCD (0x07UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_SD1_CLK (0x08UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_UART6_RXD (0x09UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_I2S1_LRCK (0x0aUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_BPWM0_CH0 (0x0bUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_EQEI2_B (0x0cUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_ECAP2_IC2 (0x0dUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_CLKO (0x0eUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_EADC0_ST (0x0fUL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD13MFP_QSPI1_MOSI1 (0x13UL << NUMAKER_SYS_GPD_MFP3_PD13MFP_Pos) + +/* PD.14 MFP */ +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_GPIO (0x00UL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_EBI_nCS0 (0x02UL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_SPI3_I2SMCLK (0x03UL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_SC1_nCD (0x04UL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_SPI0_I2SMCLK (0x05UL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_I2S1_BCLK (0x0aUL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) +#define NUMAKER_SYS_GPD_MFP3_PD14MFP_EPWM0_CH4 (0x0bUL << NUMAKER_SYS_GPD_MFP3_PD14MFP_Pos) + +/* PE.0 MFP */ +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_EBI_AD11 (0x02UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_QSPI0_MOSI0 (0x03UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_SC2_CLK (0x04UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_I2S0_MCLK (0x05UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_SPI1_MOSI (0x06UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_UART3_RXD (0x07UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_I2C1_SDA (0x08UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_UART4_nRTS (0x09UL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE0MFP_UART8_RXD (0x0aUL << NUMAKER_SYS_GPE_MFP0_PE0MFP_Pos) + +/* PE.1 MFP */ +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_EBI_AD10 (0x02UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_QSPI0_MISO0 (0x03UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_SC2_DAT (0x04UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_I2S0_BCLK (0x05UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_SPI1_MISO (0x06UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_UART3_TXD (0x07UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_I2C1_SCL (0x08UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_UART4_nCTS (0x09UL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE1MFP_UART8_TXD (0x0aUL << NUMAKER_SYS_GPE_MFP0_PE1MFP_Pos) + +/* PE.2 MFP */ +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_EBI_ALE (0x02UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_SD0_DAT0 (0x03UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_SPIM_MOSI (0x04UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_SPI3_MOSI (0x05UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_SC0_CLK (0x06UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_USCI0_CLK (0x07UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_UART6_nCTS (0x08UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_UART7_RXD (0x09UL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_UART8_nRTS (0x0aUL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_EQEI0_B (0x0bUL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_EPWM0_CH5 (0x0cUL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE2MFP_BPWM0_CH0 (0x0dUL << NUMAKER_SYS_GPE_MFP0_PE2MFP_Pos) + +/* PE.3 MFP */ +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_EBI_MCLK (0x02UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_SD0_DAT1 (0x03UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_SPIM_MISO (0x04UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_SPI3_MISO (0x05UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_SC0_DAT (0x06UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_USCI0_DAT0 (0x07UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_UART6_nRTS (0x08UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_UART7_TXD (0x09UL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_UART8_nCTS (0x0aUL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_EQEI0_A (0x0bUL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_EPWM0_CH4 (0x0cUL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) +#define NUMAKER_SYS_GPE_MFP0_PE3MFP_BPWM0_CH1 (0x0dUL << NUMAKER_SYS_GPE_MFP0_PE3MFP_Pos) + +/* PE.4 MFP */ +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_EBI_nWR (0x02UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_SD0_DAT2 (0x03UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_SPIM_CLK (0x04UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_SPI3_CLK (0x05UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_SC0_RST (0x06UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_USCI0_DAT1 (0x07UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_UART6_RXD (0x08UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_UART7_nCTS (0x09UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_UART9_RXD (0x0aUL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_EQEI0_INDEX (0x0bUL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_EPWM0_CH3 (0x0cUL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_BPWM0_CH2 (0x0dUL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE4MFP_PSIO0_CH3 (0x11UL << NUMAKER_SYS_GPE_MFP1_PE4MFP_Pos) + +/* PE.5 MFP */ +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_EBI_nRD (0x02UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_SD0_DAT3 (0x03UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_SPIM_SS (0x04UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_SPI3_SS (0x05UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_SC0_PWR (0x06UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_USCI0_CTL1 (0x07UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_UART6_TXD (0x08UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_UART7_nRTS (0x09UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_UART9_TXD (0x0aUL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_EQEI1_B (0x0bUL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_EPWM0_CH2 (0x0cUL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_BPWM0_CH3 (0x0dUL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE5MFP_PSIO0_CH2 (0x11UL << NUMAKER_SYS_GPE_MFP1_PE5MFP_Pos) + +/* PE.6 MFP */ +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_SD0_CLK (0x03UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_SPIM_D3 (0x04UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_SPI3_I2SMCLK (0x05UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_SC0_nCD (0x06UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_USCI0_CTL0 (0x07UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_UART5_RXD (0x08UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_CAN1_RXD (0x09UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_UART9_nRTS (0x0aUL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_EQEI1_A (0x0bUL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_EPWM0_CH1 (0x0cUL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_BPWM0_CH4 (0x0dUL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_ACMP3_O (0x0eUL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE6MFP_PSIO0_CH1 (0x11UL << NUMAKER_SYS_GPE_MFP1_PE6MFP_Pos) + +/* PE.7 MFP */ +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_SD0_CMD (0x03UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_SPIM_D2 (0x04UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_UART5_TXD (0x08UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_CAN1_TXD (0x09UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_UART9_nCTS (0x0aUL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_EQEI1_INDEX (0x0bUL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_EPWM0_CH0 (0x0cUL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_BPWM0_CH5 (0x0dUL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_ACMP2_O (0x0eUL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) +#define NUMAKER_SYS_GPE_MFP1_PE7MFP_PSIO0_CH0 (0x11UL << NUMAKER_SYS_GPE_MFP1_PE7MFP_Pos) + +/* PE.8 MFP */ +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_EBI_ADR10 (0x02UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_EMAC0_RMII_MDC (0x03UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_I2S0_BCLK (0x04UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_SPI2_CLK (0x05UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_UART2_TXD (0x07UL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_EPWM0_CH0 (0x0aUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_EPWM0_BRAKE0 (0x0bUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_ECAP0_IC0 (0x0cUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_EQEI2_INDEX (0x0dUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_TRACE_DATA3 (0x0eUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE8MFP_ECAP3_IC0 (0x0fUL << NUMAKER_SYS_GPE_MFP2_PE8MFP_Pos) + +/* PE.9 MFP */ +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_EBI_ADR11 (0x02UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_EMAC0_RMII_MDIO (0x03UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_I2S0_MCLK (0x04UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_SPI2_MISO (0x05UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_UART2_RXD (0x07UL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_EPWM0_CH1 (0x0aUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_EPWM0_BRAKE1 (0x0bUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_ECAP0_IC1 (0x0cUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_EQEI2_A (0x0dUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_TRACE_DATA2 (0x0eUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE9MFP_ECAP3_IC1 (0x0fUL << NUMAKER_SYS_GPE_MFP2_PE9MFP_Pos) + +/* PE.10 MFP */ +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_EBI_ADR12 (0x02UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_EMAC0_RMII_TXD0 (0x03UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_I2S0_DI (0x04UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_SPI2_MOSI (0x05UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_UART3_TXD (0x07UL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_EPWM0_CH2 (0x0aUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_EPWM1_BRAKE0 (0x0bUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_ECAP0_IC2 (0x0cUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_EQEI2_B (0x0dUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_TRACE_DATA1 (0x0eUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE10MFP_ECAP3_IC2 (0x0fUL << NUMAKER_SYS_GPE_MFP2_PE10MFP_Pos) + +/* PE.11 MFP */ +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_EBI_ADR13 (0x02UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_EMAC0_RMII_TXD1 (0x03UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_I2S0_DO (0x04UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_SPI2_SS (0x05UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_UART3_RXD (0x07UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_UART1_nCTS (0x08UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_EPWM0_CH3 (0x0aUL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_EPWM1_BRAKE1 (0x0bUL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_ECAP1_IC2 (0x0dUL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_TRACE_DATA0 (0x0eUL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) +#define NUMAKER_SYS_GPE_MFP2_PE11MFP_KPI_COL7 (0x12UL << NUMAKER_SYS_GPE_MFP2_PE11MFP_Pos) + +/* PE.12 MFP */ +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_EBI_ADR14 (0x02UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_EMAC0_RMII_TXEN (0x03UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_I2S0_LRCK (0x04UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_SPI2_I2SMCLK (0x05UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_UART1_nRTS (0x08UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_EPWM0_CH4 (0x0aUL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_ECAP1_IC1 (0x0dUL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_TRACE_CLK (0x0eUL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE12MFP_KPI_COL6 (0x12UL << NUMAKER_SYS_GPE_MFP3_PE12MFP_Pos) + +/* PE.13 MFP */ +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_EBI_ADR15 (0x02UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_EMAC0_PPS (0x03UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_I2C0_SCL (0x04UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_UART4_nRTS (0x05UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_UART1_TXD (0x08UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_EPWM0_CH5 (0x0aUL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_EPWM1_CH0 (0x0bUL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_BPWM1_CH5 (0x0cUL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_ECAP1_IC0 (0x0dUL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_TRACE_SWO (0x0eUL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE13MFP_KPI_COL5 (0x12UL << NUMAKER_SYS_GPE_MFP3_PE13MFP_Pos) + +/* PE.14 MFP */ +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_EBI_AD8 (0x02UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_UART2_TXD (0x03UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_CAN0_TXD (0x04UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_SD1_nCD (0x05UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_UART6_TXD (0x06UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE14MFP_PSIO0_CH0 (0x11UL << NUMAKER_SYS_GPE_MFP3_PE14MFP_Pos) + +/* PE.15 MFP */ +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_GPIO (0x00UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_EBI_AD9 (0x02UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_UART2_RXD (0x03UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_CAN0_RXD (0x04UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_UART6_RXD (0x06UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) +#define NUMAKER_SYS_GPE_MFP3_PE15MFP_PSIO0_CH1 (0x11UL << NUMAKER_SYS_GPE_MFP3_PE15MFP_Pos) + +/* PF.0 MFP */ +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_UART1_TXD (0x02UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_I2C1_SCL (0x03UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_UART0_TXD (0x04UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_SC1_DAT (0x05UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_I2S0_DO (0x06UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_UART2_TXD (0x08UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_I2C0_SCL (0x09UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_CAN2_TXD (0x0aUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_EPWM1_CH4 (0x0bUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_BPWM1_CH0 (0x0cUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_ACMP0_O (0x0dUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_ICE_DAT (0x0eUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_EADC0_ST (0x0fUL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF0MFP_QSPI1_MISO0 (0x13UL << NUMAKER_SYS_GPF_MFP0_PF0MFP_Pos) + +/* PF.1 MFP */ +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_UART1_RXD (0x02UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_I2C1_SDA (0x03UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_UART0_RXD (0x04UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_SC1_CLK (0x05UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_I2S0_LRCK (0x06UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_UART2_RXD (0x08UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_I2C0_SDA (0x09UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_CAN2_RXD (0x0aUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_EPWM1_CH5 (0x0bUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_BPWM1_CH1 (0x0cUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_ACMP1_O (0x0dUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_ICE_CLK (0x0eUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_EADC1_ST (0x0fUL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF1MFP_QSPI1_MOSI0 (0x13UL << NUMAKER_SYS_GPF_MFP0_PF1MFP_Pos) + +/* PF.2 MFP */ +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_EBI_nCS1 (0x02UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_UART0_RXD (0x03UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_I2C0_SDA (0x04UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_QSPI0_CLK (0x05UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_UART9_RXD (0x07UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_XT1_OUT (0x0aUL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_BPWM1_CH1 (0x0bUL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_I2C4_SMBSUS (0x0cUL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_ACMP3_O (0x0dUL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF2MFP_BMC13 (0x14UL << NUMAKER_SYS_GPF_MFP0_PF2MFP_Pos) + +/* PF.3 MFP */ +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_EBI_nCS0 (0x02UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_UART0_TXD (0x03UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_I2C0_SCL (0x04UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_UART9_TXD (0x07UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_XT1_IN (0x0aUL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_BPWM1_CH0 (0x0bUL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_I2C4_SMBAL (0x0cUL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_ACMP2_O (0x0dUL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_EADC2_ST (0x0fUL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) +#define NUMAKER_SYS_GPF_MFP0_PF3MFP_BMC12 (0x14UL << NUMAKER_SYS_GPF_MFP0_PF3MFP_Pos) + +/* PF.4 MFP */ +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_UART2_TXD (0x02UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_EBI_AD0 (0x03UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_UART2_nRTS (0x04UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_EPWM0_CH1 (0x07UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_BPWM0_CH5 (0x08UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_X32_OUT (0x0aUL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_EADC1_ST (0x0bUL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_I2C4_SDA (0x0cUL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_EQEI2_B (0x0dUL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_SPI5_MISO (0x13UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF4MFP_BMC11 (0x14UL << NUMAKER_SYS_GPF_MFP1_PF4MFP_Pos) + +/* PF.5 MFP */ +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_UART2_RXD (0x02UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_EBI_AD1 (0x03UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_UART2_nCTS (0x04UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_EPWM0_CH0 (0x07UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_BPWM0_CH4 (0x08UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_EPWM0_SYNC_OUT (0x09UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_X32_IN (0x0aUL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_EADC0_ST (0x0bUL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_I2C4_SCL (0x0cUL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_EQEI2_A (0x0dUL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_SPI5_MOSI (0x13UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF5MFP_BMC10 (0x14UL << NUMAKER_SYS_GPF_MFP1_PF5MFP_Pos) + +/* PF.6 MFP */ +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_EBI_ADR19 (0x02UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_SC0_CLK (0x03UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_I2S0_LRCK (0x04UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_SPI0_MOSI (0x05UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_UART4_RXD (0x06UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_EBI_nCS0 (0x07UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_CAN2_RXD (0x08UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_SPI3_I2SMCLK (0x09UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_TAMPER0 (0x0aUL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_EQEI2_INDEX (0x0dUL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_TRACE_SWO (0x0eUL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF6MFP_SPI5_CLK (0x13UL << NUMAKER_SYS_GPF_MFP1_PF6MFP_Pos) + +/* PF.7 MFP */ +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_EBI_ADR18 (0x02UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_SC0_DAT (0x03UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_I2S0_DO (0x04UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_SPI0_MISO (0x05UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_UART4_TXD (0x06UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_CCAP_DATA0 (0x07UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_CAN2_TXD (0x08UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_TAMPER1 (0x0aUL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) +#define NUMAKER_SYS_GPF_MFP1_PF7MFP_SPI5_SS (0x13UL << NUMAKER_SYS_GPF_MFP1_PF7MFP_Pos) + +/* PF.8 MFP */ +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_EBI_ADR17 (0x02UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_SC0_RST (0x03UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_I2S0_DI (0x04UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_SPI0_CLK (0x05UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_UART5_nCTS (0x06UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_CCAP_DATA1 (0x07UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_CAN1_RXD (0x08UL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_TAMPER2 (0x0aUL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF8MFP_UART9_RXD (0x0bUL << NUMAKER_SYS_GPF_MFP2_PF8MFP_Pos) + +/* PF.9 MFP */ +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_EBI_ADR16 (0x02UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_SC0_PWR (0x03UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_I2S0_MCLK (0x04UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_SPI0_SS (0x05UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_UART5_nRTS (0x06UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_CCAP_DATA2 (0x07UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_CAN1_TXD (0x08UL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_TAMPER3 (0x0aUL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF9MFP_UART9_TXD (0x0bUL << NUMAKER_SYS_GPF_MFP2_PF9MFP_Pos) + +/* PF.10 MFP */ +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_EBI_ADR15 (0x02UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_SC0_nCD (0x03UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_I2S0_BCLK (0x04UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_SPI0_I2SMCLK (0x05UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_UART5_RXD (0x06UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_CCAP_DATA3 (0x07UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_CAN3_RXD (0x08UL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_TAMPER4 (0x0aUL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF10MFP_UART9_nRTS (0x0bUL << NUMAKER_SYS_GPF_MFP2_PF10MFP_Pos) + +/* PF.11 MFP */ +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_GPIO (0x00UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_EBI_ADR14 (0x02UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_SPI2_MOSI (0x03UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_UART5_TXD (0x06UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_CCAP_DATA4 (0x07UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_CAN3_TXD (0x08UL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_TAMPER5 (0x0aUL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_UART9_nCTS (0x0bUL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) +#define NUMAKER_SYS_GPF_MFP2_PF11MFP_TM3 (0x0dUL << NUMAKER_SYS_GPF_MFP2_PF11MFP_Pos) + +/* PG.0 MFP */ +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_EBI_ADR8 (0x02UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_I2C0_SCL (0x04UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_I2C1_SMBAL (0x05UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_UART2_RXD (0x06UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_CAN1_TXD (0x07UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_UART1_TXD (0x08UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG0MFP_I2C3_SCL (0x09UL << NUMAKER_SYS_GPG_MFP0_PG0MFP_Pos) + +/* PG.1 MFP */ +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_EBI_ADR9 (0x02UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_SPI2_I2SMCLK (0x03UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_I2C0_SDA (0x04UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_I2C1_SMBSUS (0x05UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_UART2_TXD (0x06UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_CAN1_RXD (0x07UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_UART1_RXD (0x08UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG1MFP_I2C3_SDA (0x09UL << NUMAKER_SYS_GPG_MFP0_PG1MFP_Pos) + +/* PG.2 MFP */ +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_EBI_ADR11 (0x02UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_SPI2_SS (0x03UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_I2C0_SMBAL (0x04UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_I2C1_SCL (0x05UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_CCAP_DATA7 (0x07UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_I2C3_SMBAL (0x09UL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG2MFP_TM0 (0x0dUL << NUMAKER_SYS_GPG_MFP0_PG2MFP_Pos) + +/* PG.3 MFP */ +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_EBI_ADR12 (0x02UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_SPI2_CLK (0x03UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_I2C0_SMBSUS (0x04UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_I2C1_SDA (0x05UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_CCAP_DATA6 (0x07UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_I2C3_SMBSUS (0x09UL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) +#define NUMAKER_SYS_GPG_MFP0_PG3MFP_TM1 (0x0dUL << NUMAKER_SYS_GPG_MFP0_PG3MFP_Pos) + +/* PG.4 MFP */ +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_EBI_ADR13 (0x02UL << NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_SPI2_MISO (0x03UL << NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_CCAP_DATA5 (0x07UL << NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG4MFP_TM2 (0x0dUL << NUMAKER_SYS_GPG_MFP1_PG4MFP_Pos) + +/* PG.5 MFP */ +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_EBI_nCS1 (0x02UL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_SPI3_SS (0x03UL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_SC1_PWR (0x04UL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_I2C3_SMBAL (0x08UL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_I2S1_MCLK (0x0aUL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG5MFP_EPWM0_CH3 (0x0bUL << NUMAKER_SYS_GPG_MFP1_PG5MFP_Pos) + +/* PG.6 MFP */ +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_EBI_nCS2 (0x02UL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_SPI3_CLK (0x03UL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_SC1_RST (0x04UL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_I2C3_SMBSUS (0x08UL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_I2S1_DI (0x0aUL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG6MFP_EPWM0_CH2 (0x0bUL << NUMAKER_SYS_GPG_MFP1_PG6MFP_Pos) + +/* PG.7 MFP */ +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_EBI_nWRL (0x02UL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_SPI3_MISO (0x03UL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_SC1_DAT (0x04UL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_I2C3_SCL (0x08UL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_I2S1_DO (0x0aUL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) +#define NUMAKER_SYS_GPG_MFP1_PG7MFP_EPWM0_CH1 (0x0bUL << NUMAKER_SYS_GPG_MFP1_PG7MFP_Pos) + +/* PG.8 MFP */ +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_EBI_nWRH (0x02UL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_SPI3_MOSI (0x03UL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_SC1_CLK (0x04UL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_I2C3_SDA (0x08UL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_I2S1_LRCK (0x0aUL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG8MFP_EPWM0_CH0 (0x0bUL << NUMAKER_SYS_GPG_MFP2_PG8MFP_Pos) + +/* PG.9 MFP */ +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_EBI_AD0 (0x02UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_SD1_DAT3 (0x03UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_SPIM_D2 (0x04UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_QSPI1_MISO1 (0x05UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_CCAP_PIXCLK (0x07UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_I2C4_SCL (0x08UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_ECAP2_IC0 (0x09UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_BPWM0_CH5 (0x0cUL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_HBI_D4 (0x10UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_SPI8_SS (0x13UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG9MFP_BMC16 (0x14UL << NUMAKER_SYS_GPG_MFP2_PG9MFP_Pos) + +/* PG.10 MFP */ +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_EBI_AD1 (0x02UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_SD1_DAT2 (0x03UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_SPIM_D3 (0x04UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_QSPI1_MOSI1 (0x05UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_CCAP_SCLK (0x07UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_I2C4_SDA (0x08UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_ECAP2_IC1 (0x09UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_BPWM0_CH4 (0x0cUL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_HBI_D3 (0x10UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_SPI8_CLK (0x13UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG10MFP_BMC17 (0x14UL << NUMAKER_SYS_GPG_MFP2_PG10MFP_Pos) + +/* PG.11 MFP */ +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_EBI_AD2 (0x02UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_SD1_DAT1 (0x03UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_SPIM_SS (0x04UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_QSPI1_SS (0x05UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_UART7_TXD (0x06UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_CCAP_SFIELD (0x07UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_I2C4_SMBAL (0x08UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_ECAP2_IC2 (0x09UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_BPWM0_CH3 (0x0cUL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_HBI_D0 (0x10UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_SPI8_MOSI (0x13UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) +#define NUMAKER_SYS_GPG_MFP2_PG11MFP_BMC18 (0x14UL << NUMAKER_SYS_GPG_MFP2_PG11MFP_Pos) + +/* PG.12 MFP */ +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_EBI_AD3 (0x02UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_SD1_DAT0 (0x03UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_SPIM_CLK (0x04UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_QSPI1_CLK (0x05UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_UART7_RXD (0x06UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_CCAP_VSYNC (0x07UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_I2C4_SMBSUS (0x08UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_BPWM0_CH2 (0x0cUL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_HBI_D1 (0x10UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_SPI8_MISO (0x13UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG12MFP_BMC19 (0x14UL << NUMAKER_SYS_GPG_MFP3_PG12MFP_Pos) + +/* PG.13 MFP */ +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_EBI_AD4 (0x02UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_SD1_CMD (0x03UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_SPIM_MISO (0x04UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_QSPI1_MISO0 (0x05UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_UART6_TXD (0x06UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_CCAP_HSYNC (0x07UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_BPWM0_CH1 (0x0cUL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG13MFP_HBI_D5 (0x10UL << NUMAKER_SYS_GPG_MFP3_PG13MFP_Pos) + +/* PG.14 MFP */ +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_EBI_AD5 (0x02UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_SD1_CLK (0x03UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_SPIM_MOSI (0x04UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_QSPI1_MOSI0 (0x05UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_UART6_RXD (0x06UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_BPWM0_CH0 (0x0cUL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG14MFP_HBI_D6 (0x10UL << NUMAKER_SYS_GPG_MFP3_PG14MFP_Pos) + +/* PG.15 MFP */ +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_GPIO (0x00UL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_SD1_nCD (0x03UL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_CLKO (0x0eUL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_EADC0_ST (0x0fUL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_HBI_D7 (0x10UL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) +#define NUMAKER_SYS_GPG_MFP3_PG15MFP_QSPI1_MISO1 (0x13UL << NUMAKER_SYS_GPG_MFP3_PG15MFP_Pos) + +/* PH.0 MFP */ +#define NUMAKER_SYS_GPH_MFP0_PH0MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP0_PH0MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH0MFP_EBI_ADR7 (0x02UL << NUMAKER_SYS_GPH_MFP0_PH0MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH0MFP_UART5_TXD (0x04UL << NUMAKER_SYS_GPH_MFP0_PH0MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH0MFP_TM0_EXT (0x0dUL << NUMAKER_SYS_GPH_MFP0_PH0MFP_Pos) + +/* PH.1 MFP */ +#define NUMAKER_SYS_GPH_MFP0_PH1MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP0_PH1MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH1MFP_EBI_ADR6 (0x02UL << NUMAKER_SYS_GPH_MFP0_PH1MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH1MFP_UART5_RXD (0x04UL << NUMAKER_SYS_GPH_MFP0_PH1MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH1MFP_TM1_EXT (0x0dUL << NUMAKER_SYS_GPH_MFP0_PH1MFP_Pos) + +/* PH.2 MFP */ +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_EBI_ADR5 (0x02UL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_UART5_nRTS (0x04UL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_UART4_TXD (0x05UL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_I2C0_SCL (0x06UL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH2MFP_TM2_EXT (0x0dUL << NUMAKER_SYS_GPH_MFP0_PH2MFP_Pos) + +/* PH.3 MFP */ +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_EBI_ADR4 (0x02UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_SPI1_I2SMCLK (0x03UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_UART5_nCTS (0x04UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_UART4_RXD (0x05UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_I2C0_SDA (0x06UL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) +#define NUMAKER_SYS_GPH_MFP0_PH3MFP_TM3_EXT (0x0dUL << NUMAKER_SYS_GPH_MFP0_PH3MFP_Pos) + +/* PH.4 MFP */ +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_EBI_ADR3 (0x02UL << NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_SPI1_MISO (0x03UL << NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_UART7_nRTS (0x04UL << NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH4MFP_UART6_TXD (0x05UL << NUMAKER_SYS_GPH_MFP1_PH4MFP_Pos) + +/* PH.5 MFP */ +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_EBI_ADR2 (0x02UL << NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_SPI1_MOSI (0x03UL << NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_UART7_nCTS (0x04UL << NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH5MFP_UART6_RXD (0x05UL << NUMAKER_SYS_GPH_MFP1_PH5MFP_Pos) + +/* PH.6 MFP */ +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_EBI_ADR1 (0x02UL << NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_SPI1_CLK (0x03UL << NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_UART7_TXD (0x04UL << NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH6MFP_UART9_nCTS (0x07UL << NUMAKER_SYS_GPH_MFP1_PH6MFP_Pos) + +/* PH.7 MFP */ +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_EBI_ADR0 (0x02UL << NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_SPI1_SS (0x03UL << NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_UART7_RXD (0x04UL << NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos) +#define NUMAKER_SYS_GPH_MFP1_PH7MFP_UART9_nRTS (0x07UL << NUMAKER_SYS_GPH_MFP1_PH7MFP_Pos) + +/* PH.8 MFP */ +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_EBI_AD12 (0x02UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_QSPI0_CLK (0x03UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_SC2_PWR (0x04UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_I2S0_DI (0x05UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_SPI1_CLK (0x06UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_UART3_nRTS (0x07UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_I2C1_SMBAL (0x08UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_I2C2_SCL (0x09UL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_UART1_TXD (0x0aUL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH8MFP_UART9_nCTS (0x0dUL << NUMAKER_SYS_GPH_MFP2_PH8MFP_Pos) + +/* PH.9 MFP */ +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_EBI_AD13 (0x02UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_QSPI0_SS (0x03UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_SC2_RST (0x04UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_I2S0_DO (0x05UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_SPI1_SS (0x06UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_UART3_nCTS (0x07UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_I2C1_SMBSUS (0x08UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_I2C2_SDA (0x09UL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_UART1_RXD (0x0aUL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH9MFP_UART9_nRTS (0x0dUL << NUMAKER_SYS_GPH_MFP2_PH9MFP_Pos) + +/* PH.10 MFP */ +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_EBI_AD14 (0x02UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_QSPI0_MISO1 (0x03UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_SC2_nCD (0x04UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_I2S0_LRCK (0x05UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_SPI1_I2SMCLK (0x06UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_UART4_TXD (0x07UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_UART0_TXD (0x08UL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH10MFP_UART9_TXD (0x0dUL << NUMAKER_SYS_GPH_MFP2_PH10MFP_Pos) + +/* PH.11 MFP */ +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_EBI_AD15 (0x02UL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_QSPI0_MOSI1 (0x03UL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_UART4_RXD (0x07UL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_UART0_RXD (0x08UL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_EPWM0_CH5 (0x0bUL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) +#define NUMAKER_SYS_GPH_MFP2_PH11MFP_UART9_RXD (0x0dUL << NUMAKER_SYS_GPH_MFP2_PH11MFP_Pos) + +/* PH.12 MFP */ +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_EBI_AD0 (0x02UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_UART9_TXD (0x03UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_QSPI1_MISO1 (0x06UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_CCAP_PIXCLK (0x07UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_CAN3_TXD (0x0aUL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH12MFP_HBI_nCK (0x10UL << NUMAKER_SYS_GPH_MFP3_PH12MFP_Pos) + +/* PH.13 MFP */ +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_EBI_AD1 (0x02UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_UART9_RXD (0x03UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_QSPI1_MOSI1 (0x06UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_CCAP_SCLK (0x07UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_CAN3_RXD (0x0aUL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH13MFP_HBI_nCS (0x10UL << NUMAKER_SYS_GPH_MFP3_PH13MFP_Pos) + +/* PH.14 MFP */ +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_EBI_AD2 (0x02UL << NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_QSPI1_SS (0x06UL << NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_CCAP_SFIELD (0x07UL << NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH14MFP_HBI_D3 (0x10UL << NUMAKER_SYS_GPH_MFP3_PH14MFP_Pos) + +/* PH.15 MFP */ +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_GPIO (0x00UL << NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_EBI_AD3 (0x02UL << NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_QSPI1_CLK (0x06UL << NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_CCAP_VSYNC (0x07UL << NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos) +#define NUMAKER_SYS_GPH_MFP3_PH15MFP_HBI_D2 (0x10UL << NUMAKER_SYS_GPH_MFP3_PH15MFP_Pos) + +/* PI.6 MFP */ +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_SC1_nCD (0x05UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_I2S0_BCLK (0x06UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_SPI1_I2SMCLK (0x07UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_UART2_TXD (0x08UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_I2C1_SCL (0x09UL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_CAN3_TXD (0x0dUL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI6MFP_USB_VBUS_ST (0x0fUL << NUMAKER_SYS_GPI_MFP1_PI6MFP_Pos) + +/* PI.7 MFP */ +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_SC1_PWR (0x05UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_I2S0_MCLK (0x06UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_SPI1_MISO (0x07UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_UART2_RXD (0x08UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_I2C1_SDA (0x09UL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_CAN3_RXD (0x0dUL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) +#define NUMAKER_SYS_GPI_MFP1_PI7MFP_USB_VBUS_EN (0x0fUL << NUMAKER_SYS_GPI_MFP1_PI7MFP_Pos) + +/* PI.8 MFP */ +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_SC1_RST (0x05UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_I2S0_DI (0x06UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_SPI1_MOSI (0x07UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_UART2_nRTS (0x08UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_I2C0_SMBAL (0x09UL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI8MFP_CAN2_TXD (0x0dUL << NUMAKER_SYS_GPI_MFP2_PI8MFP_Pos) + +/* PI.9 MFP */ +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_SC1_DAT (0x05UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_I2S0_DO (0x06UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_SPI1_CLK (0x07UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_UART2_nCTS (0x08UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_I2C0_SMBSUS (0x09UL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI9MFP_CAN2_RXD (0x0dUL << NUMAKER_SYS_GPI_MFP2_PI9MFP_Pos) + +/* PI.10 MFP */ +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_SC1_CLK (0x05UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_I2S0_LRCK (0x06UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_SPI1_SS (0x07UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_UART2_TXD (0x08UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_I2C0_SCL (0x09UL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI10MFP_CAN3_TXD (0x0dUL << NUMAKER_SYS_GPI_MFP2_PI10MFP_Pos) + +/* PI.11 MFP */ +#define NUMAKER_SYS_GPI_MFP2_PI11MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP2_PI11MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI11MFP_UART2_RXD (0x08UL << NUMAKER_SYS_GPI_MFP2_PI11MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI11MFP_I2C0_SDA (0x09UL << NUMAKER_SYS_GPI_MFP2_PI11MFP_Pos) +#define NUMAKER_SYS_GPI_MFP2_PI11MFP_CAN3_RXD (0x0dUL << NUMAKER_SYS_GPI_MFP2_PI11MFP_Pos) + +/* PI.12 MFP */ +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_SPIM_SS (0x03UL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_QSPI0_MISO1 (0x04UL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_CAN0_TXD (0x0aUL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_UART4_TXD (0x0bUL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_EPWM1_CH0 (0x0cUL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI12MFP_I2C3_SMBAL (0x0fUL << NUMAKER_SYS_GPI_MFP3_PI12MFP_Pos) + +/* PI.13 MFP */ +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_SPIM_MISO (0x03UL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_QSPI0_MOSI1 (0x04UL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_CAN0_RXD (0x0aUL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_UART4_RXD (0x0bUL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_EPWM1_CH1 (0x0cUL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI13MFP_I2C3_SMBSUS (0x0fUL << NUMAKER_SYS_GPI_MFP3_PI13MFP_Pos) + +/* PI.14 MFP */ +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_SPIM_D2 (0x03UL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_QSPI0_SS (0x04UL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_UART8_nCTS (0x07UL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_CAN1_TXD (0x0aUL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_UART3_TXD (0x0bUL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_EPWM1_CH2 (0x0cUL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI14MFP_I2C3_SCL (0x0fUL << NUMAKER_SYS_GPI_MFP3_PI14MFP_Pos) + +/* PI.15 MFP */ +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_GPIO (0x00UL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_SPIM_D3 (0x03UL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_QSPI0_CLK (0x04UL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_UART8_nRTS (0x07UL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_CAN1_RXD (0x0aUL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_UART3_RXD (0x0bUL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_EPWM1_CH3 (0x0cUL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) +#define NUMAKER_SYS_GPI_MFP3_PI15MFP_I2C3_SDA (0x0fUL << NUMAKER_SYS_GPI_MFP3_PI15MFP_Pos) + +/* PJ.0 MFP */ +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_SPIM_CLK (0x03UL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_QSPI0_MISO0 (0x04UL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_UART8_TXD (0x07UL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_CAN2_TXD (0x0aUL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ0MFP_EPWM1_CH4 (0x0cUL << NUMAKER_SYS_GPJ_MFP0_PJ0MFP_Pos) + +/* PJ.1 MFP */ +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_SPIM_MOSI (0x03UL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_QSPI0_MOSI0 (0x04UL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_UART8_RXD (0x07UL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_CAN2_RXD (0x0aUL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ1MFP_EPWM1_CH5 (0x0cUL << NUMAKER_SYS_GPJ_MFP0_PJ1MFP_Pos) + +/* PJ.2 MFP */ +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_EBI_AD5 (0x02UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_UART8_nCTS (0x03UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_QSPI1_SS (0x06UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_CCAP_DATA5 (0x07UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_CAN0_TXD (0x0aUL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ2MFP_HBI_RWDS (0x10UL << NUMAKER_SYS_GPJ_MFP0_PJ2MFP_Pos) + +/* PJ.3 MFP */ +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_EBI_AD4 (0x02UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_UART8_nRTS (0x03UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_QSPI1_CLK (0x06UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_CCAP_DATA4 (0x07UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_CAN0_RXD (0x0aUL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP0_PJ3MFP_HBI_D7 (0x10UL << NUMAKER_SYS_GPJ_MFP0_PJ3MFP_Pos) + +/* PJ.4 MFP */ +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_EBI_AD3 (0x02UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_UART8_TXD (0x03UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_QSPI1_MISO0 (0x06UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_CCAP_DATA3 (0x07UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_CAN1_TXD (0x0aUL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ4MFP_HBI_D6 (0x10UL << NUMAKER_SYS_GPJ_MFP1_PJ4MFP_Pos) + +/* PJ.5 MFP */ +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_EBI_AD2 (0x02UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_UART8_RXD (0x03UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_QSPI1_MOSI0 (0x06UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_CCAP_DATA2 (0x07UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_CAN1_RXD (0x0aUL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ5MFP_HBI_D5 (0x10UL << NUMAKER_SYS_GPJ_MFP1_PJ5MFP_Pos) + +/* PJ.6 MFP */ +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_EBI_AD1 (0x02UL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_UART9_nCTS (0x03UL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_CCAP_DATA1 (0x07UL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_CAN2_TXD (0x0aUL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ6MFP_HBI_D4 (0x10UL << NUMAKER_SYS_GPJ_MFP1_PJ6MFP_Pos) + +/* PJ.7 MFP */ +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_EBI_AD0 (0x02UL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_UART9_nRTS (0x03UL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_CCAP_DATA0 (0x07UL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_CAN2_RXD (0x0aUL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP1_PJ7MFP_HBI_CK (0x10UL << NUMAKER_SYS_GPJ_MFP1_PJ7MFP_Pos) + +/* PJ.8 MFP */ +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_EBI_nRD (0x02UL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_SD1_DAT3 (0x03UL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_SPIM_SS (0x04UL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_UART7_TXD (0x06UL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_CAN2_TXD (0x0bUL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ8MFP_BPWM0_CH5 (0x0cUL << NUMAKER_SYS_GPJ_MFP2_PJ8MFP_Pos) + +/* PJ.9 MFP */ +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_EBI_nWR (0x02UL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_SD1_DAT2 (0x03UL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_SPIM_MISO (0x04UL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_UART7_RXD (0x06UL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_CAN2_RXD (0x0bUL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ9MFP_BPWM0_CH4 (0x0cUL << NUMAKER_SYS_GPJ_MFP2_PJ9MFP_Pos) + +/* PJ.10 MFP */ +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_EBI_MCLK (0x02UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_SD1_DAT1 (0x03UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_SPIM_D2 (0x04UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_UART6_TXD (0x06UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_I2C4_SCL (0x08UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_ECAP2_IC0 (0x09UL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_CAN0_TXD (0x0bUL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ10MFP_BPWM0_CH3 (0x0cUL << NUMAKER_SYS_GPJ_MFP2_PJ10MFP_Pos) + +/* PJ.11 MFP */ +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_EBI_ALE (0x02UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_SD1_DAT0 (0x03UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_SPIM_D3 (0x04UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_UART6_RXD (0x06UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_I2C4_SDA (0x08UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_ECAP2_IC1 (0x09UL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_CAN0_RXD (0x0bUL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP2_PJ11MFP_BPWM0_CH2 (0x0cUL << NUMAKER_SYS_GPJ_MFP2_PJ11MFP_Pos) + +/* PJ.12 MFP */ +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_EBI_nCS0 (0x02UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_SD1_CMD (0x03UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_SPIM_CLK (0x04UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_I2C4_SMBAL (0x08UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_ECAP2_IC2 (0x09UL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_CAN1_TXD (0x0bUL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_BPWM0_CH1 (0x0cUL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ12MFP_HSUSB_VBUS_ST (0x0fUL << NUMAKER_SYS_GPJ_MFP3_PJ12MFP_Pos) + +/* PJ.13 MFP */ +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_GPIO (0x00UL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_SD1_CLK (0x03UL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_SPIM_MOSI (0x04UL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_I2C4_SMBSUS (0x08UL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_CAN1_RXD (0x0bUL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_BPWM0_CH0 (0x0cUL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) +#define NUMAKER_SYS_GPJ_MFP3_PJ13MFP_HSUSB_VBUS_EN (0x0fUL << NUMAKER_SYS_GPJ_MFP3_PJ13MFP_Pos) + +/* End of M460 BSP sys.h pin-mux module copy */ + +#endif diff --git a/soc/arm/nuvoton_numaker/common/pinctrl_soc.h b/soc/arm/nuvoton_numaker/common/pinctrl_soc.h new file mode 100644 index 000000000000..9a8320bdff25 --- /dev/null +++ b/soc/arm/nuvoton_numaker/common/pinctrl_soc.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NUVOTON_NUMAKER_PINCTRL_SOC_H_ +#define _NUVOTON_NUMAKER_PINCTRL_SOC_H_ + +#include +#include + +#define PORT_INDEX(pinmux) (((pinmux)&0xF0000000) >> 28) +#define PIN_INDEX(pinmux) (((pinmux)&0x0F000000) >> 24) +#define MFP_CFG(pinmux) (((pinmux)&0x000000FF) << ((PIN_INDEX(pinmux) % 4) * 8)) +#define NU_MFP_POS(pinindex) ((pinindex % 4) * 8) +#define NU_MFP_MASK(pinindex) (0x1f << NU_MFP_POS(pinindex)) + +typedef struct pinctrl_soc_pin_t { + uint32_t pin_mux; +} pinctrl_soc_pin_t; + +#define NUMAKER_DT_PIN(node_id, prop, idx) {.pin_mux = DT_PROP_BY_IDX(node_id, prop, idx)}, + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) NUMAKER_DT_PIN(node_id, prop, idx) + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { \ + DT_FOREACH_PROP_ELEM(DT_PHANDLE(node_id, prop), pinmux, Z_PINCTRL_STATE_PIN_INIT) \ + } + +#endif /* _NUVOTON_NUMAKER_PINCTRL_SOC_H_ */ From 4ad399d54d0db1f97eb61331ab1e9ed42eb4bab8 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 3 Mar 2023 18:11:00 +0800 Subject: [PATCH 0431/2042] drivers: clock_control: add support for Nuvoton numaker series CLK Add Nuvoton numaker series clock controller support, including: 1. Do system clock initialization in z_arm_platform_init(). 2. Support peripheral clock control API equivalent to BSP CLK_EnableModuleClock()/CLK_SetModuleClock(). Signed-off-by: cyliang tw --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.numaker | 11 + .../clock_control/clock_control_numaker_scc.c | 162 ++ dts/arm/nuvoton/m46x.dtsi | 17 + dts/bindings/clock/nuvoton,numaker-pcc.yaml | 17 + dts/bindings/clock/nuvoton,numaker-scc.yaml | 49 + .../clock_control/clock_control_numaker.h | 41 + .../dt-bindings/clock/numaker_m46x_clock.h | 1303 +++++++++++++++++ soc/arm/nuvoton_numaker/m46x/soc.c | 52 +- 10 files changed, 1642 insertions(+), 13 deletions(-) create mode 100644 drivers/clock_control/Kconfig.numaker create mode 100644 drivers/clock_control/clock_control_numaker_scc.c create mode 100644 dts/bindings/clock/nuvoton,numaker-pcc.yaml create mode 100644 dts/bindings/clock/nuvoton,numaker-scc.yaml create mode 100644 include/zephyr/drivers/clock_control/clock_control_numaker.h create mode 100644 include/zephyr/dt-bindings/clock/numaker_m46x_clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index d75498f5363e..5e73ba3da20b 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_INFINEON_CAT1 clock_control_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_control_sam_pmc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index c21af00cdb4a..c74808e692eb 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -72,4 +72,6 @@ source "drivers/clock_control/Kconfig.sam" source "drivers/clock_control/Kconfig.smartbond" +source "drivers/clock_control/Kconfig.numaker" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.numaker b/drivers/clock_control/Kconfig.numaker new file mode 100644 index 000000000000..7f36c428b1b6 --- /dev/null +++ b/drivers/clock_control/Kconfig.numaker @@ -0,0 +1,11 @@ +# NuMaker clock controller driver configuration options + +# Copyright (c) 2022 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_NUMAKER_SCC + bool "NuMaker system clock controller driver" + default y + depends on DT_HAS_NUVOTON_NUMAKER_SCC_ENABLED + help + Enable support for NuMaker system clock controller driver diff --git a/drivers/clock_control/clock_control_numaker_scc.c b/drivers/clock_control/clock_control_numaker_scc.c new file mode 100644 index 000000000000..f33d2da120a8 --- /dev/null +++ b/drivers/clock_control/clock_control_numaker_scc.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_scc + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(clock_control_numaker_scc, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +struct numaker_scc_config { + uint32_t clk_base; + int hxt; + int lxt; + int hirc48; + uint32_t clk_pclkdiv; + uint32_t core_clock; +}; + +static inline int numaker_scc_on(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(dev); + + struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys; + + if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) { + SYS_UnlockReg(); + CLK_EnableModuleClock(scc_subsys->pcc.clk_modidx); + SYS_LockReg(); + } else { + return -EINVAL; + } + + return 0; +} + +static inline int numaker_scc_off(const struct device *dev, clock_control_subsys_t subsys) +{ + ARG_UNUSED(dev); + + struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys; + + if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) { + SYS_UnlockReg(); + CLK_DisableModuleClock(scc_subsys->pcc.clk_modidx); + SYS_LockReg(); + } else { + return -EINVAL; + } + + return 0; +} + +static inline int numaker_scc_get_rate(const struct device *dev, clock_control_subsys_t subsys, + uint32_t *rate) +{ + ARG_UNUSED(dev); + ARG_UNUSED(subsys); + ARG_UNUSED(rate); + return -ENOTSUP; +} + +static inline int numaker_scc_set_rate(const struct device *dev, clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + ARG_UNUSED(dev); + ARG_UNUSED(subsys); + ARG_UNUSED(rate); + return -ENOTSUP; +} + +static inline int numaker_scc_configure(const struct device *dev, clock_control_subsys_t subsys, + void *data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(data); + + struct numaker_scc_subsys *scc_subsys = (struct numaker_scc_subsys *)subsys; + + if (scc_subsys->subsys_id == NUMAKER_SCC_SUBSYS_ID_PCC) { + SYS_UnlockReg(); + CLK_SetModuleClock(scc_subsys->pcc.clk_modidx, scc_subsys->pcc.clk_src, + scc_subsys->pcc.clk_div); + SYS_LockReg(); + } else { + return -EINVAL; + } + + return 0; +} + +/* System clock controller driver registration */ +static struct clock_control_driver_api numaker_scc_api = { + .on = numaker_scc_on, + .off = numaker_scc_off, + .get_rate = numaker_scc_get_rate, + .set_rate = numaker_scc_set_rate, + .configure = numaker_scc_configure, +}; + +/* At most one compatible with status "okay" */ +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) <= 1, + "Requires at most one compatible with status \"okay\""); + +#define LOG_OSC_SW(osc, sw) \ + if (sw == NUMAKER_SCC_CLKSW_ENABLE) { \ + LOG_DBG("Enable " #osc); \ + } else if (sw == NUMAKER_SCC_CLKSW_DISABLE) { \ + LOG_DBG("Disable " #osc); \ + } + +static int numaker_scc_init(const struct device *dev) +{ + const struct numaker_scc_config *cfg = dev->config; + + LOG_DBG("CLK base: 0x%08x", cfg->clk_base); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hxt) + LOG_OSC_SW(HXT, cfg->hxt); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), lxt) + LOG_OSC_SW(LXT, cfg->lxt); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hirc48) + LOG_OSC_SW(HIRC48, cfg->hirc48); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), clk_pclkdiv) + LOG_DBG("CLK_PCLKDIV: 0x%08x", cfg->clk_pclkdiv); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), core_clock) + LOG_DBG("Core clock: %d (Hz)", cfg->core_clock); +#endif + + /* + * z_arm_platform_init() will respect above configurations and + * actually take charge of system clock control initialization. + */ + + SystemCoreClockUpdate(); + LOG_DBG("SystemCoreClock: %d (Hz)", SystemCoreClock); + + return 0; +} + +#define NUMICRO_SCC_INIT(inst) \ + static const struct numaker_scc_config numaker_scc_config_##inst = { \ + .clk_base = DT_INST_REG_ADDR(inst), \ + .hxt = DT_INST_ENUM_IDX_OR(inst, hxt, NUMAKER_SCC_CLKSW_UNTOUCHED), \ + .lxt = DT_INST_ENUM_IDX_OR(inst, lxt, NUMAKER_SCC_CLKSW_UNTOUCHED), \ + .hirc48 = DT_INST_ENUM_IDX_OR(inst, hirc48, NUMAKER_SCC_CLKSW_UNTOUCHED), \ + .clk_pclkdiv = DT_INST_PROP_OR(inst, clk_pclkdiv, 0), \ + .core_clock = DT_INST_PROP_OR(inst, core_clock, 0), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &numaker_scc_init, NULL, NULL, &numaker_scc_config_##inst, \ + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &numaker_scc_api); + +DT_INST_FOREACH_STATUS_OKAY(NUMICRO_SCC_INIT); diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index e06344fb7ac6..a404020b185e 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include / { cpus { @@ -39,6 +40,22 @@ }; soc { + scc: system-clock-controller@40000200 { + compatible = "nuvoton,numaker-scc"; + reg = <0x40000200 0x100>; + #clock-cells = <0>; + /* hxt = "enable"; */ + /* lxt = "enable"; */ + clk-pclkdiv = <(NUMAKER_CLK_PCLKDIV_APB0DIV_DIV2 | + NUMAKER_CLK_PCLKDIV_APB1DIV_DIV2)>; + core-clock = <200000000>; + + pcc: peripheral-clock-controller { + compatible = "nuvoton,numaker-pcc"; + #clock-cells = <3>; + }; + }; + pinctrl: pin-controller@40000500 { compatible = "nuvoton,numaker-pinctrl"; reg = <0x40000500 0xa0>; diff --git a/dts/bindings/clock/nuvoton,numaker-pcc.yaml b/dts/bindings/clock/nuvoton,numaker-pcc.yaml new file mode 100644 index 000000000000..3239665a78e5 --- /dev/null +++ b/dts/bindings/clock/nuvoton,numaker-pcc.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton NuMaker Peripheral Clock Controller (PCC) + +compatible: "nuvoton,numaker-pcc" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 3 + +clock-cells: + - clock-module-index # Same as u32ModuleIdx on invoking BSP CLK driver CLK_SetModuleClock() + - clock-source # Same as u32ClkSrc on invoking BSP CLK driver CLK_SetModuleClock() + - clock-divider # Same as u32ClkDiv on invoking BSP CLK driver CLK_SetModuleClock() diff --git a/dts/bindings/clock/nuvoton,numaker-scc.yaml b/dts/bindings/clock/nuvoton,numaker-scc.yaml new file mode 100644 index 000000000000..99ea7ed3adc5 --- /dev/null +++ b/dts/bindings/clock/nuvoton,numaker-scc.yaml @@ -0,0 +1,49 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton NuMaker System Clock Controller (SCC) + +compatible: "nuvoton,numaker-scc" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + hxt: + type: string + description: | + Enable/disable 4~24 MHz external crystal oscillator (HXT) + enum: + - "untouched" + - "enable" + - "disable" + + lxt: + type: string + description: | + Enable/disable 32.768 kHz low-speed external crystal oscillator (LXT) + enum: + - "untouched" + - "enable" + - "disable" + + hirc48: + type: string + description: | + Enable/disable 48 MHz high-speed internal RC oscillator (HIRC48) + enum: + - "untouched" + - "enable" + - "disable" + + clk-pclkdiv: + type: int + description: | + Configure APB Clock Divider register + + core-clock: + type: int + description: | + Configure core clock (HCLK) diff --git a/include/zephyr/drivers/clock_control/clock_control_numaker.h b/include/zephyr/drivers/clock_control/clock_control_numaker.h new file mode 100644 index 000000000000..a61549153ab4 --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_numaker.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_ + +/** + * @brief Enable/disable oscillators or other clocks + */ +#define NUMAKER_SCC_CLKSW_UNTOUCHED 0 +#define NUMAKER_SCC_CLKSW_ENABLE 1 +#define NUMAKER_SCC_CLKSW_DISABLE 2 + +/** + * @brief SCC subsystem ID + */ +#define NUMAKER_SCC_SUBSYS_ID_PCC 1 + +struct numaker_scc_subsys { + uint32_t subsys_id; /* SCC sybsystem ID */ + + /* Peripheral clock control configuration structure + * clk_modidx is same as u32ModuleIdx in BSP CLK_SetModuleClock(). + * clk_src is same as u32ClkSrc in BSP CLK_SetModuleClock(). + * clk_div is same as u32ClkDiv in BSP CLK_SetModuleClock(). + */ + union { + struct { + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + } pcc; + }; +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_NUMAKER_H_ */ diff --git a/include/zephyr/dt-bindings/clock/numaker_m46x_clock.h b/include/zephyr/dt-bindings/clock/numaker_m46x_clock.h new file mode 100644 index 000000000000..9243ab76b561 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/numaker_m46x_clock.h @@ -0,0 +1,1303 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NUMAKER_M46X_CLOCK_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NUMAKER_M46X_CLOCK_H + +/* Beginning of M460 BSP clk_reg.h copy */ + +#define NUMAKER_CLK_AHBCLK0_PDMA0CKEN_Pos (1) +#define NUMAKER_CLK_AHBCLK0_ISPCKEN_Pos (2) +#define NUMAKER_CLK_AHBCLK0_EBICKEN_Pos (3) +#define NUMAKER_CLK_AHBCLK0_STCKEN_Pos (4) +#define NUMAKER_CLK_AHBCLK0_EMAC0CKEN_Pos (5) +#define NUMAKER_CLK_AHBCLK0_SDH0CKEN_Pos (6) +#define NUMAKER_CLK_AHBCLK0_CRCCKEN_Pos (7) +#define NUMAKER_CLK_AHBCLK0_CCAPCKEN_Pos (8) +#define NUMAKER_CLK_AHBCLK0_SENCKEN_Pos (9) +#define NUMAKER_CLK_AHBCLK0_HSUSBDCKEN_Pos (10) +#define NUMAKER_CLK_AHBCLK0_HBICKEN_Pos (11) +#define NUMAKER_CLK_AHBCLK0_CRPTCKEN_Pos (12) +#define NUMAKER_CLK_AHBCLK0_KSCKEN_Pos (13) +#define NUMAKER_CLK_AHBCLK0_SPIMCKEN_Pos (14) +#define NUMAKER_CLK_AHBCLK0_FMCIDLE_Pos (15) +#define NUMAKER_CLK_AHBCLK0_USBHCKEN_Pos (16) +#define NUMAKER_CLK_AHBCLK0_SDH1CKEN_Pos (17) +#define NUMAKER_CLK_AHBCLK0_PDMA1CKEN_Pos (18) +#define NUMAKER_CLK_AHBCLK0_TRACECKEN_Pos (19) +#define NUMAKER_CLK_AHBCLK0_GPACKEN_Pos (24) +#define NUMAKER_CLK_AHBCLK0_GPBCKEN_Pos (25) +#define NUMAKER_CLK_AHBCLK0_GPCCKEN_Pos (26) +#define NUMAKER_CLK_AHBCLK0_GPDCKEN_Pos (27) +#define NUMAKER_CLK_AHBCLK0_GPECKEN_Pos (28) +#define NUMAKER_CLK_AHBCLK0_GPFCKEN_Pos (29) +#define NUMAKER_CLK_AHBCLK0_GPGCKEN_Pos (30) +#define NUMAKER_CLK_AHBCLK0_GPHCKEN_Pos (31) + +#define NUMAKER_CLK_APBCLK0_WDTCKEN_Pos (0) +#define NUMAKER_CLK_APBCLK0_RTCCKEN_Pos (1) +#define NUMAKER_CLK_APBCLK0_TMR0CKEN_Pos (2) +#define NUMAKER_CLK_APBCLK0_TMR1CKEN_Pos (3) +#define NUMAKER_CLK_APBCLK0_TMR2CKEN_Pos (4) +#define NUMAKER_CLK_APBCLK0_TMR3CKEN_Pos (5) +#define NUMAKER_CLK_APBCLK0_CLKOCKEN_Pos (6) +#define NUMAKER_CLK_APBCLK0_ACMP01CKEN_Pos (7) +#define NUMAKER_CLK_APBCLK0_I2C0CKEN_Pos (8) +#define NUMAKER_CLK_APBCLK0_I2C1CKEN_Pos (9) +#define NUMAKER_CLK_APBCLK0_I2C2CKEN_Pos (10) +#define NUMAKER_CLK_APBCLK0_I2C3CKEN_Pos (11) +#define NUMAKER_CLK_APBCLK0_QSPI0CKEN_Pos (12) +#define NUMAKER_CLK_APBCLK0_SPI0CKEN_Pos (13) +#define NUMAKER_CLK_APBCLK0_SPI1CKEN_Pos (14) +#define NUMAKER_CLK_APBCLK0_SPI2CKEN_Pos (15) +#define NUMAKER_CLK_APBCLK0_UART0CKEN_Pos (16) +#define NUMAKER_CLK_APBCLK0_UART1CKEN_Pos (17) +#define NUMAKER_CLK_APBCLK0_UART2CKEN_Pos (18) +#define NUMAKER_CLK_APBCLK0_UART3CKEN_Pos (19) +#define NUMAKER_CLK_APBCLK0_UART4CKEN_Pos (20) +#define NUMAKER_CLK_APBCLK0_UART5CKEN_Pos (21) +#define NUMAKER_CLK_APBCLK0_UART6CKEN_Pos (22) +#define NUMAKER_CLK_APBCLK0_UART7CKEN_Pos (23) +#define NUMAKER_CLK_APBCLK0_OTGCKEN_Pos (26) +#define NUMAKER_CLK_APBCLK0_USBDCKEN_Pos (27) +#define NUMAKER_CLK_APBCLK0_EADC0CKEN_Pos (28) +#define NUMAKER_CLK_APBCLK0_I2S0CKEN_Pos (29) +#define NUMAKER_CLK_APBCLK0_HSOTGCKEN_Pos (30) +#define NUMAKER_CLK_APBCLK1_SC0CKEN_Pos (0) +#define NUMAKER_CLK_APBCLK1_SC1CKEN_Pos (1) +#define NUMAKER_CLK_APBCLK1_SC2CKEN_Pos (2) +#define NUMAKER_CLK_APBCLK1_I2C4CKEN_Pos (3) +#define NUMAKER_CLK_APBCLK1_QSPI1CKEN_Pos (4) +#define NUMAKER_CLK_APBCLK1_SPI3CKEN_Pos (6) +#define NUMAKER_CLK_APBCLK1_SPI4CKEN_Pos (7) +#define NUMAKER_CLK_APBCLK1_USCI0CKEN_Pos (8) +#define NUMAKER_CLK_APBCLK1_PSIOCKEN_Pos (10) +#define NUMAKER_CLK_APBCLK1_DACCKEN_Pos (12) +#define NUMAKER_CLK_APBCLK1_ECAP2CKEN_Pos (13) +#define NUMAKER_CLK_APBCLK1_ECAP3CKEN_Pos (14) +#define NUMAKER_CLK_APBCLK1_EPWM0CKEN_Pos (16) +#define NUMAKER_CLK_APBCLK1_EPWM1CKEN_Pos (17) +#define NUMAKER_CLK_APBCLK1_BPWM0CKEN_Pos (18) +#define NUMAKER_CLK_APBCLK1_BPWM1CKEN_Pos (19) +#define NUMAKER_CLK_APBCLK1_EQEI2CKEN_Pos (20) +#define NUMAKER_CLK_APBCLK1_EQEI3CKEN_Pos (21) +#define NUMAKER_CLK_APBCLK1_EQEI0CKEN_Pos (22) +#define NUMAKER_CLK_APBCLK1_EQEI1CKEN_Pos (23) +#define NUMAKER_CLK_APBCLK1_TRNGCKEN_Pos (25) +#define NUMAKER_CLK_APBCLK1_ECAP0CKEN_Pos (26) +#define NUMAKER_CLK_APBCLK1_ECAP1CKEN_Pos (27) +#define NUMAKER_CLK_APBCLK1_I2S1CKEN_Pos (29) +#define NUMAKER_CLK_APBCLK1_EADC1CKEN_Pos (31) + +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos (0) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos (3) +#define NUMAKER_CLK_CLKSEL0_USBSEL_Pos (8) +#define NUMAKER_CLK_CLKSEL0_EADC0SEL_Pos (10) +#define NUMAKER_CLK_CLKSEL0_EADC1SEL_Pos (12) +#define NUMAKER_CLK_CLKSEL0_EADC2SEL_Pos (14) +#define NUMAKER_CLK_CLKSEL0_CCAPSEL_Pos (16) +#define NUMAKER_CLK_CLKSEL0_SDH0SEL_Pos (20) +#define NUMAKER_CLK_CLKSEL0_SDH1SEL_Pos (22) +#define NUMAKER_CLK_CLKSEL0_CANFD0SEL_Pos (24) +#define NUMAKER_CLK_CLKSEL0_CANFD1SEL_Pos (26) +#define NUMAKER_CLK_CLKSEL0_CANFD2SEL_Pos (28) +#define NUMAKER_CLK_CLKSEL0_CANFD3SEL_Pos (30) +#define NUMAKER_CLK_CLKSEL1_WDTSEL_Pos (0) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos (4) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos (8) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos (12) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos (16) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos (20) +#define NUMAKER_CLK_CLKSEL1_UART0SEL_Pos (24) +#define NUMAKER_CLK_CLKSEL1_UART1SEL_Pos (26) +#define NUMAKER_CLK_CLKSEL1_WWDTSEL_Pos (30) +#define NUMAKER_CLK_CLKSEL2_EPWM0SEL_Pos (0) +#define NUMAKER_CLK_CLKSEL2_EPWM1SEL_Pos (1) +#define NUMAKER_CLK_CLKSEL2_QSPI0SEL_Pos (2) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos (4) +#define NUMAKER_CLK_CLKSEL2_BPWM0SEL_Pos (8) +#define NUMAKER_CLK_CLKSEL2_BPWM1SEL_Pos (9) +#define NUMAKER_CLK_CLKSEL2_QSPI1SEL_Pos (10) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos (12) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos (16) +#define NUMAKER_CLK_CLKSEL2_UART8SEL_Pos (20) +#define NUMAKER_CLK_CLKSEL2_UART9SEL_Pos (22) +#define NUMAKER_CLK_CLKSEL2_TRNGSEL_Pos (27) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos (28) +#define NUMAKER_CLK_CLKSEL3_SC0SEL_Pos (0) +#define NUMAKER_CLK_CLKSEL3_SC1SEL_Pos (2) +#define NUMAKER_CLK_CLKSEL3_SC2SEL_Pos (4) +#define NUMAKER_CLK_CLKSEL3_KPISEL_Pos (6) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos (9) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos (12) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos (16) +#define NUMAKER_CLK_CLKSEL3_UART6SEL_Pos (20) +#define NUMAKER_CLK_CLKSEL3_UART7SEL_Pos (22) +#define NUMAKER_CLK_CLKSEL3_UART2SEL_Pos (24) +#define NUMAKER_CLK_CLKSEL3_UART3SEL_Pos (26) +#define NUMAKER_CLK_CLKSEL3_UART4SEL_Pos (28) +#define NUMAKER_CLK_CLKSEL3_UART5SEL_Pos (30) + +#define NUMAKER_CLK_CLKDIV0_HCLKDIV_Pos (0) +#define NUMAKER_CLK_CLKDIV0_USBDIV_Pos (4) +#define NUMAKER_CLK_CLKDIV0_UART0DIV_Pos (8) +#define NUMAKER_CLK_CLKDIV0_UART1DIV_Pos (12) +#define NUMAKER_CLK_CLKDIV0_EADC0DIV_Pos (16) +#define NUMAKER_CLK_CLKDIV0_SDH0DIV_Pos (24) +#define NUMAKER_CLK_CLKDIV1_SC0DIV_Pos (0) +#define NUMAKER_CLK_CLKDIV1_SC1DIV_Pos (8) +#define NUMAKER_CLK_CLKDIV1_SC2DIV_Pos (16) +#define NUMAKER_CLK_CLKDIV1_PSIODIV_Pos (24) +#define NUMAKER_CLK_CLKDIV2_I2S0DIV_Pos (0) +#define NUMAKER_CLK_CLKDIV2_I2S1DIV_Pos (4) +#define NUMAKER_CLK_CLKDIV2_KPIDIV_Pos (8) +#define NUMAKER_CLK_CLKDIV2_EADC1DIV_Pos (24) +#define NUMAKER_CLK_CLKDIV3_VSENSEDIV_Pos (8) +#define NUMAKER_CLK_CLKDIV3_EMAC0DIV_Pos (16) +#define NUMAKER_CLK_CLKDIV3_SDH1DIV_Pos (24) +#define NUMAKER_CLK_CLKDIV4_UART2DIV_Pos (0) +#define NUMAKER_CLK_CLKDIV4_UART3DIV_Pos (4) +#define NUMAKER_CLK_CLKDIV4_UART4DIV_Pos (8) +#define NUMAKER_CLK_CLKDIV4_UART5DIV_Pos (12) +#define NUMAKER_CLK_CLKDIV4_UART6DIV_Pos (16) +#define NUMAKER_CLK_CLKDIV4_UART7DIV_Pos (20) + +#define NUMAKER_CLK_PCLKDIV_APB0DIV_Pos (0) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_Pos (4) + +#define NUMAKER_CLK_APBCLK2_KPICKEN_Pos (0) +#define NUMAKER_CLK_APBCLK2_EADC2CKEN_Pos (6) +#define NUMAKER_CLK_APBCLK2_ACMP23CKEN_Pos (7) +#define NUMAKER_CLK_APBCLK2_SPI5CKEN_Pos (8) +#define NUMAKER_CLK_APBCLK2_SPI6CKEN_Pos (9) +#define NUMAKER_CLK_APBCLK2_SPI7CKEN_Pos (10) +#define NUMAKER_CLK_APBCLK2_SPI8CKEN_Pos (11) +#define NUMAKER_CLK_APBCLK2_SPI9CKEN_Pos (12) +#define NUMAKER_CLK_APBCLK2_SPI10CKEN_Pos (13) +#define NUMAKER_CLK_APBCLK2_UART8CKEN_Pos (16) +#define NUMAKER_CLK_APBCLK2_UART9CKEN_Pos (17) + +#define NUMAKER_CLK_CLKDIV5_CANFD0DIV_Pos (0) +#define NUMAKER_CLK_CLKDIV5_CANFD1DIV_Pos (4) +#define NUMAKER_CLK_CLKDIV5_CANFD2DIV_Pos (8) +#define NUMAKER_CLK_CLKDIV5_CANFD3DIV_Pos (12) +#define NUMAKER_CLK_CLKDIV5_UART8DIV_Pos (16) +#define NUMAKER_CLK_CLKDIV5_UART9DIV_Pos (20) +#define NUMAKER_CLK_CLKDIV5_EADC2DIV_Pos (24) + +#define NUMAKER_CLK_AHBCLK1_CANFD0CKEN_Pos (20) +#define NUMAKER_CLK_AHBCLK1_CANFD1CKEN_Pos (21) +#define NUMAKER_CLK_AHBCLK1_CANFD2CKEN_Pos (22) +#define NUMAKER_CLK_AHBCLK1_CANFD3CKEN_Pos (23) +#define NUMAKER_CLK_AHBCLK1_GPICKEN_Pos (24) +#define NUMAKER_CLK_AHBCLK1_GPJCKEN_Pos (25) +#define NUMAKER_CLK_AHBCLK1_BMCCKEN_Pos (28) + +#define NUMAKER_CLK_CLKSEL4_SPI4SEL_Pos (0) +#define NUMAKER_CLK_CLKSEL4_SPI5SEL_Pos (4) +#define NUMAKER_CLK_CLKSEL4_SPI6SEL_Pos (8) +#define NUMAKER_CLK_CLKSEL4_SPI7SEL_Pos (12) +#define NUMAKER_CLK_CLKSEL4_SPI8SEL_Pos (16) +#define NUMAKER_CLK_CLKSEL4_SPI9SEL_Pos (20) +#define NUMAKER_CLK_CLKSEL4_SPI10SEL_Pos (24) + +/* End of M460 BSP clk_reg.h copy */ + +/* Beginning of M460 BSP clk.h copy */ + +/* CLKSEL0 constant definitions. (Write-protection) */ + +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_PLL (0x2UL << NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_LIRC (0x3UL << NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_HCLKSEL_HIRC (0x7UL << NUMAKER_CLK_CLKSEL0_HCLKSEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_HXT_DIV2 (0x2UL << NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_HCLK_DIV2 (0x3UL << NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_HIRC_DIV2 (0x7UL << NUMAKER_CLK_CLKSEL0_STCLKSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_STCLKSEL_HCLK (0x1UL << SysTick_CTRL_CLKSOURCE_Pos) + +#define NUMAKER_CLK_CLKSEL0_USBSEL_HIRC48M (0x0UL << NUMAKER_CLK_CLKSEL0_USBSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_USBSEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_USBSEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_EADC0SEL_PLLFN_DIV2 (0x0UL << NUMAKER_CLK_CLKSEL0_EADC0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_EADC0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC0SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_EADC0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_EADC1SEL_PLLFN_DIV2 (0x0UL << NUMAKER_CLK_CLKSEL0_EADC1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_EADC1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC1SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_EADC1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_EADC2SEL_PLLFN_DIV2 (0x0UL << NUMAKER_CLK_CLKSEL0_EADC2SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC2SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_EADC2SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_EADC2SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_EADC2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_CCAPSEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_CCAPSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CCAPSEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_CCAPSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CCAPSEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_CCAPSEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CCAPSEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_CCAPSEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_SDH0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_SDH0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_SDH0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH0SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_SDH0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_SDH0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_SDH1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_SDH1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_SDH1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH1SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_SDH1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_SDH1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_SDH1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_CANFD0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_CANFD0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_CANFD0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD0SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_CANFD0SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_CANFD0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_CANFD1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_CANFD1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_CANFD1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD1SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_CANFD1SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_CANFD1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_CANFD2SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_CANFD2SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD2SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_CANFD2SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD2SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_CANFD2SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD2SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_CANFD2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL0_CANFD3SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL0_CANFD3SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD3SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL0_CANFD3SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD3SEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL0_CANFD3SEL_Pos) +#define NUMAKER_CLK_CLKSEL0_CANFD3SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL0_CANFD3SEL_Pos) + +/* CLKSEL1 constant definitions. */ + +#define NUMAKER_CLK_CLKSEL1_WDTSEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_WDTSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_WDTSEL_HCLK_DIV2048 (0x2UL << NUMAKER_CLK_CLKSEL1_WDTSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_WDTSEL_LIRC (0x3UL << NUMAKER_CLK_CLKSEL1_WDTSEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_HCLK (0x2UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_LIRC (0x4UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_CLKOSEL_PLL_DIV2 (0x6UL << NUMAKER_CLK_CLKSEL1_CLKOSEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_EXT (0x3UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_LIRC (0x5UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR0SEL_HIRC (0x7UL << NUMAKER_CLK_CLKSEL1_TMR0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_EXT (0x3UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_LIRC (0x5UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR1SEL_HIRC (0x7UL << NUMAKER_CLK_CLKSEL1_TMR1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_EXT (0x3UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_LIRC (0x5UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR2SEL_HIRC (0x7UL << NUMAKER_CLK_CLKSEL1_TMR2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_EXT (0x3UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_LIRC (0x5UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_TMR3SEL_HIRC (0x7UL << NUMAKER_CLK_CLKSEL1_TMR3SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_UART0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_UART0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL1_UART0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART0SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL1_UART0SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL1_UART0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_UART1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL1_UART1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL1_UART1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART1SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL1_UART1SEL_Pos) +#define NUMAKER_CLK_CLKSEL1_UART1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL1_UART1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL1_WWDTSEL_HCLK_DIV2048 (0x2UL << NUMAKER_CLK_CLKSEL1_WWDTSEL_Pos) +#define NUMAKER_CLK_CLKSEL1_WWDTSEL_LIRC (0x3UL << NUMAKER_CLK_CLKSEL1_WWDTSEL_Pos) + +/* CLKSEL2 constant definitions. */ + +#define NUMAKER_CLK_CLKSEL2_EPWM0SEL_HCLK (0x0UL << NUMAKER_CLK_CLKSEL2_EPWM0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_EPWM0SEL_PCLK0 (0x1UL << NUMAKER_CLK_CLKSEL2_EPWM0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_EPWM1SEL_HCLK (0x0UL << NUMAKER_CLK_CLKSEL2_EPWM1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_EPWM1SEL_PCLK1 (0x1UL << NUMAKER_CLK_CLKSEL2_EPWM1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_QSPI0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_QSPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_QSPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI0SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL2_QSPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_QSPI0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI0SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL2_SPI0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_BPWM0SEL_HCLK (0x0UL << NUMAKER_CLK_CLKSEL2_BPWM0SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_BPWM0SEL_PCLK0 (0x1UL << NUMAKER_CLK_CLKSEL2_BPWM0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_BPWM1SEL_HCLK (0x0UL << NUMAKER_CLK_CLKSEL2_BPWM1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_BPWM1SEL_PCLK1 (0x1UL << NUMAKER_CLK_CLKSEL2_BPWM1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_QSPI1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_QSPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_QSPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI1SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL2_QSPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_QSPI1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_QSPI1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_SPI1SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL2_SPI1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_I2S1SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL2_I2S1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_UART8SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_UART8SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART8SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_UART8SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART8SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL2_UART8SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART8SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_UART8SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_UART9SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_UART9SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART9SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL2_UART9SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART9SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL2_UART9SEL_Pos) +#define NUMAKER_CLK_CLKSEL2_UART9SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL2_UART9SEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_TRNGSEL_LXT (0x0UL << NUMAKER_CLK_CLKSEL2_TRNGSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_TRNGSEL_LIRC (0x1UL << NUMAKER_CLK_CLKSEL2_TRNGSEL_Pos) + +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_LXT (0x1UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_PLL_DIV2 (0x3UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_LIRC (0x4UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) +#define NUMAKER_CLK_CLKSEL2_PSIOSEL_HIRC (0x5UL << NUMAKER_CLK_CLKSEL2_PSIOSEL_Pos) + +/* CLKSEL3 constant definitions. */ + +#define NUMAKER_CLK_CLKSEL3_SC0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_SC0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_SC0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC0SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL3_SC0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_SC0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_SC1SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_SC1SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC1SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_SC1SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC1SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL3_SC1SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC1SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_SC1SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_SC2SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_SC2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC2SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_SC2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC2SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL3_SC2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SC2SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_SC2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_KPISEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_KPISEL_Pos) +#define NUMAKER_CLK_CLKSEL3_KPISEL_LIRC (0x1UL << NUMAKER_CLK_CLKSEL3_KPISEL_Pos) +#define NUMAKER_CLK_CLKSEL3_KPISEL_HIRC (0x2UL << NUMAKER_CLK_CLKSEL3_KPISEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI2SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL3_SPI2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_SPI3SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL3_SPI3SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_HIRC48M (0x4UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_I2S0SEL_PLLFN_DIV2 (0x5UL << NUMAKER_CLK_CLKSEL3_I2S0SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART6SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART6SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART6SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART6SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART6SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART6SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART6SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART6SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART7SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART7SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART7SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART7SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART7SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART7SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART7SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART7SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART2SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART2SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART2SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART2SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART2SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART2SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART3SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART3SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART3SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART3SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART3SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART3SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART4SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART4SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART4SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART4SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART4SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART4SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART4SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART4SEL_Pos) + +#define NUMAKER_CLK_CLKSEL3_UART5SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL3_UART5SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART5SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL3_UART5SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART5SEL_LXT (0x2UL << NUMAKER_CLK_CLKSEL3_UART5SEL_Pos) +#define NUMAKER_CLK_CLKSEL3_UART5SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL3_UART5SEL_Pos) + +/* CLKSEL4 constant definitions. */ + +#define NUMAKER_CLK_CLKSEL4_SPI4SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI4SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI4SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI4SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI4SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI4SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI4SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI4SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI5SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI5SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI5SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI5SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI5SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI5SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI5SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI5SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI6SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI6SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI6SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI6SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI6SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI6SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI6SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI6SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI7SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI7SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI7SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI7SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI7SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI7SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI7SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI7SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI8SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI8SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI8SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI8SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI8SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI8SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI8SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI8SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI9SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI9SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI9SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI9SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI9SEL_PCLK0 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI9SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI9SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI9SEL_Pos) + +#define NUMAKER_CLK_CLKSEL4_SPI10SEL_HXT (0x0UL << NUMAKER_CLK_CLKSEL4_SPI10SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI10SEL_PLL_DIV2 (0x1UL << NUMAKER_CLK_CLKSEL4_SPI10SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI10SEL_PCLK1 (0x2UL << NUMAKER_CLK_CLKSEL4_SPI10SEL_Pos) +#define NUMAKER_CLK_CLKSEL4_SPI10SEL_HIRC (0x3UL << NUMAKER_CLK_CLKSEL4_SPI10SEL_Pos) + +/* CLKDIV0 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV0_HCLK(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_HCLKDIV_Pos) +#define NUMAKER_CLK_CLKDIV0_USB(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_USBDIV_Pos) +#define NUMAKER_CLK_CLKDIV0_SDH0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_SDH0DIV_Pos) +#define NUMAKER_CLK_CLKDIV0_UART0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_UART0DIV_Pos) +#define NUMAKER_CLK_CLKDIV0_UART1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_UART1DIV_Pos) +#define NUMAKER_CLK_CLKDIV0_EADC0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV0_EADC0DIV_Pos) + +/* CLKDIV1 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV1_SC0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV1_SC0DIV_Pos) +#define NUMAKER_CLK_CLKDIV1_SC1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV1_SC1DIV_Pos) +#define NUMAKER_CLK_CLKDIV1_SC2(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV1_SC2DIV_Pos) +#define NUMAKER_CLK_CLKDIV1_PSIO(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV1_PSIODIV_Pos) + +/* CLKDIV2 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV2_I2S0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV2_I2S0DIV_Pos) +#define NUMAKER_CLK_CLKDIV2_I2S1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV2_I2S1DIV_Pos) +#define NUMAKER_CLK_CLKDIV2_KPI(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV2_KPIDIV_Pos) +#define NUMAKER_CLK_CLKDIV2_EADC1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV2_EADC1DIV_Pos) + +/* CLKDIV3 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV3_VSENSE(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV3_VSENSEDIV_Pos) +#define NUMAKER_CLK_CLKDIV3_EMAC0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV3_EMAC0DIV_Pos) +#define NUMAKER_CLK_CLKDIV3_SDH1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV3_SDH1DIV_Pos) + +/* CLKDIV4 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV4_UART2(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART2DIV_Pos) +#define NUMAKER_CLK_CLKDIV4_UART3(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART3DIV_Pos) +#define NUMAKER_CLK_CLKDIV4_UART4(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART4DIV_Pos) +#define NUMAKER_CLK_CLKDIV4_UART5(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART5DIV_Pos) +#define NUMAKER_CLK_CLKDIV4_UART6(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART6DIV_Pos) +#define NUMAKER_CLK_CLKDIV4_UART7(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV4_UART7DIV_Pos) + +/* CLKDIV5 constant definitions. */ + +#define NUMAKER_CLK_CLKDIV5_CANFD0(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_CANFD0DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_CANFD1(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_CANFD1DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_CANFD2(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_CANFD2DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_CANFD3(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_CANFD3DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_UART8(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_UART8DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_UART9(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_UART9DIV_Pos) +#define NUMAKER_CLK_CLKDIV5_EADC2(x) (((x)-1UL) << NUMAKER_CLK_CLKDIV5_EADC2DIV_Pos) + +/* PCLKDIV constant definitions. */ + +#define NUMAKER_CLK_PCLKDIV_PCLK0DIV1 (0x0UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK0DIV2 (0x1UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK0DIV4 (0x2UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK0DIV8 (0x3UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK0DIV16 (0x4UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK1DIV1 (0x0UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK1DIV2 (0x1UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK1DIV4 (0x2UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK1DIV8 (0x3UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_PCLK1DIV16 (0x4UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) + +#define NUMAKER_CLK_PCLKDIV_APB0DIV_DIV1 (0x0UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB0DIV_DIV2 (0x1UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB0DIV_DIV4 (0x2UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB0DIV_DIV8 (0x3UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB0DIV_DIV16 (0x4UL << NUMAKER_CLK_PCLKDIV_APB0DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_DIV1 (0x0UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_DIV2 (0x1UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_DIV4 (0x2UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_DIV8 (0x3UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) +#define NUMAKER_CLK_PCLKDIV_APB1DIV_DIV16 (0x4UL << NUMAKER_CLK_PCLKDIV_APB1DIV_Pos) + +/* MODULE constant definitions. */ + +/* + * APBCLK(31:29)|CLKSEL(28:26)|CLKSEL_Msk(25:22)|CLKSEL_Pos(21:17)|CLKDIV(16:14)| + * CLKDIV_Msk(13:10)|CLKDIV_Pos(9:5)|IP_EN_Pos(4:0) + */ + +#define NUMAKER_MODULE_NoMsk 0x0UL +#define NUMAKER_NA NUMAKER_MODULE_NoMsk + +#define NUMAKER_MODULE_APBCLK_ENC(x) (((x)&0x07UL) << 29) +#define NUMAKER_MODULE_CLKSEL_ENC(x) (((x)&0x07UL) << 26) +#define NUMAKER_MODULE_CLKSEL_Msk_ENC(x) (((x)&0x0fUL) << 22) +#define NUMAKER_MODULE_CLKSEL_Pos_ENC(x) (((x)&0x1fUL) << 17) +#define NUMAKER_MODULE_CLKDIV_ENC(x) (((x)&0x07UL) << 14) +#define NUMAKER_MODULE_CLKDIV_Msk_ENC(x) (((x)&0x0fUL) << 10) +#define NUMAKER_MODULE_CLKDIV_Pos_ENC(x) (((x)&0x1fUL) << 5) +#define NUMAKER_MODULE_IP_EN_Pos_ENC(x) (((x)&0x1fUL) << 0) + +/* AHBCLK0 */ +#define NUMAKER_PDMA0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_PDMA0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ISP_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_ISPCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EBI_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_EBICKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ST_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_STCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EMAC0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_EMAC0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(3UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(16UL)) + +#define NUMAKER_SDH0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_SDH0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(20UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(24UL)) + +#define NUMAKER_CRC_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_CRCCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_CCAP_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_CCAPCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SEN_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_SENCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(16UL) | NUMAKER_MODULE_CLKDIV_ENC(3UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_HSUSBD_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_HSUSBDCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_HBI_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_HBICKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_CRPT_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_CRPTCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_KS_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_KSCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPIM_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_SPIMCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_FMCIDLE_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_FMCIDLE_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_USBH_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_USBHCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0xFUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_SDH1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_SDH1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(22UL) | NUMAKER_MODULE_CLKDIV_ENC(3UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(24UL)) + +#define NUMAKER_PDMA1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_PDMA1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TRACE_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_TRACECKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPA_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPACKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPB_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPBCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPC_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPCCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPD_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPDCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPE_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPECKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPF_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPFCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPG_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPGCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPH_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(0UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK0_GPHCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +/* AHBCLK1 */ +#define NUMAKER_CANFD0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_CANFD0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(24UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(0UL)) + +#define NUMAKER_CANFD1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_CANFD1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(26UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_CANFD2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_CANFD2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(28UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_CANFD3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_CANFD3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(30UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(12UL)) + +#define NUMAKER_GPI_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_GPICKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_GPJ_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_GPJCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_BMC_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(4UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_AHBCLK1_BMCCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +/* APBCLK0 */ +#define NUMAKER_WDT_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_WDTCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(0UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_WWDT_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_WDTCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(30UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_RTC_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_RTCCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TMR0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_TMR0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TMR1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_TMR1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(12UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TMR2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_TMR2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(16UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TMR3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_TMR3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(20UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_CLKO_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_CLKOCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(4UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ACMP01_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_ACMP01CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_I2C0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_I2C0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_I2C1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_I2C1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_I2C2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_I2C2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_I2C3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_I2C3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_QSPI0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_QSPI0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(2UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_SPI0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(4UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_SPI1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(12UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_SPI2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(9UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_UART0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(24UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_UART1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(1UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(26UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(12UL)) + +#define NUMAKER_UART2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(24UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(0UL)) + +#define NUMAKER_UART3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(26UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_UART4_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART4CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(28UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_UART5_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART5CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(30UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(12UL)) + +#define NUMAKER_UART6_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART6CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(20UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(16UL)) + +#define NUMAKER_UART7_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_UART7CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(22UL) | NUMAKER_MODULE_CLKDIV_ENC(4UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(20UL)) + +#define NUMAKER_OTG_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_OTGCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0xFUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_USBD_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_USBDCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0xFUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_EADC0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_EADC0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(10UL) | NUMAKER_MODULE_CLKDIV_ENC(0UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(16UL)) + +#define NUMAKER_I2S0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_I2S0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(16UL) | NUMAKER_MODULE_CLKDIV_ENC(2UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(0UL)) + +#define NUMAKER_HSOTG_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(1UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK0_HSOTGCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +/* APBCLK1 */ +#define NUMAKER_SC0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_SC0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(0UL) | NUMAKER_MODULE_CLKDIV_ENC(1UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(0UL)) + +#define NUMAKER_SC1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_SC1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(2UL) | NUMAKER_MODULE_CLKDIV_ENC(1UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_SC2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_SC2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(4UL) | NUMAKER_MODULE_CLKDIV_ENC(1UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(16UL)) + +#define NUMAKER_I2C4_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_I2C4CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_QSPI1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_QSPI1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(10UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_SPI3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(12UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI4_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_SPI4CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(0UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_USCI0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_USCI0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_PSIO_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_PSIOCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(28UL) | NUMAKER_MODULE_CLKDIV_ENC(1UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(24UL)) + +#define NUMAKER_DAC_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_DACCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ECAP2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_ECAP2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ECAP3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_ECAP3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EPWM0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EPWM0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(0UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EPWM1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EPWM1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(1UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_BPWM0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_BPWM0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_BPWM1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_BPWM1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(9UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EQEI0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EQEI0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EQEI1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EQEI1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EQEI2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EQEI2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_EQEI3_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EQEI3CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_TRNG_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_TRNGCKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(1UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(27UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ECAP0_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_ECAP0CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_ECAP1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_ECAP1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_I2S1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_I2S1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(16UL) | NUMAKER_MODULE_CLKDIV_ENC(2UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(4UL)) + +#define NUMAKER_EADC1_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(2UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK1_EADC1CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(12UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +/* APBCLK2 */ +#define NUMAKER_KPI_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_KPICKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(3UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(6UL) | NUMAKER_MODULE_CLKDIV_ENC(2UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(8UL)) + +#define NUMAKER_EADC2_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_EADC2CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(0UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(14UL) | NUMAKER_MODULE_CLKDIV_ENC(2UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(24UL)) + +#define NUMAKER_ACMP23_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_ACMP23CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKSEL_Msk_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI5_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI5CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(4UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI6_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI6CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(8UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI7_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI7CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(12UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI8_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI8CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(16UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI9_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI9CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(20UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_SPI10_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_SPI10CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(4UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(7UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(24UL) | NUMAKER_MODULE_CLKDIV_ENC(NUMAKER_NA) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(NUMAKER_NA) | NUMAKER_MODULE_CLKDIV_Pos_ENC(NUMAKER_NA)) + +#define NUMAKER_UART8_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_UART8CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(20UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(16UL)) + +#define NUMAKER_UART9_MODULE \ + (NUMAKER_MODULE_APBCLK_ENC(3UL) | \ + NUMAKER_MODULE_IP_EN_Pos_ENC(NUMAKER_CLK_APBCLK2_UART9CKEN_Pos) | \ + NUMAKER_MODULE_CLKSEL_ENC(2UL) | NUMAKER_MODULE_CLKSEL_Msk_ENC(3UL) | \ + NUMAKER_MODULE_CLKSEL_Pos_ENC(22UL) | NUMAKER_MODULE_CLKDIV_ENC(5UL) | \ + NUMAKER_MODULE_CLKDIV_Msk_ENC(0x0FUL) | NUMAKER_MODULE_CLKDIV_Pos_ENC(20UL)) + +/* End of M460 BSP clk.h copy */ + +#endif diff --git a/soc/arm/nuvoton_numaker/m46x/soc.c b/soc/arm/nuvoton_numaker/m46x/soc.c index 5637007495c0..f19931265243 100644 --- a/soc/arm/nuvoton_numaker/m46x/soc.c +++ b/soc/arm/nuvoton_numaker/m46x/soc.c @@ -5,6 +5,7 @@ */ #include +#include /* Hardware and starter kit includes. */ #include @@ -21,13 +22,27 @@ void z_arm_platform_init(void) * ------------------- */ - CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk); - /* Wait for HXT clock ready */ - CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hxt) + /* Enable/disable 4~24 MHz external crystal oscillator (HXT) */ + if (DT_ENUM_IDX(DT_NODELABEL(scc), hxt) == NUMAKER_SCC_CLKSW_ENABLE) { + CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk); + /* Wait for HXT clock ready */ + CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk); + } else if (DT_ENUM_IDX(DT_NODELABEL(scc), hxt) == NUMAKER_SCC_CLKSW_DISABLE) { + CLK_DisableXtalRC(CLK_PWRCTL_HXTEN_Msk); + } +#endif - CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk); - /* Wait for LXT clock ready */ - CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), lxt) + /* Enable/disable 32.768 kHz low-speed external crystal oscillator (LXT) */ + if (DT_ENUM_IDX(DT_NODELABEL(scc), lxt) == NUMAKER_SCC_CLKSW_ENABLE) { + CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk); + /* Wait for LXT clock ready */ + CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk); + } else if (DT_ENUM_IDX(DT_NODELABEL(scc), lxt) == NUMAKER_SCC_CLKSW_DISABLE) { + CLK_DisableXtalRC(CLK_PWRCTL_LXTEN_Msk); + } +#endif /* Enable 12 MHz high-speed internal RC oscillator (HIRC) */ CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk); @@ -39,15 +54,26 @@ void z_arm_platform_init(void) /* Wait for LIRC clock ready */ CLK_WaitClockReady(CLK_STATUS_LIRCSTB_Msk); - CLK_EnableXtalRC(CLK_PWRCTL_HIRC48EN_Msk); - /* Wait for HIRC48 clock ready */ - CLK_WaitClockReady(CLK_STATUS_HIRC48STB_Msk); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), hirc48) + /* Enable/disable 48 MHz high-speed internal RC oscillator (HIRC48) */ + if (DT_ENUM_IDX(DT_NODELABEL(scc), hirc48) == NUMAKER_SCC_CLKSW_ENABLE) { + CLK_EnableXtalRC(CLK_PWRCTL_HIRC48EN_Msk); + /* Wait for HIRC48 clock ready */ + CLK_WaitClockReady(CLK_STATUS_HIRC48STB_Msk); + } else if (DT_ENUM_IDX(DT_NODELABEL(scc), hirc48) == NUMAKER_SCC_CLKSW_DISABLE) { + CLK_DisableXtalRC(CLK_PWRCTL_HIRC48EN_Msk); + } +#endif - /* Set PCLK0 and PCLK1 to HCLK/2 */ - CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), clk_pclkdiv) + /* Set CLK_PCLKDIV register on request */ + CLK->PCLKDIV = DT_PROP(DT_NODELABEL(scc), clk_pclkdiv); +#endif - /* Set core clock to 200MHz */ - CLK_SetCoreClock(200000000); +#if DT_NODE_HAS_PROP(DT_NODELABEL(scc), core_clock) + /* Set core clock (HCLK) on request */ + CLK_SetCoreClock(DT_PROP(DT_NODELABEL(scc), core_clock)); +#endif /* * Update System Core Clock From c448dceb5750909e05b9c686df804ccf10f36243 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Mon, 10 Apr 2023 19:53:23 +0800 Subject: [PATCH 0432/2042] drivers: reset: add support for NuMaker series reset Add Nuvoton numaker series reset controller support. Signed-off-by: cyliang tw --- drivers/reset/CMakeLists.txt | 1 + drivers/reset/Kconfig | 1 + drivers/reset/Kconfig.numaker | 11 + drivers/reset/reset_numaker.c | 74 +++++ dts/arm/nuvoton/m46x.dtsi | 8 + dts/bindings/reset/nuvoton,numaker-rst.yaml | 18 ++ .../dt-bindings/reset/numaker_m46x_reset.h | 271 ++++++++++++++++++ soc/arm/nuvoton_numaker/Kconfig.defconfig | 3 + 8 files changed, 387 insertions(+) create mode 100644 drivers/reset/Kconfig.numaker create mode 100644 drivers/reset/reset_numaker.c create mode 100644 dts/bindings/reset/nuvoton,numaker-rst.yaml create mode 100644 include/zephyr/dt-bindings/reset/numaker_m46x_reset.h diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index d65dd5a5e95c..3dc29327cd63 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library_sources_ifdef(CONFIG_RESET_GD32 reset_gd32.c) zephyr_library_sources_ifdef(CONFIG_RESET_RPI_PICO reset_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_RESET_AST10X0 reset_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_RESET_STM32 reset_stm32.c) +zephyr_library_sources_ifdef(CONFIG_RESET_NUMAKER reset_numaker.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 063eccde7c44..719b57f0748b 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -31,5 +31,6 @@ rsource "Kconfig.rpi_pico" rsource "Kconfig.gd32" rsource "Kconfig.aspeed" rsource "Kconfig.stm32" +rsource "Kconfig.numaker" endif # RESET diff --git a/drivers/reset/Kconfig.numaker b/drivers/reset/Kconfig.numaker new file mode 100644 index 000000000000..0a8785f7dabf --- /dev/null +++ b/drivers/reset/Kconfig.numaker @@ -0,0 +1,11 @@ +# Nuvoton NuMaker Reset Controller configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config RESET_NUMAKER + bool "Nuvoton NuMaker reset controller driver" + default y + depends on DT_HAS_NUVOTON_NUMAKER_RST_ENABLED + help + This option enables the reset controller driver for Nuvoton NuMaker MCUs. diff --git a/drivers/reset/reset_numaker.c b/drivers/reset/reset_numaker.c new file mode 100644 index 000000000000..f1e875c78d03 --- /dev/null +++ b/drivers/reset/reset_numaker.c @@ -0,0 +1,74 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Nuvoton Technology Corporation. + */ + +#define DT_DRV_COMPAT nuvoton_numaker_rst + +#include +#include +#include +#include + +/* Reset controller module IPRST offset */ +#define NUMAKER_RESET_IPRST0_OFFSET (8UL) +#define NUMAKER_RESET_IP_OFFSET(id) (NUMAKER_RESET_IPRST0_OFFSET + (((id) >> 24UL) & 0xffUL)) +/* Reset controller module configuration bit */ +#define NUMAKER_RESET_IP_BIT(id) (id & 0x00ffffffUL) + +struct reset_numaker_config { + uint32_t base; +}; + +static int reset_numaker_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const struct reset_numaker_config *config = dev->config; + + *status = !!sys_test_bit(config->base + NUMAKER_RESET_IP_OFFSET(id), + NUMAKER_RESET_IP_BIT(id)); + + return 0; +} + +static int reset_numaker_line_assert(const struct device *dev, uint32_t id) +{ + const struct reset_numaker_config *config = dev->config; + + /* Generate reset signal to the corresponding module */ + sys_set_bit(config->base + NUMAKER_RESET_IP_OFFSET(id), NUMAKER_RESET_IP_BIT(id)); + + return 0; +} + +static int reset_numaker_line_deassert(const struct device *dev, uint32_t id) +{ + const struct reset_numaker_config *config = dev->config; + + /* Release corresponding module from reset state */ + sys_clear_bit(config->base + NUMAKER_RESET_IP_OFFSET(id), NUMAKER_RESET_IP_BIT(id)); + + return 0; +} + +static int reset_numaker_line_toggle(const struct device *dev, uint32_t id) +{ + (void)reset_numaker_line_assert(dev, id); + (void)reset_numaker_line_deassert(dev, id); + + return 0; +} + +static const struct reset_driver_api reset_numaker_driver_api = { + .status = reset_numaker_status, + .line_assert = reset_numaker_line_assert, + .line_deassert = reset_numaker_line_deassert, + .line_toggle = reset_numaker_line_toggle, +}; + +static const struct reset_numaker_config config = { + .base = (uint32_t)DT_INST_REG_ADDR(0), +}; + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, &config, PRE_KERNEL_1, + CONFIG_RESET_INIT_PRIORITY, &reset_numaker_driver_api); diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index a404020b185e..fef99818efba 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { cpus { @@ -56,6 +57,13 @@ }; }; + rst: reset-controller@40000000 { + compatible = "nuvoton,numaker-rst"; + reg = <0x40000000 0x20>; + #reset-cells = <1>; + status = "okay"; + }; + pinctrl: pin-controller@40000500 { compatible = "nuvoton,numaker-pinctrl"; reg = <0x40000500 0xa0>; diff --git a/dts/bindings/reset/nuvoton,numaker-rst.yaml b/dts/bindings/reset/nuvoton,numaker-rst.yaml new file mode 100644 index 000000000000..298a48fe955b --- /dev/null +++ b/dts/bindings/reset/nuvoton,numaker-rst.yaml @@ -0,0 +1,18 @@ +# (c) Nuvoton Technology Corp. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, Numaker-RESET + +compatible: "nuvoton,numaker-rst" + +include: [reset-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#reset-cells": + const: 1 + +reset-cells: +- id diff --git a/include/zephyr/dt-bindings/reset/numaker_m46x_reset.h b/include/zephyr/dt-bindings/reset/numaker_m46x_reset.h new file mode 100644 index 000000000000..6d026ce112a7 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/numaker_m46x_reset.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NUMAKER_M46X_RESET_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_NUMAKER_M46X_RESET_H + +/* Beginning of M460 BSP sys_reg.h reset module copy */ + +#define NUMAKER_SYS_IPRST0_PDMA0RST_Pos (2) + +#define NUMAKER_SYS_IPRST0_EBIRST_Pos (3) + +#define NUMAKER_SYS_IPRST0_EMAC0RST_Pos (5) + +#define NUMAKER_SYS_IPRST0_SDH0RST_Pos (6) + +#define NUMAKER_SYS_IPRST0_CRCRST_Pos (7) + +#define NUMAKER_SYS_IPRST0_CCAPRST_Pos (8) + +#define NUMAKER_SYS_IPRST0_HSUSBDRST_Pos (10) + +#define NUMAKER_SYS_IPRST0_HBIRST_Pos (11) + +#define NUMAKER_SYS_IPRST0_CRPTRST_Pos (12) + +#define NUMAKER_SYS_IPRST0_KSRST_Pos (13) + +#define NUMAKER_SYS_IPRST0_SPIMRST_Pos (14) + +#define NUMAKER_SYS_IPRST0_HSUSBHRST_Pos (16) + +#define NUMAKER_SYS_IPRST0_SDH1RST_Pos (17) + +#define NUMAKER_SYS_IPRST0_PDMA1RST_Pos (18) + +#define NUMAKER_SYS_IPRST0_CANFD0RST_Pos (20) + +#define NUMAKER_SYS_IPRST0_CANFD1RST_Pos (21) + +#define NUMAKER_SYS_IPRST0_CANFD2RST_Pos (22) + +#define NUMAKER_SYS_IPRST0_CANFD3RST_Pos (23) + +#define NUMAKER_SYS_IPRST0_BMCRST_Pos (28) + +#define NUMAKER_SYS_IPRST1_GPIORST_Pos (1) + +#define NUMAKER_SYS_IPRST1_TMR0RST_Pos (2) + +#define NUMAKER_SYS_IPRST1_TMR1RST_Pos (3) + +#define NUMAKER_SYS_IPRST1_TMR2RST_Pos (4) + +#define NUMAKER_SYS_IPRST1_TMR3RST_Pos (5) + +#define NUMAKER_SYS_IPRST1_ACMP01RST_Pos (7) + +#define NUMAKER_SYS_IPRST1_I2C0RST_Pos (8) + +#define NUMAKER_SYS_IPRST1_I2C1RST_Pos (9) + +#define NUMAKER_SYS_IPRST1_I2C2RST_Pos (10) + +#define NUMAKER_SYS_IPRST1_I2C3RST_Pos (11) + +#define NUMAKER_SYS_IPRST1_QSPI0RST_Pos (12) + +#define NUMAKER_SYS_IPRST1_SPI0RST_Pos (13) + +#define NUMAKER_SYS_IPRST1_SPI1RST_Pos (14) + +#define NUMAKER_SYS_IPRST1_SPI2RST_Pos (15) + +#define NUMAKER_SYS_IPRST1_UART0RST_Pos (16) + +#define NUMAKER_SYS_IPRST1_UART1RST_Pos (17) + +#define NUMAKER_SYS_IPRST1_UART2RST_Pos (18) + +#define NUMAKER_SYS_IPRST1_UART3RST_Pos (19) + +#define NUMAKER_SYS_IPRST1_UART4RST_Pos (20) + +#define NUMAKER_SYS_IPRST1_UART5RST_Pos (21) + +#define NUMAKER_SYS_IPRST1_UART6RST_Pos (22) + +#define NUMAKER_SYS_IPRST1_UART7RST_Pos (23) + +#define NUMAKER_SYS_IPRST1_OTGRST_Pos (26) + +#define NUMAKER_SYS_IPRST1_USBDRST_Pos (27) + +#define NUMAKER_SYS_IPRST1_EADC0RST_Pos (28) + +#define NUMAKER_SYS_IPRST1_I2S0RST_Pos (29) + +#define NUMAKER_SYS_IPRST1_HSOTGRST_Pos (30) + +#define NUMAKER_SYS_IPRST1_TRNGRST_Pos (31) + +#define NUMAKER_SYS_IPRST2_SC0RST_Pos (0) + +#define NUMAKER_SYS_IPRST2_SC1RST_Pos (1) + +#define NUMAKER_SYS_IPRST2_SC2RST_Pos (2) + +#define NUMAKER_SYS_IPRST2_I2C4RST_Pos (3) + +#define NUMAKER_SYS_IPRST2_QSPI1RST_Pos (4) + +#define NUMAKER_SYS_IPRST2_SPI3RST_Pos (6) + +#define NUMAKER_SYS_IPRST2_SPI4RST_Pos (7) + +#define NUMAKER_SYS_IPRST2_USCI0RST_Pos (8) + +#define NUMAKER_SYS_IPRST2_PSIORST_Pos (10) + +#define NUMAKER_SYS_IPRST2_DACRST_Pos (12) + +#define NUMAKER_SYS_IPRST2_ECAP2RST_Pos (13) + +#define NUMAKER_SYS_IPRST2_ECAP3RST_Pos (14) + +#define NUMAKER_SYS_IPRST2_EPWM0RST_Pos (16) + +#define NUMAKER_SYS_IPRST2_EPWM1RST_Pos (17) + +#define NUMAKER_SYS_IPRST2_BPWM0RST_Pos (18) + +#define NUMAKER_SYS_IPRST2_BPWM1RST_Pos (19) + +#define NUMAKER_SYS_IPRST2_EQEI2RST_Pos (20) + +#define NUMAKER_SYS_IPRST2_EQEI3RST_Pos (21) + +#define NUMAKER_SYS_IPRST2_EQEI0RST_Pos (22) + +#define NUMAKER_SYS_IPRST2_EQEI1RST_Pos (23) + +#define NUMAKER_SYS_IPRST2_ECAP0RST_Pos (26) + +#define NUMAKER_SYS_IPRST2_ECAP1RST_Pos (27) + +#define NUMAKER_SYS_IPRST2_I2S1RST_Pos (29) + +#define NUMAKER_SYS_IPRST2_EADC1RST_Pos (31) + +#define NUMAKER_SYS_IPRST3_KPIRST_Pos (0) + +#define NUMAKER_SYS_IPRST3_EADC2RST_Pos (6) + +#define NUMAKER_SYS_IPRST3_ACMP23RST_Pos (7) + +#define NUMAKER_SYS_IPRST3_SPI5RST_Pos (8) + +#define NUMAKER_SYS_IPRST3_SPI6RST_Pos (9) + +#define NUMAKER_SYS_IPRST3_SPI7RST_Pos (10) + +#define NUMAKER_SYS_IPRST3_SPI8RST_Pos (11) + +#define NUMAKER_SYS_IPRST3_SPI9RST_Pos (12) + +#define NUMAKER_SYS_IPRST3_SPI10RST_Pos (13) + +#define NUMAKER_SYS_IPRST3_UART8RST_Pos (16) + +#define NUMAKER_SYS_IPRST3_UART9RST_Pos (17) + +/* End of M460 BSP sys_reg.h reset module copy */ + +/* Beginning of M460 BSP sys.h reset module copy */ + +/*--------------------------------------------------------------------- + * Module Reset Control Resister constant definitions. + *--------------------------------------------------------------------- + */ +#define NUMAKER_PDMA0_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_PDMA0RST_Pos) +#define NUMAKER_EBI_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_EBIRST_Pos) +#define NUMAKER_EMAC0_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_EMAC0RST_Pos) +#define NUMAKER_SDH0_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_SDH0RST_Pos) +#define NUMAKER_CRC_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CRCRST_Pos) +#define NUMAKER_CCAP_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CCAPRST_Pos) +#define NUMAKER_HSUSBD_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_HSUSBDRST_Pos) +#define NUMAKER_HBI_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_HBIRST_Pos) +#define NUMAKER_CRPT_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CRPTRST_Pos) +#define NUMAKER_KS_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_KSRST_Pos) +#define NUMAKER_SPIM_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_SPIMRST_Pos) +#define NUMAKER_HSUSBH_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_HSUSBHRST_Pos) +#define NUMAKER_SDH1_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_SDH1RST_Pos) +#define NUMAKER_PDMA1_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_PDMA1RST_Pos) +#define NUMAKER_CANFD0_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CANFD0RST_Pos) +#define NUMAKER_CANFD1_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CANFD1RST_Pos) +#define NUMAKER_CANFD2_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CANFD2RST_Pos) +#define NUMAKER_CANFD3_RST ((0UL << 24) | NUMAKER_SYS_IPRST0_CANFD3RST_Pos) + +#define NUMAKER_GPIO_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_GPIORST_Pos) +#define NUMAKER_TMR0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_TMR0RST_Pos) +#define NUMAKER_TMR1_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_TMR1RST_Pos) +#define NUMAKER_TMR2_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_TMR2RST_Pos) +#define NUMAKER_TMR3_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_TMR3RST_Pos) +#define NUMAKER_ACMP01_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_ACMP01RST_Pos) +#define NUMAKER_I2C0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_I2C0RST_Pos) +#define NUMAKER_I2C1_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_I2C1RST_Pos) +#define NUMAKER_I2C2_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_I2C2RST_Pos) +#define NUMAKER_I2C3_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_I2C3RST_Pos) +#define NUMAKER_QSPI0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_QSPI0RST_Pos) +#define NUMAKER_SPI0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_SPI0RST_Pos) +#define NUMAKER_SPI1_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_SPI1RST_Pos) +#define NUMAKER_SPI2_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_SPI2RST_Pos) +#define NUMAKER_UART0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART0RST_Pos) +#define NUMAKER_UART1_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART1RST_Pos) +#define NUMAKER_UART2_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART2RST_Pos) +#define NUMAKER_UART3_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART3RST_Pos) +#define NUMAKER_UART4_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART4RST_Pos) +#define NUMAKER_UART5_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART5RST_Pos) +#define NUMAKER_UART6_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART6RST_Pos) +#define NUMAKER_UART7_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_UART7RST_Pos) +#define NUMAKER_OTG_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_OTGRST_Pos) +#define NUMAKER_USBD_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_USBDRST_Pos) +#define NUMAKER_EADC0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_EADC0RST_Pos) +#define NUMAKER_I2S0_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_I2S0RST_Pos) +#define NUMAKER_HSOTG_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_HSOTGRST_Pos) +#define NUMAKER_TRNG_RST ((4UL << 24) | NUMAKER_SYS_IPRST1_TRNGRST_Pos) + +#define NUMAKER_SC0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_SC0RST_Pos) +#define NUMAKER_SC1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_SC1RST_Pos) +#define NUMAKER_SC2_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_SC2RST_Pos) +#define NUMAKER_I2C4_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_I2C4RST_Pos) +#define NUMAKER_QSPI1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_QSPI1RST_Pos) +#define NUMAKER_SPI3_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_SPI3RST_Pos) +#define NUMAKER_SPI4_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_SPI4RST_Pos) +#define NUMAKER_USCI0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_USCI0RST_Pos) +#define NUMAKER_PSIO_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_PSIORST_Pos) +#define NUMAKER_DAC_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_DACRST_Pos) +#define NUMAKER_EPWM0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EPWM0RST_Pos) +#define NUMAKER_EPWM1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EPWM1RST_Pos) +#define NUMAKER_BPWM0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_BPWM0RST_Pos) +#define NUMAKER_BPWM1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_BPWM1RST_Pos) +#define NUMAKER_EQEI0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EQEI0RST_Pos) +#define NUMAKER_EQEI1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EQEI1RST_Pos) +#define NUMAKER_EQEI2_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EQEI2RST_Pos) +#define NUMAKER_EQEI3_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EQEI3RST_Pos) +#define NUMAKER_ECAP0_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_ECAP0RST_Pos) +#define NUMAKER_ECAP1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_ECAP1RST_Pos) +#define NUMAKER_ECAP2_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_ECAP2RST_Pos) +#define NUMAKER_ECAP3_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_ECAP3RST_Pos) +#define NUMAKER_I2S1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_I2S1RST_Pos) +#define NUMAKER_EADC1_RST ((8UL << 24) | NUMAKER_SYS_IPRST2_EADC1RST_Pos) + +#define NUMAKER_KPI_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_KPIRST_Pos) +#define NUMAKER_EADC2_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_EADC2RST_Pos) +#define NUMAKER_ACMP23_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_ACMP23RST_Pos) +#define NUMAKER_SPI5_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI5RST_Pos) +#define NUMAKER_SPI6_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI6RST_Pos) +#define NUMAKER_SPI7_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI7RST_Pos) +#define NUMAKER_SPI8_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI8RST_Pos) +#define NUMAKER_SPI9_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI9RST_Pos) +#define NUMAKER_SPI10_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_SPI10RST_Pos) +#define NUMAKER_UART8_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_UART8RST_Pos) +#define NUMAKER_UART9_RST ((0x18UL << 24) | NUMAKER_SYS_IPRST3_UART9RST_Pos) + +/* End of M460 BSP sys.h reset module copy */ + +#endif diff --git a/soc/arm/nuvoton_numaker/Kconfig.defconfig b/soc/arm/nuvoton_numaker/Kconfig.defconfig index bcccdaa3c689..dbe62c375f4b 100644 --- a/soc/arm/nuvoton_numaker/Kconfig.defconfig +++ b/soc/arm/nuvoton_numaker/Kconfig.defconfig @@ -3,3 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 source "soc/arm/nuvoton_numaker/*/Kconfig.defconfig.series" + +config RESET + default y From 6176687c8821730f9d5ac561f1bc1a1cfcca1e1f Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Mon, 10 Apr 2023 19:55:54 +0800 Subject: [PATCH 0433/2042] drivers: serial: support for Nuvoton numaker series UART Add Nuvoton numaker series UART support, including interrupt-driven, also apply pinctrl and clock-control. Signed-off-by: cyliang tw --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.numaker | 16 + drivers/serial/uart_numaker.c | 449 ++++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 100 ++++ dts/bindings/serial/nuvoton,numaker-uart.yaml | 27 ++ 6 files changed, 595 insertions(+) create mode 100644 drivers/serial/Kconfig.numaker create mode 100644 drivers/serial/uart_numaker.c create mode 100644 dts/bindings/serial/nuvoton,numaker-uart.yaml diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 4d5967c0cacd..e83935dd6c3f 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -61,6 +61,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_CDNS uart_cdns.c) zephyr_library_sources_ifdef(CONFIG_UART_OPENTITAN uart_opentitan.c) zephyr_library_sources_ifdef(CONFIG_UART_HOSTLINK uart_hostlink.c) zephyr_library_sources_ifdef(CONFIG_UART_EMUL uart_emul.c) +zephyr_library_sources_ifdef(CONFIG_UART_NUMAKER uart_numaker.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 70f0f0090169..4af2f400f858 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -220,4 +220,6 @@ source "drivers/serial/Kconfig.emul" source "drivers/serial/Kconfig.native_tty" +source "drivers/serial/Kconfig.numaker" + endif # SERIAL diff --git a/drivers/serial/Kconfig.numaker b/drivers/serial/Kconfig.numaker new file mode 100644 index 000000000000..ba737a111f51 --- /dev/null +++ b/drivers/serial/Kconfig.numaker @@ -0,0 +1,16 @@ +# NPCX UART driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config UART_NUMAKER + bool "Nuvoton NUMAKER MCU serial driver" + default y + select SERIAL_HAS_DRIVER + select HAS_NUMAKER_UART + select SERIAL_SUPPORT_INTERRUPT + depends on DT_HAS_NUVOTON_NUMAKER_UART_ENABLED + help + This option enables the UART driver for Nuvoton Numaker family of + processors. + Say y if you wish to use serial port on Nuvoton Numaker MCU. diff --git a/drivers/serial/uart_numaker.c b/drivers/serial/uart_numaker.c new file mode 100644 index 000000000000..381e552eac1f --- /dev/null +++ b/drivers/serial/uart_numaker.c @@ -0,0 +1,449 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Nuvoton Technology Corporation. + */ + +#define DT_DRV_COMPAT nuvoton_numaker_uart + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(numaker_uart, LOG_LEVEL_ERR); + +struct uart_numaker_config { + UART_T *uart; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + uint32_t irq_n; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + void (*irq_config_func)(const struct device *dev); +#endif + const struct pinctrl_dev_config *pincfg; +}; + +struct uart_numaker_data { + const struct device *clock; + struct uart_config ucfg; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; +#endif +}; + +static int uart_numaker_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uart_numaker_config *config = dev->config; + uint32_t count; + + count = UART_Read(config->uart, c, 1); + if (!count) { + return -1; + } + + return 0; +} + +static void uart_numaker_poll_out(const struct device *dev, unsigned char c) +{ + const struct uart_numaker_config *config = dev->config; + + UART_Write(config->uart, &c, 1); +} + +static int uart_numaker_err_check(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + uint32_t flags = uart->FIFOSTS; + int err = 0; + + if (flags & UART_FIFOSTS_RXOVIF_Msk) { + err |= UART_ERROR_OVERRUN; + } + + if (flags & UART_FIFOSTS_PEF_Msk) { + err |= UART_ERROR_PARITY; + } + + if (flags & UART_FIFOSTS_FEF_Msk) { + err |= UART_ERROR_FRAMING; + } + + if (flags & UART_FIFOSTS_BIF_Msk) { + err |= UART_BREAK; + } + + if (flags & (UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | UART_FIFOSTS_PEF_Msk | + UART_FIFOSTS_RXOVIF_Msk)) { + uart->FIFOSTS = (UART_FIFOSTS_BIF_Msk | UART_FIFOSTS_FEF_Msk | + UART_FIFOSTS_PEF_Msk | UART_FIFOSTS_RXOVIF_Msk); + } + return err; +} + +static inline int32_t uart_numaker_convert_stopbit(enum uart_config_stop_bits sb) +{ + switch (sb) { + case UART_CFG_STOP_BITS_1: + return UART_STOP_BIT_1; + case UART_CFG_STOP_BITS_1_5: + return UART_STOP_BIT_1_5; + case UART_CFG_STOP_BITS_2: + return UART_STOP_BIT_2; + default: + return -ENOTSUP; + } +}; + +static inline int32_t uart_numaker_convert_datalen(enum uart_config_data_bits db) +{ + switch (db) { + case UART_CFG_DATA_BITS_5: + return UART_WORD_LEN_5; + case UART_CFG_DATA_BITS_6: + return UART_WORD_LEN_6; + case UART_CFG_DATA_BITS_7: + return UART_WORD_LEN_7; + case UART_CFG_DATA_BITS_8: + return UART_WORD_LEN_8; + default: + return -ENOTSUP; + } +} + +static inline uint32_t uart_numaker_convert_parity(enum uart_config_parity parity) +{ + switch (parity) { + case UART_CFG_PARITY_ODD: + return UART_PARITY_ODD; + case UART_CFG_PARITY_EVEN: + return UART_PARITY_EVEN; + case UART_CFG_PARITY_MARK: + return UART_PARITY_MARK; + case UART_CFG_PARITY_SPACE: + return UART_PARITY_SPACE; + case UART_CFG_PARITY_NONE: + default: + return UART_PARITY_NONE; + } +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_numaker_configure(const struct device *dev, const struct uart_config *cfg) +{ + const struct uart_numaker_config *config = dev->config; + struct uart_numaker_data *pData = dev->data; + int32_t databits, stopbits; + uint32_t parity; + + databits = uart_numaker_convert_datalen(cfg->data_bits); + if (databits < 0) { + return databits; + } + + stopbits = uart_numaker_convert_stopbit(cfg->stop_bits); + if (stopbits < 0) { + return stopbits; + } + + if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE) { + UART_DisableFlowCtrl(config->uart); + } else if (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { + UART_EnableFlowCtrl(config->uart); + } else { + return -ENOTSUP; + } + + parity = uart_numaker_convert_parity(cfg->parity); + + UART_SetLineConfig(config->uart, cfg->baudrate, databits, parity, stopbits); + + memcpy(&pData->ucfg, cfg, sizeof(*cfg)); + + return 0; +} + +static int uart_numaker_config_get(const struct device *dev, struct uart_config *cfg) +{ + struct uart_numaker_data *pData = dev->data; + + memcpy(cfg, &pData->ucfg, sizeof(*cfg)); + + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +static int uart_numaker_init(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + struct uart_numaker_data *pData = dev->data; + int err = 0; + + SYS_UnlockReg(); + + struct numaker_scc_subsys scc_subsys; + + 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(clk_modidx) */ + err = clock_control_on(config->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (err != 0) { + goto move_exit; + } + /* Equivalent to CLK_SetModuleClock(clk_modidx, clk_src, clk_div) */ + err = clock_control_configure(config->clk_dev, (clock_control_subsys_t)&scc_subsys, NULL); + if (err != 0) { + goto move_exit; + } + + /* + * Set pinctrl for UART0 RXD and TXD + * Set multi-function pins for UART0 RXD and TXD + */ + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err != 0) { + goto move_exit; + } + + /* Same as BSP's SYS_ResetModule(id_rst) */ + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + /* Reset UART to default state */ + reset_line_toggle_dt(&config->reset); + + UART_Open(config->uart, pData->ucfg.baudrate); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + config->irq_config_func(dev); +#endif + +move_exit: + SYS_LockReg(); + return err; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static int uart_numaker_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + int tx_bytes = 0; + + /* Check TX FIFO not full, then fill */ + while (((size - tx_bytes) > 0) && (!(uart->FIFOSTS & UART_FIFOSTS_TXFULL_Msk))) { + /* Fill one byte into TX FIFO */ + uart->DAT = tx_data[tx_bytes++]; + } + + return tx_bytes; +} + +static int uart_numaker_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + int rx_bytes = 0; + + /* Check RX FIFO not empty, then read */ + while (((size - rx_bytes) > 0) && (!(uart->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk))) { + /* Read one byte from UART RX FIFO */ + rx_data[rx_bytes++] = (uint8_t)uart->DAT; + } + + return rx_bytes; +} + +static void uart_numaker_irq_tx_enable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_EnableInt(uart, UART_INTEN_THREIEN_Msk); +} + +static void uart_numaker_irq_tx_disable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_DisableInt(uart, UART_INTEN_THREIEN_Msk); +} + +static int uart_numaker_irq_tx_ready(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + return ((!UART_IS_TX_FULL(uart)) && (uart->INTEN & UART_INTEN_THREIEN_Msk)); +} + +static int uart_numaker_irq_tx_complete(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + return (uart->INTSTS & UART_INTSTS_THREINT_Msk); +} + +static void uart_numaker_irq_rx_enable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_EnableInt(uart, UART_INTEN_RDAIEN_Msk); +} + +static void uart_numaker_irq_rx_disable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_DisableInt(uart, UART_INTEN_RDAIEN_Msk); +} + +static int uart_numaker_irq_rx_ready(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + return ((!UART_GET_RX_EMPTY(uart)) && (uart->INTEN & UART_INTEN_RDAIEN_Msk)); +} + +static void uart_numaker_irq_err_enable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_EnableInt(uart, UART_INTEN_BUFERRIEN_Msk | UART_INTEN_SWBEIEN_Msk); +} + +static void uart_numaker_irq_err_disable(const struct device *dev) +{ + const struct uart_numaker_config *config = dev->config; + UART_T *uart = config->uart; + + UART_DisableInt(uart, UART_INTEN_BUFERRIEN_Msk | UART_INTEN_SWBEIEN_Msk); +} + +static int uart_numaker_irq_is_pending(const struct device *dev) +{ + + return (uart_numaker_irq_tx_ready(dev) || (uart_numaker_irq_rx_ready(dev))); +} + +static int uart_numaker_irq_update(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* nothing to be done */ + return 1; +} + +static void uart_numaker_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, void *cb_data) +{ + struct uart_numaker_data *pData = dev->data; + + pData->user_cb = cb; + pData->user_data = cb_data; +} + +static void uart_numaker_isr(const struct device *dev) +{ + struct uart_numaker_data *pData = dev->data; + + if (pData->user_cb) { + pData->user_cb(dev, pData->user_data); + } +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_numaker_driver_api = { + .poll_in = uart_numaker_poll_in, + .poll_out = uart_numaker_poll_out, + .err_check = uart_numaker_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_numaker_configure, + .config_get = uart_numaker_config_get, +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_numaker_fifo_fill, + .fifo_read = uart_numaker_fifo_read, + .irq_tx_enable = uart_numaker_irq_tx_enable, + .irq_tx_disable = uart_numaker_irq_tx_disable, + .irq_tx_ready = uart_numaker_irq_tx_ready, + .irq_tx_complete = uart_numaker_irq_tx_complete, + .irq_rx_enable = uart_numaker_irq_rx_enable, + .irq_rx_disable = uart_numaker_irq_rx_disable, + .irq_rx_ready = uart_numaker_irq_rx_ready, + .irq_err_enable = uart_numaker_irq_err_enable, + .irq_err_disable = uart_numaker_irq_err_disable, + .irq_is_pending = uart_numaker_irq_is_pending, + .irq_update = uart_numaker_irq_update, + .irq_callback_set = uart_numaker_irq_callback_set, +#endif +}; + +#define CLOCK_CTRL_INIT(n) .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(n))), + +#define PINCTRL_DEFINE(n) PINCTRL_DT_INST_DEFINE(n); +#define PINCTRL_INIT(n) .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define NUMAKER_UART_IRQ_CONFIG_FUNC(n) \ + static void uart_numaker_irq_config_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_numaker_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#define IRQ_FUNC_INIT(n) .irq_config_func = uart_numaker_irq_config_##n +#else +#define NUMAKER_UART_IRQ_CONFIG_FUNC(n) +#define IRQ_FUNC_INIT(n) +#endif + +#define NUMAKER_UART_INIT(inst) \ + PINCTRL_DEFINE(inst) \ + NUMAKER_UART_IRQ_CONFIG_FUNC(inst) \ + \ + static const struct uart_numaker_config uart_numaker_cfg_##inst = { \ + .uart = (UART_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), \ + CLOCK_CTRL_INIT(inst).irq_n = DT_INST_IRQN(inst), \ + PINCTRL_INIT(inst) IRQ_FUNC_INIT(inst)}; \ + \ + static struct uart_numaker_data uart_numaker_data_##inst = { \ + .ucfg = \ + { \ + .baudrate = DT_INST_PROP(inst, current_speed), \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &uart_numaker_init, NULL, &uart_numaker_data_##inst, \ + &uart_numaker_cfg_##inst, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_numaker_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NUMAKER_UART_INIT) diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index fef99818efba..e8714084fc24 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -64,6 +64,106 @@ status = "okay"; }; + uart0: serial@40070000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40070000 0x1000>; + interrupts = <36 0>; + resets = <&rst NUMAKER_UART0_RST>; + clocks = <&pcc NUMAKER_UART0_MODULE NUMAKER_CLK_CLKSEL1_UART0SEL_HIRC + NUMAKER_CLK_CLKDIV0_UART0(1)>; + status = "disabled"; + }; + + uart1: serial@40071000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40071000 0x1000>; + interrupts = <37 0>; + resets = <&rst NUMAKER_UART1_RST>; + clocks = <&pcc NUMAKER_UART1_MODULE NUMAKER_CLK_CLKSEL1_UART1SEL_HIRC + NUMAKER_CLK_CLKDIV0_UART1(1)>; + status = "disabled"; + }; + + uart2: serial@40072000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40072000 0x1000>; + interrupts = <48 0>; + resets = <&rst NUMAKER_UART2_RST>; + clocks = <&pcc NUMAKER_UART2_MODULE NUMAKER_CLK_CLKSEL3_UART2SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART2(1)>; + status = "disabled"; + }; + + uart3: serial@40073000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40073000 0x1000>; + interrupts = <49 0>; + resets = <&rst NUMAKER_UART3_RST>; + clocks = <&pcc NUMAKER_UART3_MODULE NUMAKER_CLK_CLKSEL3_UART3SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART3(1)>; + status = "disabled"; + }; + + uart4: serial@40074000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40074000 0x1000>; + interrupts = <74 0>; + resets = <&rst NUMAKER_UART4_RST>; + clocks = <&pcc NUMAKER_UART4_MODULE NUMAKER_CLK_CLKSEL3_UART4SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART4(1)>; + status = "disabled"; + }; + + uart5: serial@40075000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40075000 0x1000>; + interrupts = <75 0>; + resets = <&rst NUMAKER_UART5_RST>; + clocks = <&pcc NUMAKER_UART5_MODULE NUMAKER_CLK_CLKSEL3_UART5SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART5(1)>; + status = "disabled"; + }; + + uart6: serial@40076000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40076000 0x1000>; + interrupts = <102 0>; + resets = <&rst NUMAKER_UART6_RST>; + clocks = <&pcc NUMAKER_UART6_MODULE NUMAKER_CLK_CLKSEL3_UART6SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART6(1)>; + status = "disabled"; + }; + + uart7: serial@40077000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40077000 0x1000>; + interrupts = <103 0>; + resets = <&rst NUMAKER_UART7_RST>; + clocks = <&pcc NUMAKER_UART7_MODULE NUMAKER_CLK_CLKSEL3_UART7SEL_HIRC + NUMAKER_CLK_CLKDIV4_UART7(1)>; + status = "disabled"; + }; + + uart8: serial@40078000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40078000 0x1000>; + interrupts = <99 0>; + resets = <&rst NUMAKER_UART8_RST>; + clocks = <&pcc NUMAKER_UART8_MODULE NUMAKER_CLK_CLKSEL2_UART8SEL_HIRC + NUMAKER_CLK_CLKDIV5_UART8(1)>; + status = "disabled"; + }; + + uart9: serial@40079000 { + compatible = "nuvoton,numaker-uart"; + reg = <0x40079000 0x1000>; + interrupts = <100 0>; + resets = <&rst NUMAKER_UART9_RST>; + clocks = <&pcc NUMAKER_UART9_MODULE NUMAKER_CLK_CLKSEL2_UART9SEL_HIRC + NUMAKER_CLK_CLKDIV5_UART9(1)>; + status = "disabled"; + }; + pinctrl: pin-controller@40000500 { compatible = "nuvoton,numaker-pinctrl"; reg = <0x40000500 0xa0>; diff --git a/dts/bindings/serial/nuvoton,numaker-uart.yaml b/dts/bindings/serial/nuvoton,numaker-uart.yaml new file mode 100644 index 000000000000..807144e97c5c --- /dev/null +++ b/dts/bindings/serial/nuvoton,numaker-uart.yaml @@ -0,0 +1,27 @@ +# (c) Nuvoton Technology Corp. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, Numaker-UART + +compatible: "nuvoton,numaker-uart" + +include: [uart-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true From 0fd564ef7f293c88b489d709434e3e8342ce649a Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Mon, 10 Apr 2023 21:08:49 +0800 Subject: [PATCH 0434/2042] drivers: gpio: support for Nuvoton numaker series GPIO Add Nuvoton numaker series GPIO support, including interrupt mode and also integrate clock control. Signed-off-by: cyliang tw --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.numaker | 13 + drivers/gpio/gpio_numaker.c | 275 ++++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 101 +++++++ dts/bindings/gpio/nuvoton,numaker-gpio.yaml | 19 ++ .../boards/numaker_pfm_m467.overlay | 13 + west.yml | 2 +- 8 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 drivers/gpio/Kconfig.numaker create mode 100644 drivers/gpio/gpio_numaker.c create mode 100644 dts/bindings/gpio/nuvoton,numaker-gpio.yaml create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/numaker_pfm_m467.overlay diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 16eb3caeb2ad..de378a492f76 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -79,6 +79,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) zephyr_library_sources_ifdef(CONFIG_GPIO_HOGS gpio_hogs.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) if(CONFIG_GPIO_SC18IM704) zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b4a2f0bef675..90a30656586a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -197,4 +197,6 @@ source "drivers/gpio/Kconfig.bd8lb600fs" source "drivers/gpio/Kconfig.sc18im704" +source "drivers/gpio/Kconfig.numaker" + endif # GPIO diff --git a/drivers/gpio/Kconfig.numaker b/drivers/gpio/Kconfig.numaker new file mode 100644 index 000000000000..8c1615fbff35 --- /dev/null +++ b/drivers/gpio/Kconfig.numaker @@ -0,0 +1,13 @@ +# NUMAKER GPIO driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_NUMAKER + bool "Nuvoton NUMAKER MCU gpio driver" + default y + select HAS_NUMAKER_GPIO + depends on DT_HAS_NUVOTON_NUMAKER_GPIO_ENABLED + help + This option enables the GPIO driver for Nuvoton NUMAKER family of + processors. diff --git a/drivers/gpio/gpio_numaker.c b/drivers/gpio/gpio_numaker.c new file mode 100644 index 000000000000..2c7515f2981e --- /dev/null +++ b/drivers/gpio/gpio_numaker.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_gpio + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NU_MFP_POS(pinindex) ((pinindex % 4) * 8) + +LOG_MODULE_REGISTER(gpio_numaker, LOG_LEVEL_ERR); + +struct gpio_numaker_config { + struct gpio_driver_config common; + uint32_t reg; + uint32_t gpa_base; + uint32_t size; + uint32_t clk_modidx; + const struct device *clk_dev; +}; + +struct gpio_numaker_data { + struct gpio_driver_data common; + sys_slist_t callbacks; +}; + +static int gpio_numaker_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_numaker_config *config = dev->config; + struct gpio_numaker_data *data = dev->data; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + uint32_t pinMfpMask = (0x1f << NU_MFP_POS(pin)); + uint32_t pinMask = BIT(pin); /* mask for pin index --> (0x01 << pin) */ + uint32_t port_index; + uint32_t *GPx_MFPx; + uint32_t pinMfpGpio; + int err = 0; + + ARG_UNUSED(data); + + /* Check for an invalid pin number */ + if (pin >= 15) { + return -EINVAL; + } + + SYS_UnlockReg(); + + /* Enable GPIO clock */ + struct numaker_scc_subsys scc_subsys; + + 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_EnableModuleClock(config->clk_modidx) */ + err = clock_control_on(config->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (err != 0) { + goto move_exit; + } + + /* Configure GPIO direction */ + switch (flags & GPIO_DIR_MASK) { + case GPIO_INPUT: + GPIO_SetMode(gpio_base, pinMask, GPIO_MODE_INPUT); + break; + case GPIO_OUTPUT: + GPIO_SetMode(gpio_base, pinMask, GPIO_MODE_OUTPUT); + break; + case (GPIO_INPUT | GPIO_OUTPUT): + GPIO_SetMode(gpio_base, pinMask, GPIO_MODE_QUASI); + break; + default: + err = -ENOTSUP; + goto move_exit; + } + + if (flags & GPIO_LINE_OPEN_DRAIN) { + GPIO_SetMode(gpio_base, pinMask, GPIO_MODE_OPEN_DRAIN); + } + + /* Set Multi-function, default is GPIO */ + port_index = (config->reg - config->gpa_base) / config->size; + GPx_MFPx = ((uint32_t *)&SYS->GPA_MFP0) + port_index * 4 + (pin / 4); + pinMfpGpio = 0x00UL; + /* + * E.g.: SYS->GPA_MFP0 = (SYS->GPA_MFP0 & (~SYS_GPA_MFP0_PA0MFP_Msk) ) | + * SYS_GPA_MFP0_PA0MFP_GPIO; + */ + *GPx_MFPx = (*GPx_MFPx & (~pinMfpMask)) | pinMfpGpio; + + /* Set pull control as pull-up, pull-down or pull-disable */ + if ((flags & GPIO_PULL_UP) != 0) { + GPIO_SetPullCtl(gpio_base, pinMask, GPIO_PUSEL_PULL_UP); + } else if ((flags & GPIO_PULL_DOWN) != 0) { + GPIO_SetPullCtl(gpio_base, pinMask, GPIO_PUSEL_PULL_DOWN); + } else { + GPIO_SetPullCtl(gpio_base, pinMask, GPIO_PUSEL_DISABLE); + } + + /* Set Init Level 0:low 1:high */ + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) { + gpio_base->DOUT |= pinMask; + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) { + gpio_base->DOUT &= ~pinMask; + } + +move_exit: + SYS_LockReg(); + return err; +} + +static int gpio_numaker_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + + /* Get raw bits of GPIO PIN data */ + *value = gpio_base->PIN; + + return 0; +} + +static int gpio_numaker_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + + gpio_base->DOUT = (gpio_base->DOUT & ~mask) | (mask & value); + + return 0; +} + +static int gpio_numaker_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + + /* Set raw bits of GPIO output data */ + gpio_base->DOUT |= mask; + + return 0; +} + +static int gpio_numaker_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t mask) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + + /* Clear raw bits of GPIO data */ + gpio_base->DOUT &= ~mask; + + return 0; +} + +static int gpio_numaker_port_toggle_bits(const struct device *dev, gpio_port_pins_t mask) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + + /* Toggle raw bits of GPIO data */ + gpio_base->DOUT ^= mask; + + return 0; +} + +static int gpio_numaker_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_numaker_config *config = dev->config; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + uint32_t intAttr; + + if (mode == GPIO_INT_MODE_DISABLED) { + GPIO_DisableInt(gpio_base, pin); + /* Clear the port int status */ + gpio_base->INTSRC &= BIT(pin); + } else { + switch (trig) { + case GPIO_INT_TRIG_LOW: + intAttr = ((mode == GPIO_INT_MODE_EDGE) ? GPIO_INT_FALLING : GPIO_INT_LOW); + break; + case GPIO_INT_TRIG_HIGH: + intAttr = ((mode == GPIO_INT_MODE_EDGE) ? GPIO_INT_RISING : GPIO_INT_HIGH); + break; + case GPIO_INT_TRIG_BOTH: + if (mode != GPIO_INT_MODE_EDGE) { + return -ENOTSUP; + } + intAttr = GPIO_INT_BOTH_EDGE; + break; + default: + return -ENOTSUP; + } + GPIO_EnableInt(gpio_base, pin, intAttr); + } + + return 0; +} + +static int gpio_numaker_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct gpio_numaker_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static const struct gpio_driver_api gpio_numaker_api = { + .pin_configure = gpio_numaker_configure, + .port_get_raw = gpio_numaker_port_get_raw, + .port_set_masked_raw = gpio_numaker_port_set_masked_raw, + .port_set_bits_raw = gpio_numaker_port_set_bits_raw, + .port_clear_bits_raw = gpio_numaker_port_clear_bits_raw, + .port_toggle_bits = gpio_numaker_port_toggle_bits, + .pin_interrupt_configure = gpio_numaker_pin_interrupt_configure, + .manage_callback = gpio_numaker_manage_callback}; + +static void gpio_numaker_isr(const struct device *dev) +{ + const struct gpio_numaker_config *config = dev->config; + struct gpio_numaker_data *data = dev->data; + GPIO_T *gpio_base = (GPIO_T *)config->reg; + uint32_t int_status; + + /* Get the int status */ + int_status = gpio_base->INTSRC; + + /* Clear the port int status */ + gpio_base->INTSRC = int_status; + + gpio_fire_callbacks(&data->callbacks, dev, int_status); +} + +#define CLOCK_CTRL_INIT(n) .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(n))), + +#define GPIO_NUMAKER_IRQ_INIT(n) \ + do { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_numaker_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } while (0) + +#define GPIO_NUMAKER_DEFINE(n) \ + static const struct gpio_numaker_config gpio_numaker_config##n = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .reg = DT_INST_REG_ADDR(n), \ + .gpa_base = DT_REG_ADDR(DT_NODELABEL(gpioa)), \ + .size = DT_REG_SIZE(DT_NODELABEL(gpioa)), \ + .clk_modidx = DT_INST_CLOCKS_CELL(n, clock_module_index), \ + CLOCK_CTRL_INIT(n)}; \ + \ + static struct gpio_numaker_data gpio_numaker_data##n; \ + \ + static int gpio_numaker_init##n(const struct device *dev) \ + { \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (GPIO_NUMAKER_IRQ_INIT(n);)) \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(n, &gpio_numaker_init##n, NULL, &gpio_numaker_data##n, \ + &gpio_numaker_config##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_numaker_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_NUMAKER_DEFINE) diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index e8714084fc24..470f3f713d32 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include / { cpus { @@ -169,6 +170,106 @@ reg = <0x40000500 0xa0>; status = "okay"; }; + + gpioa: gpio@40004000 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004000 0x40>; + clocks = <&pcc NUMAKER_GPA_MODULE 0 0>; + status = "disabled"; + interrupts = <16 2>; + }; + + gpiob: gpio@40004040 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004040 0x40>; + clocks = <&pcc NUMAKER_GPB_MODULE 0 0>; + status = "disabled"; + interrupts = <17 2>; + }; + + gpioc: gpio@40004080 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004080 0x40>; + clocks = <&pcc NUMAKER_GPC_MODULE 0 0>; + status = "disabled"; + interrupts = <18 2>; + }; + + gpiod: gpio@400040c0 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x400040c0 0x40>; + clocks = <&pcc NUMAKER_GPD_MODULE 0 0>; + status = "disabled"; + interrupts = <19 2>; + }; + + gpioe: gpio@40004100 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004100 0x40>; + clocks = <&pcc NUMAKER_GPE_MODULE 0 0>; + status = "disabled"; + interrupts = <20 2>; + }; + + gpiof: gpio@40004140 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004140 0x40>; + clocks = <&pcc NUMAKER_GPF_MODULE 0 0>; + status = "disabled"; + interrupts = <21 2>; + }; + + gpiog: gpio@40004180 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004180 0x40>; + clocks = <&pcc NUMAKER_GPG_MODULE 0 0>; + status = "disabled"; + interrupts = <72 2>; + }; + + gpioh: gpio@400041c0 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x400041c0 0x40>; + clocks = <&pcc NUMAKER_GPH_MODULE 0 0>; + status = "disabled"; + interrupts = <88 2>; + }; + + gpioi: gpio@40004200 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004200 0x40>; + clocks = <&pcc NUMAKER_GPI_MODULE 0 0>; + status = "disabled"; + interrupts = <110 2>; + }; + + gpioj: gpio@40004240 { + compatible = "nuvoton,numaker-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x40004240 0x40>; + clocks = <&pcc NUMAKER_GPJ_MODULE 0 0>; + status = "disabled"; + interrupts = <61 2>; + }; }; }; diff --git a/dts/bindings/gpio/nuvoton,numaker-gpio.yaml b/dts/bindings/gpio/nuvoton,numaker-gpio.yaml new file mode 100644 index 000000000000..29463aae2710 --- /dev/null +++ b/dts/bindings/gpio/nuvoton,numaker-gpio.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, Numaker-GPIO node + +compatible: "nuvoton,numaker-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/tests/drivers/gpio/gpio_basic_api/boards/numaker_pfm_m467.overlay b/tests/drivers/gpio/gpio_basic_api/boards/numaker_pfm_m467.overlay new file mode 100644 index 000000000000..57c0ea3e27a3 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/numaker_pfm_m467.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpiob 2 0>; /* UNO D0 */ + in-gpios = <&gpiob 3 0>; /* UNO D1 */ + }; +}; diff --git a/west.yml b/west.yml index 215cc46f50ba..5bb2596e34b7 100644 --- a/west.yml +++ b/west.yml @@ -175,7 +175,7 @@ manifest: groups: - hal - name: hal_nuvoton - revision: 0a1f153c433f5f637a4490651bdda6d966de3b99 + revision: 8a2b5de1670b59fcacd20d7495cb1c0f26fbe7bd path: modules/hal/nuvoton groups: - hal From 246bd7a29050649a87d978a3431178e6f80a6307 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Tue, 30 May 2023 11:38:31 +0800 Subject: [PATCH 0435/2042] board: arm: add support for nuvoton pfm m467 add support for nuvoton pfm m467 development board Signed-off-by: cyliang tw --- boards/arm/numaker_pfm_m467/Kconfig.board | 9 ++ boards/arm/numaker_pfm_m467/Kconfig.defconfig | 19 ++++ boards/arm/numaker_pfm_m467/board.cmake | 9 ++ boards/arm/numaker_pfm_m467/doc/index.rst | 99 ++++++++++++++++ boards/arm/numaker_pfm_m467/doc/pfm_m467.jpeg | Bin 0 -> 78858 bytes .../numaker_pfm_m467-pinctrl.dtsi | 23 ++++ .../arm/numaker_pfm_m467/numaker_pfm_m467.dts | 107 ++++++++++++++++++ .../numaker_pfm_m467/numaker_pfm_m467.yaml | 17 +++ .../numaker_pfm_m467_defconfig | 22 ++++ .../arm/numaker_pfm_m467/support/openocd.cfg | 2 + 10 files changed, 307 insertions(+) create mode 100644 boards/arm/numaker_pfm_m467/Kconfig.board create mode 100644 boards/arm/numaker_pfm_m467/Kconfig.defconfig create mode 100644 boards/arm/numaker_pfm_m467/board.cmake create mode 100644 boards/arm/numaker_pfm_m467/doc/index.rst create mode 100644 boards/arm/numaker_pfm_m467/doc/pfm_m467.jpeg create mode 100644 boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi create mode 100644 boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts create mode 100644 boards/arm/numaker_pfm_m467/numaker_pfm_m467.yaml create mode 100644 boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig create mode 100644 boards/arm/numaker_pfm_m467/support/openocd.cfg diff --git a/boards/arm/numaker_pfm_m467/Kconfig.board b/boards/arm/numaker_pfm_m467/Kconfig.board new file mode 100644 index 000000000000..8773aeeacc91 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/Kconfig.board @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Nuvoton PFM M467 board configuration +# +# Copyright (c) 2023 Nuvoton Technology Corporation. + +config BOARD_NUMAKER_PFM_M467 + bool "NUVOTON PFM M467 Development Board" + depends on SOC_M467 diff --git a/boards/arm/numaker_pfm_m467/Kconfig.defconfig b/boards/arm/numaker_pfm_m467/Kconfig.defconfig new file mode 100644 index 000000000000..97024136df88 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/Kconfig.defconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Nuvoton PFM M467 board configuration +# +# Copyright (c) 2023 Nuvoton Technology Corporation. + +if BOARD_NUMAKER_PFM_M467 + +config BOARD + default "numaker_pfm_m467" + +if NETWORKING + +config NET_L2_ETHERNET + default y if !MODEM + +endif # NETWORKING + +endif # BOARD_NUMAKER_PFM_M467 diff --git a/boards/arm/numaker_pfm_m467/board.cmake b/boards/arm/numaker_pfm_m467/board.cmake new file mode 100644 index 000000000000..73a61385fd63 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(nulink "-f") +board_runner_args(pyocd "--target=m467hjhae") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nulink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/canopen.board.cmake) diff --git a/boards/arm/numaker_pfm_m467/doc/index.rst b/boards/arm/numaker_pfm_m467/doc/index.rst new file mode 100644 index 000000000000..483ab34b6234 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/doc/index.rst @@ -0,0 +1,99 @@ +.. _nuvoton_pfm_m467: + +NUVOTON NUMAKER PFM M467 +######################## + +Overview +******** + +The NuMaker PFM M467 is an Internet of Things (IoT) application focused platform +specially developed by Nuvoton. The PFM-M467 is based on the NuMicro® M467 +Ethernet series MCU with ARM® -Cortex®-M4F core. + +.. image:: ./pfm_m467.jpeg + :width: 720px + :align: center + :alt: PFM-M467 + +Features: +========= +- 32-bit Arm Cortex®-M4 M467HJHAE MCU +- Core clock up to 200 MHz +- 1024 KB embedded Dual Bank Flash and 512 KB SRAM +- Ethernet (IP101GR) for network application +- USB 2.0 High-Speed OTG / Host / Device +- USB 1.1 Full-Speed OTG / Host / Device +- External SPI Flash (Winbond W25Q20) which can be regarded as ROM module +- MicroSD Card slot for T-Flash +- Arduino UNO compatible interface +- Three push-buttons: one is for reset and the other two are for user-defined +- Four LEDs: one is for power indication and the other three are for user-defined +- On-board NU-Link2 ICE debugger/programmer with SWD connector + +More information about the board can be found at the `PFM M467 User Manual`_. + +Supported Features +================== + +* The on-board 12-MHz crystal allows the device to run at its maximum operating speed of 200MHz. + +The development board configuration supports the following hardware features: + ++-----------+------------+-----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=======================+ +| NVIC | on-chip | nested vectored | +| | | interrupt controller | ++-----------+------------+-----------------------+ +| SYSTICK | on-chip | system clock | ++-----------+------------+-----------------------+ +| UART | on-chip | serial port | ++-----------+------------+-----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-----------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +More details about the supported peripherals are available in `M460 TRM`_ +Other hardware features are not currently supported by the Zephyr kernel. + +Building and Flashing +********************* +Flashing +======== + +Here is an example for the :ref:`hello_world` application. + +On board debugger Nu-link2 can emulate UART0 as a virtual COM port over usb, +To enable this, set ISW1 DIP switch 1-3 (TXD RXD VOM) to ON. +Connect the PFM M467 IoT to your host computer using the USB port, then +run a serial host program to connect with your board. For example: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: numaker_pfm_m467 + :goals: flash + +Debugging +========= + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: numaker_pfm_m467 + :goals: debug + +Step through the application in your debugger. + +References +********** + +.. _PFM M467 User Manual: + https://www.nuvoton.com/export/resource-files/UM_NuMaker-PFM-M467_User_Manual_EN_Rev1.01.pdf +.. _M460 TRM: + https://www.nuvoton.com/export/resource-files/TRM_M460_Series_EN_Rev1.01.pdf diff --git a/boards/arm/numaker_pfm_m467/doc/pfm_m467.jpeg b/boards/arm/numaker_pfm_m467/doc/pfm_m467.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..22a84bb0bb5f7c0fe208a51236a9fe6bc771923d GIT binary patch literal 78858 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%0AQ8fzQ~1PUMn6AjL? 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 literal 0 HcmV?d00001 diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi new file mode 100644 index 000000000000..09aa50f21012 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "pinctrl/m467hjhae-pinctrl.h" + +&pinctrl { + uart0_default: uart0_default { + pinmux = , + ; + }; + + /* TX/RX/RTS/CTS/RST --> D1/D0/A2/A3/D2 --> PB3/PB2/PB8/PB9/PC9 */ + uart1_default: uart1_default { + pinmux = , + , + , + , + ; + }; +}; diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts new file mode 100644 index 000000000000..988337d24d5c --- /dev/null +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "numaker_pfm_m467-pinctrl.dtsi" + +/ { + model = "Nuvoton PFM M467 board"; + compatible = "nuvoton,pfm-m467", "nuvoton,m467"; + + aliases { + led0 = &green_led; + led1 = &blue_led; + led2 = &red_led; + sw0 = &user_button_1; + sw1 = &user_button_2; + }; + + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; + label = "User LD1"; + }; + green_led: led_1 { + gpios = <&gpioh 6 GPIO_ACTIVE_LOW>; + label = "User LD2"; + }; + blue_led: led_2 { + gpios = <&gpioh 5 GPIO_ACTIVE_LOW>; + label = "User LD3"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button_1: button_1 { + label = "User SW2"; + gpios = <&gpioh 1 GPIO_ACTIVE_LOW>; + }; + user_button_2: button_2 { + label = "User SW3"; + gpios = <&gpioh 0 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&scc { + /* For USB 1.1 Host/Device/OTG, configure to 192MHz, which can generate necessary 48MHz. */ + /* For USB 2.0 Host/Device/OTG or no USB application, comment out to use default. */ + core-clock = <192000000>; +}; + +&gpiob { + status = "okay"; +}; + +&gpioh { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x00000000 0x00080000>; + }; + slot1_partition: partition@80000 { + label = "image-1"; + reg = <0x00080000 0x0007e000>; + }; + storage_partition: partition@fe000 { + label = "storage"; + reg = <0x000fe000 0x00002000>; + }; + }; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(512)>; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.yaml b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.yaml new file mode 100644 index 000000000000..b057454d8736 --- /dev/null +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +identifier: numaker_pfm_m467 +name: NUVOTON NUMAKER-PFM-M467 Kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 512 +flash: 1024 +supported: + - gpio +testing: + default: true diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig b/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig new file mode 100644 index 000000000000..8b9e8d75b12c --- /dev/null +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_M46X=y +CONFIG_SOC_M467=y +CONFIG_PINCTRL=y +CONFIG_GPIO=y + +# Enable system clock controller driver +CONFIG_CLOCK_CONTROL=y +CONFIG_CLOCK_CONTROL_NUMAKER_SCC=y + +# Enable MPU +CONFIG_ARM_MPU=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=200000000 + +# enable uart driver +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/numaker_pfm_m467/support/openocd.cfg b/boards/arm/numaker_pfm_m467/support/openocd.cfg new file mode 100644 index 000000000000..c393f756c4de --- /dev/null +++ b/boards/arm/numaker_pfm_m467/support/openocd.cfg @@ -0,0 +1,2 @@ +source [find interface/nulink.cfg] +source [find target/numicro.cfg] From c5bb959b25f8619134dd1cfa0cb5832c96a4d81e Mon Sep 17 00:00:00 2001 From: sukrit buddeewong Date: Tue, 20 Jun 2023 02:05:59 +0700 Subject: [PATCH 0436/2042] driver: uart: Fix Modbus data currupted by DE-RE signal Add UART_UARTFR_BUSY_BITS To fix modbus data was currupted Signed-off-by: sukrit buddeewong --- drivers/serial/uart_rpi_pico.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/uart_rpi_pico.c b/drivers/serial/uart_rpi_pico.c index 34fbcc3c5bc0..9eb820d6224f 100644 --- a/drivers/serial/uart_rpi_pico.c +++ b/drivers/serial/uart_rpi_pico.c @@ -290,7 +290,7 @@ static int uart_rpi_irq_tx_complete(const struct device *dev) const struct uart_rpi_config * const config = dev->config; uart_hw_t * const uart_hw = config->uart_regs; - return !!(uart_hw->fr & UART_UARTFR_TXFE_BITS); + return !!(uart_hw->fr & UART_UARTFR_TXFE_BITS) && !(uart_hw->fr & UART_UARTFR_BUSY_BITS); } static int uart_rpi_irq_rx_ready(const struct device *dev) From 6271f2fa56067aa491d918044c331558bf44c794 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 20 Jun 2023 18:05:36 +1000 Subject: [PATCH 0437/2042] net: if: default `NET_IF_LOWER_UP` at compile time The `net_if` layer should not be forcing `NET_IF_LOWER_UP` to be set on all interfaces at runtime. Because `net_init` runs relatively late by default, this is overriding any control the driver itself may have performed using `net_if_carrier_on/off`. Initialise this bit at compile-time instead. As the structure is already being initialised, this doesn't increase any footprints. Signed-off-by: Jordan Yates --- include/zephyr/net/net_if.h | 2 ++ subsys/net/ip/net_if.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index cedfe9f1db51..f8b2ad5def30 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2562,6 +2562,7 @@ struct net_if_api { .l2 = &(NET_L2_GET_NAME(_l2)), \ .l2_data = &(NET_L2_GET_DATA(dev_id, sfx)), \ .mtu = _mtu, \ + .flags = {BIT(NET_IF_LOWER_UP)}, \ }; \ static Z_DECL_ALIGN(struct net_if) \ NET_IF_GET_NAME(dev_id, sfx)[_num_configs] \ @@ -2579,6 +2580,7 @@ struct net_if_api { .dev = &(DEVICE_NAME_GET(dev_id)), \ .mtu = _mtu, \ .l2 = &(NET_L2_GET_NAME(OFFLOADED_NETDEV)), \ + .flags = {BIT(NET_IF_LOWER_UP)}, \ }; \ static Z_DECL_ALIGN(struct net_if) \ NET_IF_GET_NAME(dev_id, sfx)[NET_IF_MAX_CONFIGS] \ diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 5da2a664678d..3bc187fcf517 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -425,8 +425,6 @@ static inline void init_iface(struct net_if *iface) net_if_flag_set(iface, NET_IF_IPV6); #endif - net_if_flag_test_and_set(iface, NET_IF_LOWER_UP); - net_virtual_init(iface); NET_DBG("On iface %p", iface); From f573a702dee17c5b06575fb13397b9bc1be56d1a Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 20 Jun 2023 16:34:10 +0000 Subject: [PATCH 0438/2042] tests: mcumgr: os_mgmt_info: simplify test yaml file - Use common section to avoid duplication of excludes - use mcumgr tag Signed-off-by: Anas Nashif --- .../mgmt/mcumgr/os_mgmt_info/testcase.yaml | 80 ++++--------------- 1 file changed, 14 insertions(+), 66 deletions(-) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml index ad2ba90a5d2a..3ecfc5e10898 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml @@ -3,62 +3,33 @@ # # SPDX-License-Identifier: Apache-2.0 # +common: + tags: + - mcumgr + - os_mgmt_info + # FIXME: Exclude architectures that lack a reboot handler function + arch_exclude: + - arm64 + - nios2 + - sparc + - arc + - xtensa + - mips + - posix tests: - os.mgmt.info: - # FIXME: Exclude architectures that lack a reboot handler function - # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix - tags: os_mgmt_info + os.mgmt.info: {} os.mgmt.info_no_hooks: - # FIXME: Exclude architectures that lack a reboot handler function - # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix - tags: os_mgmt_info extra_configs: - CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=n - CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=n os.mgmt.info_bt: depends_on: ble - # FIXME: Exclude architectures that lack a reboot handler function - # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix - tags: os_mgmt_info extra_configs: - CONFIG_BT=y - CONFIG_BT_DEVICE_NAME="a_bt_name" os.mgmt.info_net: depends_on: netif - # FIXME: Exclude architectures that lack a reboot handler function # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix platform_exclude: - qemu_cortex_a9 - qemu_x86 @@ -69,38 +40,15 @@ tests: - qemu_riscv32_smp - qemu_cortex_m3 - mps2_an385 - tags: os_mgmt_info extra_configs: - CONFIG_NETWORKING=y - CONFIG_NET_HOSTNAME_ENABLE=y - CONFIG_NET_HOSTNAME="test_net_name" - CONFIG_TEST_RANDOM_GENERATOR=y os.mgmt.info_build_date: - # FIXME: Exclude architectures that lack a reboot handler function - # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix - tags: os_mgmt_info extra_configs: - CONFIG_BUILD_DATE_TIME_TEST=y os.mgmt.info_limited_size: - # FIXME: Exclude architectures that lack a reboot handler function - # FIXME: Exclude systems whereby the processor type is not known and emits a warning - arch_exclude: - - arm64 - - nios2 - - sparc - - arc - - xtensa - - mips - - posix - tags: os_mgmt_info extra_configs: - CONFIG_LIMITED_TEST=y - CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=64 From 3a13070dccc4352e1b5d925521cf5d4cdded843a Mon Sep 17 00:00:00 2001 From: Supper Thomas <78900636@qq.com> Date: Wed, 21 Jun 2023 13:07:07 +0800 Subject: [PATCH 0439/2042] boards: arm: Fix the vendor name Fix the vendor name from st to alientek Signed-off-by: Supper Thomas <78900636@qq.com> --- boards/arm/pandora_stm32l475/doc/index.rst | 4 ++-- boards/arm/pandora_stm32l475/pandora_stm32l475.dts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/arm/pandora_stm32l475/doc/index.rst b/boards/arm/pandora_stm32l475/doc/index.rst index 38623ac89f6f..62a903faf784 100644 --- a/boards/arm/pandora_stm32l475/doc/index.rst +++ b/boards/arm/pandora_stm32l475/doc/index.rst @@ -1,7 +1,7 @@ .. _stm32l475ve_pandora_board: -ST STM32L475 Pandora -#################### +Alientek STM32L475 Pandora +########################## Overview ******** diff --git a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts index d2cc14979d4b..18e99e39e400 100644 --- a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts +++ b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts @@ -14,7 +14,7 @@ / { model = "STM32L475 Pandora Development Board"; - compatible = "st,pandora_stm32l475"; + compatible = "alientek,pandora_stm32l475"; aliases { led0 = &red_led; From 0b6077443db7cdca6242f165f910b9e1721f5919 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 16 Jun 2023 10:09:08 +0100 Subject: [PATCH 0440/2042] mgmt: mcumgr: grp: img_mgmt: Add optional mutex lock support Adds an optional Kconfig that adds mutex locks to image management group functions, this prevents collision between multiple threads and/or transports. Signed-off-by: Jamie McCrae --- .../mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 9 +++++ subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig | 11 ++++++ .../mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h | 12 ++++++ .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 38 ++++++++++++++++++- .../mcumgr/grp/img_mgmt/src/img_mgmt_state.c | 9 +++++ 5 files changed, 78 insertions(+), 1 deletion(-) 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 35a129b6ad37..36220c1d128f 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -332,6 +332,15 @@ int img_mgmt_state_confirm(void); */ int img_mgmt_vercmp(const struct image_version *a, const struct image_version *b); +#if IS_ENABLED(CONFIG_MCUMGR_GRP_IMG_MUTEX) +/* + * @brief Will reset the image management state back to default (no ongoing upload), + * requires that CONFIG_MCUMGR_GRP_IMG_MUTEX be enabled to allow for mutex + * locking of the image management state object. + */ +void img_mgmt_reset_upload(void); +#endif + #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL /* * @brief Translate IMG mgmt group error code into MCUmgr error code diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig index 1a028c0743f7..b97b6db84f3c 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig @@ -25,6 +25,7 @@ menuconfig MCUMGR_GRP_IMG if MCUMGR_GRP_IMG if HEAP_MEM_POOL_SIZE > 0 + config MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT bool "Use heap mem pool for flash image DFU context" help @@ -38,6 +39,7 @@ config MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT to allocate this context or it will not be possible to perform DFU; it may also not be possible to allocate such context when heap is under pressure, due to application operation, an issue that should also be addressed within application. + endif config MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER @@ -112,6 +114,15 @@ config MCUMGR_GRP_IMG_STATUS_HOOKS uploads. Note that these are status checking only, to allow inspecting of a file upload or prevent it, CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK must be used. +config MCUMGR_GRP_IMG_MUTEX + bool "Mutex locking" + help + This will enable use of a mutex to lock the image group object access, preventing issues + of concurrent thread (i.e. multiple transport) access. This option also makes the + ``img_mgmt_reset_upload()`` function visible in the image management group header, which + can be used by applications to reset the image management state (useful if there are + multiple ways that firmware updates can be loaded). + 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/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h b/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h index 57ed3854f0be..df26b4d10111 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/include/mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h @@ -134,6 +134,18 @@ int img_mgmt_erase_if_needed(uint32_t off, uint32_t len); int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, struct img_mgmt_upload_action *action); +/** + * @brief Takes the image management lock (if enabled) to prevent other + * threads interfering with an ongoing operation. + */ +void img_mgmt_take_lock(void); + +/** + * @brief Releases the held image management lock (if enabled) to allow + * other threads to use image management operations. + */ +void img_mgmt_release_lock(void); + #define ERASED_VAL_32(x) (((x) << 24) | ((x) << 16) | ((x) << 8) | (x)) int img_mgmt_erased_val(int slot, uint8_t *erased_val); diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 66df020bfc6f..bd94489db384 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -53,6 +53,10 @@ LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); struct img_mgmt_state g_img_mgmt_state; +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX +static K_MUTEX_DEFINE(img_mgmt_mutex); +#endif + #ifdef CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR const char *img_mgmt_err_str_app_reject = "app reject"; const char *img_mgmt_err_str_hdr_malformed = "header malformed"; @@ -65,6 +69,20 @@ const char *img_mgmt_err_str_downgrade = "downgrade"; const char *img_mgmt_err_str_image_bad_flash_addr = "img addr mismatch"; #endif +void img_mgmt_take_lock(void) +{ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX + k_mutex_lock(&img_mgmt_mutex, K_FOREVER); +#endif +} + +void img_mgmt_release_lock(void) +{ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX + k_mutex_unlock(&img_mgmt_mutex); +#endif +} + /** * Finds the TLVs in the specified image slot, if any. */ @@ -115,6 +133,7 @@ int img_mgmt_active_image(void) #endif return 0; } + /* * Reads the version and build hash from the specified image slot. */ @@ -263,10 +282,16 @@ img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver) /* * Resets upload status to defaults (no upload in progress) */ +#ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX void img_mgmt_reset_upload(void) +#else +static void img_mgmt_reset_upload(void) +#endif { + img_mgmt_take_lock(); memset(&g_img_mgmt_state, 0, sizeof(g_img_mgmt_state)); g_img_mgmt_state.area_id = -1; + img_mgmt_release_lock(); } static int @@ -312,6 +337,8 @@ img_mgmt_erase(struct smp_streamer *ctxt) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* * First check if image info is valid. * This check is done incase the flash area has a corrupted image. @@ -345,11 +372,14 @@ img_mgmt_erase(struct smp_streamer *ctxt) if (IS_ENABLED(CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR)) { if (!zcbor_tstr_put_lit(zse, "rc") || !zcbor_int32_put(zse, 0)) { + img_mgmt_release_lock(); return MGMT_ERR_EMSGSIZE; } } end: + img_mgmt_release_lock(); + return MGMT_ERR_EOK; } @@ -466,6 +496,8 @@ defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* Determine what actions to take as a result of this request. */ rc = img_mgmt_upload_inspect(&req, &action); if (rc != 0) { @@ -484,7 +516,9 @@ defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) /* Request specifies incorrect offset. Respond with a success code and * the correct offset. */ - return img_mgmt_upload_good_rsp(ctxt); + rc = img_mgmt_upload_good_rsp(ctxt); + img_mgmt_release_lock(); + return rc; } #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) @@ -680,6 +714,8 @@ defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) } } + img_mgmt_release_lock(); + if (!ok) { return MGMT_ERR_EMSGSIZE; } 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 eae5aaa3e8bd..2e673fff9780 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 @@ -245,6 +245,8 @@ img_mgmt_state_read(struct smp_streamer *ctxt) ok = zcbor_tstr_put_lit(zse, "images") && zcbor_list_start_encode(zse, 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER); + img_mgmt_take_lock(); + for (i = 0; ok && i < 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER; i++) { int rc = img_mgmt_read_info(i, &ver, hash, &flags); if (rc != 0) { @@ -291,6 +293,8 @@ img_mgmt_state_read(struct smp_streamer *ctxt) zcbor_int32_put(zse, 0); } + img_mgmt_release_lock(); + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; } @@ -385,6 +389,8 @@ img_mgmt_state_write(struct smp_streamer *ctxt) return MGMT_ERR_EINVAL; } + img_mgmt_take_lock(); + /* Determine which slot is being operated on. */ if (zhash.len == 0) { if (confirm) { @@ -423,10 +429,13 @@ img_mgmt_state_write(struct smp_streamer *ctxt) /* Send the current image state in the response. */ rc = img_mgmt_state_read(ctxt); if (rc != 0) { + img_mgmt_release_lock(); return rc; } end: + img_mgmt_release_lock(); + if (!ok) { return MGMT_ERR_EMSGSIZE; } From 6877ad413f076d7aa48582a1877748b1cca13d5f Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 19 Jun 2023 12:25:43 +0100 Subject: [PATCH 0441/2042] mgmt: mcumgr: smp: Allow preventing command execution via hook Adds status checking to the command status hook which allows an application to inspect a request and, optionally, reject it. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/smp/src/smp.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 75e11f2b6c63..56c9cc17b3b0 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -201,6 +201,7 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp mgmt_handler_fn handler_fn; int rc; #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) + enum mgmt_cb_return status; struct mgmt_evt_op_cmd_arg cmd_recv; int32_t ret_rc; uint16_t ret_group; @@ -229,18 +230,39 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp zcbor_map_start_encode(cbuf->writer->zs, CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); + MGMT_CTXT_SET_RC_RSN(cbuf, NULL); + #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; - (void)mgmt_callback_notify(MGMT_EVT_OP_CMD_RECV, &cmd_recv, sizeof(cmd_recv), - &ret_rc, &ret_group); + /* 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), + &ret_rc, &ret_group); + + /* Skip running the command if a handler reported an error and return that + * instead. + */ + if (status != MGMT_CB_OK) { + if (status == MGMT_CB_ERROR_RC) { + rc = ret_rc; + } else { + bool ok = smp_add_cmd_ret(cbuf->writer->zs, ret_group, + (uint16_t)ret_rc); + + rc = (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); + } + + goto end; + } #endif - MGMT_CTXT_SET_RC_RSN(cbuf, NULL); rc = handler_fn(cbuf); +#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) && From eff9f731b10b45d241cf8a963c7828cc7f7d5fbd Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 19 Jun 2023 12:30:13 +0100 Subject: [PATCH 0442/2042] doc: release: 3.5: Add note on MGMT_EVT_OP_CMD_RECV Adds a note that this MCUmgr notification hook can now be used to reject commands and send an error back to the client. Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.5.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index c532ff873e5c..7a77feb2ab85 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -232,6 +232,11 @@ Devicetree Libraries / Subsystems ********************** +* Management + + * Added response checking to MCUmgr's :c:enumerator:`MGMT_EVT_OP_CMD_RECV` + notification callback to allow applications to reject MCUmgr commands. + HALs **** From 84d8841497b519c32edefc3aeee7388aca7643fa Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 21 Jun 2023 11:09:35 +0000 Subject: [PATCH 0443/2042] MAINTAINERS: add twister related files to area Add pytest plugin and related documenation. Also add gchwier to collabs. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7bafdc0be0e1..4498ca3040cd 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2032,11 +2032,14 @@ Twister: - hakehuang - gopiotr - golowanow + - gchwier files: - scripts/twister - scripts/pylib/twister/ - scripts/tests/twister/ - doc/develop/test/twister.rst + - scripts/pylib/pytest-twister-harness/ + - doc/develop/test/pytest.rst labels: - "area: Twister" From bf4977e41b02f0ce79fff7280032431d184a0c90 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 21 Jun 2023 04:13:15 -0400 Subject: [PATCH 0444/2042] drivers: rtc: mc146818: changes for y2k test The year needs to be corrected to an offset from 1900. Signed-off-by: Christopher Friedt --- drivers/rtc/rtc_mc146818.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c index 58177b10c866..f34b76d66a14 100644 --- a/drivers/rtc/rtc_mc146818.c +++ b/drivers/rtc/rtc_mc146818.c @@ -191,8 +191,8 @@ static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time value = rtc_read(RTC_DATA); rtc_write(RTC_DATA, value | RTC_UCI_BIT); - year = (1970 + timeptr->tm_year) % 100; - cent = (1970 + timeptr->tm_year) / 100; + year = (1900 + timeptr->tm_year) % 100; + cent = (1900 + timeptr->tm_year) / 100; if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { rtc_write(RTC_SEC, (uint8_t)bin2bcd(timeptr->tm_sec)); @@ -271,7 +271,7 @@ static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *tim timeptr->tm_sec = bcd2bin(timeptr->tm_sec); } - timeptr->tm_year = 100 * (int)cent + year - 1970; + timeptr->tm_year = 100 * (int)cent + year - 1900; timeptr->tm_nsec = 0; timeptr->tm_yday = 0; From d4ea1c920bab8aec7a9380ebeef98cba9090a217 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 20 Jun 2023 15:51:27 -0400 Subject: [PATCH 0445/2042] tests: drivers: rtc: add a y2k test Ensure that the RTC is capable of transitioning from Dec 31, 1999 to Jan 1, 2000. Signed-off-by: Christopher Friedt --- tests/drivers/rtc/rtc_api/CMakeLists.txt | 1 + tests/drivers/rtc/rtc_api/src/test_y2k.c | 58 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/drivers/rtc/rtc_api/src/test_y2k.c diff --git a/tests/drivers/rtc/rtc_api/CMakeLists.txt b/tests/drivers/rtc/rtc_api/CMakeLists.txt index bef2a923f1db..69f8bfbf1e4d 100644 --- a/tests/drivers/rtc/rtc_api/CMakeLists.txt +++ b/tests/drivers/rtc/rtc_api/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(app PRIVATE src/main.c src/test_time_incrementing.c src/test_time.c + src/test_y2k.c ) if(DEFINED CONFIG_RTC_ALARM) diff --git a/tests/drivers/rtc/rtc_api/src/test_y2k.c b/tests/drivers/rtc/rtc_api/src/test_y2k.c new file mode 100644 index 000000000000..2d7e95aeb1bd --- /dev/null +++ b/tests/drivers/rtc/rtc_api/src/test_y2k.c @@ -0,0 +1,58 @@ +/* + * Copyright 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +/* date "+%s" -d "Sat Jan 1 2000 00:00:00 GMT+0000" */ +#define Y2K_STAMP 946684800UL + +#define SECONDS_BEFORE 1 +#define SECONDS_AFTER 1 + +#define RTC_TEST_START_TIME (Y2K_STAMP - SECONDS_BEFORE) +#define RTC_TEST_STOP_TIME (Y2K_STAMP + SECONDS_AFTER) + +static const struct device *rtc = DEVICE_DT_GET(DT_ALIAS(rtc)); + +ZTEST(rtc_api, test_y2k) +{ + enum test_time { + Y99, + Y2K, + }; + + static struct rtc_time rtm[2]; + struct tm *const tm[2] = { + (struct tm *const)&rtm[0], + (struct tm *const)&rtm[1], + }; + const time_t t[] = { + [Y99] = RTC_TEST_START_TIME, + [Y2K] = RTC_TEST_STOP_TIME, + }; + + /* Party like it's 1999 */ + zassert_not_null(gmtime_r(&t[Y99], tm[Y99])); + zassert_ok(rtc_set_time(rtc, &rtm[Y99])); + + /* Living after midnight */ + k_sleep(K_SECONDS(SECONDS_BEFORE + SECONDS_AFTER)); + zassert_ok(rtc_get_time(rtc, &rtm[Y2K])); + + /* It's the end of the world as we know it */ + zassert_equal(rtm[Y2K].tm_year + 1900, 2000, "wrong year: %d", rtm[Y2K].tm_year + 1900); + zassert_equal(rtm[Y2K].tm_mon, 0, "wrong month: %d", rtm[Y2K].tm_mon); + zassert_equal(rtm[Y2K].tm_mday, 1, "wrong day-of-month: %d", rtm[Y2K].tm_mday); + zassert_equal(rtm[Y2K].tm_yday, 0, "wrong day-of-year: %d", rtm[Y2K].tm_yday); + zassert_equal(rtm[Y2K].tm_wday, 6, "wrong day-of-week: %d", rtm[Y2K].tm_wday); + zassert_equal(rtm[Y2K].tm_hour, 0, "wrong hour: %d", rtm[Y2K].tm_hour); + zassert_equal(rtm[Y2K].tm_min, 0, "wrong minute: %d", rtm[Y2K].tm_min); + zassert_equal(rtm[Y2K].tm_sec, SECONDS_AFTER, "wrong second: %d", rtm[Y2K].tm_sec); +} From 8c7140a9c0dcbf391d337a56d01f56233f0ae808 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 13 Jun 2023 09:18:16 +0530 Subject: [PATCH 0446/2042] Bluetooth: Controller: Fix BT_CTLR_CENTRAL_SPACING to ticks conversion Fix missing BT_CTLR_CENTRAL_SPACING in microseconds to ticks conversion. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_sched.c b/subsys/bluetooth/controller/ll_sw/ull_sched.c index d9e043ccc05d..8a363500b0d1 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_sched.c +++ b/subsys/bluetooth/controller/ll_sw/ull_sched.c @@ -752,7 +752,7 @@ static struct ull_hdr *ull_hdr_get_cb(uint8_t ticker_id, uint32_t *ticks_slot) *ticks_slot = conn->ull.ticks_slot; } - if (*ticks_slot < CONFIG_BT_CTLR_CENTRAL_SPACING) { + if (*ticks_slot < HAL_TICKER_US_TO_TICKS(CONFIG_BT_CTLR_CENTRAL_SPACING)) { *ticks_slot = HAL_TICKER_US_TO_TICKS(CONFIG_BT_CTLR_CENTRAL_SPACING); } From 3cbc2249cef93d88ea574ff4c3fde5098135c855 Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Mon, 19 Jun 2023 13:46:08 +0200 Subject: [PATCH 0447/2042] os: spsc_buf: Clarify claim function doc This clarifies the spsc_buf_claim function documentation. It should be easier now to understand what this function does and what are returned memory properties. Signed-off-by: Kamil Gawor --- include/zephyr/sys/spsc_pbuf.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/zephyr/sys/spsc_pbuf.h b/include/zephyr/sys/spsc_pbuf.h index 26e0104270db..09459edd4eb4 100644 --- a/include/zephyr/sys/spsc_pbuf.h +++ b/include/zephyr/sys/spsc_pbuf.h @@ -90,7 +90,7 @@ struct spsc_pbuf_ext_nocache { * * The SPSC packet buffer implements lightweight unidirectional packet buffer * with read/write semantics on top of a memory region shared - * by the reader and writer. It optionally embeds cache and memory barier + * by the reader and writer. It optionally embeds cache and memory barrier * management to ensure correct data access. * * This structure supports single writer and reader. Data stored in the buffer @@ -190,7 +190,7 @@ int spsc_pbuf_alloc(struct spsc_pbuf *pb, uint16_t len, char **buf); * @brief Commit packet to the buffer. * * Commit a packet which was previously allocated (@ref spsc_pbuf_alloc). - * If cache is used, cache writeback is perfromed on the written data. + * If cache is used, cache writeback is performed on the written data. * * @param pb A buffer to which to write. * @param len Packet length. Must be equal or less than the length used for allocation. @@ -219,12 +219,16 @@ int spsc_pbuf_read(struct spsc_pbuf *pb, char *buf, uint16_t len); /** * @brief Claim packet from the buffer. * - * Claimed packet must be freed using @ref spsc_pbuf_free. + * It claims a single packet from the buffer in the order of the commitment + * by the @ref spsc_pbuf_commit function. The first commited packet will be claimed first. + * The returned buffer is 32 bit word aligned and points to the continuous memory. + * Claimed packet must be freed using the @ref spsc_pbuf_free function. * * @note If data cache is used, cache is invalidate on the packet. * * @param[in] pb A buffer from which packet will be claimed. * @param[in,out] buf A location where claimed packet address is written. + * It is 32 bit word aligned and points to the continuous memory. * * @retval 0 No packets in the buffer. * @retval positive packet length. From b7f14ee94fe9c1a322199ed300560d534c277f5f Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Fri, 16 Jun 2023 08:53:04 +0200 Subject: [PATCH 0448/2042] ipc: icmsg: Improve packets reception This improves packet reception and fix an issue where packets bigger than internal Rx buffer were silently dropped. In current solution local data coping for reception is not needed. User gets direct pointer to shared memory which allow to efficient receive as much data as was sent. Signed-off-by: Kamil Gawor --- include/zephyr/ipc/icmsg.h | 8 +- include/zephyr/sys/spsc_pbuf.h | 2 +- subsys/ipc/ipc_service/lib/Kconfig.icmsg | 10 --- subsys/ipc/ipc_service/lib/icmsg.c | 101 ++++++++++++++++------- 4 files changed, 75 insertions(+), 46 deletions(-) diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index 6c03df42be32..b7627e2c8e12 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -45,7 +45,7 @@ struct icmsg_data_t { /* Tx/Rx buffers. */ struct spsc_pbuf *tx_ib; struct spsc_pbuf *rx_ib; - atomic_t send_buffer_reserved; + atomic_t send_buffer_state; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC struct k_mutex send; #endif @@ -59,11 +59,11 @@ struct icmsg_data_t { struct k_work_delayable notify_work; struct k_work mbox_work; atomic_t state; - uint8_t rx_buffer[CONFIG_IPC_SERVICE_ICMSG_CB_BUF_SIZE] __aligned(4); - /* No-copy */ #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - atomic_t rx_buffer_held; + atomic_t rx_buffer_state; + const void *rx_buffer; + uint16_t rx_len; #endif }; diff --git a/include/zephyr/sys/spsc_pbuf.h b/include/zephyr/sys/spsc_pbuf.h index 09459edd4eb4..682d610e34b4 100644 --- a/include/zephyr/sys/spsc_pbuf.h +++ b/include/zephyr/sys/spsc_pbuf.h @@ -220,7 +220,7 @@ int spsc_pbuf_read(struct spsc_pbuf *pb, char *buf, uint16_t len); * @brief Claim packet from the buffer. * * It claims a single packet from the buffer in the order of the commitment - * by the @ref spsc_pbuf_commit function. The first commited packet will be claimed first. + * by the @ref spsc_pbuf_commit function. The first committed packet will be claimed first. * The returned buffer is 32 bit word aligned and points to the continuous memory. * Claimed packet must be freed using the @ref spsc_pbuf_free function. * diff --git a/subsys/ipc/ipc_service/lib/Kconfig.icmsg b/subsys/ipc/ipc_service/lib/Kconfig.icmsg index 293f8cfa12a2..6847844d67a1 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig.icmsg +++ b/subsys/ipc/ipc_service/lib/Kconfig.icmsg @@ -1,16 +1,6 @@ # Copyright (c) 2022 Nordic Semiconductor (ASA) # SPDX-License-Identifier: Apache-2.0 -config IPC_SERVICE_ICMSG_CB_BUF_SIZE - int "Size of callback buffer size" - range 1 65535 - default 255 - help - Size of callback buffer used for processing received data in work - queue thread. If you are sure that your application never sends data - data bigger than some size, you can safely change this option to - reduce RAM consumption in your application. - config IPC_SERVICE_ICMSG_NOCOPY_RX bool depends on IPC_SERVICE_ICMSG diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index b28e15aa8964..b9d99a000fcf 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -11,19 +11,22 @@ #include #include -#define RX_BUF_SIZE CONFIG_IPC_SERVICE_ICMSG_CB_BUF_SIZE #define BOND_NOTIFY_REPEAT_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS) #define SHMEM_ACCESS_TO K_MSEC(CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_TO_MS) -#define RX_BUFFER_RELEASED 0 -#define RX_BUFFER_HELD 1 -#define SEND_BUFFER_UNUSED 0 -#define SEND_BUFFER_RESERVED 1 +enum rx_buffer_state { + RX_BUFFER_STATE_RELEASED, + RX_BUFFER_STATE_RELEASING, + RX_BUFFER_STATE_HELD +}; + +enum send_buffer_state { + SEND_BUFFER_STATE_UNUSED, + SEND_BUFFER_STATE_RESERVED +}; static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, 0x30, 0x72, 0x6e, 0x33, 0x6c, 0x69, 0x34}; -BUILD_ASSERT(sizeof(magic) <= RX_BUF_SIZE); -BUILD_ASSERT(RX_BUF_SIZE <= UINT16_MAX); static int mbox_deinit(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data) @@ -72,8 +75,8 @@ static bool is_endpoint_ready(struct icmsg_data_t *dev_data) static bool is_send_buffer_reserved(struct icmsg_data_t *dev_data) { - return atomic_get(&dev_data->send_buffer_reserved) == - SEND_BUFFER_RESERVED; + return atomic_get(&dev_data->send_buffer_state) == + SEND_BUFFER_STATE_RESERVED; } static int reserve_send_buffer_if_unused(struct icmsg_data_t *dev_data) @@ -86,16 +89,16 @@ static int reserve_send_buffer_if_unused(struct icmsg_data_t *dev_data) } #endif - bool was_unused = atomic_cas(&dev_data->send_buffer_reserved, - SEND_BUFFER_UNUSED, SEND_BUFFER_RESERVED); + bool was_unused = atomic_cas(&dev_data->send_buffer_state, + SEND_BUFFER_STATE_UNUSED, SEND_BUFFER_STATE_RESERVED); return was_unused ? 0 : -EALREADY; } static int release_send_buffer(struct icmsg_data_t *dev_data) { - bool was_reserved = atomic_cas(&dev_data->send_buffer_reserved, - SEND_BUFFER_RESERVED, SEND_BUFFER_UNUSED); + bool was_reserved = atomic_cas(&dev_data->send_buffer_state, + SEND_BUFFER_STATE_RESERVED, SEND_BUFFER_STATE_UNUSED); if (!was_reserved) { return -EALREADY; @@ -108,16 +111,24 @@ static int release_send_buffer(struct icmsg_data_t *dev_data) #endif } - static bool is_rx_buffer_free(struct icmsg_data_t *dev_data) { #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX - return atomic_get(&dev_data->rx_buffer_held) == RX_BUFFER_RELEASED; + return atomic_get(&dev_data->rx_buffer_state) == RX_BUFFER_STATE_RELEASED; #else return true; #endif } +static bool is_rx_buffer_held(struct icmsg_data_t *dev_data) +{ +#ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX + return atomic_get(&dev_data->rx_buffer_state) == RX_BUFFER_STATE_HELD; +#else + return false; +#endif +} + static bool is_rx_data_available(struct icmsg_data_t *dev_data) { int len = spsc_pbuf_read(dev_data->rx_ib, NULL, 0); @@ -159,31 +170,48 @@ static void submit_work_if_buffer_free_and_data_available( static void mbox_callback_process(struct k_work *item) { + char *rx_buffer; struct icmsg_data_t *dev_data = CONTAINER_OF(item, struct icmsg_data_t, mbox_work); atomic_t state = atomic_get(&dev_data->state); - int len = spsc_pbuf_read(dev_data->rx_ib, dev_data->rx_buffer, - RX_BUF_SIZE); - __ASSERT_NO_MSG(len <= RX_BUF_SIZE); + uint16_t len = spsc_pbuf_claim(dev_data->rx_ib, &rx_buffer); - if (len == -EAGAIN) { - __ASSERT_NO_MSG(false); - submit_mbox_work(dev_data); - return; - } else if (len <= 0) { + if (len == 0) { + /* Unlikely, no data in buffer. */ return; } if (state == ICMSG_STATE_READY) { if (dev_data->cb->received) { - dev_data->cb->received(dev_data->rx_buffer, len, +#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX + dev_data->rx_buffer = rx_buffer; + dev_data->rx_len = len; +#endif + + dev_data->cb->received(rx_buffer, len, dev_data->ctx); + + /* Release Rx buffer here only in case when user did not request + * to hold it. + */ + if (!is_rx_buffer_held(dev_data)) { + spsc_pbuf_free(dev_data->rx_ib, len); + +#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX + dev_data->rx_buffer = NULL; + dev_data->rx_len = 0; +#endif + } } } else { __ASSERT_NO_MSG(state == ICMSG_STATE_BUSY); - if (len != sizeof(magic) || - memcmp(magic, dev_data->rx_buffer, len)) { + + bool endpoint_invalid = (len != sizeof(magic) || memcmp(magic, rx_buffer, len)); + + spsc_pbuf_free(dev_data->rx_ib, len); + + if (endpoint_invalid) { __ASSERT_NO_MSG(false); return; } @@ -202,7 +230,6 @@ static void mbox_callback(const struct device *instance, uint32_t channel, void *user_data, struct mbox_msg *msg_data) { struct icmsg_data_t *dev_data = user_data; - submit_work_if_buffer_free(dev_data); } @@ -446,8 +473,8 @@ int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf, return -EINVAL; } - was_released = atomic_cas(&dev_data->rx_buffer_held, - RX_BUFFER_RELEASED, RX_BUFFER_HELD); + was_released = atomic_cas(&dev_data->rx_buffer_state, + RX_BUFFER_STATE_RELEASED, RX_BUFFER_STATE_HELD); if (!was_released) { return -EALREADY; } @@ -469,12 +496,24 @@ int icmsg_release_rx_buffer(const struct icmsg_config_t *conf, return -EINVAL; } - was_held = atomic_cas(&dev_data->rx_buffer_held, - RX_BUFFER_HELD, RX_BUFFER_RELEASED); + /* Do not schedule new packet processing until buffer will be released. + * Protect buffer against being freed multiple times. + */ + was_held = atomic_cas(&dev_data->rx_buffer_state, + RX_BUFFER_STATE_HELD, RX_BUFFER_STATE_RELEASING); if (!was_held) { return -EALREADY; } + spsc_pbuf_free(dev_data->rx_ib, dev_data->rx_len); + +#if CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX + dev_data->rx_buffer = NULL; + dev_data->rx_len = 0; +#endif + + atomic_set(&dev_data->rx_buffer_state, RX_BUFFER_STATE_RELEASED); + submit_work_if_buffer_free_and_data_available(dev_data); return 0; From 82bff6227645d9101c1139e2404d5caeae218fc8 Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Tue, 20 Jun 2023 14:42:22 +0200 Subject: [PATCH 0449/2042] ipc: icmsg: Align naming for buffers This remanes send_buffer to tx_buffer to be consistent with Rx buffer naming and with mbox naming. Signed-off-by: Kamil Gawor --- include/zephyr/ipc/icmsg.h | 4 +-- subsys/ipc/ipc_service/lib/icmsg.c | 46 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/zephyr/ipc/icmsg.h b/include/zephyr/ipc/icmsg.h index b7627e2c8e12..cdd1cb064d1e 100644 --- a/include/zephyr/ipc/icmsg.h +++ b/include/zephyr/ipc/icmsg.h @@ -45,9 +45,9 @@ struct icmsg_data_t { /* Tx/Rx buffers. */ struct spsc_pbuf *tx_ib; struct spsc_pbuf *rx_ib; - atomic_t send_buffer_state; + atomic_t tx_buffer_state; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC - struct k_mutex send; + struct k_mutex tx_lock; #endif /* Callbacks for an endpoint. */ diff --git a/subsys/ipc/ipc_service/lib/icmsg.c b/subsys/ipc/ipc_service/lib/icmsg.c index b9d99a000fcf..b0b9ad11e5b9 100644 --- a/subsys/ipc/ipc_service/lib/icmsg.c +++ b/subsys/ipc/ipc_service/lib/icmsg.c @@ -20,9 +20,9 @@ enum rx_buffer_state { RX_BUFFER_STATE_HELD }; -enum send_buffer_state { - SEND_BUFFER_STATE_UNUSED, - SEND_BUFFER_STATE_RESERVED +enum tx_buffer_state { + TX_BUFFER_STATE_UNUSED, + TX_BUFFER_STATE_RESERVED }; static const uint8_t magic[] = {0x45, 0x6d, 0x31, 0x6c, 0x31, 0x4b, @@ -73,39 +73,39 @@ static bool is_endpoint_ready(struct icmsg_data_t *dev_data) return atomic_get(&dev_data->state) == ICMSG_STATE_READY; } -static bool is_send_buffer_reserved(struct icmsg_data_t *dev_data) +static bool is_tx_buffer_reserved(struct icmsg_data_t *dev_data) { - return atomic_get(&dev_data->send_buffer_state) == - SEND_BUFFER_STATE_RESERVED; + return atomic_get(&dev_data->tx_buffer_state) == + TX_BUFFER_STATE_RESERVED; } -static int reserve_send_buffer_if_unused(struct icmsg_data_t *dev_data) +static int reserve_tx_buffer_if_unused(struct icmsg_data_t *dev_data) { #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC - int ret = k_mutex_lock(&dev_data->send, SHMEM_ACCESS_TO); + int ret = k_mutex_lock(&dev_data->tx_lock, SHMEM_ACCESS_TO); if (ret < 0) { return ret; } #endif - bool was_unused = atomic_cas(&dev_data->send_buffer_state, - SEND_BUFFER_STATE_UNUSED, SEND_BUFFER_STATE_RESERVED); + bool was_unused = atomic_cas(&dev_data->tx_buffer_state, + TX_BUFFER_STATE_UNUSED, TX_BUFFER_STATE_RESERVED); return was_unused ? 0 : -EALREADY; } -static int release_send_buffer(struct icmsg_data_t *dev_data) +static int release_tx_buffer(struct icmsg_data_t *dev_data) { - bool was_reserved = atomic_cas(&dev_data->send_buffer_state, - SEND_BUFFER_STATE_RESERVED, SEND_BUFFER_STATE_UNUSED); + bool was_reserved = atomic_cas(&dev_data->tx_buffer_state, + TX_BUFFER_STATE_RESERVED, TX_BUFFER_STATE_UNUSED); if (!was_reserved) { return -EALREADY; } #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC - return k_mutex_unlock(&dev_data->send); + return k_mutex_unlock(&dev_data->tx_lock); #else return 0; #endif @@ -265,7 +265,7 @@ int icmsg_open(const struct icmsg_config_t *conf, dev_data->cfg = conf; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC - k_mutex_init(&dev_data->send); + k_mutex_init(&dev_data->tx_lock); #endif dev_data->tx_ib = spsc_pbuf_init((void *)conf->tx_shm_addr, @@ -331,13 +331,13 @@ int icmsg_send(const struct icmsg_config_t *conf, return -ENODATA; } - ret = reserve_send_buffer_if_unused(dev_data); + ret = reserve_tx_buffer_if_unused(dev_data); if (ret < 0) { return -ENOBUFS; } write_ret = spsc_pbuf_write(dev_data->tx_ib, msg, len); - release_ret = release_send_buffer(dev_data); + release_ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!release_ret); if (write_ret < 0) { @@ -377,14 +377,14 @@ int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, requested_size = *size; } - ret = reserve_send_buffer_if_unused(dev_data); + ret = reserve_tx_buffer_if_unused(dev_data); if (ret < 0) { return -ENOBUFS; } ret = spsc_pbuf_alloc(dev_data->tx_ib, requested_size, &allocated_buf); if (ret < 0) { - release_ret = release_send_buffer(dev_data); + release_ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!release_ret); return ret; } @@ -408,7 +408,7 @@ int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, /* Allocated smaller buffer than requested. * Silently stop using the allocated buffer what is allowed by SPSC API */ - release_send_buffer(dev_data); + release_tx_buffer(dev_data); *size = allocated_len; return -ENOMEM; } @@ -419,7 +419,7 @@ int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf, { /* Silently stop using the allocated buffer what is allowed by SPSC API */ - return release_send_buffer(dev_data); + return release_tx_buffer(dev_data); } int icmsg_send_nocopy(const struct icmsg_config_t *conf, @@ -438,14 +438,14 @@ int icmsg_send_nocopy(const struct icmsg_config_t *conf, return -ENODATA; } - if (!is_send_buffer_reserved(dev_data)) { + if (!is_tx_buffer_reserved(dev_data)) { return -ENXIO; } spsc_pbuf_commit(dev_data->tx_ib, len); sent_bytes = len; - ret = release_send_buffer(dev_data); + ret = release_tx_buffer(dev_data); __ASSERT_NO_MSG(!ret); __ASSERT_NO_MSG(conf->mbox_tx.dev != NULL); From 0ea2e7c906b8be128d1185a01de1c8ed7a02da34 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Thu, 13 Apr 2023 16:02:31 +0200 Subject: [PATCH 0450/2042] drivers: flash: stm32 ospi: move STM32 OSPI node Move `STM32_OSPI_NODE` to the top. That allows its usage in other macros that require OSPI bus. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_ospi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 9c1120ecdc48..35c6c0038562 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -29,11 +29,13 @@ #include LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); +#define STM32_OSPI_NODE DT_INST_PARENT(0) + #define STM32_OSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) -#define STM32_OSPI_DLYB_BYPASSED DT_PROP(DT_PARENT(DT_DRV_INST(0)), dlyb_bypass) +#define STM32_OSPI_DLYB_BYPASSED DT_PROP(STM32_OSPI_NODE, dlyb_bypass) -#define STM32_OSPI_USE_DMA DT_NODE_HAS_PROP(DT_PARENT(DT_DRV_INST(0)), dmas) +#define STM32_OSPI_USE_DMA DT_NODE_HAS_PROP(STM32_OSPI_NODE, dmas) #if STM32_OSPI_USE_DMA #include @@ -118,8 +120,6 @@ struct stream { typedef void (*irq_config_func_t)(const struct device *dev); -#define STM32_OSPI_NODE DT_INST_PARENT(0) - struct flash_stm32_ospi_config { OCTOSPI_TypeDef *regs; const struct stm32_pclken pclken; /* clock subsystem */ From 5cde75688e806225dbb27b99f3c606f14b207f47 Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Thu, 13 Apr 2023 16:10:09 +0200 Subject: [PATCH 0451/2042] dts: bindings: ospi: add ospim io ports Adds properties to configure OCTOSPI IO Manager data lines. That allows to use any `IOLowPort` and `IOHightPort`. Note: OSPIM requires additional clock to be enabled. Please refer to Reference Manual. Extra clock can be enabled in devicetree. Signed-off-by: Georgij Cernysiov --- dts/bindings/ospi/st,stm32-ospi.yaml | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/dts/bindings/ospi/st,stm32-ospi.yaml b/dts/bindings/ospi/st,stm32-ospi.yaml index 7235f130bf19..aaac4141455f 100644 --- a/dts/bindings/ospi/st,stm32-ospi.yaml +++ b/dts/bindings/ospi/st,stm32-ospi.yaml @@ -81,3 +81,41 @@ properties: Enables Sample Shifting half-cycle. It is recommended to be enabled in STR mode and disabled in DTR mode. + + io-low-port: + type: string + enum: + - "IOPORT_NONE" + - "IOPORT_1_LOW" + - "IOPORT_1_HIGH" + - "IOPORT_2_LOW" + - "IOPORT_2_HIGH" + description: | + Specifies which port of the OCTOSPI IO Manager is used for the IO[3:0] pins. + + If absent, then `IOPORT__LOW` is used where `n` is the OSPI + instance number. + + Note: You might need to enable the OCTOSPI I/O manager clock to use the + property. Please refer to Reference Manual. + The clock can be enabled in the devicetree. + + io-high-port: + type: string + enum: + - "IOPORT_NONE" + - "IOPORT_1_LOW" + - "IOPORT_1_HIGH" + - "IOPORT_2_LOW" + - "IOPORT_2_HIGH" + description: | + Specifies which port of the OCTOSPI IO Manager is used for the IO[7:4] pins. + + If absent, then `IOPORT__HIGH` is used where `n` is the OSPI + instance number. + + Can be set to `IOPORT_NONE` for Single SPI, Dual SPI and Quad SPI. + + Note: You might need to enable the OCTOSPI I/O manager clock to use the + property. Please refer to Reference Manual. + The clock can be enabled in the devicetree. From f09e3abbcbaab9ebd23d75e45ec97568bc06e91b Mon Sep 17 00:00:00 2001 From: Georgij Cernysiov Date: Thu, 13 Apr 2023 16:13:18 +0200 Subject: [PATCH 0452/2042] drivers: flash: stm32 ospi: configure ospim io ports Allows to configure OSPI Manager IO ports with devicetree. If properties are absent, then original default values are preserved for compatibility. Signed-off-by: Georgij Cernysiov --- drivers/flash/flash_stm32_ospi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index 35c6c0038562..8e6d671c7596 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -31,6 +31,11 @@ LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); #define STM32_OSPI_NODE DT_INST_PARENT(0) +#define DT_OSPI_IO_PORT_PROP_OR(prop, default_value) \ + COND_CODE_1(DT_NODE_HAS_PROP(STM32_OSPI_NODE, prop), \ + (_CONCAT(HAL_OSPIM_, DT_STRING_TOKEN(STM32_OSPI_NODE, prop))), \ + ((default_value))) + #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) @@ -2069,14 +2074,18 @@ static int flash_stm32_ospi_init(const struct device *dev) ospi_mgr_cfg.ClkPort = 1; ospi_mgr_cfg.DQSPort = 1; ospi_mgr_cfg.NCSPort = 1; - ospi_mgr_cfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW; - ospi_mgr_cfg.IOHighPort = HAL_OSPIM_IOPORT_1_HIGH; + ospi_mgr_cfg.IOLowPort = DT_OSPI_IO_PORT_PROP_OR(io_low_port, + HAL_OSPIM_IOPORT_1_LOW); + ospi_mgr_cfg.IOHighPort = DT_OSPI_IO_PORT_PROP_OR(io_high_port, + HAL_OSPIM_IOPORT_1_HIGH); } else if (dev_data->hospi.Instance == OCTOSPI2) { ospi_mgr_cfg.ClkPort = 2; ospi_mgr_cfg.DQSPort = 2; ospi_mgr_cfg.NCSPort = 2; - ospi_mgr_cfg.IOLowPort = HAL_OSPIM_IOPORT_2_LOW; - ospi_mgr_cfg.IOHighPort = HAL_OSPIM_IOPORT_2_HIGH; + ospi_mgr_cfg.IOLowPort = DT_OSPI_IO_PORT_PROP_OR(io_low_port, + HAL_OSPIM_IOPORT_2_LOW); + ospi_mgr_cfg.IOHighPort = DT_OSPI_IO_PORT_PROP_OR(io_high_port, + HAL_OSPIM_IOPORT_2_HIGH); } #if defined(OCTOSPIM_CR_MUXEN) ospi_mgr_cfg.Req2AckTime = 1; From b0612e14e0e94e61ee792fffaabf924185af2793 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 23 May 2023 17:31:48 +0800 Subject: [PATCH 0453/2042] arch: arm: save 'fpscr' in the svc and isr handler `fpscr` is assigned from `struct __fpu_sf.fpscr` in `vfp_restore`, but it wasn't saved into `struct __fpu_sf.fpscr` in the svc and isr handler, So it may be a dirty value. - Fix it by saving `fpscr` in the svc hand isr handler. - Jump out if FPU isn't enabled Signed-off-by: Huifeng Zhang --- arch/arm/core/aarch32/isr_wrapper.S | 5 +++++ arch/arm/core/aarch32/swap_helper.S | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/core/aarch32/isr_wrapper.S b/arch/arm/core/aarch32/isr_wrapper.S index 82e4633634bd..205420c5dcc2 100644 --- a/arch/arm/core/aarch32/isr_wrapper.S +++ b/arch/arm/core/aarch32/isr_wrapper.S @@ -98,11 +98,16 @@ isr_system_thread: */ vmrs r0, fpexc str r0, [sp, #___fpu_t_SIZEOF - 4] + tst r0, #FPEXC_EN + beq _vfp_not_enabled + vmrs r0, fpscr + str r0, [sp, #___fpu_t_SIZEOF - 8] /* Disable VFP */ mov r0, #0 vmsr fpexc, r0 +_vfp_not_enabled: /* * Mark where to store the floating context for the undefined * instruction handler diff --git a/arch/arm/core/aarch32/swap_helper.S b/arch/arm/core/aarch32/swap_helper.S index 119bd9861286..4de2df7177a7 100644 --- a/arch/arm/core/aarch32/swap_helper.S +++ b/arch/arm/core/aarch32/swap_helper.S @@ -746,11 +746,16 @@ svc_system_thread: */ vmrs r0, fpexc str r0, [sp, #___fpu_t_SIZEOF - 4] + tst r0, #FPEXC_EN + beq _vfp_not_enabled + vmrs r0, fpscr + str r0, [sp, #___fpu_t_SIZEOF - 8] /* Disable VFP */ mov r0, #0 vmsr fpexc, r0 +_vfp_not_enabled: /* * Mark where to store the floating context for the undefined * instruction handler From 89ea503b29e17f42e060251cd5307bba79463f51 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 23 May 2023 18:28:14 +0800 Subject: [PATCH 0454/2042] arch: arm: Add support for 32 double-precision registers This adds support for 32 double-precision registers in the context switching of aarch32 architecture. Signed-off-by: Huifeng Zhang --- arch/arm/core/aarch32/Kconfig.vfp | 1 + arch/arm/core/aarch32/cortex_a_r/exc.S | 6 +++++ arch/arm/core/aarch32/cortex_a_r/exc_exit.S | 6 ++++- arch/arm/core/aarch32/cortex_a_r/fault.c | 30 ++++++++++++++------- arch/arm/core/aarch32/fatal.c | 10 +++++++ arch/arm/core/aarch32/swap_helper.S | 3 +++ include/zephyr/arch/arm/aarch32/exc.h | 13 ++++++++- 7 files changed, 57 insertions(+), 12 deletions(-) diff --git a/arch/arm/core/aarch32/Kconfig.vfp b/arch/arm/core/aarch32/Kconfig.vfp index ca300651d14a..69b6c3df82d7 100644 --- a/arch/arm/core/aarch32/Kconfig.vfp +++ b/arch/arm/core/aarch32/Kconfig.vfp @@ -154,6 +154,7 @@ config VFP_FEATURE_SINGLE_PRECISION config VFP_FEATURE_DOUBLE_PRECISION bool + select CPU_HAS_FPU_DOUBLE_PRECISION help This option signifies that the VFP coprocessor supports double-precision operations. diff --git a/arch/arm/core/aarch32/cortex_a_r/exc.S b/arch/arm/core/aarch32/cortex_a_r/exc.S index 8cec70b807e8..87742b398081 100644 --- a/arch/arm/core/aarch32/cortex_a_r/exc.S +++ b/arch/arm/core/aarch32/cortex_a_r/exc.S @@ -60,6 +60,9 @@ GTEXT(z_arm_data_abort) mov r2, sp vstmia r2!, {s0-s15} +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + vstmia r2!, {d16-d31} +#endif stm r2, {r0, r1} #endif @@ -144,6 +147,9 @@ SECTION_SUBSEC_FUNC(TEXT, __exc, z_arm_undef_instruction) mov r2, sp vstmia r2!, {s0-s15} +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + vstmia r2!, {d16-d31} +#endif stm r2, {r0, r1} #endif diff --git a/arch/arm/core/aarch32/cortex_a_r/exc_exit.S b/arch/arm/core/aarch32/cortex_a_r/exc_exit.S index 2978f64ae0e0..5706a3905004 100644 --- a/arch/arm/core/aarch32/cortex_a_r/exc_exit.S +++ b/arch/arm/core/aarch32/cortex_a_r/exc_exit.S @@ -90,7 +90,11 @@ vfp_restore\@: vmsr fpexc, r2 vmsr fpscr, r1 - vldmia sp, {s0-s15} + mov r3, sp + vldmia r3!, {s0-s15} +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + vldmia r3!, {d16-d31} +#endif vfp_exit\@: /* Leave the VFP disabled when leaving */ diff --git a/arch/arm/core/aarch32/cortex_a_r/fault.c b/arch/arm/core/aarch32/cortex_a_r/fault.c index 8d7cc6ded323..5d1e17b2d146 100644 --- a/arch/arm/core/aarch32/cortex_a_r/fault.c +++ b/arch/arm/core/aarch32/cortex_a_r/fault.c @@ -97,6 +97,24 @@ static uint32_t dump_fault(uint32_t status, uint32_t addr) #endif #if defined(CONFIG_FPU_SHARING) + +static void ALWAYS_INLINE z_arm_fpu_caller_save(struct __fpu_sf *fpu) +{ + __asm__ volatile ( + "vstmia %0, {s0-s15};\n" + : : "r" (&fpu->s[0]) + : "memory" + ); +#if CONFIG_VFP_FEATURE_REGS_S64_D32 + __asm__ volatile ( + "vstmia %0, {d16-d31};\n\t" + : + : "r" (&fpu->d[0]) + : "memory" + ); +#endif +} + /** * @brief FPU undefined instruction fault handler * @@ -150,11 +168,7 @@ bool z_arm_fault_undef_instruction_fp(void) */ spill_esf->undefined |= FPEXC_EN; spill_esf->fpscr = __get_FPSCR(); - __asm__ volatile ( - "vstmia %0, {s0-s15};\n" - : : "r" (&spill_esf->s[0]) - : "memory" - ); + z_arm_fpu_caller_save(spill_esf); } } else { /* @@ -184,11 +198,7 @@ bool z_arm_fault_undef_instruction(z_arch_esf_t *esf) */ esf->fpu.undefined = __get_FPEXC(); esf->fpu.fpscr = __get_FPSCR(); - __asm__ volatile ( - "vstmia %0, {s0-s15};\n" - : : "r" (&esf->fpu.s[0]) - : "memory" - ); + z_arm_fpu_caller_save(&esf->fpu); #endif /* Print fault information */ diff --git a/arch/arm/core/aarch32/fatal.c b/arch/arm/core/aarch32/fatal.c index 67364f047ee5..c053bb53e4a8 100644 --- a/arch/arm/core/aarch32/fatal.c +++ b/arch/arm/core/aarch32/fatal.c @@ -33,6 +33,16 @@ static void esf_dump(const z_arch_esf_t *esf) i + 2, (uint32_t)esf->fpu.s[i + 2], i + 3, (uint32_t)esf->fpu.s[i + 3]); } +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + for (int i = 0; i < ARRAY_SIZE(esf->fpu.d); i += 4) { + LOG_ERR("d[%2d]: 0x%16llx d[%2d]: 0x%16llx" + " d[%2d]: 0x%16llx d[%2d]: 0x%16llx", + i, (uint64_t)esf->fpu.d[i], + i + 1, (uint64_t)esf->fpu.d[i + 1], + i + 2, (uint64_t)esf->fpu.d[i + 2], + i + 3, (uint64_t)esf->fpu.d[i + 3]); + } +#endif LOG_ERR("fpscr: 0x%08x", esf->fpu.fpscr); #endif #if defined(CONFIG_EXTRA_EXCEPTION_INFO) diff --git a/arch/arm/core/aarch32/swap_helper.S b/arch/arm/core/aarch32/swap_helper.S index 4de2df7177a7..d125e0d740c9 100644 --- a/arch/arm/core/aarch32/swap_helper.S +++ b/arch/arm/core/aarch32/swap_helper.S @@ -147,6 +147,9 @@ out_fp_endif: beq out_store_thread_context vstmia r0!, {s0-s15} +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + vstmia r0!, {d16-d31} +#endif vmrs r3, fpscr stm r0, {r3, ip} diff --git a/include/zephyr/arch/arm/aarch32/exc.h b/include/zephyr/arch/arm/aarch32/exc.h index f4c73b9b96be..b9d615736986 100644 --- a/include/zephyr/arch/arm/aarch32/exc.h +++ b/include/zephyr/arch/arm/aarch32/exc.h @@ -71,8 +71,19 @@ extern "C" { #endif #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + +/* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls. + * + * Registers s0-s15 (d0-d7, q0-q3) do not have to be preserved (and can be used + * for passing arguments or returning results in standard procedure-call variants). + * + * Registers d16-d31 (q8-q15), do not have to be preserved. + */ struct __fpu_sf { - float s[16]; + uint32_t s[16]; /* s0~s15 (d0-d7) */ +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + uint64_t d[16]; /* d16~d31 */ +#endif uint32_t fpscr; uint32_t undefined; }; From c1ecb8faaa910cb3e41db0bddfd24ccfa9986c3f Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 23 May 2023 18:40:14 +0800 Subject: [PATCH 0455/2042] arch: arm: enable FPU and FPU sharing for v8r aarch32 This commit is to enable FPU and FPU_SHARING for v8r aarch32. Signed-off-by: Huifeng Zhang --- arch/arm/core/aarch32/Kconfig.vfp | 2 ++ arch/arm/core/aarch32/cortex_a_r/Kconfig | 1 + soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc | 2 ++ 3 files changed, 5 insertions(+) diff --git a/arch/arm/core/aarch32/Kconfig.vfp b/arch/arm/core/aarch32/Kconfig.vfp index 69b6c3df82d7..71c94b71ff14 100644 --- a/arch/arm/core/aarch32/Kconfig.vfp +++ b/arch/arm/core/aarch32/Kconfig.vfp @@ -10,6 +10,8 @@ config CPU_HAS_VFP bool select CPU_HAS_FPU + imply FPU + imply FPU_SHARING help This option signifies the support for a Vectored Floating-Point (VFP) coprocessor. diff --git a/arch/arm/core/aarch32/cortex_a_r/Kconfig b/arch/arm/core/aarch32/cortex_a_r/Kconfig index 418aa9a07ee6..10bf721a8700 100644 --- a/arch/arm/core/aarch32/cortex_a_r/Kconfig +++ b/arch/arm/core/aarch32/cortex_a_r/Kconfig @@ -99,6 +99,7 @@ config CPU_CORTEX_R52 select AARCH32_ARMV8_R select CPU_HAS_ICACHE select CPU_HAS_DCACHE + select VFP_SP_D16 help This option signifies the use of a Cortex-R52 CPU diff --git a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc index 53f5f3a0bac9..a7f2131e065e 100644 --- a/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc +++ b/soc/arm/arm/fvp_aemv8r_aarch32/Kconfig.soc @@ -10,6 +10,8 @@ config SOC_FVP_AEMV8R_AARCH32 select CPU_CORTEX_R52 select CPU_HAS_ARM_MPU select CPU_HAS_MPU + select VFP_DP_D32_FP16_FMAC + select GIC_V3 select GIC_SINGLE_SECURITY_STATE select PLATFORM_SPECIFIC_INIT From 1cec85dc07b98a82a8fdd6394c8bd263f2c6383a Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 23 May 2023 18:54:49 +0800 Subject: [PATCH 0456/2042] tests: kernel: fpu_sharing: Enable it on VFP platfrom of aarch32 - Remove raising compilation error in `float_regs_arm_gcc.h` These macros are checked in 'load_store.c', so no need to check them again in 'float_regs_arm_gcc.h' - Enable this test on the VFP platform of aarch32 Signed-off-by: Huifeng Zhang --- .../fpu_sharing/generic/src/float_context.h | 17 ++++++++- .../generic/src/float_regs_arm_gcc.h | 37 ++++++++++++++++--- .../fpu_sharing/generic/src/load_store.c | 4 +- .../kernel/fpu_sharing/generic/testcase.yaml | 2 +- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/tests/kernel/fpu_sharing/generic/src/float_context.h b/tests/kernel/fpu_sharing/generic/src/float_context.h index 12051ae770d7..304057e7538a 100644 --- a/tests/kernel/fpu_sharing/generic/src/float_context.h +++ b/tests/kernel/fpu_sharing/generic/src/float_context.h @@ -63,7 +63,20 @@ struct fp_non_volatile_register_set { #define SIZEOF_FP_VOLATILE_REGISTER_SET sizeof(struct fp_volatile_register_set) #define SIZEOF_FP_NON_VOLATILE_REGISTER_SET 0 -#elif defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) +#elif defined(CONFIG_ARM) + +#if defined(CONFIG_VFP_FEATURE_REGS_S64_D32) + +struct fp_volatile_register_set { + double regs[16]; /* d0..d15 */ +}; + +struct fp_non_volatile_register_set { + double regs[16]; /*d16..d31 */ +}; + +#elif defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) \ + || defined(CONFIG_VFP_FEATURE_REGS_S32_D16) #define FP_OPTION 0 @@ -83,6 +96,8 @@ struct fp_non_volatile_register_set { float s[16]; }; +#endif + #define SIZEOF_FP_VOLATILE_REGISTER_SET \ sizeof(struct fp_volatile_register_set) #define SIZEOF_FP_NON_VOLATILE_REGISTER_SET \ diff --git a/tests/kernel/fpu_sharing/generic/src/float_regs_arm_gcc.h b/tests/kernel/fpu_sharing/generic/src/float_regs_arm_gcc.h index 49d3e20e373c..31bc6b8e27c3 100644 --- a/tests/kernel/fpu_sharing/generic/src/float_regs_arm_gcc.h +++ b/tests/kernel/fpu_sharing/generic/src/float_regs_arm_gcc.h @@ -12,14 +12,38 @@ #ifndef _FLOAT_REGS_ARM_GCC_H #define _FLOAT_REGS_ARM_GCC_H -#if !defined(__GNUC__) \ - || !(defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP)) -#error __FILE__ goes only with ARM GCC -#endif - #include #include "float_context.h" +#if defined(CONFIG_VFP_FEATURE_REGS_S64_D32) + +static inline void _load_all_float_registers(struct fp_register_set *regs) +{ + __asm__ volatile ( + "vldmia %0, {d0-d15};\n\t" + "vldmia %1, {d16-d31};\n\t" + : : "r" (®s->fp_volatile), "r" (®s->fp_non_volatile) + ); +} + +static inline void _store_all_float_registers(struct fp_register_set *regs) +{ + __asm__ volatile ( + "vstmia %0, {d0-d15};\n\t" + "vstmia %1, {d16-d31};\n\t" + : : "r" (®s->fp_volatile), "r" (®s->fp_non_volatile) + : "memory" + ); +} + +static inline void _load_then_store_all_float_registers(struct fp_register_set *regs) +{ + _load_all_float_registers(regs); + _store_all_float_registers(regs); +} + +#else + /** * * @brief Load all floating point registers @@ -86,4 +110,7 @@ static inline void _load_then_store_all_float_registers(struct fp_register_set _load_all_float_registers(regs); _store_all_float_registers(regs); } + +#endif + #endif /* _FLOAT_REGS_ARM_GCC_H */ diff --git a/tests/kernel/fpu_sharing/generic/src/load_store.c b/tests/kernel/fpu_sharing/generic/src/load_store.c index 204b334bfafb..1193297eb415 100644 --- a/tests/kernel/fpu_sharing/generic/src/load_store.c +++ b/tests/kernel/fpu_sharing/generic/src/load_store.c @@ -44,12 +44,14 @@ #else #include "float_regs_x86_other.h" #endif /* __GNUC__ */ -#elif defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) +#elif defined(CONFIG_ARM) +#if defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) || defined(CONFIG_CPU_HAS_VFP) #if defined(__GNUC__) #include "float_regs_arm_gcc.h" #else #include "float_regs_arm_other.h" #endif /* __GNUC__ */ +#endif #elif defined(CONFIG_ARM64) #if defined(__GNUC__) #include "float_regs_arm64_gcc.h" diff --git a/tests/kernel/fpu_sharing/generic/testcase.yaml b/tests/kernel/fpu_sharing/generic/testcase.yaml index 64a328455118..4d6bc0982082 100644 --- a/tests/kernel/fpu_sharing/generic/testcase.yaml +++ b/tests/kernel/fpu_sharing/generic/testcase.yaml @@ -11,7 +11,7 @@ tests: min_ram: 16 kernel.fpu_sharing.generic.arm: extra_args: PI_NUM_ITERATIONS=70000 - filter: CONFIG_ARMV7_M_ARMV8_M_FP or CONFIG_ARMV7_R_FP + filter: CONFIG_ARMV7_M_ARMV8_M_FP or CONFIG_ARMV7_R_FP or CONFIG_CPU_HAS_VFP slow: true arch_allow: arm tags: From 9edd2951ef5235485d0d525f41bb8fbcefc5fad7 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Tue, 23 May 2023 19:04:09 +0800 Subject: [PATCH 0457/2042] tests: kernel: fpu_sharing: Add double type support Use double type when FPU supports double precision. Signed-off-by: Huifeng Zhang --- tests/kernel/fpu_sharing/generic/src/pi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/kernel/fpu_sharing/generic/src/pi.c b/tests/kernel/fpu_sharing/generic/src/pi.c index 48491cd46517..0b1a1004080f 100644 --- a/tests/kernel/fpu_sharing/generic/src/pi.c +++ b/tests/kernel/fpu_sharing/generic/src/pi.c @@ -40,7 +40,11 @@ * PI_NUM_ITERATIONS: This macro is defined in the project's Makefile and * is configurable from the command line. */ +#ifdef CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION +static double reference_pi = 0.0f; +#else static float reference_pi = 0.0f; +#endif /* * Test counters are "volatile" because GCC wasn't properly updating @@ -64,9 +68,15 @@ static K_SEM_DEFINE(test_exit_sem, 0, 1); */ static void calculate_pi_low(void) { +#ifdef CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION + volatile double pi; /* volatile to avoid optimizing out of loop */ + double divisor = 3.0f; + double sign = -1.0f; +#else volatile float pi; /* volatile to avoid optimizing out of loop */ float divisor = 3.0f; float sign = -1.0f; +#endif unsigned int ix; /* Loop until the test finishes, or an error is detected. */ @@ -103,9 +113,15 @@ static void calculate_pi_low(void) */ static void calculate_pi_high(void) { +#ifdef CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION + volatile double pi; /* volatile to avoid optimizing out of loop */ + double divisor = 3.0f; + double sign = -1.0f; +#else volatile float pi; /* volatile to avoid optimizing out of loop */ float divisor = 3.0f; float sign = -1.0f; +#endif unsigned int ix; /* Run the test until the specified maximum test count is reached */ From 7c6eb242a95902fee88653b636e99ac4e1e37113 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Fri, 16 Jun 2023 13:36:00 +0200 Subject: [PATCH 0458/2042] Bluetooth: Fix endianness handling for ext scan reports evt_type evt_type is 16 bits and thus requires endianness conversion over HCI Signed-off-by: Troels Nilsson --- subsys/bluetooth/controller/hci/hci.c | 4 ++-- subsys/bluetooth/host/scan.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index de70a3567057..4ff4e2aba621 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -6385,7 +6385,7 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data, sep->num_reports = 1U; adv_info = (void *)(((uint8_t *)sep) + sizeof(*sep)); - adv_info->evt_type = evt_type_lookup[adv->type]; + adv_info->evt_type = sys_cpu_to_le16((uint16_t)evt_type_lookup[adv->type]); #if defined(CONFIG_BT_CTLR_PRIVACY) if (rl_idx < ll_rl_size_get()) { @@ -6576,7 +6576,7 @@ static void ext_adv_info_fill(uint8_t evt_type, uint8_t phy, uint8_t sec_phy, sep->num_reports = 1U; adv_info = (void *)(((uint8_t *)sep) + sizeof(*sep)); - adv_info->evt_type = evt_type; + adv_info->evt_type = sys_cpu_to_le16((uint16_t)evt_type); if (0) { #if defined(CONFIG_BT_CTLR_PRIVACY) diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 187a91fa566c..4aa7ab5b3e41 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -572,8 +572,8 @@ static void create_ext_adv_info(struct bt_hci_evt_le_ext_advertising_info const scan_info->rssi = evt->rssi; scan_info->sid = evt->sid; scan_info->interval = sys_le16_to_cpu(evt->interval); - scan_info->adv_type = get_adv_type(evt->evt_type); - scan_info->adv_props = get_adv_props_extended(evt->evt_type); + scan_info->adv_type = get_adv_type(sys_le16_to_cpu(evt->evt_type)); + scan_info->adv_props = get_adv_props_extended(sys_le16_to_cpu(evt->evt_type)); } void bt_hci_le_adv_ext_report(struct net_buf *buf) @@ -586,6 +586,7 @@ void bt_hci_le_adv_ext_report(struct net_buf *buf) struct bt_hci_evt_le_ext_advertising_info *evt; struct bt_le_scan_recv_info scan_info; uint16_t data_status; + uint16_t evt_type; bool is_report_complete; bool more_to_come; bool is_new_advertiser; @@ -596,11 +597,12 @@ void bt_hci_le_adv_ext_report(struct net_buf *buf) } evt = net_buf_pull_mem(buf, sizeof(*evt)); - data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(evt->evt_type); + evt_type = sys_le16_to_cpu(evt->evt_type); + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(evt_type); is_report_complete = data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE; more_to_come = data_status == BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL; - if (evt->evt_type & BT_HCI_LE_ADV_EVT_TYPE_LEGACY) { + if (evt_type & BT_HCI_LE_ADV_EVT_TYPE_LEGACY) { /* Legacy advertising reports are complete. * Create event immediately. */ From c022f41c1e946a30425e25ba342317769cdb9608 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 20 Jun 2023 11:54:26 +0300 Subject: [PATCH 0459/2042] drivers: dai: intel: dmic: fix irq argument cast The argument to the dmic irq is of type "struct device *" and dmic data is actually part of it, thus make the cast correctly. Signed-off-by: Jaska Uimonen --- drivers/dai/intel/dmic/dmic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dai/intel/dmic/dmic.c b/drivers/dai/intel/dmic/dmic.c index 4651eb16c763..67ab966e83c0 100644 --- a/drivers/dai/intel/dmic/dmic.c +++ b/drivers/dai/intel/dmic/dmic.c @@ -256,7 +256,7 @@ static void dai_dmic_stop_fifo_packers(struct dai_intel_dmic *dmic, */ static void dai_dmic_irq_handler(const void *data) { - struct dai_intel_dmic *dmic = (struct dai_intel_dmic *) data; + struct dai_intel_dmic *dmic = ((struct device *)data)->data; uint32_t val0; uint32_t val1; From 8a65b3f337f4a13ce46f74ddae61de5cbf6e179b Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Wed, 21 Jun 2023 09:02:30 +0200 Subject: [PATCH 0460/2042] tests: Bluetooth: don't assume handle is 0 Don't assume the connection handle will always be 0. This is currently the case with the Zephyr link layer, but recently changed in the Softdevice Controller. Another problem is that apparently the spec allows the controller to just blackhole data instead of returning `BT_HCI_ERR_UNKNOWN_CONN_ID` if the host uses a wrong handle. Signed-off-by: Jonathan Rico --- tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c index 7dab3cbc3b0f..f762ee824737 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c @@ -41,6 +41,7 @@ static K_SEM_DEFINE(cmd_sem, 1, 1); static struct k_sem acl_pkts; static struct k_sem tx_credits; static uint16_t peer_mps; +static uint16_t conn_handle; static uint16_t active_opcode = 0xFFFF; static struct net_buf *cmd_rsp; @@ -123,6 +124,9 @@ static void handle_meta_event(struct net_buf *buf) 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: @@ -488,7 +492,7 @@ static int send_acl(struct net_buf *buf) 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(0, flags)); + 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); From 3bef10f39804e74d9220f3296a156ed90aba2117 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 21 Jun 2023 09:18:48 +0000 Subject: [PATCH 0461/2042] net: ip: always cancel IPv6 DAD when address is removed If the address was removed immediately after being added (e.g. because the interface MAC address is changed on boot), it would remain in the DAD timer list. In one scenario, the DAD timeout would eventually fire, causing the now-removed address to be modified, potentially causing issues that way. In another scenario, if the interface was immediately brought back up again with a different link-local address, this new address would reuse the first address slot on the interface. Starting the DAD process for this new address would lead to the same address slot being added to the DAD timer list a second time, causing an infinite list and associated lockup during iteration. Always remove the address from the DAD timer list when it is removed from the interface, not just when DAD fails. Signed-off-by: Armin Brauns --- subsys/net/ip/net_if.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 3bc187fcf517..02dc8a257a4c 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1337,10 +1337,6 @@ void net_if_ipv6_dad_failed(struct net_if *iface, const struct in6_addr *addr) } - k_mutex_lock(&lock, K_FOREVER); - sys_slist_find_and_remove(&active_dad_timers, &ifaddr->dad_node); - k_mutex_unlock(&lock); - net_mgmt_event_notify_with_info(NET_EVENT_IPV6_DAD_FAILED, iface, &ifaddr->address.in6_addr, sizeof(struct in6_addr)); @@ -1850,6 +1846,14 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) k_mutex_unlock(&lock); } +#if defined(CONFIG_NET_IPV6_DAD) + if (!net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { + k_mutex_lock(&lock, K_FOREVER); + sys_slist_find_and_remove(&active_dad_timers, &ipv6->unicast[i].dad_node); + k_mutex_unlock(&lock); + } +#endif + ipv6->unicast[i].is_used = false; net_ipv6_addr_create_solicited_node(addr, &maddr); From 10ef3b46d870f9672bb6407d78bf94a6e3fb9675 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 21 Jun 2023 10:48:10 +0200 Subject: [PATCH 0462/2042] Bluetooth: Mesh: fix provisionee public key usage Provisionee shall fail if provisioner sent public key identicall to OOB public key back. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/prov_device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index deceae58ad0e..48d852cb1a7a 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -357,6 +357,13 @@ static void prov_pub_key(const uint8_t *data) return; } + if (!memcmp(bt_mesh_prov->public_key_be, + bt_mesh_prov_link.conf_inputs.pub_key_provisioner, PDU_LEN_PUB_KEY)) { + LOG_ERR("Public keys are identical"); + prov_fail(PROV_ERR_NVAL_FMT); + return; + } + /* No swap needed since user provides public key in big-endian */ memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, bt_mesh_prov->public_key_be, PDU_LEN_PUB_KEY); From d13dfb9d230426aaabcf20a311a073af9bb01113 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 21 Jun 2023 17:01:42 +0200 Subject: [PATCH 0463/2042] dmic: Allow use of reserved bits in CIC_CONTROL register Since the mtl platform, the stereo bit has been removed from the CIC_CONTROL register and now it is marked as reserved. On some platforms (mtl and above), the configuration blob still has this bit set, causing the dmic driver to report an error. This commit changes the behavior of the driver to only display a warning. Signed-off-by: Adrian Warecki --- drivers/dai/intel/dmic/dmic_nhlt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 621060a7baf6..8d40d9e38553 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -474,9 +474,8 @@ int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *bespoke_cf ; LOG_DBG(" stereo_mode=%d", bf7); if (ref != val) { - LOG_ERR("dmic_set_config_nhlt(): illegal CIC_CONTROL = 0x%08x", + LOG_WRN("dmic_set_config_nhlt(): illegal CIC_CONTROL = 0x%08x", val); - return -EINVAL; } /* Clear CIC_START_A and CIC_START_B */ From 257deba9c2e4c747361a69a1ae01c51e1d3e5e15 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 21 Jun 2023 10:20:49 +0200 Subject: [PATCH 0464/2042] drivers/pcie: Fix copyright year Trivial update that was missed. Signed-off-by: Tomasz Bursztyka --- drivers/pcie/host/vc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pcie/host/vc.h b/drivers/pcie/host/vc.h index 78a9e51722cf..13b3f1cf1e53 100644 --- a/drivers/pcie/host/vc.h +++ b/drivers/pcie/host/vc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Intel Corporation. + * Copyright (c) 2023 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ From 4c7aeb252d81c480488ae5f57e3f0199ba531c9a Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 19 Jun 2023 09:41:31 -0400 Subject: [PATCH 0465/2042] doc: Correct msgq data item size discrepancy Updates the data passing summary table to indicate that the size of a message queue data item must be a multiple of its data alignment. This brings the documentation in both the summary table and the message queue documentation into alignment. Signed-off-by: Peter Mitsis --- doc/kernel/services/index.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/kernel/services/index.rst b/doc/kernel/services/index.rst index 82c49ba3b7e6..cb56ccd3673b 100644 --- a/doc/kernel/services/index.rst +++ b/doc/kernel/services/index.rst @@ -59,7 +59,7 @@ Object Bidirectional? Data structure Data item size FIFO No Queue Arbitrary [1] 4 B [2] Yes [3] Yes N/A LIFO No Queue Arbitrary [1] 4 B [2] Yes [3] Yes N/A Stack No Array Word Word Yes [3] Yes Undefined behavior -Message queue No Ring buffer Power of two Power of two Yes [3] Yes Pend thread or return -errno +Message queue No Ring buffer Arbitrary [6] Power of two Yes [3] Yes Pend thread or return -errno Mailbox Yes Queue Arbitrary [1] Arbitrary No No N/A Pipe No Ring buffer [4] Arbitrary Arbitrary Yes [5] Yes [5] Pend thread or return -errno =============== ============== =================== ============== ============== ================= ============== =============================== @@ -79,6 +79,8 @@ argument. [5] ISRS can send and/or receive only when passing K_NO_WAIT as the timeout argument. +[6] Data item size must be a multiple of the data alignment. + .. toctree:: :maxdepth: 1 From 71b522cfdd01c60a6a93f131f775a88c40f8c5f4 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 20 Jun 2023 10:34:55 -0700 Subject: [PATCH 0466/2042] tests: kernel/mp: move CONFIG_KERNEL_COHERENCE to Kconfig This moves CONFIG_KERNEL_COHERENCE from prj.conf to Kconfig. This gets rid of the cmake warning where CONFIG_KERNEL_COHERENCE is assigned the value 'y' but gets the value ''. This is simply done to avoid confusion when running the test manually. Signed-off-by: Daniel Leung --- tests/kernel/mp/Kconfig | 11 +++++++++++ tests/kernel/mp/prj.conf | 4 ---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 tests/kernel/mp/Kconfig diff --git a/tests/kernel/mp/Kconfig b/tests/kernel/mp/Kconfig new file mode 100644 index 000000000000..2f6795708fac --- /dev/null +++ b/tests/kernel/mp/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +# Must have this on where available, otherwise the linker will place +# the shared variables in cached/incoherent memory. +config KERNEL_COHERENCE + bool + default y if ARCH_HAS_COHERENCE + +source "Kconfig.zephyr" diff --git a/tests/kernel/mp/prj.conf b/tests/kernel/mp/prj.conf index 040c701bc009..6c2881737d8e 100644 --- a/tests/kernel/mp/prj.conf +++ b/tests/kernel/mp/prj.conf @@ -1,7 +1,3 @@ CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_SMP=n - -# Must have this on where available, otherwise the linker will place -# the shared variables in cached/incoherent memory. -CONFIG_KERNEL_COHERENCE=y From fbbb82d6ac423ee42a8fafae297305b4c853ebc4 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 17 May 2023 15:54:28 -0300 Subject: [PATCH 0467/2042] debug: coredump: esp32: Fix registers index for current toolchain The current toolchain version for espressif SoCs does not have the same limitation on registers indexing as the previous one, enabling sending the correct A0-A15 register values directly Signed-off-by: Lucas Tamborrino --- scripts/coredump/gdbstubs/arch/xtensa.py | 38 ++++++++++-------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/scripts/coredump/gdbstubs/arch/xtensa.py b/scripts/coredump/gdbstubs/arch/xtensa.py index 1bd4d4c65258..6194de9f02ce 100644 --- a/scripts/coredump/gdbstubs/arch/xtensa.py +++ b/scripts/coredump/gdbstubs/arch/xtensa.py @@ -292,12 +292,6 @@ class RegNum(Enum): # espressif xtensa-overlays -> xtensa_esp32/gdb/gdb/xtensa-config.c class GdbRegDef_ESP32: ARCH_DATA_BLK_STRUCT_REGS = ' Date: Thu, 18 May 2023 05:36:24 -0300 Subject: [PATCH 0468/2042] debug: coredump: xtensa: add esp32s2 Add coredump support for esp32s2. Signed-off-by: Lucas Tamborrino --- arch/xtensa/core/coredump.c | 3 +++ scripts/coredump/gdbstubs/arch/xtensa.py | 32 +++++++++++++++++++++++- soc/xtensa/esp32s2/Kconfig.soc | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index 646929fe584e..0ddaae842de0 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -17,6 +17,7 @@ enum xtensa_soc_code { XTENSA_SOC_SAMPLE_CONTROLLER, XTENSA_SOC_ESP32, XTENSA_SOC_INTEL_ADSP, + XTENSA_SOC_ESP32S2, }; struct xtensa_arch_block { @@ -111,6 +112,8 @@ void arch_coredump_info_dump(const z_arch_esf_t *esf) arch_blk.soc = XTENSA_SOC_ESP32; #elif CONFIG_SOC_FAMILY_INTEL_ADSP arch_blk.soc = XTENSA_SOC_INTEL_ADSP; + #elif CONFIG_SOC_ESP32S2 + arch_blk.soc = XTENSA_SOC_ESP32S2; #else arch_blk.soc = XTENSA_SOC_UNKNOWN; #endif diff --git a/scripts/coredump/gdbstubs/arch/xtensa.py b/scripts/coredump/gdbstubs/arch/xtensa.py index 6194de9f02ce..875476fd68f8 100644 --- a/scripts/coredump/gdbstubs/arch/xtensa.py +++ b/scripts/coredump/gdbstubs/arch/xtensa.py @@ -23,7 +23,7 @@ class XtensaSoc(Enum): SAMPLE_CONTROLLER = 1 ESP32 = 2 INTEL_ADSP_CAVS = 3 - + ESP32S2 = 4 # The previous version of this script didn't need to know # what toolchain Zephyr was built with; it assumed sample_controller @@ -62,6 +62,8 @@ def get_gdb_reg_definition(soc, toolchain): sys.exit(1) else: raise NotImplementedError + elif soc == XtensaSoc.ESP32S2: + return GdbRegDef_ESP32S2 else: raise NotImplementedError @@ -323,6 +325,34 @@ class RegNum(Enum): WINDOWBASE = 69 WINDOWSTART = 70 +class GdbRegDef_ESP32S2: + ARCH_DATA_BLK_STRUCT_REGS = ' overlays/xtensa_intel_apl/gdb/gdb/xtensa-config.c class GdbRegDef_Intel_Adsp_CAVS_Zephyr: diff --git a/soc/xtensa/esp32s2/Kconfig.soc b/soc/xtensa/esp32s2/Kconfig.soc index f9d77cc1f5d5..4792cda7a4da 100644 --- a/soc/xtensa/esp32s2/Kconfig.soc +++ b/soc/xtensa/esp32s2/Kconfig.soc @@ -10,6 +10,7 @@ config SOC_ESP32S2 select PINCTRL select XIP if !MCUBOOT select HAS_ESPRESSIF_HAL + select ARCH_SUPPORTS_COREDUMP if SOC_ESP32S2 From eb028ccf55fb79ee89e46f41c93f2245350a3ad0 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 17 May 2023 16:38:37 -0300 Subject: [PATCH 0469/2042] debug: coredump: xtensa: Add esp32s3 Add coredump support for esp32s3. Signed-off-by: Lucas Tamborrino --- arch/xtensa/core/coredump.c | 3 ++ scripts/coredump/gdbstubs/arch/xtensa.py | 42 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index 0ddaae842de0..55b1a77884e2 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -18,6 +18,7 @@ enum xtensa_soc_code { XTENSA_SOC_ESP32, XTENSA_SOC_INTEL_ADSP, XTENSA_SOC_ESP32S2, + XTENSA_SOC_ESP32S3, }; struct xtensa_arch_block { @@ -114,6 +115,8 @@ void arch_coredump_info_dump(const z_arch_esf_t *esf) arch_blk.soc = XTENSA_SOC_INTEL_ADSP; #elif CONFIG_SOC_ESP32S2 arch_blk.soc = XTENSA_SOC_ESP32S2; + #elif CONFIG_SOC_ESP32S3 + arch_blk.soc = XTENSA_SOC_ESP32S3; #else arch_blk.soc = XTENSA_SOC_UNKNOWN; #endif diff --git a/scripts/coredump/gdbstubs/arch/xtensa.py b/scripts/coredump/gdbstubs/arch/xtensa.py index 875476fd68f8..dfc2f48453e6 100644 --- a/scripts/coredump/gdbstubs/arch/xtensa.py +++ b/scripts/coredump/gdbstubs/arch/xtensa.py @@ -24,6 +24,8 @@ class XtensaSoc(Enum): ESP32 = 2 INTEL_ADSP_CAVS = 3 ESP32S2 = 4 + ESP32S3 = 5 + # The previous version of this script didn't need to know # what toolchain Zephyr was built with; it assumed sample_controller @@ -64,6 +66,8 @@ def get_gdb_reg_definition(soc, toolchain): raise NotImplementedError elif soc == XtensaSoc.ESP32S2: return GdbRegDef_ESP32S2 + elif soc == XtensaSoc.ESP32S3: + return GdbRegDef_ESP32S3 else: raise NotImplementedError @@ -147,9 +151,12 @@ def parse_arch_data_block(self): arch_data_blk = self.logfile.get_arch_data()['data'] self.version = struct.unpack('H', arch_data_blk[1:3])[0] + logger.debug("Xtensa GDB stub version: %d" % self.version) # Get SOC and toolchain to get correct format for unpack self.soc = XtensaSoc(bytearray(arch_data_blk)[0]) + logger.debug("Xtensa SOC: %s" % self.soc.name) + if self.version >= 2: self.toolchain = XtensaToolchain(bytearray(arch_data_blk)[3]) arch_data_blk_regs = arch_data_blk[4:] @@ -162,6 +169,8 @@ def parse_arch_data_block(self): self.toolchain = XtensaToolchain.ZEPHYR arch_data_blk_regs = arch_data_blk[3:] + logger.debug("Xtensa toolchain: %s" % self.toolchain.name) + self.gdb_reg_def = get_gdb_reg_definition(self.soc, self.toolchain) tu = struct.unpack(self.gdb_reg_def.ARCH_DATA_BLK_STRUCT_REGS, @@ -354,6 +363,39 @@ class RegNum(Enum): WINDOWBASE = 66 WINDOWSTART = 67 +class GdbRegDef_ESP32S3: + ARCH_DATA_BLK_STRUCT_REGS = ' overlays/xtensa_intel_apl/gdb/gdb/xtensa-config.c class GdbRegDef_Intel_Adsp_CAVS_Zephyr: ARCH_DATA_BLK_STRUCT_REGS = ' Date: Fri, 19 May 2023 16:07:29 -0300 Subject: [PATCH 0470/2042] drivers: flash: esp32xx: use K_NO_WAIT when in ISR Avoid timeout when taking semaphores in ISR. This enables flash operations inside interrupted context such as exceptions, allowing operations like saving core dump to flash for instance. Signed-off-by: Lucas Tamborrino --- drivers/flash/flash_esp32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index e2919258294c..a7c13b332cbf 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -57,6 +57,8 @@ #include LOG_MODULE_REGISTER(flash_esp32, CONFIG_FLASH_LOG_LEVEL); +#define FLASH_SEM_TIMEOUT (k_is_in_isr() ? K_NO_WAIT : K_FOREVER) + struct flash_esp32_dev_config { spi_dev_t *controller; }; @@ -77,7 +79,7 @@ static inline void flash_esp32_sem_take(const struct device *dev) { struct flash_esp32_dev_data *data = dev->data; - k_sem_take(&data->sem, K_FOREVER); + k_sem_take(&data->sem, FLASH_SEM_TIMEOUT); } static inline void flash_esp32_sem_give(const struct device *dev) From d8332d1de5ec517a6403612f5bcb663b75aa0847 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 19 May 2023 16:20:21 -0300 Subject: [PATCH 0471/2042] debug: coredump: flash partition: Use K_NO_WAIT when in ISR This code is meant to run in the context of a exception. Most architectures will fail the asertion made in z_impl_k_sem_take() when timeout is not K_NO_WAIT. This commit ensures K_NO_WAIT is used when arch_is_in_isr() is true. Signed-off-by: Lucas Tamborrino --- subsys/debug/coredump/coredump_backend_flash_partition.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/debug/coredump/coredump_backend_flash_partition.c b/subsys/debug/coredump/coredump_backend_flash_partition.c index cd96ffccd5b3..d7ce6a02cc21 100644 --- a/subsys/debug/coredump/coredump_backend_flash_partition.c +++ b/subsys/debug/coredump/coredump_backend_flash_partition.c @@ -48,6 +48,8 @@ LOG_MODULE_REGISTER(coredump, CONFIG_KERNEL_LOG_LEVEL); #define HDR_VER 1 +#define FLASH_BACKEND_SEM_TIMEOUT (k_is_in_isr() ? K_NO_WAIT : K_FOREVER) + typedef int (*data_read_cb_t)(void *arg, uint8_t *buf, size_t len); static struct { @@ -104,7 +106,7 @@ static int partition_open(void) { int ret; - (void)k_sem_take(&flash_sem, K_FOREVER); + (void)k_sem_take(&flash_sem, FLASH_BACKEND_SEM_TIMEOUT); ret = flash_area_open(FLASH_PARTITION_ID, &backend_ctx.flash_area); if (ret != 0) { @@ -618,7 +620,6 @@ struct coredump_backend_api coredump_backend_flash_partition = { .cmd = coredump_flash_backend_cmd, }; - #ifdef CONFIG_DEBUG_COREDUMP_SHELL #include From 9ae80aabd92e154b667f134c49dc43108a087329 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 19 May 2023 16:23:52 -0300 Subject: [PATCH 0472/2042] doc: services: debug: coredump: add flash partition Add flash partition guide to coredump documentation. Signed-off-by: Lucas Tamborrino --- doc/services/debugging/coredump.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/services/debugging/coredump.rst b/doc/services/debugging/coredump.rst index 23dc5a17d055..ed7bb34f51ee 100644 --- a/doc/services/debugging/coredump.rst +++ b/doc/services/debugging/coredump.rst @@ -18,6 +18,8 @@ Configure this module using the following options. Here are the options to enable output backends for core dump: * ``DEBUG_COREDUMP_BACKEND_LOGGING``: use log module for core dump output. +* ``DEBUG_COREDUMP_BACKEND_FLASH_PARTITION``: use flash partition for core + dump output. * ``DEBUG_COREDUMP_BACKEND_NULL``: fallback core dump backend if other backends cannot be enabled. All output is sent to null. @@ -62,6 +64,20 @@ This usually involves the following steps: ``ZEPHYR_TOOLCHAIN_VARIANT=zephyr`` should use the debugger in the ``xtensa-intel_apl_adsp`` toolchain of the SDK. +5. When ``DEBUG_COREDUMP_BACKEND_FLASH_PARTITION`` is enabled the core dump + data is stored in the flash partition. The flash partition must be defined + in the device tree: + + .. code-block:: devicetree + + &flash0 { + partitions { + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + }; + Example ------- From 1ffca3074705ff9f1b934b3feafc62dab1ee0436 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 24 May 2023 16:23:39 -0300 Subject: [PATCH 0473/2042] tests: subsys: debug: coredump backends: add esp32xx overlay Add overlay for esp32xx boards to coredump backends test. Signed-off-by: Lucas Tamborrino --- .../coredump_backends/boards/esp32.overlay | 25 +++++++++++++++++++ .../boards/esp32c3_devkitm.overlay | 25 +++++++++++++++++++ .../boards/esp32s2_saola.overlay | 25 +++++++++++++++++++ .../boards/esp32s3_devkitm.overlay | 25 +++++++++++++++++++ .../debug/coredump_backends/testcase.yaml | 7 +++++- 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/subsys/debug/coredump_backends/boards/esp32.overlay create mode 100644 tests/subsys/debug/coredump_backends/boards/esp32c3_devkitm.overlay create mode 100644 tests/subsys/debug/coredump_backends/boards/esp32s2_saola.overlay create mode 100644 tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/esp32.overlay b/tests/subsys/debug/coredump_backends/boards/esp32.overlay new file mode 100644 index 000000000000..eb707ee72211 --- /dev/null +++ b/tests/subsys/debug/coredump_backends/boards/esp32.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + /* + * Reduce storage_partition to make space for + * coredump_partition + */ + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00005000>; + }; + + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + + }; +}; diff --git a/tests/subsys/debug/coredump_backends/boards/esp32c3_devkitm.overlay b/tests/subsys/debug/coredump_backends/boards/esp32c3_devkitm.overlay new file mode 100644 index 000000000000..eb707ee72211 --- /dev/null +++ b/tests/subsys/debug/coredump_backends/boards/esp32c3_devkitm.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + /* + * Reduce storage_partition to make space for + * coredump_partition + */ + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00005000>; + }; + + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + + }; +}; diff --git a/tests/subsys/debug/coredump_backends/boards/esp32s2_saola.overlay b/tests/subsys/debug/coredump_backends/boards/esp32s2_saola.overlay new file mode 100644 index 000000000000..eb707ee72211 --- /dev/null +++ b/tests/subsys/debug/coredump_backends/boards/esp32s2_saola.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + /* + * Reduce storage_partition to make space for + * coredump_partition + */ + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00005000>; + }; + + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + + }; +}; diff --git a/tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay b/tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay new file mode 100644 index 000000000000..eb707ee72211 --- /dev/null +++ b/tests/subsys/debug/coredump_backends/boards/esp32s3_devkitm.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + /* + * Reduce storage_partition to make space for + * coredump_partition + */ + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00005000>; + }; + + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + + }; +}; diff --git a/tests/subsys/debug/coredump_backends/testcase.yaml b/tests/subsys/debug/coredump_backends/testcase.yaml index fa1ccc026f37..2b4399e09bfd 100644 --- a/tests/subsys/debug/coredump_backends/testcase.yaml +++ b/tests/subsys/debug/coredump_backends/testcase.yaml @@ -18,7 +18,12 @@ tests: coredump.backends.flash: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_flash_partition.conf - platform_allow: qemu_x86 + platform_allow: + - qemu_x86 + - esp32 + - esp32s2_saola + - esp32s3_devkitm + - esp32c3_devkitm coredump.backends.other: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_backend_other.conf From d2b3351acf284746f265e00d7f5842eb16133dfd Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 26 May 2023 08:13:44 -0300 Subject: [PATCH 0474/2042] manifest: update hal_espressif Update hal_espressif to enable core dump in esp32xx boards Signed-off-by: Lucas Tamborrino --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 5bb2596e34b7..4f700433757f 100644 --- a/west.yml +++ b/west.yml @@ -144,7 +144,7 @@ manifest: groups: - hal - name: hal_espressif - revision: abe299333411cb37a1cb1dd0aa2ea35c27382604 + revision: 9531c1c17873aa4935f85864ebafd20c02062a8f path: modules/hal/espressif west-commands: west/west-commands.yml groups: From c6c93e394d6a52c4541d39135681fc81b8df7dd5 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 2 Jun 2023 00:23:54 +0200 Subject: [PATCH 0475/2042] soc: cc13x2_cc26x2 series: enable RTT support All Cortex-M processors can support RTT by default. This change enables RTT support for the cc13xx/cc26xx SoC series (tested in hardware on CC1352R). Signed-off-by: Florian Grandel --- soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series | 1 + soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series | 1 + 2 files changed, 2 insertions(+) diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series index ea9154b262f3..831ea9734b42 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_CC13X2_CC26X2 select SOC_FAMILY_TISIMPLELINK select HAS_CC13X2_CC26X2_SDK select HAS_TI_CCFG + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE help Enable support for TI SimpleLink CC13x2 / CC26x2 SoCs diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series index a937b6c521c1..aadeed980c4d 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_CC13X2X7_CC26X2X7 select SOC_FAMILY_TISIMPLELINK select HAS_CC13X2X7_CC26X2X7_SDK select HAS_TI_CCFG if !BOOTLOADER_MCUBOOT + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE help Enable support for TI SimpleLink CC13x2x7 / CC26x2x7 SoCs From e229898caf23809810a7aff7fbc217f143c0e878 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 5 May 2023 09:02:32 -0300 Subject: [PATCH 0476/2042] drivers: pinctrl: esp32xx: allow internal loopback Provides a way to use pinctrl to allow internal loopback on a peripheral pin for testing purposes. This is done by using output-enable on a input pin and input-enable on a output pin. Signed-off-by: Lucas Tamborrino --- drivers/pinctrl/pinctrl_esp32.c | 19 ++++++++-- .../drivers/pinctrl/pinctrl_esp32_common.h | 3 ++ .../dt-bindings/pinctrl/esp-pinctrl-common.h | 11 ++++++ soc/riscv/esp32c3/pinctrl_soc.h | 36 ++++++++++--------- soc/xtensa/esp32/pinctrl_soc.h | 36 ++++++++++--------- soc/xtensa/esp32s2/pinctrl_soc.h | 36 ++++++++++--------- soc/xtensa/esp32s3/pinctrl_soc.h | 36 ++++++++++--------- 7 files changed, 107 insertions(+), 70 deletions(-) diff --git a/drivers/pinctrl/pinctrl_esp32.c b/drivers/pinctrl/pinctrl_esp32.c index 956039317a88..d716dd4defa4 100644 --- a/drivers/pinctrl/pinctrl_esp32.c +++ b/drivers/pinctrl/pinctrl_esp32.c @@ -147,13 +147,17 @@ static int esp32_pin_apply_config(uint32_t pin, uint32_t flags) gpio_ll_output_enable(&GPIO, io_pin); esp_rom_gpio_matrix_out(io_pin, SIG_GPIO_OUT_IDX, false, false); } else { - gpio_ll_output_disable(&GPIO, io_pin); + if (!(flags & ESP32_PIN_OUT_EN_FLAG)) { + gpio_ll_output_disable(&GPIO, io_pin); + } } if (flags & ESP32_DIR_INP_FLAG) { gpio_ll_input_enable(&GPIO, io_pin); } else { - gpio_ll_input_disable(&GPIO, io_pin); + if (!(flags & ESP32_PIN_IN_EN_FLAG)) { + gpio_ll_input_disable(&GPIO, io_pin); + } } end: @@ -223,6 +227,17 @@ static int esp32_pin_configure(const uint32_t pin_mux, const uint32_t pin_cfg) break; } + switch (ESP32_PIN_EN_DIR(pin_cfg)) { + case ESP32_PIN_OUT_EN: + flags |= ESP32_PIN_OUT_EN_FLAG; + break; + case ESP32_PIN_IN_EN: + flags |= ESP32_PIN_IN_EN_FLAG; + break; + default: + break; + } + if (flags & ESP32_PIN_OUT_HIGH_FLAG) { if (ESP32_PORT_IDX(pin_num) == 0) { gpio_dev_t *const gpio_dev = diff --git a/include/zephyr/drivers/pinctrl/pinctrl_esp32_common.h b/include/zephyr/drivers/pinctrl/pinctrl_esp32_common.h index 3db2e5459d94..421eb80cb900 100644 --- a/include/zephyr/drivers/pinctrl/pinctrl_esp32_common.h +++ b/include/zephyr/drivers/pinctrl/pinctrl_esp32_common.h @@ -28,4 +28,7 @@ #define ESP32_PIN_MODE_OUT(_cfg) \ (((_cfg) >> ESP32_PIN_OUT_SHIFT) & ESP32_PIN_OUT_MASK) +#define ESP32_PIN_EN_DIR(_cfg) \ + (((_cfg) >> ESP32_PIN_EN_DIR_SHIFT) & ESP32_PIN_EN_DIR_MASK) + #endif /* ZEPHYR_INCLUDE_DRIVERS_PINCTRL_PINCTRL_ESP32_COMMON_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h b/include/zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h index e7660ebbcadc..1fe1ea5b761f 100644 --- a/include/zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h +++ b/include/zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h @@ -39,6 +39,8 @@ #define ESP32_PIN_DRV_MASK 0x3U #define ESP32_PIN_OUT_SHIFT 4U #define ESP32_PIN_OUT_MASK 0x3U +#define ESP32_PIN_EN_DIR_SHIFT 6U +#define ESP32_PIN_EN_DIR_MASK 0x3U /* Bias definitions */ #define ESP32_NO_PULL 0x1 @@ -56,6 +58,13 @@ #define ESP32_PIN_OUT_HIGH 0x1 #define ESP32_PIN_OUT_LOW 0x2 +/* + * Enable input or output on pin + * regardless of its direction + */ +#define ESP32_PIN_OUT_EN 0x1 +#define ESP32_PIN_IN_EN 0x2 + /* * These flags are used by the pinctrl * driver, based on the DTS properties @@ -70,5 +79,7 @@ #define ESP32_DIR_OUT_FLAG BIT(6) #define ESP32_PIN_OUT_HIGH_FLAG BIT(7) #define ESP32_PIN_OUT_LOW_FLAG BIT(8) +#define ESP32_PIN_OUT_EN_FLAG BIT(9) +#define ESP32_PIN_IN_EN_FLAG BIT(10) #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ESP_PINCTRL_COMMON_H_ */ diff --git a/soc/riscv/esp32c3/pinctrl_soc.h b/soc/riscv/esp32c3/pinctrl_soc.h index 1e832f786ce0..5099a2b6e411 100644 --- a/soc/riscv/esp32c3/pinctrl_soc.h +++ b/soc/riscv/esp32c3/pinctrl_soc.h @@ -32,22 +32,23 @@ typedef struct pinctrl_soc_pin { * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) \ - DT_PROP_BY_IDX(node_id, prop, idx) +#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) DT_PROP_BY_IDX(node_id, prop, idx) /** * @brief Utility macro to initialize pincfg field in #pinctrl_pin_t. * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ - (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ - ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT)) +#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ + (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_EN * DT_PROP(node_id, output_enable)) << ESP32_PIN_EN_DIR_SHIFT) | \ + ((ESP32_PIN_IN_EN * DT_PROP(node_id, input_enable)) << ESP32_PIN_EN_DIR_SHIFT)) /** * @brief Utility macro to initialize each pin. @@ -56,9 +57,9 @@ typedef struct pinctrl_soc_pin { * @param prop Property name. * @param idx Property entry index. */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ - { .pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ - .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id) }, +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ + .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id)}, /** * @brief Utility macro to initialize state pins contained in a given property. @@ -66,10 +67,11 @@ typedef struct pinctrl_soc_pin { * @param node_id Node identifier. * @param prop Property name describing state pins. */ -#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)} +#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) \ + } /** @endcond */ diff --git a/soc/xtensa/esp32/pinctrl_soc.h b/soc/xtensa/esp32/pinctrl_soc.h index 716d0a96a8e0..78d2e4fedab4 100644 --- a/soc/xtensa/esp32/pinctrl_soc.h +++ b/soc/xtensa/esp32/pinctrl_soc.h @@ -32,22 +32,23 @@ typedef struct pinctrl_soc_pin { * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) \ - DT_PROP_BY_IDX(node_id, prop, idx) +#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) DT_PROP_BY_IDX(node_id, prop, idx) /** * @brief Utility macro to initialize pincfg field in #pinctrl_pin_t. * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ - (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ - ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT)) +#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ + (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_EN * DT_PROP(node_id, output_enable)) << ESP32_PIN_EN_DIR_SHIFT) | \ + ((ESP32_PIN_IN_EN * DT_PROP(node_id, input_enable)) << ESP32_PIN_EN_DIR_SHIFT)) /** * @brief Utility macro to initialize each pin. @@ -56,9 +57,9 @@ typedef struct pinctrl_soc_pin { * @param prop Property name. * @param idx Property entry index. */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ - { .pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ - .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id) }, +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ + .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id)}, /** * @brief Utility macro to initialize state pins contained in a given property. @@ -66,10 +67,11 @@ typedef struct pinctrl_soc_pin { * @param node_id Node identifier. * @param prop Property name describing state pins. */ -#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)} +#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) \ + } /** @endcond */ diff --git a/soc/xtensa/esp32s2/pinctrl_soc.h b/soc/xtensa/esp32s2/pinctrl_soc.h index 506ed6594786..0f7e45c5bc28 100644 --- a/soc/xtensa/esp32s2/pinctrl_soc.h +++ b/soc/xtensa/esp32s2/pinctrl_soc.h @@ -32,22 +32,23 @@ typedef struct pinctrl_soc_pin { * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) \ - DT_PROP_BY_IDX(node_id, prop, idx) +#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) DT_PROP_BY_IDX(node_id, prop, idx) /** * @brief Utility macro to initialize pincfg field in #pinctrl_pin_t. * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ - (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ - ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT)) +#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ + (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_EN * DT_PROP(node_id, output_enable)) << ESP32_PIN_EN_DIR_SHIFT) | \ + ((ESP32_PIN_IN_EN * DT_PROP(node_id, input_enable)) << ESP32_PIN_EN_DIR_SHIFT)) /** * @brief Utility macro to initialize each pin. @@ -56,9 +57,9 @@ typedef struct pinctrl_soc_pin { * @param prop Property name. * @param idx Property entry index. */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ - { .pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ - .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id) }, +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ + .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id)}, /** * @brief Utility macro to initialize state pins contained in a given property. @@ -66,10 +67,11 @@ typedef struct pinctrl_soc_pin { * @param node_id Node identifier. * @param prop Property name describing state pins. */ -#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)} +#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) \ + } /** @endcond */ diff --git a/soc/xtensa/esp32s3/pinctrl_soc.h b/soc/xtensa/esp32s3/pinctrl_soc.h index d5b846065085..6c8bddd24f57 100644 --- a/soc/xtensa/esp32s3/pinctrl_soc.h +++ b/soc/xtensa/esp32s3/pinctrl_soc.h @@ -34,22 +34,23 @@ typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) \ - DT_PROP_BY_IDX(node_id, prop, idx) +#define Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx) DT_PROP_BY_IDX(node_id, prop, idx) /** * @brief Utility macro to initialize pincfg field in #pinctrl_pin_t. * * @param node_id Node identifier. */ -#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ - (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ - ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ - ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ - ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT)) +#define Z_PINCTRL_ESP32_PINCFG_INIT(node_id) \ + (((ESP32_NO_PULL * DT_PROP(node_id, bias_disable)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_UP * DT_PROP(node_id, bias_pull_up)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PULL_DOWN * DT_PROP(node_id, bias_pull_down)) << ESP32_PIN_BIAS_SHIFT) | \ + ((ESP32_PUSH_PULL * DT_PROP(node_id, drive_push_pull)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_OPEN_DRAIN * DT_PROP(node_id, drive_open_drain)) << ESP32_PIN_DRV_SHIFT) | \ + ((ESP32_PIN_OUT_HIGH * DT_PROP(node_id, output_high)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_LOW * DT_PROP(node_id, output_low)) << ESP32_PIN_OUT_SHIFT) | \ + ((ESP32_PIN_OUT_EN * DT_PROP(node_id, output_enable)) << ESP32_PIN_EN_DIR_SHIFT) | \ + ((ESP32_PIN_IN_EN * DT_PROP(node_id, input_enable)) << ESP32_PIN_EN_DIR_SHIFT)) /** * @brief Utility macro to initialize each pin. @@ -58,9 +59,9 @@ typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; * @param prop Property name. * @param idx Property entry index. */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ - { .pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ - .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id) }, +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + {.pinmux = Z_PINCTRL_ESP32_PINMUX_INIT(node_id, prop, idx), \ + .pincfg = Z_PINCTRL_ESP32_PINCFG_INIT(node_id)}, /** * @brief Utility macro to initialize state pins contained in a given property. @@ -68,10 +69,11 @@ typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; * @param node_id Node identifier. * @param prop Property name describing state pins. */ -#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)} +#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) \ + } /** @endcond */ From e562c980ae4c1db5b4452e507c623dedbfb4a24b Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Sun, 7 May 2023 06:47:03 -0300 Subject: [PATCH 0477/2042] tests: drivers: spi: spi_loopback: esp32xx: Use internal loopback Use internal loopback for esp32xx boards, avoiding the use of external wiring. Signed-off-by: Lucas Tamborrino --- .../spi/spi_loopback/boards/esp32.overlay | 19 +++++++++++++++++++ .../boards/esp32c3_devkitm.overlay | 18 ++++++++++++++++++ .../spi_loopback/boards/esp32s2_saola.overlay | 18 ++++++++++++++++++ .../boards/esp32s3_devkitm.overlay | 18 ++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/tests/drivers/spi/spi_loopback/boards/esp32.overlay b/tests/drivers/spi/spi_loopback/boards/esp32.overlay index bb4c8ba6e80e..b2af8bbf3cb2 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32.overlay @@ -4,6 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +&pinctrl { + spim3_loopback: spim3_loopback { + group1 { + pinmux = ; + output-enable; /* Enable internal loopback */ + }; + group2 { + pinmux = ; + input-enable; /* Enable internal loopback */ + }; + group3 { + pinmux = , + ; + }; + }; +}; + &spi3 { slow@0 { compatible = "test-spi-loopback-slow"; @@ -19,4 +36,6 @@ &spi3 { dma-enabled; + pinctrl-0 = <&spim3_default>; + }; diff --git a/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay b/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay index 42856dc39c0e..34a1ab69662b 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay @@ -4,6 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +&pinctrl { + spim2_loopback: spim2_loopback { + group1 { + pinmux = ; + output-enable; /* Enable internal loopback */ + }; + group2 { + pinmux = ; + input-enable; /* Enable internal loopback */ + }; + group3 { + pinmux = , + ; + }; + }; +}; + &spi2 { slow@0 { compatible = "test-spi-loopback-slow"; @@ -19,4 +36,5 @@ &spi2 { dma-enabled; + pinctrl-0 = <&spim2_default>; }; diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s2_saola.overlay b/tests/drivers/spi/spi_loopback/boards/esp32s2_saola.overlay index 389546fdcd25..f50a945e5589 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32s2_saola.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32s2_saola.overlay @@ -4,6 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +&pinctrl { + spim3_loopback: spim3_loopback { + group1 { + pinmux = ; + output-enable; /* Enable internal loopback */ + }; + group2 { + pinmux = ; + input-enable; /* Enable internal loopback */ + }; + group3 { + pinmux = , + ; + }; + }; +}; + &spi3 { slow@0 { compatible = "test-spi-loopback-slow"; @@ -19,4 +36,5 @@ &spi3 { dma-enabled; + pinctrl-0 = <&spim3_loopback>; }; diff --git a/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay b/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay index 389546fdcd25..ce9c8e7891b5 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32s3_devkitm.overlay @@ -4,6 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ +&pinctrl { + spim3_loopback: spim3_loopback { + group1 { + pinmux = ; + output-enable; /* Enable internal loopback */ + }; + group2 { + pinmux = ; + input-enable; /* Enable internal loopback */ + }; + group3 { + pinmux = , + ; + }; + }; +}; + &spi3 { slow@0 { compatible = "test-spi-loopback-slow"; @@ -19,4 +36,5 @@ &spi3 { dma-enabled; + pinctrl-0 = <&spim3_loopback>; }; From ea949d0399be26f3cca01b13616d51de3bd76a53 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Mon, 8 May 2023 09:14:58 -0300 Subject: [PATCH 0478/2042] tests: drivers: uart: async: esp32c3: use internal loopback Use internal loopback for esp32c3 board, avoiding the use of external wiring. Signed-off-by: Lucas Tamborrino --- .../uart/uart_async_api/boards/esp32c3_devkitm.overlay | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay b/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay index 7f6a51cbb3d8..3582e7dcf943 100644 --- a/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/uart/uart_async_api/boards/esp32c3_devkitm.overlay @@ -8,10 +8,11 @@ uart1_test: uart1_test { group1 { pinmux = ; + input-enable; }; group2 { - pinmux = ; - bias-pull-up; + pinmux = ; + output-enable; }; }; }; From c2a730edc7b2591588653fa5c8b151090305ba52 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 10:59:43 +0200 Subject: [PATCH 0479/2042] Bluetooth: Shell: Also parse Broadcast Name as a valid name In the case that the advertising data has both a device name and a broadcast name, whichever one comes first will be used. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index f7a9773bd97f..41e7422aab4e 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -188,6 +188,7 @@ static bool data_cb(struct bt_data *data, void *user_data) switch (data->type) { case BT_DATA_NAME_SHORTENED: case BT_DATA_NAME_COMPLETE: + case BT_DATA_BROADCAST_NAME: memcpy(name, data->data, MIN(data->data_len, NAME_LEN - 1)); return false; default: From 2790106c339614ba188c69c14148c8df44d89ecf Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 1 May 2021 23:11:14 +0100 Subject: [PATCH 0480/2042] input: add a gpio qdec input driver Add a GPIO based quadrature decoder driver that reports relative axes movements using the input subsystem. Signed-off-by: Fabio Baltieri --- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/input/Kconfig.gpio_qdec | 9 ++ drivers/input/input_gpio_qdec.c | 240 ++++++++++++++++++++++++++++++ dts/bindings/input/gpio-qdec.yaml | 63 ++++++++ 5 files changed, 314 insertions(+) create mode 100644 drivers/input/Kconfig.gpio_qdec create mode 100644 drivers/input/input_gpio_qdec.c create mode 100644 dts/bindings/input/gpio-qdec.yaml diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index c775654d47d9..d6e0f2e80283 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -5,5 +5,6 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_SDL_TOUCH input_sdl_touch.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index f1fb121b7624..ee9508ae4d23 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -7,6 +7,7 @@ menu "Input drivers" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_keys" +source "drivers/input/Kconfig.gpio_qdec" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" diff --git a/drivers/input/Kconfig.gpio_qdec b/drivers/input/Kconfig.gpio_qdec new file mode 100644 index 000000000000..2e66fa3699b0 --- /dev/null +++ b/drivers/input/Kconfig.gpio_qdec @@ -0,0 +1,9 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_GPIO_QDEC + bool "GPIO based QDEC input driver" + default y + depends on DT_HAS_GPIO_QDEC_ENABLED + help + GPIO Quadrature Decoder input driver. diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c new file mode 100644 index 000000000000..85716fdcc1b7 --- /dev/null +++ b/drivers/input/input_gpio_qdec.c @@ -0,0 +1,240 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gpio_qdec + +#include +#include + +#include +#include +#include +#include + +#include +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]; + uint32_t sample_time_us; + uint32_t idle_timeout_ms; + uint16_t axis; + uint8_t steps_per_period; +}; + +struct gpio_qdec_data { + const struct device *dev; + struct k_timer sample_timer; + uint8_t prev_step; + int32_t acc; + struct k_work event_work; + struct k_work_delayable idle_work; + struct gpio_callback gpio_cb; +}; + +/* Positive transitions */ +#define QDEC_LL_LH 0x01 +#define QDEC_LH_HH 0x13 +#define QDEC_HH_HL 0x32 +#define QDEC_HL_LL 0x20 + +/* Negative transitions */ +#define QDEC_LL_HL 0x02 +#define QDEC_LH_LL 0x10 +#define QDEC_HH_LH 0x31 +#define QDEC_HL_HH 0x23 + +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])) { + step |= 0x01; + } + if (gpio_pin_get_dt(&cfg->gpio[1])) { + step |= 0x02; + } + + return step; +} + +static void gpio_qdec_sample_timer_timeout(struct k_timer *timer) +{ + const struct device *dev = k_timer_user_data_get(timer); + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + int8_t delta = 0; + unsigned int key; + uint8_t step; + + step = gpio_qdec_get_step(dev); + + if (data->prev_step == step) { + return; + } + + switch ((data->prev_step << 4U) | step) { + case QDEC_LL_LH: + case QDEC_LH_HH: + case QDEC_HH_HL: + case QDEC_HL_LL: + delta = 1; + break; + case QDEC_LL_HL: + case QDEC_LH_LL: + case QDEC_HH_LH: + case QDEC_HL_HH: + delta = -1; + break; + default: + LOG_WRN("%s: lost steps", dev->name); + } + + data->prev_step = step; + + key = irq_lock(); + data->acc += delta; + irq_unlock(key); + + if (abs(data->acc) >= cfg->steps_per_period) { + k_work_submit(&data->event_work); + } + + k_work_reschedule(&data->idle_work, K_MSEC(cfg->idle_timeout_ms)); +} + +static void gpio_qdec_event_worker(struct k_work *work) +{ + struct gpio_qdec_data *data = CONTAINER_OF( + work, struct gpio_qdec_data, event_work); + const struct device *dev = data->dev; + const struct gpio_qdec_config *cfg = dev->config; + unsigned int key; + int32_t acc; + + key = irq_lock(); + acc = data->acc / cfg->steps_per_period; + data->acc -= acc * cfg->steps_per_period; + irq_unlock(key); + + if (acc != 0) { + input_report_rel(data->dev, cfg->axis, acc, true, K_FOREVER); + } +} + +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; + int ret; + + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->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 gpio_qdec_data *data = CONTAINER_OF( + work, 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"); +} + +static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb, + uint32_t pins) +{ + 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"); +} + +static int gpio_qdec_init(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + int ret; + + data->dev = dev; + + k_work_init(&data->event_work, gpio_qdec_event_worker); + k_work_init_delayable(&data->idle_work, gpio_qdec_idle_worker); + + k_timer_init(&data->sample_timer, gpio_qdec_sample_timer_timeout, NULL); + 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)); + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->gpio[i]; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + + gpio_add_callback_dt(gpio, &data->gpio_cb); + } + + data->prev_step = gpio_qdec_get_step(dev); + + gpio_qdec_irq_setup(dev, true); + + LOG_DBG("Device %s initialized", dev->name); + + return 0; +} + +#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"); \ + \ + 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)}, \ + .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), \ + .axis = DT_INST_PROP(n, zephyr_axis), \ + }; \ + \ + static struct gpio_qdec_data gpio_qdec_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, NULL, \ + &gpio_qdec_data_##n, \ + &gpio_qdec_cfg_##n, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(QDEC_GPIO_INIT) diff --git a/dts/bindings/input/gpio-qdec.yaml b/dts/bindings/input/gpio-qdec.yaml new file mode 100644 index 000000000000..ef9da618bbcf --- /dev/null +++ b/dts/bindings/input/gpio-qdec.yaml @@ -0,0 +1,63 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO based QDEC input device + + Implement an input device generating relative axis event reports for a rotary + encoder connected to two GPIOs. The driver is normally idling until it sees a + transition on any of the encoder signal lines, then switches to polling mode + and samples the two signal lines periodically to track the encoder position, + and goes back to idling after the specified timeout. + + Example configuration: + + #include + + qdec { + compatible = "gpio-qdec"; + gpios = <&gpio0 14 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>, + <&gpio0 13 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>; + steps-per-period = <4>; + zephyr,axis = ; + sample-time-us = <2000>; + idle-timeout-ms = <200>; + }; + +compatible: "gpio-qdec" + +include: base.yaml + +properties: + gpios: + type: phandle-array + required: true + description: | + GPIO for the A and B encoder signals. + + steps-per-period: + type: int + required: true + description: | + How many steps to count before reporting an input event. + + zephyr,axis: + type: int + required: true + description: | + The input code for the axis to report for the device, typically any of + INPUT_REL_*. + + sample-time-us: + type: int + required: true + description: | + How often to sample the A and B signal lines when tracking the encoder + movement. + + idle-timeout-ms: + type: int + required: true + description: | + Timeout for the last detected transition before stopping the sampling + timer and going back to idle state. From 5b38136d980d44d2a3cf751e1d88d38da2d9a5b4 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Mon, 29 May 2023 15:32:20 +0800 Subject: [PATCH 0481/2042] manifest: Bump trusted-firmware-a to v2.9.0 Bump trusted-firmware-a version to v2.9.0 Signed-off-by: Huifeng Zhang --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 4f700433757f..d32fd214eec8 100644 --- a/west.yml +++ b/west.yml @@ -323,7 +323,7 @@ manifest: groups: - tee - name: trusted-firmware-a - revision: 28f5e137837f1c1a7a7b2af2dd8bb778c0a27532 + revision: 421dc050278287839f5c70019bd6aec617f2bbdb path: modules/tee/tf-a/trusted-firmware-a groups: - tee From b789a019e7ecede1bed54e3e2efcde5974dc2d68 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Wed, 21 Jun 2023 12:08:05 +0800 Subject: [PATCH 0482/2042] doc: release-notes: Add TF-A v3.5.0 notes Add release notes for TF-A for the 3.5.0 release. Signed-off-by: Huifeng Zhang --- doc/releases/release-notes-3.5.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 7a77feb2ab85..359fa1f77c27 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -249,6 +249,11 @@ Storage Trusted Firmware-M ****************** +Trusted Firmware-A +****************** + +* Updated to TF-A 2.9.0. + zcbor ***** From 2fc212c2a0f659d3deb1f1b1c2d27e262f37c92e Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Wed, 21 Jun 2023 09:26:55 +0000 Subject: [PATCH 0483/2042] bluetooth: hci: spi: initialize IRQ callback before registering it GPIO callbacks need to be initialized before being registered with a GPIO driver, otherwise the NULL `handler` hits an assert. Signed-off-by: Armin Brauns --- drivers/bluetooth/hci/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index a28f673415f3..442d86529c3b 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -495,6 +495,7 @@ static int bt_spi_open(void) /* Configure IRQ pin and the IRQ call-back/handler */ gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + gpio_init_callback(&gpio_cb, bt_to_active_isr, BIT(irq_gpio.pin)); if (gpio_add_callback(irq_gpio.port, &gpio_cb)) { return -EINVAL; } From 7e44efe70ad6415bad5b36fd124304c0868ab4fe Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 21 Jun 2023 12:49:26 -0500 Subject: [PATCH 0484/2042] drivers: gpio_mcux_lpc: Guard NXP Pint code Guard NXP PINT related code with #ifdef CONFIG_NXP_PINT. This prevents build errors on platforms that do not have a PINT but have LPC GPIO. Signed-off-by: Declan Snyder --- drivers/gpio/gpio_mcux_lpc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpio/gpio_mcux_lpc.c b/drivers/gpio/gpio_mcux_lpc.c index 5558f7e2f7fd..ae0ef1bf7963 100644 --- a/drivers/gpio/gpio_mcux_lpc.c +++ b/drivers/gpio/gpio_mcux_lpc.c @@ -21,7 +21,9 @@ #include #include #include +#ifdef CONFIG_NXP_PINT #include +#endif #include #include @@ -197,6 +199,7 @@ static int gpio_mcux_lpc_port_toggle_bits(const struct device *dev, } +#ifdef CONFIG_NXP_PINT /* Called by PINT when pin interrupt fires */ static void gpio_mcux_lpc_pint_cb(uint8_t pin, void *user) { @@ -261,6 +264,7 @@ static int gpio_mcux_lpc_pint_interrupt_cfg(const struct device *dev, gpio_mcux_lpc_pint_cb, (struct device *)dev); } +#endif /* CONFIG_NXP_PINT */ #if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT) && FSL_FEATURE_GPIO_HAS_INTERRUPT) @@ -348,9 +352,11 @@ static int gpio_mcux_lpc_pin_interrupt_configure(const struct device *dev, ((gpio_base->DIR[port] & BIT(pin)) != 0)) { return -ENOTSUP; } +#if defined(CONFIG_NXP_PINT) if (config->int_source == INT_SOURCE_PINT) { return gpio_mcux_lpc_pint_interrupt_cfg(dev, pin, mode, trig); } +#endif /* CONFIG_NXP_PINT */ #if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT) && FSL_FEATURE_GPIO_HAS_INTERRUPT) return gpio_mcux_lpc_module_interrupt_cfg(dev, pin, mode, trig); #else From 8d15cf2829ab5306122ae776b561d11dd0b2a8e4 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 15:50:03 +0200 Subject: [PATCH 0485/2042] Bluetooth: CAP: Shell: Handle -ECANCELED error code specifically If the procedure was called, we print a more specific string to let the user know that there was not an actual issue. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/cap_initiator.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 54de29c130b8..0172156bdaf6 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -36,9 +36,10 @@ static void cap_discover_cb(struct bt_conn *conn, int err, static void cap_unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, struct bt_conn *conn) { - if (err != 0) { - shell_error(ctx_shell, "Unicast start failed for conn %p (%d)", - conn, err); + if (err == -ECANCELED) { + shell_print(ctx_shell, "Unicast start was cancelled for conn %p", conn); + } else if (err != 0) { + shell_error(ctx_shell, "Unicast start failed for conn %p (%d)", conn, err); } else { shell_print(ctx_shell, "Unicast start completed"); } @@ -46,7 +47,9 @@ static void cap_unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_g static void unicast_update_complete_cb(int err, struct bt_conn *conn) { - if (err != 0) { + if (err == -ECANCELED) { + shell_print(ctx_shell, "Unicast update was cancelled for conn %p", conn); + } else if (err != 0) { shell_error(ctx_shell, "Unicast update failed for conn %p (%d)", conn, err); } else { @@ -62,7 +65,9 @@ static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, return; } - if (err != 0) { + 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); From e908f889208531ef2a64163380bda1a3a8b33d23 Mon Sep 17 00:00:00 2001 From: Simon Hein Date: Wed, 5 Apr 2023 09:00:50 +0000 Subject: [PATCH 0486/2042] docs: safety: Add safety documentation Add the safety documentation to the Zephyr documentation tree. Starts with the safety overview which describes the general goals for the safety in zephyr and introduces a process overview how a safety certification can be achieved in the zephyr project. Signed-off-by: Simon Hein --- doc/index-tex.rst | 1 + doc/index.rst | 1 + doc/safety/images/zephyr-safety-process.svg | 1 + doc/safety/index.rst | 13 + doc/safety/safety_overview.rst | 264 ++++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 doc/safety/images/zephyr-safety-process.svg create mode 100644 doc/safety/index.rst create mode 100644 doc/safety/safety_overview.rst diff --git a/doc/index-tex.rst b/doc/index-tex.rst index 6f55f862750b..09ef9e9459e6 100644 --- a/doc/index-tex.rst +++ b/doc/index-tex.rst @@ -23,3 +23,4 @@ Zephyr Project Documentation contribute/index.rst project/index.rst security/index.rst + safety/index.rst diff --git a/doc/index.rst b/doc/index.rst index 85962ad79b38..43f98f759761 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -111,6 +111,7 @@ Sections contribute/index.rst project/index.rst security/index.rst + safety/index.rst samples/index.rst boards/index.rst releases/index.rst diff --git a/doc/safety/images/zephyr-safety-process.svg b/doc/safety/images/zephyr-safety-process.svg new file mode 100644 index 000000000000..d607ff01cce4 --- /dev/null +++ b/doc/safety/images/zephyr-safety-process.svg @@ -0,0 +1 @@ +
Certification side
Certification side
Releases
Releases
Main
Main
LTS Releases
LTS Releases
LTS
LTS
Safety scope
Safety scope
Backport / Bugfix 
Backport / Bugfix 
Issue / PR within safety scope or safety relevance
Issue / PR within safety scope...
Auditable
Auditable
Decision how to handle 
Decision how to handle 
Safety committee /Architect
Safety Documentation
Safety Documentation
Code update
Code update
Documentation update
Documentation update
Certified Releases
Certified Releases
1
1
2
2
3
3
4
4
5
5
Technical SteeringCommittee ( TSC )
Decision how to handle 
Decision how to handle 
Backport / Bugfix 
Backport / Bugfix 
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/safety/index.rst b/doc/safety/index.rst new file mode 100644 index 000000000000..1eb55d12a325 --- /dev/null +++ b/doc/safety/index.rst @@ -0,0 +1,13 @@ +.. _safety_section: + +Safety +######## + +These documents describe the processes, developer guidelines and requirements +for ensuring safety is addressed within the Zephyr project. + +.. toctree:: + :maxdepth: 1 + :glob: + + safety_overview.rst diff --git a/doc/safety/safety_overview.rst b/doc/safety/safety_overview.rst new file mode 100644 index 000000000000..9a17434e6d0f --- /dev/null +++ b/doc/safety/safety_overview.rst @@ -0,0 +1,264 @@ +.. _safety_overview: + +Zephyr Safety Overview +######################## + +Introduction +************ + +This document is the safety documentation providing an overview over the safety-relevant activities +and what the Zephyr Project and the Zephyr Safety Working Group / Committee try to achieve. + +This overview is provided for people who are interested in the functional safety development part +of the Zephyr RTOS and project members who want to contribute to the safety aspects of the +project. + +Overview +******** + +In this section we give the reader an overview of what the general goal of the safety certification +is, what standard we aim to achieve and what quality standards and processes need to be implemented +to reach such a safety certification. + +Safety Document update +********************** + +This document is a living document and may evolve over time as new requirements, guidelines, or +processes are introduced. + +#. Changes will be submitted from the interested party(ies) via pull requests to the Zephyr + documentation repository. + +#. The Zephyr Safety Committee will review these changes and provide feedback or acceptance of + the changes. + +#. Once accepted, these changes will become part of the document. + +General safety scope +******************** + +The general scope of the Safety Committee is to achieve a certification for the `IEC 61508 +`__ standard and the Safety Integrity Level (SIL) 3 / +Systematic Capability (SC) 3 for a limited source scope (see certification scope TBD). Since the +code base is pre-existing, we use the route 3s/1s approach defined by the IEC 61508 standard. + +Route 3s + *Assessment of non-compliant development. Which is basically the route 1s with existing + sources.* + +Route 1s + *Compliant development. Compliance with the requirements of this standard for the avoidance and + control of systematic faults in software.* + +Summarization IEC 61508 standard +================================ + +The IEC 61508 standard is a widely recognized international standard for functional safety of +electrical, electronic, and programmable electronic safety-related systems. Here's an overview of +some of the key safety aspects of the standard: + +#. **Hazard and Risk Analysis**: The IEC 61508 standard requires a thorough analysis of potential + hazards and risks associated with a system in order to determine the appropriate level of safety + measures needed to reduce those risks to acceptable levels. + +#. **Safety Integrity Level (SIL)**: The standard introduces the concept of Safety Integrity Level + (SIL) to classify the level of risk reduction required for each safety function. The higher the + SIL, the greater the level of risk reduction required. + +#. **System Design**: The IEC 61508 standard requires a systematic approach to system design that + includes the identification of safety requirements, the development of a safety plan, and the + use of appropriate safety techniques and measures to ensure that the system meets the required + SIL. + +#. **Verification and Validation**: The standard requires rigorous testing and evaluation of the + safety-related system to ensure that it meets the specified SIL and other safety requirements. + This includes verification of the system design, validation of the system's functionality, and + ongoing monitoring and maintenance of the system. + +#. **Documentation and Traceability**: The IEC 61508 standard requires a comprehensive + documentation process to ensure that all aspects of the safety-related system are fully + documented and that there is full traceability from the safety requirements to the final system + design and implementation. + +Overall, the IEC 61508 standard provides a framework for the design, development, and +implementation of safety-related systems that aims to reduce the risk of accidents and improve +overall safety. By following the standard, organizations can ensure that their safety-related +systems are designed and implemented to the highest level of safety integrity. + +Quality +******* + +Quality is a mandatory expectation for software across the industry. The code base of the project +must achieve various software quality goals in order to be considered an auditable code base from a +safety perspective and to be usable for certification purposes. But software quality is not an +additional requirement caused by functional safety standards. Functional safety considers quality +as an existing pre-condition and therefore the "quality managed" status should be pursued for any +project regardless of the functional safety goals. The following list describes the quality goals +which need to be reached to achieve an auditable code base: + +1. Basic software quality standards + + a. :ref:`coding_guidelines` (including: static code analysis, coding style, etc.) + b. Requirements and requirements tracing + c. Test coverage + +2. Software architecture design principles + + a. Layered architecture model + b. Encapsulated components + c. Encapsulated single functionality (if not fitable and manageable in safety) + +Basic software quality standards - Safety view +============================================== + +In this chapter the Safety Committee describes why they need the above listed quality goals as +pre-condition and what needs to be done to achieve an auditable code base from the safety +perspective. Generally speaking, it can be said that all of these quality measures regarding safety +are used to minimize the error rate during code development. + +Coding Guidelines +----------------- + +The coding guidelines are the basis to a common understanding and a unified ruleset and development +style for industrial software products. For safety the coding guidelines are essential and have +another purpose beside the fact of a unified ruleset. It is also necessary to prove that the +developers follow a unified development style to prevent **systematic errors** in the process of +developing software and thus to minimize the overall **error rate** of the complete software +system. + +Also the **IEC 61508 standard** sets a pre-condition and recommendation towards the use of coding +standards / guidelines to reduce likelihood of errors. + +Requirements and requirements tracing +------------------------------------- + +Requirements and requirement management are not only important for software development, but also +very important in terms of safety. On the one hand, this specifies and describes in detail and on a +technical level what the software should do, and on the other hand, it is an important and +necessary tool to verify whether the described functionality is implemented as expected. For this +purpose, tracing the requirements down to the code level is used. With the requirements management +and tracing in hand, it can now be verified whether the functionality has been tested and +implemented correctly, thus minimizing the systematic error rate. + +Also the IEC 61508 standard highly recommends (which is like a must-have for the certification) +requirements and requirements tracing. + +Test coverage +------------- + +A high test coverage, in turn, is evidence of safety that the code conforms precisely to what it +was developed for and does not execute any unforeseen instructions. If the entire code is tested +and has a high (ideally 100%) test coverage, it has the additional advantage of quickly detecting +faulty changes and further minimizing the error rate. However, it must be noted that different +requirements apply to safety for test coverage, and various metrics must be considered, which are +prescribed by the IEC 61508 standard for the SIL 3 / SC3 target. The following must be fulfilled, +among other things: + +* Structural test coverage (entry points) 100% +* Structural test coverage (statements) 100% +* Structural test coverage (branches) 100% + +If the 100% cannot be reached (e.g. statement coverage of defensive code) that part needs to be +described and justified in the documentation. + +Software architecture design principles +======================================= + +To create and maintain a structured software product it is also necessary to consider individual +software architecture designs and implement them in accordance with safety standards because some +designs and implementations are not reasonable in safety, so that the overall software and code +base can be used as auditable code. However, most of these software architecture designs have +already been implemented in the Zephyr project and need to be verified by the Safety Committee / +Safety Working Group and the safety architect. + +Layered architecture model +-------------------------- + +The **IEC 61508 standard** strongly recommends a modular approach to software architecture. This +approach has been pursued in the Zephyr project from the beginning with its layered architecture. +The idea behind this architecture is to organize modules or components with similar functionality +into layers. As a result, each layer can be assigned a specific role in the system. This model has +the advantage in safety that interfaces between different components and layers can be shown at a +very high level, and thus it can be determined which functionalities are safety-relevant and can be +limited. Furthermore, various analyses and documentations can be built on top of this architecture, +which are important for certification and the responsible certification body. + +Encapsulated components +----------------------- + +Encapsulated components are an essential part of the architecture design for safety at this point. +The most important aspect is the separation of safety-relevant components from non-safety-relevant +components, including their associated interfaces. This ensures that the components have no +**repercussions** on other components. + +Encapsulated single functionality (if not reasonable and manageable in safety) +------------------------------------------------------------------------------ + +Another requirement for the overall system and software environment is that individual +functionalities can be disabled within components. This is because if a function is absolutely +unacceptable for safety (e.g. complete dynamic memory management), then these individual +functionalities should be able to be turned off. The Zephyr Project already offers such a +possibility through the use of Kconfig and its flexible configurability. + +Processes and workflow +********************** + +.. figure:: images/zephyr-safety-process.svg + :align: center + :alt: Safety process and workflow overview + :figclass: align-center + + Safety process and workflow overview + +The diagram describes the rough process defined by the Safety Committee to ensure safety in the +development of the Zephyr project. To ensure understanding, a few points need to be highlighted and +some details explained regarding the role of the safety architect and the role of the safety +committee in the whole process. The diagram only describes the paths that are possible when a +change is related to safety. + +#. On the main branch, the safety scope of the project should be identified, which typically + represents a small subset of the entire code base. This subset should then be made auditable + during normal development on “main”, which means that special attention is paid to quality goals + (`Quality`_) and safety processes within this scope. The Safety Architect works alongside the + Technical Steering Committee (TSC) in this area, monitoring the development process to ensure + that the architecture meets the safety requirements. + +#. At this point, the safety architect plays an increasingly important role. For PRs/issues that + fall within the safety scope, the safety architect should ideally be involved in the discussions + and decisions of minor changes in the safety scope to be able to react to safety-relevant + changes that are not conformant. If a pull request or issue introduces a significant and + influential change or improvement that requires extended discussion or decision-making, the + safety architect should bring it to the attention of the Safety Committee or the Technical + Steering Committee (TSC) as appropriate, so that they can make a decision on the best course of + action. + +#. This section describes the certification side. At this point, the code base has to be in an + "auditable" state, and ideally no further changes should be necessary or made to the code base. + There is still a path from the main branch to this area. This is needed in case a serious bug or + important change is found or implemented on the main branch in the safety scope, after the LTS + and the auditable branch were created. In this case, the Safety Committee, together with the + safety architect, must decide whether this bug fix or change should be integrated into the LTS + so that the bug fix or change could also be integrated into the auditable branch. This + integration can take three forms: First either as only a code change or second as only an update + to the safety documentation or third as both. + +#. This describes the necessary safety process required for certification itself. Here, the final + analyses, tests, and documents are created and conducted which must be created and conducted + during the certification, and which are prescribed by the certifying authority and the standard + being certified. If the certification body approves everything at this stage and the safety + process is completed, a safety release can be created and published. + +#. This transition from the auditable branch to the main branch should only occur in exceptional + circumstances, specifically when something has been identified during the certification process + that needs to be quickly adapted on the “auditable” branch in order to obtain certification. In + order to prevent this issue from arising again during the next certification, there needs to be + a path to merge these changes back into the main branch so that they are not lost, and to have + them ready for the next certification if necessary. + +.. important:: + Safety should not block the project and minimize the room to grow in any way. + +.. important:: + **TODO:** Find and define ways, guidelines and processes which minimally impact the daily work + of the maintainers, reviewers and contributors and also the safety architect itself. + But which are also suitable for safety. From 6815d9f720303e0a05e7f4ae17ebd794248f278c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:54:49 +0200 Subject: [PATCH 0487/2042] Bluetooth: MCC: Shell: Format IDs as 64-bit (llu) Fix formatting of the OTS object IDs to the proper formatting. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/mcc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/audio/shell/mcc.c b/subsys/bluetooth/audio/shell/mcc.c index 6c5d911c5557..71bc44c8ff3e 100644 --- a/subsys/bluetooth/audio/shell/mcc.c +++ b/subsys/bluetooth/audio/shell/mcc.c @@ -837,7 +837,7 @@ static int cmd_mcc_set_current_track_obj_id(const struct shell *sh, size_t argc, } if (!IN_RANGE(id, BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX)) { - shell_error(sh, "Invalid id: %lu", id); + shell_error(sh, "Invalid id: %llu", id); return -ENOEXEC; } @@ -875,7 +875,7 @@ static int cmd_mcc_set_next_track_obj_id(const struct shell *sh, size_t argc, } if (!IN_RANGE(id, BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX)) { - shell_error(sh, "Invalid id: %lu", id); + shell_error(sh, "Invalid id: %llu", id); return -ENOEXEC; } @@ -925,7 +925,7 @@ static int cmd_mcc_set_current_group_obj_id(const struct shell *sh, size_t argc, } if (!IN_RANGE(id, BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX)) { - shell_error(sh, "Invalid id: %lu", id); + shell_error(sh, "Invalid id: %llu", id); return -ENOEXEC; } @@ -1691,7 +1691,7 @@ static int cmd_mcc_otc_select(const struct shell *sh, size_t argc, char *argv[]) } if (!IN_RANGE(id, BT_OTS_OBJ_ID_MIN, BT_OTS_OBJ_ID_MAX)) { - shell_error(sh, "Invalid id: %lu", id); + shell_error(sh, "Invalid id: %llu", id); return -ENOEXEC; } From 0ace886359c622217d008b67eee02c9285cc11b3 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 21 Jun 2023 13:35:13 +0200 Subject: [PATCH 0488/2042] cache: Add note about buffer alignment and size Cache operations that act on unaligned buffers (with respect to cache line) or buffers that are not multiple of the cache line size are at least dangerous with an high risk of data and memory corruption. While we do not enforce a contract on the buffer characteristics between users and APIs, we can at least add a note in the documentation specifying an undefined behaviour when the passed buffer is unaligned or wrongly sized. Signed-off-by: Carlo Caione --- include/zephyr/arch/cache.h | 46 ++++++++++++++++++++++++++++++++++ include/zephyr/cache.h | 46 ++++++++++++++++++++++++++++++++++ include/zephyr/drivers/cache.h | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/include/zephyr/arch/cache.h b/include/zephyr/arch/cache.h index 25df6670b2d0..59bdf61e0d02 100644 --- a/include/zephyr/arch/cache.h +++ b/include/zephyr/arch/cache.h @@ -89,6 +89,13 @@ extern int arch_dcache_flush_and_invd_all(void); * * Flush the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -105,6 +112,14 @@ extern int arch_dcache_flush_range(void *addr, size_t size); * * Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -121,6 +136,14 @@ extern int arch_dcache_invd_range(void *addr, size_t size); * * Flush and Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * @@ -221,6 +244,13 @@ extern int arch_icache_flush_and_invd_all(void); * * Flush the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -237,6 +267,14 @@ extern int arch_icache_flush_range(void *addr, size_t size); * * Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -253,6 +291,14 @@ extern int arch_icache_invd_range(void *addr, size_t size); * * Flush and Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * diff --git a/include/zephyr/cache.h b/include/zephyr/cache.h index 8ab19794e069..994d96dccbe7 100644 --- a/include/zephyr/cache.h +++ b/include/zephyr/cache.h @@ -202,6 +202,13 @@ static ALWAYS_INLINE int sys_cache_instr_flush_and_invd_all(void) * * Flush the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -227,6 +234,13 @@ static ALWAYS_INLINE int z_impl_sys_cache_data_flush_range(void *addr, size_t si * * Flush the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -250,6 +264,14 @@ static ALWAYS_INLINE int sys_cache_instr_flush_range(void *addr, size_t size) * * Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -275,6 +297,14 @@ static ALWAYS_INLINE int z_impl_sys_cache_data_invd_range(void *addr, size_t siz * * Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -298,6 +328,14 @@ static ALWAYS_INLINE int sys_cache_instr_invd_range(void *addr, size_t size) * * Flush and Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * @@ -323,6 +361,14 @@ static ALWAYS_INLINE int z_impl_sys_cache_data_flush_and_invd_range(void *addr, * * Flush and Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * diff --git a/include/zephyr/drivers/cache.h b/include/zephyr/drivers/cache.h index 8b10e16740cb..b5b01dfea336 100644 --- a/include/zephyr/drivers/cache.h +++ b/include/zephyr/drivers/cache.h @@ -79,6 +79,13 @@ int cache_data_flush_and_invd_all(void); * * Flush the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -93,6 +100,14 @@ int cache_data_flush_range(void *addr, size_t size); * * Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -107,6 +122,14 @@ int cache_data_invd_range(void *addr, size_t size); * * Flush and Invalidate the specified address range of the data cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * @@ -190,6 +213,13 @@ int cache_instr_flush_and_invd_all(void); * * Flush the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed. This is usually + * not a problem because writing back is a non-destructive process that + * could be triggered by hardware at any time, so having an aligned + * @p addr or a padded @p size is not strictly necessary. + * * @param addr Starting address to flush. * @param size Range size. * @@ -204,6 +234,14 @@ int cache_instr_flush_range(void *addr, size_t size); * * Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being invalidated, all the portions of the + * non-read-only data structures sharing the same line will be + * invalidated as well. This is a destructive process that could lead to + * data loss and/or corruption. When @p addr is not aligned to the cache + * line and/or @p size is not a multiple of the cache line size the + * behaviour is undefined. + * * @param addr Starting address to invalidate. * @param size Range size. * @@ -218,6 +256,14 @@ int cache_instr_invd_range(void *addr, size_t size); * * Flush and Invalidate the specified address range of the instruction cache. * + * @note the cache operations act on cache line. When multiple data structures + * share the same cache line being flushed, all the portions of the + * data structures sharing the same line will be flushed before being + * invalidated. This is usually not a problem because writing back is a + * non-destructive process that could be triggered by hardware at any + * time, so having an aligned @p addr or a padded @p size is not strictly + * necessary. + * * @param addr Starting address to flush and invalidate. * @param size Range size. * From 7595cafb024500a747a8f9de198f94beddae51dc Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Fri, 2 Jun 2023 13:25:12 +0200 Subject: [PATCH 0489/2042] intel_adsp: timer: implemented sys_clock_idle_exit function Generic header for system clock allows to define a sys_clock_idle_exit function for the clock implementation. Implemented the function in the intel_adsp_timer to reinitialize device driver after the idle exit state. Signed-off-by: Andrey Borisovich --- drivers/timer/intel_adsp_timer.c | 9 +++++++++ soc/xtensa/intel_adsp/ace/power.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/timer/intel_adsp_timer.c b/drivers/timer/intel_adsp_timer.c index 2afc6b10406d..de6955dd40fe 100644 --- a/drivers/timer/intel_adsp_timer.c +++ b/drivers/timer/intel_adsp_timer.c @@ -225,5 +225,14 @@ static int sys_clock_driver_init(void) return 0; } +#ifdef CONFIG_PM + +void sys_clock_idle_exit(void) +{ + sys_clock_driver_init(); +} + +#endif + SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index ea3ea2e6d63f..4eda6f39df49 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -16,6 +16,7 @@ #include #include #include +#include #define LPSRAM_MAGIC_VALUE 0x13579BDF #define LPSCTL_BATTR_MASK GENMASK(16, 12) @@ -317,6 +318,7 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) imr_layout->imr_state.header.adsp_imr_magic = 0; imr_layout->imr_state.header.imr_restore_vector = NULL; imr_layout->imr_state.header.imr_ram_storage = NULL; + sys_clock_idle_exit(); } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ soc_cpus_active[cpu] = true; From 1d58b1b83f5dce19998d04d34d66be08a39de2e6 Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Thu, 23 Mar 2023 14:43:50 +0100 Subject: [PATCH 0490/2042] intel_adsp: mem_window: reinitialize after idle exit Exiting idle state requires to reinitialize all memory window instances to flush the cached memory. Added function that calls initialization of devices during runtime. Signed-off-by: Andrey Borisovich --- soc/xtensa/intel_adsp/ace/power.c | 2 ++ soc/xtensa/intel_adsp/common/include/mem_window.h | 6 ++++++ soc/xtensa/intel_adsp/common/mem_window.c | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 4eda6f39df49..a1004d5be803 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -17,6 +17,7 @@ #include #include #include +#include #define LPSRAM_MAGIC_VALUE 0x13579BDF #define LPSCTL_BATTR_MASK GENMASK(16, 12) @@ -319,6 +320,7 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) imr_layout->imr_state.header.imr_restore_vector = NULL; imr_layout->imr_state.header.imr_ram_storage = NULL; sys_clock_idle_exit(); + mem_window_idle_exit(); } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ soc_cpus_active[cpu] = true; diff --git a/soc/xtensa/intel_adsp/common/include/mem_window.h b/soc/xtensa/intel_adsp/common/include/mem_window.h index 3a2832fd2818..e38e48f5807a 100644 --- a/soc/xtensa/intel_adsp/common/include/mem_window.h +++ b/soc/xtensa/intel_adsp/common/include/mem_window.h @@ -42,6 +42,12 @@ struct mem_win_config { bool read_only; }; +/** + * @brief Reinitializes device after power state change. + * Should be run on Primary Core only. + */ +void mem_window_idle_exit(void); + #endif #endif diff --git a/soc/xtensa/intel_adsp/common/mem_window.c b/soc/xtensa/intel_adsp/common/mem_window.c index 4c027def0a75..e101d03ec162 100644 --- a/soc/xtensa/intel_adsp/common/mem_window.c +++ b/soc/xtensa/intel_adsp/common/mem_window.c @@ -37,6 +37,14 @@ __imr int mem_win_init(const struct device *dev) return 0; } +void mem_window_idle_exit(void) +{ + mem_win_init(DEVICE_DT_GET(MEM_WINDOW_NODE(0))); + mem_win_init(DEVICE_DT_GET(MEM_WINDOW_NODE(1))); + mem_win_init(DEVICE_DT_GET(MEM_WINDOW_NODE(2))); + mem_win_init(DEVICE_DT_GET(MEM_WINDOW_NODE(3))); +} + #define MEM_WINDOW_DEFINE(n) \ static const struct mem_win_config mem_win_config_##n = { \ .base_addr = DT_REG_ADDR(MEM_WINDOW_NODE(n)), \ From 355f8cfe4fbf843b9cda7548e5e9a3d1f9417b4e Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Thu, 12 Jan 2023 11:02:27 +0100 Subject: [PATCH 0491/2042] intel_adsp: ipc: device support D3 power state change When option CONFIG_PM_DEVICE is enabled, IPC driver is capable of entering D3 power state described as PM_DEVICE_ACTION_SUSPEND (and leaving that state - powering back to PM_DEVICE_ACTION_ACTIVE). New power control callbacks 'ipc_power_control_api' are introduced for use during power state transisions. They allow Zephyr application specific code to be executed. Signed-off-by: Andrey Borisovich --- .../common/include/intel_adsp_ipc.h | 38 ++++++ soc/xtensa/intel_adsp/common/ipc.c | 123 +++++++++++++++++- 2 files changed, 157 insertions(+), 4 deletions(-) diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h index e2339e24f095..eb383148fd2f 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h @@ -7,6 +7,10 @@ #include #include #include +#ifdef CONFIG_PM_DEVICE_RUNTIME +#include +#include +#endif struct intel_adsp_ipc_config { volatile struct intel_adsp_ipc *regs; @@ -174,4 +178,38 @@ bool intel_adsp_ipc_send_message_sync(const struct device *dev, void intel_adsp_ipc_send_message_emergency(const struct device *dev, uint32_t data, uint32_t ext_data); +#ifdef CONFIG_PM_DEVICE + +typedef int (*intel_adsp_ipc_resume_handler_t)(const struct device *dev, void *arg); + +typedef int (*intel_adsp_ipc_suspend_handler_t)(const struct device *dev, void *arg); + +/** + * @brief Registers resume callback handler used to resume Device from suspended state. + * + * @param dev IPC device. + * @param fn Callback function. + * @param arg Value to pass as the "arg" parameter to the function. + */ +void intel_adsp_ipc_set_resume_handler(const struct device *dev, + intel_adsp_ipc_resume_handler_t fn, void *arg); + +/** + * @brief Registers suspend callback handler used to suspend active Device. + * + * @param dev IPC device. + * @param fn Callback function. + * @param arg Value to pass as the "arg" parameter to the function. + */ +void intel_adsp_ipc_set_suspend_handler(const struct device *dev, + intel_adsp_ipc_suspend_handler_t fn, void *arg); + +struct ipc_control_driver_api { + intel_adsp_ipc_resume_handler_t resume_fn; + void *resume_fn_args; + intel_adsp_ipc_suspend_handler_t suspend_fn; + void *suspend_fn_args; +}; + +#endif /* CONFIG_PM_DEVICE */ #endif /* ZEPHYR_INCLUDE_INTEL_ADSP_IPC_H */ diff --git a/soc/xtensa/intel_adsp/common/ipc.c b/soc/xtensa/intel_adsp/common/ipc.c index c7adabe01ca9..54956cb5aece 100644 --- a/soc/xtensa/intel_adsp/common/ipc.c +++ b/soc/xtensa/intel_adsp/common/ipc.c @@ -7,7 +7,10 @@ #include #include #include - +#include +#include +#include +#include void intel_adsp_ipc_set_message_handler(const struct device *dev, intel_adsp_ipc_handler_t fn, void *arg) @@ -79,6 +82,7 @@ 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); @@ -86,6 +90,7 @@ void z_intel_adsp_ipc_isr(const void *devarg) int intel_adsp_ipc_init(const struct device *dev) { + pm_device_busy_set(dev); struct intel_adsp_ipc_data *devdata = dev->data; const struct intel_adsp_ipc_config *config = dev->config; @@ -102,6 +107,8 @@ int intel_adsp_ipc_init(const struct device *dev) config->regs->tda = INTEL_ADSP_IPC_DONE; #endif config->regs->ctl |= (INTEL_ADSP_IPC_CTL_IDIE | INTEL_ADSP_IPC_CTL_TBIE); + pm_device_busy_clear(dev); + return 0; } @@ -128,6 +135,7 @@ bool intel_adsp_ipc_is_complete(const struct device *dev) bool intel_adsp_ipc_send_message(const struct device *dev, uint32_t data, uint32_t ext_data) { + pm_device_busy_set(dev); const struct intel_adsp_ipc_config *config = dev->config; struct intel_adsp_ipc_data *devdata = dev->data; k_spinlock_key_t key = k_spin_lock(&devdata->lock); @@ -207,12 +215,119 @@ static int dt_init(const struct device *dev) return intel_adsp_ipc_init(dev); } +#ifdef CONFIG_PM_DEVICE + +void intel_adsp_ipc_set_resume_handler(const struct device *dev, + intel_adsp_ipc_resume_handler_t fn, void *arg) +{ + struct ipc_control_driver_api *api = + (struct ipc_control_driver_api *)dev->api; + struct intel_adsp_ipc_data *devdata = dev->data; + k_spinlock_key_t key = k_spin_lock(&devdata->lock); + + api->resume_fn = fn; + api->resume_fn_args = arg; + + k_spin_unlock(&devdata->lock, key); +} + +void intel_adsp_ipc_set_suspend_handler(const struct device *dev, + intel_adsp_ipc_suspend_handler_t fn, void *arg) +{ + struct ipc_control_driver_api *api = + (struct ipc_control_driver_api *)dev->api; + struct intel_adsp_ipc_data *devdata = dev->data; + k_spinlock_key_t key = k_spin_lock(&devdata->lock); + + api->suspend_fn = fn; + api->suspend_fn_args = arg; + + k_spin_unlock(&devdata->lock, key); +} + +/** + * @brief Manages IPC driver power state change. + * + * @param dev IPC device. + * @param action Power state to be changed to. + * @return int Returns 0 on success or optionaly error code from the + * registered ipc_power_control_api callbacks. + * + * @note PM lock is taken at the start of each power transition to prevent concurrent calls + * to @ref pm_device_action_run function. + * If IPC Device performs hardware operation and device is busy (what should not happen) + * function returns failure. It is API user responsibility to make sure we are not entering + * device power transition while device is busy. + */ +static int ipc_pm_action(const struct device *dev, enum pm_device_action action) +{ + if (pm_device_is_busy(INTEL_ADSP_IPC_HOST_DEV)) { + return -EBUSY; + } + + const struct ipc_control_driver_api *api = + (const struct ipc_control_driver_api *)dev->api; + + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + pm_device_state_lock(dev); + if (api->suspend_fn) { + ret = api->suspend_fn(dev, api->suspend_fn_args); + if (!ret) { + irq_disable(DT_IRQN(INTEL_ADSP_IPC_HOST_DTNODE)); + } + } + break; + case PM_DEVICE_ACTION_RESUME: + pm_device_state_lock(dev); + irq_enable(DT_IRQN(INTEL_ADSP_IPC_HOST_DTNODE)); + if (!irq_is_enabled(DT_IRQN(INTEL_ADSP_IPC_HOST_DTNODE))) { + ret = -EINTR; + break; + } + ace_ipc_intc_unmask(); + ret = intel_adsp_ipc_init(dev); + if (ret) { + break; + } + if (api->resume_fn) { + ret = api->resume_fn(dev, api->resume_fn_args); + } + break; + default: + /* Return as default value when given PM action is not supported */ + return -ENOTSUP; + } + + pm_device_state_unlock(dev); + return ret; +} + +/** + * @brief Callback functions to be executed by Zephyr application + * during IPC device suspend and resume. + */ +static struct ipc_control_driver_api ipc_power_control_api = { + .resume_fn = NULL, + .resume_fn_args = NULL, + .suspend_fn = NULL, + .suspend_fn_args = NULL +}; + +PM_DEVICE_DT_DEFINE(INTEL_ADSP_IPC_HOST_DTNODE, ipc_pm_action); + +#endif /* CONFIG_PM_DEVICE */ + static const struct intel_adsp_ipc_config ipc_host_config = { .regs = (void *)INTEL_ADSP_IPC_REG_ADDRESS, }; static struct intel_adsp_ipc_data ipc_host_data; -DEVICE_DT_DEFINE(INTEL_ADSP_IPC_HOST_DTNODE, dt_init, NULL, &ipc_host_data, &ipc_host_config, - PRE_KERNEL_2, 0, NULL); -#endif +DEVICE_DT_DEFINE(INTEL_ADSP_IPC_HOST_DTNODE, dt_init, PM_DEVICE_DT_GET(INTEL_ADSP_IPC_HOST_DTNODE), + &ipc_host_data, &ipc_host_config, PRE_KERNEL_2, 0, COND_CODE_1(CONFIG_PM_DEVICE, + (&ipc_power_control_api), (NULL))); + +#endif /* DT_NODE_EXISTS(INTEL_ADSP_IPC_HOST_DTNODE) */ From 23b3cae1b1d91cd064d31cdeb78e3a6127b5051d Mon Sep 17 00:00:00 2001 From: Andrey Borisovich Date: Wed, 24 May 2023 23:58:48 +0200 Subject: [PATCH 0492/2042] inte_adsp: ipc: prevent ipc message send during Device power transition When CONFIG_PM_DEVICE is enabled IPC Device may be during power transition during a call to intel_adsp_ipc_send_message function. Changed signatures of intel_adsp_ipc_send_message and its sync version to return int and negative error codes on error. On attempt to send IPC message during Device power transition -ESHUTDOWN error code is returned, on busy state -EBUSY. Updated all function references. Signed-off-by: Andrey Borisovich --- drivers/ipm/ipm_cavs_host.c | 6 ++--- .../common/include/intel_adsp_ipc.h | 14 ++++++----- soc/xtensa/intel_adsp/common/ipc.c | 25 ++++++++++++++----- .../logging/backends/log_backend_adsp_hda.c | 22 ++++++++-------- tests/boards/intel_adsp/hda/src/tests.h | 5 ++-- tests/boards/intel_adsp/hda_log/src/tests.h | 5 ++-- tests/boards/intel_adsp/smoke/src/cpus.c | 2 +- tests/boards/intel_adsp/smoke/src/hostipc.c | 12 ++++----- 8 files changed, 55 insertions(+), 36 deletions(-) diff --git a/drivers/ipm/ipm_cavs_host.c b/drivers/ipm/ipm_cavs_host.c index 7436770235ec..308acd8a9a20 100644 --- a/drivers/ipm/ipm_cavs_host.c +++ b/drivers/ipm/ipm_cavs_host.c @@ -78,7 +78,7 @@ static int send(const struct device *dev, int wait, uint32_t id, memcpy(buf, data, size); - bool ok = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, id, ext_data); + int ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, id, ext_data); /* The IPM docs call for "busy waiting" here, but in fact * there's a blocking synchronous call available that might be @@ -87,13 +87,13 @@ static int send(const struct device *dev, int wait, uint32_t id, * benefit anyway as all its usage is async. This is OK for * now. */ - if (ok && wait) { + if (ret == -EBUSY && wait) { while (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) { k_busy_wait(1); } } - return ok ? 0 : -EBUSY; + return ret; } static bool ipc_handler(const struct device *dev, void *arg, diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h index eb383148fd2f..2bca8c9c5b80 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_ipc.h @@ -139,30 +139,32 @@ bool intel_adsp_ipc_is_complete(const struct device *dev); * * Sends a message to the other side of an IPC link. The data and * ext_data parameters are passed using the IDR/IDD registers. - * Returns true if the message was sent, false if a current message is - * in progress (in the sense of intel_adsp_ipc_is_complete()). + * Returns 0 if the message was sent, negative error values: + * -EBUSY if there is already IPC message processed (intel_adsp_ipc_is_complete returns false). + * -ESHUTDOWN if IPC device will not send the message as it undergoes power + * transition. * * @param dev IPC device. * @param data 30 bits value to transmit with the message (IDR register). * @param ext_data Extended value to transmit with the message (IDD register). * @return message successfully transmitted. */ -bool intel_adsp_ipc_send_message(const struct device *dev, +int intel_adsp_ipc_send_message(const struct device *dev, uint32_t data, uint32_t ext_data); /** @brief Send an IPC message, block until completion. * * As for intel_adsp_ipc_send_message(), but blocks the current thread until * the completion of the message or the expiration of the provided - * timeout. + * timeout. Returns immediately if IPC device is during power transition. * * @param dev IPC device * @param data 30 bits value to transmit with the message (IDR register) * @param ext_data Extended value to transmit with the message (IDD register) * @param timeout Maximum time to wait, or K_FOREVER, or K_NO_WAIT - * @return message successfully transmitted + * @return returns 0 if message successfully transmited, otherwise error code. */ -bool intel_adsp_ipc_send_message_sync(const struct device *dev, +int intel_adsp_ipc_send_message_sync(const struct device *dev, uint32_t data, uint32_t ext_data, k_timeout_t timeout); diff --git a/soc/xtensa/intel_adsp/common/ipc.c b/soc/xtensa/intel_adsp/common/ipc.c index 54956cb5aece..cdb5757d3560 100644 --- a/soc/xtensa/intel_adsp/common/ipc.c +++ b/soc/xtensa/intel_adsp/common/ipc.c @@ -132,9 +132,22 @@ bool intel_adsp_ipc_is_complete(const struct device *dev) return not_busy && !devdata->tx_ack_pending; } -bool intel_adsp_ipc_send_message(const struct device *dev, +int intel_adsp_ipc_send_message(const struct device *dev, uint32_t data, uint32_t ext_data) { +#ifdef CONFIG_PM_DEVICE + enum pm_device_state current_state; + + if (pm_device_state_get(INTEL_ADSP_IPC_HOST_DEV, ¤t_state) != 0 || + current_state != PM_DEVICE_STATE_ACTIVE) { + return -ESHUTDOWN; + } +#endif + + if (pm_device_state_is_locked(INTEL_ADSP_IPC_HOST_DEV)) { + return -EAGAIN; + } + pm_device_busy_set(dev); const struct intel_adsp_ipc_config *config = dev->config; struct intel_adsp_ipc_data *devdata = dev->data; @@ -142,7 +155,7 @@ bool intel_adsp_ipc_send_message(const struct device *dev, if ((config->regs->idr & INTEL_ADSP_IPC_BUSY) != 0 || devdata->tx_ack_pending) { k_spin_unlock(&devdata->lock, key); - return false; + return -EBUSY; } k_sem_init(&devdata->sem, 0, 1); @@ -150,18 +163,18 @@ bool 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); - return true; + return 0; } -bool intel_adsp_ipc_send_message_sync(const struct device *dev, +int intel_adsp_ipc_send_message_sync(const struct device *dev, uint32_t data, uint32_t ext_data, k_timeout_t timeout) { struct intel_adsp_ipc_data *devdata = dev->data; - bool ret = intel_adsp_ipc_send_message(dev, data, ext_data); + int ret = intel_adsp_ipc_send_message(dev, data, ext_data); - if (ret) { + if (!ret) { k_sem_take(&devdata->sem, timeout); } return ret; diff --git a/subsys/logging/backends/log_backend_adsp_hda.c b/subsys/logging/backends/log_backend_adsp_hda.c index ef7b496d0ab9..a994be915989 100644 --- a/subsys/logging/backends/log_backend_adsp_hda.c +++ b/subsys/logging/backends/log_backend_adsp_hda.c @@ -332,8 +332,10 @@ void adsp_hda_log_init(adsp_hda_log_hook_t fn, uint32_t channel) static inline void hda_ipc_msg(const struct device *dev, uint32_t data, uint32_t ext, k_timeout_t timeout) { - __ASSERT(intel_adsp_ipc_send_message_sync(dev, data, ext, timeout), - "Unexpected ipc send message failure, try increasing IPC_TIMEOUT"); + int ret = intel_adsp_ipc_send_message_sync(dev, data, ext, timeout); + + __ASSERT(!ret, "Unexpected ipc send message failure, error code: %d", + ret); } @@ -342,20 +344,20 @@ 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. */ - bool done = false; + int ret = -1; /* Send IPC message notifying log data has been written */ do { - done = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_PRINT, + ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_HDA_PRINT, (written << 8) | CHANNEL); - } while (!done); - + if (ret == -ESHUTDOWN) { + return; + } + } while (ret); /* Wait for confirmation log data has been received */ - do { - done = intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV); - } while (!done); - + while (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) + ; } int adsp_hda_log_cavstool_init(void) diff --git a/tests/boards/intel_adsp/hda/src/tests.h b/tests/boards/intel_adsp/hda/src/tests.h index 9e00e59da6be..22bc49c3ec72 100644 --- a/tests/boards/intel_adsp/hda/src/tests.h +++ b/tests/boards/intel_adsp/hda/src/tests.h @@ -31,8 +31,9 @@ static inline void hda_ipc_msg(const struct device *dev, uint32_t data, uint32_t ext, k_timeout_t timeout) { - zassert_true(intel_adsp_ipc_send_message_sync(dev, data, ext, timeout), - "Unexpected ipc send message failure, try increasing IPC_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/src/tests.h b/tests/boards/intel_adsp/hda_log/src/tests.h index d6684b1aa9c3..f8186ab06439 100644 --- a/tests/boards/intel_adsp/hda_log/src/tests.h +++ b/tests/boards/intel_adsp/hda_log/src/tests.h @@ -13,8 +13,9 @@ static inline void hda_ipc_msg(const struct device *dev, uint32_t data, uint32_t ext, k_timeout_t timeout) { - zassert_true(intel_adsp_ipc_send_message_sync(dev, data, ext, timeout), - "Unexpected ipc send message failure, try increasing IPC_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/smoke/src/cpus.c b/tests/boards/intel_adsp/smoke/src/cpus.c index edb0bc0e1cf4..c3852bfb4594 100644 --- a/tests/boards/intel_adsp/smoke/src/cpus.c +++ b/tests/boards/intel_adsp/smoke/src/cpus.c @@ -162,7 +162,7 @@ static void halt_and_restart(int cpu) int ret; /* On older hardware we need to get the host to turn the core - * off. Construct an ADSPCS with only this core disabled + * off. Construct an ADSPCS with only this core disabled */ if (!IS_ENABLED(CONFIG_SOC_INTEL_CAVS_V25)) { intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_ADSPCS, diff --git a/tests/boards/intel_adsp/smoke/src/hostipc.c b/tests/boards/intel_adsp/smoke/src/hostipc.c index 112f44053993..cb71af352cfd 100644 --- a/tests/boards/intel_adsp/smoke/src/hostipc.c +++ b/tests/boards/intel_adsp/smoke/src/hostipc.c @@ -32,7 +32,7 @@ static bool ipc_done(const struct device *dev, void *arg) ZTEST(intel_adsp, test_host_ipc) { - bool ret; + int ret; intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_message, NULL); intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_done, NULL); @@ -41,7 +41,7 @@ ZTEST(intel_adsp, test_host_ipc) printk("Simple message send...\n"); done_flag = false; ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_SIGNAL_DONE, 0); - zassert_true(ret, "send failed"); + zassert_true(!ret, "send failed"); AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)); AWAIT(done_flag); @@ -53,7 +53,7 @@ ZTEST(intel_adsp, test_host_ipc) msg_flag = false; ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG, RETURN_MSG_SYNC_VAL); - zassert_true(ret, "send failed"); + zassert_true(!ret, "send failed"); AWAIT(done_flag); AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)); AWAIT(msg_flag); @@ -66,7 +66,7 @@ ZTEST(intel_adsp, test_host_ipc) msg_flag = false; ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG, RETURN_MSG_SYNC_VAL); - zassert_true(ret, "send failed"); + zassert_true(!ret, "send failed"); AWAIT(done_flag); AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)); AWAIT(msg_flag); @@ -77,7 +77,7 @@ ZTEST(intel_adsp, test_host_ipc) msg_flag = false; ret = intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_RETURN_MSG, RETURN_MSG_ASYNC_VAL); - zassert_true(ret, "send failed"); + zassert_true(!ret, "send failed"); AWAIT(done_flag); AWAIT(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)); AWAIT(msg_flag); @@ -92,7 +92,7 @@ ZTEST(intel_adsp, test_host_ipc) done_flag = false; ret = intel_adsp_ipc_send_message_sync(INTEL_ADSP_IPC_HOST_DEV, IPCCMD_ASYNC_DONE_DELAY, 0, K_FOREVER); - zassert_true(ret, "send failed"); + zassert_true(!ret, "send failed"); zassert_true(done_flag, "done interrupt failed to fire"); zassert_true(intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV), "sync message incomplete"); From c5623c641a3ce6e163a5a36a5b4a1bf0d6cb6316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Thu, 22 Jun 2023 10:36:22 +0200 Subject: [PATCH 0493/2042] Bluetooth: Host: Check that `conn` is not NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `gatt.c`, the function `bt_gatt_ccc_cfg_conn_lookup()` was not checking that `conn` was not NULL. That leaded to a NULL pointer dereferences later in `bt_conn_is_peer_addr_le`. Fix by checking that `conn` is not NULL. Signed-off-by: Théo Battrel --- subsys/bluetooth/host/gatt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 9de7fb161217..4d86337ba082 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -2068,7 +2068,7 @@ static struct bt_conn *bt_gatt_ccc_cfg_conn_lookup(const struct bt_gatt_ccc_cfg conn = bt_conn_lookup_addr_le(cfg->id, &cfg->peer); - if (bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { + if (conn && bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { return conn; } From c0d842bb55eea7c94ae8133143ccc2bed666bafc Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 16:26:54 +0200 Subject: [PATCH 0494/2042] Bluetooth: BAP: Shell: Remove duplicate increment of seq_num The seq_num in lc3_audio_send_data was updated twice: Once when calling get_next_seq_num and once at the end of the function. This increased the sequence numbers too fast, and made TX not worker properly. Modified to only use get_next_seq_num. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index a332f950cf08..2a17ed52889c 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -322,7 +322,6 @@ static void lc3_audio_send_data(struct k_work *work) lc3_sdu_cnt, tx_sdu_len); } lc3_sdu_cnt++; - seq_num++; } static K_WORK_DEFINE(audio_send_work, lc3_audio_send_data); From 17ea3546d3306187fa1fc35755cb7ad0506ff35a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 16:15:43 +0200 Subject: [PATCH 0495/2042] Bluetooth: BAP: Shell: Fix endianess of broadcast_id in adv data The broadcast ID was encoded as big instead of little endian in the advertising data. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 2a17ed52889c..5efada33af81 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -2621,9 +2621,7 @@ static ssize_t nonconnectable_ad_data_add(struct bt_data *data_array, return -1; } - ad_bap_broadcast_announcement[2] = (uint8_t)(broadcast_id >> 16); - ad_bap_broadcast_announcement[3] = (uint8_t)(broadcast_id >> 8); - ad_bap_broadcast_announcement[4] = (uint8_t)(broadcast_id >> 0); + sys_put_le24(broadcast_id, &ad_bap_broadcast_announcement[2]); data_array[ad_len].type = BT_DATA_SVC_DATA16; data_array[ad_len].data_len = ARRAY_SIZE(ad_bap_broadcast_announcement); data_array[ad_len].data = ad_bap_broadcast_announcement; From 16b8191be0c691873313403fa8311ea65e9bafdd Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Mon, 19 Jun 2023 17:18:03 +0100 Subject: [PATCH 0496/2042] SMP: fix build failure if SMP=y and SYS_CLOCK_EXISTS=n Fix build failure for the SMP configurations without sysclock. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- kernel/include/kernel_internal.h | 2 ++ kernel/smp.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index 7dfa7d3f0fd3..8ce31b22fbc6 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -141,8 +141,10 @@ z_thread_return_value_set_with_data(struct k_thread *thread, #ifdef CONFIG_SMP extern void z_smp_init(void); +#ifdef CONFIG_SYS_CLOCK_EXISTS extern void smp_timer_init(void); #endif +#endif extern void z_early_boot_rand_get(uint8_t *buf, size_t length); diff --git a/kernel/smp.c b/kernel/smp.c index 2ec2ea478dc5..8ae2116989e4 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -85,7 +85,9 @@ static inline FUNC_NORETURN void smp_init_top(void *arg) wait_for_start_signal(arg); z_dummy_thread_init(&dummy_thread); +#ifdef CONFIG_SYS_CLOCK_EXISTS smp_timer_init(); +#endif z_swap_unlocked(); From d9082cd5b413a46327d089f29bfcf97d850c4ebb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 11:23:49 +0200 Subject: [PATCH 0497/2042] Bluetooth: ASCS: Fix bad size of metadata_backup The metadata_backup used the codec config size instead of the metadata size. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index b9054d50c12e..8a75ba555e0f 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -2015,7 +2015,7 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, uint8_t *data, uint8_t len static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) { - struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_DATA_COUNT]; + struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_METADATA_COUNT]; struct bt_bap_stream *stream; struct bt_bap_ep *ep; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, From 3ede93f16603a79f835f42a9f32d55e1767a6a55 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 16:03:57 +0200 Subject: [PATCH 0498/2042] Bluetooth: BAP: Shell: Fix missing clear of txing_stream If the stream is stopped or released, we did not clear the txing_stream which is what would stop the sine from being attempted to being sent. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 5efada33af81..c1acd2095d33 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -192,6 +192,15 @@ static int octets_per_frame; static int64_t lc3_start_time; static int32_t lc3_sdu_cnt; +static void clear_lc3_sine_data(void) +{ + lc3_start_time = 0; + lc3_sdu_cnt = 0; + txing_stream = NULL; + + (void)k_work_cancel(&audio_send_work); +} + /** * Use the math lib to generate a sine-wave using 16 bit samples into a buffer. * @@ -1715,10 +1724,7 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) #if defined(CONFIG_LIBLC3) if (stream == default_stream) { - lc3_start_time = 0; - lc3_sdu_cnt = 0; - - k_work_cancel(&audio_send_work); + clear_lc3_sine_data(); } #endif /* CONFIG_LIBLC3 */ } @@ -1767,10 +1773,7 @@ static void stream_released_cb(struct bt_bap_stream *stream) #if defined(CONFIG_LIBLC3) /* stop sending */ if (stream == default_stream) { - lc3_start_time = 0; - lc3_sdu_cnt = 0; - - k_work_cancel(&audio_send_work); + clear_lc3_sine_data(); } #endif /* CONFIG_LIBLC3 */ } @@ -2402,12 +2405,7 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[]) { - lc3_start_time = 0; - lc3_sdu_cnt = 0; - - k_work_cancel(&audio_send_work); - - txing_stream = NULL; + clear_lc3_sine_data(); return 0; } From 969d2791907560109edf348776e1fc3d17a6b317 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 11:19:52 +0200 Subject: [PATCH 0499/2042] samples: Bluetooth: Unicast client missing err check on sem Added missing error check when taking the sem_stream_qos. Signed-off-by: Emil Gydesen --- samples/bluetooth/unicast_audio_client/src/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 63fffe8834e7..2b7d72cb7188 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -963,7 +963,11 @@ static int set_stream_qos(void) for (size_t i = 0U; i < configured_stream_count; i++) { printk("QoS: waiting for %zu streams\n", configured_stream_count); - k_sem_take(&sem_stream_qos, K_FOREVER); + err = k_sem_take(&sem_stream_qos, K_FOREVER); + if (err != 0) { + printk("failed to take sem_stream_qos (err %d)\n", err); + return err; + } } return 0; From ca1fd0352006c99d747c0398830ae868cc9ce2ba Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 11:17:28 +0200 Subject: [PATCH 0500/2042] samples: Bluetooth: Fix TMAP peripheral off-by-one URI schemes i has to be less than the size of the array, as we use i as the index. Signed-off-by: Emil Gydesen --- samples/bluetooth/tmap_peripheral/src/ccp_call_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bluetooth/tmap_peripheral/src/ccp_call_ctrl.c b/samples/bluetooth/tmap_peripheral/src/ccp_call_ctrl.c index 72aaae2aafd0..08745be0e19c 100644 --- a/samples/bluetooth/tmap_peripheral/src/ccp_call_ctrl.c +++ b/samples/bluetooth/tmap_peripheral/src/ccp_call_ctrl.c @@ -100,7 +100,7 @@ static void read_uri_schemes_string_cb(struct bt_conn *conn, int err, } } - if (i > sizeof(remote_uri)) { + if (i >= sizeof(remote_uri)) { printk("Cannot store URI of length %zu: %s\n", i, value); return; } From 8cd0758bdf1dd68e4c2f60a8948d66ea63d81c3f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 22:35:18 +0200 Subject: [PATCH 0501/2042] Bluetooth: Shell: Move scan filter to function Move the scan filter to a new function so that it may be reused by other shell modules. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 4 ++ .../audio/shell/bap_broadcast_assistant.c | 4 ++ .../audio/shell/csip_set_coordinator.c | 4 ++ subsys/bluetooth/shell/bt.c | 59 ++++++++++++++----- subsys/bluetooth/shell/bt.h | 2 + 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index c1acd2095d33..a0a1a0a98517 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -1512,6 +1512,10 @@ static bool broadcast_scan_recv(const struct bt_le_scan_recv_info *info, { char le_addr[BT_ADDR_LE_STR_LEN]; + if (!passes_scan_filter(info, ad)) { + return false; + } + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); shell_print(ctx_shell, "Found broadcaster with ID 0x%06X and addr %s", diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 938838f2ab2e..72fe52c44e49 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -561,6 +561,10 @@ static void scan_recv_cb(const struct bt_le_scan_recv_info *info, return; } + if (!passes_scan_filter(info, ad)) { + return; + } + bt_data_parse(ad, broadcast_source_found, (void *)info); } diff --git a/subsys/bluetooth/audio/shell/csip_set_coordinator.c b/subsys/bluetooth/audio/shell/csip_set_coordinator.c index ce43cda1a379..9cb747680f77 100644 --- a/subsys/bluetooth/audio/shell/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/shell/csip_set_coordinator.c @@ -165,6 +165,10 @@ 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 (!passes_scan_filter(info, ad)) { + return; + } + if (cur_inst != NULL) { bt_data_parse(ad, csip_found, (void *)info->addr); } diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 41e7422aab4e..76d836e9bc3e 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -347,41 +347,68 @@ static const char *scan_response_type_txt(uint8_t type) } } -static void scan_recv(const struct bt_le_scan_recv_info *info, - struct net_buf_simple *buf) +bool passes_scan_filter(const struct bt_le_scan_recv_info *info, const struct net_buf_simple *buf) { - char le_addr[BT_ADDR_LE_STR_LEN]; - char name[NAME_LEN]; - struct net_buf_simple buf_copy; if (scan_filter.rssi_set && (scan_filter.rssi > info->rssi)) { - return; + return false; } - bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + if (scan_filter.pa_interval_set && + (scan_filter.pa_interval > BT_CONN_INTERVAL_TO_MS(info->interval))) { + return false; + } - if (scan_filter.addr_set && !is_substring(scan_filter.addr, le_addr)) { - return; + if (scan_filter.addr_set) { + char le_addr[BT_ADDR_LE_STR_LEN] = {0}; + int err; + + err = bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + if (err != 0) { + shell_error(ctx_shell, "Failed to convert addr to string: %d", err); + return false; + } + + if (!is_substring(scan_filter.addr, le_addr)) { + return false; + } } - if (scan_verbose_output) { + if (scan_filter.name_set) { + struct net_buf_simple buf_copy; + char name[NAME_LEN] = {0}; + /* call to bt_data_parse consumes netbufs so shallow clone for verbose output */ net_buf_simple_clone(buf, &buf_copy); + bt_data_parse(&buf_copy, data_cb, name); + + if (!is_substring(scan_filter.name, name)) { + return false; + } } - (void)memset(name, 0, sizeof(name)); + return true; +} - bt_data_parse(buf, data_cb, name); +static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) +{ + char le_addr[BT_ADDR_LE_STR_LEN]; + char name[NAME_LEN]; + struct net_buf_simple buf_copy; - if (scan_filter.name_set && !is_substring(scan_filter.name, name)) { + if (!passes_scan_filter(info, buf)) { return; } - if (scan_filter.pa_interval_set && - (scan_filter.pa_interval > BT_CONN_INTERVAL_TO_MS(info->interval))) { - return; + if (scan_verbose_output) { + /* call to bt_data_parse consumes netbufs so shallow clone for verbose output */ + net_buf_simple_clone(buf, &buf_copy); } + (void)memset(name, 0, sizeof(name)); + + bt_data_parse(buf, data_cb, name); + shell_print(ctx_shell, "%s%s, AD evt type %u, RSSI %i %s " "C:%u S:%u D:%d SR:%u E:%u Prim: %s, Secn: %s, " "Interval: 0x%04x (%u us), SID: 0x%x", diff --git a/subsys/bluetooth/shell/bt.h b/subsys/bluetooth/shell/bt.h index 76772f85bf56..036633cbb631 100644 --- a/subsys/bluetooth/shell/bt.h +++ b/subsys/bluetooth/shell/bt.h @@ -19,6 +19,8 @@ extern const struct shell *ctx_shell; extern struct bt_conn *default_conn; +bool passes_scan_filter(const struct bt_le_scan_recv_info *info, const struct net_buf_simple *buf); + #if defined(CONFIG_BT_ISO) extern struct bt_iso_chan iso_chan; #endif /* CONFIG_BT_ISO */ From a16bcd291de7a57f6630afc92a73fc91027ba80e Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 22 Jun 2023 10:56:33 +0200 Subject: [PATCH 0502/2042] Bluetooth: Mesh: Avoid NULL pointer dereference in shell utils bt_mesh_elem_find can return NULL. This also gets rid of VLA in bt_mesh_shell_mdl_print_all. Coverity-CID: 321075 Fixes #59522 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/shell/utils.c | 35 +++++------------------------ 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/subsys/bluetooth/mesh/shell/utils.c b/subsys/bluetooth/mesh/shell/utils.c index 37658d99e765..8b7ca7406631 100644 --- a/subsys/bluetooth/mesh/shell/utils.c +++ b/subsys/bluetooth/mesh/shell/utils.c @@ -13,27 +13,6 @@ #include "mesh/access.h" #include "utils.h" -struct shell_model_instance { - uint16_t addr; - uint8_t elem_idx; -}; - -static void model_instances_get(uint16_t id, struct shell_model_instance *arr, uint8_t len) -{ - const struct bt_mesh_comp *comp = bt_mesh_comp_get(); - struct bt_mesh_elem *elem; - struct bt_mesh_model *mod; - - for (int i = 0; i < len; i++) { - elem = bt_mesh_elem_find(comp->elem[i].addr); - mod = bt_mesh_model_find(elem, id); - if (mod) { - arr[i].addr = comp->elem[i].addr; - arr[i].elem_idx = mod->elem_idx; - } - } -} - bool bt_mesh_shell_mdl_first_get(uint16_t id, struct bt_mesh_model **mod) { const struct bt_mesh_comp *comp = bt_mesh_comp_get(); @@ -73,17 +52,15 @@ int bt_mesh_shell_mdl_instance_set(const struct shell *sh, struct bt_mesh_model int bt_mesh_shell_mdl_print_all(const struct shell *sh, uint16_t mod_id) { - uint8_t elem_cnt = bt_mesh_elem_count(); - struct shell_model_instance mod_arr[elem_cnt]; - - memset(mod_arr, 0, sizeof(mod_arr)); - model_instances_get(mod_id, mod_arr, ARRAY_SIZE(mod_arr)); + const struct bt_mesh_comp *comp = bt_mesh_comp_get(); + struct bt_mesh_model *mod; - for (int i = 0; i < ARRAY_SIZE(mod_arr); i++) { - if (mod_arr[i].addr) { + for (int i = 0; i < comp->elem_count; i++) { + mod = bt_mesh_model_find(&comp->elem[i], mod_id); + if (mod) { shell_print(sh, "Client model instance found at addr 0x%.4X. Element index: %d", - mod_arr[i].addr, mod_arr[i].elem_idx); + comp->elem[i].addr, mod->elem_idx); } } From c214ec3cf410ee93e519bf3b34421d1af6230af0 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 22 Jun 2023 11:26:52 +0200 Subject: [PATCH 0503/2042] Bluetooth: Mesh: Fix dead code issue when getting node id state Refactor the function to avoid dead code. Coverity-CID: 321153 Fixes #59527 Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/subnet.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index df71d3a4eb83..e697d985c247 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -695,15 +695,13 @@ uint8_t bt_mesh_subnet_priv_node_id_get(uint16_t net_idx, enum bt_mesh_subnets_node_id_state bt_mesh_subnets_node_id_state_get(void) { for (int i = 0; i < ARRAY_SIZE(subnets); i++) { - bool priv_node_id = false; - + if (subnets[i].node_id) { #if CONFIG_BT_MESH_PRIV_BEACONS - priv_node_id = subnets[i].priv_beacon_ctx.node_id; + if (subnets[i].priv_beacon_ctx.node_id) { + return BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED_PRIVATE; + } #endif - - if (subnets[i].node_id || priv_node_id) { - return priv_node_id ? BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED_PRIVATE : - BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED; + return BT_MESH_SUBNETS_NODE_ID_STATE_ENABLED; } } From 80a986f43890273bbd0bf4e2da903089b2d821b9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 21 Jun 2023 19:33:12 +0100 Subject: [PATCH 0504/2042] tests: add an input build_all test Add an input build_all test with a bunch of input driver, move the ft5336 one out of sensors as well. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 1 + tests/drivers/build_all/input/CMakeLists.txt | 8 +++ tests/drivers/build_all/input/app.overlay | 62 ++++++++++++++++++++ tests/drivers/build_all/input/prj.conf | 2 + tests/drivers/build_all/input/src/main.c | 10 ++++ tests/drivers/build_all/input/testcase.yaml | 7 +++ tests/drivers/build_all/sensor/i2c.dtsi | 6 -- 7 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 tests/drivers/build_all/input/CMakeLists.txt create mode 100644 tests/drivers/build_all/input/app.overlay create mode 100644 tests/drivers/build_all/input/prj.conf create mode 100644 tests/drivers/build_all/input/src/main.c create mode 100644 tests/drivers/build_all/input/testcase.yaml diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 4498ca3040cd..e54c57f99e74 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1549,6 +1549,7 @@ Input: - include/zephyr/input/ - samples/subsys/input/ - subsys/input/ + - tests/drivers/build_all/input/ - tests/subsys/input/ description: >- Input subsystem and drivers diff --git a/tests/drivers/build_all/input/CMakeLists.txt b/tests/drivers/build_all/input/CMakeLists.txt new file mode 100644 index 000000000000..518596a02f78 --- /dev/null +++ b/tests/drivers/build_all/input/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/input/app.overlay b/tests/drivers/build_all/input/app.overlay new file mode 100644 index 000000000000..4f0bbe9547b5 --- /dev/null +++ b/tests/drivers/build_all/input/app.overlay @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@0 { + compatible = "vnd,gpio"; + gpio-controller; + reg = <00 0x1000>; + #gpio-cells = <0x2>; + status = "okay"; + }; + + gpio-keys { + compatible = "zephyr,gpio-keys"; + debounce-interval-ms = <30>; + button_0 { + gpios = <&test_gpio 0 0>; + zephyr,code = <0>; + }; + }; + + qdec-gpio { + compatible = "gpio-qdec"; + gpios = <&test_gpio 0 0>, <&test_gpio 1 0>; + steps-per-period = <4>; + zephyr,axis = <0>; + sample-time-us = <2000>; + idle-timeout-ms = <200>; + }; + + longpress: longpress { + input = <&longpress>; + compatible = "zephyr,input-longpress"; + input-codes = <0>; + short-codes = <0>; + long-codes = <0>; + long-delay-ms = <100>; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,i2c"; + reg = <0x1 0x1000>; + status = "okay"; + clock-frequency = <100000>; + + ft5336@0 { + compatible = "focaltech,ft5336"; + reg = <0x0>; + int-gpios = <&test_gpio 0 0>; + }; + }; + }; +}; diff --git a/tests/drivers/build_all/input/prj.conf b/tests/drivers/build_all/input/prj.conf new file mode 100644 index 000000000000..d87817b31bd7 --- /dev/null +++ b/tests/drivers/build_all/input/prj.conf @@ -0,0 +1,2 @@ +CONFIG_GPIO=y +CONFIG_INPUT=y diff --git a/tests/drivers/build_all/input/src/main.c b/tests/drivers/build_all/input/src/main.c new file mode 100644 index 000000000000..ccbdca6d36b1 --- /dev/null +++ b/tests/drivers/build_all/input/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/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml new file mode 100644 index 000000000000..ea0777be1310 --- /dev/null +++ b/tests/drivers/build_all/input/testcase.yaml @@ -0,0 +1,7 @@ +tests: + drivers.input.build: + tags: + - drivers + - input + build_only: true + platform_allow: native_posix diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 454712b74fe7..d7bc380c92b7 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -90,12 +90,6 @@ test_i2c_bmm150: bmm150@d { reg = <0xd>; }; -test_i2c_ft5336: ft5336@e { - compatible = "focaltech,ft5336"; - reg = <0xe>; - int-gpios = <&test_gpio 0 0>; -}; - test_i2c_ht16k33: ht16k33@f { compatible = "holtek,ht16k33"; reg = <0xf>; From 9ef019d28dd90f9ffcd8cc553f5912f95db6f95a Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 20 Jun 2023 14:25:16 +0200 Subject: [PATCH 0505/2042] Bluetooth: tmap: Fix TMAS characteristic permissions This fixes TMAS characteristic permissions. The characteristic shall have no security related permissions as per TMAP_v1.0. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/audio/tmap.c b/subsys/bluetooth/audio/tmap.c index b1024496cc77..e5375cfc8973 100644 --- a/subsys/bluetooth/audio/tmap.c +++ b/subsys/bluetooth/audio/tmap.c @@ -141,10 +141,10 @@ static ssize_t read_role(struct bt_conn *conn, /* Telephony and Media Audio Service attributes */ #define BT_TMAS_SERVICE_DEFINITION \ BT_GATT_PRIMARY_SERVICE(BT_UUID_TMAS), \ - BT_AUDIO_CHRC(BT_UUID_GATT_TMAPR, \ - BT_GATT_CHRC_READ, \ - BT_GATT_PERM_READ_ENCRYPT, \ - read_role, NULL, NULL) + BT_GATT_CHARACTERISTIC(BT_UUID_GATT_TMAPR, \ + BT_GATT_CHRC_READ, \ + BT_GATT_PERM_READ, \ + read_role, NULL, NULL) static struct bt_gatt_attr svc_attrs[] = { BT_TMAS_SERVICE_DEFINITION }; static struct bt_gatt_service tmas; From 44d61bde848377a32f4f9f12d5d20aa9b86bc04f Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 21 Jun 2023 18:24:52 +0200 Subject: [PATCH 0506/2042] posix: eventfd: fix waking up poll() Fix a regression introduced by commit e6eb0a705bc8 ("posix: eventfd: revise locking, signaling, and allocation"), which was a complete rewrite stating that: The `wait_q` and `k_poll_signal` entries were removed from `struct eventfd` as they were unnecessary. In fact, `k_poll_signal` (both `read_sig` and `write_sig`) were used to wake-up blocking `poll()` invocation in another thread. This is no longer the case now, i.e. `poll(..., POLLIN)` does not return after calling `eventfd_write()` on the observed (polled) FD. Fix this regression by bringing back `read_sig` and `write_sig` to very similar state as it was before. Fixes: e6eb0a705bc8 ("posix: eventfd: revise locking, signaling, and allocation") Signed-off-by: Marcin Niestroj --- lib/posix/eventfd.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/posix/eventfd.c b/lib/posix/eventfd.c index a8cc059cb20f..d32ac4c06b42 100644 --- a/lib/posix/eventfd.c +++ b/lib/posix/eventfd.c @@ -17,6 +17,8 @@ #define EFD_FLAGS_SET_INTERNAL (EFD_SEMAPHORE | EFD_NONBLOCK) struct eventfd { + struct k_poll_signal read_sig; + struct k_poll_signal write_sig; struct k_spinlock lock; eventfd_t cnt; int flags; @@ -49,12 +51,29 @@ static int eventfd_poll_prepare(struct eventfd *efd, struct k_poll_event **pev, struct k_poll_event *pev_end) { - if ((pfd->events & (ZSOCK_POLLOUT | ZSOCK_POLLIN)) != 0) { + if (pfd->events & ZSOCK_POLLIN) { if (*pev == pev_end) { errno = ENOMEM; return -1; } - **pev = (struct k_poll_event){0}; + + (*pev)->obj = &efd->read_sig; + (*pev)->type = K_POLL_TYPE_SIGNAL; + (*pev)->mode = K_POLL_MODE_NOTIFY_ONLY; + (*pev)->state = K_POLL_STATE_NOT_READY; + (*pev)++; + } + + if (pfd->events & ZSOCK_POLLOUT) { + if (*pev == pev_end) { + errno = ENOMEM; + return -1; + } + + (*pev)->obj = &efd->write_sig; + (*pev)->type = K_POLL_TYPE_SIGNAL; + (*pev)->mode = K_POLL_MODE_NOTIFY_ONLY; + (*pev)->state = K_POLL_STATE_NOT_READY; (*pev)++; } @@ -99,6 +118,12 @@ static int eventfd_read_locked(struct eventfd *efd, eventfd_t *value) efd->cnt = 0; } + if (efd->cnt == 0) { + k_poll_signal_reset(&efd->read_sig); + } + + k_poll_signal_raise(&efd->write_sig, 0); + return 0; } @@ -124,6 +149,12 @@ static int eventfd_write_locked(struct eventfd *efd, eventfd_t *value) /* successful write */ efd->cnt = result; + if (efd->cnt == (UINT64_MAX - 1)) { + k_poll_signal_reset(&efd->write_sig); + } + + k_poll_signal_raise(&efd->read_sig, 0); + return 0; } @@ -398,6 +429,16 @@ int eventfd(unsigned int initval, int flags) efd->flags = EFD_IN_USE_INTERNAL | flags; efd->cnt = initval; + k_poll_signal_init(&efd->write_sig); + k_poll_signal_init(&efd->read_sig); + + if (initval != 0) { + k_poll_signal_raise(&efd->read_sig, 0); + } + if (initval < UINT64_MAX - 1) { + k_poll_signal_raise(&efd->write_sig, 0); + } + z_finalize_fd(fd, efd, &eventfd_fd_vtable); return fd; From 2bc980f83190b22f4aa3f6b1560b40ece649ed95 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Wed, 21 Jun 2023 18:31:40 +0200 Subject: [PATCH 0507/2042] tests: eventfd: test wake-up from pending poll() Make sure that `poll(..., POLLIN)` executed from another thread returns when `eventfd_write()` is called. Test also the same with `poll(..., POLLOUT)` and `eventfd_read()` on eventfd with counter equal to `UINT64_MAX - 1`. Signed-off-by: Marcin Niestroj --- tests/posix/eventfd/src/blocking.c | 74 ++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/tests/posix/eventfd/src/blocking.c b/tests/posix/eventfd/src/blocking.c index 95e317cef76f..4c5ce5b982a6 100644 --- a/tests/posix/eventfd/src/blocking.c +++ b/tests/posix/eventfd/src/blocking.c @@ -73,7 +73,7 @@ ZTEST_F(eventfd, test_unset_poll_event_block) K_THREAD_STACK_DEFINE(thread_stack, CONFIG_TEST_STACK_SIZE); -static void thread_fun(void *arg1, void *arg2, void *arg3) +static void thread_eventfd_read_42(void *arg1, void *arg2, void *arg3) { eventfd_t value; struct eventfd_fixture *fixture = arg1; @@ -86,8 +86,8 @@ ZTEST_F(eventfd, test_read_then_write_block) { struct k_thread thread; - k_thread_create(&thread, thread_stack, K_THREAD_STACK_SIZEOF(thread_stack), thread_fun, - fixture, NULL, NULL, 0, 0, K_NO_WAIT); + k_thread_create(&thread, thread_stack, K_THREAD_STACK_SIZEOF(thread_stack), + thread_eventfd_read_42, fixture, NULL, NULL, 0, 0, K_NO_WAIT); k_msleep(100); @@ -97,3 +97,71 @@ ZTEST_F(eventfd, test_read_then_write_block) /* unreachable code */ k_thread_join(&thread, K_FOREVER); } + +static void thread_eventfd_write(void *arg1, void *arg2, void *arg3) +{ + struct eventfd_fixture *fixture = arg1; + + zassert_ok(eventfd_write(fixture->fd, 71)); +} + +ZTEST_F(eventfd, test_write_while_pollin) +{ + struct k_thread thread; + struct zsock_pollfd fds[] = { + { + .fd = fixture->fd, + .events = ZSOCK_POLLIN, + }, + }; + eventfd_t value; + int ret; + + k_thread_create(&thread, thread_stack, K_THREAD_STACK_SIZEOF(thread_stack), + thread_eventfd_write, fixture, NULL, NULL, 0, 0, K_MSEC(100)); + + /* Expect 1 event */ + ret = zsock_poll(fds, ARRAY_SIZE(fds), 200); + zassert_equal(ret, 1); + + zassert_equal(fds[0].revents, ZSOCK_POLLIN); + + /* Check value */ + zassert_ok(eventfd_read(fixture->fd, &value)); + zassert_equal(value, 71); + + zassert_ok(k_thread_join(&thread, K_FOREVER)); +} + +static void thread_eventfd_read(void *arg1, void *arg2, void *arg3) +{ + eventfd_t value; + struct eventfd_fixture *fixture = arg1; + + zassert_ok(eventfd_read(fixture->fd, &value)); +} + +ZTEST_F(eventfd, test_read_while_pollout) +{ + struct k_thread thread; + struct zsock_pollfd fds[] = { + { + .fd = fixture->fd, + .events = ZSOCK_POLLOUT, + }, + }; + int ret; + + zassert_ok(eventfd_write(fixture->fd, UINT64_MAX - 1)); + + k_thread_create(&thread, thread_stack, K_THREAD_STACK_SIZEOF(thread_stack), + thread_eventfd_read, fixture, NULL, NULL, 0, 0, K_MSEC(100)); + + /* Expect 1 event */ + ret = zsock_poll(fds, ARRAY_SIZE(fds), 200); + zassert_equal(ret, 1); + + zassert_equal(fds[0].revents, ZSOCK_POLLOUT); + + zassert_ok(k_thread_join(&thread, K_FOREVER)); +} From b8fc1c3607efba49ece6e049f8f9fd1e4b2ab516 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 22 Jun 2023 13:58:25 +0000 Subject: [PATCH 0508/2042] twister: run slow tests only We have many tests that are marked as slow that do not run in CI and any known workflow, to isolate them and be able to run them on their own, add a new option --enable-slow-only which causes only those tests to build and execute. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/environment.py | 6 ++++++ scripts/pylib/twister/twisterlib/testplan.py | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 4ce8dd1ecb8d..0c53a18b993e 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -553,9 +553,15 @@ def add_parse_arguments(parser = None): parser.add_argument( "-S", "--enable-slow", action="store_true", + default="--enable-slow-only" in sys.argv, help="Execute time-consuming test cases that have been marked " "as 'slow' in testcase.yaml. Normally these are only built.") + parser.add_argument( + "--enable-slow-only", action="store_true", + help="Execute time-consuming test cases that have been marked " + "as 'slow' in testcase.yaml only. This also set the option --enable-slow") + parser.add_argument( "--seed", type=int, help="Seed for native posix pseudo-random number generator") diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 005487efe83a..85340885dbb6 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -624,6 +624,7 @@ def apply_filters(self, **kwargs): runnable = (self.options.device_testing or self.options.filter == 'runnable') force_toolchain = self.options.force_toolchain force_platform = self.options.force_platform + slow_only = self.options.enable_slow_only ignore_platform_key = self.options.ignore_platform_key emu_filter = self.options.emulation_only @@ -748,6 +749,9 @@ def apply_filters(self, **kwargs): if tag_filter and not ts.tags.intersection(tag_filter): instance.add_filter("Command line testsuite tag filter", Filters.CMD_LINE) + if slow_only and not ts.slow: + instance.add_filter("Not a slow test", Filters.CMD_LINE) + if exclude_tag and ts.tags.intersection(exclude_tag): instance.add_filter("Command line testsuite exclude filter", Filters.CMD_LINE) From 54fcffb2c707c720df4764d5af4c738f6eb024b2 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 22 Jun 2023 14:03:35 +0000 Subject: [PATCH 0509/2042] doc: twister: adapt docs for --enable-slow-only Minor modification to accomodate for --enable-slow-only. Signed-off-by: Anas Nashif --- doc/develop/test/twister.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 4e842cddb773..0c2e81cd48bd 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -290,10 +290,10 @@ skip: (default False) skip testcase unconditionally. This can be used for broken tests. slow: (default False) - Don't run this test case unless --enable-slow was passed in on the - command line. Intended for time-consuming test cases that are only - run under certain circumstances, like daily builds. These test cases - are still compiled. + Don't run this test case unless --enable-slow or --enable-slow-only was + passed in on the command line. Intended for time-consuming test cases that + are only run under certain circumstances, like daily builds. These test + cases are still compiled. extra_args: Extra arguments to pass to Make when building or running the From 8eff5b6c010b2949fa75552353f130e3cc0fcac1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 16:09:35 +0200 Subject: [PATCH 0510/2042] libC minimal: Fix for POSIX arch The spin loop in _exit() needs a Z_SPIN_DELAY() for the posix architecture, so it does not hang the whole executable on that infinite loop but only the thread that exit'ed. Signed-off-by: Alberto Escolar Piedras --- lib/libc/minimal/source/stdlib/exit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libc/minimal/source/stdlib/exit.c b/lib/libc/minimal/source/stdlib/exit.c index 5700cd955866..036132ac1e95 100644 --- a/lib/libc/minimal/source/stdlib/exit.c +++ b/lib/libc/minimal/source/stdlib/exit.c @@ -11,5 +11,6 @@ void _exit(int status) { printk("exit\n"); while (1) { + Z_SPIN_DELAY(100); } } From 590e8efd4b325f91e3983547102aaa0e3552aa4b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 14:10:19 +0200 Subject: [PATCH 0511/2042] libC pico hooks: Fix for POSIX arch The spin loop in _exit() needs a Z_SPIN_DELAY() for the POSIX architecture, so it does not hang the whole executable on that infinite loop but only the thread that exit'ed. Signed-off-by: Alberto Escolar Piedras --- lib/libc/picolibc/libc-hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c index a4be33341a19..33ac8f2f0653 100644 --- a/lib/libc/picolibc/libc-hooks.c +++ b/lib/libc/picolibc/libc-hooks.c @@ -131,7 +131,7 @@ __weak void _exit(int status) { printk("exit\n"); while (1) { - ; + Z_SPIN_DELAY(100); } } From 0517c85dccff5131621d87797e97b68ad415c0ec Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 17:15:31 +0200 Subject: [PATCH 0512/2042] libC COMMON_LIBC_MALLOC_ARENA_SIZE: provide default for POSIX ARCH Provide a sensible default for the POSIX architecture, as now it is possible to build with it. Signed-off-by: Alberto Escolar Piedras --- lib/libc/common/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libc/common/Kconfig b/lib/libc/common/Kconfig index 16de0b2ccb45..e4bcf9a72f24 100644 --- a/lib/libc/common/Kconfig +++ b/lib/libc/common/Kconfig @@ -23,6 +23,7 @@ config COMMON_LIBC_MALLOC_ARENA_SIZE default 0 if MINIMAL_LIBC default 16384 if MMU default 2048 if USERSPACE && MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT + default 16384 if ARCH_POSIX default -1 help Indicate the size in bytes of the memory arena used for From 225e8c09acc60b2d5a98d3a436312c7e6bf070f3 Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Wed, 21 Jun 2023 12:43:20 +0200 Subject: [PATCH 0513/2042] mm_drv: tlb: Fix driver tests Previous fix https://github.com/zephyrproject-rtos/zephyr/pull/58891 introduced failure in driver tests suite. This patch corrects the error and reverts max_mapped_page field definition. Adds max_mapped_pages stats reset after unmaping of unused memory. Signed-off-by: Jaroslaw Stelter --- drivers/mm/mm_drv_bank.c | 6 +++--- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 5 +++++ tests/drivers/mm/sys_mm_drv_bank/src/main.c | 9 +++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/mm/mm_drv_bank.c b/drivers/mm/mm_drv_bank.c index af3ced8171d7..03209ffec419 100644 --- a/drivers/mm/mm_drv_bank.c +++ b/drivers/mm/mm_drv_bank.c @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -30,7 +29,9 @@ uint32_t sys_mm_drv_bank_page_mapped(struct mem_drv_bank *bank) { bank->unmapped_pages--; bank->mapped_pages++; - __ASSERT_NO_MSG(bank->mapped_pages <= bank->max_mapped_pages); + if (bank->mapped_pages > bank->max_mapped_pages) { + bank->max_mapped_pages = bank->mapped_pages; + } return bank->mapped_pages; } @@ -38,7 +39,6 @@ uint32_t sys_mm_drv_bank_page_unmapped(struct mem_drv_bank *bank) { bank->unmapped_pages++; bank->mapped_pages--; - __ASSERT_NO_MSG(bank->unmapped_pages <= bank->max_mapped_pages); return bank->unmapped_pages; } diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index c75c3d9f0fd7..cdce72bbf4ab 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -678,6 +678,11 @@ static int sys_mm_drv_mm_init(const struct device *dev) ret = sys_mm_drv_unmap_region(UINT_TO_POINTER(UNUSED_L2_START_ALIGNED), unused_size); + + /* Need to reset max pages statistics after unmap */ + for (int i = 0; i < L2_SRAM_BANK_NUM; i++) { + sys_mm_drv_bank_stats_reset_max(&hpsram_bank[i]); + } #endif /* diff --git a/tests/drivers/mm/sys_mm_drv_bank/src/main.c b/tests/drivers/mm/sys_mm_drv_bank/src/main.c index 9c834c5efa5c..dfde79302d28 100644 --- a/tests/drivers/mm/sys_mm_drv_bank/src/main.c +++ b/tests/drivers/mm/sys_mm_drv_bank/src/main.c @@ -39,10 +39,17 @@ ZTEST(sys_mm_bank_api, test_sys_mm_drv_bank) /* Verify that the initialization routine works as expected. */ /* It set mapped state for all pages */ sys_mm_drv_bank_init(&bank_data, BANK_PAGES); + expected.free_bytes = EXPECTED(0); + expected.allocated_bytes = EXPECTED(BANK_PAGES); + expected.max_allocated_bytes = EXPECTED(BANK_PAGES); + sys_mm_drv_bank_stats_get(&bank_data, &stats); + test_stats("MM Bank Init Error", &stats, &expected); + /* Now unmap all pages */ for (index = 0; index < BANK_PAGES; index++) { sys_mm_drv_bank_page_unmapped(&bank_data); } + sys_mm_drv_bank_stats_reset_max(&bank_data); expected.free_bytes = EXPECTED(BANK_PAGES); expected.allocated_bytes = EXPECTED(0); @@ -51,7 +58,6 @@ ZTEST(sys_mm_bank_api, test_sys_mm_drv_bank) test_stats("MM Bank Init Error", &stats, &expected); /* Verify mapped pages are counted correctly */ - count = sys_mm_drv_bank_page_mapped(&bank_data); zassert_equal(count, 1, "MM Page Mapped Error: 1st mapped = %u, not %u\n", @@ -121,7 +127,6 @@ ZTEST(sys_mm_bank_api, test_sys_mm_drv_bank) expected.max_allocated_bytes = EXPECTED(2); sys_mm_drv_bank_stats_get(&bank_data, &stats); test_stats("MM Bank Reset Max Error", &stats, &expected); - } ZTEST_SUITE(sys_mm_bank_api, NULL, NULL, NULL, NULL, NULL); From a7490d27626a35b46c9b4c4e0d16832767d4f0cd Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 22 Jun 2023 15:36:14 +0000 Subject: [PATCH 0514/2042] pinctrl: kinetis: use kernel default init priority Set the initialization priority for the pinctrl_mcux_init to CONFIG_KERNEL_INIT_PRIORITY_DEFAULT. The pinmux nodes depend on pcc, which is currently initializing at a later stage, using the default priority fixes it. Found the error with: $ west build -p -b frdm_k64f samples/basic/blinky \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /soc/pinmux@4004d000 PRE_KERNEL_1 0 < /soc/pcc@40065000 PRE_KERNEL_1 30 ERROR: /soc/pinmux@4004c000 PRE_KERNEL_1 0 < /soc/pcc@40065000 PRE_KERNEL_1 30 ERROR: /soc/pinmux@4004b000 PRE_KERNEL_1 0 < /soc/pcc@40065000 PRE_KERNEL_1 30 ERROR: /soc/pinmux@4004a000 PRE_KERNEL_1 0 < /soc/pcc@40065000 PRE_KERNEL_1 30 ERROR: /soc/pinmux@40049000 PRE_KERNEL_1 0 < /soc/pcc@40065000 PRE_KERNEL_1 30 Signed-off-by: Fabio Baltieri --- drivers/pinctrl/pinctrl_kinetis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl_kinetis.c b/drivers/pinctrl/pinctrl_kinetis.c index 1f2973b571f6..5fdb07a8cedf 100644 --- a/drivers/pinctrl/pinctrl_kinetis.c +++ b/drivers/pinctrl/pinctrl_kinetis.c @@ -76,7 +76,7 @@ static int pinctrl_mcux_init(const struct device *dev) NULL, \ NULL, &pinctrl_mcux_##n##_config, \ PRE_KERNEL_1, \ - 0, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ NULL); DT_INST_FOREACH_STATUS_OKAY(PINCTRL_MCUX_INIT) From fbe47d0c01ae5dc13816069dda9f19889a480cde Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 17:17:46 +0200 Subject: [PATCH 0515/2042] lib POSIX: timespec fix include for POSIX ARCH and emb libC Include the host timespec only if we are building with the host library for the POSIX architecture. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/posix/time.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index cada7b2f36d7..a20cf313fcd4 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -48,7 +48,7 @@ struct itimerspec { #else /* CONFIG_NEWLIB_LIBC */ /* Not Newlib */ -# ifdef CONFIG_ARCH_POSIX +# if defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC) # include # include # else @@ -82,7 +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); } -#ifdef CONFIG_ARCH_POSIX +#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); @@ -100,7 +100,7 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } #endif -#ifndef CONFIG_ARCH_POSIX +#if !(defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC)) #include #endif /* CONFIG_ARCH_POSIX */ From 3454d8f727f913d0cdee3a7e521a71a25a017c75 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 17:09:25 +0200 Subject: [PATCH 0516/2042] lib POSIX: Enable selectively for POSIX ARCH The POSIX API compatibility shim can be used for some of the POSIX ARCH targets. Narrow the Kconfig filtering accordingly. Note that the recommended configuration when building with the native simulator is still to use an embedded C library. Using the host C library will in some cases cause undesired behaviour. Signed-off-by: Alberto Escolar Piedras --- lib/posix/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index f857a49462a2..7f510210d9c6 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -12,7 +12,7 @@ config POSIX_MAX_FDS files, sockets, special devices, etc. config POSIX_API - depends on !ARCH_POSIX + depends on !NATIVE_APPLICATION bool "POSIX APIs" help Enable mostly-standards-compliant implementations of @@ -160,7 +160,7 @@ config APP_LINK_WITH_POSIX_SUBSYS config EVENTFD bool "Support for eventfd" - depends on !ARCH_POSIX + depends on !NATIVE_APPLICATION select POLL default y if POSIX_API help From 75dfdb14a1ecd87ffde6125f0d5c2fe19dcc3892 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 17:32:22 +0200 Subject: [PATCH 0517/2042] net: POSIX arch: include host header only if not emb libC Include host headers only if we are building with the host library for the POSIX architecture. Signed-off-by: Alberto Escolar Piedras --- include/zephyr/net/socket_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/socket_types.h b/include/zephyr/net/socket_types.h index 3a71815ee906..6195315e51ac 100644 --- a/include/zephyr/net/socket_types.h +++ b/include/zephyr/net/socket_types.h @@ -34,7 +34,7 @@ struct timeval { #else /* CONFIG_NEWLIB_LIBC */ -#ifdef CONFIG_ARCH_POSIX +#if defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC) #include #else #include From 78e1d6fa5eba4fc5206c3b0264606e731c96a053 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 13 Jun 2023 13:10:02 +0200 Subject: [PATCH 0518/2042] arch posix: Set C standard version in arch instead of boards The issue due to which we set the default compiler C std version to C11 is not specific to any particular POSIX arch board, but to all. Instead of setting this property for each board, let's set it at the architecture level. Signed-off-by: Alberto Escolar Piedras --- arch/posix/CMakeLists.txt | 6 ++++++ boards/posix/native_posix/CMakeLists.txt | 7 ------- boards/posix/nrf52_bsim/CMakeLists.txt | 6 ------ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 67fceca208f0..6f987149c855 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -82,5 +82,11 @@ if(NOT ${LLVM_SANITIZERS_ARG} STREQUAL "") zephyr_link_libraries("${LLVM_SANITIZERS_ARG}") endif() +# Override the C standard used for compilation to C 2011 +# This is due to some tests using _Static_assert which is a 2011 feature, but +# otherwise relying on compilers supporting it also when set to C99. +# This was in general ok, but with some host compilers and C library versions +# it led to problems. So we override it to 2011 for native_posix. +set_property(GLOBAL PROPERTY CSTD c11) add_subdirectory(core) diff --git a/boards/posix/native_posix/CMakeLists.txt b/boards/posix/native_posix/CMakeLists.txt index 0586a3bafcae..10bbf1f34428 100644 --- a/boards/posix/native_posix/CMakeLists.txt +++ b/boards/posix/native_posix/CMakeLists.txt @@ -35,10 +35,3 @@ endif() zephyr_ld_options( -lm ) - -# Override the C standard used for compilation to C 2011 -# This is due to some tests using _Static_assert which is a 2011 feature, but -# otherwise relying on compilers supporting it also when set to C99. -# This was in general ok, but with some host compilers and C library versions -# it led to problems. So we override it to 2011 for native_posix. -set_property(GLOBAL PROPERTY CSTD c11) diff --git a/boards/posix/nrf52_bsim/CMakeLists.txt b/boards/posix/nrf52_bsim/CMakeLists.txt index 76dc68ee0e44..57b76ab8194f 100644 --- a/boards/posix/nrf52_bsim/CMakeLists.txt +++ b/boards/posix/nrf52_bsim/CMakeLists.txt @@ -42,9 +42,3 @@ zephyr_library_import(bsim_libUtilv1 ${libpath}/libUtilv1.32.a) zephyr_library_import(bsim_libPhyComv1 ${libpath}/libPhyComv1.32.a) zephyr_library_import(bsim_lib2G4PhyComv1 ${libpath}/lib2G4PhyComv1.32.a) zephyr_library_import(bsim_libRandv2 ${libpath}/libRandv2.32.a) - -# This is due to some tests using _Static_assert which is a 2011 feature, but -# otherwise relying on compilers supporting it also when set to C99. -# This was in general ok, but with some host compilers and C library versions -# it led to problems. So we override it to 2011 for native applications. -set_property(GLOBAL PROPERTY CSTD c11) From 38b9120129f62a814992fbc86ae248ba53cb3155 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 8 Jun 2023 11:04:21 +0200 Subject: [PATCH 0519/2042] arch posix: native tasks header: Add missing include The native_tasks header requires the toolchain header. Let's include it directly instead of requiring users of this header to include it before. Signed-off-by: Alberto Escolar Piedras --- soc/posix/inf_clock/posix_native_task.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/posix/inf_clock/posix_native_task.h b/soc/posix/inf_clock/posix_native_task.h index f1dcfd0be47f..cb6fded1ccd3 100644 --- a/soc/posix/inf_clock/posix_native_task.h +++ b/soc/posix/inf_clock/posix_native_task.h @@ -7,6 +7,8 @@ #ifndef _POSIX_SOC_INF_CLOCK_POSIX_NATIVE_TASK_H #define _POSIX_SOC_INF_CLOCK_POSIX_NATIVE_TASK_H +#include + #ifdef __cplusplus extern "C" { #endif From 9e3d5c89e97358d7db3483871484d0de94cf823a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 14 Jun 2023 13:59:52 +0200 Subject: [PATCH 0520/2042] soc inf (POSIX): Correct Kconfig option description Let's remove the native_posix part from the SOC description and just refer to "native". Signed-off-by: Alberto Escolar Piedras --- soc/posix/inf_clock/Kconfig.soc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/posix/inf_clock/Kconfig.soc b/soc/posix/inf_clock/Kconfig.soc index 8063fe32c137..5c300b6eaff8 100644 --- a/soc/posix/inf_clock/Kconfig.soc +++ b/soc/posix/inf_clock/Kconfig.soc @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 config SOC_POSIX - bool "Native POSIX port" + bool "Native port" select ARCH_POSIX select CPU_HAS_FPU help From ea19a424c010ebd38f54532b5ea68245a012f7a6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 17 May 2023 14:27:40 +0200 Subject: [PATCH 0521/2042] posix arch: tracing: Define 3 new vprintf equivalent APIs In some cases it is necessary to have a va_list version of the posix tracing functions. Provide the definitions, and their implementations for the POSIX arch boards. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_posix/tracing.c | 19 +++++++++++++++++-- boards/posix/nrf52_bsim/trace_hook.c | 23 ++++++++++++++++++++--- include/zephyr/arch/posix/posix_trace.h | 5 +++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/boards/posix/native_posix/tracing.c b/boards/posix/native_posix/tracing.c index 8dc2bcbb3f82..5a0c4ec89d80 100644 --- a/boards/posix/native_posix/tracing.c +++ b/boards/posix/native_posix/tracing.c @@ -16,14 +16,29 @@ #include "posix_board_if.h" #include "cmdline.h" +void posix_vprint_error_and_exit(const char *format, va_list vargs) +{ + vfprintf(stderr, format, vargs); + posix_exit(1); +} + +void posix_vprint_warning(const char *format, va_list vargs) +{ + vfprintf(stderr, format, vargs); +} + +void posix_vprint_trace(const char *format, va_list vargs) +{ + vfprintf(stdout, format, vargs); +} + void posix_print_error_and_exit(const char *format, ...) { va_list variable_args; va_start(variable_args, format); - vfprintf(stderr, format, variable_args); + posix_vprint_error_and_exit(format, variable_args); va_end(variable_args); - posix_exit(1); } void posix_print_warning(const char *format, ...) diff --git a/boards/posix/nrf52_bsim/trace_hook.c b/boards/posix/nrf52_bsim/trace_hook.c index 51e28adac0a8..ff3b0555eeb0 100644 --- a/boards/posix/nrf52_bsim/trace_hook.c +++ b/boards/posix/nrf52_bsim/trace_hook.c @@ -15,15 +15,32 @@ * is down. */ +void posix_vprint_error_and_exit(const char *format, va_list vargs) +{ + bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0, + format, vargs); + posix_exit(1); +} + +void posix_vprint_warning(const char *format, va_list vargs) +{ + bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0, + format, vargs); +} + +void posix_vprint_trace(const char *format, va_list vargs) +{ + bs_trace_vprint(BS_TRACE_RAW, NULL, 0, 2, BS_TRACE_AUTOTIME, 0, + format, vargs); +} + void posix_print_error_and_exit(const char *format, ...) { va_list variable_argsp; va_start(variable_argsp, format); - bs_trace_vprint(BS_TRACE_WARNING, NULL, 0, 0, BS_TRACE_AUTOTIME, 0, - format, variable_argsp); + posix_vprint_error_and_exit(format, variable_argsp); va_end(variable_argsp); - posix_exit(1); } void posix_print_warning(const char *format, ...) diff --git a/include/zephyr/arch/posix/posix_trace.h b/include/zephyr/arch/posix/posix_trace.h index 76432e71a60c..c09d2b2a67f7 100644 --- a/include/zephyr/arch/posix/posix_trace.h +++ b/include/zephyr/arch/posix/posix_trace.h @@ -6,10 +6,15 @@ #ifndef ZEPHYR_INCLUDE_ARCH_POSIX_POSIX_TRACE_H_ #define ZEPHYR_INCLUDE_ARCH_POSIX_POSIX_TRACE_H_ +#include + #ifdef __cplusplus extern "C" { #endif +void posix_vprint_error_and_exit(const char *format, va_list vargs); +void posix_vprint_warning(const char *format, va_list vargs); +void posix_vprint_trace(const char *format, va_list vargs); void posix_print_error_and_exit(const char *format, ...); void posix_print_warning(const char *format, ...); void posix_print_trace(const char *format, ...); From 8b760196df976af37169fbe2178c7fd263bf6b64 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 17 May 2023 15:08:34 +0200 Subject: [PATCH 0522/2042] soc posix: Refactor native_tasks into own file The native_tasks logic is unrelated to the remaining of the soc logic (which handles CPU start/stopping) refactor it out into its own file. Signed-off-by: Alberto Escolar Piedras --- soc/posix/inf_clock/CMakeLists.txt | 1 + soc/posix/inf_clock/native_tasks.c | 38 ++++++++++++++++++++++++++++++ soc/posix/inf_clock/soc.c | 33 -------------------------- 3 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 soc/posix/inf_clock/native_tasks.c diff --git a/soc/posix/inf_clock/CMakeLists.txt b/soc/posix/inf_clock/CMakeLists.txt index 276b2fb78751..b256d67daa98 100644 --- a/soc/posix/inf_clock/CMakeLists.txt +++ b/soc/posix/inf_clock/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_compile_definitions(NO_POSIX_CHEATS) zephyr_library_sources( soc.c + native_tasks.c ) zephyr_library_include_directories( diff --git a/soc/posix/inf_clock/native_tasks.c b/soc/posix/inf_clock/native_tasks.c new file mode 100644 index 000000000000..0905401590bb --- /dev/null +++ b/soc/posix/inf_clock/native_tasks.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Run the set of special native tasks corresponding to the given level + * + * @param level One of _NATIVE_*_LEVEL as defined in soc.h + */ +void run_native_tasks(int level) +{ + extern void (*__native_PRE_BOOT_1_tasks_start[])(void); + extern void (*__native_PRE_BOOT_2_tasks_start[])(void); + extern void (*__native_PRE_BOOT_3_tasks_start[])(void); + extern void (*__native_FIRST_SLEEP_tasks_start[])(void); + extern void (*__native_ON_EXIT_tasks_start[])(void); + extern void (*__native_tasks_end[])(void); + + static void (**native_pre_tasks[])(void) = { + __native_PRE_BOOT_1_tasks_start, + __native_PRE_BOOT_2_tasks_start, + __native_PRE_BOOT_3_tasks_start, + __native_FIRST_SLEEP_tasks_start, + __native_ON_EXIT_tasks_start, + __native_tasks_end + }; + + void (**fptr)(void); + + for (fptr = native_pre_tasks[level]; fptr < native_pre_tasks[level+1]; + fptr++) { + if (*fptr) { /* LCOV_EXCL_BR_LINE */ + (*fptr)(); + } + } +} diff --git a/soc/posix/inf_clock/soc.c b/soc/posix/inf_clock/soc.c index ffd901ad7dc7..c0d11f44fc48 100644 --- a/soc/posix/inf_clock/soc.c +++ b/soc/posix/inf_clock/soc.c @@ -219,39 +219,6 @@ void posix_boot_cpu(void) } } -/** - * @brief Run the set of special native tasks corresponding to the given level - * - * @param level One of _NATIVE_*_LEVEL as defined in soc.h - */ -void run_native_tasks(int level) -{ - extern void (*__native_PRE_BOOT_1_tasks_start[])(void); - extern void (*__native_PRE_BOOT_2_tasks_start[])(void); - extern void (*__native_PRE_BOOT_3_tasks_start[])(void); - extern void (*__native_FIRST_SLEEP_tasks_start[])(void); - extern void (*__native_ON_EXIT_tasks_start[])(void); - extern void (*__native_tasks_end[])(void); - - static void (**native_pre_tasks[])(void) = { - __native_PRE_BOOT_1_tasks_start, - __native_PRE_BOOT_2_tasks_start, - __native_PRE_BOOT_3_tasks_start, - __native_FIRST_SLEEP_tasks_start, - __native_ON_EXIT_tasks_start, - __native_tasks_end - }; - - void (**fptr)(void); - - for (fptr = native_pre_tasks[level]; fptr < native_pre_tasks[level+1]; - fptr++) { - if (*fptr) { /* LCOV_EXCL_BR_LINE */ - (*fptr)(); - } - } -} - /** * Clean up all memory allocated by the SOC and POSIX core * From 491f7b460fb26b354707f353d0be2fa19c91c945 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 12:27:58 +0200 Subject: [PATCH 0523/2042] native_posix: Refactor sdl_events into common folder The SDL logic is not native_posix specific but can be reused between posix arch boards. Move it to a common folder so it can be reused in practice. Signed-off-by: Alberto Escolar Piedras --- boards/posix/common/sdl/CMakeLists.txt | 12 ++++++++++ boards/posix/common/sdl/Kconfig | 24 +++++++++++++++++++ .../{native_posix => common/sdl}/sdl_events.c | 0 boards/posix/native_posix/CMakeLists.txt | 7 +----- boards/posix/native_posix/Kconfig | 19 +-------------- 5 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 boards/posix/common/sdl/CMakeLists.txt create mode 100644 boards/posix/common/sdl/Kconfig rename boards/posix/{native_posix => common/sdl}/sdl_events.c (100%) diff --git a/boards/posix/common/sdl/CMakeLists.txt b/boards/posix/common/sdl/CMakeLists.txt new file mode 100644 index 000000000000..8def28b1c381 --- /dev/null +++ b/boards/posix/common/sdl/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_compile_definitions(NO_POSIX_CHEATS) + +find_package(PkgConfig REQUIRED) +pkg_search_module(SDL2 REQUIRED sdl2) +zephyr_include_directories(${SDL2_INCLUDE_DIRS}) +zephyr_link_libraries(${SDL2_LIBRARIES}) +zephyr_compile_options(${SDL2_CFLAGS_OTHER}) +zephyr_library_sources(sdl_events.c) diff --git a/boards/posix/common/sdl/Kconfig b/boards/posix/common/sdl/Kconfig new file mode 100644 index 000000000000..4731bf14cbe6 --- /dev/null +++ b/boards/posix/common/sdl/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2018 Jan Van Winkel +# Copyright (c) 2022 Basalte bv +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config HAS_SDL + depends on ARCH_POSIX + bool + help + This option specifies that the target board has SDL support + +config SDL_THREAD_INTERVAL + int "SDL thread sleep interval" + default 10 + depends on HAS_SDL + help + Sleep interval time of SDL thread to handle events in milliseconds. + +config SDL_THREAD_PRIORITY + int "SDL thread priority" + default 0 + depends on HAS_SDL + help + Priority of SDL thread to handle events. diff --git a/boards/posix/native_posix/sdl_events.c b/boards/posix/common/sdl/sdl_events.c similarity index 100% rename from boards/posix/native_posix/sdl_events.c rename to boards/posix/common/sdl/sdl_events.c diff --git a/boards/posix/native_posix/CMakeLists.txt b/boards/posix/native_posix/CMakeLists.txt index 10bbf1f34428..d9b37953e776 100644 --- a/boards/posix/native_posix/CMakeLists.txt +++ b/boards/posix/native_posix/CMakeLists.txt @@ -24,12 +24,7 @@ zephyr_library_include_directories( ) if(CONFIG_HAS_SDL) - find_package(PkgConfig REQUIRED) - pkg_search_module(SDL2 REQUIRED sdl2) - zephyr_include_directories(${SDL2_INCLUDE_DIRS}) - zephyr_link_libraries(${SDL2_LIBRARIES}) - zephyr_compile_options(${SDL2_CFLAGS_OTHER}) - zephyr_library_sources(sdl_events.c) + add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/sdl/ ${CMAKE_CURRENT_BINARY_DIR}/sdl) endif() zephyr_ld_options( diff --git a/boards/posix/native_posix/Kconfig b/boards/posix/native_posix/Kconfig index e476ff10c1b3..5b785fd642f5 100644 --- a/boards/posix/native_posix/Kconfig +++ b/boards/posix/native_posix/Kconfig @@ -21,23 +21,6 @@ config NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME case the zephyr kernel and application cannot tell the difference unless they interact with some other driver/device which runs at real time. -config HAS_SDL - bool - help - This option specifies that the target board has SDL support - -config SDL_THREAD_INTERVAL - int "SDL thread sleep interval" - default 10 - depends on HAS_SDL - help - Sleep interval time of SDL thread to handle events in milliseconds. - -config SDL_THREAD_PRIORITY - int "SDL thread priority" - default 0 - depends on HAS_SDL - help - Priority of SDL thread to handle events. +source "boards/$(ARCH)/common/sdl/Kconfig" endif # BOARD_NATIVE_POSIX From f60e4db4b33fd1fb825ca4fd178b714b9e736900 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 13:32:08 +0200 Subject: [PATCH 0524/2042] posix boards: Refactor common interrupt definitions into common header The IRQ definition macros are common between the in-tree POSIX arch boards. Let's move it to a common (optional) header. Other POSIX arch boards may still use their own definitions. Signed-off-by: Alberto Escolar Piedras --- boards/posix/common/irq/board_irq.h | 87 +++++++++++++++++++++++++++ boards/posix/native_posix/board_irq.h | 77 +----------------------- boards/posix/nrf52_bsim/board_irq.h | 68 +-------------------- 3 files changed, 90 insertions(+), 142 deletions(-) create mode 100644 boards/posix/common/irq/board_irq.h diff --git a/boards/posix/common/irq/board_irq.h b/boards/posix/common/irq/board_irq.h new file mode 100644 index 000000000000..abe28b82b948 --- /dev/null +++ b/boards/posix/common/irq/board_irq.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BOARDS_POSIX_COMMON_BOARD_IRQ_H +#define BOARDS_POSIX_COMMON_BOARD_IRQ_H + +#include +#include "zephyr/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), + const void *isr_param_p); +void posix_irq_priority_set(unsigned int irq, unsigned int prio, + uint32_t flags); + +/** + * Configure a static interrupt. + * + * @param irq_p IRQ line number + * @param priority_p Interrupt priority + * @param isr_p Interrupt service routine + * @param isr_param_p ISR parameter + * @param flags_p IRQ options + */ +#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ +{ \ + posix_isr_declare(irq_p, 0, isr_p, isr_param_p); \ + posix_irq_priority_set(irq_p, priority_p, flags_p); \ +} + + +/** + * Configure a 'direct' static interrupt. + * + * See include/irq.h for details. + */ +#define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ +{ \ + posix_isr_declare(irq_p, ISR_FLAG_DIRECT, \ + (void (*)(const void *))isr_p, NULL); \ + posix_irq_priority_set(irq_p, priority_p, flags_p); \ +} + +/** + * POSIX Architecture (board) specific ISR_DIRECT_DECLARE(), + * See include/irq.h for more information. + * + * The return of "name##_body(void)" is the indication of the interrupt + * (maybe) having caused a kernel decision to context switch + * + * Note that this convention is changed relative to the ARM and x86 archs + * + * All pre/post irq work of the interrupt is handled in the board + * posix_irq_handler() both for direct and normal interrupts together + */ +#define ARCH_ISR_DIRECT_DECLARE(name) \ + static inline int name##_body(void); \ + int name(void) \ + { \ + int check_reschedule; \ + check_reschedule = name##_body(); \ + return check_reschedule; \ + } \ + static inline int name##_body(void) + +#define ARCH_ISR_DIRECT_HEADER() do { } while (false) +#define ARCH_ISR_DIRECT_FOOTER(a) do { } while (false) + +#ifdef CONFIG_PM +extern void posix_irq_check_idle_exit(void); +#define ARCH_ISR_DIRECT_PM() posix_irq_check_idle_exit() +#else +#define ARCH_ISR_DIRECT_PM() do { } while (false) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* BOARDS_POSIX_COMMON_BOARD_IRQ_H */ diff --git a/boards/posix/native_posix/board_irq.h b/boards/posix/native_posix/board_irq.h index a070ea8c8b01..21c29768c8ef 100644 --- a/boards/posix/native_posix/board_irq.h +++ b/boards/posix/native_posix/board_irq.h @@ -1,5 +1,4 @@ /* - * Copyright (c) 2013-2014 Wind River Systems, Inc. * Copyright (c) 2017 Oticon A/S * * SPDX-License-Identifier: Apache-2.0 @@ -8,80 +7,6 @@ #ifndef BOARDS_POSIX_NATIVE_POSIX_BOARD_IRQ_H #define BOARDS_POSIX_NATIVE_POSIX_BOARD_IRQ_H -#include -#include "zephyr/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), - const void *isr_param_p); -void posix_irq_priority_set(unsigned int irq, unsigned int prio, - uint32_t flags); - -/** - * Configure a static interrupt. - * - * @param irq_p IRQ line number - * @param priority_p Interrupt priority - * @param isr_p Interrupt service routine - * @param isr_param_p ISR parameter - * @param flags_p IRQ options - */ -#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ -{ \ - posix_isr_declare(irq_p, 0, isr_p, isr_param_p); \ - posix_irq_priority_set(irq_p, priority_p, flags_p); \ -} - - -/** - * Configure a 'direct' static interrupt. - * - * See include/irq.h for details. - */ -#define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ -{ \ - posix_isr_declare(irq_p, ISR_FLAG_DIRECT, \ - (void (*)(const void *))isr_p, NULL); \ - posix_irq_priority_set(irq_p, priority_p, flags_p); \ -} - -/** - * POSIX Architecture (board) specific ISR_DIRECT_DECLARE(), - * See include/irq.h for more information. - * - * The return of "name##_body(void)" is the indication of the interrupt - * (maybe) having caused a kernel decision to context switch - * - * Note that this convention is changed relative to the ARM and x86 archs - * - * All pre/post irq work of the interrupt is handled in the board - * posix_irq_handler() both for direct and normal interrupts together - */ -#define ARCH_ISR_DIRECT_DECLARE(name) \ - static inline int name##_body(void); \ - int name(void) \ - { \ - int check_reschedule; \ - check_reschedule = name##_body(); \ - return check_reschedule; \ - } \ - static inline int name##_body(void) - -#define ARCH_ISR_DIRECT_HEADER() do { } while (false) -#define ARCH_ISR_DIRECT_FOOTER(a) do { } while (false) - -#ifdef CONFIG_PM -extern void posix_irq_check_idle_exit(void); -#define ARCH_ISR_DIRECT_PM() posix_irq_check_idle_exit() -#else -#define ARCH_ISR_DIRECT_PM() do { } while (false) -#endif - -#ifdef __cplusplus -} -#endif +#include "../common/irq/board_irq.h" #endif /* BOARDS_POSIX_NATIVE_POSIX_BOARD_IRQ_H */ diff --git a/boards/posix/nrf52_bsim/board_irq.h b/boards/posix/nrf52_bsim/board_irq.h index e333b419032a..d4a31580c939 100644 --- a/boards/posix/nrf52_bsim/board_irq.h +++ b/boards/posix/nrf52_bsim/board_irq.h @@ -1,5 +1,4 @@ /* - * Copyright (c) 2013-2014 Wind River Systems, Inc. * Copyright (c) 2017 Oticon A/S * * SPDX-License-Identifier: Apache-2.0 @@ -8,80 +7,17 @@ #ifndef BOARDS_POSIX_NRF52_BSIM_BOARD_IRQ_H #define BOARDS_POSIX_NRF52_BSIM_BOARD_IRQ_H -#include #include "zephyr/types.h" +#include "../common/irq/board_irq.h" + #ifdef __cplusplus extern "C" { #endif -void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), - const void *isr_param_p); -void posix_irq_priority_set(unsigned int irq, unsigned int prio, - uint32_t flags); void nrfbsim_WFE_model(void); void nrfbsim_SEV_model(void); -/** - * Configure a static interrupt. - * - * @param irq_p IRQ line number - * @param priority_p Interrupt priority - * @param isr_p Interrupt service routine - * @param isr_param_p ISR parameter - * @param flags_p IRQ options - */ -#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ -{ \ - posix_isr_declare(irq_p, 0, isr_p, isr_param_p); \ - posix_irq_priority_set(irq_p, priority_p, flags_p); \ -} - - -/** - * Configure a 'direct' static interrupt. - * - * See include/irq.h for details. - */ -#define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ -{ \ - posix_isr_declare(irq_p, ISR_FLAG_DIRECT, \ - (void (*)(const void *))isr_p, NULL); \ - posix_irq_priority_set(irq_p, priority_p, flags_p); \ -} - -/** - * POSIX Architecture (board) specific ISR_DIRECT_DECLARE(), - * See include/irq.h for more information. - * - * The return of "name##_body(void)" is the indication of the interrupt - * (maybe) having caused a kernel decision to context switch - * - * Note that this convention is changed relative to the ARM and x86 archs - * - * All pre/post irq work of the interrupt is handled in the board - * posix_irq_handler() both for direct and normal interrupts together - */ -#define ARCH_ISR_DIRECT_DECLARE(name) \ - static inline int name##_body(void); \ - int name(void) \ - { \ - int check_reschedule; \ - check_reschedule = name##_body(); \ - return check_reschedule; \ - } \ - static inline int name##_body(void) - -#define ARCH_ISR_DIRECT_HEADER() do { } while (false) -#define ARCH_ISR_DIRECT_FOOTER(a) do { } while (false) - -#ifdef CONFIG_PM -extern void posix_irq_check_idle_exit(void); -#define ARCH_ISR_DIRECT_PM() posix_irq_check_idle_exit() -#else -#define ARCH_ISR_DIRECT_PM() do { } while (false) -#endif - #define IRQ_ZERO_LATENCY BIT(1) /* Unused in this board*/ #ifdef __cplusplus From b4b2eaae35b2f35b7553b4d5d85cac4192a486b7 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 16:10:30 +0200 Subject: [PATCH 0525/2042] ztests: Build POSIX arch extra functionality only if possible The extra ztest functionality for the posix arch requires the host libC. Disable it if we are building with an embedded libC. Signed-off-by: Alberto Escolar Piedras --- subsys/testsuite/ztest/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/testsuite/ztest/CMakeLists.txt b/subsys/testsuite/ztest/CMakeLists.txt index c9c933289858..a0cf16151599 100644 --- a/subsys/testsuite/ztest/CMakeLists.txt +++ b/subsys/testsuite/ztest/CMakeLists.txt @@ -24,7 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c) zephyr_library_sources_ifdef(CONFIG_ZTRESS src/ztress.c) -if(CONFIG_ARCH_POSIX) +if(CONFIG_ARCH_POSIX AND CONFIG_EXTERNAL_LIBC) zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_posix.c) else() zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_defaults.c) From e9af821e226c49c53c697b1d985af655101ac2ab Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 15 Jun 2023 12:35:13 +0200 Subject: [PATCH 0526/2042] cmake: Add partial linking abstraction Add a property to abstract the partial linking/rellocatable linking for gcc ld and llvm's lld. Signed-off-by: Alberto Escolar Piedras --- cmake/linker/ld/linker_flags.cmake | 2 ++ cmake/linker/linker_flags_template.cmake | 4 ++++ cmake/linker/lld/linker_flags.cmake | 2 ++ 3 files changed, 8 insertions(+) diff --git a/cmake/linker/ld/linker_flags.cmake b/cmake/linker/ld/linker_flags.cmake index 18100b6eff21..8209f4dfbdc4 100644 --- a/cmake/linker/ld/linker_flags.cmake +++ b/cmake/linker/ld/linker_flags.cmake @@ -10,6 +10,8 @@ else() set_property(TARGET linker PROPERTY no_position_independent) endif() +set_property(TARGET linker PROPERTY partial_linking "-r") + # Some linker flags might not be purely ld specific, but a combination of # linker and compiler, such as: # --coverage for clang diff --git a/cmake/linker/linker_flags_template.cmake b/cmake/linker/linker_flags_template.cmake index df6ccfc01872..2ef080d62160 100644 --- a/cmake/linker/linker_flags_template.cmake +++ b/cmake/linker/linker_flags_template.cmake @@ -16,3 +16,7 @@ set_property(TARGET linker PROPERTY warnings_as_errors) # Linker flag for disabling position independent binaries, # such as, "-no-pie" for LD, and "--no-pie" for LLD. set_property(TARGET linker PROPERTY no_position_independent) + +# Linker flag for doing partial linking +# such as, "-r" or "--relocatable" for LD and LLD. +set_property(TARGET linker PROPERTY partial_linking) diff --git a/cmake/linker/lld/linker_flags.cmake b/cmake/linker/lld/linker_flags.cmake index f9e8cca246a8..61e72093c0ff 100644 --- a/cmake/linker/lld/linker_flags.cmake +++ b/cmake/linker/lld/linker_flags.cmake @@ -5,3 +5,5 @@ include(${ZEPHYR_BASE}/cmake/linker/ld/${COMPILER}/linker_flags.cmake OPTIONAL) set_property(TARGET linker PROPERTY no_position_independent "${LINKERFLAGPREFIX},--no-pie") + +set_property(TARGET linker PROPERTY partial_linking "-r") From dd733493f50569a54bd04590ccc1712bdc81292d Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Wed, 7 Jun 2023 14:31:42 +0300 Subject: [PATCH 0527/2042] samples: fs: littlefs: make sample workable for mmc disk driver The LittleFS sample may be used for both SDMMC and MMC disk drivers, so make it possible to work with different volume disk driver names. Signed-off-by: Mykola Kvach --- samples/subsys/fs/littlefs/README.rst | 22 +++++++++++++++++----- samples/subsys/fs/littlefs/src/main.c | 13 +++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/samples/subsys/fs/littlefs/README.rst b/samples/subsys/fs/littlefs/README.rst index a4ff2b7b224b..948da3f635ba 100644 --- a/samples/subsys/fs/littlefs/README.rst +++ b/samples/subsys/fs/littlefs/README.rst @@ -44,7 +44,7 @@ in this case). Block device (e.g. SD card) --------------------------- -One needs to prepare the SD card with littlefs file system on +One needs to prepare the SD/MMC card with littlefs file system on the host machine with the `lfs`_ program. .. _lfs: @@ -77,7 +77,7 @@ Block device (e.g. SD card) --------------------------- This example has been devised and initially tested on :ref:`Nucleo H743ZI ` -board. It can be also run on any other board with SD card connected to it. +board. It can be also run on any other board with SD/MMC card connected to it. To build the test: @@ -88,9 +88,21 @@ To build the test: :gen-args: -DCONF_FILE=prj_blk.conf :compact: -One can also set ``CONFIG_SDMMC_VOLUME_NAME`` to provide the mount point name -for `littlefs` file system block device. - +At the moment, only two types of block devices are acceptable in this sample: SDMMC and MMC. + +It is possible that both the `zephyr,sdmmc-disk` and `zephyr,mmc-disk` block devices will be +present and enabled in the final board dts and configuration files simultaneously, the mount +point name for the `littlefs` file system block device will be determined based on the +following logic: + +* if the ``CONFIG_SDMMC_VOLUME_NAME`` configuration is defined, it will be used + as the mount point name; +* if the ``CONFIG_SDMMC_VOLUME_NAME`` configuration is not defined, but the + ``CONFIG_MMC_VOLUME_NAME`` configuration is defined, ``CONFIG_MMC_VOLUME_NAME`` will + be used as the mount point name; +* if neither ``CONFIG_SDMMC_VOLUME_NAME`` nor ``CONFIG_MMC_VOLUME_NAME`` configurations + are defined, the mount point name will not be determined, and an appropriate error will + apear during the sample build. NRF52840 Development Kit ======================== diff --git a/samples/subsys/fs/littlefs/src/main.c b/samples/subsys/fs/littlefs/src/main.c index 56e2e55369c7..3891a9ca2129 100644 --- a/samples/subsys/fs/littlefs/src/main.c +++ b/samples/subsys/fs/littlefs/src/main.c @@ -309,6 +309,15 @@ static int littlefs_mount(struct fs_mount_t *mp) #endif /* CONFIG_APP_LITTLEFS_STORAGE_FLASH */ #ifdef CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC + +#if defined(CONFIG_DISK_DRIVER_SDMMC) +#define DISK_NAME CONFIG_SDMMC_VOLUME_NAME +#elif IS_ENABLED(CONFIG_DISK_DRIVER_MMC) +#define DISK_NAME CONFIG_MMC_VOLUME_NAME +#else +#error "No disk device defined, is your board supported?" +#endif + struct fs_littlefs lfsfs; static struct fs_mount_t __mp = { .type = FS_LITTLEFS, @@ -319,8 +328,8 @@ struct fs_mount_t *mp = &__mp; static int littlefs_mount(struct fs_mount_t *mp) { - static const char *disk_mount_pt = "/"CONFIG_SDMMC_VOLUME_NAME":"; - static const char *disk_pdrv = CONFIG_SDMMC_VOLUME_NAME; + static const char *disk_mount_pt = "/"DISK_NAME":"; + static const char *disk_pdrv = DISK_NAME; mp->storage_dev = (void *)disk_pdrv; mp->mnt_point = disk_mount_pt; From 936dc5b6dd3131ac24b57512b21802cfc8673fbf Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Mon, 19 Jun 2023 13:14:05 +0200 Subject: [PATCH 0528/2042] bsim: net: Add delay to echo client in ot bsim tests. This change ensures that openthread network topology will be formed properly, by delaing start of echo client application. Signed-off-by: Przemyslaw Bida --- .../bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh b/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh index 653f96802403..56a364528a50 100755 --- a/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh +++ b/tests/bsim/net/sockets/echo_test/tests_scripts/echo_test_ot.sh @@ -18,13 +18,13 @@ EXECUTE_TIMEOUT=100 cd ${BSIM_OUT_PATH}/bin Execute ./bs_${BOARD}_tests_bsim_net_sockets_echo_test_prj_conf_overlay-ot_conf \ - -v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 \ + -v=${verbosity_level} -s=${simulation_id} -start_offset=2e6 -d=0 -RealEncryption=1 \ -testid=echo_client Execute ./bs_${BOARD}_samples_net_sockets_echo_server_prj_conf_overlay-ot_conf\ -v=${verbosity_level} -s=${simulation_id} -d=1 -RealEncryption=1 \ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ - -D=2 -sim_length=26e6 -argschannel -at=40 -argsmain $@ + -D=2 -sim_length=40e6 -argschannel -at=40 -argsmain $@ wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails From f940a5a988304f4dfb3f79b7ec819f0bdbc0c9c8 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Fri, 16 Jun 2023 09:18:28 +0200 Subject: [PATCH 0529/2042] manifest: openthread: Regular openthread upmerge to `6d55738` Openthread upmerge to `6d55738`. Includes implementing of: - `OPENTHREAD_CONFIG_RADIO_STATS_ENABLE` - `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE` Signed-off-by: Przemyslaw Bida --- modules/openthread/CMakeLists.txt | 6 ++++++ modules/openthread/Kconfig.features | 6 ++++++ .../platform/openthread-core-zephyr-config.h | 11 +++++++++++ west.yml | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 508c888e0f3c..fdc466b19419 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -82,6 +82,12 @@ 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() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index dc0624edca17..e793a9bfaa4a 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -51,6 +51,9 @@ config OPENTHREAD_BORDER_ROUTING config OPENTHREAD_BORDER_ROUTING_COUNTERS bool "Border routing counters support" +config OPENTHREAD_BORDER_ROUTING_DHCP6_PD + bool "DHCPv6-PD support in border routing" + config OPENTHREAD_CHANNEL_MONITOR bool "Channel monitor support" @@ -247,6 +250,9 @@ config OPENTHREAD_POWER_SUPPLY default "EXTERNAL_UNSTABLE" if OPENTHREAD_POWER_SUPPLY_EXTERNAL_UNSTABLE default "" +config OPENTHREAD_RADIO_STATS + bool "Support for Radio Statistics" + config OPENTHREAD_RAW bool "Raw Link support" diff --git a/modules/openthread/platform/openthread-core-zephyr-config.h b/modules/openthread/platform/openthread-core-zephyr-config.h index 7eaccf7948df..8d6b5e54fd08 100644 --- a/modules/openthread/platform/openthread-core-zephyr-config.h +++ b/modules/openthread/platform/openthread-core-zephyr-config.h @@ -446,4 +446,15 @@ #define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0 #endif + +/** + * @def OPENTHREAD_CONFIG_RADIO_STATS + * + * Enable support for Radio Statistics. + * + */ +#ifdef CONFIG_OPENTHREAD_RADIO_STATS +#define OPENTHREAD_CONFIG_RADIO_STATS_ENABLE CONFIG_OPENTHREAD_RADIO_STATS +#endif + #endif /* OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ */ diff --git a/west.yml b/west.yml index d32fd214eec8..2b055344f7ac 100644 --- a/west.yml +++ b/west.yml @@ -290,7 +290,7 @@ manifest: revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad path: modules/lib/open-amp - name: openthread - revision: d9abe3071c0131a4adb5d7e7451319b735e6d855 + revision: 6d557383e8bc8654f813674e8631c2e56b8e70d0 path: modules/lib/openthread - name: picolibc path: modules/lib/picolibc From 81fa03f7a3c6c05d30017ff056650d54955bd959 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:39:31 +0200 Subject: [PATCH 0530/2042] drivers: ieee802154: cc13/26xx_subg: clean up constants The CC13xx/CC26xx Sub-GHz driver header file defined several constants that were not used in the driver. Other constants could be replaced with generic constants which were introduced in the prior commit. This change removes and/or replaces redundant definitions. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx.h | 17 ++++---- .../ieee802154_cc13xx_cc26xx_subg.c | 8 ++-- .../ieee802154_cc13xx_cc26xx_subg.h | 39 +------------------ 3 files changed, 13 insertions(+), 51 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h index 1a34193cd0fb..5dd171ff566b 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -19,18 +20,16 @@ #include /* IEEE 802.15.4-2006 2450 MHz O-QPSK PHY symbol rate (6.5.3.2) */ -#define IEEE802154_2450MHZ_OQPSK_SYMBOLS_PER_SECOND 62500 - -/* IEEE 802.15.4-2006 PHY constants (6.4.1) */ -#define IEEE802154_TURNAROUND_TIME 12 +/* For O-QPSK the physical and MAC timing symbol rates are the same, see section 12.3.3. */ +#define IEEE802154_2450MHZ_OQPSK_SYMBOLS_PER_SECOND \ + IEEE802154_PHY_SYMBOLS_PER_SECOND(IEEE802154_PHY_OQPSK_2450MHZ_SYMBOL_PERIOD_US) /* IEEE 802.15.4-2006 PHY PIB attributes (6.4.2) */ #define IEEE802154_PHY_CCA_MODE 3 + #define IEEE802154_PHY_SHR_DURATION 10 -#define IEEE802154_PHY_SYMBOLS_PER_OCTET 2 -/* IEEE 802.15.4-2006 MAC constants (7.4.1) */ -#define IEEE802154_UNIT_BACKOFF_PERIOD 20 +#define IEEE802154_PHY_SYMBOLS_PER_OCTET 2 /* ACK is 2 bytes for PHY header + 2 bytes MAC header + 2 bytes MAC footer */ #define IEEE802154_ACK_FRAME_OCTETS 6 @@ -40,8 +39,8 @@ * The macAckWaitDuration attribute does not include aUnitBackoffPeriod for * non-beacon enabled PANs (See IEEE 802.15.4-2006 7.5.6.4.2) */ -#define IEEE802154_MAC_ACK_WAIT_DURATION \ - (IEEE802154_TURNAROUND_TIME + IEEE802154_PHY_SHR_DURATION + \ +#define IEEE802154_MAC_ACK_WAIT_DURATION \ + (IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT + IEEE802154_PHY_SHR_DURATION + \ IEEE802154_ACK_FRAME_OCTETS * IEEE802154_PHY_SYMBOLS_PER_OCTET) #define CC13XX_CC26XX_RAT_CYCLES_PER_SECOND 4000000 diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index b190bdc6e5d4..91292d7a5ee8 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -489,13 +489,12 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, k_mutex_lock(&drv_data->tx_mutex, K_FOREVER); /* Prepend data with the SUN FSK PHY header */ - drv_data->tx_data[0] = frag->len + IEEE802154_SUN_PHY_FSK_PHR_LEN; + drv_data->tx_data[0] = frag->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; /* 20.2.2 PHR field format. 802.15.4-2015 */ drv_data->tx_data[1] = 0; drv_data->tx_data[1] |= BIT(3); /* FCS Type: 2-octet FCS */ drv_data->tx_data[1] |= BIT(4); /* DW: Enable Data Whitening */ - memcpy(&drv_data->tx_data[IEEE802154_SUN_PHY_FSK_PHR_LEN], - frag->data, frag->len); + memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], frag->data, frag->len); /* Chain commands */ drv_data->cmd_prop_cs.pNextOp = @@ -503,8 +502,7 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, drv_data->cmd_prop_cs.condition.rule = COND_STOP_ON_TRUE; /* Set TX data */ - drv_data->cmd_prop_tx_adv.pktLen = frag->len - + IEEE802154_SUN_PHY_FSK_PHR_LEN; + drv_data->cmd_prop_tx_adv.pktLen = frag->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; drv_data->cmd_prop_tx_adv.pPkt = drv_data->tx_data; /* Abort FG and BG processes */ diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h index 6035f70209cd..3d2c949e0c51 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -20,49 +21,13 @@ #include #include -/* See IEEE 802.15.4-2015 20.2.2 */ -#define IEEE802154_SUN_PHY_FSK_PHR_LEN 2 - -/* IEEE 802.15.4-2015 915 MHz 2FSK PHY symbol rate (20.6.3) */ -#define IEEE802154_SUN_PHY_2FSK_200K_SYMBOLS_PER_SECOND 200000 - -/* IEEE 802.15.4-2006 PHY constants (6.4.1) */ -#define IEEE802154_TURNAROUND_TIME 12 - -/* IEEE 802.15.4-2006 PHY PIB attributes (6.4.2) */ -#define IEEE802154_PHY_CCA_MODE 1 -#define IEEE802154_PHY_SHR_DURATION 2 -#define IEEE802154_PHY_SYMBOLS_PER_OCTET 8 - -/* IEEE 802.15.4-2006 MAC constants (7.4.1) */ -#define IEEE802154_UNIT_BACKOFF_PERIOD 20 - -/* ACK is 2 bytes for PHY header + 2 bytes MAC header + 2 bytes MAC footer */ -#define IEEE802154_ACK_FRAME_OCTETS 6 - -/* IEEE 802.15.4-2006 MAC PIB attributes (7.4.2) - * - * The macAckWaitDuration attribute does not include aUnitBackoffPeriod for - * non-beacon enabled PANs (See IEEE 802.15.4-2006 7.5.6.4.2) - */ -#define IEEE802154_MAC_ACK_WAIT_DURATION \ - (IEEE802154_TURNAROUND_TIME + IEEE802154_PHY_SHR_DURATION + \ - IEEE802154_ACK_FRAME_OCTETS * IEEE802154_PHY_SYMBOLS_PER_OCTET) - -#define CC13XX_CC26XX_RAT_CYCLES_PER_SECOND 4000000 - #define CC13XX_CC26XX_NUM_RX_BUF \ CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_NUM_RX_BUF /* Three additional bytes for length, RSSI and status values from CPE */ #define CC13XX_CC26XX_RX_BUF_SIZE (IEEE802154_MAX_PHY_PACKET_SIZE + 3) -/* - * Two additional bytes for the SUN FSK PHY HDR - * (See IEEE 802.15.4-2015 20.2.2) - */ -#define CC13XX_CC26XX_TX_BUF_SIZE \ - (IEEE802154_MAX_PHY_PACKET_SIZE + IEEE802154_SUN_PHY_FSK_PHR_LEN) +#define CC13XX_CC26XX_TX_BUF_SIZE (IEEE802154_PHY_SUN_FSK_PHR_LEN + IEEE802154_MAX_PHY_PACKET_SIZE) #define CC13XX_CC26XX_INVALID_RSSI INT8_MIN From 154ac22608235ceb060d7c51bb422abfbf840b49 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:45:04 +0200 Subject: [PATCH 0531/2042] drivers: ieee802154: cc13/26xx_subg: remove redundant configuration The low-level configuration of the chip's radio commands was mostly redundant. This change removes redundant configuration code. This is also relevant as a preparation to supporting further frequency bands and operating modes on the same SUN FSK channel page with similar but slightly different settings (center frequencies, channel spacing, modulation index as defined in the standard). The SUN FSK standard defines plenty of such variations with different physical characteristics and trade-offs. Such variations are highly relevant in industrial applications which will be targeted by TSCH. Using the correct settings is required for additional features (e.g. frequency hopping) and interoperability. Signed-off-by: Florian Grandel --- .../ieee802154_cc13xx_cc26xx_subg.c | 97 ++++++++++--------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 91292d7a5ee8..e20be91c9e20 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -57,10 +57,13 @@ extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_ #elif defined(CONFIG_SOC_CC1352P) extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup; #endif /* CONFIG_SOC_CC1352x, extern RADIO_DIV_SETUP */ +#else -#elif defined(CONFIG_SOC_CC1352R) -/* Radio values for CC13x2R (note: CC26x2 does not support sub-GHz radio) */ -/* From SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */ +#if defined(CONFIG_SOC_CC1352R) +/* Radio register overrides for CC13x2R (note: CC26x2 does not support sub-GHz radio) + * from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW), + * approximates SUN FSK PHY, 915 MHz band, operating mode #3. + */ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { /* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x7 (DITHER_EN=0 and IPEAK=7). */ (uint32_t)0x00F788D3, @@ -85,28 +88,6 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { (uint32_t)0xFFFFFFFF }; -/* Radio setup command for CC1312R / CC1352R */ -static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = { - .commandNo = CMD_PROP_RADIO_DIV_SETUP, - .condition.rule = COND_NEVER, - .modulation.modType = 1, /* FSK */ - .modulation.deviation = 200, - .symbolRate.preScale = 15, - .symbolRate.rateWord = 131072, - .rxBw = 0x59, /* 310.8 kHz */ - .preamConf.nPreamBytes = 7, - .formatConf.nSwBits = 24, /* 24-bit of syncword */ - .formatConf.bMsbFirst = true, - .formatConf.whitenMode = 7, - .config.biasMode = true, - .formatConf.bMsbFirst = true, - .txPower = 0x013f, /* from Smart RF Studio */ - .centerFreq = 915, - .intFreq = 0x0999, - .loDivider = 5, - .pRegOverride = ieee802154_cc13xx_overrides_sub_ghz, -}; - /* Radio values for CC13X2P */ #elif defined(CONFIG_SOC_CC1352P) /* CC1352P overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */ @@ -157,30 +138,49 @@ static uint32_t rf_prop_overrides_tx_20[] = { (uint32_t)0xFFFFFFFF }; -/* Radio setup command for CC1312P / CC1352P */ +#else +#error "unsupported CC13xx SoC" +#endif /* CONFIG_SOC_CC1352x */ + +/* Radio setup command for CC13xx */ +#if defined(CONFIG_SOC_CC1352R) +static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = { + .commandNo = CMD_PROP_RADIO_DIV_SETUP, +#elif defined(CONFIG_SOC_CC1352P) static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup = { .commandNo = CMD_PROP_RADIO_DIV_SETUP_PA, +#endif /* CONFIG_SOC_CC1352x */ .condition.rule = COND_NEVER, - .modulation.modType = 1, /* FSK */ - .modulation.deviation = 200, - .symbolRate.preScale = 15, - .symbolRate.rateWord = 131072, - .rxBw = 0x59, /* 310.8 kHz */ - .preamConf.nPreamBytes = 7, - .formatConf.nSwBits = 24, /* 24-bit of syncword */ - .formatConf.bMsbFirst = true, - .formatConf.whitenMode = 7, - .config.biasMode = true, - .formatConf.bMsbFirst = true, - .txPower = 0x013f, /* from Smart RF Studio */ - .centerFreq = 915, - .intFreq = 0x0C00, + .modulation = { + .modType = 1, /* 2-GFSK - non-standard modulation */ + .deviation = 200, /* +/- 200*250 = 50kHz deviation (modulation index 0.5) */ + }, + .symbolRate = { + .preScale = 15, + .rateWord = 131072, /* 200 kBit, see TRM, section 25.10.5.2, formula 15 */ + }, + .rxBw = 0x59, /* 310.8 kHz RX bandwidth, see TRM, section 25.10.5.2, table 25-183 */ + .preamConf.nPreamBytes = 7, /* phyFskPreambleLength = 7 + 1, also see nSwBits below */ + .formatConf = { + .nSwBits = 24, /* 24-bit (1 byte preamble + 16 bit SFD) */ + .bMsbFirst = true, + .whitenMode = 7, /* Determine whitening and CRC from PHY header */ + }, + .config.biasMode = true, /* Rely on an external antenna biasing network. */ + .txPower = 0x013f, /* 14 dBm, see TRM 25.3.3.2.16 */ + .centerFreq = 906, /* Set channel page zero, channel 1 by default, + * TODO: Use compliant SUN PHY frequencies from channel page 9. + */ + .intFreq = 0x8000, /* Use default intermediate frequency. */ .loDivider = 5, .pRegOverride = ieee802154_cc13xx_overrides_sub_ghz, +#if defined(CONFIG_SOC_CC1352P) .pRegOverrideTxStd = rf_prop_overrides_tx_std, .pRegOverrideTx20 = rf_prop_overrides_tx_20, +#endif /* CONFIG_SOC_CC1352P */ }; -#endif /* CONFIG_SOC_CC1352x, default CMD_PROP_RADIO_DIV_SETUP structures */ + +#endif /* CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP */ /* Sub GHz power tables */ #if defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_POWER_TABLE) @@ -842,7 +842,7 @@ static struct ieee802154_cc13xx_cc26xx_subg_data .bAppendStatus = true, }, /* Preamble & SFD for 2-FSK SUN PHY. 802.15.4-2015, 20.2.1 */ - .syncWord0 = 0x0055904E, + .syncWord0 = 0x55904E, .maxPktLen = IEEE802154_MAX_PHY_PACKET_SIZE, .hdrConf = { .numHdrBits = 16, @@ -860,12 +860,13 @@ static struct ieee802154_cc13xx_cc26xx_subg_data .commandNo = CMD_PROP_CS, .startTrigger.pastTrig = true, .condition.rule = COND_NEVER, - .csConf.bEnaRssi = true, - .csConf.busyOp = true, - .csConf.idleOp = true, + /* CCA Mode 1: Energy above threshold */ + .csConf = { + .bEnaRssi = true, + .busyOp = true, + .idleOp = true, + }, .rssiThr = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD, - .corrPeriod = 640, /* Filler, used for correlation only */ - .corrConfig.numCorrInv = 0x03, .csEndTrigger.triggerType = TRIG_REL_START, /* 8 symbol periods. 802.15.4-2015 Table 11.1 */ .csEndTime = 5000, @@ -882,7 +883,7 @@ static struct ieee802154_cc13xx_cc26xx_subg_data .preTrigger.triggerType = TRIG_REL_START, .preTrigger.pastTrig = true, /* Preamble & SFD for 2-FSK SUN PHY. 802.15.4-2015, 20.2.1 */ - .syncWord = 0x0055904E, + .syncWord = 0x55904E, }, }; From 6683c2833c243379d2048e97a0eac5864afb957a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 13:00:52 +0200 Subject: [PATCH 0532/2042] drivers: ieee802154: cc13/26xx_subg: remove dead code The channel-to-frequency conversion had unreachable code which is removed in this change. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index e20be91c9e20..b2a273166ef8 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -265,13 +265,9 @@ static inline int ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( * equivalent to (0.3 * 1000 * BIT(16)) / 1000, rounded up */ *fractFreq = 0x4ccd; - } else if (1 <= channel && channel <= IEEE802154_SUB_GHZ_CHANNEL_MAX) { + } else if (channel <= IEEE802154_SUB_GHZ_CHANNEL_MAX) { *frequency = 906 + 2 * (channel - 1); *fractFreq = 0; - } else if (IEEE802154_2_4_GHZ_CHANNEL_MIN <= channel - && channel <= IEEE802154_2_4_GHZ_CHANNEL_MAX) { - *frequency = 2405 + 5 * (channel - IEEE802154_2_4_GHZ_CHANNEL_MIN); - *fractFreq = 0; } else { *frequency = 0; *fractFreq = 0; From f05277a36735d91bac96351e6fc0c7164d4df749 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:45:45 +0200 Subject: [PATCH 0533/2042] drivers: ieee802154: cc13/26xx_subg: fix invalid KConfig reference The driver contained references to KConfig variables w/o the required CONFIG_ prefix. This change introduces the missing prefixes. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index b2a273166ef8..4f00b21a86f7 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -206,7 +206,7 @@ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) }, { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) }, { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) }, -#ifdef CC13X2_CC26X2_BOOST_MODE +#ifdef CONFIG_CC13X2_CC26X2_BOOST_MODE { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, #endif RF_TxPowerTable_TERMINATION_ENTRY @@ -232,7 +232,7 @@ static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = { { 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) }, { 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) }, { 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) }, -#ifdef CC13X2_CC26X2_BOOST_MODE +#ifdef CONFIG_CC13X2_CC26X2_BOOST_MODE { 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) }, #endif { 15, RF_TxPowerTable_HIGH_PA_ENTRY(18, 0, 0, 36, 0) }, From 0f21a18f4b0418dad1c7b8bea5c7fbf675ed1b9c Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:47:36 +0200 Subject: [PATCH 0534/2042] drivers: ieee802154: cc13/26xx_subg: readability improvements This change introduces standard variable names used elsewhere in the stack for improved naming consistency and readability. Signed-off-by: Florian Grandel --- .../ieee802154_cc13xx_cc26xx_subg.c | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 4f00b21a86f7..7067e2652868 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -389,17 +389,17 @@ static int ieee802154_cc13xx_cc26xx_subg_set_channel( const struct device *dev, uint16_t channel) { struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; - RF_EventMask reason; + RF_EventMask events; uint16_t freq, fract; - int r; + int ret; if (!is_subghz(channel)) { return -EINVAL; } - r = ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( + ret = ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( channel, &freq, &fract); - if (r < 0) { + if (ret < 0) { return -EINVAL; } @@ -415,20 +415,20 @@ static int ieee802154_cc13xx_cc26xx_subg_set_channel( drv_data->cmd_fs.status = IDLE; drv_data->cmd_fs.frequency = freq; drv_data->cmd_fs.fractFreq = fract; - reason = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs, + events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs, RF_PriorityNormal, NULL, 0); - if (reason != RF_EventLastCmdDone) { - LOG_DBG("Failed to set frequency: 0x%" PRIx64, reason); - r = -EIO; + if (events != RF_EventLastCmdDone) { + LOG_DBG("Failed to set frequency: 0x%" PRIx64, events); + ret = -EIO; goto out; } /* Run BG receive process on requested channel */ - r = ieee802154_cc13xx_cc26xx_subg_rx(dev); + ret = ieee802154_cc13xx_cc26xx_subg_rx(dev); out: k_mutex_unlock(&drv_data->tx_mutex); - return r; + return ret; } static int @@ -470,12 +470,12 @@ static int ieee802154_cc13xx_cc26xx_subg_set_txpower( static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, enum ieee802154_tx_mode mode, struct net_pkt *pkt, - struct net_buf *frag) + struct net_buf *buf) { struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; int retry = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_RADIO_TX_RETRIES; - RF_EventMask reason; - int r; + RF_EventMask events; + int ret; if (mode != IEEE802154_TX_MODE_CSMA_CA) { NET_ERR("TX mode %d not supported", mode); @@ -485,12 +485,12 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, k_mutex_lock(&drv_data->tx_mutex, K_FOREVER); /* Prepend data with the SUN FSK PHY header */ - drv_data->tx_data[0] = frag->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; + drv_data->tx_data[0] = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; /* 20.2.2 PHR field format. 802.15.4-2015 */ drv_data->tx_data[1] = 0; drv_data->tx_data[1] |= BIT(3); /* FCS Type: 2-octet FCS */ drv_data->tx_data[1] |= BIT(4); /* DW: Enable Data Whitening */ - memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], frag->data, frag->len); + memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len); /* Chain commands */ drv_data->cmd_prop_cs.pNextOp = @@ -498,13 +498,13 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, drv_data->cmd_prop_cs.condition.rule = COND_STOP_ON_TRUE; /* Set TX data */ - drv_data->cmd_prop_tx_adv.pktLen = frag->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; + drv_data->cmd_prop_tx_adv.pktLen = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; drv_data->cmd_prop_tx_adv.pPkt = drv_data->tx_data; /* Abort FG and BG processes */ - r = ieee802154_cc13xx_cc26xx_subg_stop(dev); - if (r < 0) { - r = -EIO; + ret = ieee802154_cc13xx_cc26xx_subg_stop(dev); + if (ret < 0) { + ret = -EIO; goto out; } @@ -513,13 +513,13 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, drv_data->cmd_prop_cs.status = IDLE; drv_data->cmd_prop_tx_adv.status = IDLE; - reason = RF_runCmd(drv_data->rf_handle, + events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_cs, RF_PriorityNormal, cmd_prop_tx_adv_callback, RF_EventLastCmdDone); - if ((reason & RF_EventLastCmdDone) == 0) { - LOG_DBG("Failed to run command (%" PRIx64 ")", reason); - r = -EIO; + if ((events & RF_EventLastCmdDone) == 0) { + LOG_DBG("Failed to run command (%" PRIx64 ")", events); + ret = -EIO; goto out; } @@ -542,18 +542,18 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, continue; } - r = 0; + ret = 0; goto out; } while (retry-- > 0); LOG_DBG("Failed to TX"); - r = -EIO; + ret = -EIO; out: (void)ieee802154_cc13xx_cc26xx_subg_rx(dev); k_mutex_unlock(&drv_data->tx_mutex); - return r; + return ret; } static void ieee802154_cc13xx_cc26xx_subg_rx_done( @@ -764,7 +764,7 @@ static struct ieee802154_radio_api static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev) { RF_Params rf_params; - RF_EventMask reason; + RF_EventMask events; struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; /* Initialize driver data */ @@ -795,18 +795,17 @@ static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev) drv_data->cmd_fs.frequency = 0; drv_data->cmd_fs.fractFreq = 0; - reason = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs, + events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_fs, RF_PriorityNormal, NULL, 0); - if (reason != RF_EventLastCmdDone) { - LOG_ERR("Failed to set frequency: 0x%" PRIx64, reason); + if (events != RF_EventLastCmdDone) { + LOG_ERR("Failed to set frequency: 0x%" PRIx64, events); return -EIO; } return 0; } -static struct ieee802154_cc13xx_cc26xx_subg_data - ieee802154_cc13xx_cc26xx_subg_data = { +static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_data = { .cmd_set_tx_power = { .commandNo = CMD_SET_TX_POWER }, From 6bb03b5e3bfed33397871184bfd32135f72d26f2 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 12:59:50 +0200 Subject: [PATCH 0535/2042] drivers: ieee802154: cc13/26xx_subg: fix/document non-standard CSMA/CA The CC13xx/CC26xx Sub-GHz driver announces a hardware CSMA/CA capability which it provides only partially. This change documents the gap. The change also fixes two related issues with the current CCA implementation: - The given default ED threshold was above the allowed threshold defined in the specification. - The CCA timeout was not calculated according to the requirements defined in the standard. Signed-off-by: Florian Grandel --- drivers/ieee802154/Kconfig.cc13xx_cc26xx | 14 +++++++++---- .../ieee802154_cc13xx_cc26xx_subg.c | 20 ++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/ieee802154/Kconfig.cc13xx_cc26xx b/drivers/ieee802154/Kconfig.cc13xx_cc26xx index 50039418e0b1..f6841638c26a 100644 --- a/drivers/ieee802154/Kconfig.cc13xx_cc26xx +++ b/drivers/ieee802154/Kconfig.cc13xx_cc26xx @@ -71,11 +71,17 @@ config IEEE802154_CC13XX_CC26XX_SUB_GHZ_NUM_RX_BUF receive buffers. config IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD - int "TI CC13xx / CC26xx IEEE 802.15.4g Carrier Sense Threshold in dBm" - default -70 + int "TI CC13xx / CC26xx IEEE 802.15.4g Carrier Sense ED Threshold in dBm" + default -80 # Based on SUN FSK, 200 kHz bit rate, no FEC, see IEEE 802.15.4-2020, section 19.6.7 help - This option sets RSSI threshold for carrier sense in the CSMA/CA - algorithm. + This option sets the energy detection (ED) threshold for + clear channel assessment (CCA) modes 1 or 3 in the CSMA/CA + algorithm. Except for the SUN O-QPSK PHY, the ED threshold + shall correspond to a received signal power of at most 10 dB + greater than the specified receiver sensitivity for that PHY, + or in accordance with local regulations (see IEEE 802.15.4-2020, + section 10.2.8). For the SUN O-QPSK PHY, the ED threshold shall + comply with IEEE 802.15.4-2020, section 21.5.13. config IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO int "TI CC13xx / CC26xx IEEE 802.15.4g initialization priority" diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 7067e2652868..98e4edfc4c9d 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -335,6 +335,7 @@ static enum ieee802154_hw_caps ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device *dev) { /* TODO: enable IEEE802154_HW_FILTER */ + /* TODO: remove or actually implement IEEE802154_HW_CSMA */ return IEEE802154_HW_FCS | IEEE802154_HW_CSMA | IEEE802154_HW_SUB_GHZ; } @@ -526,11 +527,14 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, if (drv_data->cmd_prop_cs.status != PROP_DONE_IDLE) { LOG_DBG("Channel access failure (0x%x)", drv_data->cmd_prop_cs.status); - /* Collision Avoidance is a WIP - * Currently, we just wait a random amount of us in the - * range [0,256) but k_busy_wait() is fairly inaccurate in - * practice. Future revisions may attempt to use the RAdio - * Timer (RAT) to measure this somewhat more precisely. + /* TODO: This is not a compliant CSMA/CA algorithm, use soft CSMA/CA + * instead as the SubGHz radio of this SoC has no HW CSMA/CA backoff + * algorithm support as required by IEEE 802.15.4, section 6.2.5.1. + * Alternatively construct compliant CSMA/CA with a combination + * of CMD_NOP, CMD_PROP_CS and CMD_COUNT_BRANCH commands, see + * SimpleLink SDK (rfListenBeforeTalk.c) or calculate proper backoff + * period as in the SimpleLink WiSUN stack's mac_tx.c. + * Currently, we just wait a random amount of us in the range [0,256). */ k_busy_wait(sys_rand32_get() & 0xff); continue; @@ -863,8 +867,10 @@ static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_d }, .rssiThr = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD, .csEndTrigger.triggerType = TRIG_REL_START, - /* 8 symbol periods. 802.15.4-2015 Table 11.1 */ - .csEndTime = 5000, + /* see IEEE 802.15.4, section 11.3, table 11-1 and section 10.2.8 */ + .csEndTime = RF_convertUsToRatTicks( + IEEE802154_PHY_A_CCA_TIME * + IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_US), }, .cmd_prop_tx_adv = { From f0cb607a87bb506b3e6c55700beb6ef6446043a5 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 30 May 2023 13:01:41 +0200 Subject: [PATCH 0536/2042] drivers: ieee802154: cc13/26xx_subg: inline documentation This change introduces inline documentation with references to the current version of the IEEE 802.15.4 standard. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx.h | 11 ++-- .../ieee802154_cc13xx_cc26xx_subg.c | 54 +++++++++++++++---- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h index 5dd171ff566b..9556e9eb34b6 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h @@ -2,6 +2,8 @@ * Copyright (c) 2019 Brett Witherspoon * * SPDX-License-Identifier: Apache-2.0 + * + * References are to the IEEE 802.15.4-2020 standard. */ #ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_CC13XX_CC26XX_H_ @@ -19,17 +21,18 @@ #include #include -/* IEEE 802.15.4-2006 2450 MHz O-QPSK PHY symbol rate (6.5.3.2) */ /* For O-QPSK the physical and MAC timing symbol rates are the same, see section 12.3.3. */ #define IEEE802154_2450MHZ_OQPSK_SYMBOLS_PER_SECOND \ IEEE802154_PHY_SYMBOLS_PER_SECOND(IEEE802154_PHY_OQPSK_2450MHZ_SYMBOL_PERIOD_US) -/* IEEE 802.15.4-2006 PHY PIB attributes (6.4.2) */ +/* PHY PIB attribute phyCcaMode - CCA Mode 3: Carrier sense with energy above threshold, see + * section 11.3, table 11-2 and section 10.2.8 + */ #define IEEE802154_PHY_CCA_MODE 3 -#define IEEE802154_PHY_SHR_DURATION 10 +#define IEEE802154_PHY_SHR_DURATION 10 /* in symbols, 8 preamble and 2 SFD, see section 12.1.2 */ -#define IEEE802154_PHY_SYMBOLS_PER_OCTET 2 +#define IEEE802154_PHY_SYMBOLS_PER_OCTET 2 /* see section 12.2.1 */ /* ACK is 2 bytes for PHY header + 2 bytes MAC header + 2 bytes MAC footer */ #define IEEE802154_ACK_FRAME_OCTETS 6 diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 98e4edfc4c9d..8b8038e1aa5d 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -168,7 +168,8 @@ static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_d }, .config.biasMode = true, /* Rely on an external antenna biasing network. */ .txPower = 0x013f, /* 14 dBm, see TRM 25.3.3.2.16 */ - .centerFreq = 906, /* Set channel page zero, channel 1 by default, + .centerFreq = 906, /* Set channel page zero, channel 1 by default, see IEEE 802.15.4, + * section 10.1.3.3. * TODO: Use compliant SUN PHY frequencies from channel page 9. */ .intFreq = 0x8000, /* Use default intermediate frequency. */ @@ -258,6 +259,7 @@ static inline int ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( __ASSERT_NO_MSG(frequency != NULL); __ASSERT_NO_MSG(fractFreq != NULL); + /* See IEEE 802.15.4, section 10.1.3.3. */ if (channel == IEEE802154_SUB_GHZ_CHANNEL_MIN) { *frequency = 868; /* @@ -274,6 +276,27 @@ static inline int ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( return -EINVAL; } + /* TODO: This incorrectly mixes up legacy O-QPSK SubGHz PHY channel page zero + * frequency calculation with SUN FSK operating mode #3 PHY radio settings. + * + * The correct channel frequency calculation for this PHY is on channel page 9, + * using the formula ChanCenterFreq = ChanCenterFreq0 + channel * ChanSpacing. + * + * Assuming operating mode #3, the parameters for some frequently used bands + * on this channel page are: + * 863 MHz: ChanSpacing 0.2, TotalNumChan 35, ChanCenterFreq0 863.1 + * 915 MHz: ChanSpacing 0.4, TotalNumChan 64, ChanCenterFreq0 902.4 + * + * See IEEE 802.15.4, section 10.1.3.9. + * + * Setting the PHY, channel page, band and operating mode requires additional + * radio configuration settings. + * + * Making derived MAC/PHY PIB attributes available to L2 requires an additional + * attribute getter, see + * https://github.com/zephyrproject-rtos/zephyr/issues/50336#issuecomment-1251122582. + */ + return 0; } @@ -467,7 +490,7 @@ static int ieee802154_cc13xx_cc26xx_subg_set_txpower( return 0; } -/* See IEEE 802.15.4 section 6.2.5.1 and TRM section 25.5.4.3 */ +/* See IEEE 802.15.4 section 6.7.1 and TRM section 25.5.4.3 */ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, enum ieee802154_tx_mode mode, struct net_pkt *pkt, @@ -485,12 +508,14 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, k_mutex_lock(&drv_data->tx_mutex, K_FOREVER); - /* Prepend data with the SUN FSK PHY header */ + /* Prepend data with the SUN FSK PHY header, + * see IEEE 802.15.4, section 19.2.4. + */ drv_data->tx_data[0] = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; - /* 20.2.2 PHR field format. 802.15.4-2015 */ drv_data->tx_data[1] = 0; drv_data->tx_data[1] |= BIT(3); /* FCS Type: 2-octet FCS */ drv_data->tx_data[1] |= BIT(4); /* DW: Enable Data Whitening */ + /* TODO: Zero-copy TX, see discussion in #49775. */ memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len); /* Chain commands */ @@ -575,6 +600,7 @@ static void ieee802154_cc13xx_cc26xx_subg_rx_done( status = drv_data->rx_data[i][len--]; rssi = drv_data->rx_data[i][len--]; + /* TODO: Configure firmware to include CRC in raw mode. */ if (IS_ENABLED(CONFIG_IEEE802154_RAW_MODE) && len > 0) { /* append CRC-16/CCITT */ uint16_t crc = 0; @@ -602,7 +628,7 @@ static void ieee802154_cc13xx_cc26xx_subg_rx_done( drv_data->rx_entry[i].status = DATA_ENTRY_PENDING; - /* TODO determine LQI in PROP mode */ + /* TODO: Determine LQI in PROP mode. */ net_pkt_set_ieee802154_lqi(pkt, 0xff); net_pkt_set_ieee802154_rssi_dbm(pkt, rssi == CC13XX_CC26XX_INVALID_RSSI @@ -686,7 +712,7 @@ uint16_t ieee802154_cc13xx_cc26xx_subg_get_subg_channel_count( { ARG_UNUSED(dev); - /* IEEE 802.15.4 SubGHz channels range from 0 to 10*/ + /* IEEE 802.15.4 SubGHz channels range from 0 to 10 for channel page zero. */ return 11; } @@ -719,7 +745,7 @@ static void ieee802154_cc13xx_cc26xx_subg_data_init( { uint8_t *mac; - /* FIXME do multi-protocol devices need more than one IEEE MAC? */ + /* TODO: Do multi-protocol devices need more than one IEEE MAC? */ if (sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_0) != 0xFFFFFFFF && sys_read32(CCFG_BASE + CCFG_O_IEEE_MAC_1) != 0xFFFFFFFF) { mac = (uint8_t *)(CCFG_BASE + CCFG_O_IEEE_MAC_0); @@ -840,9 +866,12 @@ static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_d .bAppendRssi = true, .bAppendStatus = true, }, - /* Preamble & SFD for 2-FSK SUN PHY. 802.15.4-2015, 20.2.1 */ + /* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0, + * see IEEE 802.15.4, section 19.2.3.2, table 19-2. + */ .syncWord0 = 0x55904E, .maxPktLen = IEEE802154_MAX_PHY_PACKET_SIZE, + /* PHR field format, see IEEE 802.15.4, section 19.2.4 */ .hdrConf = { .numHdrBits = 16, .numLenBits = 11, @@ -855,11 +884,12 @@ static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_d .cmd_prop_rx_adv_output, }, + /* TODO: Support correlation CCA modes, see section 10.2.8. */ .cmd_prop_cs = { .commandNo = CMD_PROP_CS, .startTrigger.pastTrig = true, .condition.rule = COND_NEVER, - /* CCA Mode 1: Energy above threshold */ + /* CCA Mode 1: Energy above threshold, see section 10.2.8 */ .csConf = { .bEnaRssi = true, .busyOp = true, @@ -879,11 +909,13 @@ static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_d .startTrigger.pastTrig = true, .condition.rule = COND_NEVER, .pktConf.bUseCrc = true, - /* PHR field format. 802.15.4-2015, 20.2.2 */ + /* PHR field format, see IEEE 802.15.4, section 19.2.4 */ .numHdrBits = 16, .preTrigger.triggerType = TRIG_REL_START, .preTrigger.pastTrig = true, - /* Preamble & SFD for 2-FSK SUN PHY. 802.15.4-2015, 20.2.1 */ + /* Last preamble byte and SFD for uncoded 2-FSK SUN PHY, phySunFskSfd = 0, + * see IEEE 802.15.4, section 19.2.3.2, table 19-2. + */ .syncWord = 0x55904E, }, }; From 8a86f0c30e65e6268ffd399d93b05f211e0dc6e4 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 2 Jun 2023 00:19:43 +0200 Subject: [PATCH 0537/2042] drivers: ieee802154: cc13/26xx_subg: fix CCA method The driver's CCA method had various issues and would always return an error code. This is fixed in this change. Signed-off-by: Florian Grandel --- .../ieee802154_cc13xx_cc26xx_subg.c | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 8b8038e1aa5d..4a17a225c189 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -366,23 +366,35 @@ ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device *dev) static int ieee802154_cc13xx_cc26xx_subg_cca(const struct device *dev) { struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; - RF_Stat status; + RF_EventMask events; + int ret; drv_data->cmd_prop_cs.status = IDLE; drv_data->cmd_prop_cs.pNextOp = NULL; drv_data->cmd_prop_cs.condition.rule = COND_NEVER; - status = RF_runImmediateCmd(drv_data->rf_handle, - (uint32_t *)&drv_data->cmd_prop_cs); - if (status != RF_StatSuccess) { - LOG_ERR("Failed to request CCA (0x%x)", status); + /* TODO: Check whether RX is actually enabled. */ + ret = ieee802154_cc13xx_cc26xx_subg_stop(dev); + if (ret < 0) { return -EIO; } + events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_cs, RF_PriorityNormal, + NULL, 0); + if (events != RF_EventLastCmdDone) { + LOG_DBG("Failed to request CCA: 0x%" PRIx64, events); + return -EIO; + } + + /* TODO: Should we re-enable RX? Would not normally + * be a sensible default when used before TX. + */ + switch (drv_data->cmd_prop_cs.status) { - case PROP_DONE_OK: + case PROP_DONE_IDLE: return 0; case PROP_DONE_BUSY: + case PROP_DONE_BUSYTIMEOUT: return -EBUSY; default: return -EIO; @@ -887,13 +899,14 @@ static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_d /* TODO: Support correlation CCA modes, see section 10.2.8. */ .cmd_prop_cs = { .commandNo = CMD_PROP_CS, - .startTrigger.pastTrig = true, .condition.rule = COND_NEVER, - /* CCA Mode 1: Energy above threshold, see section 10.2.8 */ .csConf = { + /* CCA Mode 1: Energy above threshold, see section 10.2.8. */ .bEnaRssi = true, + /* Abort as soon as any energy above the ED threshold is detected. */ .busyOp = true, - .idleOp = true, + /* Continue sensing until the timeout is reached. */ + .idleOp = false, }, .rssiThr = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CS_THRESHOLD, .csEndTrigger.triggerType = TRIG_REL_START, From a94877b8b16f45fdda44ae67a4ff832de35550d7 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 2 Jun 2023 00:21:34 +0200 Subject: [PATCH 0538/2042] drivers: ieee802154: cc13/26xx_subg: improve CSMA/CA compliance Switch the driver to the soft CSMA/CA algorithm as an intermediate compromise for improved standard compliance (namely expontential backoff) until true hardware support can be implemented by chaining radio commands. Signed-off-by: Florian Grandel --- drivers/ieee802154/Kconfig.cc13xx_cc26xx | 9 +- .../ieee802154_cc13xx_cc26xx_subg.c | 108 ++++++++---------- subsys/net/l2/ieee802154/ieee802154.c | 1 + 3 files changed, 49 insertions(+), 69 deletions(-) diff --git a/drivers/ieee802154/Kconfig.cc13xx_cc26xx b/drivers/ieee802154/Kconfig.cc13xx_cc26xx index f6841638c26a..e3ccf944abc1 100644 --- a/drivers/ieee802154/Kconfig.cc13xx_cc26xx +++ b/drivers/ieee802154/Kconfig.cc13xx_cc26xx @@ -90,13 +90,10 @@ config IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO Set the initialization priority number. config IEEE802154_CC13XX_CC26XX_SUB_GHZ_RADIO_TX_RETRIES - int "Radio Transmission attempts" - default NET_L2_IEEE802154_RADIO_TX_RETRIES if NET_L2_IEEE802154 - default 3 - range 1 7 + bool + select DEPRECATED help - Number of transmission attempts radio driver should do, before - replying it could not send the packet. + DEPRECATED - use NET_L2_IEEE802154_RADIO_TX_RETRIES instead config IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP bool "Use custom radio setup structures (advanced)" diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 4a17a225c189..091212725e59 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -358,47 +358,62 @@ static enum ieee802154_hw_caps ieee802154_cc13xx_cc26xx_subg_get_capabilities(const struct device *dev) { /* TODO: enable IEEE802154_HW_FILTER */ - /* TODO: remove or actually implement IEEE802154_HW_CSMA */ - return IEEE802154_HW_FCS | IEEE802154_HW_CSMA - | IEEE802154_HW_SUB_GHZ; + return IEEE802154_HW_FCS | IEEE802154_HW_SUB_GHZ; } static int ieee802154_cc13xx_cc26xx_subg_cca(const struct device *dev) { struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; RF_EventMask events; + bool was_rx_on; int ret; drv_data->cmd_prop_cs.status = IDLE; drv_data->cmd_prop_cs.pNextOp = NULL; drv_data->cmd_prop_cs.condition.rule = COND_NEVER; - /* TODO: Check whether RX is actually enabled. */ + was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE; + ret = ieee802154_cc13xx_cc26xx_subg_stop(dev); if (ret < 0) { - return -EIO; + ret = -EIO; + goto out; } events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_cs, RF_PriorityNormal, NULL, 0); if (events != RF_EventLastCmdDone) { LOG_DBG("Failed to request CCA: 0x%" PRIx64, events); - return -EIO; + ret = -EIO; + goto out; } - /* TODO: Should we re-enable RX? Would not normally - * be a sensible default when used before TX. - */ - switch (drv_data->cmd_prop_cs.status) { case PROP_DONE_IDLE: + /* Do not re-enable RX when the channel is idle as + * this usually means we want to TX directly after + * and cannot afford any extra latency. + */ return 0; case PROP_DONE_BUSY: case PROP_DONE_BUSYTIMEOUT: - return -EBUSY; + ret = -EBUSY; + break; default: - return -EIO; + ret = -EIO; + } + +out: + /* Re-enable RX if we found it on initially + * and the channel is busy (or another error + * occurred) as this usually means we back off + * and want to be able to receive packets in + * the meantime. + */ + if (was_rx_on) { + ieee802154_cc13xx_cc26xx_subg_rx(dev); } + return ret; } static int ieee802154_cc13xx_cc26xx_subg_rx(const struct device *dev) @@ -509,13 +524,12 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, struct net_buf *buf) { struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; - int retry = CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_RADIO_TX_RETRIES; RF_EventMask events; int ret; - if (mode != IEEE802154_TX_MODE_CSMA_CA) { - NET_ERR("TX mode %d not supported", mode); - return -ENOTSUP; + if (mode != IEEE802154_TX_MODE_DIRECT) { + /* For backwards compatibility we only log an error but do not bail. */ + NET_ERR("TX mode %d not supported - sending directly instead.", mode); } k_mutex_lock(&drv_data->tx_mutex, K_FOREVER); @@ -530,15 +544,14 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, /* TODO: Zero-copy TX, see discussion in #49775. */ memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len); - /* Chain commands */ - drv_data->cmd_prop_cs.pNextOp = - (rfc_radioOp_t *) &drv_data->cmd_prop_tx_adv; - drv_data->cmd_prop_cs.condition.rule = COND_STOP_ON_TRUE; - /* Set TX data */ drv_data->cmd_prop_tx_adv.pktLen = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; drv_data->cmd_prop_tx_adv.pPkt = drv_data->tx_data; + /* Reset command status */ + drv_data->cmd_prop_tx_adv.status = IDLE; + drv_data->cmd_prop_tx_adv.pNextOp = NULL; + /* Abort FG and BG processes */ ret = ieee802154_cc13xx_cc26xx_subg_stop(dev); if (ret < 0) { @@ -546,50 +559,19 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, goto out; } - do { - /* Reset command status */ - drv_data->cmd_prop_cs.status = IDLE; - drv_data->cmd_prop_tx_adv.status = IDLE; - - events = RF_runCmd(drv_data->rf_handle, - (RF_Op *)&drv_data->cmd_prop_cs, - RF_PriorityNormal, cmd_prop_tx_adv_callback, - RF_EventLastCmdDone); - if ((events & RF_EventLastCmdDone) == 0) { - LOG_DBG("Failed to run command (%" PRIx64 ")", events); - ret = -EIO; - goto out; - } - - if (drv_data->cmd_prop_cs.status != PROP_DONE_IDLE) { - LOG_DBG("Channel access failure (0x%x)", - drv_data->cmd_prop_cs.status); - /* TODO: This is not a compliant CSMA/CA algorithm, use soft CSMA/CA - * instead as the SubGHz radio of this SoC has no HW CSMA/CA backoff - * algorithm support as required by IEEE 802.15.4, section 6.2.5.1. - * Alternatively construct compliant CSMA/CA with a combination - * of CMD_NOP, CMD_PROP_CS and CMD_COUNT_BRANCH commands, see - * SimpleLink SDK (rfListenBeforeTalk.c) or calculate proper backoff - * period as in the SimpleLink WiSUN stack's mac_tx.c. - * Currently, we just wait a random amount of us in the range [0,256). - */ - k_busy_wait(sys_rand32_get() & 0xff); - continue; - } - - if (drv_data->cmd_prop_tx_adv.status != PROP_DONE_OK) { - LOG_DBG("Transmit failed (0x%x)", - drv_data->cmd_prop_tx_adv.status); - continue; - } - - ret = 0; + events = RF_runCmd(drv_data->rf_handle, (RF_Op *)&drv_data->cmd_prop_tx_adv, + RF_PriorityNormal, cmd_prop_tx_adv_callback, RF_EventLastCmdDone); + if ((events & RF_EventLastCmdDone) == 0) { + LOG_DBG("Failed to run command (%" PRIx64 ")", events); + ret = -EIO; goto out; + } - } while (retry-- > 0); - - LOG_DBG("Failed to TX"); - ret = -EIO; + if (drv_data->cmd_prop_tx_adv.status != PROP_DONE_OK) { + LOG_DBG("Transmit failed (0x%x)", drv_data->cmd_prop_tx_adv.status); + ret = -EIO; + goto out; + } out: (void)ieee802154_cc13xx_cc26xx_subg_rx(dev); diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 16afbe59ada6..a498ad25dacf 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -87,6 +87,7 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 } if (ieee802154_create_ack_frame(iface, pkt, mpdu->mhr.fs->sequence)) { + /* ACK frames must not use the CSMA/CA procedure, see section 6.2.5.1. */ ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, pkt->buffer); } From 0ea56584910eebe046368d58637fb4d307e2d7d7 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 15:58:35 +0200 Subject: [PATCH 0539/2042] drivers: ieee802154: cc13/26xx_subg: remove unused radio commands The CMD_CLEAR_RX and CMD_SET_TX_POWER commands are declared and initialized but not used anywhere. They are therefore removed to reduce RAM/flash footprint. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx.c | 9 --------- drivers/ieee802154/ieee802154_cc13xx_cc26xx.h | 2 -- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 9 --------- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h | 2 -- 4 files changed, 22 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 71675ae9a90b..00902e7e5325 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -637,11 +637,6 @@ static struct ieee802154_cc13xx_cc26xx_data ieee802154_cc13xx_cc26xx_data = { .commandNo = CMD_IEEE_CCA_REQ, }, - .cmd_clear_rx = { - .commandNo = CMD_CLEAR_RX, - .pQueue = &ieee802154_cc13xx_cc26xx_data.rx_queue, - }, - .cmd_ieee_rx = { .commandNo = CMD_IEEE_RX, .status = IDLE, @@ -715,10 +710,6 @@ static struct ieee802154_cc13xx_cc26xx_data ieee802154_cc13xx_cc26xx_data = { .endTrigger.triggerType = TRIG_NEVER }, - .cmd_set_tx_power = { - .commandNo = CMD_SET_TX_POWER - }, - .cmd_ieee_csma = { .commandNo = CMD_IEEE_CSMA, .status = IDLE, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h index 9556e9eb34b6..f1ae365af793 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.h @@ -76,9 +76,7 @@ struct ieee802154_cc13xx_cc26xx_data { volatile rfc_CMD_FS_t cmd_fs; volatile rfc_CMD_IEEE_CCA_REQ_t cmd_ieee_cca_req; - volatile rfc_CMD_CLEAR_RX_t cmd_clear_rx; volatile rfc_CMD_IEEE_RX_t cmd_ieee_rx; - volatile rfc_CMD_SET_TX_POWER_t cmd_set_tx_power; volatile rfc_CMD_IEEE_CSMA_t cmd_ieee_csma; volatile rfc_CMD_IEEE_TX_t cmd_ieee_tx; volatile rfc_CMD_IEEE_RX_ACK_t cmd_ieee_rx_ack; diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 091212725e59..c582990729fb 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -830,16 +830,7 @@ static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev) } static struct ieee802154_cc13xx_cc26xx_subg_data ieee802154_cc13xx_cc26xx_subg_data = { - .cmd_set_tx_power = { - .commandNo = CMD_SET_TX_POWER - }, - /* Common Radio Commands */ - .cmd_clear_rx = { - .commandNo = CMD_CLEAR_RX, - .pQueue = &ieee802154_cc13xx_cc26xx_subg_data.rx_queue, - }, - .cmd_fs = { .commandNo = CMD_FS, .condition.rule = COND_NEVER, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h index 3d2c949e0c51..408d326ff81f 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.h @@ -46,8 +46,6 @@ struct ieee802154_cc13xx_cc26xx_subg_data { uint8_t tx_data[CC13XX_CC26XX_TX_BUF_SIZE]; /* Common Radio Commands */ - volatile rfc_CMD_CLEAR_RX_t cmd_clear_rx; - volatile rfc_CMD_SET_TX_POWER_t cmd_set_tx_power; volatile rfc_CMD_FS_t cmd_fs; /* Sub-GHz Radio Commands */ From ea89a1f9b5b742e20d0058a55e6415ae4bad0955 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:17:59 +0200 Subject: [PATCH 0540/2042] drivers: ieee802154: cc13/26xx_subg: conditional RX after set_channel The call to radio_api->set_channel() must not switch on RX if it was previously off. Signed-off-by: Florian Grandel --- .../ieee802154_cc13xx_cc26xx_subg.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index c582990729fb..368234c05a56 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -442,21 +442,25 @@ static int ieee802154_cc13xx_cc26xx_subg_set_channel( struct ieee802154_cc13xx_cc26xx_subg_data *drv_data = dev->data; RF_EventMask events; uint16_t freq, fract; + bool was_rx_on; int ret; if (!is_subghz(channel)) { return -EINVAL; } - ret = ieee802154_cc13xx_cc26xx_subg_channel_to_frequency( - channel, &freq, &fract); + ret = ieee802154_cc13xx_cc26xx_subg_channel_to_frequency(channel, &freq, &fract); if (ret < 0) { return -EINVAL; } + was_rx_on = drv_data->cmd_prop_rx_adv.status == ACTIVE; + /* Abort FG and BG processes */ - if (ieee802154_cc13xx_cc26xx_subg_stop(dev) < 0) { - return -EIO; + ret = ieee802154_cc13xx_cc26xx_subg_stop(dev); + if (ret) { + ret = -EIO; + goto out; } /* Block TX while changing channel */ @@ -471,14 +475,15 @@ static int ieee802154_cc13xx_cc26xx_subg_set_channel( if (events != RF_EventLastCmdDone) { LOG_DBG("Failed to set frequency: 0x%" PRIx64, events); ret = -EIO; - goto out; } - /* Run BG receive process on requested channel */ - ret = ieee802154_cc13xx_cc26xx_subg_rx(dev); + k_mutex_unlock(&drv_data->tx_mutex); out: - k_mutex_unlock(&drv_data->tx_mutex); + /* Re-enable RX if we found it on initially. */ + if (was_rx_on) { + ieee802154_cc13xx_cc26xx_subg_rx(dev); + } return ret; } From 122a10fdaa2b8374b00a8d6de2ccf06b17fe9031 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:18:49 +0200 Subject: [PATCH 0541/2042] drivers: ieee802154: cc13/26xx_subg: fix header len const The length field in the header refers to the size of the MAC so it shouldn't rely on constants describing PHY header length. While currently both constants have the same value this will no longer be true for enhanced PHYs and/or MAC frames as the number of FCS bytes may then be four. Also introduces an assertion that ensures that the given package buffer does not exceed the TX buffer's length. An assertion is enough as the package buffer is allocated at compile time. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 368234c05a56..ee621f51074a 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -542,11 +542,13 @@ static int ieee802154_cc13xx_cc26xx_subg_tx(const struct device *dev, /* Prepend data with the SUN FSK PHY header, * see IEEE 802.15.4, section 19.2.4. */ - drv_data->tx_data[0] = buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN; + drv_data->tx_data[0] = buf->len + IEEE802154_FCS_LENGTH; drv_data->tx_data[1] = 0; drv_data->tx_data[1] |= BIT(3); /* FCS Type: 2-octet FCS */ drv_data->tx_data[1] |= BIT(4); /* DW: Enable Data Whitening */ + /* TODO: Zero-copy TX, see discussion in #49775. */ + __ASSERT_NO_MSG(buf->len + IEEE802154_PHY_SUN_FSK_PHR_LEN <= CC13XX_CC26XX_TX_BUF_SIZE); memcpy(&drv_data->tx_data[IEEE802154_PHY_SUN_FSK_PHR_LEN], buf->data, buf->len); /* Set TX data */ From fe03bb5f1a9ab7705d7c1a7b54487faee47cac3e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:19:37 +0200 Subject: [PATCH 0542/2042] drivers: ieee802154: cc13/26xx_subg: fix subg_start() return value The radio API should indicate errors when the interface is started. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index ee621f51074a..929995c75dc4 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -657,8 +657,7 @@ static void ieee802154_cc13xx_cc26xx_subg_rx_done( static int ieee802154_cc13xx_cc26xx_subg_start(const struct device *dev) { /* Start RX */ - (void)ieee802154_cc13xx_cc26xx_subg_rx(dev); - return 0; + return ieee802154_cc13xx_cc26xx_subg_rx(dev); } /** From 7232c38828ea472c1996388b8628e984bf106f81 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:21:05 +0200 Subject: [PATCH 0543/2042] drivers: ieee802154: cc13/26xx_subg: fix PHY overrides PHY overrides have been checked against the latest version of TI's SmartRF(TM) Studio. The result was regression tested (PER/performance) against LAUNCHXL-CC1352P1 boards. Signed-off-by: Florian Grandel --- .../ieee802154_cc13xx_cc26xx_subg.c | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index 929995c75dc4..0e1dece181dc 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -73,13 +73,15 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { (uint32_t)0x08141131, /* Tx: Configure PA ramp time, PACTL2.RC=0x3 (in ADI0, set PACTL2[4:3]=0x3) */ ADI_2HALFREG_OVERRIDE(0, 16, 0x8, 0x8, 17, 0x1, 0x1), - /* Tx: Configure PA ramping, set wait time before turning off */ - /* (0x1A ticks of 16/24 us = 17.3 us). */ + /* Tx: Configure PA ramping, set wait time before turning off + * (0x1A ticks of 16/24 us = 17.3 us). + */ HW_REG_OVERRIDE(0x6028, 0x001A), /* Rx: Set AGC reference level to 0x16 (default: 0x2E) */ HW_REG_OVERRIDE(0x609C, 0x0016), - /* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2), */ - /* trimmed for external bias and differential configuration */ + /* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2), + * trimmed for external bias and differential configuration + */ (uint32_t)0x000188A3, /* Rx: Set anti-aliasing filter bandwidth to 0x8 (in ADI0, set IFAMPCTL3[7:4]=0x8) */ ADI_HALFREG_OVERRIDE(0, 61, 0xF, 0x8), @@ -96,8 +98,9 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { ADI_2HALFREG_OVERRIDE(0, 16, 0x8, 0x8, 17, 0x1, 0x0), /* Rx: Set AGC reference level to 0x16 (default: 0x2E) */ HW_REG_OVERRIDE(0x609C, 0x0016), - /* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2), trimmed */ - /* for external bias and differential configuration */ + /* Rx: Set RSSI offset to adjust reported RSSI by -1 dB (default: -2), + * trimmed for external bias and differential configuration. + */ (uint32_t)0x000188A3, /* Rx: Set anti-aliasing filter bandwidth to 0x6 (in ADI0, set IFAMPCTL3[7:4]=0x8) */ ADI_HALFREG_OVERRIDE(0, 61, 0xF, 0x8), @@ -110,20 +113,19 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = { /* DC/DC regulator: In Tx with 14 dBm PA setting, use DCDCCTL5[3:0]=0xF */ /* (DITHER_EN=1 and IPEAK=7). In Rx, use default settings. */ (uint32_t)0x00F788D3, - /* TX power override */ - /* Tx: Set PA trim to max to maximize its output power (in ADI0, set PACTL0=0xF8) */ - ADI_REG_OVERRIDE(0, 12, 0xF8), (uint32_t)0xFFFFFFFF }; static uint32_t rf_prop_overrides_tx_std[] = { /* The TX Power element should always be the first in the list */ - TX_STD_POWER_OVERRIDE(0xB224), + TX_STD_POWER_OVERRIDE(0x013F), /* The ANADIV radio parameter based on the LO divider (0) and front-end (0) settings */ (uint32_t)0x11310703, /* override_phy_tx_pa_ramp_genfsk_std.xml */ /* Tx: Configure PA ramping, set wait time before turning off */ /* (0x1A ticks of 16/24 us = 17.3 us). */ HW_REG_OVERRIDE(0x6028, 0x001A), + /* Set TXRX pin to 0 in RX and high impedance in idle/TX. */ + HW_REG_OVERRIDE(0x60A8, 0x0401), (uint32_t)0xFFFFFFFF }; static uint32_t rf_prop_overrides_tx_20[] = { @@ -135,6 +137,8 @@ static uint32_t rf_prop_overrides_tx_20[] = { /* Tx: Configure PA ramping, set wait time before turning off */ /* (0x1F ticks of 16/24 us = 20.3 us). */ HW_REG_OVERRIDE(0x6028, 0x001F), + /* Set TXRX pin to 0 in RX/TX and high impedance in idle. */ + HW_REG_OVERRIDE(0x60A8, 0x0001), (uint32_t)0xFFFFFFFF }; From b245012ca266570e69cc87d4aa8b84299db943b0 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 15 Jun 2023 22:09:01 +0200 Subject: [PATCH 0544/2042] drivers: ieee802154: cc13/26xx_subg: R-to-P link workaround A known issue exists that does not allow a CC13/26x2R device to establish a link to a CC13/26x2P device unless the capacitor array is tuned to a non-default value in the P device. See SimpleLink(TM) cc13xx_cc26xx SDK 6.20+ Release Notes, Known Issues. Signed-off-by: Florian Grandel --- soc/arm/ti_simplelink/cc13x2_cc26x2/ccfg.c | 9 +++++++++ soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/ccfg.c b/soc/arm/ti_simplelink/cc13x2_cc26x2/ccfg.c index d1d79d82b67c..264b64101f98 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/ccfg.c +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/ccfg.c @@ -22,5 +22,14 @@ #define SET_CCFG_BL_CONFIG_BL_ENABLE 0x00 #endif /* CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_ENABLE */ +#if defined(CONFIG_SOC_CC1352P) || defined(CONFIG_SOC_CC2652P) +/* Workaround required to be able to establish links between P and R devices, + * see SimpleLink(TM) cc13xx_cc26xx SDK 6.20+ Release Notes, Known Issues: + * https://software-dl.ti.com/simplelink/esd/simplelink_cc13xx_cc26xx_sdk/6.20.00.29/exports/release_notes_simplelink_cc13xx_cc26xx_sdk_6_20_00_29.html#known-issues + */ +#define SET_CCFG_MODE_CONF_XOSC_CAP_MOD 0x0 +#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA 0xD5 +#endif + /* TI recommends setting CCFG values and then including the TI provided ccfg.c */ #include diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c index 148a128d6202..74f34acac0d5 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/ccfg.c @@ -22,5 +22,14 @@ #define SET_CCFG_BL_CONFIG_BL_ENABLE 0x00 #endif /* CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_ENABLE */ +#if defined(CONFIG_SOC_CC1352P7) || defined(CONFIG_SOC_CC2652P7) +/* Workaround required to be able to establish links between P and R devices, + * see SimpleLink(TM) cc13xx_cc26xx SDK 6.20+ Release Notes, Known Issues: + * https://software-dl.ti.com/simplelink/esd/simplelink_cc13xx_cc26xx_sdk/6.20.00.29/exports/release_notes_simplelink_cc13xx_cc26xx_sdk_6_20_00_29.html#known-issues + */ +#define SET_CCFG_MODE_CONF_XOSC_CAP_MOD 0x0 +#define SET_CCFG_MODE_CONF_XOSC_CAPARRAY_DELTA 0xD5 +#endif + /* TI recommends setting CCFG values and then including the TI provided ccfg.c */ #include From 897f7789b63e624da95f34178d4b570e801dc2a2 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 9 Jun 2023 16:16:52 +0200 Subject: [PATCH 0545/2042] boards: cc1352p1_launchxl: fix antenna mux config The antenna MUX configuration should explicitly define PULL states as giving no value will leave the GPIO register in an unspecified state. Signed-off-by: Florian Grandel --- boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi index 0fa9c59e60a3..4ecc0396d26a 100644 --- a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi +++ b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi @@ -62,20 +62,26 @@ /* On-board antenna pinmux states */ board_ant_24g_off: board_ant_24g_off { pinmux = <28 IOC_PORT_GPIO>; + bias-disable; }; board_ant_24g_on: board_ant_24g_on { pinmux = <28 IOC_PORT_RFC_GPO0>; + bias-disable; }; board_ant_tx_pa_off: board_ant_tx_pa_off { pinmux = <29 IOC_PORT_GPIO>; + bias-disable; }; board_ant_tx_pa_on: board_ant_tx_pa_on { pinmux = <29 IOC_PORT_RFC_GPO3>; + bias-disable; }; board_ant_subg_off: board_ant_subg_off { pinmux = <30 IOC_PORT_GPIO>; + bias-disable; }; board_ant_subg_on: board_ant_subg_on { pinmux = <30 IOC_PORT_RFC_GPO0>; + bias-disable; }; }; From d25626c74b1982045f4020685be7cb4d81f313b8 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Mon, 19 Jun 2023 15:04:16 +0200 Subject: [PATCH 0546/2042] boards: arm: efr32_thunderboard: add 'zephyr,bt-c2h-uart' Include 'zephyr,bt-c2h-uart' in 'chosen' node to make it possible to use HCI raw mode over UART. This was tested with 'efr32bg22_brd4184b' board running 'hci_uart' sample with Linux machine as a host (kernel 6.2). Signed-off-by: Piotr Dymacz --- boards/arm/efr32_thunderboard/thunderboard.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/efr32_thunderboard/thunderboard.dtsi b/boards/arm/efr32_thunderboard/thunderboard.dtsi index d70e62c0d3a1..2d36a291a682 100644 --- a/boards/arm/efr32_thunderboard/thunderboard.dtsi +++ b/boards/arm/efr32_thunderboard/thunderboard.dtsi @@ -6,6 +6,7 @@ / { chosen { + zephyr,bt-c2h-uart = &usart1; zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &sram0; From 192e425b90667b259b47a0645ad9112357ae6589 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 23:12:10 +0200 Subject: [PATCH 0547/2042] Bluetooth: Host: Add NULL check for addr in unpair unpair may be called from bt_unpair where addr is NULL. One such case is the `bt clear all` shell command which calls bt_unpair with addr = NULL, and the addr is just forwarded to unpair which does not check for NULL. bt_unpair allows for the addr to be NULL to clear all, but only if SMP is enabled. Modified the checks in bt_unpair to increase readability and ensure that unpair is not called with NULL. Signed-off-by: Emil Gydesen --- subsys/bluetooth/host/hci_core.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 8a793d3108f4..0713fca69c23 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1949,13 +1950,21 @@ int bt_unpair(uint8_t id, const bt_addr_le_t *addr) return -EINVAL; } - if (IS_ENABLED(CONFIG_BT_SMP) && - (!addr || bt_addr_le_eq(addr, BT_ADDR_LE_ANY))) { - bt_foreach_bond(id, unpair_remote, &id); - return 0; + if (IS_ENABLED(CONFIG_BT_SMP)) { + if (!addr || bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { + bt_foreach_bond(id, unpair_remote, &id); + } else { + unpair(id, addr); + } + } else { + CHECKIF(addr == NULL) { + LOG_DBG("addr is NULL"); + return -EINVAL; + } + + unpair(id, addr); } - unpair(id, addr); return 0; } From a5532f9fd93ac4a13e320ae166faae808acaaac5 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 22 Jun 2023 11:38:10 +0200 Subject: [PATCH 0548/2042] drivers: dma: stm32 dmamux device must be initialized after dma Add specific init priority for the stm32 DMAMUX device higher than the CONFIG_DMA_INIT_PRIORITY, to be sure that the DMAMUX initialization always comes after the stm32 DMA device init. Its default value is set to 41 when the DMA_INIT_PRIORITY is KERNEL_INIT_PRIORITY_DEFAULT (=40). Signed-off-by: Francois Ramu --- drivers/dma/Kconfig.stm32 | 8 ++++++++ drivers/dma/dmamux_stm32.c | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig.stm32 b/drivers/dma/Kconfig.stm32 index 44b2971ce506..937d98be542b 100644 --- a/drivers/dma/Kconfig.stm32 +++ b/drivers/dma/Kconfig.stm32 @@ -67,4 +67,12 @@ config DMA_STM32_BDMA help BDMA driver for STM32H7 series SoCs. +config DMAMUX_STM32_INIT_PRIORITY + int "STM32 DMAMUX init priority" + depends on DT_HAS_ST_STM32_DMAMUX_ENABLED + default 41 + help + DMAMUX driver device must be init'd after the DMA (CONFIG_DMA_INIT_PRIORITY) + DMAMUX driver device initialization priority is greater than DMA one's + endif # DMA_STM32 diff --git a/drivers/dma/dmamux_stm32.c b/drivers/dma/dmamux_stm32.c index 446aff86dd0d..bca6514190e6 100644 --- a/drivers/dma/dmamux_stm32.c +++ b/drivers/dma/dmamux_stm32.c @@ -422,7 +422,13 @@ DEVICE_DT_INST_DEFINE(index, \ &dmamux_stm32_init, \ NULL, \ &dmamux_stm32_data_##index, &dmamux_stm32_config_##index,\ - PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + PRE_KERNEL_1, CONFIG_DMAMUX_STM32_INIT_PRIORITY, \ &dma_funcs); DT_INST_FOREACH_STATUS_OKAY(DMAMUX_INIT) + +/* + * Make sure that this driver is initialized after the DMA driver (higher priority) + */ +BUILD_ASSERT(CONFIG_DMAMUX_STM32_INIT_PRIORITY >= CONFIG_DMA_INIT_PRIORITY, + "CONFIG_DMAMUX_STM32_INIT_PRIORITY must be higher than CONFIG_DMA_INIT_PRIORITY"); From e802779d8651384f278472dbecf43f4a8295e6a2 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 22 Jun 2023 12:13:41 +0200 Subject: [PATCH 0549/2042] drivers: clock control: stm32h5 set the clock freq for voltage scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the stm32h5x product specifications, the values of the voltage ragulator depends on the system clock as follows: • VOS0 (Vcore = 1.35V) with CPU and peripherals running at up to 250 MHz • VOS1 (Vcore = 1.2V) with CPU and peripherals running at up to 200 MHz • VOS2 (Vcore = 1.1V) with CPU and peripherals running at up to 150 MHz • VOS3 (Vcore = 1.0V) with CPU and peripherals running at up to 100 MHz Signed-off-by: Francois Ramu --- drivers/clock_control/clock_stm32_ll_h5.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index 910a472c2a14..e4c4d28fb125 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -367,11 +367,11 @@ static uint32_t get_vco_output_range(uint32_t vco_input_range) static void set_regu_voltage(uint32_t hclk_freq) { - if (hclk_freq < MHZ(80)) { + if (hclk_freq <= MHZ(100)) { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE3); - } else if (hclk_freq < MHZ(130)) { + } else if (hclk_freq <= MHZ(150)) { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); - } else if (hclk_freq < MHZ(180)) { + } else if (hclk_freq <= MHZ(200)) { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); } else { LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0); From 8620efe562c9025454a549bf923351402d96c907 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 22 Jun 2023 10:02:51 -0500 Subject: [PATCH 0550/2042] boards: arm: mimxrt1040_evk: document M.2 WiFi module debugging issue Document issue with M.2 WiFi module, where debug connection fails using external debugger. Current workaround is to remove J80 jumper when using onboard debugger, or remove M.2 module entirely. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1040_evk/doc/index.rst | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/boards/arm/mimxrt1040_evk/doc/index.rst b/boards/arm/mimxrt1040_evk/doc/index.rst index 12675aa674ce..97f1bfb21fb2 100644 --- a/boards/arm/mimxrt1040_evk/doc/index.rst +++ b/boards/arm/mimxrt1040_evk/doc/index.rst @@ -274,8 +274,11 @@ should see the following message in the terminal: Troubleshooting =============== +Boot Header +----------- + If the debug probe fails to connect with the following error, it's possible -that the boot header in HyperFlash is invalid or corrupted. The boot header is +that the boot header in QSPI is invalid or corrupted. The boot header is configured by :kconfig:option:`CONFIG_NXP_IMX_RT_BOOT_HEADER`. .. code-block:: console @@ -302,6 +305,27 @@ steps: #. Reset by pressing SW1 + +WiFi Module +----------- + +If the debugger fails to connect with the following error, it's possible +the M.2 WiFi module is interfering with the debug signals + +.. code-block:: console + + Remote debugging using :2331 + Remote communication error. Target disconnected.: Connection reset by peer. + "monitor" command not supported by this target. + "monitor" command not supported by this target. + You can't do that when your target is `exec' + (gdb) Could not connect to target. + Please check power, connection and settings. + +To resolve this, you may remove the M.2 WiFi module from the board when +flashing or debugging it, or remove jumper J80. + + .. _MIMXRT1040-EVK Website: https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1040-evaluation-kit:MIMXRT1040-EVK From bb5f421ade4cb3d880e2bd38bdbcaf849b9ce21b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 22 Jun 2023 15:15:29 +0000 Subject: [PATCH 0551/2042] gpio: npm1300: lower init priority Lower the priority of the npm1300 gpio driver. The GPIOs are used by some regulator nodes in the default shield config, but regulators are initialized before the gpios. Lowering the GPIO priority to sort thigs out. Found with the build time priority checking feature: $ west build -p -b nrf52dk_nrf52832 samples/shields/npm1300_ek \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /soc/i2c@40003000/pmic@6b/regulators/LDO2 POST_KERNEL 76 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 ERROR: /soc/i2c@40003000/pmic@6b/regulators/LDO1 POST_KERNEL 76 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 ERROR: /soc/i2c@40003000/pmic@6b/regulators/BUCK2 POST_KERNEL 76 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 ERROR: /soc/i2c@40003000/pmic@6b/regulators POST_KERNEL 75 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 ERROR: /soc/i2c@40003000/pmic@6b/regulators POST_KERNEL 75 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 ERROR: /soc/i2c@40003000/pmic@6b/regulators POST_KERNEL 75 < /soc/i2c@40003000/pmic@6b/gpio-controller POST_KERNEL 80 Signed-off-by: Fabio Baltieri --- drivers/gpio/Kconfig.npm1300 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig.npm1300 b/drivers/gpio/Kconfig.npm1300 index 6f419c97d1e2..c3cbf53d6e20 100644 --- a/drivers/gpio/Kconfig.npm1300 +++ b/drivers/gpio/Kconfig.npm1300 @@ -13,7 +13,7 @@ config GPIO_NPM1300 config GPIO_NPM1300_INIT_PRIORITY int "nPM1300 GPIO driver initialization priority" depends on GPIO_NPM1300 - default 80 + default 70 help Initialization priority for the nPM1300 GPIO driver. It must be greater than the I2C controller init priority. From 7bc99e246ca0f518e56e08ef5b0aec198dba688a Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 24 May 2023 08:41:25 +0100 Subject: [PATCH 0552/2042] drivers: led: npm1300: nPM1300 LED driver Added LED driver for nPM1300 PMIC Signed-off-by: Andy Sinclair --- drivers/led/CMakeLists.txt | 1 + drivers/led/Kconfig | 1 + drivers/led/Kconfig.npm1300 | 11 +++ drivers/led/led_npm1300.c | 100 +++++++++++++++++++++++ dts/bindings/led/nordic,npm1300-led.yaml | 39 +++++++++ 5 files changed, 152 insertions(+) create mode 100644 drivers/led/Kconfig.npm1300 create mode 100644 drivers/led/led_npm1300.c create mode 100644 dts/bindings/led/nordic,npm1300-led.yaml diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index 018a2f362d8c..b38ecbf58410 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c) zephyr_library_sources_ifdef(CONFIG_IS31FL3216A is31fl3216a.c) zephyr_library_sources_ifdef(CONFIG_LED_GPIO led_gpio.c) +zephyr_library_sources_ifdef(CONFIG_LED_NPM1300 led_npm1300.c) zephyr_library_sources_ifdef(CONFIG_LED_PWM led_pwm.c) zephyr_library_sources_ifdef(CONFIG_LED_XEC led_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_LP3943 lp3943.c) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 293d6347946f..91cb28544b98 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -33,6 +33,7 @@ source "drivers/led/Kconfig.lp3943" source "drivers/led/Kconfig.lp503x" source "drivers/led/Kconfig.lp5562" source "drivers/led/Kconfig.lp5569" +source "drivers/led/Kconfig.npm1300" source "drivers/led/Kconfig.pca9633" source "drivers/led/Kconfig.pwm" source "drivers/led/Kconfig.tlc59108" diff --git a/drivers/led/Kconfig.npm1300 b/drivers/led/Kconfig.npm1300 new file mode 100644 index 000000000000..e5180aa1dd1d --- /dev/null +++ b/drivers/led/Kconfig.npm1300 @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config LED_NPM1300 + bool "nPM1300 LED driver" + default y + depends on DT_HAS_NORDIC_NPM1300_LED_ENABLED + select I2C + select MFD + help + Enable the nPM1300 LED driver. diff --git a/drivers/led/led_npm1300.c b/drivers/led/led_npm1300.c new file mode 100644 index 000000000000..528700630e97 --- /dev/null +++ b/drivers/led/led_npm1300.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_npm1300_led + +#include + +#include +#include +#include + +/* nPM1300 LED base address */ +#define NPM_LED_BASE 0x0AU + +/* nPM1300 LED register offsets */ +#define NPM_LED_OFFSET_MODE 0x00U +#define NPM_LED_OFFSET_SET 0x03U +#define NPM_LED_OFFSET_CLR 0x04U + +/* nPM1300 Channel counts */ +#define NPM1300_LED_PINS 3U + +/* nPM1300 LED modes */ +#define NPM_LED_HOST 2U + +struct led_npm1300_config { + const struct device *mfd; + uint8_t mode[NPM1300_LED_PINS]; +}; + +static int led_npm1300_on(const struct device *dev, uint32_t led) +{ + const struct led_npm1300_config *config = dev->config; + + if (led >= NPM1300_LED_PINS) { + return -EINVAL; + } + + if (config->mode[led] != NPM_LED_HOST) { + return -EPERM; + } + + return mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE, NPM_LED_OFFSET_SET + (led * 2U), + 1U); +} + +static int led_npm1300_off(const struct device *dev, uint32_t led) +{ + const struct led_npm1300_config *config = dev->config; + + if (led >= NPM1300_LED_PINS) { + return -EINVAL; + } + + if (config->mode[led] != NPM_LED_HOST) { + return -EPERM; + } + + return mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE, NPM_LED_OFFSET_CLR + (led * 2U), + 1U); +} + +static const struct led_driver_api led_npm1300_api = { + .on = led_npm1300_on, + .off = led_npm1300_off, +}; + +static int led_npm1300_init(const struct device *dev) +{ + const struct led_npm1300_config *config = dev->config; + + if (!device_is_ready(config->mfd)) { + return -ENODEV; + } + + for (uint8_t led = 0U; led < NPM1300_LED_PINS; led++) { + int ret = mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE, + NPM_LED_OFFSET_MODE + led, config->mode[led]); + + if (ret < 0) { + return ret; + } + } + + return 0; +} + +#define LED_NPM1300_DEFINE(n) \ + static const struct led_npm1300_config led_npm1300_config##n = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .mode = {DT_INST_ENUM_IDX(n, nordic_led0_mode), \ + DT_INST_ENUM_IDX(n, nordic_led1_mode), \ + DT_INST_ENUM_IDX(n, nordic_led2_mode)}}; \ + \ + DEVICE_DT_INST_DEFINE(n, &led_npm1300_init, NULL, NULL, &led_npm1300_config##n, \ + POST_KERNEL, CONFIG_LED_INIT_PRIORITY, &led_npm1300_api); + +DT_INST_FOREACH_STATUS_OKAY(LED_NPM1300_DEFINE) diff --git a/dts/bindings/led/nordic,npm1300-led.yaml b/dts/bindings/led/nordic,npm1300-led.yaml new file mode 100644 index 000000000000..90c420832f9d --- /dev/null +++ b/dts/bindings/led/nordic,npm1300-led.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nPM1300 LED controller + + The nPM1300 has three LED outputs. + Each LED can automatically display error or charging status, + or be controlled by software. + +compatible: "nordic,npm1300-led" + +properties: + nordic,led0-mode: + type: string + required: true + enum: + - error + - charging + - host + description: LED 0 mode + + nordic,led1-mode: + type: string + required: true + enum: + - error + - charging + - host + description: LED 1 mode + + nordic,led2-mode: + type: string + required: true + enum: + - error + - charging + - host + description: LED 2 mode From 198d5b889f509d765917025af8cc70e9d5be1239 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 24 May 2023 08:44:07 +0100 Subject: [PATCH 0553/2042] boards: shields: npm1300_ek: Added LED support Updated overlay to include LED support Signed-off-by: Andy Sinclair --- boards/shields/npm1300_ek/npm1300_ek.overlay | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/shields/npm1300_ek/npm1300_ek.overlay b/boards/shields/npm1300_ek/npm1300_ek.overlay index a6ab3bb45e98..8c4c26321719 100644 --- a/boards/shields/npm1300_ek/npm1300_ek.overlay +++ b/boards/shields/npm1300_ek/npm1300_ek.overlay @@ -66,5 +66,12 @@ label = "Pmic button switch 0"; }; }; + + npm1300_ek_leds: leds { + compatible = "nordic,npm1300-led"; + nordic,led0-mode = "error"; + nordic,led1-mode = "charging"; + nordic,led2-mode = "host"; + }; }; }; From d79cf205c6f64ffcf92c24ea401d29f8b5b5c9b4 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 24 May 2023 08:46:20 +0100 Subject: [PATCH 0554/2042] samples: shields: npm1300_ek: Added LED to example Updated shield sample to drive LED Signed-off-by: Andy Sinclair --- samples/shields/npm1300_ek/prj.conf | 1 + samples/shields/npm1300_ek/src/main.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/samples/shields/npm1300_ek/prj.conf b/samples/shields/npm1300_ek/prj.conf index 5b2ff25a04b7..7b134995827e 100644 --- a/samples/shields/npm1300_ek/prj.conf +++ b/samples/shields/npm1300_ek/prj.conf @@ -6,3 +6,4 @@ CONFIG_LOG=y CONFIG_GPIO=y CONFIG_REGULATOR=y CONFIG_SENSOR=y +CONFIG_LED=y diff --git a/samples/shields/npm1300_ek/src/main.c b/samples/shields/npm1300_ek/src/main.c index 896604249ae6..74c5e0fcf76d 100644 --- a/samples/shields/npm1300_ek/src/main.c +++ b/samples/shields/npm1300_ek/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,8 @@ static const struct device *regulators = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_r static const struct device *charger = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_charger)); +static const struct device *leds = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_leds)); + void configure_ui(void) { int ret; @@ -40,6 +43,11 @@ void configure_ui(void) } printk("Set up button at %s pin %d\n", button1.port->name, button1.pin); + + if (!device_is_ready(leds)) { + printk("Error: led device is not ready\n"); + return; + } } void read_sensors(void) @@ -92,6 +100,15 @@ int main(void) regulator_parent_dvs_state_set(regulators, dvs_state); } + /* Update PMIC LED if button state has changed */ + if (button_state != last_button) { + if (button_state) { + led_on(leds, 2U); + } else { + led_off(leds, 2U); + } + } + /* Read and display charger status */ static int count; From bd66c1d953306eecedf1b8529fd74c1341bd316e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 26 May 2023 15:46:31 +0200 Subject: [PATCH 0555/2042] arch POSIX: Refactor into a top and bottom Where the bottom is the only one which interacts with the host operating system, and does not necessarily need to know about the Zephyr OS. This is in preparation for the native simulator, which which the bottom is also fully Zephy agnostic. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/posix_core.c | 117 ++++++++------------------------ arch/posix/core/thread.c | 56 ++++++++++++++- arch/posix/include/posix_core.h | 22 ++++-- soc/posix/inf_clock/soc.c | 4 +- 4 files changed, 102 insertions(+), 97 deletions(-) diff --git a/arch/posix/core/posix_core.c b/arch/posix/core/posix_core.c index ea8c0b5b7de6..2492c7d19e48 100644 --- a/arch/posix/core/posix_core.c +++ b/arch/posix/core/posix_core.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,8 +36,6 @@ * */ -#define POSIX_ARCH_DEBUG_PRINTS 0 - #include #include #include @@ -44,22 +43,11 @@ #include "posix_core.h" #include "posix_arch_internal.h" -#include -#include "kernel_internal.h" -#include -#include "ksched.h" -#include "kswap.h" #define PREFIX "POSIX arch core: " #define ERPREFIX PREFIX"error on " #define NO_MEM_ERR PREFIX"Can't allocate memory\n" -#if POSIX_ARCH_DEBUG_PRINTS -#define PC_DEBUG(fmt, ...) posix_print_trace(PREFIX fmt, __VA_ARGS__) -#else -#define PC_DEBUG(...) -#endif - #define PC_ALLOC_CHUNK_SIZE 64 #define PC_REUSE_ABORTED_ENTRIES 0 /* tests/kernel/threads/scheduling/schedule_api fails when setting @@ -95,6 +83,7 @@ static bool terminate; /* Are we terminating the program == cleaning up */ static void posix_wait_until_allowed(int this_th_nbr); static void *posix_thread_starter(void *arg); static void posix_preexit_cleanup(void); +extern void posix_arch_thread_entry(void *pa_thread_status); /** * Helper function, run by a thread is being aborted @@ -298,11 +287,9 @@ static void *posix_thread_starter(void *arg) */ posix_wait_until_allowed(thread_idx); - posix_new_thread_pre_start(); - posix_thread_status_t *ptr = threads_table[thread_idx].t_status; - z_thread_entry(ptr->entry_point, ptr->arg1, ptr->arg2, ptr->arg3); + posix_arch_thread_entry(ptr); /* * We only reach this point if the thread actually returns which should @@ -366,7 +353,7 @@ static int ttable_get_empty_slot(void) * arch_new_thread() picks from the kernel structures what it is that we need * to call with what parameters */ -void posix_new_thread(posix_thread_status_t *ptr) +int posix_new_thread(void *ptr) { int t_slot; @@ -375,7 +362,6 @@ void posix_new_thread(posix_thread_status_t *ptr) threads_table[t_slot].running = false; threads_table[t_slot].thead_cnt = thread_create_count++; threads_table[t_slot].t_status = ptr; - ptr->thread_idx = t_slot; PC_SAFE_CALL(pthread_create(&threads_table[t_slot].thread, NULL, @@ -388,13 +374,15 @@ void posix_new_thread(posix_thread_status_t *ptr) t_slot, threads_table[t_slot].thread); + return t_slot; } -/** - * Called from zephyr_wrapper() - * prepare whatever needs to be prepared to be able to start threads +/* + * Initialize the posix architecture + * + * Prepare whatever needs to be prepared to be able to start threads */ -void posix_init_multithreading(void) +void posix_arch_init(void) { thread_create_count = 0; @@ -412,7 +400,7 @@ void posix_init_multithreading(void) PC_SAFE_CALL(pthread_mutex_lock(&mtx_threads)); } -/** +/* * Free any allocated memory by the posix core and clean up. * Note that this function cannot be called from a SW thread * (the CPU is assumed halted. Otherwise we will cancel ourselves) @@ -424,9 +412,8 @@ void posix_init_multithreading(void) * error termination, we better do not assume things are working fine. * => we prefer the supposed memory leak report from valgrind, and ensure we * will not hang - * */ -void posix_core_clean_up(void) +void posix_arch_clean_up(void) { if (!threads_table) { /* LCOV_EXCL_BR_LINE */ @@ -453,17 +440,24 @@ void posix_core_clean_up(void) threads_table = NULL; } - void posix_abort_thread(int thread_idx) { - if (threads_table[thread_idx].state != USED) { /* LCOV_EXCL_BR_LINE */ - /* The thread may have been already aborted before */ - return; /* LCOV_EXCL_LINE */ - } + if (thread_idx == currently_allowed_thread) { + PC_DEBUG("Thread [%i] %i: %s Marked myself " + "as aborting\n", + threads_table[thread_idx].thead_cnt, + thread_idx, + __func__); + } else { + if (threads_table[thread_idx].state != USED) { /* LCOV_EXCL_BR_LINE */ + /* The thread may have been already aborted before */ + return; /* LCOV_EXCL_LINE */ + } - PC_DEBUG("Aborting not scheduled thread [%i] %i\n", - threads_table[thread_idx].thead_cnt, - thread_idx); + PC_DEBUG("Aborting not scheduled thread [%i] %i\n", + threads_table[thread_idx].thead_cnt, + thread_idx); + } threads_table[thread_idx].state = ABORTING; /* @@ -473,64 +467,13 @@ void posix_abort_thread(int thread_idx) * would be the case, but with a pthread_cancel() the mutex state would * be uncontrolled */ -} +} -#if defined(CONFIG_ARCH_HAS_THREAD_ABORT) -void z_impl_k_thread_abort(k_tid_t thread) +int posix_arch_get_unique_thread_id(int thread_idx) { - unsigned int key; - int thread_idx; - - posix_thread_status_t *tstatus = - (posix_thread_status_t *) - thread->callee_saved.thread_status; - - thread_idx = tstatus->thread_idx; - - key = irq_lock(); - - if (_current == thread) { - if (tstatus->aborted == 0) { /* LCOV_EXCL_BR_LINE */ - tstatus->aborted = 1; - } else { - posix_print_warning(/* LCOV_EXCL_LINE */ - PREFIX"The kernel is trying to abort and swap " - "out of an already aborted thread %i. This " - "should NOT have happened\n", - thread_idx); - } - threads_table[thread_idx].state = ABORTING; - PC_DEBUG("Thread [%i] %i: %s Marked myself " - "as aborting\n", - threads_table[thread_idx].thead_cnt, - thread_idx, - __func__); - } - - z_thread_abort(thread); - - if (tstatus->aborted == 0) { - PC_DEBUG("%s aborting now [%i] %i\n", - __func__, - threads_table[thread_idx].thead_cnt, - thread_idx); - - tstatus->aborted = 1; - posix_abort_thread(thread_idx); - } else { - PC_DEBUG("%s ignoring re_abort of [%i] " - "%i\n", - __func__, - threads_table[thread_idx].thead_cnt, - thread_idx); - } - - /* The abort handler might have altered the ready queue. */ - z_reschedule_irqlock(key); + return threads_table[thread_idx].thead_cnt; } -#endif - /* * Notes about coverage: diff --git a/arch/posix/core/thread.c b/arch/posix/core/thread.c index 8168e88b3ce9..a1bcecb766d9 100644 --- a/arch/posix/core/thread.c +++ b/arch/posix/core/thread.c @@ -47,10 +47,62 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, thread->callee_saved.thread_status = thread_status; - posix_new_thread(thread_status); + thread_status->thread_idx = posix_new_thread((void *)thread_status); } -void posix_new_thread_pre_start(void) +void posix_arch_thread_entry(void *pa_thread_status) { + posix_thread_status_t *ptr = pa_thread_status; posix_irq_full_unlock(); + z_thread_entry(ptr->entry_point, ptr->arg1, ptr->arg2, ptr->arg3); } + +#if defined(CONFIG_ARCH_HAS_THREAD_ABORT) +void z_impl_k_thread_abort(k_tid_t thread) +{ + unsigned int key; + int thread_idx; + + posix_thread_status_t *tstatus = + (posix_thread_status_t *) + thread->callee_saved.thread_status; + + thread_idx = tstatus->thread_idx; + + key = irq_lock(); + + if (_current == thread) { + if (tstatus->aborted == 0) { /* LCOV_EXCL_BR_LINE */ + tstatus->aborted = 1; + } else { + posix_print_warning(/* LCOV_EXCL_LINE */ + "POSIX arch: The kernel is trying to abort and swap " + "out of an already aborted thread %i. This " + "should NOT have happened\n", + thread_idx); + } + posix_abort_thread(thread_idx); + } + + z_thread_abort(thread); + + if (tstatus->aborted == 0) { + PC_DEBUG("%s aborting now [%i] %i\n", + __func__, + posix_arch_get_unique_thread_id(thread_idx), + thread_idx); + + tstatus->aborted = 1; + posix_abort_thread(thread_idx); + } else { + PC_DEBUG("%s ignoring re_abort of [%i] " + "%i\n", + __func__, + posix_arch_get_unique_thread_id(thread_idx), + thread_idx); + } + + /* The abort handler might have altered the ready queue. */ + z_reschedule_irqlock(key); +} +#endif diff --git a/arch/posix/include/posix_core.h b/arch/posix/include/posix_core.h index 7921f3b64b8a..c16d17afbd9e 100644 --- a/arch/posix/include/posix_core.h +++ b/arch/posix/include/posix_core.h @@ -39,14 +39,24 @@ typedef struct { } posix_thread_status_t; -void posix_new_thread(posix_thread_status_t *ptr); -void posix_swap(int next_allowed_thread_nbr, int this_thread_nbr); +void posix_irq_check_idle_exit(void); +void posix_arch_init(void); +void posix_arch_clean_up(void); +void posix_swap(int next_allowed_thread_nbr, int this_th_nbr); void posix_main_thread_start(int next_allowed_thread_nbr); -void posix_init_multithreading(void); -void posix_core_clean_up(void); +int posix_new_thread(void *payload); +void posix_abort_thread(int thread_idx); +int posix_arch_get_unique_thread_id(int thread_idx); -void posix_new_thread_pre_start(void); /* defined in thread.c */ -void posix_irq_check_idle_exit(void); +#ifndef POSIX_ARCH_DEBUG_PRINTS +#define POSIX_ARCH_DEBUG_PRINTS 0 +#endif + +#if POSIX_ARCH_DEBUG_PRINTS +#define PC_DEBUG(fmt, ...) posix_print_trace("POSIX arch core:" fmt, __VA_ARGS__) +#else +#define PC_DEBUG(...) +#endif #ifdef __cplusplus } diff --git a/soc/posix/inf_clock/soc.c b/soc/posix/inf_clock/soc.c index c0d11f44fc48..ac2c50155a79 100644 --- a/soc/posix/inf_clock/soc.c +++ b/soc/posix/inf_clock/soc.c @@ -182,7 +182,7 @@ static void *zephyr_wrapper(void *a) zephyr_thread); #endif - posix_init_multithreading(); + posix_arch_init(); /* Start Zephyr: */ z_cstart(); @@ -235,7 +235,7 @@ void posix_soc_clean_up(void) */ if (cpu_halted) { - posix_core_clean_up(); + posix_arch_clean_up(); run_native_tasks(_NATIVE_ON_EXIT_LEVEL); } else if (soc_terminate == false) { From 7ee41b8776444340e07e26f9ab64ebf2ca22e3db Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 26 May 2023 16:42:09 +0200 Subject: [PATCH 0556/2042] soc inf (native): Refactor into a top and bottom Where the bottom is the only one which interacts with the host operating system. And the top the only one that interacts or is aware of the hosted operating system (Zephyr). The bottom uses the native simulator CPU start/stop emulation. By now we replicate its code as a provisional measure, until the native simulator becomes standard. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/CMakeLists.txt | 6 + arch/posix/core/nsi_compat/nce.c | 292 +++++++++++++++++++++ arch/posix/core/nsi_compat/nce_if.h | 26 ++ arch/posix/core/nsi_compat/nsi_compat.c | 49 ++++ arch/posix/core/nsi_compat/nsi_compat.h | 22 ++ arch/posix/core/nsi_compat/nsi_safe_call.h | 15 ++ arch/posix/core/nsi_compat/nsi_tracing.h | 22 ++ soc/posix/inf_clock/soc.c | 163 ++---------- 8 files changed, 447 insertions(+), 148 deletions(-) create mode 100644 arch/posix/core/nsi_compat/nce.c create mode 100644 arch/posix/core/nsi_compat/nce_if.h create mode 100644 arch/posix/core/nsi_compat/nsi_compat.c create mode 100644 arch/posix/core/nsi_compat/nsi_compat.h create mode 100644 arch/posix/core/nsi_compat/nsi_safe_call.h create mode 100644 arch/posix/core/nsi_compat/nsi_tracing.h diff --git a/arch/posix/core/CMakeLists.txt b/arch/posix/core/CMakeLists.txt index bd30e58c351f..6f2652ac8f77 100644 --- a/arch/posix/core/CMakeLists.txt +++ b/arch/posix/core/CMakeLists.txt @@ -6,7 +6,13 @@ zephyr_library_sources( cpuhalt.c fatal.c irq.c + nsi_compat/nsi_compat.c + nsi_compat/nce.c posix_core.c swap.c thread.c ) + +zephyr_include_directories( + nsi_compat/ +) diff --git a/arch/posix/core/nsi_compat/nce.c b/arch/posix/core/nsi_compat/nce.c new file mode 100644 index 000000000000..54989dcd32cd --- /dev/null +++ b/arch/posix/core/nsi_compat/nce.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Native simulator CPU emulator, + * an *optional* module provided by the native simulator + * the hosted embedded OS / SW can use to emulate the CPU + * being started and stopped. + * + * Its mode of operation is that it step-locks the HW + * and SW operation, so that only one of them executes at + * a time. Check the docs for more info. + */ + +#include +#include +#include +#include +#include "nce_if.h" +#include "nsi_safe_call.h" + +struct nce_status_t { + /* Conditional variable to know if the CPU is running or halted/idling */ + pthread_cond_t cond_cpu; + /* Mutex for the conditional variable cond_cpu */ + pthread_mutex_t mtx_cpu; + /* Variable which tells if the CPU is halted (1) or not (0) */ + bool cpu_halted; + bool terminate; /* Are we terminating the program == cleaning up */ + void (*start_routine)(void); +}; + +#define NCE_DEBUG_PRINTS 0 + +#define PREFIX "NCE: " +#define ERPREFIX PREFIX"error on " +#define NO_MEM_ERR PREFIX"Can't allocate memory\n" + +#if NCE_DEBUG_PRINTS +#define NCE_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__) +#else +#define NCE_DEBUG(...) +#endif + +extern void nsi_exit(int exit_code); + +/* + * Initialize an instance of the native simulator CPU emulator + * and return a pointer to it. + * That pointer should be passed to all subsequent calls to this module. + */ +void *nce_init(void) +{ + struct nce_status_t *this; + + this = calloc(1, sizeof(struct nce_status_t)); + + if (this == NULL) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ + } + this->cpu_halted = true; + this->terminate = false; + + NSI_SAFE_CALL(pthread_cond_init(&this->cond_cpu, NULL)); + NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_cpu, NULL)); + + return (void *)this; +} + +/* + * This function will: + * + * If called from a SW thread, release the HW thread which is blocked in + * a nce_wake_cpu() and never return. + * + * If called from a HW thread, do the necessary clean up of this nce instance + * and return right away. + */ +void nce_terminate(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + /* LCOV_EXCL_START */ /* See Note1 */ + /* + * If we are being called from a HW thread we can cleanup + * + * Otherwise (!cpu_halted) we give back control to the HW thread and + * tell it to terminate ASAP + */ + if (this == NULL || this->cpu_halted) { + /* + * Note: The nce_status structure cannot be safely free'd up + * as the user is allowed to call nce_clean_up() + * repeatedly on the same structure. + * Instead we rely of on the host OS process cleanup. + * If you got here due to valgrind's leak report, please use the + * provided valgrind suppression file valgrind.supp + */ + return; + } else if (this->terminate == false) { + + this->terminate = true; + + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + this->cpu_halted = true; + + NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + + while (1) { + sleep(1); + /* This SW thread will wait until being cancelled from + * the HW thread. sleep() is a cancellation point, so it + * won't really wait 1 second + */ + } + } + /* LCOV_EXCL_STOP */ +} + +/** + * Helper function which changes the status of the CPU (halted or running) + * and waits until somebody else changes it to the opposite + * + * Both HW and SW threads will use this function to transfer control to the + * other side. + * + * This is how the idle thread halts the CPU and gets halted until the HW models + * raise a new interrupt; and how the HW models awake the CPU, and wait for it + * to complete and go to idle. + */ +static void change_cpu_state_and_wait(struct nce_status_t *this, bool halted) +{ + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + NCE_DEBUG("Going to halted = %d\n", halted); + + this->cpu_halted = halted; + + /* We let the other side know the CPU has changed state */ + NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); + + /* We wait until the CPU state has been changed. Either: + * we just awoke it, and therefore wait until the CPU has run until + * completion before continuing (before letting the HW models do + * anything else) + * or + * we are just hanging it, and therefore wait until the HW models awake + * it again + */ + while (this->cpu_halted == halted) { + /* Here we unlock the mutex while waiting */ + pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); + } + + NCE_DEBUG("Awaken after halted = %d\n", halted); + + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); +} + +/* + * Helper function that wraps the SW start_routine + */ +static void *sw_wrapper(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + /* Ensure nce_boot_cpu has reached the cond loop */ + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + +#if (NCE_DEBUG_PRINTS) + pthread_t sw_thread = pthread_self(); + + NCE_DEBUG("SW init started (%lu)\n", + sw_thread); +#endif + + this->start_routine(); + return NULL; +} + +/* + * Boot the emulated CPU, that is: + * * Spawn a new pthread which will run the first embedded SW thread + * * Hold the caller until that embedded SW thread (or a child it spawns) + * calls nce_halt_cpu() + * + * Note that during this, an embedded SW thread may call nsi_exit(), which would result + * in this function never returning. + */ +void nce_boot_cpu(void *this_arg, void (*start_routine)(void)) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + this->cpu_halted = false; + this->start_routine = start_routine; + + /* Create a thread for the embedded SW init: */ + pthread_t sw_thread; + + NSI_SAFE_CALL(pthread_create(&sw_thread, NULL, sw_wrapper, this_arg)); + + /* And we wait until the embedded OS has send the CPU to sleep for the first time */ + while (this->cpu_halted == false) { + pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); + } + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + + if (this->terminate) { + nsi_exit(0); + } +} + +/* + * Halt the CPU, that is: + * * Hold this embedded SW thread until the CPU is awaken again, + * and release the HW thread which had been held on + * nce_boot_cpu() or nce_wake_cpu(). + * + * Note: Can only be called from embedded SW threads + * Calling it from a HW thread is a programming error. + */ +void nce_halt_cpu(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this->cpu_halted == true) { + nsi_print_error_and_exit("Programming error on: %s ", + "This CPU was already halted\n"); + } + change_cpu_state_and_wait(this, true); +} + +/* + * Awake the CPU, that is: + * * Hold this HW thread until the CPU is set to idle again + * * Release the SW thread which had been held on nce_halt_cpu() + * + * Note: Can only be called from HW threads + * Calling it from a SW thread is a programming error. + */ +void nce_wake_cpu(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this->cpu_halted == false) { + nsi_print_error_and_exit("Programming error on: %s ", + "This CPU was already awake\n"); + } + change_cpu_state_and_wait(this, false); + + /* + * If while the SW was running it was decided to terminate the execution + * we stop immediately. + */ + if (this->terminate) { + nsi_exit(0); + } +} + +/* + * Return 0 if the CPU is sleeping (or terminated) + * and !=0 if the CPU is running + */ +int nce_is_cpu_running(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this != NULL) { + return !this->cpu_halted; + } else { + return false; + } +} + +/* + * Notes about coverage: + * + * Note1: When the application is closed due to a SIGTERM, the path in this + * function will depend on when that signal was received. Typically during a + * regression run, both paths will be covered. But in some cases they won't. + * Therefore and to avoid confusing developers with spurious coverage changes + * we exclude this function from the coverage check + */ diff --git a/arch/posix/core/nsi_compat/nce_if.h b/arch/posix/core/nsi_compat/nce_if.h new file mode 100644 index 000000000000..be5772a2b731 --- /dev/null +++ b/arch/posix/core/nsi_compat/nce_if.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef NSI_COMMON_SRC_INCL_NCE_IF_H +#define NSI_COMMON_SRC_INCL_NCE_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Native simulator CPU start/stop emulation module interface */ + +void *nce_init(void); +void nce_terminate(void *this); +void nce_boot_cpu(void *this, void (*start_routine)(void)); +void nce_halt_cpu(void *this); +void nce_wake_cpu(void *this); +int nce_is_cpu_running(void *this); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NCE_IF_H */ diff --git a/arch/posix/core/nsi_compat/nsi_compat.c b/arch/posix/core/nsi_compat/nsi_compat.c new file mode 100644 index 000000000000..eccd2643295d --- /dev/null +++ b/arch/posix/core/nsi_compat/nsi_compat.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This module exist to provide a basic compatibility shim + * from Native simulator components into the POSIX architecture. + * + * It is a transitional component, intended to facilitate + * the migration towards the Native simulator. + */ + +#include "zephyr/arch/posix/posix_trace.h" + +void nsi_print_error_and_exit(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + posix_vprint_error_and_exit(format, variable_args); + va_end(variable_args); +} + +void nsi_print_warning(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + posix_vprint_warning(format, variable_args); + va_end(variable_args); +} + +void nsi_print_trace(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + posix_vprint_trace(format, variable_args); + va_end(variable_args); +} + +void nsi_exit(int exit_code) +{ + extern void posix_exit(int exit_code); + + posix_exit(exit_code); +} diff --git a/arch/posix/core/nsi_compat/nsi_compat.h b/arch/posix/core/nsi_compat/nsi_compat.h new file mode 100644 index 000000000000..9537a516342d --- /dev/null +++ b/arch/posix/core/nsi_compat/nsi_compat.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ARCH_POSIX_CORE_NSI_COMPAT_H +#define ARCH_POSIX_CORE_NSI_COMPAT_H + +#include "nsi_tracing.h" +#include "nsi_safe_call.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void nsi_exit(int exit_code); + +#ifdef __cplusplus +} +#endif + +#endif /* ARCH_POSIX_CORE_NSI_COMPAT_H */ diff --git a/arch/posix/core/nsi_compat/nsi_safe_call.h b/arch/posix/core/nsi_compat/nsi_safe_call.h new file mode 100644 index 000000000000..6227cb187aeb --- /dev/null +++ b/arch/posix/core/nsi_compat/nsi_safe_call.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ARCH_POSIX_CORE_NSI_SAFE_CALLL_H +#define ARCH_POSIX_CORE_NSI_SAFE_CALLL_H + +#include "nsi_tracing.h" +#include "posix_arch_internal.h" + +#define NSI_SAFE_CALL PC_SAFE_CALL + +#endif /* ARCH_POSIX_CORE_NSI_SAFE_CALLL_H */ diff --git a/arch/posix/core/nsi_compat/nsi_tracing.h b/arch/posix/core/nsi_compat/nsi_tracing.h new file mode 100644 index 000000000000..854873bf3c86 --- /dev/null +++ b/arch/posix/core/nsi_compat/nsi_tracing.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ARCH_POSIX_CORE_NSI_TRACING_H +#define ARCH_POSIX_CORE_NSI_TRACING_H + +#ifdef __cplusplus +extern "C" { +#endif + +void nsi_print_error_and_exit(const char *format, ...); +void nsi_print_warning(const char *format, ...); +void nsi_print_trace(const char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* ARCH_POSIX_CORE_NSI_TRACING_H */ diff --git a/soc/posix/inf_clock/soc.c b/soc/posix/inf_clock/soc.c index ac2c50155a79..53d7d90c50cc 100644 --- a/soc/posix/inf_clock/soc.c +++ b/soc/posix/inf_clock/soc.c @@ -24,9 +24,6 @@ * */ -#include -#include -#include #include #include "posix_soc.h" #include "posix_board_if.h" @@ -34,34 +31,15 @@ #include "posix_arch_internal.h" #include "kernel_internal.h" #include "soc.h" +#include "nce_if.h" -#define POSIX_ARCH_SOC_DEBUG_PRINTS 0 - -#define PREFIX "POSIX SOC: " -#define ERPREFIX PREFIX"error on " - -#if POSIX_ARCH_SOC_DEBUG_PRINTS -#define PS_DEBUG(fmt, ...) posix_print_trace(PREFIX fmt, __VA_ARGS__) -#else -#define PS_DEBUG(...) -#endif - -/* Conditional variable to know if the CPU is running or halted/idling */ -static pthread_cond_t cond_cpu = PTHREAD_COND_INITIALIZER; -/* Mutex for the conditional variable posix_soc_cond_cpu */ -static pthread_mutex_t mtx_cpu = PTHREAD_MUTEX_INITIALIZER; -/* Variable which tells if the CPU is halted (1) or not (0) */ -static bool cpu_halted = true; - -static bool soc_terminate; /* Is the program being closed */ - +static void *nce_st; int posix_is_cpu_running(void) { - return !cpu_halted; + return nce_is_cpu_running(nce_st); } - /** * Helper function which changes the status of the CPU (halted or running) * and waits until somebody else changes it to the opposite @@ -75,31 +53,11 @@ int posix_is_cpu_running(void) */ void posix_change_cpu_state_and_wait(bool halted) { - PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu)); - - PS_DEBUG("Going to halted = %d\n", halted); - - cpu_halted = halted; - - /* We let the other side know the CPU has changed state */ - PC_SAFE_CALL(pthread_cond_broadcast(&cond_cpu)); - - /* We wait until the CPU state has been changed. Either: - * we just awoke it, and therefore wait until the CPU has run until - * completion before continuing (before letting the HW models do - * anything else) - * or - * we are just hanging it, and therefore wait until the HW models awake - * it again - */ - while (cpu_halted == halted) { - /* Here we unlock the mutex while waiting */ - pthread_cond_wait(&cond_cpu, &mtx_cpu); + if (halted) { + nce_halt_cpu(nce_st); + } else { + nce_wake_cpu(nce_st); } - - PS_DEBUG("Awaken after halted = %d\n", halted); - - PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu)); } /** @@ -111,15 +69,7 @@ void posix_interrupt_raised(void) /* We change the CPU to running state (we awake it), and block this * thread until the CPU is halted again */ - posix_change_cpu_state_and_wait(false); - - /* - * If while the SW was running it was decided to terminate the execution - * we stop immediately. - */ - if (soc_terminate) { - posix_exit(0); - } + nce_wake_cpu(nce_st); } @@ -136,7 +86,7 @@ void posix_halt_cpu(void) * We set the CPU in the halted state (this blocks this pthread * until the CPU is awoken again by the HW models) */ - posix_change_cpu_state_and_wait(true); + nce_halt_cpu(nce_st); /* We are awoken, normally that means some interrupt has just come * => let the "irq handler" check if/what interrupt was raised @@ -164,34 +114,6 @@ void posix_atomic_halt_cpu(unsigned int imask) posix_irq_unlock(imask); } - -/** - * Just a wrapper function to call Zephyr's z_cstart() - * called from posix_boot_cpu() - */ -static void *zephyr_wrapper(void *a) -{ - /* Ensure posix_boot_cpu has reached the cond loop */ - PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu)); - PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu)); - -#if (POSIX_ARCH_SOC_DEBUG_PRINTS) - pthread_t zephyr_thread = pthread_self(); - - PS_DEBUG("Zephyr init started (%lu)\n", - zephyr_thread); -#endif - - posix_arch_init(); - - /* Start Zephyr: */ - z_cstart(); - CODE_UNREACHABLE; - - return NULL; -} - - /** * The HW models will call this function to "boot" the CPU * == spawn the Zephyr init thread, which will then spawn @@ -199,24 +121,9 @@ static void *zephyr_wrapper(void *a) */ void posix_boot_cpu(void) { - PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu)); - - cpu_halted = false; - - pthread_t zephyr_thread; - - /* Create a thread for Zephyr init: */ - PC_SAFE_CALL(pthread_create(&zephyr_thread, NULL, zephyr_wrapper, NULL)); - - /* And we wait until Zephyr has run til completion (has gone to idle) */ - while (cpu_halted == false) { - pthread_cond_wait(&cond_cpu, &mtx_cpu); - } - PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu)); - - if (soc_terminate) { - posix_exit(0); - } + nce_st = nce_init(); + posix_arch_init(); + nce_boot_cpu(nce_st, z_cstart); } /** @@ -226,47 +133,7 @@ void posix_boot_cpu(void) */ void posix_soc_clean_up(void) { - /* LCOV_EXCL_START */ /* See Note1 */ - /* - * If we are being called from a HW thread we can cleanup - * - * Otherwise (!cpu_halted) we give back control to the HW thread and - * tell it to terminate ASAP - */ - if (cpu_halted) { - - posix_arch_clean_up(); - run_native_tasks(_NATIVE_ON_EXIT_LEVEL); - - } else if (soc_terminate == false) { - - soc_terminate = true; - - PC_SAFE_CALL(pthread_mutex_lock(&mtx_cpu)); - - cpu_halted = true; - - PC_SAFE_CALL(pthread_cond_broadcast(&cond_cpu)); - PC_SAFE_CALL(pthread_mutex_unlock(&mtx_cpu)); - - while (1) { - sleep(1); - /* This SW thread will wait until being cancelled from - * the HW thread. sleep() is a cancellation point, so it - * won't really wait 1 second - */ - } - } - /* LCOV_EXCL_STOP */ + nce_terminate(nce_st); + posix_arch_clean_up(); + run_native_tasks(_NATIVE_ON_EXIT_LEVEL); } - -/* - * Notes about coverage: - * - * Note1: When the application is closed due to a SIGTERM, the path in this - * function will depend on when that signal was received. Typically during a - * regression run, both paths will be covered. But in some cases they won't. - * Therefore and to avoid confusing developers with spurious coverage changes - * we exclude this function from the coverage check - * - */ From 06b8f4b9945859a38f175d9db0d278608daed048 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 28 Mar 2023 09:53:15 +0200 Subject: [PATCH 0557/2042] drivers: flash: stm32 qspi driver with read SFDP ID from quadflash This commit adds the jedec216 read sfdp and Read ID function API. The qspi commands are issued to the quad flash device. Signed-off-by: Francois Ramu --- drivers/flash/flash_stm32_qspi.c | 59 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index e9f26a94780b..74ea8bab7c7a 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -91,6 +91,9 @@ struct flash_stm32_qspi_config { #if STM32_QSPI_RESET_GPIO const struct gpio_dt_spec reset; #endif +#if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_qspi_nor), jedec_id) + uint8_t jedec_id[DT_INST_PROP_LEN(0, jedec_id)]; +#endif /* jedec_id */ }; struct flash_stm32_qspi_data { @@ -284,12 +287,57 @@ static int qspi_write_access(const struct device *dev, QSPI_CommandTypeDef *cmd, return dev_data->cmd_status; } +#if defined(CONFIG_FLASH_JESD216_API) +/* + * Read Serial Flash ID : + * perform a read access over SPI bus for read Identification (DataMode is already set) + * and compare to the jedec-id from the DTYS table exists + */ +static int qspi_read_jedec_id(const struct device *dev, uint8_t *id) +{ + struct flash_stm32_qspi_data *dev_data = dev->data; + uint8_t data[JESD216_READ_ID_LEN]; + + QSPI_CommandTypeDef cmd = { + .Instruction = JESD216_CMD_READ_ID, + .AddressSize = QSPI_ADDRESS_NONE, + .DummyCycles = 8, + .InstructionMode = QSPI_INSTRUCTION_1_LINE, + .AddressMode = QSPI_ADDRESS_1_LINE, + .DataMode = QSPI_DATA_1_LINE, + .NbData = JESD216_READ_ID_LEN, + }; + + HAL_StatusTypeDef hal_ret; + + hal_ret = HAL_QSPI_Command_IT(&dev_data->hqspi, &cmd); + + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to send OSPI instruction", hal_ret); + return -EIO; + } + + hal_ret = HAL_QSPI_Receive(&dev_data->hqspi, data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); + if (hal_ret != HAL_OK) { + LOG_ERR("%d: Failed to read data", hal_ret); + return -EIO; + } + + dev_data->cmd_status = 0; + id = &data[0]; + + return 0; +} +#endif /* CONFIG_FLASH_JESD216_API */ + /* * Read Serial Flash Discovery Parameter */ -static int qspi_read_sfdp(const struct device *dev, off_t addr, uint8_t *data, +static int qspi_read_sfdp(const struct device *dev, off_t addr, void *data, size_t size) { + __ASSERT(data != NULL, "null destination"); + QSPI_CommandTypeDef cmd = { .Instruction = JESD216_CMD_READ_SFDP, .Address = addr, @@ -300,7 +348,7 @@ static int qspi_read_sfdp(const struct device *dev, off_t addr, uint8_t *data, .DataMode = QSPI_DATA_1_LINE, }; - return qspi_read_access(dev, &cmd, data, size); + return qspi_read_access(dev, &cmd, (uint8_t *)data, size); } static bool qspi_address_is_valid(const struct device *dev, off_t addr, @@ -666,6 +714,10 @@ static const struct flash_driver_api flash_stm32_qspi_driver_api = { #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_stm32_qspi_pages_layout, #endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = qspi_read_sfdp, + .read_jedec_id = qspi_read_jedec_id, +#endif /* CONFIG_FLASH_JESD216_API */ }; #if defined(CONFIG_FLASH_PAGE_LAYOUT) @@ -1346,6 +1398,9 @@ static const struct flash_stm32_qspi_config flash_stm32_qspi_cfg = { #if STM32_QSPI_RESET_GPIO .reset = GPIO_DT_SPEC_INST_GET(0, reset_gpios), #endif +#if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_qspi_nor), jedec_id) + .jedec_id = DT_INST_PROP(0, jedec_id), +#endif /* jedec_id */ }; static struct flash_stm32_qspi_data flash_stm32_qspi_dev_data = { From c7b82096a465f4f03ddedb9177aedb5ec02b2703 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 28 Mar 2023 09:47:46 +0200 Subject: [PATCH 0558/2042] boards: arm: stm32h747i disco board enables QSPI interface The stm32h474i_disco has a twin NOR flash made of two MT25QL512 64MBytes quad-NOR devices. Here, the partition is fully adressing the memory size. The 1st NOR device is selected (U3 on the schematics). Signed-off-by: Francois Ramu --- boards/arm/stm32h747i_disco/doc/index.rst | 3 ++ .../stm32h747i_disco/stm32h747i_disco_m7.dts | 39 +++++++++++++++++++ .../stm32h747i_disco/stm32h747i_disco_m7.yaml | 1 + 3 files changed, 43 insertions(+) diff --git a/boards/arm/stm32h747i_disco/doc/index.rst b/boards/arm/stm32h747i_disco/doc/index.rst index d8c670aae52f..2f8d543d4464 100644 --- a/boards/arm/stm32h747i_disco/doc/index.rst +++ b/boards/arm/stm32h747i_disco/doc/index.rst @@ -27,6 +27,7 @@ Additionally, the board features: - USB OTG HS - Stereo speaker outputs - ST-MEMS digital microphones +- 2 x 512-Mbit QUAD-SPI NOR Flash memory - 256-Mbit SDRAM - 4 color user LEDs - 1 user and reset push-button @@ -71,6 +72,8 @@ The current Zephyr stm32h747i_disco board configuration supports the following h +-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| QSPI NOR | on-chip | off-chip flash | ++-----------+------------+-------------------------------------+ | SDMMC | on-chip | disk access | +-----------+------------+-------------------------------------+ | IPM | on-chip | virtual mailbox based on HSEM | diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts index fb3e4972b282..6104a7c17659 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &usart1; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,flash-controller = &mt25ql512ab1; }; sdram2: sdram@d0000000 { @@ -53,6 +54,7 @@ led0 = &green_led_1; led1 = &orange_led_2; sw0 = &wake_up; + spi-flash0 = &mt25ql512ab1; }; }; @@ -206,4 +208,41 @@ zephyr_udc0: &usbotg_hs { cd-gpios = <&gpioi 8 GPIO_ACTIVE_LOW>; }; +&quadspi { + pinctrl-0 = <&quadspi_clk_pb2 &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>; + pinctrl-names = "default"; + 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@0 { + compatible = "st,stm32-qspi-nor"; + reg = <0>; + qspi-max-frequency = <72000000>; + size = ; /* 64 MBytes */ + status = "okay"; + }; +}; + arduino_spi: &spi5 {}; diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.yaml b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.yaml index 93939e9f8305..fb67ae1e3988 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.yaml +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.yaml @@ -14,6 +14,7 @@ supported: - arduino_spi - spi - netif:eth + - qspi - memc - usb_cdc - usb_device From a13ccdad9ca8e213f47a4bb9b5a67e991a9cae4c Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 3 Mar 2023 17:49:14 +0100 Subject: [PATCH 0559/2042] boards: arm: stm32l496 disco enables the quadspi NOR This commit enables the 64Mbit quadspi NOR (mx25r6435) mounted on the stm32l496g_disco kit. Use the DMA transfer for QSPI: request 7 on channel3 of DMA2. Signed-off-by: Francois Ramu --- boards/arm/stm32l496g_disco/doc/index.rst | 2 ++ .../arm/stm32l496g_disco/stm32l496g_disco.dts | 29 +++++++++++++++++++ .../stm32l496g_disco/stm32l496g_disco.yaml | 1 + 3 files changed, 32 insertions(+) diff --git a/boards/arm/stm32l496g_disco/doc/index.rst b/boards/arm/stm32l496g_disco/doc/index.rst index a469a84823cd..681969f08afc 100644 --- a/boards/arm/stm32l496g_disco/doc/index.rst +++ b/boards/arm/stm32l496g_disco/doc/index.rst @@ -142,6 +142,8 @@ The Zephyr stm32l496g_disco board configuration supports the following hardware +-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| QSPI NOR | on-chip | off-chip flash | ++-----------+------------+-------------------------------------+ | PWM | on-chip | pwm | +-----------+------------+-------------------------------------+ | ADC | on-chip | adc | diff --git a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts index fba2c2a8da02..95453135ee44 100644 --- a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts +++ b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts @@ -18,6 +18,7 @@ zephyr,shell-uart = &usart2; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,flash-controller = &mx25r6435; }; leds { @@ -61,6 +62,7 @@ sw4 = &joy_left; volt-sensor0 = &vref; volt-sensor1 = &vbat; + spi-flash0 = &mx25r6435; }; }; @@ -174,3 +176,30 @@ zephyr_udc0: &usbotg_fs { &vbat { status = "okay"; }; + +&dma2 { + status = "okay"; +}; + +&quadspi { + pinctrl-0 = <&quadspi_bk1_io0_pb1 &quadspi_bk1_io1_pb0 + &quadspi_bk1_io2_pa7 &quadspi_bk1_io3_pa6 + &quadspi_bk1_ncs_pb11 &quadspi_clk_pa3>; + pinctrl-names = "default"; + + dmas = <&dma2 7 3 0x480>; /* channel 7 request 3 on DMA2 */ + dma-names = "tx_rx"; + + flash-id = <1>; + status = "okay"; + + mx25r6435: qspi-nor-flash@0 { + compatible = "st,stm32-qspi-nor"; + reg = <0>; + qspi-max-frequency = <8000000>; + size = ; /* 8 MBytes */ + status = "okay"; + spi-bus-width = <4>; + writeoc = "PP_1_4_4"; + }; +}; diff --git a/boards/arm/stm32l496g_disco/stm32l496g_disco.yaml b/boards/arm/stm32l496g_disco/stm32l496g_disco.yaml index be69f323831a..edf64edc3a45 100644 --- a/boards/arm/stm32l496g_disco/stm32l496g_disco.yaml +++ b/boards/arm/stm32l496g_disco/stm32l496g_disco.yaml @@ -17,3 +17,4 @@ supported: - counter - sdhc - adc + - qspi From 529f9ed0c2a508d20d0d57e75362aa0107871bf3 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 29 Mar 2023 10:23:12 +0200 Subject: [PATCH 0560/2042] boards: arm: stm32l475 disco yaml has the quadspi NOR This commit adds the support of the quadspi to the board definition .yaml file Signed-off-by: Francois Ramu --- boards/arm/disco_l475_iot1/disco_l475_iot1.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.yaml b/boards/arm/disco_l475_iot1/disco_l475_iot1.yaml index cfe2b7bf06b2..4bbb0cfe33f4 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.yaml +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.yaml @@ -23,6 +23,7 @@ supported: - watchdog - adc - dac + - qspi - dma ram: 96 flash: 1024 From 7f8342775fee9e59060f24857ea0f8d02a9daee6 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 28 Mar 2023 09:54:18 +0200 Subject: [PATCH 0561/2042] samples: drivers: jesd216 jedec ID and SFDP from quad-flash This adds the support jedec configuration to run the jedec sample application. So target board can display the content of the quad-NOR flash. Signed-off-by: Francois Ramu --- samples/drivers/jesd216/boards/disco_l475_iot1.conf | 3 +++ samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf | 3 +++ samples/drivers/jesd216/boards/stm32l496g_disco.conf | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 samples/drivers/jesd216/boards/disco_l475_iot1.conf create mode 100644 samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf create mode 100644 samples/drivers/jesd216/boards/stm32l496g_disco.conf diff --git a/samples/drivers/jesd216/boards/disco_l475_iot1.conf b/samples/drivers/jesd216/boards/disco_l475_iot1.conf new file mode 100644 index 000000000000..dbb7255d188a --- /dev/null +++ b/samples/drivers/jesd216/boards/disco_l475_iot1.conf @@ -0,0 +1,3 @@ +CONFIG_FLASH_STM32_QSPI=y +CONFIG_SPI_NOR_SFDP_RUNTIME=y +CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf b/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf new file mode 100644 index 000000000000..dbb7255d188a --- /dev/null +++ b/samples/drivers/jesd216/boards/stm32h747i_disco_m7.conf @@ -0,0 +1,3 @@ +CONFIG_FLASH_STM32_QSPI=y +CONFIG_SPI_NOR_SFDP_RUNTIME=y +CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/stm32l496g_disco.conf b/samples/drivers/jesd216/boards/stm32l496g_disco.conf new file mode 100644 index 000000000000..dbb7255d188a --- /dev/null +++ b/samples/drivers/jesd216/boards/stm32l496g_disco.conf @@ -0,0 +1,3 @@ +CONFIG_FLASH_STM32_QSPI=y +CONFIG_SPI_NOR_SFDP_RUNTIME=y +CONFIG_SPI_NOR=n From e216dcfc3d430a42bf71d97a5f60d8756d67ec7a Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Wed, 15 Mar 2023 13:26:15 +0100 Subject: [PATCH 0562/2042] samples: drivers: quadspi flash of the stm32 boards This enables the samples/drivers/spi_flash on quad-spi flash to run on any stm32 target with external NOR quad flash. The SPI_FLASH_MULTI_SECTOR_TEST test case is possible with quadspi too. Signed-off-by: Francois Ramu --- samples/drivers/spi_flash/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index 7675e25e776e..059dc7d5a274 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -26,7 +26,7 @@ #endif #define SPI_FLASH_SECTOR_SIZE 4096 -#if defined CONFIG_FLASH_STM32_OSPI +#if defined(CONFIG_FLASH_STM32_OSPI) || defined(CONFIG_FLASH_STM32_QSPI) #define SPI_FLASH_MULTI_SECTOR_TEST #endif From c88a9ef272d6a099fa72de8d6aaeb23bc1a37d12 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 5 Jun 2023 17:17:40 +0200 Subject: [PATCH 0563/2042] segger: rtt: disable unsupported shell/log features The RTT backend of the shell does not support several of the more advanced terminal features. This commit proposes to inactivate these features by default when RTT is selected as shell backend. Signed-off-by: Florian Grandel --- modules/segger/Kconfig | 1 + subsys/logging/backends/Kconfig.uart | 2 +- subsys/shell/Kconfig | 4 ++-- subsys/shell/backends/Kconfig.backends | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/segger/Kconfig b/modules/segger/Kconfig index 665e3ff716cf..1324df8cb81f 100644 --- a/modules/segger/Kconfig +++ b/modules/segger/Kconfig @@ -38,6 +38,7 @@ config SEGGER_RTT_BUFFER_SIZE_UP config SEGGER_RTT_BUFFER_SIZE_DOWN int "Size of the buffer for terminal input of target, from host" + default 32 if SHELL_BACKEND_RTT default 16 config SEGGER_RTT_PRINTF_BUFFER_SIZE diff --git a/subsys/logging/backends/Kconfig.uart b/subsys/logging/backends/Kconfig.uart index 43b544ab66ae..8c75df0ff477 100644 --- a/subsys/logging/backends/Kconfig.uart +++ b/subsys/logging/backends/Kconfig.uart @@ -4,7 +4,7 @@ config LOG_BACKEND_UART bool "UART backend" depends on UART_CONSOLE - default y if !SHELL_BACKEND_SERIAL + default y if !SHELL_BACKEND_SERIAL && !SHELL_BACKEND_RTT select LOG_OUTPUT help When enabled backend is using UART to output logs. diff --git a/subsys/shell/Kconfig b/subsys/shell/Kconfig index d155622e7bbf..342608a76a0f 100644 --- a/subsys/shell/Kconfig +++ b/subsys/shell/Kconfig @@ -90,7 +90,7 @@ config SHELL_ARGC_MAX config SHELL_TAB bool "The Tab button support in shell" - default y if !SHELL_MINIMAL + default y if !SHELL_MINIMAL && !SHELL_BACKEND_RTT help Enable using the Tab button in the shell. The button can be used for prompting commands, or for autocompletion. @@ -125,7 +125,7 @@ config SHELL_START_OBSCURED config SHELL_VT100_COMMANDS bool "VT100 commands in shell" - default y + default y if !SHELL_BACKEND_RTT help Enables VT100 commands in shell (e.g. cursor position, clear screen etc.). diff --git a/subsys/shell/backends/Kconfig.backends b/subsys/shell/backends/Kconfig.backends index af5291545ef5..0423d57d0b38 100644 --- a/subsys/shell/backends/Kconfig.backends +++ b/subsys/shell/backends/Kconfig.backends @@ -16,6 +16,8 @@ DT_CHOSEN_Z_SHELL_UART := zephyr,shell-uart config SHELL_BACKEND_SERIAL bool "Serial backend" + # Serial (UART) requires interrupts and the RTT backend cannot be used from an ISR context. + default n if SHELL_BACKEND_RTT default "$(dt_chosen_enabled,$(DT_CHOSEN_Z_SHELL_UART))" if HAS_DTS default y if !HAS_DTS select SERIAL From c62e55973b637c21e02a191005d57c5326b9b871 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 23 Jun 2023 12:08:55 +0000 Subject: [PATCH 0564/2042] intel_adsp: remove deprecated cache macros SOC_DCACHE_FLUSH and SOC_DCACHE_INVALIDATE are not being used anywhere. Signed-off-by: Anas Nashif --- soc/xtensa/intel_adsp/common/include/soc.h | 4 ---- soc/xtensa/nxp_adsp/common/include/adsp/cache.h | 6 ------ 2 files changed, 10 deletions(-) diff --git a/soc/xtensa/intel_adsp/common/include/soc.h b/soc/xtensa/intel_adsp/common/include/soc.h index e2f74b3db4a7..014ba18e4349 100644 --- a/soc/xtensa/intel_adsp/common/include/soc.h +++ b/soc/xtensa/intel_adsp/common/include/soc.h @@ -27,10 +27,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 SOC_DCACHE_FLUSH(addr, size) \ - sys_cache_data_flush_range((addr), (size)) -#define SOC_DCACHE_INVALIDATE(addr, size) \ - sys_cache_data_invd_range((addr), (size)) #define z_soc_cached_ptr(p) arch_xtensa_cached_ptr(p) #define z_soc_uncached_ptr(p) arch_xtensa_uncached_ptr(p) diff --git a/soc/xtensa/nxp_adsp/common/include/adsp/cache.h b/soc/xtensa/nxp_adsp/common/include/adsp/cache.h index 9071af5c9a01..067c08901403 100644 --- a/soc/xtensa/nxp_adsp/common/include/adsp/cache.h +++ b/soc/xtensa/nxp_adsp/common/include/adsp/cache.h @@ -9,10 +9,4 @@ #include -/* Macros for data cache operations */ -#define SOC_DCACHE_FLUSH(addr, size) \ - sys_cache_data_flush_range((addr), (size)) -#define SOC_DCACHE_INVALIDATE(addr, size) \ - sys_cache_data_invd_range((addr), (size)) - #endif From 3b6409e34e52596317b5489a68f7c40d2d2d7f5b Mon Sep 17 00:00:00 2001 From: Ethan Duckett Date: Fri, 23 Jun 2023 14:22:26 +0100 Subject: [PATCH 0565/2042] dts: stm32g4: fix clk-lse driving-capability Altered LSE in stm32g4.dtsi to same value as other ST DTS files. Signed-off-by: Ethan Duckett --- dts/arm/st/g4/stm32g4.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index f08b4c2c0126..e3dccb86db8b 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -62,8 +62,9 @@ clk_lse: clk-lse { #clock-cells = <0>; - compatible = "fixed-clock"; + compatible = "st,stm32-lse-clock"; clock-frequency = <32768>; + driving-capability = <0>; status = "disabled"; }; From e484ab2fa8cbff320c907e21f079cf70c1d1ec29 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Tue, 6 Jun 2023 11:27:15 +0100 Subject: [PATCH 0566/2042] boards: shields: npm1300_ek: Specify regulator initial modes The npm1300_ek overlay has been updated to explictly specify the initialisation modes for the dual purpose LDO / LDSW outputs. Signed-off-by: Andy Sinclair --- boards/shields/npm1300_ek/npm1300_ek.overlay | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/shields/npm1300_ek/npm1300_ek.overlay b/boards/shields/npm1300_ek/npm1300_ek.overlay index 8c4c26321719..8a0c53f2397e 100644 --- a/boards/shields/npm1300_ek/npm1300_ek.overlay +++ b/boards/shields/npm1300_ek/npm1300_ek.overlay @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &arduino_i2c { npm1300_ek_pmic: pmic@6b { compatible = "nordic,npm1300"; @@ -37,12 +39,14 @@ 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>; }; }; From 8e5cae7fa3be80534549d8ed30d2e009346320ab Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 22 Jun 2023 00:32:38 -0600 Subject: [PATCH 0567/2042] ztest: Allow 'before' functions to run in privilaged mode When writing a test suite, it's more common to want the 'before' hook to run in privilaged mode, even when the test is run in userspace. Reconfigure ztest to first run the test thread callback in privilaged mode and only enter userspace after the test rule and suite's 'before' functions ran. Signed-off-by: Yuval Peress --- .../ztest/include/zephyr/ztest_test_new.h | 46 ++++++ subsys/testsuite/ztest/src/ztest_new.c | 99 ++++++------ .../subsys/rtio/rtio_api/src/test_rtio_api.c | 147 +++--------------- 3 files changed, 124 insertions(+), 168 deletions(-) diff --git a/subsys/testsuite/ztest/include/zephyr/ztest_test_new.h b/subsys/testsuite/ztest/include/zephyr/ztest_test_new.h index 995171d4f88d..30073b4402d7 100644 --- a/subsys/testsuite/ztest/include/zephyr/ztest_test_new.h +++ b/subsys/testsuite/ztest/include/zephyr/ztest_test_new.h @@ -235,6 +235,32 @@ extern struct ztest_suite_node _ztest_suite_node_list_end[]; */ void ztest_run_all(const void *state); +/** + * The result of the current running test. It's possible that the setup function sets the result + * to ZTEST_RESULT_SUITE_* which will apply the failure/skip to every test in the suite. + */ +enum ztest_result { + ZTEST_RESULT_PENDING, + ZTEST_RESULT_PASS, + ZTEST_RESULT_FAIL, + ZTEST_RESULT_SKIP, + ZTEST_RESULT_SUITE_SKIP, + ZTEST_RESULT_SUITE_FAIL, +}; +/** + * Each enum member represents a distinct phase of execution for the test binary. + * TEST_PHASE_FRAMEWORK is active when internal ztest code is executing; the rest refer to + * corresponding phases of user test code. + */ +enum ztest_phase { + TEST_PHASE_SETUP, + TEST_PHASE_BEFORE, + TEST_PHASE_TEST, + TEST_PHASE_AFTER, + TEST_PHASE_TEARDOWN, + TEST_PHASE_FRAMEWORK, +}; + /** * Run the registered unit tests which return true from their predicate function. * @@ -251,6 +277,26 @@ static inline int ztest_run_test_suites(const void *state) #else __syscall int ztest_run_test_suites(const void *state); +#endif + +#ifdef ZTEST_UNITTEST +void z_impl___ztest_set_test_result(enum ztest_result new_result); +static inline void __ztest_set_test_result(enum ztest_result new_result) +{ + z_impl___ztest_set_test_result(new_result); +} + +void z_impl___ztest_set_test_phase(enum ztest_phase new_phase); +static inline void __ztest_set_test_phase(enum ztest_phase new_phase) +{ + z_impl___ztest_set_test_phase(new_phase); +} +#else +__syscall void __ztest_set_test_result(enum ztest_result new_result); +__syscall void __ztest_set_test_phase(enum ztest_phase new_phase); +#endif + +#ifndef ZTEST_UNITTEST #include #endif diff --git a/subsys/testsuite/ztest/src/ztest_new.c b/subsys/testsuite/ztest/src/ztest_new.c index f8419e899d9f..6119a6905e0d 100644 --- a/subsys/testsuite/ztest/src/ztest_new.c +++ b/subsys/testsuite/ztest/src/ztest_new.c @@ -32,21 +32,6 @@ static bool failed_expectation; /* ZTEST_DMEM and ZTEST_BMEM are used for the application shared memory test */ -/** - * @brief Each enum member represents a distinct phase of execution for the - * test binary. TEST_PHASE_FRAMEWORK is active when internal ztest code - * is executing; the rest refer to corresponding phases of user test - * code. - */ -enum ztest_phase { - TEST_PHASE_SETUP, - TEST_PHASE_BEFORE, - TEST_PHASE_TEST, - TEST_PHASE_AFTER, - TEST_PHASE_TEARDOWN, - TEST_PHASE_FRAMEWORK -}; - /** * @brief The current status of the test binary */ @@ -222,18 +207,10 @@ __maybe_unused static void run_test_rules(bool is_before, struct ztest_unit_test static void run_test_functions(struct ztest_suite_node *suite, struct ztest_unit_test *test, void *data) { - phase = TEST_PHASE_TEST; + __ztest_set_test_phase(TEST_PHASE_TEST); test->test(data); } -enum ztest_result { - ZTEST_RESULT_PENDING, - ZTEST_RESULT_PASS, - ZTEST_RESULT_FAIL, - ZTEST_RESULT_SKIP, - ZTEST_RESULT_SUITE_SKIP, - ZTEST_RESULT_SUITE_FAIL, -}; 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) @@ -393,7 +370,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test int ret = TC_PASS; TC_START(test->name); - phase = TEST_PHASE_BEFORE; + __ztest_set_test_phase(TEST_PHASE_BEFORE); if (test_result == ZTEST_RESULT_SUITE_FAIL) { ret = TC_FAIL; @@ -426,14 +403,14 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test ret = TC_FAIL; } - phase = TEST_PHASE_AFTER; + __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); } - phase = TEST_PHASE_FRAMEWORK; + __ztest_set_test_phase(TEST_PHASE_FRAMEWORK); ret |= cleanup_test(test); ret = get_final_test_result(test, ret); @@ -470,11 +447,11 @@ void ztest_test_fail(void) { switch (phase) { case TEST_PHASE_SETUP: - test_result = ZTEST_RESULT_SUITE_FAIL; + __ztest_set_test_result(ZTEST_RESULT_SUITE_FAIL); break; case TEST_PHASE_BEFORE: case TEST_PHASE_TEST: - test_result = ZTEST_RESULT_FAIL; + __ztest_set_test_result(ZTEST_RESULT_FAIL); test_finalize(); break; default: @@ -489,7 +466,7 @@ void ztest_test_pass(void) { switch (phase) { case TEST_PHASE_TEST: - test_result = ZTEST_RESULT_PASS; + __ztest_set_test_result(ZTEST_RESULT_PASS); test_finalize(); break; default: @@ -506,11 +483,11 @@ void ztest_test_skip(void) { switch (phase) { case TEST_PHASE_SETUP: - test_result = ZTEST_RESULT_SUITE_SKIP; + __ztest_set_test_result(ZTEST_RESULT_SUITE_SKIP); break; case TEST_PHASE_BEFORE: case TEST_PHASE_TEST: - test_result = ZTEST_RESULT_SKIP; + __ztest_set_test_result(ZTEST_RESULT_SKIP); test_finalize(); break; default: @@ -542,14 +519,20 @@ 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; - 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) || !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); - test_result = ZTEST_RESULT_PASS; + __ztest_set_test_result(ZTEST_RESULT_PASS); } static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test, void *data) @@ -561,7 +544,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test #endif TC_START(test->name); - phase = TEST_PHASE_BEFORE; + __ztest_set_test_phase(TEST_PHASE_BEFORE); /* If the suite's setup function marked us as skipped, don't bother * running the tests. @@ -572,7 +555,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test K_THREAD_STACK_SIZEOF(ztest_thread_stack), (k_thread_entry_t)test_cb, suite, test, data, CONFIG_ZTEST_THREAD_PRIORITY, - test->thread_options | K_INHERIT_PERMS, K_FOREVER); + K_INHERIT_PERMS, K_FOREVER); k_thread_access_grant(&ztest_thread, suite, test, suite->stats); if (test->name != NULL) { @@ -586,7 +569,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test } } else if (test_result != ZTEST_RESULT_SUITE_SKIP && test_result != ZTEST_RESULT_SUITE_FAIL) { - test_result = ZTEST_RESULT_PENDING; + __ztest_set_test_result(ZTEST_RESULT_PENDING); get_start_time_cyc(); run_test_rules(/*is_before=*/true, test, data); if (suite->before) { @@ -595,7 +578,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test run_test_functions(suite, test, data); } - phase = TEST_PHASE_AFTER; + __ztest_set_test_phase(TEST_PHASE_AFTER); if (suite->after != NULL) { suite->after(data); } @@ -606,7 +589,7 @@ static int run_test(struct ztest_suite_node *suite, struct ztest_unit_test *test test->stats->duration_worst_ms = tc_spend_time; } - phase = TEST_PHASE_FRAMEWORK; + __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) && @@ -714,11 +697,11 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) TC_SUITE_START(suite->name); current_test_failed_assumption = false; - test_result = ZTEST_RESULT_PENDING; - phase = TEST_PHASE_SETUP; + __ztest_set_test_result(ZTEST_RESULT_PENDING); + __ztest_set_test_phase(TEST_PHASE_SETUP); #ifndef KERNEL if (setjmp(test_suite_fail)) { - test_result = ZTEST_RESULT_SUITE_FAIL; + __ztest_set_test_result(ZTEST_RESULT_SUITE_FAIL); } #endif if (test_result != ZTEST_RESULT_SUITE_FAIL && suite->setup != NULL) { @@ -789,7 +772,7 @@ static int z_ztest_run_test_suite_ptr(struct ztest_suite_node *suite) } TC_SUITE_END(suite->name, (fail > 0 ? TC_FAIL : TC_PASS)); - phase = TEST_PHASE_TEARDOWN; + __ztest_set_test_phase(TEST_PHASE_TEARDOWN); if (suite->teardown != NULL) { suite->teardown(data); } @@ -1002,6 +985,30 @@ int z_impl_ztest_run_test_suites(const void *state) 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) +{ + 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; diff --git a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c index 78907e18a550..648ce1704d11 100644 --- a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c +++ b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c @@ -221,7 +221,7 @@ RTIO_BMEM uint8_t syscall_bufs[4]; RTIO_DEFINE(r_syscall, SQE_POOL_SIZE, CQE_POOL_SIZE); RTIO_IODEV_TEST_DEFINE(iodev_test_syscall); -void rtio_syscall_test(void *p1, void *p2, void *p3) +ZTEST_USER(rtio_api, test_rtio_syscalls) { int res; struct rtio_sqe sqe = {0}; @@ -251,24 +251,6 @@ void rtio_syscall_test(void *p1, void *p2, void *p3) } } -#ifdef CONFIG_USERSPACE -ZTEST(rtio_api, test_rtio_syscalls_usermode) -{ - - TC_PRINT("syscalls from user mode test\n"); - TC_PRINT("test iodev init\n"); - rtio_iodev_test_init(&iodev_test_syscall); - TC_PRINT("mem domain add current\n"); - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - TC_PRINT("rtio access grant\n"); - rtio_access_grant(&r_syscall, k_current_get()); - TC_PRINT("rtio iodev access grant, ptr %p\n", &iodev_test_syscall); - k_object_access_grant(&iodev_test_syscall, k_current_get()); - TC_PRINT("user mode enter\n"); - k_thread_user_mode_enter(rtio_syscall_test, NULL, NULL, NULL); -} -#endif /* CONFIG_USERSPACE */ - RTIO_BMEM uint8_t mempool_data[MEM_BLK_SIZE]; static void test_rtio_simple_mempool_(struct rtio *r, int run_count) @@ -311,30 +293,11 @@ static void test_rtio_simple_mempool_(struct rtio *r, int run_count) rtio_release_buffer(r, buffer, buffer_len); } -static void rtio_simple_mempool_test(void *a, void *b, void *c) +ZTEST_USER(rtio_api, test_rtio_simple_mempool) { - ARG_UNUSED(a); - ARG_UNUSED(b); - ARG_UNUSED(c); - - TC_PRINT("rtio simple mempool from thread %p\n", k_current_get()); for (int i = 0; i < TEST_REPEATS * 2; i++) { test_rtio_simple_mempool_(&r_simple, i); } - -} - -ZTEST(rtio_api, test_rtio_simple_mempool) -{ - rtio_iodev_test_init(&iodev_test_simple); -#ifdef CONFIG_USERSPACE - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - rtio_access_grant(&r_simple, k_current_get()); - k_object_access_grant(&iodev_test_simple, k_current_get()); - k_thread_user_mode_enter(rtio_simple_mempool_test, NULL, NULL, NULL); -#else - rtio_simple_mempool_test(NULL, NULL, NULL); -#endif } static void test_rtio_simple_cancel_(struct rtio *r) @@ -365,30 +328,13 @@ static void test_rtio_simple_cancel_(struct rtio *r) } } -static void rtio_simple_cancel_test(void *a, void *b, void *c) +ZTEST_USER(rtio_api, test_rtio_simple_cancel) { - ARG_UNUSED(a); - ARG_UNUSED(b); - ARG_UNUSED(c); - for (int i = 0; i < TEST_REPEATS; i++) { test_rtio_simple_cancel_(&r_simple); } } -ZTEST(rtio_api, test_rtio_simple_cancel) -{ - rtio_iodev_test_init(&iodev_test_simple); -#ifdef CONFIG_USERSPACE - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - rtio_access_grant(&r_simple, k_current_get()); - k_object_access_grant(&iodev_test_simple, k_current_get()); - k_thread_user_mode_enter(rtio_simple_cancel_test, NULL, NULL, NULL); -#else - rtio_simple_cancel_test(NULL, NULL, NULL); -#endif -} - static void test_rtio_chain_cancel_(struct rtio *r) { struct rtio_sqe sqe[SQE_POOL_SIZE]; @@ -396,14 +342,21 @@ static void test_rtio_chain_cancel_(struct rtio *r) struct rtio_sqe *handle; /* Prepare the chain */ + TC_PRINT("1\n"); + k_msleep(20); rtio_sqe_prep_nop(&sqe[0], (struct rtio_iodev *)&iodev_test_simple, NULL); rtio_sqe_prep_nop(&sqe[1], (struct rtio_iodev *)&iodev_test_simple, NULL); sqe[0].flags |= RTIO_SQE_CHAINED; /* Copy the chain */ + TC_PRINT("2\n"); + k_msleep(20); rtio_sqe_copy_in_get_handles(r, sqe, &handle, 2); + TC_PRINT("3\n"); + k_msleep(20); rtio_sqe_cancel(handle); TC_PRINT("Submitting 2 to RTIO\n"); + k_msleep(20); rtio_submit(r, 0); /* Check that we don't get a CQE */ @@ -422,30 +375,15 @@ static void test_rtio_chain_cancel_(struct rtio *r) } } -static void rtio_chain_cancel_test(void *a, void *b, void *c) +ZTEST_USER(rtio_api, test_rtio_chain_cancel) { - ARG_UNUSED(a); - ARG_UNUSED(b); - ARG_UNUSED(c); - + TC_PRINT("start test\n"); + k_msleep(20); for (int i = 0; i < TEST_REPEATS; i++) { test_rtio_chain_cancel_(&r_simple); } } -ZTEST(rtio_api, test_rtio_chain_cancel) -{ - rtio_iodev_test_init(&iodev_test_simple); -#ifdef CONFIG_USERSPACE - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - rtio_access_grant(&r_simple, k_current_get()); - k_object_access_grant(&iodev_test_simple, k_current_get()); - k_thread_user_mode_enter(rtio_chain_cancel_test, NULL, NULL, NULL); -#else - rtio_chain_cancel_test(NULL, NULL, NULL); -#endif -} - static void test_rtio_transaction_cancel_(struct rtio *r) { struct rtio_sqe sqe[SQE_POOL_SIZE]; @@ -479,30 +417,13 @@ static void test_rtio_transaction_cancel_(struct rtio *r) } } -static void rtio_transaction_cancel_test(void *a, void *b, void *c) +ZTEST_USER(rtio_api, test_rtio_transaction_cancel) { - ARG_UNUSED(a); - ARG_UNUSED(b); - ARG_UNUSED(c); - for (int i = 0; i < TEST_REPEATS; i++) { test_rtio_transaction_cancel_(&r_simple); } } -ZTEST(rtio_api, test_rtio_transaction_cancel) -{ - rtio_iodev_test_init(&iodev_test_simple); -#ifdef CONFIG_USERSPACE - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - rtio_access_grant(&r_simple, k_current_get()); - k_object_access_grant(&iodev_test_simple, k_current_get()); - k_thread_user_mode_enter(rtio_transaction_cancel_test, NULL, NULL, NULL); -#else - rtio_transaction_cancel_test(NULL, NULL, NULL); -#endif -} - static inline void test_rtio_simple_multishot_(struct rtio *r, int idx) { int res; @@ -558,41 +479,13 @@ static inline void test_rtio_simple_multishot_(struct rtio *r, int idx) } } -static void rtio_simple_multishot_test(void *a, void *b, void *c) +ZTEST_USER(rtio_api, test_rtio_multishot) { - ARG_UNUSED(a); - ARG_UNUSED(b); - ARG_UNUSED(c); - for (int i = 0; i < TEST_REPEATS; i++) { test_rtio_simple_multishot_(&r_simple, i); } } -ZTEST(rtio_api, test_rtio_multishot) -{ - rtio_iodev_test_init(&iodev_test_simple); -#ifdef CONFIG_USERSPACE - k_mem_domain_add_thread(&rtio_domain, k_current_get()); - rtio_access_grant(&r_simple, k_current_get()); - k_object_access_grant(&iodev_test_simple, k_current_get()); - k_thread_user_mode_enter(rtio_simple_multishot_test, NULL, NULL, NULL); -#else - rtio_simple_multishot_test(NULL, NULL, NULL); -#endif -} - - -ZTEST(rtio_api, test_rtio_syscalls) -{ - TC_PRINT("test iodev init\n"); - rtio_iodev_test_init(&iodev_test_syscall); - TC_PRINT("syscalls from kernel mode\n"); - for (int i = 0; i < TEST_REPEATS; i++) { - rtio_syscall_test(NULL, NULL, NULL); - } -} - RTIO_DEFINE(r_transaction, SQE_POOL_SIZE, CQE_POOL_SIZE); RTIO_IODEV_TEST_DEFINE(iodev_test_transaction0); @@ -739,6 +632,16 @@ static void rtio_api_before(void *a) while (rtio_cqe_copy_out(r, &cqe, 1, K_MSEC(15))) { } } + + rtio_iodev_test_init(&iodev_test_simple); + rtio_iodev_test_init(&iodev_test_syscall); +#ifdef CONFIG_USERSPACE + k_mem_domain_add_thread(&rtio_domain, k_current_get()); + rtio_access_grant(&r_simple, k_current_get()); + rtio_access_grant(&r_syscall, k_current_get()); + k_object_access_grant(&iodev_test_simple, k_current_get()); + k_object_access_grant(&iodev_test_syscall, k_current_get()); +#endif } ZTEST_SUITE(rtio_api, NULL, rtio_api_setup, rtio_api_before, NULL, NULL); From 10be3a12634d7536a6f8532647d9d6c663ef3828 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 22 Jun 2023 15:30:25 -0600 Subject: [PATCH 0568/2042] rtio: Implement a NO_RESPONSE flag for SQEs When added, the SQE's completion will not generate a CQE. Fixes #59284 Signed-off-by: Yuval Peress --- include/zephyr/rtio/rtio.h | 39 ++++++++++--------- subsys/rtio/rtio_executor.c | 2 +- .../subsys/rtio/rtio_api/src/test_rtio_api.c | 21 ++++++++++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index c017d06ad883..8845fa097faf 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -114,25 +114,6 @@ extern "C" { #define RTIO_SQE_TRANSACTION BIT(1) -/** - * @brief Equivalent to the I2C_MSG_STOP flag - */ -#define RTIO_IODEV_I2C_STOP BIT(0) - -/** - * @brief Equivalent to the I2C_MSG_RESTART flag - */ -#define RTIO_IODEV_I2C_RESTART BIT(1) - -/** - * @brief Equivalent to the I2C_MSG_10_BITS - */ -#define RTIO_IODEV_I2C_10_BITS BIT(2) - -/** - * @brief Equivalent to the I2C_MSG_ADDR_10_BITS - */ - /** * @brief The buffer should be allocated by the RTIO mempool * @@ -160,6 +141,11 @@ extern "C" { */ #define RTIO_SQE_MULTISHOT BIT(4) +/** + * @brief The SQE does not produce a CQE. + */ +#define RTIO_SQE_NO_RESPONSE BIT(5) + /** * @} */ @@ -212,6 +198,21 @@ extern "C" { * @} */ +/** + * @brief Equivalent to the I2C_MSG_STOP flag + */ +#define RTIO_IODEV_I2C_STOP BIT(0) + +/** + * @brief Equivalent to the I2C_MSG_RESTART flag + */ +#define RTIO_IODEV_I2C_RESTART BIT(1) + +/** + * @brief Equivalent to the I2C_MSG_ADDR_10_BITS + */ +#define RTIO_IODEV_I2C_10_BITS BIT(2) + /** @cond ignore */ struct rtio; struct rtio_cqe; diff --git a/subsys/rtio/rtio_executor.c b/subsys/rtio/rtio_executor.c index 91f2fdae219d..0f84d5aabf4d 100644 --- a/subsys/rtio/rtio_executor.c +++ b/subsys/rtio/rtio_executor.c @@ -149,7 +149,7 @@ static inline void rtio_executor_done(struct rtio_iodev_sqe *iodev_sqe, int resu /* SQE is no longer needed, release it */ rtio_sqe_pool_free(r->sqe_pool, curr); } - if (!is_canceled) { + if (!is_canceled && FIELD_GET(RTIO_SQE_NO_RESPONSE, sqe_flags) == 0) { /* Request was not canceled, generate a CQE */ rtio_cqe_submit(r, result, userdata, cqe_flags); } diff --git a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c index 648ce1704d11..626f5e3abda8 100644 --- a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c +++ b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c @@ -77,6 +77,27 @@ ZTEST(rtio_api, test_rtio_simple) } } +ZTEST(rtio_api, test_rtio_no_response) +{ + int res; + uintptr_t userdata[2] = {0, 1}; + struct rtio_sqe *sqe; + struct rtio_cqe cqe; + + rtio_iodev_test_init(&iodev_test_simple); + + sqe = rtio_sqe_acquire(&r_simple); + zassert_not_null(sqe, "Expected a valid sqe"); + rtio_sqe_prep_nop(sqe, (struct rtio_iodev *)&iodev_test_simple, &userdata[0]); + sqe->flags |= RTIO_SQE_NO_RESPONSE; + + res = rtio_submit(&r_simple, 0); + zassert_ok(res, "Should return ok from rtio_execute"); + + res = rtio_cqe_copy_out(&r_simple, &cqe, 1, K_MSEC(500)); + zassert_equal(0, res, "Expected no CQEs"); +} + RTIO_DEFINE(r_chain, SQE_POOL_SIZE, CQE_POOL_SIZE); RTIO_IODEV_TEST_DEFINE(iodev_test_chain0); From ea42995f2ea2c3de5662d8560fdb9bba0652bbc0 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Fri, 9 Jun 2023 21:59:05 +0100 Subject: [PATCH 0569/2042] dts: riscv: introduce PolarFire SoC I2C interface Add support for Microchip's PolarFire SoC I2C interface Signed-off-by: Conor Paxton --- dts/bindings/i2c/microchip,mpfs-i2c.yaml | 25 ++++++++++++++++++++++++ dts/riscv/microchip/mpfs-icicle.dtsi | 22 +++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 dts/bindings/i2c/microchip,mpfs-i2c.yaml diff --git a/dts/bindings/i2c/microchip,mpfs-i2c.yaml b/dts/bindings/i2c/microchip,mpfs-i2c.yaml new file mode 100644 index 000000000000..36d0b00b7d8a --- /dev/null +++ b/dts/bindings/i2c/microchip,mpfs-i2c.yaml @@ -0,0 +1,25 @@ +# +# Copyright (c) 2023 Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: + Microchip MPFS I2C Controller Device Tree Bindings + +compatible: "microchip,mpfs-i2c" + +include: i2c-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + clock-frequency: + description: | + Desired I2C bus clock frequency in Hz. As only Standard and Fast + modes are supported, possible values are 100000 and 400000. + enum: [100000, 400000] diff --git a/dts/riscv/microchip/mpfs-icicle.dtsi b/dts/riscv/microchip/mpfs-icicle.dtsi index 5b130413f63a..9c1d25161b5a 100644 --- a/dts/riscv/microchip/mpfs-icicle.dtsi +++ b/dts/riscv/microchip/mpfs-icicle.dtsi @@ -233,5 +233,27 @@ ngpios = <32>; status = "disabled"; }; + + i2c0: i2c@2010a000 { + compatible = "microchip,mpfs-i2c"; + reg = <0x2010a000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <58 1>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@2010b000 { + compatible = "microchip,mpfs-i2c"; + reg = <0x2010b000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <61 1>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + status = "disabled"; + }; }; }; From a810d2793523725ddf26ac82471c7319dab02025 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Fri, 9 Jun 2023 22:02:06 +0100 Subject: [PATCH 0570/2042] drivers: i2c: add Microchip PolarFire SoC I2C driver This patch adds driver support for Microchip's PolarFire SoC I2C. This initial support implements the Controller API only. Signed-off-by: Conor Paxton --- drivers/i2c/CMakeLists.txt | 1 + drivers/i2c/Kconfig | 1 + drivers/i2c/Kconfig.mchp_mss | 11 + drivers/i2c/i2c_mchp_mss.c | 386 +++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 drivers/i2c/Kconfig.mchp_mss create mode 100644 drivers/i2c/i2c_mchp_mss.c diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 25e4b2349948..6362ae46ecd2 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -50,6 +50,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_ANDES_ATCIIC100 i2c_andes_atciic100.c) zephyr_library_sources_ifdef(CONFIG_I2C_SC18IM704 i2c_sc18im704.c) zephyr_library_sources_ifdef(CONFIG_I2C_SMARTBOND i2c_smartbond.c) zephyr_library_sources_ifdef(CONFIG_I2C_XILINX_AXI i2c_xilinx_axi.c) +zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.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 30fbcb6087a3..159cab781cc5 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -74,6 +74,7 @@ source "drivers/i2c/Kconfig.andes_atciic100" source "drivers/i2c/Kconfig.sc18im704" source "drivers/i2c/Kconfig.smartbond" source "drivers/i2c/Kconfig.xilinx_axi" +source "drivers/i2c/Kconfig.mchp_mss" config I2C_INIT_PRIORITY int "Init priority" diff --git a/drivers/i2c/Kconfig.mchp_mss b/drivers/i2c/Kconfig.mchp_mss new file mode 100644 index 000000000000..bde3cca7ac42 --- /dev/null +++ b/drivers/i2c/Kconfig.mchp_mss @@ -0,0 +1,11 @@ +# Microchip PolarFire SoC Icicle Kit I2C configuration options + +# Copyright (c) 2023 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config I2C_MCHP_MSS + bool "Microchip PolarFire SoC I2C driver" + default y + depends on DT_HAS_MICROCHIP_MPFS_I2C_ENABLED + help + Enable PolarFire SoC Icicle Kit I2C driver. diff --git a/drivers/i2c/i2c_mchp_mss.c b/drivers/i2c/i2c_mchp_mss.c new file mode 100644 index 000000000000..887579cf9a10 --- /dev/null +++ b/drivers/i2c/i2c_mchp_mss.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(i2c_mchp, CONFIG_I2C_LOG_LEVEL); + +#define DT_DRV_COMPAT microchip_mpfs_i2c + +#define CORE_I2C_CTRL (0x00) +#define CORE_I2C_STATUS (0x04) +#define CORE_I2C_DATA (0x08) +#define CORE_I2C_ADDR_0 (0x0C) +#define CORE_I2C_FREQ (0x14) +#define CORE_I2C_GLITCHREG (0x18) +#define CORE_I2C_ADDR_1 (0x1C) + +#define CTRL_CR0 BIT(0) +#define CTRL_CR1 BIT(1) +#define CTRL_AA BIT(2) +#define CTRL_SI BIT(3) +#define CTRL_STO BIT(4) +#define CTRL_STA BIT(5) +#define CTRL_ENS1 BIT(6) +#define CTRL_CR2 BIT(7) + +#define STATUS_M_START_SENT (0x08) +#define STATUS_M_REPEATED_START_SENT (0x10) +#define STATUS_M_SLAW_ACK (0x18) +#define STATUS_M_SLAW_NACK (0x20) +#define STATUS_M_TX_DATA_ACK (0x28) +#define STATUS_M_TX_DATA_NACK (0x30) +#define STATUS_M_ARB_LOST (0x38) +#define STATUS_M_SLAR_ACK (0x40) +#define STATUS_M_SLAR_NACK (0x48) +#define STATUS_M_RX_DATA_ACKED (0x50) +#define STATUS_M_RX_DATA_NACKED (0x58) +#define STATUS_S_SLAW_ACKED (0x60) +#define STATUS_S_ARB_LOST_SLAW_ACKED (0x68) +#define STATUS_S_GENERAL_CALL_ACKED (0x70) +#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED (0x78) +#define STATUS_S_RX_DATA_ACKED (0x80) +#define STATUS_S_RX_DATA_NACKED (0x88) +#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED (0x90) +#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED (0x98) +#define STATUS_S_RX_STOP (0xA0) +#define STATUS_S_SLAR_ACKED (0xA8) +#define STATUS_S_ARB_LOST_SLAR_ACKED (0xB0) +#define STATUS_S_TX_DATA_ACK (0xB8) +#define STATUS_S_TX_DATA_NACK (0xC0) +#define STATUS_LAST_DATA_ACK (0xC8) + +#define PCLK_DIV_960 (CTRL_CR2) +#define PCLK_DIV_256 (0) +#define PCLK_DIV_224 (CTRL_CR0) +#define PCLK_DIV_192 (CTRL_CR1) +#define PCLK_DIV_160 (CTRL_CR0 | CTRL_CR1) +#define PCLK_DIV_120 (CTRL_CR0 | CTRL_CR2) +#define PCLK_DIV_60 (CTRL_CR1 | CTRL_CR2) +#define BCLK_DIV_8 (CTRL_CR0 | CTRL_CR1 | CTRL_CR2) +#define CLK_MASK (CTRL_CR0 | CTRL_CR1 | CTRL_CR2) + +/* -- Transactions types -- */ +#define NO_TRANSACTION (0x00) +#define CONTROLLER_WRITE_TRANSACTION (0x01) +#define CONTROLLER_READ_TRANSACTION (0x02) +#define CONTROLLER_RANDOM_READ_TRANSACTION (0x03) +#define WRITE_TARGET_TRANSACTION (0x04) +#define READ_TARGET_TRANSACTION (0x05) + +#define MSS_I2C_RELEASE_BUS (0x00) +#define MSS_I2C_HOLD_BUS (0x01) +#define TARGET_ADDR_SHIFT (0x01) + +#define MSS_I2C_SUCCESS (0x00) +#define MSS_I2C_IN_PROGRESS (0x01) +#define MSS_I2C_FAILED (0x02) +#define MSS_I2C_TIMED_OUT (0x03) + +struct mss_i2c_config { + uint32_t clock_freq; + uintptr_t i2c_base_addr; + uint32_t i2c_irq_base; +}; + +struct mss_i2c_data { + uint8_t ser_address; + uint8_t target_addr; + uint8_t options; + uint8_t transaction; + const uint8_t *controller_tx_buffer; + uint16_t controller_tx_size; + uint16_t controller_tx_idx; + uint8_t dir; + uint8_t *controller_rx_buffer; + uint16_t controller_rx_size; + uint16_t controller_rx_idx; + atomic_t controller_status; + uint32_t controller_timeout_ms; + const uint8_t *target_tx_buffer; + uint16_t target_tx_size; + uint16_t target_tx_idx; + uint8_t *target_rx_buffer; + uint16_t target_rx_size; + uint16_t target_rx_idx; + atomic_t target_status; + uint8_t target_mem_offset_length; + uint8_t is_target_enabled; + uint8_t bus_status; + uint8_t is_transaction_pending; + uint8_t pending_transaction; + + sys_slist_t cb; +}; + + +static int mss_i2c_configure(const struct device *dev, uint32_t dev_config_raw) +{ + const struct mss_i2c_config *cfg = dev->config; + + uint8_t ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + switch (I2C_SPEED_GET(dev_config_raw)) { + case I2C_SPEED_STANDARD: + sys_write8((ctrl | PCLK_DIV_960), cfg->i2c_base_addr + CORE_I2C_CTRL); + break; + case I2C_SPEED_FAST: + sys_write8((ctrl | PCLK_DIV_256), cfg->i2c_base_addr + CORE_I2C_CTRL); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mss_wait_complete(const struct device *dev) +{ + struct mss_i2c_data *const data = dev->data; + atomic_t i2c_status = 0; + + do { + i2c_status = atomic_get(&data->controller_status); + } while (i2c_status == MSS_I2C_IN_PROGRESS); + + return i2c_status; +} + +static int mss_i2c_read(const struct device *dev, uint8_t serial_addr, uint8_t *read_buffer, + uint32_t read_size) +{ + struct mss_i2c_data *const data = dev->data; + const struct mss_i2c_config *cfg = dev->config; + + uint8_t ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + data->target_addr = serial_addr << TARGET_ADDR_SHIFT; + data->pending_transaction = CONTROLLER_READ_TRANSACTION; + data->dir = I2C_MSG_READ; + data->controller_rx_buffer = read_buffer; + data->controller_rx_size = read_size; + data->controller_rx_idx = 0u; + + sys_write8((ctrl | CTRL_STA), cfg->i2c_base_addr + CORE_I2C_CTRL); + + return 0; +} + +static int mss_i2c_write(const struct device *dev, uint8_t serial_addr, uint8_t *tx_buffer, + uint32_t tx_num_write) +{ + struct mss_i2c_data *const data = dev->data; + const struct mss_i2c_config *cfg = dev->config; + uint8_t ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + atomic_t target_status = data->target_status; + + if (data->transaction == NO_TRANSACTION) { + data->transaction = CONTROLLER_WRITE_TRANSACTION; + } + + data->pending_transaction = CONTROLLER_WRITE_TRANSACTION; + data->target_addr = serial_addr << TARGET_ADDR_SHIFT; + data->dir = I2C_MSG_WRITE; + data->controller_tx_buffer = tx_buffer; + data->controller_tx_size = tx_num_write; + data->controller_tx_idx = 0u; + atomic_set(&data->controller_status, MSS_I2C_IN_PROGRESS); + + if (target_status == MSS_I2C_IN_PROGRESS) { + data->is_transaction_pending = CONTROLLER_WRITE_TRANSACTION; + } else { + sys_write8((ctrl | CTRL_STA), cfg->i2c_base_addr + CORE_I2C_CTRL); + } + + if (data->bus_status == MSS_I2C_HOLD_BUS) { + sys_write8((ctrl & ~CTRL_SI), cfg->i2c_base_addr + CORE_I2C_CTRL); + } + + return 0; +} + + +static int mss_i2c_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, + uint16_t addr) +{ + for (int i = 0; i < num_msgs; i++) { + struct i2c_msg *current = &msgs[i]; + + if ((current->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { + mss_i2c_read(dev, addr, current->buf, current->len); + mss_wait_complete(dev); + } else { + mss_i2c_write(dev, addr, current->buf, current->len); + mss_wait_complete(dev); + } + } + + return 0; +} + +static const struct i2c_driver_api mss_i2c_driver_api = { + .configure = mss_i2c_configure, + .transfer = mss_i2c_transfer, +}; + +static void mss_i2c_reset(const struct device *dev) +{ + const struct mss_i2c_config *cfg = dev->config; + uint8_t ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + sys_write8((ctrl & ~CTRL_ENS1), cfg->i2c_base_addr + CORE_I2C_CTRL); + + ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + sys_write8((ctrl | CTRL_ENS1), cfg->i2c_base_addr + CORE_I2C_CTRL); +} + + +static void mss_i2c_irq_handler(const struct device *dev) +{ + struct mss_i2c_data *const data = dev->data; + const struct mss_i2c_config *cfg = dev->config; + + uint8_t ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + uint8_t status = sys_read8(cfg->i2c_base_addr + CORE_I2C_STATUS); + + uint8_t hold_bus = 0; + + switch (status) { + case STATUS_M_START_SENT: + case STATUS_M_REPEATED_START_SENT: + sys_write8((ctrl & ~CTRL_STA), cfg->i2c_base_addr + CORE_I2C_CTRL); + + sys_write8(data->target_addr | data->dir, cfg->i2c_base_addr + CORE_I2C_DATA); + + data->controller_tx_idx = 0; + data->controller_rx_idx = 0; + + data->is_transaction_pending = false; + data->transaction = data->pending_transaction; + break; + case STATUS_M_ARB_LOST: + sys_write8((ctrl | CTRL_STA), cfg->i2c_base_addr + CORE_I2C_CTRL); + LOG_WRN("lost arbitration: %x\n", status); + break; + case STATUS_M_SLAW_ACK: + case STATUS_M_TX_DATA_ACK: + if (data->controller_tx_idx < data->controller_tx_size) { + sys_write8(data->controller_tx_buffer[data->controller_tx_idx], + cfg->i2c_base_addr + CORE_I2C_DATA); + + data->controller_tx_idx++; + + } else if (data->transaction == CONTROLLER_RANDOM_READ_TRANSACTION) { + data->dir = I2C_MSG_READ; + sys_write8((ctrl | CTRL_STA), cfg->i2c_base_addr + CORE_I2C_CTRL); + + } else { + data->transaction = NO_TRANSACTION; + hold_bus = data->options & MSS_I2C_HOLD_BUS; + data->bus_status = hold_bus; + + if (hold_bus == MSS_I2C_RELEASE_BUS) { + sys_write8((ctrl | CTRL_STO), cfg->i2c_base_addr + CORE_I2C_CTRL); + } + } + atomic_set(&data->controller_status, MSS_I2C_SUCCESS); + break; + case STATUS_M_TX_DATA_NACK: + case STATUS_M_SLAR_NACK: + case STATUS_M_SLAW_NACK: + sys_write8((ctrl | CTRL_STO), cfg->i2c_base_addr + CORE_I2C_CTRL); + atomic_set(&data->controller_status, MSS_I2C_FAILED); + data->transaction = NO_TRANSACTION; + break; + case STATUS_M_SLAR_ACK: + if (data->controller_rx_size > 1u) { + sys_write8((ctrl | CTRL_AA), cfg->i2c_base_addr + CORE_I2C_CTRL); + + } else if (data->controller_rx_size == 1u) { + sys_write8((ctrl & ~CTRL_AA), cfg->i2c_base_addr + CORE_I2C_CTRL); + + } else { + sys_write8((ctrl | CTRL_AA | CTRL_STO), cfg->i2c_base_addr + CORE_I2C_CTRL); + atomic_set(&data->controller_status, MSS_I2C_SUCCESS); + data->transaction = NO_TRANSACTION; + } + break; + case STATUS_M_RX_DATA_ACKED: + data->controller_rx_buffer[data->controller_rx_idx] = + sys_read8(cfg->i2c_base_addr + CORE_I2C_DATA); + + data->controller_rx_idx++; + + /* Second Last byte */ + if (data->controller_rx_idx >= (data->controller_rx_size - 1u)) { + sys_write8((ctrl & ~CTRL_AA), cfg->i2c_base_addr + CORE_I2C_CTRL); + } else { + atomic_set(&data->controller_status, MSS_I2C_IN_PROGRESS); + } + break; + case STATUS_M_RX_DATA_NACKED: + + data->controller_rx_buffer[data->controller_rx_idx] = + sys_read8(cfg->i2c_base_addr + CORE_I2C_DATA); + + hold_bus = data->options & MSS_I2C_HOLD_BUS; + data->bus_status = hold_bus; + + if (hold_bus == 0u) { + sys_write8((ctrl | CTRL_STO), cfg->i2c_base_addr + CORE_I2C_CTRL); + } + + data->transaction = NO_TRANSACTION; + atomic_set(&data->controller_status, MSS_I2C_SUCCESS); + break; + default: + break; + } + + ctrl = sys_read8(cfg->i2c_base_addr + CORE_I2C_CTRL); + + sys_write8((ctrl & ~CTRL_SI), cfg->i2c_base_addr + CORE_I2C_CTRL); +} + +#define MSS_I2C_INIT(n) \ + static int mss_i2c_init_##n(const struct device *dev) \ + { \ + mss_i2c_reset(dev); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), mss_i2c_irq_handler, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + \ + return 0; \ + } \ + \ + static struct mss_i2c_data mss_i2c_data_##n; \ + \ + static const struct mss_i2c_config mss_i2c_config_##n = { \ + .i2c_base_addr = DT_INST_REG_ADDR(n), \ + .i2c_irq_base = DT_INST_IRQN(n), \ + .clock_freq = DT_INST_PROP(n, clock_frequency), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, mss_i2c_init_##n, NULL, &mss_i2c_data_##n, &mss_i2c_config_##n, \ + PRE_KERNEL_1, CONFIG_I2C_INIT_PRIORITY, &mss_i2c_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MSS_I2C_INIT) From 05136cde61eef47fa0983a0fbb6499da31534469 Mon Sep 17 00:00:00 2001 From: Conor Paxton Date: Fri, 9 Jun 2023 22:09:00 +0100 Subject: [PATCH 0571/2042] boards: riscv: add I2C Controllers to PolarFire SoC Icicle board Microchip's PolarFire SoC contains two identical I2C peripherals in the microprocessor subsystem. Enable both by default. Signed-off-by: Conor Paxton --- boards/riscv/mpfs_icicle/mpfs_icicle.dts | 10 ++++++++++ boards/riscv/mpfs_icicle/mpfs_icicle_defconfig | 1 + 2 files changed, 11 insertions(+) diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle.dts b/boards/riscv/mpfs_icicle/mpfs_icicle.dts index 32fffc53fca9..9f28083deb80 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle.dts +++ b/boards/riscv/mpfs_icicle/mpfs_icicle.dts @@ -14,6 +14,8 @@ aliases { led0 = &led0; sw0 = &sw0; + i2c0 = &i2c0; + i2c1 = &i2c1; }; chosen { @@ -60,3 +62,11 @@ &gpio2 { status = "okay"; }; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig index 769f8ebb531d..5c41649cb3ea 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig +++ b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig @@ -18,3 +18,4 @@ CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 CONFIG_FPU=n # GPIO driver options CONFIG_GPIO=y +CONFIG_I2C=y From d6ce537be83598087e5534ae02816bc18b172ba1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 23 Jun 2023 14:28:08 +0000 Subject: [PATCH 0572/2042] doc: kernel: update thread priorities diagram cooperative priorities are negative, 0 is not a cooperative priority. Looks like the docs are showing an outdated diagram for some reason, try to update that with a refresh. Signed-off-by: Anas Nashif --- doc/kernel/services/threads/priorities.svg | 132 +-------------------- 1 file changed, 4 insertions(+), 128 deletions(-) diff --git a/doc/kernel/services/threads/priorities.svg b/doc/kernel/services/threads/priorities.svg index b6abaf1b27d1..2e9a85d4ad51 100644 --- a/doc/kernel/services/threads/priorities.svg +++ b/doc/kernel/services/threads/priorities.svg @@ -1,128 +1,4 @@ - - - - -
-
0
-
-
- 0 -
-
- - -
-
- CONFIG_NUM_COOP_PRIORITIES
-
-
- - CONFIG_NUM_COOP_PRIORITIES -
-
- - -
-
cooperative threads
-
-
- cooperative threads -
-
- - -
-
preemptible threads
-
-
- preemptible threads -
-
- - -
-
CONFIG_NUM_PREEMPT_PRIORITIES - 1
-
-
- CONFIG_NUM_PREEMPT_PRIORITIES - 1 -
-
- - - -
-
-1
-
-
- -1 -
-
- - - -
-
Higher priority
-
-
- Higher priority -
-
- - - -
-
Lower priority
-
-
- Lower priority -
-
- - -
-
1
-
-
- 1 -
-
- - - -
-
2
-
-
- 2 -
-
- - - -
-
- 2
-
-
- - 2 -
-
- - - - - -
-
Idle thread (cooperative)
-
-
- Idle thread (cooperative) -
-
- - -
-
Idle thread (preemptible)
-
-
- Idle thread (preemptible) -
-
-
+ + + +
0
0
- CONFIG_NUM_COOP_PRIORITIES
- CONFIG_NUM_COOP_PRIORITIES
cooperative threads
cooperative threads
preemptible threads
preemptible threads
CONFIG_NUM_PREEMPT_PRIORITIES - 1
CONFIG_NUM_PREEMPT_PRIORITIES - 1
-1
-1
Higher priority
Higher priority
Lower priority
Lower priority
1
1
2
2
- 2
- 2
Idle thread (cooperative)
Idle thread (cooperative)
Idle thread (preemptible)
Idle thread (preemptible)
Text is not SVG - cannot display
\ No newline at end of file From 7584c173749534f70a42c5dc18353761188067a1 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 23 Jun 2023 12:37:53 +0000 Subject: [PATCH 0573/2042] intel_adsp: restructure dmic headers and move regs to soc The ifdefs in in dmic headers is getting out of control and makes maintainence very ddifficult, especially when having to maintain out of tree SoCs sharing the same data and information. Keep header clean and per SoC and share some common registers in one place instead avoiding confusion and making it easier to read and maintain. Signed-off-by: Anas Nashif --- drivers/dai/intel/dmic/dmic.c | 2 +- drivers/dai/intel/dmic/dmic_nhlt.c | 2 +- .../intel_adsp/ace/include}/dmic_regs.h | 76 +--- .../intel_ace15_mtpm}/dmic_regs_ace1x.h | 27 ++ .../intel_ace20_lnl}/dmic_regs_ace2x.h | 0 .../cavs/include/intel_tgl_adsp/dmic_regs.h | 388 ++++++++++++++++++ 6 files changed, 423 insertions(+), 72 deletions(-) rename {drivers/dai/intel/dmic => soc/xtensa/intel_adsp/ace/include}/dmic_regs.h (85%) rename {drivers/dai/intel/dmic => soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm}/dmic_regs_ace1x.h (83%) rename {drivers/dai/intel/dmic => soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl}/dmic_regs_ace2x.h (100%) create mode 100644 soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/dmic_regs.h diff --git a/drivers/dai/intel/dmic/dmic.c b/drivers/dai/intel/dmic/dmic.c index 67ab966e83c0..d5fbb13dcfa9 100644 --- a/drivers/dai/intel/dmic/dmic.c +++ b/drivers/dai/intel/dmic/dmic.c @@ -22,7 +22,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include "dmic.h" -#include "dmic_regs.h" +#include /* Base addresses (in PDM scope) of 2ch PDM controllers and coefficient RAM. */ static const uint32_t base[4] = {PDM0, PDM1, PDM2, PDM3}; diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 8d40d9e38553..ede7dc903a87 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include #include #include "dmic.h" -#include "dmic_regs.h" +#include extern struct dai_dmic_global_shared dai_dmic_global; diff --git a/drivers/dai/intel/dmic/dmic_regs.h b/soc/xtensa/intel_adsp/ace/include/dmic_regs.h similarity index 85% rename from drivers/dai/intel/dmic/dmic_regs.h rename to soc/xtensa/intel_adsp/ace/include/dmic_regs.h index 32a260d182a6..90ef02f6183c 100644 --- a/drivers/dai/intel/dmic/dmic_regs.h +++ b/soc/xtensa/intel_adsp/ace/include/dmic_regs.h @@ -36,18 +36,11 @@ /* Interrupt on New Timestamp Enable */ #define TS_LOCAL_TSCTRL_IONTE BIT(30) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE /* DMA Type Select */ #define TS_LOCAL_TSCTRL_DMATS GENMASK(13, 12) /* Capture Link Select - select which link wall clock to time stamp. */ #define TS_LOCAL_TSCTRL_CLNKS GENMASK(11, 10) -#else /* CONFIG_SOC_SERIES_INTEL_ACE */ - -/* Automatically capture the local timestamp when the stream is started. */ -#define TS_LOCAL_TSCTRL_SIP BIT(8) - -#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ /* Hammock Harbor Time Stamp Enable */ #define TS_LOCAL_TSCTRL_HHTSE BIT(7) @@ -217,11 +210,7 @@ /* This field decides the packer mode */ -#ifdef CONFIG_SOC_SERIES_INTEL_ACE #define OUTCONTROL_IPM GENMASK(17, 15) -#else -#define OUTCONTROL_IPM GENMASK(17, 16) -#endif /* Source decimator for 1st stereo/mono data placeholder. */ #define OUTCONTROL_IPM_SOURCE_1 GENMASK(14, 13) @@ -257,12 +246,7 @@ #define OUTSTAT_ROR BIT(27) /* FIFO Level (FL): Current FIFO Level in the Asynchronous FIFO. */ -#ifdef CONFIG_SOC_SERIES_INTEL_ACE #define OUTSTAT_FL_MASK GENMASK(8, 0) -#else -#define OUTSTAT_FL_MASK GENMASK(6, 0) -#endif - /* CIC_CONTROL bits */ @@ -284,11 +268,6 @@ /* Mute currently active microphones */ #define CIC_CONTROL_MIC_MUTE BIT(1) -#ifndef CONFIG_SOC_SERIES_INTEL_ACE -/* When set, the microphone input operates in the stereo mode */ -#define CIC_CONTROL_STEREO_MODE BIT(0) -#endif - /* CIC_CONFIG masks */ @@ -308,21 +287,13 @@ */ #define MIC_CONTROL_PDM_CLKDIV GENMASK(15, 8) -#ifndef CONFIG_SOC_SERIES_INTEL_ACE -/* Selects the delay of the clocks output for microphones to align the sampling point of the data - * and clock edge. - */ -#define MIC_CONTROL_PDM_SKEW GENMASK(7, 4) -#endif /* Inverts the clock edge that will be used to sample microphone data stream. */ #define MIC_CONTROL_CLK_EDGE BIT(3) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE /* Indicates the PDM DMIC clock for the decimator will be sourced from external component instead * of using the PDM DMIC clock generator output */ #define MIC_CONTROL_SLAVE_MODE BIT(2) -#endif /* Enable clock on microphone B (Right) */ #define MIC_CONTROL_PDM_EN_B BIT(1) @@ -333,7 +304,6 @@ /* FIR_CONTROL_A bits */ -#ifdef CONFIG_SOC_SERIES_INTEL_ACE /* Enable the power gating capability of the coefficient. */ #define FIR_CONTROL_CRFPGE BIT(28) @@ -342,7 +312,6 @@ /* Enable the power gating capability of the right channel */ #define FIR_CONTROL_RDRFPGE BIT(30) -#endif /* FIR decimation filter is started. */ #define FIR_CONTROL_START BIT(7) @@ -350,10 +319,8 @@ /* Array microphone control bit for synchronous start of multiple interfaces. */ #define FIR_CONTROL_ARRAY_START_EN BIT(6) -#ifdef CONFIG_SOC_SERIES_INTEL_ACE /* Periodic synchronous start control of multiple PDM */ #define FIR_CONTROL_PERIODIC_START_EN BIT(5) -#endif /* Automatic DC compensation enable */ #define FIR_CONTROL_DCCOMP BIT(4) @@ -420,42 +387,11 @@ /* Digital Mic Shim Registers */ #ifdef CONFIG_SOC_INTEL_ACE20_LNL -#include "dmic_regs_ace2x.h" -#else /* All other CAVS and ACE platforms */ -/* DMIC Link Control - * - * This register controls the specific link. - */ -#define DMICLCTL_OFFSET 0x04 - -/* Set Power Active */ -#define DMICLCTL_SPA BIT(0) - -/* Current Power Active */ -#define DMICLCTL_CPA BIT(8) - -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -/* Owner Select */ -#define DMICLCTL_OSEL GENMASK(25, 24) - -/* Force Clock Gating */ -#define DMICLCTL_FCG BIT(26) - -/* Master Link Clock Select */ -#define DMICLCTL_MLCS GENMASK(29, 27) -#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ - -/* Dynamic Clock Gating Disable */ -#define DMICLCTL_DCGD BIT(30) - -/* Idle Clock Gating Disable */ -#define DMICLCTL_ICGD BIT(31) - - -#ifdef CONFIG_SOC_SERIES_INTEL_ACE -#include "dmic_regs_ace1x.h" -#endif /* CONFIG_SOC_SERIES_INTEL_ACE */ - -#endif /* !CONFIG_SOC_INTEL_ACE20_LNL */ +#include +#elif CONFIG_SOC_INTEL_ACE15_MTPM +#include "intel_ace15_mtpm/dmic_regs_ace1x.h" +#else +#error "Unknown SoC" +#endif #endif /* !__INTEL_DAI_DRIVER_DMIC_REGS_H__ */ diff --git a/drivers/dai/intel/dmic/dmic_regs_ace1x.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/dmic_regs_ace1x.h similarity index 83% rename from drivers/dai/intel/dmic/dmic_regs_ace1x.h rename to soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/dmic_regs_ace1x.h index c3bb5984bffb..d7ea52a752c3 100644 --- a/drivers/dai/intel/dmic/dmic_regs_ace1x.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/dmic_regs_ace1x.h @@ -127,4 +127,31 @@ /* Stereo */ #define DMICPyPDMSM_STR BIT(5) +/* DMIC Link Control + * + * This register controls the specific link. + */ +#define DMICLCTL_OFFSET 0x04 + +/* Set Power Active */ +#define DMICLCTL_SPA BIT(0) + +/* Current Power Active */ +#define DMICLCTL_CPA BIT(8) + +/* Owner Select */ +#define DMICLCTL_OSEL GENMASK(25, 24) + +/* Force Clock Gating */ +#define DMICLCTL_FCG BIT(26) + +/* Master Link Clock Select */ +#define DMICLCTL_MLCS GENMASK(29, 27) + +/* Dynamic Clock Gating Disable */ +#define DMICLCTL_DCGD BIT(30) + +/* Idle Clock Gating Disable */ +#define DMICLCTL_ICGD BIT(31) + #endif /* ! __INTEL_DAI_DRIVER_DMIC_REGS_ACE1X_H__ */ diff --git a/drivers/dai/intel/dmic/dmic_regs_ace2x.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/dmic_regs_ace2x.h similarity index 100% rename from drivers/dai/intel/dmic/dmic_regs_ace2x.h rename to soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/dmic_regs_ace2x.h diff --git a/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/dmic_regs.h b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/dmic_regs.h new file mode 100644 index 000000000000..546d431d4285 --- /dev/null +++ b/soc/xtensa/intel_adsp/cavs/include/intel_tgl_adsp/dmic_regs.h @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 Intel Corporation + * + * Author: Adrian Warecki + */ + +#ifndef __INTEL_DAI_DRIVER_DMIC_REGS_H__ +#define __INTEL_DAI_DRIVER_DMIC_REGS_H__ + +/* DMIC timestamping registers */ +#define TS_DMIC_LOCAL_TSCTRL_OFFSET 0x000 +#define TS_DMIC_LOCAL_OFFS_OFFSET 0x004 +#define TS_DMIC_LOCAL_SAMPLE_OFFSET 0x008 +#define TS_DMIC_LOCAL_WALCLK_OFFSET 0x010 +#define TS_DMIC_TSCC_OFFSET 0x018 + +/* Timestamping */ +#define TIMESTAMP_BASE 0x00071800 + +/* Time Stamp Control Register */ +#define TS_DMIC_LOCAL_TSCTRL (TIMESTAMP_BASE + TS_DMIC_LOCAL_TSCTRL_OFFSET) + +/* Intersample offset Register */ +#define TS_DMIC_LOCAL_OFFS (TIMESTAMP_BASE + TS_DMIC_LOCAL_OFFS_OFFSET) + +#define TS_DMIC_LOCAL_SAMPLE (TIMESTAMP_BASE + TS_DMIC_LOCAL_SAMPLE_OFFSET) +#define TS_DMIC_LOCAL_WALCLK (TIMESTAMP_BASE + TS_DMIC_LOCAL_WALCLK_OFFSET) + +/* Time Stamp Counter Captured 64 bits */ +#define TS_DMIC_TSCC (TIMESTAMP_BASE + TS_DMIC_TSCC_OFFSET) + +/* New Timestamp Taken */ +#define TS_LOCAL_TSCTRL_NTK BIT(31) + +/* Interrupt on New Timestamp Enable */ +#define TS_LOCAL_TSCTRL_IONTE BIT(30) + +/* Automatically capture the local timestamp when the stream is started. */ +#define TS_LOCAL_TSCTRL_SIP BIT(8) + +/* Hammock Harbor Time Stamp Enable */ +#define TS_LOCAL_TSCTRL_HHTSE BIT(7) + +/* Link Wall Clock Select */ +#define TS_LOCAL_TSCTRL_LWCS BIT(6) + +/* On Demand Time Stamp */ +#define TS_LOCAL_TSCTRL_ODTS BIT(5) + +/* Capture DMA Select */ +#define TS_LOCAL_TSCTRL_CDMAS GENMASK(4, 0) + +/* Snapshot of Audio Wall Clock Offset counter (frame offset). */ +#define TS_LOCAL_OFFS_FRM GENMASK(15, 12) + +/* Snapshot of Audio Wall Clock Offset counter (clock offset). */ +#define TS_LOCAL_OFFS_CLK GENMASK(11, 0) + + +/* DMIC register offsets */ + +/* Global registers */ + +/* Common FIFO channels register (primary & secondary) (0000 - 0FFF) + * PDM Primary Channel + */ + +/* Control registers for packers */ +#define OUTCONTROL0 0x0000 + +/* Status Register for FIFO interface */ +#define OUTSTAT0 0x0004 + +/* Data read/Write port for FIFO */ +#define OUTDATA0 0x0008 + +/* (crossed out) 000Ch LOCAL_OFFS Offset Counter + * (crossed out) 0010h LOCAL_TSC0 64-bit Wall Clock timestamp + * (crossed out) 0018h LOCAL_SAMPLE0 64-bit Sample Count + * 001Ch - 00FFh Reserved space for extensions + */ + + +/* PDM Secondary Channel */ + +/* Control registers for packers */ +#define OUTCONTROL1 0x0100 + +/* Status Register for FIFO interface */ +#define OUTSTAT1 0x0104 + +/* Data read/Write port for FIFO */ +#define OUTDATA1 0x0108 + +/* (crossed out) 010Ch LOCAL_OFFS Offset Counter + * (crossed out) 0110h LOCAL_TSC0 64-bit Wall Clock timestamp + * (crossed out) 0118h LOCAL_SAMPLE0 64-bit Sample Count + * 011Ch - 0FFFh Reserved space for extensions + */ + +#define GLOBAL_CAPABILITIES 0x200 + +#define PDM0 0x1000 +#define PDM0_COEFFICIENT_A 0x1400 +#define PDM0_COEFFICIENT_B 0x1800 + +#define PDM1 0x2000 +#define PDM1_COEFFICIENT_A 0x2400 +#define PDM1_COEFFICIENT_B 0x2800 + +#define PDM2 0x3000 +#define PDM2_COEFFICIENT_A 0x3400 +#define PDM2_COEFFICIENT_B 0x3800 + +#define PDM3 0x4000 +#define PDM3_COEFFICIENT_A 0x4400 +#define PDM3_COEFFICIENT_B 0x4800 + +#define PDM_COEF_RAM_A_LENGTH 0x0400 +#define PDM_COEF_RAM_B_LENGTH 0x0400 + +/* Local registers in each PDMx */ + +/* Control register for CIC configuration and decimator setting */ +#define CIC_CONTROL 0x000 + +/* Control of the CIC filter plus voice channel (B) FIR decimation factor */ +#define CIC_CONFIG 0x004 + +/* Microphone interface control register */ +#define MIC_CONTROL 0x00c + +/* FIR config */ + +/* Control for the FIR decimator (channel A) */ +#define FIR_CONTROL_A 0x020 + +/* Configuration of FIR decimator parameters (channel A) */ +#define FIR_CONFIG_A 0x024 + +/* DC offset for left channel */ +#define DC_OFFSET_LEFT_A 0x028 + +/* DC offset for right channel */ +#define DC_OFFSET_RIGHT_A 0x02c + +/* Gain for left channel */ +#define OUT_GAIN_LEFT_A 0x030 + +/* Gain for right channel */ +#define OUT_GAIN_RIGHT_A 0x034 + +/* Control for the FIR decimator (channel B) */ +#define FIR_CONTROL_B 0x040 + +/* Configuration of FIR decimator parameters (channel B) */ +#define FIR_CONFIG_B 0x044 + +/* DC offset for left channel */ +#define DC_OFFSET_LEFT_B 0x048 + +/* DC offset for right channel */ +#define DC_OFFSET_RIGHT_B 0x04c + +/* Gain for left channel */ +#define OUT_GAIN_LEFT_B 0x050 + +/* Gain for right channel */ +#define OUT_GAIN_RIGHT_B 0x054 + +#define PDM_COEFFICIENT_A 0x400 +#define PDM_COEFFICIENT_B 0x800 + + +/* Digital Mic Shim Registers */ + +/* Digital Microphone Link Control */ +#define DMICLCTL 0x04 + +/* Digital Microphone IP Pointer */ +#define DMICIPPTR 0x08 + + +/* OUTCONTROL0 and OUTCONTROL1 */ + +/* OUTCONTROLx IPM bit fields style */ +#define OUTCONTROL_BFTH_MAX 4 /* Max depth 16 */ + +/* Threshold Interrupt Enable */ +#define OUTCONTROL_TIE BIT(27) + +/* Start Input Packer */ +#define OUTCONTROL_SIP BIT(26) + +/* FIFO Initialize (FINIT): The software will set this bit to immediately clear FIFO pointers. */ +#define OUTCONTROL_FINIT BIT(25) + +/* Input Format Change Indicator */ +#define OUTCONTROL_FCI BIT(24) + +/* Burst FIFO Threshold */ +#define OUTCONTROL_BFTH GENMASK(23, 20) + +/* Output Format */ +#define OUTCONTROL_OF GENMASK(19, 18) + + +/* This field decides the packer mode */ +#define OUTCONTROL_IPM GENMASK(17, 16) + +/* Source decimator for 1st stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_1 GENMASK(14, 13) + +/* Source decimator for 2nd stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_2 GENMASK(12, 11) + +/* Source decimator for 3rd stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_3 GENMASK(10, 9) + +/* Source decimator for 4th stereo/mono data placeholder. */ +#define OUTCONTROL_IPM_SOURCE_4 GENMASK(8, 7) + +/* Defines the mode of operation for all source decimator. */ +#define OUTCONTROL_IPM_SOURCE_MODE BIT(6) + +/* FIFO Trigger Threshold */ +#define OUTCONTROL_TH GENMASK(5, 0) + + +/* OUTSTAT0 and OUTSTAT1 bits */ + +/* Asynchronous FIFO is empty */ +#define OUTSTAT_AFE BIT(31) + +/* Asynchronous FIFO Not Empty */ +#define OUTSTAT_ASNE BIT(29) + +/* FIFO Service Request */ +#define OUTSTAT_RFS BIT(28) + +/* Overrun */ +#define OUTSTAT_ROR BIT(27) + + /* FIFO Level (FL): Current FIFO Level in the Asynchronous FIFO. */ +#define OUTSTAT_FL_MASK GENMASK(6, 0) + +/* CIC_CONTROL bits */ + +/* Microphone interface reset. */ +#define CIC_CONTROL_SOFT_RESET BIT(16) + +/* When set to 1, the CIC channel B (right) is started, otherwise it is muted and idle. */ +#define CIC_CONTROL_CIC_START_B BIT(15) + +/* When set to 1, the CIC channel A (left) is started, otherwise it is muted and idle. */ +#define CIC_CONTROL_CIC_START_A BIT(14) + +/* Polarity of the microphone output. */ +#define CIC_CONTROL_MIC_B_POLARITY BIT(3) + +/* Polarity of the microphone output. */ +#define CIC_CONTROL_MIC_A_POLARITY BIT(2) + +/* Mute currently active microphones */ +#define CIC_CONTROL_MIC_MUTE BIT(1) + +/* When set, the microphone input operates in the stereo mode */ +#define CIC_CONTROL_STEREO_MODE BIT(0) + + +/* CIC_CONFIG masks */ + +/* Number of bits for shift right in the output stage of the CIC filter to compensate the gain + * accumulated due to decimation. + */ +#define CIC_CONFIG_CIC_SHIFT GENMASK(27, 24) + +/* Period of activation of comb section in the microphone clocks minus 1 */ +#define CIC_CONFIG_COMB_COUNT GENMASK(15, 8) + + +/* MIC_CONTROL */ + +/* Clock divider used for producing the microphone clock from audio IO clock with approximately 50% + * duty cycle. + */ +#define MIC_CONTROL_PDM_CLKDIV GENMASK(15, 8) + +#define MIC_CONTROL_PDM_SKEW GENMASK(7, 4) + +/* Inverts the clock edge that will be used to sample microphone data stream. */ +#define MIC_CONTROL_CLK_EDGE BIT(3) + +/* Enable clock on microphone B (Right) */ +#define MIC_CONTROL_PDM_EN_B BIT(1) + +/* Enable clock on microphone A (left) */ +#define MIC_CONTROL_PDM_EN_A BIT(0) + +/* FIR decimation filter is started. */ +#define FIR_CONTROL_START BIT(7) + +/* Array microphone control bit for synchronous start of multiple interfaces. */ +#define FIR_CONTROL_ARRAY_START_EN BIT(6) + +/* Automatic DC compensation enable */ +#define FIR_CONTROL_DCCOMP BIT(4) + +/* Write in the coefficient memory will mute the output for the N audio clocks */ +#define FIR_CONTROL_AUTO_MUTE BIT(2) + +/* Mute outputs of this filter and set it to zero. */ +#define FIR_CONTROL_MUTE BIT(1) + +/* Filter operates in stereo mode */ +#define FIR_CONTROL_STEREO BIT(0) + + + /* FIR_CONFIG bits */ + +/* Decimation factor of the FIR filter minus 1. */ +#define FIR_CONFIG_FIR_DECIMATION GENMASK(20, 16) + +/* Number of bits for shift right in the output stage of the CIC filter to compensate the gain + * accumulated due to decimation. + */ +#define FIR_CONFIG_FIR_SHIFT GENMASK(11, 8) + +/* The number of active taps of the FIR filter minus 1. */ +#define FIR_CONFIG_FIR_LENGTH GENMASK(7, 0) + + +/* DC_OFFSET_LEFT and DC_OFFSET_RIGHT */ + +/* Value added to the output of the FIR filter. */ +#define DC_OFFSET_DC_OFFS GENMASK(21, 0) + + +/* OUT_GAIN_LEFT and OUT_GAIN_RIGHT */ + +/* Value added to the output of the FIR filter. */ +#define OUT_GAIN GENMASK(19, 0) + +/* FIR coefficients */ +#define FIR_COEF GENMASK(19, 0) + + +/* GLOBAL_CAPABILITIES */ + +/* Nnumber of data entries supported in the PCM XCLK FIFO per FIR output. */ +#define GLOBAL_CAP_PCM_XCLK_FIFO_DEPTH GENMASK(5, 0) + +/* Port Count */ +#define GLOBAL_CAP_PORT_COUNT GENMASK(7, 6) + +/* FIR Count */ +#define GLOBAL_CAP_FIR_COUNT BIT(8) + +/* FIR max gain configuration. */ +#define GLOBAL_CAP_FIR_MAX_GAIN BIT(9) + +/* FIR A RF Depth */ +#define GLOBAL_CAP_FIR_A_RF_DEPTH GENMASK(23, 16) + +/* FIR B RF Depth */ +#define GLOBAL_CAP_FIR_B_RF_DEPTH GENMASK(31, 24) + + +/* DMIC Link Control + * + * This register controls the specific link. + */ +#define DMICLCTL_OFFSET 0x04 + +/* Set Power Active */ +#define DMICLCTL_SPA BIT(0) + +/* Current Power Active */ +#define DMICLCTL_CPA BIT(8) + +/* Dynamic Clock Gating Disable */ +#define DMICLCTL_DCGD BIT(30) + +/* Idle Clock Gating Disable */ +#define DMICLCTL_ICGD BIT(31) + +#endif /* !__INTEL_DAI_DRIVER_DMIC_REGS_H__ */ From 2ae521a5f5155a8442f0f5eb8d949d06cc05ca15 Mon Sep 17 00:00:00 2001 From: Vincent van Beveren Date: Thu, 15 Jun 2023 15:38:36 +0200 Subject: [PATCH 0574/2042] posix: fs: Fixes stat command to return file information Fixes #58911. Previously the stat command returned information on the filesystem, but not the file itself. Because block size is still set this function is backwards compatible with the previous faulty behavior. Signed-off-by: Vincent van Beveren --- lib/posix/fs.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/posix/fs.c b/lib/posix/fs.c index bc48ee7fbc6d..ca861a729b1e 100644 --- a/lib/posix/fs.c +++ b/lib/posix/fs.c @@ -20,7 +20,7 @@ BUILD_ASSERT(PATH_MAX >= MAX_FILE_NAME, "PATH_MAX is less than MAX_FILE_NAME"); struct posix_fs_desc { union { struct fs_file_t file; - struct fs_dir_t dir; + struct fs_dir_t dir; }; bool is_dir; bool used; @@ -349,22 +349,47 @@ int unlink(const char *path) int stat(const char *path, struct stat *buf) { int rc; - struct fs_statvfs stat; + struct fs_statvfs stat_vfs; + struct fs_dirent stat_file; if (buf == NULL) { errno = EBADF; return -1; } - rc = fs_statvfs(path, &stat); + rc = fs_statvfs(path, &stat_vfs); if (rc < 0) { errno = -rc; return -1; } - buf->st_size = stat.f_bsize * stat.f_blocks; - buf->st_blksize = stat.f_bsize; - buf->st_blocks = stat.f_blocks; + rc = fs_stat(path, &stat_file); + if (rc < 0) { + errno = -rc; + return -1; + } + + memset(buf, 0, sizeof(struct stat)); + + switch (stat_file.type) { + case FS_DIR_ENTRY_FILE: + buf->st_mode = S_IFREG; + break; + case FS_DIR_ENTRY_DIR: + buf->st_mode = S_IFDIR; + break; + default: + errno = EIO; + return -1; + } + buf->st_size = stat_file.size; + buf->st_blksize = stat_vfs.f_bsize; + /* + * This is a best effort guess, as this information is not provided + * by the fs_stat function. + */ + buf->st_blocks = (stat_file.size + stat_vfs.f_bsize - 1) / stat_vfs.f_bsize; + return 0; } From bd0d98bb9ecee7eca46f23d9fb994d6a3a63d46e Mon Sep 17 00:00:00 2001 From: Vincent van Beveren Date: Thu, 15 Jun 2023 15:39:33 +0200 Subject: [PATCH 0575/2042] tests: posix: fs: Add tests for stat command This commit adds tests for the stat command. Stat on the root of the filesystem is not yet supported. Signed-off-by: Vincent van Beveren --- tests/posix/fs/src/test_fs.h | 1 + tests/posix/fs/src/test_fs_stat.c | 104 ++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tests/posix/fs/src/test_fs_stat.c diff --git a/tests/posix/fs/src/test_fs.h b/tests/posix/fs/src/test_fs.h index adb1290758d3..f67a310014a7 100644 --- a/tests/posix/fs/src/test_fs.h +++ b/tests/posix/fs/src/test_fs.h @@ -7,6 +7,7 @@ #include #define FATFS_MNTP "/RAM:" +#define TEST_ROOT FATFS_MNTP"/" #define TEST_FILE FATFS_MNTP"/testfile.txt" #define TEST_DIR FATFS_MNTP"/testdir" #define TEST_DIR_FILE FATFS_MNTP"/testdir/testfile.txt" diff --git a/tests/posix/fs/src/test_fs_stat.c b/tests/posix/fs/src/test_fs_stat.c new file mode 100644 index 000000000000..14167d3f7756 --- /dev/null +++ b/tests/posix/fs/src/test_fs_stat.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 Nikhef + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "test_fs.h" + +#define FILL_SIZE 128 + +#define TEST_FILE_SIZE 80 +#define TEST_DIR_FILE_SIZE 1000 + +#define TEST_EMPTY_FILE FATFS_MNTP "/empty.dat" + +static void create_file(const char *filename, uint32_t size) +{ + int fh; + + fh = open(filename, O_CREAT | O_WRONLY); + zassert(fh >= 0, "Failed creating test file"); + + uint8_t filling[FILL_SIZE]; + + while (size > FILL_SIZE) { + zassert_equal(FILL_SIZE, write(fh, filling, FILL_SIZE)); + size -= FILL_SIZE; + } + + zassert_equal(size, write(fh, filling, size)); + + zassert_ok(close(fh)); +} + +static void before_fn(void *unused) +{ + ARG_UNUSED(unused); + + zassert_ok(mkdir(TEST_DIR, 0070)); + + create_file(TEST_FILE, TEST_FILE_SIZE); + create_file(TEST_DIR_FILE, TEST_DIR_FILE_SIZE); + create_file(TEST_EMPTY_FILE, 0); +} + +static void after_fn(void *unused) +{ + ARG_UNUSED(unused); + + zassert_ok(unlink(TEST_FILE)); + zassert_ok(unlink(TEST_DIR_FILE)); + zassert_ok(unlink(TEST_DIR)); +} + +ZTEST_SUITE(posix_fs_stat_test, NULL, test_mount, before_fn, after_fn, test_unmount); + +/** + * @brief Test stat command on file + * + * @details Tests file in root, file in directroy, non-existing file and empty file. + */ +ZTEST(posix_fs_stat_test, test_fs_stat_file) +{ + struct stat buf; + + zassert_equal(0, stat(TEST_FILE, &buf)); + zassert_equal(TEST_FILE_SIZE, buf.st_size); + zassert_equal(S_IFREG, buf.st_mode); + + zassert_equal(0, stat(TEST_DIR_FILE, &buf)); + zassert_equal(TEST_DIR_FILE_SIZE, buf.st_size); + zassert_equal(S_IFREG, buf.st_mode); + + zassert_not_equal(0, stat(TEST_ROOT "foo.txt", &buf)); + zassert_not_equal(0, stat("", &buf)); + + zassert_equal(0, stat(TEST_EMPTY_FILE, &buf)); + + zassert_equal(0, buf.st_size); + zassert_equal(S_IFREG, buf.st_mode); +} + +/** + * @brief Test stat command on dir + * + * @details Tests if we can retrieve stastics for a directory. This should only provide S_IFDIR + * return value. + */ +ZTEST(posix_fs_stat_test, test_fs_stat_dir) +{ + struct stat buf; + + zassert_equal(0, stat(TEST_DIR, &buf)); + + zassert_equal(0, buf.st_size); + zassert_equal(S_IFDIR, buf.st_mode); + + /* note: for posix compatibility should should actually work */ + zassert_not_equal(0, stat(TEST_ROOT, &buf)); +} From f7c1f9114886ff27d2c531cfc5e48959e47f1dac Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Wed, 21 Jun 2023 18:28:55 +0300 Subject: [PATCH 0576/2042] samples: openamp_rsc_table: move arch specific config from project The CONFIG_PLATFORM_SPECIFIC_INIT is ARM specific, so move this to board config file, rather than project config. It should be no restriction to run the openamp_rsc_table sample on other, non-arm, platforms. Signed-off-by: Iuliana Prodan --- samples/subsys/ipc/openamp_rsc_table/boards/stm32mp157c_dk2.conf | 1 + samples/subsys/ipc/openamp_rsc_table/prj.conf | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 samples/subsys/ipc/openamp_rsc_table/boards/stm32mp157c_dk2.conf diff --git a/samples/subsys/ipc/openamp_rsc_table/boards/stm32mp157c_dk2.conf b/samples/subsys/ipc/openamp_rsc_table/boards/stm32mp157c_dk2.conf new file mode 100644 index 000000000000..f36a9598e4b4 --- /dev/null +++ b/samples/subsys/ipc/openamp_rsc_table/boards/stm32mp157c_dk2.conf @@ -0,0 +1 @@ +CONFIG_PLATFORM_SPECIFIC_INIT=n diff --git a/samples/subsys/ipc/openamp_rsc_table/prj.conf b/samples/subsys/ipc/openamp_rsc_table/prj.conf index 77a3794cfada..eb0f0631b18c 100644 --- a/samples/subsys/ipc/openamp_rsc_table/prj.conf +++ b/samples/subsys/ipc/openamp_rsc_table/prj.conf @@ -1,7 +1,6 @@ CONFIG_KERNEL_BIN_NAME="zephyr_openamp_rsc_table" CONFIG_PRINTK=n CONFIG_IPM=y -CONFIG_PLATFORM_SPECIFIC_INIT=n CONFIG_MAIN_STACK_SIZE=1024 CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_OPENAMP=y From 67bdd178080e5fabcfb8d5aa30d8bddc85927c24 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Wed, 15 Mar 2023 14:06:47 -0700 Subject: [PATCH 0577/2042] drivers: adc: voltage divider adds DT macro initializer and scaling function for voltage divider. Signed-off-by: Jason Yuan --- .../{adc => iio/afe}/voltage-divider.yaml | 0 include/zephyr/drivers/adc/voltage_divider.h | 59 +++++++++++++++++++ 2 files changed, 59 insertions(+) rename dts/bindings/{adc => iio/afe}/voltage-divider.yaml (100%) create mode 100644 include/zephyr/drivers/adc/voltage_divider.h diff --git a/dts/bindings/adc/voltage-divider.yaml b/dts/bindings/iio/afe/voltage-divider.yaml similarity index 100% rename from dts/bindings/adc/voltage-divider.yaml rename to dts/bindings/iio/afe/voltage-divider.yaml diff --git a/include/zephyr/drivers/adc/voltage_divider.h b/include/zephyr/drivers/adc/voltage_divider.h new file mode 100644 index 000000000000..692442d4b384 --- /dev/null +++ b/include/zephyr/drivers/adc/voltage_divider.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_VOLTAGE_DIVIDER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_ADC_VOLTAGE_DIVIDER_H_ + +#include + +struct voltage_divider_dt_spec { + const struct adc_dt_spec port; + uint32_t full_ohms; + uint32_t output_ohms; +}; + +/** + * @brief Get voltage divider information from devicetree. + * + * This returns a static initializer for a @p voltage_divider_dt_spec structure + * given a devicetree node. + * + * @param node_id Devicetree node identifier. + * + * @return Static initializer for an voltage_divider_dt_spec structure. + */ +#define VOLTAGE_DIVIDER_DT_SPEC_GET(node_id) \ + { \ + .port = ADC_DT_SPEC_GET(node_id), \ + .full_ohms = DT_PROP_OR(node_id, full_ohms, 0), \ + .output_ohms = DT_PROP(node_id, output_ohms), \ + } + +/** + * @brief Calculates the actual voltage from the measured voltage + * + * @param[in] spec voltage divider specification from Devicetree. + * @param[in,out] v_to_v Pointer to the measured voltage on input, and the + * corresponding scaled voltage value on output. + * + * @retval 0 on success + * @retval -ENOTSUP if "full_ohms" is not specified + */ +static inline int voltage_divider_scale_dt(const struct voltage_divider_dt_spec *spec, + int32_t *v_to_v) +{ + /* cannot be scaled if "full_ohms" is not specified */ + if (spec->full_ohms == 0) { + return -ENOTSUP; + } + + /* voltage scaled by voltage divider values using DT binding */ + *v_to_v = *v_to_v * spec->full_ohms / spec->output_ohms; + + return 0; +} + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_VOLTAGE_DIVIDER_H_ */ From 40957389ff35c637aaea198a16478ce30c9ca339 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Fri, 17 Mar 2023 13:01:09 -0700 Subject: [PATCH 0578/2042] test: adc: voltage divider adds tests for the voltage divider binding macro and rescaling function. Signed-off-by: Jason Yuan --- tests/drivers/adc/adc_rescale/CMakeLists.txt | 10 ++ .../adc_rescale/boards/native_posix.overlay | 39 ++++++++ .../boards/native_posix_64.overlay | 6 ++ tests/drivers/adc/adc_rescale/prj.conf | 7 ++ tests/drivers/adc/adc_rescale/src/main.c | 95 +++++++++++++++++++ tests/drivers/adc/adc_rescale/testcase.yaml | 6 ++ 6 files changed, 163 insertions(+) create mode 100644 tests/drivers/adc/adc_rescale/CMakeLists.txt create mode 100644 tests/drivers/adc/adc_rescale/boards/native_posix.overlay create mode 100644 tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay create mode 100644 tests/drivers/adc/adc_rescale/prj.conf create mode 100644 tests/drivers/adc/adc_rescale/src/main.c create mode 100644 tests/drivers/adc/adc_rescale/testcase.yaml diff --git a/tests/drivers/adc/adc_rescale/CMakeLists.txt b/tests/drivers/adc/adc_rescale/CMakeLists.txt new file mode 100644 index 000000000000..e17d8c2383b8 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/CMakeLists.txt @@ -0,0 +1,10 @@ +# 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(adc_rescale) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay new file mode 100644 index 000000000000..66e5ebc7dc75 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay @@ -0,0 +1,39 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + +/ { + sensor0: vd { + compatible = "voltage-divider"; + io-channels = <&adc0 0>; + output-ohms = <50>; + full-ohms = <100>; + }; + + adc0: adc { + compatible = "zephyr,adc-emul"; + nchannels = <2>; + ref-internal-mv = <3300>; + ref-external1-mv = <5000>; + #io-channel-cells = <1>; + status = "okay"; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay b/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay new file mode 100644 index 000000000000..b71b19b0e766 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/boards/native_posix_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_posix.overlay" diff --git a/tests/drivers/adc/adc_rescale/prj.conf b/tests/drivers/adc/adc_rescale/prj.conf new file mode 100644 index 000000000000..eaab1b201026 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/prj.conf @@ -0,0 +1,7 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y + +CONFIG_ADC=y +CONFIG_ADC_LOG_LEVEL_INF=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 +CONFIG_TEST_USERSPACE=y diff --git a/tests/drivers/adc/adc_rescale/src/main.c b/tests/drivers/adc/adc_rescale/src/main.c new file mode 100644 index 000000000000..bee8c4dd1c78 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/src/main.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/* Raw to millivolt conversion doesn't handle rounding */ +#define MV_OUTPUT_EPS 10 + +#define ADC_TEST_NODE_0 DT_NODELABEL(sensor0) + +/** + * @brief Get ADC emulated device + * + * @return pointer to ADC device + */ +const struct device *get_adc_device(void) +{ + const struct device *const adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc0)); + + zassert_true(device_is_ready(adc_dev), "ADC device is not ready"); + + return adc_dev; +} + +static int init_adc(const struct adc_dt_spec *spec, int input_mv) +{ + int ret; + + zassert_true(device_is_ready(spec->dev), "ADC device is not ready"); + + ret = adc_channel_setup_dt(spec); + zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret); + + /* ADC emulator-specific setup */ + ret = adc_emul_const_value_set(spec->dev, spec->channel_id, input_mv); + zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret); + + return ret; +} + +/* + * test_adc_voltage_divider + */ +static int test_task_voltage_divider(void) +{ + int ret; + int32_t calculated_voltage = 0; + int32_t input_mv = 1000; + const struct voltage_divider_dt_spec adc_node_0 = + VOLTAGE_DIVIDER_DT_SPEC_GET(ADC_TEST_NODE_0); + + ret = init_adc(&adc_node_0.port, input_mv); + zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret); + + struct adc_sequence sequence = { + .buffer = &calculated_voltage, + .buffer_size = sizeof(calculated_voltage), + }; + adc_sequence_init_dt(&adc_node_0.port, &sequence); + + ret = adc_read(adc_node_0.port.dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + ret = adc_raw_to_millivolts_dt(&adc_node_0.port, &calculated_voltage); + zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret); + + ret = voltage_divider_scale_dt(&adc_node_0, &calculated_voltage); + zassert_equal(ret, 0, "divider_scale_voltage_dt() failed with code %d", ret); + + zassert_within(calculated_voltage, input_mv * 2, MV_OUTPUT_EPS, + "%u != %u should have set value", calculated_voltage, input_mv * 2); + + return TC_PASS; +} + +ZTEST_USER(adc_rescale, test_adc_voltage_divider) +{ + zassert_true(test_task_voltage_divider() == TC_PASS); +} + +void *adc_rescale_setup(void) +{ + k_object_access_grant(get_adc_device(), k_current_get()); + + return NULL; +} + +ZTEST_SUITE(adc_rescale, NULL, adc_rescale_setup, NULL, NULL, NULL); diff --git a/tests/drivers/adc/adc_rescale/testcase.yaml b/tests/drivers/adc/adc_rescale/testcase.yaml new file mode 100644 index 000000000000..3d60d0714866 --- /dev/null +++ b/tests/drivers/adc/adc_rescale/testcase.yaml @@ -0,0 +1,6 @@ +common: + tags: adc drivers userspace +tests: + drivers.adc.rescale: + depends_on: adc + platform_allow: native_posix From 7b73beab436251ad95c6d6fbdc6ba0cc13b9b784 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Mon, 20 Mar 2023 14:15:23 -0700 Subject: [PATCH 0579/2042] dts: bindings: adc: add shunt sensor Add bindings for a current sensor using a shunt resistor. Signed-off-by: Jason Yuan --- dts/bindings/iio/afe/current-sense-shunt.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 dts/bindings/iio/afe/current-sense-shunt.yaml diff --git a/dts/bindings/iio/afe/current-sense-shunt.yaml b/dts/bindings/iio/afe/current-sense-shunt.yaml new file mode 100644 index 000000000000..a15e4d15a9c7 --- /dev/null +++ b/dts/bindings/iio/afe/current-sense-shunt.yaml @@ -0,0 +1,27 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +description: | + When an io-channel measures the voltage over a current sense shunt, + the interesting measurement is almost always the current through the + shunt, not the voltage over it. This binding describes such a current + sense circuit. + + This is based on Linux, documentation: + https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.yaml + +compatible: "current-sense-shunt" + +include: base.yaml + +properties: + io-channels: + required: true + description: | + Channels available with this divider configuration. + + shunt-resistor-micro-ohms: + type: int + required: true + description: | + Resistance of the shunt resistor in micro-ohms From 154ad7544d645bf448eed9aa9bd12a65cd836062 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Mon, 20 Mar 2023 15:11:13 -0700 Subject: [PATCH 0580/2042] drivers: adc: current sense shunt adds DT macro initializer and scaling function for current sense shunt. Signed-off-by: Jason Yuan --- .../zephyr/drivers/adc/current_sense_shunt.h | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 include/zephyr/drivers/adc/current_sense_shunt.h diff --git a/include/zephyr/drivers/adc/current_sense_shunt.h b/include/zephyr/drivers/adc/current_sense_shunt.h new file mode 100644 index 000000000000..c72deb82f9cb --- /dev/null +++ b/include/zephyr/drivers/adc/current_sense_shunt.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_SHUNT_H_ +#define ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_SHUNT_H_ + +#include + +struct current_sense_shunt_dt_spec { + const struct adc_dt_spec port; + uint32_t shunt_micro_ohms; +}; + +/** + * @brief Get current sensor information from devicetree. + * + * This returns a static initializer for a @p current_sense_shunt_dt_spec structure + * given a devicetree node. + * + * @param node_id Devicetree node identifier. + * + * @return Static initializer for an current_sense_shunt_dt_spec structure. + */ +#define CURRENT_SENSE_SHUNT_DT_SPEC_GET(node_id) \ + { \ + .port = ADC_DT_SPEC_GET(node_id), \ + .shunt_micro_ohms = DT_PROP(node_id, shunt_resistor_micro_ohms), \ + } + +/** + * @brief Calculates the actual voltage from the measured voltage + * + * @param[in] spec current sensor specification from Devicetree. + * @param[in,out] v_to_i Pointer to the measured voltage in millivolts on input, and the + * corresponding scaled current value in milliamps on output. + */ +static inline void current_sense_shunt_scale_dt(const struct current_sense_shunt_dt_spec *spec, + int32_t *v_to_i) +{ + /* store in a temporary 64 bit variable to prevent overflow during calculation */ + int64_t tmp = *v_to_i; + + /* multiplies by 1,000,000 before dividing by shunt resistance in micro-ohms. */ + tmp = tmp * 1000000 / spec->shunt_micro_ohms; + + *v_to_i = (int32_t)tmp; +} + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_SHUNT_H_ */ From a79df5eed145ef817a4b894bfc8378ae055dc635 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Mon, 20 Mar 2023 15:26:52 -0700 Subject: [PATCH 0581/2042] test: adc: current sense shunt adds tests for the current sense shunt binding macro and rescaling function. Signed-off-by: Jason Yuan --- .../adc_rescale/boards/native_posix.overlay | 15 +++++++ tests/drivers/adc/adc_rescale/src/main.c | 42 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay index 66e5ebc7dc75..bf937a69849b 100644 --- a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay +++ b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay @@ -14,6 +14,12 @@ full-ohms = <100>; }; + sensor1: css { + compatible = "current-sense-shunt"; + io-channels = <&adc0 0>; + shunt-resistor-micro-ohms = <500000>; + }; + adc0: adc { compatible = "zephyr,adc-emul"; nchannels = <2>; @@ -36,4 +42,13 @@ zephyr,acquisition-time = ; zephyr,resolution = <12>; }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; }; diff --git a/tests/drivers/adc/adc_rescale/src/main.c b/tests/drivers/adc/adc_rescale/src/main.c index bee8c4dd1c78..27106f0f76eb 100644 --- a/tests/drivers/adc/adc_rescale/src/main.c +++ b/tests/drivers/adc/adc_rescale/src/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ #define MV_OUTPUT_EPS 10 #define ADC_TEST_NODE_0 DT_NODELABEL(sensor0) +#define ADC_TEST_NODE_1 DT_NODELABEL(sensor1) /** * @brief Get ADC emulated device @@ -85,6 +87,46 @@ ZTEST_USER(adc_rescale, test_adc_voltage_divider) zassert_true(test_task_voltage_divider() == TC_PASS); } +/* + * test_adc_current_sensor + */ +static int test_task_current_sensor(void) +{ + int ret; + int32_t calculated_current = 0; + int32_t input_mv = 3000; + const struct current_sense_shunt_dt_spec adc_node_1 = + CURRENT_SENSE_SHUNT_DT_SPEC_GET(ADC_TEST_NODE_1); + + ret = init_adc(&adc_node_1.port, input_mv); + zassert_equal(ret, 0, "Setting up of the second channel failed with code %d", ret); + + struct adc_sequence sequence = { + .buffer = &calculated_current, + .buffer_size = sizeof(calculated_current), + }; + adc_sequence_init_dt(&adc_node_1.port, &sequence); + + ret = adc_read(adc_node_1.port.dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + ret = adc_raw_to_millivolts_dt(&adc_node_1.port, &calculated_current); + zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret); + + current_sense_shunt_scale_dt(&adc_node_1, &calculated_current); + + zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS, + "%u != %u should have set value", calculated_current, + input_mv * 2); + + return TC_PASS; +} + +ZTEST_USER(adc_rescale, test_adc_current_sensor) +{ + zassert_true(test_task_current_sensor() == TC_PASS); +} + void *adc_rescale_setup(void) { k_object_access_grant(get_adc_device(), k_current_get()); From fcb4c23b95aa387328e3287b702ff00e2c70b092 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Thu, 23 Mar 2023 13:35:40 -0700 Subject: [PATCH 0582/2042] dts: bindings: afe: add current sense amplifier Add bindings for a current sensor using a shunt resistor and amplifier. Signed-off-by: Jason Yuan --- .../iio/afe/current-sense-amplifier.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 dts/bindings/iio/afe/current-sense-amplifier.yaml diff --git a/dts/bindings/iio/afe/current-sense-amplifier.yaml b/dts/bindings/iio/afe/current-sense-amplifier.yaml new file mode 100644 index 000000000000..e50bda74fe4d --- /dev/null +++ b/dts/bindings/iio/afe/current-sense-amplifier.yaml @@ -0,0 +1,39 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +description: | + When an io-channel measures the voltage over a current sense amplifier, + the interesting measurement is almost always the current through the + sense resistor, not the voltage over it. This binding describes such a current + sense circuit. + + This is based on Linux, documentation: + https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.yaml + +compatible: "current-sense-amplifier" + +include: base.yaml + +properties: + io-channels: + required: true + description: | + Channels available with this divider configuration. + + sense-resistor-micro-ohms: + type: int + required: true + description: | + Resistance of the shunt resistor in micro-ohms + + sense-gain-mult: + type: int + default: 1 + description: | + Amplifier gain multiplier. The default is <1>. + + sense-gain-div: + type: int + default: 1 + description: | + Amplifier gain divider. The default is <1>. From fe20701bd8a6dc6d98afd66499a4a0b1645f428d Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Thu, 23 Mar 2023 13:43:03 -0700 Subject: [PATCH 0583/2042] drivers: afe: current sense amplifier adds DT macro initializer and scaling function for current sense amplifier. Signed-off-by: Jason Yuan --- .../drivers/adc/current_sense_amplifier.h | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 include/zephyr/drivers/adc/current_sense_amplifier.h diff --git a/include/zephyr/drivers/adc/current_sense_amplifier.h b/include/zephyr/drivers/adc/current_sense_amplifier.h new file mode 100644 index 000000000000..60489706c3af --- /dev/null +++ b/include/zephyr/drivers/adc/current_sense_amplifier.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_AMPLIFIER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_AMPLIFIER_H_ + +#include + +struct current_sense_amplifier_dt_spec { + const struct adc_dt_spec port; + uint32_t sense_micro_ohms; + uint32_t sense_gain_mult; + uint32_t sense_gain_div; +}; + +/** + * @brief Get current sensor information from devicetree. + * + * This returns a static initializer for a @p current_sense_amplifier_dt_spec structure + * given a devicetree node. + * + * @param node_id Devicetree node identifier. + * + * @return Static initializer for an current_sense_amplifier_dt_spec structure. + */ +#define CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(node_id) \ + { \ + .port = ADC_DT_SPEC_GET(node_id), \ + .sense_micro_ohms = DT_PROP(node_id, sense_resistor_micro_ohms), \ + .sense_gain_mult = DT_PROP(node_id, sense_gain_mult), \ + .sense_gain_div = DT_PROP(node_id, sense_gain_div), \ + } + +/** + * @brief Calculates the actual voltage from the measured voltage + * + * @param[in] spec current sensor specification from Devicetree. + * @param[in,out] v_to_i Pointer to the measured voltage in millivolts on input, and the + * corresponding scaled current value in milliamps on output. + */ +static inline void +current_sense_amplifier_scale_dt(const struct current_sense_amplifier_dt_spec *spec, + int32_t *v_to_i) +{ + /* store in a temporary 64 bit variable to prevent overflow during calculation */ + int64_t tmp = *v_to_i; + + /* multiplies by 1,000,000 before dividing by sense resistance in micro-ohms. */ + tmp = tmp * 1000000 / spec->sense_micro_ohms * spec->sense_gain_div / spec->sense_gain_mult; + + *v_to_i = (int32_t)tmp; +} + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ADC_CURRENT_SENSE_AMPLIFIER_H_ */ From 570bcd3c83259bfdcc06817d92ce5ef0aa656fc0 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Thu, 23 Mar 2023 13:56:27 -0700 Subject: [PATCH 0584/2042] test: adc: current sense amplifier adds tests for the current sense amplifier binding macro and rescaling function. Signed-off-by: Jason Yuan --- .../adc_rescale/boards/native_posix.overlay | 20 +++++++- tests/drivers/adc/adc_rescale/src/main.c | 50 +++++++++++++++++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay index bf937a69849b..aa146b863690 100644 --- a/tests/drivers/adc/adc_rescale/boards/native_posix.overlay +++ b/tests/drivers/adc/adc_rescale/boards/native_posix.overlay @@ -16,13 +16,20 @@ sensor1: css { compatible = "current-sense-shunt"; - io-channels = <&adc0 0>; + io-channels = <&adc0 1>; shunt-resistor-micro-ohms = <500000>; }; + sensor2: csa { + compatible = "current-sense-amplifier"; + io-channels = <&adc0 2>; + sense-resistor-micro-ohms = <5000>; + sense-gain-mult = <100>; + }; + adc0: adc { compatible = "zephyr,adc-emul"; - nchannels = <2>; + nchannels = <3>; ref-internal-mv = <3300>; ref-external1-mv = <5000>; #io-channel-cells = <1>; @@ -51,4 +58,13 @@ zephyr,acquisition-time = ; zephyr,resolution = <12>; }; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; }; diff --git a/tests/drivers/adc/adc_rescale/src/main.c b/tests/drivers/adc/adc_rescale/src/main.c index 27106f0f76eb..e8af4d4f58a1 100644 --- a/tests/drivers/adc/adc_rescale/src/main.c +++ b/tests/drivers/adc/adc_rescale/src/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #define ADC_TEST_NODE_0 DT_NODELABEL(sensor0) #define ADC_TEST_NODE_1 DT_NODELABEL(sensor1) +#define ADC_TEST_NODE_2 DT_NODELABEL(sensor2) /** * @brief Get ADC emulated device @@ -88,9 +90,9 @@ ZTEST_USER(adc_rescale, test_adc_voltage_divider) } /* - * test_adc_current_sensor + * test_adc_current_sense_shunt */ -static int test_task_current_sensor(void) +static int test_task_current_sense_shunt(void) { int ret; int32_t calculated_current = 0; @@ -122,9 +124,49 @@ static int test_task_current_sensor(void) return TC_PASS; } -ZTEST_USER(adc_rescale, test_adc_current_sensor) +ZTEST_USER(adc_rescale, test_adc_current_sense_shunt) { - zassert_true(test_task_current_sensor() == TC_PASS); + zassert_true(test_task_current_sense_shunt() == TC_PASS); +} + +/* + * test_adc_current_sense_amplifier + */ +static int test_task_current_sense_amplifier(void) +{ + int ret; + int32_t calculated_current = 0; + int32_t input_mv = 3000; + const struct current_sense_amplifier_dt_spec adc_node_2 = + CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(ADC_TEST_NODE_2); + + ret = init_adc(&adc_node_2.port, input_mv); + zassert_equal(ret, 0, "Setting up of the third channel failed with code %d", ret); + + struct adc_sequence sequence = { + .buffer = &calculated_current, + .buffer_size = sizeof(calculated_current), + }; + adc_sequence_init_dt(&adc_node_2.port, &sequence); + + ret = adc_read(adc_node_2.port.dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + ret = adc_raw_to_millivolts_dt(&adc_node_2.port, &calculated_current); + zassert_equal(ret, 0, "adc_raw_to_millivolts_dt() failed with code %d", ret); + + current_sense_amplifier_scale_dt(&adc_node_2, &calculated_current); + + zassert_within(calculated_current, input_mv * 2, MV_OUTPUT_EPS, + "%u != %u should have set value", calculated_current, + input_mv * 2); + + return TC_PASS; +} + +ZTEST_USER(adc_rescale, test_adc_current_sense_amplifier) +{ + zassert_true(test_task_current_sense_amplifier() == TC_PASS); } void *adc_rescale_setup(void) From 5452ef378f1732a56d769e2029b1a631c61d9a56 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 22 Jun 2023 14:21:20 +0200 Subject: [PATCH 0585/2042] Bluetooth: tbs_client: Remove unused subscribe_cnt variable This removes unused subscribe_cnt from bt_tbs_instance. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs_client.c | 3 --- subsys/bluetooth/audio/tbs_internal.h | 1 - 2 files changed, 4 deletions(-) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index fef89d7c5115..62f88ac86725 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -548,9 +548,6 @@ static uint8_t notify_handler(struct bt_conn *conn, if (data == NULL) { LOG_DBG("[UNSUBSCRIBED] 0x%04X", params->value_handle); params->value_handle = 0U; - if (tbs_inst != NULL) { - tbs_inst->subscribe_cnt--; - } return BT_GATT_ITER_STOP; } diff --git a/subsys/bluetooth/audio/tbs_internal.h b/subsys/bluetooth/audio/tbs_internal.h index 95e80fdfe765..edb62972bca7 100644 --- a/subsys/bluetooth/audio/tbs_internal.h +++ b/subsys/bluetooth/audio/tbs_internal.h @@ -331,7 +331,6 @@ struct bt_tbs_instance { uint16_t termination_reason_handle; bool busy; - uint8_t subscribe_cnt; #if defined(CONFIG_BT_TBS_CLIENT_CCID) uint8_t ccid; #endif /* defined(CONFIG_BT_TBS_CLIENT_CCID) */ From a7231a4ca45e628e9efeef669349f5c8a04f0d4c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 22 Jun 2023 14:23:17 +0200 Subject: [PATCH 0586/2042] Bluetooth: aics_client: Remove unused subscribe_cnt variable This removes unused subscribe_cnt from bt_aics_client structure. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/aics_internal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/aics_internal.h b/subsys/bluetooth/audio/aics_internal.h index 6be703debf3d..c4d023bd9469 100644 --- a/subsys/bluetooth/audio/aics_internal.h +++ b/subsys/bluetooth/audio/aics_internal.h @@ -64,7 +64,6 @@ struct bt_aics_client { struct bt_gatt_subscribe_params state_sub_params; struct bt_gatt_subscribe_params status_sub_params; struct bt_gatt_subscribe_params desc_sub_params; - uint8_t subscribe_cnt; bool cp_retried; bool busy; From 6f0dc490e74eb76b093ee42f1667362091fef2ac Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 22 Jun 2023 14:24:32 +0200 Subject: [PATCH 0587/2042] Bluetooth: vocs_client: Remove unused subscribe_cnt variable This removes unused subscribe_cnt from bt_vocs_client. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/vocs_internal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/vocs_internal.h b/subsys/bluetooth/audio/vocs_internal.h index 05cb45b32ec2..83098b679d26 100644 --- a/subsys/bluetooth/audio/vocs_internal.h +++ b/subsys/bluetooth/audio/vocs_internal.h @@ -46,7 +46,6 @@ struct bt_vocs_client { struct bt_gatt_subscribe_params state_sub_params; struct bt_gatt_subscribe_params location_sub_params; struct bt_gatt_subscribe_params desc_sub_params; - uint8_t subscribe_cnt; bool cp_retried; bool busy; From d72c17684c48541f1729237836963aeb81ecef95 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 22 Jun 2023 14:27:10 +0200 Subject: [PATCH 0588/2042] Bluetooth: tbs_client: Fix possible NULL pointer dereference This fixes notification callback that can be called with NULL conn parameter when peer is being unpaired. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs_client.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 62f88ac86725..52f844c783a4 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -543,15 +543,16 @@ static uint8_t notify_handler(struct bt_conn *conn, const void *data, uint16_t length) { uint16_t handle = params->value_handle; - struct bt_tbs_instance *tbs_inst = lookup_inst_by_handle(conn, handle); + struct bt_tbs_instance *tbs_inst; - if (data == NULL) { + if (data == NULL || conn == NULL) { LOG_DBG("[UNSUBSCRIBED] 0x%04X", params->value_handle); params->value_handle = 0U; return BT_GATT_ITER_STOP; } + tbs_inst = lookup_inst_by_handle(conn, handle); if (tbs_inst != NULL) { uint8_t inst_index = tbs_index(conn, tbs_inst); From a9961593626aeaee0a66a9685841666de1ae0e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Thu, 22 Jun 2023 14:48:15 +0200 Subject: [PATCH 0589/2042] Bluetooth: Host: Fix connection reference leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If connection reference is acquired from `bt_conn_lookup_addr_le` but `bt_gatt_ccc_cfg_is_matching_conn` return false the connection was not unreferenced properly. This commit fix the issue by unreferencing the connection if the condition is false. Signed-off-by: Théo Battrel --- subsys/bluetooth/host/gatt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 4d86337ba082..5b5b4c3abb4b 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -2067,9 +2067,12 @@ static struct bt_conn *bt_gatt_ccc_cfg_conn_lookup(const struct bt_gatt_ccc_cfg struct bt_conn *conn; conn = bt_conn_lookup_addr_le(cfg->id, &cfg->peer); + if (conn) { + if (bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { + return conn; + } - if (conn && bt_gatt_ccc_cfg_is_matching_conn(conn, cfg)) { - return conn; + bt_conn_unref(conn); } return NULL; From 93abc2ad7688eaa2d82eb9ffb5224a2a43a29331 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 22 Jun 2023 17:26:21 +0200 Subject: [PATCH 0590/2042] Bluetooth: att: Reset ATT timer when retrying on security error If the remote responds with and security related error the stack tries to increase the security level to satisfy the remote permissions. This fixes missing ATT timer reset on security related ATT Error Response as the ATT operation is considered as complete. < ACL Data TX: Handle 0 flags 0x00 dlen 7 ATT: Read Request (0x0a) len 2 Handle: 0x0084 TMAS: Role > ACL Data RX: Handle 0 flags 0x02 dlen 9 ATT: Error Response (0x01) len 4 Read Request (0x0a) Handle: 0x0084 Error: Insufficient Authentication (0x05) TMAS: Role Error code: 0x05 < ACL Data TX: Handle 0 flags 0x00 dlen 6 SMP: Security Request (0x0b) len 1 Authentication requirement: Bonding, No MITM, SC, No Keypresses = bt: bt_att: ATT Timeout Signed-off-by: Mariusz Skamra --- subsys/bluetooth/host/att.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 108eb7ba30e7..2b14f37aa9c9 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -2457,6 +2457,12 @@ static uint8_t att_error_rsp(struct bt_att_chan *chan, struct net_buf *buf) #if defined(CONFIG_BT_ATT_RETRY_ON_SEC_ERR) /* Check if error can be handled by elevating security. */ if (!att_change_security(chan->chan.chan.conn, err)) { + /* ATT timeout work is normally cancelled in att_handle_rsp. + * However retrying is special case, so the timeout shall + * be cancelled here. + */ + k_work_cancel_delayable(&chan->timeout_work); + chan->req->retrying = true; return 0; } From 6bcc9de7de39d985dfce42beb6e6ddb486cb3b45 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Thu, 22 Jun 2023 17:11:20 +0300 Subject: [PATCH 0591/2042] boards: xtensa: nxp: remove uart overlay Remove uart overlay and add the node to base dts and config. Now, it can be used for multiple samples. Signed-off-by: Iuliana Prodan --- .../xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts | 23 +++++++++++++ .../nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig | 15 +++++++++ .../nxp_adsp_imx8m/nxp_adsp_imx8m_uart.conf | 7 ---- .../nxp_adsp_imx8m_uart.overlay | 33 ------------------- 4 files changed, 38 insertions(+), 40 deletions(-) delete mode 100644 boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.conf delete mode 100644 boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.overlay diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts index ae1b38ba3793..bc5b663f57d4 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include / { model = "nxp_adsp_imx8m"; @@ -14,5 +15,27 @@ chosen { zephyr,sram = &sram0; + + zephyr,console = &uart4; + zephyr,shell-uart = &uart4; + }; +}; + +&pinctrl { + /omit-if-no-ref/ uart4_default: uart4_default { + group0 { + pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, + <&iomuxc_uart4_txd_uart_tx_uart4_tx>; + bias-pull-up; + slew-rate = "slow"; + drive-strength = "x1"; + }; }; }; + +&uart4 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart4_default>; + pinctrl-names = "default"; +}; diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig index 9779d9b3d03a..2aa634b97afe 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig @@ -22,3 +22,18 @@ CONFIG_BUILD_OUTPUT_BIN=n CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_DCACHE_LINE_SIZE=128 + +# enable uart driver +CONFIG_SERIAL=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +# console (remote proc console by default) +CONFIG_CONSOLE=y + +# uart console (overrides remote proc console) +CONFIG_UART_CONSOLE=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.conf b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.conf deleted file mode 100644 index e662fa1f4b7a..000000000000 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.conf +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_CLOCK_CONTROL=y -CONFIG_UART_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_CONSOLE=y -CONFIG_PINCTRL=y diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.overlay b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.overlay deleted file mode 100644 index 24bf474c6069..000000000000 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_uart.overlay +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/ { - chosen { - zephyr,console = &uart4; - zephyr,shell-uart = &uart4; - }; -}; - -&pinctrl { - /omit-if-no-ref/ uart4_default: uart4_default { - group0 { - pinmux = <&iomuxc_uart4_rxd_uart_rx_uart4_rx>, - <&iomuxc_uart4_txd_uart_tx_uart4_tx>; - bias-pull-up; - slew-rate = "slow"; - drive-strength = "x1"; - }; - }; -}; - -&uart4 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart4_default>; - pinctrl-names = "default"; -}; From 3a6045271fa2756308ab406d0062602ceb83201c Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 23 Jun 2023 15:05:03 +0000 Subject: [PATCH 0592/2042] drivers: kscan: use zephyr_syscall_header Add call to zephyr_syscall_header to kscan driver CMakeLists.txt, so that the required syscalls will be generated when kscan drivers are used. Fixes #59710 Signed-off-by: Daniel DeGrasse --- drivers/kscan/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index 973536230883..c6c38222e230 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/kscan.h) + zephyr_library() zephyr_library_sources_ifdef(CONFIG_KSCAN_GT911 kscan_gt911.c) From 4045bab1b785eb8f1dac3627f525e6baaa97499b Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Mon, 12 Jun 2023 18:15:31 +0200 Subject: [PATCH 0593/2042] twister: pytest: Parse report file to get testcases Extended parsing of report.xml file - produced by pytest-twister-harness plugin. Now testcases are properly extracted and added to twister report. Added unit tests. Signed-off-by: Grzegorz Chwierut --- scripts/pylib/twister/twisterlib/handlers.py | 1 + scripts/pylib/twister/twisterlib/harness.py | 125 +++++++-------- .../pylib/twister/twisterlib/testinstance.py | 22 ++- scripts/tests/twister/conftest.py | 2 + .../pytest_integration/test_harness_pytest.py | 142 ++++++++++++++++++ 5 files changed, 226 insertions(+), 66 deletions(-) create mode 100644 scripts/tests/twister/pytest_integration/test_harness_pytest.py diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 7442eaa780bd..5af283cbfc4f 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -40,6 +40,7 @@ logger.setLevel(logging.DEBUG) SUPPORTED_SIMS = ["mdb-nsim", "nsim", "renode", "qemu", "tsim", "armfvp", "xt-sim", "native"] +SUPPORTED_SIMS_IN_PYTEST = ['native', 'qemu'] def terminate_process(proc): diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index f475170d857d..3df794b264af 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations from asyncio.log import logger import platform import re @@ -13,7 +14,8 @@ import time from twisterlib.environment import ZEPHYR_BASE, PYTEST_PLUGIN_INSTALLED -from twisterlib.handlers import terminate_process +from twisterlib.handlers import Handler, terminate_process, SUPPORTED_SIMS_IN_PYTEST +from twisterlib.testinstance import TestInstance logger = logging.getLogger('twister') @@ -21,8 +23,6 @@ _WINDOWS = platform.system() == 'Windows' -SUPPORTED_SIMS_IN_PYTEST = ['native', 'qemu'] - # pylint: disable=anomalous-backslash-in-string result_re = re.compile(".*(PASS|FAIL|SKIP) - (test_)?(.*) in (\\d*[.,]?\\d*) seconds") @@ -49,7 +49,6 @@ def __init__(self): self.matches = OrderedDict() self.ordered = True self.repeat = 1 - self.testcases = [] self.id = None self.fail_on_fault = True self.fault = False @@ -63,7 +62,7 @@ def __init__(self): self.run_id = None self.matched_run_id = False self.run_id_exists = False - self.instance = None + self.instance: TestInstance | None = None self.testcase_output = "" self._match = False @@ -224,7 +223,7 @@ class PytestHarnessException(Exception): class Pytest(Harness): - def configure(self, instance): + def configure(self, instance: TestInstance): super(Pytest, self).configure(instance) self.running_dir = instance.build_dir self.source_dir = instance.testsuite.source_dir @@ -234,16 +233,15 @@ def configure(self, instance): def pytest_run(self, timeout): try: cmd = self.generate_command() - if not cmd: - logger.error('Pytest command not generated, check logs') - return self.run_command(cmd, timeout) except PytestHarnessException as pytest_exception: logger.error(str(pytest_exception)) + self.state = 'failed' + self.instance.reason = str(pytest_exception) finally: if self.reserved_serial: self.instance.handler.make_device_available(self.reserved_serial) - self._apply_instance_status() + self._update_test_status() def generate_command(self): config = self.instance.testsuite.harness_config @@ -260,7 +258,7 @@ def generate_command(self): ] command.extend(pytest_args) - handler = self.instance.handler + handler: Handler = self.instance.handler if handler.options.verbose > 1: command.append('--log-level=DEBUG') @@ -277,7 +275,7 @@ def generate_command(self): raise PytestHarnessException(f'Handling of handler {handler.type_str} not implemented yet') return command - def _generate_parameters_for_hardware(self, handler): + def _generate_parameters_for_hardware(self, handler: Handler): command = ['--device-type=hardware'] hardware = handler.get_hardware() if not hardware: @@ -318,53 +316,26 @@ def _generate_parameters_for_hardware(self, handler): def run_command(self, cmd, timeout): cmd, env = self._update_command_with_env_dependencies(cmd) - with subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - env=env) as proc: + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=env + ) as proc: try: reader_t = threading.Thread(target=self._output_reader, args=(proc,), daemon=True) reader_t.start() reader_t.join(timeout) if reader_t.is_alive(): terminate_process(proc) - logger.warning('Timeout has occurred.') + logger.warning('Timeout has occurred. Can be extended in testspec file. ' + f'Currently set to {timeout} seconds.') + self.instance.reason = 'Pytest timeout' self.state = 'failed' proc.wait(timeout) - - if self.state != 'failed': - tree = ET.parse(self.report_file) - root = tree.getroot() - for child in root: - if child.tag == 'testsuite': - if child.attrib['failures'] != '0': - self.state = "failed" - elif child.attrib['skipped'] != '0': - self.state = "skipped" - elif child.attrib['errors'] != '0': - self.state = "error" - else: - self.state = "passed" - self.instance.execution_time = float(child.attrib['time']) except subprocess.TimeoutExpired: + self.state = 'failed' proc.kill() - self.state = "failed" - except ET.ParseError: - self.state = "failed" - except IOError: - logger.warning("Can't access report.xml") - self.state = "failed" - - tc = self.instance.get_case_or_create(self.id) - if self.state == "passed": - tc.status = "passed" - logger.debug("Pytest cases passed") - elif self.state == "skipped": - tc.status = "skipped" - logger.debug("Pytest cases skipped.") - else: - tc.status = "failed" - logger.info("Pytest cases failed.") @staticmethod def _update_command_with_env_dependencies(cmd): @@ -397,16 +368,52 @@ def _output_reader(proc): logger.debug('PYTEST: %s', line) proc.communicate() - def _apply_instance_status(self): - if self.state: - self.instance.status = self.state - if self.state in ["error", "failed"]: - self.instance.reason = "Pytest failed" - else: - self.instance.status = "failed" - self.instance.reason = "Pytest timeout" - if self.instance.status in ["error", "failed"]: - self.instance.add_missing_case_status("blocked", self.instance.reason) + def _update_test_status(self): + if not self.state: + self.instance.testcases = [] + try: + self._parse_report_file(self.report_file) + except Exception as e: + logger.error(f'Error when parsing file {self.report_file}: {e}') + self.state = 'failed' + finally: + if not self.instance.testcases: + self.instance.init_cases() + + self.instance.status = self.state or 'failed' + if self.instance.status in ['error', 'failed']: + self.instance.reason = self.instance.reason or 'Pytest failed' + self.instance.add_missing_case_status('blocked', self.instance.reason) + + def _parse_report_file(self, report): + tree = ET.parse(report) + root = tree.getroot() + if elem_ts := root.find('testsuite'): + if elem_ts.get('failures') != '0': + self.state = 'failed' + elif elem_ts.get('errors') != '0': + self.state = 'error' + elif elem_ts.get('skipped') == elem_ts.get('tests'): + self.state = 'skipped' + else: + self.state = 'passed' + self.instance.execution_time = float(elem_ts.get('time')) + + for elem_tc in elem_ts.findall('testcase'): + tc = self.instance.get_case_or_create(f"{self.id}.{elem_tc.get('name')}") + tc.duration = float(elem_tc.get('time')) + elem = elem_tc.find('*') + if elem is None: + tc.status = 'passed' + else: + if elem.tag == 'skipped': + tc.status = 'skipped' + elif elem.tag == 'failure': + tc.status = 'failed' + else: + tc.status = 'error' + tc.reason = elem.get('message') + tc.output = elem.text class Gtest(Harness): diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index bc8bc43b1a49..62b0dd8cd335 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -3,7 +3,7 @@ # Copyright (c) 2018-2022 Intel Corporation # Copyright 2022 NXP # SPDX-License-Identifier: Apache-2.0 - +from __future__ import annotations import os import hashlib import random @@ -11,11 +11,19 @@ import shutil import glob -from twisterlib.testsuite import TestCase +from twisterlib.testsuite import TestCase, TestSuite +from twisterlib.platform import Platform from twisterlib.error import BuildError from twisterlib.size_calc import SizeCalculator -from twisterlib.handlers import Handler, SimulationHandler, BinaryHandler, QEMUHandler, DeviceHandler, SUPPORTED_SIMS -from twisterlib.harness import SUPPORTED_SIMS_IN_PYTEST +from twisterlib.handlers import ( + Handler, + SimulationHandler, + BinaryHandler, + QEMUHandler, + DeviceHandler, + SUPPORTED_SIMS, + SUPPORTED_SIMS_IN_PYTEST, +) logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) @@ -33,8 +41,8 @@ class TestInstance: def __init__(self, testsuite, platform, outdir): - self.testsuite = testsuite - self.platform = platform + self.testsuite: TestSuite = testsuite + self.platform: Platform = platform self.status = None self.reason = "Unknown" @@ -51,7 +59,7 @@ def __init__(self, testsuite, platform, outdir): self.domains = None self.run = False - self.testcases = [] + self.testcases: list[TestCase] = [] self.init_cases() self.filters = [] self.filter_type = None diff --git a/scripts/tests/twister/conftest.py b/scripts/tests/twister/conftest.py index 86f40c12bf38..232c9c374584 100644 --- a/scripts/tests/twister/conftest.py +++ b/scripts/tests/twister/conftest.py @@ -9,6 +9,8 @@ import sys import pytest +pytest_plugins = ["pytester"] + ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts")) diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py new file mode 100644 index 000000000000..db7bf389fbdc --- /dev/null +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -0,0 +1,142 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import pytest +import textwrap + +from unittest import mock +from pathlib import Path + +from twisterlib.harness import Pytest +from twisterlib.testsuite import TestSuite +from twisterlib.testinstance import TestInstance +from twisterlib.platform import Platform + + +@pytest.fixture +def testinstance() -> TestInstance: + testsuite = TestSuite('.', 'samples/hello', 'unit.test') + testsuite.harness_config = {} + testsuite.ignore_faults = False + platform = Platform() + + testinstance = TestInstance(testsuite, platform, 'outdir') + testinstance.handler = mock.Mock() + testinstance.handler.options = mock.Mock() + testinstance.handler.options.verbose = 1 + testinstance.handler.type_str = 'native' + return testinstance + + +@pytest.mark.parametrize('device_type', ['native', 'qemu']) +def test_pytest_command(testinstance: TestInstance, device_type): + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + + testinstance.handler.type_str = device_type + ref_command = [ + 'pytest', + 'samples/hello/pytest', + f'--build-dir={testinstance.build_dir}', + f'--junit-xml={testinstance.build_dir}/report.xml', + f'--device-type={device_type}' + ] + + command = pytest_harness.generate_command() + for c in ref_command: + assert c in command + + +def test_if_report_is_parsed(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + def test_1(): + pass + def test_2(): + pass + """) + test_file = pytester.path / 'test_valid.py' + test_file.write_text(test_file_content) + report_file = Path('report.xml') + result = pytester.runpytest( + str(test_file), + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(passed=2) + 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) == 2 + for tc in testinstance.testcases: + assert tc.status == "passed" + + +def test_if_report_with_error(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + def test_exp(): + raise Exception('Test error') + def test_err(): + assert False + """) + test_file = pytester.path / 'test_error.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(failed=2) + 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 == "failed" + assert testinstance.status == "failed" + assert len(testinstance.testcases) == 2 + for tc in testinstance.testcases: + assert tc.status == "failed" + assert tc.output + assert tc.reason + + +def test_if_report_with_skip(pytester, testinstance: TestInstance): + test_file_content = textwrap.dedent(""" + import pytest + @pytest.mark.skip('Test skipped') + def test_skip_1(): + pass + def test_skip_2(): + pytest.skip('Skipped on runtime') + """) + test_file = pytester.path / 'test_skip.py' + test_file.write_text(test_file_content) + report_file = pytester.path / 'report.xml' + result = pytester.runpytest( + str(test_file), + f'--junit-xml={str(report_file)}' + ) + result.assert_outcomes(skipped=2) + 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" + assert len(testinstance.testcases) == 2 + for tc in testinstance.testcases: + assert tc.status == "skipped" From daa505780064437745d27a8b5862d54e3269a18e Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Tue, 20 Jun 2023 06:50:28 +0100 Subject: [PATCH 0594/2042] ARC: MWDT: update docs to reflect recent changes Update docs to reflect recent changes: * ARCMWDT_TOOLCHAIN_PATH auto detecting * Usage GNU helper tools from Zephyr SDK Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- .../toolchains/designware_arc_mwdt.rst | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/doc/develop/toolchains/designware_arc_mwdt.rst b/doc/develop/toolchains/designware_arc_mwdt.rst index cac9671da8fa..24d5d53dc1b2 100644 --- a/doc/develop/toolchains/designware_arc_mwdt.rst +++ b/doc/develop/toolchains/designware_arc_mwdt.rst @@ -3,28 +3,27 @@ DesignWare ARC MetaWare Development Toolkit (MWDT) ################################################## -#. You need to have `ARC MWDT - `_ installed on your - host. +#. You need to have `ARC MWDT `_ installed on + your host. -#. :ref:`Set these environment variables `: - - - Set :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``arcmwdt``. - - Set :envvar:`ARCMWDT_TOOLCHAIN_PATH` to the toolchain installation - directory. MWDT installation provides :envvar:`METAWARE_ROOT` so simply set - :envvar:`ARCMWDT_TOOLCHAIN_PATH` to ``$METAWARE_ROOT/../`` (Linux) - or ``%METAWARE_ROOT%\..\`` (Windows) +#. You need to have :ref:`Zephyr SDK ` installed on your host. .. note:: - Even though ARC MWDT compiler is used for Zephyr RTOS sources compilation, still the GNU - preprocessor & GNU objcopy might be used for some steps like DTS preprocessing and ``.bin`` - file generation. Hence we need to have either ARC or host GNU tools in :envvar:`PATH`. - Currently Zephyr looks for: + A Zephyr SDK is used as a source of tools like device tree compiler (DTC), QEMU, etc... + Even though ARC MWDT toolchain is used for Zephyr RTOS build, still the GNU preprocessor & GNU + objcopy might be used for some steps like device tree preprocessing and ``.bin`` file + generation. We used Zephyr SDK as a source of these ARC GNU tools as well. - * objcopy binaries: ``arc-elf32-objcopy`` or ``arc-linux-objcopy`` or ``objcopy`` - * gcc binaries: ``arc-elf32-gcc`` or ``arc-linux-gcc`` or ``gcc`` +#. :ref:`Set these environment variables `: + + - Set :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``arcmwdt``. + - Set :envvar:`ARCMWDT_TOOLCHAIN_PATH` to the toolchain installation directory. MWDT installation + provides :envvar:`METAWARE_ROOT` so simply set :envvar:`ARCMWDT_TOOLCHAIN_PATH` to + ``$METAWARE_ROOT/../`` (Linux) or ``%METAWARE_ROOT%\..\`` (Windows). - This list can be extended or modified in future. + .. tip:: + If you have only one ARC MWDT toolchain version installed on your machine you may skip setting + :envvar:`ARCMWDT_TOOLCHAIN_PATH` - it would be detected automatically. #. To check that you have set these variables correctly in your current environment, follow these example shell sessions (the @@ -36,10 +35,10 @@ DesignWare ARC MetaWare Development Toolkit (MWDT) $ echo $ZEPHYR_TOOLCHAIN_VARIANT arcmwdt $ echo $ARCMWDT_TOOLCHAIN_PATH - /home/you/ARC/MWDT_2019.12/ + /home/you/ARC/MWDT_2023.03/ # Windows: > echo %ZEPHYR_TOOLCHAIN_VARIANT% arcmwdt > echo %ARCMWDT_TOOLCHAIN_PATH% - C:\ARC\MWDT_2019.12\ + C:\ARC\MWDT_2023.03\ From a64499dae130415181a89a12f11973ac35071e91 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 19 Jun 2023 12:23:06 +0200 Subject: [PATCH 0595/2042] doc licensing: Remove get_maintainers.pl There is no get_maintainers.pl in the tree, and hasn't been for as long as the git history lasts. Remove its mentiona as a GPL component. get_maintainers.py is Apache 2. Signed-off-by: Alberto Escolar Piedras --- doc/LICENSING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/LICENSING.rst b/doc/LICENSING.rst index 42a997004ede..a69811df8547 100644 --- a/doc/LICENSING.rst +++ b/doc/LICENSING.rst @@ -16,7 +16,7 @@ licensing in this document. .. _GPLv2 License: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/COPYING -*scripts/{checkpatch.pl,checkstack.pl,get_maintainers.pl,spelling.txt}* +*scripts/{checkpatch.pl,checkstack.pl,spelling.txt}* *Origin:* Linux Kernel *Licensing:* `GPLv2 License`_ From eccefc4dcc3b6ef401f7574b910198faa1bb43e2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 19 Jun 2023 12:28:16 +0200 Subject: [PATCH 0596/2042] doc: contribute external: Fix link and add if not Apache2 The link to the zephyr_licensing page was broken => fix it. Also add a relatively evident if to the list: There is no need to add an entry to the licensing list if the integrated code is Apache 2. Signed-off-by: Alberto Escolar Piedras --- doc/contribute/external.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index 8d0bf379a2cc..2ce1b392edd9 100644 --- a/doc/contribute/external.rst +++ b/doc/contribute/external.rst @@ -87,7 +87,8 @@ automatically implies that the imported source code becomes part of the - The code is subject to the same checks and verification requirements as the rest of the code in the main tree, including static analysis - All files contain an SPDX tag if not already present -- An entry is added to the `licensing page ` +- If the source is not Apache 2.0 licensed, + an entry is added to the :ref:`licensing page `. This mode of integration can be applicable to both small and large external codebases, but it is typically used more commonly with the former. From 88dd32c38c7f8ed363c2b59104404dc201abccb4 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 24 Jun 2023 10:10:53 -0400 Subject: [PATCH 0597/2042] doc: services: posix: fix setvbuf typo Fix a typo in the spelling of `setvbuf()`. Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 45d3496dc4d5..84e0ea2b05d5 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -430,7 +430,7 @@ POSIX_DEVICE_IO read(),yes scanf(), setbuf(), - etvbuf(), + setvbuf(), stderr,yes stdin,yes stdout,yes From 675a66072791e0e6a18cb02ce157a0fb27a522bb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 24 Jun 2023 10:13:41 -0400 Subject: [PATCH 0598/2042] doc: services: posix: _POSIX_THREAD_PRIO_INHERIT unsupported _POSIX_THREAD_PRIO_INHERIT was mistakenly marked supported in commit a07774eada presumably because we have prototypes for the functions below. pthread_mutexattr_getprotocol() pthread_mutexattr_setprotocol() However, the functions are not actually implemented in Zephyr. Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 84e0ea2b05d5..edc384f6e908 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -97,7 +97,7 @@ Zephyr. _POSIX_THREAD_ATTR_STACKADDR,yes _POSIX_THREAD_ATTR_STACKSIZE,yes _POSIX_THREAD_CPUTIME, - _POSIX_THREAD_PRIO_INHERIT,yes + _POSIX_THREAD_PRIO_INHERIT, _POSIX_THREAD_PRIO_PROTECT, _POSIX_THREAD_PRIORITY_SCHEDULING,yes _POSIX_THREAD_SPORADIC_SERVER, From 64a477342d81dd6e0eeed55912e9d701a00515a5 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 24 Jun 2023 10:45:32 -0400 Subject: [PATCH 0599/2042] doc: services: posix: pthread_condattr_destroy and init supported The functions pthread_condattr_destroy() and pthread_condattr_init() are implemented (they just do nothing). Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index edc384f6e908..79b23e5fbc36 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -151,8 +151,8 @@ multiple processes. pthread_cond_signal(),yes pthread_cond_timedwait(),yes pthread_cond_wait(),yes - pthread_condattr_destroy(), - pthread_condattr_init(), + pthread_condattr_destroy(),yes + pthread_condattr_init(),yes pthread_create(),yes pthread_detach(),yes pthread_equal(), From b416a90672625881f229a480b0fb578468f33c57 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 24 Jun 2023 10:49:53 -0400 Subject: [PATCH 0600/2042] doc: services: posix: pthread_mutexattr_destroy init supported The functions pthread_mutexattr_destroy() and pthread_mutexattr_init() are implemented (they just do nothing). Signed-off-by: Christopher Friedt --- doc/services/portability/posix.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 79b23e5fbc36..b2a807d4f059 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -167,8 +167,8 @@ multiple processes. pthread_mutex_lock(),yes pthread_mutex_trylock(),yes pthread_mutex_unlock(),yes - pthread_mutexattr_destroy(), - pthread_mutexattr_init(), + pthread_mutexattr_destroy(),yes + pthread_mutexattr_init(),yes pthread_once(),yes pthread_self(),yes pthread_setcancelstate(),yes From b158c52e244a97423804d2eb6f4e2dd45fac4630 Mon Sep 17 00:00:00 2001 From: Alexander Razinkov Date: Mon, 22 May 2023 18:52:52 +0300 Subject: [PATCH 0601/2042] devicetree: support of 64-bit addresses from devicetree Usage of 64-bit address constants from devicetree without a UINT64_C wrapping macro results in the following warning and the cut-off of the address value: "warning: integer constant is so large that it is unsigned" This change extends devicetree API adding few wrappers over the address constant getters which add ULL size suffix to an address integer literal when the appearance of 64-bit address values is possible Signed-off-by: Alexander Razinkov --- dts/bindings/test/vnd,reg-holder-64.yaml | 15 ++++++ include/zephyr/devicetree.h | 69 ++++++++++++++++++++++++ tests/lib/devicetree/api/app.overlay | 12 +++++ tests/lib/devicetree/api/src/main.c | 32 +++++++++++ 4 files changed, 128 insertions(+) create mode 100644 dts/bindings/test/vnd,reg-holder-64.yaml diff --git a/dts/bindings/test/vnd,reg-holder-64.yaml b/dts/bindings/test/vnd,reg-holder-64.yaml new file mode 100644 index 000000000000..0e0800e784b2 --- /dev/null +++ b/dts/bindings/test/vnd,reg-holder-64.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Syntacore +# SPDX-License-Identifier: Apache-2.0 + +description: Test 64-bit register property container + +compatible: "vnd,reg-holder-64" + +include: [base.yaml] + +properties: + reg: + required: true + + reg-names: + required: true diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index ed8db9edfc70..c9aab6653431 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -18,6 +18,10 @@ #include +#if !defined(_LINKER) && !defined(_ASMLANGUAGE) +#include +#endif + #include /** @@ -2219,6 +2223,18 @@ */ #define DT_REG_ADDR(node_id) DT_REG_ADDR_BY_IDX(node_id, 0) +/** + * @brief 64-bit version of DT_REG_ADDR() + * + * This macro version adds the appropriate suffix for 64-bit unsigned + * integer literals. + * Note that this macro is equivalent to DT_REG_ADDR() in linker/ASM context. + * + * @param node_id node identifier + * @return node's register block address + */ +#define DT_REG_ADDR_U64(node_id) DT_U64_C(DT_REG_ADDR(node_id)) + /** * @brief Get a node's (only) register block size * @@ -2237,6 +2253,21 @@ #define DT_REG_ADDR_BY_NAME(node_id, name) \ DT_CAT4(node_id, _REG_NAME_, name, _VAL_ADDRESS) +/** + * @brief 64-bit version of DT_REG_ADDR_BY_NAME() + * + * This macro version adds the appropriate suffix for 64-bit unsigned + * integer literals. + * Note that this macro is equivalent to DT_REG_ADDR_BY_NAME() in + * linker/ASM context. + * + * @param node_id node identifier + * @param name lowercase-and-underscores register specifier name + * @return address of the register block specified by name + */ +#define DT_REG_ADDR_BY_NAME_U64(node_id, name) \ + DT_U64_C(DT_REG_ADDR_BY_NAME(node_id, name)) + /** * @brief Get a register block's size by name * @param node_id node identifier @@ -3681,6 +3712,21 @@ #define DT_INST_REG_ADDR_BY_NAME(inst, name) \ DT_REG_ADDR_BY_NAME(DT_DRV_INST(inst), name) +/** + * @brief 64-bit version of DT_INST_REG_ADDR_BY_NAME() + * + * This macro version adds the appropriate suffix for 64-bit unsigned + * integer literals. + * Note that this macro is equivalent to DT_INST_REG_ADDR_BY_NAME() in + * linker/ASM context. + * + * @param inst instance number + * @param name lowercase-and-underscores register specifier name + * @return address of the register block with the given @p name + */ +#define DT_INST_REG_ADDR_BY_NAME_U64(inst, name) \ + DT_U64_C(DT_INST_REG_ADDR_BY_NAME(inst, name)) + /** * @brief Get a `DT_DRV_COMPAT`'s register block size by name * @param inst instance number @@ -3697,6 +3743,19 @@ */ #define DT_INST_REG_ADDR(inst) DT_INST_REG_ADDR_BY_IDX(inst, 0) +/** + * @brief 64-bit version of DT_INST_REG_ADDR() + * + * This macro version adds the appropriate suffix for 64-bit unsigned + * integer literals. + * Note that this macro is equivalent to DT_INST_REG_ADDR() in + * linker/ASM context. + * + * @param inst instance number + * @return instance's register block address + */ +#define DT_INST_REG_ADDR_U64(inst) DT_U64_C(DT_INST_REG_ADDR(inst)) + /** * @brief Get a `DT_DRV_COMPAT`'s (only) register block size * @param inst instance number @@ -4172,6 +4231,16 @@ #define DT_INST_NODE_HAS_PROP_AND_OR(inst, prop) \ DT_INST_NODE_HAS_PROP(inst, prop) || +/** + * @def DT_U64_C + * @brief Macro to add ULL postfix to the devicetree address constants + */ +#if defined(_LINKER) || defined(_ASMLANGUAGE) +#define DT_U64_C(_v) (_v) +#else +#define DT_U64_C(_v) UINT64_C(_v) +#endif + /** @endcond */ /* have these last so they have access to all previously defined macros */ diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 0a915b1f31ff..49c71263740a 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -621,4 +621,16 @@ val = "XA XPLUS XB", "XC XPLUS XD", "XA XMINUS XB", "XC XMINUS XD"; }; }; + + test_64 { + #address-cells = < 2 >; + #size-cells = < 0 >; + + test_reg_64: reg-holder-64@ffffffff11223344 { + compatible = "vnd,reg-holder-64"; + reg = < 0xffffffff 0x11223344>; + status = "okay"; + reg-names = "test_name"; + }; + }; }; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 55c92fdc9de5..d173e3357f25 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -39,6 +39,7 @@ #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_I2C DT_NODELABEL(test_i2c) #define TEST_I2C_DEV DT_PATH(test, i2c_11112222, test_i2c_dev_10) @@ -546,6 +547,9 @@ ZTEST(devicetree_api, test_reg) /* DT_REG_ADDR */ zassert_equal(DT_REG_ADDR(TEST_ABCD1234), 0xabcd1234, ""); + /* DT_REG_ADDR_U64 */ + zassert_equal(DT_REG_ADDR_U64(TEST_ABCD1234), 0xabcd1234, ""); + /* DT_REG_SIZE */ zassert_equal(DT_REG_SIZE(TEST_ABCD1234), 0x500, ""); @@ -553,6 +557,10 @@ ZTEST(devicetree_api, test_reg) zassert_equal(DT_REG_ADDR_BY_NAME(TEST_ABCD1234, one), 0xabcd1234, ""); zassert_equal(DT_REG_ADDR_BY_NAME(TEST_ABCD1234, two), 0x98765432, ""); + /* DT_REG_ADDR_BY_NAME_U64 */ + zassert_equal(DT_REG_ADDR_BY_NAME_U64(TEST_ABCD1234, one), 0xabcd1234, ""); + zassert_equal(DT_REG_ADDR_BY_NAME_U64(TEST_ABCD1234, two), 0x98765432, ""); + /* DT_REG_SIZE_BY_NAME */ zassert_equal(DT_REG_SIZE_BY_NAME(TEST_ABCD1234, one), 0x500, ""); zassert_equal(DT_REG_SIZE_BY_NAME(TEST_ABCD1234, two), 0xff, ""); @@ -576,6 +584,9 @@ ZTEST(devicetree_api, test_reg) /* DT_INST_REG_ADDR */ zassert_equal(DT_INST_REG_ADDR(0), 0x9999aaaa, ""); + /* DT_INST_REG_ADDR_U64 */ + zassert_equal(DT_INST_REG_ADDR_U64(0), 0x9999aaaa, ""); + /* DT_INST_REG_SIZE */ zassert_equal(DT_INST_REG_SIZE(0), 0x1000, ""); @@ -583,11 +594,32 @@ ZTEST(devicetree_api, test_reg) zassert_equal(DT_INST_REG_ADDR_BY_NAME(0, first), 0x9999aaaa, ""); zassert_equal(DT_INST_REG_ADDR_BY_NAME(0, second), 0xbbbbcccc, ""); + /* DT_INST_REG_ADDR_BY_NAME_U64 */ + zassert_equal(DT_INST_REG_ADDR_BY_NAME_U64(0, first), 0x9999aaaa, ""); + zassert_equal(DT_INST_REG_ADDR_BY_NAME_U64(0, second), 0xbbbbcccc, ""); + /* DT_INST_REG_SIZE_BY_NAME */ zassert_equal(DT_INST_REG_SIZE_BY_NAME(0, first), 0x1000, ""); zassert_equal(DT_INST_REG_SIZE_BY_NAME(0, second), 0x3f, ""); } +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT vnd_reg_holder_64 +ZTEST(devicetree_api, test_reg_64) +{ + /* DT_REG_ADDR_U64 */ + zassert_equal(DT_REG_ADDR_U64(TEST_64BIT), 0xffffffff11223344, ""); + + /* DT_REG_ADDR_BY_NAME_U64 */ + zassert_equal(DT_REG_ADDR_BY_NAME_U64(TEST_64BIT, test_name), 0xffffffff11223344, ""); + + /* DT_INST_REG_ADDR_U64 */ + zassert_equal(DT_INST_REG_ADDR_U64(0), 0xffffffff11223344, ""); + + /* DT_INST_REG_ADDR_BY_NAME_U64 */ + zassert_equal(DT_INST_REG_ADDR_BY_NAME_U64(0, test_name), 0xffffffff11223344, ""); +} + #undef DT_DRV_COMPAT #define DT_DRV_COMPAT vnd_interrupt_holder ZTEST(devicetree_api, test_irq) From cb491cacad74bd81a771564add67f722f6c10796 Mon Sep 17 00:00:00 2001 From: Alexander Razinkov Date: Wed, 24 May 2023 09:50:43 +0300 Subject: [PATCH 0602/2042] drivers: support 64-bit addresses from devicetree for PLIC, MTIMER, UART Usage of 64-bit address constants from devicetree without an UINT64_C wrapping macro results in the following warning and the cut-off of the address value: "warning: integer constant is so large that it is unsigned" This change fixes such issue for PLIC, MTIMER and UART in case they are used with some 64-bit RISC-V platforms Signed-off-by: Alexander Razinkov --- drivers/interrupt_controller/intc_plic.c | 6 +++--- drivers/timer/riscv_machine_timer.c | 6 +++--- include/zephyr/sys/device_mmio.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index d7958ad9b4a1..11d41e2f191a 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -22,9 +22,9 @@ #include #define PLIC_MAX_PRIO DT_INST_PROP(0, riscv_max_priority) -#define PLIC_PRIO DT_INST_REG_ADDR_BY_NAME(0, prio) -#define PLIC_IRQ_EN DT_INST_REG_ADDR_BY_NAME(0, irq_en) -#define PLIC_REG DT_INST_REG_ADDR_BY_NAME(0, reg) +#define PLIC_PRIO DT_INST_REG_ADDR_BY_NAME_U64(0, prio) +#define PLIC_IRQ_EN DT_INST_REG_ADDR_BY_NAME_U64(0, irq_en) +#define PLIC_REG DT_INST_REG_ADDR_BY_NAME_U64(0, reg) #define PLIC_IRQS (CONFIG_NUM_IRQS - CONFIG_2ND_LVL_ISR_TBL_OFFSET) #define PLIC_EN_SIZE ((PLIC_IRQS >> 5) + 1) diff --git a/drivers/timer/riscv_machine_timer.c b/drivers/timer/riscv_machine_timer.c index f4ac7afe4d43..7ddbc359dfa7 100644 --- a/drivers/timer/riscv_machine_timer.c +++ b/drivers/timer/riscv_machine_timer.c @@ -67,9 +67,9 @@ #define DT_DRV_COMPAT scr_machine_timer #define MTIMER_HAS_DIVIDER -#define MTIMEDIV_REG (DT_INST_REG_ADDR(0) + 4) -#define MTIME_REG (DT_INST_REG_ADDR(0) + 8) -#define MTIMECMP_REG (DT_INST_REG_ADDR(0) + 16) +#define MTIMEDIV_REG (DT_INST_REG_ADDR_U64(0) + 4) +#define MTIME_REG (DT_INST_REG_ADDR_U64(0) + 8) +#define MTIMECMP_REG (DT_INST_REG_ADDR_U64(0) + 16) #define TIMER_IRQN DT_INST_IRQN(0) #endif diff --git a/include/zephyr/sys/device_mmio.h b/include/zephyr/sys/device_mmio.h index 887ea7ee18e7..bc28c3e91e44 100644 --- a/include/zephyr/sys/device_mmio.h +++ b/include/zephyr/sys/device_mmio.h @@ -116,12 +116,12 @@ struct z_device_mmio_rom { #define Z_DEVICE_MMIO_ROM_INITIALIZER(node_id) \ { \ - .addr = DT_REG_ADDR(node_id) \ + .addr = (mm_reg_t)DT_REG_ADDR_U64(node_id) \ } #define Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(name, node_id) \ { \ - .addr = DT_REG_ADDR_BY_NAME(node_id, name) \ + .addr = (mm_reg_t)DT_REG_ADDR_BY_NAME_U64(node_id, name) \ } #endif /* DEVICE_MMIO_IS_IN_RAM */ From 89f15cb2f30c324bfb47d5b07edec9a7411f8ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 23 Jun 2023 11:54:50 +0200 Subject: [PATCH 0603/2042] doc: release: update dates to ISO 8601 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write dates as ISO 8601 as previous notation could be confusing. Signed-off-by: Benjamin Cabé --- doc/releases/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/releases/index.rst b/doc/releases/index.rst index bb6c0b1f73b1..31c327081e81 100644 --- a/doc/releases/index.rst +++ b/doc/releases/index.rst @@ -50,15 +50,15 @@ Supported Releases +-----------------+----------------+---------------+ | Release | Release date | EOL | +=================+================+===============+ -| `Zephyr 2.7.5`_ | 01/06/2023 | 31/08/2024 | +| `Zephyr 2.7.5`_ | 2023-06-01 | 2024-08-31 | +-----------------+----------------+---------------+ -| `Zephyr 3.3.0`_ | 19/02/2023 | 31/10/2023 | +| `Zephyr 3.3.0`_ | 2023-02-19 | 2023-10-31 | +-----------------+----------------+---------------+ -| `Zephyr 3.2.0`_ | 30/09/2022 | 31/06/2023 | +| `Zephyr 3.2.0`_ | 2022-09-30 | 2023-06-30 | +-----------------+----------------+---------------+ -As of 01/01/2022, LTS1 (1.14.x) is not supported and has reached end of life (EOL). +As of 2022-01-01, LTS1 (1.14.x) is not supported and has reached end of life (EOL). Release Notes ************* From e7414495fa4fd188ca3aec07a33d02d873d8d7d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Fri, 23 Jun 2023 11:56:35 +0200 Subject: [PATCH 0604/2042] doc: release: add Zephyr 3.4 as supported release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Zephyr 3.4 as a supported release until end of Feb 2024. Signed-off-by: Benjamin Cabé --- doc/releases/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/index.rst b/doc/releases/index.rst index 31c327081e81..27571f65b315 100644 --- a/doc/releases/index.rst +++ b/doc/releases/index.rst @@ -52,6 +52,8 @@ Supported Releases +=================+================+===============+ | `Zephyr 2.7.5`_ | 2023-06-01 | 2024-08-31 | +-----------------+----------------+---------------+ +| `Zephyr 3.4.0`_ | 2023-06-16 | 2024-02-29 | ++-----------------+----------------+---------------+ | `Zephyr 3.3.0`_ | 2023-02-19 | 2023-10-31 | +-----------------+----------------+---------------+ | `Zephyr 3.2.0`_ | 2022-09-30 | 2023-06-30 | @@ -95,3 +97,4 @@ specific release and can be found at https://docs.zephyrproject.org/. .. _`Zephyr 2.7.5`: https://docs.zephyrproject.org/2.7.5/ .. _`Zephyr 3.2.0`: https://docs.zephyrproject.org/3.2.0/ .. _`Zephyr 3.3.0`: https://docs.zephyrproject.org/3.3.0/ +.. _`Zephyr 3.4.0`: https://docs.zephyrproject.org/3.4.0/ From 584aa4fe1a8f3bc40078a31ce1ff5e0ee09f6bb5 Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Fri, 23 Jun 2023 08:27:41 -0500 Subject: [PATCH 0605/2042] boards: bl652_dvk: Fix compatible field Compatible field should properly represent the manufacturer and board name. Signed-off-by: Ryan Erickson --- boards/arm/bl652_dvk/bl652_dvk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/bl652_dvk/bl652_dvk.dts b/boards/arm/bl652_dvk/bl652_dvk.dts index b601664bb30a..d524ac0daa21 100644 --- a/boards/arm/bl652_dvk/bl652_dvk.dts +++ b/boards/arm/bl652_dvk/bl652_dvk.dts @@ -11,7 +11,7 @@ / { model = "Laird BL652 DVK"; - compatible = "laird,bl652_dvk"; + compatible = "lairdconnect,bl652_dvk"; chosen { zephyr,console = &uart0; From 7e8d94b9d7e2684cc8f36cc2eb56f05616eae1cc Mon Sep 17 00:00:00 2001 From: Ryan Erickson Date: Fri, 23 Jun 2023 08:28:23 -0500 Subject: [PATCH 0606/2042] boards: bl654_dvk: Fix compatible field Compatible field should properly represent the manufacturer and board name. Signed-off-by: Ryan Erickson --- boards/arm/bl654_dvk/bl654_dvk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/bl654_dvk/bl654_dvk.dts b/boards/arm/bl654_dvk/bl654_dvk.dts index e2a48f9d5b0f..c43c5fab4933 100644 --- a/boards/arm/bl654_dvk/bl654_dvk.dts +++ b/boards/arm/bl654_dvk/bl654_dvk.dts @@ -11,7 +11,7 @@ / { model = "Laird BL654 Dev Kit"; - compatible = "nordic,pca10056-dk"; + compatible = "lairdconnect,bl654_dvk"; chosen { zephyr,console = &uart0; From a44f61c5f54d47b003a91152ccd3ddcb95ab59eb Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 15 Jun 2023 14:57:43 +0200 Subject: [PATCH 0607/2042] tests: lib: devicetree: api: test the 'reserved' status The `reserved` status, even though supported, was not tested. Add coverage for it. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/test/vnd,reserved-compat.yaml | 8 ++++++++ tests/lib/devicetree/api/app.overlay | 18 +++++++++++++++++- tests/lib/devicetree/api/src/main.c | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/test/vnd,reserved-compat.yaml diff --git a/dts/bindings/test/vnd,reserved-compat.yaml b/dts/bindings/test/vnd,reserved-compat.yaml new file mode 100644 index 000000000000..f09079e49acb --- /dev/null +++ b/dts/bindings/test/vnd,reserved-compat.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Test reserved compatible + +compatible: "vnd,reserved-compat" + +include: base.yaml diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 49c71263740a..03fd7765570d 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -105,7 +105,7 @@ }; /* - * This should be the only node with this + * disabled/reserved should be the only nodes with their * compatible in the tree. */ disabled-node@0 { @@ -114,6 +114,12 @@ status = "disabled"; }; + reserved-node@0 { + compatible = "vnd,reserved-node"; + reg = < 0x0 0x1000 >; + status = "reserved"; + }; + disabled_gpio: gpio@0 { compatible = "vnd,gpio-device"; gpio-controller; @@ -124,6 +130,16 @@ status = "disabled"; }; + reserved_gpio: gpio@1 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0x1 0x1000 >; + interrupts = <3 1>; + #gpio-cells = < 0x2 >; + label = "TEST_GPIO_1"; + status = "reserved"; + }; + test_no_status: intc_no_status@0 { compatible = "vnd,intc"; reg = <0x0 0x1000>; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index d173e3357f25..587c56a38267 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -293,6 +293,7 @@ ZTEST(devicetree_api, test_has_compat) zassert_true(DT_HAS_COMPAT_STATUS_OKAY(vnd_gpio_device), ""); zassert_true(DT_HAS_COMPAT_STATUS_OKAY(vnd_gpio_device), ""); zassert_false(DT_HAS_COMPAT_STATUS_OKAY(vnd_disabled_compat), ""); + zassert_false(DT_HAS_COMPAT_STATUS_OKAY(vnd_reserved_compat), ""); zassert_equal(TA_HAS_COMPAT(vnd_array_holder), 1, ""); zassert_equal(TA_HAS_COMPAT(vnd_undefined_compat), 1, ""); @@ -309,16 +310,29 @@ ZTEST(devicetree_api, test_has_status) 1, ""); zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_gpio_1), disabled), 0, ""); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_gpio_1), reserved), + 0, ""); zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_no_status), okay), 1, ""); zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_no_status), disabled), 0, ""); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_no_status), reserved), + 0, ""); zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(disabled_gpio), disabled), 1, ""); zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(disabled_gpio), okay), 0, ""); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(disabled_gpio), reserved), + 0, ""); + + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(reserved_gpio), reserved), + 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(reserved_gpio), disabled), + 0, ""); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(reserved_gpio), okay), + 0, ""); } ZTEST(devicetree_api, test_bus) From a0418f18219750138f1a4497bcbed9e51cf75069 Mon Sep 17 00:00:00 2001 From: Mark Kettner Date: Thu, 22 Jun 2023 15:47:11 +0200 Subject: [PATCH 0608/2042] modem_shell: fix compilation error. fix error: 'struct modem_shell_user_data' has no member named 'shell' Signed-off-by: Mark Kettner --- drivers/modem/modem_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/modem/modem_shell.c b/drivers/modem/modem_shell.c index b613da845588..ba824a3289a0 100644 --- a/drivers/modem/modem_shell.c +++ b/drivers/modem/modem_shell.c @@ -159,7 +159,7 @@ static void uart_mux_cb(const struct device *uart, const struct device *dev, int dlci_address, void *user_data) { struct modem_shell_user_data *data = user_data; - const struct shell *sh = data->shell; + const struct shell *sh = data->sh; int *count = data->user_data; const char *ch = "?"; @@ -235,7 +235,7 @@ static int cmd_modem_info(const struct shell *sh, size_t argc, char *argv[]) struct modem_shell_user_data user_data; int count = 0; - user_data.shell = sh; + user_data.sh = sh; user_data.user_data = &count; uart_mux_foreach(uart_mux_cb, &user_data); From e4167632df7eab91a2dd15e9def9a87b26cb4ab3 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 23 Jun 2023 01:53:52 +0530 Subject: [PATCH 0609/2042] net: wifi: Fix a typo Typo in TWT error strings. Signed-off-by: Chaitanya Tata --- 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 75139ae36c48..806424475f09 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -355,7 +355,7 @@ enum wifi_twt_fail_reason { }; static const char * const twt_err_code_tbl[] = { - [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecfied", + [WIFI_TWT_FAIL_UNSPECIFIED] = "Unspecified", [WIFI_TWT_FAIL_CMD_EXEC_FAIL] = "Command Execution failed", [WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED] = "Operation not supported", From 456859a65dd4ca7bc64bb2aa4c68013eecf499e7 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 23 Jun 2023 02:06:18 +0530 Subject: [PATCH 0610/2042] net: wifi: Do TWT checks only for setup For tear down the checks doesn't make any sense, as TWT flow is already established. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 104a79819814..266938b38518 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -297,6 +297,10 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, return -ENOTSUP; } + if (twt_params->operation == WIFI_TWT_TEARDOWN) { + return off_api->set_twt(dev, twt_params); + } + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &info, sizeof(struct wifi_iface_status))) { twt_params->fail_reason = From 97bd70fa05336b2441237fd6f7b8567a11701a05 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 23 Jun 2023 14:15:26 +0530 Subject: [PATCH 0611/2042] net: wifi: Disable trigger in TWT quick setup Most AP's are not sending proper HE triggers or stopping triggers after sometime, so, change the default to non-triggered based TWT. 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 47e47830c8e8..5d833c25f750 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -717,7 +717,7 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, params.flow_id = 0; params.setup.responder = 0; params.setup.implicit = 1; - params.setup.trigger = 1; + params.setup.trigger = 0; params.setup.announce = 0; if (!parse_number(sh, (long *)¶ms.setup.twt_wake_interval, argv[idx++], From 15476aa3985fc5c9f2886dac6d382622136e85e2 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 25 Jun 2023 21:18:19 +0530 Subject: [PATCH 0612/2042] net: wifi: Add an error code for TWT duplicate flow request This is to handle duplicate TWT setup request. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 806424475f09..ae9f8cfa6db4 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -352,6 +352,7 @@ enum wifi_twt_fail_reason { WIFI_TWT_FAIL_OPERATION_IN_PROGRESS, WIFI_TWT_FAIL_INVALID_FLOW_ID, WIFI_TWT_FAIL_IP_NOT_ASSIGNED, + WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; static const char * const twt_err_code_tbl[] = { @@ -371,6 +372,8 @@ static const char * const twt_err_code_tbl[] = { "Invalid negotiated flow id", [WIFI_TWT_FAIL_IP_NOT_ASSIGNED] = "IP address not assigned", + [WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS] = + "Flow already exists", }; static inline const char *get_twt_err_code_str(int16_t err_no) From 3be72657378673e2a055d28927c1a13d6e4c4497 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 25 Jun 2023 21:37:16 +0530 Subject: [PATCH 0613/2042] net: wifi: Fix tear down messages TWT tear down is a synchronous call, so, once it returns the operation is done. 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 5d833c25f750..3500743b1148 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -837,7 +837,7 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d requested\n", + shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s with dg: %d, flow_id: %d success\n", wifi_twt_operation2str[params.operation], params.dialog_token, params.flow_id); @@ -864,7 +864,7 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows\n", + shell_fprintf(sh, SHELL_NORMAL, "TWT operation %s all flows success\n", wifi_twt_operation2str[params.operation]); return 0; From a3ab624f5deb22b1617c67ee1bd5514550c05dde Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 25 Jun 2023 22:07:18 +0530 Subject: [PATCH 0614/2042] net: wifi: Add a demarcation print This helps see the response status and details separately. Signed-off-by: Chaitanya Tata --- 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 3500743b1148..31e722e21229 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -270,6 +270,7 @@ static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) if (resp->resp_status == WIFI_TWT_RESP_RECEIVED) { print(context.sh, SHELL_NORMAL, "TWT response: %s\n", wifi_twt_setup_cmd2str[resp->setup_cmd]); + print(context.sh, SHELL_NORMAL, "== TWT negotiated parameters ==\n"); print_twt_params(resp->dialog_token, resp->flow_id, resp->negotiation_type, From 8042218948f671673fd2104fa9eb6f94c745f89a Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 25 Jun 2023 22:40:22 +0530 Subject: [PATCH 0615/2042] net: wifi: Add a message for unsolicited TWT tear down This is for TWT tear down by AP. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 31e722e21229..503b009707d4 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -267,6 +267,12 @@ 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; + if (resp->operation == WIFI_TWT_TEARDOWN) { + print(context.sh, SHELL_NORMAL, "TWT teardown received 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", wifi_twt_setup_cmd2str[resp->setup_cmd]); From 6bbd6d37946be78f22451a234b15c9918f213183 Mon Sep 17 00:00:00 2001 From: Marek Pieta Date: Sun, 25 Jun 2023 13:41:09 +0200 Subject: [PATCH 0616/2042] mcumgr: img_mgmt: Fix unused "status" variable warning Changes aligns ifdefs to fix compilation warnings related to unused "status" variable. Signed-off-by: Marek Pieta --- subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index bd94489db384..72262363f5a2 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -456,10 +456,13 @@ img_mgmt_upload(struct smp_streamer *ctxt) bool data_match = false; #endif +#if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) + enum mgmt_cb_return status; +#endif + #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) || \ defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) || \ defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) - enum mgmt_cb_return status; int32_t ret_rc; uint16_t ret_group; #endif From 5c1228770e032a09726a41f5b7efdf0d846cb313 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 7 Jun 2023 16:39:13 +0300 Subject: [PATCH 0617/2042] net: lwm2m: Add support for X509 certificates Add support for using X509 certificates. Default settings use ECDSA certificates with SHA256 hash. When different settings are required clients should overwrite struct lwm2m_ctx->load_credentials() and struct lwm2m_ctx->set_socketoptions() Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 33 +++ .../net/lwm2m_client/overlay-dtls-cert.conf | 38 +++ subsys/net/lib/lwm2m/Kconfig | 1 - subsys/net/lib/lwm2m/lwm2m_engine.c | 254 ++++++++++++++---- subsys/net/lib/lwm2m/lwm2m_obj_security.c | 17 +- .../net/lib/lwm2m/lwm2m_engine/CMakeLists.txt | 1 + tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c | 1 + tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h | 2 + 8 files changed, 291 insertions(+), 56 deletions(-) create mode 100644 samples/net/lwm2m_client/overlay-dtls-cert.conf diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 378ca20b5d63..1cc1b425d0dc 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -2239,5 +2239,38 @@ int lwm2m_engine_enable_cache(char const *resource_path, struct lwm2m_time_serie int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache, size_t cache_len); +/** + * @brief Security modes as defined in LwM2M Security object. + */ +enum lwm2m_security_mode_e { + LWM2M_SECURITY_PSK = 0, /**< Pre-Shared Key mode */ + LWM2M_SECURITY_RAW_PK = 1, /**< Raw Public Key mode */ + LWM2M_SECURITY_CERT = 2, /**< Certificate mode */ + LWM2M_SECURITY_NOSEC = 3, /**< NoSec mode */ + LWM2M_SECURITY_CERT_EST = 4, /**< Certificate mode with EST */ +}; + +/** + * @brief Read security mode from selected security object instance. + * + * This data is only valid if RD client is running. + * + * @param ctx Pointer to client context. + * @return int Positive values are @ref lwm2m_security_mode_e, negative error codes otherwise. + */ +int lwm2m_security_mode(struct lwm2m_ctx *ctx); + +/** + * @brief Set default socket options for DTLS connections. + * + * Engine calls this when @ref lwm2m_ctx::set_socketoptions is not overwritten. + * You may call this from overwritten callback to set extra options after or + * before defaults. + * + * @param ctx Client context + * @return 0 for success or negative in case of error. + */ +int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx); + #endif /* ZEPHYR_INCLUDE_NET_LWM2M_H_ */ /**@} */ diff --git a/samples/net/lwm2m_client/overlay-dtls-cert.conf b/samples/net/lwm2m_client/overlay-dtls-cert.conf new file mode 100644 index 000000000000..1362115f7466 --- /dev/null +++ b/samples/net/lwm2m_client/overlay-dtls-cert.conf @@ -0,0 +1,38 @@ +CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_PEER_PORT=5684 + +# I need room to store certificates +CONFIG_LWM2M_SECURITY_KEY_SIZE=2048 + +# Select Zephyr mbedtls +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_TLS_VERSION_1_2=y + +# Special MbedTLS changes +CONFIG_MBEDTLS_ENABLE_HEAP=y +CONFIG_MBEDTLS_HEAP_SIZE=32768 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=1500 +CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y + +# Disable RSA, use only ECC certificates +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=n +# Enable PSK and ECDHE_ECDSA +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=y +# We only need prime256v1 curve +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y +CONFIG_MBEDTLS_CIPHER_GCM_ENABLED=y +# Optional: we could use just binary DER certificates +CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y + +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 +CONFIG_NET_SOCKETS_ENABLE_DTLS=y + +# MbedTLS needs a larger stack +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 30a25a100f0d..be770b798031 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -316,7 +316,6 @@ config LWM2M_SECURITY_INSTANCE_COUNT config LWM2M_SECURITY_KEY_SIZE int "Buffer size of the security key resources" default 16 - range 16 256 help This setting establishes the size of the key (pre-shared / public) resources in the security object instances. diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index ad11ba61db8d..5c9396e361b5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -40,6 +40,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #if defined(CONFIG_LWM2M_DTLS_SUPPORT) #include +#include #endif #if defined(CONFIG_DNS_RESOLVER) #include @@ -753,20 +754,40 @@ static void socket_loop(void) } } -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) && defined(CONFIG_TLS_CREDENTIALS) -static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#if defined(CONFIG_TLS_CREDENTIALS) +static void delete_tls_credentials(sec_tag_t tag) +{ + tls_credential_delete(tag, TLS_CREDENTIAL_PSK_ID); + tls_credential_delete(tag, TLS_CREDENTIAL_PSK); + tls_credential_delete(tag, TLS_CREDENTIAL_SERVER_CERTIFICATE); + tls_credential_delete(tag, TLS_CREDENTIAL_PRIVATE_KEY); + tls_credential_delete(tag, TLS_CREDENTIAL_CA_CERTIFICATE); +} + +static bool is_pem(const void *buf, size_t len) +{ + static const char pem_start[] = "-----BEGIN"; + + if (len < sizeof(pem_start)) { + return false; + } + if (strncmp(pem_start, (const char *) buf, sizeof(pem_start) - 1) == 0) { + return true; + } + return false; +} + +static int load_tls_type(struct lwm2m_ctx *client_ctx, uint16_t res_id, enum tls_credential_type type) { int ret = 0; void *cred = NULL; uint16_t cred_len; - uint8_t cred_flags; - - /* ignore error value */ - tls_credential_delete(client_ctx->tls_tag, type); + uint16_t max_len; - ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, NULL, - &cred_len, &cred_flags); + ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, &max_len, + &cred_len, NULL); if (ret < 0) { LOG_ERR("Unable to get resource data for %d/%d/%d", 0, client_ctx->sec_obj_inst, res_id); @@ -778,6 +799,18 @@ static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, return -EINVAL; } + /* LwM2M registry stores strings without NULL-terminator, so we need to ensure that + * string based PEM credentials are terminated properly. + */ + if (is_pem(cred, cred_len)) { + if (cred_len >= max_len) { + LOG_ERR("No space for string terminator, cannot handle PEM"); + return -EINVAL; + } + ((uint8_t *) cred)[cred_len] = 0; + cred_len += 1; + } + ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len); if (ret < 0) { LOG_ERR("Error setting cred tag %d type %d: Error %d", client_ctx->tls_tag, type, @@ -786,99 +819,212 @@ static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id, return ret; } -#endif /* CONFIG_LWM2M_DTLS_SUPPORT && CONFIG_TLS_CREDENTIALS*/ -int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) +static int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx) { - socklen_t addr_len; - int flags; int ret; -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) - uint8_t tmp; + delete_tls_credentials(ctx->tls_tag); - if (client_ctx->load_credentials) { - ret = client_ctx->load_credentials(client_ctx); - if (ret < 0) { - return ret; - } + ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_PSK_ID); + if (ret < 0) { + return ret; } -#if defined(CONFIG_TLS_CREDENTIALS) - else { - ret = load_tls_credential(client_ctx, 3, TLS_CREDENTIAL_PSK_ID); - if (ret < 0) { - return ret; - } - ret = load_tls_credential(client_ctx, 5, TLS_CREDENTIAL_PSK); - if (ret < 0) { - return ret; - } + ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PSK); + return ret; +} + +static int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx) +{ + int ret; + + delete_tls_credentials(ctx->tls_tag); + + ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_SERVER_CERTIFICATE); + if (ret < 0) { + return ret; + } + ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PRIVATE_KEY); + if (ret < 0) { + return ret; } -#endif /* CONFIG_TLS_CREDENTIALS */ -#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ - if (client_ctx->sock_fd < 0) { - ret = lwm2m_open_socket(client_ctx); - if (ret) { - return ret; - } + ret = load_tls_type(ctx, 4, TLS_CREDENTIAL_CA_CERTIFICATE); + if (ret < 0) { + return ret; } + return ret; +} +#else - if (client_ctx->set_socketoptions) { - ret = client_ctx->set_socketoptions(client_ctx); - if (ret) { - return ret; +int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx) +{ + return -EOPNOTSUPP; +} + +int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_TLS_CREDENTIALS*/ + +static int lwm2m_load_tls_credentials(struct lwm2m_ctx *ctx) +{ + switch (lwm2m_security_mode(ctx)) { + case LWM2M_SECURITY_NOSEC: + if (ctx->use_dtls) { + return -EINVAL; } + return 0; + case LWM2M_SECURITY_PSK: + return lwm2m_load_psk_credentials(ctx); + case LWM2M_SECURITY_CERT: + return lwm2m_load_x509_credentials(ctx); + default: + return -EOPNOTSUPP; } +} + +static const int cipher_list_psk[] = { + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, +}; + +static const int cipher_list_cert[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +}; + +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + +int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx) +{ #if defined(CONFIG_LWM2M_DTLS_SUPPORT) - else if (client_ctx->use_dtls) { + if (ctx->use_dtls) { + int ret; + uint8_t tmp; sec_tag_t tls_tag_list[] = { - client_ctx->tls_tag, + ctx->tls_tag, }; - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list, + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list, sizeof(tls_tag_list)); if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret); - goto error; + return ret; } if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) { int session_cache = TLS_SESSION_CACHE_ENABLED; - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE, + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE, &session_cache, sizeof(session_cache)); if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_SESSION_CACHE option: %d", errno); - goto error; + return ret; } } - if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) { + if (ctx->hostname_verify && (ctx->desthostname != NULL)) { /** store character at len position */ - tmp = client_ctx->desthostname[client_ctx->desthostnamelen]; + tmp = ctx->desthostname[ctx->desthostnamelen]; /** change it to '\0' to pass to socket*/ - client_ctx->desthostname[client_ctx->desthostnamelen] = '\0'; + ctx->desthostname[ctx->desthostnamelen] = '\0'; /** mbedtls ignores length */ - ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_HOSTNAME, - client_ctx->desthostname, - client_ctx->desthostnamelen); + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_HOSTNAME, + ctx->desthostname, ctx->desthostnamelen); /** restore character */ - client_ctx->desthostname[client_ctx->desthostnamelen] = tmp; + ctx->desthostname[ctx->desthostnamelen] = tmp; if (ret < 0) { ret = -errno; LOG_ERR("Failed to set TLS_HOSTNAME option: %d", ret); - goto error; + return ret; + } + + int verify = TLS_PEER_VERIFY_REQUIRED; + + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify, + sizeof(verify)); + if (ret) { + LOG_ERR("Failed to set TLS_PEER_VERIFY"); + } + + } else { + /* By default, Mbed TLS tries to verify peer hostname, disable it */ + int verify = TLS_PEER_VERIFY_NONE; + + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify, + sizeof(verify)); + if (ret) { + LOG_ERR("Failed to set TLS_PEER_VERIFY"); } } + + switch (lwm2m_security_mode(ctx)) { + case LWM2M_SECURITY_PSK: + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST, + cipher_list_psk, sizeof(cipher_list_psk)); + if (ret) { + LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST"); + } + break; + case LWM2M_SECURITY_CERT: + ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST, + cipher_list_cert, sizeof(cipher_list_cert)); + if (ret) { + LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST (rc %d, errno %d)", ret, + errno); + } + break; + default: + return -EOPNOTSUPP; + } + } +#else + if (!IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) && ctx->use_dtls) { + return -EOPNOTSUPP; + } +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + return 0; +} + +int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) +{ + socklen_t addr_len; + int flags; + int ret; + +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + if (client_ctx->load_credentials) { + ret = client_ctx->load_credentials(client_ctx); + } else { + ret = lwm2m_load_tls_credentials(client_ctx); + } + if (ret < 0) { + return ret; } #endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + + if (client_ctx->sock_fd < 0) { + ret = lwm2m_open_socket(client_ctx); + if (ret) { + return ret; + } + } + + if (client_ctx->set_socketoptions) { + ret = client_ctx->set_socketoptions(client_ctx); + } else { + ret = lwm2m_set_default_sockopt(client_ctx); + } + if (ret) { + goto error; + } + if ((client_ctx->remote_addr).sa_family == AF_INET) { addr_len = sizeof(struct sockaddr_in); } else if ((client_ctx->remote_addr).sa_family == AF_INET6) { diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index c590350e61d1..874925c39d89 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -56,7 +56,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SECURITY_INSTANCE_COUNT #define SECURITY_URI_LEN 255 -#define IDENTITY_LEN 128 +#define IDENTITY_LEN CONFIG_LWM2M_SECURITY_KEY_SIZE #define KEY_LEN CONFIG_LWM2M_SECURITY_KEY_SIZE /* @@ -212,6 +212,21 @@ int lwm2m_security_index_to_inst_id(int index) return inst[index].obj_inst_id; } +int lwm2m_security_mode(struct lwm2m_ctx *ctx) +{ + int ret; + uint8_t mode; + struct lwm2m_obj_path path = + LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, ctx->sec_obj_inst, SECURITY_MODE_ID); + + ret = lwm2m_get_u8(&path, &mode); + if (ret) { + return ret; + } + return (int)mode; +} + + static int lwm2m_security_init(void) { struct lwm2m_engine_obj_inst *obj_inst = NULL; diff --git a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt index 8d4a0e1ddf42..36e161c6b11d 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt +++ b/tests/net/lib/lwm2m/lwm2m_engine/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/lwm2m_engine.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/include/) target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/lib/lwm2m/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/../modules/crypto/mbedtls/include/) add_compile_definitions(CONFIG_LWM2M_ENGINE_MAX_PENDING=2) add_compile_definitions(CONFIG_LWM2M_ENGINE_MAX_REPLIES=2) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c index 2611687f4758..95790e39cdb0 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c @@ -39,6 +39,7 @@ DEFINE_FAKE_VALUE_FUNC(struct lwm2m_engine_obj_field *, lwm2m_get_engine_obj_fie DEFINE_FAKE_VALUE_FUNC(int, lwm2m_get_bool, const struct lwm2m_obj_path *, bool *); 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 *); 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 a27c658642c7..c6a61ac180b1 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h @@ -54,6 +54,7 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_get_bool, const struct lwm2m_obj_path *, bool DECLARE_FAKE_VALUE_FUNC(int, lwm2m_delete_obj_inst, uint16_t, uint16_t); 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 *); #define DO_FOREACH_FAKE(FUNC) \ do { \ @@ -81,6 +82,7 @@ DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, FUNC(lwm2m_delete_obj_inst) \ FUNC(lwm2m_clear_block_contexts) \ FUNC(z_impl_zsock_connect) \ + FUNC(lwm2m_security_mode) \ } while (0) #endif /* STUBS_H */ From 55451c6d6e3229a0e65737fc2a045ebfd2052e6b Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 15 Jun 2023 14:40:20 +0300 Subject: [PATCH 0618/2042] doc: Document various LwM2M security modes Add documentation regarding various LwM2M security modes. Signed-off-by: Seppo Takalo --- doc/connectivity/networking/api/lwm2m.rst | 73 +++++++++++++++++------ include/zephyr/net/lwm2m.h | 18 +++--- 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 0ee4eb01d429..6d26205511e3 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -364,14 +364,44 @@ endpoint name. This is important as it needs to be unique per LwM2M server: (void)memset(&client, 0x0, sizeof(client)); lwm2m_rd_client_start(&client, "unique-endpoint-name", 0, rd_client_event); -Using LwM2M library with DTLS -***************************** +.. _lwm2m_security: -The Zephyr LwM2M library can be used with DTLS transport for secure -communication by selecting :kconfig:option:`CONFIG_LWM2M_DTLS_SUPPORT`. In the client -initialization we need to create a PSK and identity. These need to match -the security information loaded onto the LwM2M server. Normally, the -endpoint name is used to lookup the related security information: +LwM2M security modes +******************** + +The Zephyr LwM2M library can be used either without security or use DTLS to secure the communication channel. +When using DTLS with the LwM2M engine, PSK (Pre-Shared Key) and X.509 certificates are the security modes that can be used to secure the communication. +The engine uses LwM2M Security object (Id 0) to read the stored credentials and feed keys from the security object into +the TLS credential subsystem, see :ref:`secure sockets documentation `. +Enable the :kconfig:option:`CONFIG_LWM2M_DTLS_SUPPORT` Kconfig option to use the security. + +Depending on the selected mode, the security object must contain following data: + +PSK + Security Mode (Resource ID 2) set to zero (Pre-Shared Key mode). + Identity (Resource ID 3) contains PSK ID in binary form. + Secret key (Resource ID 5) contains the PSK key in binary form. + If the key or identity is provided as a hex string, it must be converted to binary before storing into the security object. + +X509 + When X509 certificates are used, set Security Mode (ID 2) to ``2`` (Certificate mode). + Identity (ID 3) is used to store the client certificate and Secret key (ID 5) must have a private key associated with the certificate. + Server Public Key resource (ID 4) must contain a server certificate or CA certificate used to sign the certificate chain. + If the :kconfig:option:`CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT` Kconfig option is enabled, certificates and private key can be entered in PEM format. + Otherwise, they must be in binary DER format. + +NoSec + When no security is used, set Security Mode (Resource ID 2) to ``3`` (NoSec). + +In all modes, Server URI resource (ID 0) must contain the full URI for the target server. +When DNS names are used, the DNS resolver must be enabled. + +LwM2M stack provides callbacks in the :c:struct:`lwm2m_ctx` structure. +They are used to feed keys from the LwM2M security object into the TLS credential subsystem. +By default, these callbacks can be left as NULL pointers, in which case default callbacks are used. +When an external TLS stack, or non-default socket options are required, you can overwrite the :c:func:`lwm2m_ctx.load_credentials` or :c:func:`lwm2m_ctx.set_socketoptions` callbacks. + +An example of setting up the security object for PSK mode: .. code-block:: c @@ -383,21 +413,26 @@ endpoint name is used to lookup the related security information: static const char client_identity[] = "Client_identity"; -Next we alter the ``Security`` object resources to include DTLS security -information. The server URL should begin with ``coaps://`` to indicate security -is required. Assign a 0 value (Pre-shared Key mode) to the ``Security Mode`` -resource. Lastly, set the client identity and PSK resources. + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); + lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_PSK); + /* Set the client identity as a string, but this could be binary as well */ + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), client_identity); + /* Set the client pre-shared key (PSK) */ + lwm2m_set_opaque(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), client_psk, sizeof(client_psk)); + +An example of setting up the security object for X509 certificate mode: .. code-block:: c - /* Use coaps:// for server URL protocol */ - lwm2m_set_string(&LWM2M_OBJ(0, 0, 0), "coaps://5.39.83.206"); - /* 0 = Pre-Shared Key mode */ - lwm2m_set_u8(&LWM2M_OBJ(0, 0, 2), 0); - /* Set the client identity */ - lwm2m_set_string(&LWM2M_OBJ(0, 0, 3), (char *)client_identity); - /* Set the client pre-shared key (PSK) */ - lwm2m_set_opaque(&LWM2M_OBJ(0, 0, 5), (void *)client_psk, sizeof(client_psk)); + static const char certificate[] = "-----BEGIN CERTIFICATE-----\nMIIB6jCCAY+gAw..."; + static const char key[] = "-----BEGIN EC PRIVATE KEY-----\nMHcCAQ..."; + static const char root_ca[] = "-----BEGIN CERTIFICATE-----\nMIIBaz..."; + + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0), "coaps://lwm2m.example.com"); + 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); 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 diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 1cc1b425d0dc..dea6c1ebb538 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -145,7 +145,7 @@ struct lwm2m_ctx { */ void *processed_req; -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) || defined(__DOXYGEN__) /** TLS tag is set by client as a reference used when the * LwM2M engine calls tls_credential_(add|delete) */ @@ -182,7 +182,7 @@ struct lwm2m_ctx { */ bool connection_suspended; -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) +#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) || defined(__DOXYGEN__) /** * Flag to indicate that the client is buffering Notifications and Send messages. * True value buffer Notifications and Send messages. @@ -416,7 +416,7 @@ int lwm2m_device_add_err(uint8_t error_code); #define RESULT_UPDATE_FAILED 8 #define RESULT_UNSUP_PROTO 9 -#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback for firmware block transfer. * @@ -489,7 +489,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) +#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set data callback to handle firmware update execute events. * @@ -529,7 +529,7 @@ lwm2m_engine_execute_cb_t lwm2m_firmware_get_update_cb_inst(uint16_t obj_inst_id #endif -#if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_SWMGMT_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set callback to handle software activation requests @@ -623,7 +623,7 @@ int lwm2m_swmgmt_install_completed(uint16_t obj_inst_id, int error_code); #endif -#if defined(CONFIG_LWM2M_EVENT_LOG_OBJ_SUPPORT) +#if defined(CONFIG_LWM2M_EVENT_LOG_OBJ_SUPPORT) || defined(__DOXYGEN__) /** * @brief Set callback to read log data @@ -2253,7 +2253,7 @@ enum lwm2m_security_mode_e { /** * @brief Read security mode from selected security object instance. * - * This data is only valid if RD client is running. + * This data is valid only if RD client is running. * * @param ctx Pointer to client context. * @return int Positive values are @ref lwm2m_security_mode_e, negative error codes otherwise. @@ -2263,8 +2263,8 @@ int lwm2m_security_mode(struct lwm2m_ctx *ctx); /** * @brief Set default socket options for DTLS connections. * - * Engine calls this when @ref lwm2m_ctx::set_socketoptions is not overwritten. - * You may call this from overwritten callback to set extra options after or + * The engine calls this when @ref lwm2m_ctx::set_socketoptions is not overwritten. + * You can call this from the overwritten callback to set extra options after or * before defaults. * * @param ctx Client context From dc7fbc5d2eef67dba66c6387c57d4aee973ea952 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 14 Jun 2023 14:47:20 +0300 Subject: [PATCH 0619/2042] net: lwm2m: Fix pause and resume on non-closed sockets Pause and resume functionality was written into assumption that sockets are closed before resuming. With use new options CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE or CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE this is not always true. Fix the state machine, so that on those cases, sockets are not closed and resume is always similar like from the QUEUE mode. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_engine.c | 39 +++++----- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 72 ++++++++++--------- .../lib/lwm2m/lwm2m_rd_client/CMakeLists.txt | 1 + .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 1 + .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 1 + 5 files changed, 60 insertions(+), 54 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 5c9396e361b5..fa74666f0925 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -155,29 +155,27 @@ int lwm2m_open_socket(struct lwm2m_ctx *client_ctx) int lwm2m_close_socket(struct lwm2m_ctx *client_ctx) { - int ret = 0; - if (client_ctx->sock_fd >= 0) { - ret = zsock_close(client_ctx->sock_fd); + int ret = zsock_close(client_ctx->sock_fd); + if (ret) { LOG_ERR("Failed to close socket: %d", errno); ret = -errno; return ret; } + } - client_ctx->sock_fd = -1; - client_ctx->connection_suspended = true; + client_ctx->sock_fd = -1; + client_ctx->connection_suspended = true; #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - /* Enable Queue mode buffer store */ - client_ctx->buffer_client_messages = true; + /* Enable Queue mode buffer store */ + client_ctx->buffer_client_messages = true; #endif - lwm2m_socket_update(client_ctx); - } + lwm2m_socket_update(client_ctx); - return ret; + return 0; } - int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) { int ret = 0; @@ -185,13 +183,11 @@ int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx) if (client_ctx->sock_fd >= 0 && !client_ctx->connection_suspended) { int socket_temp_id = client_ctx->sock_fd; + /* Prevent closing */ client_ctx->sock_fd = -1; - client_ctx->connection_suspended = true; -#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - /* Enable Queue mode buffer store */ - client_ctx->buffer_client_messages = true; -#endif - lwm2m_socket_update(client_ctx); + /* Just mark as suspended */ + lwm2m_close_socket(client_ctx); + /* store back the socket handle */ client_ctx->sock_fd = socket_temp_id; } @@ -203,16 +199,19 @@ int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx) int ret; if (client_ctx->connection_suspended) { - if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE)) { + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) || + IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) { + LOG_DBG("Resume suspended connection"); lwm2m_socket_update(client_ctx); + client_ctx->connection_suspended = false; } else { + LOG_DBG("Close and resume a new connection"); lwm2m_close_socket(client_ctx); - client_ctx->connection_suspended = false; ret = lwm2m_open_socket(client_ctx); if (ret) { return ret; } - LOG_DBG("Resume suspended connection"); + client_ctx->connection_suspended = false; return lwm2m_socket_start(client_ctx); } } diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index d89ea3c5f79c..3686b8855a24 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1415,17 +1415,24 @@ int lwm2m_rd_client_pause(void) k_mutex_unlock(&client.mutex); LOG_ERR("Cannot pause. No context"); return -EPERM; - } else if (client.engine_state == ENGINE_SUSPENDED) { + } else if (sm_is_suspended()) { k_mutex_unlock(&client.mutex); LOG_ERR("LwM2M client already suspended"); return 0; } LOG_INF("Suspend client"); - if (!client.ctx->connection_suspended && client.ctx->event_cb) { + if (client.ctx->event_cb) { client.ctx->event_cb(client.ctx, event); } + /* Suspend or close the socket */ + if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) { + lwm2m_close_socket(client.ctx); + } else { + lwm2m_socket_suspend(client.ctx); + } + suspended_client_state = get_sm_state(); client.engine_state = ENGINE_SUSPENDED; @@ -1436,26 +1443,18 @@ int lwm2m_rd_client_pause(void) int lwm2m_rd_client_resume(void) { - int ret; - k_mutex_lock(&client.mutex, K_FOREVER); - if (!client.ctx) { + if (!lwm2m_rd_client_is_suspended(client.ctx)) { k_mutex_unlock(&client.mutex); - LOG_WRN("Cannot resume. No context"); - return -EPERM; - } - - if (client.engine_state != ENGINE_SUSPENDED) { - k_mutex_unlock(&client.mutex); - LOG_WRN("Cannot resume state is not Suspended"); + LOG_WRN("Cannot resume, state is not suspended"); return -EPERM; } LOG_INF("Resume Client state"); - lwm2m_close_socket(client.ctx); + if (suspended_client_state == ENGINE_UPDATE_SENT) { - /* Set back to Registration done for enable trigger Update */ + /* Set back to Registration done and trigger an update */ suspended_client_state = ENGINE_REGISTRATION_DONE; } /* Clear Possible pending RD Client message */ @@ -1463,18 +1462,24 @@ int lwm2m_rd_client_resume(void) client.engine_state = suspended_client_state; - if (!client.last_update || - (client.lifetime <= (k_uptime_get() - client.last_update) / 1000)) { - client.engine_state = ENGINE_DO_REGISTRATION; - } else { - lwm2m_rd_client_connection_resume(client.ctx); - client.trigger_update = true; + /* Do we need to resume the bootstrap? */ +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (sm_is_bootstrap()) { + client.engine_state = ENGINE_DO_BOOTSTRAP_REG; } - - ret = lwm2m_open_socket(client.ctx); - if (ret) { - LOG_ERR("Socket Open Fail"); - client.engine_state = ENGINE_INIT; +#endif + /* Or do we resume into registration state */ + if (client.engine_state >= ENGINE_DO_REGISTRATION && + client.engine_state <= ENGINE_SUSPENDED) { + if (!client.last_update || + (client.lifetime <= (k_uptime_get() - client.last_update) / 1000)) { + /* No lifetime left, register again */ + client.engine_state = ENGINE_DO_REGISTRATION; + } else { + /* Resume similarly like from QUEUE mode */ + client.engine_state = ENGINE_REGISTRATION_DONE_RX_OFF; + lwm2m_rd_client_connection_resume(client.ctx); + } } k_mutex_unlock(&client.mutex); @@ -1499,22 +1504,21 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx) } if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) { -#ifdef CONFIG_LWM2M_DTLS_SUPPORT /* - * Switch state for triggering a proper registration message - * if CONFIG_LWM2M_TLS_SESSION_CACHING is false we force full - * registration after Fully DTLS handshake + * Switch state to triggering a proper registration message + * If the socket stays open (Connection ID or no-sec), or we have TLS session cache, + * we can trigger the update, otherwise fall back to full registration. */ - if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) { + if ((IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) && + IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) || + (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) || + 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; } else { client.engine_state = ENGINE_DO_REGISTRATION; } -#else - client.engine_state = ENGINE_REGISTRATION_DONE; - client.trigger_update = true; -#endif } return 0; diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt b/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt index 2a6e8141a1ce..d69ed3856211 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt @@ -30,3 +30,4 @@ add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_UPTIME=10) add_compile_definitions(CONFIG_LWM2M_LOG_LEVEL=4) add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_ENABLED=1) add_compile_definitions(CONFIG_LWM2M_TLS_SESSION_CACHING=1) +add_compile_definitions(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE=1) 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 7d0bd84c1ac0..c0df43d3b931 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -66,6 +66,7 @@ int lwm2m_get_bool_fake_default(const struct lwm2m_obj_path *path, bool *value) DEFINE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_ctx *); 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 *); 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 *); 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 b07346de889b..70c073afbdbc 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -51,6 +51,7 @@ int lwm2m_get_bool_fake_default(const struct lwm2m_obj_path *path, bool *value); DECLARE_FAKE_VALUE_FUNC(int, lwm2m_socket_start, struct lwm2m_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 *); 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 *); From 9d3f5944326ca7f6290ba539f658a99fdf2f19f1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:50:21 +0200 Subject: [PATCH 0620/2042] Bluetooth: BAP: Shell: Print received broadcast code Print the received broadcast code as the scan delegator. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_scan_delegator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index 096306542fe2..d13e5f5f04ad 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -294,6 +294,7 @@ static void broadcast_code_cb(struct bt_conn *conn, struct sync_state *state; shell_info(ctx_shell, "Broadcast code received for %p", recv_state); + shell_hexdump(ctx_shell, broadcast_code, BT_AUDIO_BROADCAST_CODE_SIZE); state = sync_state_get(recv_state); if (state == NULL) { From 15cdcc79f0fcbe821e0fdf602057796b84d64598 Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Tue, 20 Jun 2023 14:53:07 -0600 Subject: [PATCH 0621/2042] cmake: Fix FindLlvmLld usage of unimported package The find_package_handle_standard_args function is used in FindLlvmLld without being imported. This may cause FindLlvmLld to fail non-determistically based on if it's evaluated in a CMake build/process before find_package_handle_standard_args is included. We should include what we use. Explicitly include find_package_handle_standard_args. Signed-off-by: Aaron Massey --- cmake/modules/FindGnuLd.cmake | 2 ++ cmake/modules/FindLlvmLld.cmake | 2 ++ cmake/modules/Findarmclang.cmake | 2 ++ cmake/modules/FindoneApi.cmake | 2 ++ 4 files changed, 8 insertions(+) diff --git a/cmake/modules/FindGnuLd.cmake b/cmake/modules/FindGnuLd.cmake index 9d4377b7e742..412f6badaf72 100644 --- a/cmake/modules/FindGnuLd.cmake +++ b/cmake/modules/FindGnuLd.cmake @@ -23,6 +23,8 @@ # Note that this will use CROSS_COMPILE, if defined, # as a prefix to the linker executable. +include(FindPackageHandleStandardArgs) + # GNULD_LINKER exists on repeated builds or defined manually... if(EXISTS "${GNULD_LINKER}") if(NOT DEFINED GNULD_LINKER_IS_BFD) diff --git a/cmake/modules/FindLlvmLld.cmake b/cmake/modules/FindLlvmLld.cmake index ab7fe1f695b8..223e142bf8d2 100644 --- a/cmake/modules/FindLlvmLld.cmake +++ b/cmake/modules/FindLlvmLld.cmake @@ -17,6 +17,8 @@ # 'LLVMLLD_VERSION_STRING' # The version of LLVM lld. +include(FindPackageHandleStandardArgs) + # See if the compiler has a preferred linker execute_process(COMMAND ${CMAKE_C_COMPILER} --print-prog-name=ld.lld OUTPUT_VARIABLE LLVMLLD_LINKER diff --git a/cmake/modules/Findarmclang.cmake b/cmake/modules/Findarmclang.cmake index 12c2dc034875..a84a04f163b3 100644 --- a/cmake/modules/Findarmclang.cmake +++ b/cmake/modules/Findarmclang.cmake @@ -12,6 +12,8 @@ # 'ARMCLANG_VERSION' # The version of the arm clang toolchain. +include(FindPackageHandleStandardArgs) + if(CMAKE_C_COMPILER) # Parse the 'clang --version' output to find the installed version. execute_process(COMMAND ${CMAKE_C_COMPILER} --target=${triple} --version OUTPUT_VARIABLE ARMCLANG_VERSION) diff --git a/cmake/modules/FindoneApi.cmake b/cmake/modules/FindoneApi.cmake index 0b3ff56fbf35..737aa3470072 100644 --- a/cmake/modules/FindoneApi.cmake +++ b/cmake/modules/FindoneApi.cmake @@ -12,6 +12,8 @@ # 'ONEAPI_VERSION' # The version of the oneAPI toolchain. +include(FindPackageHandleStandardArgs) + if(CMAKE_C_COMPILER) # Parse the 'clang --version' output to find the installed version. execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE ONEAPI_VERSION) From 5a4c9a2112a06fab89c6fb99a7621bdb1ebe2bdd Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 22 Jun 2023 13:43:36 +0200 Subject: [PATCH 0622/2042] Bluetooth: BAP: Unicast client shall support 0 or > 1 endpoints As per table 4.2 in BAP v1.0.1, the BAP unicast client shall support at least 2 (> 1) endpoints in either direction if it supports that direction. Since Kconfig does not support such requirements (0 || > 1), this is done using a BUILD_ASSERT. Signed-off-by: Emil Gydesen --- samples/bluetooth/tmap_central/prj.conf | 4 ++-- subsys/bluetooth/audio/Kconfig.bap | 2 +- subsys/bluetooth/audio/bap_unicast_client.c | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/samples/bluetooth/tmap_central/prj.conf b/samples/bluetooth/tmap_central/prj.conf index b73458e5dad5..a9a5c02eca30 100644 --- a/samples/bluetooth/tmap_central/prj.conf +++ b/samples/bluetooth/tmap_central/prj.conf @@ -39,8 +39,8 @@ CONFIG_BT_TBS_SUPPORTED_FEATURES=3 CONFIG_BT_ISO_TX_BUF_COUNT=2 CONFIG_BT_ISO_MAX_CHAN=2 CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=1 -CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=1 -CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=1 +CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 +CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_GATT_DYNAMIC_DB=y CONFIG_BT_EXT_ADV=y diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index 128c4767451f..d77bacb71803 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -93,7 +93,7 @@ config BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT config BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT int "Basic Audio Profile ASE Source count" - default 1 + default 2 range 0 255 help This option enables caching a number of Audio Stream Endpoint Source diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 7f769c1edaff..37b243acfdc7 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -37,6 +37,14 @@ BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 || "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT or " "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT shall be non-zero"); +BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT == 0 || + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1, + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT shall be either 0 or > 1"); + +BUILD_ASSERT(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0 || + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1, + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT shall be either 0 or > 1"); + LOG_MODULE_REGISTER(bt_bap_unicast_client, CONFIG_BT_BAP_UNICAST_CLIENT_LOG_LEVEL); #define PAC_DIR_UNUSED(dir) ((dir) != BT_AUDIO_DIR_SINK && (dir) != BT_AUDIO_DIR_SOURCE) From 8babf99834120e42880447f0f5b3ce4947c431e1 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Fri, 23 Jun 2023 04:46:54 +0100 Subject: [PATCH 0623/2042] kernel: fix z_is_inactive_timeout stab when missing sys clock Currently we provide incorrect stab value of z_is_inactive_timeout in case of the configuration without system clock (CONFIG_SYS_CLOCK_EXISTS=n). This prevents threads from being scheduled (we don't even schedule main thread in hello world example if CONFIG_SYS_CLOCK_EXISTS=n). Fix that. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- include/zephyr/timeout_q.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/timeout_q.h b/include/zephyr/timeout_q.h index fc930db62d2e..ad9564f05bd8 100644 --- a/include/zephyr/timeout_q.h +++ b/include/zephyr/timeout_q.h @@ -63,7 +63,7 @@ k_ticks_t z_timeout_remaining(const struct _timeout *timeout); /* Stubs when !CONFIG_SYS_CLOCK_EXISTS */ #define z_init_thread_timeout(thread_base) do {} while (false) #define z_abort_thread_timeout(to) (0) -#define z_is_inactive_timeout(to) 0 +#define z_is_inactive_timeout(to) 1 #define z_get_next_timeout_expiry() ((int32_t) K_TICKS_FOREVER) #define z_set_timeout_expiry(ticks, is_idle) do {} while (false) From 3be68bd4fe48d4a3723ada18af9466bb646a5ad6 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Mon, 26 Jun 2023 15:17:55 +0800 Subject: [PATCH 0624/2042] board: it8xxx2_evb/it82xx2_evb: Fix the dts compatible field of board The dts compatible field should be corrected to ite. Signed-off-by: Tim Lin --- boards/riscv/it82xx2_evb/it82xx2_evb.dts | 2 +- boards/riscv/it8xxx2_evb/it8xxx2_evb.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb.dts b/boards/riscv/it82xx2_evb/it82xx2_evb.dts index e0cbf2e67e57..2938fb7ebd5a 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb.dts +++ b/boards/riscv/it82xx2_evb/it82xx2_evb.dts @@ -11,7 +11,7 @@ / { model = "IT82XX2 EV-Board"; - compatible = "riscv,it82xx2-evb"; + compatible = "ite,it82xx2-evb"; aliases { i2c-0 = &i2c0; diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index dfe4f7a04f29..1f3e4455b2a1 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -11,7 +11,7 @@ / { model = "IT8XXX2 EV-Board"; - compatible = "riscv,it8xxx2-evb"; + compatible = "ite,it8xxx2-evb"; aliases { i2c-0 = &i2c0; From bb281e4fdebb8625f18db383ad92ab775bf7373d Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 6 Jun 2023 01:54:19 +0530 Subject: [PATCH 0625/2042] net: l2: Fix the define in comment This was a typo. Signed-off-by: Chaitanya Tata --- include/zephyr/net/net_l2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/net/net_l2.h b/include/zephyr/net/net_l2.h index dc443e0a3f54..7f221f913671 100644 --- a/include/zephyr/net/net_l2.h +++ b/include/zephyr/net/net_l2.h @@ -99,7 +99,7 @@ NET_L2_DECLARE_PUBLIC(DUMMY_L2); #if defined(CONFIG_NET_OFFLOAD) || defined(CONFIG_NET_SOCKETS_OFFLOAD) #define OFFLOADED_NETDEV_L2 OFFLOADED_NETDEV NET_L2_DECLARE_PUBLIC(OFFLOADED_NETDEV_L2); -#endif /* CONFIG_NET_L2_ETHERNET */ +#endif /* CONFIG_NET_OFFLOAD || CONFIG_NET_SOCKETS_OFFLOAD */ #ifdef CONFIG_NET_L2_ETHERNET #define ETHERNET_L2 ETHERNET From 2606ba445b137b4a4e8d344768c5d74057742636 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 6 Jun 2023 01:54:20 +0530 Subject: [PATCH 0626/2042] net: l2: Add support to identify Wi-Fi interfaces Wi-Fi is based on L2 Ethernet, so, all drivers are registered as Ethernet L2, but in order to distinguish true Ethernet and Wi-Fi devices, add a L2 type within Ethernet. Also, handle offloaded net devices that also offload Wi-Fi. This approach is better than adding a new Wi-Fi L2 as that would mean invasive changes which are unnecessary. Signed-off-by: Chaitanya Tata --- include/zephyr/net/ethernet.h | 28 +++++++++++++++++++++++ include/zephyr/net/net_if.h | 10 ++++++++ include/zephyr/net/offloaded_netdev.h | 33 +++++++++++++++++++++++++++ subsys/net/ip/net_if.c | 13 +++++++++++ 4 files changed, 84 insertions(+) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index b4fad4224dd3..1faca156ef1e 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -353,6 +353,16 @@ enum ethernet_filter_type { /** @endcond */ +/** Types of Ethernet L2 */ +enum ethernet_if_types { + /** IEEE 802.3 Ethernet (default) */ + L2_ETH_IF_TYPE_ETHERNET, + + /** IEEE 802.11 Wi-Fi*/ + L2_ETH_IF_TYPE_WIFI, +} __packed; + + struct ethernet_filter { /** Type of filter */ enum ethernet_filter_type type; @@ -601,6 +611,9 @@ struct ethernet_context { /** Is this context already initialized */ bool is_init : 1; + + /** Types of Ethernet network interfaces */ + enum ethernet_if_types eth_if_type; }; /** @@ -1010,6 +1023,21 @@ static inline int net_eth_get_ptp_port(struct net_if *iface) void net_eth_set_ptp_port(struct net_if *iface, int port); #endif /* CONFIG_NET_L2_PTP */ +/** + * @brief Check if the Ethernet L2 network interface can perform Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +static inline bool net_eth_type_is_wifi(struct net_if *iface) +{ + const struct ethernet_context *ctx = (struct ethernet_context *) + net_if_l2_data(iface); + + return ctx->eth_if_type == L2_ETH_IF_TYPE_WIFI; +} + /** * @} */ diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index f8b2ad5def30..b1661dbe8a6e 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2526,6 +2526,16 @@ int net_if_resume(struct net_if *iface); bool net_if_is_suspended(struct net_if *iface); #endif /* CONFIG_NET_POWER_MANAGEMENT */ +/** + * @brief Check if the network interface supports Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +bool net_if_is_wifi(struct net_if *iface); + + /** @cond INTERNAL_HIDDEN */ struct net_if_api { void (*init)(struct net_if *iface); diff --git a/include/zephyr/net/offloaded_netdev.h b/include/zephyr/net/offloaded_netdev.h index 5f778680ba27..ce90cf77bf37 100644 --- a/include/zephyr/net/offloaded_netdev.h +++ b/include/zephyr/net/offloaded_netdev.h @@ -29,6 +29,21 @@ extern "C" { * @{ */ +/** Types of offloaded netdev L2 */ +enum offloaded_net_if_types { + /** Unknown, device hasn't register a type */ + L2_OFFLOADED_NET_IF_TYPE_UNKNOWN, + + /** Ethernet devices */ + L2_OFFLOADED_NET_IF_TYPE_ETHERNET, + + /** Modem */ + L2_OFFLOADED_NET_IF_TYPE_MODEM, + + /** IEEE 802.11 Wi-Fi */ + L2_OFFLOADED_NET_IF_TYPE_WIFI, +}; + /** * @brief Extended net_if_api for offloaded ifaces/network devices, allowing handling of * admin up/down state changes @@ -42,11 +57,29 @@ struct offloaded_if_api { /** Enable or disable the device (in response to admin state change) */ int (*enable)(const struct net_if *iface, bool state); + + /* Types of offloaded net device */ + enum offloaded_net_if_types (*get_type)(void); }; /* Ensure offloaded_if_api is compatible with net_if_api */ BUILD_ASSERT(offsetof(struct offloaded_if_api, iface_api) == 0); +/** + * @brief Check if the offloaded network interface supports Wi-Fi. + * + * @param iface Pointer to network interface + * + * @return True if interface supports Wi-Fi, False otherwise. + */ +static inline bool net_off_is_wifi_offloaded(struct net_if *iface) +{ + const struct offloaded_if_api *api = (const struct offloaded_if_api *) + net_if_get_device(iface)->api; + + return api->get_type && api->get_type() == L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + /** * @} */ diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 02dc8a257a4c..27096780306f 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -20,6 +20,7 @@ LOG_MODULE_REGISTER(net_if, CONFIG_NET_IF_LOG_LEVEL); #include #include #include +#include #include #include @@ -4594,6 +4595,18 @@ void net_if_add_tx_timestamp(struct net_pkt *pkt) } #endif /* CONFIG_NET_PKT_TIMESTAMP_THREAD */ +bool net_if_is_wifi(struct net_if *iface) +{ + if (is_iface_offloaded(iface)) { + return net_off_is_wifi_offloaded(iface); + } +#if defined(CONFIG_NET_L2_ETHERNET) + return net_eth_type_is_wifi(iface); +#else + return false; +#endif +} + void net_if_init(void) { int if_count = 0; From 79870984975d4c11873553247b2873b117148a15 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 6 Jun 2023 01:54:20 +0530 Subject: [PATCH 0627/2042] drivers: wifi: Register Wi-Fi architecture type Identify the Wi-Fi capability to the networking stack and also the type of Wi-Fi (Native vs Offloaded), this helps identifying Wi-Fi interfaces that can be used by applications. Signed-off-by: Chaitanya Tata --- drivers/wifi/esp32/src/esp_wifi_drv.c | 2 ++ drivers/wifi/esp_at/esp.c | 5 +++++ drivers/wifi/eswifi/eswifi_core.c | 6 ++++++ drivers/wifi/simplelink/simplelink.c | 6 ++++++ drivers/wifi/winc1500/wifi_winc1500.c | 6 ++++++ subsys/net/ip/net_if.c | 3 ++- 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 88e214548686..5f69c88c02d1 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -547,7 +547,9 @@ static void esp32_wifi_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct esp32_wifi_runtime *dev_data = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; esp32_wifi_iface = iface; dev_data->state = ESP32_STA_STOPPED; diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 316a804f5494..614d7fb517ac 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -1215,8 +1215,13 @@ static void esp_iface_init(struct net_if *iface) esp_offload_init(iface); } +static enum offloaded_net_if_types esp_offload_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} static const struct net_wifi_mgmt_offload esp_api = { .wifi_iface.iface_api.init = esp_iface_init, + .wifi_iface.get_type = esp_offload_get_type, .scan = esp_mgmt_scan, .connect = esp_mgmt_connect, .disconnect = esp_mgmt_disconnect, diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index ad8976aee3aa..a92991e4552d 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -777,8 +777,14 @@ static int eswifi_init(const struct device *dev) return 0; } +static enum offloaded_net_if_types eswifi_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + static const struct net_wifi_mgmt_offload eswifi_offload_api = { .wifi_iface.iface_api.init = eswifi_iface_init, + .wifi_iface.get_type = eswifi_get_type, .scan = eswifi_mgmt_scan, .connect = eswifi_mgmt_connect, .disconnect = eswifi_mgmt_disconnect, diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index b75329e49f43..a959d8c14402 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -263,8 +263,14 @@ static void simplelink_iface_init(struct net_if *iface) } +static enum offloaded_net_if_types simplelink_get_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + static const struct net_wifi_mgmt_offload simplelink_api = { .wifi_iface.iface_api.init = simplelink_iface_init, + .wifi_iface.get_type = simplelink_get_type, .scan = simplelink_mgmt_scan, .connect = simplelink_mgmt_connect, .disconnect = simplelink_mgmt_disconnect, diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 329e18a8a68c..19525cc2fd0e 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -1099,8 +1099,14 @@ static void winc1500_iface_init(struct net_if *iface) w1500_data.iface = iface; } +static enum offloaded_net_if_types winc1500_get_wifi_type(void) +{ + return L2_OFFLOADED_NET_IF_TYPE_WIFI; +} + static const struct net_wifi_mgmt_offload winc1500_api = { .wifi_iface.iface_api.init = winc1500_iface_init, + .wifi_iface.get_type = winc1500_get_wifi_type, .scan = winc1500_mgmt_scan, .connect = winc1500_mgmt_connect, .disconnect = winc1500_mgmt_disconnect, diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 27096780306f..5484bc42d6bb 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -4601,7 +4601,8 @@ bool net_if_is_wifi(struct net_if *iface) return net_off_is_wifi_offloaded(iface); } #if defined(CONFIG_NET_L2_ETHERNET) - return net_eth_type_is_wifi(iface); + return net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) && + net_eth_type_is_wifi(iface); #else return false; #endif From b9411b75df77a58fac9e9ba71815c4143ed351ad Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Tue, 6 Jun 2023 23:36:14 +0530 Subject: [PATCH 0628/2042] net: ethernet: Fix build and doc error The API should be defined independent of L2_PTP define, this fixes build error and also the doc error, as the next function will have two doxygen headers. Signed-off-by: Chaitanya Tata --- include/zephyr/net/ethernet.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/zephyr/net/ethernet.h b/include/zephyr/net/ethernet.h index 1faca156ef1e..7e4a28bcb10b 100644 --- a/include/zephyr/net/ethernet.h +++ b/include/zephyr/net/ethernet.h @@ -1021,6 +1021,12 @@ static inline int net_eth_get_ptp_port(struct net_if *iface) */ #if defined(CONFIG_NET_L2_PTP) void net_eth_set_ptp_port(struct net_if *iface, int port); +#else +static inline void net_eth_set_ptp_port(struct net_if *iface, int port) +{ + ARG_UNUSED(iface); + ARG_UNUSED(port); +} #endif /* CONFIG_NET_L2_PTP */ /** From 91b5b4424cf3472a978217a23a01442d8f031237 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 14 Jun 2023 20:53:11 +0530 Subject: [PATCH 0629/2042] net: wifi: Add support to get and set Wi-Fi as default interface Add a configuration option to set Wi-Fi as default interface and also add an API to get first available Wi-Fi interface. Signed-off-by: Chaitanya Tata --- include/zephyr/net/net_if.h | 7 +++++++ subsys/net/ip/Kconfig | 4 ++++ subsys/net/ip/net_if.c | 17 ++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index b1661dbe8a6e..d8042d6601cf 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -2535,6 +2535,13 @@ bool net_if_is_suspended(struct net_if *iface); */ bool net_if_is_wifi(struct net_if *iface); +/** + * @brief Get first Wi-Fi network interface. + * + * @return Pointer to network interface, NULL if not found. + */ +struct net_if *net_if_get_first_wifi(void); + /** @cond INTERNAL_HIDDEN */ struct net_if_api { diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 2ce2e35171fe..e5f096e594f5 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -828,6 +828,10 @@ config NET_DEFAULT_IF_PPP bool "PPP interface" depends on NET_L2_PPP +config NET_DEFAULT_IF_WIFI + bool "WiFi interface" + depends on NET_L2_ETHERNET + endchoice config NET_PKT_TIMESTAMP diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 5484bc42d6bb..a5656517c2eb 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -617,7 +617,9 @@ struct net_if *net_if_get_default(void) #if defined(CONFIG_NET_DEFAULT_IF_UP) iface = net_if_get_first_up(); #endif - +#if defined(CONFIG_NET_DEFAULT_IF_WIFI) + iface = net_if_get_first_wifi(); +#endif return iface ? iface : _net_if_list_start; } @@ -4603,9 +4605,18 @@ bool net_if_is_wifi(struct net_if *iface) #if defined(CONFIG_NET_L2_ETHERNET) return net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) && net_eth_type_is_wifi(iface); -#else - return false; #endif + return false; +} + +struct net_if *net_if_get_first_wifi(void) +{ + STRUCT_SECTION_FOREACH(net_if, iface) { + if (net_if_is_wifi(iface)) { + return iface; + } + } + return NULL; } void net_if_init(void) From 5aced7130dd2511fdb7cdb84dc0f991d6e78da6b Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 14 Jun 2023 20:54:36 +0530 Subject: [PATCH 0630/2042] net: wifi: Use only Wi-Fi interfaces As this is Wi-Fi shell use only Wi-Fi interfaces, if none are found fail. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 503b009707d4..c6fd581a2d4c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -389,7 +389,7 @@ static int __wifi_args_to_params(size_t argc, char *argv[], static int cmd_wifi_connect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + 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)) { @@ -417,7 +417,7 @@ static int cmd_wifi_connect(const struct shell *sh, size_t argc, static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); int status; context.disconnecting = true; @@ -446,7 +446,7 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); context.sh = sh; @@ -463,7 +463,7 @@ static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_status(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_iface_status status = { 0 }; context.sh = sh; @@ -538,7 +538,7 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[]) { #if defined(CONFIG_NET_STATISTICS_WIFI) && \ defined(CONFIG_NET_STATISTICS_USER_API) - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct net_stats_wifi stats = { 0 }; int ret; @@ -561,7 +561,7 @@ static int cmd_wifi_stats(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; @@ -641,7 +641,7 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; @@ -671,7 +671,7 @@ static int cmd_wifi_ps_mode(const struct shell *sh, size_t argc, char *argv[]) static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; long timeout_ms = 0; int err = 0; @@ -704,7 +704,7 @@ static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[] static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; @@ -753,7 +753,7 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; long neg_type; @@ -808,7 +808,7 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; long neg_type = 0; long setup_cmd = 0; @@ -854,7 +854,7 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; context.sh = sh; @@ -880,7 +880,7 @@ static int cmd_wifi_twt_teardown_all(const struct shell *sh, size_t argc, static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); static struct wifi_connect_req_params cnx_params; int ret; @@ -906,7 +906,7 @@ static int cmd_wifi_ap_enable(const struct shell *sh, size_t argc, static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); int ret; ret = net_mgmt(NET_REQUEST_WIFI_AP_DISABLE, iface, NULL, 0); @@ -924,7 +924,7 @@ static int cmd_wifi_ap_disable(const struct shell *sh, size_t argc, static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_reg_domain regd = {0}; int ret; @@ -983,7 +983,7 @@ static int cmd_wifi_reg_domain(const struct shell *sh, size_t argc, static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; long interval = 0; @@ -1022,7 +1022,7 @@ static int cmd_wifi_listen_interval(const struct shell *sh, size_t argc, char *a static int cmd_wifi_ps_wakeup_mode(const struct shell *sh, size_t argc, char *argv[]) { - struct net_if *iface = net_if_get_default(); + struct net_if *iface = net_if_get_first_wifi(); struct wifi_ps_params params = { 0 }; context.sh = sh; From 159f56d57e9926513cd11268614d0845f9040f3e Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 5 Jun 2023 08:08:14 +0000 Subject: [PATCH 0631/2042] mgmt: ec_host_cmd: use one command to send response Use one common function to send Host Command response. It allows handling all response types within one function. Signed-off-by: Dawid Niedzwiecki --- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 e3922ea0b345..6ddaedca4911 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -198,7 +198,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * status = verify_rx(rx); if (status != EC_HOST_CMD_SUCCESS) { - send_status_response(hc->backend, tx, status); + ec_host_cmd_send_response(status, &args); continue; } @@ -213,7 +213,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * /* No handler in this image for requested command */ if (found_handler == NULL) { - send_status_response(hc->backend, tx, EC_HOST_CMD_INVALID_COMMAND); + ec_host_cmd_send_response(EC_HOST_CMD_INVALID_COMMAND, &args); continue; } @@ -224,7 +224,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * status = validate_handler(found_handler, &args); if (status != EC_HOST_CMD_SUCCESS) { - send_status_response(hc->backend, tx, status); + ec_host_cmd_send_response(status, &args); continue; } From c8c149dce8e27ed0ad54741d34986527bda017fc Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Wed, 31 May 2023 07:48:40 +0000 Subject: [PATCH 0632/2042] mgmt: ec_host_cmd: add logging system Add a native way to log Host Command communication. Use Zephyr logging system to do it. Use debug and normal levels. Signed-off-by: Dawid Niedzwiecki --- doc/services/device_mgmt/ec_host_cmd.rst | 12 +++++ subsys/mgmt/ec_host_cmd/Kconfig | 5 +- subsys/mgmt/ec_host_cmd/Kconfig.logging | 12 +++++ subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 50 ++++++++++++++++++- 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 subsys/mgmt/ec_host_cmd/Kconfig.logging diff --git a/doc/services/device_mgmt/ec_host_cmd.rst b/doc/services/device_mgmt/ec_host_cmd.rst index 1b3e9ff6f693..cf940ef5f30a 100644 --- a/doc/services/device_mgmt/ec_host_cmd.rst +++ b/doc/services/device_mgmt/ec_host_cmd.rst @@ -69,6 +69,18 @@ buffers are useful for applications that use multiple backends. Defining separat backend would increase the memory usage. However, some buffers can be defined by a peripheral driver e.g. eSPI. These ones should be reused as much as possible. +Logging +******* + +The host command has an embedded logging system of the ongoing communication. The are a few logging +levels: + +* `LOG_INF` is used to log a command id of a new command and not success responses. Repeats of the + same command are not logged +* `LOG_DBG` logs every command, even repeats +* `LOG_DBG` + :kconfig:option:`CONFIG_EC_HOST_CMD_LOG_DBG_BUFFERS` logs every command and responses + with the data buffers + API Reference ************* diff --git a/subsys/mgmt/ec_host_cmd/Kconfig b/subsys/mgmt/ec_host_cmd/Kconfig index 9ced4c9435f8..f71e9a6122c1 100644 --- a/subsys/mgmt/ec_host_cmd/Kconfig +++ b/subsys/mgmt/ec_host_cmd/Kconfig @@ -87,8 +87,9 @@ config EC_HOST_CMD_DEDICATED_THREAD The ec_host_cmd_init function creates a new thread dedicated for Host Command. Otherwise the ec_host_cmd_task function has to be called within another thread. -endif # EC_HOST_CMD - +source "subsys/mgmt/ec_host_cmd/Kconfig.logging" source "subsys/mgmt/ec_host_cmd/backends/Kconfig" +endif # EC_HOST_CMD + endmenu diff --git a/subsys/mgmt/ec_host_cmd/Kconfig.logging b/subsys/mgmt/ec_host_cmd/Kconfig.logging new file mode 100644 index 000000000000..2fdd6c59c527 --- /dev/null +++ b/subsys/mgmt/ec_host_cmd/Kconfig.logging @@ -0,0 +1,12 @@ +# Host command logging configs + +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config EC_HOST_CMD_LOG_DBG_BUFFERS + bool "Log full params and response buffers in debug log level" + depends on EC_HC_LOG_LEVEL_DBG + help + Every command is logged with the debug logging level. Use this config + to decide, if full reqest and response buffers are logged alongside + other command parameters. 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 6ddaedca4911..6e4b96396d4d 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -10,6 +10,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(host_cmd_handler, CONFIG_EC_HC_LOG_LEVEL); @@ -161,10 +162,20 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, struct ec_host_cmd_tx_buf *tx = &hc->tx; 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; + + LOG_INF("HC 0x%04x err %d", rx_header->cmd_id, status); send_status_response(hc->backend, tx, status); return status; } +#ifdef CONFIG_EC_HOST_CMD_LOG_DBG_BUFFERS + if (args->output_buf_size) { + LOG_HEXDUMP_DBG(args->output_buf, args->output_buf_size, "HC resp:"); + } +#endif + status = prepare_response(tx, args->output_buf_size); if (status != EC_HOST_CMD_SUCCESS) { send_status_response(hc->backend, tx, status); @@ -174,6 +185,41 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, return hc->backend->api->send(hc->backend); } +static void ec_host_cmd_log_request(const uint8_t *rx_buf) +{ + static uint16_t prev_cmd; + const struct ec_host_cmd_request_header *const rx_header = + (const struct ec_host_cmd_request_header *const)rx_buf; + + if (IS_ENABLED(CONFIG_EC_HOST_CMD_LOG_DBG_BUFFERS)) { + if (rx_header->data_len) { + const uint8_t *rx_data = rx_buf + RX_HEADER_SIZE; + static const char dbg_fmt[] = "HC 0x%04x.%d:"; + /* Use sizeof because "%04x" needs 4 bytes for command id, and + * %d needs 2 bytes for version, so no additional buffer is required. + */ + char dbg_raw[sizeof(dbg_fmt)]; + + snprintf(dbg_raw, sizeof(dbg_raw), dbg_fmt, rx_header->cmd_id, + rx_header->cmd_ver); + LOG_HEXDUMP_DBG(rx_data, rx_header->data_len, dbg_raw); + + return; + } + } + + /* In normal output mode, skip printing repeats of the same command + * that occur in rapid succession - such as flash commands during + * software sync. + */ + if (rx_header->cmd_id != prev_cmd) { + prev_cmd = rx_header->cmd_id; + LOG_INF("HC 0x%04x", rx_header->cmd_id); + } else { + LOG_DBG("HC 0x%04x", rx_header->cmd_id); + } +} + FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void *arg3) { ARG_UNUSED(arg2); @@ -196,6 +242,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * /* Wait until RX messages is received on host interface */ k_sem_take(&rx->handler_owns, K_FOREVER); + ec_host_cmd_log_request(rx->buf); status = verify_rx(rx); if (status != EC_HOST_CMD_SUCCESS) { ec_host_cmd_send_response(status, &args); @@ -203,8 +250,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * } found_handler = NULL; - STRUCT_SECTION_FOREACH(ec_host_cmd_handler, handler) - { + STRUCT_SECTION_FOREACH(ec_host_cmd_handler, handler) { if (handler->id == rx_header->cmd_id) { found_handler = handler; break; From 85c5a25e09a7465a11226729d5aac6027b20f034 Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Mon, 5 Jun 2023 18:00:58 +0200 Subject: [PATCH 0633/2042] tests: workq: Add timeout parameter Add TEST_WORK_ITEM_WAIT_MS and TEST_SUBMIT_WAIT_MS config parameters instead of hardcoded timeouts at kernel.workqueue test to allow its customization on slow simulated platforms. Signed-off-by: Dmitrii Golovanov --- tests/kernel/workq/work_queue/Kconfig | 12 ++++++++++++ tests/kernel/workq/work_queue/src/main.c | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 tests/kernel/workq/work_queue/Kconfig diff --git a/tests/kernel/workq/work_queue/Kconfig b/tests/kernel/workq/work_queue/Kconfig new file mode 100644 index 000000000000..ddd8082992d3 --- /dev/null +++ b/tests/kernel/workq/work_queue/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config TEST_WORK_ITEM_WAIT_MS + int "Test item working time, msec." + default 100 + +config TEST_SUBMIT_WAIT_MS + int "Test item submission interval, msec." + default 50 diff --git a/tests/kernel/workq/work_queue/src/main.c b/tests/kernel/workq/work_queue/src/main.c index fef4ab036c8b..d55e074de0bc 100644 --- a/tests/kernel/workq/work_queue/src/main.c +++ b/tests/kernel/workq/work_queue/src/main.c @@ -21,8 +21,9 @@ #include #define NUM_TEST_ITEMS 6 -/* Each work item takes 100ms */ -#define WORK_ITEM_WAIT 100 + +/* Each work item takes 100ms by default. */ +#define WORK_ITEM_WAIT (CONFIG_TEST_WORK_ITEM_WAIT_MS) /* In fact, each work item could take up to this value */ #define WORK_ITEM_WAIT_ALIGNED \ @@ -32,7 +33,8 @@ * Wait 50ms between work submissions, to ensure co-op and prempt * preempt thread submit alternatively. */ -#define SUBMIT_WAIT 50 +#define SUBMIT_WAIT (CONFIG_TEST_SUBMIT_WAIT_MS) + #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) /* How long to wait for the full test suite to complete. Allow for a From 4beb51c52ffeffb8b2cd0c150634ceb1c6913f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Casper=20Egholm=20J=C3=B8rgensen?= Date: Fri, 16 Jun 2023 14:38:08 +0200 Subject: [PATCH 0634/2042] drivers: src: hwinfo: Report reset cause for lockup_sysresetreq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix incomplete reset cause to be reported for NXP MIMXRT1062-evkb. In the event of a reset due to core lockup or software reset request on a 1062 board, the current NXP hwinfo driver reports an incomplete reset cause (only Ipp reset pin). This is happening because the 1062 uses a combined CPU lockup and system reset request register bit that should be checked, whereas the current driver only checks for the existence of a lockup-only status bit. This commit adds a check on the flag FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ already present in MIMXRT1062_features.h, to report such a reset cause should it occur. Signed-off-by: Casper Egholm Jørgensen --- drivers/hwinfo/hwinfo_mcux_src.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/hwinfo/hwinfo_mcux_src.c b/drivers/hwinfo/hwinfo_mcux_src.c index ecd64edabcf8..4e7b6e55675f 100644 --- a/drivers/hwinfo/hwinfo_mcux_src.c +++ b/drivers/hwinfo/hwinfo_mcux_src.c @@ -37,6 +37,12 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) flags |= RESET_CPU_LOCKUP; } #endif +#if (defined(FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ) && \ + FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ) + if (reason & kSRC_LockupSysResetFlag) { + flags |= RESET_CPU_LOCKUP | RESET_SOFTWARE; + } +#endif #if (defined(FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B) && FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B) if (reason & kSRC_CsuResetFlag) { flags |= RESET_SECURITY; @@ -115,6 +121,10 @@ int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported) #if (defined(FSL_FEATURE_SRC_HAS_SCR_LOCKUP_RST) && FSL_FEATURE_SRC_HAS_SCR_LOCKUP_RST) | RESET_CPU_LOCKUP #endif +#if (defined(FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ) && \ + FSL_FEATURE_SRC_HAS_SRSR_LOCKUP_SYSRESETREQ) + | RESET_CPU_LOCKUP | RESET_SOFTWARE +#endif #if (defined(FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B) && FSL_FEATURE_SRC_HAS_SRSR_CSU_RESET_B) | RESET_SECURITY #endif From e99b8f3433a88dff0f1503cde48d9faf2b0c3475 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:39:44 +0200 Subject: [PATCH 0635/2042] Bluetooth: BAP: Shell: Fix missing src_id in mod_src The src_id was never set in cmd_bap_broadcast_assistant_mod_src. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_broadcast_assistant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 72fe52c44e49..e521344daa2f 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -689,6 +689,7 @@ static int cmd_bap_broadcast_assistant_mod_src(const struct shell *sh, return -ENOEXEC; } + param.src_id = src_id; param.pa_sync = shell_strtobool(argv[2], 0, &result); if (result != 0) { From 69a93f38352ddcd4f7bd8fc7f5894494db3abe20 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 6 Jun 2023 12:38:09 +0200 Subject: [PATCH 0636/2042] bluetooth: tester: LE Audio: Fix sending ISO data The host app should increment the sequence number within SDU interval whether it has any data to send data to the controller or not. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/overlay-le-audio.conf | 6 +- tests/bluetooth/tester/src/btp/btp_bap.h | 5 + tests/bluetooth/tester/src/btp_bap.c | 194 +++++++++++++++---- 3 files changed, 170 insertions(+), 35 deletions(-) diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index 1645f10c8db7..b7c40d047553 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -4,6 +4,10 @@ CONFIG_BT_BAP_UNICAST_SERVER=y 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 + +# Ring buffer for streaming ISO data +CONFIG_RING_BUFFER=y # These have to be the same as in the controller (hci_rpmsg) CONFIG_BT_MAX_CONN=2 @@ -22,7 +26,7 @@ CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 # Support an ISO channel per ASE -CONFIG_BT_ISO_MAX_CHAN=2 +CONFIG_BT_ISO_MAX_CHAN=4 # PACS CONFIG_BT_PAC_SNK_LOC_WRITEABLE=y diff --git a/tests/bluetooth/tester/src/btp/btp_bap.h b/tests/bluetooth/tester/src/btp/btp_bap.h index 876acae98434..2157d6c79fc6 100644 --- a/tests/bluetooth/tester/src/btp/btp_bap.h +++ b/tests/bluetooth/tester/src/btp/btp_bap.h @@ -28,6 +28,10 @@ struct btp_bap_send_cmd { uint8_t data[0]; } __packed; +struct btp_bap_send_rp { + uint8_t data_len; +} __packed; + /* BAP events */ #define BTP_BAP_EV_DISCOVERY_COMPLETED 0x80 struct btp_bap_discovery_completed_ev { @@ -43,6 +47,7 @@ struct btp_bap_codec_cap_found_ev { uint16_t frequencies; uint8_t frame_durations; uint32_t octets_per_frame; + uint8_t channel_counts; } __packed; #define BTP_BAP_EV_ASE_FOUND 0x82 diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index 348535ead511..4ef9f1b68f94 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -50,9 +51,13 @@ struct audio_stream { struct bt_bap_stream stream; uint8_t ase_id; uint8_t conn_id; - uint16_t seq_num; + 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; }; #define MAX_STREAMS_COUNT MAX(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \ @@ -83,6 +88,16 @@ static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(CONFIG_BT_ISO_RX_MTU + static bool already_sent; +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 void print_codec(const struct bt_codec *codec) { LOG_DBG("codec 0x%02x cid 0x%04x vid 0x%04x count %zu", @@ -449,7 +464,8 @@ static void stream_configured(struct bt_bap_stream *stream, struct audio_connection *audio_conn; struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); - LOG_DBG("Configured stream %p", 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; @@ -525,6 +541,23 @@ static void stream_started(struct bt_bap_stream *stream) struct audio_stream *a_stream = CONTAINER_OF(stream, struct audio_stream, stream); LOG_DBG("Started stream %p", stream); + + if (stream->dir == BT_AUDIO_DIR_SINK) { + /* 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)); + } + btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, BT_ASCS_START_OP, BTP_STATUS_SUCCESS); } @@ -534,6 +567,13 @@ 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); + + if (stream->dir == BT_AUDIO_DIR_SINK) { + /* 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_STOP_OP, BTP_STATUS_SUCCESS); } @@ -604,6 +644,9 @@ static void btp_send_pac_codec_found_ev(struct bt_conn *conn, const struct bt_co bt_codec_get_val(codec, BT_CODEC_LC3_FRAME_LEN, &data); memcpy(&ev.octets_per_frame, data->data.data, sizeof(ev.octets_per_frame)); + bt_codec_get_val(codec, BT_CODEC_LC3_CHAN_COUNT, &data); + memcpy(&ev.channel_counts, data->data.data, sizeof(ev.channel_counts)); + tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_CODEC_CAP_FOUND, &ev, sizeof(ev)); } @@ -625,7 +668,6 @@ static void unicast_client_location_cb(struct bt_conn *conn, enum bt_audio_dir dir, enum bt_audio_location loc) { - LOG_DBG("unicast_client_location_cb"); LOG_DBG("dir %u loc %X", dir, loc); } @@ -633,7 +675,6 @@ static void available_contexts_cb(struct bt_conn *conn, enum bt_audio_context snk_ctx, enum bt_audio_context src_ctx) { - LOG_DBG("available_contexts_cb"); LOG_DBG("snk ctx %u src ctx %u", snk_ctx, src_ctx); } @@ -641,28 +682,24 @@ static void available_contexts_cb(struct bt_conn *conn, 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("config_cb"); 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("qos_cb"); 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("enable_cb"); 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) { - LOG_DBG("start_cb"); LOG_DBG("stream %p start operation rsp_code %u reason %u", stream, rsp_code, reason); already_sent = false; } @@ -670,34 +707,30 @@ static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp 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("stop_cb"); 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("disable_cb"); 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("metadata_cb"); 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("release_cb"); 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_codec *codec) { - LOG_DBG("pac_record_cb"); + LOG_DBG(""); if (codec != NULL) { LOG_DBG("Discovered codec capabilities %p", codec); @@ -710,7 +743,7 @@ static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_b { struct audio_connection *audio_conn; - LOG_DBG("endpoint_cb"); + LOG_DBG(""); if (ep != NULL) { LOG_DBG("Discovered ASE %p, id %u, dir 0x%02x", ep, ep->status.id, ep->dir); @@ -736,7 +769,7 @@ static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_b static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) { - LOG_DBG("discover_cb"); + LOG_DBG(""); if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) { LOG_DBG("Discover remote ASEs failed: %d", err); @@ -819,16 +852,102 @@ static uint8_t bap_discover(const void *cmd, uint16_t cmd_len, 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 bt_iso_chan *iso_chan; + 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) { + iso_chan = bt_bap_stream_iso_chan_get(&stream->stream); + err = bt_iso_chan_get_tx_sync(iso_chan, &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 */ + } + + buf = net_buf_alloc(&tx_pool, K_NO_WAIT); + if (!buf) { + LOG_ERR("Cannot allocate net_buf. Dropping data."); + k_work_schedule_for_queue(&iso_data_work_q, dwork, + K_USEC(stream->stream.qos->interval)); + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + + /* Get buffer within a ring buffer memory */ + size = ring_buf_get_claim(&audio_ring_buf, &data, stream->stream.qos->sdu); + if (size != 0) { + 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 ASE: ase_id %d len %d seq %d", stream->stream.ep->status.id, + size, stream->last_req_seq_num); + + err = bt_bap_stream_send(&stream->stream, buf, stream->last_req_seq_num, + BT_ISO_TIMESTAMP_NONE); + if (err != 0) { + LOG_ERR("Failed to send audio data to stream: ase_id %d dir seq %d %d err %d", + stream->ase_id, stream->stream.dir, stream->last_req_seq_num, err); + net_buf_unref(buf); + } + + if (size != 0) { + /* 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) { - int err; + 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 net_buf *buf; struct bt_conn_info conn_info; + uint32_t ret; conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); if (!conn) { @@ -844,22 +963,10 @@ static uint8_t bap_send(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } - LOG_DBG("Sending data to ASE: ase_id %d len %d seq %d", cp->ase_id, cp->data_len, - stream->seq_num); - - buf = net_buf_alloc(&tx_pool, K_FOREVER); - net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); - - net_buf_add_mem(buf, cp->data, cp->data_len); + ret = ring_buf_put(&audio_ring_buf, cp->data, cp->data_len); - err = bt_bap_stream_send(&stream->stream, buf, stream->seq_num++, BT_ISO_TIMESTAMP_NONE); - if (err != 0) { - LOG_ERR("Failed to send audio data to stream: ase_id %d dir %d err %d", - stream->ase_id, stream->stream.dir, err); - net_buf_unref(buf); - - return BTP_STATUS_FAILED; - } + rp->data_len = ret; + *rsp_len = sizeof(*rp) + 1; return BTP_STATUS_SUCCESS; } @@ -983,7 +1090,7 @@ static int client_create_unicast_group(struct audio_connection *audio_conn, uint } param.params = pair_params; - param.params_count = stream_cnt; + param.params_count = MAX(sink_cnt, src_cnt); param.packing = BT_ISO_PACKING_SEQUENTIAL; LOG_DBG("Creating unicast group"); @@ -1146,6 +1253,18 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, } audio_conn = &connections[bt_conn_index(conn)]; + + if (audio_conn->unicast_group != NULL) { + err = bt_bap_unicast_group_delete(audio_conn->unicast_group); + if (err != 0) { + LOG_DBG("Failed to delete the unicast group, err %d", err); + bt_conn_unref(conn); + + return BTP_STATUS_FAILED; + } + audio_conn->unicast_group = NULL; + } + qos = &audio_conn->qos; qos->phy = BT_CODEC_QOS_2M; qos->framing = cp->framing; @@ -1265,7 +1384,9 @@ static uint8_t ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } - LOG_DBG("Starting stream"); + LOG_DBG("Starting stream %p, ep %u, dir %u", &stream->stream, cp->ase_id, + stream->stream.ep->dir); + err = bt_bap_stream_start(&stream->stream); if (err != 0) { LOG_DBG("Could not start stream: %d", err); @@ -1655,6 +1776,11 @@ uint8_t tester_init_bap(void) 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); + tester_register_command_handlers(BTP_SERVICE_ID_BAP, bap_handlers, ARRAY_SIZE(bap_handlers)); From c8a650fa894946d29100c7eb99c2bfcb230852a8 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Wed, 21 Jun 2023 11:08:42 +0200 Subject: [PATCH 0637/2042] bluetooth: tester: has: Update name of bt_has_register_param The bt_has_register_param was renamed to bt_has_features_param recently. Fixes build errors. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/src/btp_has.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp_has.c b/tests/bluetooth/tester/src/btp_has.c index 1ea93a593e7b..76aa2d85acb4 100644 --- a/tests/bluetooth/tester/src/btp_has.c +++ b/tests/bluetooth/tester/src/btp_has.c @@ -183,7 +183,7 @@ uint8_t tester_init_has(void) tester_register_command_handlers(BTP_SERVICE_ID_HAS, has_handlers, ARRAY_SIZE(has_handlers)); - struct bt_has_register_param params = { + struct bt_has_features_param params = { BT_HAS_HEARING_AID_TYPE_BINAURAL, false, true }; int err = bt_has_register(¶ms); From 76dc5d37cb136fea15e84a5cdd3c59cc84763784 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Wed, 21 Jun 2023 11:12:17 +0200 Subject: [PATCH 0638/2042] bluetooth: tester: vcp: Remove unused include Fixes build error: mesh/keys.h:40:2: error: #error "Crypto library has not been chosen" Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/src/btp_vcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/bluetooth/tester/src/btp_vcp.c b/tests/bluetooth/tester/src/btp_vcp.c index 70cdecf7eb0d..744adf8ddc18 100644 --- a/tests/bluetooth/tester/src/btp_vcp.c +++ b/tests/bluetooth/tester/src/btp_vcp.c @@ -15,8 +15,6 @@ #include "zephyr/bluetooth/audio/vocs.h" #include "zephyr/sys/util.h" -#include - #include #define LOG_MODULE_NAME bttester_vcp LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); From 7d7874c75b42f391a08de112b42f0b048da1b50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kopy=C5=9Bci=C5=84ski?= Date: Fri, 26 May 2023 14:11:12 +0200 Subject: [PATCH 0639/2042] Tests: Bluetooth: tester: add BTP command for connecting Proxy Client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to execute MESH/CL/MPXS tests. Signed-off-by: Krzysztof Kopyściński --- tests/bluetooth/tester/overlay-mesh.conf | 1 + tests/bluetooth/tester/src/btp/btp_mesh.h | 6 ++++++ tests/bluetooth/tester/src/btp_mesh.c | 24 +++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/tests/bluetooth/tester/overlay-mesh.conf b/tests/bluetooth/tester/overlay-mesh.conf index 963b864ba2b9..840af06c1c08 100644 --- a/tests/bluetooth/tester/overlay-mesh.conf +++ b/tests/bluetooth/tester/overlay-mesh.conf @@ -22,3 +22,4 @@ CONFIG_BT_MESH_CDB=y 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 diff --git a/tests/bluetooth/tester/src/btp/btp_mesh.h b/tests/bluetooth/tester/src/btp/btp_mesh.h index 5aa191d7d7b8..096f61bcb161 100644 --- a/tests/bluetooth/tester/src/btp/btp_mesh.h +++ b/tests/bluetooth/tester/src/btp/btp_mesh.h @@ -747,6 +747,12 @@ struct btp_mesh_cfg_krp_set_rp { uint8_t phase; } __packed; +#define BTP_MESH_PROXY_CONNECT 0x77 + +struct btp_proxy_connect_cmd { + uint16_t net_idx; +} __packed; + /* events */ #define BTP_MESH_EV_OUT_NUMBER_ACTION 0x80 struct btp_mesh_out_number_action_ev { diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 9af4867a84a3..37dd04ab3e47 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -916,6 +916,23 @@ static uint8_t proxy_identity_enable(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +#if defined(CONFIG_BT_MESH_PROXY_CLIENT) +static uint8_t proxy_connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_proxy_connect_cmd *cp = cmd; + int err; + + err = bt_mesh_proxy_connect(cp->net_idx); + if (err) { + LOG_ERR("Failed to connect to GATT Proxy (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} +#endif + static uint8_t composition_data_get(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -2849,6 +2866,13 @@ static const struct btp_handler handlers[] = { .expect_len = 0, .func = proxy_identity_enable, }, +#if defined(CONFIG_BT_MESH_PROXY_CLIENT) + { + .opcode = BTP_MESH_PROXY_CONNECT, + .expect_len = sizeof(struct btp_proxy_connect_cmd), + .func = proxy_connect + }, +#endif }; void net_recv_ev(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, const void *payload, From ee67bdfc56d78584856196d761b4c64e71d033b0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 31 May 2023 16:11:22 +0200 Subject: [PATCH 0640/2042] tests libC: Filter based on type of target not whole arch The POSIX arch now also supports embedded libCs for some targets. Narrow the test filter accordingly. Signed-off-by: Alberto Escolar Piedras --- tests/lib/c_lib/testcase.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/testcase.yaml index 2035719e5221..51b1e97bbf92 100644 --- a/tests/lib/c_lib/testcase.yaml +++ b/tests/lib/c_lib/testcase.yaml @@ -1,12 +1,13 @@ common: tags: - clib - arch_exclude: posix + filter: not CONFIG_NATIVE_APPLICATION integration_platforms: - mps2_an385 tests: libraries.libc: ignore_faults: true + filter: not (CONFIG_ARCH_POSIX and CONFIG_EXTERNAL_LIBC) libraries.libc.picolibc: filter: CONFIG_PICOLIBC_SUPPORTED tags: picolibc From 14573fcbf6e38779613418f7b106d701be146ac8 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 26 Jun 2023 16:50:37 +0300 Subject: [PATCH 0641/2042] tests: lwm2m: Fix too small test buffer ZTEST(lwm2m_registry, test_strings) is using opaque resource 0/0/3 to write a test string "coap://127.0.0.1" which happens to be same length as default key size. Need more room to add end marker and verify it. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/lwm2m_registry/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf index 3bbd185d38b5..1825b4175bcc 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf +++ b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf @@ -9,6 +9,7 @@ CONFIG_NEWLIB_LIBC=y CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 +CONFIG_LWM2M_SECURITY_KEY_SIZE=32 CONFIG_LWM2M_IPSO_SUPPORT=y CONFIG_LWM2M_IPSO_TEMP_SENSOR=y CONFIG_LWM2M_IPSO_TEMP_SENSOR_VERSION_1_1=y From 0f6ded79898713ea261c76098fb112822902263b Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 19 Jun 2023 13:18:23 +0300 Subject: [PATCH 0642/2042] test: net: lwm2m: Fix build warning about unitialized vars Few variables were uninitialized on certain cases. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/engine/src/lwm2m_observation.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c b/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c index 8106d7180b3d..9371702b2e90 100644 --- a/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c +++ b/tests/net/lib/lwm2m/engine/src/lwm2m_observation.c @@ -49,10 +49,10 @@ static void assert_path_list_order(sys_slist_t *lwm2m_path_list) struct lwm2m_obj_path_list *prev = NULL; struct lwm2m_obj_path_list *entry, *tmp; - uint16_t obj_id_max; - uint16_t obj_inst_id_max; - uint16_t res_id_max; - uint16_t res_inst_id_max; + uint16_t obj_id_max = 0; + uint16_t obj_inst_id_max = 0; + uint16_t res_id_max = 0; + uint16_t res_inst_id_max = 0; if (sys_slist_is_empty(lwm2m_path_list)) { return; From e92f8acff91fa2cf75eea51808e65e71439335d9 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 21 Jun 2023 13:15:47 +0300 Subject: [PATCH 0643/2042] tests: net: lwm2m: Remove timing sensitive assert As the lwm2m_reset_message() is stubbed, it does not remove a message from rettry queue. Therefore depending on the simulation speed, retries can happen one or many times. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/lwm2m_engine/src/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c index 86811fec805e..6e432f6dca8b 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/main.c @@ -57,7 +57,6 @@ static int lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path *path, bool *v static void test_service(struct k_work *work) { - LOG_INF("Test service"); k_sleep(K_MSEC(10)); } @@ -339,8 +338,8 @@ ZTEST(lwm2m_engine, test_retransmit_request) k_sleep(K_MSEC(500)); ret = lwm2m_engine_stop(&ctx); zassert_equal(ret, 0); - zassert_equal(lwm2m_reset_message_fake.call_count, 1, "Message was not reseted"); - zassert_equal(lwm2m_send_message_async_fake.call_count, 1, "Message was not sent"); + zassert_not_equal(lwm2m_reset_message_fake.call_count, 0, "Message was not reseted"); + zassert_not_equal(lwm2m_send_message_async_fake.call_count, 0, "Message was not sent"); } ZTEST(lwm2m_engine, test_socket_recv) From a7498c39e2d34d33a463fc861f1f39f0a626b8da Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 19 Jun 2023 13:16:30 +0300 Subject: [PATCH 0644/2042] tests: net: lwm2m: Remove unnecessary filtering Content-format tests do not require network or Newlibc, so by removing these filters. Defined a native_posix as the only integration platform because all simulated arm-zephyr-eabi platforms are filtered out by Twister. Signed-off-by: Seppo Takalo --- tests/net/lib/lwm2m/block_transfer/testcase.yaml | 10 +++++++--- tests/net/lib/lwm2m/content_json/prj.conf | 2 -- tests/net/lib/lwm2m/content_json/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/content_link_format/prj.conf | 2 -- tests/net/lib/lwm2m/content_link_format/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/content_oma_tlv/prj.conf | 2 -- tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/content_plain_text/prj.conf | 2 -- tests/net/lib/lwm2m/content_plain_text/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/content_raw_cbor/prj.conf | 2 -- tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/content_senml_cbor/prj.conf | 2 -- tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/engine/prj.conf | 1 - tests/net/lib/lwm2m/engine/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml | 7 ++++--- tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml | 11 +++-------- tests/net/lib/lwm2m/lwm2m_registry/prj.conf | 2 -- tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml | 7 ++++--- 19 files changed, 46 insertions(+), 53 deletions(-) diff --git a/tests/net/lib/lwm2m/block_transfer/testcase.yaml b/tests/net/lib/lwm2m/block_transfer/testcase.yaml index 55a40d517eb4..66f145fd18fb 100644 --- a/tests/net/lib/lwm2m/block_transfer/testcase.yaml +++ b/tests/net/lib/lwm2m/block_transfer/testcase.yaml @@ -1,5 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.block_transfer: - tags: lwm2m net + platform_key: + - simulation + tags: + - lwm2m + - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_json/prj.conf b/tests/net/lib/lwm2m/content_json/prj.conf index 5f99626db5fb..3f2cd3e60f24 100644 --- a/tests/net/lib/lwm2m/content_json/prj.conf +++ b/tests/net/lib/lwm2m/content_json/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 CONFIG_LWM2M_RW_JSON_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_json/testcase.yaml b/tests/net/lib/lwm2m/content_json/testcase.yaml index 2004897b6e20..a283ce908ef6 100644 --- a/tests/net/lib/lwm2m/content_json/testcase.yaml +++ b/tests/net/lib/lwm2m/content_json/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_json: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_link_format/prj.conf b/tests/net/lib/lwm2m/content_link_format/prj.conf index b70c6003eef6..952b54a4566a 100644 --- a/tests/net/lib/lwm2m/content_link_format/prj.conf +++ b/tests/net/lib/lwm2m/content_link_format/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_RW_JSON_SUPPORT=y CONFIG_JSON_LIBRARY=y diff --git a/tests/net/lib/lwm2m/content_link_format/testcase.yaml b/tests/net/lib/lwm2m/content_link_format/testcase.yaml index c075d55edf3c..5448cf68fd05 100644 --- a/tests/net/lib/lwm2m/content_link_format/testcase.yaml +++ b/tests/net/lib/lwm2m/content_link_format/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_link_format: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_oma_tlv/prj.conf b/tests/net/lib/lwm2m/content_oma_tlv/prj.conf index 9c9cec3be7c5..6041addad837 100644 --- a/tests/net/lib/lwm2m/content_oma_tlv/prj.conf +++ b/tests/net/lib/lwm2m/content_oma_tlv/prj.conf @@ -5,6 +5,4 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y diff --git a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml index 710858883677..2bf877f73537 100644 --- a/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml +++ b/tests/net/lib/lwm2m/content_oma_tlv/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_oma_tlv: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_plain_text/prj.conf b/tests/net/lib/lwm2m/content_plain_text/prj.conf index 9c9cec3be7c5..6041addad837 100644 --- a/tests/net/lib/lwm2m/content_plain_text/prj.conf +++ b/tests/net/lib/lwm2m/content_plain_text/prj.conf @@ -5,6 +5,4 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y diff --git a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml index cc902805c829..bd70dd790b30 100644 --- a/tests/net/lib/lwm2m/content_plain_text/testcase.yaml +++ b/tests/net/lib/lwm2m/content_plain_text/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_plain_text: - filter: TOOLCHAIN_HAS_NEWLIB == 1 + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_raw_cbor/prj.conf b/tests/net/lib/lwm2m/content_raw_cbor/prj.conf index 0fae8dcbbeb4..64ab6f89d22a 100644 --- a/tests/net/lib/lwm2m/content_raw_cbor/prj.conf +++ b/tests/net/lib/lwm2m/content_raw_cbor/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_VERSION_1_1=y CONFIG_LWM2M_RW_CBOR_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml index 13a564aa97d4..9fc90f109bc0 100644 --- a/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_raw_cbor/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_raw_cbor: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/content_senml_cbor/prj.conf b/tests/net/lib/lwm2m/content_senml_cbor/prj.conf index d6bdaceb9345..27a8364af588 100644 --- a/tests/net/lib/lwm2m/content_senml_cbor/prj.conf +++ b/tests/net/lib/lwm2m/content_senml_cbor/prj.conf @@ -5,8 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y - CONFIG_LWM2M=y CONFIG_LWM2M_VERSION_1_1=y CONFIG_LWM2M_RW_CBOR_SUPPORT=y diff --git a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml index 4d2db6e5838b..55cd89a9f51b 100644 --- a/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml +++ b/tests/net/lib/lwm2m/content_senml_cbor/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.content_senml_cbor: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/engine/prj.conf b/tests/net/lib/lwm2m/engine/prj.conf index 18a5df2ad223..4477075056a5 100644 --- a/tests/net/lib/lwm2m/engine/prj.conf +++ b/tests/net/lib/lwm2m/engine/prj.conf @@ -5,7 +5,6 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 diff --git a/tests/net/lib/lwm2m/engine/testcase.yaml b/tests/net/lib/lwm2m/engine/testcase.yaml index 28047c0fa5f4..3263441b418d 100644 --- a/tests/net/lib/lwm2m/engine/testcase.yaml +++ b/tests/net/lib/lwm2m/engine/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.engine: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml index 9f58cafdea44..a7f628405ebf 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_engine/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.lwm2m_engine: - platform_allow: native_posix + platform_key: + - simulation tags: - lwm2m - net + integration_platforms: + - native_posix diff --git a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml index 7e6415395ca9..b5f21f0d9dc5 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/testcase.yaml @@ -1,16 +1,11 @@ common: - depends_on: netif + platform_key: + - simulation tags: - - net - lwm2m - platform_allow: - - native_posix - - qemu_x86 - - qemu_x86_64 + - net integration_platforms: - native_posix - - qemu_x86 - tests: net.lwm2m.lwm2m_rd_client: extra_args: EXTRA_CFLAGS="" diff --git a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf index 1825b4175bcc..0b7b96721227 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/prj.conf +++ b/tests/net/lib/lwm2m/lwm2m_registry/prj.conf @@ -2,10 +2,8 @@ CONFIG_NETWORKING=y CONFIG_NET_TEST=y CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y - CONFIG_ENTROPY_GENERATOR=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_NEWLIB_LIBC=y CONFIG_LWM2M=y CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512 diff --git a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml index b0fda561cff3..ca0f06f58b57 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml +++ b/tests/net/lib/lwm2m/lwm2m_registry/testcase.yaml @@ -1,8 +1,9 @@ -common: - depends_on: netif tests: net.lwm2m.lwm2m_registry: + platform_key: + - simulation tags: - lwm2m - net - filter: TOOLCHAIN_HAS_NEWLIB == 1 + integration_platforms: + - native_posix From 1eb4317d5c118550c80c55573f087b62785f2afd Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 12:24:49 +0800 Subject: [PATCH 0645/2042] dts: bindings: vendor-prefixes: Add efinix prefix Add efinix manufacturer binding prefix. Signed-off-by: Manojkumar Subramaniam --- 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 c7bcb10eabbc..f6244d4e3947 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -173,6 +173,7 @@ ebv EBV Elektronik eckelmann Eckelmann AG edt Emerging Display Technologies eeti eGalax_eMPIA Technology Inc +efinix Efinix Inc einfochips Einfochips elan Elan Microelectronic Corp. element14 Element14 (A Premier Farnell Company) From 2ec89ba8319fa8955068753bf8d5534384213018 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 12:31:29 +0800 Subject: [PATCH 0646/2042] dts: bindings: gpio: Add `efinix,sapphire-gpio` A new gpio controller addition Signed-off-by: Manojkumar Subramaniam --- dts/bindings/gpio/efinix,sapphire-gpio.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 dts/bindings/gpio/efinix,sapphire-gpio.yaml diff --git a/dts/bindings/gpio/efinix,sapphire-gpio.yaml b/dts/bindings/gpio/efinix,sapphire-gpio.yaml new file mode 100644 index 000000000000..24808c1cec88 --- /dev/null +++ b/dts/bindings/gpio/efinix,sapphire-gpio.yaml @@ -0,0 +1,19 @@ +description: Efinix Sapphire GPIO + +compatible: "efinix,sapphire-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + ngpios: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags From 197cce50d0fdd59bcb0b86dd83dd1a2475344213 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 12:36:17 +0800 Subject: [PATCH 0647/2042] dts: bindings: serial: Add `efinix,sapphire-uart0` A new UART controller addition, interrupt is optional Signed-off-by: Manojkumar Subramaniam --- dts/bindings/serial/efinix,sapphire-uart0.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 dts/bindings/serial/efinix,sapphire-uart0.yaml diff --git a/dts/bindings/serial/efinix,sapphire-uart0.yaml b/dts/bindings/serial/efinix,sapphire-uart0.yaml new file mode 100644 index 000000000000..87c675dd9efc --- /dev/null +++ b/dts/bindings/serial/efinix,sapphire-uart0.yaml @@ -0,0 +1,9 @@ +description: Efinix Sapphire UART + +compatible: "efinix,sapphire-uart0" + +include: uart-controller.yaml + +properties: + reg: + required: true From e8109f903c7ef039b1df64c05ea0098c4f3a60e0 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 12:40:21 +0800 Subject: [PATCH 0648/2042] dts: bindings: timer: Add `efinix,sapphire-timer0` A new timer controller addition Signed-off-by: Manojkumar Subramaniam --- dts/bindings/timer/efinix-sapphire,timer0.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 dts/bindings/timer/efinix-sapphire,timer0.yaml diff --git a/dts/bindings/timer/efinix-sapphire,timer0.yaml b/dts/bindings/timer/efinix-sapphire,timer0.yaml new file mode 100644 index 000000000000..42acf89adf0f --- /dev/null +++ b/dts/bindings/timer/efinix-sapphire,timer0.yaml @@ -0,0 +1,12 @@ +description: Efinix Sapphire timer + +compatible: "efinix,sapphire-timer0" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true From 80fda5349257b85cd2c3aea8ebc0b1c31e1191d3 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 13:04:45 +0800 Subject: [PATCH 0649/2042] dts: riscv: add a initial SoC dtsi for Efinix Sapphire SoC Sapphire SoC from Efinix Signed-off-by: Manojkumar Subramaniam --- dts/riscv/efinix/sapphire_soc.dtsi | 103 +++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 dts/riscv/efinix/sapphire_soc.dtsi diff --git a/dts/riscv/efinix/sapphire_soc.dtsi b/dts/riscv/efinix/sapphire_soc.dtsi new file mode 100644 index 000000000000..c61eec170ed6 --- /dev/null +++ b/dts/riscv/efinix/sapphire_soc.dtsi @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + model = "efinix,sapphire"; + compatible = "efinix,sapphire"; + + chosen { + zephyr,sram = &ram0; + }; + + ram0: memory@F9000000 { + device_type = "memory"; + reg = <0xF9000000 DT_SIZE_K(192)>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + clock-frequency = <100000000>; + compatible = "riscv"; + device_type = "cpu"; + reg = <0>; + riscv,isa = "rv32imac"; + status = "okay"; + timebase-frequency = <100000000>; + + hlic: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "efinix,sapphire"; + ranges; + + plic0: interrupt-controller@f8c00000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts-extended = <&hlic 11>; + reg = < 0xf8c00000 0x00001000 + 0xf8c02000 0x00000800 + 0xf8e00000 0x00010000 >; + reg-names = "prio", "irq_en", "reg"; + riscv,max-priority = <3>; + riscv,ndev = <32>; + }; + + clint: clint@f8b00000 { + compatible = "sifive,clint0"; + interrupts-extended = <&hlic 3 &hlic 7>; + reg = <0xf8b00000 0x10000>; + }; + + timer0: timer@e0002800 { + compatible = "efinix,sapphire-timer0"; + reg = <0xe0002800 0x40>; + interrupt-parent = <&plic0>; + interrupts = <19 0>; + status = "disabled"; + }; + + gpio0: gpio@f8015000 { + compatible = "efinix,sapphire-gpio"; + reg = <0xf8015000 0x100>; + reg-names = "base"; + ngpios = <4>; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + uart0: uart@f8010000 { + compatible = "efinix,sapphire-uart0"; + interrupt-parent = <&plic0>; + interrupts = <1 1>; + reg = <0xf8010000 0x40>; + reg-names = "base"; + current-speed = <115200>; + status = "disabled"; + }; + + }; +}; From 6e887e3f61dba4712db0854d8eaded37a5a3bd6c Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Tue, 21 Mar 2023 03:44:20 +0800 Subject: [PATCH 0650/2042] soc: riscv: Add initial support for Efinix Sapphire SoC - It's a riscv privilege spec SoC Signed-off-by: Manojkumar Subramaniam --- .../efinix-sapphire/CMakeLists.txt | 4 +++ .../efinix-sapphire/Kconfig.defconfig.series | 30 +++++++++++++++++++ .../efinix-sapphire/Kconfig.series | 9 ++++++ .../efinix-sapphire/Kconfig.soc | 18 +++++++++++ .../efinix-sapphire/linker.ld | 3 ++ .../riscv-privileged/efinix-sapphire/soc.h | 18 +++++++++++ 6 files changed, 82 insertions(+) create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/linker.ld create mode 100644 soc/riscv/riscv-privileged/efinix-sapphire/soc.h diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt b/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt new file mode 100644 index 000000000000..9fc806359379 --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series new file mode 100644 index 000000000000..233428931a38 --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_EFINIX_SAPPHIRE + +config SOC_SERIES + default "efinix-sapphire" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +config RISCV_HAS_CPU_IDLE + bool + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +config RISCV_HAS_PLIC + bool + default y + +config NUM_IRQS + int + default 36 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +endif # SOC_SERIES_EFINIX_SAPPHIRE diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series new file mode 100644 index 000000000000..8505cf1318a6 --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_EFINIX_SAPPHIRE + bool "Efinix Sapphire SOC implementation" + select RISCV + select SOC_FAMILY_RISCV_PRIVILEGED + help + Enable support for Efinix Sapphire SOC implementation diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc new file mode 100644 index 000000000000..dba8491b8bda --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc @@ -0,0 +1,18 @@ +# 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 + bool "Efinix Sapphire VexRiscv 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_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/linker.ld b/soc/riscv/riscv-privileged/efinix-sapphire/linker.ld new file mode 100644 index 000000000000..4cfd67a53f50 --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/linker.ld @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +#include diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h b/soc/riscv/riscv-privileged/efinix-sapphire/soc.h new file mode 100644 index 000000000000..e06175662263 --- /dev/null +++ b/soc/riscv/riscv-privileged/efinix-sapphire/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RISCV32_EFINIX_SAPPHIRE_SOC_H_ +#define __RISCV32_EFINIX_SAPPHIRE_SOC_H_ + +#include "soc_common.h" +#include +#include + +#ifndef _ASMLANGUAGE + +#endif /* _ASMLANGUAGE */ + +#endif /* __RISCV32_EFINIX_SAPPHIRE_SOC_H_ */ From 1ca6a5d77f4adaad0563c6c28031b4c86b3635af Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Fri, 17 Mar 2023 13:34:26 +0800 Subject: [PATCH 0651/2042] drivers: gpio: gpio_efinix_sapphire: initial version Add GPIO driver for Efinix Sapphire SoCs. Signed-off-by: Manojkumar Subramaniam --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.efinix_sapphire | 9 ++ drivers/gpio/gpio_efinix_sapphire.c | 234 +++++++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 drivers/gpio/Kconfig.efinix_sapphire create mode 100644 drivers/gpio/gpio_efinix_sapphire.c diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index de378a492f76..13b4c6eba83a 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -80,6 +80,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_RT1718S gpio_rt1718s_port.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) zephyr_library_sources_ifdef(CONFIG_GPIO_HOGS gpio_hogs.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) if(CONFIG_GPIO_SC18IM704) zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 90a30656586a..62ff3cb89e09 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -199,4 +199,6 @@ source "drivers/gpio/Kconfig.sc18im704" source "drivers/gpio/Kconfig.numaker" +source "drivers/gpio/Kconfig.efinix_sapphire" + endif # GPIO diff --git a/drivers/gpio/Kconfig.efinix_sapphire b/drivers/gpio/Kconfig.efinix_sapphire new file mode 100644 index 000000000000..fdbc431eb938 --- /dev/null +++ b/drivers/gpio/Kconfig.efinix_sapphire @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_EFINIX_SAPPHIRE + bool "Efinx sapphire GPIO driver" + default y + depends on DT_HAS_EFINIX_SAPPHIRE_GPIO_ENABLED + help + Enable Efinix sapphire GPIO driver. diff --git a/drivers/gpio/gpio_efinix_sapphire.c b/drivers/gpio/gpio_efinix_sapphire.c new file mode 100644 index 000000000000..9456406a63c3 --- /dev/null +++ b/drivers/gpio/gpio_efinix_sapphire.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT efinix_sapphire_gpio + +#include + +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(gpio_efinix_sapphire); + +#define SUPPORTED_FLAGS \ + (GPIO_INPUT | GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH | \ + GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH) + +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +#define BSP_GPIO_INPUT 0x00 +#define BSP_GPIO_OUTPUT 0x04 +#define BSP_GPIO_OUTPUT_ENABLE 0x08 +#define BSP_GPIO_INTERRUPT_RISE_ENABLE 0x20 +#define BSP_GPIO_INTERRUPT_FALL_ENABLE 0x24 +#define BSP_GPIO_INTERRUPT_HIGH_ENABLE 0x28 +#define BSP_GPIO_INTERRUPT_LOW_ENABLE 0x2c + +/* efinix sapphire specefic 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 */ +struct gpio_efinix_sapphire_data { + struct gpio_driver_data common; + const struct device *dev; + sys_slist_t cb; +}; + +/* Device access pointer helpers */ +#define DEV_GPIO_CFG(dev) ((const struct gpio_efinix_sapphire_cfg *)(dev)->config) +#define GPIO_OUTPUT_ADDR config->base_addr + BSP_GPIO_OUTPUT + +static inline void cfg_output_enable_bit(const struct gpio_efinix_sapphire_cfg *config, + gpio_pin_t pin, uint32_t type) +{ + +#define GPIO_OUTPUT_ENABLE_ADDR config->base_addr + BSP_GPIO_OUTPUT_ENABLE + uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ENABLE_ADDR); + + if (type == GPIO_INPUT) { + sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ENABLE_ADDR); + } else if (type == GPIO_OUTPUT) { + sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ENABLE_ADDR); + } +} + +static inline void cfg_output_bit(const struct gpio_efinix_sapphire_cfg *config, gpio_pin_t pin, + uint32_t value) +{ + + uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR); + + if (value == GPIO_LOW) { + sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ADDR); + } else if (value == GPIO_HIGH) { + sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ADDR); + } +} + +/* To use the controller bare minimun 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) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + /* Check if the controller supports the requested GPIO configuration. */ + if (flags & ~SUPPORTED_FLAGS) { + return -ENOTSUP; + } + + if ((flags & GPIO_DIR_MASK) == GPIO_DIR_MASK) { + /* Pin cannot be configured as input and output */ + return -ENOTSUP; + } else if ((flags & GPIO_DIR_MASK) == GPIO_DISCONNECTED) { + /* Pin has to be configured as input or output */ + return -ENOTSUP; + } + + /* Configure the output register based on the direction flag */ + if (flags & GPIO_OUTPUT) { + /* Set the pin as output */ + cfg_output_enable_bit(config, BIT(pin), GPIO_OUTPUT); + if (flags & GPIO_OUTPUT_INIT_HIGH) { + /* Set the pin to high */ + cfg_output_bit(config, BIT(pin), GPIO_HIGH); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + /* Set the pin to low */ + cfg_output_bit(config, BIT(pin), GPIO_LOW); + } + } else { + /* Set the pin as input */ + cfg_output_enable_bit(config, BIT(pin), GPIO_INPUT); + } + + return 0; +} + +static inline uint32_t get_port(const struct gpio_efinix_sapphire_cfg *config) +{ + uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR); + + return (c_reg_val & BIT_MASK(config->n_gpios)); +} + +static inline void set_port(const struct gpio_efinix_sapphire_cfg *config, uint32_t value) +{ + sys_write32(value, GPIO_OUTPUT_ADDR); +} + +static int gpio_efinix_sapphire_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + *value = get_port(config); + return 0; +} + +static int gpio_efinix_sapphire_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + uint32_t c_reg_val = get_port(config); + + /* Sets ports value at one go */ + c_reg_val &= ~mask; + c_reg_val |= (value & mask); + + set_port(config, c_reg_val); + + return 0; +} + +static int gpio_efinix_sapphire_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + uint32_t c_reg_val = get_port(config); + + /* Sets ports value at one go */ + c_reg_val |= pins; + + set_port(config, c_reg_val); + + return 0; +} + +static int gpio_efinix_sapphire_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + uint32_t c_reg_val = get_port(config); + + /* Sets ports value at one go */ + c_reg_val &= ~pins; + + set_port(config, c_reg_val); + + return 0; +} + +static int gpio_efinix_sapphire_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + uint32_t c_reg_val = get_port(config); + + /* Sets ports value at one go */ + c_reg_val ^= pins; + + set_port(config, c_reg_val); + + return 0; +} + +static int gpio_efinix_sapphire_init(const struct device *dev) +{ + const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev); + + if (config->n_gpios > 4) { + return -EINVAL; + } + return 0; +} + +/* API map */ +static const struct gpio_driver_api gpio_efinix_sapphire_api = { + .pin_configure = gpio_efinix_sapphire_config, + .port_get_raw = gpio_efinix_sapphire_port_get_raw, + .port_set_masked_raw = gpio_efinix_sapphire_port_set_masked_raw, + .port_set_bits_raw = gpio_efinix_sapphire_port_set_bits_raw, + .port_clear_bits_raw = gpio_efinix_sapphire_port_clear_bits_raw, + .port_toggle_bits = gpio_efinix_sapphire_port_toggle_bits, +}; + +#define GPIO_EFINIX_SAPPHIRE_INIT(n) \ + static struct gpio_efinix_sapphire_cfg gpio_efinix_sapphire_cfg_##n = { \ + .base_addr = DT_INST_REG_ADDR(n), \ + .n_gpios = DT_INST_PROP(n, ngpios), \ +}; \ +static struct gpio_efinix_sapphire_data gpio_efinix_sapphire_data_##n; \ + DEVICE_DT_INST_DEFINE(n, \ + gpio_efinix_sapphire_init, \ + NULL, \ + &gpio_efinix_sapphire_data_##n, \ + &gpio_efinix_sapphire_cfg_##n, \ + POST_KERNEL, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_efinix_sapphire_api \ + ); \ + +DT_INST_FOREACH_STATUS_OKAY(GPIO_EFINIX_SAPPHIRE_INIT) From d78c0e538c88c1f6c760faa4777b6ba9670ca204 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Tue, 21 Mar 2023 02:10:57 +0800 Subject: [PATCH 0652/2042] drivers: serial: add uart_efinix_sapphire initial version Add UART driver for Efinix Sapphire SoCs Signed-off-by: Manojkumar Subramaniam --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.efinix_sapphire | 10 +++ drivers/serial/uart_efinix_sapphire.c | 90 ++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 drivers/serial/Kconfig.efinix_sapphire create mode 100644 drivers/serial/uart_efinix_sapphire.c diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index e83935dd6c3f..9224c29aa645 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -62,6 +62,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_OPENTITAN uart_opentitan.c) zephyr_library_sources_ifdef(CONFIG_UART_HOSTLINK uart_hostlink.c) zephyr_library_sources_ifdef(CONFIG_UART_EMUL uart_emul.c) zephyr_library_sources_ifdef(CONFIG_UART_NUMAKER uart_numaker.c) +zephyr_library_sources_ifdef(CONFIG_UART_EFINIX_SAPPIHIRE uart_efinix_sapphire.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4af2f400f858..405fda7d0744 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -222,4 +222,6 @@ source "drivers/serial/Kconfig.native_tty" source "drivers/serial/Kconfig.numaker" +source "drivers/serial/Kconfig.efinix_sapphire" + endif # SERIAL diff --git a/drivers/serial/Kconfig.efinix_sapphire b/drivers/serial/Kconfig.efinix_sapphire new file mode 100644 index 000000000000..860ad80020b1 --- /dev/null +++ b/drivers/serial/Kconfig.efinix_sapphire @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +config UART_EFINIX_SAPPIHIRE + bool "EFINIX_SAPPIHIRE serial driver" + default y + depends on DT_HAS_EFINIX_SAPPHIRE_UART0_ENABLED + select SERIAL_HAS_DRIVER + help + This option enables Efinix sapphire serial driver. diff --git a/drivers/serial/uart_efinix_sapphire.c b/drivers/serial/uart_efinix_sapphire.c new file mode 100644 index 000000000000..06ce999538a5 --- /dev/null +++ b/drivers/serial/uart_efinix_sapphire.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT efinix_sapphire_uart0 + +#include +#include +#include +#include +#include + +#define UART_IRQ DT_INST_IRQN(0) +#define UART0_BASE_ADDR DT_INST_REG_ADDR(0) + +#define BSP_UART_DATA 0x00 +#define BSP_UART_STATUS 0x04 +#define BSP_UART_CLOCK_DIVIDER 0x08 +#define BSP_UART_FRAME_CONFIG 0x0C + +#define BSP_UART_WRITE_AVAILABILITY_MASK GENMASK(23, 16) +#define BSP_UART_READ_OCCUPANCY_MASK GENMASK(31, 24) + +#define UART0_DATA_REG_ADDR UART0_BASE_ADDR + BSP_UART_DATA +#define UART0_STATUS_REG_ADDR UART0_BASE_ADDR + BSP_UART_STATUS +#define UART0_CLOCK_REG_ADDR UART0_BASE_ADDR + BSP_UART_CLOCK_DIVIDER +#define UART0_FRAME_REG_ADDR UART0_BASE_ADDR + BSP_UART_FRAME_CONFIG + +#define UART0_SAMPLE_PER_BAUD 8 +#define UART0_PARITY 0 /* Off */ +#define UART0_STOP 0 /* 1 stop bit */ + + +struct uart_efinix_sapphire_config { + uint32_t baudrate; +}; + +static void uart_efinix_sapphire_poll_out(const struct device *dev, unsigned char c) +{ + /* uart_writeAvailability */ + while ((sys_read32(UART0_STATUS_REG_ADDR) & BSP_UART_WRITE_AVAILABILITY_MASK) == 0) { + } + + sys_write8(c, UART0_DATA_REG_ADDR); +} + +static int uart_efinix_sapphire_poll_in(const struct device *dev, unsigned char *c) +{ + + if ((sys_read32(UART0_STATUS_REG_ADDR) & BSP_UART_READ_OCCUPANCY_MASK) != 0) { + *c = (unsigned char)sys_read8(UART0_DATA_REG_ADDR); + return 0; + } + + return -1; +} + +static const struct uart_driver_api uart_efinix_sapphire_api = { + .poll_in = uart_efinix_sapphire_poll_in, + .poll_out = uart_efinix_sapphire_poll_out, + .err_check = NULL, +}; + +static const struct uart_efinix_sapphire_config uart_efinix_sapphire_cfg_0 = { + .baudrate = DT_INST_PROP(0, current_speed), +}; + +static int uart_efinix_sapphire_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + uint32_t prescaler = ((CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / + (uart_efinix_sapphire_cfg_0.baudrate * UART0_SAMPLE_PER_BAUD)) - + 1) & + 0xFFFFF; + sys_write32(prescaler, UART0_CLOCK_REG_ADDR); + + /* 8 data bits, no parity, 1 stop bit */ + uint32_t frame_config = (UART0_SAMPLE_PER_BAUD - 1) | UART0_PARITY << 8 | UART0_STOP << 16; + + sys_write32(frame_config, UART0_FRAME_REG_ADDR); + + return 0; +} + +/* Device tree instance 0 init */ +DEVICE_DT_INST_DEFINE(0, uart_efinix_sapphire_init, NULL, NULL, &uart_efinix_sapphire_cfg_0, + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, (void *)&uart_efinix_sapphire_api); From dc88a20bd72df8008e7890e5b9cdd3e791df2237 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Wed, 26 Apr 2023 18:04:12 +0000 Subject: [PATCH 0653/2042] boards: riscv: Add initial support for titanium_ti60_f225 This FPGA board can be loaded with a RISC-V core and utilized with Zephyr. Product link: https://www.efinixinc.com/products-devkits-titaniumti60f225.html Signed-off-by: Manojkumar Subramaniam --- boards/riscv/titanium_ti60_f225/Kconfig.board | 6 ++ .../titanium_ti60_f225/Kconfig.defconfig | 9 +++ .../img/Ti60-BGA225-board-block-diagram.jpg | Bin 0 -> 79335 bytes .../doc/img/ti60f225-board-top.jpg | Bin 0 -> 98553 bytes boards/riscv/titanium_ti60_f225/doc/index.rst | 60 ++++++++++++++++++ .../titanium_ti60_f225/titanium_ti60_f225.dts | 55 ++++++++++++++++ .../titanium_ti60_f225.yaml | 10 +++ .../titanium_ti60_f225_defconfig | 13 ++++ 8 files changed, 153 insertions(+) create mode 100644 boards/riscv/titanium_ti60_f225/Kconfig.board create mode 100644 boards/riscv/titanium_ti60_f225/Kconfig.defconfig create mode 100644 boards/riscv/titanium_ti60_f225/doc/img/Ti60-BGA225-board-block-diagram.jpg create mode 100644 boards/riscv/titanium_ti60_f225/doc/img/ti60f225-board-top.jpg create mode 100644 boards/riscv/titanium_ti60_f225/doc/index.rst create mode 100644 boards/riscv/titanium_ti60_f225/titanium_ti60_f225.dts create mode 100644 boards/riscv/titanium_ti60_f225/titanium_ti60_f225.yaml create mode 100644 boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig diff --git a/boards/riscv/titanium_ti60_f225/Kconfig.board b/boards/riscv/titanium_ti60_f225/Kconfig.board new file mode 100644 index 000000000000..d6ed41ffc79d --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TITANIUM_TI60_F225 + bool "Board with Efinix Sapphire riscv SoC" + depends on SOC_SERIES_EFINIX_SAPPHIRE diff --git a/boards/riscv/titanium_ti60_f225/Kconfig.defconfig b/boards/riscv/titanium_ti60_f225/Kconfig.defconfig new file mode 100644 index 000000000000..577c21b3d1a6 --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_TITANIUM_TI60_F225 + +config BOARD + default "titanium_ti60_f225" + +endif # BOARD_TITANIUM_TI60_F225 diff --git a/boards/riscv/titanium_ti60_f225/doc/img/Ti60-BGA225-board-block-diagram.jpg b/boards/riscv/titanium_ti60_f225/doc/img/Ti60-BGA225-board-block-diagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b6d1990a7203e345590b04a2c5eedd80ee50883b GIT binary patch literal 79335 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 nI_J*0^R9gBpE~Exx$~}k>z_L3&bjlheCwY& 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
3v|&D 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 SHhcX|3A5DviTA&!$N$-kO~O$C literal 0 HcmV?d00001 diff --git a/boards/riscv/titanium_ti60_f225/doc/index.rst b/boards/riscv/titanium_ti60_f225/doc/index.rst new file mode 100644 index 000000000000..1b6430e9309f --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/doc/index.rst @@ -0,0 +1,60 @@ +.. _titanium_ti60_f225: + +Efinix Titanium Ti60 F225 +######################### + +Overview +******** + +The Efinix Titanium Ti60 F225 development kit contains a Ti60 FPGA, which is fabricated on a 16nm process and deliver +high performance with the lowest possible power on a small physical size. In addition, Efinix offers Sapphire SoC IP, +which is a user-configurable RISC-V SoC based on the VexRiscv core with configurable feature set and extension. +Using the Efinity IP Manager, you can configure the SoC to include only the peripherals that you require. + +.. figure:: img/ti60f225-board-top.jpg + :align: center + :alt: titanium_ti60_f225_board + +Figure is the development board + +Board block diagram +******************* + +.. figure:: img/Ti60-BGA225-board-block-diagram.jpg + :align: center + :alt: titanium_ti60_f225_board-block-diagram + +More information can be found on `Ti60F225`_ website. + +Sapphire SoC setup on the FPGA guide +************************************* + +Guide to setup the SoC found at `Efinix-Zephyr`_ + +Building +******** + +Build applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: titanium_ti60_f225 + :goals: build + +Flashing +******** + +Flashing the binary into SPI NOR flash requires Efinity programmer, Please find the guide at `Efinix-Zephyr`_ + +.. note:: + + The Zephyr RTOS has been verified using the SoC bitstream generated by Efinity IDE v2022.2.322. + +References +********** + +.. target-notes:: + +.. _Ti60F225: https://www.efinixinc.com/products-devkits-titaniumti60f225.html +.. _Efinix-Zephyr: https://github.com/Efinix-Inc/zephyr-efinix diff --git a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.dts b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.dts new file mode 100644 index 000000000000..8487efea0dac --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.dts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "Efinix Titanium Ti60 F225"; + compatible = "efinix,titanium-ti60-f225"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &ram0; + }; + + aliases { + led0 = &green_led; + }; + + leds { + compatible = "gpio-leds"; + + green_led: led_0 { + gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + label = "Green LED 3"; + }; + + + red_led: led_1 { + gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + label = "Red LED 2"; + }; + + blue_led: led_2 { + gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + label = "Blue LED 1"; + }; + + }; + +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; +}; + +&gpio0 { + status = "okay"; +}; diff --git a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.yaml b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.yaml new file mode 100644 index 000000000000..b52f6d8660a0 --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225.yaml @@ -0,0 +1,10 @@ +identifier: titanium_ti60_f225 +name: titanium_ti60_f225 FPGA development kit with Efinix Sapphire riscv SoC +type: mcu +arch: riscv32 +toolchain: + - zephyr +ram: 196608 +supported: + - gpio + - uart diff --git a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig new file mode 100644 index 000000000000..096980b864ec --- /dev/null +++ b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_EFINIX_SAPPHIRE=y +CONFIG_BOARD_TITANIUM_TI60_F225=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_CLOCK_CONTROL=n +CONFIG_XIP=n +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_INIT_STACKS=n From 1a28c79ff158e81bfd0aa4550c438d0d8bf95b49 Mon Sep 17 00:00:00 2001 From: Manojkumar Subramaniam Date: Tue, 9 May 2023 18:17:23 +0000 Subject: [PATCH 0654/2042] tests: drivers: build_all: gpio: add efinix_sapphire Build only test for efinix_sapphire gpio driver. Signed-off-by: Manojkumar Subramaniam --- .../build_all/gpio/efinix_sapphire.overlay | 21 +++++++++++++++++++ tests/drivers/build_all/gpio/testcase.yaml | 6 ++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/drivers/build_all/gpio/efinix_sapphire.overlay diff --git a/tests/drivers/build_all/gpio/efinix_sapphire.overlay b/tests/drivers/build_all/gpio/efinix_sapphire.overlay new file mode 100644 index 000000000000..bfa659c94abe --- /dev/null +++ b/tests/drivers/build_all/gpio/efinix_sapphire.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Efinix Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { + #address-cells = <1>; + #size-cells = <1>; + + test_gpio: gpio@deadbeef { + compatible = "efinix,sapphire-gpio"; + gpio-controller; + reg = <0xdeadbeef 0x1000>; + #gpio-cells = <0x2>; + ngpios = <4>; + status = "okay"; + }; + }; +}; diff --git a/tests/drivers/build_all/gpio/testcase.yaml b/tests/drivers/build_all/gpio/testcase.yaml index 892d40780127..bd720d569d58 100644 --- a/tests/drivers/build_all/gpio/testcase.yaml +++ b/tests/drivers/build_all/gpio/testcase.yaml @@ -11,3 +11,9 @@ tests: - gpio - spi - i2c + + drivers.gpio.build.efinix_sapphire: + min_ram: 32 + platform_allow: titanium_ti60_f225 + depends_on: gpio + extra_args: DTC_OVERLAY_FILE="efinix_sapphire.overlay" From c7c6ce4d13798ef89fe1e72f31798f044d3fbb70 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 22 Jun 2023 15:47:21 +0200 Subject: [PATCH 0655/2042] tests: drivers: i2c: i2c_target_api add nucleo_wl55jc Adds nucleo_wl55jc in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index 7b75c8d9b621..a9a1222c2934 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -15,6 +15,7 @@ tests: - nucleo_g071rb - nucleo_f207zg - nucleo_f429zi + - nucleo_wl55jc - rpi_pico integration_platforms: - nucleo_f091rc From 0a71da1e3fb4438efa754bc45198643833e5f333 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 14 Jun 2023 17:04:42 +0200 Subject: [PATCH 0656/2042] tests: drivers: i2c: i2c_target_api add nucleo_wl55jc Adds necessary overlay nucleo_wl55jc in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_wl55jc.conf | 2 ++ .../boards/nucleo_wl55jc.overlay | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.conf new file mode 100644 index 000000000000..34b2571d1251 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.overlay new file mode 100644 index 000000000000..333f50715b98 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_wl55jc.overlay @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c2 PA11 CN10:5 PA12 CN10:3 + * i2c3 PB14 CN7:36 PB13 CN7:38 + * + * Short Pin PA11 to PB14, and PA12 to PB13, for the test to pass. + */ + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; + +&i2c3 { + pinctrl-0 = <&i2c3_scl_pb13 &i2c3_sda_pb14>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; From 2c3dd0122e59275f9da83eab7bf1fcc8d280785a Mon Sep 17 00:00:00 2001 From: Sean Madigan Date: Thu, 15 Jun 2023 14:26:41 +0100 Subject: [PATCH 0657/2042] bluetooth: controller: kconfig: Move BT_CTLR_SCAN_SYNC_ISO_SET Move BT_CTLR_SCAN_SYNC_ISO_SET to Kconfig from Kconfig.ll_sw_split This means it can be used by other controllers and alligns with location of other iso configs - e.g. BT_CTLR_SYNC_ISO_STREAM_COUNT Signed-off-by: Sean Madigan --- subsys/bluetooth/controller/Kconfig | 8 ++++++++ subsys/bluetooth/controller/Kconfig.ll_sw_split | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 4cc413ea03cb..2eb3ed62e7c1 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -800,6 +800,14 @@ config BT_CTLR_ADV_ISO_PDU_LEN_MAX help Maximum Broadcast Isochronous Channel PDU Length. +config BT_CTLR_SCAN_SYNC_ISO_SET + int "LE ISO Broadcast Isochronous Groups Sync Sets" + depends on BT_CTLR_SYNC_ISO + range 1 64 + default 1 + help + Maximum supported broadcast isochronous groups (BIGs) sync sets. + config BT_CTLR_SYNC_ISO_STREAM_MAX int "Maximum supported ISO Synchronized Receiver Streams per Broadcast ISO group" depends on BT_CTLR_SYNC_ISO diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 0342889e3e14..7a9bf2c2b78f 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -355,14 +355,6 @@ config BT_CTLR_SCAN_AUX_SET help Maximum supported auxiliary channel scan sets. -config BT_CTLR_SCAN_SYNC_ISO_SET - int "LE ISO Broadcast Isochronous Groups Sync Sets" - depends on BT_CTLR_SYNC_ISO - range 1 64 - default 1 - help - Maximum supported broadcast isochronous groups (BIGs) sync sets. - config BT_CTLR_ADV_ENABLE_STRICT bool "Enforce Strict Advertising Enable/Disable" depends on BT_BROADCASTER From 7993f2001ec7ae2382bd280540d9c863ce4e903c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 17:05:03 +0200 Subject: [PATCH 0658/2042] Bluetooth: BAP: Shell: Fix missing NULL check for cmd_list stream may be NULL when we check for stream->conn. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index a0a1a0a98517..4840bc65824b 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -1469,7 +1469,7 @@ static int cmd_list(const struct shell *sh, size_t argc, char *argv[]) for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { struct bt_bap_stream *stream = &unicast_streams[i].stream.bap_stream; - if (stream->conn != NULL) { + if (stream != NULL && stream->conn != NULL) { shell_print(sh, " %s#%u: stream %p dir 0x%02x group %p", stream == default_stream ? "*" : " ", i, stream, stream_dir(stream), stream->group); From dd0db3f7d6f7dc9d7ea8c88b97e54dd7c1e7b281 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:33:00 +0200 Subject: [PATCH 0659/2042] Bluetooth: BAP: Shell: Fix broadcast assistant bad code print The bad code field should only be printed when there is an actual bad code, otherwise it just prints all-0s. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_broadcast_assistant.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index e521344daa2f..7994a5c0e6e4 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -129,11 +129,11 @@ static void bap_broadcast_assistant_recv_state_cb( bad_code, sizeof(bad_code)); is_bad_code = state->encrypt_state == BT_BAP_BIG_ENC_STATE_BAD_CODE; - shell_print(ctx_shell, "BASS recv state: src_id %u, addr %s, " - "sid %u, sync_state %u, encrypt_state %u%s%s", - state->src_id, le_addr, state->adv_sid, - state->pa_sync_state, state->encrypt_state, - is_bad_code ? ", bad code" : "", bad_code); + shell_print( + ctx_shell, + "BASS recv state: src_id %u, addr %s, sid %u, sync_state %u, encrypt_state %u%s%s", + state->src_id, le_addr, state->adv_sid, state->pa_sync_state, state->encrypt_state, + is_bad_code ? ", bad code" : "", is_bad_code ? bad_code : ""); for (int i = 0; i < state->num_subgroups; i++) { const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; From acc59cfc9a709d4ef4ab71c727f54d12f75d7847 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:35:24 +0200 Subject: [PATCH 0660/2042] Bluetooth: BAP: Shell: Add missing addr print in broadcast assistant The shell_print was meant to print the address of the broadcast source along with the broadcast_id. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_broadcast_assistant.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 7994a5c0e6e4..4b082c431d9a 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -495,6 +495,7 @@ static bool broadcast_source_found(struct bt_data *data, void *user_data) { struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; const struct bt_le_scan_recv_info *info = user_data; + char addr_str[BT_ADDR_LE_STR_LEN]; struct bt_uuid_16 adv_uuid; uint32_t broadcast_id; int err; @@ -524,9 +525,9 @@ static bool broadcast_source_found(struct bt_data *data, void *user_data) return false; } - shell_print(ctx_shell, - "Found BAP broadcast source with addressand ID 0x%06X\n", - broadcast_id); + bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str)); + shell_print(ctx_shell, "Found BAP broadcast source with address %s and ID 0x%06X\n", + addr_str, broadcast_id); bt_addr_le_copy(¶m.addr, info->addr); param.adv_sid = info->sid; From addc8a538ac757e4d1a5fa67e4b2c440ff5f5f8b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:37:39 +0200 Subject: [PATCH 0661/2042] Bluetooth: BAP: Shell: Stop scan on broadcast found When the broadcast assistant have found the expected broadcast source it should stop scanning. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_broadcast_assistant.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 4b082c431d9a..1cc06ab29f8d 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -529,6 +529,11 @@ static bool broadcast_source_found(struct bt_data *data, void *user_data) shell_print(ctx_shell, "Found BAP broadcast source with address %s and ID 0x%06X\n", addr_str, broadcast_id); + err = bt_le_scan_stop(); + if (err) { + shell_error(ctx_shell, "Failed to stop scan: %d", err); + } + bt_addr_le_copy(¶m.addr, info->addr); param.adv_sid = info->sid; param.pa_interval = info->interval; From 2901e7cd5983dfa92f4d385e6b21bc710305bda2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:47:27 +0200 Subject: [PATCH 0662/2042] Bluetooth: BAP: Shell: Fix assistant broadcast code Fixes 2 issues: 1) The broadcast code would only ever get the first value, even if the command specified up to 16 values. 2) The broadcast code is not just hex values, so hex2bin does not make sense, and strlen + memcpy is much simpler. Signed-off-by: Emil Gydesen --- .../audio/shell/bap_broadcast_assistant.c | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 1cc06ab29f8d..dd551d490f68 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -916,16 +916,15 @@ static int cmd_bap_broadcast_assistant_broadcast_code(const struct shell *sh, return -ENOEXEC; } - broadcast_code_len = hex2bin(argv[2], strlen(argv[2]), - broadcast_code, - sizeof(broadcast_code)); - - if (broadcast_code_len == 0U) { - shell_error(sh, "Could not parse broadcast code"); + broadcast_code_len = strlen(argv[2]); + if (!IN_RANGE(broadcast_code_len, 1, BT_AUDIO_BROADCAST_CODE_SIZE)) { + shell_error(sh, "Invalid broadcast code length: %zu", broadcast_code_len); return -ENOEXEC; } + memcpy(broadcast_code, argv[2], broadcast_code_len); + shell_info(sh, "Sending broadcast code:"); shell_hexdump(sh, broadcast_code, sizeof(broadcast_code)); @@ -1006,15 +1005,13 @@ static int cmd_bap_broadcast_assistant(const struct shell *sh, size_t argc, return -ENOEXEC; } -SHELL_STATIC_SUBCMD_SET_CREATE(bap_broadcast_assistant_cmds, - SHELL_CMD_ARG(discover, NULL, - "Discover BASS on the server", +SHELL_STATIC_SUBCMD_SET_CREATE( + bap_broadcast_assistant_cmds, + SHELL_CMD_ARG(discover, NULL, "Discover BASS on the server", cmd_bap_broadcast_assistant_discover, 1, 0), - SHELL_CMD_ARG(scan_start, NULL, - "Start scanning for broadcasters", + SHELL_CMD_ARG(scan_start, NULL, "Start scanning for broadcasters", cmd_bap_broadcast_assistant_scan_start, 1, 1), - SHELL_CMD_ARG(scan_stop, NULL, - "Stop scanning for BISs", + SHELL_CMD_ARG(scan_stop, NULL, "Stop scanning for BISs", cmd_bap_broadcast_assistant_scan_stop, 1, 0), SHELL_CMD_ARG(add_src, NULL, "Add a source " @@ -1029,24 +1026,20 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bap_broadcast_assistant_cmds, SHELL_CMD_ARG(add_pa_sync, NULL, "Add a PA sync as a source " "[bis_index [bis_index [bix_index [...]]]]>", - cmd_bap_broadcast_assistant_add_pa_sync, 3, - BT_ISO_MAX_GROUP_ISO_COUNT), + cmd_bap_broadcast_assistant_add_pa_sync, 3, BT_ISO_MAX_GROUP_ISO_COUNT), SHELL_CMD_ARG(mod_src, NULL, "Set sync [] " "[] []", cmd_bap_broadcast_assistant_mod_src, 3, 2), SHELL_CMD_ARG(broadcast_code, NULL, "Send a space separated broadcast code of up to 16 bytes " - " [broadcast code]", - cmd_bap_broadcast_assistant_broadcast_code, 2, 16), - SHELL_CMD_ARG(rem_src, NULL, - "Remove a source ", + " ", + cmd_bap_broadcast_assistant_broadcast_code, 3, 0), + SHELL_CMD_ARG(rem_src, NULL, "Remove a source ", cmd_bap_broadcast_assistant_rem_src, 2, 0), - SHELL_CMD_ARG(read_state, NULL, - "Remove a source ", + SHELL_CMD_ARG(read_state, NULL, "Remove a source ", cmd_bap_broadcast_assistant_read_recv_state, 2, 0), - SHELL_SUBCMD_SET_END -); + SHELL_SUBCMD_SET_END); SHELL_CMD_ARG_REGISTER(bap_broadcast_assistant, &bap_broadcast_assistant_cmds, "Bluetooth BAP broadcast assistant client shell commands", From feaae8b1043823d9409b4b6b68715f68387bf461 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:51:31 +0200 Subject: [PATCH 0663/2042] Bluetooth: BAP: Shell: Only register scan delegator callbacks once If the callbacks are registered more than once, the linked list causes an infinite loop. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap_scan_delegator.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index d13e5f5f04ad..baf52bd8034d 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -381,8 +381,15 @@ static struct bt_le_per_adv_sync_cb pa_sync_cb = { static int cmd_bap_scan_delegator_init(const struct shell *sh, size_t argc, char **argv) { - bt_le_per_adv_sync_cb_register(&pa_sync_cb); - bt_bap_scan_delegator_register_cb(&scan_delegator_cb); + static bool registered; + + if (!registered) { + bt_le_per_adv_sync_cb_register(&pa_sync_cb); + bt_bap_scan_delegator_register_cb(&scan_delegator_cb); + + registered = true; + } + return 0; } static int cmd_bap_scan_delegator_set_past_pref(const struct shell *sh, From ac8dc349114912ddb0de60303ef13fb29aa41ad7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:53:01 +0200 Subject: [PATCH 0664/2042] Bluetooth: CAP: Shell: Fix type in cmd_cap_initiator_unicast_stop "starteds" should be "started". Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/cap_initiator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 0172156bdaf6..bc7e6c6fa844 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -462,7 +462,7 @@ static int cmd_cap_initiator_unicast_stop(const struct shell *sh, size_t argc, shell_error(sh, "Not connected"); return -ENOEXEC; } else if (default_unicast_group == NULL) { - shell_error(sh, "No unicast group starteds"); + shell_error(sh, "No unicast group started"); return -ENOEXEC; } From adabb009141e1f86a501dc326e8cbb3b01f9e291 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 20:09:31 +0200 Subject: [PATCH 0665/2042] Bluetooth: Audio: Shell: Update audio.conf to more sane values Some values have been reduced and some have been increased to better follow the audio configurations in BAP and support more incoming data. Also removes HRS as that is not used by LE Audio. Signed-off-by: Emil Gydesen --- tests/bluetooth/shell/audio.conf | 35 ++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index c5a4e56d7e42..40d24233f6a8 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -1,8 +1,8 @@ # Increased stack due to settings API usage CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 -# Needed for devices with many PAC records -CONFIG_BT_RX_STACK_SIZE=4096 +# Needed for devices with many PAC records or large BASEs +CONFIG_BT_RX_STACK_SIZE=8192 CONFIG_TEST=y CONFIG_TEST_LOGGING_DEFAULTS=n @@ -22,7 +22,6 @@ CONFIG_BT_DEVICE_NAME_DYNAMIC=y # TBS Client may require up to 12 buffers CONFIG_BT_L2CAP_TX_BUF_COUNT=12 CONFIG_BT_ID_MAX=2 -CONFIG_BT_HRS=y CONFIG_BT_FILTER_ACCEPT_LIST=y CONFIG_BT_REMOTE_INFO=y CONFIG_BT_REMOTE_VERSION=y @@ -45,29 +44,36 @@ CONFIG_BT_AUTO_PHY_UPDATE=y CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y +# Support an ISO channel per ASE +CONFIG_BT_ISO_MAX_CHAN=4 +CONFIG_BT_ISO_TX_BUF_COUNT=10 +CONFIG_BT_ISO_RX_BUF_COUNT=20 +CONFIG_BT_ISO_TX_MTU=310 +CONFIG_BT_ISO_RX_MTU=310 + CONFIG_BT_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 -# Support an ISO channel per ASE -CONFIG_BT_ISO_MAX_CHAN=8 -CONFIG_BT_ISO_TX_BUF_COUNT=10 -CONFIG_BT_ISO_RX_BUF_COUNT=10 -CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=8 + +CONFIG_BT_BAP_UNICAST_CLIENT=y +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 -CONFIG_BT_ASCS_ASE_SNK_COUNT=2 -CONFIG_BT_ASCS_ASE_SRC_COUNT=2 + CONFIG_BT_CODEC_MAX_METADATA_COUNT=10 CONFIG_BT_CODEC_MAX_DATA_LEN=40 CONFIG_BT_CODEC_MAX_DATA_COUNT=10 CONFIG_BT_CODEC_MAX_DATA_LEN=40 -CONFIG_BT_BAP_UNICAST_CLIENT=y + CONFIG_BT_BAP_BROADCAST_SOURCE=y +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=4 + CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2 CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=4 -CONFIG_BT_ISO_TX_BUF_COUNT=5 + CONFIG_BT_VOCS_MAX_INSTANCE_COUNT=1 CONFIG_BT_VOCS_CLIENT_MAX_INSTANCE_COUNT=1 @@ -121,7 +127,7 @@ CONFIG_UTF8=y # Object Transfer CONFIG_BT_OTS=y CONFIG_BT_OTS_SECONDARY_SVC=y -CONFIG_BT_OTS_MAX_OBJ_CNT=50 +CONFIG_BT_OTS_MAX_OBJ_CNT=0x30 CONFIG_BT_OTS_CLIENT=y CONFIG_BT_BAP_SCAN_DELEGATOR=y @@ -145,6 +151,7 @@ CONFIG_BT_CAP_INITIATOR=y # DEBUGGING CONFIG_LOG=y +CONFIG_BT_AUDIO_LOG_LEVEL_DBG=y CONFIG_BT_MPL_LOG_LEVEL_DBG=y CONFIG_BT_MCS_LOG_LEVEL_DBG=y CONFIG_BT_MCC_LOG_LEVEL_DBG=y @@ -157,6 +164,8 @@ CONFIG_BT_BAP_UNICAST_SERVER_LOG_LEVEL_DBG=y CONFIG_BT_BAP_UNICAST_CLIENT_LOG_LEVEL_DBG=y CONFIG_BT_BAP_BROADCAST_SOURCE_LOG_LEVEL_DBG=y CONFIG_BT_BAP_BROADCAST_SINK_LOG_LEVEL_DBG=y +CONFIG_BT_BAP_BROADCAST_ASSISTANT_LOG_LEVEL_DBG=y +CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVEL_DBG=y CONFIG_BT_HAS_LOG_LEVEL_DBG=y CONFIG_BT_HAS_CLIENT_LOG_LEVEL_DBG=y CONFIG_BT_TBS_LOG_LEVEL_DBG=y From 2b74450544abfaa73d7d4c7dde6b644e8b4b8ed3 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:09:12 +0200 Subject: [PATCH 0666/2042] Bluetooth: CSIP: Update CSIP duplicate rank search In the CSIP Set Coordinator verify_members we verify that all members have unique ranks. This was done as part of the initial loop, but it is more efficient to do this as a separate loop as we can reduce the number of items to compare, as well as guarding this properly by !zero_rank. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/csip_set_coordinator.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index ce9933ffded2..6a910c3bdc55 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -1494,9 +1494,12 @@ static int verify_members(const struct bt_csip_set_coordinator_set_member **memb LOG_DBG("Found mix of 0 and non-0 ranks"); return -EINVAL; } + } - if (!zero_rank) { - for (size_t j = 0U; j < i; j++) { + if (CONFIG_BT_MAX_CONN > 1 && !zero_rank && count > 1U) { + /* Search for duplicate ranks */ + for (uint8_t i = 0U; i < count - 1; i++) { + for (uint8_t j = i + 1; j < count; j++) { if (ranks[j] == ranks[i]) { /* duplicate rank */ LOG_DBG("Duplicate rank (%u) for members[%zu] " From 82e5eba817b1df88568b132bc82b1182bf81ad96 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 15:21:58 +0200 Subject: [PATCH 0667/2042] Bluetooth: BAP: Fix bt_bap_scan_delegator_find_state The bt_bap_scan_delegator_find_state did not properly return the correct receive state due to confusing return value of the iterator function. Modify it to use a simple bool. This fixes all issues with "Failed to find receive state for sink" when using the Broadcast Sink. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 13 +++++-------- subsys/bluetooth/audio/bap_broadcast_sink.c | 20 +++++++++----------- subsys/bluetooth/audio/bap_scan_delegator.c | 12 ++++++------ tests/bsim/bluetooth/audio/prj.conf | 2 ++ 4 files changed, 22 insertions(+), 25 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index dc368a2ce3d4..c1a0c021b0cf 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -1844,20 +1844,17 @@ int bt_bap_scan_delegator_mod_src(const struct bt_bap_scan_delegator_mod_src_par */ int bt_bap_scan_delegator_rem_src(uint8_t src_id); -enum bt_bap_scan_delegator_iter { - BT_BAP_SCAN_DELEGATOR_ITER_STOP = 0, - BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE, -}; - /** Callback function for Scan Delegator receive state search functions * * @param recv_state The receive state. * @param user_data User data. * - * @return @ref BT_BAP_SCAN_DELEGATOR_ITER_STOP to stop iterating or - * @ref BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE to continue. + * @retval true to stop iterating. If this is used in the context of + * bt_bap_scan_delegator_find_state(), the recv_state will be returned by + * bt_bap_scan_delegator_find_state() + * @retval false to continue iterating */ -typedef enum bt_bap_scan_delegator_iter (*bt_bap_scan_delegator_state_func_t)( +typedef bool (*bt_bap_scan_delegator_state_func_t)( const struct bt_bap_scan_delegator_recv_state *recv_state, void *user_data); /** @brief Iterate through all existing receive states diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 5f872171daf9..d4ecf7d86825 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -55,23 +55,21 @@ static sys_slist_t sink_cbs = SYS_SLIST_STATIC_INIT(&sink_cbs); static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink); -static enum bt_bap_scan_delegator_iter -find_recv_state_by_sink_cb(const struct bt_bap_scan_delegator_recv_state *recv_state, - void *user_data) +static bool find_recv_state_by_sink_cb(const struct bt_bap_scan_delegator_recv_state *recv_state, + void *user_data) { const struct bt_bap_broadcast_sink *sink = user_data; if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID) && sink->bass_src_id == recv_state->src_id) { - return BT_BAP_SCAN_DELEGATOR_ITER_STOP; + return true; } - return BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE; + return false; } -static enum bt_bap_scan_delegator_iter -find_recv_state_by_pa_sync_cb(const struct bt_bap_scan_delegator_recv_state *recv_state, - void *user_data) +static bool find_recv_state_by_pa_sync_cb(const struct bt_bap_scan_delegator_recv_state *recv_state, + void *user_data) { struct bt_le_per_adv_sync *sync = user_data; struct bt_le_per_adv_sync_info sync_info; @@ -81,15 +79,15 @@ find_recv_state_by_pa_sync_cb(const struct bt_bap_scan_delegator_recv_state *rec if (err != 0) { LOG_DBG("Failed to get sync info: %d", err); - return BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE; + return false; } if (bt_addr_le_eq(&recv_state->addr, &sync_info.addr) && recv_state->adv_sid == sync_info.sid) { - return BT_BAP_SCAN_DELEGATOR_ITER_STOP; + return true; } - return BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE; + return false; }; static void update_recv_state_big_synced(const struct bt_bap_broadcast_sink *sink) diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index f83b35c7cc41..97f977af7e54 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -1390,10 +1390,10 @@ void bt_bap_scan_delegator_foreach_state(bt_bap_scan_delegator_state_func_t func { for (size_t i = 0U; i < ARRAY_SIZE(scan_delegator.recv_states); i++) { if (scan_delegator.recv_states[i].active) { - enum bt_bap_scan_delegator_iter iter; + bool stop; - iter = func(&scan_delegator.recv_states[i].state, user_data); - if (iter == BT_BAP_SCAN_DELEGATOR_ITER_STOP) { + stop = func(&scan_delegator.recv_states[i].state, user_data); + if (stop) { return; } } @@ -1406,7 +1406,7 @@ struct scan_delegator_state_find_state_param { void *user_data; }; -static enum bt_bap_scan_delegator_iter +static bool scan_delegator_state_find_state_cb(const struct bt_bap_scan_delegator_recv_state *recv_state, void *user_data) { @@ -1417,10 +1417,10 @@ scan_delegator_state_find_state_cb(const struct bt_bap_scan_delegator_recv_state if (found) { param->recv_state = recv_state; - return BT_BAP_SCAN_DELEGATOR_ITER_STOP; + return true; } - return BT_BAP_SCAN_DELEGATOR_ITER_CONTINUE; + return false; } const struct bt_bap_scan_delegator_recv_state * diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index e33905562a25..4f9459c168e0 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -120,6 +120,8 @@ CONFIG_BT_TMAP=y # DEBUGGING CONFIG_LOG=y +CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y +CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y CONFIG_BT_VCP_VOL_REND_LOG_LEVEL_DBG=y CONFIG_BT_VCP_VOL_CTLR_LOG_LEVEL_DBG=y CONFIG_BT_AICS_LOG_LEVEL_DBG=y From 9065c2d156ff97dc0a8f31698ea7388625cf228d Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 22 Jun 2023 18:45:01 +0000 Subject: [PATCH 0668/2042] input: convert xpt2046 from kscan Convert the XPT2046 driver to the input subsystem, change the api, remove the callback and enable logic. Signed-off-by: Fabio Baltieri --- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/{kscan => input}/Kconfig.xpt2046 | 2 +- .../kscan_xpt2046.c => input/input_xpt2046.c} | 77 +++++-------------- drivers/kscan/CMakeLists.txt | 1 - drivers/kscan/Kconfig | 1 - .../{kscan => input}/xptek,xpt2046.yaml | 2 +- 7 files changed, 24 insertions(+), 61 deletions(-) rename drivers/{kscan => input}/Kconfig.xpt2046 (93%) rename drivers/{kscan/kscan_xpt2046.c => input/input_xpt2046.c} (84%) rename dts/bindings/{kscan => input}/xptek,xpt2046.yaml (96%) diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index d6e0f2e80283..a5483ffc7649 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_SDL_TOUCH input_sdl_touch.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_XPT2046 input_xpt2046.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index ee9508ae4d23..6e1d8abf5e89 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -10,6 +10,7 @@ source "drivers/input/Kconfig.gpio_keys" source "drivers/input/Kconfig.gpio_qdec" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" +source "drivers/input/Kconfig.xpt2046" endmenu # Input Drivers diff --git a/drivers/kscan/Kconfig.xpt2046 b/drivers/input/Kconfig.xpt2046 similarity index 93% rename from drivers/kscan/Kconfig.xpt2046 rename to drivers/input/Kconfig.xpt2046 index 5d7d1247c41a..21ce148dbbe4 100644 --- a/drivers/kscan/Kconfig.xpt2046 +++ b/drivers/input/Kconfig.xpt2046 @@ -1,7 +1,7 @@ # Copyright (c) 2023 Seppo Takalo # SPDX-License-Identifier: Apache-2.0 -config KSCAN_XPT2046 +config INPUT_XPT2046 bool "XPT2046 resistive touch panel driver" default y depends on DT_HAS_XPTEK_XPT2046_ENABLED diff --git a/drivers/kscan/kscan_xpt2046.c b/drivers/input/input_xpt2046.c similarity index 84% rename from drivers/kscan/kscan_xpt2046.c rename to drivers/input/input_xpt2046.c index 67b2c805e3e5..4c4f4c514b52 100644 --- a/drivers/kscan/kscan_xpt2046.c +++ b/drivers/input/input_xpt2046.c @@ -6,12 +6,12 @@ #define DT_DRV_COMPAT xptek_xpt2046 -#include #include -#include +#include +#include #include -LOG_MODULE_REGISTER(xpt2046, CONFIG_KSCAN_LOG_LEVEL); +LOG_MODULE_REGISTER(xpt2046, CONFIG_INPUT_LOG_LEVEL); struct xpt2046_config { const struct spi_dt_spec bus; @@ -27,9 +27,7 @@ struct xpt2046_config { }; struct xpt2046_data { const struct device *dev; - kscan_callback_t callback; struct gpio_callback int_gpio_cb; - bool enabled; struct k_work work; struct k_work_delayable dwork; uint8_t rbuf[9]; @@ -109,14 +107,14 @@ static void xpt2046_release_handler(struct k_work *kw) struct xpt2046_data *data = CONTAINER_OF(dw, struct xpt2046_data, dwork); struct xpt2046_config *config = (struct xpt2046_config *)data->dev->config; - if (!data->pressed || !data->enabled) { + if (!data->pressed) { return; } /* Check if touch is still pressed */ if (gpio_pin_get_dt(&config->int_gpio) == 0) { data->pressed = false; - data->callback(data->dev, data->last_y, data->last_y, false); + input_report_key(data->dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); } else { /* Re-check later */ k_work_reschedule(&data->dwork, K_MSEC(10)); @@ -168,58 +166,23 @@ static void xpt2046_work_handler(struct k_work *kw) /* Don't send any other than "pressed" events. * releasing seem to cause just random noise */ - if (data->enabled && pressed) { + if (pressed) { LOG_DBG("raw: x=%4u y=%4u ==> x=%4d y=%4d", meas.x, meas.y, x, y); + + input_report_abs(data->dev, INPUT_ABS_X, x, false, K_FOREVER); + input_report_abs(data->dev, INPUT_ABS_Y, y, false, K_FOREVER); + input_report_key(data->dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER); + data->last_x = x; data->last_y = y; data->pressed = pressed; - data->callback(data->dev, (uint32_t)y, (uint32_t)x, pressed); + /* Ensure that we send released event */ k_work_reschedule(&data->dwork, K_MSEC(100)); } gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); } -static int xpt2046_configure(const struct device *dev, kscan_callback_t callback) -{ - struct xpt2046_data *data = dev->data; - - if (!callback) { - LOG_ERR("Callback is null"); - return -EINVAL; - } - LOG_DBG("%s: set callback", dev->name); - - data->callback = callback; - - return 0; -} - -static int xpt2046_enable_callback(const struct device *dev) -{ - struct xpt2046_data *data = dev->data; - const struct xpt2046_config *config = dev->config; - - LOG_DBG("%s: enable cb", dev->name); - data->enabled = true; - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); - - return 0; -} - -static int xpt2046_disable_callback(const struct device *dev) -{ - struct xpt2046_data *data = dev->data; - const struct xpt2046_config *config = dev->config; - - gpio_remove_callback(config->int_gpio.port, &data->int_gpio_cb); - data->enabled = false; - - LOG_DBG("%s: disable cb", dev->name); - - return 0; -} - static int xpt2046_init(const struct device *dev) { int r; @@ -254,17 +217,17 @@ static int xpt2046_init(const struct device *dev) gpio_init_callback(&data->int_gpio_cb, xpt2046_isr_handler, BIT(config->int_gpio.pin)); + r = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (r < 0) { + LOG_ERR("Could not set gpio callback"); + return r; + } + LOG_INF("Init '%s' device", dev->name); return 0; } -static const struct kscan_driver_api xpt2046_driver_api = { - .config = xpt2046_configure, - .enable_callback = xpt2046_enable_callback, - .disable_callback = xpt2046_disable_callback, -}; - #define XPT2046_INIT(index) \ static const struct xpt2046_config xpt2046_config_##index = { \ .bus = SPI_DT_SPEC_INST_GET( \ @@ -281,8 +244,8 @@ static const struct kscan_driver_api xpt2046_driver_api = { }; \ static struct xpt2046_data xpt2046_data_##index; \ DEVICE_DT_INST_DEFINE(index, xpt2046_init, NULL, &xpt2046_data_##index, \ - &xpt2046_config_##index, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ - &xpt2046_driver_api); \ + &xpt2046_config_##index, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); \ BUILD_ASSERT(DT_INST_PROP(index, min_x) < DT_INST_PROP(index, max_x), \ "min_x must be less than max_x"); \ BUILD_ASSERT(DT_INST_PROP(index, min_y) < DT_INST_PROP(index, max_y), \ diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index c6c38222e230..b9b150873c47 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -10,7 +10,6 @@ zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_CST816S kscan_cst816s.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_CAP1203 kscan_cap1203.c) -zephyr_library_sources_ifdef(CONFIG_KSCAN_XPT2046 kscan_xpt2046.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE kscan_handlers.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index 30b05eb168e6..c5fcee278d55 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -16,7 +16,6 @@ source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" source "drivers/kscan/Kconfig.cst816s" source "drivers/kscan/Kconfig.cap1203" -source "drivers/kscan/Kconfig.xpt2046" source "drivers/kscan/Kconfig.input" module = KSCAN diff --git a/dts/bindings/kscan/xptek,xpt2046.yaml b/dts/bindings/input/xptek,xpt2046.yaml similarity index 96% rename from dts/bindings/kscan/xptek,xpt2046.yaml rename to dts/bindings/input/xptek,xpt2046.yaml index 758137c2ee73..e01a20bc3aa2 100644 --- a/dts/bindings/kscan/xptek,xpt2046.yaml +++ b/dts/bindings/input/xptek,xpt2046.yaml @@ -4,7 +4,7 @@ description: Driver for XPT2046 touch IC compatible: "xptek,xpt2046" -include: [kscan.yaml, spi-device.yaml] +include: spi-device.yaml properties: int-gpios: From 368126866203008d3938616281f3bd8e13592f84 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 22 Jun 2023 19:07:07 +0000 Subject: [PATCH 0669/2042] tests: build_all: input: add an entry for xpt2046 Build the xpt2046 driver with the input build_all. Fix a typo while at it. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/app.overlay | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 4f0bbe9547b5..746b8a6e5452 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -12,7 +12,7 @@ test_gpio: gpio@0 { compatible = "vnd,gpio"; gpio-controller; - reg = <00 0x1000>; + reg = <0x0 0x1000>; #gpio-cells = <0x2>; status = "okay"; }; @@ -58,5 +58,30 @@ int-gpios = <&test_gpio 0 0>; }; }; + + spi@2 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "vnd,spi"; + reg = <0x2 0x1000>; + status = "okay"; + clock-frequency = <2000000>; + + /* one entry for every devices */ + cs-gpios = <&test_gpio 0 0>; + + xpt2046@0 { + compatible = "xptek,xpt2046"; + spi-max-frequency = <0>; + reg = <0x0>; + int-gpios = <&test_gpio 0 0>; + touchscreen-size-x = <10>; + touchscreen-size-y = <10>; + min-x = <0>; + min-y = <0>; + max-x = <1>; + max-y = <1>; + }; + }; }; }; From a71bff7f49f78aa3d8526ab71e4c9709e9bc51aa Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 23 Jun 2023 00:49:04 +0530 Subject: [PATCH 0670/2042] net: wifi: Fix power save timeout data type This should be an unsigned integer. Also, add a comment to explain this feature. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_mgmt.h | 8 +++++++- subsys/net/l2/wifi/wifi_shell.c | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 8740d6b4bd45..7f9cb68c5e99 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -203,7 +203,13 @@ struct wifi_ps_params { unsigned short listen_interval; enum wifi_ps_wakeup_mode wakeup_mode; enum wifi_ps_mode mode; - int timeout_ms; + /* This is the time out to wait after sending a TX packet + * before going back to power save (in ms) to receive any replies + * from the AP. Zero means this feature is disabled. + * + * It's a tradeoff between power consumption and latency. + */ + unsigned int timeout_ms; enum ps_param_type type; enum wifi_config_ps_param_fail_reason fail_reason; }; diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index c6fd581a2d4c..9546eaa49fd5 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -593,8 +593,13 @@ static int cmd_wifi_ps(const struct shell *sh, size_t argc, char *argv[]) shell_fprintf(sh, SHELL_NORMAL, "PS wake up mode: %s\n", config.ps_params.wakeup_mode ? "Listen interval" : "DTIM"); - shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", - config.ps_params.timeout_ms); + if (config.ps_params.timeout_ms) { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", + config.ps_params.timeout_ms); + } else { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + } + if (config.num_twt_flows == 0) { shell_fprintf(sh, SHELL_NORMAL, "No TWT flows\n"); @@ -695,8 +700,11 @@ static int cmd_wifi_ps_timeout(const struct shell *sh, size_t argc, char *argv[] return -ENOEXEC; } - shell_fprintf(sh, SHELL_NORMAL, - "PS timeout %d ms\n", params.timeout_ms); + if (params.timeout_ms) { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: %d ms\n", params.timeout_ms); + } else { + shell_fprintf(sh, SHELL_NORMAL, "PS timeout: disabled\n"); + } return 0; } From 379ee55ee02bec6a67d2686821882648a4c69051 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 23 Jun 2023 15:22:56 +0200 Subject: [PATCH 0671/2042] Bluetooth: BAP: Shell: Move audio_send_work above clear_lc3_sine_data Since clear_lc3_sine_data references audio_send_work, it must be declared before the clear_lc3_sine_data function. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 4840bc65824b..3c6c85204371 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -192,6 +192,9 @@ static int octets_per_frame; static int64_t lc3_start_time; static int32_t lc3_sdu_cnt; +static void lc3_audio_send_data(struct k_work *work); +static K_WORK_DEFINE(audio_send_work, lc3_audio_send_data); + static void clear_lc3_sine_data(void) { lc3_start_time = 0; @@ -333,8 +336,6 @@ static void lc3_audio_send_data(struct k_work *work) lc3_sdu_cnt++; } -static K_WORK_DEFINE(audio_send_work, lc3_audio_send_data); - void sdu_sent_cb(struct bt_bap_stream *stream) { if (txing_stream == NULL || txing_stream->qos == NULL) { From b3259e5bf5c232766e75a1eb309effeff26ba41e Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 26 Jun 2023 10:32:03 +0200 Subject: [PATCH 0672/2042] Bluetooth: ascs: Fix possible ASE stuck in releasing state It may happen that CIS is scheduled in the future and did not started yet once accepted. When ASE goes to Releasing state in such case the ISO has to be disconnected, because otherwise ASE will stuck in releasing state. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 8a75ba555e0f..fd79ed245bd8 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -212,10 +212,10 @@ static void ascs_disconnect_stream_work_handler(struct k_work *work) (void)k_work_cancel_delayable(&pair_ase->disconnect_work); } - if (stream != NULL && ep->iso != NULL && - ep->iso->chan.state == BT_ISO_STATE_CONNECTED) { + (ep->iso->chan.state == BT_ISO_STATE_CONNECTED || + ep->iso->chan.state == BT_ISO_STATE_CONNECTING)) { const int err = bt_bap_stream_disconnect(stream); if (err != 0) { From a7d1110242ce1c9f2cb6b082bad48d4d036d5602 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 26 Jun 2023 13:48:29 +0100 Subject: [PATCH 0673/2042] MAINTAINERS: cleanup the ITE Platform maintainer entry Drop the collabors entries that were already in maintainers (no need for the dup), change the board expression so that it matches both ITE boards currently in the repo. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index e54c57f99e74..1dfacb2e4299 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2442,15 +2442,12 @@ ITE Platforms: - GTLin08 - RuibinChang collaborators: - - Dino-Li - - GTLin08 - - RuibinChang - jackrosenthal - keith-zephyr - brockus-zephyr - sjg20 files: - - boards/riscv/it8xxx2_evb/ + - boards/riscv/it8*_evb/ - drivers/*/*/*it8xxx2*.c - drivers/*/*it8xxx2*.c - dts/bindings/*/*ite* From 6050a10f8b298fe6994bb47ab9775ba535a604dd Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 26 Jun 2023 17:32:04 +0300 Subject: [PATCH 0674/2042] net: lwm2m: Allow setting string to zero length Lwm2m firmware object have defined a write of zero length string as a cancel operation. So allow lwm2m_set_opaque(path, NULL, 0); Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_registry.c | 14 +++++--- .../lwm2m/lwm2m_registry/src/lwm2m_registry.c | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_registry.c b/subsys/net/lib/lwm2m/lwm2m_registry.c index bbf0591121d6..f34a01fe5ead 100644 --- a/subsys/net/lib/lwm2m/lwm2m_registry.c +++ b/subsys/net/lib/lwm2m/lwm2m_registry.c @@ -626,7 +626,7 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value return ret; } - if (memcmp(data_ptr, value, len) != 0) { + if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) { changed = true; } @@ -644,12 +644,18 @@ static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value switch (obj_field->data_type) { case LWM2M_RES_TYPE_OPAQUE: - memcpy((uint8_t *)data_ptr, value, len); + if (len) { + memcpy((uint8_t *)data_ptr, value, len); + } break; case LWM2M_RES_TYPE_STRING: - strncpy(data_ptr, value, len - 1); - ((char *)data_ptr)[len - 1] = '\0'; + if (len) { + strncpy(data_ptr, value, len - 1); + ((char *)data_ptr)[len - 1] = '\0'; + } else { + ((char *)data_ptr)[0] = '\0'; + } break; case LWM2M_RES_TYPE_U32: 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 aa927e6eb0b9..a5d1240fd909 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -351,3 +351,37 @@ ZTEST(lwm2m_registry, test_strings) ret = lwm2m_get_string(&path, buf, len); zassert_equal(ret, -ENOMEM); } + +ZTEST(lwm2m_registry, test_null_strings) +{ + int ret; + char buf[256] = {0}; + struct lwm2m_obj_path path = LWM2M_OBJ(0, 0, 0); + + ret = lwm2m_register_post_write_callback(&path, post_write_cb); + zassert_equal(ret, 0); + + callback_checker = 0; + ret = lwm2m_set_string(&path, "string"); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), strlen("string")); + + callback_checker = 0; + ret = lwm2m_set_string(&path, ""); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), 0); + + callback_checker = 0; + ret = lwm2m_set_opaque(&path, NULL, 0); + zassert_equal(ret, 0); + zassert_equal(callback_checker, 0x02); + ret = lwm2m_get_string(&path, buf, sizeof(buf)); + zassert_equal(ret, 0); + zassert_equal(strlen(buf), 0); +} From 74d0ea0eb625e5dd0efd304de574de9d6f5764f2 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 27 Jun 2023 16:35:03 +0200 Subject: [PATCH 0675/2042] tests: drivers: i2c: i2c_target_api add nucleo_l073rg Adds nucleo_l073rg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index a9a1222c2934..4e9c6693dab1 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -16,6 +16,7 @@ tests: - nucleo_f207zg - nucleo_f429zi - nucleo_wl55jc + - nucleo_l073rz - rpi_pico integration_platforms: - nucleo_f091rc From 4cc7a841ca1da3136410d455e6b881896604ba44 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 14 Jun 2023 11:34:35 +0200 Subject: [PATCH 0676/2042] boards: arm: nucleo_l073rg: add i2c2 Adds i2c2 on nucleo_l073rg to use the i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- boards/arm/nucleo_l073rz/nucleo_l073rz.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts index ee6a9ea36b98..63d672f7dd0e 100644 --- a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts @@ -125,6 +125,13 @@ clock-frequency = ; }; +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + &spi1 { pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; pinctrl-names = "default"; From c96b78663cbc66ca380844dc12bdcb8e8ba8c6ff Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 14 Jun 2023 11:35:25 +0200 Subject: [PATCH 0677/2042] tests: drivers: i2c: i2c_target_api add nucleo_l073rg Adds necessary overlay nucleo_l073rg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_l073rz.conf | 2 ++ .../boards/nucleo_l073rz.overlay | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.conf new file mode 100644 index 000000000000..34b2571d1251 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.overlay new file mode 100644 index 000000000000..db6f83236cbd --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_l073rz.overlay @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN10:5 PB8 CN10:3 + * i2c2 PB11 CN10:18 PB10 CN10:25 + * + * Short Pin PB9 to PB11, and PB8 to PB10, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From bcc737dc2cd0dfa3da37fb704dbbbeec09cdb993 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 27 Jun 2023 16:53:05 +0200 Subject: [PATCH 0678/2042] tests: drivers: i2c: i2c_target_api add nucleo_f746zg Adds nucleo_f746zg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index 4e9c6693dab1..140d19c7b8ba 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -10,6 +10,7 @@ common: tests: drivers.i2c.target_api.dual_role: platform_allow: + - nucleo_f746zg - nucleo_f091rc - stm32f072b_disco - nucleo_g071rb From e86fc5fb75388b69bcaed5ed08f6df1273f60e9c Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 15 Jun 2023 14:21:16 +0200 Subject: [PATCH 0679/2042] boards: arm: nucleo_f746zg: add i2c2 Adds i2c2 on nucleo_f746zg to use the i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- boards/arm/nucleo_f746zg/nucleo_f746zg.dts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boards/arm/nucleo_f746zg/nucleo_f746zg.dts b/boards/arm/nucleo_f746zg/nucleo_f746zg.dts index b0060d4ee85e..60206a874203 100644 --- a/boards/arm/nucleo_f746zg/nucleo_f746zg.dts +++ b/boards/arm/nucleo_f746zg/nucleo_f746zg.dts @@ -126,6 +126,13 @@ zephyr_udc0: &usbotg_fs { clock-frequency = ; }; +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + &timers1 { st,prescaler = <10000>; status = "okay"; From abc5f4cad2eeba1a4992e9368247b8a72f732c0d Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 15 Jun 2023 14:22:29 +0200 Subject: [PATCH 0680/2042] tests: drivers: i2c: i2c_target_api add nucleo_f746zg Adds necessary overlay nucleo_f746zg in i2c_target_api test case to enables the board. Signed-off-by: Marc Desvaux --- .../i2c_target_api/boards/nucleo_f746zg.conf | 2 ++ .../boards/nucleo_f746zg.overlay | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.conf b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.conf new file mode 100644 index 000000000000..34b2571d1251 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.conf @@ -0,0 +1,2 @@ +CONFIG_I2C_STM32_INTERRUPT=y +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.overlay b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.overlay new file mode 100644 index 000000000000..8e740ab17af7 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/nucleo_f746zg.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* I2C bus pins are exposed on the ST morpho header. + * + * Bus SDA SCL + * Pin Hdr Pin Hdr + * i2c1 PB9 CN7:4 PB8 CN7:2 + * i2c2 PB11 CN10:34 PB10 CN10:32 + * + * Short Pin PB9 to PB11, and PB8 to PB10, for the test to pass. + */ + +&i2c1 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&i2c2 { + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From 04ce5b9e5839096245719e82383f1312bc8bddc0 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Tue, 23 May 2023 20:24:41 +0200 Subject: [PATCH 0681/2042] mgmt: hawkbit: remove NET_SOCKETS_POSIX_NAMES dependency Currently, it is not possible to use hawkbit with code that requires POSIX_API to be set due to the dependency on NET_SOCKETS_POSIX_NAMES. Since a lot of other code has already been moved to `zsock_`, this commit does the same for hawkbit. Co-authored-by: rojedag Signed-off-by: Matthias Breithaupt --- samples/subsys/mgmt/hawkbit/prj.conf | 1 - subsys/mgmt/hawkbit/Kconfig | 1 - subsys/mgmt/hawkbit/hawkbit.c | 18 +++++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/samples/subsys/mgmt/hawkbit/prj.conf b/samples/subsys/mgmt/hawkbit/prj.conf index fbb5f45edb61..a96c9461a831 100644 --- a/samples/subsys/mgmt/hawkbit/prj.conf +++ b/samples/subsys/mgmt/hawkbit/prj.conf @@ -13,7 +13,6 @@ CONFIG_NETWORKING=y CONFIG_HTTP_CLIENT=y CONFIG_DNS_RESOLVER=y CONFIG_JSON_LIBRARY=y -CONFIG_NET_SOCKETS_POSIX_NAMES=y CONFIG_BOOTLOADER_MCUBOOT=y #Main Stack Size diff --git a/subsys/mgmt/hawkbit/Kconfig b/subsys/mgmt/hawkbit/Kconfig index 45f47aabb6ea..c48abdb1f9b1 100644 --- a/subsys/mgmt/hawkbit/Kconfig +++ b/subsys/mgmt/hawkbit/Kconfig @@ -14,7 +14,6 @@ menuconfig HAWKBIT depends on HTTP_CLIENT depends on DNS_RESOLVER depends on JSON_LIBRARY - depends on NET_SOCKETS_POSIX_NAMES depends on BOOTLOADER_MCUBOOT select MPU_ALLOW_FLASH_WRITE select IMG_ENABLE_IMAGE_CHECK diff --git a/subsys/mgmt/hawkbit/hawkbit.c b/subsys/mgmt/hawkbit/hawkbit.c index a4b1a8d45480..cf16a12bafa1 100644 --- a/subsys/mgmt/hawkbit/hawkbit.c +++ b/subsys/mgmt/hawkbit/hawkbit.c @@ -203,8 +203,8 @@ static const struct json_obj_descr json_dep_fbk_descr[] = { static bool start_http_client(void) { int ret = -1; - struct addrinfo *addr; - struct addrinfo hints; + struct zsock_addrinfo *addr; + struct zsock_addrinfo hints; int resolve_attempts = 10; #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) @@ -224,7 +224,7 @@ static bool start_http_client(void) } while (resolve_attempts--) { - ret = getaddrinfo(CONFIG_HAWKBIT_SERVER, CONFIG_HAWKBIT_PORT, &hints, &addr); + ret = zsock_getaddrinfo(CONFIG_HAWKBIT_SERVER, CONFIG_HAWKBIT_PORT, &hints, &addr); if (ret == 0) { break; } @@ -237,7 +237,7 @@ static bool start_http_client(void) return false; } - hb_context.sock = socket(addr->ai_family, SOCK_STREAM, protocol); + hb_context.sock = zsock_socket(addr->ai_family, SOCK_STREAM, protocol); if (hb_context.sock < 0) { LOG_ERR("Failed to create TCP socket"); goto err; @@ -260,24 +260,24 @@ static bool start_http_client(void) } #endif - if (connect(hb_context.sock, addr->ai_addr, addr->ai_addrlen) < 0) { + if (zsock_connect(hb_context.sock, addr->ai_addr, addr->ai_addrlen) < 0) { LOG_ERR("Failed to connect to server"); goto err_sock; } - freeaddrinfo(addr); + zsock_freeaddrinfo(addr); return true; err_sock: - close(hb_context.sock); + zsock_close(hb_context.sock); err: - freeaddrinfo(addr); + zsock_freeaddrinfo(addr); return false; } static void cleanup_connection(void) { - if (close(hb_context.sock) < 0) { + if (zsock_close(hb_context.sock) < 0) { LOG_ERR("Could not close the socket"); } } From a46fb81449fb9cbd298d0c8d584c4a4113e024b9 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 15:58:17 +0200 Subject: [PATCH 0682/2042] Bluetooth: BAP: Shell: Set default_stream on configured Instead of setting the default_stream when we initiate the configure operatio, we set it when it has succeded. In case that the codec configure fails, the stream should not really be considered configured as the default. This also ensures that the default_stream is set when using the CAP shell commands. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 3c6c85204371..18c154aed0ac 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -785,6 +785,10 @@ static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rs { shell_print(ctx_shell, "stream %p config operation rsp_code %u reason %u", stream, rsp_code, reason); + + if (default_stream == NULL) { + default_stream = stream; + } } static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code, @@ -916,6 +920,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED; const struct named_lc3_preset *named_preset; struct unicast_stream *uni_stream; + struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep = NULL; unsigned long index; uint8_t conn_index; @@ -928,7 +933,9 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) conn_index = bt_conn_index(default_conn); if (default_stream == NULL) { - default_stream = &unicast_streams[0].stream.bap_stream; + bap_stream = &unicast_streams[0].stream.bap_stream; + } else { + bap_stream = default_stream; } index = shell_strtoul(argv[2], 0, &err); @@ -1019,7 +1026,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) } } - uni_stream = CONTAINER_OF(default_stream, struct unicast_stream, stream); + uni_stream = CONTAINER_OF(bap_stream, struct unicast_stream, stream); copy_unicast_stream_preset(uni_stream, named_preset); /* If location has been modifed, we update the location in the codec configuration */ @@ -1039,14 +1046,14 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) } } - if (default_stream->ep == ep) { - err = bt_bap_stream_reconfig(default_stream, &uni_stream->codec); + if (bap_stream->ep == ep) { + err = bt_bap_stream_reconfig(bap_stream, &uni_stream->codec); if (err != 0) { shell_error(sh, "Unable reconfig stream: %d", err); return -ENOEXEC; } } else { - err = bt_bap_stream_config(default_conn, default_stream, ep, &uni_stream->codec); + err = bt_bap_stream_config(default_conn, bap_stream, ep, &uni_stream->codec); if (err != 0) { shell_error(sh, "Unable to config stream: %d", err); return err; From 4d4886c05684333232c516567ce1bfb065cd72db Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 26 Jun 2023 14:02:02 +0200 Subject: [PATCH 0683/2042] Bluetooth: Mesh: remove unnecessary mbedtls options from mesh Unnecessary mbedtls config option has been removed from ble mesh KConfig. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 3a2a35b28385..750bc534bf18 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -36,7 +36,6 @@ config BT_MESH_USES_MBEDTLS_PSA select MBEDTLS select MBEDTLS_ZEPHYR_ENTROPY select MBEDTLS_PSA_CRYPTO_C - select MBEDTLS_CIPHER select MBEDTLS_MAC_CMAC_ENABLED select MBEDTLS_CIPHER_AES_ENABLED select MBEDTLS_AES_ROM_TABLES From db8881dd97d12952af5c7f6837157cd62fe5d378 Mon Sep 17 00:00:00 2001 From: Lang Xie Date: Fri, 26 May 2023 17:02:48 +0200 Subject: [PATCH 0684/2042] tests: bluetooth: tester: Reduce nrf53 BT_BUF_ACL_RX_SIZE PTS l2cap tests need BT_BUF_ACL_RX_SIZE to be 100. Signed-off-by: Lang Xie Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/nrf5340_hci_rpmsg.conf | 8 -------- tests/bluetooth/tester/nrf5340_hci_rpmsg_cpunet.conf | 4 ++++ tests/bluetooth/tester/overlay-le-audio.conf | 6 ------ 3 files changed, 4 insertions(+), 14 deletions(-) create mode 100644 tests/bluetooth/tester/nrf5340_hci_rpmsg_cpunet.conf diff --git a/tests/bluetooth/tester/nrf5340_hci_rpmsg.conf b/tests/bluetooth/tester/nrf5340_hci_rpmsg.conf index 16d6d2ab402c..234d0f5a2492 100644 --- a/tests/bluetooth/tester/nrf5340_hci_rpmsg.conf +++ b/tests/bluetooth/tester/nrf5340_hci_rpmsg.conf @@ -3,11 +3,3 @@ CONFIG_BT_MAX_CONN=2 CONFIG_BT_BUF_EVT_RX_COUNT=16 CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_SIZE=251 - -# L2CAP SDU/PDU TX MTU -CONFIG_BT_L2CAP_TX_MTU=247 - -# The minimum value for this is -# L2AP MPS + L2CAP header (4) -CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/tests/bluetooth/tester/nrf5340_hci_rpmsg_cpunet.conf b/tests/bluetooth/tester/nrf5340_hci_rpmsg_cpunet.conf new file mode 100644 index 000000000000..0be8cca95f8d --- /dev/null +++ b/tests/bluetooth/tester/nrf5340_hci_rpmsg_cpunet.conf @@ -0,0 +1,4 @@ +# Apply this overlay at hci_rpmsg controller build +CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y +CONFIG_BT_CTLR_DATA_LENGTH_MAX=100 +CONFIG_BT_BUF_ACL_RX_SIZE=100 diff --git a/tests/bluetooth/tester/overlay-le-audio.conf b/tests/bluetooth/tester/overlay-le-audio.conf index b7c40d047553..d8903d56cb6f 100644 --- a/tests/bluetooth/tester/overlay-le-audio.conf +++ b/tests/bluetooth/tester/overlay-le-audio.conf @@ -14,12 +14,6 @@ CONFIG_BT_MAX_CONN=2 CONFIG_BT_BUF_EVT_RX_COUNT=16 CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -# L2CAP SDU/PDU TX MTU -CONFIG_BT_L2CAP_TX_MTU=247 -# The minimum value for this is -# L2AP MPS + L2CAP header (4) -CONFIG_BT_BUF_ACL_RX_SIZE=255 # ASCS CONFIG_BT_ASCS_ASE_SNK_COUNT=2 From 51d57f612d807a68ac06486f647c8cd943109472 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Tue, 27 Jun 2023 16:06:02 +0800 Subject: [PATCH 0685/2042] drivers: pinctrl: add pin group for NuMaker pinctrl Update Nuvoton numaker series pinctrl, let support pin group. Signed-off-by: cyliang tw --- .../numaker_pfm_m467-pinctrl.dtsi | 18 ++-- drivers/pinctrl/pinctrl_numaker.c | 37 ++++++-- dts/arm/nuvoton/m46x.dtsi | 6 +- .../pinctrl/nuvoton,numaker-pinctrl.yaml | 85 ++++++++++--------- soc/arm/nuvoton_numaker/common/pinctrl_soc.h | 32 +++++-- 5 files changed, 116 insertions(+), 62 deletions(-) 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 09aa50f21012..8aff684b1a9a 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi @@ -8,16 +8,20 @@ &pinctrl { uart0_default: uart0_default { - pinmux = , - ; + group0 { + pinmux = , + ; + }; }; /* TX/RX/RTS/CTS/RST --> D1/D0/A2/A3/D2 --> PB3/PB2/PB8/PB9/PC9 */ uart1_default: uart1_default { - pinmux = , - , - , - , - ; + group0 { + pinmux = , + , + , + , + ; + }; }; }; diff --git a/drivers/pinctrl/pinctrl_numaker.c b/drivers/pinctrl/pinctrl_numaker.c index 2799e0a43c18..a443f705edf4 100644 --- a/drivers/pinctrl/pinctrl_numaker.c +++ b/drivers/pinctrl/pinctrl_numaker.c @@ -9,20 +9,40 @@ #include #include +/* Get mfp_base, it should be == (&SYS->GPA_MFP0) */ +#define MFP_BASE DT_INST_REG_ADDR_BY_NAME(0, mfp) +#define MFOS_BASE DT_INST_REG_ADDR_BY_NAME(0, mfos) +#define GPA_BASE DT_REG_ADDR(DT_NODELABEL(gpioa)) +#define GPIO_SIZE DT_REG_SIZE(DT_NODELABEL(gpioa)) + +#define SLEWCTL_PIN_SHIFT(pin_idx) ((pin_idx) * 2) +#define SLEWCTL_MASK(pin_idx) (3 << SLEWCTL_PIN_SHIFT(pin_idx)) + +static void gpio_configure(const pinctrl_soc_pin_t *pin, uint8_t port_idx, uint8_t pin_idx) +{ + GPIO_T *port; + + port = (GPIO_T *)(GPA_BASE + port_idx * GPIO_SIZE); + + port->SMTEN = (port->SMTEN & ~BIT(pin_idx)) | + ((pin->schmitt_enable ? 1 : 0) << pin_idx); + port->SLEWCTL = (port->SLEWCTL & ~SLEWCTL_MASK(pin_idx)) | + (pin->slew_rate << SLEWCTL_PIN_SHIFT(pin_idx)); + +} /** * Configure pin multi-function */ static void configure_pin(const pinctrl_soc_pin_t *pin) { uint32_t pin_mux = pin->pin_mux; - uint32_t pin_index = PIN_INDEX(pin_mux); - uint32_t port_index = PORT_INDEX(pin_mux); + uint8_t pin_index = PIN_INDEX(pin_mux); + uint8_t port_index = PORT_INDEX(pin_mux); uint32_t mfp_cfg = MFP_CFG(pin_mux); - /* Get mfp_base, it should be == (&SYS->GPA_MFP0) in M467 */ - uint32_t mfp_base = DT_REG_ADDR(DT_NODELABEL(pinctrl)); - uint32_t *GPx_MFPx = ((uint32_t *)mfp_base) + port_index * 4 + (pin_index / 4); + uint32_t *GPx_MFPx = ((uint32_t *)MFP_BASE) + port_index * 4 + (pin_index / 4); + uint32_t *GPx_MFOSx = ((uint32_t *)MFOS_BASE) + port_index; uint32_t pinMask = NU_MFP_MASK(pin_index); /* @@ -30,6 +50,13 @@ static void configure_pin(const pinctrl_soc_pin_t *pin) * SYS_GPA_MFP0_PA0MFP_SC0_CD; */ *GPx_MFPx = (*GPx_MFPx & (~pinMask)) | mfp_cfg; + if (pin->open_drain != 0) { + *GPx_MFOSx |= BIT(pin_index); + } else { + *GPx_MFOSx &= ~BIT(pin_index); + } + + gpio_configure(pin, port_index, pin_index); } /* Pinctrl API implementation */ diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 470f3f713d32..d4bec675f61b 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -165,9 +165,11 @@ status = "disabled"; }; - pinctrl: pin-controller@40000500 { + pinctrl: pin-controller@40000080 { compatible = "nuvoton,numaker-pinctrl"; - reg = <0x40000500 0xa0>; + reg = <0x40000080 0x28 + 0x40000500 0xa0>; + reg-names = "mfos", "mfp"; status = "okay"; }; diff --git a/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml index 1e2d4f631d04..4474f9b089fa 100644 --- a/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml +++ b/dts/bindings/pinctrl/nuvoton,numaker-pinctrl.yaml @@ -20,7 +20,9 @@ description: | /* configuration for the uart0 "default" state */ uart0_default: uart0_default { /* configure PB13 as UART0 TX and PB12 as UART0 RX */ - pinmux = , ; + group0 { + pinmux = , ; + }; }; }; @@ -37,44 +39,47 @@ description: | compatible: "nuvoton,numaker-pinctrl" -include: - - name: base.yaml - - name: pincfg-node.yaml - child-binding: - property-allowlist: - - drive-push-pull - - drive-open-drain - - bias-disable - - bias-pull-down - - bias-pull-up +include: base.yaml + +properties: + reg: + required: true child-binding: - description: | - Each child node defines the configuration for a particular state. - properties: - pinmux: - required: true - type: array - description: | - An array of pins sharing the same group properties. The pins should - be defined using pre-defined macros or, alternatively, using NVT_PINMUX - macros depending on the pinmux model used by the SoC series. - drive-strength: - type: string - default: "low" - enum: - - "low" - - "fast" - description: | - Set the driving strength of a pin. Hardware default configuration is low and - it's enough to drive most components, like as LED, CAN transceiver and so on. - slew-rate: - type: string - default: "low" - enum: - - "fast" - - "low" - description: | - Set the speed of a pin. This setting effectively limits the - slew rate of the output signal. Hardware default configuration is low. - Fast slew rate could support high speed pins, like as SPI CLK up to 50MHz. + description: NuMaker pin controller pin group + child-binding: + description: | + Each child node defines the configuration for a particular state. + include: + - name: pincfg-node.yaml + property-allowlist: + - drive-open-drain + - input-schmitt-enable + properties: + pinmux: + required: true + type: array + description: | + An array of pins sharing the same group properties. The pins should + be defined using pre-defined macros or, alternatively, using NVT_PINMUX + macros depending on the pinmux model used by the SoC series. + drive-strength: + type: string + default: "low" + enum: + - "low" + - "fast" + description: | + Set the driving strength of a pin. Hardware default configuration is low and + it's enough to drive most components, like as LED, CAN transceiver and so on. + slew-rate: + type: string + default: "low" + enum: + - "low" + - "high" + - "fast" + description: | + Set the speed of a pin. This setting effectively limits the + slew rate of the output signal. Hardware default configuration is low. + Fast slew rate could support fast speed pins, like as SPI CLK up to 50MHz. diff --git a/soc/arm/nuvoton_numaker/common/pinctrl_soc.h b/soc/arm/nuvoton_numaker/common/pinctrl_soc.h index 9a8320bdff25..4c12b81c94bc 100644 --- a/soc/arm/nuvoton_numaker/common/pinctrl_soc.h +++ b/soc/arm/nuvoton_numaker/common/pinctrl_soc.h @@ -12,21 +12,37 @@ #define PORT_INDEX(pinmux) (((pinmux)&0xF0000000) >> 28) #define PIN_INDEX(pinmux) (((pinmux)&0x0F000000) >> 24) -#define MFP_CFG(pinmux) (((pinmux)&0x000000FF) << ((PIN_INDEX(pinmux) % 4) * 8)) +#define MFP_CFG(pinmux) (((pinmux)&0x000000FF) << ((PIN_INDEX(pinmux) % 4) * 8)) #define NU_MFP_POS(pinindex) ((pinindex % 4) * 8) #define NU_MFP_MASK(pinindex) (0x1f << NU_MFP_POS(pinindex)) +#ifdef __cplusplus +extern "C" { +#endif + typedef struct pinctrl_soc_pin_t { uint32_t pin_mux; + uint32_t open_drain: 1; + uint32_t schmitt_enable: 1; + uint32_t slew_rate: 2; } pinctrl_soc_pin_t; -#define NUMAKER_DT_PIN(node_id, prop, idx) {.pin_mux = DT_PROP_BY_IDX(node_id, prop, idx)}, - -#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) NUMAKER_DT_PIN(node_id, prop, idx) - -#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ - { \ - DT_FOREACH_PROP_ELEM(DT_PHANDLE(node_id, prop), pinmux, Z_PINCTRL_STATE_PIN_INIT) \ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .pin_mux = DT_PROP_BY_IDX(node_id, prop, idx), \ + .open_drain = DT_PROP(node_id, drive_open_drain), \ + .schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \ + .slew_rate = DT_ENUM_IDX(node_id, slew_rate), \ + }, + +#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 /* _NUVOTON_NUMAKER_PINCTRL_SOC_H_ */ From f124c0d06ac16662ee8cdad8b041e750b2af8218 Mon Sep 17 00:00:00 2001 From: Tommi Kangas Date: Tue, 27 Jun 2023 11:45:49 +0300 Subject: [PATCH 0686/2042] net: lib: coap: Use zsock_ functions Use Zephyr internal zsock_ calls to remove dependency to NET_SOCKETS_POSIX_NAMES. Signed-off-by: Tommi Kangas --- subsys/net/lib/coap/coap_client.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index 1640a701de94..ec0c4d1f7fb9 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -38,9 +38,9 @@ static int send_request(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { if (addrlen == 0) { - return sendto(sock, buf, len, flags, NULL, 0); + return zsock_sendto(sock, buf, len, flags, NULL, 0); } else { - return sendto(sock, buf, len, flags, dest_addr, addrlen); + return zsock_sendto(sock, buf, len, flags, dest_addr, addrlen); } } @@ -48,9 +48,9 @@ static int receive(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { if (*addrlen == 0) { - return recvfrom(sock, buf, max_len, flags, NULL, NULL); + return zsock_recvfrom(sock, buf, max_len, flags, NULL, NULL); } else { - return recvfrom(sock, buf, max_len, flags, src_addr, addrlen); + return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); } } @@ -369,16 +369,16 @@ static int handle_poll(struct coap_client *client) int ret = 0; while (1) { - struct pollfd fds; + struct zsock_pollfd fds; fds.fd = client->fd; - fds.events = POLLIN; + fds.events = ZSOCK_POLLIN; fds.revents = 0; /* rfc7252#section-5.2.2, use separate timeout value for a separate response */ if (client->pending.timeout != 0) { - ret = poll(&fds, 1, client->pending.timeout); + ret = zsock_poll(&fds, 1, client->pending.timeout); } else { - ret = poll(&fds, 1, COAP_SEPARATE_TIMEOUT); + ret = zsock_poll(&fds, 1, COAP_SEPARATE_TIMEOUT); } if (ret < 0) { @@ -403,25 +403,25 @@ static int handle_poll(struct coap_client *client) break; } } else { - if (fds.revents & POLLERR) { + if (fds.revents & ZSOCK_POLLERR) { LOG_ERR("Error in poll"); ret = -EIO; break; } - if (fds.revents & POLLHUP) { + if (fds.revents & ZSOCK_POLLHUP) { LOG_ERR("Error in poll: POLLHUP"); ret = -ECONNRESET; break; } - if (fds.revents & POLLNVAL) { + if (fds.revents & ZSOCK_POLLNVAL) { LOG_ERR("Error in poll: POLLNVAL - fd not open"); ret = -EINVAL; break; } - if (!(fds.revents & POLLIN)) { + if (!(fds.revents & ZSOCK_POLLIN)) { LOG_ERR("Unknown poll error"); ret = -EINVAL; break; @@ -455,7 +455,7 @@ static int recv_response(struct coap_client *client, struct coap_packet *respons int ret; memset(client->recv_buf, 0, sizeof(client->recv_buf)); - len = receive(client->fd, client->recv_buf, sizeof(client->recv_buf), MSG_DONTWAIT, + len = receive(client->fd, client->recv_buf, sizeof(client->recv_buf), ZSOCK_MSG_DONTWAIT, &client->address, &client->socklen); if (len < 0) { From 431108d89e1750dbea05dce64dbb7fd329aa610e Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Tue, 27 Jun 2023 12:55:22 +0200 Subject: [PATCH 0687/2042] intel_adsp: ace: Restore IDC interrupt on D3 exit After exiting D3 state if IMR context save is enabled, IDC interrupt must be re-enabled again for all cores. Signed-off-by: Serhiy Katsyuba --- soc/xtensa/intel_adsp/ace/multiprocessing.c | 11 +++++++++++ soc/xtensa/intel_adsp/ace/power.c | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index e78295641530..51901d3d9c80 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -79,6 +79,17 @@ void soc_mp_init(void) soc_cpus_active[0] = true; } +#ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE +/* + * Called after exiting D3 state when context restore is enabled. + * Re-enables IDC interrupt again for all cores. Called once from core 0. + */ +void soc_mp_on_d3_exit(void) +{ + soc_mp_init(); +} +#endif + void soc_start_core(int cpu_num) { int retry = CORE_POWER_CHECK_NUM; diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index a1004d5be803..9ac30bfc4cc6 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -75,6 +75,14 @@ uint8_t *global_imr_ram_storage; * @biref a d3 restore boot entry point */ extern void boot_entry_d3_restore(void); + +/* + * @brief re-enables IDC interrupt for all cores after exiting D3 state + * + * Called once from core 0 + */ +extern void soc_mp_on_d3_exit(void); + #else /* @@ -321,6 +329,7 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) imr_layout->imr_state.header.imr_ram_storage = NULL; sys_clock_idle_exit(); mem_window_idle_exit(); + soc_mp_on_d3_exit(); } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ soc_cpus_active[cpu] = true; From 59880738f511d10ced99aa812935285b809d9708 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Mon, 26 Jun 2023 18:28:53 +0200 Subject: [PATCH 0688/2042] net: if: prepare net_if_ipv6_addr_rm() for future changes Move the creation of the multicast solicited node address outside the loop. There is no functional change but it prepares for some future changes. Signed-off-by: Florian Vaussard --- subsys/net/ip/net_if.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index a5656517c2eb..63c8262d6358 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1810,6 +1810,7 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) { bool ret = false; struct net_if_ipv6 *ipv6; + struct in6_addr maddr; int i; NET_ASSERT(addr); @@ -1821,9 +1822,9 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) goto out; } - for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { - struct in6_addr maddr; + net_ipv6_addr_create_solicited_node(addr, &maddr); + for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { if (!ipv6->unicast[i].is_used) { continue; } @@ -1859,8 +1860,6 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) ipv6->unicast[i].is_used = false; - net_ipv6_addr_create_solicited_node(addr, &maddr); - net_if_ipv6_maddr_rm(iface, &maddr); NET_DBG("[%d] interface %p address %s type %s removed", From 56e0d8eef3f199e7121c4818388d1d0bb347a5cc Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Mon, 26 Jun 2023 18:28:54 +0200 Subject: [PATCH 0689/2042] net: if: split the search loop of net_if_ipv6_addr_rm() First search for a match, then perform the removal outside the loop. There is no functional change but this prepares for some future changes. Signed-off-by: Florian Vaussard --- subsys/net/ip/net_if.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 63c8262d6358..50b7b6e26501 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1811,7 +1811,7 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) bool ret = false; struct net_if_ipv6 *ipv6; struct in6_addr maddr; - int i; + int found = -1; NET_ASSERT(addr); @@ -1824,7 +1824,7 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) net_ipv6_addr_create_solicited_node(addr, &maddr); - for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { if (!ipv6->unicast[i].is_used) { continue; } @@ -1834,12 +1834,17 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) continue; } - if (!ipv6->unicast[i].is_infinite) { + found = i; + break; + } + + if (found >= 0) { + if (!ipv6->unicast[found].is_infinite) { k_mutex_lock(&lock, K_FOREVER); sys_slist_find_and_remove( &active_address_lifetime_timers, - &ipv6->unicast[i].lifetime.node); + &ipv6->unicast[found].lifetime.node); if (sys_slist_is_empty( &active_address_lifetime_timers)) { @@ -1853,18 +1858,19 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) #if defined(CONFIG_NET_IPV6_DAD) if (!net_if_flag_is_set(iface, NET_IF_IPV6_NO_ND)) { k_mutex_lock(&lock, K_FOREVER); - sys_slist_find_and_remove(&active_dad_timers, &ipv6->unicast[i].dad_node); + sys_slist_find_and_remove(&active_dad_timers, + &ipv6->unicast[found].dad_node); k_mutex_unlock(&lock); } #endif - ipv6->unicast[i].is_used = false; + ipv6->unicast[found].is_used = false; net_if_ipv6_maddr_rm(iface, &maddr); NET_DBG("[%d] interface %p address %s type %s removed", - i, iface, net_sprint_ipv6_addr(addr), - net_addr_type2str(ipv6->unicast[i].addr_type)); + found, iface, net_sprint_ipv6_addr(addr), + net_addr_type2str(ipv6->unicast[found].addr_type)); /* Using the IPv6 address pointer here can give false * info if someone adds a new IP address into this position @@ -1873,7 +1879,7 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) net_mgmt_event_notify_with_info( NET_EVENT_IPV6_ADDR_DEL, iface, - &ipv6->unicast[i].address.in6_addr, + &ipv6->unicast[found].address.in6_addr, sizeof(struct in6_addr)); ret = true; From 2eb7433f5b0b48edc8c4f54de490c5e043407b08 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Mon, 26 Jun 2023 18:28:55 +0200 Subject: [PATCH 0690/2042] net: if: do not remove the solicited-node multicast address if used Two different IPv6 addresses can have the same solicited node multicast address, for example when they are derived from the same EUI-64 interface identifier during the auto-configuration process. For example, an interface with a physical address 70:07:12:34:56:78 can have the following: - link-local address FE80::7207:12FF:FE34:5678 - global unicast address 2001:1234:::7207:12FF:FE34:5678 Both addresses will have the same solicited-node multicast address FF02::1:FF34:5678. Currently, if one removes the global unicast address, the solicited-node multicast address is also removed, leaving the link-local address out of the solicited-node multicast group. This breaks some protocols like Neighbour Discovery. Count how many times the solicited-node multicast address is used and remove it only if it is not shared by any other unicast address. Fixes #59683 Signed-off-by: Florian Vaussard --- subsys/net/ip/net_if.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 50b7b6e26501..9ae49b5830af 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1812,6 +1812,7 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) struct net_if_ipv6 *ipv6; struct in6_addr maddr; int found = -1; + unsigned int maddr_count = 0; NET_ASSERT(addr); @@ -1825,17 +1826,27 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) net_ipv6_addr_create_solicited_node(addr, &maddr); for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + struct in6_addr unicast_maddr; + if (!ipv6->unicast[i].is_used) { continue; } + /* count how many times this solicited-node multicast address is identical + * for all the used unicast addresses + */ + net_ipv6_addr_create_solicited_node(&ipv6->unicast[i].address.in6_addr, + &unicast_maddr); + if (net_ipv6_addr_cmp(&maddr, &unicast_maddr)) { + maddr_count++; + } + if (!net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr, addr)) { continue; } found = i; - break; } if (found >= 0) { @@ -1866,7 +1877,12 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr) ipv6->unicast[found].is_used = false; - net_if_ipv6_maddr_rm(iface, &maddr); + if (maddr_count == 1) { + /* remove the solicited-node multicast address only if no other + * unicast address is also using it + */ + net_if_ipv6_maddr_rm(iface, &maddr); + } NET_DBG("[%d] interface %p address %s type %s removed", found, iface, net_sprint_ipv6_addr(addr), From 6837229ff2db1adb413bf21cf34ca0f255545211 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 27 Jun 2023 14:53:56 +0200 Subject: [PATCH 0691/2042] tests: net: iface: remove useless assignment The value of in6addr_mcast is overwritten in iface_setup() before being assigned to the interface. Remove the useless initial value since it is never used, in order to avoid misleading information. Signed-off-by: Florian Vaussard --- tests/net/iface/src/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c index d4b294ede7b3..70cf41db19b6 100644 --- a/tests/net/iface/src/main.c +++ b/tests/net/iface/src/main.c @@ -55,8 +55,7 @@ static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } }; -static struct in6_addr in6addr_mcast = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; +static struct in6_addr in6addr_mcast; static struct net_if *iface1; static struct net_if *iface2; From 90355f143f21d9ba985f62ea95d96ff83f6922ef Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 27 Jun 2023 14:57:49 +0200 Subject: [PATCH 0692/2042] tests: net: iface: verify multicast address not removed if used If two IPv6 addresses have the same solicited-node multicast address because they derive from the same EUI-64 interface identifier, make sure that the solicited-node multicast address is not removed when one of the IPV6 address is removed but only when both addresses are removed. Signed-off-by: Florian Vaussard --- tests/net/iface/src/main.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c index 70cf41db19b6..12ee3404ef83 100644 --- a/tests/net/iface/src/main.c +++ b/tests/net/iface/src/main.c @@ -879,6 +879,60 @@ ZTEST(net_iface, test_v6_addr_add_rm) v6_addr_rm(); } +ZTEST(net_iface, test_v6_addr_add_rm_solicited) +{ + const struct in6_addr prefix = { { { 0x20, 0x01, 0x1b, 0x98, 0x24, 0xb8, 0x7e, 0xbb, + 0, 0, 0, 0, 0, 0, 0, 0 } } }; + struct in6_addr iid_addr = { }; + struct in6_addr iid_addr_mcast = { }; + struct in6_addr unicast_addr = { }; + struct in6_addr unicast_addr_mcast = { }; + struct net_if_addr *ifaddr; + struct net_if_mcast_addr *maddr; + bool ret; + + /* Add a link-local address based on the interface identifier */ + net_ipv6_addr_create_iid(&iid_addr, net_if_get_link_addr(iface4)); + ifaddr = net_if_ipv6_addr_add(iface4, &iid_addr, + NET_ADDR_AUTOCONF, 0); + zassert_not_null(ifaddr, "Cannot add IPv6 link-local address"); + + /* Add the corresponding solicited-node multicast address */ + net_ipv6_addr_create_solicited_node(&iid_addr, &iid_addr_mcast); + maddr = net_if_ipv6_maddr_add(iface4, &iid_addr_mcast); + zassert_not_null(maddr, "Cannot add solicited-node multicast address"); + + /* Add an autoconfigured global unicast address */ + net_ipv6_addr_create_iid(&unicast_addr, net_if_get_link_addr(iface4)); + memcpy(&unicast_addr, &prefix, sizeof(prefix) / 2); + ifaddr = net_if_ipv6_addr_add(iface4, &unicast_addr, + NET_ADDR_AUTOCONF, 0); + zassert_not_null(ifaddr, "Cannot add IPv6 global unicast address"); + + /* Add the corresponding solicited-node multicast address (should exist) */ + net_ipv6_addr_create_solicited_node(&unicast_addr, &unicast_addr_mcast); + zassert_mem_equal(&unicast_addr_mcast, &iid_addr_mcast, + sizeof(struct in6_addr)); + maddr = net_if_ipv6_maddr_add(iface4, &unicast_addr_mcast); + zassert_is_null(maddr, "Solicited-node multicast address was added twice"); + + /* Remove the global unicast address */ + ret = net_if_ipv6_addr_rm(iface4, &unicast_addr); + zassert_true(ret, "Cannot remove IPv6 global unicast address"); + + /* The solicited-node multicast address should stay */ + maddr = net_if_ipv6_maddr_lookup(&iid_addr_mcast, &iface4); + zassert_not_null(maddr, "Solicited-node multicast address was removed"); + + /* Remove the link-local address */ + ret = net_if_ipv6_addr_rm(iface4, &iid_addr); + zassert_true(ret, "Cannot remove IPv6 link-local address"); + + /* The solicited-node multicast address should be gone */ + maddr = net_if_ipv6_maddr_lookup(&iid_addr_mcast, &iface4); + zassert_is_null(maddr, "Solicited-node multicast address was not removed"); +} + #define MY_ADDR_V6_USER { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0x65 } } } From 710422ec5e57e6b88d0821a31cee30fcc194094c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 May 2023 13:57:04 -0700 Subject: [PATCH 0693/2042] include/zephyr: Fix linker scripts to define _end after all static RAM data The Zephyr linker scripts have inconsistent ordering of various chunks of data which lands in RAM at runtime. This leads to the value of _end not being consistently defined as the maximum address of static variables used in the application. Create a helper linker fragment, zephyr/linker/ram-end.ld, which can be included after the last possible definition of RAM data, that consistently sets _image_ram_end, _end and z_mapped_end. Signed-off-by: Keith Packard --- boards/x86/qemu_x86/qemu_x86_tiny.ld | 11 ++++++----- include/zephyr/arch/arc/v2/linker.ld | 8 ++++---- .../arm/aarch32/cortex_a_r/scripts/linker.ld | 13 ++++++------- .../arm/aarch32/cortex_m/scripts/linker.ld | 9 ++++----- include/zephyr/arch/arm64/scripts/linker.ld | 12 ++++++------ include/zephyr/arch/mips/linker.ld | 7 ++++--- include/zephyr/arch/nios2/linker.ld | 10 ++++------ include/zephyr/arch/riscv/common/linker.ld | 11 +++++------ include/zephyr/arch/sparc/linker.ld | 7 ++++--- include/zephyr/arch/x86/ia32/linker.ld | 8 ++++---- include/zephyr/arch/x86/intel64/linker.ld | 10 ++++++---- include/zephyr/linker/ram-end.ld | 14 ++++++++++++++ soc/arm64/nxp_imx/mimx9/linker.ld | 19 +++++++++---------- soc/riscv/openisa_rv32m1/linker.ld | 9 ++++----- soc/riscv/riscv-ite/it8xxx2/linker.ld | 11 +++++------ .../riscv-privileged/andes_v5/ae350/linker.ld | 11 +++++------ soc/xtensa/intel_adsp/ace/ace-link.ld | 2 ++ 17 files changed, 92 insertions(+), 80 deletions(-) create mode 100644 include/zephyr/linker/ram-end.ld diff --git a/boards/x86/qemu_x86/qemu_x86_tiny.ld b/boards/x86/qemu_x86/qemu_x86_tiny.ld index aea569b85fe3..c53e2a7b4098 100644 --- a/boards/x86/qemu_x86/qemu_x86_tiny.ld +++ b/boards/x86/qemu_x86/qemu_x86_tiny.ld @@ -788,14 +788,9 @@ SECTIONS __kernel_ram_end = KERNEL_BASE_ADDR + KERNEL_RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - _image_ram_end = .; _image_ram_all = (KERNEL_BASE_ADDR + KERNEL_RAM_SIZE) - _image_ram_start; - z_mapped_end = .; z_mapped_size = z_mapped_end - z_mapped_start; - _end = .; /* end of image */ - - GROUP_END(RAMABLE_REGION) #ifndef LINKER_ZEPHYR_FINAL /* static interrupts */ @@ -823,6 +818,12 @@ SECTIONS */ #include +#define LAST_RAM_ALIGN MMU_PAGE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) + #include /DISCARD/ : { *(.note.GNU-stack) } diff --git a/include/zephyr/arch/arc/v2/linker.ld b/include/zephyr/arch/arc/v2/linker.ld index d33866370daf..a7751d961194 100644 --- a/include/zephyr/arch/arc/v2/linker.ld +++ b/include/zephyr/arch/arc/v2/linker.ld @@ -246,8 +246,6 @@ SECTIONS { MPU_MIN_SIZE_ALIGN /* Define linker symbols */ - _image_ram_end = .; - _end = .; /* end of image */ __kernel_ram_end = .; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; @@ -278,13 +276,15 @@ SECTIONS { } GROUP_DATA_LINK_IN(YCCM, RAMABLE_REGION) #endif - GROUP_END(RAMABLE_REGION) - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include SECTION_PROLOGUE(.ARC.attributes, 0,) { diff --git a/include/zephyr/arch/arm/aarch32/cortex_a_r/scripts/linker.ld b/include/zephyr/arch/arm/aarch32/cortex_a_r/scripts/linker.ld index fb206d8d7e6f..a27dd55a8cf2 100644 --- a/include/zephyr/arch/arm/aarch32/cortex_a_r/scripts/linker.ld +++ b/include/zephyr/arch/arm/aarch32/cortex_a_r/scripts/linker.ld @@ -332,16 +332,9 @@ SECTIONS /* Define linker symbols */ - . = ALIGN(_region_min_align); - _image_ram_end = .; - _end = .; /* end of image */ - z_mapped_end = .; - __kernel_ram_end = RAM_ADDR + RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - GROUP_END(RAMABLE_REGION) - #if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ocm), okay) GROUP_START(OCM) @@ -373,6 +366,12 @@ GROUP_END(OCM) */ #include +#define LAST_RAM_ALIGN . = ALIGN(_region_min_align); + +#include + + GROUP_END(RAMABLE_REGION) + #include SECTION_PROLOGUE(.ARM.attributes, 0,) diff --git a/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld index 567e213fe6d1..b170b514a9ce 100644 --- a/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/aarch32/cortex_m/scripts/linker.ld @@ -361,14 +361,9 @@ SECTIONS /* Define linker symbols */ - _image_ram_end = .; - _end = .; /* end of image */ - __kernel_ram_end = RAM_ADDR + RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - GROUP_END(RAMABLE_REGION) - #if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) GROUP_START(ITCM) @@ -426,6 +421,10 @@ GROUP_END(DTCM) */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include /DISCARD/ : { *(.note.GNU-stack) } diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index 5500e8c13864..fa08b7303047 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -295,21 +295,21 @@ SECTIONS /* Define linker symbols */ - MMU_ALIGN; - _image_ram_end = .; - _end = .; /* end of image */ - z_mapped_end = .; - __kernel_ram_end = RAM_ADDR + RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - GROUP_END(RAMABLE_REGION) /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#define LAST_RAM_ALIGN MMU_ALIGN; + +#include + + GROUP_END(RAMABLE_REGION) + #include SECTION_PROLOGUE(.ARM.attributes, 0,) diff --git a/include/zephyr/arch/mips/linker.ld b/include/zephyr/arch/mips/linker.ld index 8bc91ee114f4..cbff890822c7 100644 --- a/include/zephyr/arch/mips/linker.ld +++ b/include/zephyr/arch/mips/linker.ld @@ -181,14 +181,15 @@ SECTIONS #include - _image_ram_end = .; - _end = .; /* end of image */ - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include .mdebug.abi32 : { diff --git a/include/zephyr/arch/nios2/linker.ld b/include/zephyr/arch/nios2/linker.ld index 1814302c2a64..6958533eaf6b 100644 --- a/include/zephyr/arch/nios2/linker.ld +++ b/include/zephyr/arch/nios2/linker.ld @@ -259,17 +259,15 @@ SECTIONS #include - /* Define linker symbols */ - _image_ram_end = .; - _end = .; /* end of image */ - - GROUP_END(RAMABLE_REGION) - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include } diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index 181cf553186f..3dbec5f0a201 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -305,11 +305,6 @@ SECTIONS __data_region_end = .; - MPU_MIN_SIZE_ALIGN - - _image_ram_end = .; - _end = .; /* end of image */ - __kernel_ram_end = .; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; @@ -370,7 +365,11 @@ GROUP_END(DTCM) */ #include - GROUP_END(RAMABLE_REGION) +#define LAST_RAM_ALIGN MPU_MIN_SIZE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) #include diff --git a/include/zephyr/arch/sparc/linker.ld b/include/zephyr/arch/sparc/linker.ld index 36e884302e45..725339ef0b7c 100644 --- a/include/zephyr/arch/sparc/linker.ld +++ b/include/zephyr/arch/sparc/linker.ld @@ -154,14 +154,15 @@ SECTIONS #include - _image_ram_end = .; - _end = .; /* end of image */ - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include /DISCARD/ : { *(.note.GNU-stack) } diff --git a/include/zephyr/arch/x86/ia32/linker.ld b/include/zephyr/arch/x86/ia32/linker.ld index 1305860ee70c..c6db8f8ae75e 100644 --- a/include/zephyr/arch/x86/ia32/linker.ld +++ b/include/zephyr/arch/x86/ia32/linker.ld @@ -503,14 +503,10 @@ SECTIONS __kernel_ram_end = KERNEL_BASE_ADDR + KERNEL_RAM_SIZE; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - _image_ram_end = .; _image_ram_all = (KERNEL_BASE_ADDR + KERNEL_RAM_SIZE) - _image_ram_start; z_mapped_end = .; z_mapped_size = z_mapped_end - z_mapped_start; - _end = .; /* end of image */ - - GROUP_END(RAMABLE_REGION) #ifndef LINKER_ZEPHYR_FINAL /* static interrupts */ @@ -538,6 +534,10 @@ SECTIONS */ #include +#include + + GROUP_END(RAMABLE_REGION) + #include /DISCARD/ : { *(.note.GNU-stack) } diff --git a/include/zephyr/arch/x86/intel64/linker.ld b/include/zephyr/arch/x86/intel64/linker.ld index f2fd47ad54ea..8949b94e657f 100644 --- a/include/zephyr/arch/x86/intel64/linker.ld +++ b/include/zephyr/arch/x86/intel64/linker.ld @@ -192,10 +192,12 @@ SECTIONS /* Must be last in RAM */ #include - MMU_PAGE_ALIGN - _image_ram_end = .; - z_mapped_end = .; - _end = .; + +#define LAST_RAM_ALIGN MMU_PAGE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) /* All unused memory also owned by the kernel for heaps */ __kernel_ram_end = KERNEL_BASE_ADDR + KERNEL_RAM_SIZE; diff --git a/include/zephyr/linker/ram-end.ld b/include/zephyr/linker/ram-end.ld new file mode 100644 index 000000000000..61b06a4ecb61 --- /dev/null +++ b/include/zephyr/linker/ram-end.ld @@ -0,0 +1,14 @@ +/* + * Added after the very last allocation that might land in RAM to define the various + * end-of-used-memory symbols + */ + + SECTION_PROLOGUE(.last_ram_section,,) + { +#ifdef LAST_RAM_ALIGN + LAST_RAM_ALIGN +#endif + _image_ram_end = .; + _end = .; /* end of image */ + z_mapped_end = .; + } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) diff --git a/soc/arm64/nxp_imx/mimx9/linker.ld b/soc/arm64/nxp_imx/mimx9/linker.ld index 1562fbdaf509..102d9f1b0445 100644 --- a/soc/arm64/nxp_imx/mimx9/linker.ld +++ b/soc/arm64/nxp_imx/mimx9/linker.ld @@ -312,21 +312,20 @@ SECTIONS /* Define linker symbols */ - MMU_ALIGN; - _image_ram_end = .; - _end = .; /* end of image */ - z_mapped_end = .; - - __kernel_ram_end = RAM_ADDR + RAM_SIZE; - __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - - GROUP_END(RAMABLE_REGION) - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#define LAST_RAM_ALIGN MMU_ALIGN; + +#include + + GROUP_END(RAMABLE_REGION) + + __kernel_ram_end = RAM_ADDR + RAM_SIZE; + __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; + #include SECTION_PROLOGUE(.ARM.attributes, 0,) diff --git a/soc/riscv/openisa_rv32m1/linker.ld b/soc/riscv/openisa_rv32m1/linker.ld index 1ec6fa4ef4de..7ade2d4e8dd3 100644 --- a/soc/riscv/openisa_rv32m1/linker.ld +++ b/soc/riscv/openisa_rv32m1/linker.ld @@ -233,16 +233,15 @@ SECTIONS */ #include - _image_ram_end = .; - _end = .; /* end of image */ - - GROUP_END(RAM) - /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#include + + GROUP_END(RAMABLE_REGION) + #ifdef CONFIG_GEN_ISR_TABLES /* Bogus section, post-processed during the build to initialize interrupts. */ #include diff --git a/soc/riscv/riscv-ite/it8xxx2/linker.ld b/soc/riscv/riscv-ite/it8xxx2/linker.ld index 2aabe427b007..798e1ae6dc38 100644 --- a/soc/riscv/riscv-ite/it8xxx2/linker.ld +++ b/soc/riscv/riscv-ite/it8xxx2/linker.ld @@ -356,11 +356,6 @@ SECTIONS __data_region_end = .; - MPU_MIN_SIZE_ALIGN - - _image_ram_end = .; - _end = .; /* end of image */ - __kernel_ram_end = .; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; @@ -369,7 +364,11 @@ SECTIONS */ #include - GROUP_END(RAMABLE_REGION) +#define LAST_RAM_ALIGN MPU_MIN_SIZE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) #include diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld index 8e3acde20b18..9e613a0d9301 100644 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld +++ b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld @@ -274,11 +274,6 @@ SECTIONS __data_region_end = .; - MPU_MIN_SIZE_ALIGN - - _image_ram_end = .; - _end = .; /* end of image */ - __kernel_ram_end = .; __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; @@ -339,7 +334,11 @@ GROUP_END(DTCM) */ #include - GROUP_END(RAMABLE_REGION) +#define LAST_RAM_ALIGN MPU_MIN_SIZE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) #include diff --git a/soc/xtensa/intel_adsp/ace/ace-link.ld b/soc/xtensa/intel_adsp/ace/ace-link.ld index 516e2b7137c2..a4aaf6b8087d 100644 --- a/soc/xtensa/intel_adsp/ace/ace-link.ld +++ b/soc/xtensa/intel_adsp/ace/ace-link.ld @@ -403,6 +403,8 @@ SECTIONS { _unused_ram_start_marker = .; *(.unused_ram_start_marker) *(.unused_ram_start_marker.*) + _end = .; + z_mapped_end = .; } >ram . = L2_SRAM_BASE + L2_SRAM_SIZE; From bbec614b78b3a083fc7a559ae3ac00a5af24973d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 9 May 2023 22:09:57 -0700 Subject: [PATCH 0694/2042] cmake/linker_script: Fix cmake linker scripts to define _end The generated scripts don't include a definition for any symbol indicating the end of statically allocated memory (such as "_end"). Add a shared cmake fragment, ram-end.cmake, which contains the necessary instructions to define _end and z_mapped_end consistently to align with the other sample linker scripts. Signed-off-by: Keith Packard --- cmake/linker_script/arm/linker.cmake | 2 ++ cmake/linker_script/common/ram-end.cmake | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 cmake/linker_script/common/ram-end.cmake diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index b7d736f00bf0..15a2ebd1130e 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -135,6 +135,8 @@ if(NOT CONFIG_USERSPACE) zephyr_linker_section_configure(SECTION .noinit INPUT ".kernel_noinit.*") endif() +include(${COMMON_ZEPHYR_LINKER_DIR}/ram-end.cmake) + zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_start EXPR "(@__bss_start@)") zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_end EXPR "(${RAM_ADDR} + ${RAM_SIZE})") zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_size EXPR "(@__kernel_ram_end@ - @__bss_start@)") diff --git a/cmake/linker_script/common/ram-end.cmake b/cmake/linker_script/common/ram-end.cmake new file mode 100644 index 000000000000..bb210e199f66 --- /dev/null +++ b/cmake/linker_script/common/ram-end.cmake @@ -0,0 +1,7 @@ +zephyr_linker_section(NAME .last_ram_section VMA RAM LMA RAM_REGION TYPE BSS) +zephyr_linker_section_configure( + SECTION .last_ram_section + INPUT "" + SYMBOLS _end z_mapped_end + KEEP + ) From 419fa3ca6a9b2ada78ee9b4c7e573eaffbefce0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarno=20L=C3=A4ms=C3=A4?= Date: Mon, 5 Jun 2023 12:46:34 +0300 Subject: [PATCH 0695/2042] net: lib: coap: CoAP client, multiple request handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use only single thread for handling polling of the sockets. Each client will have only 1 active socket which to poll. Each client can have multiple simultaneous requests ongoing. The client only has one buffer for receiving and one buffer for sending. Therefore the messages are reformed when resending. Signed-off-by: Jarno Lämsä --- include/zephyr/net/coap_client.h | 34 +- subsys/net/lib/coap/Kconfig | 12 + subsys/net/lib/coap/coap_client.c | 587 ++++++++++++++++++++---------- 3 files changed, 421 insertions(+), 212 deletions(-) diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h index dc5d008c1b74..86c4911de5be 100644 --- a/include/zephyr/net/coap_client.h +++ b/include/zephyr/net/coap_client.h @@ -77,27 +77,29 @@ struct coap_client_option { }; /** @cond INTERNAL_HIDDEN */ -struct coap_client { - int fd; - struct sockaddr address; - socklen_t socklen; - uint8_t send_buf[MAX_COAP_MSG_LEN]; - uint8_t recv_buf[MAX_COAP_MSG_LEN]; +struct coap_client_internal_request { uint8_t request_token[COAP_TOKEN_MAX_LEN]; - int request_tkl; - int offset; - int retry_count; + 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; struct coap_pending pending; - struct coap_client_request *coap_request; + struct coap_client_request coap_request; struct coap_packet request; - k_tid_t tid; - struct k_thread thread; - struct k_sem coap_client_recv_sem; - atomic_t coap_client_recv_active; +}; - K_THREAD_STACK_MEMBER(coap_thread_stack, CONFIG_COAP_CLIENT_STACK_SIZE); +struct coap_client { + int fd; + struct sockaddr address; + socklen_t socklen; + bool response_ready; + struct k_mutex send_mutex; + uint8_t send_buf[MAX_COAP_MSG_LEN]; + uint8_t recv_buf[MAX_COAP_MSG_LEN]; + struct coap_client_internal_request requests[CONFIG_COAP_CLIENT_MAX_REQUESTS]; }; /** @endcond */ @@ -123,7 +125,7 @@ int coap_client_init(struct coap_client *client, const char *info); * * @param client Client instance. * @param sock Open socket file descriptor. - * @param addr the destination address of the request. + * @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. * @return zero when operation started successfully or negative error code otherwise. diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 12a7c0c9b006..e7587ab21acb 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -133,6 +133,18 @@ config COAP_CLIENT_STACK_SIZE int "Stack size of the CoAP client thread" default 1024 +config COAP_CLIENT_MAX_INSTANCES + int "Maximum number of CoAP clients" + default 2 + help + Maximum number of CoAP clients + +config COAP_CLIENT_MAX_REQUESTS + int "Maximum number of simultaneous requests per client" + default 2 + help + Maximum number of CoAP requests a single client can handle at a time + endif # COAP_CLIENT module = COAP diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c index ec0c4d1f7fb9..7c11d0502c6e 100644 --- a/subsys/net/lib/coap/coap_client.c +++ b/subsys/net/lib/coap/coap_client.c @@ -18,21 +18,15 @@ LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL); #define COAP_PATH_ELEM_QUERY '?' #define COAP_PATH_ELEM_AMP '&' #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 -static int coap_client_schedule_poll(struct coap_client *client, int sock, - struct coap_client_request *req) -{ - client->fd = sock; - client->coap_request = req; - - k_sem_give(&client->coap_client_recv_sem); - atomic_set(&client->coap_client_recv_active, 1); - - return 0; -} +static struct coap_client *clients[CONFIG_COAP_CLIENT_MAX_INSTANCES]; +static int num_clients; +static K_SEM_DEFINE(coap_client_recv_sem, 0, 1); +static atomic_t coap_client_recv_active; static int send_request(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) @@ -54,15 +48,72 @@ static int receive(int sock, void *buf, size_t max_len, int flags, } } -static void reset_block_contexts(struct coap_client *client) +static void reset_block_contexts(struct coap_client_internal_request *request) { - client->recv_blk_ctx.block_size = 0; - client->recv_blk_ctx.total_size = 0; - client->recv_blk_ctx.current = 0; + request->recv_blk_ctx.block_size = 0; + request->recv_blk_ctx.total_size = 0; + request->recv_blk_ctx.current = 0; - client->send_blk_ctx.block_size = 0; - client->send_blk_ctx.total_size = 0; - client->send_blk_ctx.current = 0; + request->send_blk_ctx.block_size = 0; + request->send_blk_ctx.total_size = 0; + request->send_blk_ctx.current = 0; +} + +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); +} + +static int coap_client_schedule_poll(struct coap_client *client, int sock, + struct coap_client_request *req, + struct coap_client_internal_request *internal_req) +{ + client->fd = sock; + memcpy(&internal_req->coap_request, req, sizeof(struct coap_client_request)); + internal_req->request_ongoing = true; + + if (!coap_client_recv_active) { + k_sem_give(&coap_client_recv_sem); + } + atomic_set(&coap_client_recv_active, 1); + + return 0; +} + +bool has_ongoing_request(struct coap_client *client) +{ + for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) { + if (client->requests[i].request_ongoing == true) { + return true; + } + } + + return false; +} + +struct coap_client_internal_request *get_free_request(struct coap_client *client) +{ + for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) { + if (client->requests[i].request_ongoing == false) { + return &client->requests[i]; + } + } + + return NULL; +} + +static bool has_ongoing_requests(void) +{ + bool has_requests = false; + + for (int i = 0; i < num_clients; i++) { + has_requests |= has_ongoing_request(clients[i]); + } + + return has_requests; } static int coap_client_init_path_options(struct coap_packet *pckt, const char *path) @@ -190,39 +241,55 @@ static enum coap_block_size coap_client_default_block_size(void) } static int coap_client_init_request(struct coap_client *client, - struct coap_client_request *req) + struct coap_client_request *req, + struct coap_client_internal_request *internal_req, + bool reconstruct) { int ret = 0; int i; memset(client->send_buf, 0, sizeof(client->send_buf)); - ret = coap_packet_init(&client->request, client->send_buf, MAX_COAP_MSG_LEN, 1, - req->confirmable ? COAP_TYPE_CON : COAP_TYPE_NON_CON, - COAP_TOKEN_MAX_LEN, coap_next_token(), req->method, - coap_next_id()); + + if (!reconstruct) { + uint8_t *token = coap_next_token(); + + internal_req->last_id = coap_next_id(); + internal_req->request_tkl = COAP_TOKEN_MAX_LEN & 0xf; + memcpy(internal_req->request_token, token, internal_req->request_tkl); + } + + ret = coap_packet_init(&internal_req->request, client->send_buf, MAX_COAP_MSG_LEN, + 1, req->confirmable ? COAP_TYPE_CON : COAP_TYPE_NON_CON, + COAP_TOKEN_MAX_LEN, internal_req->request_token, req->method, + internal_req->last_id); if (ret < 0) { LOG_ERR("Failed to init CoAP message %d", ret); goto out; } - ret = coap_client_init_path_options(&client->request, req->path); + ret = coap_client_init_path_options(&internal_req->request, req->path); if (ret < 0) { LOG_ERR("Failed to parse path to options %d", ret); goto out; } - ret = coap_append_option_int(&client->request, COAP_OPTION_CONTENT_FORMAT, req->fmt); + /* Add content format option only if there is a payload */ + if (req->payload) { + ret = coap_append_option_int(&internal_req->request, + COAP_OPTION_CONTENT_FORMAT, req->fmt); - if (ret < 0) { - LOG_ERR("Failed to append content format option"); - goto out; + if (ret < 0) { + LOG_ERR("Failed to append content format option"); + goto out; + } } /* Blockwise receive ongoing, request next block. */ - if (client->recv_blk_ctx.current > 0) { - ret = coap_append_block2_option(&client->request, &client->recv_blk_ctx); + if (internal_req->recv_blk_ctx.current > 0) { + ret = coap_append_block2_option(&internal_req->request, + &internal_req->recv_blk_ctx); if (ret < 0) { LOG_ERR("Failed to append block 2 option"); @@ -232,7 +299,7 @@ static int coap_client_init_request(struct coap_client *client, /* Add extra options if any */ for (i = 0; i < req->num_options; i++) { - ret = coap_packet_append_option(&client->request, req->options[i].code, + ret = coap_packet_append_option(&internal_req->request, req->options[i].code, req->options[i].value, req->options[i].len); if (ret < 0) { @@ -246,15 +313,16 @@ static int coap_client_init_request(struct coap_client *client, uint16_t offset; /* Blockwise send ongoing, add block1 */ - if (client->send_blk_ctx.total_size > 0 || + if (internal_req->send_blk_ctx.total_size > 0 || (req->len > CONFIG_COAP_CLIENT_MESSAGE_SIZE)) { - if (client->send_blk_ctx.total_size == 0) { - coap_block_transfer_init(&client->send_blk_ctx, + if (internal_req->send_blk_ctx.total_size == 0) { + coap_block_transfer_init(&internal_req->send_blk_ctx, coap_client_default_block_size(), req->len); } - ret = coap_append_block1_option(&client->request, &client->send_blk_ctx); + ret = coap_append_block1_option(&internal_req->request, + &internal_req->send_blk_ctx); if (ret < 0) { LOG_ERR("Failed to append block1 option"); @@ -262,29 +330,29 @@ static int coap_client_init_request(struct coap_client *client, } } - ret = coap_packet_append_payload_marker(&client->request); + ret = coap_packet_append_payload_marker(&internal_req->request); if (ret < 0) { LOG_ERR("Failed to append payload marker to CoAP message"); goto out; } - if (client->send_blk_ctx.total_size > 0) { + if (internal_req->send_blk_ctx.total_size > 0) { uint16_t block_in_bytes = - coap_block_size_to_bytes(client->send_blk_ctx.block_size); + coap_block_size_to_bytes(internal_req->send_blk_ctx.block_size); - payload_len = client->send_blk_ctx.total_size - - client->send_blk_ctx.current; + payload_len = internal_req->send_blk_ctx.total_size - + internal_req->send_blk_ctx.current; if (payload_len > block_in_bytes) { payload_len = block_in_bytes; } - offset = client->send_blk_ctx.current; + offset = internal_req->send_blk_ctx.current; } else { payload_len = req->len; offset = 0; } - ret = coap_packet_append_payload(&client->request, req->payload + offset, + ret = coap_packet_append_payload(&internal_req->request, req->payload + offset, payload_len); if (ret < 0) { @@ -292,22 +360,22 @@ static int coap_client_init_request(struct coap_client *client, goto out; } - if (client->send_blk_ctx.total_size > 0) { - coap_next_block(&client->request, &client->send_blk_ctx); + if (internal_req->send_blk_ctx.total_size > 0) { + coap_next_block(&internal_req->request, &internal_req->send_blk_ctx); } } - client->request_tkl = coap_header_get_token(&client->request, client->request_token); out: return ret; } - int coap_client_req(struct coap_client *client, int sock, const struct sockaddr *addr, struct coap_client_request *req, int retries) { int ret; - if (client->coap_client_recv_active) { + struct coap_client_internal_request *internal_req = get_free_request(client); + + if (internal_req == NULL) { return -EAGAIN; } @@ -315,44 +383,75 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr return -EINVAL; } + /* Don't allow changing to a different socket if there is already request ongoing. */ + if (client->fd != sock && has_ongoing_request(client)) { + return -EALREADY; + } + + /* Don't allow changing to a different address if there is already request ongoing. */ if (addr != NULL) { - memcpy(&client->address, addr, sizeof(*addr)); - client->socklen = sizeof(client->address); + if (memcmp(&client->address, addr, sizeof(*addr)) != 0) { + if (has_ongoing_request(client)) { + LOG_WRN("Can't change to a different socket, request ongoing."); + return -EALREADY; + } + + memcpy(&client->address, addr, sizeof(*addr)); + client->socklen = sizeof(client->address); + } } else { - memset(&client->address, 0, sizeof(client->address)); - client->socklen = 0; + if (client->socklen != 0) { + if (has_ongoing_request(client)) { + LOG_WRN("Can't change to a different socket, request ongoing."); + return -EALREADY; + } + + memset(&client->address, 0, sizeof(client->address)); + client->socklen = 0; + } } + reset_internal_request(internal_req); + if (retries == -1) { - client->retry_count = DEFAULT_RETRY_AMOUNT; + internal_req->retry_count = DEFAULT_RETRY_AMOUNT; } else { - client->retry_count = retries; + internal_req->retry_count = retries; } - ret = coap_client_init_request(client, req); + if (k_mutex_lock(&client->send_mutex, K_NO_WAIT)) { + return -EAGAIN; + } + + ret = coap_client_init_request(client, req, internal_req, false); if (ret < 0) { LOG_ERR("Failed to initialize coap request"); - return ret; + k_mutex_unlock(&client->send_mutex); + goto out; } - ret = coap_client_schedule_poll(client, sock, req); + ret = coap_client_schedule_poll(client, sock, req, internal_req); if (ret < 0) { LOG_ERR("Failed to schedule polling"); + k_mutex_unlock(&client->send_mutex); goto out; } - ret = coap_pending_init(&client->pending, &client->request, &client->address, - client->retry_count); + ret = coap_pending_init(&internal_req->pending, &internal_req->request, &client->address, + internal_req->retry_count); if (ret < 0) { LOG_ERR("Failed to initialize pending struct"); + k_mutex_unlock(&client->send_mutex); goto out; } - coap_pending_cycle(&client->pending); + coap_pending_cycle(&internal_req->pending); + + ret = send_request(sock, internal_req->request.data, internal_req->request.offset, 0, + &client->address, client->socklen); - ret = send_request(sock, client->request.data, client->request.offset, 0, &client->address, - client->socklen); + k_mutex_unlock(&client->send_mutex); if (ret < 0) { LOG_ERR("Transmission failed: %d", errno); @@ -364,89 +463,144 @@ int coap_client_req(struct coap_client *client, int sock, const struct sockaddr return ret; } -static int handle_poll(struct coap_client *client) +static void report_callback_error(struct coap_client_internal_request *internal_req, int error_code) +{ + if (internal_req->coap_request.cb) { + internal_req->coap_request.cb(error_code, 0, NULL, 0, true, + internal_req->coap_request.user_data); + } +} + +static bool timeout_expired(struct coap_client_internal_request *internal_req) +{ + return (internal_req->request_ongoing && + internal_req->pending.timeout <= k_uptime_get_32()); +} + +static int resend_request(struct coap_client *client, + struct coap_client_internal_request *internal_req) { int ret = 0; - while (1) { - struct zsock_pollfd fds; - - fds.fd = client->fd; - fds.events = ZSOCK_POLLIN; - fds.revents = 0; - /* rfc7252#section-5.2.2, use separate timeout value for a separate response */ - if (client->pending.timeout != 0) { - ret = zsock_poll(&fds, 1, client->pending.timeout); + if (internal_req->pending.timeout != 0 && coap_pending_cycle(&internal_req->pending)) { + LOG_ERR("Timeout in poll, retrying send"); + + /* Reset send block context as it was updated in previous init from packet */ + if (internal_req->send_blk_ctx.total_size > 0) { + internal_req->send_blk_ctx.current = internal_req->offset; + } + k_mutex_lock(&client->send_mutex, K_FOREVER); + ret = coap_client_init_request(client, &internal_req->coap_request, + internal_req, true); + if (ret < 0) { + LOG_ERR("Error re-creating CoAP request"); } else { - ret = zsock_poll(&fds, 1, COAP_SEPARATE_TIMEOUT); + ret = send_request(client->fd, internal_req->request.data, + internal_req->request.offset, 0, &client->address, + client->socklen); + if (ret > 0) { + ret = 0; + } else { + LOG_ERR("Failed to resend request, %d", ret); + } } + k_mutex_unlock(&client->send_mutex); + } else { + LOG_ERR("Timeout in poll, no more retries left"); + ret = -ETIMEDOUT; + report_callback_error(internal_req, ret); + internal_req->request_ongoing = false; + } + + return ret; +} + +static int coap_client_resend_handler(void) +{ + int ret = 0; + + for (int i = 0; i < num_clients; i++) { + for (int j = 0; j < CONFIG_COAP_CLIENT_MAX_REQUESTS; j++) { + if (timeout_expired(&clients[i]->requests[j])) { + ret = resend_request(clients[i], &clients[i]->requests[j]); + } + } + } + + return ret; +} + +static int handle_poll(void) +{ + int ret = 0; + + while (1) { + struct zsock_pollfd fds[CONFIG_COAP_CLIENT_MAX_INSTANCES] = {0}; + int nfds = 0; + + /* Use periodic timeouts */ + for (int i = 0; i < num_clients; i++) { + fds[i].fd = clients[i]->fd; + fds[i].events = ZSOCK_POLLIN; + fds[i].revents = 0; + nfds++; + } + + ret = zsock_poll(fds, nfds, COAP_PERIODIC_TIMEOUT); if (ret < 0) { LOG_ERR("Error in poll:%d", errno); errno = 0; return ret; } else if (ret == 0) { - if (client->pending.timeout != 0 && coap_pending_cycle(&client->pending)) { - LOG_ERR("Timeout in poll, retrying send"); - ret = send_request(client->fd, client->request.data, - client->request.offset, 0, &client->address, - client->socklen); - if (ret < 0) { - LOG_ERR("Transmission failed: %d", errno); - ret = -errno; - break; - } - } else { - /* No more retries left, don't retry */ - LOG_ERR("Timeout in poll, no more retries"); - ret = -EFAULT; - break; - } - } else { - if (fds.revents & ZSOCK_POLLERR) { - LOG_ERR("Error in poll"); - ret = -EIO; - break; - } + /* Resend all the expired pending messages */ + ret = coap_client_resend_handler(); - if (fds.revents & ZSOCK_POLLHUP) { - LOG_ERR("Error in poll: POLLHUP"); - ret = -ECONNRESET; - break; + if (ret < 0) { + LOG_ERR("Error resending request: %d", ret); } - if (fds.revents & ZSOCK_POLLNVAL) { - LOG_ERR("Error in poll: POLLNVAL - fd not open"); - ret = -EINVAL; - break; + if (!has_ongoing_requests()) { + return ret; } - if (!(fds.revents & ZSOCK_POLLIN)) { - LOG_ERR("Unknown poll error"); - ret = -EINVAL; - break; + } else { + for (int i = 0; i < nfds; i++) { + if (fds[i].revents & ZSOCK_POLLERR) { + LOG_ERR("Error in poll for socket %d", fds[i].fd); + } + if (fds[i].revents & ZSOCK_POLLHUP) { + LOG_ERR("Error in poll: POLLHUP for socket %d", fds[i].fd); + } + if (fds[i].revents & ZSOCK_POLLNVAL) { + LOG_ERR("Error in poll: POLLNVAL - fd %d not open", + fds[i].fd); + } + if (fds[i].revents & ZSOCK_POLLIN) { + clients[i]->response_ready = true; + } } - ret = 0; - break; + return 0; } } return ret; } -static bool token_compare(struct coap_client *client, const struct coap_packet *resp) +static bool token_compare(struct coap_client_internal_request *internal_req, + const struct coap_packet *resp) { uint8_t response_token[COAP_TOKEN_MAX_LEN]; uint8_t response_tkl; response_tkl = coap_header_get_token(resp, response_token); - if (client->request_tkl != response_tkl) { + if (internal_req->request_tkl != response_tkl) { return false; } - return memcmp(&client->request_token, &response_token, response_tkl) == 0; + return memcmp(&internal_req->request_token, &response_token, response_tkl) == 0; } static int recv_response(struct coap_client *client, struct coap_packet *response) @@ -477,28 +631,19 @@ static int recv_response(struct coap_client *client, struct coap_packet *respons return ret; } -static void report_callback_error(struct coap_client *client, int error_code) -{ - if (client->coap_request->cb) { - client->coap_request->cb(error_code, 0, NULL, 0, true, - client->coap_request->user_data); - } -} - static int send_ack(struct coap_client *client, const struct coap_packet *req, uint8_t response_code) { int ret; + struct coap_packet ack; - ret = coap_ack_init(&client->request, req, client->send_buf, MAX_COAP_MSG_LEN, - response_code); + ret = coap_ack_init(&ack, req, client->send_buf, MAX_COAP_MSG_LEN, response_code); if (ret < 0) { LOG_ERR("Failed to initialize CoAP ACK-message"); return ret; } - ret = send_request(client->fd, client->request.data, client->request.offset, 0, - &client->address, client->socklen); + ret = send_request(client->fd, ack.data, ack.offset, 0, &client->address, client->socklen); if (ret < 0) { LOG_ERR("Error sending a CoAP ACK-message"); return ret; @@ -514,10 +659,11 @@ static int send_reset(struct coap_client *client, const struct coap_packet *req, uint16_t id; uint8_t token[COAP_TOKEN_MAX_LEN]; uint8_t tkl; + struct coap_packet reset; id = coap_header_get_id(req); tkl = response_code ? coap_header_get_token(req, token) : 0; - ret = coap_packet_init(&client->request, client->send_buf, MAX_COAP_MSG_LEN, COAP_VERSION, + ret = coap_packet_init(&reset, client->send_buf, MAX_COAP_MSG_LEN, COAP_VERSION, COAP_TYPE_RESET, tkl, token, response_code, id); if (ret < 0) { @@ -525,7 +671,7 @@ static int send_reset(struct coap_client *client, const struct coap_packet *req, return ret; } - ret = send_request(client->fd, client->request.data, client->request.offset, 0, + ret = send_request(client->fd, reset.data, reset.offset, 0, &client->address, client->socklen); if (ret < 0) { LOG_ERR("Error sending CoAP reset message"); @@ -535,6 +681,43 @@ static int send_reset(struct coap_client *client, const struct coap_packet *req, return 0; } +struct coap_client_internal_request *get_request_with_id(struct coap_client *client, + uint16_t message_id) +{ + for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) { + if (client->requests[i].request_ongoing == true && + client->requests[i].pending.id == message_id) { + return &client->requests[i]; + } + } + + return NULL; +} + +struct coap_client_internal_request *get_request_with_token(struct coap_client *client, + const struct coap_packet *resp) +{ + + uint8_t response_token[COAP_TOKEN_MAX_LEN]; + uint8_t response_tkl; + + response_tkl = coap_header_get_token(resp, response_token); + + for (int i = 0; i < CONFIG_COAP_CLIENT_MAX_REQUESTS; i++) { + if (client->requests[i].request_ongoing) { + if (client->requests[i].request_tkl != response_tkl) { + continue; + } + if (memcmp(&client->requests[i].request_token, &response_token, + response_tkl) == 0) { + return &client->requests[i]; + } + } + } + + return NULL; +} + static int handle_response(struct coap_client *client, const struct coap_packet *response) { int ret = 0; @@ -543,6 +726,7 @@ static int handle_response(struct coap_client *client, const struct coap_packet int block_num; bool blockwise_transfer = false; bool last_block = false; + struct coap_client_internal_request *internal_req; /* Handle different types, ACK might be separate or piggybacked * CON and NCON contains a separate response, CON needs an empty response @@ -552,13 +736,14 @@ static int handle_response(struct coap_client *client, const struct coap_packet */ response_type = coap_header_get_type(response); + internal_req = get_request_with_id(client, coap_header_get_id(response)); /* Reset and Ack need to match the message ID with request */ if ((response_type == COAP_TYPE_ACK || response_type == COAP_TYPE_RESET) && - coap_header_get_id(response) != client->pending.id) { + internal_req == NULL) { LOG_ERR("Unexpected ACK or Reset"); return -EFAULT; } else if (response_type == COAP_TYPE_RESET) { - coap_pending_clear(&client->pending); + coap_pending_clear(&internal_req->pending); } /* CON, NON_CON and piggybacked ACK need to match the token with original request */ @@ -566,16 +751,24 @@ static int handle_response(struct coap_client *client, const struct coap_packet uint8_t response_code = coap_header_get_code(response); const uint8_t *payload = coap_packet_get_payload(response, &payload_len); - /* Separate response */ + /* Separate response coming */ if (payload_len == 0 && response_type == COAP_TYPE_ACK && response_code == COAP_CODE_EMPTY) { - /* Clear the pending, poll uses now the separate timeout for the response. */ - coap_pending_clear(&client->pending); + internal_req->pending.t0 = k_uptime_get_32(); + internal_req->pending.timeout = internal_req->pending.t0 + COAP_SEPARATE_TIMEOUT; + internal_req->pending.retries = 0; return 1; } - /* Check for tokens */ - if (!token_compare(client, response)) { + /* Check for tokens + * Separate response doesn't match with message ID, + * check if there is a separate request waiting with matching token + */ + if (internal_req == NULL) { + internal_req = get_request_with_token(client, response); + } + + if (internal_req == NULL || !token_compare(internal_req, response)) { LOG_ERR("Not matching tokens, respond with reset"); ret = send_reset(client, response, COAP_RESPONSE_CODE_NOT_FOUND); return 1; @@ -590,8 +783,8 @@ static int handle_response(struct coap_client *client, const struct coap_packet } } - if (client->pending.timeout != 0) { - coap_pending_clear(&client->pending); + if (internal_req->pending.timeout != 0) { + coap_pending_clear(&internal_req->pending); } /* Check if block2 exists */ @@ -602,26 +795,27 @@ static int handle_response(struct coap_client *client, const struct coap_packet block_num = GET_BLOCK_NUM(block_option); if (block_num == 0) { - coap_block_transfer_init(&client->recv_blk_ctx, + coap_block_transfer_init(&internal_req->recv_blk_ctx, coap_client_default_block_size(), 0); - client->offset = 0; + internal_req->offset = 0; } - ret = coap_update_from_block(response, &client->recv_blk_ctx); + ret = coap_update_from_block(response, &internal_req->recv_blk_ctx); if (ret < 0) { LOG_ERR("Error updating block context"); } - coap_next_block(response, &client->recv_blk_ctx); + coap_next_block(response, &internal_req->recv_blk_ctx); } else { - client->offset = 0; + internal_req->offset = 0; last_block = true; } /* Check if this was a response to last blockwise send */ - if (client->send_blk_ctx.total_size > 0) { + if (internal_req->send_blk_ctx.total_size > 0) { blockwise_transfer = true; - if (client->send_blk_ctx.total_size == client->send_blk_ctx.current) { + internal_req->offset = internal_req->send_blk_ctx.current; + if (internal_req->send_blk_ctx.total_size == internal_req->send_blk_ctx.current) { last_block = true; } else { last_block = false; @@ -629,40 +823,43 @@ static int handle_response(struct coap_client *client, const struct coap_packet } /* Call user callback */ - if (client->coap_request->cb) { - client->coap_request->cb(response_code, client->offset, payload, payload_len, - last_block, client->coap_request->user_data); + if (internal_req->coap_request.cb) { + internal_req->coap_request.cb(response_code, internal_req->offset, payload, + payload_len, last_block, + internal_req->coap_request.user_data); /* Update the offset for next callback in a blockwise transfer */ if (blockwise_transfer) { - client->offset += payload_len; + internal_req->offset += payload_len; } } /* If this wasn't last block, send the next request */ if (blockwise_transfer && !last_block) { - ret = coap_client_init_request(client, client->coap_request); + k_mutex_lock(&client->send_mutex, K_FOREVER); + ret = coap_client_init_request(client, &internal_req->coap_request, internal_req, + false); if (ret < 0) { LOG_ERR("Error creating a CoAP request"); + k_mutex_unlock(&client->send_mutex); goto fail; } - if (client->pending.timeout != 0) { - LOG_ERR("Previous pending hasn't arrived"); - goto fail; - } - - ret = coap_pending_init(&client->pending, &client->request, &client->address, - client->retry_count); + ret = coap_pending_init(&internal_req->pending, &internal_req->request, + &client->address, internal_req->retry_count); if (ret < 0) { LOG_ERR("Error creating pending"); + k_mutex_unlock(&client->send_mutex); goto fail; } - coap_pending_cycle(&client->pending); + coap_pending_cycle(&internal_req->pending); + + ret = send_request(client->fd, internal_req->request.data, + internal_req->request.offset, 0, &client->address, + client->socklen); + k_mutex_unlock(&client->send_mutex); - ret = send_request(client->fd, client->request.data, client->request.offset, 0, - &client->address, client->socklen); if (ret < 0) { LOG_ERR("Error sending a CoAP request"); goto fail; @@ -671,51 +868,52 @@ static int handle_response(struct coap_client *client, const struct coap_packet } } fail: + client->response_ready = false; + internal_req->request_ongoing = false; return ret; } void coap_client_recv(void *coap_cl, void *a, void *b) { int ret; - struct coap_client *const client = coap_cl; - reset_block_contexts(client); - k_sem_take(&client->coap_client_recv_sem, K_FOREVER); + k_sem_take(&coap_client_recv_sem, K_FOREVER); while (true) { - struct coap_packet response; - - atomic_set(&client->coap_client_recv_active, 1); - ret = handle_poll(client); + atomic_set(&coap_client_recv_active, 1); + ret = handle_poll(); if (ret < 0) { - /* Error in polling, clear pending. */ + /* Error in polling */ LOG_ERR("Error in poll"); - coap_pending_clear(&client->pending); - report_callback_error(client, ret); goto idle; } - ret = recv_response(client, &response); - if (ret < 0) { - LOG_ERR("Error receiving response"); - report_callback_error(client, ret); - goto idle; - } + for (int i = 0; i < num_clients; i++) { + if (clients[i]->response_ready) { + struct coap_packet response; - ret = handle_response(client, &response); - if (ret < 0) { - LOG_ERR("Error handling respnse"); - report_callback_error(client, ret); - goto idle; + ret = recv_response(clients[i], &response); + if (ret < 0) { + LOG_ERR("Error receiving response"); + clients[i]->response_ready = false; + continue; + } + + ret = handle_response(clients[i], &response); + if (ret < 0) { + LOG_ERR("Error handling respnse"); + } + + clients[i]->response_ready = false; + } } - /* There are more messages coming for the original request */ - if (ret > 0) { + /* There are more messages coming */ + if (has_ongoing_requests()) { continue; } else { idle: - reset_block_contexts(client); - atomic_set(&client->coap_client_recv_active, 0); - k_sem_take(&client->coap_client_recv_sem, K_FOREVER); + atomic_set(&coap_client_recv_active, 0); + k_sem_take(&coap_client_recv_sem, K_FOREVER); } } } @@ -726,22 +924,19 @@ int coap_client_init(struct coap_client *client, const char *info) return -EINVAL; } - client->fd = -1; - k_sem_init(&client->coap_client_recv_sem, 0, 1); + if (num_clients >= CONFIG_COAP_CLIENT_MAX_INSTANCES) { + return -ENOSPC; + } - client->tid = - k_thread_create(&client->thread, client->coap_thread_stack, - K_THREAD_STACK_SIZEOF(client->coap_thread_stack), - coap_client_recv, client, NULL, NULL, - CONFIG_COAP_CLIENT_THREAD_PRIORITY, 0, K_NO_WAIT); + k_mutex_init(&client->send_mutex); - if (IS_ENABLED(CONFIG_THREAD_NAME)) { - if (info != NULL) { - k_thread_name_set(client->tid, info); - } else { - k_thread_name_set(client->tid, "coap_client"); - } - } + clients[num_clients] = client; + num_clients++; return 0; } + + +K_THREAD_DEFINE(coap_client_recv_thread, CONFIG_COAP_CLIENT_STACK_SIZE, + coap_client_recv, NULL, NULL, NULL, + CONFIG_COAP_CLIENT_THREAD_PRIORITY, 0, 0); From a3612c70c8c972435eb5daf46be9053754cf37fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarno=20L=C3=A4ms=C3=A4?= Date: Mon, 26 Jun 2023 15:03:53 +0300 Subject: [PATCH 0696/2042] tests: Ztest tests for coap client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test handling multiple requests. Signed-off-by: Jarno Lämsä --- tests/net/lib/coap_client/CMakeLists.txt | 3 +- tests/net/lib/coap_client/src/main.c | 62 ++++++++++++++++++++---- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/tests/net/lib/coap_client/CMakeLists.txt b/tests/net/lib/coap_client/CMakeLists.txt index 60506c23c2d3..9486b914706e 100644 --- a/tests/net/lib/coap_client/CMakeLists.txt +++ b/tests/net/lib/coap_client/CMakeLists.txt @@ -24,5 +24,6 @@ add_compile_definitions(CONFIG_COAP_CLIENT_MESSAGE_HEADER_SIZE=48) add_compile_definitions(CONFIG_COAP_CLIENT_STACK_SIZE=1024) add_compile_definitions(CONFIG_COAP_CLIENT_THREAD_PRIORITY=10) add_compile_definitions(CONFIG_COAP_LOG_LEVEL=4) -add_compile_definitions(CONFIG_NET_SOCKETS_POSIX_NAMES=y) add_compile_definitions(CONFIG_COAP_INIT_ACK_TIMEOUT_MS=2000) +add_compile_definitions(CONFIG_COAP_CLIENT_MAX_REQUESTS=2) +add_compile_definitions(CONFIG_COAP_CLIENT_MAX_INSTANCES=2) diff --git a/tests/net/lib/coap_client/src/main.c b/tests/net/lib/coap_client/src/main.c index cb77c7c0cfe3..9e66015dbee0 100644 --- a/tests/net/lib/coap_client/src/main.c +++ b/tests/net/lib/coap_client/src/main.c @@ -17,7 +17,8 @@ DEFINE_FFF_GLOBALS; static uint8_t last_response_code; static const char *test_path = "test"; -static uint16_t last_message_id; + +static uint16_t messages_needing_response[2]; static struct coap_client client; @@ -33,11 +34,21 @@ static char *long_payload = "Lorem ipsum dolor sit amet, consectetur adipiscing static ssize_t z_impl_zsock_recvfrom_custom_fake(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + uint16_t last_message_id = 0; + LOG_INF("Recvfrom"); - static uint8_t ack_data[] = { + uint8_t ack_data[] = { 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if (messages_needing_response[0] != 0) { + last_message_id = messages_needing_response[0]; + messages_needing_response[0] = 0; + } else { + last_message_id = messages_needing_response[1]; + messages_needing_response[1] = 0; + } + ack_data[2] = (uint8_t) (last_message_id >> 8); ack_data[3] = (uint8_t) last_message_id; @@ -50,11 +61,17 @@ static ssize_t z_impl_zsock_sendto_custom_fake(int sock, void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { - LOG_INF("Sendto"); - last_message_id = 0; + uint16_t last_message_id = 0; + last_message_id |= ((uint8_t *) buf)[2] << 8; last_message_id |= ((uint8_t *) buf)[3]; + if (messages_needing_response[0] == 0) { + messages_needing_response[0] = last_message_id; + } else { + messages_needing_response[1] = last_message_id; + } + last_response_code = ((uint8_t *) buf)[1]; LOG_INF("Latest message ID: %d", last_message_id); @@ -65,10 +82,20 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_response(int sock, void *buf, s int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + uint16_t last_message_id = 0; + static uint8_t ack_data[] = { 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if (messages_needing_response[0] != 0) { + last_message_id = messages_needing_response[0]; + messages_needing_response[0] = 0; + } else { + last_message_id = messages_needing_response[1]; + messages_needing_response[1] = 0; + } + ack_data[2] = (uint8_t) (last_message_id >> 8); ack_data[3] = (uint8_t) last_message_id; @@ -81,10 +108,20 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_empty_ack(int sock, void *buf, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + uint16_t last_message_id = 0; + static uint8_t ack_data[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if (messages_needing_response[0] != 0) { + last_message_id = messages_needing_response[0]; + messages_needing_response[0] = 0; + } else { + last_message_id = messages_needing_response[1]; + messages_needing_response[1] = 0; + } + ack_data[2] = (uint8_t) (last_message_id >> 8); ack_data[3] = (uint8_t) last_message_id; @@ -99,10 +136,20 @@ static ssize_t z_impl_zsock_recvfrom_custom_fake_unmatching(int sock, void *buf, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + uint16_t last_message_id = 0; + static uint8_t ack_data[] = { 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + if (messages_needing_response[0] != 0) { + last_message_id = messages_needing_response[0]; + messages_needing_response[0] = 0; + } else { + last_message_id = messages_needing_response[1]; + messages_needing_response[1] = 0; + } + ack_data[2] = (uint8_t) (last_message_id >> 8); ack_data[3] = (uint8_t) last_message_id; @@ -242,7 +289,7 @@ ZTEST(coap_client, test_no_response) LOG_INF("Send request"); clear_socket_events(); - ret = coap_client_req(&client, 0, &address, &client_request, -1); + ret = coap_client_req(&client, 0, &address, &client_request, 0); zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(1000)); @@ -307,15 +354,12 @@ ZTEST(coap_client, test_multiple_requests) zassert_true(ret >= 0, "Sending request failed, %d", ret); ret = coap_client_req(&client, 0, &address, &client_request, -1); - zassert_equal(ret, -EAGAIN, "Shouldn't be able to send 2 requests at same time"); + zassert_true(ret >= 0, "Sending request failed, %d", ret); k_sleep(K_MSEC(5)); k_sleep(K_MSEC(1000)); zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response"); - ret = coap_client_req(&client, 0, &address, &client_request, -1); - zassert_true(ret >= 0, "Sending request failed, %d", ret); - k_sleep(K_MSEC(5)); k_sleep(K_MSEC(1000)); zassert_equal(last_response_code, COAP_RESPONSE_CODE_OK, "Unexpected response"); From fc945035d26b72bce11e59a2e2a666e55f03ad77 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 23 Jun 2023 14:10:02 +0200 Subject: [PATCH 0697/2042] samples: drivers: auxdisplay requires a fixture to run on a platform Add a config "fixture_auxdisplay" to make the samples/drivers/auxdisplay runnable on a platform, else the application is useless This fixture will differ from the existing "fixture_display" Signed-off-by: Francois Ramu --- samples/drivers/auxdisplay/sample.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/drivers/auxdisplay/sample.yaml b/samples/drivers/auxdisplay/sample.yaml index 33d7c88412fe..bcd26ff67139 100644 --- a/samples/drivers/auxdisplay/sample.yaml +++ b/samples/drivers/auxdisplay/sample.yaml @@ -4,6 +4,8 @@ sample: tests: sample.drivers.auxdisplay: tags: auxdisplay + harness_config: + fixture: fixture_auxdisplay platform_allow: nucleo_f746zg integration_platforms: - nucleo_f746zg From 2f5068fcda0cb33284b6a8d777fbb95c9703ad82 Mon Sep 17 00:00:00 2001 From: Sjors Hettinga Date: Tue, 27 Jun 2023 20:13:14 +0200 Subject: [PATCH 0698/2042] MAINTAINERS: Add self as network collaborator Add myself as collaborator for the networking subsystem. Signed-off-by: Sjors Hettinga --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1dfacb2e4299..fda0bd0c29f4 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1804,6 +1804,7 @@ Networking: - rlubos collaborators: - tbursztyka + - ssharks files: - drivers/net/ - include/zephyr/net/ From b9d46b5483837968016c104e0d5d52a280abb94d Mon Sep 17 00:00:00 2001 From: Theo Gasteiger Date: Sat, 10 Jun 2023 16:45:24 +0200 Subject: [PATCH 0699/2042] Bluetooth: Audio: Encrypted BISes cause MPU FAULT When enabling BIS encryption, a MPU fault will occur. Signed-off-by: Theo Gasteiger --- subsys/bluetooth/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index ee5d0f0b0e33..ae91baf884a0 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -41,7 +41,7 @@ config BT_HCI_TX_STACK_SIZE default 512 if BT_H4 default 512 if BT_H5 default 416 if BT_SPI - default 940 if BT_CTLR && BT_LL_SW_SPLIT && NO_OPTIMIZATIONS + default 940 if BT_CTLR && BT_LL_SW_SPLIT && (NO_OPTIMIZATIONS || BT_ISO_BROADCAST) default 1024 if BT_CTLR && BT_LL_SW_SPLIT && BT_CENTRAL default 768 if BT_CTLR && BT_LL_SW_SPLIT default 512 if BT_USERCHAN From c75bf5ebc504dc655c4c94c60edf55b4ea013b27 Mon Sep 17 00:00:00 2001 From: Evgeniy Paltsev Date: Tue, 20 Jun 2023 08:46:06 +0100 Subject: [PATCH 0700/2042] ARC: MWDT: cleanup search path handling Cleanup ARC MWDT search path handling: * Don't print warning if ARCMWDT_TOOLCHAIN_PATH is missing but METAWARE_ROOT is set. Treat it as valid case and do message with status level instead of warning. * Make rest of the error messages more understandable for users. Signed-off-by: Eugeniy Paltsev Signed-off-by: Evgeniy Paltsev --- cmake/toolchain/arcmwdt/generic.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/toolchain/arcmwdt/generic.cmake b/cmake/toolchain/arcmwdt/generic.cmake index ddd517770a2a..3f5fded2dac4 100644 --- a/cmake/toolchain/arcmwdt/generic.cmake +++ b/cmake/toolchain/arcmwdt/generic.cmake @@ -2,17 +2,17 @@ zephyr_get(ARCMWDT_TOOLCHAIN_PATH) -if(NOT DEFINED ARCMWDT_TOOLCHAIN_PATH AND DEFINED ENV{METAWARE_ROOT}) - message(WARNING "ARCMWDT_TOOLCHAIN_PATH is not set, use default toolchain from METAWARE_ROOT") - set(METAWARE_ROOT $ENV{METAWARE_ROOT}) +set(METAWARE_ROOT $ENV{METAWARE_ROOT}) +if(NOT DEFINED ARCMWDT_TOOLCHAIN_PATH AND DEFINED METAWARE_ROOT) + message(STATUS "ARCMWDT_TOOLCHAIN_PATH is not set, use default toolchain from METAWARE_ROOT: '${METAWARE_ROOT}'") if(NOT EXISTS ${METAWARE_ROOT}) message(FATAL_ERROR "Nothing found at METAWARE_ROOT: '${METAWARE_ROOT}'") endif() cmake_path(GET METAWARE_ROOT PARENT_PATH ARCMWDT_TOOLCHAIN_PATH) +elseif(NOT DEFINED ARCMWDT_TOOLCHAIN_PATH AND NOT DEFINED METAWARE_ROOT) + message(FATAL_ERROR "No MWDT toolchain specified: neither ARCMWDT_TOOLCHAIN_PATH nor METAWARE_ROOT defined") endif() -assert(ARCMWDT_TOOLCHAIN_PATH "ARCMWDT_TOOLCHAIN_PATH is not set") - if(NOT EXISTS ${ARCMWDT_TOOLCHAIN_PATH}) message(FATAL_ERROR "Nothing found at ARCMWDT_TOOLCHAIN_PATH: '${ARCMWDT_TOOLCHAIN_PATH}'") endif() From 7ae4e2472808648e3c13e887c04de2a0306eceb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarno=20L=C3=A4ms=C3=A4?= Date: Tue, 27 Jun 2023 10:52:12 +0300 Subject: [PATCH 0701/2042] net: lib: lwm2m: Use int16_t for signal strength MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The signal strength for the connectivity monitor was defined as int8_t, however this was too small for LTE RSRP values, which has range [-140,-44]. Signed-off-by: Jarno Lämsä --- subsys/net/lib/lwm2m/lwm2m_obj_connmon.c | 4 ++-- .../lwm2m/lwm2m_registry/src/lwm2m_registry.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c index c0e14429c857..aabb9fd3fd1d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_connmon.c @@ -84,7 +84,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); /* resource state variables */ static int8_t net_bearer; -static int8_t rss; +static int16_t rss; static uint8_t link_quality; static uint32_t cellid; static uint16_t mnc; @@ -99,7 +99,7 @@ static struct lwm2m_engine_obj connmon; static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(CONNMON_NETWORK_BEARER_ID, R, U8), OBJ_FIELD_DATA(CONNMON_AVAIL_NETWORK_BEARER_ID, R, U8), - OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S8), + OBJ_FIELD_DATA(CONNMON_RADIO_SIGNAL_STRENGTH, R, S16), OBJ_FIELD_DATA(CONNMON_LINK_QUALITY, R, U8), OBJ_FIELD_DATA(CONNMON_IP_ADDRESSES, R, STRING), OBJ_FIELD_DATA(CONNMON_ROUTER_IP_ADDRESSES, R_OPT, STRING), 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 a5d1240fd909..5b79c476e7f0 100644 --- a/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c +++ b/tests/net/lib/lwm2m/lwm2m_registry/src/lwm2m_registry.c @@ -130,12 +130,12 @@ ZTEST(lwm2m_registry, test_connmon) int ret; uint16_t u16_buf = 0; uint32_t u32_buf = 0; - int8_t s8_buf = 0; + int16_t s16_buf = 0; int32_t s32_buf = 0; uint16_t u16_getbuf = 0; uint32_t u32_getbuf = 0; - int8_t s8_getbuf = 0; + int16_t s16_getbuf = 0; int32_t s32_getbuf = 0; ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 9), &u16_buf, sizeof(u16_buf), @@ -144,8 +144,8 @@ ZTEST(lwm2m_registry, test_connmon) ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 8), &u32_buf, sizeof(u32_buf), sizeof(u32_buf), 0); zassert_equal(ret, 0); - ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 2), &s8_buf, sizeof(s8_buf), - sizeof(s8_buf), 0); + ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 2), &s16_buf, sizeof(s16_buf), + sizeof(s16_buf), 0); zassert_equal(ret, 0); ret = lwm2m_set_res_buf(&LWM2M_OBJ(4, 0, 11), &s32_buf, sizeof(s32_buf), sizeof(s32_buf), 0); @@ -155,28 +155,28 @@ ZTEST(lwm2m_registry, test_connmon) zassert_equal(ret, 0); ret = lwm2m_set_u32(&LWM2M_OBJ(4, 0, 8), 0xDEADBEEF); zassert_equal(ret, 0); - ret = lwm2m_set_s8(&LWM2M_OBJ(4, 0, 2), -5); + ret = lwm2m_set_s16(&LWM2M_OBJ(4, 0, 2), -5); zassert_equal(ret, 0); ret = lwm2m_set_s32(&LWM2M_OBJ(4, 0, 11), 0xCC00CC00); zassert_equal(ret, 0); zassert_equal(u16_buf, 0x5A5A); zassert_equal(u32_buf, 0xDEADBEEF); - zassert_equal(s8_buf, -5); + zassert_equal(s16_buf, -5); zassert_equal(s32_buf, 0xCC00CC00); ret = lwm2m_get_u16(&LWM2M_OBJ(4, 0, 9), &u16_getbuf); zassert_equal(ret, 0); ret = lwm2m_get_u32(&LWM2M_OBJ(4, 0, 8), &u32_getbuf); zassert_equal(ret, 0); - ret = lwm2m_get_s8(&LWM2M_OBJ(4, 0, 2), &s8_getbuf); + ret = lwm2m_get_s16(&LWM2M_OBJ(4, 0, 2), &s16_getbuf); zassert_equal(ret, 0); ret = lwm2m_get_s32(&LWM2M_OBJ(4, 0, 11), &s32_getbuf); zassert_equal(ret, 0); zassert_equal(u16_buf, u16_getbuf); zassert_equal(u32_buf, u32_getbuf); - zassert_equal(s8_buf, s8_getbuf); + zassert_equal(s16_buf, s16_getbuf); zassert_equal(s32_buf, s32_getbuf); } From cd264b21e4a90ed85a63116bd148b890ab347db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Wed, 28 Jun 2023 08:25:45 +0200 Subject: [PATCH 0702/2042] Bluetooth: Host: Abort pairing if disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If disconnection has been triggered in between the security update and the call to `smp_pairing_complete` we need to abort the pairing. The disconnection may have been triggered by `bt_unpair`, in that case the keys will have been erased and it will lead to an assertion to continue as if nothing happened. To resolve this issue, at the beginning of `smp_pairing_complete` the `status` is set to `BT_SMP_ERR_UNSPECIFIED` if there is no connection. Signed-off-by: Théo Battrel --- subsys/bluetooth/host/smp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 2fad1ea235f7..9b40910cb304 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -1632,7 +1632,15 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status) { struct bt_conn *conn = smp->chan.chan.conn; - LOG_DBG("status 0x%x", status); + LOG_DBG("got status 0x%x", status); + + if (conn->state != BT_CONN_CONNECTED) { + /* If disconnection has been triggered in between the security update + * and the call to this function we need to abort the pairing. + */ + LOG_WRN("Not connected!"); + status = BT_SMP_ERR_UNSPECIFIED; + } if (!status) { #if defined(CONFIG_BT_BREDR) @@ -1701,7 +1709,7 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status) smp_reset(smp); - if (conn->sec_level != conn->required_sec_level) { + if (conn->state == BT_CONN_CONNECTED && conn->sec_level != conn->required_sec_level) { bt_smp_start_security(conn); } } From 4256472fbf0c6b1164e6e552dd9f7ec07885d03f Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 28 Jun 2023 17:41:17 +0200 Subject: [PATCH 0703/2042] Bluetooth: Mesh: Reduce BT_L2CAP_TX_MTU for mesh to 33 Since the acl mtu for mesh is reduced to 37 in PR #59004, there is no need in BT_L2CAP_TX_MTU to be longer than 33 bytes for mesh. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/host/Kconfig.l2cap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/Kconfig.l2cap b/subsys/bluetooth/host/Kconfig.l2cap index 82c9e55b864b..acb948c425a0 100644 --- a/subsys/bluetooth/host/Kconfig.l2cap +++ b/subsys/bluetooth/host/Kconfig.l2cap @@ -30,7 +30,6 @@ config BT_L2CAP_TX_FRAG_COUNT config BT_L2CAP_TX_MTU int "Maximum supported L2CAP MTU for L2CAP TX buffers" default 253 if BT_BREDR - default 69 if BT_MESH_GATT default 66 if BT_EATT default 65 if BT_SMP default 64 if BT_BAP_UNICAST_SERVER || \ @@ -39,6 +38,7 @@ config BT_L2CAP_TX_MTU BT_BAP_SCAN_DELEGATOR || \ BT_BAP_BROADCAST_ASSISTANT default 49 if BT_HAS || BT_HAS_CLIENT + default 33 if BT_MESH_GATT default 23 range 66 2000 if BT_EATT range 65 2000 if BT_SMP From 6abef011089b19f02fb606f6842f0f2a88ad7861 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 29 Jun 2023 05:31:03 +0530 Subject: [PATCH 0704/2042] samples: Bluetooth: hci_rpmsg: Fix Rx Prio thread stack usage Fix Rx Prio thread stack usage value to Kconfig default value. After long duration use of hci_rpmsg in audio application, remaining stack was 80 bytes, hence increase back to 448 as set in the Kconfig defaults. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf | 2 +- .../bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf | 2 +- .../bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf | 2 +- .../bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf index 31c333a85693..f0a22f760f9b 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_bis-bt_ll_sw_split.conf @@ -28,7 +28,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host features CONFIG_BT_EXT_ADV=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf index 8ff728cfd18e..049aa2519bb4 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf @@ -28,7 +28,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host features CONFIG_BT_EXT_ADV=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf index 3d212d3ded51..21d4a042ad75 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_df-bt_ll_sw_split.conf @@ -28,7 +28,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host features CONFIG_BT_EXT_ADV=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf index 2ed5d1018fd9..68c5aa5b0583 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -28,7 +28,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host features CONFIG_BT_EXT_ADV=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf index 32d4ab23bfc9..74dc735c076c 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf @@ -20,7 +20,7 @@ CONFIG_BT_BUF_CMD_TX_COUNT=10 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host CONFIG_BT_BROADCASTER=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf index e85f88bb550e..648b2dd56bc3 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf @@ -25,7 +25,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host CONFIG_BT_BROADCASTER=n diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf index c40a92b58e99..97fa131c7ddf 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf @@ -25,7 +25,7 @@ CONFIG_BT_BUF_CMD_TX_SIZE=255 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host CONFIG_BT_BROADCASTER=y diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf index 2dd0035bc5aa..d88aa87f8aa4 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf @@ -20,7 +20,7 @@ CONFIG_BT_BUF_CMD_TX_COUNT=10 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=384 +CONFIG_BT_CTLR_RX_PRIO_STACK_SIZE=448 # Host CONFIG_BT_BROADCASTER=n From 87d65dc502aa150dd88b22f97d1245499393977b Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 29 Jun 2023 05:52:17 +0530 Subject: [PATCH 0705/2042] samples: Bluetooth: hci_rpmsg/uart: Fix BT_CTLR_ISO_TX_BUFFER_SIZE Restore back BT_CTLR_ISO_TX_BUFFER_SIZE to 251 after fix in commit e460847b6083 ("Bluetooth: host: don't fragment ISO if len <= MTU"). Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf | 2 +- .../bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf | 2 +- .../hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf | 2 +- samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf | 2 +- tests/bsim/bluetooth/ll/cis/prj.conf | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf index 049aa2519bb4..7fab285f3bed 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_cis-bt_ll_sw_split.conf @@ -89,7 +89,7 @@ CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf index 68c5aa5b0583..bb95b6ea74ea 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -106,7 +106,7 @@ CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf index 648b2dd56bc3..f29917aaf935 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf @@ -56,7 +56,7 @@ CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=16 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf index 97fa131c7ddf..ddd7d7e7b317 100644 --- a/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_rpmsg/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf @@ -56,7 +56,7 @@ CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=16 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf b/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf index 8730af936372..1f976f75f225 100644 --- a/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_uart/overlay-all-bt_ll_sw_split.conf @@ -98,7 +98,7 @@ CONFIG_BT_CTLR_CONN_ISO_PDU_LEN_MAX=251 # ISO Transmissions CONFIG_BT_CTLR_ISO_TX_BUFFERS=8 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISOAL_SOURCES=2 # ISO Receptions diff --git a/tests/bsim/bluetooth/ll/cis/prj.conf b/tests/bsim/bluetooth/ll/cis/prj.conf index f7aa0bd7ed7b..0b6b764393b6 100644 --- a/tests/bsim/bluetooth/ll/cis/prj.conf +++ b/tests/bsim/bluetooth/ll/cis/prj.conf @@ -35,7 +35,7 @@ CONFIG_BT_CTLR_ISOAL_SOURCES=9 CONFIG_BT_CTLR_ISOAL_SINKS=9 CONFIG_BT_CTLR_ISO_TX_BUFFERS=18 -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=259 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ISO_RX_BUFFERS=1 CONFIG_BT_CTLR_PHY_CODED=n From bd9cee0a9fa25249e2fdd9241b5de63e8daaf506 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 29 Jun 2023 05:56:19 +0530 Subject: [PATCH 0706/2042] Bluetooth: Controller: Inherit BT_ISO_TX_MTU value Inherit BT_ISO_TX_MTU value for BT_CTLR_ISO_TX_BUFFER_SIZE. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig | 1 + subsys/bluetooth/controller/include/ll_feat.h | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 2eb3ed62e7c1..f79332d8b41f 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -237,6 +237,7 @@ config BT_CTLR_ISO_TX_BUFFER_SIZE int "Isochronous Tx buffer size" depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO range 1 4095 + default BT_ISO_TX_MTU if BT_ISO default 1 help Size of the Isochronous Tx buffers and the value returned in HCI LE diff --git a/subsys/bluetooth/controller/include/ll_feat.h b/subsys/bluetooth/controller/include/ll_feat.h index 1ab2cf6c5832..1eb2d86a1c3d 100644 --- a/subsys/bluetooth/controller/include/ll_feat.h +++ b/subsys/bluetooth/controller/include/ll_feat.h @@ -201,12 +201,8 @@ #if defined(CONFIG_BT_CTLR_ADV_ISO) #define LL_FEAT_BIT_ISO_BROADCASTER BIT64(BT_LE_FEAT_BIT_ISO_BROADCASTER) -#if defined(CONFIG_BT_ISO_TX_MTU) #define LL_BIS_OCTETS_TX_MAX MIN(CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX, \ - CONFIG_BT_ISO_TX_MTU) -#else /* !CONFIG_BT_ISO_TX_MTU */ -#define LL_BIS_OCTETS_TX_MAX CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX -#endif /* !CONFIG_BT_ISO_TX_MTU */ + CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE) #else /* !CONFIG_BT_CTLR_ADV_ISO */ #define LL_FEAT_BIT_ISO_BROADCASTER 0 #define LL_BIS_OCTETS_TX_MAX 0 From a9955d3e177cdb251eb12adeac856798745515dc Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jun 2023 16:01:11 +0800 Subject: [PATCH 0707/2042] drivers: watchdog: Add Andestech ATCWDT200 driver. Support the Andes atcwdt200 watchdog driver. Signed-off-by: Kevin Wang --- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts | 6 +- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml | 1 + drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.andes_atcwdt200 | 14 + drivers/watchdog/wdt_andes_atcwdt200.c | 366 ++++++++++++++++++ .../watchdog/andestech,atcwdt200.yaml | 18 + dts/riscv/andes/andes_v5_ae350.dtsi | 10 +- 8 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 drivers/watchdog/Kconfig.andes_atcwdt200 create mode 100644 drivers/watchdog/wdt_andes_atcwdt200.c create mode 100644 dts/bindings/watchdog/andestech,atcwdt200.yaml diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts index 8ff809f022c9..011e8e5597c4 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Andes Technology Corporation + * Copyright (c) 2023 Andes Technology Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -180,3 +180,7 @@ status = "okay"; cs-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; }; + +&wdt { + status = "okay"; +}; diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml index 8a2a1031993f..37e25bc5d8eb 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml @@ -12,6 +12,7 @@ supported: - i2c - spi - eeprom + - watchdog testing: ignore_tags: - bluetooth diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 12317539ac7b..e06eb3d407c5 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -40,5 +40,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_OPENTITAN wdt_opentitan.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c) +zephyr_library_sources_ifdef(CONFIG_WDT_ANDES_ATCWDT200 wdt_andes_atcwdt200.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index cae4b5261434..950c8c4e7c2e 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -110,4 +110,6 @@ source "drivers/watchdog/Kconfig.ifx_cat1" source "drivers/watchdog/Kconfig.opentitan" +source "drivers/watchdog/Kconfig.andes_atcwdt200" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.andes_atcwdt200 b/drivers/watchdog/Kconfig.andes_atcwdt200 new file mode 100644 index 000000000000..b4160c7bf242 --- /dev/null +++ b/drivers/watchdog/Kconfig.andes_atcwdt200 @@ -0,0 +1,14 @@ +# Kconfig Andes Watchdog configuration options +# +# Copyright (c) 2023 Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +config WDT_ANDES_ATCWDT200 + bool "Andes Watchdog driver" + default y + depends on DT_HAS_ANDESTECH_ATCWDT200_ENABLED + select COUNTER + help + Enable driver for the Andes Watchdog driver. diff --git a/drivers/watchdog/wdt_andes_atcwdt200.c b/drivers/watchdog/wdt_andes_atcwdt200.c new file mode 100644 index 000000000000..6c314488568b --- /dev/null +++ b/drivers/watchdog/wdt_andes_atcwdt200.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT andestech_atcwdt200 + +#include +#include +#include + +#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL +#include +#include +#include +#include +LOG_MODULE_REGISTER(wdt_andes); + +/* Watchdog register */ +#define REG_IDR 0x00 +#define REG_CTRL 0x10 +#define REG_RESTAR 0x14 +#define REG_WREN 0x18 +#define REG_STATUS 0x1c + +#define WDT_CTRL(addr) (addr + REG_CTRL) +#define WDT_RESTAR(addr) (addr + REG_RESTAR) +#define WDT_WREN(addr) (addr + REG_WREN) +#define WDT_STATUS(addr) (addr + REG_STATUS) + +/* Atcwdt200 magic number */ +/* 0x10 Control Register */ + +#define WDT_CTRL_RSTTIME_POW_2_7 0x000 +#define WDT_CTRL_RSTTIME_POW_2_8 0x100 +#define WDT_CTRL_RSTTIME_POW_2_9 0x200 +#define WDT_CTRL_RSTTIME_POW_2_10 0x300 +#define WDT_CTRL_RSTTIME_POW_2_11 0x400 +#define WDT_CTRL_RSTTIME_POW_2_12 0x500 +#define WDT_CTRL_RSTTIME_POW_2_13 0x600 +#define WDT_CTRL_RSTTIME_POW_2_14 0x700 + +#define WDT_CTRL_INTTIME_POW_2_6 0x000 +#define WDT_CTRL_INTTIME_POW_2_8 0x010 +#define WDT_CTRL_INTTIME_POW_2_10 0x020 +#define WDT_CTRL_INTTIME_POW_2_11 0x030 +#define WDT_CTRL_INTTIME_POW_2_12 0x040 +#define WDT_CTRL_INTTIME_POW_2_13 0x050 +#define WDT_CTRL_INTTIME_POW_2_14 0x060 +#define WDT_CTRL_INTTIME_POW_2_15 0x070 +#define WDT_CTRL_INTTIME_POW_2_17 0x080 +#define WDT_CTRL_INTTIME_POW_2_19 0x090 +#define WDT_CTRL_INTTIME_POW_2_21 0x0A0 +#define WDT_CTRL_INTTIME_POW_2_23 0x0B0 +#define WDT_CTRL_INTTIME_POW_2_25 0x0C0 +#define WDT_CTRL_INTTIME_POW_2_27 0x0D0 +#define WDT_CTRL_INTTIME_POW_2_29 0x0E0 +#define WDT_CTRL_INTTIME_POW_2_31 0x0F0 + +#define WDT_CTRL_RSTEN 0x8 +#define WDT_CTRL_INTEN 0x4 +#define WDT_CTRL_APBCLK 0x2 +#define WDT_CTRL_EXTCLK 0x0 +#define WDT_CTRL_EN 0x1 + +/* Magic Number for Restart Register */ +#define WDT_RESTART_NUM 0xcafe + +/* Magic Number for Write Enable Register */ +#define WDT_WREN_NUM 0x5aa5 + +/* 0x1C Status Register */ +#define WDT_ST_INTEXPIRED 0x1 +#define WDT_ST_INTEXPIRED_CLR 0x1 + +/* + * SMU(System Management Unit) Registers for hwinfo driver + */ + +/* Register offset*/ +#define SMU_RESET_WRSR 0x10 +#define SMU_RESET_REGHI 0x60 +#define SMU_RESET_REGLO 0x50 +#define SMU_CMD 0x14 + +#define SMU_RESET_CMD 0x3c + +#define WDOGCFG_PERIOD_MIN BIT(7) +#define WDOGCFG_PERIOD_MAX BIT(14) +#define EXT_CLOCK_FREQ BIT(15) + +static const struct device *const syscon_dev = + DEVICE_DT_GET(DT_NODELABEL(syscon)); +static const struct device *const counter_dev = + DEVICE_DT_GET(DT_NODELABEL(pit0)); + +struct counter_alarm_cfg alarm_cfg; + +struct wdt_atcwdt200_config { + uintptr_t base; +}; + +struct wdt_atcwdt200_dev_data { + bool timeout_valid; + counter_alarm_callback_t counter_callback; + struct k_spinlock lock; +}; + +static int wdt_atcwdt200_disable(const struct device *dev); + +static void wdt_counter_cb(const struct device *counter_dev, uint8_t chan_id, + uint32_t counter, + void *user_data) +{ + const struct device *dev = DEVICE_DT_INST_GET(0); + struct wdt_atcwdt200_dev_data *wdt_data = dev->data; + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + k_spinlock_key_t key; + + key = k_spin_lock(&wdt_data->lock); + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(WDT_RESTART_NUM, WDT_RESTAR(wdt_addr)); + + counter_set_channel_alarm(counter_dev, 2, &alarm_cfg); + + k_spin_unlock(&wdt_data->lock, key); +} + +/** + * @brief Set maximum length of timeout to watchdog + * + * @param dev Watchdog device struct + */ +static void wdt_atcwdt200_set_max_timeout(const struct device *dev) +{ + struct wdt_atcwdt200_dev_data *data = dev->data; + k_spinlock_key_t key; + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + uint32_t reg, counter_freq; + + key = k_spin_lock(&data->lock); + + counter_freq = counter_get_frequency(counter_dev); + + alarm_cfg.flags = 0; + alarm_cfg.callback = wdt_counter_cb; + alarm_cfg.user_data = &alarm_cfg; + alarm_cfg.ticks = ((WDOGCFG_PERIOD_MAX * counter_freq) / EXT_CLOCK_FREQ) >> 1; + + reg = WDT_CTRL_RSTTIME_POW_2_14; + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(reg, WDT_CTRL(wdt_addr)); + + data->timeout_valid = true; + + k_spin_unlock(&data->lock, key); +} + +static int wdt_atcwdt200_disable(const struct device *dev) +{ + struct wdt_atcwdt200_dev_data *data = dev->data; + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + k_spinlock_key_t key; + uint32_t reg; + + key = k_spin_lock(&data->lock); + + reg = sys_read32(WDT_CTRL(wdt_addr)); + reg &= ~(WDT_CTRL_RSTEN | WDT_CTRL_EN); + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(reg, WDT_CTRL(wdt_addr)); + + k_spin_unlock(&data->lock, key); + + wdt_atcwdt200_set_max_timeout(dev); + counter_cancel_channel_alarm(counter_dev, 2); + + return 0; +} + +static int wdt_atcwdt200_setup(const struct device *dev, uint8_t options) +{ + struct wdt_atcwdt200_dev_data *data = dev->data; + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + k_spinlock_key_t key; + uint32_t reg; + uint32_t ret = 0; + + if (!data->timeout_valid) { + LOG_ERR("No valid timeouts installed"); + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + + reg = sys_read32(WDT_CTRL(wdt_addr)); + reg |= (WDT_CTRL_RSTEN | WDT_CTRL_EN); + + if ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) == + WDT_OPT_PAUSE_HALTED_BY_DBG) { + counter_cancel_channel_alarm(counter_dev, 2); + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(reg, WDT_CTRL(wdt_addr)); + goto out; + } else { + ret = counter_set_channel_alarm(counter_dev, 2, &alarm_cfg); + if (ret != 0) { + ret = -EINVAL; + goto out; + } + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(reg, WDT_CTRL(wdt_addr)); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +/** + * @brief Calculates the watchdog counter value (wdogcmp0) and + * scaler (wdogscale) to be installed in the watchdog timer + * + * @param timeout Timeout value in milliseconds. + * @param scaler Pointer to return scaler power of 2 + * + * @return Watchdog counter value + */ +static uint32_t wdt_atcwdt200_convtime(uint32_t timeout, uint32_t *scaler) +{ + int i; + uint32_t rst_period, cnt; + + cnt = (uint32_t)((timeout * EXT_CLOCK_FREQ) / 1000); + rst_period = cnt; + + for (i = 0; i < 14 && cnt > 0; i++) { + cnt >>= 1; + } + + *scaler = i; + + return rst_period; +} + +static int wdt_atcwdt200_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct wdt_atcwdt200_dev_data *data = dev->data; + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + k_spinlock_key_t key; + uint32_t rst_period, reg, counter_freq, scaler; + + if (cfg->window.min != 0U || cfg->window.max == 0U) { + return -EINVAL; + } + + counter_freq = counter_get_frequency(counter_dev); + rst_period = wdt_atcwdt200_convtime(cfg->window.max, &scaler); + + if (rst_period < 0 || WDOGCFG_PERIOD_MAX < rst_period) { + LOG_ERR("Unsupported watchdog timeout\n"); + return -EINVAL; + } + + wdt_atcwdt200_disable(dev); + + key = k_spin_lock(&data->lock); + + switch (cfg->flags) { + case WDT_FLAG_RESET_SOC: + if (scaler < 7) { + reg = WDT_CTRL_RSTTIME_POW_2_7; + } else { + scaler = scaler - 7; + reg = scaler << 8; + } + + alarm_cfg.flags = 0; + alarm_cfg.callback = wdt_counter_cb; + alarm_cfg.user_data = &alarm_cfg; + alarm_cfg.ticks = (((cfg->window.max * counter_freq) / 1000) >> 1); + + break; + case WDT_FLAG_RESET_NONE: + case WDT_FLAG_RESET_CPU_CORE: + default: + LOG_ERR("Unsupported watchdog config flags\n"); + k_spin_unlock(&data->lock, key); + return -ENOTSUP; + } + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(reg, WDT_CTRL(wdt_addr)); + + k_spin_unlock(&data->lock, key); + return 0; +} + +static int wdt_atcwdt200_feed(const struct device *dev, int channel_id) +{ + uint32_t wdt_addr = ((const struct wdt_atcwdt200_config *)(dev->config))->base; + + ARG_UNUSED(channel_id); + + sys_write32(WDT_WREN_NUM, WDT_WREN(wdt_addr)); + sys_write32(WDT_RESTART_NUM, WDT_RESTAR(wdt_addr)); + + return 0; +} + +static const struct wdt_driver_api wdt_atcwdt200_api = { + .setup = wdt_atcwdt200_setup, + .disable = wdt_atcwdt200_disable, + .install_timeout = wdt_atcwdt200_install_timeout, + .feed = wdt_atcwdt200_feed, +}; + +static int wdt_atcwdt200_init(const struct device *dev) +{ + struct wdt_atcwdt200_dev_data *data = dev->data; + + data->timeout_valid = false; + data->counter_callback = wdt_counter_cb; + uint32_t ret; + + counter_start(counter_dev); + + ret = syscon_write_reg(syscon_dev, SMU_RESET_REGLO, + ((uint32_t)((unsigned long) + Z_MEM_PHYS_ADDR(CONFIG_KERNEL_ENTRY)))); + if (ret < 0) { + return -EINVAL; + } + + ret = syscon_write_reg(syscon_dev, SMU_RESET_REGHI, + ((uint32_t)((uint64_t)((unsigned long) + Z_MEM_PHYS_ADDR(CONFIG_KERNEL_ENTRY)) >> 32))); + if (ret < 0) { + return -EINVAL; + } + +#ifdef CONFIG_WDT_DISABLE_AT_BOOT + wdt_atcwdt200_disable(dev); +#else + data->timeout_valid = true; + wdt_atcwdt200_set_max_timeout(dev); + wdt_atcwdt200_setup(dev, 0x0); +#endif + return 0; +} + +static struct wdt_atcwdt200_dev_data wdt_atcwdt200_data; + +static const struct wdt_atcwdt200_config wdt_atcwdt200_cfg = { + .base = DT_INST_REG_ADDR(0), +}; + +DEVICE_DT_INST_DEFINE(0, wdt_atcwdt200_init, NULL, + &wdt_atcwdt200_data, &wdt_atcwdt200_cfg, PRE_KERNEL_2, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_atcwdt200_api); diff --git a/dts/bindings/watchdog/andestech,atcwdt200.yaml b/dts/bindings/watchdog/andestech,atcwdt200.yaml new file mode 100644 index 000000000000..07d260dda2f3 --- /dev/null +++ b/dts/bindings/watchdog/andestech,atcwdt200.yaml @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023, Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Andes Watchdog driver + +compatible: "andestech,atcwdt200" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index fc4dab3cfffd..ad4900eb5c4d 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Andes Technology Corporation + * Copyright (c) 2023 Andes Technology Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -326,6 +326,14 @@ status = "disabled"; }; + wdt: wdt@f0500000 { + compatible = "andestech,atcwdt200"; + reg = <0xf0500000 0x1000>; + interrupts = <20 1>; + interrupt-parent = <&plic0>; + status = "disabled"; + }; + smc0: smc@e0400000 { compatible = "andestech,atfsmc020"; reg = <0xe0400000 0x1000>; From 5876cc53d45201b0f7f185ae9f16c1e992422166 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 15 Jun 2023 16:05:06 +0800 Subject: [PATCH 0708/2042] tests: drivers: watchdog: wdt_basic_api: 1. Add atcwdt200 options for WDT_NODE in testcase. 2. Add the board overlay file in wdt sample to specify the watchdog0 alias Signed-off-by: Kevin Wang --- .../drivers/watchdog/boards/adp_xc7k_ae350.overlay | 11 +++++++++++ tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 samples/drivers/watchdog/boards/adp_xc7k_ae350.overlay diff --git a/samples/drivers/watchdog/boards/adp_xc7k_ae350.overlay b/samples/drivers/watchdog/boards/adp_xc7k_ae350.overlay new file mode 100644 index 000000000000..07950998629f --- /dev/null +++ b/samples/drivers/watchdog/boards/adp_xc7k_ae350.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &wdt; + }; +}; diff --git a/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c b/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c index 43bb751277f6..76199a27d635 100644 --- a/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c +++ b/tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c @@ -98,6 +98,10 @@ #define WDT_NODE DT_INST(0, gd_gd32_fwdgt) #elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_counter_watchdog) #define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_counter_watchdog) +#elif DT_HAS_COMPAT_STATUS_OKAY(andestech_atcwdt200) +#define WDT_NODE DT_INST(0, andestech_atcwdt200) +#define TIMEOUTS 0 +#define WDT_TEST_MAX_WINDOW 200U #endif #if DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_watchdog) #define WDT_TEST_MAX_WINDOW 20000U From 6da521c9b6150550c9d1db9bd6e66208ecc9ecdb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 11 Jun 2023 06:43:21 +0530 Subject: [PATCH 0709/2042] Bluetooth: Controller: Fix offset_min_us be >= PDU_CIS_OFFSET_MIN_US Fix calculation that ensured cis_offset_min_us being >= PDU_CIS_OFFSET_MIN_US. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index 11a217d662fc..6dc29b9216fe 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -913,7 +913,7 @@ static void mfy_cig_offset_get(void *param) conn = ll_conn_get(cis->lll.acl_handle); conn_interval_us = (uint32_t)conn->lll.interval * CONN_INT_UNIT_US; - while (offset_min_us > (conn_interval_us + PDU_CIS_OFFSET_MIN_US)) { + while (offset_min_us >= (conn_interval_us + PDU_CIS_OFFSET_MIN_US)) { offset_min_us -= conn_interval_us; } @@ -1044,7 +1044,7 @@ static void mfy_cis_offset_get(void *param) /* Compensate for the difference between ACL elapsed vs CIG elapsed */ offset_min_us += elapsed_cig_us - elapsed_acl_us; - while (offset_min_us > (cig_interval_us + PDU_CIS_OFFSET_MIN_US)) { + while (offset_min_us >= (cig_interval_us + PDU_CIS_OFFSET_MIN_US)) { offset_min_us -= cig_interval_us; } From 019f88ec2162ce64fcdef54f47daa2506e9b0ba3 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sun, 11 Jun 2023 06:45:04 +0530 Subject: [PATCH 0710/2042] Bluetooth: Controller: Fix CIS failed to be established Fix CIS create implementation to consider CIG events with laziness before the new CIS in an already active CIG is made active. Previous laziness value of the CIG events is determined and at the CIG event where the new CIS event_count is calculated the lazy_active value determined is decremented from the total lazy value. Without this fix, event_count of the new active CIS events where incorrect, causing CIS create resulting in fail to be established. Signed-off-by: Vinayak Kariappa Chettimada --- .../bluetooth/controller/ll_sw/lll_conn_iso.h | 9 ++ .../bluetooth/controller/ll_sw/ull_conn_iso.c | 135 ++++++++++++++++-- 2 files changed, 135 insertions(+), 9 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h index 5a8702d012c4..dadaa37ac3a5 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn_iso.h @@ -46,6 +46,15 @@ struct lll_conn_iso_stream { uint8_t active:1; /* 1 if CIS LLL is active */ uint8_t datapath_ready_rx:1;/* 1 if datapath for RX is ready */ +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + /* Lazy at CIS active. Number of previously skipped CIG events that is + * determined when CIS is made active and subtracted from total CIG + * events that where skipped when this CIS gets to use radio for the + * first time. + */ + uint16_t lazy_active; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* Resumption information */ uint8_t next_subevent; /* Next subevent to schedule */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c index d405b392b2cb..570f1e3000f8 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_iso.c @@ -65,6 +65,12 @@ static int init_reset(void); +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) +static void cis_lazy_fill(struct ll_conn_iso_stream *cis); +static void mfy_cis_lazy_fill(void *param); +static void ticker_next_slot_get_op_cb(uint32_t status, void *param); +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ +static void ticker_start_op_cb(uint32_t status, void *param); static void ticker_update_cig_op_cb(uint32_t status, void *param); static void ticker_resume_op_cb(uint32_t status, void *param); static void ticker_resume_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, @@ -686,6 +692,11 @@ void ull_conn_iso_ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift, if (cis->lll.handle != 0xFFFF && cis->lll.active) { cis->lll.event_count += (lazy + 1U); +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + cis->lll.event_count -= cis->lll.lazy_active; + cis->lll.lazy_active = 0U; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + leading_event_count = MAX(leading_event_count, cis->lll.event_count); @@ -760,13 +771,6 @@ 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 void ticker_op_cb(uint32_t status, void *param) -{ - ARG_UNUSED(param); - - LL_ASSERT(status == TICKER_STATUS_SUCCESS); -} - 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) @@ -790,7 +794,6 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, cis->lll.offset = cis_offs_to_cig_ref; cis->lll.handle = cis_handle; - cis->lll.active = 1U; #if defined(CONFIG_BT_CTLR_LE_ENC) if (conn->lll.enc_tx) { @@ -844,6 +847,13 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, * validated handle. */ if (cig->state == CIG_STATE_ACTIVE) { +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + cis_lazy_fill(cis); +#else /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* Set CIS active in already active CIG */ + cis->lll.active = 1U; +#endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ + /* We're done */ return; } @@ -994,11 +1004,118 @@ void ull_conn_iso_start(struct ll_conn *conn, uint16_t cis_handle, ticks_periodic, ticks_remainder, TICKER_NULL_LAZY, ticks_slot, ull_conn_iso_ticker_cb, cig, - ticker_op_cb, NULL); + ticker_start_op_cb, NULL); LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) || (ticker_status == TICKER_STATUS_BUSY)); + /* Set CIG and the first CIS state as active */ cig->state = CIG_STATE_ACTIVE; + cis->lll.active = 1U; + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) + /* CIS event lazy at CIS create */ + cis->lll.lazy_active = 0U; +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ +} + +#if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING) +static void cis_lazy_fill(struct ll_conn_iso_stream *cis) +{ + static memq_link_t link; + static struct mayfly mfy = {0U, 0U, &link, NULL, mfy_cis_lazy_fill}; + uint32_t ret; + + mfy.param = cis; + ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1U, &mfy); + LL_ASSERT(!ret); +} + +static void mfy_cis_lazy_fill(void *param) +{ + struct ll_conn_iso_stream *cis; + struct ll_conn_iso_group *cig; + uint32_t ticks_to_expire; + uint32_t ticks_current; + uint32_t remainder; + uint8_t ticker_id; + uint16_t lazy; + uint8_t retry; + uint8_t id; + + cis = param; + cig = cis->group; + ticker_id = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig); + + id = TICKER_NULL; + ticks_to_expire = 0U; + ticks_current = 0U; + + /* In the first iteration the actual ticks_current value is returned + * which will be different from the initial value of 0 that is set. + * Subsequent iterations should return the same ticks_current as the + * reference tick. + * In order to avoid infinite updates to ticker's reference due to any + * race condition due to expiring tickers, we try upto 3 more times. + * Hence, first iteration to get an actual ticks_current and 3 more as + * retries when there could be race conditions that changes the value + * of ticks_current. + * + * ticker_next_slot_get_ext() restarts iterating when updated value of + * ticks_current is returned. + */ + retry = 4U; + do { + uint32_t volatile ret_cb; + uint32_t ticks_previous; + uint32_t ret; + bool success; + + ticks_previous = ticks_current; + + ret_cb = TICKER_STATUS_BUSY; + ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_LOW, &id, + &ticks_current, &ticks_to_expire, &remainder, &lazy, + NULL, NULL, ticker_next_slot_get_op_cb, + (void *)&ret_cb); + if (ret == TICKER_STATUS_BUSY) { + /* Busy wait until Ticker Job is enabled after any Radio + * event is done using the Radio hardware. Ticker Job + * ISR is disabled during Radio events in LOW_LAT + * feature to avoid Radio ISR latencies. + */ + while (ret_cb == TICKER_STATUS_BUSY) { + ticker_job_sched(TICKER_INSTANCE_ID_CTLR, + TICKER_USER_ID_ULL_LOW); + } + } + + success = (ret_cb == TICKER_STATUS_SUCCESS); + LL_ASSERT(success); + + LL_ASSERT((ticks_current == ticks_previous) || retry--); + + LL_ASSERT(id != TICKER_NULL); + } while (id != ticker_id); + + /* Set CIS active in already active CIG and any previous laziness in + * CIG before the CIS gets active that be decremented when event_count + * is incremented in ull_conn_iso_ticker_cb(). + */ + cis->lll.active = 1U; + cis->lll.lazy_active = lazy; +} + +static void ticker_next_slot_get_op_cb(uint32_t status, void *param) +{ + *((uint32_t volatile *)param) = status; +} +#endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */ + +static void ticker_start_op_cb(uint32_t status, void *param) +{ + ARG_UNUSED(param); + + LL_ASSERT(status == TICKER_STATUS_SUCCESS); } static void ticker_update_cig_op_cb(uint32_t status, void *param) From cfcbe5d68ed38ac8ac622c4da5a438b9112f8bc6 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 5 Jun 2023 21:34:07 +0530 Subject: [PATCH 0711/2042] Bluetooth: Controller: Remove redudant header file includes Remove redundant header file includes, introduce radio used resources header file. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hal/cntr.h | 1 - subsys/bluetooth/controller/hal/debug.h | 2 +- subsys/bluetooth/controller/ll_sw/lll_chan.c | 1 + .../controller/ll_sw/nordic/hal/nrf5/cntr.c | 2 - .../controller/ll_sw/nordic/hal/nrf5/ecb.c | 2 - .../nrf5/nrfx_glue/bt_ctlr_used_resources.h | 2 + .../ll_sw/nordic/hal/nrf5/radio/radio.c | 2 +- .../ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h | 61 ++++---- .../ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h | 5 - .../nordic/hal/nrf5/radio/radio_nrf52805.h | 13 -- .../nordic/hal/nrf5/radio/radio_nrf52810.h | 12 -- .../nordic/hal/nrf5/radio/radio_nrf52811.h | 51 ------- .../nordic/hal/nrf5/radio/radio_nrf52820.h | 51 ------- .../nordic/hal/nrf5/radio/radio_nrf52832.h | 12 -- .../nordic/hal/nrf5/radio/radio_nrf52833.h | 51 ------- .../nordic/hal/nrf5/radio/radio_nrf52840.h | 21 +-- .../nordic/hal/nrf5/radio/radio_nrf5340.h | 50 ------- .../nordic/hal/nrf5/radio/radio_nrf5_dppi.h | 13 -- .../nordic/hal/nrf5/radio/radio_nrf5_ppi.h | 6 - .../hal/nrf5/radio/radio_nrf5_ppi_resources.h | 2 - .../hal/nrf5/radio/radio_nrf5_resources.h | 130 ++++++++++++++++++ .../nordic/hal/nrf5/radio/radio_sim_nrfxx.h | 12 -- .../controller/ll_sw/nordic/hal/nrf5/ticker.c | 3 +- .../ll_sw/nordic/hal/radio_vendor_hal.h | 2 - .../ll_sw/openisa/hal/RV32M1/cntr.c | 8 +- .../controller/ll_sw/openisa/hal/RV32M1/ecb.c | 5 +- .../ll_sw/openisa/hal/RV32M1/radio/radio.c | 1 - .../ll_sw/openisa/hal/RV32M1/ticker.c | 2 +- 28 files changed, 170 insertions(+), 353 deletions(-) create mode 100644 subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h diff --git a/subsys/bluetooth/controller/hal/cntr.h b/subsys/bluetooth/controller/hal/cntr.h index 39862c1a6060..6b4303e6c064 100644 --- a/subsys/bluetooth/controller/hal/cntr.h +++ b/subsys/bluetooth/controller/hal/cntr.h @@ -4,7 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include void cntr_init(void); uint32_t cntr_start(void); diff --git a/subsys/bluetooth/controller/hal/debug.h b/subsys/bluetooth/controller/hal/debug.h index ba776c480c74..0dd6fa32f445 100644 --- a/subsys/bluetooth/controller/hal/debug.h +++ b/subsys/bluetooth/controller/hal/debug.h @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ - #include "common/assert.h" +#include "common/assert.h" #ifdef CONFIG_BT_CTLR_ASSERT_HANDLER void bt_ctlr_assert_handle(char *file, uint32_t line); diff --git a/subsys/bluetooth/controller/ll_sw/lll_chan.c b/subsys/bluetooth/controller/ll_sw/lll_chan.c index 3d66bbb54294..213fce38a8f5 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_chan.c +++ b/subsys/bluetooth/controller/ll_sw/lll_chan.c @@ -5,6 +5,7 @@ */ #include +#include #include "hal/ccm.h" #include "hal/radio.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c index c566a86c3ab8..01adf92467d7 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/cntr.c @@ -5,8 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include #include "hal/cntr.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c index 82d12aebcdee..fe3618bf340e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ecb.c @@ -7,8 +7,6 @@ #include -#include - #include #include "util/mem.h" 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 c621d01e5d90..a84e14cb9fba 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 @@ -3,6 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "../radio/radio_nrf5_resources.h" #include "../radio/radio_nrf5_fem.h" #ifdef DPPI_PRESENT diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c index dd2c5aaacb2c..fb46b8ab180f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c @@ -5,13 +5,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include #include #include #include +#include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h index 88a0f048d4ff..a03e55f519df 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5.h @@ -5,38 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define HAL_RADIO_NS2US_CEIL(ns) ((ns + 999)/1000) -#define HAL_RADIO_NS2US_ROUND(ns) ((ns + 500)/1000) - -/* Use the timer instance ID, not NRF_TIMERx directly, so that it can be checked - * in radio_nrf5_ppi.h by the preprocessor. - */ -#define EVENT_TIMER_ID 0 -#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - */ -#define NRF_RADIO_TXRX_END_EVENT EVENTS_END -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. - * This is a default shortcut used to automatically disable Radio after end of PDU. - */ -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk +#include -/* Delay of EVENTS_PHYEND event on receive PDU without CTE inclded when CTEINLINE is enabled */ -#define RADIO_EVENTS_PHYEND_DELAY_US 16 +/* Common radio resources */ +#include "radio_nrf5_resources.h" -/* Delay of CCM TASKS_CRYPT start in number of bits for Radio Bit counter */ -#define CCM_TASKS_CRYPT_DELAY_BITS 3 - -/* EVENTS_TIMER capture register used for sampling TIMER time-stamps. */ -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 - -/* Define to reset PPI registration */ -#define NRF_PPI_NONE 0 +/* Helpers for radio timing conversions */ +#define HAL_RADIO_NS2US_CEIL(ns) ((ns + 999)/1000) +#define HAL_RADIO_NS2US_ROUND(ns) ((ns + 500)/1000) +/* SoC specific defines */ #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX) #include "radio_sim_nrfxx.h" #elif defined(CONFIG_SOC_SERIES_NRF51X) @@ -54,7 +32,6 @@ #elif defined(CONFIG_SOC_NRF52833) #include "radio_nrf52833.h" #elif defined(CONFIG_SOC_NRF52840) -#include #include "radio_nrf52840.h" #elif defined(CONFIG_SOC_NRF5340_CPUNET) #include @@ -63,20 +40,23 @@ #error "Unsupported SoC." #endif -#if defined(CONFIG_SOC_SERIES_NRF51X) -#define HAL_RADIO_PDU_LEN_MAX (BIT(5) - 1) -#else -#define HAL_RADIO_PDU_LEN_MAX (BIT(8) - 1) -#endif - -#include +/* Define to reset PPI registration */ +#define NRF_PPI_NONE 0 /* This has to come before the ppi/dppi includes below. */ #include "radio_nrf5_fem.h" #if defined(PPI_PRESENT) +#include +#include "radio_nrf5_ppi_resources.h" #include "radio_nrf5_ppi.h" #elif defined(DPPI_PRESENT) +#include +#include +#include +#include +#include +#include "radio_nrf5_dppi_resources.h" #include "radio_nrf5_dppi.h" #else #error "PPI or DPPI abstractions missing." @@ -84,6 +64,13 @@ #include "radio_nrf5_txp.h" +/* SoC specific Radio PDU length field maximum value */ +#if defined(CONFIG_SOC_SERIES_NRF51X) +#define HAL_RADIO_PDU_LEN_MAX (BIT(5) - 1) +#else +#define HAL_RADIO_PDU_LEN_MAX (BIT(8) - 1) +#endif + /* Common NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h index c73ed742b6d5..c1e27087150a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf51.h @@ -5,11 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* TXEN->TXIDLE + TXIDLE->TX in microseconds. */ #define HAL_RADIO_NRF51_TXEN_TXIDLE_TX_US 140 #define HAL_RADIO_NRF51_TXEN_TXIDLE_TX_NS 140000 diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h index 77999d430288..93d2215e9542 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52805.h @@ -179,19 +179,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ - -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h index f4d82fae7f74..9e03963ae6c6 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52810.h @@ -181,18 +181,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* nRF52810 itself is not affected with these anomalies but it might be diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h index c09910b6cba2..1247f6e69c08 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52811.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extensio at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h index 667570bc4c43..33ba6fa16541 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52820.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extensio at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h index 0a5f00a0b26c..a5df5fe1ccea 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52832.h @@ -182,18 +182,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h index d613382e236d..18b53976d97d 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52833.h @@ -336,57 +336,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in - * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Use NRF_TIMER3 for PHYEND delay compensation because it has 6 channels available. - * In other cases NRF_TIMER1 with its 4 channels is enough. - */ -#define SW_SWITCH_TIMER NRF_TIMER3 -/* Allocate 2 adjacent channels for PHYEND delay compensation. Channels 4 and 5 will be used for it. - * It must be two channels because Radio TX/RX mode SW SWITCH uses two channels. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 4 -#else /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* SoC specific NRF_RADIO power-on reset value. Refer to Product Specification, * RADIO Registers section for the documented reset values. * diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h index a169987437e2..98fe83ebea79 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf52840.h @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + /* NRF Radio HW timing constants * - provided in US and NS (for higher granularity) * - based on empirical measurements and sniffer logs @@ -337,25 +339,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h index 9e9015dc8c8e..e0f430145082 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5340.h @@ -337,56 +337,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 0 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 -#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 -#undef HAL_EVENT_TIMER_SAMPLE_TASK -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 - -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - * - * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU - * including CTE EVENTS_PHYEND event is generated at very end of a PDU, after CTE is received or - * transmitted. In case there is no CTE in a PDU the EVENTS_PHYEND event is generated in the same - * instant as EVENTS_END event. - */ -#undef NRF_RADIO_TXRX_END_EVENT -#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND - -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. - * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. - * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. - * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. - * If there is no CTE, it is generated in the same instant as EVENTS_END. - */ -#undef NRF_RADIO_SHORTS_PDU_END_DISABLE -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk - -#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) -/* Allocate 2 adjacent channels for PHYEND delay compensation. Use the same channels as for - * PHY CODED S2. The CTEINLINE may not be enabled for PHY CODED so PHYEND event is generated - * at the same instant as END event. Hence the channels are uesed interchangeably. - * That saves from use of another timer. - */ -#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 2 -#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ - -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - /* nRF5340 supports +3dBm Tx Power using high voltage request, define +3dBm * value for Controller use. */ 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 2e6505af006d..085b881d47ee 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 @@ -4,17 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_SOC_NRF5340_CPUNET) || defined(DPPI_PRESENT) - -#include -#include -#include -#include -#include -#include -#include - -#include "radio_nrf5_dppi_resources.h" static inline void hal_radio_nrf_ppi_channels_enable(uint32_t mask) { @@ -765,5 +754,3 @@ hal_radio_sw_switch_phyend_delay_compensation_config_clear(uint8_t radio_enable_ #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ - -#endif /* CONFIG_SOC_NRF5340_CPUNET || DPPI_PRESENT */ 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 be2be5e86ef2..866769c95eb7 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 @@ -4,11 +4,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_COMPATIBLE_NRF52X) - -#include - -#include "radio_nrf5_ppi_resources.h" static inline void hal_radio_nrf_ppi_channels_enable(uint32_t mask) { @@ -726,4 +721,3 @@ static inline void hal_radio_sw_switch_ppi_group_setup(void) } #endif /* !CONFIG_BT_CTLR_TIFS_HW */ -#endif /* CONFIG_SOC_SERIES_NRF51X || CONFIG_SOC_COMPATIBLE_NRF52X */ 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 f8c71788634f..163d3e915eaf 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 @@ -3,8 +3,6 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include "radio_nrf5_fem.h" #if defined(CONFIG_BT_CTLR_TIFS_HW) || !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h new file mode 100644 index 000000000000..f3fba24873db --- /dev/null +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Use the timer instance ID, not NRF_TIMERx directly, so that it can be checked + * in radio_nrf5_ppi.h by the preprocessor. + */ +#if !defined(CONFIG_BT_CTLR_TIFS_HW) + +#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#define EVENT_TIMER_ID 4 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +#define SW_SWITCH_TIMER EVENT_TIMER + +#if defined(CONFIG_BT_CTLR_PHY_CODED) +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3 +#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5 + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE2 + +#else /* !CONFIG_BT_CTLR_PHY_CODED */ +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 +#endif /* !CONFIG_BT_CTLR_PHY_CODED */ + +#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#define EVENT_TIMER_ID 0 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +#define SW_SWITCH_TIMER NRF_TIMER1 +#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 + +#if defined(CONFIG_BT_CTLR_PHY_CODED) +#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2 +#endif /* !CONFIG_BT_CTLR_PHY_CODED */ + +#if defined(CONFIG_BT_CTLR_DF) + +#if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE) +/* Allocate 2 adjacent channels for PHYEND delay compensation. Use the same channels as for + * PHY CODED S2. The CTEINLINE may not be enabled for PHY CODED so PHYEND event is generated + * at the same instant as END event. Hence the channels are uesed interchangeably. + * That saves from use of another timer. + */ +#define SW_SWITCH_TIMER_EVTS_COMP_PHYEND_DELAY_COMPENSATION_BASE 2 +#endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */ + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + * + * When direction finding is enabled a PDU may include Constant Tone Extension at its end. For PDU + * including CTE EVENTS_PHYEND event is generated at very end of a PDU. In case there is no CTE in + * a PDU the EVENTS_PHYEND event is generated in the same instant as EVENTS_END event. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_PHYEND + +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_PHYEND to EVENTS_DISABLE. + * This is a mask for SOC that has Direction Finding Extension in a Radio peripheral. + * It enables shortcut for EVENTS_PHYEND event generated at very end to Radio EVENTS_DISABLE event. + * In case there is a CTE in a PDU then EVENTS_PHYEND event is generated after the CTE. + * If there is no CTE, it is generated in the same instant as EVENTS_END. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_PHYEND_DISABLE_Msk + +/* Delay of EVENTS_PHYEND event on receive PDU without CTE inclded when CTEINLINE is enabled */ +#define RADIO_EVENTS_PHYEND_DELAY_US 16 + +/* Delay of CCM TASKS_CRYPT start in number of bits for Radio Bit counter */ +#define CCM_TASKS_CRYPT_DELAY_BITS 3 + +#else /* !CONFIG_BT_CTLR_DF */ +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk +#endif /* !CONFIG_BT_CTLR_DF */ + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 +#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ + +#else /* !CONFIG_BT_CTLR_TIFS_HW */ +#define EVENT_TIMER_ID 0 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) + +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 +#endif /* !CONFIG_BT_CTLR_TIFS_HW */ diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h index 643e03555459..a767fe1ab30f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_sim_nrfxx.h @@ -183,18 +183,6 @@ #endif /* !CONFIG_BT_CTLR_TIFS_HW */ #endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) -#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) -#undef EVENT_TIMER_ID -#define EVENT_TIMER_ID 4 -#define SW_SWITCH_TIMER EVENT_TIMER -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#define SW_SWITCH_TIMER NRF_TIMER1 -#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0 -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ -#endif /* !CONFIG_BT_CTLR_TIFS_HW */ - static inline void hal_radio_reset(void) { /* TODO: Add any required setup for each radio event diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c index ae9dd686133d..482e48b198b6 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/ticker.c @@ -5,8 +5,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include -#include + #include #include "hal/cntr.h" diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h index a3324ce44e34..972638298f7c 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/radio_vendor_hal.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - #include "hal/nrf5/radio/radio.h" #include "hal/nrf5/radio/radio_nrf5.h" #include "hal/nrf5/radio/radio_nrf5_txp.h" 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 edbb1b7d4316..e3e2496b1a4c 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/cntr.c @@ -6,14 +6,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include -#include "hal/cntr.h" +#include +#include "hal/cntr.h" #include "hal/debug.h" -#include -#include "ll_irqs.h" +#include "ll_irqs.h" #define PCS_SOURCE_RTC 2 diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c index da627366143f..2d6f7bb86cb8 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ecb.c @@ -8,11 +8,10 @@ #include -#include - -#include #include +#include + #include "hal/ecb.h" #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c index 0ed3c6f348b6..6107bfc9c68a 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/radio/radio.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c index fea28ce18a96..aaa881fccd01 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/hal/RV32M1/ticker.c @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include -#include #include "hal/cntr.h" From ac8499550d72594124b8a2101144b94a220ba4fe Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 5 Jun 2023 21:41:17 +0530 Subject: [PATCH 0712/2042] Bluetooth: Controller: Fix use of pre-programmed PPI Fix to not use pre-programmed PPI when NRF_TIMER0 is not used as the radio event timer. Signed-off-by: Vinayak Kariappa Chettimada --- .../hal/nrf5/radio/radio_nrf5_ppi_resources.h | 12 +++---- .../hal/nrf5/radio/radio_nrf5_resources.h | 35 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) 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 163d3e915eaf..5c5093f4b521 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 @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if defined(CONFIG_BT_CTLR_TIFS_HW) || !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#if (EVENT_TIMER_ID == 0) /* PPI channel 20 is pre-programmed with the following fixed settings: * EEP: TIMER0->EVENTS_COMPARE[0] @@ -35,7 +35,7 @@ */ #define HAL_RADIO_END_TIME_CAPTURE_PPI 27 -#else /* CONFIG_BT_CTLR_TIFS_HW || !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#else /* EVENT_TIMER_ID != 0 */ #define HAL_RADIO_ENABLE_TX_ON_TICK_PPI 2 #define HAL_RADIO_ENABLE_RX_ON_TICK_PPI 2 @@ -43,7 +43,7 @@ #define HAL_RADIO_DISABLE_ON_HCTO_PPI 4 #define HAL_RADIO_END_TIME_CAPTURE_PPI 5 -#endif /* CONFIG_BT_CTLR_TIFS_HW || !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#endif /* EVENT_TIMER_ID != 0 */ /* Start event timer on RTC tick wire the RTC0 EVENTS_COMPARE[2] event to * EVENT_TIMER TASKS_START task. @@ -89,7 +89,7 @@ #if !defined(CONFIG_BT_CTLR_TIFS_HW) /* PPI setup used for SW-based auto-switching during TIFS. */ -#if !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) +#if (EVENT_TIMER_ID == 0) /* Clear SW-switch timer on packet end: * wire the RADIO EVENTS_END event to SW_SWITCH_TIMER TASKS_CLEAR task. @@ -98,7 +98,7 @@ */ #define HAL_SW_SWITCH_TIMER_CLEAR_PPI 8 -#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#else /* EVENT_TIMER_ID != 0 */ /* Clear event timer (sw-switch timer) on Radio end: * wire the RADIO EVENTS_END event to the @@ -109,7 +109,7 @@ */ #define HAL_SW_SWITCH_TIMER_CLEAR_PPI HAL_RADIO_END_TIME_CAPTURE_PPI -#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ +#endif /* EVENT_TIMER_ID != 0 */ /* Wire a SW SWITCH TIMER EVENTS_COMPARE[] event * to a PPI GROUP TASK DISABLE task (PPI group with index ). diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h index f3fba24873db..87acc1896ee1 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h @@ -7,8 +7,24 @@ /* Use the timer instance ID, not NRF_TIMERx directly, so that it can be checked * in radio_nrf5_ppi.h by the preprocessor. */ -#if !defined(CONFIG_BT_CTLR_TIFS_HW) +#if defined(CONFIG_BT_CTLR_TIFS_HW) +#define EVENT_TIMER_ID 0 +#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) +/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission + * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is + * received or transmitted. + */ +#define NRF_RADIO_TXRX_END_EVENT EVENTS_END +/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. + * This is a default shortcut used to automatically disable Radio after end of PDU. + */ +#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk + +#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 +#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 + +#else /* !CONFIG_BT_CTLR_TIFS_HW */ #if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER) #define EVENT_TIMER_ID 4 #define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) @@ -110,21 +126,4 @@ #define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 #define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 #endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */ - -#else /* !CONFIG_BT_CTLR_TIFS_HW */ -#define EVENT_TIMER_ID 0 -#define EVENT_TIMER _CONCAT(NRF_TIMER, EVENT_TIMER_ID) - -/* Wrapper for EVENTS_END event generated by Radio peripheral at the very end of the transmission - * or reception of a PDU on air. In case of regular PDU it is generated when last bit of CRC is - * received or transmitted. - */ -#define NRF_RADIO_TXRX_END_EVENT EVENTS_END -/* Wrapper for RADIO_SHORTS mask connecting EVENTS_END to EVENTS_DISABLE. - * This is a default shortcut used to automatically disable Radio after end of PDU. - */ -#define NRF_RADIO_SHORTS_PDU_END_DISABLE RADIO_SHORTS_END_DISABLE_Msk - -#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 3 -#define HAL_EVENT_TIMER_SAMPLE_TASK NRF_TIMER_TASK_CAPTURE3 #endif /* !CONFIG_BT_CTLR_TIFS_HW */ From 3c341639085bccdf5245264d2b9a63d70d3aada2 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 4 Feb 2023 10:19:19 +0530 Subject: [PATCH 0713/2042] Bluetooth: Controller: Add -ECANCELED on return from lll_preempt_calc Add -ECANCELED on return from lll_preempt_calc so that assert check can be placed in the prepare callbacks of the state/role implementations. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c | 2 ++ subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c | 2 ++ 7 files changed, 14 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index f8f3c8fa1f4a..463fb312f017 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -1040,6 +1040,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 620370f8e74b..7c537c1f2cbf 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -322,6 +322,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(lll_isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 349836e23524..92a03c6716c2 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -243,6 +243,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(lll_isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index 9af7d7b95b2a..f8064b4de719 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -245,6 +245,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(lll_isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index 977fd15a8c35..d9bc9b995616 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -327,6 +327,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(lll_isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { 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 8401e94fcbf8..771d23b59f04 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -481,6 +481,8 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) ticks_at_event)) { radio_isr_set(isr_abort, lll); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED && * (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) 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 26d8c3b84789..6a4b0dbcf2e9 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 @@ -565,6 +565,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event)) { radio_isr_set(isr_done, lll_aux); radio_disable(); + + return -ECANCELED; } else #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ { From ae679bc9ff37dba1703b3d3d4db89b7831524cbf Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 13 Feb 2023 16:11:57 +0530 Subject: [PATCH 0714/2042] Bluetooth: Controller: Move EVENT_OVERHEAD_START_US verbose assertion Move the EVENT_OVERHEAD_START_US verbose assertion to each state/role LLL implementation so that correct state/role that is delayed is conveyed in the assertion message. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll.c | 5 +- .../controller/ll_sw/nordic/lll/lll_adv.c | 42 +++++----- .../controller/ll_sw/nordic/lll/lll_adv_aux.c | 32 ++++---- .../controller/ll_sw/nordic/lll/lll_adv_iso.c | 18 ++-- .../ll_sw/nordic/lll/lll_adv_sync.c | 26 +++--- .../controller/ll_sw/nordic/lll/lll_central.c | 20 +++-- .../ll_sw/nordic/lll/lll_central_iso.c | 15 ++-- .../ll_sw/nordic/lll/lll_peripheral.c | 18 ++-- .../ll_sw/nordic/lll/lll_peripheral_iso.c | 15 ++-- .../controller/ll_sw/nordic/lll/lll_scan.c | 82 +++++++++---------- .../ll_sw/nordic/lll/lll_scan_aux.c | 56 ++++++------- .../controller/ll_sw/nordic/lll/lll_sync.c | 20 +++-- .../ll_sw/nordic/lll/lll_sync_iso.c | 20 +++-- 13 files changed, 188 insertions(+), 181 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index 0c9dceec3e05..cfd13e87148b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -470,10 +470,7 @@ uint32_t lll_preempt_calc(struct ull_hdr *ull, uint8_t ticker_id, * duration. * 3. Increase the preempt to start ticks for future events. */ - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(diff)); - - return 1U; + return diff; } return 0U; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 463fb312f017..44c59b0ea2cf 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -936,6 +936,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct lll_adv *lll; uint32_t remainder; uint32_t start_us; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_A(1); @@ -1034,36 +1035,37 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_BASE + ull_adv_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_BASE + - ull_adv_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(isr_abort, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) - if (lll->aux) { - /* fill in aux ptr in pdu */ - ull_adv_aux_lll_auxptr_fill(pdu, lll); - - /* NOTE: as first primary channel PDU does not use remainder, the packet - * timer is started one tick in advance to start the radio with - * microsecond precision, hence compensate for the higher start_us value - * captured at radio start of the first primary channel PDU. - */ - lll->aux->ticks_pri_pdu_offset += 1U; - } + if (lll->aux) { + /* fill in aux ptr in pdu */ + ull_adv_aux_lll_auxptr_fill(pdu, lll); + + /* NOTE: as first primary channel PDU does not use remainder, the packet + * timer is started one tick in advance to start the radio with + * microsecond precision, hence compensate for the higher start_us value + * captured at radio start of the first primary channel PDU. + */ + lll->aux->ticks_pri_pdu_offset += 1U; + } #endif - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_A(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 7c537c1f2cbf..88811dbbbc98 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -120,6 +120,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint32_t start_us; uint8_t chan_idx; uint8_t phy_s; + uint32_t ret; uint8_t upd; uint32_t aa; @@ -316,30 +317,31 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_AUX_BASE + ull_adv_aux_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_AUX_BASE + - ull_adv_aux_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - - if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC) && - IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) && - sec_pdu->adv_ext_ind.ext_hdr_len && - sec_pdu->adv_ext_ind.ext_hdr.sync_info) { - ull_adv_sync_lll_syncinfo_fill(sec_pdu, lll); - } - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC) && + IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) && + sec_pdu->adv_ext_ind.ext_hdr_len && + sec_pdu->adv_ext_ind.ext_hdr.sync_info) { + ull_adv_sync_lll_syncinfo_fill(sec_pdu, lll); } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); + DEBUG_RADIO_START_A(1); 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 545cbfd2a89b..f99209f5d309 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 @@ -188,6 +188,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t start_us; + uint32_t ret; uint8_t phy; DEBUG_RADIO_START_A(1); @@ -417,23 +418,24 @@ static int prepare_cb_common(struct lll_prepare_param *p) ARG_UNUSED(start_us); #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ - if (0) { #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_ISO_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, (TICKER_ID_ADV_ISO_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } else { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); /* Calculate ahead the next subevent channel index */ next_chan_calc(lll, event_counter, data_chan_id); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index 92a03c6716c2..e65b7327e76e 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -120,6 +120,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint32_t remainder; uint32_t start_us; uint8_t phy_s; + uint32_t ret; uint8_t upd; DEBUG_RADIO_START_A(1); @@ -237,28 +238,29 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_SYNC_BASE + + ull_adv_sync_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_ADV_SYNC_BASE + - ull_adv_sync_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; #if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO) - if (lll->iso) { - ull_adv_iso_lll_biginfo_fill(pdu, lll); - } + if (lll->iso) { + ull_adv_iso_lll_biginfo_fill(pdu, lll); + } #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */ - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_A(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index f8064b4de719..0ff4eb7a88db 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -101,6 +101,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint8_t cte_len; + uint32_t ret; DEBUG_RADIO_START_M(1); @@ -240,21 +241,22 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_M(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index 56dc226a07ec..e3a5e848bfd8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -375,21 +375,22 @@ static int prepare_cb(struct lll_prepare_param *p) ARG_UNUSED(start_us); #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */ - if (false) { - #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), + ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, - (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, cig_lll); radio_disable(); return -ECANCELED; -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ /* Adjust the SN and NESN for skipped CIG events */ cis_handle = cis_handle_curr; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index d9bc9b995616..d90ef2162fde 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -113,6 +113,7 @@ static int prepare_cb(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; DEBUG_RADIO_START_S(1); @@ -322,21 +323,22 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_S(1); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index 11eba66c0dc1..d410ee84fe0b 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -350,21 +350,22 @@ static int prepare_cb(struct lll_prepare_param *p) #endif /* !CONFIG_BT_CTLR_PHY */ #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */ - if (false) { - #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), + ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, - (TICKER_ID_CONN_ISO_BASE + cig_lll->handle), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, cig_lll); radio_disable(); return -ECANCELED; -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } +#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ /* Adjust the SN and NESN for skipped CIG events */ uint16_t cis_handle = cis_handle_curr; 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 771d23b59f04..57021cce6f94 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -343,6 +343,7 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) struct lll_scan *lll; struct ull_hdr *ull; uint32_t remainder; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_O(1); @@ -475,60 +476,51 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_BASE + ull_scan_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_BASE + - ull_scan_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(isr_abort, lll); radio_disable(); return -ECANCELED; - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED && - * (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) - */ - { - uint32_t ret; - - if (!is_resume && lll->ticks_window) { - /* start window close timeout */ - ret = ticker_start(TICKER_INSTANCE_ID_CTLR, - TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, - ticks_at_event, lll->ticks_window, - TICKER_NULL_PERIOD, - TICKER_NULL_REMAINDER, - TICKER_NULL_LAZY, TICKER_NULL_SLOT, - ticker_stop_cb, lll, - ticker_op_start_cb, - (void *)__LINE__); - LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || - (ret == TICKER_STATUS_BUSY)); - } + } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ + + if (!is_resume && lll->ticks_window) { + /* start window close timeout */ + ret = ticker_start(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, TICKER_ID_SCAN_STOP, + ticks_at_event, lll->ticks_window, TICKER_NULL_PERIOD, + TICKER_NULL_REMAINDER, TICKER_NULL_LAZY, TICKER_NULL_SLOT, + ticker_stop_cb, lll, ticker_op_start_cb, (void *)__LINE__); + LL_ASSERT((ret == TICKER_STATUS_SUCCESS) || + (ret == TICKER_STATUS_BUSY)); + } #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - /* calc next group in us for the anchor where first connection - * event to be placed. - */ - if (lll->conn) { - static memq_link_t link; - static struct mayfly mfy_after_cen_offset_get = { - 0, 0, &link, NULL, - ull_sched_mfy_after_cen_offset_get}; - uint32_t retval; - - mfy_after_cen_offset_get.param = p; - - retval = mayfly_enqueue(TICKER_USER_ID_LLL, - TICKER_USER_ID_ULL_LOW, 1, - &mfy_after_cen_offset_get); - LL_ASSERT(!retval); - } -#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + /* calc next group in us for the anchor where first connection + * event to be placed. + */ + if (lll->conn) { + static memq_link_t link; + static struct mayfly mfy_after_cen_offset_get = { + 0U, 0U, &link, NULL, ull_sched_mfy_after_cen_offset_get}; + uint32_t retval; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); + mfy_after_cen_offset_get.param = p; + + retval = mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_LOW, 1U, + &mfy_after_cen_offset_get); + LL_ASSERT(!retval); } +#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); 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 6a4b0dbcf2e9..64b64e34c41f 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 @@ -427,6 +427,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint8_t is_lll_scan; uint32_t remainder; uint32_t hcto; + uint32_t ret; uint32_t aa; DEBUG_RADIO_START_O(1); @@ -559,45 +560,44 @@ static int prepare_cb(struct lll_prepare_param *p) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE + + ull_scan_aux_lll_handle_get(lll_aux)), ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE + - ull_scan_aux_lll_handle_get(lll_aux)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(isr_done, lll_aux); radio_disable(); return -ECANCELED; - } else -#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; + } +#endif /* !CONFIG_BT_CTLR_XTAL_ADVANCED */ #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - /* calc end of group in us for the anchor where next connection - * event to be placed. - */ - if (lll && lll->conn) { - static memq_link_t link; - static struct mayfly mfy_after_cen_offset_get = { - 0, 0, &link, NULL, - ull_sched_mfy_after_cen_offset_get}; - - /* NOTE: LLL scan instance passed, as done when - * establishing legacy connections. - */ - p->param = lll; - mfy_after_cen_offset_get.param = p; + /* calc end of group in us for the anchor where next connection + * event to be placed. + */ + if (lll && lll->conn) { + static memq_link_t link; + static struct mayfly mfy_after_cen_offset_get = { + 0U, 0U, &link, NULL, ull_sched_mfy_after_cen_offset_get}; - ret = mayfly_enqueue(TICKER_USER_ID_LLL, - TICKER_USER_ID_ULL_LOW, 1, - &mfy_after_cen_offset_get); - LL_ASSERT(!ret); - } -#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + /* NOTE: LLL scan instance passed, as done when + * establishing legacy connections. + */ + p->param = lll; + mfy_after_cen_offset_get.param = p; - ret = lll_prepare_done(lll_aux); + ret = mayfly_enqueue(TICKER_USER_ID_LLL, TICKER_USER_ID_ULL_LOW, 1U, + &mfy_after_cen_offset_get); LL_ASSERT(!ret); } +#endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */ + + ret = lll_prepare_done(lll_aux); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); 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 02173b6b92a5..50f9253e270f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -440,6 +440,7 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; lll = p->param; @@ -507,22 +508,23 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_BASE + ull_sync_lll_handle_get(lll)), + ticks_at_event); /* check if preempt to start has changed */ - if (lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_BASE + - ull_sync_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(isr_done, lll); radio_disable(); return -ECANCELED; - } else + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); DEBUG_RADIO_START_O(1); 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 22d4a6e75211..09d9ee2db1bf 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 @@ -201,6 +201,7 @@ static int prepare_cb_common(struct lll_prepare_param *p) struct ull_hdr *ull; uint32_t remainder; uint32_t hcto; + uint32_t ret; uint8_t phy; DEBUG_RADIO_START_O(1); @@ -368,24 +369,25 @@ static int prepare_cb_common(struct lll_prepare_param *p) HAL_RADIO_GPIO_LNA_OFFSET); #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */ - if (0) { #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \ (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US) + uint32_t overhead; + + overhead = lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_ISO_BASE + + ull_sync_iso_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ - } else if (lll_preempt_calc(ull, (TICKER_ID_SCAN_SYNC_ISO_BASE + - ull_sync_iso_lll_handle_get(lll)), - ticks_at_event)) { + if (overhead) { + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", + __func__, HAL_TICKER_TICKS_TO_US(overhead)); radio_isr_set(lll_isr_abort, lll); radio_disable(); return -ECANCELED; + } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ - } else { - uint32_t ret; - ret = lll_prepare_done(lll); - LL_ASSERT(!ret); - } + ret = lll_prepare_done(lll); + LL_ASSERT(!ret); /* Calculate ahead the next subevent channel index */ next_chan_calc(lll, event_counter, data_chan_id); From 5aae5d2583a0d8f7848166afca45755ce186c173 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 28 Jun 2023 09:57:57 +0530 Subject: [PATCH 0715/2042] Bluetooth: Controller: Fix Connected ISO for aborted prepare Fix Connected ISO implementation to correctly handle SN, NESN and payload_count when prepare callback is aborted due to CPU overhead related latencies. Signed-off-by: Vinayak Kariappa Chettimada --- .../ll_sw/nordic/lll/lll_central_iso.c | 26 +++++++++++++++++-- .../ll_sw/nordic/lll/lll_peripheral_iso.c | 20 ++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index e3a5e848bfd8..d2c5226e1920 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -155,6 +155,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint16_t lazy; uint32_t ret; uint8_t phy; + int err = 0; DEBUG_RADIO_START_M(1); @@ -385,10 +386,11 @@ static int prepare_cb(struct lll_prepare_param *p) if (overhead) { LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", __func__, HAL_TICKER_TICKS_TO_US(overhead)); - radio_isr_set(lll_isr_abort, cig_lll); + + radio_isr_set(isr_done, cis_lll); radio_disable(); - return -ECANCELED; + err = -ECANCELED; } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ @@ -409,10 +411,30 @@ static int prepare_cb(struct lll_prepare_param *p) /* sn and nesn are 1-bit, only Least Significant bit is needed */ cis_lll->sn += cis_lll->tx.bn * cis_lazy; cis_lll->nesn += cis_lll->rx.bn * cis_lazy; + + /* Adjust sn and nesn for canceled events */ + if (err) { + /* Adjust sn when flushing Tx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->tx.bn_curr <= cis_lll->tx.bn) { + lll_flush_tx(cis_lll); + } + + /* Adjust nesn when flushing Rx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); + } + } } } } while (cis_lll); + /* Return if prepare callback cancelled */ + if (err) { + return err; + } + /* Prepare is done */ ret = lll_prepare_done(cig_lll); LL_ASSERT(!ret); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index d410ee84fe0b..e136729147d0 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -173,6 +173,7 @@ static int prepare_cb(struct lll_prepare_param *p) uint16_t lazy; uint32_t ret; uint8_t phy; + int err = 0; DEBUG_RADIO_START_S(1); @@ -360,10 +361,11 @@ static int prepare_cb(struct lll_prepare_param *p) if (overhead) { LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", __func__, HAL_TICKER_TICKS_TO_US(overhead)); - radio_isr_set(lll_isr_abort, cig_lll); + + radio_isr_set(isr_done, cis_lll); radio_disable(); - return -ECANCELED; + err = -ECANCELED; } #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */ @@ -399,9 +401,23 @@ static int prepare_cb(struct lll_prepare_param *p) /* sn and nesn are 1-bit, only Least Significant bit is needed */ cis_lll->sn += cis_lll->tx.bn * lazy; cis_lll->nesn += cis_lll->rx.bn * lazy; + + /* Adjust sn and nesn for canceled events */ + if (err) { + /* Adjust nesn when flushing Rx */ + /* FIXME: When Flush Timeout is implemented */ + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { + lll_flush_rx(cis_lll); + } + } } }; + /* Return if prepare callback cancelled */ + if (err) { + return err; + } + /* Prepare is done */ ret = lll_prepare_done(cig_lll); LL_ASSERT(!ret); From 96c076b9c12dd49647509046b830b4a503bc807f Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 28 Jun 2023 04:57:15 +0530 Subject: [PATCH 0716/2042] Bluetooth: Controller: Add LL_ASSERT_OVERHEAD define Add LL_ASSERT_OVERHEAD define to reuse the assertion check related to increase in actual EVENT_OVERHEAD_START_US value. Introduce Kconfig option to permit radio event be skipped when increased prepare callback latencies are measured, instead of assertion. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/Kconfig.ll_sw_split | 13 +++++++++++++ subsys/bluetooth/controller/hal/debug.h | 8 ++++++++ subsys/bluetooth/controller/ll_sw/lll_common.c | 16 +++++++++------- .../bluetooth/controller/ll_sw/nordic/lll/lll.c | 5 +++++ .../controller/ll_sw/nordic/lll/lll_adv.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_adv_aux.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_adv_iso.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_adv_sync.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_central.c | 4 ++-- .../ll_sw/nordic/lll/lll_central_iso.c | 3 +-- .../controller/ll_sw/nordic/lll/lll_peripheral.c | 4 ++-- .../ll_sw/nordic/lll/lll_peripheral_iso.c | 3 +-- .../controller/ll_sw/nordic/lll/lll_scan.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_scan_aux.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_sync.c | 4 ++-- .../controller/ll_sw/nordic/lll/lll_sync_iso.c | 4 ++-- 16 files changed, 57 insertions(+), 31 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 7a9bf2c2b78f..9dd013c47868 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -458,6 +458,19 @@ config BT_CTLR_SCHED_ADVANCED Disabling this feature will lead to overlapping role in timespace leading to skipped events amongst active roles. +config BT_CTLR_ASSERT_OVERHEAD_START + bool "Assert on Prepare Latency" + default y + help + Assert on increased Radio Event Prepare callback latencies due to + CPU usage overheads in the Controller implementation. + + Disabling this option permits the Controller to gracefully skip radio + events that are delayed due to CPU usage latencies; as long as the + radio event skips are not for every consecutive radio event interval, + otherwise leading to remote supervision timeout and possible missing + local disconnect events. + config BT_CTLR_CENTRAL_SPACING int "Central Connection Spacing" depends on BT_CTLR_SCHED_ADVANCED diff --git a/subsys/bluetooth/controller/hal/debug.h b/subsys/bluetooth/controller/hal/debug.h index 0dd6fa32f445..9f2fc3d0c95c 100644 --- a/subsys/bluetooth/controller/hal/debug.h +++ b/subsys/bluetooth/controller/hal/debug.h @@ -27,4 +27,12 @@ void bt_ctlr_assert_handle(char *file, uint32_t line); BT_ASSERT_MSG(cond, fmt, ##__VA_ARGS__) #endif +#if defined(CONFIG_BT_CTLR_ASSERT_OVERHEAD_START) +#define LL_ASSERT_OVERHEAD(overhead) \ + LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", \ + __func__, HAL_TICKER_TICKS_TO_US(overhead)); +#else /* !CONFIG_BT_CTLR_ASSERT_OVERHEAD_START */ +#define LL_ASSERT_OVERHEAD(overhead) ARG_UNUSED(overhead) +#endif /* !CONFIG_BT_CTLR_ASSERT_OVERHEAD_START */ + #include "hal/debug_vendor_hal.h" diff --git a/subsys/bluetooth/controller/ll_sw/lll_common.c b/subsys/bluetooth/controller/ll_sw/lll_common.c index a91e933b4029..ed35b4ddd083 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_common.c +++ b/subsys/bluetooth/controller/ll_sw/lll_common.c @@ -38,6 +38,8 @@ int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, lll_prepare_cb_t prepare_cb, int8_t event_prio, struct lll_prepare_param *prepare_param) { + int err; + #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) int prio = event_prio; struct lll_hdr *hdr = prepare_param->param; @@ -60,20 +62,20 @@ int lll_prepare(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, prepare_param->prio = prio; #endif /* CONFIG_BT_CTLR_JIT_SCHEDULING */ - return lll_prepare_resolve(is_abort_cb, abort_cb, prepare_cb, - prepare_param, 0, 0); + err = lll_prepare_resolve(is_abort_cb, abort_cb, prepare_cb, prepare_param, 0U, 0U); + + return err; } void lll_resume(void *param) { struct lll_event *next; - int ret; + int err; next = param; - ret = lll_prepare_resolve(next->is_abort_cb, next->abort_cb, - next->prepare_cb, &next->prepare_param, - next->is_resume, 1); - LL_ASSERT(!ret || ret == -EINPROGRESS); + err = lll_prepare_resolve(next->is_abort_cb, next->abort_cb, next->prepare_cb, + &next->prepare_param, next->is_resume, 1U); + LL_ASSERT(!err || err == -EINPROGRESS); } #if defined(CONFIG_BT_CTLR_JIT_SCHEDULING) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c index cfd13e87148b..bc71bbcd5a65 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll.c @@ -755,6 +755,11 @@ int lll_prepare_resolve(lll_is_abort_cb_t is_abort_cb, lll_abort_cb_t abort_cb, err = prepare_cb(prepare_param); + if (!IS_ENABLED(CONFIG_BT_CTLR_ASSERT_OVERHEAD_START) && + (err == -ECANCELED)) { + err = 0; + } + #if !defined(CONFIG_BT_CTLR_LOW_LAT) uint32_t ret; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c index 44c59b0ea2cf..851c82692b81 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv.c @@ -1041,8 +1041,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_abort, lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c index 88811dbbbc98..ca566a04db48 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_aux.c @@ -323,8 +323,8 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); 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 f99209f5d309..a1e543d3963c 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 @@ -425,8 +425,8 @@ static int prepare_cb_common(struct lll_prepare_param *p) overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_ISO_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c index e65b7327e76e..1e56f70493cd 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c @@ -244,8 +244,8 @@ static int prepare_cb(struct lll_prepare_param *p) ull_adv_sync_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c index 0ff4eb7a88db..a73364ef4109 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central.c @@ -246,8 +246,8 @@ static int prepare_cb(struct lll_prepare_param *p) overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index d2c5226e1920..3e5f688172d8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -384,8 +384,7 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); radio_isr_set(isr_done, cis_lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c index d90ef2162fde..14796717885f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral.c @@ -328,8 +328,8 @@ static int prepare_cb(struct lll_prepare_param *p) overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c index e136729147d0..811c1315ffe2 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_peripheral_iso.c @@ -359,8 +359,7 @@ static int prepare_cb(struct lll_prepare_param *p) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); radio_isr_set(isr_done, cis_lll); radio_disable(); 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 57021cce6f94..251b0c3a2a7a 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -482,8 +482,8 @@ static int common_prepare_cb(struct lll_prepare_param *p, bool is_resume) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_abort, lll); radio_disable(); 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 64b64e34c41f..4c9be4fafd49 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 @@ -566,8 +566,8 @@ static int prepare_cb(struct lll_prepare_param *p) ull_scan_aux_lll_handle_get(lll_aux)), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_done, lll_aux); radio_disable(); 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 50f9253e270f..36551b73281f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -514,8 +514,8 @@ static int prepare_cb_common(struct lll_prepare_param *p, uint8_t chan_idx) ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(isr_done, lll); radio_disable(); 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 09d9ee2db1bf..db58ff402f1b 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 @@ -377,8 +377,8 @@ static int prepare_cb_common(struct lll_prepare_param *p) ull_sync_iso_lll_handle_get(lll)), ticks_at_event); /* check if preempt to start has changed */ if (overhead) { - LL_ASSERT_MSG(false, "%s: Actual EVENT_OVERHEAD_START_US = %u", - __func__, HAL_TICKER_TICKS_TO_US(overhead)); + LL_ASSERT_OVERHEAD(overhead); + radio_isr_set(lll_isr_abort, lll); radio_disable(); From ae6aa6165c6c90273a4f1fe8d3d881b3c63d082d Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Thu, 29 Sep 2022 13:34:38 +0200 Subject: [PATCH 0717/2042] json: Fix multidimensional array support This patch fixes support for encoding and decoding multidimensional arrays as described by the JSON_OBJ_DESCR_ARRAY_ARRAY() macro. Currently, the JSON array encoding and decoding functions, arr_encode() and arr_parse(), expect array elements to be of object or primitive type. However, arrays may be nested and so an array's elements may also be arrays. In order to support nested arrays, two special cases must be considered: 1. The array of objects/arrays sub-descriptor is described by two `json_obj_descr` structs and so two instead of one `json_obj_descr` structs must be skipped when iterating over the JSON descriptor to get to an array's elements. 2. The implicit array item count field has to be considered for the parent itself and all its child array items when calculating an element's size. Fixes #50801 Signed-off-by: Markus Fuchs --- lib/os/json.c | 61 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/lib/os/json.c b/lib/os/json.c index 1a2aea3d1da9..614a1852bad5 100644 --- a/lib/os/json.c +++ b/lib/os/json.c @@ -519,8 +519,17 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr) case JSON_TOK_TRUE: case JSON_TOK_FALSE: return sizeof(bool); - case JSON_TOK_ARRAY_START: - return descr->array.n_elements * get_elem_size(descr->array.element_descr); + case JSON_TOK_ARRAY_START: { + ptrdiff_t size; + + size = descr->array.n_elements * get_elem_size(descr->array.element_descr); + /* Consider additional item count field for array objects */ + if (descr->field_name_len > 0) { + size = size + sizeof(size_t); + } + + return size; + } case JSON_TOK_OBJECT_START: { ptrdiff_t total = 0; size_t i; @@ -542,23 +551,25 @@ static int arr_parse(struct json_obj *obj, const struct json_obj_descr *elem_descr, size_t max_elements, void *field, void *val) { - ptrdiff_t elem_size = get_elem_size(elem_descr); - void *last_elem = (char *)field + elem_size * max_elements; - size_t *elements = NULL; - struct json_token value; + void *value = val; + size_t *elements = (size_t *)((char *)value + elem_descr->offset); + ptrdiff_t elem_size; + void *last_elem; + struct json_token tok; - if (val) { - elements = (size_t *)((char *)val + elem_descr->offset); + /* For nested arrays, skip parent descriptor to get elements */ + if (elem_descr->type == JSON_TOK_ARRAY_START) { + elem_descr = elem_descr->array.element_descr; } - __ASSERT_NO_MSG(elem_size > 0); + *elements = 0; + elem_size = get_elem_size(elem_descr); + last_elem = (char *)field + elem_size * max_elements; - if (elements) { - *elements = 0; - } + __ASSERT_NO_MSG(elem_size > 0); - while (!arr_next(obj, &value)) { - if (value.type == JSON_TOK_ARRAY_END) { + while (!arr_next(obj, &tok)) { + if (tok.type == JSON_TOK_ARRAY_END) { return 0; } @@ -566,13 +577,18 @@ static int arr_parse(struct json_obj *obj, return -ENOSPC; } - if (decode_value(obj, elem_descr, &value, field, NULL) < 0) { - return -EINVAL; + /* For nested arrays, update value to current field, + * so it matches descriptor's offset to length field + */ + if (elem_descr->type == JSON_TOK_ARRAY_START) { + value = field; } - if (elements) { - (*elements)++; + if (decode_value(obj, elem_descr, &tok, field, value) < 0) { + return -EINVAL; } + + (*elements)++; field = (char *)field + elem_size; } @@ -835,7 +851,7 @@ static int arr_encode(const struct json_obj_descr *elem_descr, const void *field, const void *val, json_append_bytes_t append_bytes, void *data) { - ptrdiff_t elem_size = get_elem_size(elem_descr); + ptrdiff_t elem_size; /* * NOTE: Since an element descriptor's offset isn't meaningful * (array elements occur at multiple offsets in `val'), we use @@ -851,6 +867,13 @@ static int arr_encode(const struct json_obj_descr *elem_descr, return ret; } + /* For nested arrays, skip parent descriptor to get elements */ + if (elem_descr->type == JSON_TOK_ARRAY_START) { + elem_descr = elem_descr->array.element_descr; + } + + elem_size = get_elem_size(elem_descr); + for (i = 0; i < n_elem; i++) { /* * Though "field" points at the next element in the From 230433180732c56a5ee4c0728e5705461fdccbbc Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Tue, 27 Jun 2023 10:49:11 +0200 Subject: [PATCH 0718/2042] tests: lib: json: Switch non-ascii text to octal escape sequences Switch the non-ascii text in the tests to use octal escape sequences to avoid potential compiler issues on platforms not defaulting to utf-8 text encodings. Signed-off-by: Markus Fuchs --- tests/lib/json/src/main.c | 96 +++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index a0be4db0e77f..43d7733a0e64 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -260,8 +260,8 @@ ZTEST(lib_json_test, test_json_decoding_array_array) int ret; struct obj_array_array obj_array_array_ts; char encoded[] = "{\"objects_array\":[" - "[{\"height\":168,\"name\":\"Simón Bolívar\"}]," - "[{\"height\":173,\"name\":\"Pelé\"}]," + "[{\"height\":168,\"name\":\"Sim\303\263n Bol\303\255var\"}]," + "[{\"height\":173,\"name\":\"Pel\303\251\"}]," "[{\"height\":195,\"name\":\"Usain Bolt\"}]]" "}"; @@ -275,14 +275,14 @@ ZTEST(lib_json_test, test_json_decoding_array_array) "Array doesn't have correct number of items"); zassert_true(!strcmp(obj_array_array_ts.objects_array[0].objects.name, - "Simón Bolívar"), "String not decoded correctly"); + "Sim\303\263n Bol\303\255var"), "String not decoded correctly"); zassert_equal(obj_array_array_ts.objects_array[0].objects.height, 168, - "Simón Bolívar height not decoded correctly"); + "Sim\303\263n Bol\303\255var height not decoded correctly"); zassert_true(!strcmp(obj_array_array_ts.objects_array[1].objects.name, - "Pelé"), "String not decoded correctly"); + "Pel\303\251"), "String not decoded correctly"); zassert_equal(obj_array_array_ts.objects_array[1].objects.height, 173, - "Pelé height not decoded correctly"); + "Pel\303\251 height not decoded correctly"); zassert_true(!strcmp(obj_array_array_ts.objects_array[2].objects.name, "Usain Bolt"), "String not decoded correctly"); @@ -294,23 +294,23 @@ ZTEST(lib_json_test, test_json_obj_arr_encoding) { struct obj_array oa = { .elements = { - [0] = { .name = "Simón Bolívar", .height = 168 }, - [1] = { .name = "Muggsy Bogues", .height = 160 }, - [2] = { .name = "Pelé", .height = 173 }, - [3] = { .name = "Hakeem Olajuwon", .height = 213 }, - [4] = { .name = "Alex Honnold", .height = 180 }, - [5] = { .name = "Hazel Findlay", .height = 157 }, - [6] = { .name = "Daila Ojeda", .height = 158 }, - [7] = { .name = "Albert Einstein", .height = 172 }, - [8] = { .name = "Usain Bolt", .height = 195 }, - [9] = { .name = "Paavo Nurmi", .height = 174 }, + [0] = { .name = "Sim\303\263n Bol\303\255var", .height = 168 }, + [1] = { .name = "Muggsy Bogues", .height = 160 }, + [2] = { .name = "Pel\303\251", .height = 173 }, + [3] = { .name = "Hakeem Olajuwon", .height = 213 }, + [4] = { .name = "Alex Honnold", .height = 180 }, + [5] = { .name = "Hazel Findlay", .height = 157 }, + [6] = { .name = "Daila Ojeda", .height = 158 }, + [7] = { .name = "Albert Einstein", .height = 172 }, + [8] = { .name = "Usain Bolt", .height = 195 }, + [9] = { .name = "Paavo Nurmi", .height = 174 }, }, .num_elements = 10, }; const char encoded[] = "{\"elements\":[" - "{\"name\":\"Simón Bolívar\",\"height\":168}," + "{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," "{\"name\":\"Muggsy Bogues\",\"height\":160}," - "{\"name\":\"Pelé\",\"height\":173}," + "{\"name\":\"Pel\303\251\",\"height\":173}," "{\"name\":\"Hakeem Olajuwon\",\"height\":213}," "{\"name\":\"Alex Honnold\",\"height\":180}," "{\"name\":\"Hazel Findlay\",\"height\":157}," @@ -333,8 +333,8 @@ ZTEST(lib_json_test, test_json_arr_obj_decoding) { int ret; struct obj_array obj_array_array_ts; - char encoded[] = "[{\"height\":168,\"name\":\"Simón Bolívar\"}," - "{\"height\":173,\"name\":\"Pelé\"}," + char encoded[] = "[{\"height\":168,\"name\":\"Sim\303\263n Bol\303\255var\"}," + "{\"height\":173,\"name\":\"Pel\303\251\"}," "{\"height\":195,\"name\":\"Usain Bolt\"}" "]"; @@ -347,14 +347,14 @@ ZTEST(lib_json_test, test_json_arr_obj_decoding) "Array doesn't have correct number of items"); zassert_true(!strcmp(obj_array_array_ts.elements[0].name, - "Simón Bolívar"), "String not decoded correctly"); + "Sim\303\263n Bol\303\255var"), "String not decoded correctly"); zassert_equal(obj_array_array_ts.elements[0].height, 168, - "Simón Bolívar height not decoded correctly"); + "Sim\303\263n Bol\303\255var height not decoded correctly"); zassert_true(!strcmp(obj_array_array_ts.elements[1].name, - "Pelé"), "String not decoded correctly"); + "Pel\303\251"), "String not decoded correctly"); zassert_equal(obj_array_array_ts.elements[1].height, 173, - "Pelé height not decoded correctly"); + "Pel\303\251 height not decoded correctly"); zassert_true(!strcmp(obj_array_array_ts.elements[2].name, "Usain Bolt"), "String not decoded correctly"); @@ -366,23 +366,23 @@ ZTEST(lib_json_test, test_json_arr_obj_encoding) { struct obj_array oa = { .elements = { - [0] = { .name = "Simón Bolívar", .height = 168 }, - [1] = { .name = "Muggsy Bogues", .height = 160 }, - [2] = { .name = "Pelé", .height = 173 }, - [3] = { .name = "Hakeem Olajuwon", .height = 213 }, - [4] = { .name = "Alex Honnold", .height = 180 }, - [5] = { .name = "Hazel Findlay", .height = 157 }, - [6] = { .name = "Daila Ojeda", .height = 158 }, - [7] = { .name = "Albert Einstein", .height = 172 }, - [8] = { .name = "Usain Bolt", .height = 195 }, - [9] = { .name = "Paavo Nurmi", .height = 174 }, + [0] = { .name = "Sim\303\263n Bol\303\255var", .height = 168 }, + [1] = { .name = "Muggsy Bogues", .height = 160 }, + [2] = { .name = "Pel\303\251", .height = 173 }, + [3] = { .name = "Hakeem Olajuwon", .height = 213 }, + [4] = { .name = "Alex Honnold", .height = 180 }, + [5] = { .name = "Hazel Findlay", .height = 157 }, + [6] = { .name = "Daila Ojeda", .height = 158 }, + [7] = { .name = "Albert Einstein", .height = 172 }, + [8] = { .name = "Usain Bolt", .height = 195 }, + [9] = { .name = "Paavo Nurmi", .height = 174 }, }, .num_elements = 10, }; char encoded[] = "[" - "{\"name\":\"Simón Bolívar\",\"height\":168}," + "{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," "{\"name\":\"Muggsy Bogues\",\"height\":160}," - "{\"name\":\"Pelé\",\"height\":173}," + "{\"name\":\"Pel\303\251\",\"height\":173}," "{\"name\":\"Hakeem Olajuwon\",\"height\":213}," "{\"name\":\"Alex Honnold\",\"height\":180}," "{\"name\":\"Hazel Findlay\",\"height\":157}," @@ -408,9 +408,9 @@ ZTEST(lib_json_test, test_json_obj_arr_decoding) { struct obj_array oa; char encoded[] = "{\"elements\":[" - "{\"name\":\"Simón Bolívar\",\"height\":168}," + "{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," "{\"name\":\"Muggsy Bogues\",\"height\":160}," - "{\"name\":\"Pelé\",\"height\":173}," + "{\"name\":\"Pel\303\251\",\"height\":173}," "{\"name\":\"Hakeem Olajuwon\",\"height\":213}," "{\"name\":\"Alex Honnold\",\"height\":180}," "{\"name\":\"Hazel Findlay\",\"height\":157}," @@ -421,16 +421,16 @@ ZTEST(lib_json_test, test_json_obj_arr_decoding) "]}"; const struct obj_array expected = { .elements = { - [0] = { .name = "Simón Bolívar", .height = 168 }, - [1] = { .name = "Muggsy Bogues", .height = 160 }, - [2] = { .name = "Pelé", .height = 173 }, - [3] = { .name = "Hakeem Olajuwon", .height = 213 }, - [4] = { .name = "Alex Honnold", .height = 180 }, - [5] = { .name = "Hazel Findlay", .height = 157 }, - [6] = { .name = "Daila Ojeda", .height = 158 }, - [7] = { .name = "Albert Einstein", .height = 172 }, - [8] = { .name = "Usain Bolt", .height = 195 }, - [9] = { .name = "Paavo Nurmi", .height = 174 }, + [0] = { .name = "Sim\303\263n Bol\303\255var", .height = 168 }, + [1] = { .name = "Muggsy Bogues", .height = 160 }, + [2] = { .name = "Pel\303\251", .height = 173 }, + [3] = { .name = "Hakeem Olajuwon", .height = 213 }, + [4] = { .name = "Alex Honnold", .height = 180 }, + [5] = { .name = "Hazel Findlay", .height = 157 }, + [6] = { .name = "Daila Ojeda", .height = 158 }, + [7] = { .name = "Albert Einstein", .height = 172 }, + [8] = { .name = "Usain Bolt", .height = 195 }, + [9] = { .name = "Paavo Nurmi", .height = 174 }, }, .num_elements = 10, }; From 56234aee5dc645acd922a5c3cb4ecb98116249de Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Thu, 29 Sep 2022 13:37:52 +0200 Subject: [PATCH 0719/2042] tests: lib: json: Fix and enhance test for array of arrays Fix encoded JSON string in test_json_decoding_array_array() test so it matches the described array object and add a test case for encoding arrays of arrays. Signed-off-by: Markus Fuchs --- tests/lib/json/src/main.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index 43d7733a0e64..e11552eb3fb6 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -255,14 +255,39 @@ ZTEST(lib_json_test, test_json_limits) "Integer limits not decoded correctly"); } +ZTEST(lib_json_test, test_json_encoding_array_array) +{ + struct obj_array_array obj_array_array_ts = { + .objects_array = { + [0] = { { .name = "Sim\303\263n Bol\303\255var", .height = 168 } }, + [1] = { { .name = "Pel\303\251", .height = 173 } }, + [2] = { { .name = "Usain Bolt", .height = 195 } }, + }, + .objects_array_len = 3, + }; + char encoded[] = "{\"objects_array\":[" + "{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," + "{\"name\":\"Pel\303\251\",\"height\":173}," + "{\"name\":\"Usain Bolt\",\"height\":195}" + "]}"; + char buffer[sizeof(encoded)]; + int ret; + + ret = json_obj_encode_buf(array_array_descr, ARRAY_SIZE(array_array_descr), + &obj_array_array_ts, buffer, sizeof(buffer)); + zassert_equal(ret, 0, "Encoding array returned error"); + zassert_true(!strcmp(buffer, encoded), + "Encoded array of objects is not consistent"); +} + ZTEST(lib_json_test, test_json_decoding_array_array) { int ret; struct obj_array_array obj_array_array_ts; char encoded[] = "{\"objects_array\":[" - "[{\"height\":168,\"name\":\"Sim\303\263n Bol\303\255var\"}]," - "[{\"height\":173,\"name\":\"Pel\303\251\"}]," - "[{\"height\":195,\"name\":\"Usain Bolt\"}]]" + "{\"height\":168,\"name\":\"Sim\303\263n Bol\303\255var\"}," + "{\"height\":173,\"name\":\"Pel\303\251\"}," + "{\"height\":195,\"name\":\"Usain Bolt\"}]" "}"; ret = json_obj_parse(encoded, sizeof(encoded), From 7a7a78bd9291a27ff4bbf1464633ac99dd261757 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Thu, 29 Sep 2022 13:38:42 +0200 Subject: [PATCH 0720/2042] tests: lib: json: Add tests for handling two-dimensional arrays Add tests for encoding and decoding two-dimensional arrays as described by the JSON_OBJ_DESCR_ARRAY_ARRAY() macro. Signed-off-by: Markus Fuchs --- tests/lib/json/src/main.c | 191 +++++++++++++++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index e11552eb3fb6..c39e114ef142 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -106,6 +106,17 @@ static const struct json_obj_descr array_array_descr[] = { ARRAY_SIZE(array_descr)), }; +struct obj_array_2dim { + struct obj_array objects_array_array[3]; + size_t objects_array_array_len; +}; + +static const struct json_obj_descr array_2dim_descr[] = { + JSON_OBJ_DESCR_ARRAY_ARRAY(struct obj_array_2dim, objects_array_array, 3, + objects_array_array_len, obj_array_descr, + ARRAY_SIZE(obj_array_descr)), +}; + ZTEST(lib_json_test, test_json_encoding) { struct test_struct ts = { @@ -332,7 +343,7 @@ ZTEST(lib_json_test, test_json_obj_arr_encoding) }, .num_elements = 10, }; - const char encoded[] = "{\"elements\":[" + char encoded[] = "{\"elements\":[" "{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," "{\"name\":\"Muggsy Bogues\",\"height\":160}," "{\"name\":\"Pel\303\251\",\"height\":173}," @@ -479,6 +490,184 @@ ZTEST(lib_json_test, test_json_obj_arr_decoding) } } +ZTEST(lib_json_test, test_json_2dim_arr_obj_encoding) +{ + struct obj_array_2dim obj_array_array_ts = { + .objects_array_array = { + [0] = { + .elements = { + [0] = { + .name = "Sim\303\263n Bol\303\255var", + .height = 168 + }, + [1] = { + .name = "Pel\303\251", + .height = 173 + }, + [2] = { + .name = "Usain Bolt", + .height = 195 + }, + }, + .num_elements = 3 + }, + [1] = { + .elements = { + [0] = { + .name = "Muggsy Bogues", + .height = 160 + }, + [1] = { + .name = "Hakeem Olajuwon", + .height = 213 + }, + }, + .num_elements = 2 + }, + [2] = { + .elements = { + [0] = { + .name = "Alex Honnold", + .height = 180 + }, + [1] = { + .name = "Hazel Findlay", + .height = 157 + }, + [2] = { + .name = "Daila Ojeda", + .height = 158 + }, + [3] = { + .name = "Albert Einstein", + .height = 172 + }, + }, + .num_elements = 4 + }, + }, + .objects_array_array_len = 3, + }; + char encoded[] = "{\"objects_array_array\":[" + "[{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," + "{\"name\":\"Pel\303\251\",\"height\":173}," + "{\"name\":\"Usain Bolt\",\"height\":195}]," + "[{\"name\":\"Muggsy Bogues\",\"height\":160}," + "{\"name\":\"Hakeem Olajuwon\",\"height\":213}]," + "[{\"name\":\"Alex Honnold\",\"height\":180}," + "{\"name\":\"Hazel Findlay\",\"height\":157}," + "{\"name\":\"Daila Ojeda\",\"height\":158}," + "{\"name\":\"Albert Einstein\",\"height\":172}]" + "]}"; + char buffer[sizeof(encoded)]; + int ret; + + ret = json_obj_encode_buf(array_2dim_descr, ARRAY_SIZE(array_2dim_descr), + &obj_array_array_ts, buffer, sizeof(buffer)); + zassert_equal(ret, 0, "Encoding two-dimensional array returned error"); + zassert_true(!strcmp(buffer, encoded), + "Encoded two-dimensional array is not consistent"); +} + +ZTEST(lib_json_test, test_json_2dim_obj_arr_decoding) +{ + struct obj_array_2dim oaa; + char encoded[] = "{\"objects_array_array\":[" + "[{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," + "{\"name\":\"Pel\303\251\",\"height\":173}," + "{\"name\":\"Usain Bolt\",\"height\":195}]," + "[{\"name\":\"Muggsy Bogues\",\"height\":160}," + "{\"name\":\"Hakeem Olajuwon\",\"height\":213}]," + "[{\"name\":\"Alex Honnold\",\"height\":180}," + "{\"name\":\"Hazel Findlay\",\"height\":157}," + "{\"name\":\"Daila Ojeda\",\"height\":158}," + "{\"name\":\"Albert Einstein\",\"height\":172}]" + "]}"; + const struct obj_array_2dim expected = { + .objects_array_array = { + [0] = { + .elements = { + [0] = { + .name = "Sim\303\263n Bol\303\255var", + .height = 168 + }, + [1] = { + .name = "Pel\303\251", + .height = 173 + }, + [2] = { + .name = "Usain Bolt", + .height = 195 + }, + }, + .num_elements = 3 + }, + [1] = { + .elements = { + [0] = { + .name = "Muggsy Bogues", + .height = 160 + }, + [1] = { + .name = "Hakeem Olajuwon", + .height = 213 + }, + }, + .num_elements = 2 + }, + [2] = { + .elements = { + [0] = { + .name = "Alex Honnold", + .height = 180 + }, + [1] = { + .name = "Hazel Findlay", + .height = 157 + }, + [2] = { + .name = "Daila Ojeda", + .height = 158 + }, + [3] = { + .name = "Albert Einstein", + .height = 172 + }, + }, + .num_elements = 4 + }, + }, + .objects_array_array_len = 3, + }; + int ret; + + ret = json_obj_parse(encoded, sizeof(encoded), + array_2dim_descr, + ARRAY_SIZE(array_2dim_descr), + &oaa); + + zassert_equal(ret, 1, "Array of arrays fields not decoded correctly"); + zassert_equal(oaa.objects_array_array_len, 3, + "Number of subarrays not decoded correctly"); + zassert_equal(oaa.objects_array_array[0].num_elements, 3, + "Number of object fields not decoded correctly"); + zassert_equal(oaa.objects_array_array[1].num_elements, 2, + "Number of object fields not decoded correctly"); + zassert_equal(oaa.objects_array_array[2].num_elements, 4, + "Number of object fields not decoded correctly"); + + for (int i = 0; i < expected.objects_array_array_len; i++) { + for (int j = 0; j < expected.objects_array_array[i].num_elements; j++) { + zassert_true(!strcmp(oaa.objects_array_array[i].elements[j].name, + expected.objects_array_array[i].elements[j].name), + "Element [%d][%d] name not decoded correctly", i, j); + zassert_equal(oaa.objects_array_array[i].elements[j].height, + expected.objects_array_array[i].elements[j].height, + "Element [%d][%d] height not decoded correctly", i, j); + } + } +} + struct encoding_test { char *str; int result; From b311c533bfe98684357a82ea11d55bc146210e4a Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Wed, 2 Nov 2022 09:57:26 +0100 Subject: [PATCH 0721/2042] tests: lib: json: Add test for array of objects Add tests for encoding and decoding nested arrays of objects located inside a parent object at a non-zero offset. Signed-off-by: Markus Fuchs --- tests/lib/json/src/main.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index c39e114ef142..4bab23d92908 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -27,6 +27,8 @@ struct test_struct { int another_array[10]; /* JSON: "another-array" */ size_t another_array_len; struct test_nested xnother_nexx; /* JSON: "4nother_ne$+" */ + struct test_nested nested_obj_array[2]; + size_t obj_array_len; }; struct elt { @@ -69,6 +71,8 @@ static const struct json_obj_descr test_descr[] = { JSON_TOK_NUMBER), JSON_OBJ_DESCR_OBJECT_NAMED(struct test_struct, "4nother_ne$+", xnother_nexx, nested_descr), + JSON_OBJ_DESCR_OBJ_ARRAY(struct test_struct, nested_obj_array, 2, + obj_array_len, nested_descr, ARRAY_SIZE(nested_descr)), }; static const struct json_obj_descr elt_descr[] = { @@ -146,6 +150,11 @@ ZTEST(lib_json_test, test_json_encoding) .nested_bool = true, .nested_string = "no escape necessary", }, + .nested_obj_array = { + {1, true, "true"}, + {0, false, "false"} + }, + .obj_array_len = 2 }; char encoded[] = "{\"some_string\":\"zephyr 123\uABCD\"," "\"some_int\":42,\"some_bool\":true," @@ -158,7 +167,10 @@ ZTEST(lib_json_test, test_json_encoding) "\"another-array\":[2,3,5,7]," "\"4nother_ne$+\":{\"nested_int\":1234," "\"nested_bool\":true," - "\"nested_string\":\"no escape necessary\"}" + "\"nested_string\":\"no escape necessary\"}," + "\"nested_obj_array\":[" + "{\"nested_int\":1,\"nested_bool\":true,\"nested_string\":\"true\"}," + "{\"nested_int\":0,\"nested_bool\":false,\"nested_string\":\"false\"}]" "}"; char buffer[sizeof(encoded)]; int ret; @@ -193,7 +205,10 @@ ZTEST(lib_json_test, test_json_decoding) "\"another-array\":[2,3,5,7]," "\"4nother_ne$+\":{\"nested_int\":1234," "\"nested_bool\":true," - "\"nested_string\":\"no escape necessary\"}" + "\"nested_string\":\"no escape necessary\"}," + "\"nested_obj_array\":[" + "{\"nested_int\":1,\"nested_bool\":true,\"nested_string\":\"true\"}," + "{\"nested_int\":0,\"nested_bool\":false,\"nested_string\":\"false\"}]" "}\n"; const int expected_array[] = { 11, 22, 33, 45, 299 }; const int expected_other_array[] = { 2, 3, 5, 7 }; @@ -237,6 +252,20 @@ ZTEST(lib_json_test, test_json_decoding) zassert_true(!strcmp(ts.xnother_nexx.nested_string, "no escape necessary"), "Named nested string not decoded correctly"); + zassert_equal(ts.obj_array_len, 2, + "Array of objects does not have correct number of items"); + zassert_equal(ts.nested_obj_array[0].nested_int, 1, + "Integer in first object array element not decoded correctly"); + zassert_equal(ts.nested_obj_array[0].nested_bool, true, + "Boolean value in first object array element not decoded correctly"); + zassert_true(!strcmp(ts.nested_obj_array[0].nested_string, "true"), + "String in first object array element not decoded correctly"); + zassert_equal(ts.nested_obj_array[1].nested_int, 0, + "Integer in second object array element not decoded correctly"); + zassert_equal(ts.nested_obj_array[1].nested_bool, false, + "Boolean value in second object array element not decoded correctly"); + zassert_true(!strcmp(ts.nested_obj_array[1].nested_string, "false"), + "String in second object array element not decoded correctly"); } ZTEST(lib_json_test, test_json_limits) From 8757c71bd04a470bb35aa6b290fa4a04b8c6a489 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Thu, 3 Nov 2022 11:38:00 +0100 Subject: [PATCH 0722/2042] json: Fix 64-bit support This patch fixes encoding arrays of objects on 64-bit targets. Fixes #36696 Signed-off-by: Markus Fuchs --- lib/os/json.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/os/json.c b/lib/os/json.c index 614a1852bad5..801e2e11406c 100644 --- a/lib/os/json.c +++ b/lib/os/json.c @@ -535,12 +535,10 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr) size_t i; for (i = 0; i < descr->object.sub_descr_len; i++) { - ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]); - - total += ROUND_UP(s, 1 << descr->align_shift); + total += get_elem_size(&descr->object.sub_descr[i]); } - return total; + return ROUND_UP(total, 1 << descr->align_shift); } default: return -EINVAL; From 2a31c4c5300899c63437ce0782c0a4164ac710ff Mon Sep 17 00:00:00 2001 From: Al Semjonovs Date: Mon, 1 May 2023 11:43:43 -0600 Subject: [PATCH 0723/2042] sensors: icm42688 async API Implementation of the async API for the icm42688 Signed-off-by: Al Semjonovs --- drivers/sensor/icm42688/CMakeLists.txt | 2 + drivers/sensor/icm42688/Kconfig | 7 + drivers/sensor/icm42688/icm42688.c | 111 ++++---- drivers/sensor/icm42688/icm42688.h | 12 +- drivers/sensor/icm42688/icm42688_decoder.c | 315 +++++++++++++++++++++ drivers/sensor/icm42688/icm42688_decoder.h | 35 +++ drivers/sensor/icm42688/icm42688_rtio.c | 81 ++++++ drivers/sensor/icm42688/icm42688_rtio.h | 12 + drivers/sensor/icm42688/icm42688_trigger.c | 4 +- 9 files changed, 516 insertions(+), 63 deletions(-) create mode 100644 drivers/sensor/icm42688/icm42688_decoder.c create mode 100644 drivers/sensor/icm42688/icm42688_decoder.h create mode 100644 drivers/sensor/icm42688/icm42688_rtio.c create mode 100644 drivers/sensor/icm42688/icm42688_rtio.h diff --git a/drivers/sensor/icm42688/CMakeLists.txt b/drivers/sensor/icm42688/CMakeLists.txt index 1e9acaa3731a..cf9308bb95c4 100644 --- a/drivers/sensor/icm42688/CMakeLists.txt +++ b/drivers/sensor/icm42688/CMakeLists.txt @@ -8,6 +8,8 @@ zephyr_library_sources( icm42688_spi.c ) +zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API icm42688_rtio.c) +zephyr_library_sources_ifdef(CONFIG_ICM42688_DECODER icm42688_decoder.c) zephyr_library_sources_ifdef(CONFIG_ICM42688_TRIGGER icm42688_trigger.c) zephyr_library_sources_ifdef(CONFIG_EMUL_ICM42688 icm42688_emul.c) zephyr_include_directories_ifdef(CONFIG_EMUL_ICM42688 .) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 5cdfb3cdc1ee..19d0602cbd31 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -21,6 +21,13 @@ config EMUL_ICM42688 Enable the hardware emulator for the ICM42688. Doing so allows exercising sensor APIs for this IMU in native_posix and qemu. +config ICM42688_DECODER + bool "ICM42688 decoder logic" + default y if ICM42688 + help + Compile the ICM42688 decoder API which allows decoding raw data returned + from the sensor. + if ICM42688 choice diff --git a/drivers/sensor/icm42688/icm42688.c b/drivers/sensor/icm42688/icm42688.c index 329907a010d9..b8ebef4f147e 100644 --- a/drivers/sensor/icm42688/icm42688.c +++ b/drivers/sensor/icm42688/icm42688.c @@ -13,23 +13,15 @@ #include #include "icm42688.h" +#include "icm42688_decoder.h" #include "icm42688_reg.h" +#include "icm42688_rtio.h" #include "icm42688_spi.h" #include "icm42688_trigger.h" #include LOG_MODULE_REGISTER(ICM42688, CONFIG_SENSOR_LOG_LEVEL); -struct icm42688_sensor_data { - struct icm42688_dev_data dev_data; - - int16_t readings[7]; -}; - -struct icm42688_sensor_config { - struct icm42688_dev_cfg dev_cfg; -}; - static void icm42688_convert_accel(struct sensor_value *val, int16_t raw_val, struct icm42688_cfg *cfg) { @@ -47,42 +39,40 @@ static inline void icm42688_convert_temp(struct sensor_value *val, int16_t raw_v icm42688_temp_c((int32_t)raw_val, &val->val1, &val->val2); } -static int icm42688_channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) +int icm42688_channel_parse_readings(enum sensor_channel chan, int16_t readings[7], + struct icm42688_cfg *cfg, struct sensor_value *val) { - struct icm42688_sensor_data *data = dev->data; - switch (chan) { case SENSOR_CHAN_ACCEL_XYZ: - icm42688_convert_accel(&val[0], data->readings[1], &data->dev_data.cfg); - icm42688_convert_accel(&val[1], data->readings[2], &data->dev_data.cfg); - icm42688_convert_accel(&val[2], data->readings[3], &data->dev_data.cfg); + icm42688_convert_accel(&val[0], readings[1], cfg); + icm42688_convert_accel(&val[1], readings[2], cfg); + icm42688_convert_accel(&val[2], readings[3], cfg); break; case SENSOR_CHAN_ACCEL_X: - icm42688_convert_accel(val, data->readings[1], &data->dev_data.cfg); + icm42688_convert_accel(val, readings[1], cfg); break; case SENSOR_CHAN_ACCEL_Y: - icm42688_convert_accel(val, data->readings[2], &data->dev_data.cfg); + icm42688_convert_accel(val, readings[2], cfg); break; case SENSOR_CHAN_ACCEL_Z: - icm42688_convert_accel(val, data->readings[3], &data->dev_data.cfg); + icm42688_convert_accel(val, readings[3], cfg); break; case SENSOR_CHAN_GYRO_XYZ: - icm42688_convert_gyro(&val[0], data->readings[4], &data->dev_data.cfg); - icm42688_convert_gyro(&val[1], data->readings[5], &data->dev_data.cfg); - icm42688_convert_gyro(&val[2], data->readings[6], &data->dev_data.cfg); + icm42688_convert_gyro(&val[0], readings[4], cfg); + icm42688_convert_gyro(&val[1], readings[5], cfg); + icm42688_convert_gyro(&val[2], readings[6], cfg); break; case SENSOR_CHAN_GYRO_X: - icm42688_convert_gyro(val, data->readings[4], &data->dev_data.cfg); + icm42688_convert_gyro(val, readings[4], cfg); break; case SENSOR_CHAN_GYRO_Y: - icm42688_convert_gyro(val, data->readings[5], &data->dev_data.cfg); + icm42688_convert_gyro(val, readings[5], cfg); break; case SENSOR_CHAN_GYRO_Z: - icm42688_convert_gyro(val, data->readings[6], &data->dev_data.cfg); + icm42688_convert_gyro(val, readings[6], cfg); break; case SENSOR_CHAN_DIE_TEMP: - icm42688_convert_temp(val, data->readings[0]); + icm42688_convert_temp(val, readings[0]); break; default: return -ENOTSUP; @@ -91,13 +81,21 @@ static int icm42688_channel_get(const struct device *dev, enum sensor_channel ch return 0; } +static int icm42688_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct icm42688_dev_data *data = dev->data; + + return icm42688_channel_parse_readings(chan, data->readings, &data->cfg, val); +} + static int icm42688_sample_fetch(const struct device *dev, enum sensor_channel chan) { uint8_t status; - struct icm42688_sensor_data *data = dev->data; - const struct icm42688_sensor_config *cfg = dev->config; + struct icm42688_dev_data *data = dev->data; + const struct icm42688_dev_cfg *cfg = dev->config; - int res = icm42688_spi_read(&cfg->dev_cfg.spi, REG_INT_STATUS, &status, 1); + int res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); if (res) { return res; @@ -125,8 +123,8 @@ static int icm42688_sample_fetch(const struct device *dev, enum sensor_channel c static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { - const struct icm42688_sensor_data *data = dev->data; - struct icm42688_cfg new_config = data->dev_data.cfg; + const struct icm42688_dev_data *data = dev->data; + struct icm42688_cfg new_config = data->cfg; int res = 0; __ASSERT_NO_MSG(val != NULL); @@ -173,8 +171,8 @@ static int icm42688_attr_set(const struct device *dev, enum sensor_channel chan, static int icm42688_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val) { - const struct icm42688_sensor_data *data = dev->data; - const struct icm42688_cfg *cfg = &data->dev_data.cfg; + const struct icm42688_dev_data *data = dev->data; + const struct icm42688_cfg *cfg = &data->cfg; int res = 0; __ASSERT_NO_MSG(val != NULL); @@ -222,16 +220,20 @@ static const struct sensor_driver_api icm42688_driver_api = { .attr_get = icm42688_attr_get, #ifdef CONFIG_ICM42688_TRIGGER .trigger_set = icm42688_trigger_set, +#endif + .get_decoder = icm42688_get_decoder, +#ifdef CONFIG_SENSOR_ASYNC_API + .submit = icm42688_submit, #endif }; int icm42688_init(const struct device *dev) { - struct icm42688_sensor_data *data = dev->data; - const struct icm42688_sensor_config *cfg = dev->config; + struct icm42688_dev_data *data = dev->data; + const struct icm42688_dev_cfg *cfg = dev->config; int res; - if (!spi_is_ready_dt(&cfg->dev_cfg.spi)) { + if (!spi_is_ready_dt(&cfg->spi)) { LOG_ERR("SPI bus is not ready"); return -ENODEV; } @@ -247,22 +249,18 @@ int icm42688_init(const struct device *dev) LOG_ERR("Failed to initialize triggers"); return res; } - - res = icm42688_trigger_enable_interrupt(dev); - if (res != 0) { - LOG_ERR("Failed to enable triggers"); - return res; - } #endif - data->dev_data.cfg.accel_mode = ICM42688_ACCEL_LN; - data->dev_data.cfg.gyro_mode = ICM42688_GYRO_LN; - data->dev_data.cfg.accel_fs = ICM42688_ACCEL_FS_2G; - data->dev_data.cfg.gyro_fs = ICM42688_GYRO_FS_125; - data->dev_data.cfg.accel_odr = ICM42688_ACCEL_ODR_1000; - data->dev_data.cfg.gyro_odr = ICM42688_GYRO_ODR_1000; + memset(&data->cfg, 0, sizeof(struct icm42688_cfg)); + data->cfg.accel_mode = ICM42688_ACCEL_LN; + data->cfg.gyro_mode = ICM42688_GYRO_LN; + data->cfg.accel_fs = ICM42688_ACCEL_FS_2G; + data->cfg.gyro_fs = ICM42688_GYRO_FS_125; + data->cfg.accel_odr = ICM42688_ACCEL_ODR_1000; + data->cfg.gyro_odr = ICM42688_GYRO_ODR_1000; + data->cfg.fifo_en = false; - res = icm42688_configure(dev, &data->dev_data.cfg); + res = icm42688_configure(dev, &data->cfg); if (res != 0) { LOG_ERR("Failed to configure"); return res; @@ -286,16 +284,15 @@ void icm42688_unlock(const struct device *dev) #define ICM42688_SPI_CFG \ SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_TRANSFER_MSB +#define ICM42688_DEFINE_DATA(inst) \ + static struct icm42688_dev_data icm42688_driver_##inst; #define ICM42688_INIT(inst) \ - static struct icm42688_sensor_data icm42688_driver_##inst = { 0 }; \ + ICM42688_DEFINE_DATA(inst); \ \ - static const struct icm42688_sensor_config icm42688_cfg_##inst = { \ - .dev_cfg = \ - { \ - .spi = SPI_DT_SPEC_INST_GET(inst, ICM42688_SPI_CFG, 0U), \ - .gpio_int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ - }, \ + static const struct icm42688_dev_cfg icm42688_cfg_##inst = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, ICM42688_SPI_CFG, 0U), \ + .gpio_int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, icm42688_init, NULL, &icm42688_driver_##inst, \ diff --git a/drivers/sensor/icm42688/icm42688.h b/drivers/sensor/icm42688/icm42688.h index ac7c531c99d6..18ae4606e725 100644 --- a/drivers/sensor/icm42688/icm42688.h +++ b/drivers/sensor/icm42688/icm42688.h @@ -411,6 +411,8 @@ struct icm42688_dev_data { const struct sensor_trigger *data_ready_trigger; struct k_mutex mutex; #endif /* CONFIG_ICM42688_TRIGGER */ + + int16_t readings[7]; }; /** @@ -515,7 +517,7 @@ static inline void icm42688_accel_g(struct icm42688_cfg *cfg, int32_t in, int32_ * @param out_dps whole deg/s output in int32_t * @param out_udps micro (1/1000000) deg/s as uint32_t */ -static inline void icm42688_gyro_dps(struct icm42688_cfg *cfg, int32_t in, int32_t *out_dps, +static inline void icm42688_gyro_dps(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_dps, uint32_t *out_udps) { int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */ @@ -565,8 +567,8 @@ static inline void icm42688_gyro_dps(struct icm42688_cfg *cfg, int32_t in, int32 * @param out_ms meters/s^2 (whole) output in int32_t * @param out_ums micrometers/s^2 output as uint32_t */ -static inline void icm42688_accel_ms(struct icm42688_cfg *cfg, int32_t in, int32_t *out_ms, - uint32_t *out_ums) +static inline void icm42688_accel_ms(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_ms, + int32_t *out_ums) { int64_t sensitivity = 0; /* value equivalent for 1g */ @@ -603,8 +605,8 @@ static inline void icm42688_accel_ms(struct icm42688_cfg *cfg, int32_t in, int32 * @param out_rads whole rad/s output in int32_t * @param out_urads microrad/s as uint32_t */ -static inline void icm42688_gyro_rads(struct icm42688_cfg *cfg, int32_t in, int32_t *out_rads, - uint32_t *out_urads) +static inline void icm42688_gyro_rads(const struct icm42688_cfg *cfg, int32_t in, int32_t *out_rads, + int32_t *out_urads) { int64_t sensitivity = 0; /* value equivalent for 10x gyro reading deg/s */ diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c new file mode 100644 index 000000000000..16cb48dbcca0 --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "icm42688_decoder.h" +#include "icm42688_reg.h" +#include "icm42688.h" +#include + +#include +LOG_MODULE_REGISTER(ICM42688_DECODER, CONFIG_SENSOR_LOG_LEVEL); + +#define DT_DRV_COMPAT invensense_icm42688 + +static int icm42688_get_shift(enum sensor_channel channel, int accel_fs, int gyro_fs, int8_t *shift) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (accel_fs) { + case ICM42688_ACCEL_FS_2G: + *shift = 5; + return 0; + case ICM42688_ACCEL_FS_4G: + *shift = 6; + return 0; + case ICM42688_ACCEL_FS_8G: + *shift = 7; + return 0; + case ICM42688_ACCEL_FS_16G: + *shift = 8; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (gyro_fs) { + case ICM42688_GYRO_FS_15_625: + *shift = -1; + return 0; + case ICM42688_GYRO_FS_31_25: + *shift = 0; + return 0; + case ICM42688_GYRO_FS_62_5: + *shift = 1; + return 0; + case ICM42688_GYRO_FS_125: + *shift = 2; + return 0; + case ICM42688_GYRO_FS_250: + *shift = 3; + return 0; + case ICM42688_GYRO_FS_500: + *shift = 4; + return 0; + case ICM42688_GYRO_FS_1000: + *shift = 5; + return 0; + case ICM42688_GYRO_FS_2000: + *shift = 6; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_DIE_TEMP: + *shift = 9; + return 0; + default: + return -EINVAL; + } +} + +static enum sensor_channel icm42688_get_channel_from_position(int pos) +{ + switch (pos) { + case 0: + return SENSOR_CHAN_DIE_TEMP; + case 1: + return SENSOR_CHAN_ACCEL_X; + case 2: + return SENSOR_CHAN_ACCEL_Y; + case 3: + return SENSOR_CHAN_ACCEL_Z; + case 4: + return SENSOR_CHAN_GYRO_X; + case 5: + return SENSOR_CHAN_GYRO_Y; + case 6: + return SENSOR_CHAN_GYRO_Z; + default: + return SENSOR_CHAN_MAX; + } +} + +int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel chan, + int32_t reading, q31_t *out) +{ + int32_t whole; + int32_t fraction; + int64_t intermediate; + int8_t shift; + int rc; + + rc = icm42688_get_shift(chan, cfg->accel_fs, cfg->gyro_fs, &shift); + if (rc != 0) { + return rc; + } + + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42688_accel_ms(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42688_gyro_rads(cfg, reading, &whole, &fraction); + break; + case SENSOR_CHAN_DIE_TEMP: + icm42688_temp_c(reading, &whole, &fraction); + break; + default: + return -ENOTSUP; + } + intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); + if (shift < 0) { + intermediate = intermediate * INT32_MAX * (1 << -shift) / INT64_C(1000000); + } else if (shift > 0) { + intermediate = intermediate * INT32_MAX / (((1 << shift) - 1) * INT64_C(1000000)); + } + *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); + + return 0; +} + +static int icm42688_get_channel_position(enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: + return 0; + case SENSOR_CHAN_ACCEL_XYZ: + case SENSOR_CHAN_ACCEL_X: + return 1; + case SENSOR_CHAN_ACCEL_Y: + return 2; + case SENSOR_CHAN_ACCEL_Z: + return 3; + case SENSOR_CHAN_GYRO_XYZ: + case SENSOR_CHAN_GYRO_X: + return 4; + case SENSOR_CHAN_GYRO_Y: + return 5; + case SENSOR_CHAN_GYRO_Z: + return 6; + default: + return 0; + } +} + +static uint8_t icm42688_encode_channel(enum sensor_channel chan) +{ + uint8_t encode_bmask = 0; + + switch (chan) { + case SENSOR_CHAN_DIE_TEMP: + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + encode_bmask = BIT(icm42688_get_channel_position(chan)); + break; + case SENSOR_CHAN_ACCEL_XYZ: + encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_X)) | + BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Y)) | + BIT(icm42688_get_channel_position(SENSOR_CHAN_ACCEL_Z)); + break; + case SENSOR_CHAN_GYRO_XYZ: + encode_bmask = BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_X)) | + BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Y)) | + BIT(icm42688_get_channel_position(SENSOR_CHAN_GYRO_Z)); + break; + default: + break; + } + + return encode_bmask; +} + +int icm42688_encode(const struct device *dev, const enum sensor_channel *const channels, + const size_t num_channels, uint8_t *buf) +{ + struct icm42688_dev_data *data = dev->data; + struct icm42688_encoded_data *edata = (struct icm42688_encoded_data *)buf; + + edata->channels = 0; + + for (int i = 0; i < num_channels; i++) { + edata->channels |= icm42688_encode_channel(channels[i]); + } + + edata->header.is_fifo = false; + edata->header.accel_fs = data->cfg.accel_fs; + edata->header.gyro_fs = data->cfg.gyro_fs; + edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + return 0; +} + +static int icm42688_one_shot_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, + sensor_channel_iterator_t *cit, enum sensor_channel *channels, + q31_t *values, uint8_t max_count) +{ + const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer; + uint8_t channels_read = edata->channels; + struct icm42688_cfg cfg = { + .accel_fs = edata->header.accel_fs, + .gyro_fs = edata->header.gyro_fs, + }; + int chan; + int pos; + int count = 0; + int num_samples = __builtin_popcount(channels_read); + + channels_read = edata->channels; + + if (*fit != 0) { + return 0; + } + + /* Skip channels already decoded */ + for (int i = 0; i < *cit && channels_read; i++) { + chan = __builtin_ctz(channels_read); + channels_read &= ~BIT(chan); + } + + /* Decode remaining channels */ + while (channels_read && *cit < num_samples && count < max_count) { + chan = icm42688_get_channel_from_position(__builtin_ctz(channels_read)); + + channels[count] = chan; + pos = icm42688_get_channel_position(chan); + + icm42688_convert_raw_to_q31(&cfg, chan, edata->readings[pos], &values[count]); + + count++; + channels_read &= ~BIT(chan); + *cit += 1; + } + + if (*cit >= __builtin_popcount(edata->channels)) { + *fit += 1; + *cit = 0; + } + + return count; +} + +static int icm42688_decoder_decode(const uint8_t *buffer, sensor_frame_iterator_t *fit, + sensor_channel_iterator_t *cit, enum sensor_channel *channels, + q31_t *values, uint8_t max_count) +{ + return icm42688_one_shot_decode(buffer, fit, cit, channels, values, max_count); +} + +static int icm42688_decoder_get_frame_count(const uint8_t *buffer, uint16_t *frame_count) +{ + ARG_UNUSED(buffer); + *frame_count = 1; + return 0; +} + +static int icm42688_decoder_get_timestamp(const uint8_t *buffer, uint64_t *timestamp_ns) +{ + const struct icm42688_decoder_header *header = + (const struct icm42688_decoder_header *)buffer; + + *timestamp_ns = header->timestamp; + return 0; +} + +static int icm42688_decoder_get_shift(const uint8_t *buffer, enum sensor_channel channel_type, + int8_t *shift) +{ + const struct icm42688_decoder_header *header = + (const struct icm42688_decoder_header *)buffer; + + return icm42688_get_shift(channel_type, header->accel_fs, header->gyro_fs, shift); +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = icm42688_decoder_get_frame_count, + .get_timestamp = icm42688_decoder_get_timestamp, + .get_shift = icm42688_decoder_get_shift, + .decode = icm42688_decoder_decode, +}; + +int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + + return 0; +} diff --git a/drivers/sensor/icm42688/icm42688_decoder.h b/drivers/sensor/icm42688/icm42688_decoder.h new file mode 100644 index 000000000000..2ef806373c94 --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_decoder.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ + +#include +#include + +struct icm42688_decoder_header { + uint64_t timestamp; + uint8_t is_fifo: 1; + uint8_t gyro_fs: 3; + uint8_t accel_fs: 2; + uint8_t reserved: 2; +} __attribute__((__packed__)); + +struct icm42688_encoded_data { + struct icm42688_decoder_header header; + struct { + uint8_t channels: 7; + uint8_t reserved: 1; + } __attribute__((__packed__)); + int16_t readings[7]; +}; + +int icm42688_encode(const struct device *dev, const enum sensor_channel *const channels, + const size_t num_channels, uint8_t *buf); + +int icm42688_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_DECODER_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_rtio.c b/drivers/sensor/icm42688/icm42688_rtio.c new file mode 100644 index 000000000000..c1b20689393d --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_rtio.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "icm42688.h" +#include "icm42688_decoder.h" +#include "icm42688_reg.h" +#include "icm42688_spi.h" + +#include +LOG_MODULE_REGISTER(ICM42688_RTIO, CONFIG_SENSOR_LOG_LEVEL); + +static int icm42688_rtio_sample_fetch(const struct device *dev, int16_t readings[7]) +{ + uint8_t status; + const struct icm42688_dev_cfg *cfg = dev->config; + uint8_t *buffer = (uint8_t *)readings; + + int res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); + + if (res) { + return res; + } + + if (!FIELD_GET(BIT_INT_STATUS_DATA_RDY, status)) { + return -EBUSY; + } + + res = icm42688_read_all(dev, buffer); + + if (res) { + return res; + } + + for (int i = 0; i < 7; i++) { + readings[i] = sys_le16_to_cpu((buffer[i * 2] << 8) | buffer[i * 2 + 1]); + } + + return 0; +} + +int icm42688_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + 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 icm42688_encoded_data); + int rc; + uint8_t *buf; + uint32_t buf_len; + struct icm42688_encoded_data *edata; + + /* 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; + } + + edata = (struct icm42688_encoded_data *)buf; + + icm42688_encode(dev, channels, num_channels, buf); + + rc = icm42688_rtio_sample_fetch(dev, edata->readings); + /* Check that the fetch succeeded */ + if (rc != 0) { + LOG_ERR("Failed to fetch samples"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + + rtio_iodev_sqe_ok(iodev_sqe, 0); + + return 0; +} + +BUILD_ASSERT(sizeof(struct icm42688_decoder_header) == 9); diff --git a/drivers/sensor/icm42688/icm42688_rtio.h b/drivers/sensor/icm42688/icm42688_rtio.h new file mode 100644 index 000000000000..748c8a022b09 --- /dev/null +++ b/drivers/sensor/icm42688/icm42688_rtio.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ +#define ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ + +int icm42688_submit(const struct device *sensor, struct rtio_iodev_sqe *iodev_sqe); + +#endif /* ZEPHYR_DRIVERS_SENSOR_ICM42688_RTIO_H_ */ diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index 4bf728b40545..adaecf84baa6 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -32,6 +32,7 @@ static void icm42688_gpio_callback(const struct device *dev, struct gpio_callbac #endif } +#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD) static void icm42688_thread_cb(const struct device *dev) { struct icm42688_dev_data *data = dev->data; @@ -44,8 +45,9 @@ static void icm42688_thread_cb(const struct device *dev) icm42688_unlock(dev); } +#endif -#if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) +#ifdef CONFIG_ICM42688_TRIGGER_OWN_THREAD static void icm42688_thread(void *p1, void *p2, void *p3) { From 5572a27468c215f52298fcd1f88c10f13c842546 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 6 Jun 2023 15:56:38 +0200 Subject: [PATCH 0724/2042] docs: bluetooth: mesh: Add note about storing runtime configuration All public API declared in cfg.h won't schedule storing of the change persistently if BT_MESH_VALID flag is not set. The flag is set after the node is provisioned. Signed-off-by: Pavel Vasilyev --- doc/connectivity/bluetooth/api/mesh/cfg.rst | 4 ++++ doc/connectivity/bluetooth/api/mesh/core.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/doc/connectivity/bluetooth/api/mesh/cfg.rst b/doc/connectivity/bluetooth/api/mesh/cfg.rst index 68bf08506994..01d3c9ca2e52 100644 --- a/doc/connectivity/bluetooth/api/mesh/cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/cfg.rst @@ -14,6 +14,10 @@ cases, the mesh node can't rely on the Configuration Client to detect or determi local constraints, such as low battery power or changes in topology. For these scenarios, this API can be used to change the configuration locally. +.. note:: + Runtime configuration changes before the node is provisioned will not be stored + in the :ref:`persistent storage `. + API reference ************* diff --git a/doc/connectivity/bluetooth/api/mesh/core.rst b/doc/connectivity/bluetooth/api/mesh/core.rst index 19166b65a09b..b9fdd164257e 100644 --- a/doc/connectivity/bluetooth/api/mesh/core.rst +++ b/doc/connectivity/bluetooth/api/mesh/core.rst @@ -67,6 +67,8 @@ vulnerability and flash wear out. the RPL between reboots, will make the device vulnerable to replay attacks and not perform the replay protection required by the spec. +.. _bluetooth_mesh_persistent_storage: + Persistent storage ****************** From c627164d284b376add902bc87a6c59208c3a3909 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 6 Jun 2023 12:51:16 +0200 Subject: [PATCH 0725/2042] Bluetooth: CSIP: Shell: Fix discover_members The cmd_csip_set_coordinator_discover_members did not properly handle the members_found and addr_found values. It has been modified to run through all known values before scanning, and set the value appropriately. This also fixes a minor bug where err = 0 was missing. Signed-off-by: Emil Gydesen --- .../audio/shell/csip_set_coordinator.c | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/shell/csip_set_coordinator.c b/subsys/bluetooth/audio/shell/csip_set_coordinator.c index 9cb747680f77..755807dbb021 100644 --- a/subsys/bluetooth/audio/shell/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/shell/csip_set_coordinator.c @@ -244,7 +244,7 @@ static int cmd_csip_set_coordinator_discover(const struct shell *sh, char addr[BT_ADDR_LE_STR_LEN]; static bool initialized; struct bt_conn *conn; - int err; + int err = 0; if (!initialized) { k_work_init_delayable(&discover_members_timer, @@ -311,10 +311,45 @@ static int cmd_csip_set_coordinator_discover_members(const struct shell *sh, return -EINVAL; } - if (members_found > 1) { - members_found = 1; + /* Reset and populate based on current connections */ + memset(addr_found, 0, sizeof(addr_found)); + members_found = 0; + for (size_t i = 0U; i < ARRAY_SIZE(set_members); i++) { + const struct bt_csip_set_coordinator_set_member *set_member = set_members[i]; + + if (set_member == NULL) { + continue; + } + + for (size_t j = 0U; j < ARRAY_SIZE(set_members[i]->insts); j++) { + const struct bt_csip_set_coordinator_csis_inst *inst = + &set_members[i]->insts[j]; + + if (memcmp(inst->info.set_sirk, cur_inst->info.set_sirk, + BT_CSIP_SET_SIRK_SIZE) == 0) { + bt_addr_le_copy(&addr_found[members_found++], + bt_conn_get_dst(conns[i])); + break; + } + } } + if (cur_inst->info.set_size > 0) { + if (members_found == cur_inst->info.set_size) { + shell_print(sh, "All members already known"); + + return 0; + } else if (members_found > cur_inst->info.set_size) { + shell_error(sh, "Found %u members but set size is %u", members_found, + cur_inst->info.set_size); + + return -ENOEXEC; + } + } + + shell_print(sh, "Already know %u/%u members, start scanning for remaining", members_found, + cur_inst->info.set_size); + err = k_work_reschedule(&discover_members_timer, BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE); if (err < 0) { /* Can return 0, 1 and 2 for success */ From 69fead199828a418c31a2f4f8362e6d94dc703ef Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Tue, 6 Jun 2023 19:44:24 +0530 Subject: [PATCH 0726/2042] net: mgmt: Support for forced Passive scan Default scan mode is Active. User can force the scan mode to passive through Kconfig option or using 'passive' option from shell. Using either of this option will override regulatory settings and forces all scan channels to be passive only. Signed-off-by: Ajay Parida --- drivers/wifi/esp32/src/esp_wifi_drv.c | 9 ++++++++- drivers/wifi/esp_at/esp.c | 6 +++++- drivers/wifi/eswifi/eswifi_core.c | 6 +++++- drivers/wifi/simplelink/simplelink.c | 6 +++++- drivers/wifi/winc1500/wifi_winc1500.c | 6 +++++- include/zephyr/net/wifi.h | 5 +++++ include/zephyr/net/wifi_mgmt.h | 14 +++++++++++++- subsys/net/l2/wifi/Kconfig | 8 ++++++++ subsys/net/l2/wifi/wifi_mgmt.c | 9 ++++++++- subsys/net/l2/wifi/wifi_shell.c | 26 ++++++++++++++++++++++++-- 10 files changed, 86 insertions(+), 9 deletions(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 5f69c88c02d1..5272b6df21e4 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -388,7 +388,9 @@ static int esp32_wifi_connect(const struct device *dev, return 0; } -static int esp32_wifi_scan(const struct device *dev, scan_result_cb_t cb) +static int esp32_wifi_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct esp32_wifi_runtime *data = dev->data; int ret = 0; @@ -402,6 +404,11 @@ static int esp32_wifi_scan(const struct device *dev, scan_result_cb_t cb) wifi_scan_config_t scan_config = { 0 }; + if (params) { + /* The enum values are same, so, no conversion needed */ + scan_config->scan_type = params->scan_type; + } + ret = esp_wifi_set_mode(ESP32_WIFI_MODE_STA); ret |= esp_wifi_scan_start(&scan_config, false); diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 614d7fb517ac..e245c2073ff6 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -899,10 +899,14 @@ static void esp_mgmt_scan_work(struct k_work *work) dev->scan_cb = NULL; } -static int esp_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int esp_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct esp_data *data = dev->data; + ARG_UNUSED(params); + if (data->scan_cb != NULL) { return -EINPROGRESS; } diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index a92991e4552d..44c911831dfe 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -520,10 +520,14 @@ int eswifi_mgmt_iface_status(const struct device *dev, return 0; } -static int eswifi_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int eswifi_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { struct eswifi_dev *eswifi = dev->data; + ARG_UNUSED(params); + LOG_DBG(""); eswifi_lock(eswifi); diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index a959d8c14402..c7e7e9ab725a 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -136,11 +136,15 @@ static void simplelink_scan_work_handler(struct k_work *work) } } -static int simplelink_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int simplelink_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { int err; int status; + ARG_UNUSED(params); + /* Cancel any previous scan processing in progress: */ k_work_cancel_delayable(&simplelink_data.work); diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 19525cc2fd0e..acab7e94d006 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -976,8 +976,12 @@ static void winc1500_thread(void) } } -static int winc1500_mgmt_scan(const struct device *dev, scan_result_cb_t cb) +static int winc1500_mgmt_scan(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb) { + ARG_UNUSED(params); + if (w1500_data.scan_cb) { return -EALREADY; } diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index ae9f8cfa6db4..9c65f3197901 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -264,6 +264,11 @@ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode) } } +enum wifi_scan_type { + WIFI_SCAN_TYPE_ACTIVE = 0, + WIFI_SCAN_TYPE_PASSIVE, +}; + enum wifi_ps { WIFI_PS_DISABLED = 0, WIFI_PS_ENABLED, diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 7f9cb68c5e99..b303d01fc1bd 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -143,6 +143,16 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) + +struct wifi_scan_params { + /* The scan_type is only a hint to the underlying Wi-Fi chip for the + * preferred mode of scan. The actual mode of scan can depend on factors + * such as the Wi-Fi chip implementation support, regulatory domain + * restrictions etc. + */ + enum wifi_scan_type scan_type; +}; + /* Each result is provided to the net_mgmt_event_callback * via its info attribute (see net_mgmt.h) */ @@ -321,7 +331,9 @@ struct net_wifi_mgmt_offload { * result by the driver. The wifi mgmt part will take care of * raising the necessary event etc... */ - int (*scan)(const struct device *dev, scan_result_cb_t cb); + int (*scan)(const struct device *dev, + struct wifi_scan_params *params, + scan_result_cb_t cb); int (*connect)(const struct device *dev, struct wifi_connect_req_params *params); int (*disconnect)(const struct device *dev); diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index 48bcff3943e6..ade546fac7d0 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -38,3 +38,11 @@ config WIFI_MGMT_TWT_CHECK_IP being unreachable (IP Level) or unable to receive down link traffic even when it is awake intervals. Rejecting TWT setup till Wi-Fi interface has a valid IP address might be desirable in most scenarios. + +config WIFI_MGMT_FORCED_PASSIVE_SCAN + bool "Force Passive scan" + help + Force passive scan (typically used to reduce power consumption), + the scan type is always sent as passive. + This doesn't guarantee that passive scan will be used, it depends + on the underlying chip implementation to support and honour scan type. diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 266938b38518..c3bc788132c3 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -84,12 +84,19 @@ static int wifi_scan(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + struct wifi_scan_params *params = data; if (off_api == NULL || off_api->scan == NULL) { return -ENOTSUP; } - return off_api->scan(dev, scan_result_cb); + if (data && (len == sizeof(*params))) { +#ifdef CONFIG_WIFI_MGMT_FORCED_PASSIVE_SCAN + params->scan_type = WIFI_SCAN_TYPE_PASSIVE; +#endif + } + + return off_api->scan(dev, params, scan_result_cb); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN, wifi_scan); diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 9546eaa49fd5..5372f8746d73 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -447,10 +447,29 @@ static int cmd_wifi_disconnect(const struct shell *sh, size_t argc, static int cmd_wifi_scan(const struct shell *sh, size_t argc, char *argv[]) { struct net_if *iface = net_if_get_first_wifi(); + struct wifi_scan_params params = { 0 }; context.sh = sh; - if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) { + if (argc > 2) { + shell_fprintf(sh, SHELL_WARNING, "Invalid number of arguments\n"); + return -ENOEXEC; + } + + if (argc == 2) { + if (!strcmp(argv[1], "passive")) { + params.scan_type = WIFI_SCAN_TYPE_PASSIVE; + } else if (!strcmp(argv[1], "active")) { + params.scan_type = WIFI_SCAN_TYPE_ACTIVE; + } else { + shell_fprintf(sh, SHELL_WARNING, "Invalid argument\n"); + shell_fprintf(sh, SHELL_INFO, + "Valid argument : / \n"); + return -ENOEXEC; + } + } + + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, ¶ms, sizeof(params))) { shell_fprintf(sh, SHELL_WARNING, "Scan request failed\n"); return -ENOEXEC; @@ -1114,7 +1133,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(wifi_commands, cmd_wifi_ps_mode, 2, 0), - SHELL_CMD(scan, NULL, "Scan for Wi-Fi APs", cmd_wifi_scan), + SHELL_CMD(scan, NULL, + "Scan for Wi-Fi APs\n" + " : >\n", + 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), From f1ebbb6c1ff9be5ee4b039c890ce9311e801d676 Mon Sep 17 00:00:00 2001 From: Ajay Parida Date: Mon, 26 Jun 2023 17:59:35 +0530 Subject: [PATCH 0727/2042] doc: release-notes: add passive scan support release notes Added Wi-Fi passive scan support related info. Signed-off-by: Ajay Parida --- doc/releases/release-notes-3.5.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 359fa1f77c27..c3df09560b58 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -223,6 +223,10 @@ Trusted Firmware-M Networking ********** +* Wi-Fi + * Added Passive scan support. + * The Wi-Fi scan API updated with Wi-Fi scan parameter to allow scan mode selection. + USB *** From 11bc9b8dca77da7a374c0d221fe52c156bb18e11 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:24:03 +0000 Subject: [PATCH 0728/2042] boards: arm: mimxrt1170_evkb: add RT1170 EVKB Add RT1170 EVKB definition to Zephyr. This board is similar to the RT1170 EVK, but uses a different quadspi flash chip, and includes an audio connector as well as an additional display connection. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/CMakeLists.txt | 19 ++- boards/arm/mimxrt1170_evk/Kconfig.board | 12 +- boards/arm/mimxrt1170_evk/Kconfig.defconfig | 15 ++- boards/arm/mimxrt1170_evk/doc/index.rst | 109 +++++++++--------- boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi | 3 +- .../arm/mimxrt1170_evk/mimxrt1170_evk_cm4.dts | 4 +- .../mimxrt1170_evk_cm4_defconfig | 3 +- .../mimxrt1170_evk_cm7_defconfig | 3 +- .../mimxrt1170_evk/mimxrt1170_evkb_cm4.dts | 81 +++++++++++++ .../mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml | 21 ++++ .../mimxrt1170_evkb_cm4_defconfig | 16 +++ .../mimxrt1170_evk/mimxrt1170_evkb_cm7.dts | 82 +++++++++++++ .../mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 23 ++++ .../mimxrt1170_evkb_cm7_defconfig | 17 +++ 14 files changed, 339 insertions(+), 69 deletions(-) create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4_defconfig create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml create mode 100644 boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7_defconfig diff --git a/boards/arm/mimxrt1170_evk/CMakeLists.txt b/boards/arm/mimxrt1170_evk/CMakeLists.txt index a3187ed9c2db..571772ea2a15 100644 --- a/boards/arm/mimxrt1170_evk/CMakeLists.txt +++ b/boards/arm/mimxrt1170_evk/CMakeLists.txt @@ -1,26 +1,35 @@ # -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # # SPDX-License-Identifier: Apache-2.0 # if(CONFIG_NXP_IMX_RT_BOOT_HEADER) zephyr_library() - if(NOT (DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM7) - OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM4)) + if(NOT ((DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM7) + OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM4) + OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVKB_CM7) + OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVKB_CM4))) message(WARNING "It appears you are using the board definition for " "the MIMXRT1170-EVK, but targeting a custom board. You may need to " "update your flash configuration or device configuration data blocks") endif() + if ((DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM7) + OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVK_CM4)) + set(RT1170_BOARD_NAME "evkmimxrt1170") + elseif((DEFINED CONFIG_BOARD_MIMXRT1170_EVKB_CM7) + OR (DEFINED CONFIG_BOARD_MIMXRT1170_EVKB_CM4)) + set(RT1170_BOARD_NAME "evkbmimxrt1170") + endif() set(RT1170_BOARD_DIR - "${ZEPHYR_HAL_NXP_MODULE_DIR}/mcux/mcux-sdk/boards/evkmimxrt1170") + "${ZEPHYR_HAL_NXP_MODULE_DIR}/mcux/mcux-sdk/boards/${RT1170_BOARD_NAME}") if(CONFIG_BOOT_FLEXSPI_NOR) # Include flash configuration block for RT1170 EVK from NXP's HAL. # This configuration block may need modification if another flash chip is # used on your custom board. See NXP AN12238 for more information. zephyr_compile_definitions(XIP_BOOT_HEADER_ENABLE=1) zephyr_compile_definitions(BOARD_FLASH_SIZE=CONFIG_FLASH_SIZE*1024) - zephyr_library_sources(${RT1170_BOARD_DIR}/xip/evkmimxrt1170_flexspi_nor_config.c) + zephyr_library_sources(${RT1170_BOARD_DIR}/xip/${RT1170_BOARD_NAME}_flexspi_nor_config.c) zephyr_library_include_directories(${RT1170_BOARD_DIR}/xip) endif() if(CONFIG_DEVICE_CONFIGURATION_DATA) diff --git a/boards/arm/mimxrt1170_evk/Kconfig.board b/boards/arm/mimxrt1170_evk/Kconfig.board index 3e3ee89a609d..b3b5a6e78f87 100644 --- a/boards/arm/mimxrt1170_evk/Kconfig.board +++ b/boards/arm/mimxrt1170_evk/Kconfig.board @@ -1,4 +1,4 @@ -# Copyright (c) 2021, NXP +# Copyright 2021,2023 NXP # SPDX-License-Identifier: Apache-2.0 config BOARD_MIMXRT1170_EVK_CM7 @@ -10,3 +10,13 @@ config BOARD_MIMXRT1170_EVK_CM4 bool "NXP MIMXRT1170-EVK CM4" depends on SOC_MIMXRT1176_CM4 select SOC_PART_NUMBER_MIMXRT1176DVMAA + +config BOARD_MIMXRT1170_EVKB_CM7 + bool "NXP MIMXRT1170-EVKB CM7" + depends on SOC_MIMXRT1176_CM7 + select SOC_PART_NUMBER_MIMXRT1176DVMAA + +config BOARD_MIMXRT1170_EVKB_CM4 + bool "NXP MIMXRT1170-EVKB CM4" + depends on SOC_MIMXRT1176_CM4 + select SOC_PART_NUMBER_MIMXRT1176DVMAA diff --git a/boards/arm/mimxrt1170_evk/Kconfig.defconfig b/boards/arm/mimxrt1170_evk/Kconfig.defconfig index dac37e54ad3d..00d7f158ce61 100644 --- a/boards/arm/mimxrt1170_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1170_evk/Kconfig.defconfig @@ -3,19 +3,22 @@ # Copyright 2021,2023 NXP # SPDX-License-Identifier: Apache-2.0 -if BOARD_MIMXRT1170_EVK_CM7 || BOARD_MIMXRT1170_EVK_CM4 +if BOARD_MIMXRT1170_EVK_CM7 || BOARD_MIMXRT1170_EVK_CM4 || \ + BOARD_MIMXRT1170_EVKB_CM7 || BOARD_MIMXRT1170_EVKB_CM4 config BOARD default "mimxrt1170_evk_cm7" if BOARD_MIMXRT1170_EVK_CM7 default "mimxrt1170_evk_cm4" if BOARD_MIMXRT1170_EVK_CM4 + default "mimxrt1170_evkb_cm7" if BOARD_MIMXRT1170_EVKB_CM7 + default "mimxrt1170_evkb_cm4" if BOARD_MIMXRT1170_EVKB_CM4 choice CODE_LOCATION - default CODE_FLEXSPI if BOARD_MIMXRT1170_EVK_CM7 - default CODE_OCRAM if BOARD_MIMXRT1170_EVK_CM4 && SECOND_CORE_MCUX - default CODE_SRAM0 if BOARD_MIMXRT1170_EVK_CM4 + default CODE_FLEXSPI if CPU_CORTEX_M7 + default CODE_OCRAM if CPU_CORTEX_M4 && SECOND_CORE_MCUX + default CODE_SRAM0 if CPU_CORTEX_M4 endchoice -if SECOND_CORE_MCUX && BOARD_MIMXRT1170_EVK_CM4 +if SECOND_CORE_MCUX && CPU_CORTEX_M4 config BUILD_OUTPUT_INFO_HEADER default y @@ -106,4 +109,4 @@ endchoice endif # LVGL -endif # BOARD_MIMXRT1170_EVK_CM7 || BOARD_MIMXRT1170_EVK_CM4 +endif diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index e302eb544fa5..3d6a9481f9f6 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -1,14 +1,15 @@ .. _mimxrt1170_evk: -NXP MIMXRT1170-EVK -################## +NXP MIMXRT1170-EVK/EVKB +####################### Overview ******** The dual core i.MX RT1170 runs on the Cortex-M7 core at 1 GHz and on the Cortex-M4 at 400 MHz. The i.MX RT1170 MCU offers support over a wide temperature range -and is qualified for consumer, industrial and automotive markets. +and is qualified for consumer, industrial and automotive markets. Zephyr +supports the initial revision of this EVK, as well as EVK rev B. .. image:: mimxrt1170_evk.jpg :align: center @@ -86,55 +87,59 @@ Supported Features NXP considers the MIMXRT1170-EVK as the superset board for the i.MX RT11xx family of MCUs. This board is a focus for NXP's Full Platform Support for Zephyr, to better enable the entire RT11xx family. NXP prioritizes enabling -this board with new support for Zephyr features. The mimxrt1170_evk board -configuration supports the following hardware features: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| GPIO | on-chip | gpio | -+-----------+------------+-------------------------------------+ -| COUNTER | on-chip | counter | -+-----------+------------+-------------------------------------+ -| CAN | on-chip | flexcan | -+-----------+------------+-------------------------------------+ -| SPI | on-chip | spi | -+-----------+------------+-------------------------------------+ -| I2C | on-chip | i2c | -+-----------+------------+-------------------------------------+ -| PWM | on-chip | pwm | -+-----------+------------+-------------------------------------+ -| ADC | on-chip | adc | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port-polling; | -| | | serial port-interrupt | -+-----------+------------+-------------------------------------+ -| DMA | on-chip | dma | -+-----------+------------+-------------------------------------+ -| GPT | on-chip | gpt | -+-----------+------------+-------------------------------------+ -| WATCHDOG | on-chip | watchdog | -+-----------+------------+-------------------------------------+ -| ENET | on-chip | ethernet | -+-----------+------------+-------------------------------------+ -| SAI | on-chip | i2s | -+-----------+------------+-------------------------------------+ -| USB | on-chip | USB Device | -+-----------+------------+-------------------------------------+ -| HWINFO | on-chip | Unique device serial number | -+-----------+------------+-------------------------------------+ -| DISPLAY | on-chip | display | -+-----------+------------+-------------------------------------+ -| ACMP | on-chip | analog comparator | -+-----------+------------+-------------------------------------+ -| CAAM RNG | on-chip | entropy | -+-----------+------------+-------------------------------------+ -| FLEXSPI | on-chip | flash programming | -+-----------+------------+-------------------------------------+ +this board with new support for Zephyr features. Note that this table +covers two boards: the RT1170 EVK (`mimxrt1170_evk_cm7/cm4`), and +RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) + ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| Interface | Controller | Driver/Component | RT1170 EVK | RT1170 EVKB | ++===========+============+=====================================+=================+=================+ +| NVIC | on-chip | nested vector interrupt controller | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| SYSTICK | on-chip | systick | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| GPIO | on-chip | gpio | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| COUNTER | on-chip | gpt | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| CAN | on-chip | flexcan | Supported (M7) | Supported (M7) | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| SPI | on-chip | spi | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| I2C | on-chip | i2c | Supported | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| PWM | on-chip | pwm | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| ADC | on-chip | adc | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| UART | on-chip | serial port-polling; | Supported | Supported | +| | | serial port-interrupt; | | | +| | | serial port-async | | | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| DMA | on-chip | dma | Supported | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| GPT | on-chip | gpt | Supported | Supported | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| WATCHDOG | on-chip | watchdog | Supported (M7) | Supported (M7) | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| ENET | on-chip | ethernet | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| SAI | on-chip | i2s | Supported | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| USB | on-chip | USB Device | Supported (M7) | Supported (M7) | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| HWINFO | on-chip | Unique device serial number | Supported (M7) | Supported (M7) | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| DISPLAY | on-chip | display | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| ACMP | on-chip | analog comparator | Supported | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| CAAM RNG | on-chip | entropy | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| FLEXSPI | on-chip | flash programming | Supported (M7) | No support | ++-----------+------------+-------------------------------------+-----------------+-----------------+ +| SDHC | on-chip | SD host controller | Supported (M7) | Supported (M7) | ++-----------+------------+-------------------------------------+-----------------+-----------------+ The default configuration can be found in the defconfig file: ``boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7_defconfig`` diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi index 7a66df05d96f..bd6739d5ca77 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,7 @@ magn0 = &fxos8700; accel0 = &fxos8700; sdhc0 = &usdhc1; + pwm-led0 = &green_pwm_led; }; leds { diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4.dts index c4402d7fec34..cbef2377dab1 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, NXP + * Copyright 2021,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,7 +25,7 @@ zephyr,shell-uart = &lpuart1; zephyr,canbus = &flexcan2; zephyr,flash-controller = &is25wp128; - zephyr,flash = &is25wp128; + zephyr,flash = &sram0; nxp,m4-partition = &slot1_partition; zephyr,ipc = &mailbox_b; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4_defconfig b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4_defconfig index 0f35d0fc274e..dacbbf3e1d2a 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4_defconfig +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm4_defconfig @@ -1,9 +1,10 @@ # -# Copyright (c) 2021, NXP +# Copyright 2021,2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +CONFIG_BOARD_MIMXRT1170_EVK_CM4=y CONFIG_SOC_MIMXRT1176_CM4=y CONFIG_SOC_SERIES_IMX_RT=y CONFIG_CONSOLE=y diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7_defconfig b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7_defconfig index d6835e582bcd..db4c2d5c5a88 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7_defconfig +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7_defconfig @@ -1,9 +1,10 @@ # -# Copyright (c) 2021, NXP +# Copyright 2021,2023 NXP # # SPDX-License-Identifier: Apache-2.0 # +CONFIG_BOARD_MIMXRT1170_EVK_CM7=y CONFIG_SOC_MIMXRT1176_CM7=y CONFIG_SOC_SERIES_IMX_RT=y CONFIG_CONSOLE=y diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts new file mode 100644 index 000000000000..ba170241404b --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts @@ -0,0 +1,81 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mimxrt1170_evk_cm4.dts" + +/ { + chosen { + /delete-property/ zephyr,flash-controller; + /delete-property/ zephyr,code-partition; + }; + + aliases { + /delete-property/ magn0; + /delete-property/ accel0; + }; +}; + +&flexspi { + /* RT1170 EVKB uses a different QSPI flash chip */ + /delete-node/ is25wp128@0; + status = "okay"; + reg = <0x400cc000 0x4000>, <0x30000000 DT_SIZE_M(64)>; + w25q512nw:w25q512nw@0 { + /* IS25WP128 flash chip not currently enabled */ + compatible = "nxp,imx-flexspi-nor"; + size = ; + reg = <0>; + spi-max-frequency = <133000000>; + status = "okay"; + jedec-id = [ef 60 20]; + erase-block-size = <4096>; + write-block-size = <1>; + + /* + * Partitions are present to support dual core operation. + * as flash write is not supported, MCUBoot is not enabled. + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(128)>; + }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 0x301000>; + }; + slot1_partition: partition@321000 { + label = "image-1"; + reg = <0x00321000 0x300000>; + }; + scratch_partition: partition@621000 { + label = "image-scratch"; + reg = <0x00621000 DT_SIZE_K(128)>; + }; + storage_partition: partition@641000 { + label = "storage"; + reg = <0x00641000 DT_SIZE_K(1856)>; + }; + }; + }; +}; + +&lpi2c5 { + /* FXOS accelerometer is not present in this board */ + /delete-node/ fxos8700@1f; +}; + +/* Disable ethernet, as PHY is not supported */ +&enet { + status = "disabled"; +}; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml new file mode 100644 index 000000000000..9eef40b73115 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml @@ -0,0 +1,21 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: mimxrt1170_evkb_cm4 +name: NXP MIMXRT1170-EVKB CM4 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 128 +flash: 128 +supported: + - dma + - gpio + - i2c + - pwm diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4_defconfig b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4_defconfig new file mode 100644 index 000000000000..b1dd310aa4bf --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4_defconfig @@ -0,0 +1,16 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BOARD_MIMXRT1170_EVKB_CM4=y +CONFIG_SOC_MIMXRT1176_CM4=y +CONFIG_SOC_SERIES_IMX_RT=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_PINCTRL=y diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts new file mode 100644 index 000000000000..e93f701cd875 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts @@ -0,0 +1,82 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mimxrt1170_evk_cm7.dts" + +/ { + chosen { + zephyr,flash = &w25q512nw; + /delete-property/ zephyr,flash-controller; + /delete-property/ zephyr,code-partition; + }; + + aliases { + /delete-property/ magn0; + /delete-property/ accel0; + }; +}; + +&flexspi { + /* RT1170 EVKB uses a different QSPI flash chip */ + /delete-node/ is25wp128@0; + status = "okay"; + reg = <0x400cc000 0x4000>, <0x30000000 DT_SIZE_M(64)>; + w25q512nw:w25q512nw@0 { + /* IS25WP128 flash chip not currently enabled */ + compatible = "nxp,imx-flexspi-nor"; + size = ; + reg = <0>; + spi-max-frequency = <133000000>; + status = "okay"; + jedec-id = [ef 60 20]; + erase-block-size = <4096>; + write-block-size = <1>; + + /* + * Partitions are present to support dual core operation. + * as flash write is not supported, MCUBoot is not enabled. + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(128)>; + }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 0x301000>; + }; + slot1_partition: partition@321000 { + label = "image-1"; + reg = <0x00321000 0x300000>; + }; + scratch_partition: partition@621000 { + label = "image-scratch"; + reg = <0x00621000 DT_SIZE_K(128)>; + }; + storage_partition: partition@641000 { + label = "storage"; + reg = <0x00641000 DT_SIZE_K(1856)>; + }; + }; + }; +}; + +&lpi2c5 { + /* FXOS accelerometer is not present in this board */ + /delete-node/ fxos8700@1f; +}; + +/* Disable ethernet, as PHY is not supported */ +&enet { + status = "disabled"; +}; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml new file mode 100644 index 000000000000..59d8ae3f5cc9 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -0,0 +1,23 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +identifier: mimxrt1170_evkb_cm7 +name: NXP MIMXRT1170-EVKB CM7 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 65536 +flash: 65536 +supported: + - counter + - can + - gpio + - hwinfo + - usb_device + - watchdog diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7_defconfig b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7_defconfig new file mode 100644 index 000000000000..a59d2e39e479 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7_defconfig @@ -0,0 +1,17 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_BOARD_MIMXRT1170_EVKB_CM7=y +CONFIG_SOC_MIMXRT1176_CM7=y +CONFIG_SOC_SERIES_IMX_RT=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_FLEXSPI_CONFIG_BLOCK_OFFSET=0x400 +CONFIG_PINCTRL=y From 74ffb99a72ef297a4e63afb5a8170a539189168b Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:25:18 +0000 Subject: [PATCH 0729/2042] boards: arm: mixmrt1170_evkb: add support for ADC Add support for ADC sample and API test on RT1170 EVKB. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 2 +- .../mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 1 + .../adc/boards/mimxrt1170_evkb_cm7.overlay | 34 ++++++++++++++++++ .../boards/mimxrt1170_evkb_cm7.overlay | 36 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/adc/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 tests/drivers/adc/adc_api/boards/mimxrt1170_evkb_cm7.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 3d6a9481f9f6..3c697cf4c21a 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -110,7 +110,7 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) +-----------+------------+-------------------------------------+-----------------+-----------------+ | PWM | on-chip | pwm | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| ADC | on-chip | adc | Supported (M7) | No support | +| ADC | on-chip | adc | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ | UART | on-chip | serial port-polling; | Supported | Supported | | | | serial port-interrupt; | | | diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml index 59d8ae3f5cc9..db79cb830569 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -15,6 +15,7 @@ toolchain: ram: 65536 flash: 65536 supported: + - adc - counter - can - gpio diff --git a/samples/drivers/adc/boards/mimxrt1170_evkb_cm7.overlay b/samples/drivers/adc/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..490660fb3c6f --- /dev/null +++ b/samples/drivers/adc/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2023 NXP + */ + +#include + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&lpadc0 0>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + /* + * To use this sample: + * - Connect LPADC0 CH0 signal to voltage between 0~1.8V (J9 pin 10) + */ + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,vref-mv = <1800>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/tests/drivers/adc/adc_api/boards/mimxrt1170_evkb_cm7.overlay b/tests/drivers/adc/adc_api/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..95093c47b6e1 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2023 NXP + */ + +#include + +/ { + zephyr,user { + io-channels = <&lpadc0 0>, <&lpadc0 1>; + }; +}; + +&lpadc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL0"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; From 968ba5190d6688d1fdcdcbe711d948638e6d2b33 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:26:04 +0000 Subject: [PATCH 0730/2042] boards: arm: mimxrt1170_evkb: add support for DMA test Enable DMA test for RT1170 EVKB Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 2 +- boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 1 + .../chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay | 7 +++++++ .../dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay | 7 +++++++ .../dma/loop_transfer/boards/mimxrt1170_evkb_cm7.overlay | 7 +++++++ 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 3c697cf4c21a..2026327ac4dd 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -116,7 +116,7 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) | | | serial port-interrupt; | | | | | | serial port-async | | | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| DMA | on-chip | dma | Supported | No support | +| DMA | on-chip | dma | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ | GPT | on-chip | gpt | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml index db79cb830569..78c5e090fd72 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -18,6 +18,7 @@ supported: - adc - counter - can + - dma - gpio - hwinfo - usb_device 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 new file mode 100644 index 000000000000..c2d4a85453f4 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 000000000000..c2d4a85453f4 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &edma_lpsr0 { }; diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.overlay b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..afc9c1b2495a --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &edma0 { }; From 903cfc8f1521f24b544f680818dfaf215761d9a3 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:26:54 +0000 Subject: [PATCH 0731/2042] boards: arm : mimxrt1170_evkb: add support for I2C Add support for I2C on RT1170 EVKB, verified using I2C target API test. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 2 +- .../mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 1 + .../boards/mimxrt1170_evkb_cm4.overlay | 25 +++++++++++++++++++ .../boards/mimxrt1170_evkb_cm7.overlay | 25 +++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm7.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 2026327ac4dd..c886b65384e5 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -106,7 +106,7 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) +-----------+------------+-------------------------------------+-----------------+-----------------+ | SPI | on-chip | spi | Supported (M7) | No support | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| I2C | on-chip | i2c | Supported | No support | +| I2C | on-chip | i2c | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ | PWM | on-chip | pwm | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml index 78c5e090fd72..ad1dcaa4fcc8 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -21,5 +21,6 @@ supported: - dma - gpio - hwinfo + - i2c - usb_device - watchdog diff --git a/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 000000000000..4e17adc5dce5 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* To test this sample, connect J26.12 <-> J10.20 and J26.10 <-> J10.18 */ + +&lpi2c1 { + status = "okay"; + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&lpi2c5 { + status = "okay"; + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; diff --git a/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm7.overlay b/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..4e17adc5dce5 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* To test this sample, connect J26.12 <-> J10.20 and J26.10 <-> J10.18 */ + +&lpi2c1 { + status = "okay"; + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&lpi2c5 { + status = "okay"; + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; From 2ef5eb977210281d281fab9cf3579f7eff38dbd7 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:28:07 +0000 Subject: [PATCH 0732/2042] boards: arm: mimxrt1170_evkb: add support for SPI Add support for SPI on RT1170 EVKB, verified using SPI loopback sample. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 2 +- .../arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts | 4 ++++ .../mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml | 1 + .../mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 1 + .../boards/mimxrt1170_evkb_cm4.overlay | 18 ++++++++++++++++++ .../boards/mimxrt1170_evkb_cm7.overlay | 18 ++++++++++++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm7.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index c886b65384e5..14b6669ee7a6 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -104,7 +104,7 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) +-----------+------------+-------------------------------------+-----------------+-----------------+ | CAN | on-chip | flexcan | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| SPI | on-chip | spi | Supported (M7) | No support | +| SPI | on-chip | spi | Supported (M7) | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ | I2C | on-chip | i2c | Supported | Supported | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts index ba170241404b..727ada86cd35 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts @@ -70,6 +70,10 @@ }; }; +&lpspi1 { + status = "okay"; +}; + &lpi2c5 { /* FXOS accelerometer is not present in this board */ /delete-node/ fxos8700@1f; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml index 9eef40b73115..e9519f594cd1 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.yaml @@ -18,4 +18,5 @@ supported: - dma - gpio - i2c + - spi - pwm diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml index ad1dcaa4fcc8..a2a26721ae06 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -22,5 +22,6 @@ supported: - gpio - hwinfo - i2c + - spi - usb_device - watchdog diff --git a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm4.overlay b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 000000000000..fa2b906bbd7c --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&lpspi1 { + slow@0 { + compatible = "test-spi-loopback-slow"; + reg = <0>; + spi-max-frequency = <500000>; + }; + fast@0 { + compatible = "test-spi-loopback-fast"; + reg = <0>; + spi-max-frequency = <16000000>; + }; +}; diff --git a/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm7.overlay b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..fa2b906bbd7c --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&lpspi1 { + 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 d5329d1391a92da77a48839dd7718ce8898b0563 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 17:29:46 +0000 Subject: [PATCH 0733/2042] boards: arm: mixmrt1170_evkb: enable display support Enable display support for RT1170 EVKB, using display sample with RK055HDMIPI4M display. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 2 +- boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml | 2 ++ samples/drivers/display/boards/mimxrt1170_evkb_cm7.conf | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/display/boards/mimxrt1170_evkb_cm7.conf diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 14b6669ee7a6..4483f35ea901 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -130,7 +130,7 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) +-----------+------------+-------------------------------------+-----------------+-----------------+ | HWINFO | on-chip | Unique device serial number | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| DISPLAY | on-chip | display | Supported (M7) | No support | +| DISPLAY | on-chip | display | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ | ACMP | on-chip | analog comparator | Supported | No support | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml index a2a26721ae06..5da139df53ee 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.yaml @@ -22,6 +22,8 @@ supported: - gpio - hwinfo - i2c + - kscan:touch + - mipi_dsi - spi - usb_device - watchdog diff --git a/samples/drivers/display/boards/mimxrt1170_evkb_cm7.conf b/samples/drivers/display/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 000000000000..072545354b96 --- /dev/null +++ b/samples/drivers/display/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,7 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_HEAP_MEM_POOL_SIZE=4194304 From 90e3650acf9b624b0e533fb13c633b1a7bfd5754 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 23:11:49 +0000 Subject: [PATCH 0734/2042] samples: ipc: enable openamp sample for RT1170 EVKB Enable openamp sample for RT1170 EVKB. Signed-off-by: Daniel DeGrasse --- samples/subsys/ipc/openamp/Kconfig.sysbuild | 3 +- .../openamp/boards/mimxrt1170_evkb_cm7.conf | 7 +++ .../boards/mimxrt1170_evkb_cm7.overlay | 22 +++++++++ .../remote/boards/mimxrt1170_evkb_cm4.conf | 8 +++ .../remote/boards/mimxrt1170_evkb_cm4.overlay | 49 +++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.conf create mode 100644 samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.conf create mode 100644 samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay diff --git a/samples/subsys/ipc/openamp/Kconfig.sysbuild b/samples/subsys/ipc/openamp/Kconfig.sysbuild index 0247dcb45b8d..7a7963ad16f1 100644 --- a/samples/subsys/ipc/openamp/Kconfig.sysbuild +++ b/samples/subsys/ipc/openamp/Kconfig.sysbuild @@ -1,4 +1,4 @@ -# Copyright 2022 NXP +# Copyright 2022-2023 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -12,3 +12,4 @@ string default "v2m_musca_b1_ns" if $(BOARD) = "v2m_musca_b1" default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.conf b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 000000000000..ae8dba8cc217 --- /dev/null +++ b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,7 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..39e6c6896e7f --- /dev/null +++ b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,22 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,ipc_shm = &ocram2_overlay; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set. + */ + ocram2_overlay: memory@202c0000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-region-mpu = "IO"; + }; +}; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.conf b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 000000000000..7b43b448c72c --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,8 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 000000000000..9cdfe651f055 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + /* Switch to lpuart2, since primary core uses lpuart1 */ + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + zephyr,ipc_shm = &ocram2_overlay; + }; + + 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"; + }; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-region-mpu = "IO"; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; From f4550dbda8dcff1525e8760f736726367fbd78b7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:12:38 +0200 Subject: [PATCH 0735/2042] Bluetooth: TBS: Guard check for MAX_TBS_INSTANCES Add check for CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 1 before comparing inst_cnt, as otherwise it was always false which caused a coverity issue. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/tbs_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 52f844c783a4..3f4c61acfa6d 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1589,7 +1589,8 @@ static uint8_t primary_discover_tbs(struct bt_conn *conn, const struct bt_gatt_a srv_inst->current_inst->start_handle = attr->handle + 1; srv_inst->current_inst->end_handle = prim_service->end_handle; - if (srv_inst->inst_cnt < CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES) { + if (CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 1 && + srv_inst->inst_cnt < CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES) { return BT_GATT_ITER_CONTINUE; } } From 9694e85614f930b288f4396f539b2158b8c247e5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 23 Jun 2023 09:55:58 +0200 Subject: [PATCH 0736/2042] Bluetooth: ascs: Drop ISO PDUs if ASE is not in streaming state This fixes missing drop of ISO Data PDUs received in non-streaming state. The server shall indicate first it's readiness to receive the ISO Data by calling bt_bap_stream_start that triggers state transition from Enabling to Streaming state. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index fd79ed245bd8..20372beaf894 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -671,10 +671,12 @@ static void ascs_iso_recv(struct bt_iso_chan *chan, return; } - if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA) && - ep->status.state != BT_BAP_EP_STATE_STREAMING) { - LOG_DBG("ep %p is not in the streaming state: %s", ep, - bt_bap_ep_state_str(ep->status.state)); + if (ep->status.state != BT_BAP_EP_STATE_STREAMING) { + if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) { + LOG_DBG("ep %p is not in the streaming state: %s", ep, + bt_bap_ep_state_str(ep->status.state)); + } + return; } From 91ad386cb5dd359a997fbce964f6a4fd246b6357 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 23 Jun 2023 10:02:09 +0200 Subject: [PATCH 0737/2042] tests: Bluetooth: ascs: Add ISO Data PDU recv tests This adds tests for receiving ISO Data PDU. * test_recv_in_streaming_state - test whether received ISO Data PDU is sent to upper layers. * test_recv_in_enabling_state - test whether received ISO Data PDu is dropped because upper layer is not ready to receive the data yet. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/main.c | 58 ++++++++++++++++++++++ tests/bluetooth/audio/mocks/CMakeLists.txt | 1 + tests/bluetooth/audio/mocks/src/net_buf.c | 13 +++++ 3 files changed, 72 insertions(+) create mode 100644 tests/bluetooth/audio/mocks/src/net_buf.c diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 4133bb08d7ca..5bee5fc955d3 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -421,3 +421,61 @@ ZTEST_F(ascs_test_suite, test_release_stream_pair_on_acl_disconnection_server_te bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); } + +ZTEST_F(ascs_test_suite, test_recv_in_streaming_state) +{ + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + uint8_t ase_id = fixture->ase_snk.id; + struct bt_iso_recv_info info = { + .seq_num = 1, + .flags = BT_ISO_FLAGS_VALID, + }; + struct bt_iso_chan *chan; + struct net_buf buf; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); + + bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + test_preamble_state_streaming(conn, ase_id, stream, &chan, false); + + chan->ops->recv(chan, &info, &buf); + + /* Verification */ + expect_bt_bap_stream_ops_recv_called_once(stream, &info, &buf); + + bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); +} + +ZTEST_F(ascs_test_suite, test_recv_in_enabling_state) +{ + struct bt_bap_stream *stream = &fixture->stream; + struct bt_conn *conn = &fixture->conn; + uint8_t ase_id = fixture->ase_snk.id; + struct bt_iso_recv_info info = { + .seq_num = 1, + .flags = BT_ISO_FLAGS_VALID, + }; + struct bt_iso_chan *chan; + struct net_buf buf; + int err; + + Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); + + bt_bap_unicast_server_register_cb(&mock_bap_unicast_server_cb); + + 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); + + test_mocks_reset(); + + chan->ops->recv(chan, &info, &buf); + + /* Verification */ + expect_bt_bap_stream_ops_recv_not_called(); + + bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb); +} diff --git a/tests/bluetooth/audio/mocks/CMakeLists.txt b/tests/bluetooth/audio/mocks/CMakeLists.txt index 7129fccc99a1..b61387615816 100644 --- a/tests/bluetooth/audio/mocks/CMakeLists.txt +++ b/tests/bluetooth/audio/mocks/CMakeLists.txt @@ -16,6 +16,7 @@ add_library(mocks STATIC src/iso.c src/kernel.c src/mem_slab.c + src/net_buf.c src/pacs.c ) diff --git a/tests/bluetooth/audio/mocks/src/net_buf.c b/tests/bluetooth/audio/mocks/src/net_buf.c new file mode 100644 index 000000000000..70b854266733 --- /dev/null +++ b/tests/bluetooth/audio/mocks/src/net_buf.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +void net_buf_unref(struct net_buf *buf) +{ + +} From 7b94d57b3274b632dfc75b7f26632504e6d93896 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 23 Jun 2023 10:49:05 +0200 Subject: [PATCH 0738/2042] Bluetooth: unicast_client: Drop ISO PDUs if ASE is not in streaming state This fixes missing drop of ISO Data PDUs received in non-streaming state. The client shall indicate first it's readiness to receive the ISO Data. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/bap_unicast_client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 37b243acfdc7..8389aa0581f7 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -235,10 +235,12 @@ static void unicast_client_ep_iso_recv(struct bt_iso_chan *chan, return; } - if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA) && - ep->status.state != BT_BAP_EP_STATE_STREAMING) { - LOG_DBG("ep %p is not in the streaming state: %s", ep, - bt_bap_ep_state_str(ep->status.state)); + if (ep->status.state != BT_BAP_EP_STATE_STREAMING) { + if (IS_ENABLED(CONFIG_BT_BAP_DEBUG_STREAM_DATA)) { + LOG_DBG("ep %p is not in the streaming state: %s", ep, + bt_bap_ep_state_str(ep->status.state)); + } + return; } From a32ba627ce4bc051f6c7f6b998ae70216c5fdc71 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 23 Jun 2023 15:24:51 +0200 Subject: [PATCH 0739/2042] Bluetooth: BAP: Shell: Improve printing of the BASE Add offsets for each layer in the BASE and add printing of the presentation delay. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 18c154aed0ac..c45333b97cb9 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -1566,13 +1566,14 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba } shell_print(ctx_shell, "Received BASE from sink %p:", sink); + shell_print(ctx_shell, "Presentation delay: %u", base->pd); for (int i = 0; i < base->subgroup_count; i++) { const struct bt_bap_base_subgroup *subgroup; subgroup = &base->subgroups[i]; - shell_print(ctx_shell, "Subgroup[%d]:", i); + shell_print(ctx_shell, "%2sSubgroup[%d]:", "", i); print_codec(ctx_shell, &subgroup->codec); for (int j = 0; j < subgroup->bis_count; j++) { @@ -1580,8 +1581,7 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba bis_data = &subgroup->bis_data[j]; - shell_print(ctx_shell, "BIS[%d] index 0x%02x", - i, bis_data->index); + shell_print(ctx_shell, "%4sBIS[%d] index 0x%02x", "", i, bis_data->index); bis_indexes[index_count++] = bis_data->index; for (int k = 0; k < bis_data->data_count; k++) { @@ -1589,10 +1589,8 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba codec_data = &bis_data->data[k]; - shell_print(ctx_shell, - "data #%u: type 0x%02x len %u", - i, codec_data->data.type, - codec_data->data.data_len); + shell_print(ctx_shell, "%6sdata #%u: type 0x%02x len %u", "", i, + codec_data->data.type, codec_data->data.data_len); shell_hexdump(ctx_shell, codec_data->data.data, codec_data->data.data_len - sizeof(codec_data->data.type)); From db5767e50f30736108e2d4e99fb8ecc79c41ab39 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 27 Jun 2023 08:38:33 +0200 Subject: [PATCH 0740/2042] Bluetooth: audio: Accept empty CCID list in audio metadata The CCID list can be empty, as the Assigned Numbers is not strict regarding it's minimum length. Fixes: #59666 Signed-off-by: Mariusz Skamra --- samples/bluetooth/hap_ha/src/bap_unicast_sr.c | 7 +------ samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c | 7 +------ samples/bluetooth/unicast_audio_server/src/main.c | 7 +------ subsys/bluetooth/audio/shell/bap.c | 7 +------ tests/bluetooth/tester/src/btp_bap.c | 7 +------ tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c | 7 +------ tests/bsim/bluetooth/audio/src/cap_acceptor_test.c | 7 +------ 7 files changed, 7 insertions(+), 42 deletions(-) diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index b6c1de0a1b0b..dd32065ecb63 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -297,12 +297,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; diff --git a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c index efecfaec92fe..645c32875b75 100644 --- a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c +++ b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c @@ -246,12 +246,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 8197a9f5e314..1c340689cd1d 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -438,12 +438,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index c45333b97cb9..a68f354f6b76 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -518,12 +518,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index 4ef9f1b68f94..e1eba8d2aea0 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -360,12 +360,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; 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 88ab2fd7164e..e97c6b24de3a 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -189,12 +189,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index eae27963e580..1ea1b9f8abf1 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -354,12 +354,7 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_CCID_LIST: /* 2 - 254 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; From 17223f136fb7679f6c5257aca2cf67c83c250794 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 27 Jun 2023 14:34:41 +0200 Subject: [PATCH 0741/2042] Bluetooth: audio: Fix metadata length checks This fixes metadata length checks for BT_AUDIO_METADATA_TYPE_EXTENDED and BT_AUDIO_METADATA_TYPE_VENDOR that should be at least 2 bytes long. Signed-off-by: Mariusz Skamra --- samples/bluetooth/hap_ha/src/bap_unicast_sr.c | 7 ++++--- samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c | 7 ++++--- samples/bluetooth/unicast_audio_server/src/main.c | 7 ++++--- subsys/bluetooth/audio/shell/bap.c | 7 ++++--- tests/bluetooth/tester/src/btp_bap.c | 7 ++++--- tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c | 7 ++++--- tests/bsim/bluetooth/audio/src/cap_acceptor_test.c | 7 ++++--- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index dd32065ecb63..23814b139ada 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -290,9 +290,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } diff --git a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c index 645c32875b75..0206238cc6b9 100644 --- a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c +++ b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c @@ -239,9 +239,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 1c340689cd1d..8a2f40b4454d 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -431,9 +431,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index a68f354f6b76..9b9887ea38a2 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -511,9 +511,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index e1eba8d2aea0..4954d616e49b 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -353,9 +353,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } 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 e97c6b24de3a..b98b345e7be1 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -182,9 +182,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 1ea1b9f8abf1..12632e216e5f 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -347,9 +347,10 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } return true; - case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 1 - 255 octets */ - case BT_AUDIO_METADATA_TYPE_VENDOR: /* 1 - 255 octets */ - if (len < 1) { + case BT_AUDIO_METADATA_TYPE_EXTENDED: /* 2 - 255 octets */ + case BT_AUDIO_METADATA_TYPE_VENDOR: /* 2 - 255 octets */ + /* At least Extended Metadata Type / Company_ID should be there */ + if (len < 2) { return false; } From 737afd31fedf0637d3b71ea1d0c08148f12d6938 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 27 Jun 2023 11:26:02 +0200 Subject: [PATCH 0742/2042] doc: bluetooth: mesh: Add dfu cli cancel command to doc Add description of the `mesh model dfu cli cancel` shell command. Signed-off-by: Pavel Vasilyev --- doc/connectivity/bluetooth/api/mesh/shell.rst | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 7a3f2e1b291e..e70d426a6ed1 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -1108,6 +1108,16 @@ The Firmware Update Client model can be added to the mesh shell by enabling conf * ``Group``: Optional group address to use when communicating with the Target nodes. If omitted, the Firmware Update Client will address each Target node individually. +``mesh models dfu cli cancel []`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Cancel the DFU procedure at any state on a specific Target node or on all Target nodes. + When a Target node address is provided, the Firmware Update Client model will try to cancel the DFU procedure on the provided Target node. + Otherwise, the Firmware Update Client model will try to cancel the ongoing DFU procedure on all Target nodes. + + * ``Addr``: Optional unicast address of a Target node on which to cancel the DFU procedure. + + ``mesh models dfu cli apply`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1120,12 +1130,6 @@ The Firmware Update Client model can be added to the mesh shell by enabling conf Confirm that the most recent DFU transfer was successfully applied on all Target nodes. Can only be called after a DFU transfer is completed and applied. -``mesh models dfu cli progress`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Check the progress of the current transfer. - - ``mesh models dfu cli suspend`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1137,11 +1141,13 @@ The Firmware Update Client model can be added to the mesh shell by enabling conf Resume the suspended DFU transfer. -``mesh models dfu srv progress`` + +``mesh models dfu cli progress`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Check the progress of the current transfer. + ``mesh models dfu cli instance-set `` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 007dc6d98fa9bc06d5640565a61bfabd51ffeadb Mon Sep 17 00:00:00 2001 From: Ibe Van de Veire Date: Wed, 28 Jun 2023 14:06:32 +0200 Subject: [PATCH 0743/2042] drivers: uart: atmel_sam: Added reset after error check Following the sam4s datasheet, the OVRE, PARE and FRAME flags should be cleared after a uart error occured. This is done writing a 1 to the RSTSTA bit in the UART_CR. Signed-off-by: Ibe Van de Veire --- drivers/serial/uart_sam.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/serial/uart_sam.c b/drivers/serial/uart_sam.c index 1796395965a2..0173c15b6bc8 100644 --- a/drivers/serial/uart_sam.c +++ b/drivers/serial/uart_sam.c @@ -91,6 +91,8 @@ static int uart_sam_err_check(const struct device *dev) errors |= UART_ERROR_FRAMING; } + uart->UART_CR = UART_CR_RSTSTA; + return errors; } From 40d224022608a3e5d68e95cc4d6f7606f1d48fb2 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 29 Jun 2023 16:38:40 +0200 Subject: [PATCH 0744/2042] net: context: set default offloaded iface during net_context_get() Set default offloaded interface during net_context_get() call, so that net_context_recv() can be called before net_context_connect(). There is already an assumption about using default network interface, so this should not be harmful. Fixes: 2c7507036050 ("net: sockets: tcp: Fix possible race between connect/recv") Signed-off-by: Marcin Niestroj --- subsys/net/ip/net_context.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 571e08c2aebf..a32a673de4ac 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -337,6 +337,8 @@ int net_context_get(sa_family_t family, enum net_sock_type type, uint16_t proto, *context = NULL; return ret; } + + net_context_set_iface(*context, net_if_get_default()); } return 0; From 33b116407b03883efd889f75d69f5bc753b7ade3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 21:27:38 +0200 Subject: [PATCH 0745/2042] arch: arm: cortex_m: scb: fix MPU code compilation guards The implementation of `z_arm_clear_arm_mpu_config` was compiled for all ARM cores that declare to have an MPU. However, we only want to compile it if the MPU is actually enabled. Signed-off-by: Gerard Marull-Paretas --- arch/arm/core/aarch32/cortex_m/scb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/core/aarch32/cortex_m/scb.c b/arch/arm/core/aarch32/cortex_m/scb.c index 5c664166ff9e..3e19db8b43bd 100644 --- a/arch/arm/core/aarch32/cortex_m/scb.c +++ b/arch/arm/core/aarch32/cortex_m/scb.c @@ -41,6 +41,7 @@ void __weak sys_arch_reboot(int type) NVIC_SystemReset(); } +#if defined(CONFIG_ARM_MPU) #if defined(CONFIG_CPU_HAS_ARM_MPU) /** * @@ -75,6 +76,7 @@ void z_arm_clear_arm_mpu_config(void) } } #endif /* CONFIG_CPU_HAS_NXP_MPU */ +#endif /* CONFIG_ARM_MPU */ #if defined(CONFIG_INIT_ARCH_HW_AT_BOOT) /** @@ -96,10 +98,10 @@ void z_arm_init_arch_hw_at_boot(void) /* Initialize System Control Block components */ -#if defined(CONFIG_CPU_HAS_ARM_MPU) || defined(CONFIG_CPU_HAS_NXP_MPU) +#if defined(CONFIG_ARM_MPU) /* Clear MPU region configuration */ z_arm_clear_arm_mpu_config(); -#endif /* CONFIG_CPU_HAS_ARM_MPU */ +#endif /* CONFIG_ARM_MPU */ /* Disable NVIC interrupts */ for (uint8_t i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) { From 69f7fd9cb2759b0b68b78285dcd31bcfa03babd0 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 16 May 2023 14:16:14 +0200 Subject: [PATCH 0746/2042] Bluetooth: Audio: Rename bt_codec to bt_audio_codec_{cap, conf, data} Rename the bt_codec struct to bt_audio_codec_conf or to the new struct bt_audio_codec_cap. Rename the bt_codec_data to bt_audio_codec_data. The purpose of this is to split the codec specific configuration and codec capabilities into seperate structs, as they do not reflect the same values, or used for the same purpose. This commit depends on the preset macros workings on either type of struct (for now), but will be modified in future updates. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/audio.h | 194 +++++----- include/zephyr/bluetooth/audio/bap.h | 115 +++--- .../zephyr/bluetooth/audio/bap_lc3_preset.h | 278 +++++++------- include/zephyr/bluetooth/audio/cap.h | 16 +- include/zephyr/bluetooth/audio/lc3.h | 347 +++++++++--------- include/zephyr/bluetooth/audio/pacs.h | 4 +- .../bluetooth/broadcast_audio_sink/src/main.c | 6 +- .../broadcast_audio_source/src/main.c | 2 +- samples/bluetooth/hap_ha/src/bap_unicast_sr.c | 84 ++--- .../tmap_central/src/cap_initiator.c | 47 ++- .../tmap_peripheral/src/bap_unicast_sr.c | 188 +++------- .../bluetooth/unicast_audio_client/src/main.c | 65 ++-- .../bluetooth/unicast_audio_server/src/main.c | 91 +++-- subsys/bluetooth/audio/Kconfig.bap | 24 +- subsys/bluetooth/audio/ascs.c | 195 +++++----- subsys/bluetooth/audio/ascs_internal.h | 5 +- subsys/bluetooth/audio/audio.c | 69 ++-- subsys/bluetooth/audio/bap_broadcast_sink.c | 57 +-- subsys/bluetooth/audio/bap_broadcast_source.c | 94 ++--- subsys/bluetooth/audio/bap_endpoint.h | 18 +- subsys/bluetooth/audio/bap_iso.h | 2 +- subsys/bluetooth/audio/bap_stream.c | 114 +++--- subsys/bluetooth/audio/bap_stream.h | 17 +- subsys/bluetooth/audio/bap_unicast_client.c | 342 ++++++++++++----- .../audio/bap_unicast_client_internal.h | 9 +- subsys/bluetooth/audio/bap_unicast_server.c | 19 +- subsys/bluetooth/audio/bap_unicast_server.h | 5 +- subsys/bluetooth/audio/cap_initiator.c | 44 +-- subsys/bluetooth/audio/cap_stream.c | 2 +- subsys/bluetooth/audio/codec.c | 85 ++--- subsys/bluetooth/audio/pacs.c | 24 +- subsys/bluetooth/audio/pacs_internal.h | 5 - subsys/bluetooth/audio/shell/audio.h | 153 +++++--- subsys/bluetooth/audio/shell/bap.c | 109 +++--- .../audio/shell/bap_broadcast_assistant.c | 8 +- subsys/bluetooth/audio/shell/cap_initiator.c | 12 +- .../audio/ascs/src/test_ase_control_params.c | 10 +- .../ascs/src/test_ase_state_transition.c | 57 ++- .../src/test_ase_state_transition_invalid.c | 14 +- tests/bluetooth/audio/ascs/src/test_common.c | 10 +- .../audio/mocks/include/bap_stream.h | 2 +- .../audio/mocks/include/bap_unicast_server.h | 16 +- tests/bluetooth/audio/mocks/src/bap_stream.c | 2 +- .../audio/mocks/src/bap_unicast_client.c | 7 +- .../audio/mocks/src/bap_unicast_server.c | 16 +- tests/bluetooth/audio/mocks/src/pacs.c | 6 +- tests/bluetooth/shell/audio.conf | 11 +- tests/bluetooth/tester/src/btp_bap.c | 199 +++++----- tests/bsim/bluetooth/audio/prj.conf | 2 +- .../audio/src/bap_broadcast_sink_test.c | 14 +- .../audio/src/bap_broadcast_source_test.c | 13 +- .../audio/src/bap_unicast_client_test.c | 30 +- .../bluetooth/audio/src/bap_unicast_common.c | 54 ++- .../bluetooth/audio/src/bap_unicast_common.h | 5 +- .../audio/src/bap_unicast_server_test.c | 89 +++-- .../bluetooth/audio/src/cap_acceptor_test.c | 46 ++- .../audio/src/cap_initiator_broadcast_test.c | 46 +-- .../audio/src/cap_initiator_unicast_test.c | 37 +- 58 files changed, 1864 insertions(+), 1671 deletions(-) diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 1d7995c66fee..bcc8f976f943 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -178,29 +178,28 @@ enum bt_audio_metadata_type { #define BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED 0x01 /** @brief Codec configuration structure */ -struct bt_codec_data { +struct bt_audio_codec_data { struct bt_data data; - uint8_t value[CONFIG_BT_CODEC_MAX_DATA_LEN]; + uint8_t value[CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN]; }; /** - * @brief Helper to declare elements of bt_codec_data arrays + * @brief Helper to declare elements of bt_audio_codec_data arrays * - * This macro is mainly for creating an array of struct bt_codec_data - * elements inside bt_codec which is then passed to the likes of - * bt_bap_stream_config or bt_bap_stream_reconfig. + * This macro is mainly for creating an array of struct bt_audio_codec_data elements which is then + * passed to the likes of bt_bap_stream_config() or bt_bap_stream_reconfig(). * * @param _type Type of advertising data field * @param _bytes Variable number of single-byte parameters */ -#define BT_CODEC_DATA(_type, _bytes...) \ +#define BT_AUDIO_CODEC_DATA(_type, _bytes...) \ { \ - .data = BT_DATA(_type, ((uint8_t []) { _bytes }), \ - sizeof((uint8_t []) { _bytes })) \ + .data = BT_DATA(_type, ((uint8_t[]){_bytes}), \ + sizeof((uint8_t[]){_bytes})) \ } /** - * @brief Helper to declare bt_codec structure + * @brief Helper to declare @ref bt_audio_codec_cfg or @ref bt_audio_codec_cap structure * * @param _id Codec ID * @param _cid Company ID @@ -208,16 +207,16 @@ struct bt_codec_data { * @param _data Codec Specific Data in LVT format * @param _meta Codec Specific Metadata in LVT format */ -#define BT_CODEC(_id, _cid, _vid, _data, _meta) \ +#define BT_AUDIO_CODEC(_id, _cid, _vid, _data, _meta) \ { \ /* Use HCI data path as default, can be overwritten by application */ \ .path_id = BT_ISO_DATA_PATH_HCI, \ .id = _id, \ .cid = _cid, \ .vid = _vid, \ - .data_count = ARRAY_SIZE(((struct bt_codec_data[]) _data)), \ + .data_count = ARRAY_SIZE(((struct bt_audio_codec_data[])_data)), \ .data = _data, \ - .meta_count = ARRAY_SIZE(((struct bt_codec_data[]) _meta)), \ + .meta_count = ARRAY_SIZE(((struct bt_audio_codec_data[])_meta)), \ .meta = _meta, \ } @@ -289,8 +288,36 @@ enum bt_audio_location { BT_AUDIO_LOCATION_LEFT_SURROUND | \ BT_AUDIO_LOCATION_RIGHT_SURROUND) -/** @brief Codec structure. */ -struct bt_codec { +/** @brief Codec capability structure. */ +struct bt_audio_codec_cap { + /** Data path ID + * + * @ref BT_ISO_DATA_PATH_HCI for HCI path, or any other value for + * vendor specific ID. + */ + uint8_t path_id; + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; +#if defined(CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT) + /** Codec Specific Capabilities Data count */ + size_t data_count; + /** Codec Specific Capabilities Data */ + struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT */ +#if defined(CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT) + /** Codec Specific Capabilities Metadata count */ + size_t meta_count; + /** Codec Specific Capabilities Metadata */ + struct bt_audio_codec_data meta[CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT */ +}; + +/** @brief Codec specific configuration structure. */ +struct bt_audio_codec_cfg { /** Data path ID * * @ref BT_ISO_DATA_PATH_HCI for HCI path, or any other value for @@ -303,18 +330,18 @@ struct bt_codec { uint16_t cid; /** Codec Company Vendor ID */ uint16_t vid; -#if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT) - /** Codec Specific Data count */ +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) + /** Codec Specific Configuration Data count */ size_t data_count; - /** Codec Specific Data */ - struct bt_codec_data data[CONFIG_BT_CODEC_MAX_DATA_COUNT]; -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ -#if defined(CONFIG_BT_CODEC_MAX_METADATA_COUNT) - /** Codec Specific Metadata count */ + /** Codec Specific Configuration Data */ + struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */ +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) + /** Codec Specific Configuration Metadata count */ size_t meta_count; - /** Codec Specific Metadata */ - struct bt_codec_data meta[CONFIG_BT_CODEC_MAX_METADATA_COUNT]; -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT */ + /** Codec Specific Configuration Metadata */ + struct bt_audio_codec_data meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT */ }; /** @brief Audio Capability type */ @@ -324,7 +351,7 @@ enum bt_audio_dir { }; /** - * @brief Helper to declare elements of bt_codec_qos + * @brief Helper to declare elements of bt_audio_codec_qos * * @param _interval SDU interval (usec) * @param _framing Framing @@ -334,8 +361,7 @@ enum bt_audio_dir { * @param _latency Maximum Transport Latency (msec) * @param _pd Presentation Delay (usec) */ -#define BT_CODEC_QOS(_interval, _framing, _phy, _sdu, _rtn, _latency, \ - _pd) \ +#define BT_AUDIO_CODEC_QOS(_interval, _framing, _phy, _sdu, _rtn, _latency, _pd) \ { \ .interval = _interval, \ .framing = _framing, \ @@ -348,19 +374,19 @@ enum bt_audio_dir { /** @brief Codec QoS Framing */ enum { - BT_CODEC_QOS_UNFRAMED = 0x00, - BT_CODEC_QOS_FRAMED = 0x01, + BT_AUDIO_CODEC_QOS_UNFRAMED = 0x00, + BT_AUDIO_CODEC_QOS_FRAMED = 0x01, }; /** @brief Codec QoS Preferred PHY */ enum { - BT_CODEC_QOS_1M = BIT(0), - BT_CODEC_QOS_2M = BIT(1), - BT_CODEC_QOS_CODED = BIT(2), + BT_AUDIO_CODEC_QOS_1M = BIT(0), + BT_AUDIO_CODEC_QOS_2M = BIT(1), + BT_AUDIO_CODEC_QOS_CODED = BIT(2), }; /** - * @brief Helper to declare Input Unframed bt_codec_qos + * @brief Helper to declare Input Unframed bt_audio_codec_qos * * @param _interval SDU interval (usec) * @param _sdu Maximum SDU Size @@ -368,12 +394,12 @@ enum { * @param _latency Maximum Transport Latency (msec) * @param _pd Presentation Delay (usec) */ -#define BT_CODEC_QOS_UNFRAMED(_interval, _sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS(_interval, BT_CODEC_QOS_UNFRAMED, BT_CODEC_QOS_2M, _sdu, \ - _rtn, _latency, _pd) +#define BT_AUDIO_CODEC_QOS_UNFRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS(_interval, BT_AUDIO_CODEC_QOS_UNFRAMED, BT_AUDIO_CODEC_QOS_2M, _sdu, \ + _rtn, _latency, _pd) /** - * @brief Helper to declare Input Framed bt_codec_qos + * @brief Helper to declare Input Framed bt_audio_codec_qos * * @param _interval SDU interval (usec) * @param _sdu Maximum SDU Size @@ -381,12 +407,12 @@ enum { * @param _latency Maximum Transport Latency (msec) * @param _pd Presentation Delay (usec) */ -#define BT_CODEC_QOS_FRAMED(_interval, _sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS(_interval, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, _sdu, \ - _rtn, _latency, _pd) +#define BT_AUDIO_CODEC_QOS_FRAMED(_interval, _sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS(_interval, BT_AUDIO_CODEC_QOS_FRAMED, BT_AUDIO_CODEC_QOS_2M, _sdu, \ + _rtn, _latency, _pd) /** @brief Codec QoS structure. */ -struct bt_codec_qos { +struct bt_audio_codec_qos { /** QoS PHY */ uint8_t phy; @@ -419,7 +445,7 @@ struct bt_codec_qos { }; /** - * @brief Helper to declare elements of @ref bt_codec_qos_pref + * @brief Helper to declare elements of @ref bt_audio_codec_qos_pref * * @param _unframed_supported Unframed PDUs supported * @param _phy Preferred Target PHY @@ -430,21 +456,21 @@ struct bt_codec_qos { * @param _pref_pd_min Preferred Minimum Presentation Delay (usec) * @param _pref_pd_max Preferred Maximum Presentation Delay (usec) */ -#define BT_CODEC_QOS_PREF(_unframed_supported, _phy, _rtn, _latency, _pd_min, \ - _pd_max, _pref_pd_min, _pref_pd_max) \ - { \ - .unframed_supported = _unframed_supported, \ - .phy = _phy, \ - .rtn = _rtn, \ - .latency = _latency, \ - .pd_min = _pd_min, \ - .pd_max = _pd_max, \ - .pref_pd_min = _pref_pd_min, \ - .pref_pd_max = _pref_pd_max, \ +#define BT_AUDIO_CODEC_QOS_PREF(_unframed_supported, _phy, _rtn, _latency, _pd_min, _pd_max, \ + _pref_pd_min, _pref_pd_max) \ + { \ + .unframed_supported = _unframed_supported, \ + .phy = _phy, \ + .rtn = _rtn, \ + .latency = _latency, \ + .pd_min = _pd_min, \ + .pd_max = _pd_max, \ + .pref_pd_min = _pref_pd_min, \ + .pref_pd_max = _pref_pd_max, \ } /** @brief Audio Stream Quality of Service Preference structure. */ -struct bt_codec_qos_pref { +struct bt_audio_codec_qos_pref { /** @brief Unframed PDUs supported * * Unlike the other fields, this is not a preference but whether @@ -494,7 +520,7 @@ struct bt_codec_qos_pref { uint32_t pref_pd_max; }; -/** @brief Turns an array of bt_codec_data to a flat LTV encoded uint8_t array +/** @brief Turns an array of bt_audio_codec_data to a flat LTV encoded uint8_t array * * The resulting @p buf array can then be used to send over air. * @@ -507,14 +533,14 @@ struct bt_codec_qos_pref { * @retval The length of the encoded data if successful. * @retval -ENOMEM if the @p codec_data did not fit into the @p buf. */ -ssize_t bt_audio_codec_data_to_buf(const struct bt_codec_data *codec_data, size_t count, +ssize_t bt_audio_codec_data_to_buf(const struct bt_audio_codec_data *codec_data, size_t count, uint8_t *buf, size_t buf_size); /** * @brief Audio codec Config APIs * @defgroup bt_audio_codec_cfg Codec config parsing APIs * - * Functions to parse codec config data when formatted as LTV wrapped into @ref bt_codec. + * Functions to parse codec config data when formatted as LTV wrapped into @ref bt_audio_codec_cfg. * * @{ */ @@ -522,7 +548,7 @@ ssize_t bt_audio_codec_data_to_buf(const struct bt_codec_data *codec_data, size_ /** * @brief Codec parser error codes for @ref bt_audio_codec_cfg. */ -enum bt_audio_codec_parse_err { +enum bt_audio_codec_cfg_parse_err { /** @brief The requested type is not present in the data set. */ BT_AUDIO_CODEC_PARSE_ERR_SUCCESS = 0, @@ -539,21 +565,21 @@ enum bt_audio_codec_parse_err { /**@brief Extract the frequency from a codec configuration. * - * @param codec The codec configuration to extract data from. + * @param codec_cfg The codec configuration to extract data from. * * @return The frequency in Hz if found else a negative value of type - * @ref bt_audio_codec_parse_err. + * @ref bt_audio_codec_cfg_parse_err. */ -int bt_codec_cfg_get_freq(const struct bt_codec *codec); +int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg); /** @brief Extract frame duration from BT codec config * - * @param codec The codec configuration to extract data from. + * @param codec_cfg The codec configuration to extract data from. * * @return Frame duration in microseconds if value is found else a negative value - * of type @ref bt_audio_codec_parse_err. + * of type @ref bt_audio_codec_cfg_parse_err. */ -int bt_codec_cfg_get_frame_duration_us(const struct bt_codec *codec); +int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg); /** @brief Extract channel allocation from BT codec config * @@ -561,16 +587,16 @@ int bt_codec_cfg_get_frame_duration_us(const struct bt_codec *codec); * specified by @ref bt_audio_location * Shall match one or more of the bits set in BT_PAC_SNK_LOC/BT_PAC_SRC_LOC. * - * Up to the configured @ref BT_CODEC_LC3_CHAN_COUNT number of channels can be present. + * Up to the configured @ref BT_AUDIO_CODEC_LC3_CHAN_COUNT number of channels can be present. * - * @param codec The codec configuration to extract data from. + * @param codec_cfg The codec configuration to extract data from. * @param chan_allocation Pointer to the variable to store the extracted value in. * * @return BT_AUDIO_CODEC_PARSE_SUCCESS if value is found and stored in the pointer provided - * else a negative value of type @ref bt_audio_codec_parse_err. + * else a negative value of type @ref bt_audio_codec_cfg_parse_err. */ -int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec, - enum bt_audio_location *chan_allocation); +int bt_audio_codec_cfg_get_chan_allocation_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_location *chan_allocation); /** @brief Extract frame size in octets from BT codec config * @@ -583,12 +609,12 @@ int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec, * Hence it is recommended to use the received SDU size and divide by * blocks_per_sdu rather than relying on this octets_per_sdu value to be fixed. * - * @param codec The codec configuration to extract data from. + * @param codec_cfg The codec configuration to extract data from. * * @return Frame length in octets if value is found else a negative value - * of type @ref bt_audio_codec_parse_err. + * of type @ref bt_audio_codec_cfg_parse_err. */ -int bt_codec_cfg_get_octets_per_frame(const struct bt_codec *codec); +int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg); /** @brief Extract number of audio frame blockss in each SDU from BT codec config * @@ -600,35 +626,35 @@ int bt_codec_cfg_get_octets_per_frame(const struct bt_codec *codec); * for different channels. If the stream have two audio channels and this value is two * there will be four frames in the SDU. * - * @param codec The codec configuration to extract data from. + * @param codec_cfg The codec configuration to extract data from. * @param fallback_to_default If true this function will return the default value of 1 * if the type is not found. In this case the function will only fail if a NULL * pointer is provided. * * @return The count of codec frames in each SDU if value is found else a negative value - * of type @ref bt_audio_codec_parse_err - unless when \p fallback_to_default is true + * of type @ref bt_audio_codec_cfg_parse_err - unless when \p fallback_to_default is true * then the value 1 is returned if frames per sdu is not found. */ -int bt_codec_cfg_get_frame_blocks_per_sdu(const struct bt_codec *codec, bool fallback_to_default); +int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg, + bool fallback_to_default); /** @brief Lookup a specific value based on type * - * Depending on context bt_codec will be either codec capabilities, codec configuration or - * meta data. + * Depending on context bt_audio_codec_cfg will be either codec capabilities, codec configuration + * or meta data. * * Typically types used are: - * @ref bt_codec_capability_type - * @ref bt_codec_config_type + * @ref bt_audio_codec_capability_type + * @ref bt_audio_codec_config_type * @ref bt_audio_metadata_type * - * @param codec The codec data to search in. + * @param codec_cfg The codec data to search in. * @param type The type id to look for * @param data Pointer to the data-pointer to update when item is found * @return True if the type is found, false otherwise. */ -bool bt_codec_get_val(const struct bt_codec *codec, - uint8_t type, - const struct bt_codec_data **data); +bool bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, + const struct bt_audio_codec_data **data); /** @} */ /* End of bt_audio_codec_cfg */ diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index c1a0c021b0cf..eb5829a67b88 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -455,10 +455,10 @@ struct bt_bap_stream { struct bt_bap_ep *ep; /** Codec Configuration */ - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; /** QoS Configuration */ - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; /** Audio stream operations */ struct bt_bap_stream_ops *ops; @@ -493,7 +493,8 @@ struct bt_bap_stream_ops { * @param stream Stream object that has been configured. * @param pref Remote QoS preferences. */ - void (*configured)(struct bt_bap_stream *stream, const struct bt_codec_qos_pref *pref); + void (*configured)(struct bt_bap_stream *stream, + const struct bt_audio_codec_qos_pref *pref); /** * @brief Stream QoS set callback @@ -614,12 +615,12 @@ void bt_bap_stream_cb_register(struct bt_bap_stream *stream, struct bt_bap_strea * @param conn Connection object * @param stream Stream object being configured * @param ep Remote Audio Endpoint being configured - * @param codec Codec configuration + * @param codec_cfg Codec configuration * * @return Allocated Audio Stream object or NULL in case of error. */ int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, - struct bt_codec *codec); + struct bt_audio_codec_cfg *codec_cfg); /** * @brief Reconfigure Audio Stream @@ -630,11 +631,11 @@ int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, str * This can only be done for unicast streams. * * @param stream Stream object being reconfigured - * @param codec Codec configuration + * @param codec_cfg Codec configuration * * @return 0 in case of success or negative value in case of error. */ -int bt_bap_stream_reconfig(struct bt_bap_stream *stream, struct bt_codec *codec); +int bt_bap_stream_reconfig(struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg); /** * @brief Configure Audio Stream QoS @@ -664,7 +665,7 @@ int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group); * * @return 0 in case of success or negative value in case of error. */ -int bt_bap_stream_enable(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_stream_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count); /** @@ -678,7 +679,7 @@ int bt_bap_stream_enable(struct bt_bap_stream *stream, struct bt_codec_data *met * * @return 0 in case of success or negative value in case of error. */ -int bt_bap_stream_metadata(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_stream_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count); /** @@ -787,21 +788,21 @@ struct bt_bap_unicast_server_cb { * Config callback is called whenever an endpoint is requested to be * configured * - * @param[in] conn Connection object. - * @param[in] ep Local Audio Endpoint being configured. - * @param[in] dir Direction of the endpoint. - * @param[in] codec Codec configuration. - * @param[out] stream Pointer to stream that will be configured for the endpoint. - * @param[out] pref Pointer to a QoS preference object that shall be populated with - * values. Invalid values will reject the codec configuration request. - * @param[out] rsp Object for the ASE operation response. Only used if the return - * value is non-zero. + * @param[in] conn Connection object. + * @param[in] ep Local Audio Endpoint being configured. + * @param[in] dir Direction of the endpoint. + * @param[in] codec_cfg Codec configuration. + * @param[out] stream Pointer to stream that will be configured for the endpoint. + * @param[out] pref Pointer to a QoS preference object that shall be populated with + * values. Invalid values will reject the codec configuration request. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. * * @return 0 in case of success or negative value in case of error. */ int (*config)(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp); + 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); /** * @brief Stream reconfig request callback @@ -809,19 +810,19 @@ struct bt_bap_unicast_server_cb { * Reconfig callback is called whenever an Audio Stream needs to be * reconfigured with different codec configuration. * - * @param[in] stream Stream object being reconfigured. - * @param[in] dir Direction of the endpoint. - * @param[in] codec Codec configuration. - * @param[out] pref Pointer to a QoS preference object that shall be populated with - * values. Invalid values will reject the codec configuration request. - * @param[out] rsp Object for the ASE operation response. Only used if the return - * value is non-zero. + * @param[in] stream Stream object being reconfigured. + * @param[in] dir Direction of the endpoint. + * @param[in] codec_cfg Codec configuration. + * @param[out] pref Pointer to a QoS preference object that shall be populated with + * values. Invalid values will reject the codec configuration request. + * @param[out] rsp Object for the ASE operation response. Only used if the return + * value is non-zero. * * @return 0 in case of success or negative value in case of error. */ int (*reconfig)(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp); + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp); /** * @brief Stream QoS request callback @@ -836,7 +837,7 @@ struct bt_bap_unicast_server_cb { * * @return 0 in case of success or negative value in case of error. */ - int (*qos)(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, + int (*qos)(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, struct bt_bap_ascs_rsp *rsp); /** @@ -852,7 +853,7 @@ struct bt_bap_unicast_server_cb { * * @return 0 in case of success or negative value in case of error. */ - int (*enable)(struct bt_bap_stream *stream, const struct bt_codec_data *meta, + int (*enable)(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp); /** @@ -881,7 +882,7 @@ struct bt_bap_unicast_server_cb { * * @return 0 in case of success or negative value in case of error. */ - int (*metadata)(struct bt_bap_stream *stream, const struct bt_codec_data *meta, + int (*metadata)(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp); /** @@ -972,14 +973,14 @@ void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t fun * * @param conn Connection object * @param stream Configured stream object to be attached to the ASE - * @param codec Codec configuration + * @param codec_cfg Codec configuration * @param qos_pref Audio Stream Quality of Service Preference * * @return 0 in case of success or negative value in case of error. */ int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, - struct bt_codec *codec, - const struct bt_codec_qos_pref *qos_pref); + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_audio_codec_qos_pref *qos_pref); /** @} */ /* End of group bt_bap_unicast_server */ @@ -995,7 +996,7 @@ struct bt_bap_unicast_group_stream_param { struct bt_bap_stream *stream; /** The QoS settings for the stream object. */ - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; }; /** @brief Parameter struct for the unicast group functions @@ -1031,7 +1032,7 @@ struct bt_bap_unicast_group_param { * @brief Create audio unicast group. * * Create a new audio unicast group with one or more audio streams as a unicast client. Streams in - * a unicast group shall share the same interval, framing and latency (see @ref bt_codec_qos). + * a unicast group shall share the same interval, framing and latency (see @ref bt_audio_codec_qos). * * @param[in] param The unicast group create parameters. * @param[out] unicast_group Pointer to the unicast group created. @@ -1224,14 +1225,14 @@ struct bt_bap_unicast_client_cb { * The @p codec is only valid while in the callback, so the values must be stored by the * receiver if future use is wanted. * - * @param conn Connection to the remote unicast server. - * @param dir The type of remote endpoints and capabilities discovered. - * @param codec Remote capabilities. + * @param conn Connection to the remote unicast server. + * @param dir The type of remote endpoints and capabilities discovered. + * @param codec_cap Remote capabilities. * * If discovery procedure has complete both @p codec and @p ep are set to NULL. */ void (*pac_record)(struct bt_conn *conn, enum bt_audio_dir dir, - const struct bt_codec *codec); + const struct bt_audio_codec_cap *codec_cap); /** * @brief Remote Audio Stream Endoint (ASE) discovered @@ -1295,18 +1296,18 @@ int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir); struct bt_bap_base_bis_data { /* Unique index of the BIS */ uint8_t index; -#if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT) +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) /** Codec Specific Data count. * - * Only valid if the data_count of struct bt_codec in the subgroup is 0 + * Only valid if the data_count of struct bt_audio_codec_cfg in the subgroup is 0 */ size_t data_count; /** Codec Specific Data * - * Only valid if the data_count of struct bt_codec in the subgroup is 0 + * Only valid if the data_count of struct bt_audio_codec_cfg in the subgroup is 0 */ - struct bt_codec_data data[CONFIG_BT_CODEC_MAX_DATA_COUNT]; -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ + struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */ }; struct bt_bap_base_subgroup { @@ -1317,7 +1318,7 @@ struct bt_bap_base_subgroup { * If the data_count of the codec is 0, then codec specific data may be * found for each BIS in the bis_data. */ - struct bt_codec codec; + 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]; }; @@ -1362,7 +1363,7 @@ struct bt_bap_broadcast_source_stream_param { /** Audio stream */ struct bt_bap_stream *stream; -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 /** * @brief The number of elements in the @p data array. * @@ -1371,8 +1372,8 @@ struct bt_bap_broadcast_source_stream_param { size_t data_count; /** BIS Codec Specific Configuration */ - struct bt_codec_data *data; -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ + struct bt_audio_codec_data *data; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ }; /** Broadcast Source subgroup parameters*/ @@ -1384,7 +1385,7 @@ struct bt_bap_broadcast_source_subgroup_param { struct bt_bap_broadcast_source_stream_param *params; /** Subgroup Codec configuration. */ - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; }; /** Broadcast Source create parameters */ @@ -1396,7 +1397,7 @@ struct bt_bap_broadcast_source_create_param { struct bt_bap_broadcast_source_subgroup_param *params; /** Quality of Service configuration. */ - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; /** * @brief Broadcast Source packing mode. @@ -1449,13 +1450,14 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param * * service parameters. This can only be done when the source is stopped. * * @param source Pointer to the broadcast source - * @param codec Codec configuration. + * @param codec_cfg Codec configuration. * @param qos Quality of Service configuration * * @return Zero on success or (negative) error code otherwise. */ -int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, struct bt_codec *codec, - struct bt_codec_qos *qos); +int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, + struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos *qos); /** * @brief Modify the metadata of an audio broadcast source. @@ -1470,7 +1472,8 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, str * @return Zero on success or (negative) error code otherwise. */ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source, - const struct bt_codec_data meta[], size_t meta_count); + const struct bt_audio_codec_data meta[], + size_t meta_count); /** * @brief Start audio broadcast source. diff --git a/include/zephyr/bluetooth/audio/bap_lc3_preset.h b/include/zephyr/bluetooth/audio/bap_lc3_preset.h index 0886c1804260..bc4d0c8078e7 100644 --- a/include/zephyr/bluetooth/audio/bap_lc3_preset.h +++ b/include/zephyr/bluetooth/audio/bap_lc3_preset.h @@ -14,15 +14,15 @@ /** Struct to hold a BAP defined LC3 preset */ struct bt_bap_lc3_preset { /** The LC3 Codec */ - struct bt_codec codec; + struct bt_audio_codec_cfg codec_cfg; /** The BAP spec defined QoS values */ - struct bt_codec_qos qos; + struct bt_audio_codec_qos qos; }; /** Helper to declare an LC3 preset structure */ #define BT_BAP_LC3_PRESET(_codec, _qos) \ { \ - .codec = _codec, .qos = _qos, \ + .codec_cfg = _codec, .qos = _qos, \ } /* LC3 Unicast presets defined by table 5.2 in the BAP v1.0 specification */ @@ -34,8 +34,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Unicast 8_2_1 codec configuration @@ -44,8 +44,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(30u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(30u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Unicast 16_1_1 codec configuration @@ -54,8 +54,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Unicast 16_2_1 codec configuration @@ -66,8 +66,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(40u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Unicast 24_1_1 codec configuration @@ -76,8 +76,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Unicast 24_2_1 codec configuration @@ -88,8 +88,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(60u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(60u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Unicast 32_1_1 codec configuration @@ -98,8 +98,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Unicast 32_2_1 codec configuration @@ -108,8 +108,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(80u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Unicast 441_1_1 codec configuration @@ -118,9 +118,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ - BT_CODEC_QOS(8163u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 97u, 5u, 24u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(8163u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 97u, 5u, 24u, 40000u)) /** * @brief Helper to declare LC3 Unicast 441_2_1 codec configuration @@ -129,9 +129,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ - BT_CODEC_QOS(10884u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 130u, 5u, 31u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(10884u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 130u, 5u, 31u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_1_1 codec configuration @@ -140,8 +140,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 5u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 5u, 15u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_2_1 codec configuration @@ -150,8 +150,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(100u, 5u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100u, 5u, 20u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_3_1 codec configuration @@ -160,8 +160,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 5u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 5u, 15u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_4_1 codec configuration @@ -170,8 +170,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(120u, 5u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120u, 5u, 20u, 40000u)) /** * @brief Helper to declare LC3 Unicast 8_5_1 codec configuration @@ -180,8 +180,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 5u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 5u, 15u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_6_1 codec configuration @@ -190,8 +190,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(155u, 5u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(155u, 5u, 20u, 40000u)) /** * @brief Helper to declare LC3 Unicast 8_1_2 codec configuration @@ -201,8 +201,8 @@ struct bt_bap_lc3_preset { */ /* Following presets are for unicast high reliability audio data */ #define BT_BAP_LC3_UNICAST_PRESET_8_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 8_2_2 codec configuration @@ -211,8 +211,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_8_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(30u, 13u, 95u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(30u, 13u, 95u, 40000u)) /** * @brief Helper to declare LC3 Unicast 16_1_2 codec configuration @@ -221,8 +221,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_16_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 16_2_2 codec configuration @@ -231,8 +231,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_16_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(40u, 13u, 95u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40u, 13u, 95u, 40000u)) /** * @brief Helper to declare LC3 Unicast 24_1_2 codec configuration @@ -241,8 +241,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_24_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 24_2_2 codec configuration @@ -251,8 +251,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_24_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(60u, 13u, 95u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(60u, 13u, 95u, 40000u)) /** * @brief Helper to declare LC3 Unicast 32_1_2 codec configuration @@ -261,8 +261,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_32_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 32_2_2 codec configuration @@ -271,8 +271,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_32_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(80u, 13u, 95u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80u, 13u, 95u, 40000u)) /** * @brief Helper to declare LC3 Unicast 441_1_2 codec configuration @@ -281,9 +281,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_441_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ - BT_CODEC_QOS(8163u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 97u, 13u, 80u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(8163u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 97u, 13u, 80u, 40000u)) /** * @brief Helper to declare LC3 Unicast 441_2_2 codec configuration @@ -292,9 +292,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_441_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ - BT_CODEC_QOS(10884u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 130u, 13u, \ - 85u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(10884u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 130u, 13u, 85u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_1_2 codec configuration @@ -303,8 +303,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_2_2 codec configuration @@ -313,8 +313,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(100u, 13u, 95u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100u, 13u, 95u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_3_2 codec configuration @@ -323,8 +323,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_3_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_4_2 codec configuration @@ -333,8 +333,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_4_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(120u, 13u, 100u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120u, 13u, 100u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_5_2 codec configuration @@ -343,8 +343,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_5_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 13u, 75u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 13u, 75u, 40000u)) /** * @brief Helper to declare LC3 Unicast 48_6_2 codec configuration @@ -353,8 +353,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_UNICAST_PRESET_48_6_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(155u, 13u, 100u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(155u, 13u, 100u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 8_1_1 codec configuration @@ -364,8 +364,8 @@ struct bt_bap_lc3_preset { */ /* LC3 Broadcast presets defined by table 6.4 in the BAP v1.0 specification */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 8_2_1 codec configuration @@ -374,8 +374,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(30u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(30u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 16_1_1 codec configuration @@ -384,8 +384,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 16_2_1 codec configuration @@ -396,8 +396,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(40u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 24_1_1 codec configuration @@ -406,8 +406,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 24_2_1 codec configuration @@ -418,8 +418,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(60u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(60u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 32_1_1 codec configuration @@ -428,8 +428,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 2u, 8u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 2u, 8u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 32_2_1 codec configuration @@ -438,8 +438,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(80u, 2u, 10u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80u, 2u, 10u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 441_1_1 codec configuration @@ -448,9 +448,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ - BT_CODEC_QOS(8163u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 97u, 4u, 24u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(8163u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 97u, 4u, 24u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 441_2_1 codec configuration @@ -459,9 +459,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ - BT_CODEC_QOS(10884u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 130u, 4u, 31u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(10884u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 130u, 4u, 31u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_1_1 codec configuration @@ -470,8 +470,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 4u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 4u, 15u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_2_1 codec configuration @@ -480,8 +480,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(100u, 4u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100u, 4u, 20u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_3_1 codec configuration @@ -490,8 +490,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 4u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 4u, 15u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_4_1 codec configuration @@ -500,8 +500,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(120u, 4u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120u, 4u, 20u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_5_1 codec configuration @@ -510,8 +510,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 4u, 15u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 4u, 15u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_6_1 codec configuration @@ -520,8 +520,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_1(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(155u, 4u, 20u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(155u, 4u, 20u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 8_1_2 codec configuration @@ -531,8 +531,8 @@ struct bt_bap_lc3_preset { */ /* Following presets are for broadcast high reliability audio data */ #define BT_BAP_LC3_BROADCAST_PRESET_8_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 4u, 45u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(26u, 4u, 45u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 8_2_2 codec configuration @@ -541,8 +541,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_8_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(30u, 4u, 60u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(30u, 4u, 60u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 16_1_2 codec configuration @@ -551,8 +551,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 4u, 45u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30u, 4u, 45u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 16_2_2 codec configuration @@ -563,8 +563,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_16_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(40u, 4u, 60u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40u, 4u, 60u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 24_1_2 codec configuration @@ -573,8 +573,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 4u, 45u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(45u, 4u, 45u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 24_2_2 codec configuration @@ -585,8 +585,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_24_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(60u, 4u, 60u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(60u, 4u, 60u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 32_1_2 codec configuration @@ -595,8 +595,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 4u, 45u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60u, 4u, 45u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 32_2_2 codec configuration @@ -605,8 +605,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_32_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(80u, 4u, 60u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80u, 4u, 60u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 441_1_2 codec configuration @@ -615,9 +615,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ - BT_CODEC_QOS(8163u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 97u, 4u, 54u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(8163u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 97u, 4u, 54u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 441_2_2 codec configuration @@ -626,9 +626,9 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_441_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET( \ - BT_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ - BT_CODEC_QOS(10884u, BT_CODEC_QOS_FRAMED, BT_CODEC_QOS_2M, 130u, 4u, 60u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_QOS(10884u, BT_AUDIO_CODEC_QOS_FRAMED, \ + BT_AUDIO_CODEC_QOS_2M, 130u, 4u, 60u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_1_2 codec configuration @@ -637,8 +637,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_1_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 4u, 50u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75u, 4u, 50u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_2_2 codec configuration @@ -647,8 +647,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_2_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(100u, 4u, 65u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100u, 4u, 65u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_3_2 codec configuration @@ -657,8 +657,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_3_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 4u, 50u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90u, 4u, 50u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_4_2 codec configuration @@ -667,8 +667,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_4_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(120u, 4u, 65u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120u, 4u, 65u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_5_2 codec configuration @@ -677,8 +677,8 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_5_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 4u, 50u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(117u, 4u, 50u, 40000u)) /** * @brief Helper to declare LC3 Broadcast 48_6_2 codec configuration @@ -687,7 +687,7 @@ struct bt_bap_lc3_preset { * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ #define BT_BAP_LC3_BROADCAST_PRESET_48_6_2(_loc, _stream_context) \ - BT_BAP_LC3_PRESET(BT_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ - BT_CODEC_LC3_QOS_10_UNFRAMED(155u, 4u, 65u, 40000u)) + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(155u, 4u, 65u, 40000u)) #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_BAP_LC3_PRESET_ */ diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 1436b96ca874..8891d905c62c 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -179,14 +179,14 @@ struct bt_cap_unicast_audio_start_stream_param { /** * @brief Codec configuration. * - * The @p codec.meta shall include a list of CCIDs + * The @p codec_cfg.meta shall include a list of CCIDs * (@ref BT_AUDIO_METADATA_TYPE_CCID_LIST) as well as a non-0 * stream context (@ref BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) bitfield. */ - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; /** Quality of Service configuration. */ - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; }; struct bt_cap_unicast_audio_start_param { @@ -212,7 +212,7 @@ struct bt_cap_unicast_audio_update_param { * The metadata shall a list of CCIDs as * well as a non-0 context bitfield. */ - struct bt_codec_data *meta; + struct bt_audio_codec_data *meta; }; /** @@ -310,7 +310,7 @@ struct bt_cap_initiator_broadcast_stream_param { size_t data_count; /** BIS Codec Specific Configuration */ - struct bt_codec_data *data; + struct bt_audio_codec_data *data; }; struct bt_cap_initiator_broadcast_subgroup_param { @@ -321,7 +321,7 @@ struct bt_cap_initiator_broadcast_subgroup_param { struct bt_cap_initiator_broadcast_stream_param *stream_params; /** Subgroup Codec configuration. */ - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; }; struct bt_cap_initiator_broadcast_create_param { @@ -332,7 +332,7 @@ struct bt_cap_initiator_broadcast_create_param { struct bt_cap_initiator_broadcast_subgroup_param *subgroup_params; /** Quality of Service configuration. */ - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; /** @brief Broadcast Source packing mode. * @@ -415,7 +415,7 @@ int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broad * @return 0 on success or negative error value on failure. */ int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source, - const struct bt_codec_data meta[], + const struct bt_audio_codec_data meta[], size_t meta_count); /** diff --git a/include/zephyr/bluetooth/audio/lc3.h b/include/zephyr/bluetooth/audio/lc3.h index 90647cf1414a..cde496df2c49 100644 --- a/include/zephyr/bluetooth/audio/lc3.h +++ b/include/zephyr/bluetooth/audio/lc3.h @@ -13,7 +13,7 @@ /** * @brief LC3 - * @defgroup bt_codec_lc3 AUDIO + * @defgroup BT_AUDIO_CODEC_LC3 AUDIO * @ingroup bluetooth * @{ */ @@ -28,7 +28,7 @@ extern "C" { /** * @brief LC3 codec ID */ -#define BT_CODEC_LC3_ID 0x06 +#define BT_AUDIO_CODEC_LC3_ID 0x06 /** * @brief Codec capability type id's @@ -38,119 +38,118 @@ extern "C" { * * Even though they are in-fixed with LC3 they can be used for other codec types as well. */ -enum bt_codec_capability_type { +enum bt_audio_codec_capability_type { /** * @brief LC3 sample frequency capability type */ - BT_CODEC_LC3_FREQ = 0x01, + BT_AUDIO_CODEC_LC3_FREQ = 0x01, /** * @brief LC3 frame duration capability type */ - BT_CODEC_LC3_DURATION = 0x02, + BT_AUDIO_CODEC_LC3_DURATION = 0x02, /** * @brief LC3 channel count capability type */ - BT_CODEC_LC3_CHAN_COUNT = 0x03, + BT_AUDIO_CODEC_LC3_CHAN_COUNT = 0x03, /** * @brief LC3 frame length capability type */ - BT_CODEC_LC3_FRAME_LEN = 0x04, + BT_AUDIO_CODEC_LC3_FRAME_LEN = 0x04, /** * @brief Max codec frame count per SDU capability type */ - BT_CODEC_LC3_FRAME_COUNT = 0x05, + BT_AUDIO_CODEC_LC3_FRAME_COUNT = 0x05, }; /** * @brief LC3 8 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_8KHZ BIT(0) +#define BT_AUDIO_CODEC_LC3_FREQ_8KHZ BIT(0) /** * @brief LC3 11.025 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_11KHZ BIT(1) +#define BT_AUDIO_CODEC_LC3_FREQ_11KHZ BIT(1) /** * @brief LC3 16 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_16KHZ BIT(2) +#define BT_AUDIO_CODEC_LC3_FREQ_16KHZ BIT(2) /** * @brief LC3 22.05 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_22KHZ BIT(3) +#define BT_AUDIO_CODEC_LC3_FREQ_22KHZ BIT(3) /** * @brief LC3 24 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_24KHZ BIT(4) +#define BT_AUDIO_CODEC_LC3_FREQ_24KHZ BIT(4) /** * @brief LC3 32 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_32KHZ BIT(5) +#define BT_AUDIO_CODEC_LC3_FREQ_32KHZ BIT(5) /** * @brief LC3 44.1 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_44KHZ BIT(6) +#define BT_AUDIO_CODEC_LC3_FREQ_44KHZ BIT(6) /** * @brief LC3 48 Khz frequency capability */ -#define BT_CODEC_LC3_FREQ_48KHZ BIT(7) +#define BT_AUDIO_CODEC_LC3_FREQ_48KHZ BIT(7) /** * @brief LC3 any frequency capability */ -#define BT_CODEC_LC3_FREQ_ANY (BT_CODEC_LC3_FREQ_8KHZ | \ - BT_CODEC_LC3_FREQ_16KHZ | \ - BT_CODEC_LC3_FREQ_24KHZ | \ - BT_CODEC_LC3_FREQ_32KHZ | \ - BT_CODEC_LC3_FREQ_44KHZ | \ - BT_CODEC_LC3_FREQ_48KHZ) +#define BT_AUDIO_CODEC_LC3_FREQ_ANY \ + (BT_AUDIO_CODEC_LC3_FREQ_8KHZ | BT_AUDIO_CODEC_LC3_FREQ_16KHZ | \ + BT_AUDIO_CODEC_LC3_FREQ_24KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | \ + BT_AUDIO_CODEC_LC3_FREQ_44KHZ | BT_AUDIO_CODEC_LC3_FREQ_48KHZ) /** * @brief LC3 7.5 msec frame duration capability */ -#define BT_CODEC_LC3_DURATION_7_5 BIT(0) +#define BT_AUDIO_CODEC_LC3_DURATION_7_5 BIT(0) /** * @brief LC3 10 msec frame duration capability */ -#define BT_CODEC_LC3_DURATION_10 BIT(1) +#define BT_AUDIO_CODEC_LC3_DURATION_10 BIT(1) /** * @brief LC3 any frame duration capability */ -#define BT_CODEC_LC3_DURATION_ANY (BT_CODEC_LC3_DURATION_7_5 | \ - BT_CODEC_LC3_DURATION_10) +#define BT_AUDIO_CODEC_LC3_DURATION_ANY \ + (BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10) /** * @brief LC3 7.5 msec preferred frame duration capability */ -#define BT_CODEC_LC3_DURATION_PREFER_7_5 BIT(4) +#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_7_5 BIT(4) /** * @brief LC3 10 msec preferred frame duration capability */ -#define BT_CODEC_LC3_DURATION_PREFER_10 BIT(5) +#define BT_AUDIO_CODEC_LC3_DURATION_PREFER_10 BIT(5) /** * @brief LC3 minimum supported channel counts */ -#define BT_CODEC_LC3_CHAN_COUNT_MIN 1 +#define BT_AUDIO_CODEC_LC3_CHAN_COUNT_MIN 1 /** * @brief LC3 maximum supported channel counts */ -#define BT_CODEC_LC3_CHAN_COUNT_MAX 8 +#define BT_AUDIO_CODEC_LC3_CHAN_COUNT_MAX 8 /** * @brief LC3 channel count support capability * * Macro accepts variable number of channel counts. * The allowed channel counts are defined by specification and have to be in range from - * @ref BT_CODEC_LC3_CHAN_COUNT_MIN to @ref BT_CODEC_LC3_CHAN_COUNT_MAX inclusive. + * @ref BT_AUDIO_CODEC_LC3_CHAN_COUNT_MIN to @ref BT_AUDIO_CODEC_LC3_CHAN_COUNT_MAX inclusive. * * Example to support 1 and 3 channels: - * BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 3) + * BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 3) */ -#define BT_CODEC_LC3_CHAN_COUNT_SUPPORT(...) ((uint8_t)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) +#define BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(...) \ + ((uint8_t)((FOR_EACH(BIT, (|), __VA_ARGS__)) >> 1)) -struct bt_codec_lc3_frame_len { +struct BT_AUDIO_CODEC_LC3_frame_len { uint16_t min; uint16_t max; }; @@ -163,85 +162,85 @@ struct bt_codec_lc3_frame_len { * * Even though they are in-fixed with LC3 they can be used for other codec types as well. */ -enum bt_codec_config_type { +enum bt_audio_codec_config_type { /** @brief LC3 Sample Frequency configuration type. */ - BT_CODEC_CONFIG_LC3_FREQ = 0x01, + BT_AUDIO_CODEC_CONFIG_LC3_FREQ = 0x01, /** @brief LC3 Frame Duration configuration type. */ - BT_CODEC_CONFIG_LC3_DURATION = 0x02, + BT_AUDIO_CODEC_CONFIG_LC3_DURATION = 0x02, /** @brief LC3 channel Allocation configuration type. */ - BT_CODEC_CONFIG_LC3_CHAN_ALLOC = 0x03, + BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC = 0x03, /** @brief LC3 Frame Length configuration type. */ - BT_CODEC_CONFIG_LC3_FRAME_LEN = 0x04, + BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN = 0x04, /** @brief Codec frame blocks, per SDU configuration type. */ - BT_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU = 0x05, + BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU = 0x05, }; /** * @brief 8 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_8KHZ 0x01 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ 0x01 /** * @brief 11.025 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_11KHZ 0x02 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ 0x02 /** * @brief 16 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_16KHZ 0x03 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ 0x03 /** * @brief 22.05 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_22KHZ 0x04 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ 0x04 /** * @brief 24 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_24KHZ 0x05 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ 0x05 /** * @brief 32 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_32KHZ 0x06 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ 0x06 /** * @brief 44.1 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_44KHZ 0x07 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ 0x07 /** * @brief 48 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_48KHZ 0x08 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ 0x08 /** * @brief 88.2 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_88KHZ 0x09 +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ 0x09 /** * @brief 96 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_96KHZ 0x0a +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ 0x0a /** * @brief 176.4 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_176KHZ 0x0b +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ 0x0b /** * @brief 192 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_192KHZ 0x0c +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ 0x0c /** * @brief 384 Khz codec Sample Frequency configuration */ -#define BT_CODEC_CONFIG_LC3_FREQ_384KHZ 0x0d +#define BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ 0x0d /** * @brief LC3 7.5 msec Frame Duration configuration */ -#define BT_CODEC_CONFIG_LC3_DURATION_7_5 0x00 +#define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5 0x00 /** * @brief LC3 10 msec Frame Duration configuration */ -#define BT_CODEC_CONFIG_LC3_DURATION_10 0x01 +#define BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10 0x01 /** @@ -255,36 +254,38 @@ enum bt_codec_config_type { * If the flags argument is != 1 it will evaluate to the third argument which inserts a LTV * entry for the max_frames_per_sdu value. */ -#define BT_CODEC_LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max, _max_frames_per_sdu) \ -{ \ - BT_CODEC_DATA(BT_CODEC_LC3_FREQ, BT_BYTES_LIST_LE16(_freq)), \ - BT_CODEC_DATA(BT_CODEC_LC3_DURATION, _duration), \ - BT_CODEC_DATA(BT_CODEC_LC3_CHAN_COUNT, _chan_count), \ - BT_CODEC_DATA(BT_CODEC_LC3_FRAME_LEN, \ - BT_BYTES_LIST_LE16(_len_min), \ - BT_BYTES_LIST_LE16(_len_max)) \ - COND_CODE_1(_max_frames_per_sdu, (), \ - (, BT_CODEC_DATA(BT_CODEC_LC3_FRAME_COUNT, \ - _max_frames_per_sdu))) \ -} +#define BT_AUDIO_CODEC_LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max, \ + _max_frames_per_sdu) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FREQ, BT_BYTES_LIST_LE16(_freq)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_DURATION, _duration), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_CHAN_COUNT, _chan_count), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_LEN, \ + BT_BYTES_LIST_LE16(_len_min), \ + BT_BYTES_LIST_LE16(_len_max)) \ + COND_CODE_1(_max_frames_per_sdu, (), \ + (, BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_COUNT, \ + _max_frames_per_sdu))) \ + } /** * @brief Helper to declare LC3 codec metadata */ -#define BT_CODEC_LC3_META(_prefer_context) \ -{ \ - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, BT_BYTES_LIST_LE16(_prefer_context)) \ -} +#define BT_AUDIO_CODEC_LC3_META(_prefer_context) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_BYTES_LIST_LE16(_prefer_context)) \ + } /** * @brief Helper to declare LC3 codec */ -#define BT_CODEC_LC3(_freq, _duration, _chan_count, _len_min, _len_max, \ - _max_frames_per_sdu, _prefer_context) \ - BT_CODEC(BT_CODEC_LC3_ID, 0x0000, 0x0000, \ - BT_CODEC_LC3_DATA(_freq, _duration, _chan_count, _len_min, \ - _len_max, _max_frames_per_sdu), \ - BT_CODEC_LC3_META(_prefer_context)) +#define BT_AUDIO_CODEC_LC3(_freq, _duration, _chan_count, _len_min, _len_max, _max_frames_per_sdu, \ + _prefer_context) \ + BT_AUDIO_CODEC(BT_AUDIO_CODEC_LC3_ID, 0x0000, 0x0000, \ + BT_AUDIO_CODEC_LC3_DATA(_freq, _duration, _chan_count, _len_min, _len_max, \ + _max_frames_per_sdu), \ + BT_AUDIO_CODEC_LC3_META(_prefer_context)) /** * @brief Helper to declare LC3 codec data configuration @@ -297,40 +298,44 @@ enum bt_codec_config_type { * If the flags argument is != 1 it will evaluate to the third argument which inserts a LTV * entry for the _frame_blocks_per_sdu value. */ -#define BT_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frame_blocks_per_sdu) \ -{ \ - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, _freq), \ - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_DURATION, _duration), \ - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_CHAN_ALLOC, BT_BYTES_LIST_LE32(_loc)), \ - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FRAME_LEN, BT_BYTES_LIST_LE16(_len)), \ - COND_CODE_1(_frame_blocks_per_sdu, (), \ - (, BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, \ - _frame_blocks_per_sdu))) \ -} +#define BT_AUDIO_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frame_blocks_per_sdu) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, _freq), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_DURATION, _duration), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, \ + BT_BYTES_LIST_LE32(_loc)), \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN, \ + BT_BYTES_LIST_LE16(_len)), \ + COND_CODE_1(_frame_blocks_per_sdu, (), \ + (, BT_AUDIO_CODEC_DATA( \ + BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, \ + _frame_blocks_per_sdu))) \ + } /** * @brief Helper to declare LC3 codec metadata configuration */ -#define BT_CODEC_LC3_CONFIG_META(_stream_context) \ -{ \ - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, BT_BYTES_LIST_LE16(_stream_context)) \ -} +#define BT_AUDIO_CODEC_LC3_CONFIG_META(_stream_context) \ + { \ + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, \ + BT_BYTES_LIST_LE16(_stream_context)) \ + } /** * @brief Helper to declare LC3 codec configuration. * - * @param _freq Sampling frequency (BT_CODEC_CONFIG_LC3_FREQ_*) - * @param _duration Frame duration (BT_CODEC_CONFIG_LC3_DURATION_*) + * @param _freq Sampling frequency (BT_AUDIO_CODEC_CONFIG_LC3_FREQ_*) + * @param _duration Frame duration (BT_AUDIO_CODEC_CONFIG_LC3_DURATION_*) * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _len Octets per frame (16-bit integer) * @param _frames_per_sdu Frames per SDU (8-bit integer) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, \ - _stream_context) \ - BT_CODEC(BT_CODEC_LC3_ID, 0x0000, 0x0000, \ - BT_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frames_per_sdu), \ - BT_CODEC_LC3_CONFIG_META(_stream_context)) +#define BT_AUDIO_CODEC_LC3_CONFIG(_freq, _duration, _loc, _len, _frames_per_sdu, _stream_context) \ + BT_AUDIO_CODEC( \ + BT_AUDIO_CODEC_LC3_ID, 0x0000, 0x0000, \ + BT_AUDIO_CODEC_LC3_CONFIG_DATA(_freq, _duration, _loc, _len, _frames_per_sdu), \ + BT_AUDIO_CODEC_LC3_CONFIG_META(_stream_context)) /** * @brief Helper to declare LC3 8.1 codec configuration @@ -338,40 +343,40 @@ enum bt_codec_config_type { * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_8_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_8KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 26u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_8_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 26u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 8.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_8_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_8KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 30u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_8_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 30u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 16.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_16_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_16KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 30u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 30u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 16.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_16_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_16KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 40u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 40u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 24.1 codec configuration @@ -379,142 +384,140 @@ enum bt_codec_config_type { * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_24_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_24KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 45u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_24_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 45u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 24.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_24_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_24KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 60u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_24_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 60u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 32.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_32_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_32KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 60u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 60u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 32.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_32_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_32KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 80u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 80u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 441.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_441_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_44KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 98u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_441_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 98u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 441.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_441_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_44KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 130u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_441_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 130u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.1 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_1(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 75u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 75u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.2 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_2(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 100u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 100u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.3 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_3(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 90u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 90u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.4 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_4(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 120u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 120u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.5 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_5(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 117u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_5(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5, _loc, 117u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 48.6 codec configuration * * @param _loc Audio channel location bitfield (@ref bt_audio_location) * @param _stream_context Stream context (BT_AUDIO_CONTEXT_*) */ -#define BT_CODEC_LC3_CONFIG_48_6(_loc, _stream_context) \ - BT_CODEC_LC3_CONFIG(BT_CODEC_CONFIG_LC3_FREQ_48KHZ, \ - BT_CODEC_CONFIG_LC3_DURATION_10, _loc, 155u, \ - 1, _stream_context) +#define BT_AUDIO_CODEC_LC3_CONFIG_48_6(_loc, _stream_context) \ + BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ, \ + BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, 155u, 1, \ + _stream_context) /** * @brief Helper to declare LC3 codec QoS for 7.5ms interval */ -#define BT_CODEC_LC3_QOS_7_5(_framing, _sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS(7500u, _framing, BT_CODEC_QOS_2M, _sdu, _rtn, \ - _latency, _pd) +#define BT_AUDIO_CODEC_LC3_QOS_7_5(_framing, _sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS(7500u, _framing, BT_AUDIO_CODEC_QOS_2M, _sdu, _rtn, _latency, _pd) /** * @brief Helper to declare LC3 codec QoS for 7.5ms interval unframed input */ -#define BT_CODEC_LC3_QOS_7_5_UNFRAMED(_sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS_UNFRAMED(7500u, _sdu, _rtn, _latency, _pd) +#define BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(_sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS_UNFRAMED(7500u, _sdu, _rtn, _latency, _pd) /** * @brief Helper to declare LC3 codec QoS for 10ms frame internal */ -#define BT_CODEC_LC3_QOS_10(_framing, _sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS(10000u, _framing, BT_CODEC_QOS_2M, _sdu, _rtn, \ - _latency, _pd) +#define BT_AUDIO_CODEC_LC3_QOS_10(_framing, _sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS(10000u, _framing, BT_AUDIO_CODEC_QOS_2M, _sdu, _rtn, _latency, _pd) /** * @brief Helper to declare LC3 codec QoS for 10ms interval unframed input */ -#define BT_CODEC_LC3_QOS_10_UNFRAMED(_sdu, _rtn, _latency, _pd) \ - BT_CODEC_QOS_UNFRAMED(10000u, _sdu, _rtn, _latency, _pd) +#define BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(_sdu, _rtn, _latency, _pd) \ + BT_AUDIO_CODEC_QOS_UNFRAMED(10000u, _sdu, _rtn, _latency, _pd) #ifdef __cplusplus } diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index 64533abe8ed8..3400baac92b9 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -18,8 +18,8 @@ extern "C" { /** @brief Published Audio Capability structure. */ struct bt_pacs_cap { - /** Capability codec reference */ - struct bt_codec *codec; + /** Codec capability reference */ + struct bt_audio_codec_cap *codec_cap; /* Internally used list node */ sys_snode_t _node; diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index 5107b8db9d19..4a017b6197d6 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -45,8 +45,8 @@ static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; static struct bt_conn *broadcast_assistant_conn; static struct bt_le_ext_adv *ext_adv; -static struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); +static struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); /* 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 @@ -416,7 +416,7 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { }; static struct bt_pacs_cap cap = { - .codec = &codec, + .codec_cap = &codec_cap, }; static int init(void) diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index bb761c662a65..668786c657f9 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -102,7 +102,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) for (size_t i = 0U; i < ARRAY_SIZE(subgroup_param); i++) { subgroup_param[i].params_count = streams_per_subgroup; subgroup_param[i].params = stream_params + i * streams_per_subgroup; - subgroup_param[i].codec = &preset_16_2_1.codec; + subgroup_param[i].codec_cfg = &preset_16_2_1.codec_cfg; } for (size_t j = 0U; j < ARRAY_SIZE(stream_params); j++) { diff --git a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c index 23814b139ada..501f81bf4880 100644 --- a/samples/bluetooth/hap_ha/src/bap_unicast_sr.c +++ b/samples/bluetooth/hap_ha/src/bap_unicast_sr.c @@ -21,11 +21,10 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_ASE_SRC_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -static struct bt_codec lc3_codec = - BT_CODEC_LC3(BT_CODEC_LC3_FREQ_16KHZ | BT_CODEC_LC3_FREQ_24KHZ, - BT_CODEC_LC3_DURATION_10, - BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_LC3( + BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ, + BT_AUDIO_CODEC_LC3_DURATION_10, BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); static struct bt_conn *default_conn; static struct k_work_delayable audio_send_work; @@ -36,8 +35,8 @@ static struct audio_source { } source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; static size_t configured_source_stream_count; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, - 10, 20000, 40000, 20000, 40000); +static const struct bt_audio_codec_qos_pref qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 20000, 40000, 20000, 40000); static uint16_t get_and_incr_seq_num(const struct bt_bap_stream *stream) { @@ -59,50 +58,47 @@ static void print_hex(const uint8_t *ptr, size_t len) } } -static void print_codec(const struct bt_codec *codec) +static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); - - for (size_t i = 0; i < codec->data_count; i++) { - printk("data #%zu: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_count); + + for (size_t i = 0; i < codec_cfg->data_count; i++) { + printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + print_hex(codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type)); printk("\n"); } - if (codec->id == BT_CODEC_LC3_ID) { + if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) { /* LC3 uses the generic LTV format - other codecs might do as well */ enum bt_audio_location chan_allocation; - printk(" Frequency: %d Hz\n", bt_codec_cfg_get_freq(codec)); - printk(" Frame Duration: %d us\n", bt_codec_cfg_get_frame_duration_us(codec)); - if (bt_codec_cfg_get_chan_allocation_val(codec, &chan_allocation) == 0) { + printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } printk(" Octets per frame: %d (negative means value not pressent)\n", - bt_codec_cfg_get_octets_per_frame(codec)); + bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); printk(" Frames per SDU: %d\n", - bt_codec_cfg_get_frame_blocks_per_sdu(codec, true)); + bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); } - for (size_t i = 0; i < codec->meta_count; i++) { - printk("meta #%zu: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + for (size_t i = 0; i < codec_cfg->meta_count; i++) { + printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + print_hex(codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type)); printk("\n"); } } -static void print_qos(const struct bt_codec_qos *qos) +static 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", @@ -188,12 +184,12 @@ static struct bt_bap_stream *stream_alloc(void) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *stream = stream_alloc(); if (*stream == NULL) { @@ -214,12 +210,12 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE); @@ -227,7 +223,7 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, return -ENOEXEC; } -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +static int lc3_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); @@ -237,7 +233,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Enable: stream %p meta_count %u\n", stream, meta_count); @@ -307,13 +303,13 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Metadata: stream %p meta_count %u\n", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { printk("Invalid metadata type %u or length %u\n", @@ -417,11 +413,11 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { }; static struct bt_pacs_cap cap_sink = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; static struct bt_pacs_cap cap_source = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; int bap_unicast_sr_init(void) diff --git a/samples/bluetooth/tmap_central/src/cap_initiator.c b/samples/bluetooth/tmap_central/src/cap_initiator.c index 0daeccffff7c..bfe97175a04e 100644 --- a/samples/bluetooth/tmap_central/src/cap_initiator.c +++ b/samples/bluetooth/tmap_central/src/cap_initiator.c @@ -33,7 +33,7 @@ static K_SEM_DEFINE(sem_discover_source, 0, 1); static K_SEM_DEFINE(sem_audio_start, 0, 1); static void unicast_stream_configured(struct bt_bap_stream *stream, - const struct bt_codec_qos_pref *pref) + const struct bt_audio_codec_qos_pref *pref) { printk("Configured stream %p\n", stream); @@ -180,36 +180,32 @@ static void print_hex(const uint8_t *ptr, size_t len) } } -static void print_codec_capabilities(const struct bt_codec *codec) +static void print_codec_capabilities(const struct bt_audio_codec_cap *codec_cap) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); - - for (size_t i = 0; i < codec->data_count; i++) { - printk("data #%zu: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + printk("codec_cap 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cap->id, codec_cap->cid, + codec_cap->vid, codec_cap->data_count); + + for (size_t i = 0; i < codec_cap->data_count; i++) { + printk("data #%zu: type 0x%02x len %u\n", i, codec_cap->data[i].data.type, + codec_cap->data[i].data.data_len); + print_hex(codec_cap->data[i].data.data, + codec_cap->data[i].data.data_len - sizeof(codec_cap->data[i].data.type)); printk("\n"); } - for (size_t i = 0; i < codec->meta_count; i++) { - printk("meta #%zu: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + for (size_t i = 0; i < codec_cap->meta_count; i++) { + printk("meta #%zu: type 0x%02x len %u\n", i, codec_cap->meta[i].data.type, + codec_cap->meta[i].data.data_len); + print_hex(codec_cap->meta[i].data.data, + codec_cap->meta[i].data.data_len - sizeof(codec_cap->meta[i].data.type)); printk("\n"); } } -static void print_remote_codec(const struct bt_codec *codec_capabilities, enum bt_audio_dir dir) +static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum bt_audio_dir dir) { - printk("codec_capabilities %p dir 0x%02x\n", codec_capabilities, dir); - print_codec_capabilities(codec_capabilities); + printk("codec_cap %p dir 0x%02x\n", codec_cap, dir); + print_codec_capabilities(codec_cap); } static void add_remote_sink(struct bt_bap_ep *ep) @@ -250,9 +246,10 @@ static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) } } -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) { - print_remote_codec(codec, dir); + print_remote_codec(codec_cap, dir); } static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) @@ -347,7 +344,7 @@ static int unicast_audio_start(struct bt_conn *conn, struct bt_bap_unicast_group stream_param.member.member = conn; stream_param.stream = &unicast_streams[0]; stream_param.ep = unicast_sink_eps[0]; - stream_param.codec = &unicast_preset_48_2_1.codec; + stream_param.codec_cfg = &unicast_preset_48_2_1.codec_cfg; stream_param.qos = &unicast_preset_48_2_1.qos; err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); diff --git a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c index 0206238cc6b9..54f3df7805e7 100644 --- a/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c +++ b/samples/bluetooth/tmap_peripheral/src/bap_unicast_sr.c @@ -23,53 +23,12 @@ #define AVAILABLE_SINK_CONTEXT CONFIG_BT_PACS_SNK_CONTEXT #define AVAILABLE_SOURCE_CONTEXT CONFIG_BT_PACS_SRC_CONTEXT -static struct bt_bap_lc3_preset codec_cfg_src_16_1_1 = - BT_BAP_LC3_UNICAST_PRESET_16_1_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SRC_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_16_1_1 = - BT_BAP_LC3_UNICAST_PRESET_16_1_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_src_32_1_1 = - BT_BAP_LC3_UNICAST_PRESET_32_1_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SRC_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_32_1_1 = - BT_BAP_LC3_UNICAST_PRESET_32_1_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_src_32_2_1 = - BT_BAP_LC3_UNICAST_PRESET_32_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SRC_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_32_2_1 = - BT_BAP_LC3_UNICAST_PRESET_32_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_1_1 = - BT_BAP_LC3_UNICAST_PRESET_48_1_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_2_1 = - BT_BAP_LC3_UNICAST_PRESET_48_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_3_1 = - BT_BAP_LC3_UNICAST_PRESET_48_3_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_4_1 = - BT_BAP_LC3_UNICAST_PRESET_48_4_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_5_1 = - BT_BAP_LC3_UNICAST_PRESET_48_5_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); - -static struct bt_bap_lc3_preset codec_cfg_snk_48_6_1 = - BT_BAP_LC3_UNICAST_PRESET_48_6_1(BT_AUDIO_LOCATION_FRONT_LEFT, - CONFIG_BT_PACS_SNK_CONTEXT); +static struct bt_audio_codec_cap lc3_codec_cap = + BT_AUDIO_CODEC_LC3(BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_32KHZ | + BT_AUDIO_CODEC_LC3_FREQ_48KHZ, + BT_AUDIO_CODEC_LC3_DURATION_7_5 | BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(2), 30, 155u, 1u, + (CONFIG_BT_PACS_SNK_CONTEXT | CONFIG_BT_PACS_SRC_CONTEXT)); static struct bt_conn *default_conn; static struct bt_bap_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; @@ -79,8 +38,8 @@ static struct audio_source { } source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; static size_t configured_source_stream_count; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, - 10, 20000, 40000, 20000, 40000); +static const struct bt_audio_codec_qos_pref qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 20000, 40000, 20000, 40000); static void print_hex(const uint8_t *ptr, size_t len) { @@ -89,50 +48,47 @@ static void print_hex(const uint8_t *ptr, size_t len) } } -static void print_codec(const struct bt_codec *codec) +static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); - - for (size_t i = 0; i < codec->data_count; i++) { - printk("data #%zu: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_count); + + for (size_t i = 0; i < codec_cfg->data_count; i++) { + printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + print_hex(codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type)); printk("\n"); } - if (codec->id == BT_CODEC_LC3_ID) { + if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) { /* LC3 uses the generic LTV format - other codecs might do as well */ uint32_t chan_allocation; - printk(" Frequency: %d Hz\n", bt_codec_cfg_get_freq(codec)); - printk(" Frame Duration: %d us\n", bt_codec_cfg_get_frame_duration_us(codec)); - if (bt_codec_cfg_get_chan_allocation_val(codec, &chan_allocation) == 0) { + printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } printk(" Octets per frame: %d (negative means value not pressent)\n", - bt_codec_cfg_get_octets_per_frame(codec)); + bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); printk(" Frames per SDU: %d\n", - bt_codec_cfg_get_frame_blocks_per_sdu(codec, true)); + bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); } - for (size_t i = 0; i < codec->meta_count; i++) { - printk("meta #%zu: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + for (size_t i = 0; i < codec_cfg->meta_count; i++) { + printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + print_hex(codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type)); printk("\n"); } } -static void print_qos(const struct bt_codec_qos *qos) +static 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", @@ -154,13 +110,13 @@ static struct bt_bap_stream *stream_alloc(void) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *stream = stream_alloc(); if (*stream == NULL) { @@ -182,17 +138,17 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *pref = qos_pref; return 0; } -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +static int lc3_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); @@ -202,7 +158,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Enable: stream %p meta_count %u\n", stream, meta_count); @@ -256,14 +212,14 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Metadata: stream %p meta_count %u\n", stream, meta_count); bool stream_context_present = false; for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { printk("Invalid metadata type %u or length %u\n", @@ -388,52 +344,8 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .disconnected = disconnected, }; -static struct bt_pacs_cap cap_sink_16_1_1 = { - .codec = &codec_cfg_snk_16_1_1.codec, -}; - -static struct bt_pacs_cap cap_source_16_1_1 = { - .codec = &codec_cfg_src_16_1_1.codec, -}; - -static struct bt_pacs_cap cap_sink_32_1_1 = { - .codec = &codec_cfg_snk_32_1_1.codec, -}; - -static struct bt_pacs_cap cap_source_32_1_1 = { - .codec = &codec_cfg_src_32_1_1.codec, -}; - -static struct bt_pacs_cap cap_sink_32_2_1 = { - .codec = &codec_cfg_snk_32_2_1.codec, -}; - -static struct bt_pacs_cap cap_source_32_2_1 = { - .codec = &codec_cfg_src_32_2_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_1_1 = { - .codec = &codec_cfg_snk_48_1_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_2_1 = { - .codec = &codec_cfg_snk_48_2_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_3_1 = { - .codec = &codec_cfg_snk_48_3_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_4_1 = { - .codec = &codec_cfg_snk_48_4_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_5_1 = { - .codec = &codec_cfg_snk_48_5_1.codec, -}; - -static struct bt_pacs_cap cap_sink_48_6_1 = { - .codec = &codec_cfg_snk_48_6_1.codec, +static struct bt_pacs_cap cap = { + .codec_cap = &lc3_codec_cap, }; int bap_unicast_sr_init(void) @@ -442,17 +354,7 @@ int bap_unicast_sr_init(void) if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) { /* Register CT required capabilities */ - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_16_1_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_32_1_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_32_2_1); - - /* Register UMR required capabilities */ - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_1_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_2_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_3_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_4_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_5_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink_48_6_1); + bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); if (IS_ENABLED(CONFIG_TMAP_PERIPHERAL_LEFT)) { bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_LEFT); @@ -468,9 +370,7 @@ int bap_unicast_sr_init(void) if (IS_ENABLED(CONFIG_BT_ASCS_ASE_SRC)) { /* Register CT required capabilities */ - bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source_16_1_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source_32_1_1); - bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source_32_2_1); + bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap); if (IS_ENABLED(CONFIG_TMAP_PERIPHERAL_LEFT)) { bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, BT_AUDIO_LOCATION_FRONT_LEFT); diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 2b7d72cb7188..db3cd03efbab 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -223,13 +223,14 @@ static void lc3_audio_timer_timeout(struct k_work *work) static void init_lc3(void) { + const struct bt_audio_codec_cfg *codec_cfg = &codec_configuration.codec_cfg; unsigned int num_samples; - freq_hz = bt_codec_cfg_get_freq(&codec_configuration.codec); - frame_duration_us = bt_codec_cfg_get_frame_duration_us(&codec_configuration.codec); - octets_per_frame = bt_codec_cfg_get_octets_per_frame(&codec_configuration.codec); - frames_per_sdu = bt_codec_cfg_get_frame_blocks_per_sdu(&codec_configuration.codec, true); - octets_per_frame = bt_codec_cfg_get_octets_per_frame(&codec_configuration.codec); + freq_hz = bt_audio_codec_cfg_get_freq(codec_cfg); + frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg); + 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); + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); if (freq_hz < 0) { printk("Error: Codec frequency not set, cannot start codec."); @@ -352,28 +353,24 @@ static void print_hex(const uint8_t *ptr, size_t len) } } -static void print_codec_capabilities(const struct bt_codec *codec) +static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); - - for (size_t i = 0; i < codec->data_count; i++) { - printk("data #%zu: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cap->id, codec_cap->cid, + codec_cap->vid, codec_cap->data_count); + + for (size_t i = 0; i < codec_cap->data_count; i++) { + printk("data #%zu: type 0x%02x len %u\n", i, codec_cap->data[i].data.type, + codec_cap->data[i].data.data_len); + print_hex(codec_cap->data[i].data.data, + codec_cap->data[i].data.data_len - sizeof(codec_cap->data[i].data.type)); printk("\n"); } - for (size_t i = 0; i < codec->meta_count; i++) { - printk("meta #%zu: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + for (size_t i = 0; i < codec_cap->meta_count; i++) { + printk("meta #%zu: type 0x%02x len %u\n", i, codec_cap->meta[i].data.type, + codec_cap->meta[i].data.data_len); + print_hex(codec_cap->meta[i].data.data, + codec_cap->meta[i].data.data_len - sizeof(codec_cap->meta[i].data.type)); printk("\n"); } } @@ -485,7 +482,7 @@ static void start_scan(void) } static void stream_configured(struct bt_bap_stream *stream, - const struct bt_codec_qos_pref *pref) + const struct bt_audio_codec_qos_pref *pref) { printk("Audio Stream %p configured\n", stream); @@ -591,11 +588,12 @@ static void add_remote_sink(struct bt_bap_ep *ep) printk("Could not add sink ep\n"); } -static void print_remote_codec(const struct bt_codec *codec_capabilities, enum bt_audio_dir dir) +static void print_remote_codec_cap(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_dir dir) { - printk("codec_capabilities %p dir 0x%02x\n", codec_capabilities, dir); + printk("codec_cap %p dir 0x%02x\n", codec_cap, dir); - print_codec_capabilities(codec_capabilities); + print_codec_cap(codec_cap); } static void discover_sinks_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) @@ -712,9 +710,10 @@ static void available_contexts_cb(struct bt_conn *conn, printk("snk ctx %u src ctx %u\n", snk_ctx, src_ctx); } -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) { - print_remote_codec(codec, dir); + print_remote_codec_cap(codec_cap, dir); } static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) @@ -837,8 +836,7 @@ static int configure_stream(struct bt_bap_stream *stream, struct bt_bap_ep *ep) { int err; - err = bt_bap_stream_config(default_conn, stream, ep, - &codec_configuration.codec); + err = bt_bap_stream_config(default_conn, stream, ep, &codec_configuration.codec_cfg); if (err != 0) { return err; } @@ -982,9 +980,8 @@ static int enable_streams(void) for (size_t i = 0U; i < configured_stream_count; i++) { int err; - err = bt_bap_stream_enable(&streams[i], - codec_configuration.codec.meta, - codec_configuration.codec.meta_count); + err = bt_bap_stream_enable(&streams[i], codec_configuration.codec_cfg.meta, + codec_configuration.codec_cfg.meta_count); if (err != 0) { printk("Unable to enable stream: %d\n", err); return err; diff --git a/samples/bluetooth/unicast_audio_server/src/main.c b/samples/bluetooth/unicast_audio_server/src/main.c index 8a2f40b4454d..c73fe2e2f7ac 100644 --- a/samples/bluetooth/unicast_audio_server/src/main.c +++ b/samples/bluetooth/unicast_audio_server/src/main.c @@ -33,10 +33,10 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ASCS_ASE_SRC_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); -static struct bt_codec lc3_codec = - BT_CODEC_LC3(BT_CODEC_LC3_FREQ_ANY, BT_CODEC_LC3_DURATION_10, - BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_audio_codec_cap lc3_codec_cap = + BT_AUDIO_CODEC_LC3(BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); static struct bt_conn *default_conn; static struct k_work_delayable audio_send_work; @@ -49,8 +49,8 @@ static struct audio_source { } source_streams[CONFIG_BT_ASCS_ASE_SRC_COUNT]; static size_t configured_source_stream_count; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, - 10, 40000, 40000, 40000, 40000); +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); static K_SEM_DEFINE(sem_disconnected, 0, 1); @@ -118,50 +118,47 @@ void print_hex(const uint8_t *ptr, size_t len) } } -static void print_codec(const struct bt_codec *codec) +static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); - - for (size_t i = 0; i < codec->data_count; i++) { - printk("data #%zu: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_count); + + for (size_t i = 0; i < codec_cfg->data_count; i++) { + printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + print_hex(codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type)); printk("\n"); } - if (codec->id == BT_CODEC_LC3_ID) { + if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) { /* LC3 uses the generic LTV format - other codecs might do as well */ enum bt_audio_location chan_allocation; - printk(" Frequency: %d Hz\n", bt_codec_cfg_get_freq(codec)); - printk(" Frame Duration: %d us\n", bt_codec_cfg_get_frame_duration_us(codec)); - if (bt_codec_cfg_get_chan_allocation_val(codec, &chan_allocation) == 0) { + printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg)); + printk(" Frame Duration: %d us\n", + bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + if (bt_audio_codec_cfg_get_chan_allocation_val(codec_cfg, &chan_allocation) == 0) { printk(" Channel allocation: 0x%x\n", chan_allocation); } printk(" Octets per frame: %d (negative means value not pressent)\n", - bt_codec_cfg_get_octets_per_frame(codec)); + bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); printk(" Frames per SDU: %d\n", - bt_codec_cfg_get_frame_blocks_per_sdu(codec, true)); + bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); } - for (size_t i = 0; i < codec->meta_count; i++) { - printk("meta #%zu: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + for (size_t i = 0; i < codec_cfg->meta_count; i++) { + printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + print_hex(codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type)); printk("\n"); } } -static void print_qos(const struct bt_codec_qos *qos) +static 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", @@ -277,12 +274,12 @@ static struct bt_bap_stream *stream_alloc(enum bt_audio_dir dir) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *stream = stream_alloc(dir); if (*stream == NULL) { @@ -309,12 +306,12 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); #if defined(CONFIG_LIBLC3) /* Nothing to free as static memory is used */ @@ -327,7 +324,7 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, return -ENOEXEC; } -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +static int lc3_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); @@ -344,15 +341,16 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Enable: stream %p meta_count %u\n", stream, meta_count); #if defined(CONFIG_LIBLC3) { - const int freq = bt_codec_cfg_get_freq(stream->codec); - const int frame_duration_us = bt_codec_cfg_get_frame_duration_us(stream->codec); + const int freq = bt_audio_codec_cfg_get_freq(stream->codec_cfg); + const int frame_duration_us = + bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); if (freq < 0) { printk("Error: Codec frequency not set, cannot start codec."); @@ -368,7 +366,8 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data * return -1; } - frames_per_sdu = bt_codec_cfg_get_frame_blocks_per_sdu(stream->codec, true); + frames_per_sdu = + bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); lc3_decoder = lc3_setup_decoder(frame_duration_us, freq, @@ -448,13 +447,13 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Metadata: stream %p meta_count %u\n", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { printk("Invalid metadata type %u or length %u\n", @@ -640,11 +639,11 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { }; static struct bt_pacs_cap cap_sink = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; static struct bt_pacs_cap cap_source = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; static int set_location(void) diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index d77bacb71803..4bb2361dc0a5 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -38,7 +38,15 @@ config BT_BAP_UNICAST_CLIENT This option enables support for Bluetooth Unicast Audio Client using Isochronous channels. -config BT_CODEC_MAX_DATA_COUNT +config BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + int "Codec Specific Configuration Data Count" + default 5 + range 1 128 + help + This option defines the maximum number of LTV entries a codec can + store. + +config BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT int "Codec Capabilities Data Count" default 5 range 1 128 @@ -46,7 +54,7 @@ config BT_CODEC_MAX_DATA_COUNT This option defines the maximum number of LTV entries a codec can store. -config BT_CODEC_MAX_DATA_LEN +config BT_AUDIO_CODEC_MAX_DATA_LEN int "Codec Capabilities Data Length" default 4 range 1 128 @@ -54,8 +62,16 @@ config BT_CODEC_MAX_DATA_LEN This option defines the maximum value length of an LTV entry a codec can store. -config BT_CODEC_MAX_METADATA_COUNT - int "Codec Metadata Count" +config BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT + int "Codec Specific Configuration Metadata Count" + default 2 + range 1 128 + help + This option defines the maximum number of LTV entries a metadata can + store. + +config BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT + int "Codec Capabilities Metadata Count" default 2 range 1 128 help diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 20372beaf894..01ea1359f998 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -62,12 +62,12 @@ static struct bt_ascs_ase { struct k_work_delayable disconnect_work; } ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; -#define MAX_CODEC_CONFIG \ - MIN(UINT8_MAX, \ - CONFIG_BT_CODEC_MAX_DATA_COUNT * CONFIG_BT_CODEC_MAX_DATA_LEN) -#define MAX_METADATA \ - MIN(UINT8_MAX, \ - CONFIG_BT_CODEC_MAX_METADATA_COUNT * CONFIG_BT_CODEC_MAX_DATA_LEN) +#define MAX_CODEC_CONFIG \ + MIN(UINT8_MAX, \ + CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN) +#define MAX_METADATA \ + MIN(UINT8_MAX, \ + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN) /* Minimum state size when in the codec configured state */ #define MIN_CONFIG_STATE_SIZE (1 + 1 + 1 + 1 + 1 + 2 + 3 + 3 + 3 + 3 + 5 + 1) @@ -458,8 +458,8 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) } } -static void ascs_codec_data_add(struct net_buf_simple *buf, const char *prefix, - uint8_t num, struct bt_codec_data *data) +static void ascs_codec_data_add(struct net_buf_simple *buf, const char *prefix, uint8_t num, + struct bt_audio_codec_data *data) { struct bt_ascs_codec_config *cc; int i; @@ -480,7 +480,7 @@ static void ascs_codec_data_add(struct net_buf_simple *buf, const char *prefix, static void ascs_ep_get_status_config(struct bt_bap_ep *ep, struct net_buf_simple *buf) { struct bt_ascs_ase_status_config *cfg; - struct bt_codec_qos_pref *pref = &ep->qos_pref; + struct bt_audio_codec_qos_pref *pref = &ep->qos_pref; cfg = net_buf_simple_add(buf, sizeof(*cfg)); cfg->framing = pref->unframed_supported ? BT_ASCS_QOS_FRAMING_UNFRAMED @@ -492,18 +492,18 @@ static void ascs_ep_get_status_config(struct bt_bap_ep *ep, struct net_buf_simpl sys_put_le24(pref->pd_max, cfg->pd_max); sys_put_le24(pref->pref_pd_min, cfg->prefer_pd_min); sys_put_le24(pref->pref_pd_max, cfg->prefer_pd_max); - cfg->codec.id = ep->codec.id; - cfg->codec.cid = sys_cpu_to_le16(ep->codec.cid); - cfg->codec.vid = sys_cpu_to_le16(ep->codec.vid); + cfg->codec.id = ep->codec_cfg.id; + cfg->codec.cid = sys_cpu_to_le16(ep->codec_cfg.cid); + cfg->codec.vid = sys_cpu_to_le16(ep->codec_cfg.vid); LOG_DBG("dir %s unframed_supported 0x%02x phy 0x%02x rtn %u " - "latency %u pd_min %u pd_max %u pref_pd_min %u pref_pd_max %u codec 0x%02x", + "latency %u pd_min %u pd_max %u pref_pd_min %u pref_pd_max %u codec id 0x%02x", bt_audio_dir_str(ep->dir), pref->unframed_supported, pref->phy, pref->rtn, pref->latency, pref->pd_min, pref->pd_max, pref->pref_pd_min, pref->pref_pd_max, - ep->stream->codec->id); + ep->stream->codec_cfg->id); cfg->cc_len = buf->len; - ascs_codec_data_add(buf, "data", ep->codec.data_count, ep->codec.data); + ascs_codec_data_add(buf, "data", ep->codec_cfg.data_count, ep->codec_cfg.data); cfg->cc_len = buf->len - cfg->cc_len; } @@ -522,12 +522,11 @@ static void ascs_ep_get_status_qos(struct bt_bap_ep *ep, struct net_buf_simple * qos->latency = sys_cpu_to_le16(ep->stream->qos->latency); sys_put_le24(ep->stream->qos->pd, qos->pd); - LOG_DBG("dir %s codec 0x%02x interval %u framing 0x%02x phy 0x%02x " - "rtn %u latency %u pd %u", - bt_audio_dir_str(ep->dir), ep->stream->codec->id, - ep->stream->qos->interval, ep->stream->qos->framing, - ep->stream->qos->phy, ep->stream->qos->rtn, - ep->stream->qos->latency, ep->stream->qos->pd); + LOG_DBG("dir %s codec id 0x%02x interval %u framing 0x%02x phy 0x%02x " + "rtn %u latency %u pd %u", + bt_audio_dir_str(ep->dir), ep->stream->codec_cfg->id, ep->stream->qos->interval, + ep->stream->qos->framing, ep->stream->qos->phy, ep->stream->qos->rtn, + ep->stream->qos->latency, ep->stream->qos->pd); } static void ascs_ep_get_status_enable(struct bt_bap_ep *ep, struct net_buf_simple *buf) @@ -539,7 +538,7 @@ static void ascs_ep_get_status_enable(struct bt_bap_ep *ep, struct net_buf_simpl enable->cis_id = ep->cis_id; enable->metadata_len = buf->len; - ascs_codec_data_add(buf, "meta", ep->codec.meta_count, ep->codec.meta); + ascs_codec_data_add(buf, "meta", ep->codec_cfg.meta_count, ep->codec_cfg.meta); enable->metadata_len = buf->len - enable->metadata_len; LOG_DBG("dir %s cig 0x%02x cis 0x%02x", @@ -1198,15 +1197,15 @@ static void ascs_cp_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) static bool ascs_codec_config_store(struct bt_data *data, void *user_data) { - struct bt_codec *codec = user_data; - struct bt_codec_data *cdata; + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_audio_codec_data *cdata; - if (codec->data_count >= ARRAY_SIZE(codec->data)) { + if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) { LOG_ERR("No slot available for Codec Config"); return false; } - cdata = &codec->data[codec->data_count]; + cdata = &codec_cfg->data[codec_cfg->data_count]; if (data->data_len > sizeof(cdata->value)) { LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len, @@ -1214,7 +1213,7 @@ static bool ascs_codec_config_store(struct bt_data *data, void *user_data) return false; } - LOG_DBG("#%u type 0x%02x len %u", codec->data_count, data->type, data->data_len); + LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len); cdata->data.type = data->type; cdata->data.data_len = data->data_len; @@ -1225,25 +1224,25 @@ static bool ascs_codec_config_store(struct bt_data *data, void *user_data) LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data"); - codec->data_count++; + codec_cfg->data_count++; return true; } -struct codec_lookup_id_data { +struct codec_cap_lookup_id_data { uint8_t id; uint16_t cid; uint16_t vid; - struct bt_codec *codec; + struct bt_audio_codec_cap *codec_cap; }; static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) { - struct codec_lookup_id_data *data = user_data; + struct codec_cap_lookup_id_data *data = user_data; - if (cap->codec->id == data->id && cap->codec->cid == data->cid && - cap->codec->vid == data->vid) { - data->codec = cap->codec; + if (cap->codec_cap->id == data->id && cap->codec_cap->cid == data->cid && + cap->codec_cap->vid == data->vid) { + data->codec_cap = cap->codec_cap; return false; } @@ -1255,8 +1254,8 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin uint8_t *cc, uint8_t len, struct bt_bap_ascs_rsp *rsp) { struct net_buf_simple ad; - struct bt_codec *codec; - struct codec_lookup_id_data lookup_data = { + struct bt_audio_codec_cfg *codec_cfg; + struct codec_cap_lookup_id_data lookup_data = { .id = id, .cid = cid, .vid = vid, @@ -1268,14 +1267,14 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin return -EINVAL; } - codec = &ep->codec; + codec_cfg = &ep->codec_cfg; LOG_DBG("ep %p dir %s codec id 0x%02x cid 0x%04x vid 0x%04x len %u", ep, bt_audio_dir_str(ep->dir), id, cid, vid, len); bt_pacs_cap_foreach(ep->dir, codec_lookup_id, &lookup_data); - if (lookup_data.codec == NULL) { + if (lookup_data.codec_cap == NULL) { LOG_DBG("Codec with id %u for dir %s is not supported by our capabilities", id, bt_audio_dir_str(ep->dir)); @@ -1284,11 +1283,11 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin return -ENOENT; } - codec->id = id; - codec->cid = cid; - codec->vid = vid; - codec->data_count = 0; - codec->path_id = lookup_data.codec->path_id; + codec_cfg->id = id; + codec_cfg->cid = cid; + codec_cfg->vid = vid; + codec_cfg->data_count = 0; + codec_cfg->path_id = lookup_data.codec_cap->path_id; if (len == 0) { *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); @@ -1298,12 +1297,12 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin net_buf_simple_init_with_data(&ad, cc, len); /* Parse LTV entries */ - bt_data_parse(&ad, ascs_codec_config_store, codec); + bt_data_parse(&ad, ascs_codec_config_store, codec_cfg); /* Check if all entries could be parsed */ if (ad.len) { LOG_ERR("Unable to parse Codec Config: len %u", ad.len); - (void)memset(codec, 0, sizeof(*codec)); + (void)memset(codec_cfg, 0, sizeof(*codec_cfg)); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_CODEC_DATA); return -EINVAL; @@ -1316,15 +1315,15 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) { struct bt_bap_stream *stream; - struct bt_codec codec; + struct bt_audio_codec_cfg codec_cfg; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); int err; LOG_DBG("ase %p latency 0x%02x phy 0x%02x codec 0x%02x " - "cid 0x%04x vid 0x%04x codec config len 0x%02x", ase, - cfg->latency, cfg->phy, cfg->codec.id, cfg->codec.cid, - cfg->codec.vid, cfg->cc_len); + "cid 0x%04x vid 0x%04x codec config len 0x%02x", + ase, cfg->latency, cfg->phy, cfg->codec.id, cfg->codec.cid, cfg->codec.vid, + cfg->cc_len); if (cfg->latency < BT_ASCS_CONFIG_LATENCY_LOW || cfg->latency > BT_ASCS_CONFIG_LATENCY_HIGH) { @@ -1361,14 +1360,13 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) /* Store current codec configuration to be able to restore it * in case of error. */ - (void)memcpy(&codec, &ase->ep.codec, sizeof(codec)); + (void)memcpy(&codec_cfg, &ase->ep.codec_cfg, sizeof(codec_cfg)); - err = ascs_ep_set_codec(&ase->ep, cfg->codec.id, - sys_le16_to_cpu(cfg->codec.cid), - sys_le16_to_cpu(cfg->codec.vid), - (uint8_t *)cfg->cc, cfg->cc_len, &rsp); + err = ascs_ep_set_codec(&ase->ep, cfg->codec.id, sys_le16_to_cpu(cfg->codec.cid), + sys_le16_to_cpu(cfg->codec.vid), (uint8_t *)cfg->cc, cfg->cc_len, + &rsp); if (err) { - (void)memcpy(&ase->ep.codec, &codec, sizeof(codec)); + (void)memcpy(&ase->ep.codec_cfg, &codec_cfg, sizeof(codec_cfg)); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err; } @@ -1376,10 +1374,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) if (ase->ep.stream != NULL) { if (unicast_server_cb != NULL && unicast_server_cb->reconfig != NULL) { - err = unicast_server_cb->reconfig(ase->ep.stream, - ase->ep.dir, - &ase->ep.codec, - &ase->ep.qos_pref, + err = unicast_server_cb->reconfig(ase->ep.stream, ase->ep.dir, + &ase->ep.codec_cfg, &ase->ep.qos_pref, &rsp); } else { err = -ENOTSUP; @@ -1396,7 +1392,7 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) LOG_ERR("Reconfig failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); - (void)memcpy(&ase->ep.codec, &codec, sizeof(codec)); + (void)memcpy(&ase->ep.codec_cfg, &codec_cfg, sizeof(codec_cfg)); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err; @@ -1408,7 +1404,7 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) if (unicast_server_cb != NULL && unicast_server_cb->config != NULL) { err = unicast_server_cb->config(ase->conn, &ase->ep, ase->ep.dir, - &ase->ep.codec, &stream, + &ase->ep.codec_cfg, &stream, &ase->ep.qos_pref, &rsp); } else { err = -ENOTSUP; @@ -1425,7 +1421,7 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) LOG_ERR("Config failed: err %d, stream %p, code %u, reason %u", err, stream, rsp.code, rsp.reason); - (void)memcpy(&ase->ep.codec, &codec, sizeof(codec)); + (void)memcpy(&ase->ep.codec_cfg, &codec_cfg, sizeof(codec_cfg)); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err ? err : -ENOMEM; @@ -1436,15 +1432,16 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) ascs_cp_rsp_success(ASE_ID(ase)); - bt_bap_stream_attach(ase->conn, stream, &ase->ep, &ase->ep.codec); + bt_bap_stream_attach(ase->conn, stream, &ase->ep, &ase->ep.codec_cfg); ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); return 0; } -int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_codec *codec, - const struct bt_codec_qos_pref *qos_pref) +int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_audio_codec_qos_pref *qos_pref) { int err; struct bt_ascs_ase *ase; @@ -1452,7 +1449,7 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struc struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - CHECKIF(conn == NULL || stream == NULL || codec == NULL || qos_pref == NULL) { + CHECKIF(conn == NULL || stream == NULL || codec_cfg == NULL || qos_pref == NULL) { LOG_DBG("NULL value(s) supplied)"); return -EINVAL; } @@ -1485,15 +1482,15 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struc return -EBADMSG; } - err = ascs_ep_set_codec(ep, codec->id, sys_le16_to_cpu(codec->cid), - sys_le16_to_cpu(codec->vid), NULL, 0, &rsp); + err = ascs_ep_set_codec(ep, codec_cfg->id, sys_le16_to_cpu(codec_cfg->cid), + sys_le16_to_cpu(codec_cfg->vid), NULL, 0, &rsp); if (err) { return err; } ep->qos_pref = *qos_pref; - bt_bap_stream_attach(conn, stream, ep, &ep->codec); + bt_bap_stream_attach(conn, stream, ep, &ep->codec_cfg); ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); @@ -1608,7 +1605,7 @@ 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_codec_qos *qos, +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) { @@ -1702,9 +1699,9 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos * the CIS ID in the QoS procedure). */ if (ep->dir == BT_AUDIO_DIR_SINK) { - bt_audio_codec_to_iso_path(&ep->iso->rx.path, stream->codec); + bt_audio_codec_cfg_to_iso_path(&ep->iso->rx.path, stream->codec_cfg); } else { - bt_audio_codec_to_iso_path(&ep->iso->tx.path, stream->codec); + bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); } ep->cig_id = cig_id; @@ -1720,7 +1717,7 @@ static void ase_qos(struct bt_ascs_ase *ase, const struct bt_ascs_qos *qos) { struct bt_bap_ep *ep = &ase->ep; struct bt_bap_stream *stream = ep->stream; - struct bt_codec_qos *cqos = &ep->qos; + struct bt_audio_codec_qos *cqos = &ep->qos; const uint8_t cig_id = qos->cig; const uint8_t cis_id = qos->cis; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, @@ -1837,10 +1834,10 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) static bool ascs_codec_store_metadata(struct bt_data *data, void *user_data) { - struct bt_codec *codec = user_data; - struct bt_codec_data *meta; + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_audio_codec_data *meta; - meta = &codec->meta[codec->meta_count]; + meta = &codec_cfg->meta[codec_cfg->meta_count]; meta->data.type = data->type; meta->data.data_len = data->data_len; @@ -1848,9 +1845,9 @@ static bool ascs_codec_store_metadata(struct bt_data *data, void *user_data) meta->data.data = meta->value; (void)memcpy(meta->value, data->data, data->data_len); - LOG_DBG("#%zu: data: %s", codec->meta_count, bt_hex(meta->value, data->data_len)); + LOG_DBG("#%zu: data: %s", codec_cfg->meta_count, bt_hex(meta->value, data->data_len)); - codec->meta_count++; + codec_cfg->meta_count++; return true; } @@ -1874,9 +1871,9 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) LOG_DBG("#%u type 0x%02x len %u", result->count, data_type, data_len); - if (result->count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) { + if (result->count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) { LOG_ERR("Not enough buffers for Codec Config Metadata: %zu > %zu", result->count, - CONFIG_BT_CODEC_MAX_DATA_LEN); + CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN); *result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); result->err = -ENOMEM; @@ -1884,9 +1881,9 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) return false; } - if (data_len > CONFIG_BT_CODEC_MAX_DATA_LEN) { + if (data_len > CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN) { LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len, - CONFIG_BT_CODEC_MAX_DATA_LEN); + CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN); *result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); result->err = -ENOMEM; @@ -1974,28 +1971,28 @@ static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_ } static int ascs_ep_set_metadata(struct bt_bap_ep *ep, uint8_t *data, uint8_t len, - struct bt_codec *codec, struct bt_bap_ascs_rsp *rsp) + struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_ascs_rsp *rsp) { struct net_buf_simple meta_ltv; int err; *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - if (ep == NULL && codec == NULL) { + if (ep == NULL && codec_cfg == NULL) { *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE); return -EINVAL; } - LOG_DBG("ep %p len %u codec %p", ep, len, codec); + LOG_DBG("ep %p len %u codec %p", ep, len, codec_cfg); if (len == 0) { - (void)memset(codec->meta, 0, sizeof(codec->meta)); + (void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta)); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); return 0; } - if (codec == NULL) { - codec = &ep->codec; + if (codec_cfg == NULL) { + codec_cfg = &ep->codec_cfg; } /* Extract metadata LTV for this specific endpoint */ @@ -2007,17 +2004,17 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, uint8_t *data, uint8_t len } /* reset cached metadata */ - ep->codec.meta_count = 0; + ep->codec_cfg.meta_count = 0; /* store data contents */ - bt_data_parse(&meta_ltv, ascs_codec_store_metadata, codec); + bt_data_parse(&meta_ltv, ascs_codec_store_metadata, codec_cfg); return 0; } static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) { - struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_METADATA_COUNT]; + struct bt_audio_codec_data metadata_backup[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT]; struct bt_bap_stream *stream; struct bt_bap_ep *ep; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, @@ -2048,8 +2045,8 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } /* Backup existing metadata */ - (void)memcpy(metadata_backup, ep->codec.meta, sizeof(metadata_backup)); - err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec, &rsp); + (void)memcpy(metadata_backup, ep->codec_cfg.meta, sizeof(metadata_backup)); + err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec_cfg, &rsp); if (err) { ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return; @@ -2057,8 +2054,8 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) stream = ep->stream; if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) { - err = unicast_server_cb->metadata(stream, ep->codec.meta, - ep->codec.meta_count, &rsp); + err = unicast_server_cb->metadata(stream, ep->codec_cfg.meta, + ep->codec_cfg.meta_count, &rsp); } else { err = -ENOTSUP; rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, @@ -2072,7 +2069,7 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } /* Restore backup */ - (void)memcpy(ep->codec.meta, metadata_backup, sizeof(metadata_backup)); + (void)memcpy(ep->codec_cfg.meta, metadata_backup, sizeof(metadata_backup)); LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); @@ -2106,7 +2103,7 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) return err; } - err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec, &rsp); + err = ascs_ep_set_metadata(ep, meta->data, meta->len, &ep->codec_cfg, &rsp); if (err) { ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err; @@ -2114,8 +2111,8 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) stream = ep->stream; if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) { - err = unicast_server_cb->enable(stream, ep->codec.meta, - ep->codec.meta_count, &rsp); + err = unicast_server_cb->enable(stream, ep->codec_cfg.meta, + ep->codec_cfg.meta_count, &rsp); } else { err = -ENOTSUP; rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index 4e1839de575c..ec8f763ba157 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -342,7 +342,8 @@ void bt_ascs_cleanup(void); void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state); -int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_codec *codec, - const struct bt_codec_qos_pref *qos_pref); +int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_audio_codec_qos_pref *qos_pref); void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data); diff --git a/subsys/bluetooth/audio/audio.c b/subsys/bluetooth/audio/audio.c index a0ce5cf19d24..bb9ec4ee5297 100644 --- a/subsys/bluetooth/audio/audio.c +++ b/subsys/bluetooth/audio/audio.c @@ -109,11 +109,8 @@ ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr * /* 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_codec_ltv(struct net_buf_simple *buf, - struct bt_codec_data *codec_data) +static int decode_codec_ltv(struct net_buf_simple *buf, struct bt_audio_codec_data *codec_data) { - void *value; - if (buf->len < sizeof(codec_data->data.data_len)) { LOG_DBG("Not enough data for LTV length field: %u", buf->len); @@ -135,6 +132,9 @@ static int decode_codec_ltv(struct net_buf_simple *buf, codec_data->data.type = net_buf_simple_pull_u8(buf); +#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + void *value; + codec_data->data.data = codec_data->value; if (buf->len < codec_data->data.data_len) { @@ -146,6 +146,15 @@ static int decode_codec_ltv(struct net_buf_simple *buf, value = net_buf_simple_pull_mem(buf, codec_data->data.data_len); (void)memcpy(codec_data->value, value, codec_data->data.data_len); +#else /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN == 0 */ + if (codec_data->data.data_len > 0) { + LOG_DBG("Cannot store data"); + + return -ENOMEM; + } + + codec_data->data.data = NULL; +#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */ return 0; } @@ -177,6 +186,7 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da } if (len > 0) { +#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 struct net_buf_simple ltv_buf; void *ltv_data; @@ -188,7 +198,7 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da while (ltv_buf.len != 0) { - struct bt_codec_data *bis_codec_data; + struct bt_audio_codec_data *bis_codec_data; int err; if (bis->data_count >= ARRAY_SIZE(bis->data)) { @@ -208,6 +218,11 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da bis->data_count++; } +#else /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN == 0 */ + LOG_DBG("Cannot store codec config data"); + + return -ENOMEM; +#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN */ } return 0; @@ -216,11 +231,11 @@ static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_da static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgroup *subgroup) { struct net_buf_simple ltv_buf; - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; void *ltv_data; uint8_t len; - codec = &subgroup->codec; + codec_cfg = &subgroup->codec_cfg; subgroup->bis_count = net_buf_simple_pull_u8(buf); if (subgroup->bis_count > ARRAY_SIZE(subgroup->bis_data)) { @@ -230,9 +245,9 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro return -ENOMEM; } - codec->id = net_buf_simple_pull_u8(buf); - codec->cid = net_buf_simple_pull_le16(buf); - codec->vid = net_buf_simple_pull_le16(buf); + 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); @@ -242,7 +257,7 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro return -EINVAL; } -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 /* Use an extra net_buf_simple to be able to decode until it * is empty (len = 0) */ @@ -255,25 +270,25 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro * broadcasted BASEs */ while (ltv_buf.len != 0) { - struct bt_codec_data *codec_data; + struct bt_audio_codec_data *codec_data; int err; - if (codec->data_count >= ARRAY_SIZE(codec->data)) { + if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) { LOG_WRN("BIS codec data overflow; discarding"); break; } - codec_data = &codec->data[codec->data_count]; + codec_data = &codec_cfg->data[codec_cfg->data_count]; err = decode_codec_ltv(<v_buf, codec_data); if (err != 0) { LOG_DBG("Failed to decode codec config data for entry %u: %d", - codec->data_count, err); + codec_cfg->data_count, err); return err; } - codec->data_count++; + codec_cfg->data_count++; } if (buf->len < sizeof(len)) { @@ -281,13 +296,13 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro return -ENOMEM; } -#else /* CONFIG_BT_CODEC_MAX_DATA_COUNT == 0 */ +#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT == 0 */ if (len > 0) { LOG_DBG("Cannot store codec config data"); return -ENOMEM; } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */ /* codec metadata length */ len = net_buf_simple_pull_u8(buf); @@ -297,7 +312,7 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro return -EMSGSIZE; } -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 /* Use an extra net_buf_simple to be able to decode until it * is empty (len = 0) */ @@ -310,33 +325,33 @@ static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgro * broadcasted BASEs */ while (ltv_buf.len != 0) { - struct bt_codec_data *metadata; + struct bt_audio_codec_data *metadata; int err; - if (codec->meta_count >= ARRAY_SIZE(codec->meta)) { + if (codec_cfg->meta_count >= ARRAY_SIZE(codec_cfg->meta)) { LOG_WRN("BIS codec metadata overflow; discarding"); break; } - metadata = &codec->meta[codec->meta_count]; + metadata = &codec_cfg->meta[codec_cfg->meta_count]; err = decode_codec_ltv(<v_buf, metadata); if (err != 0) { LOG_DBG("Failed to decode codec metadata for entry %u: %d", - codec->meta_count, err); + codec_cfg->meta_count, err); return err; } - codec->meta_count++; + codec_cfg->meta_count++; } -#else /* CONFIG_BT_CODEC_MAX_METADATA_COUNT == 0 */ +#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT == 0 */ if (len > 0) { LOG_DBG("Cannot store metadata"); return -ENOMEM; } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT */ for (size_t i = 0U; i < subgroup->bis_count; i++) { const int err = decode_bis_data(buf, &subgroup->bis_data[i]); @@ -419,7 +434,7 @@ int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base) } #endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ -ssize_t bt_audio_codec_data_to_buf(const struct bt_codec_data *codec_data, size_t count, +ssize_t bt_audio_codec_data_to_buf(const struct bt_audio_codec_data *codec_data, size_t count, uint8_t *buf, size_t buf_size) { size_t total_len = 0; diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index d4ecf7d86825..66a45fef555a 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -46,9 +46,9 @@ static struct bt_bap_ep broadcast_sink_eps[CONFIG_BT_BAP_BROADCAST_SNK_COUNT] static struct bt_bap_broadcast_sink broadcast_sinks[CONFIG_BT_BAP_BROADCAST_SNK_COUNT]; static struct bt_le_scan_cb broadcast_scan_cb; -struct codec_lookup_id_data { +struct codec_cap_lookup_id_data { uint8_t id; - struct bt_codec *codec; + struct bt_audio_codec_cap *codec_cap; }; static sys_slist_t sink_cbs = SYS_SLIST_STATIC_INIT(&sink_cbs); @@ -244,7 +244,7 @@ static void broadcast_sink_set_ep_state(struct bt_bap_ep *ep, uint8_t state) if (stream != NULL) { bt_bap_iso_unbind_ep(ep->iso, ep); stream->ep = NULL; - stream->codec = NULL; + stream->codec_cfg = NULL; ep->stream = NULL; } } @@ -589,11 +589,11 @@ static void update_recv_state_base_copy_meta(const struct bt_bap_base *base, size_t total_len; /* Copy metadata into subgroup_param, changing it from an array - * of bt_codec_data to a uint8_t buffer + * of bt_audio_codec_data to a uint8_t buffer */ total_len = 0U; - for (size_t j = 0; j < subgroup->codec.meta_count; j++) { - const struct bt_codec_data *meta = &subgroup->codec.meta[j]; + for (size_t j = 0; j < subgroup->codec_cfg.meta_count; j++) { + const struct bt_audio_codec_data *meta = &subgroup->codec_cfg.meta[j]; const struct bt_data *data = &meta->data; const uint8_t len = data->data_len; const uint8_t type = data->type; @@ -1126,7 +1126,8 @@ static struct bt_bap_ep *broadcast_sink_new_ep(uint8_t index) } static int bt_bap_broadcast_sink_setup_stream(struct bt_bap_broadcast_sink *sink, - struct bt_bap_stream *stream, struct bt_codec *codec) + struct bt_bap_stream *stream, + struct bt_audio_codec_cfg *codec_cfg) { struct bt_bap_iso *iso; struct bt_bap_ep *ep; @@ -1152,11 +1153,11 @@ 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_to_iso_path(iso->chan.qos->rx->path, codec); + bt_audio_codec_cfg_to_iso_path(iso->chan.qos->rx->path, codec_cfg); bt_bap_iso_unref(iso); - bt_bap_stream_attach(NULL, stream, ep, codec); + bt_bap_stream_attach(NULL, stream, ep, codec_cfg); stream->qos = &sink->codec_qos; return 0; @@ -1174,7 +1175,7 @@ static void broadcast_sink_cleanup_streams(struct bt_bap_broadcast_sink *sink) } stream->qos = NULL; - stream->codec = NULL; + stream->codec_cfg = NULL; stream->group = NULL; sys_slist_remove(&sink->streams, NULL, &stream->_node); @@ -1203,14 +1204,15 @@ static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink) (void)memset(sink, 0, sizeof(*sink)); /* also clears flags */ } -static struct bt_codec *codec_from_base_by_index(struct bt_bap_base *base, uint8_t index) +static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_base *base, + 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 j = 0U; j < subgroup->bis_count; j++) { if (subgroup->bis_data[j].index == index) { - return &subgroup->codec; + return &subgroup->codec_cfg; } } } @@ -1220,10 +1222,10 @@ static struct bt_codec *codec_from_base_by_index(struct bt_bap_base *base, uint8 static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) { - struct codec_lookup_id_data *data = user_data; + struct codec_cap_lookup_id_data *data = user_data; - if (cap->codec->id == data->id) { - data->codec = cap->codec; + if (cap->codec_cap->id == data->id) { + data->codec_cap = cap->codec_cap; return false; } @@ -1297,7 +1299,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_codec *codecs[BROADCAST_SNK_STREAM_CNT] = { NULL }; + struct bt_audio_codec_cfg *codec_cfgs[BROADCAST_SNK_STREAM_CNT] = {NULL}; uint8_t stream_count; int err; @@ -1348,29 +1350,30 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde stream_count = 0; for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { if ((indexes_bitfield & BIT(i)) != 0) { - struct bt_codec *codec = codec_from_base_by_index(&sink->base, i); - struct codec_lookup_id_data lookup_data = { }; + 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 == NULL) { + 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->id; + lookup_data.id = codec_cfg->id; bt_pacs_cap_foreach(BT_AUDIO_DIR_SINK, codec_lookup_id, &lookup_data); - if (lookup_data.codec == NULL) { + if (lookup_data.codec_cap == NULL) { LOG_DBG("Codec with id %u is not supported by our capabilities", - codec->id); + codec_cfg->id); return -ENOENT; } - codec->path_id = lookup_data.codec->path_id; + codec_cfg->path_id = lookup_data.codec_cap->path_id; - codecs[stream_count++] = codec; + codec_cfgs[stream_count++] = codec_cfg; if (stream_count > BROADCAST_SNK_STREAM_CNT) { LOG_DBG("Cannot sync to more than %d streams", @@ -1390,12 +1393,12 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde sink->stream_count = 0U; for (size_t i = 0; i < stream_count; i++) { struct bt_bap_stream *stream; - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; stream = streams[i]; - codec = codecs[i]; + codec_cfg = codec_cfgs[i]; - err = bt_bap_broadcast_sink_setup_stream(sink, stream, codec); + err = bt_bap_broadcast_sink_setup_stream(sink, stream, codec_cfg); if (err != 0) { LOG_DBG("Failed to setup streams[%zu]: %d", i, err); broadcast_sink_cleanup_streams(sink); diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index e24b61274a78..24e8d9f9cc3e 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -27,7 +27,7 @@ struct bt_bap_broadcast_subgroup { sys_slist_t streams; /* The codec of the subgroup */ - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; /* List node */ sys_snode_t _node; @@ -265,7 +265,8 @@ static struct bt_bap_broadcast_subgroup *broadcast_source_new_subgroup(uint8_t i } static int broadcast_source_setup_stream(uint8_t index, struct bt_bap_stream *stream, - struct bt_codec *codec, struct bt_codec_qos *qos, + struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos *qos, struct bt_bap_broadcast_source *source) { struct bt_bap_iso *iso; @@ -287,11 +288,11 @@ 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_to_iso_path(iso->chan.qos->tx->path, codec); + bt_audio_codec_cfg_to_iso_path(iso->chan.qos->tx->path, codec_cfg); bt_bap_iso_unref(iso); - bt_bap_stream_attach(NULL, stream, ep, codec); + bt_bap_stream_attach(NULL, stream, ep, codec_cfg); stream->qos = qos; ep->broadcast_source = source; @@ -303,7 +304,7 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, uint8_t *streams_encoded, struct net_buf_simple *buf) { struct bt_bap_stream *stream; - const struct bt_codec *codec; + const struct bt_audio_codec_cfg *codec_cfg; uint8_t stream_count; uint8_t bis_index; uint8_t *start; @@ -314,19 +315,18 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, stream_count++; } - codec = subgroup->codec; + codec_cfg = subgroup->codec_cfg; net_buf_simple_add_u8(buf, stream_count); - net_buf_simple_add_u8(buf, codec->id); - net_buf_simple_add_le16(buf, codec->cid); - net_buf_simple_add_le16(buf, codec->vid); - + net_buf_simple_add_u8(buf, codec_cfg->id); + net_buf_simple_add_le16(buf, codec_cfg->cid); + net_buf_simple_add_le16(buf, codec_cfg->vid); /* Insert codec configuration data in LTV format */ start = net_buf_simple_add(buf, sizeof(len)); - for (int i = 0; i < codec->data_count; i++) { - const struct bt_data *codec_data = &codec->data[i].data; + for (int i = 0; i < codec_cfg->data_count; i++) { + const struct bt_data *codec_data = &codec_cfg->data[i].data; if ((buf->size - buf->len) < (sizeof(codec_data->data_len) + sizeof(codec_data->type) + @@ -339,7 +339,6 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, net_buf_simple_add_u8(buf, codec_data->data_len + sizeof(codec_data->type)); net_buf_simple_add_u8(buf, codec_data->type); net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len); - } /* Calculate length of codec config data */ len = net_buf_simple_tail(buf) - start - sizeof(len); @@ -354,8 +353,8 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, /* Insert codec metadata in LTV format*/ start = net_buf_simple_add(buf, sizeof(len)); - for (int i = 0; i < codec->meta_count; i++) { - const struct bt_data *metadata = &codec->meta[i].data; + for (int i = 0; i < codec_cfg->meta_count; i++) { + const struct bt_data *metadata = &codec_cfg->meta[i].data; if ((buf->size - buf->len) < (sizeof(metadata->data_len) + sizeof(metadata->type) + @@ -395,7 +394,7 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, /* Insert codec configuration data in LTV format */ start = net_buf_simple_add(buf, sizeof(len)); -#if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT) +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) for (size_t j = 0U; j < stream_data[i].data_count; j++) { const struct bt_data *codec_data = &stream_data[i].data[j].data; @@ -412,7 +411,7 @@ static bool encode_base_subgroup(struct bt_bap_broadcast_subgroup *subgroup, net_buf_simple_add_u8(buf, codec_data->type); net_buf_simple_add_mem(buf, codec_data->data, codec_data->data_len); } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */ /* Calculate length of codec config data */ len = net_buf_simple_tail(buf) - start - sizeof(len); @@ -504,7 +503,7 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source) bt_bap_iso_unbind_ep(stream->ep->iso, stream->ep); stream->ep->stream = NULL; stream->ep = NULL; - stream->codec = NULL; + stream->codec_cfg = NULL; stream->qos = NULL; stream->group = NULL; @@ -519,7 +518,7 @@ static void broadcast_source_cleanup(struct bt_bap_broadcast_source *source) static bool valid_create_param(const struct bt_bap_broadcast_source_create_param *param) { - const struct bt_codec_qos *qos; + const struct bt_audio_codec_qos *qos; CHECKIF(param == NULL) { LOG_DBG("param is NULL"); @@ -580,8 +579,8 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param return false; } - CHECKIF(!bt_audio_valid_codec(subgroup_param->codec)) { - LOG_DBG("subgroup_params[%zu].codec is invalid", i); + CHECKIF(!bt_audio_valid_codec_cfg(subgroup_param->codec_cfg)) { + LOG_DBG("subgroup_params[%zu].codec_cfg is invalid", i); return false; } @@ -610,12 +609,13 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param return false; } -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 - CHECKIF(stream_param->data_count > CONFIG_BT_CODEC_MAX_DATA_COUNT) { +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 + CHECKIF(stream_param->data_count > + CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) { LOG_DBG("subgroup_params[%zu].stream_params[%zu]->data_count too " "large: %zu/%d", i, j, stream_param->data_count, - CONFIG_BT_CODEC_MAX_DATA_COUNT); + CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT); return false; } @@ -629,7 +629,7 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param } } } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ } return true; @@ -673,7 +673,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param * struct bt_bap_broadcast_source **out_source) { struct bt_bap_broadcast_source *source; - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; size_t stream_count; uint8_t index; int err; @@ -723,7 +723,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param * return -ENOMEM; } - subgroup->codec = subgroup_param->codec; + subgroup->codec_cfg = subgroup_param->codec_cfg; sys_slist_append(&source->subgroups, &subgroup->_node); /* Check that we are not above the maximum BIS count */ @@ -742,8 +742,7 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param * stream = stream_param->stream; err = broadcast_source_setup_stream(index, stream, - subgroup_param->codec, - qos, source); + subgroup_param->codec_cfg, qos, source); if (err != 0) { LOG_DBG("Failed to setup streams[%zu]: %d", i, err); broadcast_source_cleanup(source); @@ -794,8 +793,9 @@ int bt_bap_broadcast_source_create(struct bt_bap_broadcast_source_create_param * return 0; } -int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, struct bt_codec *codec, - struct bt_codec_qos *qos) +int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, + struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos *qos) { struct bt_bap_broadcast_subgroup *subgroup; enum bt_bap_ep_state broadcast_state; @@ -806,8 +806,8 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, str return -EINVAL; } - CHECKIF(!bt_audio_valid_codec(codec)) { - LOG_DBG("codec is invalid"); + CHECKIF(!bt_audio_valid_codec_cfg(codec_cfg)) { + LOG_DBG("codec_cfg is invalid"); return -EINVAL; } @@ -838,10 +838,10 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, str iso_qos = stream->ep->iso->chan.qos->tx; - bt_bap_stream_attach(NULL, stream, stream->ep, codec); + bt_bap_stream_attach(NULL, stream, stream->ep, codec_cfg); bt_audio_codec_qos_to_iso_qos(iso_qos, qos); - bt_audio_codec_to_iso_path(iso_qos->path, codec); + bt_audio_codec_cfg_to_iso_path(iso_qos->path, codec_cfg); stream->qos = qos; } } @@ -851,30 +851,30 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, str return 0; } -static void broadcast_source_store_metadata(struct bt_codec *codec, - const struct bt_codec_data meta[], +static void broadcast_source_store_metadata(struct bt_audio_codec_cfg *codec_cfg, + const struct bt_audio_codec_data meta[], size_t meta_count) { size_t old_meta_count; - old_meta_count = codec->meta_count; + old_meta_count = codec_cfg->meta_count; /* Update metadata */ - codec->meta_count = meta_count; - (void)memcpy(codec->meta, meta, meta_count * sizeof(*meta)); + codec_cfg->meta_count = meta_count; + (void)memcpy(codec_cfg->meta, meta, meta_count * sizeof(*meta)); if (old_meta_count > meta_count) { size_t meta_count_diff = old_meta_count - meta_count; /* If we previously had more metadata entries we reset the * data that was not overwritten by the new metadata */ - (void)memset(&codec->meta[meta_count], - 0, meta_count_diff * sizeof(*meta)); + (void)memset(&codec_cfg->meta[meta_count], 0, meta_count_diff * sizeof(*meta)); } } int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *source, - const struct bt_codec_data meta[], size_t meta_count) + const struct bt_audio_codec_data meta[], + size_t meta_count) { struct bt_bap_broadcast_subgroup *subgroup; enum bt_bap_ep_state broadcast_state; @@ -893,9 +893,9 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour return -EINVAL; } - CHECKIF(meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) { - LOG_DBG("Invalid meta_count: %zu (max %d)", - meta_count, CONFIG_BT_CODEC_MAX_METADATA_COUNT); + CHECKIF(meta_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) { + LOG_DBG("Invalid meta_count: %zu (max %d)", meta_count, + CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT); return -EINVAL; } @@ -919,7 +919,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour * for each subgroup individually */ SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { - broadcast_source_store_metadata(subgroup->codec, meta, meta_count); + broadcast_source_store_metadata(subgroup->codec_cfg, meta, meta_count); } return 0; diff --git a/subsys/bluetooth/audio/bap_endpoint.h b/subsys/bluetooth/audio/bap_endpoint.h index b01acfa04118..bef99f383b37 100644 --- a/subsys/bluetooth/audio/bap_endpoint.h +++ b/subsys/bluetooth/audio/bap_endpoint.h @@ -38,9 +38,9 @@ struct bt_bap_ep { uint8_t cis_id; struct bt_ascs_ase_status status; struct bt_bap_stream *stream; - struct bt_codec codec; - struct bt_codec_qos qos; - struct bt_codec_qos_pref qos_pref; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; + struct bt_audio_codec_qos_pref qos_pref; struct bt_bap_iso *iso; /* Used by the unicast server and client */ @@ -56,7 +56,7 @@ struct bt_bap_unicast_group { uint8_t index; bool allocated; /* QoS used to create the CIG */ - const struct bt_codec_qos *qos; + const struct bt_audio_codec_qos *qos; struct bt_iso_cig *cig; /* The ISO API for CIG creation requires an array of pointers to ISO channels */ struct bt_iso_chan *cis[UNICAST_GROUP_STREAM_CNT]; @@ -64,12 +64,12 @@ struct bt_bap_unicast_group { }; struct bt_audio_broadcast_stream_data { -#if defined(CONFIG_BT_CODEC_MAX_DATA_COUNT) +#if defined(CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) /** Codec Specific Data count */ size_t data_count; /** Codec Specific Data */ - struct bt_codec_data data[CONFIG_BT_CODEC_MAX_DATA_COUNT]; -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT */ + struct bt_audio_codec_data data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT */ }; struct bt_bap_broadcast_source { @@ -79,7 +79,7 @@ struct bt_bap_broadcast_source { uint32_t broadcast_id; /* 24 bit */ struct bt_iso_big *big; - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; /* The codec specific configured data for each stream in the subgroup */ struct bt_audio_broadcast_stream_data stream_data[BROADCAST_STREAM_CNT]; @@ -121,7 +121,7 @@ struct bt_bap_broadcast_sink { uint16_t biginfo_num_bis; uint32_t broadcast_id; /* 24 bit */ struct bt_bap_base base; - struct bt_codec_qos codec_qos; + 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]; diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index ec653065d43e..abc586b9c0fd 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -16,7 +16,7 @@ struct bt_bap_iso_dir { struct bt_bap_ep *ep; struct bt_iso_chan_path path; struct bt_iso_chan_io_qos qos; - uint8_t cc[CONFIG_BT_CODEC_MAX_DATA_COUNT * CONFIG_BT_CODEC_MAX_DATA_LEN]; + uint8_t cc[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN]; }; struct bt_bap_iso { diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index 5df9731d081e..ce50b22f6536 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -31,13 +31,13 @@ LOG_MODULE_REGISTER(bt_bap_stream, CONFIG_BT_BAP_STREAM_LOG_LEVEL); -static uint8_t pack_bt_codec_cc(const struct bt_codec *codec, uint8_t cc[]) +static uint8_t pack_bt_audio_codec_cc(const struct bt_audio_codec_cfg *codec_cfg, uint8_t cc[]) { uint8_t len; len = 0U; - for (size_t i = 0U; i < codec->data_count; i++) { - const struct bt_data *data = &codec->data[i].data; + for (size_t i = 0U; i < codec_cfg->data_count; i++) { + const struct bt_data *data = &codec_cfg->data[i].data; /* We assume that data_len and data has previously been verified * and that based on the Kconfigs we can assume that the length @@ -52,21 +52,21 @@ static uint8_t pack_bt_codec_cc(const struct bt_codec *codec, uint8_t cc[]) return len; } -void bt_audio_codec_to_iso_path(struct bt_iso_chan_path *path, - const struct bt_codec *codec) +void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, + const struct bt_audio_codec_cfg *codec_cfg) { - path->pid = codec->path_id; - path->format = codec->id; - path->cid = codec->cid; - path->vid = codec->vid; - path->delay = 0; /* TODO: Add to bt_codec? Use presentation delay? */ - path->cc_len = pack_bt_codec_cc(codec, path->cc); + 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 = pack_bt_audio_codec_cc(codec_cfg, path->cc); } #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, - const struct bt_codec_qos *codec_qos) + const struct bt_audio_codec_qos *codec_qos) { io->sdu = codec_qos->sdu; io->phy = codec_qos->phy; @@ -94,9 +94,9 @@ void bt_bap_stream_init(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_codec *codec) + struct bt_audio_codec_cfg *codec_cfg) { - LOG_DBG("conn %p stream %p ep %p codec %p", (void *)conn, stream, ep, codec); + LOG_DBG("conn %p stream %p ep %p codec_cfg %p", (void *)conn, stream, ep, codec_cfg); if (conn != NULL) { __ASSERT(stream->conn == NULL || stream->conn == conn, @@ -105,7 +105,7 @@ void bt_bap_stream_attach(struct bt_conn *conn, struct bt_bap_stream *stream, st stream->conn = bt_conn_ref(conn); } } - stream->codec = codec; + stream->codec_cfg = codec_cfg; stream->ep = ep; ep->stream = stream; } @@ -140,7 +140,7 @@ int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info) return 0; } -enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos) +enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_audio_codec_qos *qos) { if (qos->interval < BT_ISO_SDU_INTERVAL_MIN || qos->interval > BT_ISO_SDU_INTERVAL_MAX) { @@ -149,14 +149,14 @@ enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos) return BT_BAP_ASCS_REASON_INTERVAL; } - if (qos->framing > BT_CODEC_QOS_FRAMED) { + if (qos->framing > BT_AUDIO_CODEC_QOS_FRAMED) { LOG_DBG("Invalid Framing 0x%02x", qos->framing); return BT_BAP_ASCS_REASON_FRAMING; } - if (qos->phy != BT_CODEC_QOS_1M && - qos->phy != BT_CODEC_QOS_2M && - qos->phy != BT_CODEC_QOS_CODED) { + if (qos->phy != BT_AUDIO_CODEC_QOS_1M && + qos->phy != BT_AUDIO_CODEC_QOS_2M && + qos->phy != BT_AUDIO_CODEC_QOS_CODED) { LOG_DBG("Invalid PHY 0x%02x", qos->phy); return BT_BAP_ASCS_REASON_PHY; } @@ -182,7 +182,8 @@ enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos) return BT_BAP_ASCS_REASON_NONE; } -bool bt_audio_valid_codec_data(const struct bt_codec_data *data) +#if CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 +bool bt_audio_valid_codec_data(const struct bt_audio_codec_data *data) { if (data->data.data_len > ARRAY_SIZE(data->value)) { LOG_DBG("data invalid length: %zu/%zu", data->data.data_len, @@ -192,41 +193,42 @@ bool bt_audio_valid_codec_data(const struct bt_codec_data *data) return true; } +#endif /* CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */ -bool bt_audio_valid_codec(const struct bt_codec *codec) +bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) { - if (codec == NULL) { + if (codec_cfg == NULL) { LOG_DBG("codec is NULL"); return false; } -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 - if (codec->data_count > CONFIG_BT_CODEC_MAX_DATA_COUNT) { - LOG_DBG("codec->data_count (%zu) is invalid", codec->data_count); +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 + if (codec_cfg->data_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) { + LOG_DBG("codec_cfg->data_count (%zu) is invalid", codec_cfg->data_count); return false; } - for (size_t i = 0U; i < codec->data_count; i++) { - if (!bt_audio_valid_codec_data(&codec->data[i])) { - LOG_DBG("codec->data[%zu] invalid", i); + for (size_t i = 0U; i < codec_cfg->data_count; i++) { + if (!bt_audio_valid_codec_data(&codec_cfg->data[i])) { + LOG_DBG("codec_cfg->data[%zu] invalid", i); return false; } } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 - if (codec->meta_count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) { - LOG_DBG("codec->meta_count (%zu) is invalid", codec->meta_count); +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 + if (codec_cfg->meta_count > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT) { + LOG_DBG("codec_cfg->meta_count (%zu) is invalid", codec_cfg->meta_count); return false; } - for (size_t i = 0U; i < codec->meta_count; i++) { - if (!bt_audio_valid_codec_data(&codec->meta[i])) { - LOG_DBG("codec->meta[%zu] invalid", i); + for (size_t i = 0U; i < codec_cfg->meta_count; i++) { + if (!bt_audio_valid_codec_data(&codec_cfg->meta[i])) { + LOG_DBG("codec_cfg->meta[%zu] invalid", i); return false; } } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */ return true; } @@ -304,9 +306,9 @@ static bool bt_bap_stream_is_broadcast(const struct bt_bap_stream *stream) } enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream, - const struct bt_codec_qos *qos) + const struct bt_audio_codec_qos *qos) { - const struct bt_codec_qos_pref *qos_pref = &stream->ep->qos_pref; + const struct bt_audio_codec_qos_pref *qos_pref = &stream->ep->qos_pref; if (qos_pref->latency < qos->latency) { /* Latency is a preferred value. Print debug info but do not fail. */ @@ -332,7 +334,7 @@ void bt_bap_stream_detach(struct bt_bap_stream *stream) bt_conn_unref(stream->conn); stream->conn = NULL; } - stream->codec = NULL; + stream->codec_cfg = NULL; stream->ep->stream = NULL; stream->ep = NULL; @@ -387,17 +389,17 @@ static uint8_t conn_get_role(const struct bt_conn *conn) #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_bap_ep *ep, - struct bt_codec *codec) + struct bt_audio_codec_cfg *codec_cfg) { uint8_t role; int err; - LOG_DBG("conn %p stream %p, ep %p codec %p codec id 0x%02x " + LOG_DBG("conn %p stream %p, ep %p codec_cfg %p codec id 0x%02x " "codec cid 0x%04x codec vid 0x%04x", (void *)conn, stream, ep, - codec, codec ? codec->id : 0, codec ? codec->cid : 0, - codec ? codec->vid : 0); + codec_cfg, codec_cfg ? codec_cfg->id : 0, codec_cfg ? codec_cfg->cid : 0, + codec_cfg ? codec_cfg->vid : 0); - CHECKIF(conn == NULL || stream == NULL || codec == NULL) { + CHECKIF(conn == NULL || stream == NULL || codec_cfg == NULL) { LOG_DBG("NULL value(s) supplied)"); return -EINVAL; } @@ -426,9 +428,9 @@ int bt_bap_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, str return -EBADMSG; } - bt_bap_stream_attach(conn, stream, ep, codec); + bt_bap_stream_attach(conn, stream, ep, codec_cfg); - err = bt_bap_unicast_client_config(stream, codec); + err = bt_bap_unicast_client_config(stream, codec_cfg); if (err != 0) { LOG_DBG("Failed to configure stream: %d", err); return err; @@ -475,7 +477,7 @@ int bt_bap_stream_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group) } int bt_bap_stream_enable(struct bt_bap_stream *stream, - struct bt_codec_data *meta, + struct bt_audio_codec_data *meta, size_t meta_count) { uint8_t role; @@ -548,21 +550,21 @@ int bt_bap_stream_stop(struct bt_bap_stream *stream) #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ int bt_bap_stream_reconfig(struct bt_bap_stream *stream, - struct bt_codec *codec) + struct bt_audio_codec_cfg *codec_cfg) { uint8_t state; uint8_t role; int err; - LOG_DBG("stream %p codec %p", stream, codec); + LOG_DBG("stream %p codec_cfg %p", stream, codec_cfg); CHECKIF(stream == NULL || stream->ep == NULL || stream->conn == NULL) { LOG_DBG("Invalid stream"); return -EINVAL; } - CHECKIF(codec == NULL) { - LOG_DBG("codec is NULL"); + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); return -EINVAL; } @@ -582,9 +584,9 @@ int bt_bap_stream_reconfig(struct bt_bap_stream *stream, role = conn_get_role(stream->conn); if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && role == BT_HCI_ROLE_CENTRAL) { - err = bt_bap_unicast_client_config(stream, codec); + err = bt_bap_unicast_client_config(stream, codec_cfg); } else if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && role == BT_HCI_ROLE_PERIPHERAL) { - err = bt_bap_unicast_server_reconfig(stream, codec); + err = bt_bap_unicast_server_reconfig(stream, codec_cfg); } else { err = -EOPNOTSUPP; } @@ -592,7 +594,7 @@ int bt_bap_stream_reconfig(struct bt_bap_stream *stream, if (err != 0) { LOG_DBG("reconfiguring stream failed: %d", err); } else { - stream->codec = codec; + stream->codec_cfg = codec_cfg; } return 0; @@ -639,7 +641,7 @@ int bt_bap_stream_start(struct bt_bap_stream *stream) } int bt_bap_stream_metadata(struct bt_bap_stream *stream, - struct bt_codec_data *meta, + struct bt_audio_codec_data *meta, size_t meta_count) { uint8_t state; diff --git a/subsys/bluetooth/audio/bap_stream.h b/subsys/bluetooth/audio/bap_stream.h index e7777f8d5a0b..62bb51d0b269 100644 --- a/subsys/bluetooth/audio/bap_stream.h +++ b/subsys/bluetooth/audio/bap_stream.h @@ -15,20 +15,21 @@ int bt_bap_stream_disconnect(struct bt_bap_stream *stream); 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_codec *codec); + struct bt_audio_codec_cfg *codec_cfg); -void bt_audio_codec_to_iso_path(struct bt_iso_chan_path *path, - const struct bt_codec *codec); +void bt_audio_codec_cfg_to_iso_path(struct bt_iso_chan_path *path, + const 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_codec_qos *codec_qos); + const struct bt_audio_codec_qos *codec_qos); void bt_bap_stream_detach(struct bt_bap_stream *stream); -enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos); -bool bt_audio_valid_codec_data(const struct bt_codec_data *data); -bool bt_audio_valid_codec(const struct bt_codec *codec); +enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_audio_codec_qos *qos); +bool bt_audio_valid_codec_data(const struct bt_audio_codec_data *data); +bool bt_audio_valid_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg); bool bt_bap_stream_can_disconnect(const struct bt_bap_stream *stream); + enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream, - const struct bt_codec_qos *qos); + const struct bt_audio_codec_qos *qos); struct bt_iso_chan *bt_bap_stream_iso_chan_get(struct bt_bap_stream *stream); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 8389aa0581f7..5a75eeaff963 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -115,10 +115,11 @@ static const struct bt_bap_unicast_client_cb *unicast_client_cbs; /* TODO: Move the functions to avoid these prototypes */ static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint8_t len, - struct bt_codec *codec); + struct bt_audio_codec_cfg *codec_cfg); -static int unicast_client_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uint16_t vid, - void *data, uint8_t len, struct bt_codec *codec); +static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, + uint16_t vid, void *data, uint8_t len, + struct bt_audio_codec_cfg *codec_cfg); static int unicast_client_ep_start(struct bt_bap_ep *ep, struct net_buf_simple *buf); @@ -631,7 +632,7 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_ struct bt_bap_unicast_client_ep *client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep); struct bt_ascs_ase_status_config *cfg; - struct bt_codec_qos_pref *pref; + struct bt_audio_codec_qos_pref *pref; struct bt_bap_stream *stream; void *cc; @@ -654,11 +655,12 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_ cfg = net_buf_simple_pull_mem(buf, sizeof(*cfg)); - if (stream->codec == NULL) { + if (stream->codec_cfg == NULL) { LOG_ERR("Stream %p does not have a codec configured", stream); return; - } else if (stream->codec->id != cfg->codec.id) { - LOG_ERR("Codec configuration mismatched: %u, %u", stream->codec->id, cfg->codec.id); + } else if (stream->codec_cfg->id != cfg->codec.id) { + LOG_ERR("Codec configuration mismatched: %u, %u", stream->codec_cfg->id, + cfg->codec.id); /* TODO: Release the stream? */ return; } @@ -687,10 +689,10 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_ "latency %u pd_min %u pd_max %u pref_pd_min %u pref_pd_max %u codec 0x%02x ", bt_audio_dir_str(ep->dir), pref->unframed_supported, pref->phy, pref->rtn, pref->latency, pref->pd_min, pref->pd_max, pref->pref_pd_min, pref->pref_pd_max, - stream->codec->id); + stream->codec_cfg->id); - unicast_client_ep_set_codec(ep, cfg->codec.id, sys_le16_to_cpu(cfg->codec.cid), - sys_le16_to_cpu(cfg->codec.vid), cc, cfg->cc_len, NULL); + unicast_client_ep_set_codec_cfg(ep, cfg->codec.id, sys_le16_to_cpu(cfg->codec.cid), + sys_le16_to_cpu(cfg->codec.vid), cc, cfg->cc_len, NULL); /* Notify upper layer */ if (stream->ops != NULL && stream->ops->configured != NULL) { @@ -747,7 +749,7 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim LOG_DBG("dir %s cig 0x%02x cis 0x%02x codec 0x%02x interval %u " "framing 0x%02x phy 0x%02x rtn %u latency %u pd %u", - bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id, stream->codec->id, + bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id, stream->codec_cfg->id, stream->qos->interval, stream->qos->framing, stream->qos->phy, stream->qos->rtn, stream->qos->latency, stream->qos->pd); @@ -767,12 +769,12 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim /* If the endpoint is a source, then we need to * configure our RX parameters */ - bt_audio_codec_to_iso_path(&ep->iso->rx.path, stream->codec); + 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_to_iso_path(&ep->iso->tx.path, stream->codec); + bt_audio_codec_cfg_to_iso_path(&ep->iso->tx.path, stream->codec_cfg); } } @@ -1111,7 +1113,7 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si } static void unicast_client_codec_data_add(struct net_buf_simple *buf, const char *prefix, - size_t num, const struct bt_codec_data *data) + size_t num, const struct bt_audio_codec_data *data) { for (size_t i = 0; i < num; i++) { const struct bt_data *d = &data[i].data; @@ -1127,17 +1129,9 @@ static void unicast_client_codec_data_add(struct net_buf_simple *buf, const char } } -static bool unicast_client_codec_config_store(struct bt_data *data, void *user_data) +static bool unicast_client_codec_data_store(struct bt_data *data, void *user_data) { - struct bt_codec *codec = user_data; - struct bt_codec_data *cdata; - - if (codec->data_count >= ARRAY_SIZE(codec->data)) { - LOG_ERR("No slot available for Codec Config"); - return false; - } - - cdata = &codec->data[codec->data_count]; + struct bt_audio_codec_data *cdata = user_data; if (data->data_len > sizeof(cdata->value)) { LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len, @@ -1145,8 +1139,6 @@ static bool unicast_client_codec_config_store(struct bt_data *data, void *user_d return false; } - LOG_DBG("#%u type 0x%02x len %u", codec->data_count, data->type, data->data_len); - cdata->data.type = data->type; cdata->data.data_len = data->data_len; @@ -1156,33 +1148,78 @@ static bool unicast_client_codec_config_store(struct bt_data *data, void *user_d LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data"); - codec->data_count++; - return true; } -static int unicast_client_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uint16_t vid, - void *data, uint8_t len, struct bt_codec *codec) +static bool unicast_client_codec_config_cfg_store(struct bt_data *data, void *user_data) +{ + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_audio_codec_data *cdata; + + if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) { + LOG_ERR("No slot available for Codec Config"); + return false; + } + + cdata = &codec_cfg->data[codec_cfg->data_count]; + + LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len); + + if (unicast_client_codec_data_store(data, cdata)) { + codec_cfg->data_count++; + + return true; + } + + return false; +} + +static bool unicast_client_codec_config_cap_store(struct bt_data *data, void *user_data) +{ + struct bt_audio_codec_cap *codec_cap = user_data; + struct bt_audio_codec_data *cdata; + + if (codec_cap->data_count >= ARRAY_SIZE(codec_cap->data)) { + LOG_ERR("No slot available for Codec Config"); + return false; + } + + cdata = &codec_cap->data[codec_cap->data_count]; + + LOG_DBG("#%u type 0x%02x len %u", codec_cap->data_count, data->type, data->data_len); + + if (unicast_client_codec_data_store(data, cdata)) { + codec_cap->data_count++; + + return true; + } + + return false; +} + +static int unicast_client_ep_set_codec_cfg(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, + uint16_t vid, void *data, uint8_t len, + struct bt_audio_codec_cfg *codec_cfg) { struct net_buf_simple ad; - if (!ep && !codec) { + if (!ep && !codec_cfg) { return -EINVAL; } LOG_DBG("ep %p codec id 0x%02x cid 0x%04x vid 0x%04x len %u", ep, id, cid, vid, len); - if (!codec) { - codec = &ep->codec; + if (!codec_cfg) { + codec_cfg = &ep->codec_cfg; } - codec->id = id; - codec->cid = cid; - codec->vid = vid; + codec_cfg->id = id; + codec_cfg->cid = cid; + codec_cfg->vid = vid; /* Reset current metadata */ - codec->data_count = 0; - (void)memset(codec->data, 0, sizeof(codec->data)); + codec_cfg->data_count = 0; + (void)memset(codec_cfg->data, 0, sizeof(codec_cfg->data)); if (!len) { return 0; @@ -1191,7 +1228,7 @@ static int unicast_client_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_ net_buf_simple_init_with_data(&ad, data, len); /* Parse LTV entries */ - bt_data_parse(&ad, unicast_client_codec_config_store, codec); + bt_data_parse(&ad, unicast_client_codec_config_cfg_store, codec_cfg); /* Check if all entries could be parsed */ if (ad.len) { @@ -1202,63 +1239,162 @@ static int unicast_client_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_ return 0; fail: - (void)memset(codec, 0, sizeof(*codec)); + (void)memset(codec_cfg, 0, sizeof(*codec_cfg)); return -EINVAL; } -static bool unicast_client_codec_metadata_store(struct bt_data *data, void *user_data) +static int unicast_client_set_codec_cap(uint8_t id, uint16_t cid, uint16_t vid, void *data, + uint8_t len, struct bt_audio_codec_cap *codec_cap) { - struct bt_codec *codec = user_data; - struct bt_codec_data *meta; + struct net_buf_simple ad; - if (codec->meta_count >= ARRAY_SIZE(codec->meta)) { - LOG_ERR("No slot available for Codec Config Metadata"); - return false; + if (!codec_cap) { + return -EINVAL; } - meta = &codec->meta[codec->meta_count]; + LOG_DBG("codec id 0x%02x cid 0x%04x vid 0x%04x len %u", id, cid, vid, len); - if (data->data_len > sizeof(meta->value)) { - LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len, - sizeof(meta->value)); - return false; + codec_cap->id = id; + codec_cap->cid = cid; + codec_cap->vid = vid; + + /* Reset current metadata */ + codec_cap->data_count = 0; + (void)memset(codec_cap->data, 0, sizeof(codec_cap->data)); + + if (!len) { + return 0; } - LOG_DBG("#%u type 0x%02x len %u", codec->meta_count, data->type, data->data_len); + net_buf_simple_init_with_data(&ad, data, len); + + /* Parse LTV entries */ + bt_data_parse(&ad, unicast_client_codec_config_cap_store, codec_cap); - meta->data.type = data->type; - meta->data.data_len = data->data_len; + /* Check if all entries could be parsed */ + if (ad.len) { + LOG_ERR("Unable to parse Codec Config: len %u", ad.len); + goto fail; + } - /* Deep copy data contents */ - meta->data.data = meta->value; - (void)memcpy(meta->value, data->data, data->data_len); + return 0; - LOG_HEXDUMP_DBG(meta->value, data->data_len, "data"); +fail: + (void)memset(codec_cap, 0, sizeof(*codec_cap)); + return -EINVAL; +} - codec->meta_count++; +static bool unicast_client_codec_cfg_metadata_store(struct bt_data *data, void *user_data) +{ + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_audio_codec_data *meta; - return true; + if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) { + LOG_ERR("No slot available for Codec Config"); + return false; + } + + meta = &codec_cfg->data[codec_cfg->meta_count]; + + LOG_DBG("#%u type 0x%02x len %u", codec_cfg->meta_count, data->type, data->data_len); + + if (unicast_client_codec_data_store(data, meta)) { + codec_cfg->meta_count++; + + return true; + } + + return false; } static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint8_t len, - struct bt_codec *codec) + struct bt_audio_codec_cfg *codec_cfg) { struct net_buf_simple meta; int err; - if (!ep && !codec) { + if (!ep && !codec_cfg) { return -EINVAL; } - LOG_DBG("ep %p len %u codec %p", ep, len, codec); + LOG_DBG("ep %p len %u codec_cfg %p", ep, len, codec_cfg); + + if (!codec_cfg) { + codec_cfg = &ep->codec_cfg; + } + + /* Reset current metadata */ + codec_cfg->meta_count = 0; + (void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta)); + + if (!len) { + return 0; + } + + net_buf_simple_init_with_data(&meta, data, len); + + /* Parse LTV entries */ + bt_data_parse(&meta, unicast_client_codec_cfg_metadata_store, codec_cfg); + + /* Check if all entries could be parsed */ + if (meta.len) { + LOG_ERR("Unable to parse Metadata: len %u", meta.len); + err = -EINVAL; + + if (meta.len > 2) { + /* Value of the Metadata Type field in error */ + err = meta.data[2]; + } + + goto fail; + } + + return 0; + +fail: + codec_cfg->meta_count = 0; + (void)memset(codec_cfg->meta, 0, sizeof(codec_cfg->meta)); + return err; +} + +static bool unicast_client_codec_cap_metadata_store(struct bt_data *data, void *user_data) +{ + struct bt_audio_codec_cap *codec_cap = user_data; + struct bt_audio_codec_data *meta; + + if (codec_cap->meta_count >= ARRAY_SIZE(codec_cap->meta)) { + LOG_ERR("No slot available for Codec Config"); + return false; + } + + meta = &codec_cap->meta[codec_cap->meta_count]; + + LOG_DBG("#%u type 0x%02x len %u", codec_cap->meta_count, data->type, data->data_len); + + if (unicast_client_codec_data_store(data, meta)) { + codec_cap->meta_count++; - if (!codec) { - codec = &ep->codec; + return true; } + return false; +} + +static int unicast_client_set_codec_cap_metadata(void *data, uint8_t len, + struct bt_audio_codec_cap *codec_cap) +{ + struct net_buf_simple meta; + int err; + + if (!codec_cap) { + return -EINVAL; + } + + LOG_DBG("len %u codec_cap %p", len, codec_cap); + /* Reset current metadata */ - codec->meta_count = 0; - (void)memset(codec->meta, 0, sizeof(codec->meta)); + codec_cap->meta_count = 0; + (void)memset(codec_cap->meta, 0, sizeof(codec_cap->meta)); if (!len) { return 0; @@ -1267,7 +1403,7 @@ static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint net_buf_simple_init_with_data(&meta, data, len); /* Parse LTV entries */ - bt_data_parse(&meta, unicast_client_codec_metadata_store, codec); + bt_data_parse(&meta, unicast_client_codec_cap_metadata_store, codec_cap); /* Check if all entries could be parsed */ if (meta.len) { @@ -1285,8 +1421,8 @@ static int unicast_client_ep_set_metadata(struct bt_bap_ep *ep, void *data, uint return 0; fail: - codec->meta_count = 0; - (void)memset(codec->meta, 0, sizeof(codec->meta)); + codec_cap->meta_count = 0; + (void)memset(codec_cap->meta, 0, sizeof(codec_cap->meta)); return err; } @@ -1610,7 +1746,7 @@ static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *e return bt_gatt_subscribe(conn, &client_ep->subscribe); } -static void pac_record_cb(struct bt_conn *conn, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, const struct bt_audio_codec_cap *codec_cap) { if (unicast_client_cbs != NULL && unicast_client_cbs->pac_record != NULL) { struct unicast_client *client = &uni_cli_insts[bt_conn_index(conn)]; @@ -1620,7 +1756,7 @@ static void pac_record_cb(struct bt_conn *conn, const struct bt_codec *codec) * index and total count of records in the callback, so that it easier for the * upper layers to determine when a new set of PAC records is being reported. */ - unicast_client_cbs->pac_record(conn, dir, codec); + unicast_client_cbs->pac_record(conn, dir, codec_cap); } } @@ -1725,12 +1861,12 @@ struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(struct bt_conn *conn, } static int unicast_client_ep_config(struct bt_bap_ep *ep, struct net_buf_simple *buf, - const struct bt_codec *codec) + const struct bt_audio_codec_cfg *codec_cfg) { struct bt_ascs_config *req; uint8_t cc_len; - LOG_DBG("ep %p buf %p codec %p", ep, buf, codec); + LOG_DBG("ep %p buf %p codec %p", ep, buf, codec_cfg); if (!ep) { return -EINVAL; @@ -1750,25 +1886,25 @@ static int unicast_client_ep_config(struct bt_bap_ep *ep, struct net_buf_simple } LOG_DBG("id 0x%02x dir %s codec 0x%02x", ep->status.id, bt_audio_dir_str(ep->dir), - codec->id); + codec_cfg->id); req = net_buf_simple_add(buf, sizeof(*req)); req->ase = ep->status.id; req->latency = 0x02; /* TODO: Select target latency based on additional input? */ req->phy = 0x02; /* TODO: Select target PHY based on additional input? */ - req->codec.id = codec->id; - req->codec.cid = codec->cid; - req->codec.vid = codec->vid; + req->codec.id = codec_cfg->id; + req->codec.cid = codec_cfg->cid; + req->codec.vid = codec_cfg->vid; cc_len = buf->len; - unicast_client_codec_data_add(buf, "data", codec->data_count, codec->data); + unicast_client_codec_data_add(buf, "data", codec_cfg->data_count, codec_cfg->data); req->cc_len = buf->len - cc_len; return 0; } int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *buf, - struct bt_codec_qos *qos) + struct bt_audio_codec_qos *qos) { struct bt_ascs_qos *req; struct bt_conn_iso *conn_iso; @@ -1814,7 +1950,7 @@ int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *bu } static int unicast_client_ep_enable(struct bt_bap_ep *ep, struct net_buf_simple *buf, - struct bt_codec_data *meta, size_t meta_count) + struct bt_audio_codec_data *meta, size_t meta_count) { struct bt_ascs_metadata *req; @@ -1842,7 +1978,7 @@ static int unicast_client_ep_enable(struct bt_bap_ep *ep, struct net_buf_simple } static int unicast_client_ep_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf, - struct bt_codec_data *meta, size_t meta_count) + struct bt_audio_codec_data *meta, size_t meta_count) { struct bt_ascs_metadata *req; @@ -2096,7 +2232,7 @@ static void unicast_client_ep_reset(struct bt_conn *conn) } static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, - const struct bt_codec_qos *qos) + const struct bt_audio_codec_qos *qos) { cig_param->framing = qos->framing; cig_param->packing = BT_ISO_PACKING_SEQUENTIAL; /* TODO: Add to QoS struct */ @@ -2109,7 +2245,8 @@ static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, * between CIS'es. The implementation shall take the CIG parameters from * unicast_group instead. */ -static int bt_audio_cig_create(struct bt_bap_unicast_group *group, const struct bt_codec_qos *qos) +static int bt_audio_cig_create(struct bt_bap_unicast_group *group, + const struct bt_audio_codec_qos *qos) { struct bt_iso_cig_param param; uint8_t cis_count; @@ -2143,7 +2280,7 @@ static int bt_audio_cig_create(struct bt_bap_unicast_group *group, const struct } static int bt_audio_cig_reconfigure(struct bt_bap_unicast_group *group, - const struct bt_codec_qos *qos) + const struct bt_audio_codec_qos *qos) { struct bt_iso_cig_param param; uint8_t cis_count; @@ -2282,7 +2419,7 @@ static void unicast_group_del_iso(struct bt_bap_unicast_group *group, struct bt_ } static void unicast_client_codec_qos_to_iso_qos(struct bt_bap_iso *iso, - const struct bt_codec_qos *qos, + const struct bt_audio_codec_qos *qos, enum bt_audio_dir dir) { struct bt_iso_chan_io_qos *io_qos; @@ -2325,7 +2462,7 @@ static void unicast_group_add_stream(struct bt_bap_unicast_group *group, struct bt_bap_iso *iso, enum bt_audio_dir dir) { struct bt_bap_stream *stream = param->stream; - struct bt_codec_qos *qos = param->qos; + struct bt_audio_codec_qos *qos = param->qos; LOG_DBG("group %p stream %p qos %p iso %p dir %u", group, stream, qos, iso, dir); @@ -2521,7 +2658,7 @@ static int stream_pair_param_check(const struct bt_bap_unicast_group_stream_pair return 0; } -static int group_qos_common_set(const struct bt_codec_qos **group_qos, +static int group_qos_common_set(const struct bt_audio_codec_qos **group_qos, const struct bt_bap_unicast_group_stream_pair_param *param) { if (param->rx_param != NULL && *group_qos == NULL) { @@ -2539,7 +2676,7 @@ int bt_bap_unicast_group_create(struct bt_bap_unicast_group_param *param, struct bt_bap_unicast_group **out_unicast_group) { struct bt_bap_unicast_group *unicast_group; - const struct bt_codec_qos *group_qos = NULL; + const struct bt_audio_codec_qos *group_qos = NULL; int err; CHECKIF(out_unicast_group == NULL) @@ -2610,7 +2747,7 @@ int bt_bap_unicast_group_add_streams(struct bt_bap_unicast_group *unicast_group, struct bt_bap_unicast_group_stream_pair_param params[], size_t num_param) { - const struct bt_codec_qos *group_qos = unicast_group->qos; + const struct bt_audio_codec_qos *group_qos = unicast_group->qos; struct bt_bap_stream *tmp_stream; size_t total_stream_cnt; struct bt_iso_cig *cig; @@ -2729,7 +2866,8 @@ int bt_bap_unicast_group_delete(struct bt_bap_unicast_group *unicast_group) return 0; } -int bt_bap_unicast_client_config(struct bt_bap_stream *stream, const struct bt_codec *codec) +int bt_bap_unicast_client_config(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg) { struct bt_bap_ep *ep = stream->ep; struct bt_ascs_config_op *op; @@ -2753,7 +2891,7 @@ int bt_bap_unicast_client_config(struct bt_bap_stream *stream, const struct bt_c op = net_buf_simple_add(buf, sizeof(*op)); op->num_ases = 0x01; - err = unicast_client_ep_config(ep, buf, codec); + err = unicast_client_ep_config(ep, buf, codec_cfg); if (err != 0) { return err; } @@ -2893,7 +3031,7 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group return 0; } -int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count) { struct bt_bap_ep *ep = stream->ep; @@ -2926,7 +3064,7 @@ int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_codec_d return bt_bap_unicast_client_ep_send(stream->conn, ep, buf); } -int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count) { struct bt_bap_ep *ep = stream->ep; @@ -3840,10 +3978,10 @@ static uint8_t unicast_client_read_func(struct bt_conn *conn, uint8_t err, } for (i = 0U; i < rsp->num_pac; i++) { + struct bt_audio_codec_cap codec_cap; struct bt_pac_codec *pac_codec; struct bt_pac_ltv_data *meta, *cc; void *cc_ltv, *meta_ltv; - struct bt_codec codec; LOG_DBG("pac #%u/%u", i + 1, rsp->num_pac); @@ -3885,22 +4023,22 @@ static uint8_t unicast_client_read_func(struct bt_conn *conn, uint8_t err, meta_ltv = net_buf_simple_pull_mem(buf, meta->len); - if (unicast_client_ep_set_codec( - NULL, pac_codec->id, sys_le16_to_cpu(pac_codec->cid), - sys_le16_to_cpu(pac_codec->vid), cc_ltv, cc->len, &codec)) { + if (unicast_client_set_codec_cap(pac_codec->id, sys_le16_to_cpu(pac_codec->cid), + sys_le16_to_cpu(pac_codec->vid), cc_ltv, cc->len, + &codec_cap)) { LOG_ERR("Unable to parse Codec"); break; } - if (unicast_client_ep_set_metadata(NULL, meta_ltv, meta->len, &codec)) { + if (unicast_client_set_codec_cap_metadata(meta_ltv, meta->len, &codec_cap)) { LOG_ERR("Unable to parse Codec Metadata"); break; } - LOG_DBG("codec 0x%02x config count %u meta count %u ", codec.id, codec.data_count, - codec.meta_count); + LOG_DBG("codec 0x%02x config count %u meta count %u ", codec_cap.id, + codec_cap.data_count, codec_cap.meta_count); - pac_record_cb(conn, &codec); + pac_record_cb(conn, &codec_cap); } reset_att_buf(client); diff --git a/subsys/bluetooth/audio/bap_unicast_client_internal.h b/subsys/bluetooth/audio/bap_unicast_client_internal.h index cb8f350ce234..2a5b25dea6eb 100644 --- a/subsys/bluetooth/audio/bap_unicast_client_internal.h +++ b/subsys/bluetooth/audio/bap_unicast_client_internal.h @@ -6,14 +6,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -int bt_bap_unicast_client_config(struct bt_bap_stream *stream, const struct bt_codec *codec); +int bt_bap_unicast_client_config(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group *group); -int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count); -int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count); int bt_bap_unicast_client_disable(struct bt_bap_stream *stream); @@ -27,7 +28,7 @@ int bt_bap_unicast_client_release(struct bt_bap_stream *stream); struct net_buf_simple *bt_bap_unicast_client_ep_create_pdu(struct bt_conn *conn, uint8_t op); int bt_bap_unicast_client_ep_qos(struct bt_bap_ep *ep, struct net_buf_simple *buf, - struct bt_codec_qos *qos); + struct bt_audio_codec_qos *qos); int bt_bap_unicast_client_ep_send(struct bt_conn *conn, struct bt_bap_ep *ep, struct net_buf_simple *buf); diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index 9c66a6fdc3ff..d204a6b3babf 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -63,7 +63,8 @@ int bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb *c return 0; } -int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt_codec *codec) +int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg) { struct bt_bap_ep *ep; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, @@ -74,8 +75,7 @@ int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt if (unicast_server_cb != NULL && unicast_server_cb->reconfig != NULL) { - err = unicast_server_cb->reconfig(stream, ep->dir, codec, - &ep->qos_pref, &rsp); + err = unicast_server_cb->reconfig(stream, ep->dir, codec_cfg, &ep->qos_pref, &rsp); } else { err = -ENOTSUP; } @@ -84,7 +84,7 @@ int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt return err; } - (void)memcpy(&ep->codec, &codec, sizeof(codec)); + (void)memcpy(&ep->codec_cfg, codec_cfg, sizeof(*codec_cfg)); ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); @@ -114,7 +114,7 @@ int bt_bap_unicast_server_start(struct bt_bap_stream *stream) return 0; } -int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec_data meta[], +int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data meta[], size_t meta_count) { struct bt_bap_ep *ep; @@ -131,8 +131,7 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec ep = stream->ep; for (size_t i = 0U; i < meta_count; i++) { - (void)memcpy(&ep->codec.meta[i], &meta[i], - sizeof(ep->codec.meta[i])); + (void)memcpy(&ep->codec_cfg.meta[i], &meta[i], sizeof(ep->codec_cfg.meta[i])); } if (err) { @@ -204,10 +203,10 @@ int bt_bap_unicast_server_release(struct bt_bap_stream *stream) } int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, - struct bt_codec *codec, - const struct bt_codec_qos_pref *qos_pref) + struct bt_audio_codec_cfg *codec_cfg, + const struct bt_audio_codec_qos_pref *qos_pref) { - return bt_ascs_config_ase(conn, stream, codec, qos_pref); + return bt_ascs_config_ase(conn, stream, codec_cfg, qos_pref); } void bt_bap_unicast_server_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data) diff --git a/subsys/bluetooth/audio/bap_unicast_server.h b/subsys/bluetooth/audio/bap_unicast_server.h index 26198bcf4721..8470ace1237f 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.h +++ b/subsys/bluetooth/audio/bap_unicast_server.h @@ -9,9 +9,10 @@ #include #include -int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt_codec *codec); +int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg); int bt_bap_unicast_server_start(struct bt_bap_stream *stream); -int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec_data meta[], +int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data meta[], size_t meta_count); int bt_bap_unicast_server_disable(struct bt_bap_stream *stream); int bt_bap_unicast_server_release(struct bt_bap_stream *stream); diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index d877f99b80b3..ec164de4b73b 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -38,8 +38,7 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb) return 0; } -static bool cap_initiator_valid_metadata(const struct bt_codec_data meta[], - size_t meta_count) +static bool cap_initiator_valid_metadata(const struct bt_audio_codec_data meta[], size_t meta_count) { bool stream_context_found; @@ -82,21 +81,21 @@ static bool cap_initiator_broadcast_audio_start_valid_param( for (size_t i = 0U; i < param->subgroup_count; i++) { const struct bt_cap_initiator_broadcast_subgroup_param *subgroup_param; - const struct bt_codec *codec; + const struct bt_audio_codec_cfg *codec_cfg; bool valid_metadata; subgroup_param = ¶m->subgroup_params[i]; - codec = subgroup_param->codec; + codec_cfg = subgroup_param->codec_cfg; /* Streaming Audio Context shall be present in CAP */ - CHECKIF(codec == NULL) { - LOG_DBG("subgroup[%zu]->codec is NULL", i); + CHECKIF(codec_cfg == NULL) { + LOG_DBG("subgroup[%zu]->codec_cfg is NULL", i); return false; } - valid_metadata = cap_initiator_valid_metadata(codec->meta, - codec->meta_count); + valid_metadata = + cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_count); CHECKIF(!valid_metadata) { LOG_DBG("Invalid metadata supplied for subgroup[%zu]", i); @@ -135,7 +134,7 @@ static void cap_initiator_broadcast_to_bap_broadcast_param( struct bt_bap_broadcast_source_subgroup_param *bap_subgroup_param = &bap_param->params[i]; - bap_subgroup_param->codec = cap_subgroup_param->codec; + bap_subgroup_param->codec_cfg = cap_subgroup_param->codec_cfg; bap_subgroup_param->params_count = cap_subgroup_param->stream_count; bap_subgroup_param->params = &bap_stream_params[stream_cnt]; @@ -146,13 +145,13 @@ static void cap_initiator_broadcast_to_bap_broadcast_param( &bap_subgroup_param->params[j]; bap_stream_param->stream = &cap_stream_param->stream->bap_stream; -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 bap_stream_param->data_count = cap_stream_param->data_count; /* We do not need to copy the data, as that is the same type of struct, so * we can just point to the CAP parameter data */ bap_stream_param->data = cap_stream_param->data; -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ } } } @@ -212,7 +211,7 @@ int bt_cap_initiator_broadcast_audio_start(struct bt_cap_broadcast_source *broad } int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source, - const struct bt_codec_data meta[], + const struct bt_audio_codec_data meta[], size_t meta_count) { CHECKIF(broadcast_source == NULL) { @@ -654,18 +653,16 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st ¶m->stream_params[i]; const union bt_cap_set_member *member = &stream_param->member; const struct bt_cap_stream *cap_stream = stream_param->stream; - const struct bt_codec *codec = stream_param->codec; + const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg; const struct bt_bap_stream *bap_stream; - CHECKIF(stream_param->codec == NULL) { - LOG_DBG("param->stream_params[%zu].codec is NULL", i); + CHECKIF(stream_param->codec_cfg == NULL) { + LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i); return false; } - CHECKIF(!cap_initiator_valid_metadata(codec->meta, - codec->meta_count)) { - LOG_DBG("param->stream_params[%zu].codec is invalid", - i); + CHECKIF(!cap_initiator_valid_metadata(codec_cfg->meta, codec_cfg->meta_count)) { + LOG_DBG("param->stream_params[%zu].codec_cfg is invalid", i); return false; } @@ -775,7 +772,7 @@ static int cap_initiator_unicast_audio_configure( struct bt_cap_stream *cap_stream = stream_param->stream; struct bt_bap_stream *bap_stream = &cap_stream->bap_stream; struct bt_bap_ep *ep = stream_param->ep; - struct bt_codec *codec = stream_param->codec; + struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg; struct bt_conn *conn; int err; @@ -797,7 +794,7 @@ static int cap_initiator_unicast_audio_configure( active_proc.streams[i] = cap_stream; - err = bt_bap_stream_config(conn, bap_stream, ep, codec); + err = bt_bap_stream_config(conn, bap_stream, ep, codec_cfg); if (err != 0) { LOG_DBG("bt_bap_stream_config failed for param->stream_params[%zu]: %d", i, err); @@ -1022,9 +1019,8 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) int err; /* TODO: Add metadata */ - err = bt_bap_stream_enable(bap_stream, - bap_stream->codec->meta, - bap_stream->codec->meta_count); + err = bt_bap_stream_enable(bap_stream, bap_stream->codec_cfg->meta, + bap_stream->codec_cfg->meta_count); if (err != 0) { LOG_DBG("Failed to enable stream %p: %d", cap_stream_active, err); diff --git a/subsys/bluetooth/audio/cap_stream.c b/subsys/bluetooth/audio/cap_stream.c index c36c0beab55e..c9c91de1f4ad 100644 --- a/subsys/bluetooth/audio/cap_stream.c +++ b/subsys/bluetooth/audio/cap_stream.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(bt_cap_stream, CONFIG_BT_CAP_STREAM_LOG_LEVEL); #if defined(CONFIG_BT_BAP_UNICAST) static void cap_stream_configured_cb(struct bt_bap_stream *bap_stream, - const struct bt_codec_qos_pref *pref) + const struct bt_audio_codec_qos_pref *pref) { struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 59b82539f373..4f83d75045f2 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -18,18 +18,17 @@ LOG_MODULE_REGISTER(bt_audio_codec, CONFIG_BT_AUDIO_CODEC_LOG_LEVEL); -bool bt_codec_get_val(const struct bt_codec *codec, - uint8_t type, - const struct bt_codec_data **data) +bool bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, uint8_t type, + const struct bt_audio_codec_data **data) { - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return false; } - for (size_t i = 0; i < codec->data_count; i++) { - if (codec->data[i].data.type == type) { - *data = &codec->data[i]; + for (size_t i = 0; i < codec_cfg->data_count; i++) { + if (codec_cfg->data[i].data.type == type) { + *data = &codec_cfg->data[i]; return true; } @@ -38,43 +37,43 @@ bool bt_codec_get_val(const struct bt_codec *codec, return false; } -int bt_codec_cfg_get_freq(const struct bt_codec *codec) +int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) { - const struct bt_codec_data *element; + const struct bt_audio_codec_data *element; - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM; } - if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FREQ, &element)) { + if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FREQ, &element)) { switch (element->data.data[0]) { - case BT_CODEC_CONFIG_LC3_FREQ_8KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_8KHZ: return 8000; - case BT_CODEC_CONFIG_LC3_FREQ_11KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_11KHZ: return 11025; - case BT_CODEC_CONFIG_LC3_FREQ_16KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ: return 16000; - case BT_CODEC_CONFIG_LC3_FREQ_22KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_22KHZ: return 22050; - case BT_CODEC_CONFIG_LC3_FREQ_24KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ: return 24000; - case BT_CODEC_CONFIG_LC3_FREQ_32KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_32KHZ: return 32000; - case BT_CODEC_CONFIG_LC3_FREQ_44KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_44KHZ: return 44100; - case BT_CODEC_CONFIG_LC3_FREQ_48KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ: return 48000; - case BT_CODEC_CONFIG_LC3_FREQ_88KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_88KHZ: return 88200; - case BT_CODEC_CONFIG_LC3_FREQ_96KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_96KHZ: return 96000; - case BT_CODEC_CONFIG_LC3_FREQ_176KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_176KHZ: return 176400; - case BT_CODEC_CONFIG_LC3_FREQ_192KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_192KHZ: return 192000; - case BT_CODEC_CONFIG_LC3_FREQ_384KHZ: + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_384KHZ: return 384000; default: return BT_AUDIO_CODEC_PARSE_ERR_INVALID_VALUE_FOUND; @@ -84,20 +83,20 @@ int bt_codec_cfg_get_freq(const struct bt_codec *codec) return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND; } -int bt_codec_cfg_get_frame_duration_us(const struct bt_codec *codec) +int bt_audio_codec_cfg_get_frame_duration_us(const struct bt_audio_codec_cfg *codec_cfg) { - const struct bt_codec_data *element; + const struct bt_audio_codec_data *element; - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM; } - if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_DURATION, &element)) { + if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_DURATION, &element)) { switch (element->data.data[0]) { - case BT_CODEC_CONFIG_LC3_DURATION_7_5: + case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_7_5: return 7500; - case BT_CODEC_CONFIG_LC3_DURATION_10: + case BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10: return 10000; default: return BT_AUDIO_CODEC_PARSE_ERR_INVALID_VALUE_FOUND; @@ -107,12 +106,12 @@ int bt_codec_cfg_get_frame_duration_us(const struct bt_codec *codec) return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND; } -int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec, +int bt_audio_codec_cfg_get_chan_allocation_val(const struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_location *chan_allocation) { - const struct bt_codec_data *element; + const struct bt_audio_codec_data *element; - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM; } @@ -122,7 +121,7 @@ int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec, } *chan_allocation = 0; - if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_CHAN_ALLOC, &element)) { + if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, &element)) { *chan_allocation = sys_le32_to_cpu(*((uint32_t *)&element->data.data[0])); @@ -132,16 +131,16 @@ int bt_codec_cfg_get_chan_allocation_val(const struct bt_codec *codec, return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND; } -int bt_codec_cfg_get_octets_per_frame(const struct bt_codec *codec) +int bt_audio_codec_cfg_get_octets_per_frame(const struct bt_audio_codec_cfg *codec_cfg) { - const struct bt_codec_data *element; + const struct bt_audio_codec_data *element; - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM; } - if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FRAME_LEN, &element)) { + if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_LEN, &element)) { return sys_le16_to_cpu(*((uint16_t *)&element->data.data[0])); } @@ -149,16 +148,18 @@ int bt_codec_cfg_get_octets_per_frame(const struct bt_codec *codec) return BT_AUDIO_CODEC_PARSE_ERR_TYPE_NOT_FOUND; } -int bt_codec_cfg_get_frame_blocks_per_sdu(const struct bt_codec *codec, bool fallback_to_default) +int bt_audio_codec_cfg_get_frame_blocks_per_sdu(const struct bt_audio_codec_cfg *codec_cfg, + bool fallback_to_default) { - const struct bt_codec_data *element; + const struct bt_audio_codec_data *element; - CHECKIF(codec == NULL) { + CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); return BT_AUDIO_CODEC_PARSE_ERR_INVALID_PARAM; } - if (bt_codec_get_val(codec, BT_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, &element)) { + if (bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_CONFIG_LC3_FRAME_BLKS_PER_SDU, + &element)) { return element->data.data[0]; } diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index ce8144d1b2f4..8b5c664fa99c 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -76,7 +76,7 @@ static K_SEM_DEFINE(read_buf_sem, 1, 1); NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN); static ssize_t pac_data_add(struct net_buf_simple *buf, size_t count, - struct bt_codec_data *data) + struct bt_audio_codec_data *data) { size_t len = 0; @@ -108,7 +108,7 @@ struct pac_records_build_data { static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data) { struct pac_records_build_data *data = user_data; - struct bt_codec *codec = cap->codec; + struct bt_audio_codec_cap *codec_cap = cap->codec_cap; struct net_buf_simple *buf = data->buf; struct net_buf_simple_state state; struct bt_pac_ltv_data *cc, *meta; @@ -122,9 +122,9 @@ static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data) } pac_codec = net_buf_simple_add(buf, sizeof(*pac_codec)); - pac_codec->id = codec->id; - pac_codec->cid = sys_cpu_to_le16(codec->cid); - pac_codec->vid = sys_cpu_to_le16(codec->vid); + pac_codec->id = codec_cap->id; + pac_codec->cid = sys_cpu_to_le16(codec_cap->cid); + pac_codec->vid = sys_cpu_to_le16(codec_cap->vid); if (net_buf_simple_tailroom(buf) < sizeof(*cc)) { goto fail; @@ -132,7 +132,7 @@ static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data) cc = net_buf_simple_add(buf, sizeof(*cc)); - len = pac_data_add(buf, codec->data_count, codec->data); + len = pac_data_add(buf, codec_cap->data_count, codec_cap->data); if (len < 0 || len > UINT8_MAX) { goto fail; } @@ -145,7 +145,7 @@ static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data) meta = net_buf_simple_add(buf, sizeof(*meta)); - len = pac_data_add(buf, codec->meta_count, codec->meta); + len = pac_data_add(buf, codec_cap->meta_count, codec_cap->meta); if (len < 0 || len > UINT8_MAX) { goto fail; } @@ -777,20 +777,22 @@ void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, /* Register Audio Capability */ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap) { + const struct bt_audio_codec_cap *codec_cap; struct pacs *pac; - if (!cap || !cap->codec) { + if (!cap || !cap->codec_cap) { return -EINVAL; } + codec_cap = cap->codec_cap; + pac = pacs_get(dir); if (!pac) { return -EINVAL; } - LOG_DBG("cap %p dir %s codec 0x%02x codec cid 0x%04x " - "codec vid 0x%04x", cap, bt_audio_dir_str(dir), cap->codec->id, - cap->codec->cid, cap->codec->vid); + LOG_DBG("cap %p dir %s codec_cap id 0x%02x codec_cap cid 0x%04x codec_cap vid 0x%04x", cap, + bt_audio_dir_str(dir), codec_cap->id, codec_cap->cid, codec_cap->vid); sys_slist_append(&pac->list, &cap->_node); diff --git a/subsys/bluetooth/audio/pacs_internal.h b/subsys/bluetooth/audio/pacs_internal.h index 3befe6ae8538..9f5291ae5797 100644 --- a/subsys/bluetooth/audio/pacs_internal.h +++ b/subsys/bluetooth/audio/pacs_internal.h @@ -17,11 +17,6 @@ struct bt_pac_codec { uint16_t vid; /* Vendor specific Codec ID */ } __packed; -/* TODO: Figure out the capabilities types */ -#define BT_CODEC_CAP_PARAMS 0x01 -#define BT_CODEC_CAP_DRM 0x0a -#define BT_CODEC_CAP_DRM_VALUE 0x0b - struct bt_pac_ltv { uint8_t len; uint8_t type; diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 4abc62aa0957..4c3842616ed1 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -56,13 +56,13 @@ struct named_lc3_preset { struct unicast_stream { struct bt_cap_stream stream; - struct bt_codec codec; - struct bt_codec_qos qos; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; }; struct broadcast_stream { struct bt_cap_stream stream; - struct bt_codec_data data; + struct bt_audio_codec_data data; }; struct broadcast_source { @@ -70,8 +70,8 @@ struct broadcast_source { struct bt_bap_broadcast_source *bap_source; struct bt_cap_broadcast_source *cap_source; }; - struct bt_codec codec; - struct bt_codec_qos qos; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; }; extern struct unicast_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + @@ -87,7 +87,7 @@ extern const struct named_lc3_preset *default_source_preset; #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ #endif /* CONFIG_BT_BAP_UNICAST */ -static inline void print_qos(const struct shell *sh, const struct bt_codec_qos *qos) +static inline void print_qos(const struct shell *sh, const struct bt_audio_codec_qos *qos) { #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST) shell_print(sh, @@ -100,29 +100,62 @@ static inline void print_qos(const struct shell *sh, const struct bt_codec_qos * #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE || CONFIG_BT_BAP_UNICAST */ } -static inline void print_codec(const struct shell *sh, const struct bt_codec *codec) +static inline void print_codec_cap(const struct shell *sh, + const struct bt_audio_codec_cap *codec_cap) { - shell_print(sh, "codec 0x%02x cid 0x%04x vid 0x%04x", codec->id, codec->cid, codec->vid); - -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 - shell_print(sh, "data_count %u", codec->data_count); - for (size_t i = 0U; i < codec->data_count; i++) { - shell_print(sh, "data #%u: type 0x%02x len %u", i, codec->data[i].data.type, - codec->data[i].data.data_len); - shell_hexdump(sh, codec->data[i].data.data, - codec->data[i].data.data_len - sizeof(codec->data[i].data.type)); + shell_print(sh, "codec cap id 0x%02x cid 0x%04x vid 0x%04x", codec_cap->id, codec_cap->cid, + codec_cap->vid); + +#if CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT > 0 + shell_print(sh, "data_count %u", codec_cap->data_count); + for (size_t i = 0U; i < codec_cap->data_count; i++) { + shell_print(sh, "data #%u: type 0x%02x len %u", i, codec_cap->data[i].data.type, + codec_cap->data[i].data.data_len); + shell_hexdump(sh, codec_cap->data[i].data.data, + codec_cap->data[i].data.data_len - + sizeof(codec_cap->data[i].data.type)); } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ - -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 - shell_print(sh, "meta_count %u", codec->data_count); - for (size_t i = 0U; i < codec->meta_count; i++) { - shell_print(sh, "meta #%u: type 0x%02x len %u", i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - shell_hexdump(sh, codec->meta[i].data.data, - codec->meta[i].data.data_len - sizeof(codec->meta[i].data.type)); +#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_COUNT > 0 */ + +#if CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT > 0 + shell_print(sh, "meta_count %u", codec_cap->data_count); + for (size_t i = 0U; i < codec_cap->meta_count; i++) { + shell_print(sh, "meta #%u: type 0x%02x len %u", i, codec_cap->meta[i].data.type, + codec_cap->meta[i].data.data_len); + shell_hexdump(sh, codec_cap->meta[i].data.data, + codec_cap->meta[i].data.data_len - + sizeof(codec_cap->meta[i].data.type)); } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_COUNT > 0 */ +} + +static inline void print_codec_cfg(const struct shell *sh, + const struct bt_audio_codec_cfg *codec_cfg) +{ + shell_print(sh, "codec cfg id 0x%02x cid 0x%04x vid 0x%04x", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid); + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 + shell_print(sh, "data_count %u", codec_cfg->data_count); + for (size_t i = 0U; i < codec_cfg->data_count; i++) { + shell_print(sh, "data #%u: type 0x%02x len %u", i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + shell_hexdump(sh, codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - + sizeof(codec_cfg->data[i].data.type)); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 + shell_print(sh, "meta_count %u", codec_cfg->data_count); + for (size_t i = 0U; i < codec_cfg->meta_count; i++) { + shell_print(sh, "meta #%u: type 0x%02x len %u", i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + shell_hexdump(sh, codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - + sizeof(codec_cfg->meta[i].data.type)); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */ } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) @@ -144,7 +177,7 @@ static inline void print_base(const struct shell *sh, const struct bt_bap_base * subgroup = &base->subgroups[i]; shell_print(sh, "Subgroup[%d]:", i); - print_codec(sh, &subgroup->codec); + print_codec_cfg(sh, &subgroup->codec_cfg); for (size_t j = 0U; j < subgroup->bis_count; j++) { const struct bt_bap_base_bis_data *bis_data; @@ -154,9 +187,9 @@ static inline void print_base(const struct shell *sh, const struct bt_bap_base * shell_print(sh, "BIS[%d] index 0x%02x", j, bis_data->index); bis_indexes[index_count++] = bis_data->index; -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 for (size_t k = 0U; k < bis_data->data_count; k++) { - const struct bt_codec_data *codec_data; + const struct bt_audio_codec_data *codec_data; codec_data = &bis_data->data[k]; @@ -166,7 +199,7 @@ static inline void print_base(const struct shell *sh, const struct bt_bap_base * codec_data->data.data_len - sizeof(codec_data->data.type)); } -#endif /* CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 */ } } @@ -190,64 +223,76 @@ static inline 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, &named_preset->preset.codec, sizeof(stream->codec)); + memcpy(&stream->codec_cfg, &named_preset->preset.codec_cfg, sizeof(stream->codec_cfg)); -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 /* Need to update the `bt_data.data` pointer to the new value after copying the codec */ - for (size_t i = 0U; i < ARRAY_SIZE(stream->codec.data); i++) { - const struct bt_codec_data *preset_data = &named_preset->preset.codec.data[i]; - struct bt_codec_data *data = &stream->codec.data[i]; + for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.data); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.data[i]; + struct bt_audio_codec_data *data = &stream->codec_cfg.data[i]; const uint8_t data_len = preset_data->data.data_len; data->data.data = data->value; data->data.data_len = data_len; memcpy(data->value, preset_data->data.data, data_len); } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ - -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 - for (size_t i = 0U; i < ARRAY_SIZE(stream->codec.meta); i++) { - const struct bt_codec_data *preset_data = &named_preset->preset.codec.meta[i]; - struct bt_codec_data *data = &stream->codec.meta[i]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && \ + * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \ + */ + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.meta); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.meta[i]; + struct bt_audio_codec_data *data = &stream->codec_cfg.meta[i]; const uint8_t data_len = preset_data->data.data_len; data->data.data = data->value; data->data.data_len = data_len; memcpy(data->value, preset_data->data.data, data_len); } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && \ + * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \ + */ } static inline void copy_broadcast_source_preset(struct broadcast_source *source, const struct named_lc3_preset *named_preset) { memcpy(&source->qos, &named_preset->preset.qos, sizeof(source->qos)); - memcpy(&source->codec, &named_preset->preset.codec, sizeof(source->codec)); + memcpy(&source->codec_cfg, &named_preset->preset.codec_cfg, sizeof(source->codec_cfg)); -#if CONFIG_BT_CODEC_MAX_DATA_COUNT > 0 +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 /* Need to update the `bt_data.data` pointer to the new value after copying the codec */ - for (size_t i = 0U; i < ARRAY_SIZE(source->codec.data); i++) { - const struct bt_codec_data *preset_data = &named_preset->preset.codec.data[i]; - struct bt_codec_data *data = &source->codec.data[i]; + for (size_t i = 0U; i < ARRAY_SIZE(source->codec_cfg.data); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.data[i]; + struct bt_audio_codec_data *data = &source->codec_cfg.data[i]; const uint8_t data_len = preset_data->data.data_len; data->data.data = data->value; data->data.data_len = data_len; memcpy(data->value, preset_data->data.data, data_len); } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ - -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 - for (size_t i = 0U; i < ARRAY_SIZE(source->codec.meta); i++) { - const struct bt_codec_data *preset_data = &named_preset->preset.codec.meta[i]; - struct bt_codec_data *data = &source->codec.meta[i]; +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \ + * 0 \ + */ + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + for (size_t i = 0U; i < ARRAY_SIZE(source->codec_cfg.meta); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.meta[i]; + struct bt_audio_codec_data *data = &source->codec_cfg.meta[i]; const uint8_t data_len = preset_data->data.data_len; data->data.data = data->value; data->data.data_len = data_len; memcpy(data->value, preset_data->data.data, data_len); } -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \ + * 0 \ + */ } #endif /* CONFIG_BT_AUDIO */ diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 9b9887ea38a2..5842dde2a0a0 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -37,8 +37,8 @@ struct unicast_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, - 20000u, 40000u, 20000u, 40000u); +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); #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) struct bt_bap_unicast_group *default_unicast_group; @@ -229,16 +229,16 @@ static void init_lc3(const struct bt_bap_stream *stream) { size_t num_samples; - if (stream == NULL || stream->codec == NULL) { + if (stream == NULL || stream->codec_cfg == NULL) { shell_error(ctx_shell, "invalid stream to init LC3"); return; } - freq_hz = bt_codec_cfg_get_freq(stream->codec); - frame_duration_us = bt_codec_cfg_get_frame_duration_us(stream->codec); - octets_per_frame = bt_codec_cfg_get_octets_per_frame(stream->codec); - frames_per_sdu = bt_codec_cfg_get_frame_blocks_per_sdu(stream->codec, true); - octets_per_frame = bt_codec_cfg_get_octets_per_frame(stream->codec); + freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg); + frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); + frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); + octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); if (freq_hz < 0) { printk("Error: Codec frequency not set, cannot start codec."); @@ -416,12 +416,12 @@ static struct bt_bap_stream *stream_alloc(void) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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) { shell_print(ctx_shell, "ASE Codec Config: conn %p ep %p dir %u", conn, ep, dir); - print_codec(ctx_shell, codec); + print_codec_cfg(ctx_shell, codec_cfg); *stream = stream_alloc(); if (*stream == NULL) { @@ -442,12 +442,12 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + const struct bt_audio_codec_cfg *codec_cfg, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) { shell_print(ctx_shell, "ASE Codec Reconfig: stream %p", stream); - print_codec(ctx_shell, codec); + print_codec_cfg(ctx_shell, codec_cfg); if (default_stream == NULL) { set_unicast_stream(stream); @@ -458,7 +458,7 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, return 0; } -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos, struct bt_bap_ascs_rsp *rsp) { shell_print(ctx_shell, "QoS: stream %p %p", stream, qos); @@ -468,7 +468,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { shell_print(ctx_shell, "Enable: stream %p meta_count %zu", stream, @@ -528,14 +528,14 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { shell_print(ctx_shell, "Metadata: stream %p meta_count %zu", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { shell_print(ctx_shell, @@ -575,11 +575,10 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp return 0; } -static struct bt_codec lc3_codec = BT_CODEC_LC3(BT_CODEC_LC3_FREQ_ANY, - BT_CODEC_LC3_DURATION_ANY, - BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | - BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_audio_codec_cap lc3_codec_cap = + BT_AUDIO_CODEC_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)); static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, @@ -594,11 +593,11 @@ static const struct bt_bap_unicast_server_cb unicast_server_cb = { }; static struct bt_pacs_cap cap_sink = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; static struct bt_pacs_cap cap_source = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; #if defined(CONFIG_BT_BAP_UNICAST) @@ -633,7 +632,7 @@ static uint16_t strmeta(const char *name) return 0u; } -static int set_metadata(struct bt_codec *codec, const char *meta_str) +static int set_metadata(struct bt_audio_codec_cfg *codec_cfg, const char *meta_str) { uint16_t context; @@ -643,7 +642,7 @@ static int set_metadata(struct bt_codec *codec, const char *meta_str) } /* TODO: Check the type and only overwrite the streaming context */ - sys_put_le16(context, codec->meta[0].value); + sys_put_le16(context, codec_cfg->meta[0].value); return 0; } @@ -679,12 +678,14 @@ static uint8_t stream_dir(const struct bt_bap_stream *stream) return 0; } -static void print_remote_codec(const struct bt_conn *conn, const struct bt_codec *codec, - enum bt_audio_dir dir) +static void print_remote_codec_cap(const struct bt_conn *conn, + const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_dir dir) { - shell_print(ctx_shell, "conn %p: codec %p dir 0x%02x", conn, codec, dir); + shell_print(ctx_shell, "conn %p: codec_cap %p dir 0x%02x", conn, codec_cap, + dir); - print_codec(ctx_shell, codec); + print_codec_cap(ctx_shell, codec_cap); } #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 @@ -723,9 +724,10 @@ static void add_source(const struct bt_conn *conn, struct bt_bap_ep *ep) } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */ -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) { - print_remote_codec(conn, codec, dir); + print_remote_codec_cap(conn, codec_cap, dir); } static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) @@ -1027,11 +1029,11 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) /* If location has been modifed, we update the location in the codec configuration */ if (location != BT_AUDIO_LOCATION_PROHIBITED) { - for (size_t i = 0U; i < uni_stream->codec.data_count; i++) { - struct bt_codec_data *data = &uni_stream->codec.data[i]; + for (size_t i = 0U; i < uni_stream->codec_cfg.data_count; i++) { + struct bt_audio_codec_data *data = &uni_stream->codec_cfg.data[i]; /* Overwrite the location value */ - if (data->data.type == BT_CODEC_CONFIG_LC3_CHAN_ALLOC) { + if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { const uint32_t loc_32 = location; sys_put_le32(loc_32, data->value); @@ -1043,13 +1045,14 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) } if (bap_stream->ep == ep) { - err = bt_bap_stream_reconfig(bap_stream, &uni_stream->codec); + err = bt_bap_stream_reconfig(bap_stream, &uni_stream->codec_cfg); if (err != 0) { shell_error(sh, "Unable reconfig stream: %d", err); return -ENOEXEC; } } else { - err = bt_bap_stream_config(default_conn, bap_stream, ep, &uni_stream->codec); + err = bt_bap_stream_config(default_conn, bap_stream, ep, + &uni_stream->codec_cfg); if (err != 0) { shell_error(sh, "Unable to config stream: %d", err); return err; @@ -1063,7 +1066,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) static int cmd_stream_qos(const struct shell *sh, size_t argc, char *argv[]) { - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; unsigned long interval; int err; @@ -1276,7 +1279,7 @@ static int cmd_qos(const struct shell *sh, size_t argc, char *argv[]) static int cmd_enable(const struct shell *sh, size_t argc, char *argv[]) { - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; int err; if (default_stream == NULL) { @@ -1284,17 +1287,17 @@ static int cmd_enable(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - codec = default_stream->codec; + codec_cfg = default_stream->codec_cfg; if (argc > 1) { - err = set_metadata(codec, argv[1]); + err = set_metadata(codec_cfg, argv[1]); if (err != 0) { shell_error(sh, "Unable to handle metadata update: %d", err); return err; } } - err = bt_bap_stream_enable(default_stream, codec->meta, codec->meta_count); + err = bt_bap_stream_enable(default_stream, codec_cfg->meta, codec_cfg->meta_count); if (err) { shell_error(sh, "Unable to enable Channel"); return -ENOEXEC; @@ -1358,18 +1361,18 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "%s", named_preset->name); - print_codec(ctx_shell, &named_preset->preset.codec); + print_codec_cfg(ctx_shell, &named_preset->preset.codec_cfg); print_qos(ctx_shell, &named_preset->preset.qos); return 0; } -#define MAX_META_DATA \ - (CONFIG_BT_CODEC_MAX_METADATA_COUNT * sizeof(struct bt_codec_data)) +#define MAX_META_DATA \ + (CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT * sizeof(struct bt_audio_codec_data)) static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[]) { - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; int err; if (default_stream == NULL) { @@ -1377,17 +1380,17 @@ static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - codec = default_stream->codec; + codec_cfg = default_stream->codec_cfg; if (argc > 1) { - err = set_metadata(codec, argv[1]); + err = set_metadata(codec_cfg, argv[1]); if (err != 0) { shell_error(sh, "Unable to handle metadata update: %d", err); return err; } } - err = bt_bap_stream_metadata(default_stream, codec->meta, codec->meta_count); + err = bt_bap_stream_metadata(default_stream, codec_cfg->meta, codec_cfg->meta_count); if (err) { shell_error(sh, "Unable to set Channel metadata"); return -ENOEXEC; @@ -1570,7 +1573,7 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba subgroup = &base->subgroups[i]; shell_print(ctx_shell, "%2sSubgroup[%d]:", "", i); - print_codec(ctx_shell, &subgroup->codec); + 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; @@ -1581,7 +1584,7 @@ static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_ba bis_indexes[index_count++] = bis_data->index; for (int k = 0; k < bis_data->data_count; k++) { - const struct bt_codec_data *codec_data; + const struct bt_audio_codec_data *codec_data; codec_data = &bis_data->data[k]; @@ -1898,7 +1901,7 @@ static int cmd_create_broadcast(const struct shell *sh, size_t argc, } subgroup_param.params_count = ARRAY_SIZE(stream_params); subgroup_param.params = stream_params; - subgroup_param.codec = &default_source.codec; + subgroup_param.codec_cfg = &default_source.codec_cfg; create_param.params_count = 1U; create_param.params = &subgroup_param; create_param.qos = &default_source.qos; diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index dd551d490f68..51a69a82618a 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -871,9 +871,9 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, subgroup_param->bis_sync = subgroup_bis_indexes & bis_bitfield_req; -#if CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 - metadata_len = bt_audio_codec_data_to_buf(subgroup->codec.meta, - subgroup->codec.meta_count, +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 + metadata_len = bt_audio_codec_data_to_buf(subgroup->codec_cfg.meta, + subgroup->codec_cfg.meta_count, subgroup_param->metadata, sizeof(subgroup_param->metadata)); if (metadata_len < 0) { @@ -881,7 +881,7 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, } #else metadata_len = 0U; -#endif /* CONFIG_BT_CODEC_MAX_METADATA_COUNT > 0 */ +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 */ subgroup_param->metadata_len = metadata_len; } diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index bc7e6c6fa844..0fabfdf14299 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -249,7 +249,7 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, stream_param[start_param.count].stream = stream; stream_param[start_param.count].ep = snk_ep; copy_unicast_stream_preset(uni_stream, default_sink_preset); - stream_param[start_param.count].codec = &uni_stream->codec; + stream_param[start_param.count].codec_cfg = &uni_stream->codec_cfg; stream_param[start_param.count].qos = &uni_stream->qos; group_stream_params[start_param.count].qos = @@ -283,7 +283,7 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, stream_param[start_param.count].stream = stream; stream_param[start_param.count].ep = src_ep; copy_unicast_stream_preset(uni_stream, default_source_preset); - stream_param[start_param.count].codec = &uni_stream->codec; + stream_param[start_param.count].codec_cfg = &uni_stream->codec_cfg; stream_param[start_param.count].qos = &uni_stream->qos; group_stream_params[start_param.count].qos = @@ -388,8 +388,8 @@ 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.meta; - params[count].meta_count = uni_stream->codec.meta_count; + params[count].meta = uni_stream->codec_cfg.meta; + params[count].meta_count = uni_stream->codec_cfg.meta_count; count++; } @@ -430,8 +430,8 @@ 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.meta; - params[count].meta_count = uni_stream->codec.meta_count; + params[count].meta = uni_stream->codec_cfg.meta; + params[count].meta_count = uni_stream->codec_cfg.meta_count; count++; } diff --git a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c index 7cca787fba62..e56a30f7f4a8 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_control_params.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_control_params.c @@ -319,14 +319,14 @@ ZTEST_F(test_ase_control_params, test_codec_configure_invalid_ase_id_0x00) } static struct bt_bap_stream test_stream; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, - 0x02, 10, 40000, 40000, - 40000, 40000); +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); static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const struct bt_bap_ep *ep, - enum bt_audio_dir dir, const struct bt_codec *codec, + enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) { *stream = &test_stream; 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 fbe2a6d6b666..17fb10e9dd3e 100644 --- a/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c +++ b/tests/bluetooth/audio/ascs/src/test_ase_state_transition.c @@ -28,9 +28,8 @@ #define test_sink_ase_state_transition_fixture test_ase_state_transition_fixture #define test_source_ase_state_transition_fixture test_ase_state_transition_fixture -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, - 0x02, 10, 40000, 40000, - 40000, 40000); +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); struct test_ase_state_transition_fixture { struct bt_conn conn; @@ -322,15 +321,15 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_qos_configured) ZTEST_F(test_sink_ase_state_transition, test_server_idle_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; int err; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); - err = bt_bap_unicast_server_config_ase(conn, stream, &codec, &qos_pref); + err = bt_bap_unicast_server_config_ase(conn, stream, &codec_cfg, &qos_pref); zassert_false(err < 0, "bt_bap_unicast_server_config_ase returned err %d", err); /* Verification */ @@ -340,8 +339,8 @@ ZTEST_F(test_sink_ase_state_transition, test_server_idle_to_codec_configured) ZTEST_F(test_sink_ase_state_transition, test_server_codec_configured_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; uint8_t ase_id = fixture->ase.id; @@ -351,7 +350,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_codec_configured_to_codec_co test_preamble_state_codec_configured(conn, ase_id, stream); - err = bt_bap_stream_reconfig(stream, &codec); + err = bt_bap_stream_reconfig(stream, &codec_cfg); zassert_false(err < 0, "bt_bap_stream_reconfig returned err %d", err); /* Verification */ @@ -380,8 +379,8 @@ ZTEST_F(test_sink_ase_state_transition, test_server_codec_configured_to_releasin ZTEST_F(test_sink_ase_state_transition, test_server_qos_configured_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; uint8_t ase_id = fixture->ase.id; @@ -391,7 +390,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_qos_configured_to_codec_conf test_preamble_state_qos_configured(conn, ase_id, stream); - err = bt_bap_stream_reconfig(stream, &codec); + err = bt_bap_stream_reconfig(stream, &codec_cfg); zassert_false(err < 0, "bt_bap_stream_reconfig returned err %d", err); /* Verification */ @@ -439,8 +438,8 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_releasing) ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_enabling) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), }; @@ -505,8 +504,8 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming) ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_streaming) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), }; @@ -897,15 +896,15 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_disabling_to_ ZTEST_F(test_source_ase_state_transition, test_server_idle_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; int err; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SRC); - err = bt_bap_unicast_server_config_ase(conn, stream, &codec, &qos_pref); + err = bt_bap_unicast_server_config_ase(conn, stream, &codec_cfg, &qos_pref); zassert_false(err < 0, "bt_bap_unicast_server_config_ase returned err %d", err); /* Verification */ @@ -915,8 +914,8 @@ ZTEST_F(test_source_ase_state_transition, test_server_idle_to_codec_configured) ZTEST_F(test_source_ase_state_transition, test_server_codec_configured_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; uint8_t ase_id = fixture->ase.id; @@ -926,7 +925,7 @@ ZTEST_F(test_source_ase_state_transition, test_server_codec_configured_to_codec_ test_preamble_state_codec_configured(conn, ase_id, stream); - err = bt_bap_stream_reconfig(stream, &codec); + err = bt_bap_stream_reconfig(stream, &codec_cfg); zassert_false(err < 0, "bt_bap_stream_reconfig returned err %d", err); /* Verification */ @@ -955,8 +954,8 @@ ZTEST_F(test_source_ase_state_transition, test_server_codec_configured_to_releas ZTEST_F(test_source_ase_state_transition, test_server_qos_configured_to_codec_configured) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); struct bt_bap_stream *stream = &fixture->stream; struct bt_conn *conn = &fixture->conn; uint8_t ase_id = fixture->ase.id; @@ -966,7 +965,7 @@ ZTEST_F(test_source_ase_state_transition, test_server_qos_configured_to_codec_co test_preamble_state_qos_configured(conn, ase_id, stream); - err = bt_bap_stream_reconfig(stream, &codec); + err = bt_bap_stream_reconfig(stream, &codec_cfg); zassert_false(err < 0, "bt_bap_stream_reconfig returned err %d", err); /* Verification */ @@ -1014,8 +1013,8 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_releasing) ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_enabling) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), }; @@ -1057,8 +1056,8 @@ ZTEST_F(test_source_ase_state_transition, test_server_enabling_to_disabling) ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_streaming) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), }; 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 de613815eaab..32c0c7767cc8 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 @@ -449,11 +449,11 @@ ZTEST_F(test_ase_state_transition_invalid, test_client_source_state_disabling) static void test_server_config_codec_expect_error(struct bt_bap_stream *stream) { - struct bt_codec codec = BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, - BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); + struct bt_audio_codec_cfg codec_cfg = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); int err; - err = bt_bap_stream_reconfig(stream, &codec); + err = bt_bap_stream_reconfig(stream, &codec_cfg); zassert_false(err == 0, "bt_bap_stream_reconfig unexpected success"); } @@ -490,8 +490,8 @@ static void test_server_config_qos_expect_error(struct bt_bap_stream *stream) static void test_server_enable_expect_error(struct bt_bap_stream *stream) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_RINGTONE & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_RINGTONE >> 8) & 0xFFU)), }; @@ -516,8 +516,8 @@ static void test_server_receiver_stop_ready_expect_error(struct bt_bap_stream *s static void test_server_update_metadata_expect_error(struct bt_bap_stream *stream) { - struct bt_codec_data meta[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + struct bt_audio_codec_data meta[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, (BT_AUDIO_CONTEXT_TYPE_RINGTONE & 0xFFU), ((BT_AUDIO_CONTEXT_TYPE_RINGTONE >> 8) & 0xFFU)), }; diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index adecbf2f2c37..bc529097b8f3 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -133,14 +133,14 @@ uint8_t test_ase_id_get(const struct bt_gatt_attr *ase) } static struct bt_bap_stream *stream_allocated; -static const struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, - 0x02, 10, 40000, 40000, - 40000, 40000); +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); static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const struct bt_bap_ep *ep, - enum bt_audio_dir dir, const struct bt_codec *codec, + enum bt_audio_dir dir, + const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, + struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) { *stream = stream_allocated; diff --git a/tests/bluetooth/audio/mocks/include/bap_stream.h b/tests/bluetooth/audio/mocks/include/bap_stream.h index 553c0cded746..41d146f810d2 100644 --- a/tests/bluetooth/audio/mocks/include/bap_stream.h +++ b/tests/bluetooth/audio/mocks/include/bap_stream.h @@ -16,7 +16,7 @@ void mock_bap_stream_init(void); void mock_bap_stream_cleanup(void); DECLARE_FAKE_VOID_FUNC(mock_bap_stream_configured_cb, struct bt_bap_stream *, - const struct bt_codec_qos_pref *); + const struct bt_audio_codec_qos_pref *); DECLARE_FAKE_VOID_FUNC(mock_bap_stream_qos_set_cb, struct bt_bap_stream *); DECLARE_FAKE_VOID_FUNC(mock_bap_stream_enabled_cb, struct bt_bap_stream *); DECLARE_FAKE_VOID_FUNC(mock_bap_stream_metadata_updated_cb, struct bt_bap_stream *); diff --git a/tests/bluetooth/audio/mocks/include/bap_unicast_server.h b/tests/bluetooth/audio/mocks/include/bap_unicast_server.h index 77d10b3f5d5b..61d02a8f4702 100644 --- a/tests/bluetooth/audio/mocks/include/bap_unicast_server.h +++ b/tests/bluetooth/audio/mocks/include/bap_unicast_server.h @@ -16,20 +16,20 @@ void mock_bap_unicast_server_init(void); void mock_bap_unicast_server_cleanup(void); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_config, struct bt_conn *, - const struct bt_bap_ep *, enum bt_audio_dir, const struct bt_codec *, - struct bt_bap_stream **, struct bt_codec_qos_pref *const, - struct bt_bap_ascs_rsp *); + const struct bt_bap_ep *, enum bt_audio_dir, + const struct bt_audio_codec_cfg *, struct bt_bap_stream **, + struct bt_audio_codec_qos_pref *const, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_reconfig, struct bt_bap_stream *, - enum bt_audio_dir, const struct bt_codec *, - struct bt_codec_qos_pref *const, struct bt_bap_ascs_rsp *); + enum bt_audio_dir, const struct bt_audio_codec_cfg *, + struct bt_audio_codec_qos_pref *const, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_qos, struct bt_bap_stream *, - const struct bt_codec_qos *, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_qos *, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_enable, struct bt_bap_stream *, - const struct bt_codec_data *, size_t, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_start, struct bt_bap_stream *, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_metadata, struct bt_bap_stream *, - const struct bt_codec_data *, size_t, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_disable, struct bt_bap_stream *, struct bt_bap_ascs_rsp *); DECLARE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_stop, struct bt_bap_stream *, diff --git a/tests/bluetooth/audio/mocks/src/bap_stream.c b/tests/bluetooth/audio/mocks/src/bap_stream.c index d4597b65362e..c022865dc0a1 100644 --- a/tests/bluetooth/audio/mocks/src/bap_stream.c +++ b/tests/bluetooth/audio/mocks/src/bap_stream.c @@ -24,7 +24,7 @@ struct bt_bap_stream_ops mock_bap_stream_ops; DEFINE_FAKE_VOID_FUNC(mock_bap_stream_configured_cb, struct bt_bap_stream *, - const struct bt_codec_qos_pref *); + const struct bt_audio_codec_qos_pref *); DEFINE_FAKE_VOID_FUNC(mock_bap_stream_qos_set_cb, struct bt_bap_stream *); DEFINE_FAKE_VOID_FUNC(mock_bap_stream_enabled_cb, struct bt_bap_stream *); DEFINE_FAKE_VOID_FUNC(mock_bap_stream_metadata_updated_cb, struct bt_bap_stream *); diff --git a/tests/bluetooth/audio/mocks/src/bap_unicast_client.c b/tests/bluetooth/audio/mocks/src/bap_unicast_client.c index 44179310b0c0..d5cfd4823f78 100644 --- a/tests/bluetooth/audio/mocks/src/bap_unicast_client.c +++ b/tests/bluetooth/audio/mocks/src/bap_unicast_client.c @@ -11,7 +11,8 @@ bool bt_bap_ep_is_unicast_client(const struct bt_bap_ep *ep) return false; } -int bt_bap_unicast_client_config(struct bt_bap_stream *stream, const struct bt_codec *codec) +int bt_bap_unicast_client_config(struct bt_bap_stream *stream, + const struct bt_audio_codec_cfg *codec_cfg) { zassert_unreachable("Unexpected call to '%s()' occurred", __func__); return 0; @@ -23,14 +24,14 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group return 0; } -int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_enable(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count) { zassert_unreachable("Unexpected call to '%s()' occurred", __func__); return 0; } -int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_codec_data *meta, +int bt_bap_unicast_client_metadata(struct bt_bap_stream *stream, struct bt_audio_codec_data *meta, size_t meta_count) { zassert_unreachable("Unexpected call to '%s()' occurred", __func__); diff --git a/tests/bluetooth/audio/mocks/src/bap_unicast_server.c b/tests/bluetooth/audio/mocks/src/bap_unicast_server.c index b59180d0a426..e6907a32b5b2 100644 --- a/tests/bluetooth/audio/mocks/src/bap_unicast_server.c +++ b/tests/bluetooth/audio/mocks/src/bap_unicast_server.c @@ -31,20 +31,20 @@ void mock_bap_unicast_server_cleanup(void) } DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_config, struct bt_conn *, - const struct bt_bap_ep *, enum bt_audio_dir, const struct bt_codec *, - struct bt_bap_stream **, struct bt_codec_qos_pref *const, - struct bt_bap_ascs_rsp *); + const struct bt_bap_ep *, enum bt_audio_dir, + const struct bt_audio_codec_cfg *, struct bt_bap_stream **, + struct bt_audio_codec_qos_pref *const, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_reconfig, struct bt_bap_stream *, - enum bt_audio_dir, const struct bt_codec *, struct bt_codec_qos_pref *const, - struct bt_bap_ascs_rsp *); + enum bt_audio_dir, const struct bt_audio_codec_cfg *, + struct bt_audio_codec_qos_pref *const, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_qos, struct bt_bap_stream *, - const struct bt_codec_qos *, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_qos *, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_enable, struct bt_bap_stream *, - const struct bt_codec_data *, size_t, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_start, struct bt_bap_stream *, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_metadata, struct bt_bap_stream *, - const struct bt_codec_data *, size_t, struct bt_bap_ascs_rsp *); + const struct bt_audio_codec_data *, size_t, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_disable, struct bt_bap_stream *, struct bt_bap_ascs_rsp *); DEFINE_FAKE_VALUE_FUNC(int, mock_bap_unicast_server_cb_stop, struct bt_bap_stream *, diff --git a/tests/bluetooth/audio/mocks/src/pacs.c b/tests/bluetooth/audio/mocks/src/pacs.c index 61e24859a3fe..11cfd629dbcd 100644 --- a/tests/bluetooth/audio/mocks/src/pacs.c +++ b/tests/bluetooth/audio/mocks/src/pacs.c @@ -13,9 +13,9 @@ #define PACS_FFF_FAKES_LIST(FAKE) \ FAKE(bt_pacs_cap_foreach) \ -static struct bt_codec lc3_codec = - BT_CODEC_LC3(BT_CODEC_LC3_FREQ_ANY, BT_CODEC_LC3_DURATION_10, - BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, +static struct bt_audio_codec_cfg lc3_codec = + BT_AUDIO_CODEC_LC3(BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, (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 *); diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 40d24233f6a8..14fa76b3db2e 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -61,11 +61,14 @@ CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 -CONFIG_BT_CODEC_MAX_METADATA_COUNT=10 -CONFIG_BT_CODEC_MAX_DATA_LEN=40 -CONFIG_BT_CODEC_MAX_DATA_COUNT=10 -CONFIG_BT_CODEC_MAX_DATA_LEN=40 +CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT=10 +CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=40 +CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT=10 +CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=40 +CONFIG_BT_ASCS_ASE_SNK_COUNT=2 +CONFIG_BT_ASCS_ASE_SRC_COUNT=2 +CONFIG_BT_BAP_UNICAST_CLIENT=y CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=4 diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index 4954d616e49b..7f78f0d35ce7 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -40,12 +40,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); #define AVAILABLE_SINK_CONTEXT SUPPORTED_SINK_CONTEXT #define AVAILABLE_SOURCE_CONTEXT SUPPORTED_SOURCE_CONTEXT -static struct bt_codec default_codec = - BT_CODEC_LC3(BT_CODEC_LC3_FREQ_ANY, BT_CODEC_LC3_DURATION_10, - BT_CODEC_LC3_CHAN_COUNT_SUPPORT(1), - 40u, 120u, 1u, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | - BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_audio_codec_cap default_codec_cap = + BT_AUDIO_CODEC_LC3(BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); struct audio_stream { struct bt_bap_stream stream; @@ -69,15 +67,15 @@ struct audio_connection { struct audio_stream streams[MAX_STREAMS_COUNT]; size_t configured_sink_stream_count; size_t configured_source_stream_count; - struct bt_codec codec; - struct bt_codec_qos qos; + struct bt_audio_codec_cfg codec_cfg; + struct bt_audio_codec_qos qos; struct bt_bap_unicast_group *unicast_group; struct bt_bap_ep *end_points[MAX_END_POINTS_COUNT]; size_t end_points_count; } connections[CONFIG_BT_MAX_CONN]; -static struct bt_codec_qos_pref qos_pref = BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, - 10, 10000, 40000, 10000, 40000); +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), @@ -97,45 +95,73 @@ static void audio_send_timeout(struct k_work *work); K_THREAD_STACK_DEFINE(iso_data_thread_stack_area, ISO_DATA_THREAD_STACK_SIZE); static struct k_work_q iso_data_work_q; - -static void print_codec(const struct bt_codec *codec) +static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) { - LOG_DBG("codec 0x%02x cid 0x%04x vid 0x%04x count %zu", - codec->id, codec->cid, codec->vid, codec->data_count); + LOG_DBG("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %zu", codec_cfg->id, codec_cfg->cid, + codec_cfg->vid, codec_cfg->data_count); - for (size_t i = 0; i < codec->data_count; i++) { - LOG_DBG("data #%zu: type 0x%02x len %u", i, codec->data[i].data.type, - codec->data[i].data.data_len); - LOG_HEXDUMP_DBG(codec->data[i].data.data, codec->data[i].data.data_len - - sizeof(codec->data[i].data.type), ""); + for (size_t i = 0; i < codec_cfg->data_count; i++) { + LOG_DBG("data #%zu: type 0x%02x len %u", i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + LOG_HEXDUMP_DBG(codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - + sizeof(codec_cfg->data[i].data.type), + ""); } - if (codec->id == BT_CODEC_LC3_ID) { + if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) { /* LC3 uses the generic LTV format - other codecs might do as well */ enum bt_audio_location chan_allocation; - LOG_DBG(" Frequency: %d Hz", bt_codec_cfg_get_freq(codec)); - LOG_DBG(" Frame Duration: %d us", bt_codec_cfg_get_frame_duration_us(codec)); - if (bt_codec_cfg_get_chan_allocation_val(codec, &chan_allocation) == 0) { + LOG_DBG(" Frequency: %d Hz", bt_audio_codec_cfg_get_freq(codec_cfg)); + LOG_DBG(" Frame Duration: %d us", + bt_audio_codec_cfg_get_frame_duration_us(codec_cfg)); + if (bt_audio_codec_cfg_get_chan_allocation_val(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_codec_cfg_get_octets_per_frame(codec)); + bt_audio_codec_cfg_get_octets_per_frame(codec_cfg)); LOG_DBG(" Frames per SDU: %d", - bt_codec_cfg_get_frame_blocks_per_sdu(codec, true)); + bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true)); + } + + for (size_t i = 0; i < codec_cfg->meta_count; i++) { + LOG_DBG("meta #%zu: type 0x%02x len %u", i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + LOG_HEXDUMP_DBG(codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - + sizeof(codec_cfg->meta[i].data.type), + ""); + } +} + +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_count); + + for (size_t i = 0; i < codec_cap->data_count; i++) { + LOG_DBG("data #%zu: type 0x%02x len %u", i, codec_cap->data[i].data.type, + codec_cap->data[i].data.data_len); + LOG_HEXDUMP_DBG(codec_cap->data[i].data.data, + codec_cap->data[i].data.data_len - + sizeof(codec_cap->data[i].data.type), + ""); } - for (size_t i = 0; i < codec->meta_count; i++) { - LOG_DBG("meta #%zu: type 0x%02x len %u", i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - LOG_HEXDUMP_DBG(codec->meta[i].data.data, codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type), ""); + for (size_t i = 0; i < codec_cap->meta_count; i++) { + LOG_DBG("meta #%zu: type 0x%02x len %u", i, codec_cap->meta[i].data.type, + codec_cap->meta[i].data.data_len); + LOG_HEXDUMP_DBG(codec_cap->meta[i].data.data, + codec_cap->meta[i].data.data_len - + sizeof(codec_cap->meta[i].data.type), + ""); } } -static inline void print_qos(const struct bt_codec_qos *qos) +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); @@ -196,7 +222,7 @@ static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t a tester_event(BTP_SERVICE_ID_ASCS, BTP_ASCS_EV_OPERATION_COMPLETED, &ev, sizeof(ev)); } -static int validate_codec_parameters(const struct bt_codec *codec) +static int validate_codec_parameters(const struct bt_audio_codec_cfg *codec_cfg) { int freq_hz; int frame_duration_us; @@ -205,11 +231,12 @@ static int validate_codec_parameters(const struct bt_codec *codec) int chan_allocation_err; enum bt_audio_location chan_allocation; - freq_hz = bt_codec_cfg_get_freq(codec); - frame_duration_us = bt_codec_cfg_get_frame_duration_us(codec); - chan_allocation_err = bt_codec_cfg_get_chan_allocation_val(codec, &chan_allocation); - octets_per_frame = bt_codec_cfg_get_octets_per_frame(codec); - frames_per_sdu = bt_codec_cfg_get_frame_blocks_per_sdu(codec, true); + freq_hz = bt_audio_codec_cfg_get_freq(codec_cfg); + frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(codec_cfg); + chan_allocation_err = + bt_audio_codec_cfg_get_chan_allocation_val(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); if (freq_hz < 0) { LOG_DBG("Error: Invalid codec frequency."); @@ -240,17 +267,17 @@ static int validate_codec_parameters(const struct bt_codec *codec) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); - if (validate_codec_parameters(codec)) { + if (validate_codec_parameters(codec_cfg)) { *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_REJECTED, BT_BAP_ASCS_REASON_CODEC_DATA); @@ -288,17 +315,17 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); return 0; } -static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +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); @@ -308,7 +335,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { LOG_DBG("Enable: stream %p meta_count %zu", stream, meta_count); @@ -370,14 +397,13 @@ static bool valid_metadata_type(uint8_t type, uint8_t len, const uint8_t *data) } } -static int lc3_metadata(struct bt_bap_stream *stream, - const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { LOG_DBG("Metadata: stream %p meta_count %zu", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = data = &meta[i]; + const struct bt_audio_codec_data *data = data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len, data->data.data)) { LOG_DBG("Invalid metadata type %u or length %u", @@ -455,7 +481,7 @@ static void btp_send_stream_received_ev(struct bt_conn *conn, struct bt_bap_ep * } static void stream_configured(struct bt_bap_stream *stream, - const struct bt_codec_qos_pref *pref) + 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); @@ -618,26 +644,27 @@ static void btp_send_discovery_completed_ev(struct bt_conn *conn, uint8_t status tester_event(BTP_SERVICE_ID_BAP, BTP_BAP_EV_DISCOVERY_COMPLETED, &ev, sizeof(ev)); } -static void btp_send_pac_codec_found_ev(struct bt_conn *conn, const struct bt_codec *codec, +static void btp_send_pac_codec_found_ev(struct bt_conn *conn, + const struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_dir dir) { struct btp_bap_codec_cap_found_ev ev; struct bt_conn_info info; - const struct bt_codec_data *data; + const struct bt_audio_codec_data *data; (void)bt_conn_get_info(conn, &info); bt_addr_le_copy(&ev.address, info.le.dst); ev.dir = dir; - ev.coding_format = codec->id; + ev.coding_format = codec_cfg->id; - bt_codec_get_val(codec, BT_CODEC_LC3_FREQ, &data); + bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_LC3_FREQ, &data); memcpy(&ev.frequencies, data->data.data, sizeof(ev.frequencies)); - bt_codec_get_val(codec, BT_CODEC_LC3_DURATION, &data); + bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_LC3_DURATION, &data); memcpy(&ev.frame_durations, data->data.data, sizeof(ev.frame_durations)); - bt_codec_get_val(codec, BT_CODEC_LC3_FRAME_LEN, &data); + bt_audio_codec_cfg_get_val(codec_cfg, BT_AUDIO_CODEC_LC3_FRAME_LEN, &data); memcpy(&ev.octets_per_frame, data->data.data, sizeof(ev.octets_per_frame)); bt_codec_get_val(codec, BT_CODEC_LC3_CHAN_COUNT, &data); @@ -724,14 +751,15 @@ static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code r 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_codec *codec) +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 != NULL) { - LOG_DBG("Discovered codec capabilities %p", codec); - print_codec(codec); - btp_send_pac_codec_found_ev(conn, codec, dir); + 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); } } @@ -1008,11 +1036,11 @@ static struct bt_conn_cb conn_callbacks = { }; static struct bt_pacs_cap cap_sink = { - .codec = &default_codec, + .codec_cap = &default_codec_cap, }; static struct bt_pacs_cap cap_source = { - .codec = &default_codec, + .codec_cap = &default_codec_cap, }; static uint8_t ascs_supported_commands(const void *cmd, uint16_t cmd_len, @@ -1029,17 +1057,18 @@ static uint8_t ascs_supported_commands(const void *cmd, uint16_t cmd_len, } static int server_stream_config(struct bt_conn *conn, struct bt_bap_stream *stream, - struct bt_codec *codec, struct bt_codec_qos_pref *qos) + 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, qos); + err = bt_bap_unicast_server_config_ase(conn, stream, codec_cfg, qos); if (err != 0) { return err; } - print_codec(&default_codec); + print_codec_cfg(&codec_cfg); ep = stream->ep; LOG_DBG("ASE Codec Config: ase_id %u dir %u", ep->status.id, ep->dir); @@ -1101,15 +1130,15 @@ static int client_create_unicast_group(struct audio_connection *audio_conn, uint static bool codec_config_store(struct bt_data *data, void *user_data) { - struct bt_codec *codec = user_data; - struct bt_codec_data *cdata; + struct bt_audio_codec_cfg *codec_cfg = user_data; + struct bt_audio_codec_data *cdata; - if (codec->data_count >= ARRAY_SIZE(codec->data)) { + if (codec_cfg->data_count >= ARRAY_SIZE(codec_cfg->data)) { LOG_ERR("No slot available for Codec Config"); return false; } - cdata = &codec->data[codec->data_count]; + cdata = &codec_cfg->data[codec_cfg->data_count]; if (data->data_len > sizeof(cdata->value)) { LOG_ERR("Not enough space for Codec Config: %u > %zu", data->data_len, @@ -1117,7 +1146,7 @@ static bool codec_config_store(struct bt_data *data, void *user_data) return false; } - LOG_DBG("#%u type 0x%02x len %u", codec->data_count, data->type, data->data_len); + LOG_DBG("#%u type 0x%02x len %u", codec_cfg->data_count, data->type, data->data_len); cdata->data.type = data->type; cdata->data.data_len = data->data_len; @@ -1128,7 +1157,7 @@ static bool codec_config_store(struct bt_data *data, void *user_data) LOG_HEXDUMP_DBG(cdata->value, data->data_len, "data"); - codec->data_count++; + codec_cfg->data_count++; return true; } @@ -1142,7 +1171,7 @@ static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len, struct bt_conn_info conn_info; struct audio_connection *audio_conn; struct audio_stream *stream; - struct bt_codec *codec; + struct bt_audio_codec_cfg *codec_cfg; struct bt_bap_ep *ep; struct net_buf_simple buf; @@ -1156,18 +1185,18 @@ static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len, (void)bt_conn_get_info(conn, &conn_info); - codec = &audio_conn->codec; - memset(codec, 0, sizeof(*codec)); + codec_cfg = &audio_conn->codec_cfg; + memset(codec_cfg, 0, sizeof(*codec_cfg)); - codec->id = cp->coding_format; - codec->vid = cp->vid; - codec->cid = cp->cid; + codec_cfg->id = cp->coding_format; + codec_cfg->vid = cp->vid; + codec_cfg->cid = cp->cid; if (cp->ltvs_len != 0) { net_buf_simple_init_with_data(&buf, (uint8_t *)cp->ltvs, cp->ltvs_len); /* Parse LTV entries */ - bt_data_parse(&buf, codec_config_store, codec); + bt_data_parse(&buf, codec_config_store, codec_cfg); /* Check if all entries could be parsed */ if (buf.len) { @@ -1205,13 +1234,13 @@ static uint8_t ascs_configure_codec(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } - err = bt_bap_stream_config(conn, &stream->stream, ep, codec); + err = bt_bap_stream_config(conn, &stream->stream, ep, codec_cfg); } else { - err = server_stream_config(conn, &stream->stream, codec, &qos_pref); + err = server_stream_config(conn, &stream->stream, codec_cfg, &qos_pref); } } else { /* Reconfigure a stream */ - err = bt_bap_stream_reconfig(&stream->stream, codec); + err = bt_bap_stream_reconfig(&stream->stream, codec_cfg); } bt_conn_unref(conn); @@ -1231,7 +1260,7 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, const struct btp_ascs_configure_qos_cmd *cp = cmd; struct bt_conn_info conn_info; struct audio_connection *audio_conn; - struct bt_codec_qos *qos; + struct bt_audio_codec_qos *qos; struct bt_conn *conn; conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); @@ -1262,7 +1291,7 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, } qos = &audio_conn->qos; - qos->phy = BT_CODEC_QOS_2M; + qos->phy = BT_AUDIO_CODEC_QOS_2M; qos->framing = cp->framing; qos->rtn = cp->retransmission_num; qos->sdu = cp->max_sdu; @@ -1464,7 +1493,7 @@ static uint8_t ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp const struct btp_ascs_update_metadata_cmd *cp = cmd; struct audio_connection *audio_conn; struct audio_stream *stream; - struct bt_codec_data meta; + struct bt_audio_codec_data meta; struct bt_conn *conn; conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &cp->address); diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index 4f9459c168e0..c70248cd5128 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -24,7 +24,7 @@ CONFIG_BT_ASCS_ASE_SNK_COUNT=2 CONFIG_BT_ASCS_ASE_SRC_COUNT=2 CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_BAP_BROADCAST_SINK=y -CONFIG_BT_CODEC_MAX_DATA_LEN=128 +CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN=128 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1 CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1 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 82cdab957980..af0e4272f076 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_sink_test.c @@ -26,13 +26,13 @@ CREATE_FLAG(flag_received); static struct bt_bap_broadcast_sink *g_sink; static struct bt_bap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)]; -static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_BROADCAST_PRESET_16_2_1( +static struct bt_audio_codec_cap codec_cap_16_2_1 = BT_AUDIO_CODEC_LC3_CONFIG_16_2( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); static K_SEM_DEFINE(sem_started, 0U, ARRAY_SIZE(streams)); static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams)); -static struct bt_codec_data metadata[CONFIG_BT_CODEC_MAX_METADATA_COUNT]; +static struct bt_audio_codec_data metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT]; /* 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 @@ -81,11 +81,11 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap if (TEST_FLAG(base_received)) { if (base->subgroup_count > 0 && - memcmp(metadata, base->subgroups[0].codec.meta, - sizeof(base->subgroups[0].codec.meta)) != 0) { + memcmp(metadata, base->subgroups[0].codec_cfg.meta, + sizeof(base->subgroups[0].codec_cfg.meta)) != 0) { - (void)memcpy(metadata, base->subgroups[0].codec.meta, - sizeof(base->subgroups[0].codec.meta)); + (void)memcpy(metadata, base->subgroups[0].codec_cfg.meta, + sizeof(base->subgroups[0].codec_cfg.meta)); SET_FLAG(flag_base_metadata_updated); } @@ -145,7 +145,7 @@ static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { }; static struct bt_pacs_cap cap = { - .codec = &preset_16_2_1.codec, + .codec_cap = &codec_cap_16_2_1, }; static void started_cb(struct bt_bap_stream *stream) 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 421093695477..4d5edf1a05b7 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -99,8 +99,8 @@ static struct bt_bap_stream_ops stream_ops = { static int setup_broadcast_source(struct bt_bap_broadcast_source **source) { - struct bt_codec_data bis_codec_data = BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, - BT_CODEC_CONFIG_LC3_FREQ_16KHZ); + struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ); struct bt_bap_broadcast_source_stream_param stream_params[ARRAY_SIZE(broadcast_source_streams)]; struct bt_bap_broadcast_source_subgroup_param @@ -122,7 +122,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 = &stream_params[i]; - subgroup_params[i].codec = &preset_16_2_1.codec; + subgroup_params[i].codec_cfg = &preset_16_2_1.codec_cfg; } create_param.params_count = ARRAY_SIZE(subgroup_params); @@ -246,8 +246,8 @@ static int stop_extended_adv(struct bt_le_ext_adv *adv) static void test_main(void) { - struct bt_codec_data new_metadata[1] = - BT_CODEC_LC3_CONFIG_META(BT_AUDIO_CONTEXT_TYPE_ALERTS); + struct bt_audio_codec_data new_metadata[1] = + BT_AUDIO_CODEC_LC3_CONFIG_META(BT_AUDIO_CONTEXT_TYPE_ALERTS); struct bt_bap_broadcast_source *source; struct bt_le_ext_adv *adv; int err; @@ -273,7 +273,8 @@ static void test_main(void) } printk("Reconfiguring broadcast source\n"); - err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec, &preset_16_2_1.qos); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, + &preset_16_2_1.qos); if (err != 0) { FAIL("Unable to reconfigure broadcast source: %d\n", err); return; 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 275379087e19..53c816d5e18e 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_client_test.c @@ -32,7 +32,7 @@ static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1 CREATE_FLAG(flag_mtu_exchanged); CREATE_FLAG(flag_sink_discovered); CREATE_FLAG(flag_source_discovered); -CREATE_FLAG(flag_codec_found); +CREATE_FLAG(flag_codec_cap_found); CREATE_FLAG(flag_endpoint_found); CREATE_FLAG(flag_stream_codec_configured); static atomic_t flag_stream_qos_configured; @@ -43,7 +43,7 @@ CREATE_FLAG(flag_stream_released); CREATE_FLAG(flag_operation_success); static void stream_configured(struct bt_bap_stream *stream, - const struct bt_codec_qos_pref *pref) + const struct bt_audio_codec_qos_pref *pref) { printk("Configured stream %p\n", stream); @@ -231,11 +231,12 @@ static void add_remote_source(struct bt_bap_ep *ep) FAIL("Could not add source ep\n"); } -static void print_remote_codec(const struct bt_codec *codec, enum bt_audio_dir dir) +static void print_remote_codec_cap(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_dir dir) { - printk("codec %p dir 0x%02x\n", codec, dir); + printk("codec %p dir 0x%02x\n", codec_cap, dir); - print_codec(codec); + print_codec_cap(codec_cap); } static void discover_sinks_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) @@ -262,10 +263,11 @@ static void discover_sources_cb(struct bt_conn *conn, int err, enum bt_audio_dir SET_FLAG(flag_source_discovered); } -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) { - print_remote_codec(codec, dir); - SET_FLAG(flag_codec_found); + print_remote_codec_cap(codec_cap, dir); + SET_FLAG(flag_codec_cap_found); } static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep) @@ -352,7 +354,7 @@ static void discover_sinks(void) unicast_client_cbs.discover = discover_sinks_cb; - UNSET_FLAG(flag_codec_found); + UNSET_FLAG(flag_codec_cap_found); UNSET_FLAG(flag_sink_discovered); UNSET_FLAG(flag_endpoint_found); @@ -364,7 +366,7 @@ static void discover_sinks(void) memset(g_sinks, 0, sizeof(g_sinks)); - WAIT_FOR_FLAG(flag_codec_found); + WAIT_FOR_FLAG(flag_codec_cap_found); WAIT_FOR_FLAG(flag_endpoint_found); WAIT_FOR_FLAG(flag_sink_discovered); } @@ -375,7 +377,7 @@ static void discover_sources(void) unicast_client_cbs.discover = discover_sources_cb; - UNSET_FLAG(flag_codec_found); + UNSET_FLAG(flag_codec_cap_found); UNSET_FLAG(flag_source_discovered); err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SOURCE); @@ -386,7 +388,7 @@ static void discover_sources(void) memset(g_sources, 0, sizeof(g_sources)); - WAIT_FOR_FLAG(flag_codec_found); + WAIT_FOR_FLAG(flag_codec_cap_found); WAIT_FOR_FLAG(flag_source_discovered); } @@ -399,7 +401,7 @@ static int codec_configure_stream(struct bt_bap_stream *stream, struct bt_bap_ep do { - err = bt_bap_stream_config(default_conn, stream, ep, &preset_16_2_1.codec); + err = bt_bap_stream_config(default_conn, stream, ep, &preset_16_2_1.codec_cfg); if (err == -EBUSY) { k_sleep(BAP_STREAM_RETRY_WAIT); } else if (err != 0) { @@ -499,7 +501,7 @@ static void enable_streams(size_t stream_cnt) static int metadata_update_stream(struct bt_bap_stream *stream) { - struct bt_codec_data new_meta = BT_CODEC_DATA( + struct bt_audio_codec_data new_meta = BT_AUDIO_CODEC_DATA( BT_AUDIO_METADATA_TYPE_VENDOR, 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, diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_common.c b/tests/bsim/bluetooth/audio/src/bap_unicast_common.c index c335a1929fb4..8da762058423 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_common.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_common.c @@ -14,33 +14,55 @@ void print_hex(const uint8_t *ptr, size_t len) } } -void print_codec(const struct bt_codec *codec) +void print_codec_cap(const struct bt_audio_codec_cap *codec_cap) { - printk("codec 0x%02x cid 0x%04x vid 0x%04x count %u\n", - codec->id, codec->cid, codec->vid, codec->data_count); + printk("codec_cfg ID 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cap->id, + codec_cap->cid, codec_cap->vid, codec_cap->data_count); - for (uint8_t i = 0; i < codec->data_count; i++) { + for (uint8_t i = 0; i < codec_cap->data_count; i++) { + printk("data #%u: type 0x%02x len %u\n", i, codec_cap->data[i].data.type, + codec_cap->data[i].data.data_len); + print_hex(codec_cap->data[i].data.data, + codec_cap->data[i].data.data_len - sizeof(codec_cap->data[i].data.type)); + printk("\n"); + } + + for (uint8_t i = 0; i < codec_cap->meta_count; i++) { + printk("meta #%u: type 0x%02x len %u\n", i, codec_cap->meta[i].data.type, + codec_cap->meta[i].data.data_len); + print_hex(codec_cap->meta[i].data.data, + codec_cap->meta[i].data.data_len - sizeof(codec_cap->meta[i].data.type)); + printk("\n"); + } +} + +void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg) +{ + printk("codec_cap ID 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, + codec_cfg->cid, codec_cfg->vid, codec_cfg->data_count); + + for (uint8_t i = 0; i < codec_cfg->data_count; i++) { printk("data #%u: type 0x%02x len %u\n", - i, codec->data[i].data.type, - codec->data[i].data.data_len); - print_hex(codec->data[i].data.data, - codec->data[i].data.data_len - - sizeof(codec->data[i].data.type)); + i, codec_cfg->data[i].data.type, + codec_cfg->data[i].data.data_len); + print_hex(codec_cfg->data[i].data.data, + codec_cfg->data[i].data.data_len - + sizeof(codec_cfg->data[i].data.type)); printk("\n"); } - for (uint8_t i = 0; i < codec->meta_count; i++) { + for (uint8_t i = 0; i < codec_cfg->meta_count; i++) { printk("meta #%u: type 0x%02x len %u\n", - i, codec->meta[i].data.type, - codec->meta[i].data.data_len); - print_hex(codec->meta[i].data.data, - codec->meta[i].data.data_len - - sizeof(codec->meta[i].data.type)); + i, codec_cfg->meta[i].data.type, + codec_cfg->meta[i].data.data_len); + print_hex(codec_cfg->meta[i].data.data, + codec_cfg->meta[i].data.data_len - + sizeof(codec_cfg->meta[i].data.type)); printk("\n"); } } -void print_qos(const struct bt_codec_qos *qos) +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", diff --git a/tests/bsim/bluetooth/audio/src/bap_unicast_common.h b/tests/bsim/bluetooth/audio/src/bap_unicast_common.h index acc8ccd96345..86edcb57677f 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_common.h +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_common.h @@ -13,7 +13,8 @@ #include void print_hex(const uint8_t *ptr, size_t len); -void print_codec(const struct bt_codec *codec); -void print_qos(const struct bt_codec_qos *qos); +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 b98b345e7be1..dce4d5a1e4a4 100644 --- a/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_unicast_server_test.c @@ -20,52 +20,49 @@ extern enum bst_result_t bst_result; #define PREF_CONTEXT \ (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA) -static struct bt_codec lc3_codec = { +static struct bt_audio_codec_cap lc3_codec_cap = { .path_id = BT_ISO_DATA_PATH_HCI, - .id = BT_CODEC_LC3_ID, + .id = BT_AUDIO_CODEC_LC3_ID, .cid = 0x0000U, .vid = 0x0000U, .data_count = 5U, .data = { - BT_CODEC_DATA(BT_CODEC_LC3_FREQ, - (BT_CODEC_LC3_FREQ_16KHZ & 0xFFU), - ((BT_CODEC_LC3_FREQ_16KHZ >> 8) & 0xFFU)), - BT_CODEC_DATA(BT_CODEC_LC3_DURATION, BT_CODEC_LC3_DURATION_10), - BT_CODEC_DATA(BT_CODEC_LC3_CHAN_COUNT, CHANNEL_COUNT_1), - BT_CODEC_DATA(BT_CODEC_LC3_FRAME_LEN, - (40U & 0xFFU), ((40U >> 8) & 0xFFU), - (40U & 0xFFU), ((40U >> 8) & 0xFFU)), - BT_CODEC_DATA(BT_CODEC_LC3_FRAME_COUNT, 1U) - }, + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FREQ, + BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_LC3_FREQ_16KHZ)), + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_DURATION, + BT_AUDIO_CODEC_LC3_DURATION_10), + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_CHAN_COUNT, CHANNEL_COUNT_1), + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_LEN, BT_BYTES_LIST_LE32(40U)), + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_LC3_FRAME_COUNT, 1U), + }, .meta_count = 2, .meta = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, - (PREF_CONTEXT & 0xFFU), - ((PREF_CONTEXT >> 8) & 0xFFU)), - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, - 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) - } + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, + BT_BYTES_LIST_LE32(PREF_CONTEXT)), + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, + 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), + }, }; static struct bt_bap_stream streams[CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT]; -static const struct bt_codec_qos_pref qos_pref = - BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000); +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); /* TODO: Expand with BAP data */ static const struct bt_data unicast_server_ad[] = { @@ -97,12 +94,12 @@ static struct bt_bap_stream *stream_alloc(void) } static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *stream = stream_alloc(); if (*stream == NULL) { @@ -123,19 +120,19 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_ } static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, struct bt_codec_qos_pref *const pref, - struct bt_bap_ascs_rsp *rsp) + 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(codec); + print_codec_cfg(codec_cfg); *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 lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +static int lc3_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); @@ -145,7 +142,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, return 0; } -static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Enable: stream %p meta_count %zu\n", stream, meta_count); @@ -199,13 +196,13 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, +static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta, size_t meta_count, struct bt_bap_ascs_rsp *rsp) { printk("Metadata: stream %p meta_count %zu\n", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { printk("Invalid metadata type %u or length %u\n", data->data.type, @@ -290,7 +287,7 @@ static struct bt_bap_stream_ops stream_ops = { static void init(void) { static struct bt_pacs_cap cap = { - .codec = &lc3_codec, + .codec_cap = &lc3_codec_cap, }; int err; diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 12632e216e5f..4b15da29299a 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -29,15 +29,11 @@ CREATE_FLAG(flag_pa_sync_lost); static struct bt_bap_broadcast_sink *g_broadcast_sink; static struct bt_cap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; -static struct bt_bap_lc3_preset unicast_preset_16_2_1 = - BT_BAP_LC3_UNICAST_PRESET_16_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, - SINK_CONTEXT); -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_UNSPECIFIED); +static struct bt_audio_codec_cap codec_cap_16_2_1 = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); -static const struct bt_codec_qos_pref unicast_qos_pref = - BT_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u); +static const struct bt_audio_codec_qos_pref unicast_qos_pref = + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u); static bool auto_start_sink_streams; @@ -95,8 +91,8 @@ static bool valid_subgroup_metadata(const struct bt_bap_base_subgroup *subgroup) { bool stream_context_found = false; - for (size_t j = 0U; j < subgroup->codec.meta_count; j++) { - const struct bt_data *metadata = &subgroup->codec.meta[j].data; + for (size_t j = 0U; j < subgroup->codec_cfg.meta_count; j++) { + const struct bt_data *metadata = &subgroup->codec_cfg.meta[j].data; if (metadata->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { if (metadata->data_len != 2) { /* Stream context size */ @@ -257,14 +253,14 @@ static struct bt_bap_stream *unicast_stream_alloc(void) } static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *ep, - enum bt_audio_dir dir, const struct bt_codec *codec, + enum bt_audio_dir dir, const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream, - struct bt_codec_qos_pref *const pref, + 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(codec); + print_codec_cfg(codec_cfg); *stream = unicast_stream_alloc(); if (*stream == NULL) { @@ -284,13 +280,13 @@ static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *e } static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir, - const struct bt_codec *codec, - struct bt_codec_qos_pref *const pref, + 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(codec); + print_codec_cfg(codec_cfg); *pref = unicast_qos_pref; @@ -300,7 +296,7 @@ static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_d return -ENOEXEC; } -static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos, +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); @@ -310,8 +306,9 @@ static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_code return 0; } -static int unicast_server_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta, - size_t meta_count, struct bt_bap_ascs_rsp *rsp) +static int unicast_server_enable(struct bt_bap_stream *stream, + const struct bt_audio_codec_data *meta, size_t meta_count, + struct bt_bap_ascs_rsp *rsp) { printk("Enable: stream %p meta_count %zu\n", stream, meta_count); @@ -364,13 +361,14 @@ static bool valid_metadata_type(uint8_t type, uint8_t len) } } -static int unicast_server_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta, - size_t meta_count, struct bt_bap_ascs_rsp *rsp) +static int unicast_server_metadata(struct bt_bap_stream *stream, + const struct bt_audio_codec_data *meta, size_t meta_count, + struct bt_bap_ascs_rsp *rsp) { printk("Metadata: stream %p meta_count %zu\n", stream, meta_count); for (size_t i = 0; i < meta_count; i++) { - const struct bt_codec_data *data = &meta[i]; + const struct bt_audio_codec_data *data = &meta[i]; if (!valid_metadata_type(data->data.type, data->data.data_len)) { printk("Invalid metadata type %u or length %u\n", data->data.type, @@ -522,7 +520,7 @@ static void init(void) if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) { static struct bt_pacs_cap unicast_cap = { - .codec = &unicast_preset_16_2_1.codec, + .codec_cap = &codec_cap_16_2_1, }; err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &unicast_cap); @@ -555,7 +553,7 @@ static void init(void) if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) { static struct bt_pacs_cap broadcast_cap = { - .codec = &broadcast_preset_16_2_1.codec, + .codec_cap = &codec_cap_16_2_1, }; err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &broadcast_cap); 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 d28bd4a88261..a2305b9d2638 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_broadcast_test.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "common.h" #define BROADCAST_STREMT_CNT CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT @@ -224,15 +225,15 @@ static void stop_and_delete_extended_adv(struct bt_le_ext_adv *adv) static void test_broadcast_audio_create_inval(void) { - struct bt_codec_data bis_codec_data = - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); + struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ); struct bt_cap_initiator_broadcast_stream_param stream_params[ARRAY_SIZE(broadcast_source_streams)]; 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_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + struct bt_audio_codec_cfg invalid_codec = BT_AUDIO_CODEC_LC3_CONFIG_16_2( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); int err; for (size_t i = 0U; i < ARRAY_SIZE(broadcast_streams); i++) { @@ -243,7 +244,7 @@ static void test_broadcast_audio_create_inval(void) subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); subgroup_param.stream_params = stream_params; - subgroup_param.codec = &broadcast_preset_16_2_1.codec; + subgroup_param.codec_cfg = &broadcast_preset_16_2_1.codec_cfg; create_param.subgroup_count = 1U; create_param.subgroup_params = &subgroup_param; @@ -267,7 +268,7 @@ static void test_broadcast_audio_create_inval(void) /* Clear metadata so that it does not contain the mandatory stream context */ memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - subgroup_param.codec = &invalid_codec; + subgroup_param.codec_cfg = &invalid_codec; err = bt_cap_initiator_broadcast_audio_create(&create_param, NULL); if (err == 0) { FAIL("bt_cap_initiator_broadcast_audio_create with invalid metadata did not " @@ -282,8 +283,8 @@ static void test_broadcast_audio_create_inval(void) static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadcast_source) { - struct bt_codec_data bis_codec_data = - BT_CODEC_DATA(BT_CODEC_CONFIG_LC3_FREQ, BT_CODEC_CONFIG_LC3_FREQ_16KHZ); + struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ); struct bt_cap_initiator_broadcast_stream_param stream_params[ARRAY_SIZE(broadcast_source_streams)]; struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; @@ -298,7 +299,7 @@ static void test_broadcast_audio_create(struct bt_cap_broadcast_source **broadca subgroup_param.stream_count = ARRAY_SIZE(broadcast_streams); subgroup_param.stream_params = stream_params; - subgroup_param.codec = &broadcast_preset_16_2_1.codec; + subgroup_param.codec_cfg = &broadcast_preset_16_2_1.codec_cfg; create_param.subgroup_count = 1U; create_param.subgroup_params = &subgroup_param; @@ -357,16 +358,16 @@ static void test_broadcast_audio_start(struct bt_cap_broadcast_source *broadcast static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *broadcast_source) { const uint16_t mock_ccid = 0x1234; - const struct bt_codec_data new_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), - ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), - ((mock_ccid >> 8) & 0xFFU)), + const struct bt_audio_codec_data new_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), + ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), + ((mock_ccid >> 8) & 0xFFU)), }; - const struct bt_codec_data invalid_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), - ((mock_ccid >> 8) & 0xFFU)), + const struct bt_audio_codec_data invalid_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, (mock_ccid & 0xFFU), + ((mock_ccid >> 8) & 0xFFU)), }; int err; @@ -407,10 +408,11 @@ static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *br static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source) { const uint16_t mock_ccid = 0x1234; - const struct bt_codec_data new_metadata[] = { - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), - BT_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, BT_BYTES_LIST_LE16(mock_ccid)), + const struct bt_audio_codec_data 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, + BT_BYTES_LIST_LE16(mock_ccid)), }; int 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 39ae4d672b22..a3f17800112e 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -33,7 +33,7 @@ CREATE_FLAG(flag_mtu_exchanged); CREATE_FLAG(flag_sink_discovered); static void unicast_stream_configured(struct bt_bap_stream *stream, - const struct bt_codec_qos_pref *pref) + const struct bt_audio_codec_qos_pref *pref) { printk("Configured stream %p\n", stream); @@ -167,16 +167,17 @@ static void add_remote_sink(struct bt_bap_ep *ep) FAIL("Could not add source ep\n"); } -static void print_remote_codec(const struct bt_codec *codec, enum bt_audio_dir dir) +static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum bt_audio_dir dir) { - printk("codec %p dir 0x%02x\n", codec, dir); + printk("codec_cap %p dir 0x%02x\n", codec_cap, dir); - print_codec(codec); + print_codec_cap(codec_cap); } -static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, const struct bt_codec *codec) +static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, + const struct bt_audio_codec_cap *codec_cap) { - print_remote_codec(codec, dir); + print_remote_codec(codec_cap, dir); SET_FLAG(flag_codec_found); } @@ -351,8 +352,8 @@ static void unicast_group_create(struct bt_bap_unicast_group **out_unicast_group static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group) { - struct bt_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + 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_start_stream_param invalid_stream_param; struct bt_cap_unicast_audio_start_stream_param valid_stream_param; struct bt_cap_unicast_audio_start_param invalid_start_param; @@ -366,7 +367,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group valid_stream_param.member.member = default_conn; valid_stream_param.stream = &unicast_client_streams[0]; valid_stream_param.ep = unicast_sink_eps[0]; - valid_stream_param.codec = &unicast_preset_16_2_1.codec; + valid_stream_param.codec_cfg = &unicast_preset_16_2_1.codec_cfg; valid_stream_param.qos = &unicast_preset_16_2_1.qos; /* Test NULL parameters */ @@ -439,7 +440,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 = NULL; + invalid_stream_param.codec_cfg = NULL; err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with NULL stream params codec did not " @@ -461,7 +462,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)); memset(&invalid_codec.meta, 0, sizeof(invalid_codec.meta)); - invalid_stream_param.codec = &invalid_codec; + invalid_stream_param.codec_cfg = &invalid_codec; err = bt_cap_initiator_unicast_audio_start(&invalid_start_param, unicast_group); if (err == 0) { FAIL("bt_cap_initiator_unicast_audio_start with invalid Codec metadata did not " @@ -482,7 +483,7 @@ static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group, bool stream_param[0].member.member = default_conn; stream_param[0].stream = &unicast_client_streams[0]; stream_param[0].ep = unicast_sink_eps[0]; - stream_param[0].codec = &unicast_preset_16_2_1.codec; + stream_param[0].codec_cfg = &unicast_preset_16_2_1.codec_cfg; stream_param[0].qos = &unicast_preset_16_2_1.qos; UNSET_FLAG(flag_started); @@ -500,14 +501,14 @@ static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group, bool static void unicast_audio_update_inval(void) { - struct bt_codec invalid_codec = - BT_CODEC_LC3_CONFIG_16_2(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA); + 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; int err; param.stream = &unicast_client_streams[0]; - param.meta = unicast_preset_16_2_1.codec.meta; - param.meta_count = unicast_preset_16_2_1.codec.meta_count; + param.meta = unicast_preset_16_2_1.codec_cfg.meta; + param.meta_count = unicast_preset_16_2_1.codec_cfg.meta_count; err = bt_cap_initiator_unicast_audio_update(NULL, 1); if (err == 0) { @@ -539,8 +540,8 @@ static void unicast_audio_update(void) int err; param.stream = &unicast_client_streams[0]; - param.meta = unicast_preset_16_2_1.codec.meta; - param.meta_count = unicast_preset_16_2_1.codec.meta_count; + param.meta = unicast_preset_16_2_1.codec_cfg.meta; + param.meta_count = unicast_preset_16_2_1.codec_cfg.meta_count; UNSET_FLAG(flag_updated); From 7d5eea869d6ba888d00b90a9912cdab16ed82ae5 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 29 Jun 2023 13:57:28 +0200 Subject: [PATCH 0747/2042] drivers gpio_nrfx: Get peripheral address from HAL Instead of getting the hardcoded address from the DT structure use its symbolic name (Also from DT) which will be resolved by the nRF HAL definitions. This allows the GPIO peripherals' addresses to be redefined for the simulated targets. Signed-off-by: Alberto Escolar Piedras --- drivers/gpio/gpio_nrfx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 47657d3eda3c..41a1ade7b619 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -406,7 +406,7 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { .port_pin_mask = \ GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \ }, \ - .port = (NRF_GPIO_Type *)DT_INST_REG_ADDR(id), \ + .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) \ }; \ From 9445ca017cbbc0a164ab3059de291ada4b9f726c Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 30 Jun 2023 09:38:17 +0200 Subject: [PATCH 0748/2042] drivers gpio_nrfx: Don't use directly CMSIS instrunction intrinsic To ease building for workstation tests, instead of using the ARM CMSIS instructions instrinsics directly, use the NRFX macro that uses the compiler builtins when necessary. Signed-off-by: Alberto Escolar Piedras --- drivers/gpio/gpio_nrfx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 41a1ade7b619..35e901b152e1 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -303,7 +303,7 @@ static int gpio_nrfx_port_get_direction(const struct device *port, if (inputs != NULL) { while (map) { - uint32_t pin = __CLZ(__RBIT(map)); + uint32_t pin = NRF_CTZ(map); uint32_t pin_cnf = reg->PIN_CNF[pin]; /* Check if the pin has its input buffer connected. */ From cf0ff30b530a9897c34fb5106c2716d3c13945d6 Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Fri, 30 Jun 2023 14:36:44 +0530 Subject: [PATCH 0749/2042] bluetooth: ots: Fix bt_ots_init paramter struct naming Patch to rename struct bt_ots_init to struct bt_ots_init_param to avoid duplicating the name bt_ots_init. Fix for issue#45968 Signed-off-by: Jai Arora --- include/zephyr/bluetooth/services/ots.h | 4 ++-- samples/bluetooth/peripheral_ots/src/main.c | 2 +- subsys/bluetooth/audio/mcs.c | 2 +- subsys/bluetooth/services/ots/ots.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/zephyr/bluetooth/services/ots.h b/include/zephyr/bluetooth/services/ots.h index 5e0c73682e08..716053623742 100644 --- a/include/zephyr/bluetooth/services/ots.h +++ b/include/zephyr/bluetooth/services/ots.h @@ -749,7 +749,7 @@ struct bt_ots_cb { }; /** @brief Descriptor for OTS initialization. */ -struct bt_ots_init { +struct bt_ots_init_param { /* OTS features */ struct bt_ots_feat features; @@ -803,7 +803,7 @@ void *bt_ots_svc_decl_get(struct bt_ots *ots); * * @return 0 in case of success or negative value in case of error. */ -int bt_ots_init(struct bt_ots *ots, struct bt_ots_init *ots_init); +int bt_ots_init(struct bt_ots *ots, struct bt_ots_init_param *ots_init); /** @brief Get a free instance of OTS from the pool. * diff --git a/samples/bluetooth/peripheral_ots/src/main.c b/samples/bluetooth/peripheral_ots/src/main.c index 24597c9c76c9..50f9fc4de71c 100644 --- a/samples/bluetooth/peripheral_ots/src/main.c +++ b/samples/bluetooth/peripheral_ots/src/main.c @@ -223,7 +223,7 @@ static int ots_init(void) int err; struct bt_ots *ots; struct object_creation_data obj_data; - struct bt_ots_init ots_init; + struct bt_ots_init_param ots_init; struct bt_ots_obj_add_param param; const char * const first_object_name = "first_object.txt"; const char * const second_object_name = "second_object.gif"; diff --git a/subsys/bluetooth/audio/mcs.c b/subsys/bluetooth/audio/mcs.c index 04486215c496..3d31af7a828b 100644 --- a/subsys/bluetooth/audio/mcs.c +++ b/subsys/bluetooth/audio/mcs.c @@ -1348,7 +1348,7 @@ int bt_mcs_init(struct bt_ots_cb *ots_cbs) mcs = (struct bt_gatt_service)BT_GATT_SERVICE(svc_attrs); #ifdef CONFIG_BT_OTS - struct bt_ots_init ots_init; + struct bt_ots_init_param ots_init; ots = bt_ots_free_instance_get(); if (!ots) { diff --git a/subsys/bluetooth/services/ots/ots.c b/subsys/bluetooth/services/ots/ots.c index 744a2c224e36..f054b9a5e59d 100644 --- a/subsys/bluetooth/services/ots/ots.c +++ b/subsys/bluetooth/services/ots/ots.c @@ -443,7 +443,7 @@ void *bt_ots_svc_decl_get(struct bt_ots *ots) #endif int bt_ots_init(struct bt_ots *ots, - struct bt_ots_init *ots_init) + struct bt_ots_init_param *ots_init) { int err; From ac95e57bbea498aceb73712be3a15d0989fe0385 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 30 Jun 2023 10:03:12 +0100 Subject: [PATCH 0750/2042] modules: hal_nordic: nrf_802154: Make paths relative Makes the files listed in the cmake file relative as they do not need to be absolute paths. Signed-off-by: Jamie McCrae --- modules/hal_nordic/nrf_802154/CMakeLists.txt | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index 1ec8afbfdfb9..e2b42cff8c53 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -7,12 +7,12 @@ zephyr_interface_library_named(zephyr-802154-interface) if (CONFIG_NRF_802154_RADIO_DRIVER) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/radio/platform/nrf_802154_random_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_gpiote_crit_sect.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_clock_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_gpiote_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_irq_zephyr.c - ${CMAKE_CURRENT_SOURCE_DIR}/sl_opensource/platform/nrf_802154_temperature_zephyr.c + radio/platform/nrf_802154_random_zephyr.c + sl_opensource/platform/nrf_802154_gpiote_crit_sect.c + sl_opensource/platform/nrf_802154_clock_zephyr.c + sl_opensource/platform/nrf_802154_gpiote_zephyr.c + sl_opensource/platform/nrf_802154_irq_zephyr.c + sl_opensource/platform/nrf_802154_temperature_zephyr.c ) target_compile_definitions(zephyr-802154-interface @@ -37,17 +37,17 @@ endif () if (CONFIG_NRF_802154_SERIALIZATION) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_serialization_crit_sect.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_log.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_backend_ipc.c - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_spinel_response_notifier.c + serialization/platform/nrf_802154_serialization_crit_sect.c + serialization/platform/nrf_802154_spinel_log.c + serialization/platform/nrf_802154_spinel_backend_ipc.c + serialization/platform/nrf_802154_spinel_response_notifier.c ) endif () if (CONFIG_NRF_802154_SER_RADIO) target_sources(nrf-802154-platform PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/serialization/platform/nrf_802154_init_net.c + serialization/platform/nrf_802154_init_net.c ) endif () From 5fa5534afc9a4a9de0869d616e02b5ecfb101c75 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 28 Jun 2023 23:17:45 +0200 Subject: [PATCH 0751/2042] doc: kernel: clocks: define "current time" Scheduling relative timeouts from within timer callbacks (=sys clock ISR context) differs from scheduling relative timeouts from an application context. This change documents and explains the rationale of this distinction. Signed-off-by: Florian Grandel --- doc/kernel/services/timing/clocks.rst | 20 +++++++++++++++++--- kernel/timeout.c | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/doc/kernel/services/timing/clocks.rst b/doc/kernel/services/timing/clocks.rst index 901fe88477d9..3a016b3f3516 100644 --- a/doc/kernel/services/timing/clocks.rst +++ b/doc/kernel/services/timing/clocks.rst @@ -100,9 +100,23 @@ For example: All these values are specified using a :c:struct:`k_timeout_t` value. This is an opaque struct type that must be initialized using one of a family -of kernel timeout macros. The most common, :c:macro:`K_MSEC` , defines -a time in milliseconds after the current time (strictly: the time at -which the kernel receives the timeout value). +of kernel timeout macros. The most common, :c:macro:`K_MSEC`, defines +a time in milliseconds after the current time. + +What is meant by "current time" for relative timeouts depends on the context: + +* When scheduling a relative timeout from within a timeout callback (e.g. from + within the expiry function passed to :c:func:`k_timer_init` or the work handler + passed to :c:func:`k_work_init_delayable`), "current time" is the exact time at + which the currently firing timeout was originally scheduled even if the "real + time" will already have advanced. This is to ensure that timers scheduled from + within another timer's callback will always be calculated with a precise offset + to the firing timer. It is thereby possible to fire at regular intervals without + introducing systematic clock drift over time. + +* When scheduling a timeout from application context, "current time" means the + value returned by :c:func:`k_uptime_ticks` at the time at which the kernel + receives the timeout value. Other options for timeout initialization follow the unit conventions described above: :c:macro:`K_NSEC()`, :c:macro:`K_USEC`, :c:macro:`K_TICKS` and diff --git a/kernel/timeout.c b/kernel/timeout.c index f5daf8222596..a539fb5d6701 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -21,7 +21,7 @@ static struct k_spinlock timeout_lock; #define MAX_WAIT (IS_ENABLED(CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE) \ ? K_TICKS_FOREVER : INT_MAX) -/* Cycles left to process in the currently-executing sys_clock_announce() */ +/* Ticks left to process in the currently-executing sys_clock_announce() */ static int announce_remaining; #if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) @@ -61,6 +61,22 @@ static void remove_timeout(struct _timeout *t) static int32_t elapsed(void) { + /* While sys_clock_announce() is executing, new relative timeouts will be + * scheduled relatively to the currently firing timeout's original tick + * value (=curr_tick) rather than relative to the current + * sys_clock_elapsed(). + * + * This means that timeouts being scheduled from within timeout callbacks + * will be scheduled at well-defined offsets from the currently firing + * timeout. + * + * As a side effect, the same will happen if an ISR with higher priority + * preempts a timeout callback and schedules a timeout. + * + * The distinction is implemented by looking at announce_remaining which + * will be non-zero while sys_clock_announce() is executing and zero + * otherwise. + */ return announce_remaining == 0 ? sys_clock_elapsed() : 0U; } From 03b49422094f9a04a80c5eb5f39c823857a16128 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 28 Jun 2023 23:20:50 +0200 Subject: [PATCH 0752/2042] doc: drivers: system timer: unique documentation header Without enough context, the "clock" term is underspecified in Zephyr. This change renames "Clock API" to "System Clock API" as both the functions as well as the remaining documentation calls the clock being documented here this way. This tries to ensure that people landing on this API from context free search will be less confused. Signed-off-by: Florian Grandel --- include/zephyr/drivers/timer/system_timer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/timer/system_timer.h b/include/zephyr/drivers/timer/system_timer.h index 52af7495e465..654df3874599 100644 --- a/include/zephyr/drivers/timer/system_timer.h +++ b/include/zephyr/drivers/timer/system_timer.h @@ -23,8 +23,8 @@ extern "C" { #endif /** - * @brief Clock APIs - * @defgroup clock_apis Clock APIs + * @brief System Clock APIs + * @defgroup clock_apis System Clock APIs * @{ */ From e61ac7711945d42a14f480df1f76433ee881963c Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 29 Jun 2023 12:11:12 +0200 Subject: [PATCH 0753/2042] Bluetooth: Shell: Restore missing `bt_addr_le_to_str` in `scan_recv` This restores a line of code that was accidentally deleted in 5580cb439188f4a5a1804127e474c8a872393fe2. This fixes an uninitialized `le_addr` getting printed and producing garbage output in the scan results. Signed-off-by: Aleksander Wasaznik --- subsys/bluetooth/shell/bt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 76d836e9bc3e..ed0e4a2739f7 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -408,6 +408,7 @@ static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_si (void)memset(name, 0, sizeof(name)); bt_data_parse(buf, data_cb, name); + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); shell_print(ctx_shell, "%s%s, AD evt type %u, RSSI %i %s " "C:%u S:%u D:%d SR:%u E:%u Prim: %s, Secn: %s, " From db8bb73eae4989610cc1b744bc37d19d7e822730 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 28 Jun 2023 13:00:58 +0200 Subject: [PATCH 0754/2042] samples: Bluetooth: Add CAP AD for TMAP peripheral The TMAP peripheral sample was missing the CAP announcement service data. Signed-off-by: Emil Gydesen --- samples/bluetooth/tmap_peripheral/src/main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/samples/bluetooth/tmap_peripheral/src/main.c b/samples/bluetooth/tmap_peripheral/src/main.c index 5ae1a363f047..2fb2dd54c682 100644 --- a/samples/bluetooth/tmap_peripheral/src/main.c +++ b/samples/bluetooth/tmap_peripheral/src/main.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -36,11 +37,15 @@ static struct k_work_delayable media_pause_set_work; static uint8_t unicast_server_addata[] = { BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL), /* ASCS UUID */ BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, /* Target Announcement */ - (((AVAILABLE_SINK_CONTEXT) >> 0) & 0xFF), - (((AVAILABLE_SINK_CONTEXT) >> 8) & 0xFF), + BT_BYTES_LIST_LE16(AVAILABLE_SINK_CONTEXT), 0x00, /* Metadata length */ }; +static const uint8_t cap_addata[] = { + BT_UUID_16_ENCODE(BT_UUID_CAS_VAL), + BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED, +}; + static uint8_t tmap_addata[] = { BT_UUID_16_ENCODE(BT_UUID_TMAS_VAL), /* TMAS UUID */ (BT_TMAP_ROLE_UMR | BT_TMAP_ROLE_CT), 0x00, /* TMAP Role */ @@ -50,15 +55,16 @@ static uint8_t csis_rsi_addata[BT_CSIP_RSI_SIZE]; static bool peer_is_cg; static bool peer_is_ums; -/* TODO: Expand with BAP data */ 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_GAP_APPEARANCE, 0x09, 0x41), /* Appearance - Earbud */ - BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL)), + BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL), + BT_UUID_16_ENCODE(BT_UUID_CAS_VAL), BT_UUID_16_ENCODE(BT_UUID_TMAS_VAL)), #if defined(CONFIG_BT_CSIP_SET_MEMBER) BT_DATA(BT_DATA_CSIS_RSI, csis_rsi_addata, ARRAY_SIZE(csis_rsi_addata)), #endif /* CONFIG_BT_CSIP_SET_MEMBER */ BT_DATA(BT_DATA_SVC_DATA16, tmap_addata, ARRAY_SIZE(tmap_addata)), + BT_DATA(BT_DATA_SVC_DATA16, cap_addata, ARRAY_SIZE(cap_addata)), BT_DATA(BT_DATA_SVC_DATA16, unicast_server_addata, ARRAY_SIZE(unicast_server_addata)), }; From cd78331c2307a1d4ac04046ee19878ba7f291e90 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 21 Jun 2023 14:44:13 +0200 Subject: [PATCH 0755/2042] Bluetooth: Shell: Only print PAST peer if there is one Only print the "PAST peer" string if there is an actual PAST peer. Signed-off-by: Emil Gydesen --- subsys/bluetooth/shell/bt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index ed0e4a2739f7..aea64c923296 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -847,22 +847,22 @@ struct bt_le_per_adv_sync *per_adv_syncs[CONFIG_BT_PER_ADV_SYNC_MAX]; static void per_adv_sync_sync_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info) { + const bool is_past_peer = info->conn != NULL; char le_addr[BT_ADDR_LE_STR_LEN]; char past_peer[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - if (info->conn) { + if (is_past_peer) { conn_addr_str(info->conn, past_peer, sizeof(past_peer)); - } else { - memset(past_peer, 0, sizeof(past_peer)); } shell_print(ctx_shell, "PER_ADV_SYNC[%u]: [DEVICE]: %s synced, " "Interval 0x%04x (%u us), PHY %s, SD 0x%04X, PAST peer %s", bt_le_per_adv_sync_get_index(sync), le_addr, info->interval, BT_CONN_INTERVAL_TO_US(info->interval), - phy2str(info->phy), info->service_data, past_peer); + phy2str(info->phy), info->service_data, + is_past_peer ? past_peer : "not present"); if (info->conn) { /* if from PAST */ for (int i = 0; i < ARRAY_SIZE(per_adv_syncs); i++) { From 70655721fb3e6fb1187d9ad8e2baf12c3f56a609 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Tue, 20 Jun 2023 13:09:19 +0000 Subject: [PATCH 0756/2042] cmake: remove extraneous newlines in build output Using `west build --board=stm32f769i_disco --pristine=always samples/subsys/shell/fs/` as an example: Before: -- west build: building application [1/205] Preparing syscall dependency handling [2/205] Generating include/generated/version.h -- Zephyr version: 3.4.0 ($ZEPHYR_HOME), build: zephyr-v3.4.0-9-gec9b30d354ec [195/205] Linking C executable zephyr/zephyr_pre0.elf [199/205] Linking C executable zephyr/zephyr_pre1.elf [205/205] Linking C executable zephyr/zephyr.elf Memory region Used Size Region Size %age Used FLASH: 94040 B 2 MB 4.48% RAM: 39528 B 384 KB 10.05% QSPI: 0 GB 256 MB 0.00% DTCM: 0 GB 128 KB 0.00% SDRAM1: 0 GB 16 MB 0.00% IDT_LIST: 0 GB 2 KB 0.00% After: -- west build: building application [1/205] Preparing syscall dependency handling [2/205] Generating include/generated/version.h -- Zephyr version: 3.4.0 ($ZEPHYR_HOME), build: zephyr-v3.4.0-9-gec9b30d354ec [205/205] Linking C executable zephyr/zephyr.elf Memory region Used Size Region Size %age Used FLASH: 94040 B 2 MB 4.48% RAM: 39528 B 384 KB 10.05% QSPI: 0 GB 256 MB 0.00% DTCM: 0 GB 128 KB 0.00% SDRAM1: 0 GB 16 MB 0.00% IDT_LIST: 0 GB 2 KB 0.00% Signed-off-by: Armin Brauns --- 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 69d802e32cac..5d654ed80369 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -2934,7 +2934,7 @@ function(target_byproducts) endif() add_custom_command(TARGET ${TB_TARGET} - POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "" + POST_BUILD COMMAND ${CMAKE_COMMAND} -E true BYPRODUCTS ${TB_BYPRODUCTS} COMMENT "Logical command for additional byproducts on target: ${TB_TARGET}" ) From 8785a9f4247c830748a2a4b1bbf90ddefc20842b Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Fri, 28 Apr 2023 14:38:23 -0700 Subject: [PATCH 0757/2042] net: conn_mgr: Minor fixes - Add missing event sleep after taking all ifaces up in test_connect_disconnect. - Add missing event sleep after resetting ifaces in conn_mgr_conn_before - Fix typo in comment for internal state flags. - Add missing NET_MGMT_EVENT_BIT to conn_mgr_connectivity event definitions. - Missing net_mgmt.h include in conn_mgr_connectivity.h - Split conn_mgr_conn iface reset into network and state resets, before and after event sleep, so that triggered events do not corrupt the state reset. - Reduce SIMULATED_EVENT_DELAY to 100ms to avoid timeouts on real-time targets. - Use macro for simulated event wait times. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/conn_mgr_connectivity.h | 4 +- subsys/net/conn_mgr/conn_mgr_private.h | 2 +- tests/net/conn_mgr_conn/src/main.c | 42 +++++++++++++++----- tests/net/conn_mgr_conn/src/test_conn_impl.c | 2 +- tests/net/conn_mgr_conn/src/test_conn_impl.h | 4 +- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index 34b885d86321..e877ad97fabf 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -34,7 +35,8 @@ extern "C" { /* Connectivity Events */ #define _NET_MGMT_CONN_LAYER NET_MGMT_LAYER(NET_MGMT_LAYER_L2) #define _NET_MGMT_CONN_CODE NET_MGMT_LAYER_CODE(0x207) -#define _NET_MGMT_CONN_BASE (_NET_MGMT_CONN_LAYER | _NET_MGMT_CONN_CODE) +#define _NET_MGMT_CONN_BASE (_NET_MGMT_CONN_LAYER | _NET_MGMT_CONN_CODE | \ + NET_MGMT_EVENT_BIT) #define _NET_MGMT_CONN_IF_EVENT (NET_MGMT_IFACE_BIT | _NET_MGMT_CONN_BASE) enum net_event_ethernet_cmd { diff --git a/subsys/net/conn_mgr/conn_mgr_private.h b/subsys/net/conn_mgr/conn_mgr_private.h index 9e147653828b..94e7a0b79580 100644 --- a/subsys/net/conn_mgr/conn_mgr_private.h +++ b/subsys/net/conn_mgr/conn_mgr_private.h @@ -27,7 +27,7 @@ /* Configuration flags */ #define CONN_MGR_IF_IGNORED BIT(7) -/* Internal state flags*/ +/* Internal state flags */ #define CONN_MGR_IF_READY BIT(14) /* Event flags */ diff --git a/tests/net/conn_mgr_conn/src/main.c b/tests/net/conn_mgr_conn/src/main.c index dbe1d4cb3374..373dcdd04265 100644 --- a/tests/net/conn_mgr_conn/src/main.c +++ b/tests/net/conn_mgr_conn/src/main.c @@ -29,7 +29,12 @@ static inline struct test_conn_data *conn_mgr_if_get_data(struct net_if *iface) return binding->ctx; } -static void reset_test_iface(struct net_if *iface) +/** + * @brief Reset the network state of the provided iface. + * + * @param iface - iface to reset. + */ +static void reset_test_iface_networking(struct net_if *iface) { if (net_if_is_admin_up(iface)) { (void)net_if_down(iface); @@ -37,7 +42,15 @@ static void reset_test_iface(struct net_if *iface) /* Some tests can leave the iface in a bad state where it is admin-down but not dormant */ net_if_dormant_on(iface); +} +/** + * @brief Reset testing state for the provided iface. + * + * @param iface - iface to reset. + */ +static void reset_test_iface_state(struct net_if *iface) +{ struct conn_mgr_conn_binding *iface_binding = conn_mgr_if_get_binding(iface); struct test_conn_data *iface_data = conn_mgr_if_get_data(iface); @@ -98,12 +111,22 @@ static void conn_mgr_conn_handler(struct net_mgmt_event_callback *cb, static void conn_mgr_conn_before(void *data) { ARG_UNUSED(data); - reset_test_iface(ifa1); - reset_test_iface(ifa2); - reset_test_iface(ifb); - reset_test_iface(ifni); - reset_test_iface(ifnone); - reset_test_iface(ifnull); + reset_test_iface_networking(ifa1); + reset_test_iface_networking(ifa2); + reset_test_iface_networking(ifb); + reset_test_iface_networking(ifni); + reset_test_iface_networking(ifnone); + reset_test_iface_networking(ifnull); + + /* Allow any triggered events to shake out */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + + reset_test_iface_state(ifa1); + reset_test_iface_state(ifa2); + reset_test_iface_state(ifb); + reset_test_iface_state(ifni); + reset_test_iface_state(ifnone); + reset_test_iface_state(ifnull); k_mutex_lock(&event_mutex, K_FOREVER); @@ -171,6 +194,7 @@ ZTEST(conn_mgr_conn, test_connect_disconnect) zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail"); zassert_equal(net_if_up(ifa2), 0, "net_if_up should not fail"); zassert_equal(net_if_up(ifb), 0, "net_if_up should not fail"); + k_sleep(K_MSEC(1)); /* Verify ifaces are still disconnected */ zassert_false(net_if_is_up(ifa1), "Ifaces must be disconnected before test"); @@ -526,7 +550,7 @@ ZTEST(conn_mgr_conn, test_connect_timeout) zassert_false(net_if_is_up(ifa1), "ifa1 should not be up if instructed to time out"); /* Ensure timeout event is fired */ - k_sleep(K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS + 1)); + k_sleep(SIMULATED_EVENT_WAIT_TIME); k_mutex_lock(&event_mutex, K_FOREVER); stats = test_event_stats; @@ -557,7 +581,7 @@ ZTEST(conn_mgr_conn, test_connect_fatal_error) zassert_false(net_if_is_up(ifa1), "ifa1 should not be up if instructed to time out"); /* Ensure fatal_error event is fired */ - k_sleep(K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS + 1)); + k_sleep(SIMULATED_EVENT_WAIT_TIME); k_mutex_lock(&event_mutex, K_FOREVER); stats = test_event_stats; diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.c b/tests/net/conn_mgr_conn/src/test_conn_impl.c index 8d2395160590..c6e4cff6a2d0 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.c +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.c @@ -57,7 +57,7 @@ static void simulate_event(struct net_if *target, int event) simulated_event = event; simulated_event_iface = target; - k_work_reschedule(&simulate_event_work, K_SECONDS(SIMULATED_EVENT_DELAY_SECONDS)); + k_work_reschedule(&simulate_event_work, SIMULATED_EVENT_DELAY_TIME); k_mutex_unlock(&simulated_event_mutex); } diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.h b/tests/net/conn_mgr_conn/src/test_conn_impl.h index 6408bb802cfc..1df7e6d02011 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.h +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.h @@ -76,7 +76,9 @@ CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_N); #define TEST_L2_CONN_IMPL_NI_CTX_TYPE struct test_conn_data CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_NI); -#define SIMULATED_EVENT_DELAY_SECONDS 5 +#define SIMULATED_EVENT_DELAY_MS 100 +#define SIMULATED_EVENT_DELAY_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS) +#define SIMULATED_EVENT_WAIT_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS + 10) #ifdef __cplusplus } From f3d75c4c6570c24a4a0dfb6145b5868d2caa0c87 Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Wed, 26 Apr 2023 13:58:47 -0700 Subject: [PATCH 0758/2042] net: conn_mgr: Support Auto-Connect To reduce the need for boilerplate in application code, conn_mgr now supports an auto-connect feature on all ifaces with connectivity bindings. conn_mgr will automatically call conn_mgr_if_connect on any iface with a connectivity binding that enters the admin-up state, unless the newly added CONN_MGR_IF_NO_AUTO_CONNECT flag has been set for that iface. Also adjust automated tests to account for and take advantage of this behavior. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/conn_mgr_connectivity.h | 6 ++ subsys/net/conn_mgr/conn_mgr_connectivity.c | 62 ++++++++++++++++++++ subsys/net/conn_mgr/conn_mgr_private.h | 2 + tests/net/conn_mgr/src/main.c | 41 ------------- tests/net/conn_mgr_conn/src/main.c | 64 ++++++++++++++++++++- 5 files changed, 133 insertions(+), 42 deletions(-) diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index e877ad97fabf..2ea5eff203fd 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -180,6 +180,12 @@ enum conn_mgr_if_flag { */ CONN_MGR_IF_PERSISTENT, + /* No auto-connect + * When set, conn_mgr will not automatically attempt to connect this iface when it reaches + * admin-up. + */ + CONN_MGR_IF_NO_AUTO_CONNECT, + /** @cond INTERNAL_HIDDEN */ /* Total number of flags - must be at the end of the enum */ CONN_MGR_NUM_IF_FLAGS, diff --git a/subsys/net/conn_mgr/conn_mgr_connectivity.c b/subsys/net/conn_mgr/conn_mgr_connectivity.c index 8fae71acec17..9ea08cccde44 100644 --- a/subsys/net/conn_mgr/conn_mgr_connectivity.c +++ b/subsys/net/conn_mgr/conn_mgr_connectivity.c @@ -235,8 +235,52 @@ int conn_mgr_if_set_timeout(struct net_if *iface, int timeout) return 0; } +/* Automated behavior handling */ + +/** + * @brief Perform automated behaviors in response to ifaces going admin-up. + * + * @param iface - The iface which became admin-up. + */ +static void conn_mgr_conn_handle_iface_admin_up(struct net_if *iface) +{ + int err; + + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* Ignore ifaces for which auto-connect is disabled */ + if (conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT)) { + return; + } + + /* Otherwise, automatically instruct the iface to connect */ + err = conn_mgr_if_connect(iface); + if (err < 0) { + NET_ERR("iface auto-connect failed: %d", err); + } +} + +static struct net_mgmt_event_callback conn_mgr_conn_iface_cb; +static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + if ((mgmt_event & CONN_MGR_CONN_IFACE_EVENTS_MASK) != mgmt_event) { + return; + } + + switch (mgmt_event) { + case NET_EVENT_IF_UP: + conn_mgr_conn_handle_iface_admin_up(iface); + break; + } +} + void conn_mgr_conn_init(void) { + /* Initialize connectivity bindings. */ STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { if (!(binding->impl->api)) { LOG_ERR("Connectivity implementation has NULL API, and will be treated as " @@ -255,4 +299,22 @@ void conn_mgr_conn_init(void) k_mutex_unlock(binding->mutex); } } + + /* Set up event listeners for automated behaviors */ + net_mgmt_init_event_callback(&conn_mgr_conn_iface_cb, conn_mgr_conn_iface_handler, + CONN_MGR_CONN_IFACE_EVENTS_MASK); + net_mgmt_add_event_callback(&conn_mgr_conn_iface_cb); + + /* Trigger any initial automated behaviors for ifaces */ + STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { + if (binding->impl->api) { + /* We need to fire conn_mgr_conn_handle_iface_admin_up for any + * (connectivity-enabled) ifaces that went admin-up before we registerred + * the event callback that typically handles this. + */ + if (net_if_is_admin_up(binding->iface)) { + conn_mgr_conn_handle_iface_admin_up(binding->iface); + } + } + } } diff --git a/subsys/net/conn_mgr/conn_mgr_private.h b/subsys/net/conn_mgr/conn_mgr_private.h index 94e7a0b79580..1e20b33b49e5 100644 --- a/subsys/net/conn_mgr/conn_mgr_private.h +++ b/subsys/net/conn_mgr/conn_mgr_private.h @@ -37,6 +37,8 @@ #define CONN_MGR_IFACE_EVENTS_MASK (NET_EVENT_IF_DOWN | \ NET_EVENT_IF_UP) +#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP) + #define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \ NET_EVENT_IPV6_ADDR_DEL | \ NET_EVENT_IPV6_DAD_SUCCEED | \ diff --git a/tests/net/conn_mgr/src/main.c b/tests/net/conn_mgr/src/main.c index ee7c0c9cbd90..33e50fdde8c4 100644 --- a/tests/net/conn_mgr/src/main.c +++ b/tests/net/conn_mgr/src/main.c @@ -186,10 +186,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -202,10 +198,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -266,10 +258,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -292,10 +280,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -308,10 +292,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -353,10 +333,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -366,10 +342,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take A up */ zassert_equal(net_if_up(ifa), 0, "net_if_up should succeed for ifa."); - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_connect(ifa), 0, - "conn_mgr_if_connect should succeed for ifa."); - } /* Expect connectivity gained */ k_sleep(EVENT_WAIT_TIME); @@ -408,10 +380,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect connectivity lost */ @@ -481,11 +449,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* Take iface up */ zassert_equal(net_if_up(iface), 0, "net_if_up should succeed."); - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_connect(iface), 0, - "conn_mgr_if_connect should succeed."); - } - /* Verify that no events have been fired yet */ k_sleep(EVENT_WAIT_TIME); stats = get_reset_stats(); @@ -643,10 +606,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* Take iface up */ zassert_equal(net_if_up(iface), 0, "net_if_up should succeed."); - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_connect(iface), 0, - "conn_mgr_if_connect should succeed."); - } /* Verify events are fired */ k_sleep(EVENT_WAIT_TIME); diff --git a/tests/net/conn_mgr_conn/src/main.c b/tests/net/conn_mgr_conn/src/main.c index 373dcdd04265..fbb88d7732d1 100644 --- a/tests/net/conn_mgr_conn/src/main.c +++ b/tests/net/conn_mgr_conn/src/main.c @@ -55,8 +55,12 @@ static void reset_test_iface_state(struct net_if *iface) struct test_conn_data *iface_data = conn_mgr_if_get_data(iface); if (iface_binding) { + /* Reset all flags and settings for the binding */ iface_binding->flags = 0; iface_binding->timeout = CONN_MGR_IF_NO_TIMEOUT; + + /* Disable auto-connect */ + conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT, true); } if (iface_data) { @@ -761,6 +765,9 @@ ZTEST(conn_mgr_conn, test_flags) { struct conn_mgr_conn_binding *ifa1_binding = conn_mgr_if_get_binding(ifa1); + /* Firstly, clear all flags (some are automatically enabled before each test) */ + ifa1_binding->flags = 0; + /* Try setting persistence flag */ zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true), 0, "Setting persistence flag should succeed for ifa1"); @@ -773,6 +780,19 @@ ZTEST(conn_mgr_conn, test_flags) zassert_equal(ifa1_binding->flags, BIT(CONN_MGR_IF_PERSISTENT), "Persistence flag set should affect conn struct"); + /* Try setting no-autoconnect flag */ + zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, true), 0, + "Setting no-autoconnect flag should succeed for ifa1"); + + /* Verify success */ + zassert_true(conn_mgr_if_get_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT), + "No-autoconnect should be set for ifa1"); + + /* Verify that the conn struct agrees, since this is what implementations may use */ + zassert_equal(ifa1_binding->flags, + BIT(CONN_MGR_IF_PERSISTENT) | BIT(CONN_MGR_IF_NO_AUTO_CONNECT), + "Persistence flag set should affect conn struct"); + /* Try unsetting persistence flag */ zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false), 0, "Unsetting persistence flag should succeed for ifa1"); @@ -782,8 +802,20 @@ ZTEST(conn_mgr_conn, test_flags) "Persistence should be unset for ifa1"); /* Verify that the conn struct agrees, since this is what implementations may use */ - zassert_equal(ifa1_binding->flags, 0, + zassert_equal(ifa1_binding->flags, BIT(CONN_MGR_IF_NO_AUTO_CONNECT), "Persistence flag unset should affect conn struct"); + + /* Try unsetting no-autoconnect flag */ + zassert_equal(conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false), 0, + "Clearing no-autoconnect flag should succeed for ifa1"); + + /* Verify success */ + zassert_false(conn_mgr_if_get_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT), + "No-autoconnect should be set for ifa1"); + + /* Verify that the conn struct agrees, since this is what implementations may use */ + zassert_equal(ifa1_binding->flags, 0, + "No-autoconnect flag set should affect conn struct"); } /* Verify that flag get/set fail and behave as expected respectively for invalid ifaces and @@ -857,4 +889,34 @@ ZTEST(conn_mgr_conn, test_timeout_invalid) "Getting timeout should yield CONN_MGR_IF_NO_TIMEOUT for ifnone"); } +/* Verify that auto-connect works as expected. */ +ZTEST(conn_mgr_conn, test_auto_connect) +{ + /* Disable auto-connect. + * Not strictly necessary, since this is the default for this suite, but do it anyways + * since this test case specifically focuses on auto-connect. + */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, true); + + /* Take the iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail."); + + /* Verify no connection */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_up(ifa1), "Auto-connect should not trigger if disabled."); + + /* Take the iface down */ + zassert_equal(net_if_down(ifa1), 0, "net_if_down should not fail."); + + /* Enable auto-connect */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Take the iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should not fail."); + + /* Verify connection */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Auto-connect should succeed if enabled."); +} + ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL); From b65613e79cb2577e2f417db552b9daf13de93d03 Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Wed, 26 Apr 2023 16:30:23 -0700 Subject: [PATCH 0759/2042] net: conn_mgr: Support Auto-Down To reduce the amount of boiler-plate needed in applications, this commit grants conn_mgr the ability to automatically take ifaces that have given up on connecting into the admin-down state. Tests adjusted as appropriate. This behavior can be disabled globally by disabling NET_CONNECTION_MANAGER_AUTO_IF_DOWN, or disabled per-iface using the CONN_MGR_IF_NO_AUTO_DOWN flag. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/conn_mgr_connectivity.h | 6 + subsys/net/conn_mgr/Kconfig | 4 + subsys/net/conn_mgr/conn_mgr_connectivity.c | 106 ++++++++- subsys/net/conn_mgr/conn_mgr_private.h | 6 +- tests/net/conn_mgr/src/main.c | 43 ---- tests/net/conn_mgr_conn/src/main.c | 223 ++++++++++++++++++- tests/net/conn_mgr_conn/src/test_conn_impl.c | 7 +- tests/net/conn_mgr_conn/src/test_conn_impl.h | 19 ++ 8 files changed, 367 insertions(+), 47 deletions(-) diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index 2ea5eff203fd..34d8e04e1537 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -186,6 +186,12 @@ enum conn_mgr_if_flag { */ CONN_MGR_IF_NO_AUTO_CONNECT, + /* No auto-down + * When set, conn_mgr will not automatically take the iface admin-down when it stops + * trying to connect, even if NET_CONNECTION_MANAGER_AUTO_IF_DOWN is enabled. + */ + CONN_MGR_IF_NO_AUTO_DOWN, + /** @cond INTERNAL_HIDDEN */ /* Total number of flags - must be at the end of the enum */ CONN_MGR_NUM_IF_FLAGS, diff --git a/subsys/net/conn_mgr/Kconfig b/subsys/net/conn_mgr/Kconfig index 5c742fb852f5..b9567bf5eb8c 100644 --- a/subsys/net/conn_mgr/Kconfig +++ b/subsys/net/conn_mgr/Kconfig @@ -36,4 +36,8 @@ config NET_CONNECTION_MANAGER_PRIORITY help This sets the starting priority of the connection manager thread. +config NET_CONNECTION_MANAGER_AUTO_IF_DOWN + bool "Automatically call net_if_down on ifaces that have given up on connecting" + default y + endif # NET_CONNECTION_MANAGER diff --git a/subsys/net/conn_mgr/conn_mgr_connectivity.c b/subsys/net/conn_mgr/conn_mgr_connectivity.c index 9ea08cccde44..ebdd41dc5aeb 100644 --- a/subsys/net/conn_mgr/conn_mgr_connectivity.c +++ b/subsys/net/conn_mgr/conn_mgr_connectivity.c @@ -48,6 +48,8 @@ int conn_mgr_if_connect(struct net_if *iface) return status; } +static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface); + int conn_mgr_if_disconnect(struct net_if *iface) { struct conn_mgr_conn_binding *binding; @@ -77,6 +79,16 @@ int conn_mgr_if_disconnect(struct net_if *iface) out: k_mutex_unlock(binding->mutex); + /* Since the connectivity implementation will not automatically attempt to reconnect after + * a call to conn_mgr_if_disconnect, conn_mgr_conn_if_auto_admin_down should be called. + * + * conn_mgr_conn_handle_iface_down will only call conn_mgr_conn_if_auto_admin_down if + * persistence is disabled. To ensure conn_mgr_conn_if_auto_admin_down is called in all + * cases, we must call it directly from here. If persistence is disabled, this will result + * in conn_mgr_conn_if_auto_admin_down being called twice, but that is not an issue. + */ + conn_mgr_conn_if_auto_admin_down(iface); + return status; } @@ -263,6 +275,61 @@ static void conn_mgr_conn_handle_iface_admin_up(struct net_if *iface) } } +/** + * @brief Take the provided iface admin-down. + * + * Called automatically by conn_mgr when an iface has lost connection and will not attempt to + * regain it. + * + * @param iface - The iface to take admin-down + */ +static void conn_mgr_conn_if_auto_admin_down(struct net_if *iface) +{ + /* NOTE: This will be double-fired for ifaces that are both non-persistent + * and are being directly requested to disconnect, since both of these conditions + * separately trigger conn_mgr_conn_if_auto_admin_down. + * + * This is fine, because net_if_down is idempotent, but if you are adding other + * behaviors to this function, bear it in mind. + */ + + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* Take the iface admin-down if AUTO_DOWN is enabled */ + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER_AUTO_IF_DOWN) && + !conn_mgr_if_get_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN)) { + net_if_down(iface); + } +} + +/** + * @brief Perform automated behaviors in response to any iface that loses oper-up state. + * + * This is how conn_mgr_conn automatically takes such ifaces admin-down if they are not persistent. + * + * @param iface - The iface which lost oper-up state. + */ +static void conn_mgr_conn_handle_iface_down(struct net_if *iface) +{ + /* Ignore ifaces that don't have connectivity implementations */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + /* If the iface is persistent, we expect it to try to reconnect, so nothing else to do */ + if (conn_mgr_if_get_flag(iface, CONN_MGR_IF_PERSISTENT)) { + return; + } + + /* Otherwise, we do not expect the iface to reconnect, and we should call + * conn_mgr_conn_if_auto_admin_down + */ + conn_mgr_conn_if_auto_admin_down(iface); +} + static struct net_mgmt_event_callback conn_mgr_conn_iface_cb; static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) @@ -272,12 +339,45 @@ static void conn_mgr_conn_iface_handler(struct net_mgmt_event_callback *cb, uint } switch (mgmt_event) { - case NET_EVENT_IF_UP: + case NET_EVENT_IF_DOWN: + conn_mgr_conn_handle_iface_down(iface); + break; + case NET_EVENT_IF_ADMIN_UP: conn_mgr_conn_handle_iface_admin_up(iface); break; } } +static struct net_mgmt_event_callback conn_mgr_conn_self_cb; +static void conn_mgr_conn_self_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, + struct net_if *iface) +{ + if ((mgmt_event & CONN_MGR_CONN_SELF_EVENTS_MASK) != mgmt_event) { + return; + } + + switch (NET_MGMT_GET_COMMAND(mgmt_event)) { + case NET_EVENT_CONN_CMD_IF_FATAL_ERROR: + if (cb->info) { + NET_ERR("Fatal connectivity error on iface %d (%p). Reason: %d.", + net_if_get_by_iface(iface), iface, *((int *)cb->info) + ); + } else { + NET_ERR("Unknown fatal connectivity error on iface %d (%p).", + net_if_get_by_iface(iface), iface + ); + } + __fallthrough; + case NET_EVENT_CONN_CMD_IF_TIMEOUT: + /* If a timeout or fatal error occurs, we do not expect the iface to try to + * reconnect, so call conn_mgr_conn_if_auto_admin_down. + */ + conn_mgr_conn_if_auto_admin_down(iface); + break; + } + +} + void conn_mgr_conn_init(void) { /* Initialize connectivity bindings. */ @@ -305,6 +405,10 @@ void conn_mgr_conn_init(void) CONN_MGR_CONN_IFACE_EVENTS_MASK); net_mgmt_add_event_callback(&conn_mgr_conn_iface_cb); + net_mgmt_init_event_callback(&conn_mgr_conn_self_cb, conn_mgr_conn_self_handler, + CONN_MGR_CONN_SELF_EVENTS_MASK); + net_mgmt_add_event_callback(&conn_mgr_conn_self_cb); + /* Trigger any initial automated behaviors for ifaces */ STRUCT_SECTION_FOREACH(conn_mgr_conn_binding, binding) { if (binding->impl->api) { diff --git a/subsys/net/conn_mgr/conn_mgr_private.h b/subsys/net/conn_mgr/conn_mgr_private.h index 1e20b33b49e5..c2f3097a8d46 100644 --- a/subsys/net/conn_mgr/conn_mgr_private.h +++ b/subsys/net/conn_mgr/conn_mgr_private.h @@ -37,7 +37,11 @@ #define CONN_MGR_IFACE_EVENTS_MASK (NET_EVENT_IF_DOWN | \ NET_EVENT_IF_UP) -#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP) +#define CONN_MGR_CONN_IFACE_EVENTS_MASK (NET_EVENT_IF_ADMIN_UP |\ + NET_EVENT_IF_DOWN) + +#define CONN_MGR_CONN_SELF_EVENTS_MASK (NET_EVENT_CONN_IF_TIMEOUT | \ + NET_EVENT_CONN_IF_FATAL_ERROR) #define CONN_MGR_IPV6_EVENTS_MASK (NET_EVENT_IPV6_ADDR_ADD | \ NET_EVENT_IPV6_ADDR_DEL | \ diff --git a/tests/net/conn_mgr/src/main.c b/tests/net/conn_mgr/src/main.c index 33e50fdde8c4..9a225c3fb113 100644 --- a/tests/net/conn_mgr/src/main.c +++ b/tests/net/conn_mgr/src/main.c @@ -44,9 +44,6 @@ static void reset_test_iface(struct net_if *iface) struct in6_addr *ll_ipv6; if (net_if_is_admin_up(iface)) { - if (conn_mgr_if_is_bound(iface)) { - (void)conn_mgr_if_disconnect(iface); - } (void)net_if_down(iface); } @@ -206,10 +203,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect no events */ @@ -219,10 +212,6 @@ static void cycle_ready_ifaces(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect connectivity loss */ @@ -266,10 +255,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -300,10 +285,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifba."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -313,10 +294,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) "No events should be fired if connectivity availability did not change."); /* Take A down */ - if (conn_mgr_if_is_bound(ifa)) { - zassert_equal(conn_mgr_if_disconnect(ifa), 0, - "conn_mgr_if_disconnect should succeed for ifa."); - } zassert_equal(net_if_down(ifa), 0, "net_if_down should succeed for ifa."); /* Expect connectivity lost */ @@ -353,10 +330,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) zassert_equal(stats.conn_iface, ifa, "ifa should be blamed."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -368,10 +341,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) /* Take B up */ zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for ifb."); - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_connect(ifb), 0, - "conn_mgr_if_connect should succeed for ifb."); - } /* Expect no events */ k_sleep(EVENT_WAIT_TIME); @@ -392,10 +361,6 @@ static void cycle_ignored_iface(struct net_if *ifa, struct net_if *ifb) zassert_equal(stats.dconn_iface, ifa, "ifa should be blamed."); /* Take B down */ - if (conn_mgr_if_is_bound(ifb)) { - zassert_equal(conn_mgr_if_disconnect(ifb), 0, - "conn_mgr_if_disconnect should succeed for ifb."); - } zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for ifb."); /* Expect no events */ @@ -566,10 +531,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* (10 -> 00): Lose oper-up from semi-ready state */ /* Take iface down */ - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_disconnect(iface), 0, - "conn_mgr_if_disconnect should succeed."); - } zassert_equal(net_if_down(iface), 0, "net_if_down should succeed."); /* Verify there are no events fired */ @@ -619,10 +580,6 @@ static void cycle_iface_states(struct net_if *iface, enum ip_order ifa_ipm) /* (11 -> 01): Lose oper-up from ready state */ /* Take iface down */ - if (conn_mgr_if_is_bound(iface)) { - zassert_equal(conn_mgr_if_disconnect(iface), 0, - "conn_mgr_if_disconnect should succeed."); - } zassert_equal(net_if_down(iface), 0, "net_if_down should succeed."); /* Verify events are fired */ diff --git a/tests/net/conn_mgr_conn/src/main.c b/tests/net/conn_mgr_conn/src/main.c index fbb88d7732d1..e7154329d5a8 100644 --- a/tests/net/conn_mgr_conn/src/main.c +++ b/tests/net/conn_mgr_conn/src/main.c @@ -59,8 +59,9 @@ static void reset_test_iface_state(struct net_if *iface) iface_binding->flags = 0; iface_binding->timeout = CONN_MGR_IF_NO_TIMEOUT; - /* Disable auto-connect */ + /* Disable auto-connect and auto-down */ conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_CONNECT, true); + conn_mgr_if_set_flag(iface, CONN_MGR_IF_NO_AUTO_DOWN, true); } if (iface_data) { @@ -919,4 +920,224 @@ ZTEST(conn_mgr_conn, test_auto_connect) zassert_true(net_if_is_up(ifa1), "Auto-connect should succeed if enabled."); } +/* Verify that if auto-down is enabled, disconnecting an iface also takes it down, + * regardless of whether persistence is enabled, but only if auto-down is disabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_disconnect) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down, disable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on direct disconnect."); + + + + /* Enable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on direct disconnect, even if persistence is enabled."); + + + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Disconnect iface */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, + "conn_mgr_if_disconnect should succeed."); + + /* Verify up */ + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger if it is disabled."); +} + +/* Verify that auto-down takes an iface down if connection is lost, but only if persistence is not + * enabled, and only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_conn_loss) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down, disable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify down */ + k_sleep(K_MSEC(1)); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on connection loss if persistence is disabled."); + + /* Enable persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify up */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection loss if persistence is enabled."); + + /* Disable persistence and disable auto-down*/ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, false); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Reconnect iface */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Simulate connection loss */ + simulate_connection_loss(ifa1); + + /* Verify up */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection loss if it is disabled."); +} + +/* Verify that timeout takes the iface down, even if + * persistence is enabled, but only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_timeout) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down and persistence*/ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Schedule timeout */ + ifa1_data->timeout = true; + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify iface down after timeout */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on connection timeout, even if persistence is enabled."); + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up (timing out again) */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify iface up after timeout */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on connection timeout if it is disabled."); +} + + +/* Verify that fatal error takes the iface down, even if + * persistence is enabled, but only if auto-down is enabled. + */ +ZTEST(conn_mgr_conn, test_auto_down_fatal) +{ + /* For convenience, use auto-connect for this test. */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_CONNECT, false); + + /* Enable auto-down and persistence */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_PERSISTENT, true); + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, false); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Raise fatal error */ + simulate_fatal_error(ifa1, -EAGAIN); + + /* Verify iface down after fatal error */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_false(net_if_is_admin_up(ifa1), + "Auto-down should trigger on fatal error, even if persistence is enabled."); + + /* Disable auto-down */ + conn_mgr_if_set_flag(ifa1, CONN_MGR_IF_NO_AUTO_DOWN, true); + + /* Take iface up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed."); + + /* Verify connected */ + k_sleep(K_MSEC(1)); + zassert_true(net_if_is_up(ifa1), "Connection should succeed."); + + /* Raise fatal error */ + simulate_fatal_error(ifa1, -EAGAIN); + + /* Verify iface still up after fatal error */ + k_sleep(SIMULATED_EVENT_WAIT_TIME); + zassert_true(net_if_is_admin_up(ifa1), + "Auto-down should not trigger on fatal error if it is disabled."); +} + + ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL); diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.c b/tests/net/conn_mgr_conn/src/test_conn_impl.c index c6e4cff6a2d0..a0f2de45c545 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.c +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.c @@ -67,11 +67,16 @@ static void simulate_timeout(struct net_if *target) simulate_event(target, 0); } -static void simulate_fatal_error(struct net_if *target, int reason) +void simulate_fatal_error(struct net_if *target, int reason) { simulate_event(target, reason); } +void simulate_connection_loss(struct net_if *target) +{ + net_if_dormant_on(target); +} + /* Connectivity implementations */ static void inc_call_count(struct test_conn_data *data, bool a) diff --git a/tests/net/conn_mgr_conn/src/test_conn_impl.h b/tests/net/conn_mgr_conn/src/test_conn_impl.h index 1df7e6d02011..bab0c9b3aa9a 100644 --- a/tests/net/conn_mgr_conn/src/test_conn_impl.h +++ b/tests/net/conn_mgr_conn/src/test_conn_impl.h @@ -80,6 +80,25 @@ CONN_MGR_CONN_DECLARE_PUBLIC(TEST_L2_CONN_IMPL_NI); #define SIMULATED_EVENT_DELAY_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS) #define SIMULATED_EVENT_WAIT_TIME K_MSEC(SIMULATED_EVENT_DELAY_MS + 10) +/* Helper API for controlling implementations from tests */ + +/** + * @brief Simulate a connection loss on the target iface. + * + * @param target - iface to simulate connection loss on. + */ +void simulate_connection_loss(struct net_if *target); + +/** + * @brief Simulate a fatal error on the target iface + * + * Please do not simulate events on more than one iface at a time. + * + * @param target - iface to simulate fatal error on. + * @param reason - Reason to be given for the fatal error. + */ +void simulate_fatal_error(struct net_if *target, int reason); + #ifdef __cplusplus } #endif From ad6fdaf2c23f9fc7206036e565db71ea0b2331d3 Mon Sep 17 00:00:00 2001 From: Georges Oates_Larsen Date: Tue, 2 May 2023 16:46:30 -0700 Subject: [PATCH 0760/2042] net: conn_mgr: Bulk convenience functions To further reduce the need for networking boilerplate in applications, provide bulk versions of net_if_up, net_if_down, conn_mgr_if_connect, and conn_mgr_if_disconnect that affect all available / eligible ifaces at once. Since it is not intuitive whether these functions should affect ifaces which conn_mgr is ignoring, these functions take an argument that allows this to be specified by the application. Signed-off-by: Georges Oates_Larsen --- include/zephyr/net/conn_mgr_connectivity.h | 51 +++ subsys/net/conn_mgr/conn_mgr_connectivity.c | 145 ++++++- tests/net/conn_mgr_conn/prj.conf | 4 + tests/net/conn_mgr_conn/src/main.c | 439 ++++++++++++++++++++ 4 files changed, 638 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/conn_mgr_connectivity.h b/include/zephyr/net/conn_mgr_connectivity.h index 34d8e04e1537..ba7041a038b3 100644 --- a/include/zephyr/net/conn_mgr_connectivity.h +++ b/include/zephyr/net/conn_mgr_connectivity.h @@ -423,6 +423,57 @@ int conn_mgr_if_set_timeout(struct net_if *iface, int timeout); */ void conn_mgr_conn_init(void); +/** + * @brief Convenience function that takes all available ifaces into the admin-up state. + * + * Essentially a wrapper for net_if_up. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up calls returned 0, otherwise the first nonzero value + * returned by a net_if_up call. + */ +int conn_mgr_all_if_up(bool skip_ignored); + + +/** + * @brief Convenience function that takes all available ifaces into the admin-down state. + * + * Essentially a wrapper for net_if_down. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_down calls returned 0, otherwise the first nonzero value + * returned by a net_if_down call. + */ +int conn_mgr_all_if_down(bool skip_ignored); + +/** + * @brief Convenience function that takes all available ifaces into the admin-up state, and + * connects those that support connectivity. + * + * Essentially a wrapper for net_if_up and conn_mgr_if_connect. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero + * value returned by either net_if_up or conn_mgr_if_connect. + */ +int conn_mgr_all_if_connect(bool skip_ignored); + +/** + * @brief Convenience function that disconnects all available ifaces that support connectivity + * without putting them into admin-down state (unless auto-down is enabled for the iface). + * + * Essentially a wrapper for net_if_down. + * + * @param skip_ignored - If true, only affect ifaces that aren't ignored by conn_mgr. + * Otherwise, affect all ifaces. + * @return 0 if all net_if_up and conn_mgr_if_connect calls returned 0, otherwise the first nonzero + * value returned by either net_if_up or conn_mgr_if_connect. + */ +int conn_mgr_all_if_disconnect(bool skip_ignored); + /** * @} */ diff --git a/subsys/net/conn_mgr/conn_mgr_connectivity.c b/subsys/net/conn_mgr/conn_mgr_connectivity.c index ebdd41dc5aeb..e50ac0614f65 100644 --- a/subsys/net/conn_mgr/conn_mgr_connectivity.c +++ b/subsys/net/conn_mgr/conn_mgr_connectivity.c @@ -8,8 +8,10 @@ LOG_MODULE_REGISTER(conn_mgr_conn, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL); #include -#include #include +#include + +#include #include "conn_mgr_private.h" @@ -422,3 +424,144 @@ void conn_mgr_conn_init(void) } } } + +enum conn_mgr_conn_all_if_oper { + ALL_IF_UP, + ALL_IF_DOWN, + ALL_IF_CONNECT, + ALL_IF_DISCONNECT +}; + +struct conn_mgr_conn_all_if_ctx { + bool skip_ignored; + enum conn_mgr_conn_all_if_oper operation; + int status; +}; + +/* Per-iface callback for conn_mgr_conn_all_if_up */ +static void conn_mgr_conn_all_if_cb(struct net_if *iface, void *user_data) +{ + int status = 0; + struct conn_mgr_conn_all_if_ctx *context = (struct conn_mgr_conn_all_if_ctx *)user_data; + + /* Skip ignored ifaces if so desired */ + if (context->skip_ignored && conn_mgr_is_iface_ignored(iface)) { + return; + } + + /* Perform the requested operation */ + switch (context->operation) { + case ALL_IF_UP: + /* Do not take iface admin up if it already is. */ + if (net_if_is_admin_up(iface)) { + return; + } + + status = net_if_up(iface); + break; + case ALL_IF_DOWN: + /* Do not take iface admin down if it already is. */ + if (!net_if_is_admin_up(iface)) { + return; + } + + status = net_if_down(iface); + break; + case ALL_IF_CONNECT: + /* Connect operation only supported if iface is bound */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + status = conn_mgr_if_connect(iface); + break; + case ALL_IF_DISCONNECT: + /* Disconnect operation only supported if iface is bound */ + if (!conn_mgr_if_is_bound(iface)) { + return; + } + + status = conn_mgr_if_disconnect(iface); + break; + } + + if (status == 0) { + return; + } + + if (context->status == 0) { + context->status = status; + } + + NET_ERR("%s failed for iface %d (%p). Error: %d", + context->operation == ALL_IF_UP ? "net_if_up" : + context->operation == ALL_IF_DOWN ? "net_if_down" : + context->operation == ALL_IF_CONNECT ? "conn_mgr_if_connect" : + context->operation == ALL_IF_DISCONNECT ? "conn_mgr_if_disconnect" : + "invalid", + net_if_get_by_iface(iface), iface, status + ); +} + +int conn_mgr_all_if_up(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_UP, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_down(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_DOWN, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_connect(bool skip_ignored) +{ + /* First, take all ifaces up. + * All bound ifaces will do this automatically when connect is called, but non-bound ifaces + * won't, so we must request it explicitly. + */ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_UP, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + /* Now connect all ifaces. + * We are delibarately not resetting context.status between these two calls so that + * the first nonzero status code encountered between the two of them is what is returned. + */ + context.operation = ALL_IF_CONNECT; + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} + +int conn_mgr_all_if_disconnect(bool skip_ignored) +{ + struct conn_mgr_conn_all_if_ctx context = { + .operation = ALL_IF_DISCONNECT, + .skip_ignored = skip_ignored, + .status = 0 + }; + + net_if_foreach(conn_mgr_conn_all_if_cb, &context); + + return context.status; +} diff --git a/tests/net/conn_mgr_conn/prj.conf b/tests/net/conn_mgr_conn/prj.conf index 5ffa0ba9d9fc..ec6b62f6be3f 100644 --- a/tests/net/conn_mgr_conn/prj.conf +++ b/tests/net/conn_mgr_conn/prj.conf @@ -24,3 +24,7 @@ CONFIG_ZTEST_NEW_API=y CONFIG_NET_IF_MAX_IPV4_COUNT=6 CONFIG_NET_IF_MAX_IPV6_COUNT=6 CONFIG_TEST_USERSPACE=y + +# Increased net event queue size needed since this test performs simultaneous events on a +# large number of ifaces. +CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=16 diff --git a/tests/net/conn_mgr_conn/src/main.c b/tests/net/conn_mgr_conn/src/main.c index e7154329d5a8..9d36688ae879 100644 --- a/tests/net/conn_mgr_conn/src/main.c +++ b/tests/net/conn_mgr_conn/src/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "conn_mgr_private.h" #include "test_conn_impl.h" #include "test_ifaces.h" @@ -54,6 +55,9 @@ static void reset_test_iface_state(struct net_if *iface) struct conn_mgr_conn_binding *iface_binding = conn_mgr_if_get_binding(iface); struct test_conn_data *iface_data = conn_mgr_if_get_data(iface); + /* Some tests mark ifaces as ignored, this must be reset between each test. */ + conn_mgr_watch_iface(iface); + if (iface_binding) { /* Reset all flags and settings for the binding */ iface_binding->flags = 0; @@ -1139,5 +1143,440 @@ ZTEST(conn_mgr_conn, test_auto_down_fatal) "Auto-down should not trigger on fatal error if it is disabled."); } +/* Verify that all_if_up brings all ifaces up, but only if they are not ignored or + * skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_up) +{ + /* Ignore an iface */ + conn_mgr_ignore_iface(ifa1); + + /* Take all ifaces up (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_up(false), 0, "conn_mgr_all_if_up should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + + /* Manually take all ifaces down */ + zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces up (skip ignored) */ + zassert_equal(conn_mgr_all_if_up(true), 0, "conn_mgr_all_if_up should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all except ignored are up */ + zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-up."); + + zassert_false(net_if_is_admin_up(ifa1), "Ignored iface should not be admin-up."); +} + +/* Verify that all_if_connect brings all ifaces up, and connects all bound ifaces, but only those + * that are not ignored, or all of them if skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_connect) +{ + /* Ignore a bound and an unbound iface */ + conn_mgr_ignore_iface(ifa1); + conn_mgr_ignore_iface(ifnone); + + /* Connect all ifaces (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_connect(false), 0, "conn_mgr_all_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify bound ifaces are connected */ + zassert_true(net_if_is_up(ifa1), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifa2), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All bound ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All bound ifaces should be connected."); + + /* Manually take all ifaces down */ + zassert_equal(conn_mgr_if_disconnect(ifa1), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifa2), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifb), 0, "net_if_disconnect should succeed."); + zassert_equal(conn_mgr_if_disconnect(ifni), 0, "net_if_disconnect should succeed."); + + zassert_equal(net_if_down(ifa1), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifa2), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifb), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifni), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnull), 0, "net_if_down should succeed for all ifaces."); + zassert_equal(net_if_down(ifnone), 0, "net_if_down should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Connect all ifaces (skip ignored) */ + zassert_equal(conn_mgr_all_if_connect(true), 0, "conn_mgr_all_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all except ignored are up */ + zassert_true(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-up."); + + zassert_false(net_if_is_admin_up(ifa1), "All ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ignored ifaces should be admin-down."); + + /* Verify bound ifaces are connected, except for ignored */ + zassert_true(net_if_is_up(ifa2), "All non-ignored bound ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All non-ignored bound ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All non-ignored bound ifaces should be connected."); + + zassert_false(net_if_is_up(ifa1), "Ignored iface should not be connected."); +} + +/* Verify that all_if_down takes all ifaces down, but only if they are not ignored, + * or skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_down) +{ + /* Ignore an iface */ + conn_mgr_ignore_iface(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_down(false), 0, "conn_mgr_all_if_down should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are down */ + zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down."); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down (skip ignored) */ + zassert_equal(conn_mgr_all_if_down(true), 0, "conn_mgr_all_if_down should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all except the ignored iface is down */ + zassert_false(net_if_is_admin_up(ifa2), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All non-ignored ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All non-ignored ifaces should be admin-down."); + + zassert_true(net_if_is_admin_up(ifa1), "Ignored iface should be admin-up."); +} + +/* Verify that all_if_disconnect disconnects all bound ifaces, but only if they are not ignored, + * or skip_ignored is false + */ +ZTEST(conn_mgr_conn, test_all_if_disconnect) +{ + /* Ignore a bound iface */ + conn_mgr_ignore_iface(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Disconnect all ifaces (do not skip ignored) */ + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all bound ifaces are disconnected */ + zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected."); + + /* Verify that all ifaces are still up, even if disconnected */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Manually reconnect bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Disconnect all ifaces (skip ignored) */ + zassert_equal(conn_mgr_all_if_disconnect(true), 0, + "conn_mgr_all_if_disconnect should succeed."); + k_sleep(K_MSEC(1)); + + /* Verify that all bound ifaces are disconnected, except the ignored iface */ + zassert_false(net_if_is_up(ifa2), "All non-ignored bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All non-ignored bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All non-ignored bound ifaces should be disconnected."); + + zassert_true(net_if_is_up(ifa1), "Ignored iface should still be connected"); +} + + +/* Verify that double calls to all_if_up do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_up_double) +{ + /* Take all ifaces up twice in a row */ + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed."); + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_up(false), 0, + "conn_mgr_all_if_up should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); +} + +/* Verify that double calls to all_if_down do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_down_double) +{ + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Take all ifaces down twice in a row */ + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed."); + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_down(false), 0, + "conn_mgr_all_if_down should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are down */ + zassert_false(net_if_is_admin_up(ifa1), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifa2), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifb), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifni), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnull), "All ifaces should be admin-down."); + zassert_false(net_if_is_admin_up(ifnone), "All ifaces should be admin-down."); +} + +/* Verify that double calls to all_if_connect do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_connect_double) +{ + /* Connect all ifaces twice in a row */ + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed."); + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_connect(false), 0, + "conn_mgr_all_if_connect should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify all bound ifaces are connected */ +} + +/* Verify that double calls to all_if_disconnect do not raise errors */ +ZTEST(conn_mgr_conn, test_all_if_disconnect_double) +{ + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Connect all ifaces twice in a row */ + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed."); + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed twice in a row."); + + /* One more time, after a delay, to be sure */ + k_sleep(K_MSEC(1)); + zassert_equal(conn_mgr_all_if_disconnect(false), 0, + "conn_mgr_all_if_disconnect should succeed twice in a row."); + k_sleep(K_MSEC(1)); + + /* Verify all bound ifaces are disconnected */ + zassert_false(net_if_is_up(ifa1), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifa2), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All bound ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All bound ifaces should be disconnected."); + + /* Verify all ifaces are up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); +} + + + +/* Testing error passing for all_if_up/all_if_down is not possible without using an L2 other than + * Dummy, since the dummy L2 is not capable of erroring in response to either of these. + * + * However, since all bulk convenience functions share a single implementation, testing + * connect and disconnect is sufficient to gain acceptable coverage of this behavior for all of + * them. + */ + +/* Verify that all_if_connect successfully forwards errors encountered on individual ifaces */ +ZTEST(conn_mgr_conn, test_all_if_connect_err) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* Schedule a connect error on one of the ifaces */ + ifa1_data->api_err = -ECHILD; + + /* Verify that this error is passed to all_if_connect */ + zassert_equal(conn_mgr_all_if_connect(false), -ECHILD, + "conn_mgr_all_if_connect should fail with the requested error."); + k_sleep(K_MSEC(1)); + + /* Verify that all ifaces went admin-up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify that all the non-error ifaces are connected */ + zassert_true(net_if_is_up(ifa2), "All non-failing ifaces should be connected."); + zassert_true(net_if_is_up(ifb), "All non-failing ifaces should be connected."); + zassert_true(net_if_is_up(ifni), "All non-failing ifaces should be connected."); + + /* Verify that the error iface is not connected */ + zassert_false(net_if_is_up(ifa1), "The failing iface should not be connected."); +} + +/* Verify that all_if_disconnect successfully forwards errors encountered on individual ifaces */ +ZTEST(conn_mgr_conn, test_all_if_disconnect_err) +{ + struct test_conn_data *ifa1_data = conn_mgr_if_get_data(ifa1); + + /* Manually take all ifaces up */ + zassert_equal(net_if_up(ifa1), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifa2), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifb), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifni), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnull), 0, "net_if_up should succeed for all ifaces."); + zassert_equal(net_if_up(ifnone), 0, "net_if_up should succeed for all ifaces."); + k_sleep(K_MSEC(1)); + + /* Manually connect all bound ifaces */ + zassert_equal(conn_mgr_if_connect(ifa1), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifa2), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifb), 0, "conn_mgr_if_connect should succeed."); + zassert_equal(conn_mgr_if_connect(ifni), 0, "conn_mgr_if_connect should succeed."); + k_sleep(K_MSEC(1)); + + /* Schedule a disconnect error on one of the ifaces */ + ifa1_data->api_err = -ECHILD; + + /* Verify that this error is passed to all_if_disconnect */ + zassert_equal(conn_mgr_all_if_disconnect(false), -ECHILD, + "conn_mgr_all_if_disconnect should fail with the requested error."); + + /* Verify that all ifaces are still admin-up */ + zassert_true(net_if_is_admin_up(ifa1), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifa2), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifb), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifni), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnull), "All ifaces should be admin-up."); + zassert_true(net_if_is_admin_up(ifnone), "All ifaces should be admin-up."); + + /* Verify that all the non-error ifaces are disconnected */ + zassert_false(net_if_is_up(ifa2), "All non-failing ifaces should be disconnected."); + zassert_false(net_if_is_up(ifb), "All non-failing ifaces should be disconnected."); + zassert_false(net_if_is_up(ifni), "All non-failing ifaces should be disconnected."); + + /* Verify that the error iface is not connected */ + zassert_true(net_if_is_up(ifa1), "The failing iface should not be disconnected."); +} ZTEST_SUITE(conn_mgr_conn, NULL, conn_mgr_conn_setup, conn_mgr_conn_before, NULL, NULL); From 43ef100a22d2532122e6c663f3220567a87bb26f Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 6 Jun 2023 19:31:56 +0200 Subject: [PATCH 0761/2042] Bluetooth: TMAP: Make callback const The callback should not be modified by the stack, and should thus be const. Also fixes a missing include of conn.h. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/tmap.h | 3 ++- subsys/bluetooth/audio/tmap.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/zephyr/bluetooth/audio/tmap.h b/include/zephyr/bluetooth/audio/tmap.h index 517e4951920d..ab6fefd4a71d 100644 --- a/include/zephyr/bluetooth/audio/tmap.h +++ b/include/zephyr/bluetooth/audio/tmap.h @@ -9,6 +9,7 @@ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TMAP_ #define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_TMAP_ +#include #include /** @brief TMAP Role characteristic */ @@ -52,7 +53,7 @@ int bt_tmap_register(enum bt_tmap_role role); * * @return 0 on success or negative error value on failure. */ -int bt_tmap_discover(struct bt_conn *conn, struct bt_tmap_cb *tmap_cb); +int bt_tmap_discover(struct bt_conn *conn, const struct bt_tmap_cb *tmap_cb); /** * @brief Set one or multiple TMAP roles dynamically. diff --git a/subsys/bluetooth/audio/tmap.c b/subsys/bluetooth/audio/tmap.c index e5375cfc8973..475718fb8b6b 100644 --- a/subsys/bluetooth/audio/tmap.c +++ b/subsys/bluetooth/audio/tmap.c @@ -26,7 +26,7 @@ LOG_MODULE_REGISTER(bt_tmap, CONFIG_BT_TMAP_LOG_LEVEL); #define TMAP_ALL_ROLES 0x3F static uint16_t tmap_role; -static struct bt_tmap_cb *cb; +static const struct bt_tmap_cb *cb; static bool tmas_found; static struct bt_uuid_16 uuid[CONFIG_BT_MAX_CONN] = {BT_UUID_INIT_16(0)}; @@ -167,7 +167,7 @@ int bt_tmap_register(enum bt_tmap_role role) return 0; } -int bt_tmap_discover(struct bt_conn *conn, struct bt_tmap_cb *tmap_cb) +int bt_tmap_discover(struct bt_conn *conn, const struct bt_tmap_cb *tmap_cb) { int err = 0; uint8_t conn_id = bt_conn_index(conn); From 49a70aa1bba600825074fbb431d5c187a45db136 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 6 Jun 2023 19:32:42 +0200 Subject: [PATCH 0762/2042] Bluetooth: TMAP: Add TMAP shell module Add simple TMAP shell module that supports the TMAP discovery. Signed-off-by: Emil Gydesen --- doc/connectivity/bluetooth/api/index.rst | 1 + doc/connectivity/bluetooth/api/shell/tmap.rst | 22 ++++ subsys/bluetooth/audio/shell/CMakeLists.txt | 4 + subsys/bluetooth/audio/shell/tmap.c | 121 ++++++++++++++++++ tests/bluetooth/shell/audio.conf | 6 + 5 files changed, 154 insertions(+) create mode 100644 doc/connectivity/bluetooth/api/shell/tmap.rst create mode 100644 subsys/bluetooth/audio/shell/tmap.c diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index 80713940ed04..51c363861140 100644 --- a/doc/connectivity/bluetooth/api/index.rst +++ b/doc/connectivity/bluetooth/api/index.rst @@ -37,3 +37,4 @@ Bluetooth APIs shell/csip.rst shell/iso.rst shell/mcp.rst + shell/tmap.rst diff --git a/doc/connectivity/bluetooth/api/shell/tmap.rst b/doc/connectivity/bluetooth/api/shell/tmap.rst new file mode 100644 index 000000000000..416644b30692 --- /dev/null +++ b/doc/connectivity/bluetooth/api/shell/tmap.rst @@ -0,0 +1,22 @@ +Bluetooth: Telephone and Media Audio Profile Shell +################################################## + +This document describes how to run the Telephone and Media Audio Profile functionality. +Unlike most other low-layer profiles, TMAP is a profile that exists and has a service (TMAS) on all +devices. Thus both the initiator and acceptor (or central and peripheral) should do a discovery of +the remote device's TMAS to see what TMAP roles they support. + +Using the TMAP Shell +******************** + +When the Bluetooth stack has been initialized (:code:`bt init`), the TMAS can be registered by +by calling :code:`tmap init`. + +.. code-block:: console + + + tmap --help + tmap - Bluetooth TMAP shell commands + Subcommands: + init :Initialize and register the TMAS + discover :Discover TMAS on remote device diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index 43b4cd879505..a5230278330d 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -63,6 +63,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_HAS_CLIENT has_client.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_TMAP + tmap.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/tmap.c b/subsys/bluetooth/audio/shell/tmap.c new file mode 100644 index 000000000000..6a30e5807737 --- /dev/null +++ b/subsys/bluetooth/audio/shell/tmap.c @@ -0,0 +1,121 @@ +/** @file + * @brief Bluetooth Telephone and Media Audio Profile shell + * + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "shell/bt.h" + +#define TMAP_CG_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && \ + IS_ENABLED(CONFIG_BT_TBS) && IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR)) + +#define TMAP_CT_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) && IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && \ + IS_ENABLED(CONFIG_BT_TBS_CLIENT) && \ + (IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK) && \ + IS_ENABLED(CONFIG_BT_VCP_VOL_REND) == IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK))) + +#define TMAP_UMS_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && \ + IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK) && IS_ENABLED(CONFIG_BT_VCP_VOL_CTLR) && \ + IS_ENABLED(CONFIG_BT_MCS)) + +#define TMAP_UMR_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) && IS_ENABLED(CONFIG_BT_ASCS_ASE_SNK) && \ + IS_ENABLED(CONFIG_BT_VCP_VOL_REND)) + +#define TMAP_BMS_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_INITIATOR) && IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE)) + +#define TMAP_BMR_SUPPORTED \ + (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) && IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) + +static int cmd_tmap_init(const struct shell *sh, size_t argc, char **argv) +{ + const enum bt_tmap_role role = (TMAP_CG_SUPPORTED ? BT_TMAP_ROLE_CG : 0U) | + (TMAP_CT_SUPPORTED ? BT_TMAP_ROLE_CT : 0U) | + (TMAP_UMS_SUPPORTED ? BT_TMAP_ROLE_UMS : 0U) | + (TMAP_UMR_SUPPORTED ? BT_TMAP_ROLE_UMR : 0U) | + (TMAP_BMS_SUPPORTED ? BT_TMAP_ROLE_BMS : 0U) | + (TMAP_BMR_SUPPORTED ? BT_TMAP_ROLE_BMR : 0U); + int err; + + shell_info(sh, "Registering TMAS with role: %u", role); + + err = bt_tmap_register(role); + if (err != 0) { + shell_error(sh, "bt_tmap_register (err %d)", err); + + return -ENOEXEC; + } + + return 0; +} + +static void tmap_discover_cb(enum bt_tmap_role role, struct bt_conn *conn, int err) +{ + if (err != 0) { + shell_error(ctx_shell, "tmap discovery (err %d)", err); + return; + } + + shell_print(ctx_shell, "tmap discovered for conn %p: role 0x%02x", conn, role); +} + +static const struct bt_tmap_cb tmap_cb = { + .discovery_complete = tmap_discover_cb, +}; + +static int cmd_tmap_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_tmap_discover(default_conn, &tmap_cb); + if (err != 0) { + shell_error(sh, "bt_tmap_discover (err %d)", err); + + return -ENOEXEC; + } + + return err; +} + +static int cmd_tmap(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(tmap_cmds, + SHELL_CMD_ARG(init, NULL, "Initialize and register the TMAS", cmd_tmap_init, 1, 0), + SHELL_CMD_ARG(discover, NULL, "Discover TMAS on remote device", cmd_tmap_discover, 1, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_ARG_REGISTER(tmap, &tmap_cmds, "Bluetooth tmap client shell commands", cmd_tmap, 1, 1); diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 14fa76b3db2e..04f3503edd33 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -152,6 +152,9 @@ CONFIG_BT_CAP_ACCEPTOR=y CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER=y CONFIG_BT_CAP_INITIATOR=y +# Telephone and Media Audio Profile +CONFIG_BT_TMAP=y + # DEBUGGING CONFIG_LOG=y CONFIG_BT_AUDIO_LOG_LEVEL_DBG=y @@ -186,3 +189,6 @@ CONFIG_BT_BAP_ISO_LOG_LEVEL_DBG=y CONFIG_BT_AUDIO_CODEC_LOG_LEVEL_DBG=y CONFIG_BT_CSIP_SET_COORDINATOR_LOG_LEVEL_DBG=y 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_TMAP_LOG_LEVEL_DBG=y From 121c505153580b87bdfc9186e4806794dfd31a1f Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 8 Jun 2023 07:39:02 +0530 Subject: [PATCH 0763/2042] samples: Bluetooth: iso_broadcast: Sent callback to sync ISO Data send Use the ISO Data sent callback in iso_broadcast sample to synchronize the ISO data send. ISO Data sent callback is generated every SDU interval corresponding to the number of completed packets event generated by the Controller. Signed-off-by: Vinayak Kariappa Chettimada --- samples/bluetooth/iso_broadcast/src/main.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/samples/bluetooth/iso_broadcast/src/main.c b/samples/bluetooth/iso_broadcast/src/main.c index fbdd9a7d3b29..6061e3b185e3 100644 --- a/samples/bluetooth/iso_broadcast/src/main.c +++ b/samples/bluetooth/iso_broadcast/src/main.c @@ -19,6 +19,8 @@ NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, BIS_ISO_CHAN_COUNT, static K_SEM_DEFINE(sem_big_cmplt, 0, BIS_ISO_CHAN_COUNT); static K_SEM_DEFINE(sem_big_term, 0, BIS_ISO_CHAN_COUNT); +static K_SEM_DEFINE(sem_iso_data, CONFIG_BT_ISO_TX_BUF_COUNT, + CONFIG_BT_ISO_TX_BUF_COUNT); #define INITIAL_TIMEOUT_COUNTER (BIG_TERMINATE_TIMEOUT_US / BIG_SDU_INTERVAL_US) @@ -40,9 +42,15 @@ static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) k_sem_give(&sem_big_term); } +static void iso_sent(struct bt_iso_chan *chan) +{ + k_sem_give(&sem_iso_data); +} + static struct bt_iso_chan_ops iso_ops = { .connected = iso_connected, .disconnected = iso_disconnected, + .sent = iso_sent, }; static struct bt_iso_chan_io_qos iso_tx_qos = { @@ -140,12 +148,9 @@ int main(void) } while (true) { - int ret; - - k_sleep(K_USEC(big_create_param.interval)); - for (uint8_t chan = 0U; chan < BIS_ISO_CHAN_COUNT; chan++) { struct net_buf *buf; + int ret; buf = net_buf_alloc(&bis_tx_pool, K_MSEC(BUF_ALLOC_TIMEOUT)); @@ -154,6 +159,15 @@ int main(void) " %u\n", chan); return 0; } + + ret = k_sem_take(&sem_iso_data, + K_MSEC(BUF_ALLOC_TIMEOUT)); + if (ret) { + printk("k_sem_take for ISO data sent failed\n"); + net_buf_unref(buf); + return 0; + } + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); sys_put_le32(iso_send_count, iso_data); net_buf_add_mem(buf, iso_data, sizeof(iso_data)); From 28dbbebc96933a1780e4708df6c1a29b96ef7fb2 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 8 Jun 2023 13:14:10 +0200 Subject: [PATCH 0764/2042] tests: Bluetooth: Split cap initiator unicast inval test to new func Add a new test function to test invalid behavior to keep the valid behavior test cleaner. Signed-off-by: Emil Gydesen --- .../audio/src/cap_initiator_unicast_test.c | 46 ++++++++++++++++--- .../bsim/bluetooth/audio/test_scripts/_cap.sh | 2 + .../audio/test_scripts/cap_unicast_inval.sh | 27 +++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_inval.sh 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 a3f17800112e..4d3698bd7128 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -640,7 +640,6 @@ static void test_main_cap_initiator_unicast(void) WAIT_FOR_FLAG(flag_mtu_exchanged); - discover_cas_inval(); discover_cas(); discover_sink(); @@ -649,17 +648,13 @@ static void test_main_cap_initiator_unicast(void) unicast_group_create(&unicast_group); for (size_t j = 0U; j < iterations; j++) { - unicast_audio_start_inval(unicast_group); unicast_audio_start(unicast_group, true); - unicast_audio_update_inval(); unicast_audio_update(); - unicast_audio_stop_inval(); unicast_audio_stop(unicast_group); } - unicast_group_delete_inval(); unicast_group_delete(unicast_group); unicast_group = NULL; } @@ -667,6 +662,39 @@ static void test_main_cap_initiator_unicast(void) PASS("CAP initiator unicast passed\n"); } +static void test_main_cap_initiator_unicast_inval(void) +{ + struct bt_bap_unicast_group *unicast_group; + + init(); + + scan_and_connect(); + + WAIT_FOR_FLAG(flag_mtu_exchanged); + + discover_cas_inval(); + discover_cas(); + + discover_sink(); + + unicast_group_create(&unicast_group); + + unicast_audio_start_inval(unicast_group); + unicast_audio_start(unicast_group, true); + + unicast_audio_update_inval(); + unicast_audio_update(); + + unicast_audio_stop_inval(); + unicast_audio_stop(unicast_group); + + unicast_group_delete_inval(); + unicast_group_delete(unicast_group); + unicast_group = NULL; + + PASS("CAP initiator unicast inval passed\n"); +} + static void test_cap_initiator_unicast_timeout(void) { struct bt_bap_unicast_group *unicast_group; @@ -703,7 +731,7 @@ static void test_cap_initiator_unicast_timeout(void) unicast_group_delete(unicast_group); unicast_group = NULL; - PASS("CAP initiator unicast passed\n"); + PASS("CAP initiator unicast timeout passed\n"); } static const struct bst_test_instance test_cap_initiator_unicast[] = { @@ -719,6 +747,12 @@ static const struct bst_test_instance test_cap_initiator_unicast[] = { .test_tick_f = test_tick, .test_main_f = test_cap_initiator_unicast_timeout, }, + { + .test_id = "cap_initiator_unicast_inval", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_main_cap_initiator_unicast_inval, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh index b4ba35bb3fa6..622a32d0373f 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh @@ -6,6 +6,8 @@ dir_path=$(dirname "$0") +$dir_path/cap_unicast_inval.sh + $dir_path/cap_unicast.sh $dir_path/cap_broadcast.sh diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_inval.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_inval.sh new file mode 100755 index 000000000000..c868f738d7b6 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_inval.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_inval" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=20 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +printf "\n\n======== Running CAP unicast test =========\n\n" + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=cap_initiator_unicast_inval -rs=46 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast -rs=23 + +# 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 $@ + +wait_for_background_jobs From 6e066b468349bed2c35bda920bae384f4dc61faa Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:28:46 +0200 Subject: [PATCH 0765/2042] Bluetooth: BAP: Shell: Improve recv statistics Add more information when we print the recv every 100th packet, and remove all per-recv printing. This also resets all information on stream start. This does, however, no properly support multiple streams. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 48 +++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 5842dde2a0a0..5965ec51b7b8 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -1654,34 +1654,46 @@ static struct bt_bap_broadcast_sink_cb sink_cbs = { #endif /* CONFIG_BT_BAP_BROADCAST_SINK */ #if defined(CONFIG_BT_AUDIO_RX) +static size_t lost_pkts; +static size_t err_pkts; +static size_t dup_psn; +static size_t rx_cnt; +static size_t dup_ts; + static void audio_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { static struct bt_iso_recv_info last_info; - static size_t rx_cnt; - /* TODO: Make it possible to only print every X packets, and make X settable by the shell */ - if ((rx_cnt % 100) == 0) { - shell_print(ctx_shell, - "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u", - rx_cnt, stream, buf->len, info->ts, info->seq_num, - info->flags); - } + rx_cnt++; if (info->ts == last_info.ts) { - shell_error(ctx_shell, "[%zu]: Duplicate TS: %u", - rx_cnt, info->ts); + dup_ts++; } if (info->seq_num == last_info.seq_num) { - shell_error(ctx_shell, "[%zu]: Duplicate seq_num: %u", - rx_cnt, info->seq_num); + dup_psn++; } - (void)memcpy(&last_info, info, sizeof(last_info)); + if (info->flags & BT_ISO_FLAGS_ERROR) { + err_pkts++; + } - rx_cnt++; + if (info->flags & BT_ISO_FLAGS_LOST) { + lost_pkts++; + } + + /* TODO: Make it possible to only print every X packets, and make X settable by the shell */ + if ((rx_cnt % 100) == 0) { + shell_print(ctx_shell, + "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u " + "(dup ts %zu; dup psn %zu, err_pkts %zu, lost_pkts %zu)", + rx_cnt, stream, buf->len, info->ts, info->seq_num, info->flags, dup_ts, + dup_psn, err_pkts, lost_pkts); + } + + (void)memcpy(&last_info, info, sizeof(last_info)); } #endif /* CONFIG_BT_AUDIO_RX */ @@ -1725,6 +1737,14 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) static void stream_started_cb(struct bt_bap_stream *stream) { printk("Stream %p started\n", stream); + +#if defined(CONFIG_BT_AUDIO_RX) + lost_pkts = 0U; + err_pkts = 0U; + dup_psn = 0U; + rx_cnt = 0U; + dup_ts = 0U; +#endif } static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) From c6632d65d85c841aef28c409f3456c5d61e62c1a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 27 Jun 2023 13:59:29 +0200 Subject: [PATCH 0766/2042] Bluetooth: BAP: Shell: Add runtime config of recv_stats_interval The internval of how often we report receive stats can now be configured via the cmd_recv_stats command. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 38 ++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 5965ec51b7b8..63e088553b1f 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -1654,6 +1654,7 @@ static struct bt_bap_broadcast_sink_cb sink_cbs = { #endif /* CONFIG_BT_BAP_BROADCAST_SINK */ #if defined(CONFIG_BT_AUDIO_RX) +static unsigned long recv_stats_interval = 100U; static size_t lost_pkts; static size_t err_pkts; static size_t dup_psn; @@ -1684,8 +1685,7 @@ static void audio_recv(struct bt_bap_stream *stream, lost_pkts++; } - /* TODO: Make it possible to only print every X packets, and make X settable by the shell */ - if ((rx_cnt % 100) == 0) { + if ((rx_cnt % recv_stats_interval) == 0) { shell_print(ctx_shell, "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u " "(dup ts %zu; dup psn %zu, err_pkts %zu, lost_pkts %zu)", @@ -2441,6 +2441,35 @@ static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[]) #endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ +#if defined(CONFIG_BT_AUDIO_RX) +static int cmd_recv_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + if (argc == 1) { + shell_info(sh, "Current receive stats interval: %lu", recv_stats_interval); + } else { + int err = 0; + unsigned long interval; + + interval = shell_strtoul(argv[1], 0, &err); + if (err != 0) { + shell_error(sh, "Could not parse interval: %d", err); + + return -ENOEXEC; + } + + if (interval == 0U) { + shell_error(sh, "Interval cannot be 0"); + + return -ENOEXEC; + } + + recv_stats_interval = interval; + } + + return 0; +} +#endif /* CONFIG_BT_AUDIO_RX */ + #if defined(CONFIG_BT_BAP_UNICAST_SERVER) static void print_ase_info(struct bt_bap_ep *ep, void *user_data) { @@ -2515,6 +2544,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave", cmd_stop_sine, 1, 0), #endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ +#if defined(CONFIG_BT_AUDIO_RX) + SHELL_CMD_ARG(recv_stats, NULL, + "Sets or gets the receive statistics reporting interval in # of packets", + cmd_recv_stats, 1, 1), +#endif /* CONFIG_BT_AUDIO_RX */ SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_location, NULL, " ", cmd_set_loc, 3, 0), SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_context, NULL, From 4e15a090834f6a8a56a98fdb6ff2c2ec7857c46e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 20:02:20 +0200 Subject: [PATCH 0767/2042] Bluetooth: BAP: Filter PA data duplicates by default When syncing via the broadcast sink or the scan delegator it makes more sense to filter on duplicates, as the expected data rarely changes. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_broadcast_sink.c | 4 ++-- subsys/bluetooth/audio/shell/bap_scan_delegator.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index 66a45fef555a..fc5e22178fcf 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -830,8 +830,8 @@ static uint16_t interval_to_sync_timeout(uint16_t interval) 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 = {0}; struct bt_bap_broadcast_sink_cb *listener; - struct bt_le_per_adv_sync_param param; struct bt_bap_broadcast_sink *sink; int err; @@ -851,7 +851,7 @@ static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info, } bt_addr_le_copy(¶m.addr, info->addr); - param.options = 0; + param.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; param.sid = info->sid; param.skip = PA_SYNC_SKIP; param.timeout = interval_to_sync_timeout(info->interval); diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index baf52bd8034d..ab4ee9ede0de 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -178,6 +178,7 @@ static int pa_sync_no_past(struct sync_state *state, recv_state = state->recv_state; bt_addr_le_copy(¶m.addr, &recv_state->addr); + param.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE; param.sid = recv_state->adv_sid; param.skip = PA_SYNC_SKIP; param.timeout = interval_to_sync_timeout(pa_interval); From f1a3b7d7e23a7d0922cb914ea91c9f5ebde2d2fb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 12:49:54 +0200 Subject: [PATCH 0768/2042] Bluetooth: CAP: Add null check for free_conn When populating the conns array in bt_cap_initiator_codec_configured, coverity did not like just having the __ASSERT, so modified the checks. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/cap_initiator.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index ec164de4b73b..8b98fa6edb9b 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -941,8 +941,11 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) continue; } - __ASSERT(free_conn, "No free conns"); - *free_conn = stream_conn; + if (free_conn != NULL) { + *free_conn = stream_conn; + } else { + __ASSERT_PRINT("No free conns"); + } } /* All streams in the procedure share the same unicast group, so we just From 3d53a75180878683098d359a74c4c9c4d0a0bd1d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 19 Jun 2023 19:17:04 +0200 Subject: [PATCH 0769/2042] Bluetooth: BAP: Shell: Register CAP callbacks if CAP initiator If we are use the shell as a CAP initiator, then we need to register the stream callbacks for the CAP streams as well, as CAP will use the BAP callbacks. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 63e088553b1f..fbf74f8f60b0 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -2306,6 +2306,15 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_BAP_UNICAST) for (i = 0; i < ARRAY_SIZE(unicast_streams); i++) { bt_bap_stream_cb_register(&unicast_streams[i].stream.bap_stream, &stream_ops); + + if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) && + IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) { + /* If we use the cap initiator, we need to register the callbacks for CAP + * as well, as CAP will override and use the BAP callbacks if doing a CAP + * procedure + */ + bt_cap_stream_ops_register(&unicast_streams[i].stream, &stream_ops); + } } #endif /* CONFIG_BT_BAP_UNICAST */ From 92d612e79d5eb9bd368da4a548b3ade47ebf779e Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:23:46 +0200 Subject: [PATCH 0770/2042] Bluetooth: VCP: Return if VOCS/AICS inst count is 0 In the prepare_aics_inst and prepare_vocs_inst the loops should not run if the count is 0. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/vcp_vol_rend.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/bluetooth/audio/vcp_vol_rend.c b/subsys/bluetooth/audio/vcp_vol_rend.c index 51dab75b3d4a..5e982a1db33d 100644 --- a/subsys/bluetooth/audio/vcp_vol_rend.c +++ b/subsys/bluetooth/audio/vcp_vol_rend.c @@ -260,6 +260,10 @@ static int prepare_vocs_inst(struct bt_vcp_vol_rend_register_param *param) int j; int i; + if (CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT == 0) { + return 0; + } + __ASSERT(param, "NULL param"); for (j = 0, i = 0; i < ARRAY_SIZE(vcs_attrs); i++) { @@ -303,6 +307,10 @@ static int prepare_aics_inst(struct bt_vcp_vol_rend_register_param *param) int j; int i; + if (CONFIG_BT_VCP_VOL_REND_AICS_INSTANCE_COUNT == 0) { + return 0; + } + __ASSERT(param, "NULL param"); for (j = 0, i = 0; i < ARRAY_SIZE(vcs_attrs); i++) { From 11b12ae905f6dd7e048bfb2f2a2bfe2a39141823 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:28:00 +0200 Subject: [PATCH 0771/2042] Bluetooth: MICP: Return if AICS inst count is 0 In the prepare_aics_inst the loop should not run if the count is 0. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/micp_mic_dev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/audio/micp_mic_dev.c b/subsys/bluetooth/audio/micp_mic_dev.c index 9ba3abdd2361..272edfd2eb6b 100644 --- a/subsys/bluetooth/audio/micp_mic_dev.c +++ b/subsys/bluetooth/audio/micp_mic_dev.c @@ -116,6 +116,10 @@ static int prepare_aics_inst(struct bt_micp_mic_dev_register_param *param) int j; int err; + if (CONFIG_BT_MICP_MIC_DEV_AICS_INSTANCE_COUNT == 0) { + return 0; + } + for (j = 0, i = 0; i < ARRAY_SIZE(mics_attrs); i++) { if (bt_uuid_cmp(mics_attrs[i].uuid, BT_UUID_GATT_INCLUDE) == 0) { micp_inst.aics_insts[j] = bt_aics_free_instance_get(); From 915a649392694f0dcb76415c46c742cb2c857772 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 28 Jun 2023 14:38:28 +0200 Subject: [PATCH 0772/2042] Bluetooth: CSIP: Add missing input validation for csis_int_by_handle The bt_csip_set_coordinator_csis_inst_by_handle did not check the input parameters and could call lookup_instance_by_handle with handle == 0 which triggers an ASSERT. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/csip_set_coordinator.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index 6a910c3bdc55..7d506e725808 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -1375,8 +1375,21 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { struct bt_csip_set_coordinator_csis_inst *bt_csip_set_coordinator_csis_inst_by_handle( struct bt_conn *conn, uint16_t start_handle) { - const struct bt_csip_set_coordinator_svc_inst *svc_inst = - lookup_instance_by_handle(conn, start_handle); + const struct bt_csip_set_coordinator_svc_inst *svc_inst; + + CHECKIF(conn == NULL) { + LOG_DBG("conn is NULL"); + + return NULL; + } + + CHECKIF(start_handle == 0) { + LOG_DBG("start_handle is 0"); + + return NULL; + } + + svc_inst = lookup_instance_by_handle(conn, start_handle); if (svc_inst != NULL) { struct bt_csip_set_coordinator_inst *client; From c651dfbb2b99a0d5d4537544519b6f622c1e255c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 30 Jun 2023 10:36:19 -0300 Subject: [PATCH 0773/2042] soc: nuvoton_numaker: add guard in defconfg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It must be guarded so the option selection doesn't appear at root level. Fixes #59876 Signed-off-by: Manuel Argüelles --- soc/arm/nuvoton_numaker/Kconfig.defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soc/arm/nuvoton_numaker/Kconfig.defconfig b/soc/arm/nuvoton_numaker/Kconfig.defconfig index dbe62c375f4b..72d91af7c01e 100644 --- a/soc/arm/nuvoton_numaker/Kconfig.defconfig +++ b/soc/arm/nuvoton_numaker/Kconfig.defconfig @@ -4,5 +4,9 @@ source "soc/arm/nuvoton_numaker/*/Kconfig.defconfig.series" +if SOC_FAMILY_NUMAKER + config RESET default y + +endif From 793910fdde42ceed84fbbc5e032a9cecb7409cee Mon Sep 17 00:00:00 2001 From: Najumon Ba Date: Thu, 30 Mar 2023 11:17:50 +0530 Subject: [PATCH 0774/2042] build: west: add acpica module into zephyr project Integrate acpica module into zephyr project for enable acpi bus support. Signed-off-by: Najumon Ba --- modules/acpica/CMakeLists.txt | 177 ++++++++++++++++++++++++++++++++++ modules/acpica/Kconfig | 9 ++ west.yml | 3 + 3 files changed, 189 insertions(+) create mode 100644 modules/acpica/CMakeLists.txt create mode 100644 modules/acpica/Kconfig diff --git a/modules/acpica/CMakeLists.txt b/modules/acpica/CMakeLists.txt new file mode 100644 index 000000000000..29f685e02668 --- /dev/null +++ b/modules/acpica/CMakeLists.txt @@ -0,0 +1,177 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +set(ACPI_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/) +set(INC_DIR ${ACPI_DIR}/source/include/) +set(SRC_DIR ${ACPI_DIR}/source) +set(COMP_DIR ${ACPI_DIR}/source/components) +set(PARENT_SRC_DIR ${ACPI_DIR}../../zephyr) +set(ACPI_PARENT_DIR ${ACPI_DIR}/../) + +zephyr_include_directories( + ${PARENT_SRC_DIR}/include/ + ${ACPI_PARENT_DIR}/ + ${INC_DIR}/ + ${INC_DIR}/platform/ + ${SRC_DIR}/compiler/ + ${ZEPHYR_CURRENT_MODULE_DIR}/generate/zephyr/ + ${SRC_DIR}/tools/acpiexec/ + ${SRC_DIR}/tools/acpidump/ +) + +if (CONFIG_ACPI) + zephyr_library() + + add_compile_definitions(__ZEPHYR__) + add_compile_definitions(ACPI_DEBUG_OUTPUT) + add_compile_definitions(ACPI_EXAMPLE_APP) + add_compile_definitions(CONFIG_EXTERNAL_LIBC) + + get_filename_component(libname "${SRC_DIR}/common/" NAME) + + zephyr_library_sources( + ${COMP_DIR}/dispatcher/dsargs.c + ${COMP_DIR}/dispatcher/dscontrol.c + ${COMP_DIR}/dispatcher/dsdebug.c + ${COMP_DIR}/dispatcher/dsfield.c + ${COMP_DIR}/dispatcher/dsinit.c + ${COMP_DIR}/dispatcher/dsmethod.c + ${COMP_DIR}/dispatcher/dsmthdat.c + ${COMP_DIR}/dispatcher/dsobject.c + ${COMP_DIR}/dispatcher/dsopcode.c + ${COMP_DIR}/dispatcher/dspkginit.c + ${COMP_DIR}/dispatcher/dsutils.c + ${COMP_DIR}/dispatcher/dswexec.c + ${COMP_DIR}/dispatcher/dswload.c + ${COMP_DIR}/dispatcher/dswload2.c + ${COMP_DIR}/dispatcher/dswscope.c + ${COMP_DIR}/dispatcher/dswstate.c + + ${COMP_DIR}/events/evhandler.c + ${COMP_DIR}/events/evmisc.c + ${COMP_DIR}/events/evregion.c + ${COMP_DIR}/events/evrgnini.c + ${COMP_DIR}/events/evxface.c + ${COMP_DIR}/events/evxfregn.c + ${COMP_DIR}/executer/exconcat.c + ${COMP_DIR}/executer/exconfig.c + ${COMP_DIR}/executer/exconvrt.c + ${COMP_DIR}/executer/excreate.c + ${COMP_DIR}/executer/exdebug.c + ${COMP_DIR}/executer/exdump.c + ${COMP_DIR}/executer/exfield.c + ${COMP_DIR}/executer/exfldio.c + ${COMP_DIR}/executer/exmisc.c + ${COMP_DIR}/executer/exmutex.c + ${COMP_DIR}/executer/exnames.c + ${COMP_DIR}/executer/exoparg1.c + ${COMP_DIR}/executer/exoparg2.c + ${COMP_DIR}/executer/exoparg3.c + ${COMP_DIR}/executer/exoparg6.c + ${COMP_DIR}/executer/exprep.c + ${COMP_DIR}/executer/exregion.c + ${COMP_DIR}/executer/exresnte.c + ${COMP_DIR}/executer/exresolv.c + ${COMP_DIR}/executer/exresop.c + ${COMP_DIR}/executer/exserial.c + ${COMP_DIR}/executer/exstore.c + ${COMP_DIR}/executer/exstoren.c + ${COMP_DIR}/executer/exstorob.c + ${COMP_DIR}/executer/exsystem.c + ${COMP_DIR}/executer/extrace.c + ${COMP_DIR}/executer/exutils.c + ${COMP_DIR}/hardware/hwpci.c + ${COMP_DIR}/namespace/nsaccess.c + ${COMP_DIR}/namespace/nsalloc.c + ${COMP_DIR}/namespace/nsarguments.c + ${COMP_DIR}/namespace/nsconvert.c + ${COMP_DIR}/namespace/nsdump.c + ${COMP_DIR}/namespace/nseval.c + ${COMP_DIR}/namespace/nsinit.c + ${COMP_DIR}/namespace/nsload.c + ${COMP_DIR}/namespace/nsnames.c + ${COMP_DIR}/namespace/nsobject.c + ${COMP_DIR}/namespace/nsparse.c + ${COMP_DIR}/namespace/nspredef.c + ${COMP_DIR}/namespace/nsprepkg.c + ${COMP_DIR}/namespace/nsrepair.c + ${COMP_DIR}/namespace/nsrepair2.c + ${COMP_DIR}/namespace/nssearch.c + ${COMP_DIR}/namespace/nsutils.c + ${COMP_DIR}/namespace/nswalk.c + ${COMP_DIR}/namespace/nsxfeval.c + ${COMP_DIR}/namespace/nsxfname.c + ${COMP_DIR}/namespace/nsxfobj.c + ${COMP_DIR}/parser/psargs.c + ${COMP_DIR}/parser/psloop.c + ${COMP_DIR}/parser/psobject.c + ${COMP_DIR}/parser/psopcode.c + ${COMP_DIR}/parser/psopinfo.c + ${COMP_DIR}/parser/psparse.c + ${COMP_DIR}/parser/psscope.c + ${COMP_DIR}/parser/pstree.c + ${COMP_DIR}/parser/psutils.c + ${COMP_DIR}/parser/pswalk.c + ${COMP_DIR}/parser/psxface.c + ${COMP_DIR}/tables/tbdata.c + ${COMP_DIR}/tables/tbfadt.c + ${COMP_DIR}/tables/tbfind.c + ${COMP_DIR}/tables/tbinstal.c + ${COMP_DIR}/tables/tbprint.c + ${COMP_DIR}/tables/tbutils.c + ${COMP_DIR}/tables/tbxface.c + ${COMP_DIR}/tables/tbxfload.c + ${COMP_DIR}/tables/tbxfroot.c + ${COMP_DIR}/utilities/utaddress.c + ${COMP_DIR}/utilities/utalloc.c + ${COMP_DIR}/utilities/utascii.c + ${COMP_DIR}/utilities/utbuffer.c + ${COMP_DIR}/utilities/utcache.c + ${COMP_DIR}/utilities/utcksum.c + ${COMP_DIR}/utilities/utcopy.c + ${COMP_DIR}/utilities/utdebug.c + ${COMP_DIR}/utilities/utdecode.c + ${COMP_DIR}/utilities/utdelete.c + ${COMP_DIR}/utilities/uterror.c + ${COMP_DIR}/utilities/uteval.c + ${COMP_DIR}/utilities/utexcep.c + ${COMP_DIR}/utilities/utglobal.c + ${COMP_DIR}/utilities/uthex.c + ${COMP_DIR}/utilities/utids.c + ${COMP_DIR}/utilities/utinit.c + ${COMP_DIR}/utilities/utlock.c + ${COMP_DIR}/utilities/utmath.c + ${COMP_DIR}/utilities/utmisc.c + ${COMP_DIR}/utilities/utmutex.c + ${COMP_DIR}/utilities/utobject.c + ${COMP_DIR}/utilities/utosi.c + ${COMP_DIR}/utilities/utownerid.c + ${COMP_DIR}/utilities/utnonansi.c + ${COMP_DIR}/utilities/utpredef.c + ${COMP_DIR}/utilities/utresrc.c + ${COMP_DIR}/utilities/utstate.c + ${COMP_DIR}/utilities/utstring.c + ${COMP_DIR}/utilities/utstrsuppt.c + ${COMP_DIR}/utilities/utstrtoul64.c + ${COMP_DIR}/utilities/utxface.c + ${COMP_DIR}/utilities/utxferror.c + ${COMP_DIR}/utilities/utxfinit.c + ${COMP_DIR}/utilities/utresdecode.c + ${COMP_DIR}/hardware/hwvalid.c + ${COMP_DIR}/resources/rsxface.c + ${COMP_DIR}/resources/rsutils.c + ${COMP_DIR}/resources/rsaddr.c + ${COMP_DIR}/resources/rscalc.c + ${COMP_DIR}/resources/rscreate.c + ${COMP_DIR}/resources/rsdumpinfo.c + ${COMP_DIR}/resources/rsinfo.c + ${COMP_DIR}/resources/rsio.c + ${COMP_DIR}/resources/rsirq.c + ${COMP_DIR}/resources/rslist.c + ${COMP_DIR}/resources/rsmemory.c + ${COMP_DIR}/resources/rsmisc.c + ${COMP_DIR}/resources/rsserial.c + + ${SRC_DIR}/os_specific/service_layers/oszephyr.c + ) +endif (CONFIG_ACPI) diff --git a/modules/acpica/Kconfig b/modules/acpica/Kconfig new file mode 100644 index 000000000000..07d6d24c2787 --- /dev/null +++ b/modules/acpica/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config ACPI + bool + +menu "ACPI driver support" + +endmenu diff --git a/west.yml b/west.yml index 2b055344f7ac..eee485402fec 100644 --- a/west.yml +++ b/west.yml @@ -29,6 +29,9 @@ manifest: # # Please add items below based on alphabetical order projects: + - name: acpica + revision: f16a0b4d0f0edd7b78a332fcf507be2187fac21e + path: modules/lib/acpica - name: bsim repo-path: babblesim-manifest revision: 384a091445c57b44ac8cbd18ebd245b47c71db94 From 90347583acc5ff2158555123a633414284d4cfb3 Mon Sep 17 00:00:00 2001 From: Najumon Ba Date: Thu, 30 Mar 2023 12:43:28 +0530 Subject: [PATCH 0775/2042] board: x86: rpl_crb: added acpi support for raptor lake crb added acpi support for raptor lake crb Signed-off-by: Najumon Ba --- boards/x86/rpl_crb/Kconfig.defconfig | 8 ++++++++ boards/x86/rpl_crb/rpl_crb_defconfig | 2 ++ 2 files changed, 10 insertions(+) diff --git a/boards/x86/rpl_crb/Kconfig.defconfig b/boards/x86/rpl_crb/Kconfig.defconfig index bcb79a4f485f..b8d9d4ba6080 100644 --- a/boards/x86/rpl_crb/Kconfig.defconfig +++ b/boards/x86/rpl_crb/Kconfig.defconfig @@ -26,4 +26,12 @@ config APIC_TIMER_TSC_N default 249 endif +config ACPI + default y + +if SHELL +config SHELL_STACK_SIZE + default 320000 +endif + endif # BOARD_RPL_CRB diff --git a/boards/x86/rpl_crb/rpl_crb_defconfig b/boards/x86/rpl_crb/rpl_crb_defconfig index d5b40368fa46..0a720a83ce8f 100644 --- a/boards/x86/rpl_crb/rpl_crb_defconfig +++ b/boards/x86/rpl_crb/rpl_crb_defconfig @@ -13,3 +13,5 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y +CONFIG_HEAP_MEM_POOL_SIZE=64000000 +CONFIG_MAIN_STACK_SIZE=320000 From f25dfcf88ca56f0d503ea7f117a26996963110f2 Mon Sep 17 00:00:00 2001 From: Najumon Ba Date: Thu, 30 Mar 2023 12:46:11 +0530 Subject: [PATCH 0776/2042] lib: acpi: added acpi support using acpica lib Add ACPI support for Zephyr using acpica open source project. ACPI subsystem use to discover and configure hardware components, perform power management (e.g. putting unused hardware components to sleep), auto configuration (e.g. Plug and Play and hot swapping) etc. Signed-off-by: Najumon Ba --- drivers/Kconfig | 1 - include/zephyr/acpi/acpi.h | 125 +++++++ lib/CMakeLists.txt | 1 + lib/Kconfig | 1 + lib/acpi/CMakeLists.txt | 6 + lib/acpi/Kconfig | 54 +++ lib/acpi/acpi.c | 649 +++++++++++++++++++++++++++++++++++++ lib/acpi/acpi_shell.c | 281 ++++++++++++++++ 8 files changed, 1117 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/acpi/acpi.h create mode 100644 lib/acpi/CMakeLists.txt create mode 100644 lib/acpi/Kconfig create mode 100644 lib/acpi/acpi.c create mode 100644 lib/acpi/acpi_shell.c diff --git a/drivers/Kconfig b/drivers/Kconfig index d615249727c3..5641465a3e3a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -82,5 +82,4 @@ source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" source "drivers/sip_svc/Kconfig" - endmenu diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h new file mode 100644 index 000000000000..b3e46ef52cd4 --- /dev/null +++ b/include/zephyr/acpi/acpi.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DRIVERS_ACPI_H_ +#define ZEPHYR_INCLUDE_DRIVERS_ACPI_H_ +#include +#include + +#define ACPI_RES_INVALID ACPI_RESOURCE_TYPE_MAX + +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; +}; + +/** + * @brief retrieve legacy interrupt number for a PCI device. + * + * @param bdf the BDF of endpoint/PCI device + * @return return IRQ number or UINT_MAX if not fund + */ +uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf); + +/** + * @brief retrieve current resource setting of a device. + * + * @param dev_name the name of the device + * @param res the list of acpi resource list + * @return return 0 on success or error code + */ +int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res); + +/** + * @brief retrieve possible resource setting of a device. + * + * @param dev_name the name of the device + * @param res the list of acpi resource list + * @return return 0 on success or error code + */ +int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res); + +/** + * @brief Free current resource list memory which is retrived by + * acpi_current_resource_get. + * + * @param res the list of acpi resource list + * @return return 0 on success or error code + */ +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 the the size of 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 given resource type. + * + * @param res the list of acpi resource list + * @param res_type the acpi resource type + * @return resource list for the given type on success or NULL + */ +ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type); + +/** + * @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 + */ +struct acpi_dev *acpi_device_get(char *hid, int inst); + +/** + * @brief retrieve acpi device info form index. + * + * @param index the device index of an acpi child device + * @return acpi child device info on success or NULL + */ +struct acpi_dev *acpi_device_by_index_get(int index); + +/** + * @brief parse resource table for irq info. + * + * @param res_lst the list of acpi resource list + * @return irq resource list on success or NULL + */ +static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst) +{ + ACPI_RESOURCE *res = acpi_resource_parse(res_lst, ACPI_RESOURCE_TYPE_IRQ); + + return res ? &res->Data.Irq : NULL; +} + +/** + * @brief parse resource table for identify resource type. + * + * @param res the list of acpi resource list + * @return resource type on success or invalid resource type + */ +int acpi_device_type_get(ACPI_RESOURCE *res); + +/** + * @brief retrieve acpi table for the given signature. + * + * @param signature pointer to the 4-character ACPI signature for the requested table + * @param inst instance number for the requested table + * @param acpi_table pointer to the acpi table + * @return return 0 on success or error code + */ +int acpi_table_get(char *signature, int inst, void **acpi_table); + +#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c413b3144764..0f15dbfc3c9b 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(hash) add_subdirectory(os) 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 57c185204fb7..b57628a759d9 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -17,4 +17,5 @@ source "lib/open-amp/Kconfig" source "lib/smf/Kconfig" +source "lib/acpi/Kconfig" endmenu diff --git a/lib/acpi/CMakeLists.txt b/lib/acpi/CMakeLists.txt new file mode 100644 index 000000000000..301c680e9a52 --- /dev/null +++ b/lib/acpi/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(acpi.c) +zephyr_library_sources_ifdef(CONFIG_ACPI_SHELL acpi_shell.c) diff --git a/lib/acpi/Kconfig b/lib/acpi/Kconfig new file mode 100644 index 000000000000..366dfa66782b --- /dev/null +++ b/lib/acpi/Kconfig @@ -0,0 +1,54 @@ +# ACPI configuration options + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ACPI + bool "ACPI support" + help + This option enables support for ACPI driver. + +if ACPI + +module = ACPI +module-str = acpi +source "subsys/logging/Kconfig.template.log_config" + +config ACPI_MAX_PRT_ENTRY + int "Size of PRT buffer" + default 4096 + help + Size of PRT table buffer. + +config ACPI_SHELL + bool "ACPI command Shell" + default y + depends on SHELL + help + Enable commands for debugging ACPI using the built-in shell. + +config ACPI_DEV_MAX + int "maximum child devices" + default 1000 + help + maximum acpi child devices. + +config ACPI_INIT_PRIORITY + int "acpi boot time init level" + default 42 + help + boot time init level for acpi driver. + +config ACPI_MAX_INIT_TABLES + int "acpi table size" + default 16 + help + acpi table size. + +endif # ACPI + +config ACPI_HID_LEN_MAX + int "Size of HID name" + default 12 + help + Size of HID string. diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c new file mode 100644 index 000000000000..c65e40b25d6f --- /dev/null +++ b/lib/acpi/acpi.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "acpi.h" +#include "accommon.h" +#include "acapps.h" +#include + +#include +#include +#include +LOG_MODULE_REGISTER(ACPI, CONFIG_ACPI_LOG_LEVEL); + +struct acpi { + struct acpi_dev child_dev[CONFIG_ACPI_DEV_MAX]; + int num_dev; + ACPI_PCI_ROUTING_TABLE pci_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; + bool early_init; + int status; +}; + +static struct acpi bus_ctx = { + .status = AE_NOT_CONFIGURED, +}; + +static ACPI_TABLE_DESC acpi_table[CONFIG_ACPI_MAX_INIT_TABLES]; + +static int acpi_init(void); + +static int check_init_status(void) +{ + int ret; + + if (ACPI_SUCCESS(bus_ctx.status)) { + return 0; + } + + if (bus_ctx.status == AE_NOT_CONFIGURED) { + LOG_DBG("ACPI init\n"); + ret = acpi_init(); + } else { + LOG_ERR("ACPI init was not success\n"); + ret = -EIO; + } + return ret; +} + +static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx) +{ + ACPI_INFO(("Received a notify 0x%X", value)); +} + +static ACPI_STATUS region_handler(UINT32 Function, ACPI_PHYSICAL_ADDRESS address, UINT32 bit_width, + UINT64 *value, void *handler_ctx, void *region_ctx) +{ + return AE_OK; +} + +static ACPI_STATUS region_init(ACPI_HANDLE RegionHandle, UINT32 Function, void *handler_ctx, + void **region_ctx) +{ + if (Function == ACPI_REGION_DEACTIVATE) { + *region_ctx = NULL; + } else { + *region_ctx = RegionHandle; + } + + return AE_OK; +} + +static ACPI_STATUS install_handlers(void) +{ + ACPI_STATUS status; + + /* Install global notify handler */ + status = AcpiInstallNotifyHandler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, notify_handler, + NULL); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While installing Notify handler")); + goto exit; + } + + status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_SYSTEM_MEMORY, + region_handler, region_init, NULL); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While installing an OpRegion handler")); + } +exit: + + return status; +} + +static ACPI_STATUS initialize_acpica(void) +{ + ACPI_STATUS status; + + /* Initialize the ACPI subsystem */ + status = AcpiInitializeSubsystem(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI")); + goto exit; + } + + /* Initialize the ACPI Table Manager and get all ACPI tables */ + if (!bus_ctx.early_init) { + status = AcpiInitializeTables(NULL, 16, FALSE); + } else { + /* Copy the root table list to dynamic memory if already initialized */ + status = AcpiReallocateRootTable(); + } + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While initializing Table Manager")); + goto exit; + } + + /* Initialize the ACPI hardware */ + status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While enabling ACPI")); + goto exit; + } + + /* Install local handlers */ + status = install_handlers(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While installing handlers")); + goto exit; + } + + /* Create the ACPI namespace from ACPI tables */ + status = AcpiLoadTables(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While loading ACPI tables")); + goto exit; + } + + /* Complete the ACPI namespace object initialization */ + status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "While initializing ACPI objects")); + } +exit: + + return status; +} + +static ACPI_NAMESPACE_NODE *acpi_name_lookup(char *name) +{ + char *path; + ACPI_STATUS status; + ACPI_NAMESPACE_NODE *node; + + LOG_DBG(""); + + status = AcpiNsInternalizeName(name, &path); + if (ACPI_FAILURE(status)) { + LOG_ERR("Invalid namestring: %s", name); + return NULL; + } + + status = AcpiNsLookup(NULL, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node); + if (ACPI_FAILURE(status)) { + LOG_ERR("Could not locate name: %s, %d", name, status); + node = NULL; + } + + ACPI_FREE(path); + return node; +} + +static ACPI_NAMESPACE_NODE *acpi_evaluate_method(char *bus_name, char *method) +{ + ACPI_NAMESPACE_NODE *node; + ACPI_NAMESPACE_NODE *handle; + ACPI_NAMESPACE_NODE *prt_node = NULL; + + LOG_DBG("%s", bus_name); + + handle = acpi_name_lookup(bus_name); + if (!handle) { + LOG_ERR("No ACPI node with given name: %s", bus_name); + goto exit; + } + + if (handle->Type != ACPI_TYPE_DEVICE) { + LOG_ERR("No ACPI node foud with given name: %s", bus_name); + goto exit; + } + + node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, handle); + + (void)AcpiGetHandle(node, method, ACPI_CAST_PTR(ACPI_HANDLE, &prt_node)); + + if (!prt_node) { + LOG_ERR("No entry for the ACPI node with given name: %s", bus_name); + goto exit; + } + return node; +exit: + return NULL; +} + +static ACPI_STATUS acpi_enable_pic_mode(void) +{ + ACPI_STATUS status; + ACPI_OBJECT_LIST arg_list; + ACPI_OBJECT arg[1]; + + arg_list.Count = 1; + arg_list.Pointer = arg; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; + + status = AcpiEvaluateObject(NULL, "\\_PIC", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + LOG_WRN("error While executing \\_pic method: %d", status); + } + + return status; +} + +static int acpi_get_irq_table(struct acpi *bus, char *bus_name, + ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size) +{ + ACPI_BUFFER rt_buffer; + ACPI_NAMESPACE_NODE *node; + int status; + + LOG_DBG("%s", bus_name); + + node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT); + if (!node) { + LOG_ERR("Evaluation failed for given device: %s", bus_name); + return -ENODEV; + } + + rt_buffer.Pointer = rt_table; + rt_buffer.Length = ACPI_DEBUG_BUFFER_SIZE; + + status = AcpiGetIrqRoutingTable(node, &rt_buffer); + if (ACPI_FAILURE(status)) { + LOG_ERR("unable to retrieve IRQ Routing Table: %s", bus_name); + return -EIO; + } + + for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { + if (!bus->pci_prt_table[i].SourceIndex) { + break; + } + /* mark the PRT irq numbers as reserved. */ + arch_irq_set_used(bus->pci_prt_table[i].SourceIndex); + } + + return 0; +} + +static int acpi_retrieve_legacy_irq(struct acpi *bus) +{ + /* TODO: assume platform have only one PCH with single PCI bus (bus 0). */ + return acpi_get_irq_table(bus, "_SB.PC00", bus->pci_prt_table, sizeof(bus->pci_prt_table)); +} + +static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 level, void *ctx, + void **ret_value) +{ + ACPI_NAMESPACE_NODE *node; + ACPI_BUFFER rt_buffer; + struct acpi *bus = (struct acpi *)ctx; + struct acpi_dev *child_dev; + + node = ACPI_CAST_PTR(ACPI_NAMESPACE_NODE, obj_handle); + char *path_name; + int status; + ACPI_DEVICE_INFO *dev_info; + + LOG_DBG("%s %p\n", __func__, node); + + /* get device info such as HID, Class ID etc. */ + status = AcpiGetObjectInfo(obj_handle, &dev_info); + if (ACPI_FAILURE(status)) { + LOG_ERR("AcpiGetObjectInfo failed: %s", AcpiFormatException(status)); + goto exit; + } + + if (bus->num_dev >= CONFIG_ACPI_DEV_MAX) { + return AE_NO_MEMORY; + } + + child_dev = (struct acpi_dev *)&bus->child_dev[bus->num_dev++]; + child_dev->handle = obj_handle; + child_dev->dev_info = dev_info; + + path_name = AcpiNsGetNormalizedPathname(node, TRUE); + if (!path_name) { + LOG_ERR("No memory for path_name\n"); + goto exit; + } else { + LOG_DBG("Device path: %s\n", path_name); + child_dev->path = path_name; + } + + rt_buffer.Pointer = NULL; + rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = AcpiGetCurrentResources(node, &rt_buffer); + if (ACPI_FAILURE(status)) { + LOG_DBG("AcpiGetCurrentResources failed: %s", AcpiFormatException(status)); + } else { + child_dev->res_lst = rt_buffer.Pointer; + } + +exit: + + return status; +} + +static int acpi_enum_devices(struct acpi *bus) +{ + LOG_DBG(""); + + AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + dev_resource_enum_callback, NULL, bus, NULL); + + return 0; +} + +static int acpi_init(void) +{ + int status; + + LOG_DBG(""); + + if (bus_ctx.status != AE_NOT_CONFIGURED) { + LOG_DBG("acpi init already done"); + return bus_ctx.status; + } + + /* For debug version only */ + ACPI_DEBUG_INITIALIZE(); + + status = initialize_acpica(); + if (ACPI_FAILURE(status)) { + LOG_ERR("Error in ACPI init:%d", status); + goto exit; + } + + /* Enable IO APIC mode */ + status = acpi_enable_pic_mode(); + if (ACPI_FAILURE(status)) { + LOG_WRN("Error in enable pic mode acpi method:%d", status); + } + + status = acpi_retrieve_legacy_irq(&bus_ctx); + if (status) { + LOG_ERR("Error in retrieve legacy interrupt info:%d", status); + goto exit; + } + + acpi_enum_devices(&bus_ctx); + +exit: + bus_ctx.status = status; + + return status; +} + +static int acpi_early_init(void) +{ + ACPI_STATUS status; + + LOG_DBG(""); + + if (bus_ctx.early_init) { + LOG_DBG("acpi early init already done"); + return 0; + } + + status = AcpiInitializeTables(acpi_table, CONFIG_ACPI_MAX_INIT_TABLES, TRUE); + if (ACPI_FAILURE(status)) { + LOG_ERR("Error in acpi table init:%d", status); + return -EIO; + } + + bus_ctx.early_init = true; + + return 0; +} + +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 (((bus_ctx.pci_prt_table[i].Address >> 16) & 0xffff) == slot && + bus_ctx.pci_prt_table[i].Pin + 1 == pin) { + LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, + bus_ctx.pci_prt_table[i].SourceIndex); + return bus_ctx.pci_prt_table[i].SourceIndex; + } + } + + return UINT_MAX; +} + +int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res) +{ + ACPI_BUFFER rt_buffer; + ACPI_NAMESPACE_NODE *node; + int status; + + LOG_DBG("%s", dev_name); + + status = check_init_status(); + if (status) { + return status; + } + + node = acpi_evaluate_method(dev_name, METHOD_NAME__CRS); + if (!node) { + LOG_ERR("Evaluation failed for given device: %s", dev_name); + status = -ENOTSUP; + goto exit; + } + + rt_buffer.Pointer = NULL; + rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = AcpiGetCurrentResources(node, &rt_buffer); + if (ACPI_FAILURE(status)) { + LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status)); + status = -ENOTSUP; + } else { + *res = rt_buffer.Pointer; + } + +exit: + + return status; +} + +int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res) +{ + ACPI_BUFFER rt_buffer; + ACPI_NAMESPACE_NODE *node; + int status; + + LOG_DBG("%s", dev_name); + + status = check_init_status(); + if (status) { + return status; + } + + node = acpi_evaluate_method(dev_name, METHOD_NAME__PRS); + if (!node) { + LOG_ERR("Evaluation failed for given device: %s", dev_name); + status = -ENOTSUP; + goto exit; + } + + rt_buffer.Pointer = NULL; + rt_buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER; + + AcpiGetPossibleResources(node, &rt_buffer); + *res = rt_buffer.Pointer; + +exit: + + return status; +} + +int acpi_current_resource_free(ACPI_RESOURCE *res) +{ + ACPI_FREE(res); + + return 0; +} + +int acpi_get_irq_routing_table(char *bus_name, + ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size) +{ + int ret; + + ret = check_init_status(); + if (ret) { + return ret; + } + + return acpi_get_irq_table(&bus_ctx, bus_name, rt_table, rt_size); +} + +ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) +{ + do { + if (!res->Length) { + LOG_DBG("Error: zero length found!\n"); + break; + } else if (res->Type == res_type) { + break; + } + res = ACPI_NEXT_RESOURCE(res); + } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); + + if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { + return NULL; + } + + return res; +} + +static int acpi_res_type(ACPI_RESOURCE *res) +{ + int type; + + switch (res->Type) { + case ACPI_RESOURCE_TYPE_IO: + type = ACPI_RESOURCE_TYPE_IO; + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + type = ACPI_RESOURCE_TYPE_FIXED_IO; + break; + case ACPI_RESOURCE_TYPE_MEMORY24: + type = ACPI_RESOURCE_TYPE_MEMORY24; + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + type = ACPI_RESOURCE_TYPE_MEMORY32; + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + type = ACPI_RESOURCE_TYPE_FIXED_MEMORY32; + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + type = ACPI_RESOURCE_TYPE_ADDRESS16; + break; + case ACPI_RESOURCE_TYPE_ADDRESS32: + type = ACPI_RESOURCE_TYPE_ADDRESS32; + break; + case ACPI_RESOURCE_TYPE_ADDRESS64: + type = ACPI_RESOURCE_TYPE_ADDRESS64; + break; + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + type = ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64; + break; + default: + type = ACPI_RESOURCE_TYPE_MAX; + } + + return type; +} + +int acpi_device_type_get(ACPI_RESOURCE *res) +{ + int type = ACPI_RESOURCE_TYPE_MAX; + + do { + if (!res->Length) { + LOG_ERR("Error: zero length found!\n"); + break; + } + type = acpi_res_type(res); + if (type != ACPI_RESOURCE_TYPE_MAX) { + break; + } + res = ACPI_NEXT_RESOURCE(res); + } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); + + return type; +} + +struct acpi_dev *acpi_device_get(char *hid, int inst) +{ + struct acpi_dev *child_dev; + int i = 0, inst_id; + + LOG_DBG(""); + + if (check_init_status()) { + return NULL; + } + + do { + child_dev = &bus_ctx.child_dev[i]; + if (!child_dev->path) { + LOG_DBG("NULL device path found\n"); + continue; + } + + if (!child_dev->res_lst || !child_dev->dev_info || + !child_dev->dev_info->HardwareId.Length) { + continue; + } + + 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) { + return child_dev; + } + } else { + return child_dev; + } + } + } while (i++ < bus_ctx.num_dev); + + return NULL; +} + +struct acpi_dev *acpi_device_by_index_get(int index) +{ + return index < bus_ctx.num_dev ? &bus_ctx.child_dev[index] : NULL; +} + +int acpi_table_get(char *signature, int inst, void **acpi_table) +{ + int status; + ACPI_TABLE_HEADER *table; + + if (!bus_ctx.early_init) { + status = acpi_early_init(); + if (status) { + LOG_ERR("ACPI early int failed"); + return status; + } + } + + status = AcpiGetTable(signature, inst, &table); + if (ACPI_FAILURE(status)) { + LOG_ERR("ACPI get table failed: %d", status); + return -EIO; + } + + *acpi_table = table; + + return 0; +} diff --git a/lib/acpi/acpi_shell.c b/lib/acpi/acpi_shell.c new file mode 100644 index 000000000000..570bb18d821e --- /dev/null +++ b/lib/acpi/acpi_shell.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_PR_BUFF (4096) + +static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; +static uint8_t prs_buffer[MAX_PR_BUFF]; + +static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst) +{ + ACPI_RESOURCE *res = res_lst; + + shell_print(sh, "\n**** ACPI Device Resource Info ****\n"); + + do { + + if (!res->Length) { + shell_error(sh, "Error: zero length found!\n"); + break; + } + + switch (res->Type) { + case ACPI_RESOURCE_TYPE_IRQ: + shell_print(sh, "\nACPI_RESOURCE_TYPE_IRQ\n\n"); + ACPI_RESOURCE_IRQ *irq_res = &res->Data.Irq; + + shell_print(sh, + "DescriptorLength: %x, Triggering:%x, Polarity:%x, Shareable:%x,", + irq_res->DescriptorLength, irq_res->Triggering, irq_res->Polarity, + irq_res->Shareable); + shell_print(sh, + "InterruptCount:%d, Interrupts[0]:%x\n", irq_res->InterruptCount, + irq_res->Interrupts[0]); + break; + case ACPI_RESOURCE_TYPE_IO: + ACPI_RESOURCE_IO * io_res = &res->Data.Io; + + shell_print(sh, "\n ACPI_RESOURCE_TYPE_IO\n"); + shell_print(sh, + "IoDecode: %x, Alignment:%x, AddressLength:%x, Minimum:%x,Maximum:%x\n", + io_res->IoDecode, io_res->Alignment, + io_res->AddressLength, io_res->Minimum, + io_res->Maximum); + break; + case ACPI_RESOURCE_TYPE_DMA: + shell_print(sh, "ACPI_RESOURCE_TYPE_DMA\n\n"); + break; + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + shell_print(sh, "ACPI_RESOURCE_TYPE_START_DEPENDENT\n\n"); + break; + case ACPI_RESOURCE_TYPE_END_DEPENDENT: + shell_print(sh, "ACPI_RESOURCE_TYPE_END_DEPENDENT\n\n"); + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_IO\n\n"); + break; + case ACPI_RESOURCE_TYPE_VENDOR: + shell_print(sh, "ACPI_RESOURCE_TYPE_VENDOR\n\n"); + break; + case ACPI_RESOURCE_TYPE_MEMORY24: + shell_print(sh, "ACPI_RESOURCE_TYPE_MEMORY24\n\n"); + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + ACPI_RESOURCE_MEMORY32 * mem_res = &res->Data.Memory32; + + shell_print(sh, "\nACPI_RESOURCE_TYPE_MEMORY32\n\n"); + shell_print(sh, "Minimum:%x, Maximum:%x\n", + mem_res->Minimum, mem_res->Maximum); + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + ACPI_RESOURCE_FIXED_MEMORY32 * fix_mem_res = &res->Data.FixedMemory32; + + shell_print(sh, "\nACPI_RESOURCE_TYPE_FIXED_MEMORY32\n\n"); + shell_print(sh, "Address:%x\n", fix_mem_res->Address); + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + shell_print(sh, "ACPI_RESOURCE_TYPE_ADDRESS16\n\n"); + break; + case ACPI_RESOURCE_TYPE_ADDRESS32: + ACPI_RESOURCE_ADDRESS32 * add_res = &res->Data.Address32; + + shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS32\n\n"); + shell_print(sh, "Minimum:%x, Maximum:%x\n", add_res->Address.Minimum, + add_res->Address.Maximum); + break; + case ACPI_RESOURCE_TYPE_ADDRESS64: + ACPI_RESOURCE_ADDRESS64 * add_res64 = &res->Data.Address64; + + shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS64\n\n"); + shell_print(sh, + "Minimum:%llx, Maximum:%llx\n", add_res64->Address.Minimum, + add_res64->Address.Maximum); + break; + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64\n\n"); + break; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ\n\n"); + break; + case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: + shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER\n\n"); + break; + case ACPI_RESOURCE_TYPE_GPIO: + shell_print(sh, "ACPI_RESOURCE_TYPE_GPIO\n\n"); + break; + case ACPI_RESOURCE_TYPE_FIXED_DMA: + shell_print(sh, "ACPI_RESOURCE_TYPE_FIXED_DMA\n\n"); + break; + case ACPI_RESOURCE_TYPE_SERIAL_BUS: + shell_print(sh, "ACPI_RESOURCE_TYPE_SERIAL_BUS\n\n"); + break; + case ACPI_RESOURCE_TYPE_PIN_FUNCTION: + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_FUNCTION\n\n"); + break; + case ACPI_RESOURCE_TYPE_PIN_CONFIG: + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_CONFIG\n\n"); + break; + case ACPI_RESOURCE_TYPE_PIN_GROUP: + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP\n\n"); + break; + case ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION: + shell_print(sh, + "ACPI_RESOURCE_TYPE_PIN_GROUP_FUNCTION\n\n"); + break; + case ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG: + shell_print(sh, "ACPI_RESOURCE_TYPE_PIN_GROUP_CONFIG\n\n"); + break; + default: + } + + res = ACPI_NEXT_RESOURCE(res); + + } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); +} + +static int dump_dev_crs(const struct shell *sh, size_t argc, char **argv) +{ + int status; + ACPI_RESOURCE *res_lst; + + if (argc < 2) { + shell_error(sh, "invalid arugment\n"); + return -EINVAL; + } + + status = acpi_current_resource_get(argv[1], &res_lst); + if (status) { + shell_error(sh, "Error on ACPI _CRS method: %d\n", status); + return status; + } + + dump_dev_res(sh, res_lst); + + acpi_current_resource_free(res_lst); + + return 0; +} + +static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) +{ + int status; + ACPI_RESOURCE *res_lst = (ACPI_RESOURCE *)prs_buffer; + + if (argc < 2) { + shell_error(sh, "invalid arugment\n"); + return -EINVAL; + } + + status = acpi_possible_resource_get(argv[1], &res_lst); + if (status) { + shell_error(sh, "Error in on ACPI _PRS method: %d\n", status); + return status; + } + + dump_dev_res(sh, res_lst); + + return 0; +} + +static int dump_prt(const struct shell *sh, size_t argc, char **argv) +{ + int status, cnt; + ACPI_PCI_ROUTING_TABLE *prt; + + if (argc < 2) { + shell_error(sh, "invalid arugment\n"); + return -EINVAL; + } + + status = acpi_get_irq_routing_table(argv[1], + irq_prt_table, sizeof(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\n", cnt); + shell_print(sh, + "DevNum: %lld Pin:%d IRQ: %d\n", (prt->Address >> 16) & 0xFFFF, prt->Pin, + prt->SourceIndex); + + prt = ACPI_ADD_PTR(ACPI_PCI_ROUTING_TABLE, prt, prt->Length); + } + + return 0; +} + +static int enum_dev(const struct shell *sh, size_t argc, char **argv) +{ + struct acpi_dev *dev; + + if (argc < 2) { + return -EINVAL; + } + + dev = acpi_device_get(argv[1], 0); + if (!dev || !dev->res_lst) { + shell_error(sh, "acpi get device failed for HID: %s\n", argv[1]); + return -EIO; + } + shell_print(sh, "\nName:%s\n", dev->path ? dev->path : "Non"); + dump_dev_res(sh, dev->res_lst); + + return 0; +} + +static int read_table(const struct shell *sh, size_t argc, char **argv) +{ + int status; + ACPI_TABLE_HEADER *table; + + if (argc < 2) { + return -EINVAL; + } + + shell_print(sh, "ACPI Table Name: %s\n", argv[1]); + + status = acpi_table_get(argv[1], 0, (void **)&table); + if (status) { + shell_error(sh, "ACPI get table failed: %d\n", status); + return status; + } + + shell_print(sh, "ACPI Table Info:\n"); + shell_print(sh, "Signature: %4s Table Length:%d Revision:%d OemId:%s\n", + table->Signature, table->Length, table->Revision, table->OemId); + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_acpi, + SHELL_CMD(crs, NULL, + "display device current resource settings (eg:acpi crs _SB.PC00.LPCB.RTC)", + dump_dev_crs), + SHELL_CMD(prs, NULL, + "display device possible resource settings (eg:acpi crs _SB.PC00.LPCB.RTC)", + dump_dev_prs), + SHELL_CMD(prt, NULL, "display PRT details for a given bus (eg:acpi prt _SB.PC00)", + dump_prt), + 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)", + read_table), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +SHELL_CMD_REGISTER(acpi, &sub_acpi, "Demo commands", NULL); From a72271f27fd4b4fbc4ffc8876be4333d95b3ad86 Mon Sep 17 00:00:00 2001 From: Najumon Ba Date: Fri, 31 Mar 2023 09:14:56 +0530 Subject: [PATCH 0777/2042] drivers: pcie: add prt support for pci legacy interrupt add support for obtain irq number from pci irq routing table Signed-off-by: Najumon Ba --- drivers/pcie/host/pcie.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 5f19d704bad5..5b2198b52784 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -14,6 +14,7 @@ LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); #include #include #include +#include #if CONFIG_PCIE_MSI #include @@ -285,7 +286,13 @@ unsigned int pcie_alloc_irq(pcie_bdf_t bdf) if (irq == PCIE_CONF_INTR_IRQ_NONE || irq >= CONFIG_MAX_IRQ_LINES || arch_irq_is_used(irq)) { - irq = arch_irq_allocate(); + + if (IS_ENABLED(CONFIG_ACPI)) { + irq = acpi_legacy_irq_get(bdf); + } else { + irq = arch_irq_allocate(); + } + if (irq == UINT_MAX) { return PCIE_CONF_INTR_IRQ_NONE; } From b3d78de656d0679cbdf43d4566b228eaec70ed63 Mon Sep 17 00:00:00 2001 From: Najumon Ba Date: Tue, 11 Apr 2023 14:58:35 +0530 Subject: [PATCH 0778/2042] arch: x86: updated acpi config macro renamed x86 CONFIG_ACPI config macro to CONFIG_x86_ACPI. Signed-off-by: Najumon Ba --- arch/x86/Kconfig | 6 +++--- arch/x86/core/CMakeLists.txt | 2 +- arch/x86/core/intel64/cpu.c | 2 +- arch/x86/core/pcie.c | 4 ++-- boards/x86/qemu_x86/board.cmake | 2 +- drivers/Kconfig | 1 + include/zephyr/arch/x86/acpi.h | 6 +++--- tests/arch/x86/info/CMakeLists.txt | 2 +- tests/arch/x86/info/prj.conf | 2 +- tests/boot/uefi/prj.conf | 2 +- tests/drivers/disk/disk_access/boards/qemu_x86_64.conf | 2 +- tests/drivers/disk/disk_performance/boards/qemu_x86_64.conf | 2 +- 12 files changed, 17 insertions(+), 16 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7249e04e4bad..5f22707aed93 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -227,7 +227,7 @@ choice Reboot via the RST_CNT register, going back to BIOS. endchoice -config ACPI +config X86_ACPI bool "ACPI (Advanced Configuration and Power Interface) support" depends on X86_PC_COMPATIBLE help @@ -235,14 +235,14 @@ config ACPI config PCIE_MMIO_CFG bool "Use MMIO PCI configuration space access" - select ACPI + select X86_ACPI help Selects the use of the memory-mapped PCI Express Extended Configuration Space instead of the traditional 0xCF8/0xCFC IO Port registers. config KERNEL_VM_SIZE - default 0x40000000 if ACPI + default 0x40000000 if X86_ACPI config X86_PC_COMPATIBLE bool diff --git a/arch/x86/core/CMakeLists.txt b/arch/x86/core/CMakeLists.txt index 3926bc3e9ea0..4c4bfa98fe9d 100644 --- a/arch/x86/core/CMakeLists.txt +++ b/arch/x86/core/CMakeLists.txt @@ -15,7 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_PCIE pcie.c) 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 acpi.c) +zephyr_library_sources_ifdef(CONFIG_X86_ACPI 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/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 26263b2e4625..80e9e65b90dc 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -142,7 +142,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, uint8_t vector = ((unsigned long) x86_ap_start) >> 12; uint8_t apic_id; - if (IS_ENABLED(CONFIG_ACPI)) { + if (IS_ENABLED(CONFIG_X86_ACPI)) { struct acpi_cpu *cpu; cpu = z_acpi_get_cpu(cpu_num); diff --git a/arch/x86/core/pcie.c b/arch/x86/core/pcie.c index 1d2888b8d126..47b78f990c13 100644 --- a/arch/x86/core/pcie.c +++ b/arch/x86/core/pcie.c @@ -8,7 +8,7 @@ #include #include -#ifdef CONFIG_ACPI +#ifdef CONFIG_X86_ACPI #include #endif @@ -35,7 +35,7 @@ static bool do_pcie_mmio_cfg; static void pcie_mm_init(void) { -#ifdef CONFIG_ACPI +#ifdef CONFIG_X86_ACPI struct acpi_mcfg *m = z_acpi_find_table(ACPI_MCFG_SIGNATURE); if (m != NULL) { diff --git a/boards/x86/qemu_x86/board.cmake b/boards/x86/qemu_x86/board.cmake index 934b078154e5..214d85ecc877 100644 --- a/boards/x86/qemu_x86/board.cmake +++ b/boards/x86/qemu_x86/board.cmake @@ -66,7 +66,7 @@ set(QEMU_FLAGS_${ARCH} -nographic ) -if(NOT CONFIG_ACPI) +if(NOT CONFIG_X86_ACPI) list(APPEND QEMU_FLAGS_${ARCH} -no-acpi) endif() diff --git a/drivers/Kconfig b/drivers/Kconfig index 5641465a3e3a..d615249727c3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -82,4 +82,5 @@ source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" source "drivers/sip_svc/Kconfig" + endmenu diff --git a/include/zephyr/arch/x86/acpi.h b/include/zephyr/arch/x86/acpi.h index ad237f2e5608..df4a5dcc0897 100644 --- a/include/zephyr/arch/x86/acpi.h +++ b/include/zephyr/arch/x86/acpi.h @@ -169,7 +169,7 @@ union acpi_dmar_id { uint16_t raw; }; -#if defined(CONFIG_ACPI) +#if defined(CONFIG_X86_ACPI) void *z_acpi_find_table(uint32_t signature); @@ -187,7 +187,7 @@ z_acpi_get_dev_scope_paths(struct acpi_dmar_dev_scope *dev_scope, int *n); uint16_t z_acpi_get_dev_id_from_dmar(uint8_t dev_scope_type); -#else /* CONFIG_ACPI */ +#else /* CONFIG_X86_ACPI */ #define z_acpi_find_table(...) NULL #define z_acpi_get_cpu(...) NULL @@ -197,7 +197,7 @@ uint16_t z_acpi_get_dev_id_from_dmar(uint8_t dev_scope_type); #define z_acpi_get_dev_scope_paths(...) NULL #define z_acpi_get_dev_id_from_dmar(...) USHRT_MAX -#endif /* CONFIG_ACPI */ +#endif /* CONFIG_X86_ACPI */ #endif /* _ASMLANGUAGE */ diff --git a/tests/arch/x86/info/CMakeLists.txt b/tests/arch/x86/info/CMakeLists.txt index 7a6c14f12d3c..a8c8dcdf1ade 100644 --- a/tests/arch/x86/info/CMakeLists.txt +++ b/tests/arch/x86/info/CMakeLists.txt @@ -8,6 +8,6 @@ project(x86_info) target_sources(app PRIVATE src/main.c) target_sources(app PRIVATE src/timer.c) -target_sources_ifdef(CONFIG_ACPI app PRIVATE src/acpi.c) +target_sources_ifdef(CONFIG_X86_ACPI app PRIVATE src/acpi.c) target_sources_ifdef(CONFIG_MULTIBOOT app PRIVATE src/multiboot.c) target_sources_ifdef(CONFIG_X86_MEMMAP app PRIVATE src/memmap.c) diff --git a/tests/arch/x86/info/prj.conf b/tests/arch/x86/info/prj.conf index bb56a340a7ee..4e89c3de68a9 100644 --- a/tests/arch/x86/info/prj.conf +++ b/tests/arch/x86/info/prj.conf @@ -1,4 +1,4 @@ -CONFIG_ACPI=y +CONFIG_X86_ACPI=y CONFIG_MULTIBOOT_INFO=y CONFIG_MULTIBOOT_MEMMAP=y CONFIG_COUNTER=y diff --git a/tests/boot/uefi/prj.conf b/tests/boot/uefi/prj.conf index 48ca509cdd56..17df3666c726 100644 --- a/tests/boot/uefi/prj.conf +++ b/tests/boot/uefi/prj.conf @@ -1,4 +1,4 @@ CONFIG_QEMU_UEFI_BOOT=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_SRAM_SIZE=204800 -CONFIG_ACPI=y +CONFIG_X86_ACPI=y diff --git a/tests/drivers/disk/disk_access/boards/qemu_x86_64.conf b/tests/drivers/disk/disk_access/boards/qemu_x86_64.conf index 0c14f763bf95..9760440e93b1 100644 --- a/tests/drivers/disk/disk_access/boards/qemu_x86_64.conf +++ b/tests/drivers/disk/disk_access/boards/qemu_x86_64.conf @@ -1,4 +1,4 @@ -CONFIG_ACPI=y +CONFIG_X86_ACPI=y CONFIG_PCIE=y CONFIG_PCIE_MSI=y CONFIG_PCIE_MSI_X=y diff --git a/tests/drivers/disk/disk_performance/boards/qemu_x86_64.conf b/tests/drivers/disk/disk_performance/boards/qemu_x86_64.conf index 0c14f763bf95..9760440e93b1 100644 --- a/tests/drivers/disk/disk_performance/boards/qemu_x86_64.conf +++ b/tests/drivers/disk/disk_performance/boards/qemu_x86_64.conf @@ -1,4 +1,4 @@ -CONFIG_ACPI=y +CONFIG_X86_ACPI=y CONFIG_PCIE=y CONFIG_PCIE_MSI=y CONFIG_PCIE_MSI_X=y From 49580bd374e33e5a747ed7e34562271e2fbedf4d Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 9 Mar 2023 13:55:33 -0500 Subject: [PATCH 0779/2042] drivers: systick: implement option for sys_clock_cycle_get_64() This driver, due to its limited 24-bits counter, is already tracking a cycle count in software. Allow that count to be a 64-bits value so this won't wrap in a matter of only a few seconds when the hardware clock is fast. This is very cheap to do as expensive math operations (i.e. divisions) are performed only on counter intervals whose values fit in 32 bits like before. Signed-off-by: Nicolas Pitre --- drivers/timer/Kconfig.cortex_m_systick | 16 +++++++++++ drivers/timer/cortex_m_systick.c | 37 ++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/timer/Kconfig.cortex_m_systick b/drivers/timer/Kconfig.cortex_m_systick index 33c0e1a6e260..31e4f56fce51 100644 --- a/drivers/timer/Kconfig.cortex_m_systick +++ b/drivers/timer/Kconfig.cortex_m_systick @@ -24,3 +24,19 @@ config CORTEX_M_SYSTICK_INSTALL_ISR help This option should be selected by SysTick-based drivers so that the sys_clock_isr() function is installed. + +config CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER + bool "Cortex-M SYSTICK timer with sys_clock_cycle_get_64() support" + depends on CORTEX_M_SYSTICK + default y if (SYS_CLOCK_HW_CYCLES_PER_SEC > 60000000) + select TIMER_HAS_64BIT_CYCLE_COUNTER + help + This driver, due to its limited 24-bits hardware counter, is already + tracking a separate cycle count in software. This option make that + count a 64-bits value to support sys_clock_cycle_get_64(). + This is cheap to do as expensive math operations (i.e. divisions) + are performed only on counter interval values that always fit in + 32 bits. + + This is set to y by default when the hardware clock is fast enough + to wrap sys_clock_cycle_get_32() in about a minute or less. diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 0009cc2fcc9a..53d85aa23e45 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -36,6 +36,12 @@ static struct k_spinlock lock; static uint32_t last_load; +#ifdef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER +#define cycle_t uint64_t +#else +#define cycle_t uint32_t +#endif + /* * This local variable holds the amount of SysTick HW cycles elapsed * and it is updated in sys_clock_isr() and sys_clock_set_timeout(). @@ -46,13 +52,19 @@ static uint32_t last_load; * * t = cycle_counter + elapsed(); */ -static uint32_t cycle_count; +static cycle_t cycle_count; /* * This local variable holds the amount of elapsed SysTick HW cycles * that have been announced to the kernel. + * + * Note: + * Additions/subtractions/comparisons of 64-bits values on 32-bits systems + * are very cheap. Divisions are not. Make sure the difference between + * cycle_count and announced_cycles is stored in a 32-bit variable before + * dividing it by CYC_PER_TICK. */ -static uint32_t announced_cycles; +static cycle_t announced_cycles; /* * This local variable holds the amount of elapsed HW cycles due to @@ -119,6 +131,7 @@ static uint32_t elapsed(void) void sys_clock_isr(void *arg) { ARG_UNUSED(arg); + uint32_t dcycles; uint32_t dticks; /* Update overflow_cyc and clear COUNTFLAG by invoking elapsed() */ @@ -143,7 +156,8 @@ void sys_clock_isr(void *arg) * We can assess if this is the case by inspecting COUNTFLAG. */ - dticks = (cycle_count - announced_cycles) / CYC_PER_TICK; + dcycles = cycle_count - announced_cycles; + dticks = dcycles / CYC_PER_TICK; announced_cycles += dticks * CYC_PER_TICK; sys_clock_announce(dticks); } else { @@ -240,7 +254,8 @@ uint32_t sys_clock_elapsed(void) } k_spinlock_key_t key = k_spin_lock(&lock); - uint32_t cyc = elapsed() + cycle_count - announced_cycles; + uint32_t unannounced = cycle_count - announced_cycles; + uint32_t cyc = elapsed() + unannounced; k_spin_unlock(&lock, key); return cyc / CYC_PER_TICK; @@ -249,12 +264,24 @@ uint32_t sys_clock_elapsed(void) uint32_t sys_clock_cycle_get_32(void) { k_spinlock_key_t key = k_spin_lock(&lock); - uint32_t ret = elapsed() + cycle_count; + uint32_t ret = cycle_count; + ret += elapsed(); k_spin_unlock(&lock, key); return ret; } +#ifdef CONFIG_CORTEX_M_SYSTICK_64BIT_CYCLE_COUNTER +uint64_t sys_clock_cycle_get_64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t ret = cycle_count + elapsed(); + + k_spin_unlock(&lock, key); + return ret; +} +#endif + void sys_clock_idle_exit(void) { if (last_load == TIMER_STOPPED) { From db1a718341a3724b82c052e6e6b7db19251f7a22 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 30 Jun 2023 12:28:20 +0200 Subject: [PATCH 0780/2042] drivers: dma: intel-adsp-hda: add a missing "break" A "switch" statement in intel_adsp_hda_dma_status() seems to be missing a "break". The second "break" is unneeded but seems to be a part of the coding style. Signed-off-by: Guennadi Liakhovetski --- drivers/dma/dma_intel_adsp_hda.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 7f166e217b49..64318101e88a 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -212,6 +212,7 @@ int intel_adsp_hda_dma_status(const struct device *dev, uint32_t channel, intel_adsp_hda_underrun_clear(cfg->base, cfg->regblock_size, channel); return -EPIPE; } + break; case PERIPHERAL_TO_MEMORY: xrun_det = intel_adsp_hda_is_buffer_overrun(cfg->base, cfg->regblock_size, channel); @@ -219,6 +220,7 @@ int intel_adsp_hda_dma_status(const struct device *dev, uint32_t channel, intel_adsp_hda_overrun_clear(cfg->base, cfg->regblock_size, channel); return -EPIPE; } + break; default: break; } From f6eeb9dc84bec63dea231a49e97992875b659614 Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Sun, 25 Jun 2023 14:52:02 +0530 Subject: [PATCH 0781/2042] soc: MEC1701: Removed Microchip MEC1701 Removed MEC1701 SOC specific sources Signed-off-by: Manimaran A --- boards/arm/mec2016evb_assy6797/CMakeLists.txt | 8 - boards/arm/mec2016evb_assy6797/Kconfig.board | 6 - .../arm/mec2016evb_assy6797/Kconfig.defconfig | 9 - boards/arm/mec2016evb_assy6797/doc/index.rst | 212 ------------------ .../doc/mec2016evb_assy6797.jpg | Bin 42279 -> 0 bytes .../mec2016evb_assy6797.dts | 25 --- .../mec2016evb_assy6797.yaml | 15 -- .../mec2016evb_assy6797_defconfig | 14 -- boards/arm/mec2016evb_assy6797/pinmux.c | 38 ---- dts/arm/microchip/mec1701qsz.dtsi | 54 ----- soc/arm/microchip_mec/Kconfig.soc | 2 +- soc/arm/microchip_mec/common/soc_i2c.c | 17 -- soc/arm/microchip_mec/common/soc_i2c.h | 2 - soc/arm/microchip_mec/mec1701/CMakeLists.txt | 5 - .../mec1701/Kconfig.defconfig.mec1701qsz | 14 -- .../mec1701/Kconfig.defconfig.series | 18 -- soc/arm/microchip_mec/mec1701/Kconfig.series | 14 -- soc/arm/microchip_mec/mec1701/Kconfig.soc | 14 -- soc/arm/microchip_mec/mec1701/linker.ld | 9 - soc/arm/microchip_mec/mec1701/soc.c | 36 --- soc/arm/microchip_mec/mec1701/soc.h | 18 -- 21 files changed, 1 insertion(+), 529 deletions(-) delete mode 100644 boards/arm/mec2016evb_assy6797/CMakeLists.txt delete mode 100644 boards/arm/mec2016evb_assy6797/Kconfig.board delete mode 100644 boards/arm/mec2016evb_assy6797/Kconfig.defconfig delete mode 100644 boards/arm/mec2016evb_assy6797/doc/index.rst delete mode 100644 boards/arm/mec2016evb_assy6797/doc/mec2016evb_assy6797.jpg delete mode 100644 boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.dts delete mode 100644 boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.yaml delete mode 100644 boards/arm/mec2016evb_assy6797/mec2016evb_assy6797_defconfig delete mode 100644 boards/arm/mec2016evb_assy6797/pinmux.c delete mode 100644 dts/arm/microchip/mec1701qsz.dtsi delete mode 100644 soc/arm/microchip_mec/mec1701/CMakeLists.txt delete mode 100644 soc/arm/microchip_mec/mec1701/Kconfig.defconfig.mec1701qsz delete mode 100644 soc/arm/microchip_mec/mec1701/Kconfig.defconfig.series delete mode 100644 soc/arm/microchip_mec/mec1701/Kconfig.series delete mode 100644 soc/arm/microchip_mec/mec1701/Kconfig.soc delete mode 100644 soc/arm/microchip_mec/mec1701/linker.ld delete mode 100644 soc/arm/microchip_mec/mec1701/soc.c delete mode 100644 soc/arm/microchip_mec/mec1701/soc.h diff --git a/boards/arm/mec2016evb_assy6797/CMakeLists.txt b/boards/arm/mec2016evb_assy6797/CMakeLists.txt deleted file mode 100644 index 17fd9d4425ca..000000000000 --- a/boards/arm/mec2016evb_assy6797/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2019 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 -# - -zephyr_library() -zephyr_library_sources(pinmux.c) diff --git a/boards/arm/mec2016evb_assy6797/Kconfig.board b/boards/arm/mec2016evb_assy6797/Kconfig.board deleted file mode 100644 index 0ab279fccdee..000000000000 --- a/boards/arm/mec2016evb_assy6797/Kconfig.board +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2019, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_MEC2016EVB_ASSY6797 - bool "Microchip MEC2016 EVB ASSY 6797 Development board" - depends on SOC_MEC1701_QSZ diff --git a/boards/arm/mec2016evb_assy6797/Kconfig.defconfig b/boards/arm/mec2016evb_assy6797/Kconfig.defconfig deleted file mode 100644 index fd416a22c430..000000000000 --- a/boards/arm/mec2016evb_assy6797/Kconfig.defconfig +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2019 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -if BOARD_MEC2016EVB_ASSY6797 - -config BOARD - default "mec2016evb_assy6797" - -endif # BOARD_MEC2016EVB_ASSY6797 diff --git a/boards/arm/mec2016evb_assy6797/doc/index.rst b/boards/arm/mec2016evb_assy6797/doc/index.rst deleted file mode 100644 index dc03e7fb9a08..000000000000 --- a/boards/arm/mec2016evb_assy6797/doc/index.rst +++ /dev/null @@ -1,212 +0,0 @@ -.. _mec2016evb_assy6797: - -Microchip MEC2016EVB ASSY6797 -############################# - -Overview -******** - -The MEC2016EVB_ASSY6797 kit is a development platform to evaluate the -Microchip MEC1701X series microcontrollers. This board needs to be mated with -part number MEC170X 144WFBA SOLDER DC ASSY 6801(cpu board) in order to operate. - -.. image:: mec2016evb_assy6797.jpg - :align: center - :alt: MEC2016 EVB ASSY 6797 - -Hardware -******** - -- MEC1701QC2SZ ARM Cortex-M4F Processor -- 480 KB RAM and 64 KB boot ROM -- 2 Microchip BC-Link Interconnection bus -- Keyboard interface -- ADC & GPIO headers -- UART0 and UART1 -- FAN0, FAN1, FAN2 headers -- FAN PWM interface -- Jtag and Trace ports -- PECI interface 3.0 -- I2C voltage translator -- 10 SMBUS headers -- 3 UDP I2C headers -- VCI interface -- 5 independent Hardware Driven PS/2 Ports -- eSPI header -- LPC sideband headers -- 4 Breathing/Blinking LEDs -- 2 Sockets for SPI NOR chips -- One reset and VCC_PWRDGD pushbuttons - -For more information about the SOC please visit: - -- `MEC170x Reference Manual`_ - -Supported Features -================== - -The mec2016evb_assy6797 board configuration supports the following hardware -features: - -+-----------+------------+-------------------------------------+ -| Interface | Controller | Driver/Component | -+===========+============+=====================================+ -| NVIC | on-chip | nested vector interrupt controller | -+-----------+------------+-------------------------------------+ -| SYSTICK | on-chip | systick | -+-----------+------------+-------------------------------------+ -| UART | on-chip | serial port | -+-----------+------------+-------------------------------------+ - -Other hardware features are not currently supported by Zephyr (at the moment) - -The default configuration can be found in the Kconfig file: -``boards/arm/mec2016evb_assy6797/mec2016evb_assy6797_defconfig`` - - -Connections and IOs -=================== - -Microchip to provide the schematic for this board. - -System Clock -============ - -The MEC1701 MCU is configured to use the 48Mhz internal oscillator with the -on-chip PLL to generate a resulting EC clock rate of 12 MHz. See Processor clock -control register (chapter 4 in user manual) - -Serial Port -=========== - -UART0 is configured for serial logs. - -Jumper settings -*************** - -Please follow the jumper settings below to properly demo this -board. Advanced users may deviate from this recommendation. - -Jump setting for MEC2016 EVB Assy 6797 Rev A1p0 -=============================================== - -Power-related jumpers. - -+-------+------+------+------+------+------+-------+-------+ -| JP31 | JP32 | JP35 | JP36 | JP49 | JP50 | JP54 | JP55 | -+=======+======+======+======+======+======+=======+=======+ -| 1-2 | 1-2 | 1-2 | 1-2 | 1-2 | 1-2 | 1-2 | 1-2 | -+-------+------+------+------+------+------+-------+-------+ - -+-------+-------+------+------+------+-------+ -| JP56 | JP57 | JP58 | JP60 | JP61 | JP102 | -+=======+=======+======+======+======+=======+ -| 1-2 | 1-2 | 1-2 | 1-2 | 1-2 | 2-3 | -+-------+-------+------+------+------+-------+ - -These jumpers configure VCC Power good, nRESETI and JTAG_STRAP respectively. - -+------------------+-----------+--------------+ -| JP1 | JP2 | JP51 | -| (VCC Power good) | (nRESETI) | (JTAG_STRAP) | -+==================+===========+==============+ -| 1-2 | 1-2 | 2-3 | -+------------------+-----------+--------------+ - -Each column of the following table illustrates how to enable UART0, JTAG, -PVT SPI, SHD SPI and LED0-3 respectively. - -+---------+--------+-----------+----------+---------+ -| JP27 | JP10 | JP34 | JP75 | JP68 | -| (UART0) | (JTAG) | (PVT SPI) | (SHD SPI)| (LED0-3)| -+=========+========+===========+==========+=========+ -| 11-12 | 2-3 | 2-3 | 2-3 | 1-2 | -+---------+--------+-----------+----------+---------+ -| 8-9 | 5-6 | 5-6 | 5-6 | 3-4 | -+---------+--------+-----------+----------+---------+ -| | 8-9 | 8-9 | 8-9 | 5-6 | -+---------+--------+-----------+----------+---------+ -| | 11-12 | 11-12 | 11-12 | 7-8 | -+---------+--------+-----------+----------+---------+ -| | | 14-15 | 14-15 | | -+---------+--------+-----------+----------+---------+ -| | | 17-18 | 17-18 | | -+---------+--------+-----------+----------+---------+ - -Jump settings for MEC170x 144WFBGA Socket DC Assy 6801 Rev B1p0 -=============================================================== - -The jumper configuration explained above covers the base board. Now the CPU -board requires the following settings. - -+-------+-------+ -| JP1 | JP2 | -+=======+=======+ -| 1-2 | 2-3 | -+-------+-------+ - -Programming and Debugging -************************* - -This board comes with a Cortex ETM port which facilitates tracing and debugging -using a single physical connection. In addition, it comes with sockets for -JTAG only sessions. - -Flashing -======== - -#. Connect the SPI Dongle ASSY 6791 to J36 (SPI dongle) in order to flash and - boot from SHD SPI NOR. Then proceed to flash using Dediprog SF100 or a - similar tool for flashing SPI chips. Remember that SPI MISO/MOSI are - swapped on dediprog headers! - -#. Run your favorite terminal program to listen for output. Under Linux the - terminal should be :code:`/dev/ttyACM0`. For example: - - .. code-block:: console - - $ minicom -D /dev/ttyACM0 -o - - The -o option tells minicom not to send the modem initialization - string. Connection should be configured as follows: - - - Speed: 115200 - - Data: 8 bits - - Parity: None - - Stop bits: 1 - -#. Connect the MEC2016EVB_ASSY_6797 board to your host computer using the - UART0 port. Then build :ref:`hello_world` application. It is important - to generate a binary with a new load address, for example do the following:: - - ${OBJCOPY} --change-addresses -0xb0000 -O binary -S ${in_elf} ${out_bin} - - Once you obtain the binary, proceed to use the microchip tool mec2016_spi_gen - in order to create the final binary. This binary is what you need to flash - in your spi nor. - - .. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: mec2016evb_assy6797 - :goals: build flash - - You should see "Hello World! mec2016evb_assy6797" in your terminal. - -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: mec2016evb_assy6797 - :maybe-skip-config: - :goals: debug - -References -********** -.. target-notes:: - -.. _MEC170x Reference Manual: - http://ww1.microchip.com/downloads/en/DeviceDoc/MEC170x-Data-Sheet-DS00002206D.pdf diff --git a/boards/arm/mec2016evb_assy6797/doc/mec2016evb_assy6797.jpg b/boards/arm/mec2016evb_assy6797/doc/mec2016evb_assy6797.jpg deleted file mode 100644 index 85e29fc34bb61a03596d97dd9cb20e34d9d201cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42279 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 z 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

^n3%iZ=JdTbQ~Lm#8mDg(#~E|W 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 diff --git a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.dts b/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.dts deleted file mode 100644 index 43b97ac54586..000000000000 --- a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.dts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2018, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; - -#include - -/ { - model = "Microchip MEC2016EVB_ASSY6797 evaluation board"; - compatible = "microchip,mec2016evb_assy679", "microchip,mec1701qsz"; - - chosen { - zephyr,sram = &sram0; - zephyr,console = &uart0; - zephyr,flash = &flash0; - }; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; -}; diff --git a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.yaml b/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.yaml deleted file mode 100644 index 127dc494ff23..000000000000 --- a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright (c) 2019, Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 -# - -identifier: mec2016evb_assy6797 -name: MEC2016 EVB ASSY 6797 -type: mcu -arch: arm -toolchain: - - zephyr - - gnuarmemb -ram: 64 -flash: 416 diff --git a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797_defconfig b/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797_defconfig deleted file mode 100644 index 77a9d525b5e4..000000000000 --- a/boards/arm/mec2016evb_assy6797/mec2016evb_assy6797_defconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright (c) 2019, Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SOC_MEC1701_QSZ=y -CONFIG_SOC_SERIES_MEC1701X=y -CONFIG_BOARD_MEC2016EVB_ASSY6797=y -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=48000000 - -CONFIG_CONSOLE=y -CONFIG_UART_CONSOLE=y -CONFIG_SERIAL=y diff --git a/boards/arm/mec2016evb_assy6797/pinmux.c b/boards/arm/mec2016evb_assy6797/pinmux.c deleted file mode 100644 index d4b1be5c9f5c..000000000000 --- a/boards/arm/mec2016evb_assy6797/pinmux.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "soc.h" - -static int board_pinmux_init(void) -{ - - /* See table 2-4 from the Data sheet*/ -#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart0), okay) - /* Set muxing, for UART 0 and power up */ - PCR_INST->CLK_REQ_2_b.UART_0_CLK_REQ = 1; - UART0_INST->CONFIG = 0; - UART0_INST->ACTIVATE = 1; - GPIO_100_137_INST->GPIO_104_PIN_CONTROL_b.MUX_CONTROL = 1; - GPIO_100_137_INST->GPIO_105_PIN_CONTROL_b.MUX_CONTROL = 1; -#endif - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) - /* Set muxing, for UART 1 and power up */ - PCR_INST->CLK_REQ_2_b.UART_1_CLK_REQ = 1; - UART1_INST->CONFIG = 0; - UART1_INST->ACTIVATE = 1; - GPIO_140_176_INST->GPIO_170_PIN_CONTROL_b.MUX_CONTROL = 2; - GPIO_140_176_INST->GPIO_171_PIN_CONTROL_b.MUX_CONTROL = 2; - GPIO_100_137_INST->GPIO_113_PIN_CONTROL_b.GPIO_DIRECTION = 1; -#endif - return 0; -} - -SYS_INIT(board_pinmux_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/dts/arm/microchip/mec1701qsz.dtsi b/dts/arm/microchip/mec1701qsz.dtsi deleted file mode 100644 index 49923eaec8f3..000000000000 --- a/dts/arm/microchip/mec1701qsz.dtsi +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-m4f"; - reg = <0>; - }; - }; - - flash0: flash@b0000 { - reg = <0x000B0000 0x68000>; - }; - - sram0: memory@118000 { - compatible = "mmio-sram"; - reg = <0x00118000 0x10000>; - }; - - soc { - uart0: uart@400f2400 { - compatible = "ns16550"; - reg = <0x400f2400 0x400>; - interrupts = <40 0>; - clock-frequency = <1843200>; - current-speed = <38400>; - reg-shift = <0>; - status = "disabled"; - }; - uart1: uart@400f2800 { - compatible = "ns16550"; - reg = <0x400f2800 0x400>; - interrupts = <41 0>; - clock-frequency = <1843200>; - current-speed = <38400>; - reg-shift = <0>; - status = "disabled"; - }; - }; -}; - -&nvic { - arm,num-irq-priority-bits = <3>; -}; diff --git a/soc/arm/microchip_mec/Kconfig.soc b/soc/arm/microchip_mec/Kconfig.soc index 295434b66d5f..85734699608d 100644 --- a/soc/arm/microchip_mec/Kconfig.soc +++ b/soc/arm/microchip_mec/Kconfig.soc @@ -1,4 +1,4 @@ -# Microchip MEC1701 MCU line +# Microchip MEC172x, MEC1501 MCU line # Copyright (c) 2018 Intel Corporation # SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm/microchip_mec/common/soc_i2c.c b/soc/arm/microchip_mec/common/soc_i2c.c index b2e5afbf1789..0e33437af985 100644 --- a/soc/arm/microchip_mec/common/soc_i2c.c +++ b/soc/arm/microchip_mec/common/soc_i2c.c @@ -53,23 +53,6 @@ static const struct mec_i2c_port mec_i2c_ports[] = { { 0065, 2, 0066, 2 }, /* VTR3 */ { 0071, 2, 0070, 2 }, /* VTR3 */ { 0150, 1, 0147, 1 } -#elif defined(CONFIG_SOC_SERIES_MEC1701X) - { 0004, 1, 0003, 1 }, - { 0006, 1, 0005, 1 }, - { 0155, 1, 0154, 1 }, - { 0010, 1, 0007, 1 }, - { 0144, 1, 0143, 1 }, - { 0142, 1, 0141, 1 }, - { 0140, 1, 0132, 1 }, /* VTR2 */ - { 0013, 1, 0012, 1 }, /* VTR2 */ - { 0150, 1, 0147, 1 }, - { 0146, 1, 0145, 1 }, - { 0131, 1, 0130, 1 }, /* VTR2 */ - { 0xFF, 0, 0xFF, 0 }, /* No I2C Ports 11 - 15 */ - { 0xFF, 0, 0xFF, 0 }, - { 0xFF, 0, 0xFF, 0 }, - { 0xFF, 0, 0xFF, 0 }, - { 0xFF, 0, 0xFF, 0 } #endif }; diff --git a/soc/arm/microchip_mec/common/soc_i2c.h b/soc/arm/microchip_mec/common/soc_i2c.h index 2398b1421bb2..e4092b6aebfd 100644 --- a/soc/arm/microchip_mec/common/soc_i2c.h +++ b/soc/arm/microchip_mec/common/soc_i2c.h @@ -16,8 +16,6 @@ #define MEC_I2C_PORT_MASK 0xFEFFU #elif defined(CONFIG_SOC_MEC1501_HSZ) #define MEC_I2C_PORT_MASK 0xFEFFU -#elif defined(CONFIG_SOC_MEC1701_QSZ) -#define MEC_I2C_PORT_MASK 0x07FFU #endif #define MCHP_I2C_PORT_0 0 diff --git a/soc/arm/microchip_mec/mec1701/CMakeLists.txt b/soc/arm/microchip_mec/mec1701/CMakeLists.txt deleted file mode 100644 index 332416ba43b0..000000000000 --- a/soc/arm/microchip_mec/mec1701/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - soc.c - ) diff --git a/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.mec1701qsz b/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.mec1701qsz deleted file mode 100644 index 437ec1e44fae..000000000000 --- a/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.mec1701qsz +++ /dev/null @@ -1,14 +0,0 @@ -# Microchip MEC1701QSZ MCU - -# Copyright (c) 2018 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -if SOC_MEC1701_QSZ - -config SOC - default "mec1701qsz" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 48000000 - -endif # SOC_MEC1701_QSZ diff --git a/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.series b/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.series deleted file mode 100644 index 46bbdda69495..000000000000 --- a/soc/arm/microchip_mec/mec1701/Kconfig.defconfig.series +++ /dev/null @@ -1,18 +0,0 @@ -# Microchip MEC MCU series configuration options - -# Copyright (c) 2018 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_MEC1701X - -config SOC_SERIES - default "mec1701" - -config NUM_IRQS - # must be >= the highest interrupt number used - # - include the UART interrupts - #for the moment 42 needs to be corrected in terms of devices added - default 42 - -source "soc/arm/microchip_mec/mec1701/Kconfig.defconfig.mec1701*" -endif # SOC_SERIES_MEC1701X diff --git a/soc/arm/microchip_mec/mec1701/Kconfig.series b/soc/arm/microchip_mec/mec1701/Kconfig.series deleted file mode 100644 index 51d49ce2d32d..000000000000 --- a/soc/arm/microchip_mec/mec1701/Kconfig.series +++ /dev/null @@ -1,14 +0,0 @@ -# Microchip MEC1701 MCU core series - -# Copyright (c) 2018 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_MEC1701X - bool "Microchip MEC1701X Series" - select ARM - select CPU_CORTEX_M4 - select CPU_CORTEX_M_HAS_DWT - select SOC_FAMILY_MEC - select CPU_HAS_FPU - help - Enable support for Microchip MEC Cortex-M4 MCU series diff --git a/soc/arm/microchip_mec/mec1701/Kconfig.soc b/soc/arm/microchip_mec/mec1701/Kconfig.soc deleted file mode 100644 index 9464f49f44ea..000000000000 --- a/soc/arm/microchip_mec/mec1701/Kconfig.soc +++ /dev/null @@ -1,14 +0,0 @@ -# Microchip MEC1701 MCU core series - -# Copyright (c) 2018 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "MEC1701 Selection" - depends on SOC_SERIES_MEC1701X - -config SOC_MEC1701_QSZ - bool "MEC1701_QSZ" - select HAS_MEC_HAL - -endchoice diff --git a/soc/arm/microchip_mec/mec1701/linker.ld b/soc/arm/microchip_mec/mec1701/linker.ld deleted file mode 100644 index 96ec397da785..000000000000 --- a/soc/arm/microchip_mec/mec1701/linker.ld +++ /dev/null @@ -1,9 +0,0 @@ -/* linker.ld - Linker command/script file */ - -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include diff --git a/soc/arm/microchip_mec/mec1701/soc.c b/soc/arm/microchip_mec/mec1701/soc.c deleted file mode 100644 index 63c6e699054f..000000000000 --- a/soc/arm/microchip_mec/mec1701/soc.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - - -static int soc_init(void) -{ - __IO uint32_t *girc_enable_set; - - __enable_irq(); - - /* Enable clocks for Interrupts and CPU */ - PCR_INST->CLK_REQ_1_b.INT_CLK_REQ = 1; - PCR_INST->CLK_REQ_1_b.PROCESSOR_CLK_REQ = 1; - - /* Route all interrupts from EC to NVIC */ - EC_REG_BANK_INST->INTERRUPT_CONTROL = 0x1; - for (girc_enable_set = (uint32_t *)&INTS_INST->GIRQ08_EN_SET; - girc_enable_set <= &INTS_INST->GIRQ15_EN_SET; - girc_enable_set += 5) { - /* This probably will require tuning, but drawing 8.2 also - illustrates how to disable spurious interrupts */ - *girc_enable_set = 0xFFFFFFFF; - } - - return 0; -} - -SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/microchip_mec/mec1701/soc.h b/soc/arm/microchip_mec/mec1701/soc.h deleted file mode 100644 index 522b9cd86bf3..000000000000 --- a/soc/arm/microchip_mec/mec1701/soc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __MEC_SOC_H -#define __MEC_SOC_H - -#define SYSCLK_DEFAULT_IOSC_HZ MHZ(48) - -#ifndef _ASMLANGUAGE - -#include "MCHP_MEC1701.h" - -#endif - -#endif From 66018d5f0a3ce4b817726701ae6cb14a483cf5e0 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Fri, 30 Jun 2023 12:14:24 -0700 Subject: [PATCH 0782/2042] driver: adc: fix documentation comments fixes errors in adc documentation comment Signed-off-by: Jason Yuan --- include/zephyr/drivers/adc/current_sense_amplifier.h | 2 +- include/zephyr/drivers/adc/current_sense_shunt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/adc/current_sense_amplifier.h b/include/zephyr/drivers/adc/current_sense_amplifier.h index 60489706c3af..6035eeb4ed29 100644 --- a/include/zephyr/drivers/adc/current_sense_amplifier.h +++ b/include/zephyr/drivers/adc/current_sense_amplifier.h @@ -35,7 +35,7 @@ struct current_sense_amplifier_dt_spec { } /** - * @brief Calculates the actual voltage from the measured voltage + * @brief Calculates the actual amperage from the measured voltage * * @param[in] spec current sensor specification from Devicetree. * @param[in,out] v_to_i Pointer to the measured voltage in millivolts on input, and the diff --git a/include/zephyr/drivers/adc/current_sense_shunt.h b/include/zephyr/drivers/adc/current_sense_shunt.h index c72deb82f9cb..05e402a46aa5 100644 --- a/include/zephyr/drivers/adc/current_sense_shunt.h +++ b/include/zephyr/drivers/adc/current_sense_shunt.h @@ -31,7 +31,7 @@ struct current_sense_shunt_dt_spec { } /** - * @brief Calculates the actual voltage from the measured voltage + * @brief Calculates the actual amperage from the measured voltage * * @param[in] spec current sensor specification from Devicetree. * @param[in,out] v_to_i Pointer to the measured voltage in millivolts on input, and the From 9291c9f7d6e9612463789edcfdbc558554d8cd14 Mon Sep 17 00:00:00 2001 From: Caspar Friedrich Date: Wed, 10 May 2023 23:17:57 +0200 Subject: [PATCH 0783/2042] drivers: tla2021: Add driver This adds a driver for Texas Instruments Cost-Optimized, Ultra-Small, 12-Bit, System-Monitoring ADCs. Currently only TLA2021 is supported, TLA2022 and TLA2024 may follow based on this driver. Signed-off-by: Caspar Friedrich --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.tla2021 | 34 ++++ drivers/adc/adc_tla2021.c | 318 +++++++++++++++++++++++++++++++ dts/bindings/adc/ti,tla2021.yaml | 15 ++ 5 files changed, 370 insertions(+) create mode 100644 drivers/adc/Kconfig.tla2021 create mode 100644 drivers/adc/adc_tla2021.c create mode 100644 dts/bindings/adc/ti,tla2021.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 63be06b419aa..eded385c80c1 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -41,3 +41,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_GECKO_IADC iadc_gecko.c) zephyr_library_sources_ifdef(CONFIG_ADC_INFINEON_CAT1 adc_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_GPADC adc_smartbond_gpadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_SDADC adc_smartbond_sdadc.c) +zephyr_library_sources_ifdef(CONFIG_ADC_TLA2021 adc_tla2021.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 0cfcbf05ecbd..48c57c71a359 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -108,4 +108,6 @@ source "drivers/adc/Kconfig.ifx_cat1" source "drivers/adc/Kconfig.smartbond" +source "drivers/adc/Kconfig.tla2021" + endif # ADC diff --git a/drivers/adc/Kconfig.tla2021 b/drivers/adc/Kconfig.tla2021 new file mode 100644 index 000000000000..fff48ed82af5 --- /dev/null +++ b/drivers/adc/Kconfig.tla2021 @@ -0,0 +1,34 @@ +# Copyright (c) 2023 Caspar Friedrich +# SPDX-License-Identifier: Apache-2.0 + +config ADC_TLA2021 + bool "Texas Instruments TLA2021 Low-Power ADC" + default y + depends on DT_HAS_TI_TLA2021_ENABLED + select I2C + help + TLA202x Cost-Optimized, Ultra-Small, 12-Bit, System-Monitoring ADCs + +if ADC_TLA2021 + +config ADC_TLA2021_INIT_PRIORITY + int "Priority for the driver initialization" + default ADC_INIT_PRIORITY + help + Fine tune the priority for the driver initialization. Make sure it's + higher (-> lower priority) than I2C_INIT_PRIORITY. + +config ADC_TLA2021_ACQUISITION_THREAD_PRIORITY + int "Priority for the data acquisition thread" + default 0 + help + Execution priority for the internal data acquisition thread. + +config ADC_TLA2021_ACQUISITION_THREAD_STACK_SIZE + int "Stack size for the data acquisition thread" + default 512 + help + Stack size for the internal data acquisition thread. Requires room + for I2C operations. + +endif # ADC_TLA2021 diff --git a/drivers/adc/adc_tla2021.c b/drivers/adc/adc_tla2021.c new file mode 100644 index 000000000000..8c68c8b81ee0 --- /dev/null +++ b/drivers/adc/adc_tla2021.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2023 Caspar Friedrich + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER + +/* + * This requires to be included _after_ `#define ADC_CONTEXT_USES_KERNEL_TIMER` + */ +#include "adc_context.h" + +#define DT_DRV_COMPAT ti_tla2021 + +LOG_MODULE_REGISTER(tla2021, CONFIG_ADC_LOG_LEVEL); + +#define ACQ_THREAD_PRIORITY CONFIG_ADC_TLA2021_ACQUISITION_THREAD_PRIORITY +#define ACQ_THREAD_STACK_SIZE CONFIG_ADC_TLA2021_ACQUISITION_THREAD_STACK_SIZE + +#define ADC_CHANNEL_msk BIT(0) +#define ADC_RESOLUTION 12 + +/* + * Conversion Data Register (RP = 00h) [reset = 0000h] + */ +#define REG_DATA 0x00 +#define REG_DATA_pos 4 + +/* + * Configuration Register (RP = 01h) [reset = 8583h] + */ +#define REG_CONFIG 0x01 +#define REG_CONFIG_DEFAULT 0x8583 +#define REG_CONFIG_DR_pos 5 +#define REG_CONFIG_MODE_pos 8 +#define REG_CONFIG_PGA_pos 9 /* TLA2022 and TLA2024 Only */ +#define REG_CONFIG_MUX_pos 12 /* TLA2024 Only */ +#define REG_CONFIG_OS_pos 15 +#define REG_CONFIG_OS_msk (BIT_MASK(1) << REG_CONFIG_OS_pos) + +typedef int16_t tla2021_reg_data_t; +typedef uint16_t tla2021_reg_config_t; + +struct tla2021_config { + const struct i2c_dt_spec bus; + k_tid_t acq_thread_id; +}; + +struct tla2021_data { + const struct device *dev; + struct adc_context ctx; + struct k_sem acq_lock; + tla2021_reg_data_t *buffer; + tla2021_reg_data_t *repeat_buffer; + + /* + * Shadow register + */ + tla2021_reg_config_t reg_config; +}; + +static int tla2021_read_register(const struct device *dev, uint8_t reg, uint16_t *value) +{ + int ret; + + const struct tla2021_config *config = dev->config; + uint8_t tmp[2]; + + ret = i2c_write_read_dt(&config->bus, ®, sizeof(reg), tmp, sizeof(tmp)); + if (ret) { + return ret; + } + + *value = sys_get_be16(tmp); + + return 0; +} + +static int tla2021_write_register(const struct device *dev, uint8_t reg, uint16_t value) +{ + int ret; + + const struct tla2021_config *config = dev->config; + uint8_t tmp[3] = {reg}; + + sys_put_be16(value, &tmp[1]); + + ret = i2c_write_dt(&config->bus, tmp, sizeof(tmp)); + if (ret) { + return ret; + } + + return 0; +} + +static int tla2021_channel_setup(const struct device *dev, const struct adc_channel_cfg *cfg) +{ + if (cfg->gain != ADC_GAIN_1) { + LOG_ERR("Invalid gain"); + return -EINVAL; + } + + if (cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Invalid reference"); + return -EINVAL; + } + + if (cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Invalid acquisition time"); + return -EINVAL; + } + + return 0; +} + +static int tla2021_start_read(const struct device *dev, const struct adc_sequence *seq) +{ + struct tla2021_data *data = dev->data; + + const size_t num_extra_samples = seq->options ? seq->options->extra_samplings : 0; + const size_t num_samples = (1 + num_extra_samples) * POPCOUNT(seq->channels); + + if (!(seq->channels & ADC_CHANNEL_msk)) { + LOG_ERR("Selected channel(s) not supported: %x", seq->channels); + return -EINVAL; + } + + if (seq->resolution != ADC_RESOLUTION) { + LOG_ERR("Selected resolution not supported: %d", seq->resolution); + return -EINVAL; + } + + if (seq->oversampling) { + LOG_ERR("Oversampling is not supported"); + return -EINVAL; + } + + if (seq->calibrate) { + LOG_ERR("Calibration is not supported"); + return -EINVAL; + } + + if (!seq->buffer) { + LOG_ERR("Buffer invalid"); + return -EINVAL; + } + + if (seq->buffer_size < (num_samples * sizeof(tla2021_reg_data_t))) { + LOG_ERR("buffer size too small"); + return -EINVAL; + } + + data->buffer = seq->buffer; + + adc_context_start_read(&data->ctx, seq); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int tla2021_read_async(const struct device *dev, const struct adc_sequence *seq, + struct k_poll_signal *async) +{ + int ret; + + struct tla2021_data *data = dev->data; + + adc_context_lock(&data->ctx, async ? true : false, async); + ret = tla2021_start_read(dev, seq); + adc_context_release(&data->ctx, ret); + + return ret; +} + +static int tla2021_read(const struct device *dev, const struct adc_sequence *seq) +{ + return tla2021_read_async(dev, seq, NULL); +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + int ret; + + struct tla2021_data *data = CONTAINER_OF(ctx, struct tla2021_data, ctx); + const struct device *dev = data->dev; + + tla2021_reg_config_t reg = data->reg_config; + + /* + * Start single-shot conversion + */ + WRITE_BIT(reg, REG_CONFIG_MODE_pos, 1); + WRITE_BIT(reg, REG_CONFIG_OS_pos, 1); + ret = tla2021_write_register(dev, REG_CONFIG, reg); + if (ret) { + LOG_WRN("Failed to start conversion"); + } + + data->repeat_buffer = data->buffer; + + k_sem_give(&data->acq_lock); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct tla2021_data *data = CONTAINER_OF(ctx, struct tla2021_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void tla2021_acq_thread_fn(void *p1, void *p2, void *p3) +{ + int ret; + + struct tla2021_data *data = p1; + const struct device *dev = data->dev; + + while (true) { + k_sem_take(&data->acq_lock, K_FOREVER); + + tla2021_reg_config_t reg; + tla2021_reg_data_t res; + + /* + * Wait until sampling is done + */ + do { + ret = tla2021_read_register(dev, REG_CONFIG, ®); + if (ret < 0) { + adc_context_complete(&data->ctx, ret); + } + } while (!(reg & REG_CONFIG_OS_msk)); + + /* + * Read result + */ + ret = tla2021_read_register(dev, REG_DATA, &res); + if (ret) { + adc_context_complete(&data->ctx, ret); + } + + /* + * ADC data is stored in the upper 12 bits + */ + res >>= REG_DATA_pos; + *data->buffer++ = res; + + adc_context_on_sampling_done(&data->ctx, data->dev); + } +} + +static int tla2021_init(const struct device *dev) +{ + int ret; + + const struct tla2021_config *config = dev->config; + struct tla2021_data *data = dev->data; + + k_sem_init(&data->acq_lock, 0, 1); + + if (!i2c_is_ready_dt(&config->bus)) { + LOG_ERR("Bus not ready"); + return -EINVAL; + } + + ret = tla2021_write_register(dev, REG_CONFIG, data->reg_config); + if (ret) { + LOG_ERR("Device reset failed: %d", ret); + return ret; + } + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api tla2021_driver_api = { + .channel_setup = tla2021_channel_setup, + .read = tla2021_read, + .ref_internal = 2048, +#ifdef CONFIG_ADC_ASYNC + .read_async = tla2021_read_async, +#endif +}; + +#define TLA2021_INIT(n) \ + static const struct tla2021_config inst_##n##_config; \ + static struct tla2021_data inst_##n##_data; \ + K_THREAD_DEFINE(inst_##n##_thread, ACQ_THREAD_STACK_SIZE, tla2021_acq_thread_fn, \ + &inst_##n##_data, NULL, NULL, ACQ_THREAD_PRIORITY, 0, 0); \ + static const struct tla2021_config inst_##n##_config = { \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + .acq_thread_id = inst_##n##_thread, \ + }; \ + static struct tla2021_data inst_##n##_data = { \ + .dev = DEVICE_DT_INST_GET(n), \ + ADC_CONTEXT_INIT_LOCK(inst_##n##_data, ctx), \ + ADC_CONTEXT_INIT_TIMER(inst_##n##_data, ctx), \ + ADC_CONTEXT_INIT_SYNC(inst_##n##_data, ctx), \ + .reg_config = REG_CONFIG_DEFAULT, \ + }; \ + DEVICE_DT_INST_DEFINE(n, &tla2021_init, NULL, &inst_##n##_data, &inst_##n##_config, \ + POST_KERNEL, CONFIG_ADC_TLA2021_INIT_PRIORITY, &tla2021_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TLA2021_INIT) + +BUILD_ASSERT(CONFIG_I2C_INIT_PRIORITY < CONFIG_ADC_TLA2021_INIT_PRIORITY); diff --git a/dts/bindings/adc/ti,tla2021.yaml b/dts/bindings/adc/ti,tla2021.yaml new file mode 100644 index 000000000000..4b3ad6b63792 --- /dev/null +++ b/dts/bindings/adc/ti,tla2021.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Caspar Friedrich +# SPDX-License-Identifier: Apache-2.0 + +description: Texas Instruments TLA2021 Low-Power ADC + +compatible: "ti,tla2021" + +include: [i2c-device.yaml, adc-controller.yaml] + +properties: + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input From 33e3ddd4d52a0a3ecfcb9e36b5faf58f663bb6bb Mon Sep 17 00:00:00 2001 From: Jiaxuan Weng <1391548050@qq.com> Date: Thu, 29 Jun 2023 09:31:37 +0800 Subject: [PATCH 0784/2042] boards: xtensa: Add support for xiao esp32s3 add board support and overlay for seeed xiao esp32s3. Signed-off-by: Jiaxuan Weng <1391548050@qq.com> --- boards/xtensa/xiao_esp32s3/Kconfig.board | 8 + boards/xtensa/xiao_esp32s3/Kconfig.defconfig | 18 ++ boards/xtensa/xiao_esp32s3/Kconfig.sysbuild | 10 + boards/xtensa/xiao_esp32s3/board.cmake | 9 + .../xiao_esp32s3/doc/img/xiao_esp32s3.jpg | Bin 0 -> 57885 bytes .../doc/img/xiao_esp32s3_pinout.jpg | Bin 0 -> 71000 bytes boards/xtensa/xiao_esp32s3/doc/index.rst | 239 ++++++++++++++++++ .../xiao_esp32s3/seeed_xiao_connector.dtsi | 29 +++ .../xtensa/xiao_esp32s3/support/openocd.cfg | 7 + .../xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi | 43 ++++ boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts | 127 ++++++++++ boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml | 20 ++ .../xiao_esp32s3/xiao_esp32s3_defconfig | 14 + .../blinky_pwm/boards/xiao_esp32s3.overlay | 44 ++++ samples/net/wifi/boards/xiao_esp32s3.conf | 11 + samples/net/wifi/boards/xiao_esp32s3.overlay | 9 + 16 files changed, 588 insertions(+) create mode 100644 boards/xtensa/xiao_esp32s3/Kconfig.board create mode 100644 boards/xtensa/xiao_esp32s3/Kconfig.defconfig create mode 100644 boards/xtensa/xiao_esp32s3/Kconfig.sysbuild create mode 100644 boards/xtensa/xiao_esp32s3/board.cmake create mode 100644 boards/xtensa/xiao_esp32s3/doc/img/xiao_esp32s3.jpg create mode 100644 boards/xtensa/xiao_esp32s3/doc/img/xiao_esp32s3_pinout.jpg create mode 100644 boards/xtensa/xiao_esp32s3/doc/index.rst create mode 100644 boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi create mode 100644 boards/xtensa/xiao_esp32s3/support/openocd.cfg create mode 100644 boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi create mode 100644 boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts create mode 100644 boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml create mode 100644 boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig create mode 100644 samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay create mode 100644 samples/net/wifi/boards/xiao_esp32s3.conf create mode 100644 samples/net/wifi/boards/xiao_esp32s3.overlay diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.board b/boards/xtensa/xiao_esp32s3/Kconfig.board new file mode 100644 index 000000000000..aa4b08ecf0f0 --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/Kconfig.board @@ -0,0 +1,8 @@ +# XIAO ESP32S3 board configuration + +# Copyright (c) 2023 Seeed Studio inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_XIAO_ESP32S3 + bool "XIAO ESP32S3 Board" + depends on SOC_ESP32S3 diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig new file mode 100644 index 000000000000..4a1b168cf54a --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Seeed Studio inc. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "xiao_esp32s3" + depends on BOARD_XIAO_ESP32S3 + +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/xiao_esp32s3/Kconfig.sysbuild b/boards/xtensa/xiao_esp32s3/Kconfig.sysbuild new file mode 100644 index 000000000000..3a2d17ac5cfd --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/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/xiao_esp32s3/board.cmake b/boards/xtensa/xiao_esp32s3/board.cmake new file mode 100644 index 000000000000..2f04d1fe8861 --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/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/xiao_esp32s3/doc/img/xiao_esp32s3.jpg b/boards/xtensa/xiao_esp32s3/doc/img/xiao_esp32s3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ede72715582987037cf47b0d0eda9a4ebe93ae67 GIT binary patch literal 57885 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�IF60|Wv9 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'LOn662Q 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 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. 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. Default is ``no``. +- ``verifyFlash=yes`` verify the SoC internal flash content after programming + (use together with ``loadTo=flash``). Default is ``no``. + +For example, to erase and verify flash content: + +.. code-block:: console + + west flash --startup-args elfFile=build/zephyr/zephyr.elf loadTo=flash eraseFlash=yes verifyFlash=yes + +Debugging +========= + +Run the ``west debug`` command to launch the Lauterbach TRACE32 software +debugging interface. Alternatively, run ``west debug -r jlink`` to start a +command line debugging session using SEGGER J-Link. + +References +********** + +.. target-notes:: + +.. _NXP MR-CANHUBK3: + https://www.nxp.com/design/development-boards/automotive-development-platforms/s32k-mcu-platforms/s32k344-evaluation-board-for-mobile-robotics-incorporating-100baset1-and-six-can-fd:MR-CANHUBK344 + +.. _NXP S32K344: + https://www.nxp.com/products/processors-and-microcontrollers/s32-automotive-platform/s32k-auto-general-purpose-mcus/s32k3-microcontrollers-for-automotive-general-purpose:S32K3 + +.. _NXP FS26 Safety System Basis Chip: + https://www.nxp.com/products/power-management/pmics-and-sbcs/safety-sbcs/safety-system-basis-chip-with-low-power-fit-for-asil-d:FS26 + +.. _Lauterbach TRACE32: + https://www.lauterbach.com + +.. _SEGGER J-Link: + https://wiki.segger.com/NXP_S32K3xx From 3a10923bbf3a7bbeb9bdcbb9b54a2c88a0960a61 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 20 Jun 2023 19:13:53 +1000 Subject: [PATCH 0945/2042] drivers: wifi: esp_at: use dormant states Update ESP AT modem driver to control the network interface dormant state based on the network connection status, as described in the docs. Signed-off-by: Jordan Yates --- drivers/wifi/esp_at/esp.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 5722928ac0e5..ef3022eb1d47 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -414,6 +414,7 @@ MODEM_CMD_DEFINE(on_cmd_wifi_connected) esp_flags_set(dev, EDF_STA_CONNECTED); wifi_mgmt_raise_connect_result_event(dev->net_iface, 0); + net_if_dormant_off(dev->net_iface); return 0; } @@ -438,6 +439,7 @@ static void esp_mgmt_disconnect_work(struct k_work *work) esp_mode_switch_submit_if_needed(dev); net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); + net_if_dormant_on(dev->net_iface); wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0); } @@ -740,6 +742,7 @@ MODEM_CMD_DEFINE(on_cmd_ready) if (net_if_is_carrier_ok(dev->net_iface)) { + net_if_dormant_on(dev->net_iface); net_if_carrier_off(dev->net_iface); LOG_ERR("Unexpected reset"); } @@ -911,7 +914,7 @@ static int esp_mgmt_scan(const struct device *dev, return -EINPROGRESS; } - if (!net_if_is_up(data->net_iface)) { + if (!net_if_is_carrier_ok(data->net_iface)) { return -EIO; } @@ -954,6 +957,7 @@ static void esp_mgmt_connect_work(struct k_work *work) memset(dev->conn_cmd, 0, sizeof(dev->conn_cmd)); if (ret < 0) { + net_if_dormant_on(dev->net_iface); if (esp_flags_are_set(dev, EDF_STA_CONNECTED)) { esp_flags_clear(dev, EDF_STA_CONNECTED); wifi_mgmt_raise_disconnect_result_event(dev->net_iface, @@ -965,6 +969,7 @@ static void esp_mgmt_connect_work(struct k_work *work) } else if (!esp_flags_are_set(dev, EDF_STA_CONNECTED)) { esp_flags_set(dev, EDF_STA_CONNECTED); wifi_mgmt_raise_connect_result_event(dev->net_iface, 0); + net_if_dormant_off(dev->net_iface); } esp_mode_flags_clear(dev, EDF_STA_LOCK); @@ -979,7 +984,8 @@ static int esp_mgmt_connect(const struct device *dev, struct esp_data *data = dev->data; int len; - if (!net_if_is_up(data->net_iface)) { + if (!net_if_is_carrier_ok(data->net_iface) || + !net_if_is_admin_up(data->net_iface)) { return -EIO; } @@ -1169,6 +1175,7 @@ static void esp_init_work(struct k_work *work) LOG_INF("ESP Wi-Fi ready"); + /* L1 network layer (physical layer) is up */ net_if_carrier_on(dev->net_iface); k_sem_give(&dev->sem_if_up); @@ -1230,6 +1237,9 @@ static int esp_reset(const struct device *dev) static void esp_iface_init(struct net_if *iface) { esp_offload_init(iface); + + /* Not currently connected to a network */ + net_if_dormant_on(iface); } static enum offloaded_net_if_types esp_offload_get_type(void) From 81310769a95f6cc782cac98605b43ac799af4591 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Thu, 6 Jul 2023 16:00:28 -0600 Subject: [PATCH 0946/2042] emul: spi: SPI_EMUL_INIT(n) hard-coded to instance #0 The `SPI_EMUL_INIT(n)` macro used to instantiate SPI bus emulators builds an array of SPI devices attached to the bus, but always checks instance #0 of the bus and not `n`. This makes multiple instances of an emulated SPI bus unusable and popualtes them all with bus 0's devices. Change the `0` to `n`, which matches how the I2C bus emulator does it. Signed-off-by: Tristan Honscheid --- drivers/spi/spi_emul.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index 183941ee750f..98445319b991 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -120,7 +120,7 @@ static struct spi_driver_api spi_emul_api = { #define SPI_EMUL_INIT(n) \ static const struct emul_link_for_bus emuls_##n[] = { DT_FOREACH_CHILD( \ - DT_DRV_INST(0), EMUL_LINK_AND_COMMA) }; \ + DT_DRV_INST(n), EMUL_LINK_AND_COMMA) }; \ static struct emul_list_for_bus spi_emul_cfg_##n = { \ .children = emuls_##n, \ .num_children = ARRAY_SIZE(emuls_##n), \ From a1dc40fdacf44f9e9289af2d3336602c1bceb083 Mon Sep 17 00:00:00 2001 From: Johan Lafon Date: Thu, 6 Jul 2023 15:09:11 +0200 Subject: [PATCH 0947/2042] dts: arm: st: fix SDMMC2 for the H7 family The different references manuals of the STM32H7 family (RM099, RM0433, RM0445 and RM0468) states that SDMMC2RTS and STMMC2EN are on bit 9 of respectively RCC_AHB2RSTR and RCC_AHB2ENR (not on bit 8). Fixes the stm32h7 dts accordingly. Signed-off-by: Johan Lafon --- dts/arm/st/h7/stm32h7.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 012460b885a6..febaf76bca11 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -960,9 +960,9 @@ sdmmc2: sdmmc@48022400 { compatible = "st,stm32-sdmmc"; reg = <0x48022400 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000100>, + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000200>, <&rcc STM32_SRC_PLL1_Q SDMMC_SEL(0)>; - resets = <&rctl STM32_RESET(AHB2, 8U)>; + resets = <&rctl STM32_RESET(AHB2, 9U)>; interrupts = <124 0>; status = "disabled"; }; From ac7cabf9915efc4db5cc0ea5158b7693b9839656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Thu, 6 Jul 2023 11:27:15 +0200 Subject: [PATCH 0948/2042] Bluetooth: Tests: Use the correct ad data size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device privacy test was using the wrong value for the advertising data. To fix the error, the test now use the `BT_DATA_BYTES` macro to create the `bt_data` structure. Also use `BT_DATA_NAME_COMPLETE` instead of the raw value. Signed-off-by: Théo Battrel --- .../host/privacy/device/src/test_undirected_peripheral.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/bsim/bluetooth/host/privacy/device/src/test_undirected_peripheral.c b/tests/bsim/bluetooth/host/privacy/device/src/test_undirected_peripheral.c index 2bb22ce40851..402b590de00e 100644 --- a/tests/bsim/bluetooth/host/privacy/device/src/test_undirected_peripheral.c +++ b/tests/bsim/bluetooth/host/privacy/device/src/test_undirected_peripheral.c @@ -232,14 +232,10 @@ static void update_adv_params(struct bt_le_ext_adv *adv, enum adv_param_t adv_pa } if (use_ext_adv && adv_params == NCONN_SCAN) { - uint8_t data[4] = {0x61, 0x6c, 0x65, 0x64}; - struct bt_data sd; + struct bt_data sd = + BT_DATA_BYTES(BT_DATA_NAME_COMPLETE, 'z', 'e', 'p', 'h', 'y', 'r'); size_t sd_len = 1; - sd.type = 0x09; - sd.data_len = 0x05; - sd.data = data; - err = bt_le_ext_adv_set_data(adv, NULL, 0, &sd, sd_len); if (err) { LOG_ERR("Failed to set advertising data (%d)", err); From f94fd8e60c89124c6c9cf40c72a4089a58fe4a32 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Thu, 6 Jul 2023 10:48:08 +0200 Subject: [PATCH 0949/2042] samples: subsys: usb cdc acm composite with mini nb of USB EndPoints The stm32f207 and stm32f429 target boards only have 4 bidir EP on the USB FS node. This is not enough to run the sample: simply exclude those 2 target platforms Signed-off-by: Francois Ramu --- samples/subsys/usb/cdc_acm_composite/sample.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/subsys/usb/cdc_acm_composite/sample.yaml b/samples/subsys/usb/cdc_acm_composite/sample.yaml index f0a505fb996d..efaedd868520 100644 --- a/samples/subsys/usb/cdc_acm_composite/sample.yaml +++ b/samples/subsys/usb/cdc_acm_composite/sample.yaml @@ -1,9 +1,14 @@ sample: + description: Application with two CDC ACM instances requires at least + two OUT and four IN endpoints on the USB device controller. name: CDC ACM Composite USB tests: sample.usb.cdc-acm-composite: depends_on: usb_device tags: usb + platform_exclude: + - nucleo_f429zi + - nucleo_f207zg arch_exclude: posix harness: console harness_config: From 8a78148e6101836158bfa14a7c33f4fe6e1f6069 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Thu, 6 Jul 2023 09:57:30 +0200 Subject: [PATCH 0950/2042] manifest: openthread: regular openthread upmerge `37fb770` Implementation of new option: `OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT` Signed-off-by: Przemyslaw Bida --- modules/openthread/CMakeLists.txt | 6 ++++++ modules/openthread/Kconfig.features | 4 ++++ west.yml | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index fdc466b19419..267e1a443cda 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -352,6 +352,12 @@ 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() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index e793a9bfaa4a..a6834ce924fa 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -212,6 +212,10 @@ config OPENTHREAD_NEIGHBOR_DISCOVERY_AGENT config OPENTHREAD_NETDATA_PUBLISHER bool "Thread Network Data publisher" +config OPENTHREAD_OPERATIONAL_DATASET_AUTO_INIT + bool "Operational dataset auto init" + default y + config OPENTHREAD_OTNS bool "OTNS support" diff --git a/west.yml b/west.yml index 99a8537ac14b..299457fcb98e 100644 --- a/west.yml +++ b/west.yml @@ -293,7 +293,7 @@ manifest: revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad path: modules/lib/open-amp - name: openthread - revision: 6d557383e8bc8654f813674e8631c2e56b8e70d0 + revision: 37fb77098982d17555dd7a3f58832714bb9df56e path: modules/lib/openthread - name: picolibc path: modules/lib/picolibc From 2a00b9e5055f6f0f77b6ad1a8c3265006dde6e2e Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 5 Jul 2023 18:34:56 +0200 Subject: [PATCH 0951/2042] ci: github: workflows: west_cmds: install natsort package Install the natsort package before running the west commands test suites. The natsort package is required by twister, which is imported in the runners, since c37deeb0c4602dc3eeb700a7dc3ed317283fff17. Signed-off-by: Henrik Brix Andersen --- .github/workflows/west_cmds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/west_cmds.yml b/.github/workflows/west_cmds.yml index f1d2c4c6c7ce..0d30209831df 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -69,7 +69,7 @@ jobs: - name: install pytest run: | pip3 install wheel - pip3 install pytest west pyelftools canopen progress mypy intelhex psutil ply pyserial + pip3 install pytest west pyelftools canopen natsort progress mypy intelhex psutil ply pyserial - name: run pytest-win if: runner.os == 'Windows' run: | From c5402548d15cbdd595f7e2c0fc08d3b0b50040a4 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Wed, 5 Jul 2023 17:58:24 +0200 Subject: [PATCH 0952/2042] scripts: west: runners: esp32: add support for disabling flasher stub Add support for disabling loading of the flasher stub and instead only talk to the ROM bootloader. Signed-off-by: Henrik Brix Andersen --- scripts/west_commands/runners/esp32.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/west_commands/runners/esp32.py b/scripts/west_commands/runners/esp32.py index c80860334f6e..d435014fc382 100644 --- a/scripts/west_commands/runners/esp32.py +++ b/scripts/west_commands/runners/esp32.py @@ -18,7 +18,7 @@ class Esp32BinaryRunner(ZephyrBinaryRunner): def __init__(self, cfg, device, boot_address, part_table_address, app_address, erase=False, baud=921600, flash_size='detect', flash_freq='40m', flash_mode='dio', espidf='espidf', - bootloader_bin=None, partition_table_bin=None): + bootloader_bin=None, partition_table_bin=None, no_stub=False): super().__init__(cfg) self.elf = cfg.elf_file self.app_bin = cfg.bin_file @@ -34,6 +34,7 @@ def __init__(self, cfg, device, boot_address, part_table_address, self.espidf = espidf self.bootloader_bin = bootloader_bin self.partition_table_bin = partition_table_bin + self.no_stub = no_stub @classmethod def name(cls): @@ -73,6 +74,8 @@ def do_add_parser(cls, parser): help='Bootloader image to flash') parser.add_argument('--esp-flash-partition_table', help='Partition table to flash') + parser.add_argument('--esp-no-stub', default=False, action='store_true', + help='Disable launching the flasher stub, only talk to ROM bootloader') @classmethod def do_create(cls, cfg, args): @@ -89,7 +92,8 @@ def do_create(cls, cfg, args): baud=args.esp_baud_rate, flash_size=args.esp_flash_size, flash_freq=args.esp_flash_freq, flash_mode=args.esp_flash_mode, espidf=espidf, bootloader_bin=args.esp_flash_bootloader, - partition_table_bin=args.esp_flash_partition_table) + partition_table_bin=args.esp_flash_partition_table, + no_stub=args.esp_no_stub) def do_run(self, command, **kwargs): self.require(self.espidf) @@ -101,6 +105,8 @@ def do_run(self, command, **kwargs): cmd_erase = cmd_flash + ['erase_flash'] self.check_call(cmd_erase) + if self.no_stub is True: + cmd_flash.extend(['--no-stub']) if self.device is not None: cmd_flash.extend(['--port', self.device]) cmd_flash.extend(['--baud', self.baud]) From 016774a06bd5590af324cf6be65ff4fc9a7b47e6 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Mon, 12 Jun 2023 10:45:02 +0200 Subject: [PATCH 0953/2042] Bluetooth: controller: Fix link_tx overwrite at Central CIS creation In the case where memq_deinit in LLL flushing ends up with the free link being the link provided by the CIS instance, and pointed to by lll.link_tx_free, the free counter data in the link element is overwritten during central CIS creation. This has the effect that when starting the next CIG, there will suddenly be 0 links available, and controller fails assertion. By saving- and restoring the lll.link_tx before and after CIS configuration cache copying, the free counter is intact. Signed-off-by: Morten Priess --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 5 ++++- 1 file changed, 4 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 2293b134e9ff..9b18ef3101c4 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -228,6 +228,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) for (uint8_t i = 0U; i < ll_iso_setup.cis_count; i++) { struct ll_conn_iso_stream *cis; memq_link_t *link_tx_free; + memq_link_t link_tx; cis = ll_conn_iso_stream_get_by_id(ll_iso_setup.stream[i].cis_id); if (cis) { @@ -254,8 +255,9 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) cig->lll.num_cis++; } - /* Store TX free link before transfer */ + /* Store TX link and free link before transfer */ link_tx_free = cis->lll.link_tx_free; + link_tx = cis->lll.link_tx; /* Transfer parameters from configuration cache */ memcpy(cis, &ll_iso_setup.stream[i], sizeof(struct ll_conn_iso_stream)); @@ -264,6 +266,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) cis->framed = cig->central.framing || force_framed; cis->lll.link_tx_free = link_tx_free; + cis->lll.link_tx = link_tx; cis->lll.handle = ll_conn_iso_stream_handle_get(cis); handles[i] = cis->lll.handle; } From 12ef3453c6362a1a25e9a0e1924e13d325240852 Mon Sep 17 00:00:00 2001 From: Morten Priess Date: Fri, 30 Jun 2023 11:38:11 +0200 Subject: [PATCH 0954/2042] Bluetooth: controller: Fix CIG state overwrite in parameters_commit The CIG state variable is set to CIG_STATE_CONFIGURABLE, but then cleared by memcpy from configuration cache. Set state after memcpy. Fixes EBQ test /HCI/CIS/BI-10-C. Signed-off-by: Morten Priess --- 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 9b18ef3101c4..739111c34f4e 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -167,7 +167,6 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) /* No space for new CIG */ return BT_HCI_ERR_INSUFFICIENT_RESOURCES; } - cig->state = CIG_STATE_CONFIGURABLE; cig->lll.num_cis = 0U; } else if (cig->state != CIG_STATE_CONFIGURABLE) { @@ -181,6 +180,8 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) /* Transfer parameters from configuration cache and clear LLL fields */ memcpy(cig, &ll_iso_setup.group, sizeof(struct ll_conn_iso_group)); + cig->state = CIG_STATE_CONFIGURABLE; + /* Setup LLL parameters */ cig->lll.handle = ll_conn_iso_group_handle_get(cig); cig->lll.role = BT_HCI_ROLE_CENTRAL; From 2cf3caa11c433c28b11273752a5764c3c8c90e9e Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Fri, 30 Jun 2023 00:49:40 -0700 Subject: [PATCH 0955/2042] driver: wdt: npcx: add WDT_OPT_PAUSE_HALTED_BY_DBG support. This CL adds WDT_OPT_PAUSE_HALTED_BY_DBG support by enabling freeze mode. Signed-off-by: Mulin Chao --- drivers/watchdog/wdt_npcx.c | 7 ++-- dts/arm/nuvoton/npcx/npcx.dtsi | 6 ++-- soc/arm/nuvoton_npcx/common/reg/reg_def.h | 42 +++++++++++++++++++++++ soc/arm/nuvoton_npcx/common/scfg.c | 13 +++++++ soc/arm/nuvoton_npcx/common/soc_dbg.h | 26 ++++++++++++++ 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 soc/arm/nuvoton_npcx/common/soc_dbg.h diff --git a/drivers/watchdog/wdt_npcx.c b/drivers/watchdog/wdt_npcx.c index 4af2659e5a42..482bbd1c7334 100644 --- a/drivers/watchdog/wdt_npcx.c +++ b/drivers/watchdog/wdt_npcx.c @@ -39,6 +39,7 @@ #include #include +#include "soc_dbg.h" LOG_MODULE_REGISTER(wdt_npcx, CONFIG_WDT_LOG_LEVEL); /* Watchdog operating frequency is fixed to LFCLK (32.768) kHz */ @@ -227,9 +228,11 @@ static int wdt_npcx_setup(const struct device *dev, uint8_t options) return -ENOTSUP; } + /* Stall the WDT counter when halted by debugger */ if ((options & WDT_OPT_PAUSE_HALTED_BY_DBG) != 0) { - LOG_ERR("WDT_OPT_PAUSE_HALTED_BY_DBG is not supported"); - return -ENOTSUP; + npcx_dbg_freeze_enable(true); + } else { + npcx_dbg_freeze_enable(false); } /* diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index 3034afec3285..78f0b84ba5ba 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -83,10 +83,12 @@ scfg: scfg@400c3000 { compatible = "nuvoton,npcx-scfg"; /* First reg region is System Configuration Device */ - /* Second reg region is System Glue Device */ + /* Second reg region is Debugger Interface Device */ + /* Third reg region is System Glue Device */ reg = <0x400c3000 0x70 + 0x400c3070 0x30 0x400a5000 0x2000>; - reg-names = "scfg", "glue"; + reg-names = "scfg", "dbg", "glue"; #alt-cells = <3>; #lvol-cells = <2>; }; diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 0bb92a99532b..31517a0189c4 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -158,6 +158,48 @@ static inline uint32_t npcx_pwdwn_ctl_offset(uint32_t ctl_no) #define NPCX_ENIDL_CTL_PECI_ENI 2 #define NPCX_ENIDL_CTL_ADC_ACC_DIS 1 +/* Macro functions for Development and Debugger Interface (DDI) registers */ +#define NPCX_DBGCTRL(base) (*(volatile uint8_t *)(base + 0x004)) +#define NPCX_DBGFRZEN1(base) (*(volatile uint8_t *)(base + 0x006)) +#define NPCX_DBGFRZEN2(base) (*(volatile uint8_t *)(base + 0x007)) +#define NPCX_DBGFRZEN3(base) (*(volatile uint8_t *)(base + 0x008)) +#define NPCX_DBGFRZEN4(base) (*(volatile uint8_t *)(base + 0x009)) + +/* DDI register fields */ +#define NPCX_DBGCTRL_CCDEV_SEL FIELD(6, 2) +#define NPCX_DBGCTRL_CCDEV_DIR 5 +#define NPCX_DBGCTRL_SEQ_WK_EN 4 +#define NPCX_DBGCTRL_FRCLK_SEL_DIS 3 +#define NPCX_DBGFRZEN1_SPIFEN 7 +#define NPCX_DBGFRZEN1_HIFEN 6 +#define NPCX_DBGFRZEN1_ESPISEN 5 +#define NPCX_DBGFRZEN1_UART1FEN 4 +#define NPCX_DBGFRZEN1_SMB3FEN 3 +#define NPCX_DBGFRZEN1_SMB2FEN 2 +#define NPCX_DBGFRZEN1_MFT2FEN 1 +#define NPCX_DBGFRZEN1_MFT1FEN 0 +#define NPCX_DBGFRZEN2_ITIM6FEN 7 +#define NPCX_DBGFRZEN2_ITIM5FEN 6 +#define NPCX_DBGFRZEN2_ITIM4FEN 5 +#define NPCX_DBGFRZEN2_ITIM64FEN 3 +#define NPCX_DBGFRZEN2_SMB1FEN 2 +#define NPCX_DBGFRZEN2_SMB0FEN 1 +#define NPCX_DBGFRZEN2_MFT3FEN 0 +#define NPCX_DBGFRZEN3_GLBL_FRZ_DIS 7 +#define NPCX_DBGFRZEN3_ITIM3FEN 6 +#define NPCX_DBGFRZEN3_ITIM2FEN 5 +#define NPCX_DBGFRZEN3_ITIM1FEN 4 +#define NPCX_DBGFRZEN3_I3CFEN 2 +#define NPCX_DBGFRZEN3_SMB4FEN 1 +#define NPCX_DBGFRZEN3_SHMFEN 0 +#define NPCX_DBGFRZEN4_UART2FEN 6 +#define NPCX_DBGFRZEN4_UART3FEN 5 +#define NPCX_DBGFRZEN4_UART4FEN 4 +#define NPCX_DBGFRZEN4_LCTFEN 3 +#define NPCX_DBGFRZEN4_SMB7FEN 2 +#define NPCX_DBGFRZEN4_SMB6FEN 1 +#define NPCX_DBGFRZEN4_SMB5FEN 0 + /* * System Configuration (SCFG) device registers */ diff --git a/soc/arm/nuvoton_npcx/common/scfg.c b/soc/arm/nuvoton_npcx/common/scfg.c index 18d7f228d2dc..42add909aa7c 100644 --- a/soc/arm/nuvoton_npcx/common/scfg.c +++ b/soc/arm/nuvoton_npcx/common/scfg.c @@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(pimux_npcx, LOG_LEVEL_ERR); struct npcx_scfg_config { /* scfg device base address */ uintptr_t base_scfg; + uintptr_t base_dbg; uintptr_t base_glue; }; @@ -45,6 +46,7 @@ static const struct npcx_alt def_alts[] = { static const struct npcx_scfg_config npcx_scfg_cfg = { .base_scfg = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), scfg), + .base_dbg = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), dbg), .base_glue = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), glue), }; @@ -129,6 +131,17 @@ void npcx_host_interface_sel(enum npcx_hif_type hif_type) SET_FIELD(inst_scfg->DEVCNT, NPCX_DEVCNT_HIF_TYP_SEL_FIELD, hif_type); } +void npcx_dbg_freeze_enable(bool enable) +{ + const uintptr_t dbg_base = npcx_scfg_cfg.base_dbg; + + if (enable) { + NPCX_DBGFRZEN3(dbg_base) &= ~BIT(NPCX_DBGFRZEN3_GLBL_FRZ_DIS); + } else { + NPCX_DBGFRZEN3(dbg_base) |= BIT(NPCX_DBGFRZEN3_GLBL_FRZ_DIS); + } +} + /* Pin-control driver registration */ static int npcx_scfg_init(void) { diff --git a/soc/arm/nuvoton_npcx/common/soc_dbg.h b/soc/arm/nuvoton_npcx/common/soc_dbg.h new file mode 100644 index 000000000000..dc8f2ce1202c --- /dev/null +++ b/soc/arm/nuvoton_npcx/common/soc_dbg.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NUVOTON_NPCX_SOC_DBG_H_ +#define _NUVOTON_NPCX_SOC_DBG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configure the Automatic Freeze mode. If this mode is enabled, whenever + * the Core is halted, various modules’ clocks, counters are stopped and + * destructive reads are disabled, pending the respective module enable bit for + * debugging. + */ +void npcx_dbg_freeze_enable(bool enable); + +#ifdef __cplusplus +} +#endif + +#endif /* _NUVOTON_NPCX_SOC_DBG_H_ */ From a21c8f0281ab51f5a2ef410882ebb47e83fba268 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Tue, 4 Jul 2023 15:06:38 +0200 Subject: [PATCH 0956/2042] logging: cmake: Remove duplicate source entry log_cache.c was listed twice for zephyr_sources_ifdef. Signed-off-by: Pieter De Gendt --- subsys/logging/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/logging/CMakeLists.txt b/subsys/logging/CMakeLists.txt index 715577f79ab5..e1cd8e7d5f51 100644 --- a/subsys/logging/CMakeLists.txt +++ b/subsys/logging/CMakeLists.txt @@ -12,7 +12,6 @@ if(NOT CONFIG_LOG_MODE_MINIMAL) log_mgmt.c log_cache.c log_msg.c - log_cache.c ) zephyr_sources_ifdef( From 3f2daa256cffec0540c5bf8590c565cf6dd6e3d3 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 4 Jul 2023 13:34:52 +0200 Subject: [PATCH 0957/2042] Bluetooth: BAP: Fix issue with pa sync and ID in broadcast_sink_create The broadcast_id and the pa_sync fields should be set before calling broadcast_sink_add_src as broadcast_sink_add_src will those values to compare against other receive states. The function was also missing a call to broadcast_sink_cleanup for the newly allocated sink in case there was an error. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/bap_broadcast_sink.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index fc5e22178fcf..0ce52048b826 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -1265,6 +1265,9 @@ int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t br return -ENOMEM; } + sink->broadcast_id = broadcast_id; + sink->pa_sync = pa_sync; + recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_pa_sync_cb, (void *)pa_sync); if (recv_state == NULL) { @@ -1275,14 +1278,12 @@ int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t br LOG_DBG("Broadcast ID mismatch: 0x%X != 0x%X", recv_state->broadcast_id, broadcast_id); + broadcast_sink_cleanup(sink); return -EINVAL; } sink->bass_src_id = recv_state->src_id; } - - sink->broadcast_id = broadcast_id; - sink->pa_sync = pa_sync; atomic_set_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_INITIALIZED); SYS_SLIST_FOR_EACH_CONTAINER(&sink_cbs, listener, _node) { From 7199425792e8321d48ab082909d9bded92f7f46c Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Thu, 29 Jun 2023 16:14:27 +0200 Subject: [PATCH 0958/2042] Bluetooth: Mesh: add statistic module PR adds the statistic module to estimate frame handling. The module helps to understand the ratio of the received\relayed\dropped\transmited frames. That shows the efficiency of the current configuration\implementation. Signed-off-by: Aleksandr Khromykh --- doc/connectivity/bluetooth/api/mesh.rst | 1 + .../bluetooth/api/mesh/statistic.rst | 19 +++++ include/zephyr/bluetooth/mesh.h | 1 + include/zephyr/bluetooth/mesh/statistic.h | 69 +++++++++++++++++++ subsys/bluetooth/mesh/CMakeLists.txt | 2 + subsys/bluetooth/mesh/Kconfig | 8 +++ subsys/bluetooth/mesh/adv.c | 29 ++++++++ subsys/bluetooth/mesh/adv.h | 24 +------ subsys/bluetooth/mesh/net.c | 5 ++ subsys/bluetooth/mesh/statistic.c | 64 +++++++++++++++++ subsys/bluetooth/mesh/statistic.h | 14 ++++ 11 files changed, 213 insertions(+), 23 deletions(-) create mode 100644 doc/connectivity/bluetooth/api/mesh/statistic.rst create mode 100644 include/zephyr/bluetooth/mesh/statistic.h create mode 100644 subsys/bluetooth/mesh/statistic.c create mode 100644 subsys/bluetooth/mesh/statistic.h diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index d954348841dd..1eb691b96c8a 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -21,4 +21,5 @@ Read more about Bluetooth mesh on the mesh/proxy.rst mesh/heartbeat.rst mesh/cfg.rst + mesh/statistic.rst mesh/shell.rst diff --git a/doc/connectivity/bluetooth/api/mesh/statistic.rst b/doc/connectivity/bluetooth/api/mesh/statistic.rst new file mode 100644 index 000000000000..bf974b9ae91c --- /dev/null +++ b/doc/connectivity/bluetooth/api/mesh/statistic.rst @@ -0,0 +1,19 @@ +.. _bluetooth_mesh_stat: + +Frame statistic +############### + +The frame statistic API allows monitoring the number of received frames over +different interfaces, and the number of planned and succeeded transmission and +relaying attempts. + +The API helps the user to estimate the efficiency of the advertiser configuration +parameters and the scanning ability of the device. The number of the monitored +parameters can be easily extended by customer values. + +An application can read out and clean up statistics at any time. + +API reference +************* + +.. doxygengroup:: bt_mesh_stat diff --git a/include/zephyr/bluetooth/mesh.h b/include/zephyr/bluetooth/mesh.h index eeea9e4bccaa..a4ef70dc6ded 100644 --- a/include/zephyr/bluetooth/mesh.h +++ b/include/zephyr/bluetooth/mesh.h @@ -48,5 +48,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */ diff --git a/include/zephyr/bluetooth/mesh/statistic.h b/include/zephyr/bluetooth/mesh/statistic.h new file mode 100644 index 000000000000..c5403d2fd546 --- /dev/null +++ b/include/zephyr/bluetooth/mesh/statistic.h @@ -0,0 +1,69 @@ +/** @file + * @brief BLE mesh statistic APIs. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ + +#include + +/** + * @brief Statistic + * @defgroup bt_mesh_stat Statistic + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** The structure that keeps statistics of mesh frames handling. */ +struct bt_mesh_statistic { + /** All received frames passed basic validation and decryption. */ + /** Received frames over advertiser. */ + uint32_t rx_adv; + /** Received frames over loopback. */ + uint32_t rx_loopback; + /** Received frames over proxy. */ + uint32_t rx_proxy; + /** Received over unknown interface. */ + uint32_t rx_uknown; + /** Counter of frames that were initiated to relay over advertiser bearer. */ + uint32_t tx_adv_relay_planned; + /** Counter of frames that succeeded relaying over advertiser bearer. */ + uint32_t tx_adv_relay_succeeded; + /** Counter of frames that were initiated to send over advertiser bearer locally. */ + uint32_t tx_local_planned; + /** Counter of frames that succeeded to send over advertiser bearer locally. */ + uint32_t tx_local_succeeded; + /** Counter of frames that were initiated to send over friend bearer. */ + uint32_t tx_friend_planned; + /** Counter of frames that succeeded to send over friend bearer. */ + uint32_t tx_friend_succeeded; +}; + +/** @brief Get mesh frame handling statistic. + * + * @param st BLE mesh statistic. + */ +void bt_mesh_stat_get(struct bt_mesh_statistic *st); + +/** @brief Reset mesh frame handling statistic. + */ +void bt_mesh_stat_reset(void); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_STATISTIC_H_ */ diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index df97ee49d0ff..10b142e87f59 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -120,6 +120,8 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV sol_pdu_rpl_srv.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_STATISTIC statistic.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 750bc534bf18..70f1ce7c93ad 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1666,4 +1666,12 @@ config BT_MESH_DEBUG_USE_ID_ADDR endif # BT_MESH_LOG_LEVEL_DBG +config BT_MESH_STATISTIC + bool "The frame handling statistics [EXPERIMENTAL]" + select EXPERIMENTAL + help + The module gathers statistics of received, relayed, and transmitted + frames. This helps to estimate the quality of the communication and + the sufficiency of configured advertiser instances. + endif # BT_MESH diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index fd5e84a6db1e..2132c14e1519 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -25,6 +25,7 @@ #include "proxy.h" #include "pb_gatt_srv.h" #include "solicitation.h" +#include "statistic.h" #define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL #include @@ -46,6 +47,30 @@ 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) +{ + if (!adv->started) { + adv->started = 1; + + if (adv->cb && adv->cb->start) { + adv->cb->start(duration, err, adv->cb_data); + } + + if (err) { + adv->cb = NULL; + } else if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { + bt_mesh_stat_succeeded_count(adv); + } + } +} + +static void bt_mesh_adv_send_end(int err, struct bt_mesh_adv const *adv) +{ + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(err, adv->cb_data); + } +} + static void adv_buf_destroy(struct net_buf *buf) { struct bt_mesh_adv adv = *BT_MESH_ADV(buf); @@ -230,6 +255,10 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_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(BT_MESH_ADV(buf)); + } + if (IS_ENABLED(CONFIG_BT_MESH_ADV_EXT_FRIEND_SEPARATE) && BT_MESH_ADV(buf)->tag == BT_MESH_FRIEND_ADV) { net_buf_put(&bt_mesh_friend_queue, net_buf_ref(buf)); diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 9f886c8980bb..3d0acf8a7ac5 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -83,29 +83,7 @@ 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); -static inline void bt_mesh_adv_send_start(uint16_t duration, int err, - struct bt_mesh_adv *adv) -{ - if (!adv->started) { - adv->started = 1; - - if (adv->cb && adv->cb->start) { - adv->cb->start(duration, err, adv->cb_data); - } - - if (err) { - adv->cb = NULL; - } - } -} - -static inline void bt_mesh_adv_send_end( - int err, struct bt_mesh_adv const *adv) -{ - if (adv->started && adv->cb && adv->cb->end) { - adv->cb->end(err, adv->cb_data); - } -} +void bt_mesh_adv_send_start(uint16_t duration, int err, struct bt_mesh_adv *adv); int bt_mesh_scan_active_set(bool active); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 7a65ffe2e6fe..4632d6f7164f 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -35,6 +35,7 @@ #include "settings.h" #include "prov.h" #include "cfg.h" +#include "statistic.h" #ifdef CONFIG_BT_MESH_V1d1 #include "sar_cfg_internal.h" @@ -851,6 +852,10 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, return; } + if (IS_ENABLED(CONFIG_BT_MESH_STATISTIC)) { + bt_mesh_stat_rx(net_if); + } + /* Save the state so the buffer can later be relayed */ net_buf_simple_save(&buf, &state); diff --git a/subsys/bluetooth/mesh/statistic.c b/subsys/bluetooth/mesh/statistic.c new file mode 100644 index 000000000000..5b1ffe7e0f53 --- /dev/null +++ b/subsys/bluetooth/mesh/statistic.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "adv.h" +#include "net.h" +#include "statistic.h" + +static struct bt_mesh_statistic stat; + +void bt_mesh_stat_get(struct bt_mesh_statistic *st) +{ + memcpy(st, &stat, sizeof(struct bt_mesh_statistic)); +} + +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) +{ + if (adv->tag & BT_MESH_LOCAL_ADV) { + stat.tx_local_planned++; + } else if (adv->tag & BT_MESH_RELAY_ADV) { + stat.tx_adv_relay_planned++; + } else if (adv->tag & BT_MESH_FRIEND_ADV) { + stat.tx_friend_planned++; + } +} + +void bt_mesh_stat_succeeded_count(struct bt_mesh_adv *adv) +{ + if (adv->tag & BT_MESH_LOCAL_ADV) { + stat.tx_local_succeeded++; + } else if (adv->tag & BT_MESH_RELAY_ADV) { + stat.tx_adv_relay_succeeded++; + } else if (adv->tag & BT_MESH_FRIEND_ADV) { + stat.tx_friend_succeeded++; + } +} + +void bt_mesh_stat_rx(enum bt_mesh_net_if net_if) +{ + switch (net_if) { + case BT_MESH_NET_IF_ADV: + stat.rx_adv++; + break; + case BT_MESH_NET_IF_LOCAL: + stat.rx_loopback++; + break; + case BT_MESH_NET_IF_PROXY: + case BT_MESH_NET_IF_PROXY_CFG: + stat.rx_proxy++; + break; + default: + stat.rx_uknown++; + break; + } +} diff --git a/subsys/bluetooth/mesh/statistic.h b/subsys/bluetooth/mesh/statistic.h new file mode 100644 index 000000000000..fdb488f0d81b --- /dev/null +++ b/subsys/bluetooth/mesh/statistic.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#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_rx(enum bt_mesh_net_if net_if); + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_STATISTIC_H_ */ From 9b4d0804199debcae6d488ce47dead182ba9b84c Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Mon, 3 Jul 2023 16:10:29 +0200 Subject: [PATCH 0959/2042] Bluetooth: Mesh: add shell statistic commands Commit adds commands to get and to clear the frame statistic. Signed-off-by: Aleksandr Khromykh --- doc/connectivity/bluetooth/api/mesh/shell.rst | 15 +++++++ subsys/bluetooth/mesh/shell/shell.c | 40 +++++++++++++++++++ tests/bluetooth/mesh_shell/prj.conf | 1 + 3 files changed, 56 insertions(+) diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index e70d426a6ed1..dcdac4ed4f94 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -1693,3 +1693,18 @@ The Solicitation PDU RPL Client model is an optional mesh subsystem that can be * ``RngStart``: Start address of the SSRC range. * ``Ackd``: This argument decides on whether an acknowledged or unacknowledged message will be sent. * ``RngLen``: Range length for the SSRC addresses to be cleared from the solicitiation RPL list. This parameter is optional; if absent, only a single SSRC address will be cleared. + + +Frame statistic +=============== + +``mesh stat get`` +----------------- + + Get the frame statistic. The command prints numbers of received frames, as well as numbers of planned and succeeded transmission attempts. + + +``mesh stat clear`` +------------------- + + Clear all statistics collected before. diff --git a/subsys/bluetooth/mesh/shell/shell.c b/subsys/bluetooth/mesh/shell/shell.c index a5231ce2e7d0..3cf577ea6a82 100644 --- a/subsys/bluetooth/mesh/shell/shell.c +++ b/subsys/bluetooth/mesh/shell/shell.c @@ -1595,6 +1595,35 @@ static int cmd_appidx(const struct shell *sh, size_t argc, char *argv[]) return 0; } +#if defined(CONFIG_BT_MESH_STATISTIC) +static int cmd_stat_get(const struct shell *sh, size_t argc, char *argv[]) +{ + struct bt_mesh_statistic st; + + bt_mesh_stat_get(&st); + + shell_print(sh, "Received frames over:"); + shell_print(sh, "adv: %d", st.rx_adv); + shell_print(sh, "loopback: %d", st.rx_loopback); + shell_print(sh, "proxy: %d", st.rx_proxy); + shell_print(sh, "unknown: %d", st.rx_uknown); + + shell_print(sh, "Transmitted frames: - "); + shell_print(sh, "relay adv: %d - %d", st.tx_adv_relay_planned, st.tx_adv_relay_succeeded); + shell_print(sh, "local adv: %d - %d", st.tx_local_planned, st.tx_local_succeeded); + shell_print(sh, "friend: %d - %d", st.tx_friend_planned, st.tx_friend_succeeded); + + return 0; +} + +static int cmd_stat_clear(const struct shell *sh, size_t argc, char *argv[]) +{ + bt_mesh_stat_reset(); + + return 0; +} +#endif + #if defined(CONFIG_BT_MESH_SHELL_CDB) SHELL_STATIC_SUBCMD_SET_CREATE( cdb_cmds, @@ -1723,6 +1752,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(target_cmds, SHELL_CMD_ARG(app, NULL, "[AppKeyIdx]", cmd_appidx, 1, 1), SHELL_SUBCMD_SET_END); +#if defined(CONFIG_BT_MESH_STATISTIC) +SHELL_STATIC_SUBCMD_SET_CREATE(stat_cmds, + SHELL_CMD_ARG(get, NULL, NULL, cmd_stat_get, 1, 0), + SHELL_CMD_ARG(clear, NULL, NULL, cmd_stat_clear, 1, 0), + SHELL_SUBCMD_SET_END); +#endif + /* Placeholder for model shell modules that is configured in the application */ SHELL_SUBCMD_SET_CREATE(model_cmds, (mesh, models)); @@ -1760,6 +1796,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, #endif SHELL_CMD(target, &target_cmds, "Target commands", bt_mesh_shell_mdl_cmds_help), +#if defined(CONFIG_BT_MESH_STATISTIC) + SHELL_CMD(stat, &stat_cmds, "Statistic commands", bt_mesh_shell_mdl_cmds_help), +#endif + SHELL_SUBCMD_SET_END ); diff --git a/tests/bluetooth/mesh_shell/prj.conf b/tests/bluetooth/mesh_shell/prj.conf index 0672ec6cbb31..6535b77c3ab3 100644 --- a/tests/bluetooth/mesh_shell/prj.conf +++ b/tests/bluetooth/mesh_shell/prj.conf @@ -78,3 +78,4 @@ CONFIG_BT_MESH_IV_UPDATE_TEST=y CONFIG_BT_MESH_LOG_LEVEL_DBG=y CONFIG_BT_MESH_CDB=y CONFIG_BT_MESH_PROVISIONER=y +CONFIG_BT_MESH_STATISTIC=y From 8cb7e8e9e6c8b7af13212c41257553cbadd666ad Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 30 Jun 2023 09:35:44 +0200 Subject: [PATCH 0960/2042] nrf52_bsim: Add replacement of __CLZ() Add a replacement of the ARM CMSIS __CLZ() intrinsic/ CLZ instruction (Count leading zeroes) Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/cmsis/cmsis_instr.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/boards/posix/nrf52_bsim/cmsis/cmsis_instr.h b/boards/posix/nrf52_bsim/cmsis/cmsis_instr.h index 978b1d8c349f..e3dfd2aad232 100644 --- a/boards/posix/nrf52_bsim/cmsis/cmsis_instr.h +++ b/boards/posix/nrf52_bsim/cmsis/cmsis_instr.h @@ -151,4 +151,16 @@ static inline uint32_t __LDREXW(volatile uint32_t *ptr) */ static inline void __CLREX(void) { /* Nothing to be done */ } +/** + * \brief Model of an ARM CLZ instruction + */ +static inline unsigned char __CLZ(uint32_t value) +{ + if (value == 0) { + return 32; + } else { + return __builtin_clz(value); + } +} + #endif /* BOARDS_POSIX_NRF52_BSIM_CMSIS_INSTR_H */ From b83941db904040d47f5da789ea89b7ee115d1716 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 30 Jun 2023 16:30:33 +0200 Subject: [PATCH 0961/2042] test gpio_basic_api: Add option to skip pulls test Some boards configuration may not support the pulls test even if the underlaying SOC driver does support the feature. Add the option to skip that test. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/gpio/gpio_basic_api/Kconfig | 7 +++++++ tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/drivers/gpio/gpio_basic_api/Kconfig diff --git a/tests/drivers/gpio/gpio_basic_api/Kconfig b/tests/drivers/gpio/gpio_basic_api/Kconfig new file mode 100644 index 000000000000..f17d6288a625 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/Kconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config SKIP_PULL_TEST + bool "Skip the pull test even if the driver supports it" diff --git a/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c b/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c index 415cd48f3b36..c7e21185f58f 100644 --- a/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c +++ b/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c @@ -668,8 +668,10 @@ ZTEST(gpio_port, test_gpio_port) "check_input_levels failed"); zassert_equal(bits_logical(), TC_PASS, "bits_logical failed"); - zassert_equal(check_pulls(), TC_PASS, - "check_pulls failed"); + if (!IS_ENABLED(CONFIG_SKIP_PULL_TEST)) { + zassert_equal(check_pulls(), TC_PASS, + "check_pulls failed"); + } if (IS_ENABLED(CONFIG_GPIO_GET_CONFIG)) { zassert_equal(pin_get_config(), TC_PASS, "pin_get_config failed"); From e0e88394f57f9e48c82bf72fc5668cd1a8be61b4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 3 Jul 2023 11:38:02 +0200 Subject: [PATCH 0962/2042] manifest: Update nRF HW models to latest The nRF HW models have been updated to include the following fixes and improvements. * GPIO & GPIOTE: Add HW models, including PPI connections and HAL glue. * NRF_NVMC: Avoid segfault on double call of cleanup * BLECrypt_if: Avoid segfault on double call of cleanup 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 299457fcb98e..96d21ca78aa7 100644 --- a/west.yml +++ b/west.yml @@ -287,7 +287,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 37c571ef7c4a86dad852566fc43eb36f42534e9f + revision: 33b999d50093da88cf935383da2bdac70ffd9456 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad From 710a304e67f8718c9371a79bc8a0a647dcd551cd Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 29 Jun 2023 12:54:33 +0200 Subject: [PATCH 0963/2042] nrf52_bsim: Enable GPIO & GPIOTE peripherals in DT Now the HW models include the GPIO & GPIOTE peripherals. Let's enable them. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/nrf52_bsim.dts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/boards/posix/nrf52_bsim/nrf52_bsim.dts b/boards/posix/nrf52_bsim/nrf52_bsim.dts index 861a9eb29fb3..9c01240540eb 100644 --- a/boards/posix/nrf52_bsim/nrf52_bsim.dts +++ b/boards/posix/nrf52_bsim/nrf52_bsim.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Linaro Limited. + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,8 +25,6 @@ /delete-property/ uart-0; /delete-property/ uart-1; /delete-property/ adc-0; - /delete-property/ gpio-1; - /delete-property/ gpiote-0; /delete-property/ wdt-0; /delete-property/ pwm-0; /delete-property/ pwm-1; @@ -44,8 +43,6 @@ /delete-node/ adc@40007000; /delete-node/ uart@40002000; /delete-node/ uart@40028000; - /delete-node/ gpiote@40006000; - /delete-node/ gpio@50000300; /delete-node/ i2c@40003000; /delete-node/ i2c@40004000; /delete-node/ pwm@4001c000; @@ -71,14 +68,19 @@ /delete-property/ ble-coded-phy-supported; }; -&ieee802154 { +&gpiote { status = "okay"; }; &gpio0 { - /* Needed by - * modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_gpiote_zephyr.c - */ + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&ieee802154 { status = "okay"; }; From 970ba8294a31c37a35d6a6d301ecea767aabf7b4 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 30 Jun 2023 10:40:38 +0200 Subject: [PATCH 0964/2042] tests gpio_hogs: Enable for nrf52_bsim Add an overlay for the nrf52_bsim so this test can be run in this board. Signed-off-by: Alberto Escolar Piedras --- .../gpio/gpio_hogs/boards/nrf52_bsim.overlay | 35 +++++++++++++++++++ tests/drivers/gpio/gpio_hogs/testcase.yaml | 1 + 2 files changed, 36 insertions(+) create mode 100644 tests/drivers/gpio/gpio_hogs/boards/nrf52_bsim.overlay diff --git a/tests/drivers/gpio/gpio_hogs/boards/nrf52_bsim.overlay b/tests/drivers/gpio/gpio_hogs/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..6e52de42a232 --- /dev/null +++ b/tests/drivers/gpio/gpio_hogs/boards/nrf52_bsim.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 +*/ + +#include + +/ { + zephyr,user { + output-high-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + output-low-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + input-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + }; +}; + +&gpio0 { + hog1 { + gpio-hog; + gpios = <13 GPIO_ACTIVE_LOW>; + output-high; + }; + + hog2 { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-low; + }; + + hog3 { + gpio-hog; + gpios = <11 GPIO_ACTIVE_LOW>; + input; + }; +}; diff --git a/tests/drivers/gpio/gpio_hogs/testcase.yaml b/tests/drivers/gpio/gpio_hogs/testcase.yaml index 13776ffb4499..70d49fe50798 100644 --- a/tests/drivers/gpio/gpio_hogs/testcase.yaml +++ b/tests/drivers/gpio/gpio_hogs/testcase.yaml @@ -10,6 +10,7 @@ tests: - frdm_k64f - nrf52840dk_nrf52840 - nucleo_g474re + - nrf52_bsim integration_platforms: - native_posix - native_posix_64 From 081c4647cdc8d20cf9d64ae6114ebeb81ba4dd7f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 30 Jun 2023 16:32:00 +0200 Subject: [PATCH 0965/2042] test gpio_basic_api: Enable for nrf52_bsim Add DT and kconfig overlays for the nrf52_bsim so this test can be run in this board too. This simulated board supports short-circuiting pins either programmatically or thru configuration files, but it does not support a pull in an input being able to drag a non driven output, so we need to skip the pull test. Signed-off-by: Alberto Escolar Piedras --- .../gpio/gpio_basic_api/boards/nrf52_bsim.conf | 1 + .../gpio/gpio_basic_api/boards/nrf52_bsim.overlay | 13 +++++++++++++ tests/drivers/gpio/gpio_basic_api/src/main.c | 10 ++++++++++ tests/drivers/gpio/gpio_basic_api/testcase.yaml | 2 +- 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.conf create mode 100644 tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.overlay diff --git a/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.conf b/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.conf new file mode 100644 index 000000000000..b9d02cf11d5d --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.conf @@ -0,0 +1 @@ +CONFIG_SKIP_PULL_TEST=y diff --git a/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.overlay b/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..4184548292a6 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/nrf52_bsim.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test-gpio-basic-api"; + out-gpios = <&gpio1 1 0>; + in-gpios = <&gpio1 2 0>; + }; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/src/main.c b/tests/drivers/gpio/gpio_basic_api/src/main.c index 146aac3cfed1..11c5da9671db 100644 --- a/tests/drivers/gpio/gpio_basic_api/src/main.c +++ b/tests/drivers/gpio/gpio_basic_api/src/main.c @@ -14,6 +14,8 @@ #include "device_imx.h" #elif defined(CONFIG_BOARD_MIMXRT1050_EVK) #include +#elif defined(CONFIG_BOARD_NRF52_BSIM) +#include #endif static void board_setup(void) @@ -87,6 +89,14 @@ static void board_setup(void) zassert_true(device_is_ready(dev), "GPIO dev is not ready"); int rc = gpio_add_callback(dev, &gpio_emul_callback); __ASSERT(rc == 0, "gpio_add_callback() failed: %d", rc); +#elif defined(CONFIG_BOARD_NRF52_BSIM) + static bool done; + + if (!done) { + done = true; + /* This functions allows to programmatically short-circuit SOC GPIO pins */ + nrf_gpio_backend_register_short(1, PIN_OUT, 1, PIN_IN); + } #endif } diff --git a/tests/drivers/gpio/gpio_basic_api/testcase.yaml b/tests/drivers/gpio/gpio_basic_api/testcase.yaml index bf6c5a14c827..9fb9d7fb2929 100644 --- a/tests/drivers/gpio/gpio_basic_api/testcase.yaml +++ b/tests/drivers/gpio/gpio_basic_api/testcase.yaml @@ -13,6 +13,6 @@ tests: filter: dt_compat_enabled("test-gpio-basic-api") drivers.gpio.nrf_sense_edge: - platform_allow: nrf52840dk_nrf52840 + platform_allow: nrf52840dk_nrf52840 nrf52_bsim extra_args: "DTC_OVERLAY_FILE=boards/nrf52840dk_nrf52840.overlay;\ boards/nrf52840dk_nrf52840_sense_edge.overlay" From 34f11e0ce384341e790387dc9ec394ab6b7caba0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 29 Jun 2023 12:55:17 +0200 Subject: [PATCH 0966/2042] nrf52_bsim: test filter: Remove GPIO filter The HW models now also support the GPIO. Let's stop filtering it out, and instead explicitly claim we support it. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/nrf52_bsim.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/posix/nrf52_bsim/nrf52_bsim.yaml b/boards/posix/nrf52_bsim/nrf52_bsim.yaml index 11b93cc7f54f..5b29b9740098 100644 --- a/boards/posix/nrf52_bsim/nrf52_bsim.yaml +++ b/boards/posix/nrf52_bsim/nrf52_bsim.yaml @@ -9,6 +9,7 @@ toolchain: - zephyr testing: ignore_tags: - - gpio - modem - uart +supported: + - gpio From 488396b8af3717f16844c0bebd0cf7d307a9ceae Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 3 Jul 2023 12:11:34 +0200 Subject: [PATCH 0967/2042] test gpio_get_direction: Enable for nrf52_bsim Add needed overlay so the test case run. Signed-off-by: Alberto Escolar Piedras --- .../boards/nrf52_bsim.overlay | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/drivers/gpio/gpio_get_direction/boards/nrf52_bsim.overlay diff --git a/tests/drivers/gpio/gpio_get_direction/boards/nrf52_bsim.overlay b/tests/drivers/gpio/gpio_get_direction/boards/nrf52_bsim.overlay new file mode 100644 index 000000000000..385cec00fe20 --- /dev/null +++ b/tests/drivers/gpio/gpio_get_direction/boards/nrf52_bsim.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + + aliases { + led0 = &led0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; + }; +}; From 5336e7fd145f37a638aae23f72f33413f97e594e Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Thu, 29 Jun 2023 23:12:49 -0400 Subject: [PATCH 0968/2042] drivers: sensor: ina23x: Use micro-ohms for rshunt Changes rshunt-milliohms to rshunt-micro-ohms allowing for current sensing of greater than 16.4A (1mOhm resistor). This is commonly set to 100 uOhm for VMU/FMU boards/applications. Co-authored-by: James Goppert Signed-off-by: Benjamin Perseghetti --- .../nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi | 8 ++++---- boards/arm/stm32g071b_disco/stm32g071b_disco.dts | 2 +- drivers/sensor/ina23x/ina230.c | 4 ++-- drivers/sensor/ina23x/ina230.h | 2 +- drivers/sensor/ina23x/ina237.c | 6 +++--- drivers/sensor/ina23x/ina237.h | 2 +- dts/bindings/sensor/ti,ina23x-common.yaml | 4 ++-- tests/drivers/build_all/sensor/i2c.dtsi | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi index d603c019c575..614fadf8ae73 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_nrf5340_cpuapp_common.dtsi @@ -156,7 +156,7 @@ INA230_CONV_TIME_4156, INA230_AVG_MODE_1024)>; current-lsb-microamps = <1>; - rshunt-milliohms = <510>; + rshunt-micro-ohms = <510000>; }; vdd1_codec_sensor: ina231@45 { @@ -167,7 +167,7 @@ INA230_CONV_TIME_4156, INA230_AVG_MODE_1024)>; current-lsb-microamps = <1>; - rshunt-milliohms = <2200>; + rshunt-micro-ohms = <2200000>; }; vdd2_codec_sensor: ina231@41 { @@ -178,7 +178,7 @@ INA230_CONV_TIME_4156, INA230_AVG_MODE_1024)>; current-lsb-microamps = <1>; - rshunt-milliohms = <2200>; + rshunt-micro-ohms = <2200000>; }; vdd2_nrf_sensor: ina231@40 { @@ -189,7 +189,7 @@ INA230_CONV_TIME_4156, INA230_AVG_MODE_1024)>; current-lsb-microamps = <1>; - rshunt-milliohms = <1000>; + rshunt-micro-ohms = <1000000>; }; }; diff --git a/boards/arm/stm32g071b_disco/stm32g071b_disco.dts b/boards/arm/stm32g071b_disco/stm32g071b_disco.dts index c643387a52a7..b1882a5f72db 100644 --- a/boards/arm/stm32g071b_disco/stm32g071b_disco.dts +++ b/boards/arm/stm32g071b_disco/stm32g071b_disco.dts @@ -144,7 +144,7 @@ INA230_CONV_TIME_1100, INA230_AVG_MODE_1)>; current-lsb-microamps = <1000>; - rshunt-milliohms = <15>; + rshunt-micro-ohms = <15000>; }; }; diff --git a/drivers/sensor/ina23x/ina230.c b/drivers/sensor/ina23x/ina230.c index 7c7357e4c221..6e7c23ba152d 100644 --- a/drivers/sensor/ina23x/ina230.c +++ b/drivers/sensor/ina23x/ina230.c @@ -192,7 +192,7 @@ static int ina230_calibrate(const struct device *dev) /* See datasheet "Programming" section */ val = (INA230_CAL_SCALING * 10000U) / - (config->current_lsb * config->rshunt); + ((config->current_lsb * config->rshunt) / 1000U); ret = ina23x_reg_write(&config->bus, INA230_REG_CALIB, val); if (ret < 0) { @@ -276,7 +276,7 @@ static const struct sensor_driver_api ina230_driver_api = { .bus = I2C_DT_SPEC_INST_GET(inst), \ .config = DT_INST_PROP(inst, config), \ .current_lsb = DT_INST_PROP(inst, current_lsb_microamps),\ - .rshunt = DT_INST_PROP(inst, rshunt_milliohms), \ + .rshunt = DT_INST_PROP(inst, rshunt_micro_ohms), \ COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, alert_gpios),\ (INA230_CFG_IRQ(inst)), ()) \ }; \ diff --git a/drivers/sensor/ina23x/ina230.h b/drivers/sensor/ina23x/ina230.h index 04cfc013d6fd..68a4bbef2358 100644 --- a/drivers/sensor/ina23x/ina230.h +++ b/drivers/sensor/ina23x/ina230.h @@ -50,7 +50,7 @@ struct ina230_config { struct i2c_dt_spec bus; uint16_t config; uint32_t current_lsb; - uint16_t rshunt; + uint32_t rshunt; #ifdef CONFIG_INA230_TRIGGER bool trig_enabled; uint16_t mask; diff --git a/drivers/sensor/ina23x/ina237.c b/drivers/sensor/ina23x/ina237.c index b1142a558ebd..468f4af9f96d 100644 --- a/drivers/sensor/ina23x/ina237.c +++ b/drivers/sensor/ina23x/ina237.c @@ -244,8 +244,8 @@ static int ina237_calibrate(const struct device *dev) int ret; /* see datasheet "Current and Power calculations" section */ - val = (INA237_CAL_SCALING * config->current_lsb * config->rshunt) / - 10000000U; + val = (INA237_CAL_SCALING * ((config->current_lsb * config->rshunt) / + 1000U)) / 10000000U; ret = ina23x_reg_write(&config->bus, INA237_REG_CALIB, val); if (ret < 0) { @@ -379,7 +379,7 @@ static const struct sensor_driver_api ina237_driver_api = { .config = DT_INST_PROP(inst, config), \ .adc_config = DT_INST_PROP(inst, adc_config), \ .current_lsb = DT_INST_PROP(inst, current_lsb_microamps), \ - .rshunt = DT_INST_PROP(inst, rshunt_milliohms), \ + .rshunt = DT_INST_PROP(inst, rshunt_micro_ohms), \ .alert_config = DT_INST_PROP_OR(inst, alert_config, 0x01), \ .alert_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, alert_gpios, {0}), \ }; \ diff --git a/drivers/sensor/ina23x/ina237.h b/drivers/sensor/ina23x/ina237.h index 7b9bd95ef5e1..b028f5ffb9bb 100644 --- a/drivers/sensor/ina23x/ina237.h +++ b/drivers/sensor/ina23x/ina237.h @@ -49,7 +49,7 @@ struct ina237_config { uint16_t config; uint16_t adc_config; uint32_t current_lsb; - uint16_t rshunt; + uint32_t rshunt; const struct gpio_dt_spec alert_gpio; uint16_t alert_config; }; diff --git a/dts/bindings/sensor/ti,ina23x-common.yaml b/dts/bindings/sensor/ti,ina23x-common.yaml index 7e196a30a43f..7f481ca616d5 100644 --- a/dts/bindings/sensor/ti,ina23x-common.yaml +++ b/dts/bindings/sensor/ti,ina23x-common.yaml @@ -34,10 +34,10 @@ properties: while keeping a good measurement resolution. The units are in uA/LSB so that low maximum currents can be measured with enough resolution. - rshunt-milliohms: + rshunt-micro-ohms: type: int required: true - description: Shunt resistor value in milliohms + description: Shunt resistor value in microOhms alert-gpios: type: phandle-array diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index d7bc380c92b7..c725f8b9d197 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -591,7 +591,7 @@ test_i2c_ina230: ina230@5e { reg = <0x5e>; config = <0>; current-lsb-microamps = <1000>; - rshunt-milliohms = <0>; + rshunt-micro-ohms = <0>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; @@ -608,7 +608,7 @@ test_i2c_ina231: ina231@60 { reg = <0x60>; config = <0>; current-lsb-microamps = <1000>; - rshunt-milliohms = <0>; + rshunt-micro-ohms = <0>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; @@ -620,7 +620,7 @@ test_i2c_ina237: ina237@61 { config = <0>; current-lsb-microamps = <1000>; adc-config = <0>; - rshunt-milliohms = <0>; + rshunt-micro-ohms = <0>; alert-config = <0>; alert-gpios = <&test_gpio 0 0>; }; From da95a407bfd6269b9e76f8582c8e93e846cfacba Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Mon, 3 Jul 2023 15:18:15 -0400 Subject: [PATCH 0969/2042] drivers: sensor: ina23x: calculate cal at compile. Calculate the calibration value at compile for ina23x. Maximizes the precision of the calcualtion value by using 64bit math at compile, allows for removal of rshunt config option. Code cleaned up with clang-format. Co-authored-by: Trent Piepho Signed-off-by: Benjamin Perseghetti --- drivers/sensor/ina23x/ina230.c | 71 ++++++++++--------------- drivers/sensor/ina23x/ina230.h | 2 +- drivers/sensor/ina23x/ina237.c | 64 +++++++++------------- drivers/sensor/ina23x/ina237.h | 2 +- tests/drivers/build_all/sensor/i2c.dtsi | 6 +-- 5 files changed, 56 insertions(+), 89 deletions(-) diff --git a/drivers/sensor/ina23x/ina230.c b/drivers/sensor/ina23x/ina230.c index 6e7c23ba152d..12d6c50b95cb 100644 --- a/drivers/sensor/ina23x/ina230.c +++ b/drivers/sensor/ina23x/ina230.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(INA230, CONFIG_SENSOR_LOG_LEVEL); /** @brief Calibration scaling value (value scaled by 100000) */ -#define INA230_CAL_SCALING 512U +#define INA230_CAL_SCALING 512ULL /** @brief The LSB value for the bus voltage register, in microvolts/LSB. */ #define INA230_BUS_VOLTAGE_UV_LSB 1250U @@ -24,8 +24,7 @@ LOG_MODULE_REGISTER(INA230, CONFIG_SENSOR_LOG_LEVEL); /** @brief The scaling for the power register. */ #define INA230_POWER_SCALING 25 -static int ina230_channel_get(const struct device *dev, - enum sensor_channel chan, +static int ina230_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct ina230_data *data = dev->data; @@ -61,8 +60,7 @@ static int ina230_channel_get(const struct device *dev, break; case SENSOR_CHAN_POWER: - power_uw = data->power * INA230_POWER_SCALING - * config->current_lsb; + power_uw = data->power * INA230_POWER_SCALING * config->current_lsb; /* convert to fractional watts */ val->val1 = (int32_t)(power_uw / 1000000U); @@ -77,16 +75,13 @@ static int ina230_channel_get(const struct device *dev, return 0; } -static int ina230_sample_fetch(const struct device *dev, - enum sensor_channel chan) +static int ina230_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct ina230_data *data = dev->data; const struct ina230_config *config = dev->config; int ret; - if (chan != SENSOR_CHAN_ALL && - chan != SENSOR_CHAN_VOLTAGE && - chan != SENSOR_CHAN_CURRENT && + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_CURRENT && chan != SENSOR_CHAN_POWER) { return -ENOTSUP; } @@ -119,8 +114,7 @@ static int ina230_sample_fetch(const struct device *dev, } static int ina230_attr_set(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) + enum sensor_attribute attr, const struct sensor_value *val) { const struct ina230_config *config = dev->config; uint16_t data = val->val1; @@ -141,8 +135,7 @@ static int ina230_attr_set(const struct device *dev, enum sensor_channel chan, } static int ina230_attr_get(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, - struct sensor_value *val) + enum sensor_attribute attr, struct sensor_value *val) { const struct ina230_config *config = dev->config; uint16_t data; @@ -187,14 +180,10 @@ static int ina230_attr_get(const struct device *dev, enum sensor_channel chan, static int ina230_calibrate(const struct device *dev) { const struct ina230_config *config = dev->config; - uint16_t val; int ret; /* See datasheet "Programming" section */ - val = (INA230_CAL_SCALING * 10000U) / - ((config->current_lsb * config->rshunt) / 1000U); - - ret = ina23x_reg_write(&config->bus, INA230_REG_CALIB, val); + ret = ina23x_reg_write(&config->bus, INA230_REG_CALIB, config->cal); if (ret < 0) { return ret; } @@ -232,8 +221,7 @@ static int ina230_init(const struct device *dev) return ret; } - ret = ina23x_reg_write(&config->bus, INA230_REG_ALERT, - config->alert_limit); + ret = ina23x_reg_write(&config->bus, INA230_REG_ALERT, config->alert_limit); if (ret < 0) { LOG_ERR("Failed to write alert register!"); return ret; @@ -245,7 +233,7 @@ static int ina230_init(const struct device *dev) return ret; } } -#endif /* CONFIG_INA230_TRIGGER */ +#endif /* CONFIG_INA230_TRIGGER */ return 0; } @@ -261,32 +249,27 @@ static const struct sensor_driver_api ina230_driver_api = { }; #ifdef CONFIG_INA230_TRIGGER -#define INA230_CFG_IRQ(inst) \ - .trig_enabled = true, \ - .mask = DT_INST_PROP(inst, mask), \ - .alert_limit = DT_INST_PROP(inst, alert_limit), \ +#define INA230_CFG_IRQ(inst) \ + .trig_enabled = true, .mask = DT_INST_PROP(inst, mask), \ + .alert_limit = DT_INST_PROP(inst, alert_limit), \ .alert_gpio = GPIO_DT_SPEC_INST_GET(inst, alert_gpios) #else #define INA230_CFG_IRQ(inst) #endif /* CONFIG_INA230_TRIGGER */ -#define INA230_DRIVER_INIT(inst) \ - static struct ina230_data drv_data_##inst; \ - static const struct ina230_config drv_config_##inst = { \ - .bus = I2C_DT_SPEC_INST_GET(inst), \ - .config = DT_INST_PROP(inst, config), \ - .current_lsb = DT_INST_PROP(inst, current_lsb_microamps),\ - .rshunt = DT_INST_PROP(inst, rshunt_micro_ohms), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, alert_gpios),\ - (INA230_CFG_IRQ(inst)), ()) \ - }; \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, \ - &ina230_init, \ - NULL, \ - &drv_data_##inst, \ - &drv_config_##inst, \ - POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, \ - &ina230_driver_api); +#define INA230_DRIVER_INIT(inst) \ + static struct ina230_data drv_data_##inst; \ + static const struct ina230_config drv_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .config = DT_INST_PROP(inst, config), \ + .current_lsb = DT_INST_PROP(inst, current_lsb_microamps), \ + .cal = (uint16_t)((INA230_CAL_SCALING * 10000000ULL) / \ + ((uint64_t)DT_INST_PROP(inst, current_lsb_microamps) * \ + DT_INST_PROP(inst, rshunt_micro_ohms))), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, alert_gpios), (INA230_CFG_IRQ(inst)), \ + ())}; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, &ina230_init, NULL, &drv_data_##inst, \ + &drv_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &ina230_driver_api); DT_INST_FOREACH_STATUS_OKAY(INA230_DRIVER_INIT) diff --git a/drivers/sensor/ina23x/ina230.h b/drivers/sensor/ina23x/ina230.h index 68a4bbef2358..1f45ffa12e29 100644 --- a/drivers/sensor/ina23x/ina230.h +++ b/drivers/sensor/ina23x/ina230.h @@ -50,7 +50,7 @@ struct ina230_config { struct i2c_dt_spec bus; uint16_t config; uint32_t current_lsb; - uint32_t rshunt; + uint16_t cal; #ifdef CONFIG_INA230_TRIGGER bool trig_enabled; uint16_t mask; diff --git a/drivers/sensor/ina23x/ina237.c b/drivers/sensor/ina23x/ina237.c index 468f4af9f96d..0811a0c49704 100644 --- a/drivers/sensor/ina23x/ina237.c +++ b/drivers/sensor/ina23x/ina237.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(INA237, CONFIG_SENSOR_LOG_LEVEL); /** @brief Calibration scaling value (scaled by 10^-5) */ -#define INA237_CAL_SCALING 8192U +#define INA237_CAL_SCALING 8192ULL /** @brief The LSB value for the bus voltage register, in microvolts/LSB. */ #define INA237_BUS_VOLTAGE_UV_LSB 3125 @@ -25,8 +25,7 @@ LOG_MODULE_REGISTER(INA237, CONFIG_SENSOR_LOG_LEVEL); /** @brief Power scaling (scaled by 10) */ #define INA237_POWER_SCALING 2 -static int ina237_channel_get(const struct device *dev, - enum sensor_channel chan, +static int ina237_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct ina237_data *data = dev->data; @@ -61,8 +60,7 @@ static int ina237_channel_get(const struct device *dev, case SENSOR_CHAN_POWER: /* see datasheet "Current and Power calculations" section */ - power_uw = (data->power * INA237_POWER_SCALING * - config->current_lsb) / 10000U; + power_uw = (data->power * INA237_POWER_SCALING * config->current_lsb) / 10000U; /* convert to fractional watts */ val->val1 = (int32_t)(power_uw / 1000000U); @@ -166,14 +164,11 @@ static int ina237_read_data(const struct device *dev) * @retval 0 for success * @retval negative errno code on fail */ -static int ina237_sample_fetch(const struct device *dev, - enum sensor_channel chan) +static int ina237_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct ina237_data *data = dev->data; - if (chan != SENSOR_CHAN_ALL && - chan != SENSOR_CHAN_VOLTAGE && - chan != SENSOR_CHAN_CURRENT && + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_CURRENT && chan != SENSOR_CHAN_POWER) { return -ENOTSUP; } @@ -188,8 +183,7 @@ static int ina237_sample_fetch(const struct device *dev, } static int ina237_attr_set(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) + enum sensor_attribute attr, const struct sensor_value *val) { const struct ina237_config *config = dev->config; uint16_t data = val->val1; @@ -206,8 +200,7 @@ static int ina237_attr_set(const struct device *dev, enum sensor_channel chan, } static int ina237_attr_get(const struct device *dev, enum sensor_channel chan, - enum sensor_attribute attr, - struct sensor_value *val) + enum sensor_attribute attr, struct sensor_value *val) { const struct ina237_config *config = dev->config; uint16_t data; @@ -240,14 +233,10 @@ static int ina237_attr_get(const struct device *dev, enum sensor_channel chan, static int ina237_calibrate(const struct device *dev) { const struct ina237_config *config = dev->config; - uint16_t val; int ret; /* see datasheet "Current and Power calculations" section */ - val = (INA237_CAL_SCALING * ((config->current_lsb * config->rshunt) / - 1000U)) / 10000000U; - - ret = ina23x_reg_write(&config->bus, INA237_REG_CALIB, val); + ret = ina23x_reg_write(&config->bus, INA237_REG_CALIB, config->cal); if (ret < 0) { return ret; } @@ -347,8 +336,7 @@ static int ina237_init(const struct device *dev) return 0; } -static int ina237_trigger_set(const struct device *dev, - const struct sensor_trigger *trig, +static int ina237_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { ARG_UNUSED(trig); @@ -372,24 +360,20 @@ static const struct sensor_driver_api ina237_driver_api = { .channel_get = ina237_channel_get, }; -#define INA237_DRIVER_INIT(inst) \ - static struct ina237_data ina237_data_##inst; \ - static const struct ina237_config ina237_config_##inst = { \ - .bus = I2C_DT_SPEC_INST_GET(inst), \ - .config = DT_INST_PROP(inst, config), \ - .adc_config = DT_INST_PROP(inst, adc_config), \ - .current_lsb = DT_INST_PROP(inst, current_lsb_microamps), \ - .rshunt = DT_INST_PROP(inst, rshunt_micro_ohms), \ - .alert_config = DT_INST_PROP_OR(inst, alert_config, 0x01), \ - .alert_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, alert_gpios, {0}), \ - }; \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, \ - &ina237_init, \ - NULL, \ - &ina237_data_##inst, \ - &ina237_config_##inst, \ - POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, \ - &ina237_driver_api); +#define INA237_DRIVER_INIT(inst) \ + static struct ina237_data ina237_data_##inst; \ + static const struct ina237_config ina237_config_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .config = DT_INST_PROP(inst, config), \ + .adc_config = DT_INST_PROP(inst, adc_config), \ + .current_lsb = DT_INST_PROP(inst, current_lsb_microamps), \ + .cal = INA237_CAL_SCALING * DT_INST_PROP(inst, current_lsb_microamps) * \ + DT_INST_PROP(inst, rshunt_micro_ohms) / 10000000000ULL, \ + .alert_config = DT_INST_PROP_OR(inst, alert_config, 0x01), \ + .alert_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, alert_gpios, {0}), \ + }; \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, &ina237_init, NULL, &ina237_data_##inst, \ + &ina237_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &ina237_driver_api); \ DT_INST_FOREACH_STATUS_OKAY(INA237_DRIVER_INIT) diff --git a/drivers/sensor/ina23x/ina237.h b/drivers/sensor/ina23x/ina237.h index b028f5ffb9bb..95cff3d85b46 100644 --- a/drivers/sensor/ina23x/ina237.h +++ b/drivers/sensor/ina23x/ina237.h @@ -49,7 +49,7 @@ struct ina237_config { uint16_t config; uint16_t adc_config; uint32_t current_lsb; - uint32_t rshunt; + uint16_t cal; const struct gpio_dt_spec alert_gpio; uint16_t alert_config; }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index c725f8b9d197..487f0c3d3aea 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -591,7 +591,7 @@ test_i2c_ina230: ina230@5e { reg = <0x5e>; config = <0>; current-lsb-microamps = <1000>; - rshunt-micro-ohms = <0>; + rshunt-micro-ohms = <1000>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; @@ -608,7 +608,7 @@ test_i2c_ina231: ina231@60 { reg = <0x60>; config = <0>; current-lsb-microamps = <1000>; - rshunt-micro-ohms = <0>; + rshunt-micro-ohms = <1000>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; @@ -620,7 +620,7 @@ test_i2c_ina237: ina237@61 { config = <0>; current-lsb-microamps = <1000>; adc-config = <0>; - rshunt-micro-ohms = <0>; + rshunt-micro-ohms = <1000>; alert-config = <0>; alert-gpios = <&test_gpio 0 0>; }; From f2d6e0f6607ee180feee78c6a1b4d6bb08a9c0e0 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 19 Jun 2023 09:02:12 +0000 Subject: [PATCH 0970/2042] mgmt: ec_host_cmd: set max response every command Update the response buffer size, passed to a command handler, every command, since a backend could change it in runtime. Signed-off-by: Dawid Niedzwiecki --- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6e4b96396d4d..ff3b428ce589 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -233,7 +233,6 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * /* The pointer to rx buffer is constant during communication */ struct ec_host_cmd_handler_args args = { .output_buf = (uint8_t *)tx->buf + TX_HEADER_SIZE, - .output_buf_max = tx->len_max - TX_HEADER_SIZE, .input_buf = rx->buf + RX_HEADER_SIZE, .reserved = NULL, }; @@ -266,6 +265,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * args.command = rx_header->cmd_id; args.version = rx_header->cmd_ver; args.input_buf_size = rx_header->data_len; + args.output_buf_max = tx->len_max - TX_HEADER_SIZE, args.output_buf_size = 0; status = validate_handler(found_handler, &args); From 521f0ba4f891fd4a508a6d3e15f8504317336ca2 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 19 Jun 2023 09:02:43 +0000 Subject: [PATCH 0971/2042] mgmt: ec_host_cmd: clear response buffer every command The response buffer has to be cleared every command not to pass unintended content e.g. response from a previous command, or stack content. Signed-off-by: Dawid Niedzwiecki --- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 6 ++++++ 1 file changed, 6 insertions(+) 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 ff3b428ce589..784a6c9c0f8f 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -274,6 +274,12 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * continue; } + /* + * Pre-emptively clear the entire response buffer so we do not + * have any left over contents from previous host commands. + */ + memset(args.output_buf, 0, args.output_buf_max); + status = found_handler->handler(&args); ec_host_cmd_send_response(status, &args); From 40924edec2eb860d6e96683d45bbd1905b798574 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 19 Jun 2023 09:03:32 +0000 Subject: [PATCH 0972/2042] mgmt: ec_host_cmd: fix checking command version The sizeof is used in a wrong way which causes incorrect checking a version of a command. Use NUM_BITS instead. Signed-off-by: Dawid Niedzwiecki --- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 784a6c9c0f8f..c160246dd7e9 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -123,7 +123,7 @@ static enum ec_host_cmd_status validate_handler(const struct ec_host_cmd_handler return EC_HOST_CMD_INVALID_RESPONSE; } - if (args->version > sizeof(handler->version_mask) || + if (args->version >= NUM_BITS(handler->version_mask) || !(handler->version_mask & BIT(args->version))) { return EC_HOST_CMD_INVALID_VERSION; } From e1401fcf5e3870502389b7de8ab54b3e6d493935 Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Fri, 26 May 2023 14:25:59 -0600 Subject: [PATCH 0973/2042] emul: Add SBS Gauge emulator backend_api In order to support easier setup of test scenarios with fuel gauge emulators, we should expose an API that can change internal emulator state. Add a minimal fuel gauge emulator backend API for setting the charging current and voltage with a sample implementation in the emul_sbs_gauge with an associated driver test. Signed-off-by: Aaron Massey --- doc/hardware/peripherals/fuel_gauge.rst | 1 + drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c | 36 ++++++++- include/zephyr/drivers/emul_fuel_gauge.h | 73 +++++++++++++++++++ .../fuel_gauge/sbs_gauge/src/test_sbs_gauge.c | 31 ++++++++ 4 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 include/zephyr/drivers/emul_fuel_gauge.h diff --git a/doc/hardware/peripherals/fuel_gauge.rst b/doc/hardware/peripherals/fuel_gauge.rst index b5f0bd26d888..bc042c8b21f9 100644 --- a/doc/hardware/peripherals/fuel_gauge.rst +++ b/doc/hardware/peripherals/fuel_gauge.rst @@ -35,3 +35,4 @@ API Reference ************* .. doxygengroup:: fuel_gauge_interface +.. doxygengroup:: fuel_gauge_emulator_backend diff --git a/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c b/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c index 18dc997b014f..f735e07598d2 100644 --- a/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c +++ b/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(sbs_sbs_gauge); #include #include #include +#include #include #include "sbs_gauge.h" @@ -32,6 +33,13 @@ struct sbs_gauge_emul_data { uint16_t remaining_time_alarm; uint16_t mode; int16_t at_rate; + struct { + /* Non-register values associated with the state of the battery */ + /* Battery terminal voltage */ + uint32_t uV; + /* Battery terminal current - Pos is charging, Neg is discharging */ + int uA; + } batt_state; }; /** Static configuration for the emulator */ @@ -90,6 +98,11 @@ static int emul_sbs_gauge_reg_read(const struct emul *target, int reg, int *val) *val = data->at_rate; break; case SBS_GAUGE_CMD_VOLTAGE: + *val = data->batt_state.uV / 1000; + break; + case SBS_GAUGE_CMD_CURRENT: + *val = data->batt_state.uA / 1000; + break; case SBS_GAUGE_CMD_AVG_CURRENT: case SBS_GAUGE_CMD_TEMP: case SBS_GAUGE_CMD_ASOC: @@ -102,7 +115,6 @@ static int emul_sbs_gauge_reg_read(const struct emul *target, int reg, int *val) case SBS_GAUGE_CMD_RUNTIME2EMPTY: case SBS_GAUGE_CMD_CYCLE_COUNT: case SBS_GAUGE_CMD_DESIGN_VOLTAGE: - case SBS_GAUGE_CMD_CURRENT: case SBS_GAUGE_CMD_CHG_CURRENT: case SBS_GAUGE_CMD_CHG_VOLTAGE: case SBS_GAUGE_CMD_FLAGS: @@ -220,6 +232,23 @@ static int sbs_gauge_emul_transfer_i2c(const struct emul *target, struct i2c_msg return rc; } +static int emul_sbs_fuel_gauge_set_battery_charging(const struct emul *target, uint32_t uV, int uA) +{ + struct sbs_gauge_emul_data *data = target->data; + + if (uV == 0 || uA == 0) + return -EINVAL; + + data->batt_state.uA = uA; + data->batt_state.uV = uV; + + return 0; +} + +static const struct fuel_gauge_emul_driver_api sbs_gauge_backend_api = { + .set_battery_charging = emul_sbs_fuel_gauge_set_battery_charging, +}; + static const struct i2c_emul_api sbs_gauge_emul_api_i2c = { .transfer = sbs_gauge_emul_transfer_i2c, }; @@ -243,11 +272,12 @@ static int emul_sbs_sbs_gauge_init(const struct emul *target, const struct devic * Main instantiation macro. SBS Gauge Emulator only implemented for I2C */ #define SBS_GAUGE_EMUL(n) \ - static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \ + static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \ static const struct sbs_gauge_emul_cfg sbs_gauge_emul_cfg_##n = { \ .addr = DT_INST_REG_ADDR(n), \ }; \ EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_gauge_init, &sbs_gauge_emul_data_##n, \ - &sbs_gauge_emul_cfg_##n, &sbs_gauge_emul_api_i2c, NULL) + &sbs_gauge_emul_cfg_##n, &sbs_gauge_emul_api_i2c, \ + &sbs_gauge_backend_api) DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_EMUL) diff --git a/include/zephyr/drivers/emul_fuel_gauge.h b/include/zephyr/drivers/emul_fuel_gauge.h new file mode 100644 index 000000000000..812de61a79f2 --- /dev/null +++ b/include/zephyr/drivers/emul_fuel_gauge.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Backend APIs for the fuel gauge emulators. + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_ +#define ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Fuel gauge backend emulator APIs + * @defgroup fuel_gauge_emulator_backend fuel gauge backed emulator APIs + * @ingroup io_interfaces + * @{ + */ + +/** + * @cond INTERNAL_HIDDEN + * + * These are for internal use only, so skip these in public documentation. + */ +__subsystem struct fuel_gauge_emul_driver_api { + int (*set_battery_charging)(const struct emul *emul, uint32_t uV, int uA); +}; +/** + * @endcond + */ + +/** + * @brief Set charging for fuel gauge associated battery. + * + * Set how much the battery associated with a fuel gauge IC is charging or discharging. Where + * voltage is always positive and a positive or negative current denotes charging or discharging, + * respectively. + * + * @param target Pointer to the emulator structure for the fuel gauge emulator instance. + * @param uV Microvolts describing the battery voltage. + * @param uA Microamps describing the battery current where negative is discharging. + * + * @retval 0 If successful. + * @retval -EINVAL if mV or mA are 0. + */ +static inline int emul_fuel_gauge_set_battery_charging(const struct emul *target, uint32_t uV, + int uA) +{ + const struct fuel_gauge_emul_driver_api *backend_api = + (const struct fuel_gauge_emul_driver_api *)target->backend_api; + + return backend_api->set_battery_charging(target, uV, uA); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_*/ diff --git a/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c b/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c index 54418eb1970a..5a67149181d3 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c +++ b/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include #include #include @@ -16,6 +18,7 @@ struct sbs_gauge_new_api_fixture { const struct device *dev; + const struct emul *sbs_fuel_gauge; const struct fuel_gauge_driver_api *api; }; @@ -24,6 +27,7 @@ static void *sbs_gauge_new_api_setup(void) static ZTEST_DMEM struct sbs_gauge_new_api_fixture fixture; fixture.dev = DEVICE_DT_GET_ANY(sbs_sbs_gauge_new_api); + fixture.sbs_fuel_gauge = EMUL_DT_GET(DT_NODELABEL(smartbattery0)); k_object_access_all_grant(fixture.dev); @@ -344,5 +348,32 @@ ZTEST_USER_F(sbs_gauge_new_api, test_get_buffer_props__returns_ok) zassert_ok(ret); } +ZTEST_F(sbs_gauge_new_api, test_charging_5v_3a) +{ + /* Validate what props are supported by the driver */ + uint32_t expected_uV = 5000 * 1000; + uint32_t expected_uA = 3000 * 1000; + + struct fuel_gauge_get_property props[] = { + { + .property_type = FUEL_GAUGE_VOLTAGE, + }, + { + .property_type = FUEL_GAUGE_CURRENT, + }, + }; + + zassume_ok(emul_fuel_gauge_set_battery_charging(fixture->sbs_fuel_gauge, expected_uV, + expected_uA)); + zassert_ok(fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props))); + + zassert_ok(props[0].status); + zassert_equal(props[0].value.voltage, expected_uV, "Got %d instead of %d", + props[0].value.voltage, expected_uV); + + zassert_ok(props[1].status); + zassert_equal(props[1].value.current, expected_uA, "Got %d instead of %d", + props[1].value.current, expected_uA); +} ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL); From 3e33d6af893a06c565ce816889a8e556ddb03eb9 Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Fri, 26 May 2023 15:24:45 -0600 Subject: [PATCH 0974/2042] emul: SBS Gauge emulator reset rule Since we have state that gets mutated between tests in the SBS fuel gauge emulator we ought to reset its state before each test. Add a reset rule to the SBS fuel gauge emulator that resets the state before each test. Note: This includes allowing the emulator state to be modified by user-threads. Signed-off-by: Aaron Massey --- drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c b/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c index f735e07598d2..69b9f798b55e 100644 --- a/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c +++ b/drivers/fuel_gauge/sbs_gauge/emul_sbs_gauge.c @@ -253,6 +253,33 @@ static const struct i2c_emul_api sbs_gauge_emul_api_i2c = { .transfer = sbs_gauge_emul_transfer_i2c, }; +static void sbs_gauge_emul_reset(const struct emul *target) +{ + struct sbs_gauge_emul_data *data = target->data; + + memset(data, 0, sizeof(*data)); +} + +#ifdef CONFIG_ZTEST +#include + +/* Add test reset handlers in when using emulators with tests */ +#define SBS_GAUGE_EMUL_RESET_RULE_BEFORE(inst) \ + sbs_gauge_emul_reset(EMUL_DT_GET(DT_DRV_INST(inst))); + +static void emul_sbs_gauge_reset_rule_after(const struct ztest_unit_test *test, void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_EMUL_RESET_RULE_BEFORE) +} +ZTEST_RULE(emul_sbs_gauge_reset, NULL, emul_sbs_gauge_reset_rule_after); +#else /* !CONFIG_ZTEST */ +/* Stub ZTEST_DMEM in case emulator is not used in a testing environment. */ +#define ZTEST_DMEM +#endif /* CONFIG_ZTEST */ + /** * Set up a new SBS_GAUGE emulator (I2C) * @@ -262,9 +289,10 @@ static const struct i2c_emul_api sbs_gauge_emul_api_i2c = { */ static int emul_sbs_sbs_gauge_init(const struct emul *target, const struct device *parent) { - ARG_UNUSED(target); ARG_UNUSED(parent); + sbs_gauge_emul_reset(target); + return 0; } @@ -272,7 +300,7 @@ static int emul_sbs_sbs_gauge_init(const struct emul *target, const struct devic * Main instantiation macro. SBS Gauge Emulator only implemented for I2C */ #define SBS_GAUGE_EMUL(n) \ - static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \ + static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \ static const struct sbs_gauge_emul_cfg sbs_gauge_emul_cfg_##n = { \ .addr = DT_INST_REG_ADDR(n), \ }; \ From 4ce1f03aa98c896713834793b3bfc6581d6ac450 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Apr 2023 12:54:58 +1000 Subject: [PATCH 0975/2042] kernel: event modification functions return previous value Update the return value of functions that modify the internal event state from `void` to `uint32_t`, so that calling code can determine whether the event was already in a given state, or if the call modified it. This simplifies the usage of `struct k_event` as an alternative to `atomic_t` that users can block on. Implements #57216 Signed-off-by: Jordan Yates --- include/zephyr/kernel.h | 16 ++++++++++++---- kernel/events.c | 38 +++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 1efc59283228..f1fb7a74f52c 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -2201,8 +2201,10 @@ __syscall void k_event_init(struct k_event *event); * * @param event Address of the event object * @param events Set of events to post to @a event + * + * @retval Previous value of the events in @a event */ -__syscall void k_event_post(struct k_event *event, uint32_t events); +__syscall uint32_t k_event_post(struct k_event *event, uint32_t events); /** * @brief Set the events in an event object @@ -2216,8 +2218,10 @@ __syscall void k_event_post(struct k_event *event, uint32_t events); * * @param event Address of the event object * @param events Set of events to set in @a event + * + * @retval Previous value of the events in @a event */ -__syscall void k_event_set(struct k_event *event, uint32_t events); +__syscall uint32_t k_event_set(struct k_event *event, uint32_t events); /** * @brief Set or clear the events in an event object @@ -2230,8 +2234,10 @@ __syscall void k_event_set(struct k_event *event, uint32_t events); * @param event Address of the event object * @param events Set of events to set/clear in @a event * @param events_mask Mask to be applied to @a events + * + * @retval Previous value of the events in @a events_mask */ -__syscall void k_event_set_masked(struct k_event *event, uint32_t events, +__syscall uint32_t k_event_set_masked(struct k_event *event, uint32_t events, uint32_t events_mask); /** @@ -2241,8 +2247,10 @@ __syscall void k_event_set_masked(struct k_event *event, uint32_t events, * * @param event Address of the event object * @param events Set of events to clear in @a event + * + * @retval Previous value of the events in @a event */ -__syscall void k_event_clear(struct k_event *event, uint32_t events); +__syscall uint32_t k_event_clear(struct k_event *event, uint32_t events); /** * @brief Wait for any of the specified events diff --git a/kernel/events.c b/kernel/events.c index 5e71aa57ca65..96cae5bc4a86 100644 --- a/kernel/events.c +++ b/kernel/events.c @@ -119,12 +119,13 @@ static int event_walk_op(struct k_thread *thread, void *data) return 0; } -static void k_event_post_internal(struct k_event *event, uint32_t events, +static uint32_t k_event_post_internal(struct k_event *event, uint32_t events, uint32_t events_mask) { k_spinlock_key_t key; struct k_thread *thread; struct event_walk_data data; + uint32_t previous_events; data.head = NULL; key = k_spin_lock(&event->lock); @@ -132,6 +133,7 @@ static void k_event_post_internal(struct k_event *event, uint32_t events, SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_event, post, event, events, events_mask); + previous_events = event->events & events_mask; events = (event->events & ~events_mask) | (events & events_mask); event->events = events; @@ -164,62 +166,64 @@ static void k_event_post_internal(struct k_event *event, uint32_t events, SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_event, post, event, events, events_mask); + + return previous_events; } -void z_impl_k_event_post(struct k_event *event, uint32_t events) +uint32_t z_impl_k_event_post(struct k_event *event, uint32_t events) { - k_event_post_internal(event, events, events); + return k_event_post_internal(event, events, events); } #ifdef CONFIG_USERSPACE -void z_vrfy_k_event_post(struct k_event *event, uint32_t events) +uint32_t z_vrfy_k_event_post(struct k_event *event, uint32_t events) { Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); - z_impl_k_event_post(event, events); + return z_impl_k_event_post(event, events); } #include #endif -void z_impl_k_event_set(struct k_event *event, uint32_t events) +uint32_t z_impl_k_event_set(struct k_event *event, uint32_t events) { - k_event_post_internal(event, events, ~0); + return k_event_post_internal(event, events, ~0); } #ifdef CONFIG_USERSPACE -void z_vrfy_k_event_set(struct k_event *event, uint32_t events) +uint32_t z_vrfy_k_event_set(struct k_event *event, uint32_t events) { Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); - z_impl_k_event_set(event, events); + return z_impl_k_event_set(event, events); } #include #endif -void z_impl_k_event_set_masked(struct k_event *event, uint32_t events, +uint32_t z_impl_k_event_set_masked(struct k_event *event, uint32_t events, uint32_t events_mask) { - k_event_post_internal(event, events, events_mask); + return k_event_post_internal(event, events, events_mask); } #ifdef CONFIG_USERSPACE -void z_vrfy_k_event_set_masked(struct k_event *event, uint32_t events, +uint32_t z_vrfy_k_event_set_masked(struct k_event *event, uint32_t events, uint32_t events_mask) { Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); - z_impl_k_event_set_masked(event, events, events_mask); + return z_impl_k_event_set_masked(event, events, events_mask); } #include #endif -void z_impl_k_event_clear(struct k_event *event, uint32_t events) +uint32_t z_impl_k_event_clear(struct k_event *event, uint32_t events) { - k_event_post_internal(event, 0, events); + return k_event_post_internal(event, 0, events); } #ifdef CONFIG_USERSPACE -void z_vrfy_k_event_clear(struct k_event *event, uint32_t events) +uint32_t z_vrfy_k_event_clear(struct k_event *event, uint32_t events) { Z_OOPS(Z_SYSCALL_OBJ(event, K_OBJ_EVENT)); - z_impl_k_event_clear(event, events); + return z_impl_k_event_clear(event, events); } #include #endif From 5312ebd972866c38a6439dc5429febeb08d9f935 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Apr 2023 13:02:19 +1000 Subject: [PATCH 0976/2042] kernel: add `k_event_test` Add `k_event_test`, a helper function around `k_event_wait` which is intended as an equivalent to `atomic_test_bit` in the atomic API. Signed-off-by: Jordan Yates --- include/zephyr/kernel.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index f1fb7a74f52c..d3a435a4d38a 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -2300,6 +2300,19 @@ __syscall uint32_t k_event_wait(struct k_event *event, uint32_t events, __syscall uint32_t k_event_wait_all(struct k_event *event, uint32_t events, bool reset, k_timeout_t timeout); +/** + * @brief Test the events currently tracked in the event object + * + * @param event Address of the event object + * @param events_mask Set of desired events to test + * + * @retval Current value of events in @a events_mask + */ +static inline uint32_t k_event_test(struct k_event *event, uint32_t events_mask) +{ + return k_event_wait(event, events_mask, false, K_NO_WAIT); +} + /** * @brief Statically define and initialize an event object * From c3c586a1b4205b1c4b82173b8dbd4508416f7fb8 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Apr 2023 13:18:31 +1000 Subject: [PATCH 0977/2042] tests: kernel: events: test return value Add tests for the return value of `k_event_post`, `k_event_clear`, `k_event_set` and ``k_event_set_masked`. Signed-off-by: Jordan Yates --- tests/kernel/events/event_api/src/main.c | 1 + .../events/event_api/src/test_event_apis.c | 43 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/kernel/events/event_api/src/main.c b/tests/kernel/events/event_api/src/main.c index f4b98f678020..650b0e4159d8 100644 --- a/tests/kernel/events/event_api/src/main.c +++ b/tests/kernel/events/event_api/src/main.c @@ -15,6 +15,7 @@ * -# k_event_set * -# k_event_wait * -# k_event_wait_all + * -# k_event_test * * @defgroup kernel_event_tests events * @ingroup all_tests diff --git a/tests/kernel/events/event_api/src/test_event_apis.c b/tests/kernel/events/event_api/src/test_event_apis.c index f4eb0f80fc2e..275040f508d8 100644 --- a/tests/kernel/events/event_api/src/test_event_apis.c +++ b/tests/kernel/events/event_api/src/test_event_apis.c @@ -341,10 +341,11 @@ ZTEST(events_api, test_event_deliver) static struct k_event event; uint32_t events; uint32_t events_mask; + uint32_t previous; k_event_init(&event); - zassert_true(event.events == 0); + zassert_equal(k_event_test(&event, ~0), 0); /* * Verify k_event_post() and k_event_set() update the @@ -352,43 +353,49 @@ ZTEST(events_api, test_event_deliver) */ events = 0xAAAA; - k_event_post(&event, events); - zassert_true(event.events == events); + previous = k_event_post(&event, events); + zassert_equal(previous, 0x0000); + zassert_equal(k_event_test(&event, ~0), events); events |= 0x55555ABC; - k_event_post(&event, events); - zassert_true(event.events == events); + previous = k_event_post(&event, events); + zassert_equal(previous, events & 0xAAAA); + zassert_equal(k_event_test(&event, ~0), events); events = 0xAAAA0000; - k_event_set(&event, events); - zassert_true(event.events == events); + previous = k_event_set(&event, events); + zassert_equal(previous, 0xAAAA | 0x55555ABC); + zassert_equal(k_event_test(&event, ~0), events); /* * Verify k_event_set_masked() update the events * stored in the event object as expected */ events = 0x33333333; - k_event_set(&event, events); - zassert_true(event.events == events); + (void)k_event_set(&event, events); + zassert_equal(k_event_test(&event, ~0), events); events_mask = 0x11111111; - k_event_set_masked(&event, 0, events_mask); - zassert_true(event.events == 0x22222222); + previous = k_event_set_masked(&event, 0, events_mask); + zassert_equal(previous, 0x11111111); + zassert_equal(k_event_test(&event, ~0), 0x22222222); events_mask = 0x22222222; - k_event_set_masked(&event, 0, events_mask); - zassert_true(event.events == 0); + previous = k_event_set_masked(&event, 0, events_mask); + zassert_equal(previous, 0x22222222); + zassert_equal(k_event_test(&event, ~0), 0); events = 0x22222222; events_mask = 0x22222222; - k_event_set_masked(&event, events, events_mask); - zassert_true(event.events == events); + previous = k_event_set_masked(&event, events, events_mask); + zassert_equal(previous, 0x00000000); + zassert_equal(k_event_test(&event, ~0), events); events = 0x11111111; events_mask = 0x33333333; - k_event_set_masked(&event, events, events_mask); - zassert_true(event.events == events); - + previous = k_event_set_masked(&event, events, events_mask); + zassert_equal(previous, 0x22222222); + zassert_equal(k_event_test(&event, ~0), events); } /** From fa49f77973224dc4f79a081d1f98eab9bb5e047c Mon Sep 17 00:00:00 2001 From: Dino Li Date: Thu, 9 Mar 2023 16:59:37 +0800 Subject: [PATCH 0978/2042] drivers/crypto/it8xxx2: add support for SHA256 hardware accelerator Add SHA256 accelerator support for it8xxx2 series. This driver passes the following test: tests/crypto/crypto_hash/ Signed-off-by: Dino Li --- boards/riscv/it8xxx2_evb/it8xxx2_evb.dts | 3 + drivers/crypto/CMakeLists.txt | 1 + drivers/crypto/Kconfig | 1 + drivers/crypto/Kconfig.it8xxx2 | 13 ++ drivers/crypto/crypto_it8xxx2_sha.c | 225 +++++++++++++++++++++++ dts/bindings/crypto/ite,it8xxx2-sha.yaml | 12 ++ dts/riscv/ite/it8xxx2.dtsi | 6 + 7 files changed, 261 insertions(+) create mode 100644 drivers/crypto/Kconfig.it8xxx2 create mode 100644 drivers/crypto/crypto_it8xxx2_sha.c create mode 100644 dts/bindings/crypto/ite,it8xxx2-sha.yaml diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts index 1f3e4455b2a1..1b127e4bc0e7 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.dts @@ -179,6 +179,9 @@ pinctrl-0 = <&peci_gpf6_default>; pinctrl-names = "default"; }; +&sha0 { + status = "okay"; +}; &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/drivers/crypto/CMakeLists.txt b/drivers/crypto/CMakeLists.txt index 94423278a884..acb9730d2e0a 100644 --- a/drivers/crypto/CMakeLists.txt +++ b/drivers/crypto/CMakeLists.txt @@ -9,4 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_NRF_ECB crypto_nrf_ecb.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_INTEL_SHA crypto_intel_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_NPCX_SHA crypto_npcx_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCHP_XEC_SYMCR crypto_mchp_xec_symcr.c) +zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA crypto_it8xxx2_sha.c) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index a93d2aa7e253..d5dbf9e26858 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -78,5 +78,6 @@ source "drivers/crypto/Kconfig.nrf_ecb" source "drivers/crypto/Kconfig.intel" source "drivers/crypto/Kconfig.npcx" source "drivers/crypto/Kconfig.xec" +source "drivers/crypto/Kconfig.it8xxx2" endif # CRYPTO diff --git a/drivers/crypto/Kconfig.it8xxx2 b/drivers/crypto/Kconfig.it8xxx2 new file mode 100644 index 000000000000..d38062db84c1 --- /dev/null +++ b/drivers/crypto/Kconfig.it8xxx2 @@ -0,0 +1,13 @@ +# Copyright (c) 2023 ITE Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config CRYPTO_IT8XXX2_SHA + bool "ITE IT8XXX2 SHA driver" + default y + depends on DT_HAS_ITE_IT8XXX2_SHA_ENABLED + select SOC_IT8XXX2_SHA256_HW_ACCELERATE + help + Enable ITE IT8XXX2 SHA driver. + This driver supports SHA256 hardware accelerator of the it8xxx2 series. + It requires 256 + 256 bytes in the RAM's first 4k-bytes to calculate + SHA256 hash. diff --git a/drivers/crypto/crypto_it8xxx2_sha.c b/drivers/crypto/crypto_it8xxx2_sha.c new file mode 100644 index 000000000000..3e8dbee69bc3 --- /dev/null +++ b/drivers/crypto/crypto_it8xxx2_sha.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2023 ITE Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it8xxx2_sha + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(sha_it8xxx2, CONFIG_CRYPTO_LOG_LEVEL); + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "unsupported sha instance"); + +#define IT8XXX2_SHA_REGS_BASE DT_REG_ADDR(DT_NODELABEL(sha0)) + +/* 0x00: Hash Control Register */ +#define IT8XXX2_REG_HASHCTRLR (0) +/* 0x01: SHA256 Hash Base Address 1 Register */ +#define IT8XXX2_REG_SHA_HBADDR (1) +/* 0x02: SHA256 Hash Base Address 2 Register */ +#define IT8XXX2_REG_SHA_HBADDR2 (2) + +#define IT8XXX2_SHA_START_SHA256 BIT(1) + +#define SHA_SHA256_HASH_LEN 32 +#define SHA_SHA256_BLOCK_LEN 64 +#define SHA_SHA256_K_LEN 256 +#define SHA_SHA256_HASH_LEN_WORDS (SHA_SHA256_HASH_LEN / sizeof(uint32_t)) +#define SHA_SHA256_BLOCK_LEN_WORDS (SHA_SHA256_BLOCK_LEN / sizeof(uint32_t)) +#define SHA_SHA256_K_LEN_WORDS (SHA_SHA256_K_LEN / sizeof(uint32_t)) + +/* + * This struct is used by the hardware and must be stored in RAM first 4k-byte + * and aligned on a 256-byte boundary. + */ +struct chip_sha256_ctx { + union { + /* W[0] ~ W[15] */ + uint32_t w_sha[SHA_SHA256_BLOCK_LEN_WORDS]; + uint8_t w_input[SHA_SHA256_BLOCK_LEN]; + }; + /* reserved */ + uint32_t reserved1[8]; + /* H[0] ~ H[7] */ + uint32_t h[SHA_SHA256_HASH_LEN_WORDS]; + /* reserved */ + uint32_t reserved2[30]; + uint32_t w_input_index; + uint32_t total_len; + /* K[0] ~ K[63] */ + uint32_t k[SHA_SHA256_K_LEN_WORDS]; +} __aligned(256); + +Z_GENERIC_SECTION(.__sha256_ram_block) struct chip_sha256_ctx chip_ctx; + +static const uint32_t sha256_h0[SHA_SHA256_HASH_LEN_WORDS] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 +}; + +/* + * References of K of SHA-256: + * https://en.wikipedia.org/wiki/SHA-2#Pseudocode + */ +static const uint32_t sha256_k[SHA_SHA256_K_LEN_WORDS] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void it8xxx2_sha256_init(bool init_k) +{ + int i; + + chip_ctx.total_len = 0; + chip_ctx.w_input_index = 0; + + /* Initialize hash values */ + for (i = 0; i < ARRAY_SIZE(sha256_h0); i++) { + chip_ctx.h[i] = sha256_h0[i]; + } + /* Initialize array of round constants */ + if (init_k) { + for (int i = 0; i < ARRAY_SIZE(sha256_k); i++) { + chip_ctx.k[i] = sha256_k[i]; + } + } +} + +static void it8xxx2_sha256_module_calculation(void) +{ + uint32_t key; + uint8_t hash_ctrl; + + /* + * Since W field on it8xxx2 requires big-endian format, change byte + * order before computing hash. + */ + for (int i = 0; i < SHA_SHA256_BLOCK_LEN_WORDS; i++) { + chip_ctx.w_sha[i] = sys_cpu_to_be32(chip_ctx.w_sha[i]); + } + /* + * Global interrupt is disabled because the CPU cannot access memory + * via the DLM (Data Local Memory) bus while HW module is computing + * hash. + */ + key = irq_lock(); + hash_ctrl = sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_HASHCTRLR); + sys_write8(hash_ctrl | IT8XXX2_SHA_START_SHA256, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_HASHCTRLR); + hash_ctrl = sys_read8(IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_HASHCTRLR); + irq_unlock(key); + + chip_ctx.w_input_index = 0; +} + +static int it8xxx2_hash_handler(struct hash_ctx *ctx, struct hash_pkt *pkt, + bool finish) +{ + uint32_t rem_len = pkt->in_len; + uint32_t in_buf_idx = 0; + + while (rem_len--) { + chip_ctx.w_input[chip_ctx.w_input_index++] = + pkt->in_buf[in_buf_idx++]; + if (chip_ctx.w_input_index >= SHA_SHA256_BLOCK_LEN) { + it8xxx2_sha256_module_calculation(); + } + } + chip_ctx.total_len += pkt->in_len; + + if (finish) { + uint32_t *ob_ptr = (uint32_t *)pkt->out_buf; + + /* Pre-processing (Padding) */ + memset(&chip_ctx.w_input[chip_ctx.w_input_index], + 0, SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); + chip_ctx.w_input[chip_ctx.w_input_index] = 0x80; + + if (chip_ctx.w_input_index >= 56) { + it8xxx2_sha256_module_calculation(); + memset(&chip_ctx.w_input[chip_ctx.w_input_index], + 0, SHA_SHA256_BLOCK_LEN - chip_ctx.w_input_index); + } + chip_ctx.w_sha[15] = sys_cpu_to_be32(chip_ctx.total_len * 8); + it8xxx2_sha256_module_calculation(); + + for (int i = 0; i < SHA_SHA256_HASH_LEN_WORDS; i++) { + ob_ptr[i] = sys_be32_to_cpu(chip_ctx.h[i]); + } + + it8xxx2_sha256_init(false); + } + + return 0; +} + +static int it8xxx2_hash_session_free(const struct device *dev, + struct hash_ctx *ctx) +{ + it8xxx2_sha256_init(false); + + return 0; +} + +static inline int it8xxx2_query_hw_caps(const struct device *dev) +{ + return (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS); +} + +static int it8xxx2_hash_begin_session(const struct device *dev, + struct hash_ctx *ctx, enum hash_algo algo) +{ + if (algo != CRYPTO_HASH_ALGO_SHA256) { + LOG_ERR("Unsupported algo"); + return -EINVAL; + } + + if (ctx->flags & ~(it8xxx2_query_hw_caps(dev))) { + LOG_ERR("Unsupported flag"); + return -EINVAL; + } + + it8xxx2_sha256_init(false); + ctx->hash_hndlr = it8xxx2_hash_handler; + + return 0; +} + +static int it8xxx2_sha_init(const struct device *dev) +{ + it8xxx2_sha256_init(true); + /* Configure base address register for W and H */ + sys_write8(((uint32_t)&chip_ctx >> 6) & 0xfc, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHA_HBADDR); + /* Configure base address register for K */ + sys_write8(((uint32_t)&chip_ctx.k >> 6) & 0xfc, + IT8XXX2_SHA_REGS_BASE + IT8XXX2_REG_SHA_HBADDR2); + + return 0; +} + +static struct crypto_driver_api it8xxx2_crypto_api = { + .hash_begin_session = it8xxx2_hash_begin_session, + .hash_free_session = it8xxx2_hash_session_free, + .query_hw_caps = it8xxx2_query_hw_caps, +}; + +DEVICE_DT_INST_DEFINE(0, &it8xxx2_sha_init, NULL, NULL, NULL, POST_KERNEL, + CONFIG_CRYPTO_INIT_PRIORITY, &it8xxx2_crypto_api); diff --git a/dts/bindings/crypto/ite,it8xxx2-sha.yaml b/dts/bindings/crypto/ite,it8xxx2-sha.yaml new file mode 100644 index 000000000000..598e2fc9a866 --- /dev/null +++ b/dts/bindings/crypto/ite,it8xxx2-sha.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023, ITE Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: ITE IT8XXX2 Crypto SHA accelerator. + +compatible: "ite,it8xxx2-sha" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 705ff1f08a09..3fbf0c062520 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -708,6 +708,12 @@ kso17-gpios = <&gpioc 5 (GPIO_OPEN_DRAIN | GPIO_PULL_UP)>; }; + sha0: sha@f0202d { + compatible = "ite,it8xxx2-sha"; + reg = <0x00f0202d 0x3>; + status = "disabled"; + }; + usbpd0: usbpd@f03700 { compatible = "ite,it8xxx2-usbpd"; reg = <0x00f03700 0x100>; From e8a7c6706f7a48754b17d2d2bb4688fe6a54c805 Mon Sep 17 00:00:00 2001 From: Emil Obalski Date: Mon, 26 Jun 2023 15:01:36 +0200 Subject: [PATCH 0979/2042] scripts: west: Check for sysbuild flag when parsing test item If build is used with -T option, sysbuild flag was ignored neverthelesss being present in sample.yaml/testcase.yaml file. Signed-off-by: Emil Obalski --- scripts/west_commands/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index 0e27c3c626e3..379f5e702947 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -290,6 +290,7 @@ def _parse_test_item(self, test_item): self.args.cmake_opts.extend(args) else: self.args.cmake_opts = args + self.args.sysbuild = item.get('sysbuild') return found_test_metadata def _sanity_precheck(self): From f46453cabb660f6a4ee5b81f0163a229cb5dfbee Mon Sep 17 00:00:00 2001 From: Ren Chen Date: Fri, 30 Jun 2023 09:49:13 +0800 Subject: [PATCH 0980/2042] drivers: usb: usb_dc_it82xx2: correct the resumed/suspended mechanism This change corrects the it82xx2 resumed/suspended mechanism and power policy flow. The sof package is used to judge if the device can be set as suspended state. If there is no sof package received(suspended), the chip power policy is set as standby(deep doze) mode. Meanwhile, the USB D+ interrupt is enabled. The interrupt is triggered at resume signal(from J to K state). Chip sets its power state as active(doze) mode and disable the interrupt. Signed-off-by: Ren Chen --- drivers/usb/device/usb_dc_it82xx2.c | 152 ++++++++++++++++------------ 1 file changed, 90 insertions(+), 62 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index 1d92ce117112..d90c351841b3 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -177,6 +177,7 @@ struct it82xx2_endpoint_data { }; struct usb_it82xx2_data { + const struct device *dev; struct it82xx2_endpoint_data ep_data[MAX_NUM_ENDPOINTS]; enum it82xx2_setup_stage st_state; /* Setup State */ @@ -196,6 +197,8 @@ struct usb_it82xx2_data { bool ep_ready[3]; struct k_sem ep_sem[3]; + struct k_sem suspended_sem; + struct k_work_delayable check_suspended_work; }; /* Mapped to the bit definitions in the EPN_EXTEND_CONTROL1 Register @@ -238,24 +241,48 @@ static struct usb_it82xx2_regs *it82xx2_get_usb_regs(void) return usb_regs; } +static void it82xx2_enable_sof_int(bool enable) +{ + struct usb_it82xx2_regs *const usb_regs = + (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + + usb_regs->dc_interrupt_status = DC_SOF_RECEIVED; + if (enable) { + usb_regs->dc_interrupt_mask |= DC_SOF_RECEIVED; + } else { + usb_regs->dc_interrupt_mask &= ~DC_SOF_RECEIVED; + } +} + +/* Standby(deep doze) mode enable/disable */ +static void it82xx2_enable_standby_state(bool enable) +{ + if (enable) { + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } else { + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } +} + /* WU90 (USB D+) Enable/Disable */ static void it82xx2_enable_wu90_irq(const struct device *dev, bool enable) { const struct usb_it82xx2_config *cfg = dev->config; + /* Clear pending interrupt */ + it8xxx2_wuc_clear_status(cfg->wuc_list[0].wucs, cfg->wuc_list[0].mask); + if (enable) { irq_enable(IT8XXX2_WU90_IRQ); } else { irq_disable(IT8XXX2_WU90_IRQ); - /* Clear pending interrupt */ - it8xxx2_wuc_clear_status(cfg->wuc_list[0].wucs, - cfg->wuc_list[0].mask); } } static void it82xx2_wu90_isr(const struct device *dev) { it82xx2_enable_wu90_irq(dev, false); + it82xx2_enable_standby_state(false); LOG_DBG("USB D+ (WU90) Triggered"); } @@ -276,8 +303,6 @@ static void it8xxx2_usb_dc_wuc_init(const struct device *dev) /* Connect WU90 (USB D+) interrupt but make it disabled initally */ IRQ_CONNECT(IT8XXX2_WU90_IRQ, 0, it82xx2_wu90_isr, 0, 0); - irq_disable(IT8XXX2_WU90_IRQ); - } /* Function it82xx2_get_ep_fifo_ctrl_reg_idx(uint8_t ep_idx): @@ -460,16 +485,12 @@ static int it82xx2_usb_dc_ip_init(uint8_t p_action) usb_regs->host_device_control = 0; } - usb_regs->dc_control = - DC_GLOBAL_ENABLE | DC_FULL_SPEED_LINE_POLARITY | - DC_FULL_SPEED_LINE_RATE | DC_CONNECT_TO_HOST; - usb_regs->dc_interrupt_status = DC_TRANS_DONE | DC_RESET_EVENT | DC_SOF_RECEIVED; usb_regs->dc_interrupt_mask = 0x00; usb_regs->dc_interrupt_mask = - DC_TRANS_DONE | DC_RESET_EVENT; + DC_TRANS_DONE | DC_RESET_EVENT | DC_SOF_RECEIVED; usb_regs->dc_address = DC_ADDR_NULL; @@ -486,9 +507,6 @@ 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; - /* Disabling WU90 (USB D+) of WUI */ - irq_disable(IT8XXX2_WU90_IRQ); - return it82xx2_usb_dc_ip_init(0); } @@ -786,16 +804,10 @@ static void it82xx2_usb_dc_isr(void) usb_regs->dc_interrupt_status = DC_RESET_EVENT; } } - /* resume,not test */ - if (status & DC_RESUME_INT) { - udata0.suspended = false; - usb_regs->dc_interrupt_mask &= ~DC_RESUME_INT; - usb_regs->dc_interrupt_status = DC_RESUME_INT; - if (udata0.usb_status_cb) { - (*(udata0.usb_status_cb))(USB_DC_RESUME, NULL); - } - - return; + /* sof received */ + if (status & DC_SOF_RECEIVED) { + it82xx2_enable_sof_int(false); + k_work_reschedule(&udata0.check_suspended_work, K_MSEC(5)); } /* transaction done */ if (status & DC_TRANS_DONE) { @@ -807,14 +819,49 @@ static void it82xx2_usb_dc_isr(void) } +static void suspended_check_handler(struct k_work *item) +{ + struct usb_it82xx2_data *udata = + CONTAINER_OF(item, struct usb_it82xx2_data, check_suspended_work); + + struct usb_it82xx2_regs *const usb_regs = + (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + + if (usb_regs->dc_interrupt_status & DC_SOF_RECEIVED) { + usb_regs->dc_interrupt_status = DC_SOF_RECEIVED; + if (udata->suspended) { + if (udata->usb_status_cb) { + (*(udata->usb_status_cb))(USB_DC_RESUME, NULL); + } + udata->suspended = false; + k_sem_give(&udata->suspended_sem); + } + k_work_reschedule(&udata->check_suspended_work, K_MSEC(5)); + return; + } + + it82xx2_enable_sof_int(true); + + if (!udata->suspended) { + if (udata->usb_status_cb) { + (*(udata->usb_status_cb))(USB_DC_SUSPEND, NULL); + } + udata->suspended = true; + it82xx2_enable_wu90_irq(udata->dev, true); + it82xx2_enable_standby_state(true); + + k_sem_reset(&udata->suspended_sem); + } +} + /* * USB Device Controller API */ int usb_dc_attach(void) { int ret; - - pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + struct usb_it82xx2_regs *const usb_regs = + (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); if (udata0.attached) { LOG_DBG("Already Attached"); @@ -842,9 +889,19 @@ int usb_dc_attach(void) 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.suspended_sem, 0, 1); + + k_work_init_delayable(&udata0.check_suspended_work, suspended_check_handler); - /* Connect and enable USB interrupt */ + /* Connect USB interrupt */ IRQ_CONNECT(IT8XXX2_USB_IRQ, 0, it82xx2_usb_dc_isr, 0, 0); + + usb_regs->dc_control = + DC_GLOBAL_ENABLE | DC_FULL_SPEED_LINE_POLARITY | + DC_FULL_SPEED_LINE_RATE | DC_CONNECT_TO_HOST; + + /* Enable USB D+ and USB interrupts */ + it82xx2_enable_wu90_irq(udata0.dev, true); irq_enable(IT8XXX2_USB_IRQ); return 0; @@ -855,8 +912,6 @@ int usb_dc_detach(void) struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); - if (!udata0.attached) { LOG_DBG("Already Detached"); return 0; @@ -869,9 +924,6 @@ int usb_dc_detach(void) usb_regs->dc_control &= ~DC_CONNECT_TO_HOST; udata0.attached = 0U; - /* Enabling WU90 (USB D+) of WUI */ - irq_enable(IT8XXX2_WU90_IRQ); - return 0; } @@ -1591,39 +1643,13 @@ int usb_dc_ep_mps(const uint8_t ep) return udata0.ep_data[ep_idx].mps; } -static bool it82xx2_check_suspend(void) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - - if (usb_regs->dc_interrupt_status & DC_SOF_RECEIVED) { - usb_regs->dc_interrupt_status = - usb_regs->dc_interrupt_status; - } - /* Check suspend, no SOF in last 3ms */ - k_msleep(4); - - if (usb_regs->dc_interrupt_status & DC_SOF_RECEIVED) { - return false; - } - - usb_regs->dc_interrupt_status = DC_SOF_RECEIVED | DC_RESUME_INT; - usb_regs->dc_interrupt_mask |= DC_RESUME_INT; - udata0.suspended = true; - - if (udata0.usb_status_cb) { - (*(udata0.usb_status_cb))(USB_DC_SUSPEND, NULL); - } - - return true; -} - int usb_dc_wakeup_request(void) { + int ret; struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - if (udata0.suspended || it82xx2_check_suspend()) { + if (udata0.suspended) { usb_regs->dc_control = DC_GLOBAL_ENABLE | DC_FULL_SPEED_LINE_POLARITY | @@ -1638,9 +1664,9 @@ int usb_dc_wakeup_request(void) DC_GLOBAL_ENABLE | DC_FULL_SPEED_LINE_POLARITY | DC_FULL_SPEED_LINE_RATE | DC_CONNECT_TO_HOST; - if (udata0.suspended) { - udata0.suspended = false; - irq_disable(IT8XXX2_WU90_IRQ); + ret = k_sem_take(&udata0.suspended_sem, K_MSEC(500)); + if (ret < 0) { + LOG_ERR("failed to wake up host"); } } return 0; @@ -1660,6 +1686,8 @@ static int it82xx2_usb_dc_init(const struct device *dev) /* Initializing WU90 (USB D+) */ it8xxx2_usb_dc_wuc_init(dev); + udata0.dev = dev; + return 0; } From 7ea8e2f507744d329bebd9e486dcd0cbf0c84c30 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 2 Jul 2023 16:14:18 -0400 Subject: [PATCH 0981/2042] shields: Add arduino uno click shield The shield converts Arduino UNO R3 headers to two mikroBUS sockets. Two mickoBUS sockets are exposed via the overlay labelled mikrobus_header_1 and mikrobus_header_2. mikrobus_header_1 is used as the default and assigned the node label mikrobus_header. Signed-off-by: Andriy Gelman --- .../shields/arduino_uno_click/Kconfig.shield | 5 ++ .../arduino_uno_click.overlay | 59 +++++++++++++++++++ .../shields/arduino_uno_click/doc/index.rst | 58 ++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 boards/shields/arduino_uno_click/Kconfig.shield create mode 100644 boards/shields/arduino_uno_click/arduino_uno_click.overlay create mode 100644 boards/shields/arduino_uno_click/doc/index.rst diff --git a/boards/shields/arduino_uno_click/Kconfig.shield b/boards/shields/arduino_uno_click/Kconfig.shield new file mode 100644 index 000000000000..ea8fc8d74675 --- /dev/null +++ b/boards/shields/arduino_uno_click/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +config ARDUINO_UNO_CLICK + def_bool $(shields_list_contains,arduino_uno_click) diff --git a/boards/shields/arduino_uno_click/arduino_uno_click.overlay b/boards/shields/arduino_uno_click/arduino_uno_click.overlay new file mode 100644 index 000000000000..206430e0875f --- /dev/null +++ b/boards/shields/arduino_uno_click/arduino_uno_click.overlay @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + mikrobus_header_1: mikrobus-connector-1 { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &arduino_header 0 0>, /* AN -> A0 */ + <1 0 &arduino_header 3 0>, /* RST -> A3 */ + <2 0 &arduino_header 16 0>, /* CS -> D10 */ + <3 0 &arduino_header 19 0>, /* SCK -> D13 */ + <4 0 &arduino_header 18 0>, /* MISO -> D12 */ + <5 0 &arduino_header 17 0>, /* MOSI -> D11 */ + /* +3.3V */ + /* GND */ + <6 0 &arduino_header 12 0>, /* PWM -> D6 */ + <7 0 &arduino_header 8 0>, /* INT -> D2 */ + <8 0 &arduino_header 6 0>, /* RX -> D0 */ + <9 0 &arduino_header 7 0>, /* TX -> D1 */ + <10 0 &arduino_header 5 0>, /* SCL -> A5 */ + <11 0 &arduino_header 4 0>; /* SDA -> A4 */ + /* +5V */ + /* GND */ + }; + + mikrobus_header_2: mikrobus-connector-2 { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &arduino_header 1 0>, /* AN -> A1 */ + <1 0 &arduino_header 2 0>, /* RST -> A2 */ + <2 0 &arduino_header 15 0>, /* CS -> D9 */ + <3 0 &arduino_header 19 0>, /* SCK -> D13 */ + <4 0 &arduino_header 18 0>, /* MISO -> D12 */ + <5 0 &arduino_header 17 0>, /* MOSI -> D11 */ + /* +3.3V */ + /* GND */ + <6 0 &arduino_header 11 0>, /* PWM -> D5 */ + <7 0 &arduino_header 9 0>, /* INT -> D3 */ + <8 0 &arduino_header 6 0>, /* RX -> D0 */ + <9 0 &arduino_header 7 0>, /* TX -> D1 */ + <10 0 &arduino_header 5 0>, /* SCL -> A5 */ + <11 0 &arduino_header 4 0>; /* SDA -> A4 */ + /* +5V */ + /* GND */ + }; +}; + +mikrobus_spi: &arduino_spi {}; +mikrobus_serial: &arduino_serial {}; +mikrobus_i2c: &arduino_i2c {}; + +mikrobus_header: &mikrobus_header_1 {}; diff --git a/boards/shields/arduino_uno_click/doc/index.rst b/boards/shields/arduino_uno_click/doc/index.rst new file mode 100644 index 000000000000..c13c3cb8d8c3 --- /dev/null +++ b/boards/shields/arduino_uno_click/doc/index.rst @@ -0,0 +1,58 @@ +.. _arduino_uno_click: + +Arduino UNO click shield +######################## + +Overview +******** + +The Arduino UNO click is an extension to the Arduino UNO R3 headers. +It's a simple shield that converts Arduino UNO R3 headers to two mikroBUS +host sockets that allow you to connect many other click shields to your +board. +In other words, the Arduino UNO click will generally be used by other +shields using the mikroBUS interface. + +Two mikroBUS headers are exposed by the overlay: ``mikrobus_header_1`` and +``mikrobus_header_2``, each corresponding to a socket on the Arduino UNO +click shield. + +The first socket (``mikrobus_header_1``) is the default socket which is +assigned the node label ``mikrobus_header`` in the overlay. + +More information about the shield can be found at +`Arduino UNO click shield website`_. + +Requirements +************ + +This shield can only be used with a board which provides a configuration +for Arduino R3 connector. + +The board must also define node aliases for arduino Serial, +SPI and I2C interfaces (see :ref:`shields` for more details). + +Connecting shields should use the first socket (``mikrobus_header_1``). This +socket is assigned the ``mikrobus_header`` node label. + +Programming +*********** + +Include ``-DSHIELD=arduino_uno_click`` when you invoke ``west build`` with +other mikroBUS shields. For example: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_server + :host-os: unix + :board: sam_v71_xult + :gen-args: -DOVERLAY_CONFIG=overlay-802154.conf + :shield: "arduino_uno_click atmel_rf2xx_mikrobus" + :goals: build + +References +********** + +.. target-notes:: + +.. _Arduino UNO click shield website: + https://www.mikroe.com/arduino-uno-click-shield From 2bf61ee8d6fbb43f89b2dbeb65d8fba4352a6f0f Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Sun, 2 Jul 2023 18:41:36 +0200 Subject: [PATCH 0982/2042] Bluetooth: Mesh: Restructure Kconfig options Current structure of Bluetooth Mesh Kconfig options is quite messy. This makes impossible to understand which configuration belongs to which feature. Especially when using interactive Kconfig interface, like menuconfig or guiconfig. This commit restructures the options grouping them by protocol layer they belong to (Network, Transport, Access, etc.), or specific feature (LPN, Friend, Proxy, Relay, etc.), or implementation (Advertiser, Shell, Persistent storage). Amount of supported keys, subnets, group addresses and labels are grouped under Capabilities menu. Generic options that don't fall to any category are kept at the root menu. For better visibility, if a specific feature or layer has more than 1 option, they are hidden under menu. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/Kconfig | 1237 +++++++++++++++++---------------- subsys/bluetooth/mesh/net.c | 7 - 2 files changed, 652 insertions(+), 592 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 70f1ce7c93ad..d91f2495aae5 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -13,163 +13,11 @@ menuconfig BT_MESH if BT_MESH -choice BT_MESH_CRYPTO_LIB - prompt "Crypto library selection for mesh security" - default BT_MESH_USES_TFM_PSA if BUILD_WITH_TFM - default BT_MESH_USES_TINYCRYPT - -config BT_MESH_USES_TINYCRYPT - bool "Use TinyCrypt" - select TINYCRYPT - select TINYCRYPT_AES - select TINYCRYPT_AES_CMAC - select TINYCRYPT_ECC_DH - select TINYCRYPT_SHA256 - select TINYCRYPT_SHA256_HMAC - select BT_HOST_CCM - help - Use TinyCrypt library to perform crypto operations. - -config BT_MESH_USES_MBEDTLS_PSA - bool "Use mbed TLS PSA [EXPERIMENTAL]" - select EXPERIMENTAL - select MBEDTLS - select MBEDTLS_ZEPHYR_ENTROPY - select MBEDTLS_PSA_CRYPTO_C - select MBEDTLS_MAC_CMAC_ENABLED - select MBEDTLS_CIPHER_AES_ENABLED - select MBEDTLS_AES_ROM_TABLES - select MBEDTLS_CIPHER_CCM_ENABLED - select MBEDTLS_ECP_C - select MBEDTLS_ECDH_C - select MBEDTLS_ECDSA_C - select MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED - select MBEDTLS_ECP_DP_SECP256R1_ENABLED - select MBEDTLS_PK_WRITE_C - help - Use mbed TLS library to perform crypto operations. Support of - mbed TLS and PSA is experimental and only BabbleSim tests were run. - Mbed TLS still does not support ITS (internal trust storage) based - on Zephyr's settings subsystem. - Not possible to use for embedded devices yet. - -config BT_MESH_USES_TFM_PSA - bool "Use TF-M PSA [EXPERIMENTAL]" - select EXPERIMENTAL - depends on BUILD_WITH_TFM - help - Use TF-M that implements PSA security framework. Support of TF-M is - experimental. It is only possible to use with platforms that TF-M supports. - For more platform details see TF-M documentation. - -endchoice - -if BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA - -config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET - int "Offset of BLE Mesh key id range regarding PSA_KEY_ID_USER_MIN" - default 0 - help - The PSA specification mandates to set key identifiers for keys - with persistent lifetime. The users of the PSA API is responsible - (BLE Mesh is user of PSA API) to provide correct and unique identifiers. - The BLE Mesh identifier range should be between PSA_KEY_ID_USER_MIN and - PSA_KEY_ID_USER_MAX. BLE Mesh requires two ids for each subnetwork, two ids - for each application key, and two ids for the device key and device key candidate. - It should consider the Mesh Configuration Database instances if database enabled. - -endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA - -# Virtual option enabled whenever Generic Provisioning layer is needed -config BT_MESH_PROV - bool - -config BT_MESH_PROV_DEVICE - bool "Provisioning device role support" - depends on BT_MESH_PROV - default y - help - Enable this option to allow the device to be provisioned into a mesh network. - -config BT_MESH_PROV_OOB_PUBLIC_KEY - bool "OOB Public key support" - depends on BT_MESH_PROV_DEVICE - help - Enable this option if public key is to be exchanged via Out of Band (OOB) technology. - -config BT_MESH_PB_ADV - bool "Provisioning support using the advertising bearer (PB-ADV)" - select BT_MESH_PROV - default y - help - Enable this option to allow the device to be provisioned over - the advertising bearer. - -config BT_MESH_UNPROV_BEACON_INT - int - prompt "The interval (in seconds) to send the unprovisioned beacon" if BT_MESH_PB_ADV - default 5 - range 1 10 - help - This option specifies the interval (in seconds) at which the - device sends unprovisioned beacon. - -config BT_MESH_PB_ADV_RETRANS_TIMEOUT - int "Timeout value of retransmit provisioning PDUs" - default 500 - range 100 800 - help - Timeout value of retransmit provisioning PDUs. - -config BT_MESH_PROVISIONER - bool "Provisioner support" - depends on BT_MESH_CDB - depends on BT_MESH_PROV - depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT_CLIENT - help - Enable this option to have support for provisioning remote devices. - -config BT_MESH_CDB - bool "Mesh Configuration Database" +################################################################################################### +# Invisible options +################################################################################################### -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. - -if BT_MESH_CDB - -config BT_MESH_CDB_NODE_COUNT - int "Maximum number of nodes in the database" - default 8 - range 1 4096 - help - This option specifies how many nodes each network can at most - save in the configuration database. - -config BT_MESH_CDB_SUBNET_COUNT - int "Maximum number of subnets in the database" - default 1 - range 1 4096 - help - This option specifies how many subnets that can at most be - saved in the configuration database. - -config BT_MESH_CDB_APP_KEY_COUNT - int "Maximum number of application keys in the database" - default 1 - range 1 4096 - help - This option specifies how many application keys that can at most - be saved in the configuration database. - -endif # BT_MESH_CDB - -if BT_CONN - -# Virtual option enabled whenever any Proxy protocol is needed +# Virtual option enabled whenever Proxy Server or Client is needed config BT_MESH_PROXY bool @@ -194,261 +42,22 @@ config BT_MESH_GATT_SERVER config BT_MESH_PB_GATT_COMMON bool -config BT_MESH_PB_GATT_CLIENT - bool "Provisioner support using GATT (PB-GATT)" - select BT_MESH_PROV - select BT_GATT_CLIENT - select BT_MESH_GATT_CLIENT - select BT_MESH_PB_GATT_COMMON - select BT_MESH_PROVISIONER - depends on BT_CENTRAL - help - Enable this option to allow the provisioner provisioning the - device over GATT. - -config BT_MESH_PB_GATT - bool "Provisioning support using GATT (PB-GATT)" - select BT_MESH_GATT_SERVER - select BT_MESH_PROV - select BT_MESH_PB_GATT_COMMON - help - Enable this option to allow the device to be provisioned over - GATT. - -config BT_MESH_PB_GATT_USE_DEVICE_NAME - bool "Include Bluetooth device name in scan response" - depends on BT_MESH_PB_GATT - default y - help - This option includes GAP device name in scan response when - the PB-GATT is enabled. - -config BT_MESH_PROXY_CLIENT - bool "Proxy client support" - select BT_GATT_CLIENT - select BT_MESH_GATT_CLIENT - depends on BT_CENTRAL - help - This option enables support for the Mesh GATT Proxy Client, - i.e. the ability to act as a proxy between a Mesh GATT Service - and a Mesh network. - -config BT_MESH_GATT_PROXY - bool "GATT Proxy Service support" - select BT_MESH_GATT_SERVER - select BT_MESH_PROXY - help - This option enables support for the Mesh GATT Proxy Service, - i.e. the ability to act as a proxy between a Mesh GATT Client - and a Mesh network. - -config BT_MESH_GATT_PROXY_ENABLED - bool "GATT Proxy enabled" - depends on BT_MESH_GATT_PROXY - default y - help - Controls whether the GATT Proxy feature is enabled by default. - Can be changed through runtime configuration. - -config BT_MESH_NODE_ID_TIMEOUT - int "Node Identity advertising timeout" - depends on BT_MESH_GATT_PROXY - range 1 60 - default 60 - help - This option determines for how long the local node advertises - using Node Identity. The given value is in seconds. The - specification limits this to 60 seconds, and implies that to - be the appropriate value as well, so just leaving this as the - default is the safest option. - -config BT_MESH_PROXY_USE_DEVICE_NAME - bool "Include Bluetooth device name in scan response" - depends on BT_MESH_GATT_PROXY - help - This option includes GAP device name in scan response when - the GATT Proxy feature is enabled. - -config BT_MESH_PROXY_FILTER_SIZE - int "Maximum number of filter entries per Proxy Client" - default 16 - range 1 32767 - depends on BT_MESH_GATT_PROXY - help - This option specifies how many Proxy Filter entries the local - node supports. This helps in reducing unwanted traffic getting sent to - the proxy client. This value is application specific and should be large - enough so that proxy client can communicate with several devices through - this proxy server node using the default accept list filter type. - -config BT_MESH_MAX_CONN - int "Maximum number of simultaneous connections used by the stack" - default BT_MAX_CONN - range 1 BT_MAX_CONN - help - Maximum number of simultaneous Bluetooth connections that the Bluetooth - mesh stack can use. - -endif # BT_CONN - -config BT_MESH_ACCESS_LAYER_MSG - bool "Direct Bluetooth message access layer messages" - help - This option allows the application to directly access - Bluetooth access layer messages without the need to - instantiate Bluetooth mesh models. - -config BT_MESH_SELF_TEST - bool "Perform self-tests" - help - This option adds extra self-tests which are run every time - mesh networking is initialized. - -config BT_MESH_IV_UPDATE_TEST - bool "Test the IV Update Procedure" - help - This option removes the 96 hour limit of the IV Update - Procedure and lets the state be changed at any time. - -config BT_MESH_SUBNET_COUNT - int "Maximum number of mesh subnets per network" - default 1 - range 1 4096 - help - This option specifies how many subnets a Mesh network can - participate in at the same time. - -config BT_MESH_APP_KEY_COUNT - int "Maximum number of application keys per network" - default 1 - range 1 4096 - help - This option specifies how many application keys the device can - store per network. - -config BT_MESH_MODEL_KEY_COUNT - int "Maximum number of application keys per model" - default 1 - range 1 4096 - help - This option specifies how many application keys each model can - at most be bound to. - -config BT_MESH_MODEL_GROUP_COUNT - int "Maximum number of group address subscriptions per model" - default 1 - range 1 4096 - help - This option specifies how many group addresses each model can - at most be subscribed to. - -config BT_MESH_MODEL_VND_MSG_CID_FORCE - bool "Force vendor model to use the corresponding CID field message" - default y - help - This option forces vendor model to use messages for the - corresponding CID field. - -config BT_MESH_LABEL_COUNT - int "Maximum number of Label UUIDs used for Virtual Addresses" - default 1 - range 0 4096 - help - This option specifies how many Label UUIDs can be stored. - -config BT_MESH_LABEL_NO_RECOVER - bool "[DEPRECATED] Don't recover Label UUIDs from groups address subscription list" - select DEPRECATED - depends on BT_MESH_LABEL_COUNT > 0 - help - After adding support for virtual addresses with collision (where two Label UUIDs have the - same virtual address), the format of the data in the persistent storage with the Label - UUIDs which a model is subscribed to or publishes to has been changed. The recovery - code is added and the Label UUIDs will be recovered by picking first Label UUID matching - to the virtual address in the subscription list or model publication. This options can - disable the recovery code and save some flash if the recovery is not required (e.g. - virtual address support wasn't enabled before this option was added, or the devices were - unprovisioned before upgrading to the version with this option). The option is marked as - deprecated to remove the recovery code eventually. - -config BT_MESH_CRPL - int "Maximum capacity of the replay protection list" - default 10 - range 2 65535 - help - This options specifies the maximum capacity of the replay - protection list. This option is similar to the network message - cache size, but has a different purpose. - -choice BT_MESH_RPL_STORAGE_MODE - prompt "Replay protection list storage mode" - default BT_MESH_RPL_STORAGE_MODE_SETTINGS - -config BT_MESH_RPL_STORAGE_MODE_SETTINGS - bool "Persistent storage of RPL in Settings" - help - Persistent storage of RPL in Settings. If BT_SETTINGS is not - enabled this choise will provide a non-persistent implementation - variant of the RPL list. - -endchoice - -if BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS - -config BT_MESH_RPL_STORE_TIMEOUT - int "Minimum interval after which unsaved RPL and SRPL entries are updated in the settings subsystem" - range -1 1000000 - default 5 - help - This value defines time in seconds until unsaved RPL and SRPL entries - are written to the persistent storage. Setting this value - to a large number may lead to security vulnerabilities if a node - gets powered off before the timer is fired. When flash is used - as the persistent storage setting this value to a low number - may wear out flash sooner or later. However, if the RPL gets - updated infrequently a value as low as 0 (write immediately) - may make sense. Setting this value to -1 will disable this timer. - In this case, a user is responsible to store pending RPL entries - using @ref bt_mesh_rpl_pending_store. In the mean time, when - IV Index is updated, the outdated RPL entries will still be - stored by @ref BT_MESH_STORE_TIMEOUT. Finding the right balance - between this timeout and calling @ref bt_mesh_rpl_pending_store - may reduce a risk of security vulnerability and flash wear out. - Failure to store the RPL and becoming vulnerable after reboot - will cause the device to not perform the replay protection - required by the spec. - -endif # BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS +# Virtual option enabled whenever Generic Provisioning layer is needed +config BT_MESH_PROV + bool -config BT_MESH_MSG_CACHE_SIZE - int "Network message cache size" - default 32 - range 2 65535 - help - Number of messages that are cached by the node to avoid acting on the - recently seen duplicate messages. This option is similar to - the replay protection list, but has a different purpose. Network message - cache helps prevent unnecessary decryption operations. This also prevents - unnecessary relaying and helps in getting rid of relay loops. Setting - this value to a very low number can cause unnecessary network traffic. - Setting this value to a very large number can impact the processing time - for each received network PDU and increases RAM footprint proportionately. +################################################################################################### +# Visible options +################################################################################################### -config BT_MESH_ADV_BUF_COUNT - int "Number of advertising buffers for local messages" - default 6 - range 1 256 - help - Number of advertising buffers available for sending local messages. - This should be chosen based on the number of local messages that the node - can send simultaneously. +menu "Advertiser" choice BT_MESH_ADV prompt "Advertiser mode" default BT_MESH_ADV_EXT if BT_EXT_ADV default BT_MESH_ADV_LEGACY -config BT_MESH_ADV_LEGACY +menuconfig BT_MESH_ADV_LEGACY bool "Legacy advertising" help Use legacy advertising commands for mesh sending. Legacy @@ -459,7 +68,31 @@ config BT_MESH_ADV_LEGACY retransmissions than requested because of limitations of HCI interface API. -config BT_MESH_ADV_EXT +if BT_MESH_ADV_LEGACY + +config BT_MESH_ADV_STACK_SIZE + int "Mesh advertiser thread stack size" + default 1024 if BT_HOST_CRYPTO + default 776 if BT_MESH_PRIV_BEACONS + default 768 + help + Size of bt mesh adv thread stack. + + NOTE: This is an advanced setting and should not be changed unless + absolutely necessary + +config BT_MESH_ADV_PRIO + int "Mesh advertiser thread priority" + default 7 + help + Priority of bt mesh adv thread. + + NOTE: This is an advanced setting and should not be changed unless + absolutely necessary + +endif # BT_MESH_ADV_LEGACY + +menuconfig BT_MESH_ADV_EXT bool "Extended advertising" depends on BT_CTLR_ADV_EXT || !BT_CTLR depends on BT_EXT_ADV @@ -468,8 +101,6 @@ config BT_MESH_ADV_EXT Extended advertising is faster and uses less memory than legacy advertising, but isn't supported by all controllers. -endchoice - if BT_MESH_ADV_EXT config BT_MESH_RELAY_ADV_SETS @@ -519,60 +150,241 @@ config BT_MESH_ADV_EXT_FRIEND_SEPARATE endif # BT_MESH_ADV_EXT -config BT_MESH_ADV_STACK_SIZE - int "Mesh advertiser thread stack size" - depends on BT_MESH_ADV_LEGACY - default 1024 if BT_HOST_CRYPTO - default 776 if BT_MESH_PRIV_BEACONS - default 768 +endchoice + +config BT_MESH_ADV_BUF_COUNT + int "Number of advertising buffers for local messages" + default 6 + range 1 256 help - Size of bt mesh adv thread stack. + Number of advertising buffers available for sending local messages. + This should be chosen based on the number of local messages that the node + can send simultaneously. - NOTE: This is an advanced setting and should not be changed unless - absolutely necessary +config BT_MESH_DEBUG_USE_ID_ADDR + bool "Use identity address for all advertising" + help + This option forces the usage of the local identity address for + all advertising. This can be a help for debugging (analyzing + traces), however it should never be enabled for a production + build as it compromises the privacy of the device. -config BT_MESH_ADV_PRIO - int "Mesh advertiser thread priority" - depends on BT_MESH_ADV_LEGACY - default 7 +endmenu # Advertiser + +menu "Provisioning" + +menuconfig BT_MESH_PB_ADV + bool "PB-ADV support" + select BT_MESH_PROV + default y help - Priority of bt mesh adv thread. + Enable this option to allow the device to be provisioned over + the advertising bearer. - NOTE: This is an advanced setting and should not be changed unless - absolutely necessary +config BT_MESH_UNPROV_BEACON_INT + int + prompt "The interval (in seconds) to send the unprovisioned beacon" if BT_MESH_PB_ADV + default 5 + range 1 10 + help + This option specifies the interval (in seconds) at which the + device sends unprovisioned beacon. -config BT_MESH_IV_UPDATE_SEQ_LIMIT - hex "Sequence number limit to start iv update" - default 0x800000 - range 0x000001 0xFFFFFE +if BT_MESH_PB_ADV + +config BT_MESH_PB_ADV_RETRANS_TIMEOUT + int "Timeout value of retransmit provisioning PDUs" + default 500 + range 100 800 + help + Timeout value of retransmit provisioning PDUs. + +endif # BT_MESH_PB_ADV + +if BT_CONN + +config BT_MESH_PB_GATT + bool "PB-GATT Server support" + select BT_MESH_GATT_SERVER + select BT_MESH_PROV + select BT_MESH_PB_GATT_COMMON + select BT_MESH_PROV_DEVICE + help + Enable this option to allow the device to be provisioned over + GATT. + +config BT_MESH_PB_GATT_USE_DEVICE_NAME + bool "Include Bluetooth device name in scan response" + depends on BT_MESH_PB_GATT + default y + help + This option includes GAP device name in scan response when + the PB-GATT is enabled. + +config BT_MESH_PB_GATT_CLIENT + bool "PB-GATT Client support" + select BT_MESH_PROV + select BT_GATT_CLIENT + select BT_MESH_GATT_CLIENT + select BT_MESH_PB_GATT_COMMON + select BT_MESH_PROVISIONER + depends on BT_CENTRAL + help + Enable this option to allow the provisioner provisioning the + device over GATT. + +endif # BT_CONN + +config BT_MESH_PROV_DEVICE + bool "Provisioning device role support" + depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT + default y + help + Enable this option to allow the device to be provisioned into a mesh network. + +config BT_MESH_PROV_OOB_PUBLIC_KEY + bool "OOB Public key support" + depends on BT_MESH_PROV_DEVICE + help + Enable this option if public key is to be exchanged via Out of Band (OOB) technology. + +config BT_MESH_PROVISIONER + bool "Provisioner support" + depends on BT_MESH_CDB + depends on BT_MESH_PROV + depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT_CLIENT + help + Enable this option to have support for provisioning remote devices. + +menuconfig BT_MESH_CDB + bool "Mesh Configuration Database" + +if BT_MESH_CDB + +config BT_MESH_CDB_NODE_COUNT + int "Maximum number of nodes in the database" + default 8 + range 1 4096 + help + This option specifies how many nodes each network can at most + save in the configuration database. + +config BT_MESH_CDB_SUBNET_COUNT + int "Maximum number of subnets in the database" + default 1 + range 1 4096 + help + This option specifies how many subnets that can at most be + saved in the configuration database. + +config BT_MESH_CDB_APP_KEY_COUNT + int "Maximum number of application keys in the database" + default 1 + range 1 4096 + help + This option specifies how many application keys that can at most + be saved in the configuration database. + +endif # BT_MESH_CDB + +endmenu # Provisioning + +menu "Network layer" + +config BT_MESH_LOOPBACK_BUFS + int "Number of loopback buffers" + default 3 + help + The number of buffers allocated for the network loopback mechanism. + Loopback is used when the device sends messages to itself. + +config BT_MESH_NETWORK_TRANSMIT_COUNT + int "Network Transmit Count" + default 2 + range 0 7 + help + Controls the initial number of retransmissions of original messages, + in addition to the first transmission. Can be changed through runtime + configuration. + +config BT_MESH_NETWORK_TRANSMIT_INTERVAL + int "Network Transmit Interval" + default 20 + range 10 330 + help + Controls the initial interval between retransmissions of original + messages, in milliseconds. Can be changed through runtime + configuration. + +config BT_MESH_MSG_CACHE_SIZE + int "Network message cache size" + default 32 + range 2 65535 + help + Number of messages that are cached by the node to avoid acting on the + recently seen duplicate messages. This option is similar to + the replay protection list, but has a different purpose. Network message + cache helps prevent unnecessary decryption operations. This also prevents + unnecessary relaying and helps in getting rid of relay loops. Setting + this value to a very low number can cause unnecessary network traffic. + Setting this value to a very large number can impact the processing time + for each received network PDU and increases RAM footprint proportionately. + +menuconfig BT_MESH_RELAY + bool "Relay support" + help + Support for acting as a Mesh Relay Node. + +if BT_MESH_RELAY + +config BT_MESH_RELAY_ENABLED + bool "Relay feature enabled by default" + default y + help + Controls whether the Relay feature is enabled by default when the + device boots up for the first time or unprovisioned. Can be changed + at runtime using bt_mesh_relay_set() function. + +config BT_MESH_RELAY_RETRANSMIT_COUNT + int "Relay Retransmit Count" + default 2 + range 0 7 + help + Controls the initial number of retransmissions of relayed messages, in + addition to the first transmission. Can be changed through runtime + configuration. + +config BT_MESH_RELAY_RETRANSMIT_INTERVAL + int "Relay Retransmit Interval" + default 20 + range 10 330 + help + Controls the initial interval between retransmissions of relayed + messages, in milliseconds. Can be changed through runtime + configuration. + +config BT_MESH_RELAY_BUF_COUNT + int "Number of advertising buffers for relayed messages" + default 32 + range 1 256 help - This option specifies the sequence number value to start iv update. + Number of advertising buffers available for messages to be relayed. + High number of advertising buffers increases the reliability of the + mesh network. Low number of advertising buffers reduces the message + latency on the Relay Node, but at the same time increases the amount + of packet drops. When considering the message latency, also consider + the values of BT_MESH_RELAY_RETRANSMIT_COUNT and + BT_MESH_RELAY_RETRANSMIT_INTERVAL. A higher number of + BT_MESH_RELAY_ADV_SETS allows the increase in the number of buffers + while maintaining the latency. -config BT_MESH_IVU_DIVIDER - int "Divider for IV Update state refresh timer" - default 4 - range 2 96 - help - When the IV Update state enters Normal operation or IV Update - in Progress, we need to keep track of how many hours has passed - in the state, since the specification requires us to remain in - the state at least for 96 hours (Update in Progress has an - additional upper limit of 144 hours). +endif # BT_MESH_RELAY - In order to fulfill the above requirement, even if the node might - be powered off once in a while, we need to store persistently - how many hours the node has been in the state. This doesn't - necessarily need to happen every hour (thanks to the flexible - duration range). The exact cadence will depend a lot on the - ways that the node will be used and what kind of power source it - has. +endmenu # Network layer - Since there is no single optimal answer, this configuration - option allows specifying a divider, i.e. how many intervals - the 96 hour minimum gets split into. After each interval the - duration that the node has been in the current state gets - stored to flash. E.g. the default value of 4 means that the - state is saved every 24 hours (96 / 4). +menu "Transport layer" + +menu "Transport SAR configuration" config BT_MESH_TX_SEG_MSG_COUNT int "Maximum number of simultaneous outgoing segmented messages" @@ -659,6 +471,30 @@ 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 @@ -683,6 +519,10 @@ config BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT 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 int "Default TTL value" default 7 @@ -691,88 +531,295 @@ config BT_MESH_DEFAULT_TTL Controls the default TTL value for outgoing messages. Can be changed through runtime configuration. -config BT_MESH_LOOPBACK_BUFS - int "Number of loopback buffers" - default 3 +menu "Replay Protection List" + +config BT_MESH_CRPL + int "Maximum capacity of the replay protection list" + default 10 + range 2 65535 help - The number of buffers allocated for the network loopback mechanism. - Loopback is used when the device sends messages to itself. + This options specifies the maximum capacity of the replay + protection list. This option is similar to the network message + cache size, but has a different purpose. -config BT_MESH_NETWORK_TRANSMIT_COUNT - int "Network Transmit Count" - default 2 - range 0 7 +choice BT_MESH_RPL_STORAGE_MODE + prompt "Replay protection list storage mode" + default BT_MESH_RPL_STORAGE_MODE_SETTINGS + +config BT_MESH_RPL_STORAGE_MODE_SETTINGS + bool "Persistent storage of RPL in Settings" + help + Persistent storage of RPL in Settings. If BT_SETTINGS is not + enabled this choise will provide a non-persistent implementation + variant of the RPL list. + +endchoice + +endmenu # Replay Protection List + +endmenu # Transport layer + +menu "Access layer" + +config BT_MESH_ACCESS_LAYER_MSG + bool "Direct Bluetooth message access layer messages" + help + This option allows the application to directly access + Bluetooth access layer messages without the need to + instantiate Bluetooth mesh models. + +config BT_MESH_MODEL_VND_MSG_CID_FORCE + bool "Force vendor model to use the corresponding CID field message" + default y + help + This option forces vendor model to use messages for the + corresponding CID field. + +config BT_MESH_MODEL_EXTENSIONS + bool "Support for Model extensions" + help + Enable support for the model extension concept, allowing the Access + layer to know about mesh model relationships. + +config BT_MESH_LABEL_NO_RECOVER + bool "[DEPRECATED] Don't recover Label UUIDs from groups address subscription list" + select DEPRECATED + depends on BT_MESH_LABEL_COUNT > 0 + help + After adding support for virtual addresses with collision (where two Label UUIDs have the + same virtual address), the format of the data in the persistent storage with the Label + UUIDs which a model is subscribed to or publishes to has been changed. The recovery + code is added and the Label UUIDs will be recovered by picking first Label UUID matching + to the virtual address in the subscription list or model publication. This options can + disable the recovery code and save some flash if the recovery is not required (e.g. + virtual address support wasn't enabled before this option was added, or the devices were + unprovisioned before upgrading to the version with this option). The option is marked as + deprecated to remove the recovery code eventually. + +endmenu # Access layer + +menu "Models" + +config BT_MESH_CFG_CLI + bool "Support for Configuration Client Model" + help + Enable support for the configuration client model. + +if BT_MESH_CFG_CLI + +config BT_MESH_CFG_CLI_TIMEOUT + int "Config Client model timeout in milliseconds" + default 5000 + help + This timeout controls how long config client waits for a response + message to arrive. This value can be changed at runtime using + @ref bt_mesh_cfg_cli_timeout_set. + +endif # BT_MESH_CFG_CLI + +config BT_MESH_HEALTH_CLI + bool "Support for Health Client Model" + help + Enable support for the health client model. + +if BT_MESH_HEALTH_CLI + +config BT_MESH_HEALTH_CLI_TIMEOUT + int "Health Client model timeout in milliseconds" + default 2000 + help + This timeout controls how long health client waits for a response + message to arrive. This value can be changed at runtime using + @ref bt_mesh_health_cli_timeout_set. + +endif # BT_MESH_HEALTH_CLI + +endmenu # Models + +menu "Proxy" + visible if BT_CONN + +menuconfig BT_MESH_GATT_PROXY + bool "GATT Proxy Service support" + select BT_MESH_GATT_SERVER + select BT_MESH_PROXY + help + This option enables support for the Mesh GATT Proxy Service, + i.e. the ability to act as a proxy between a Mesh GATT Client + and a Mesh network. + +if BT_MESH_GATT_PROXY + +config BT_MESH_GATT_PROXY_ENABLED + bool "GATT Proxy enabled" + depends on BT_MESH_GATT_PROXY + default y + help + Controls whether the GATT Proxy feature is enabled by default. + Can be changed through runtime configuration. + +config BT_MESH_NODE_ID_TIMEOUT + int "Node Identity advertising timeout" + range 1 60 + default 60 + help + This option determines for how long the local node advertises + using Node Identity. The given value is in seconds. The + specification limits this to 60 seconds, and implies that to + be the appropriate value as well, so just leaving this as the + default is the safest option. + +config BT_MESH_PROXY_USE_DEVICE_NAME + bool "Include Bluetooth device name in scan response" + help + This option includes GAP device name in scan response when + the GATT Proxy feature is enabled. + +config BT_MESH_PROXY_FILTER_SIZE + int "Maximum number of filter entries per Proxy Client" + default 16 + range 1 32767 + help + This option specifies how many Proxy Filter entries the local + node supports. This helps in reducing unwanted traffic getting sent to + the proxy client. This value is application specific and should be large + enough so that proxy client can communicate with several devices through + this proxy server node using the default accept list filter type. + +endif # BT_MESH_GATT_PROXY + +config BT_MESH_PROXY_CLIENT + bool "Proxy client support" + select BT_GATT_CLIENT + select BT_MESH_GATT_CLIENT + depends on BT_CENTRAL + help + This option enables support for the Mesh GATT Proxy Client, + i.e. the ability to act as a proxy between a Mesh GATT Service + and a Mesh network. + +endmenu # Proxy + +choice BT_MESH_CRYPTO_LIB + prompt "Crypto library:" + default BT_MESH_USES_TFM_PSA if BUILD_WITH_TFM + default BT_MESH_USES_TINYCRYPT + help + Crypto library selection for mesh security. + +config BT_MESH_USES_TINYCRYPT + bool "TinyCrypt" + select TINYCRYPT + select TINYCRYPT_AES + select TINYCRYPT_AES_CMAC + select TINYCRYPT_ECC_DH + select TINYCRYPT_SHA256 + select TINYCRYPT_SHA256_HMAC + select BT_HOST_CCM + help + Use TinyCrypt library to perform crypto operations. + +config BT_MESH_USES_MBEDTLS_PSA + bool "mbed TLS PSA [EXPERIMENTAL]" + select EXPERIMENTAL + select MBEDTLS + select MBEDTLS_ZEPHYR_ENTROPY + select MBEDTLS_PSA_CRYPTO_C + select MBEDTLS_MAC_CMAC_ENABLED + select MBEDTLS_CIPHER_AES_ENABLED + select MBEDTLS_AES_ROM_TABLES + select MBEDTLS_CIPHER_CCM_ENABLED + select MBEDTLS_ECP_C + select MBEDTLS_ECDH_C + select MBEDTLS_ECDSA_C + select MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + select MBEDTLS_ECP_DP_SECP256R1_ENABLED + select MBEDTLS_PK_WRITE_C help - Controls the initial number of retransmissions of original messages, - in addition to the first transmission. Can be changed through runtime - configuration. + Use mbed TLS library to perform crypto operations. Support of + mbed TLS and PSA is experimental and only BabbleSim tests were run. + Mbed TLS still does not support ITS (internal trust storage) based + on Zephyr's settings subsystem. + Not possible to use for embedded devices yet. -config BT_MESH_NETWORK_TRANSMIT_INTERVAL - int "Network Transmit Interval" - default 20 - range 10 330 +config BT_MESH_USES_TFM_PSA + bool "Use TF-M PSA [EXPERIMENTAL]" + select EXPERIMENTAL + depends on BUILD_WITH_TFM help - Controls the initial interval between retransmissions of original - messages, in milliseconds. Can be changed through runtime - configuration. + Use TF-M that implements PSA security framework. Support of TF-M is + experimental. It is only possible to use with platforms that TF-M supports. + For more platform details see TF-M documentation. -menuconfig BT_MESH_RELAY - bool "Relay support" +endchoice + +if BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA + +config BT_MESH_PSA_KEY_ID_USER_MIN_OFFSET + int "Offset of BLE Mesh key id range regarding PSA_KEY_ID_USER_MIN" + default 0 help - Support for acting as a Mesh Relay Node. + The PSA specification mandates to set key identifiers for keys + with persistent lifetime. The users of the PSA API is responsible + (BLE Mesh is user of PSA API) to provide correct and unique identifiers. + The BLE Mesh identifier range should be between PSA_KEY_ID_USER_MIN and + PSA_KEY_ID_USER_MAX. BLE Mesh requires two ids for each subnetwork, two ids + for each application key, and two ids for the device key and device key candidate. + It should consider the Mesh Configuration Database instances if database enabled. -if BT_MESH_RELAY +endif # BT_MESH_USES_MBEDTLS_PSA || BT_MESH_USES_TFM_PSA -config BT_MESH_RELAY_ENABLED - bool "Relay enabled" +config BT_MESH_BEACON_ENABLED + bool "Secure network beacon enabled" default y help - Controls whether the Mesh Relay feature is enabled by default. Can be - changed through runtime configuration. + Controls whether the Secure network beacon feature is enabled by + default. Can be changed through runtime configuration. -config BT_MESH_RELAY_RETRANSMIT_COUNT - int "Relay Retransmit Count" - default 2 - range 0 7 +menu "IV Index & Sequence number" + +config BT_MESH_IV_UPDATE_TEST + bool "Test the IV Update Procedure" help - Controls the initial number of retransmissions of relayed messages, in - addition to the first transmission. Can be changed through runtime - configuration. + This option removes the 96 hour limit of the IV Update + Procedure and lets the state be changed at any time. -config BT_MESH_RELAY_RETRANSMIT_INTERVAL - int "Relay Retransmit Interval" - default 20 - range 10 330 +config BT_MESH_IV_UPDATE_SEQ_LIMIT + hex "Sequence number limit to start iv update" + default 0x800000 + range 0x000001 0xFFFFFE help - Controls the initial interval between retransmissions of relayed - messages, in milliseconds. Can be changed through runtime - configuration. + This option specifies the sequence number value to start iv update. -config BT_MESH_RELAY_BUF_COUNT - int "Number of advertising buffers for relayed messages" - default 32 - range 1 256 +config BT_MESH_IVU_DIVIDER + int "Divider for IV Update state refresh timer" + default 4 + range 2 96 help - Number of advertising buffers available for messages to be relayed. - High number of advertising buffers increases the reliability of the - mesh network. Low number of advertising buffers reduces the message - latency on the Relay Node, but at the same time increases the amount - of packet drops. When considering the message latency, also consider - the values of BT_MESH_RELAY_RETRANSMIT_COUNT and - BT_MESH_RELAY_RETRANSMIT_INTERVAL. A higher number of - BT_MESH_RELAY_ADV_SETS allows the increase in the number of buffers - while maintaining the latency. + When the IV Update state enters Normal operation or IV Update + in Progress, we need to keep track of how many hours has passed + in the state, since the specification requires us to remain in + the state at least for 96 hours (Update in Progress has an + additional upper limit of 144 hours). -endif + In order to fulfill the above requirement, even if the node might + be powered off once in a while, we need to store persistently + how many hours the node has been in the state. This doesn't + necessarily need to happen every hour (thanks to the flexible + duration range). The exact cadence will depend a lot on the + ways that the node will be used and what kind of power source it + has. -config BT_MESH_BEACON_ENABLED - bool "Secure network beacon enabled" - default y - help - Controls whether the Secure network beacon feature is enabled by - default. Can be changed through runtime configuration. + Since there is no single optimal answer, this configuration + option allows specifying a divider, i.e. how many intervals + the 96 hour minimum gets split into. After each interval the + duration that the node has been in the current state gets + stored to flash. E.g. the default value of 4 means that the + state is saved every 24 hours (96 / 4). -config BT_MESH_LOW_POWER +endmenu # IV Index & Sequence number + +menuconfig BT_MESH_LOW_POWER bool "Support for Low Power features" help Enable this option to be able to act as a Low Power Node. @@ -900,7 +947,7 @@ config BT_MESH_LPN_SUB_ALL_NODES_ADDR endif # BT_MESH_LOW_POWER -config BT_MESH_FRIEND +menuconfig BT_MESH_FRIEND bool "Support for acting as a Friend Node" help Enable this option to be able to act as a Friend Node. @@ -908,11 +955,12 @@ config BT_MESH_FRIEND if BT_MESH_FRIEND config BT_MESH_FRIEND_ENABLED - bool "Friend feature enabled" + bool "Friend feature enabled by default" default y help - Controls whether the Friend feature is enabled by default. Can be - changed through runtime configuration. + Controls whether the Friend feature is enabled by default when the + device boots up for the first time or unprovisioned. Can be changed + at runtime using bt_mesh_friend_set() function. config BT_MESH_FRIEND_RECV_WIN int "Friend Receive Window" @@ -968,40 +1016,6 @@ config BT_MESH_FRIEND_ADV_LATENCY endif # BT_MESH_FRIEND -config BT_MESH_CFG_CLI - bool "Support for Configuration Client Model" - help - Enable support for the configuration client model. - -if BT_MESH_CFG_CLI - -config BT_MESH_CFG_CLI_TIMEOUT - int "Config Client model timeout in milliseconds" - default 5000 - help - This timeout controls how long config client waits for a response - message to arrive. This value can be changed at runtime using - @ref bt_mesh_cfg_cli_timeout_set. - -endif # BT_MESH_CFG_CLI - -config BT_MESH_HEALTH_CLI - bool "Support for Health Client Model" - help - Enable support for the health client model. - -if BT_MESH_HEALTH_CLI - -config BT_MESH_HEALTH_CLI_TIMEOUT - int "Health Client model timeout in milliseconds" - default 2000 - help - This timeout controls how long health client waits for a response - message to arrive. This value can be changed at runtime using - @ref bt_mesh_health_cli_timeout_set. - -endif # BT_MESH_HEALTH_CLI - menuconfig BT_MESH_V1d1 bool "Bluetooth mesh v1.1 support [EXPERIMENTAL]" select EXPERIMENTAL @@ -1011,6 +1025,13 @@ menuconfig BT_MESH_V1d1 with this option enabled because the Bluetooth mesh v1.1 specification is in a draft state. +config BT_MESH_ECDH_P256_CMAC_AES128_AES_CCM + bool "Support CMAC AES128 for OOB authentication" if BT_MESH_V1d1 + 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 @@ -1562,42 +1583,51 @@ endmenu endif # BT_MESH_V1d1 -# Configuration options for 1.0.1 transport layer -if !BT_MESH_V1d1 +menu "Capabilities" -config BT_MESH_TX_SEG_RETRANS_COUNT - int "Transport message segment retransmit attempts" - default 4 - range 1 8 +config BT_MESH_SUBNET_COUNT + int "Maximum number of mesh subnets per network" + default 1 + range 1 4096 help - Maximum number of transport message segment retransmit attempts - for outgoing segment message. + This option specifies how many subnets a Mesh network can + participate in at the same time. -config BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST - int "Transport message segment retransmit interval for unicast messages" - default 400 - range 200 500 +config BT_MESH_APP_KEY_COUNT + int "Maximum number of application keys per network" + default 1 + range 1 4096 help - Maximum time of retransmit segment message to unicast address. + This option specifies how many application keys the device can + store per network. -config BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP - int "Transport message segment retransmit interval for group messages" - default 50 - range 20 200 +config BT_MESH_MODEL_KEY_COUNT + int "Maximum number of application keys per model" + default 1 + range 1 4096 help - Maximum time of retransmit segment message to group address. - -endif #!BT_MESH_V1d1 + This option specifies how many application keys each model can + at most be bound to. -rsource "shell/Kconfig" +config BT_MESH_MODEL_GROUP_COUNT + int "Maximum number of group address subscriptions per model" + default 1 + range 1 4096 + help + This option specifies how many group addresses each model can + at most be subscribed to. -config BT_MESH_MODEL_EXTENSIONS - bool "Support for Model extensions" +config BT_MESH_LABEL_COUNT + int "Maximum number of Label UUIDs used for Virtual Addresses" + default 1 + range 0 4096 help - Enable support for the model extension concept, allowing the Access - layer to know about mesh model relationships. + This option specifies how many Label UUIDs can be stored. -if BT_SETTINGS +endmenu # Capabilities + +menu "Persistent storage" + visible if BT_SETTINGS config BT_MESH_STORE_TIMEOUT int "Delay (in seconds) before storing anything persistently" @@ -1612,6 +1642,7 @@ config BT_MESH_SEQ_STORE_RATE int "How often the sequence number gets updated in storage" range 0 1000000 default 128 + default 1 if !BT_SETTINGS # To keep compiling the code help This value defines how often the local sequence number gets updated in persistent storage (i.e. flash). E.g. a value of 100 @@ -1624,6 +1655,33 @@ config BT_MESH_SEQ_STORE_RATE off with a value that's guaranteed to be larger than the last one used before power off. +if BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS + +config BT_MESH_RPL_STORE_TIMEOUT + int "Minimum interval after which unsaved RPL and SRPL entries are updated in the settings subsystem" + range -1 1000000 + default 5 + help + This value defines time in seconds until unsaved RPL and SRPL entries + are written to the persistent storage. Setting this value + to a large number may lead to security vulnerabilities if a node + gets powered off before the timer is fired. When flash is used + as the persistent storage setting this value to a low number + may wear out flash sooner or later. However, if the RPL gets + updated infrequently a value as low as 0 (write immediately) + may make sense. Setting this value to -1 will disable this timer. + In this case, a user is responsible to store pending RPL entries + using @ref bt_mesh_rpl_pending_store. In the mean time, when + IV Index is updated, the outdated RPL entries will still be + stored by @ref BT_MESH_STORE_TIMEOUT. Finding the right balance + between this timeout and calling @ref bt_mesh_rpl_pending_store + may reduce a risk of security vulnerability and flash wear out. + Failure to store the RPL and becoming vulnerable after reboot + will cause the device to not perform the replay protection + required by the spec. + +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" default y @@ -1652,19 +1710,28 @@ config BT_MESH_SETTINGS_WORKQ_STACK_SIZE Size of the settings workqueue stack. endif # BT_MESH_SETTINGS_WORKQ -endif # BT_SETTINGS -if BT_MESH_LOG_LEVEL_DBG +endmenu # Persistent storage -config BT_MESH_DEBUG_USE_ID_ADDR - bool "Use identity address for all advertising" +rsource "shell/Kconfig" + +if BT_CONN + +config BT_MESH_MAX_CONN + int "Maximum number of simultaneous Bluetooth connections" + default BT_MAX_CONN + range 1 BT_MAX_CONN help - This option forces the usage of the local identity address for - all advertising. This can be a help for debugging (analyzing - traces), however it should never be enabled for a production - build as it compromises the privacy of the device. + Maximum number of simultaneous Bluetooth connections that the Bluetooth + mesh stack can use. + +endif # BT_CONN -endif # BT_MESH_LOG_LEVEL_DBG +config BT_MESH_SELF_TEST + bool "Perform self-tests" + help + This option adds extra self-tests which are run every time + mesh networking is initialized. config BT_MESH_STATISTIC bool "The frame handling statistics [EXPERIMENTAL]" diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 4632d6f7164f..94b2acfdbbab 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -58,13 +58,6 @@ LOG_MODULE_REGISTER(bt_mesh_net); #define SRC(pdu) (sys_get_be16(&(pdu)[5])) #define DST(pdu) (sys_get_be16(&(pdu)[7])) -/** Define CONFIG_BT_MESH_SEQ_STORE_RATE even if settings are disabled to - * compile the code. - */ -#ifndef CONFIG_BT_SETTINGS -#define CONFIG_BT_MESH_SEQ_STORE_RATE 1 -#endif - /* Mesh network information for persistent storage. */ struct net_val { uint16_t primary_addr; From 8fc22e14a99f9d1a5c7ab0f78acec0f92da4f22a Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Thu, 6 Jul 2023 13:18:08 +0200 Subject: [PATCH 0983/2042] Bluetooth: Mesh: Remove TODO file is outdated Remove TODO file is outdated. Signed-off-by: Pavel Vasilyev --- subsys/bluetooth/mesh/TODO | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 subsys/bluetooth/mesh/TODO diff --git a/subsys/bluetooth/mesh/TODO b/subsys/bluetooth/mesh/TODO deleted file mode 100644 index b6f916d53641..000000000000 --- a/subsys/bluetooth/mesh/TODO +++ /dev/null @@ -1,6 +0,0 @@ -Bluetooth mesh implementation tasks -=================================== - - * Ability to act as provisioner - - * More generally useful models from the Model Specification From 4da15181080a8c3bf4480661ab79627a4b46629e Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Wed, 5 Jul 2023 07:35:24 +0200 Subject: [PATCH 0984/2042] regulator: shell: fix unitialized variable warning from SCA Static code analysis it has highlighted that a variable is beeing accessed before initializing. This is a very minor fix to resolve this potential issue. Signed-off-by: Martin Kiepfer --- drivers/regulator/regulator_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index ce7c262ed5c3..626b74e678bb 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -131,7 +131,7 @@ static int cmd_vlist(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; unsigned int volt_cnt; - int32_t last_volt_uv; + int32_t last_volt_uv = 0; ARG_UNUSED(argc); From eba4d34b687c5fd1297b552156669da194059fa3 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Thu, 6 Jul 2023 13:13:52 +0200 Subject: [PATCH 0985/2042] tests: Bluetooth: Mesh: test 32-bytes auth static OOB Mesh 1.1 specification extended static OOB authentication value till 32bytes. PR adds one more test vector in provisioning bsim test to check it. Signed-off-by: Aleksandr Khromykh --- tests/bsim/bluetooth/mesh/src/test_provision.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/bsim/bluetooth/mesh/src/test_provision.c b/tests/bsim/bluetooth/mesh/src/test_provision.c index 2f6e43469c56..3d1e10bfbbf2 100644 --- a/tests/bsim/bluetooth/mesh/src/test_provision.c +++ b/tests/bsim/bluetooth/mesh/src/test_provision.c @@ -53,6 +53,11 @@ 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]; @@ -68,6 +73,9 @@ 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}, From 963422111cf2bf97aa6d1ea88702ff3ea3759828 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 7 Jul 2023 09:42:18 +0200 Subject: [PATCH 0986/2042] driver gpio nrfx: Fix undefined output in gpio_nrfx_port_get_direction gpio_nrfx_port_get_direction() is meant to check which inputs are enabled, and does so by checking one bit at a time and setting that bit into the "input" parameter. But "input" was never zeroed, so any garbage ones it may have remains. Zero it. This fixes a problem where if the "input" parameter was not zeroed by the caller, the result of the funcion call is undefined. Detected by valgrind on: tests/drivers/gpio/gpio_get_direction Conditional jump or move depends on uninitialised value(s) by gpio_get_direction_test_disconnect (main.c:64) Conditional jump or move depends on uninitialised value(s) by gpio_get_direction_test_output (main.c:102) When running this test for the nrf52_bsim. Signed-off-by: Alberto Escolar Piedras --- drivers/gpio/gpio_nrfx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 35e901b152e1..1683b8b2ceac 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -302,6 +302,7 @@ static int gpio_nrfx_port_get_direction(const struct device *port, } if (inputs != NULL) { + *inputs = 0; while (map) { uint32_t pin = NRF_CTZ(map); uint32_t pin_cnf = reg->PIN_CNF[pin]; From 3b59d6842f5bf1a722dfb5c877ab1591e822a436 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Thu, 6 Jul 2023 16:08:08 -0600 Subject: [PATCH 0987/2042] sensor: ism330dhcx: Incorrect handle passed to ctx struct in SPI mode The ISM330DHCX driver immediately segfaults when run in SPI mode. A bad pointer is being passed into the `dev` param of `ism330dhcx_spi_read`. Tracing this back, it appears that the handle field of the ctx struct is being set to the device's data struct while `ism330dhcx_spi_read` expects `ctx->handle` to be a pointer to a device struct. Modify `ism330dhcx_spi_init()` to insert the correct pointer into the context struct. Unfortunately this requires a cast to discard the `const` qualifier, but this is how it is done in I2C mode (see `ism330dhcx_i2c_init()`). The only other way would be to change the declaration of `stmdev_ctx_t`, which is owned by the HAL module. Signed-off-by: Tristan Honscheid --- drivers/sensor/ism330dhcx/ism330dhcx_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/ism330dhcx/ism330dhcx_spi.c b/drivers/sensor/ism330dhcx/ism330dhcx_spi.c index 5a20812caa12..103978e65d56 100644 --- a/drivers/sensor/ism330dhcx/ism330dhcx_spi.c +++ b/drivers/sensor/ism330dhcx/ism330dhcx_spi.c @@ -107,7 +107,7 @@ int ism330dhcx_spi_init(const struct device *dev) data->ctx_spi.mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay; data->ctx = &data->ctx_spi; - data->ctx->handle = data; + data->ctx->handle = (void *)dev; return 0; } From a6e9782b01099023a61787d282c83091395b46d5 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Fri, 7 Jul 2023 09:34:18 +0200 Subject: [PATCH 0988/2042] drivers: ieee802154: fix declaration in case blocks The code declares variables in switch-case blocks. This seems to compile without an error on GCC 11 and newer, but older compilers don't accept this code. Signed-off-by: Damian Krolik --- drivers/ieee802154/ieee802154_nrf5.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index f11c1953c2c7..a6a78580dbe5 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -940,7 +940,7 @@ static int nrf5_configure(const struct device *dev, } break; #if defined(CONFIG_IEEE802154_CSL_ENDPOINT) - case IEEE802154_CONFIG_CSL_RX_TIME: + case IEEE802154_CONFIG_CSL_RX_TIME: { /* * `target_time_convert_to_64_bits()` is a workaround until OpenThread (the only * CSL user in Zephyr so far) is able to schedule RX windows using 64-bit time. @@ -948,9 +948,9 @@ static int nrf5_configure(const struct device *dev, uint64_t csl_rx_time = target_time_convert_to_64_bits(config->csl_rx_time); nrf_802154_csl_writer_anchor_time_set(csl_rx_time); - break; + } break; - case IEEE802154_CONFIG_RX_SLOT: + case IEEE802154_CONFIG_RX_SLOT: { /* Note that even if the nrf_802154_receive_at function is not called in time * (for example due to the call being blocked by higher priority threads) and * the delayed reception window is not scheduled, the CSL phase will still be @@ -966,7 +966,7 @@ static int nrf5_configure(const struct device *dev, nrf_802154_receive_at(start, config->rx_slot.duration, config->rx_slot.channel, DRX_SLOT_RX); - break; + } break; case IEEE802154_CONFIG_CSL_PERIOD: nrf_802154_csl_writer_period_set(config->csl_period); From 935268ee64fdf43e65eb7ede7fdea2a0e45caf5b Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 4 Jul 2023 17:50:12 +0200 Subject: [PATCH 0989/2042] devicetree.h: DT_FOREACH_NODE_VARGS, DT_FOREACH_STATUS_OKAY_NODE_VARGS Add the _VARGS variant of DT_FOREACH_NODE and DT_FOREACH_STATUS_OKAY_NODE for when we want to do some kind of operation on all the nodes in the tree. Signed-off-by: Carlo Caione --- include/zephyr/devicetree.h | 30 +++++++++++++++++++++++++++++ scripts/dts/gen_defines.py | 5 +++++ tests/lib/devicetree/api/src/main.c | 11 +++++++++++ 3 files changed, 46 insertions(+) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index c9aab6653431..94ab5b8d3ada 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -2470,6 +2470,20 @@ */ #define DT_FOREACH_NODE(fn) DT_FOREACH_HELPER(fn) +/** + * @brief Invokes @p fn for every node in the tree with multiple arguments. + * + * The macro @p fn takes multiple arguments. The first should be the node + * identifier for the node. The remaining are passed-in by the caller. + * + * The macro is expanded once for each node in the tree. The order that nodes + * are visited in is not specified. + * + * @param fn macro to invoke + * @param ... variable number of arguments to pass to @p fn + */ +#define DT_FOREACH_NODE_VARGS(fn, ...) DT_FOREACH_VARGS_HELPER(fn, __VA_ARGS__) + /** * @brief Invokes @p fn for every status `okay` node in the tree. * @@ -2483,6 +2497,22 @@ */ #define DT_FOREACH_STATUS_OKAY_NODE(fn) DT_FOREACH_OKAY_HELPER(fn) +/** + * @brief Invokes @p fn for every status `okay` node in the tree with multiple + * arguments. + * + * The macro @p fn takes multiple arguments. The first should be the node + * identifier for the node. The remaining are passed-in by the caller. + * + * The macro is expanded once for each node in the tree with status `okay` (as + * usual, a missing status property is treated as status `okay`). The order + * that nodes are visited in is not specified. + * + * @param fn macro to invoke + * @param ... variable number of arguments to pass to @p fn + */ +#define DT_FOREACH_STATUS_OKAY_NODE_VARGS(fn, ...) DT_FOREACH_OKAY_VARGS_HELPER(fn, __VA_ARGS__) + /** * @brief Invokes @p fn for each child of @p node_id * diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 2394e3a7d476..ed47d3ae1512 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -921,6 +921,11 @@ def write_global_macros(edt): out_dt_define("FOREACH_OKAY_HELPER(fn)", " ".join(f"fn(DT_{node.z_path_id})" for node in edt.nodes if node.status == "okay")) + out_dt_define("FOREACH_VARGS_HELPER(fn, ...)", + " ".join(f"fn(DT_{node.z_path_id}, __VA_ARGS__)" for node in edt.nodes)) + out_dt_define("FOREACH_OKAY_VARGS_HELPER(fn, ...)", + " ".join(f"fn(DT_{node.z_path_id}, __VA_ARGS__)" for node in edt.nodes + if node.status == "okay")) n_okay_macros = {} for_each_macros = {} diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 587c56a38267..eb96de5a81db 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -1426,8 +1426,19 @@ ZTEST(devicetree_api, test_foreach) zassert_equal(1, DT_FOREACH_STATUS_OKAY_NODE(IS_ALIASES), ""); zassert_equal(0, DT_FOREACH_STATUS_OKAY_NODE(IS_DISABLED_GPIO), ""); +#define IS_ALIASES_VARGS(node_id, mul) + ((mul) * DT_SAME_NODE(DT_PATH(aliases), node_id)) +#define IS_DISABLED_GPIO_VARGS(node_id, mul) + ((mul) * \ + DT_SAME_NODE(DT_NODELABEL(disabled_gpio), node_id)) + zassert_equal(2, DT_FOREACH_NODE_VARGS(IS_ALIASES_VARGS, 2), ""); + zassert_equal(2, DT_FOREACH_NODE_VARGS(IS_DISABLED_GPIO_VARGS, 2), ""); + zassert_equal(2, DT_FOREACH_STATUS_OKAY_NODE_VARGS(IS_ALIASES_VARGS, 2), ""); + zassert_equal(0, DT_FOREACH_STATUS_OKAY_NODE_VARGS(IS_DISABLED_GPIO_VARGS, 2), ""); + + #undef IS_ALIASES #undef IS_DISABLED_GPIO +#undef IS_ALIASES_VARGS +#undef IS_DISABLED_GPIO_VARGS } #undef DT_DRV_COMPAT From 2e4d7ec5a829fb21d99441f7579af8418dfe067f Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 22 Jun 2023 14:57:43 +0200 Subject: [PATCH 0990/2042] drivers : ethernet: add SOC_SERIES_STM32H5X add Ethernet SOC_SERIES_STM32H5X Signed-off-by: Marc Desvaux --- drivers/ethernet/Kconfig.stm32_hal | 9 +- drivers/ethernet/eth_stm32_hal.c | 165 ++++++++++++++------------ drivers/ethernet/eth_stm32_hal_priv.h | 5 +- 3 files changed, 95 insertions(+), 84 deletions(-) diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index de0150e0c69f..b10455e9f181 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -22,12 +22,13 @@ choice ETH_STM32_HAL_API_VERSION config ETH_STM32_HAL_API_V2 bool "Use new HAL driver" - depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32H5X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X help Use the new HAL driver instead of the legacy one. config ETH_STM32_HAL_API_V1 bool "Use new HAL driver" + depends on !SOC_SERIES_STM32H5X select DEPRECATED if SOC_SERIES_STM32H7X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X help Driver version based on legacy HAL version. Deprecated unless using STM32F2 series. @@ -135,7 +136,7 @@ config ETH_STM32_AUTO_NEGOTIATION_ENABLE config ETH_STM32_HW_CHECKSUM bool "Use TX and RX hardware checksum" - depends on !SOC_SERIES_STM32H7X + depends on (!SOC_SERIES_STM32H7X && !SOC_SERIES_STM32H5X ) help Enable receive and transmit checksum offload to enhance throughput performances. @@ -157,7 +158,7 @@ config ETH_STM32_MODE_HALFDUPLEX endif # !ETH_STM32_AUTO_NEGOTIATION_ENABLE -if SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X +if SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X || SOC_SERIES_STM32H5X config PTP_CLOCK_STM32_HAL bool "STM32 HAL PTP clock driver support" @@ -197,7 +198,7 @@ config ETH_STM32_HAL_PTP_CLOCK_INIT_PRIO a dependency from the network stack that this device initializes before network stack (NET_INIT_PRIO). -endif # SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X +endif # SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X || SOC_SERIES_STM32H5X config ETH_STM32_MULTICAST_FILTER bool "Multicast hash filter support" diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 730dc7a46b38..267bddfb1db4 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -51,7 +51,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define PHY_ADDR CONFIG_ETH_STM32_HAL_PHY_ADDRESS -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) #define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ #define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ @@ -72,7 +72,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define IS_ETH_DMATXDESC_OWN(dma_tx_desc) (dma_tx_desc->Status & \ ETH_DMATXDESC_OWN) -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #define ETH_DMA_TX_TIMEOUT_MS 20U /* transmit timeout in milliseconds */ @@ -80,7 +80,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) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) #define __eth_stm32_desc __attribute__((section(".eth_stm32_desc"))) #define __eth_stm32_buf __attribute__((section(".eth_stm32_buf"))) #elif defined(CONFIG_NOCACHE_MEMORY) @@ -213,7 +213,8 @@ static inline uint16_t allocate_tx_buffer(void) } #endif /* CONFIG_ETH_STM32_HAL_API_V2 */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) static ETH_TxPacketConfig tx_config; #endif @@ -222,19 +223,20 @@ static HAL_StatusTypeDef read_eth_phy_register(ETH_HandleTypeDef *heth, uint32_t PHYReg, uint32_t *RegVal) { -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) return HAL_ETH_ReadPHYRegister(heth, PHYAddr, PHYReg, RegVal); #else ARG_UNUSED(PHYAddr); return HAL_ETH_ReadPHYRegister(heth, PHYReg, RegVal); -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ } static inline void setup_mac_filter(ETH_HandleTypeDef *heth) { __ASSERT_NO_MSG(heth != NULL); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) ETH_MACFilterConfigTypeDef MACFilterConf; HAL_ETH_GetMACFilterConfig(heth, &MACFilterConf); @@ -275,7 +277,7 @@ static inline void setup_mac_filter(ETH_HandleTypeDef *heth) tmp = heth->Instance->MACFFR; k_sleep(K_MSEC(1)); heth->Instance->MACFFR = tmp; -#endif /* CONFIG_SOC_SERIES_STM32H7X) */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X) */ } #if defined(CONFIG_PTP_CLOCK_STM32_HAL) @@ -355,14 +357,14 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) ctx.first_tx_buffer_index = allocate_tx_buffer(); buf_header = &dma_tx_buffer_header[ctx.first_tx_buffer_index]; #else /* CONFIG_ETH_STM32_HAL_API_V2 */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) uint32_t cur_tx_desc_idx; cur_tx_desc_idx = heth->TxDescList.CurTxDesc; dma_tx_desc = (ETH_DMADescTypeDef *)heth->TxDescList.TxDesc[cur_tx_desc_idx]; #else dma_tx_desc = heth->TxDesc; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ while (IS_ETH_DMATXDESC_OWN(dma_tx_desc) != (uint32_t)RESET) { k_yield(); @@ -375,7 +377,7 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) /* Enable transmit timestamp */ #if defined(CONFIG_ETH_STM32_HAL_API_V2) HAL_ETH_PTP_InsertTxTimestamp(heth); -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) dma_tx_desc->DESC2 |= ETH_DMATXNDESCRF_TTSE; #else dma_tx_desc->Status |= ETH_DMATXDESC_TTSE; @@ -408,27 +410,28 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) buf_header->tx_buff.next = NULL; #else /* CONFIG_ETH_STM32_HAL_API_V2 */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) dma_buffer = dma_tx_buffer[cur_tx_desc_idx]; #else dma_buffer = (uint8_t *)(dma_tx_desc->Buffer1Addr); -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ if (net_pkt_read(pkt, dma_buffer, total_len)) { res = -ENOBUFS; goto error; } -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) ETH_BufferTypeDef tx_buffer_def; tx_buffer_def.buffer = dma_buffer; tx_buffer_def.len = total_len; tx_buffer_def.next = NULL; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #endif /* CONFIG_ETH_STM32_HAL_API_V2 */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) tx_config.Length = total_len; #if defined(CONFIG_ETH_STM32_HAL_API_V2) @@ -517,12 +520,12 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) res = -EIO; goto error; } -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ #if defined(CONFIG_PTP_CLOCK_STM32_HAL) && !defined(CONFIG_ETH_STM32_HAL_API_V2) if (timestamped_frame) { /* Retrieve transmission timestamp from last DMA TX descriptor */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) ETH_TxDescListTypeDef * dma_tx_desc_list; __IO ETH_DMADescTypeDef *last_dma_tx_desc; @@ -575,7 +578,7 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) pkt->timestamp.second = UINT64_MAX; pkt->timestamp.nanosecond = UINT32_MAX; } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ net_if_add_tx_timestamp(pkt); } @@ -628,7 +631,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) void *appbuf = NULL; struct eth_stm32_rx_buffer_header *rx_header; #else -#if !defined(CONFIG_SOC_SERIES_STM32H7X) +#if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32H5X) __IO ETH_DMADescTypeDef *dma_rx_desc; #endif /* !CONFIG_SOC_SERIES_STM32H7X */ uint8_t *dma_buffer; @@ -663,7 +666,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) rx_header; rx_header = rx_header->next) { total_len += rx_header->size; } -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) if (HAL_ETH_IsRxDataAvailable(heth) != true) { /* no frame available */ return NULL; @@ -697,7 +700,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) total_len = heth->RxFrameInfos.length; dma_buffer = (uint8_t *)heth->RxFrameInfos.buffer; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #if defined(CONFIG_PTP_CLOCK_STM32_HAL) #if defined(CONFIG_ETH_STM32_HAL_API_V2) @@ -707,7 +710,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) timestamp.nanosecond = ts_registers.TimeStampLow; } -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) ETH_RxDescListTypeDef * dma_rx_desc_list; dma_rx_desc_list = &heth->RxDescList; @@ -746,7 +749,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) timestamp.second = last_dma_rx_desc->TimeStampHigh; timestamp.nanosecond = last_dma_rx_desc->TimeStampLow; } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #endif /* CONFIG_PTP_CLOCK_STM32_HAL */ pkt = net_pkt_rx_alloc_with_buffer(get_iface(dev_data, *vlan_tag), @@ -785,7 +788,7 @@ static struct net_pkt *eth_rx(const struct device *dev, uint16_t *vlan_tag) rx_header->used = false; } -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) hal_ret = HAL_ETH_BuildRxDescriptors(heth); if (hal_ret != HAL_OK) { LOG_ERR("HAL_ETH_BuildRxDescriptors: failed: %d", hal_ret); @@ -940,7 +943,8 @@ static void eth_isr(const struct device *dev) HAL_ETH_IRQHandler(heth); } -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth_handle) { __ASSERT_NO_MSG(heth_handle != NULL); @@ -953,7 +957,7 @@ void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth_handle) k_sem_give(&dev_data->tx_int_sem); } -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ #if defined(CONFIG_ETH_STM32_HAL_API_V2) void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) @@ -965,9 +969,9 @@ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) __ASSERT_NO_MSG(heth != NULL); uint32_t dma_error; -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) uint32_t mac_error; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ const uint32_t error_code = HAL_ETH_GetError(heth); struct eth_stm32_hal_dev_data *dev_data = @@ -977,7 +981,7 @@ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) case HAL_ETH_ERROR_DMA: dma_error = HAL_ETH_GetDMAError(heth); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) if ((dma_error & ETH_DMA_RX_WATCHDOG_TIMEOUT_FLAG) || (dma_error & ETH_DMA_RX_PROCESS_STOPPED_FLAG) || (dma_error & ETH_DMA_RX_BUFFER_UNAVAILABLE_FLAG)) { @@ -998,10 +1002,10 @@ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) (dma_error & ETH_DMASR_TJTS)) { eth_stats_update_errors_tx(dev_data->iface); } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ break; -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) case HAL_ETH_ERROR_MAC: mac_error = HAL_ETH_GetMACError(heth); @@ -1018,20 +1022,20 @@ void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) eth_stats_update_errors_tx(dev_data->iface); } break; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ } -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) dev_data->stats.error_details.rx_crc_errors = heth->Instance->MMCRCRCEPR; dev_data->stats.error_details.rx_align_errors = heth->Instance->MMCRAEPR; #else dev_data->stats.error_details.rx_crc_errors = heth->Instance->MMCRFCECR; dev_data->stats.error_details.rx_align_errors = heth->Instance->MMCRFAECR; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #endif /* CONFIG_NET_STATISTICS_ETHERNET */ } -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) /* DMA and MAC errors callback only appear in H7 series */ void HAL_ETH_DMAErrorCallback(ETH_HandleTypeDef *heth_handle) { @@ -1170,11 +1174,12 @@ static int eth_initialize(const struct device *dev) heth->Init.MACAddr = dev_data->mac_addr; -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) heth->Init.TxDesc = dma_tx_desc_tab; heth->Init.RxDesc = dma_rx_desc_tab; heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE; -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ hal_ret = HAL_ETH_Init(heth); if (hal_ret == HAL_TIMEOUT) { @@ -1191,14 +1196,15 @@ static int eth_initialize(const struct device *dev) /* Enable timestamping of RX packets. We enable all packets to be * timestamped to cover both IEEE 1588 and gPTP. */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL; #else heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #endif /* CONFIG_PTP_CLOCK_STM32_HAL */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) /* Tx config init: */ memset(&tx_config, 0, sizeof(ETH_TxPacketConfig)); tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | @@ -1206,18 +1212,20 @@ static int eth_initialize(const struct device *dev) tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ? ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC : ETH_CHECKSUM_DISABLE; tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT; -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ dev_data->link_up = false; /* Initialize semaphores */ k_mutex_init(&dev_data->tx_mutex); k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT); -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT); -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) /* Adjust MDC clock range depending on HCLK frequency: */ HAL_ETH_SetMDIOClockRange(heth); @@ -1234,7 +1242,7 @@ static int eth_initialize(const struct device *dev) if (hal_ret != HAL_OK) { LOG_ERR("HAL_ETH_SetMACConfig: failed: %d", hal_ret); } -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2 */ #if defined(CONFIG_ETH_STM32_HAL_API_V2) @@ -1244,7 +1252,7 @@ static int eth_initialize(const struct device *dev) } hal_ret = HAL_ETH_Start_IT(heth); -#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) for (uint32_t i = 0; i < ETH_RX_DESC_CNT; i++) { hal_ret = HAL_ETH_DescAssignMemory(heth, i, dma_rx_buffer[i], NULL); @@ -1380,13 +1388,13 @@ static void net_if_stm32_mcast_cb(struct net_if *iface, /* Save a copy of the hash table which we update with * the hash for a single multicast address for join */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) hash_table[0] = heth->Instance->MACHT0R; hash_table[1] = heth->Instance->MACHT1R; #else hash_table[0] = heth->Instance->MACHTLR; hash_table[1] = heth->Instance->MACHTHR; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ } k_mutex_lock(&multicast_addr_lock, K_FOREVER); @@ -1459,13 +1467,13 @@ static void net_if_stm32_mcast_cb(struct net_if *iface, k_mutex_unlock(&multicast_addr_lock); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACHT0R = hash_table[0]; heth->Instance->MACHT1R = hash_table[1]; #else heth->Instance->MACHTLR = hash_table[0]; heth->Instance->MACHTHR = hash_table[1]; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ } #endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */ @@ -1576,7 +1584,7 @@ static int eth_stm32_hal_set_config(const struct device *dev, break; case ETHERNET_CONFIG_TYPE_PROMISC_MODE: #if defined(CONFIG_NET_PROMISCUOUS_MODE) -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) if (config->promisc_mode) { heth->Instance->MACPFR |= ETH_MACPFR_PR; } else { @@ -1588,7 +1596,7 @@ static int eth_stm32_hal_set_config(const struct device *dev, } else { heth->Instance->MACFFR &= ~ETH_MACFFR_PM; } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ ret = 0; #endif /* CONFIG_NET_PROMISCUOUS_MODE */ break; @@ -1658,7 +1666,8 @@ static struct eth_stm32_hal_dev_data eth0_data = { .heth = { .Instance = (ETH_TypeDef *)DT_INST_REG_ADDR(0), .Init = { -#if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_ETH_STM32_HAL_API_V2) +#if !defined(CONFIG_SOC_SERIES_STM32H7X) && !defined(CONFIG_SOC_SERIES_STM32H5X) && \ + !defined(CONFIG_ETH_STM32_HAL_API_V2) #if defined(CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE) .AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE, #else @@ -1701,7 +1710,7 @@ static int ptp_clock_stm32_set(const struct device *dev, key = irq_lock(); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACSTSUR = tm->second; heth->Instance->MACSTNUR = tm->nanosecond; heth->Instance->MACTSCR |= ETH_MACTSCR_TSINIT; @@ -1715,7 +1724,7 @@ static int ptp_clock_stm32_set(const struct device *dev, while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTI_Msk) { /* spin lock */ } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ irq_unlock(key); @@ -1733,7 +1742,7 @@ static int ptp_clock_stm32_get(const struct device *dev, key = irq_lock(); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) tm->second = heth->Instance->MACSTSR; tm->nanosecond = heth->Instance->MACSTNR; second_2 = heth->Instance->MACSTSR; @@ -1741,7 +1750,7 @@ static int ptp_clock_stm32_get(const struct device *dev, tm->second = heth->Instance->PTPTSHR; tm->nanosecond = heth->Instance->PTPTSLR; second_2 = heth->Instance->PTPTSHR; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ irq_unlock(key); @@ -1769,7 +1778,7 @@ static int ptp_clock_stm32_adjust(const struct device *dev, int increment) } else { key = irq_lock(); -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACSTSUR = 0; if (increment >= 0) { heth->Instance->MACSTNUR = increment; @@ -1791,7 +1800,7 @@ static int ptp_clock_stm32_adjust(const struct device *dev, int increment) while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTU_Msk) { /* spin lock */ } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ ret = 0; irq_unlock(key); @@ -1830,7 +1839,7 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) /* Update addend register */ addend_val = UINT32_MAX * eth_dev_data->clk_ratio * ratio; -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSAR = addend_val; heth->Instance->MACTSCR |= ETH_MACTSCR_TSADDREG; while (heth->Instance->MACTSCR & ETH_MACTSCR_TSADDREG_Msk) { @@ -1842,7 +1851,7 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSARU_Msk) { /* spin lock */ } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ ret = 0; @@ -1875,26 +1884,26 @@ static int ptp_stm32_init(const struct device *port) ptp_context->eth_dev_data = eth_dev_data; /* Mask the Timestamp Trigger interrupt */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACIER &= ~(ETH_MACIER_TSIE); #else heth->Instance->MACIMR &= ~(ETH_MACIMR_TSTIM); -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Enable timestamping */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSCR |= ETH_MACTSCR_TSENA; #else heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSE; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Query ethernet clock rate */ ret = clock_control_get_rate(eth_dev_data->clock, -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) (clock_control_subsys_t)ð_cfg->pclken, #else (clock_control_subsys_t)ð_cfg->pclken_ptp, -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ &ptp_hclk_rate); if (ret) { LOG_ERR("Failed to query ethernet clock"); @@ -1911,11 +1920,11 @@ static int ptp_stm32_init(const struct device *port) LOG_ERR("PTP clock period is more than %d nanoseconds", UINT8_MAX); return -EINVAL; } -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACSSIR = ss_incr_ns << ETH_MACMACSSIR_SSINC_Pos; #else heth->Instance->PTPSSIR = ss_incr_ns; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Program timestamp addend register */ eth_dev_data->clk_ratio = @@ -1930,7 +1939,7 @@ static int ptp_stm32_init(const struct device *port) eth_dev_data->clk_ratio_adj = 1.0f; addend_val = UINT32_MAX * eth_dev_data->clk_ratio * eth_dev_data->clk_ratio_adj; -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSAR = addend_val; heth->Instance->MACTSCR |= ETH_MACTSCR_TSADDREG; while (heth->Instance->MACTSCR & ETH_MACTSCR_TSADDREG_Msk) { @@ -1942,24 +1951,24 @@ static int ptp_stm32_init(const struct device *port) while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSARU_Msk) { k_yield(); } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Enable fine timestamp correction method */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSCR |= ETH_MACTSCR_TSCFUPDT; #else heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSFCU; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Enable nanosecond rollover into a new second */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSCR |= ETH_MACTSCR_TSCTRLSSR; #else heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSSR; -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ /* Initialize timestamp */ -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACSTSUR = 0; heth->Instance->MACSTNUR = 0; heth->Instance->MACTSCR |= ETH_MACTSCR_TSINIT; @@ -1973,7 +1982,7 @@ static int ptp_stm32_init(const struct device *port) while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTI_Msk) { k_yield(); } -#endif /* CONFIG_SOC_SERIES_STM32H7X */ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */ #if defined(CONFIG_ETH_STM32_HAL_API_V2) /* Set PTP Configuration done */ diff --git a/drivers/ethernet/eth_stm32_hal_priv.h b/drivers/ethernet/eth_stm32_hal_priv.h index 56e754044e4d..99644585dffa 100644 --- a/drivers/ethernet/eth_stm32_hal_priv.h +++ b/drivers/ethernet/eth_stm32_hal_priv.h @@ -41,9 +41,10 @@ struct eth_stm32_hal_dev_data { const struct device *clock; struct k_mutex tx_mutex; struct k_sem rx_int_sem; -#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_ETH_STM32_HAL_API_V2) +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) || \ + defined(CONFIG_ETH_STM32_HAL_API_V2) struct k_sem tx_int_sem; -#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2*/ +#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X || CONFIG_ETH_STM32_HAL_API_V2*/ K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_STM32_HAL_RX_THREAD_STACK_SIZE); struct k_thread rx_thread; From 0bfad255dc6a61d4748e8ecb628dfc8627033ea1 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 22 Jun 2023 14:58:33 +0200 Subject: [PATCH 0991/2042] board: arm: nucleo_h563zi: add Ethernet add Ethernet for STMH563ZI Signed-off-by: Marc Desvaux --- boards/arm/nucleo_h563zi/Kconfig.defconfig | 7 +++++++ boards/arm/nucleo_h563zi/nucleo_h563zi.dts | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/boards/arm/nucleo_h563zi/Kconfig.defconfig b/boards/arm/nucleo_h563zi/Kconfig.defconfig index b43ccb20cd4a..4730fdb7a797 100644 --- a/boards/arm/nucleo_h563zi/Kconfig.defconfig +++ b/boards/arm/nucleo_h563zi/Kconfig.defconfig @@ -8,4 +8,11 @@ if BOARD_NUCLEO_H563ZI config BOARD default "nucleo_h563zi" +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + endif # BOARD_NUCLEO_H563ZI diff --git a/boards/arm/nucleo_h563zi/nucleo_h563zi.dts b/boards/arm/nucleo_h563zi/nucleo_h563zi.dts index 651ded06dea0..347a9fa95489 100644 --- a/boards/arm/nucleo_h563zi/nucleo_h563zi.dts +++ b/boards/arm/nucleo_h563zi/nucleo_h563zi.dts @@ -8,6 +8,7 @@ /dts-v1/; #include "nucleo_h563zi-common.dtsi" + / { model = "STMicroelectronics STM32H563ZI-NUCLEO board"; compatible = "st,stm32h563zi-nucleo"; @@ -18,7 +19,7 @@ chosen { zephyr,console = &usart3; zephyr,shell-uart = &usart3; - zephyr,sram = &sram0; + zephyr,sram = &sram1; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; }; @@ -36,3 +37,17 @@ &rng { status = "okay"; }; + +&mac { + status = "okay"; + pinctrl-0 = <ð_mdc_pc1 + ð_rxd0_pc4 + ð_rxd1_pc5 + ð_ref_clk_pa1 + ð_mdio_pa2 + ð_crs_dv_pa7 + ð_tx_en_pg11 + ð_txd0_pg13 + ð_txd1_pb15>; + pinctrl-names = "default"; +}; From be7db19b3375f4891dbcaed7325f7870b7170e2a Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Mon, 26 Jun 2023 14:54:31 +0200 Subject: [PATCH 0992/2042] dts: arm: st: h5: add Ethernet add Ethernet for STMH563ZI Signed-off-by: Marc Desvaux --- dts/arm/st/h5/stm32h5.dtsi | 11 +++++++++++ dts/arm/st/h5/stm32h563Xi.dtsi | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index 2052ea10c5de..d0388f2ec80e 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -461,6 +461,17 @@ status = "disabled"; }; + mac: ethernet@40028000 { + compatible = "st,stm32-ethernet"; + reg = <0x40028000 0x8000>; + interrupts = <106 0>; + clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx"; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x00080000>, + <&rcc STM32_CLOCK_BUS_AHB1 0x00100000>, + <&rcc STM32_CLOCK_BUS_AHB1 0x00200000>; + status = "disabled"; + }; + gpdma1: dma@40020000 { compatible = "st,stm32u5-dma"; #dma-cells = <3>; diff --git a/dts/arm/st/h5/stm32h563Xi.dtsi b/dts/arm/st/h5/stm32h563Xi.dtsi index 60ea91fc3155..fa80a94828ac 100644 --- a/dts/arm/st/h5/stm32h563Xi.dtsi +++ b/dts/arm/st/h5/stm32h563Xi.dtsi @@ -8,8 +8,22 @@ #include / { - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(640)>; + sram1: memory@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; + zephyr,memory-region = "SRAM1"; + }; + + sram2: memory@20040000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(64)>; + zephyr,memory-region = "SRAM2"; + }; + + sram3: memory@20050000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20050000 DT_SIZE_K(320)>; + zephyr,memory-region = "SRAM3"; }; soc { From 4293835192983bf0f132ed48a1b236dea950405c Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Thu, 22 Jun 2023 15:04:09 +0200 Subject: [PATCH 0993/2042] soc : arm: st_stm32: stm32h5: add linker for STM32H5X add some modifications for linker Signed-off-by: Marc Desvaux --- soc/arm/st_stm32/stm32h5/CMakeLists.txt | 1 + soc/arm/st_stm32/stm32h5/sections.ld | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 soc/arm/st_stm32/stm32h5/sections.ld diff --git a/soc/arm/st_stm32/stm32h5/CMakeLists.txt b/soc/arm/st_stm32/stm32h5/CMakeLists.txt index ac3ba70ace6e..9cb843e9cafc 100644 --- a/soc/arm/st_stm32/stm32h5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h5/CMakeLists.txt @@ -4,3 +4,4 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) +zephyr_linker_sources(SECTIONS sections.ld) diff --git a/soc/arm/st_stm32/stm32h5/sections.ld b/soc/arm/st_stm32/stm32h5/sections.ld new file mode 100644 index 000000000000..ead1bcd811b6 --- /dev/null +++ b/soc/arm/st_stm32/stm32h5/sections.ld @@ -0,0 +1,19 @@ +/* + * 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 8e403042580e7f8cb346ffecfcbeeff83629c10b Mon Sep 17 00:00:00 2001 From: Eduardo Montoya Date: Fri, 7 Jul 2023 10:40:28 +0200 Subject: [PATCH 0994/2042] net: openthread: remove unneeded `OPENTHREAD_MAX_CHILDREN` default value After https://github.com/openthread/openthread/pull/9213 there is no need to reduce the `ChildMask` size for MTD builds. Signed-off-by: Eduardo Montoya --- modules/openthread/Kconfig.thread | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/openthread/Kconfig.thread b/modules/openthread/Kconfig.thread index 0a7a399e9032..73c547919a7f 100644 --- a/modules/openthread/Kconfig.thread +++ b/modules/openthread/Kconfig.thread @@ -62,7 +62,6 @@ config OPENTHREAD_POLL_PERIOD config OPENTHREAD_MAX_CHILDREN int "The maximum number of children" range 1 511 - default 1 if OPENTHREAD_MTD default 32 config OPENTHREAD_MAX_IP_ADDR_PER_CHILD From dadacfaac209e477ad9e8c029719751d09ac0fc0 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 23 Jun 2023 11:06:58 +0200 Subject: [PATCH 0995/2042] soc (native): Use nce directly from native_simulator Instead of keeping a replica of the nce code, now that the native_simulator is in tree, let's use it directly. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/CMakeLists.txt | 2 +- arch/posix/core/nsi_compat/nce.c | 292 ------------------------------- 2 files changed, 1 insertion(+), 293 deletions(-) delete mode 100644 arch/posix/core/nsi_compat/nce.c diff --git a/arch/posix/core/CMakeLists.txt b/arch/posix/core/CMakeLists.txt index 1dd088b938fe..23802715c1dd 100644 --- a/arch/posix/core/CMakeLists.txt +++ b/arch/posix/core/CMakeLists.txt @@ -17,7 +17,7 @@ if(CONFIG_NATIVE_APPLICATION) zephyr_library_sources( posix_core.c nsi_compat/nsi_compat.c - nsi_compat/nce.c + ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nce.c ) else() zephyr_library_sources( diff --git a/arch/posix/core/nsi_compat/nce.c b/arch/posix/core/nsi_compat/nce.c deleted file mode 100644 index 54989dcd32cd..000000000000 --- a/arch/posix/core/nsi_compat/nce.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2017 Oticon A/S - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * Native simulator CPU emulator, - * an *optional* module provided by the native simulator - * the hosted embedded OS / SW can use to emulate the CPU - * being started and stopped. - * - * Its mode of operation is that it step-locks the HW - * and SW operation, so that only one of them executes at - * a time. Check the docs for more info. - */ - -#include -#include -#include -#include -#include "nce_if.h" -#include "nsi_safe_call.h" - -struct nce_status_t { - /* Conditional variable to know if the CPU is running or halted/idling */ - pthread_cond_t cond_cpu; - /* Mutex for the conditional variable cond_cpu */ - pthread_mutex_t mtx_cpu; - /* Variable which tells if the CPU is halted (1) or not (0) */ - bool cpu_halted; - bool terminate; /* Are we terminating the program == cleaning up */ - void (*start_routine)(void); -}; - -#define NCE_DEBUG_PRINTS 0 - -#define PREFIX "NCE: " -#define ERPREFIX PREFIX"error on " -#define NO_MEM_ERR PREFIX"Can't allocate memory\n" - -#if NCE_DEBUG_PRINTS -#define NCE_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__) -#else -#define NCE_DEBUG(...) -#endif - -extern void nsi_exit(int exit_code); - -/* - * Initialize an instance of the native simulator CPU emulator - * and return a pointer to it. - * That pointer should be passed to all subsequent calls to this module. - */ -void *nce_init(void) -{ - struct nce_status_t *this; - - this = calloc(1, sizeof(struct nce_status_t)); - - if (this == NULL) { /* LCOV_EXCL_BR_LINE */ - nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ - } - this->cpu_halted = true; - this->terminate = false; - - NSI_SAFE_CALL(pthread_cond_init(&this->cond_cpu, NULL)); - NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_cpu, NULL)); - - return (void *)this; -} - -/* - * This function will: - * - * If called from a SW thread, release the HW thread which is blocked in - * a nce_wake_cpu() and never return. - * - * If called from a HW thread, do the necessary clean up of this nce instance - * and return right away. - */ -void nce_terminate(void *this_arg) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - /* LCOV_EXCL_START */ /* See Note1 */ - /* - * If we are being called from a HW thread we can cleanup - * - * Otherwise (!cpu_halted) we give back control to the HW thread and - * tell it to terminate ASAP - */ - if (this == NULL || this->cpu_halted) { - /* - * Note: The nce_status structure cannot be safely free'd up - * as the user is allowed to call nce_clean_up() - * repeatedly on the same structure. - * Instead we rely of on the host OS process cleanup. - * If you got here due to valgrind's leak report, please use the - * provided valgrind suppression file valgrind.supp - */ - return; - } else if (this->terminate == false) { - - this->terminate = true; - - NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); - - this->cpu_halted = true; - - NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); - NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); - - while (1) { - sleep(1); - /* This SW thread will wait until being cancelled from - * the HW thread. sleep() is a cancellation point, so it - * won't really wait 1 second - */ - } - } - /* LCOV_EXCL_STOP */ -} - -/** - * Helper function which changes the status of the CPU (halted or running) - * and waits until somebody else changes it to the opposite - * - * Both HW and SW threads will use this function to transfer control to the - * other side. - * - * This is how the idle thread halts the CPU and gets halted until the HW models - * raise a new interrupt; and how the HW models awake the CPU, and wait for it - * to complete and go to idle. - */ -static void change_cpu_state_and_wait(struct nce_status_t *this, bool halted) -{ - NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); - - NCE_DEBUG("Going to halted = %d\n", halted); - - this->cpu_halted = halted; - - /* We let the other side know the CPU has changed state */ - NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); - - /* We wait until the CPU state has been changed. Either: - * we just awoke it, and therefore wait until the CPU has run until - * completion before continuing (before letting the HW models do - * anything else) - * or - * we are just hanging it, and therefore wait until the HW models awake - * it again - */ - while (this->cpu_halted == halted) { - /* Here we unlock the mutex while waiting */ - pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); - } - - NCE_DEBUG("Awaken after halted = %d\n", halted); - - NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); -} - -/* - * Helper function that wraps the SW start_routine - */ -static void *sw_wrapper(void *this_arg) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - /* Ensure nce_boot_cpu has reached the cond loop */ - NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); - NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); - -#if (NCE_DEBUG_PRINTS) - pthread_t sw_thread = pthread_self(); - - NCE_DEBUG("SW init started (%lu)\n", - sw_thread); -#endif - - this->start_routine(); - return NULL; -} - -/* - * Boot the emulated CPU, that is: - * * Spawn a new pthread which will run the first embedded SW thread - * * Hold the caller until that embedded SW thread (or a child it spawns) - * calls nce_halt_cpu() - * - * Note that during this, an embedded SW thread may call nsi_exit(), which would result - * in this function never returning. - */ -void nce_boot_cpu(void *this_arg, void (*start_routine)(void)) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); - - this->cpu_halted = false; - this->start_routine = start_routine; - - /* Create a thread for the embedded SW init: */ - pthread_t sw_thread; - - NSI_SAFE_CALL(pthread_create(&sw_thread, NULL, sw_wrapper, this_arg)); - - /* And we wait until the embedded OS has send the CPU to sleep for the first time */ - while (this->cpu_halted == false) { - pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); - } - NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); - - if (this->terminate) { - nsi_exit(0); - } -} - -/* - * Halt the CPU, that is: - * * Hold this embedded SW thread until the CPU is awaken again, - * and release the HW thread which had been held on - * nce_boot_cpu() or nce_wake_cpu(). - * - * Note: Can only be called from embedded SW threads - * Calling it from a HW thread is a programming error. - */ -void nce_halt_cpu(void *this_arg) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - if (this->cpu_halted == true) { - nsi_print_error_and_exit("Programming error on: %s ", - "This CPU was already halted\n"); - } - change_cpu_state_and_wait(this, true); -} - -/* - * Awake the CPU, that is: - * * Hold this HW thread until the CPU is set to idle again - * * Release the SW thread which had been held on nce_halt_cpu() - * - * Note: Can only be called from HW threads - * Calling it from a SW thread is a programming error. - */ -void nce_wake_cpu(void *this_arg) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - if (this->cpu_halted == false) { - nsi_print_error_and_exit("Programming error on: %s ", - "This CPU was already awake\n"); - } - change_cpu_state_and_wait(this, false); - - /* - * If while the SW was running it was decided to terminate the execution - * we stop immediately. - */ - if (this->terminate) { - nsi_exit(0); - } -} - -/* - * Return 0 if the CPU is sleeping (or terminated) - * and !=0 if the CPU is running - */ -int nce_is_cpu_running(void *this_arg) -{ - struct nce_status_t *this = (struct nce_status_t *)this_arg; - - if (this != NULL) { - return !this->cpu_halted; - } else { - return false; - } -} - -/* - * Notes about coverage: - * - * Note1: When the application is closed due to a SIGTERM, the path in this - * function will depend on when that signal was received. Typically during a - * regression run, both paths will be covered. But in some cases they won't. - * Therefore and to avoid confusing developers with spurious coverage changes - * we exclude this function from the coverage check - */ From 375d8414a089f4a5f43d751b63b1cdc2b5324645 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:48:41 +0200 Subject: [PATCH 0996/2042] boards: nucleo_f030r8: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f030r8/nucleo_f030r8.dts | 1 + .../nucleo_f030r8/st_morpho_connector.dtsi | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 boards/arm/nucleo_f030r8/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f030r8/nucleo_f030r8.dts b/boards/arm/nucleo_f030r8/nucleo_f030r8.dts index 8fe4bb3ae947..d10a5c439c07 100644 --- a/boards/arm/nucleo_f030r8/nucleo_f030r8.dts +++ b/boards/arm/nucleo_f030r8/nucleo_f030r8.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F030R8-NUCLEO board"; diff --git a/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi b/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi new file mode 100644 index 000000000000..6ab1c8ce24d6 --- /dev/null +++ b/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 6e77e1ba68c20ac4baadd065ae2d72ca77ee9f1d Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:49:03 +0200 Subject: [PATCH 0997/2042] boards: nucleo_f070rb: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f070rb/nucleo_f070rb.dts | 1 + .../nucleo_f070rb/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_f070rb/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f070rb/nucleo_f070rb.dts b/boards/arm/nucleo_f070rb/nucleo_f070rb.dts index a72967e229c4..45069f138413 100644 --- a/boards/arm/nucleo_f070rb/nucleo_f070rb.dts +++ b/boards/arm/nucleo_f070rb/nucleo_f070rb.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics NUCLEO-F070RB board"; diff --git a/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi new file mode 100644 index 000000000000..0727b65bc252 --- /dev/null +++ b/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 8b35cf779470df5c4809ee67cdcc78c372c4abe4 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:49:26 +0200 Subject: [PATCH 0998/2042] boards: nucleo_f091rc: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f091rc/nucleo_f091rc.dts | 1 + .../nucleo_f091rc/st_morpho_connector.dtsi | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 boards/arm/nucleo_f091rc/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f091rc/nucleo_f091rc.dts b/boards/arm/nucleo_f091rc/nucleo_f091rc.dts index cd7882e5f3c5..c975ba202eba 100644 --- a/boards/arm/nucleo_f091rc/nucleo_f091rc.dts +++ b/boards/arm/nucleo_f091rc/nucleo_f091rc.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F091RC-NUCLEO board"; diff --git a/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi b/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi new file mode 100644 index 000000000000..354dab3052f2 --- /dev/null +++ b/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From bb80d85b1b9a1219ebd3f0a8ed8afb0cdcaf5f44 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:49:51 +0200 Subject: [PATCH 0999/2042] boards: nucleo_f103rb: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f103rb/nucleo_f103rb.dts | 1 + .../nucleo_f103rb/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_f103rb/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f103rb/nucleo_f103rb.dts b/boards/arm/nucleo_f103rb/nucleo_f103rb.dts index fc3ebb3152c8..9cae21bfef10 100644 --- a/boards/arm/nucleo_f103rb/nucleo_f103rb.dts +++ b/boards/arm/nucleo_f103rb/nucleo_f103rb.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F103RB-NUCLEO board"; diff --git a/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi new file mode 100644 index 000000000000..3bfb0315db3a --- /dev/null +++ b/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From d3220277c9c918db9bfee550aa8f5ae8365940db Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:50:13 +0200 Subject: [PATCH 1000/2042] boards: nucleo_f303re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f303re/nucleo_f303re.dts | 1 + .../nucleo_f303re/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_f303re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f303re/nucleo_f303re.dts b/boards/arm/nucleo_f303re/nucleo_f303re.dts index 4222c286b38f..95020a3f0733 100644 --- a/boards/arm/nucleo_f303re/nucleo_f303re.dts +++ b/boards/arm/nucleo_f303re/nucleo_f303re.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F303RE-NUCLEO board"; diff --git a/boards/arm/nucleo_f303re/st_morpho_connector.dtsi b/boards/arm/nucleo_f303re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..0727b65bc252 --- /dev/null +++ b/boards/arm/nucleo_f303re/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 1ac72b309353aac3cf88624312fe7dcd2e71f2e2 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:50:40 +0200 Subject: [PATCH 1001/2042] boards: nucleo_f334r8: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f334r8/nucleo_f334r8.dts | 1 + .../nucleo_f334r8/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_f334r8/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f334r8/nucleo_f334r8.dts b/boards/arm/nucleo_f334r8/nucleo_f334r8.dts index e8be87eae74d..83d8bd181494 100644 --- a/boards/arm/nucleo_f334r8/nucleo_f334r8.dts +++ b/boards/arm/nucleo_f334r8/nucleo_f334r8.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F334R8-NUCLEO board"; diff --git a/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi b/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi new file mode 100644 index 000000000000..0727b65bc252 --- /dev/null +++ b/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From e6960ea010b6531c2b07086ecfe869ef69e0ce07 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:51:05 +0200 Subject: [PATCH 1002/2042] boards: nucleo_f401re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f401re/nucleo_f401re.dts | 1 + .../nucleo_f401re/st_morpho_connector.dtsi | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 boards/arm/nucleo_f401re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f401re/nucleo_f401re.dts b/boards/arm/nucleo_f401re/nucleo_f401re.dts index 959c66b7e512..06039ac52329 100644 --- a/boards/arm/nucleo_f401re/nucleo_f401re.dts +++ b/boards/arm/nucleo_f401re/nucleo_f401re.dts @@ -9,6 +9,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F401RE-NUCLEO board"; diff --git a/boards/arm/nucleo_f401re/st_morpho_connector.dtsi b/boards/arm/nucleo_f401re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..2385545b7f28 --- /dev/null +++ b/boards/arm/nucleo_f401re/st_morpho_connector.dtsi @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 55c54bd421c1666f92629e117880a5ffd5ea93e5 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:51:54 +0200 Subject: [PATCH 1003/2042] boards: nucleo_f410rb: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f410rb/nucleo_f410rb.dts | 1 + .../nucleo_f410rb/st_morpho_connector.dtsi | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 boards/arm/nucleo_f410rb/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f410rb/nucleo_f410rb.dts b/boards/arm/nucleo_f410rb/nucleo_f410rb.dts index 65a27b46b584..c6024f4c2337 100644 --- a/boards/arm/nucleo_f410rb/nucleo_f410rb.dts +++ b/boards/arm/nucleo_f410rb/nucleo_f410rb.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F410RB-NUCLEO board"; diff --git a/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi new file mode 100644 index 000000000000..b4d0911921a7 --- /dev/null +++ b/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 5499a3102eb3bcf627ce0f1285c1ec2d53175524 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:52:14 +0200 Subject: [PATCH 1004/2042] boards: nucleo_f411re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f411re/nucleo_f411re.dts | 1 + .../nucleo_f411re/st_morpho_connector.dtsi | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 boards/arm/nucleo_f411re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f411re/nucleo_f411re.dts b/boards/arm/nucleo_f411re/nucleo_f411re.dts index dd5112862a00..1a9a3ef3b8cc 100644 --- a/boards/arm/nucleo_f411re/nucleo_f411re.dts +++ b/boards/arm/nucleo_f411re/nucleo_f411re.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F411RE-NUCLEO board"; diff --git a/boards/arm/nucleo_f411re/st_morpho_connector.dtsi b/boards/arm/nucleo_f411re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..2385545b7f28 --- /dev/null +++ b/boards/arm/nucleo_f411re/st_morpho_connector.dtsi @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From a6c4d7f919dc4e0ddcd43d93987f2c899275ed99 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:52:31 +0200 Subject: [PATCH 1005/2042] boards: nucleo_f446re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_f446re/nucleo_f446re.dts | 1 + .../nucleo_f446re/st_morpho_connector.dtsi | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 boards/arm/nucleo_f446re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_f446re/nucleo_f446re.dts b/boards/arm/nucleo_f446re/nucleo_f446re.dts index ce5dc151228a..6e123424e5e7 100644 --- a/boards/arm/nucleo_f446re/nucleo_f446re.dts +++ b/boards/arm/nucleo_f446re/nucleo_f446re.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32F446RE-NUCLEO board"; diff --git a/boards/arm/nucleo_f446re/st_morpho_connector.dtsi b/boards/arm/nucleo_f446re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..2385545b7f28 --- /dev/null +++ b/boards/arm/nucleo_f446re/st_morpho_connector.dtsi @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From e6a51a92191381ec1a2be06659bf0ed34472d221 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:53:20 +0200 Subject: [PATCH 1006/2042] boards: nucleo_l053r8: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_l053r8/nucleo_l053r8.dts | 1 + .../nucleo_l053r8/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_l053r8/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_l053r8/nucleo_l053r8.dts b/boards/arm/nucleo_l053r8/nucleo_l053r8.dts index ffd16f75f594..480532f4bfd7 100644 --- a/boards/arm/nucleo_l053r8/nucleo_l053r8.dts +++ b/boards/arm/nucleo_l053r8/nucleo_l053r8.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32L053R8-NUCLEO board"; diff --git a/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi b/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi new file mode 100644 index 000000000000..30c9999389c2 --- /dev/null +++ b/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 4c87e60005a7db68d6511736a834a76f9f0fd896 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:53:31 +0200 Subject: [PATCH 1007/2042] boards: nucleo_l073rz: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_l073rz/nucleo_l073rz.dts | 1 + .../nucleo_l073rz/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_l073rz/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts index 63d672f7dd0e..c35da231f808 100644 --- a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32L073RZ-NUCLEO board"; diff --git a/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi b/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi new file mode 100644 index 000000000000..30c9999389c2 --- /dev/null +++ b/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From be6853d9cc266ba563ed8452b32c4bf08c45df89 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:54:21 +0200 Subject: [PATCH 1008/2042] boards: nucleo_l152re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_l152re/nucleo_l152re.dts | 1 + .../nucleo_l152re/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_l152re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_l152re/nucleo_l152re.dts b/boards/arm/nucleo_l152re/nucleo_l152re.dts index 23aad047b4be..527591b6d5d6 100644 --- a/boards/arm/nucleo_l152re/nucleo_l152re.dts +++ b/boards/arm/nucleo_l152re/nucleo_l152re.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32L152RE-NUCLEO board"; diff --git a/boards/arm/nucleo_l152re/st_morpho_connector.dtsi b/boards/arm/nucleo_l152re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..30c9999389c2 --- /dev/null +++ b/boards/arm/nucleo_l152re/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 17ef81c60e0b18d9b35eb5732e0297ee84297c1e Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:54:45 +0200 Subject: [PATCH 1009/2042] boards: nucleo_l452re: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_l452re/nucleo_l452re.dts | 1 + .../nucleo_l452re/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_l452re/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_l452re/nucleo_l452re.dts b/boards/arm/nucleo_l452re/nucleo_l452re.dts index 5dbac905201d..73f8ec9a09f7 100644 --- a/boards/arm/nucleo_l452re/nucleo_l452re.dts +++ b/boards/arm/nucleo_l452re/nucleo_l452re.dts @@ -9,6 +9,7 @@ #include "nucleo_l452re_common.dtsi" #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32L452RE-NUCLEO board"; diff --git a/boards/arm/nucleo_l452re/st_morpho_connector.dtsi b/boards/arm/nucleo_l452re/st_morpho_connector.dtsi new file mode 100644 index 000000000000..30c9999389c2 --- /dev/null +++ b/boards/arm/nucleo_l452re/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From 652d9a5b0adc4bbf22d591a26181552b3e198981 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Mon, 26 Jun 2023 12:56:14 +0200 Subject: [PATCH 1010/2042] boards: nucleo_l476rg: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- boards/arm/nucleo_l476rg/nucleo_l476rg.dts | 1 + .../nucleo_l476rg/st_morpho_connector.dtsi | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 boards/arm/nucleo_l476rg/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts index 7104b0d9301f..f2ae533fa73d 100644 --- a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts +++ b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { model = "STMicroelectronics STM32L476RG-NUCLEO board"; diff --git a/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi b/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi new file mode 100644 index 000000000000..30c9999389c2 --- /dev/null +++ b/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; From b95cdb2a334b380a384be6d1fd042c8312f346b9 Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Mon, 22 May 2023 14:29:23 +0000 Subject: [PATCH 1011/2042] drivers: serial: stm32: add support for RS485 configuration The stm32 UART can output a "driver enable" signal on the RTS pin that allows controlling e.g. external RS-485 drivers. This can already be configured through the devicetree using the `de-*` properties, but not through uart_configure(). This commit enables the use of .flow_ctrl=UART_CFG_FLOW_CTRL_RS485. This is supported on all devices other than l1, f1, f2, and f4 as found by this search: $ grep -rLw USART_CR3_DEM ../modules/hal/stm32/stm32cube/*/soc/*.h |\ grep -vE 'system_|partition_|stm32[^0-9]+[0-9]?xx\.h' |\ cut -d/ -f6 |\ sort -u Signed-off-by: Armin Brauns --- drivers/serial/uart_stm32.c | 67 ++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 004679b50116..45a16e9e8931 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -56,6 +56,13 @@ LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL); #define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \ st_stm32_lpuart, okay)) +/* Available everywhere except l1, f1, f2, f4. */ +#ifdef USART_CR3_DEM +#define HAS_DRIVER_ENABLE 1 +#else +#define HAS_DRIVER_ENABLE 0 +#endif + #if HAS_LPUART_1 #ifdef USART_PRESC_PRESCALER uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint16_t presc_idx, @@ -256,6 +263,27 @@ static inline uint32_t uart_stm32_get_hwctrl(const struct device *dev) return LL_USART_GetHWFlowCtrl(config->usart); } +#if HAS_DRIVER_ENABLE +static inline void uart_stm32_set_driver_enable(const struct device *dev, + bool driver_enable) +{ + const struct uart_stm32_config *config = dev->config; + + if (driver_enable) { + LL_USART_EnableDEMode(config->usart); + } else { + LL_USART_DisableDEMode(config->usart); + } +} + +static inline bool uart_stm32_get_driver_enable(const struct device *dev) +{ + const struct uart_stm32_config *config = dev->config; + + return LL_USART_IsEnabledDEMode(config->usart); +} +#endif + static inline uint32_t uart_stm32_cfg2ll_parity(enum uart_config_parity parity) { switch (parity) { @@ -388,7 +416,7 @@ static inline enum uart_config_data_bits uart_stm32_ll2cfg_databits(uint32_t db, /** * @brief Get LL hardware flow control define from * Zephyr hardware flow control option. - * @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS. + * @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS and UART_CFG_FLOW_CTRL_RS485. * @param fc: Zephyr hardware flow control option. * @retval LL_USART_HWCONTROL_RTS_CTS, or LL_USART_HWCONTROL_NONE. */ @@ -396,6 +424,9 @@ static inline uint32_t uart_stm32_cfg2ll_hwctrl(enum uart_config_flow_control fc { if (fc == UART_CFG_FLOW_CTRL_RTS_CTS) { return LL_USART_HWCONTROL_RTS_CTS; + } else if (fc == UART_CFG_FLOW_CTRL_RS485) { + /* Driver Enable is handled separately */ + return LL_USART_HWCONTROL_NONE; } return LL_USART_HWCONTROL_NONE; @@ -428,6 +459,9 @@ static int uart_stm32_configure(const struct device *dev, const uint32_t databits = uart_stm32_cfg2ll_databits(cfg->data_bits, cfg->parity); const uint32_t flowctrl = uart_stm32_cfg2ll_hwctrl(cfg->flow_ctrl); +#if HAS_DRIVER_ENABLE + bool driver_enable = cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485; +#endif /* Hardware doesn't support mark or space parity */ if ((cfg->parity == UART_CFG_PARITY_MARK) || @@ -473,12 +507,16 @@ static int uart_stm32_configure(const struct device *dev, return -ENOTSUP; } - /* Driver supports only RTS CTS flow control */ - if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { - if (!IS_UART_HWFLOW_INSTANCE(config->usart) || - UART_CFG_FLOW_CTRL_RTS_CTS != cfg->flow_ctrl) { - return -ENOTSUP; - } + /* Driver supports only RTS/CTS and RS485 flow control */ + if (!(cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE + || (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS && + IS_UART_HWFLOW_INSTANCE(config->usart)) +#if HAS_DRIVER_ENABLE + || (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485 && + IS_UART_DRIVER_ENABLE_INSTANCE(config->usart)) +#endif + )) { + return -ENOTSUP; } LL_USART_Disable(config->usart); @@ -499,6 +537,12 @@ static int uart_stm32_configure(const struct device *dev, uart_stm32_set_hwctrl(dev, flowctrl); } +#if HAS_DRIVER_ENABLE + if (driver_enable != uart_stm32_get_driver_enable(dev)) { + uart_stm32_set_driver_enable(dev, driver_enable); + } +#endif + if (cfg->baudrate != data->baud_rate) { uart_stm32_set_baudrate(dev, cfg->baudrate); data->baud_rate = cfg->baudrate; @@ -521,6 +565,11 @@ static int uart_stm32_config_get(const struct device *dev, uart_stm32_get_databits(dev), uart_stm32_get_parity(dev)); cfg->flow_ctrl = uart_stm32_ll2cfg_hwctrl( uart_stm32_get_hwctrl(dev)); +#if HAS_DRIVER_ENABLE + if (uart_stm32_get_driver_enable(dev)) { + cfg->flow_ctrl = UART_CFG_FLOW_CTRL_RS485; + } +#endif return 0; } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ @@ -1705,14 +1754,14 @@ static int uart_stm32_init(const struct device *dev) } #endif -#ifdef USART_CR3_DEM +#if HAS_DRIVER_ENABLE if (config->de_enable) { if (!IS_UART_DRIVER_ENABLE_INSTANCE(config->usart)) { LOG_ERR("%s does not support driver enable", dev->name); return -EINVAL; } - LL_USART_EnableDEMode(config->usart); + uart_stm32_set_driver_enable(dev, true); LL_USART_SetDEAssertionTime(config->usart, config->de_assert_time); LL_USART_SetDEDeassertionTime(config->usart, config->de_deassert_time); From 5b44ebe1595a8d4a46f5721271557d4159498673 Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Mon, 3 Jul 2023 13:45:30 +0200 Subject: [PATCH 1012/2042] bluetooth: host: smp: Add bondable flag overlay per connection The current API for changing the bondable mode uses the global flag. With Zephyr support for multiple Bluetooth identities, the API for changing the bondable mode should be more fine-grained. The bondable requirements of one identity should not have an impact on another identity which can have a different set of requirements. This change introduces function to overlay bondable flag per connection. Signed-off-by: Mateusz Kapala --- include/zephyr/bluetooth/conn.h | 20 +++++++++++++++++ subsys/bluetooth/host/Kconfig | 7 ++++++ subsys/bluetooth/host/smp.c | 38 +++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 81a96937b08e..5487e3e2cfeb 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1082,6 +1082,26 @@ void bt_conn_cb_register(struct bt_conn_cb *cb); */ void bt_set_bondable(bool enable); +/** @brief Set/clear the bonding flag for a given connection. + * + * Set/clear the Bonding flag in the Authentication Requirements of + * SMP Pairing Request/Response data for a given connection. + * + * The bonding flag for a given connection cannot be set/cleared if + * security procedures in the SMP module have already started. + * This function can be called only once per connection. + * + * If the bonding flag is not set/cleared for a given connection, + * the value will depend on global configuration which is set using + * bt_set_bondable. + * The default value of the global configuration is defined using + * CONFIG_BT_BONDABLE Kconfig option. + * + * @param conn Connection object. + * @param enable Value allowing/disallowing to be bondable. + */ +int bt_conn_set_bondable(struct bt_conn *conn, bool enable); + /** @brief Allow/disallow remote LE SC OOB data to be used for pairing. * * Set/clear the OOB data flag for LE SC SMP Pairing Request/Response data. diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index ae91baf884a0..00ed7718a321 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -600,6 +600,13 @@ config BT_BONDING_REQUIRED set the bondable flag in their pairing request. Any other kind of requests will be rejected. +config BT_BONDABLE_PER_CONNECTION + bool "Set/clear the bonding flag per-connection [EXPERIMENTAL]" + select EXPERIMENTAL + help + Enable support for the bt_conn_set_bondable API function that is + used to set/clear the bonding flag on a per-connection basis. + config BT_STORE_DEBUG_KEYS bool "Store Debug Mode bonds" help diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 9b40910cb304..86fbd723cd57 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -209,6 +209,9 @@ struct bt_smp { /* Used Bluetooth authentication callbacks. */ atomic_ptr_t auth_cb; + + /* Bondable flag */ + atomic_t bondable; }; static unsigned int fixed_passkey = BT_PASSKEY_INVALID; @@ -288,6 +291,11 @@ static K_SEM_DEFINE(sc_local_pkey_ready, 0, 1); */ #define BT_SMP_AUTH_CB_UNINITIALIZED ((atomic_ptr_val_t)bt_smp_pool) +/* Value used to mark that per-connection bondable flag is not initialized. + * Value false/true represent if flag is cleared or set and cannot be used for that purpose. + */ +#define BT_SMP_BONDABLE_UNINITIALIZED ((atomic_val_t)-1) + static bool le_sc_supported(void) { /* @@ -310,6 +318,13 @@ static const struct bt_conn_auth_cb *latch_auth_cb(struct bt_smp *smp) return atomic_ptr_get(&smp->auth_cb); } +static bool latch_bondable(struct bt_smp *smp) +{ + atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)bondable); + + return atomic_get(&smp->bondable); +} + static uint8_t get_io_capa(struct bt_smp *smp) { const struct bt_conn_auth_cb *smp_auth_cb = latch_auth_cb(smp); @@ -2592,7 +2607,7 @@ static uint8_t get_auth(struct bt_smp *smp, uint8_t auth) auth |= BT_SMP_AUTH_MITM; } - if (bondable) { + if (latch_bondable(smp)) { auth |= BT_SMP_AUTH_BONDING; } else { auth &= ~BT_SMP_AUTH_BONDING; @@ -3977,7 +3992,7 @@ static uint8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf) } if (IS_ENABLED(CONFIG_BT_BONDING_REQUIRED) && - !(bondable && (auth & BT_SMP_AUTH_BONDING))) { + !(latch_bondable(smp) && (auth & BT_SMP_AUTH_BONDING))) { /* Reject security req if not both intend to bond */ LOG_DBG("Bonding required"); return BT_SMP_ERR_UNSPECIFIED; @@ -4541,6 +4556,7 @@ static void bt_smp_connected(struct bt_l2cap_chan *chan) smp_reset(smp); atomic_ptr_set(&smp->auth_cb, BT_SMP_AUTH_CB_UNINITIALIZED); + atomic_set(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED); } static void bt_smp_disconnected(struct bt_l2cap_chan *chan) @@ -5291,6 +5307,24 @@ static inline int smp_self_test(void) } #endif +#if defined(CONFIG_BT_BONDABLE_PER_CONNECTION) +int bt_conn_set_bondable(struct bt_conn *conn, bool enable) +{ + struct bt_smp *smp; + + smp = smp_chan_get(conn); + if (!smp) { + return -EINVAL; + } + + if (atomic_cas(&smp->bondable, BT_SMP_BONDABLE_UNINITIALIZED, (atomic_val_t)enable)) { + return 0; + } else { + return -EALREADY; + } +} +#endif + int bt_smp_auth_cb_overlay(struct bt_conn *conn, const struct bt_conn_auth_cb *cb) { struct bt_smp *smp; From 8e5673ccd19230a7de50978b0fdc037772607692 Mon Sep 17 00:00:00 2001 From: Mateusz Kapala Date: Wed, 5 Jul 2023 14:09:58 +0200 Subject: [PATCH 1013/2042] bluetooth: tests: Add bsim test for setting bondable flag per-conn Added test for the bt_conn_set_bondable API function. Check if we can pair without setting the bonding flag on the per-connection basis if the device was already bonded on the other identity. Signed-off-by: Mateusz Kapala --- tests/bsim/bluetooth/host/compile.sh | 1 + .../bond_per_connection/CMakeLists.txt | 18 ++ .../security/bond_per_connection/prj.conf | 17 ++ .../bond_per_connection/src/bs_bt_utils.c | 209 ++++++++++++++++++ .../bond_per_connection/src/bs_bt_utils.h | 85 +++++++ .../bond_per_connection/src/central.c | 55 +++++ .../security/bond_per_connection/src/main.c | 40 ++++ .../bond_per_connection/src/peripheral.c | 56 +++++ .../test_scripts/_compile.sh | 20 ++ .../bond_per_connection/test_scripts/_env.sh | 30 +++ .../test_scripts/run_test.sh | 25 +++ 11 files changed, 556 insertions(+) create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/CMakeLists.txt create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/prj.conf create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.c create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.h create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/src/central.c create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/src/main.c create mode 100644 tests/bsim/bluetooth/host/security/bond_per_connection/src/peripheral.c create mode 100755 tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_compile.sh create mode 100755 tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_env.sh create mode 100755 tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/run_test.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index aa12780f2d83..dd5ef2347188 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -65,6 +65,7 @@ app=tests/bsim/bluetooth/host/privacy/legacy compile app=tests/bsim/bluetooth/host/security/bond_overwrite_allowed compile app=tests/bsim/bluetooth/host/security/bond_overwrite_denied compile +app=tests/bsim/bluetooth/host/security/bond_per_connection compile app=tests/bsim/bluetooth/host/security/ccc_update compile app=tests/bsim/bluetooth/host/security/ccc_update conf_file=prj_2.conf compile diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/CMakeLists.txt b/tests/bsim/bluetooth/host/security/bond_per_connection/CMakeLists.txt new file mode 100644 index 000000000000..2fa69bf185ff --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/CMakeLists.txt @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_multi_id_bond_per_connection) + +target_sources(app PRIVATE + src/bs_bt_utils.c + src/central.c + src/main.c + src/peripheral.c +) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/prj.conf b/tests/bsim/bluetooth/host/security/bond_per_connection/prj.conf new file mode 100644 index 000000000000..afa7d4490392 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/prj.conf @@ -0,0 +1,17 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y + +CONFIG_BT_SMP=y + +CONFIG_ASSERT=y +CONFIG_BT_TESTING=y +CONFIG_LOG=y + +CONFIG_BT_ID_MAX=3 +CONFIG_BT_MAX_PAIRED=2 +CONFIG_BT_MAX_CONN=1 + +CONFIG_BT_PRIVACY=y + +CONFIG_BT_BONDABLE_PER_CONNECTION=y diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.c b/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.c new file mode 100644 index 000000000000..1523e10d8a5a --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" + +BUILD_ASSERT(CONFIG_BT_MAX_PAIRED >= 2, "CONFIG_BT_MAX_PAIRED is too small."); +BUILD_ASSERT(CONFIG_BT_ID_MAX >= 3, "CONFIG_BT_ID_MAX is too small."); + +#define BS_SECONDS(dur_sec) ((bs_time_t)dur_sec * 1000000) +#define TEST_TIMEOUT_SIMULATED BS_SECONDS(60) + +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; +} + +DEFINE_FLAG(flag_is_connected); +struct bt_conn *g_conn; +DEFINE_FLAG(bondable); +DEFINE_FLAG(call_bt_conn_set_bondable); + +void wait_connected(void) +{ + WAIT_FOR_FLAG(flag_is_connected); +} + +void wait_disconnected(void) +{ + WAIT_FOR_FLAG_UNSET(flag_is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + UNSET_FLAG(flag_is_connected); +} + +BUILD_ASSERT(CONFIG_BT_MAX_CONN == 1, "This test assumes a single link."); +static void connected(struct bt_conn *conn, uint8_t err) +{ + ASSERT((!g_conn || (conn == g_conn)), "Unexpected new connection."); + + if (!g_conn) { + g_conn = bt_conn_ref(conn); + } + + if (err != 0) { + clear_g_conn(); + return; + } + + SET_FLAG(flag_is_connected); + + if (GET_FLAG(call_bt_conn_set_bondable) && bt_conn_set_bondable(conn, GET_FLAG(bondable))) { + ASSERT(0, "Fail during setting bondable flag for given connection."); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +void clear_g_conn(void) +{ + struct bt_conn *conn; + + conn = g_conn; + g_conn = NULL; + ASSERT(conn, "Test error: No g_conn!\n"); + bt_conn_unref(conn); +} + +/* The following flags are raised by events and lowered by test code. */ +DEFINE_FLAG(flag_pairing_complete); +DEFINE_FLAG(flag_bonded); +DEFINE_FLAG(flag_not_bonded); + +static void pairing_complete(struct bt_conn *conn, bool bonded) +{ + SET_FLAG(flag_pairing_complete); + + if (bonded) { + SET_FLAG(flag_bonded); + } else { + SET_FLAG(flag_not_bonded); + } +} + +static struct bt_conn_auth_info_cb bt_conn_auth_info_cb = { + .pairing_complete = pairing_complete, +}; + +void bs_bt_utils_setup(void) +{ + int err; + + err = bt_enable(NULL); + ASSERT(!err, "bt_enable failed.\n"); + err = bt_conn_auth_info_cb_register(&bt_conn_auth_info_cb); + ASSERT(!err, "bt_conn_auth_info_cb_register failed.\n"); +} + +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) +{ + 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) { + FAIL("Unexpected advertisement type."); + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Got scan result, connecting.. dst %s, RSSI %d\n", addr_str, rssi); + + err = bt_le_scan_stop(); + ASSERT(!err, "Err bt_le_scan_stop %d", err); + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &g_conn); + ASSERT(!err, "Err bt_conn_le_create %d", err); +} + +void scan_connect_to_first_result(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, scan_connect_to_first_result__device_found); + ASSERT(!err, "Err bt_le_scan_start %d", err); +} + +void disconnect(void) +{ + int err; + + err = bt_conn_disconnect(g_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + ASSERT(!err, "Err bt_conn_disconnect %d", err); +} + +void unpair(int id) +{ + int err; + + err = bt_unpair(id, BT_ADDR_LE_ANY); + ASSERT(!err, "Err bt_unpair %d", err); +} + +void set_security(bt_security_t sec) +{ + int err; + + err = bt_conn_set_security(g_conn, sec); + ASSERT(!err, "Err bt_conn_set_security %d", err); +} + +void advertise_connectable(int id, bt_addr_le_t *directed_dst) +{ + int err; + struct bt_le_adv_param param = {}; + + param.id = id; + param.interval_min = 0x0020; + param.interval_max = 0x4000; + param.options |= BT_LE_ADV_OPT_ONE_TIME; + param.options |= BT_LE_ADV_OPT_CONNECTABLE; + + if (directed_dst) { + param.options |= BT_LE_ADV_OPT_DIR_ADDR_RPA; + param.peer = directed_dst; + } + + err = bt_le_adv_start(¶m, NULL, 0, NULL, 0); + ASSERT(err == 0, "Advertising failed to start (err %d)\n", err); +} + +void set_bondable(bool enable) +{ + if (enable) { + SET_FLAG(bondable); + } else { + UNSET_FLAG(bondable); + } +} + +void enable_bt_conn_set_bondable(bool enable) +{ + if (enable) { + SET_FLAG(call_bt_conn_set_bondable); + } else { + UNSET_FLAG(call_bt_conn_set_bondable); + } +} diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.h b/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.h new file mode 100644 index 000000000000..fc440c6bec86 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/src/bs_bt_utils.h @@ -0,0 +1,85 @@ +/** + * Common functions and helpers for BSIM GATT tests + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_tracing.h" +#include "bs_types.h" +#include "bstests.h" +#include "time_machine.h" +#include "zephyr/sys/__assert.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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 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 TAKE_FLAG(flag) \ + while (!(bool)atomic_cas(&flag, true, false)) { \ + (void)k_sleep(K_MSEC(1)); \ + } +#define GET_FLAG(flag) \ + (bool)atomic_get(&flag) + +#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) + +void test_tick(bs_time_t HW_device_time); +void test_init(void); + +DECLARE_FLAG(flag_pairing_complete); +DECLARE_FLAG(flag_bonded); +DECLARE_FLAG(flag_not_bonded); + +extern struct bt_conn *g_conn; +void wait_connected(void); +void wait_disconnected(void); +void clear_g_conn(void); +void bs_bt_utils_setup(void); +void scan_connect_to_first_result(void); +void disconnect(void); +void unpair(int id); +void set_security(bt_security_t sec); +void advertise_connectable(int id, bt_addr_le_t *directed_dst); +void set_bondable(bool enable); +void enable_bt_conn_set_bondable(bool enable); diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/src/central.c b/tests/bsim/bluetooth/host/security/bond_per_connection/src/central.c new file mode 100644 index 000000000000..f31261b68c09 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/src/central.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "zephyr/bluetooth/addr.h" +#include "zephyr/bluetooth/conn.h" + +#include + +#include + +void central(void) +{ + bs_bt_utils_setup(); + + printk("== Bonding id a - global bondable mode ==\n"); + BUILD_ASSERT(CONFIG_BT_BONDABLE, "CONFIG_BT_BONDABLE must be enabled by default."); + enable_bt_conn_set_bondable(false); + scan_connect_to_first_result(); + wait_connected(); + set_security(BT_SECURITY_L2); + TAKE_FLAG(flag_pairing_complete); + TAKE_FLAG(flag_bonded); + disconnect(); + wait_disconnected(); + unpair(BT_ID_DEFAULT); + clear_g_conn(); + + printk("== Bonding id a - bond per-connection ==\n"); + enable_bt_conn_set_bondable(true); + set_bondable(true); + scan_connect_to_first_result(); + wait_connected(); + set_security(BT_SECURITY_L2); + TAKE_FLAG(flag_pairing_complete); + TAKE_FLAG(flag_bonded); + disconnect(); + wait_disconnected(); + clear_g_conn(); + + printk("== Bonding id b - bond per-connection ==\n"); + scan_connect_to_first_result(); + wait_connected(); + set_security(BT_SECURITY_L2); + TAKE_FLAG(flag_pairing_complete); + TAKE_FLAG(flag_not_bonded); + disconnect(); + wait_disconnected(); + clear_g_conn(); + + PASS("PASS\n"); +} diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/src/main.c b/tests/bsim/bluetooth/host/security/bond_per_connection/src/main.c new file mode 100644 index 000000000000..7553f7b5f836 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/src/main.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "bstests.h" + +void central(void); +void peripheral(void); + +static const struct bst_test_instance test_to_add[] = { + { + .test_id = "central", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = central, + }, + { + .test_id = "peripheral", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = peripheral, + }, + 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/security/bond_per_connection/src/peripheral.c b/tests/bsim/bluetooth/host/security/bond_per_connection/src/peripheral.c new file mode 100644 index 000000000000..5e11d6ac712f --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/src/peripheral.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_bt_utils.h" +#include "zephyr/bluetooth/addr.h" +#include "zephyr/bluetooth/bluetooth.h" +#include "zephyr/bluetooth/conn.h" +#include "zephyr/toolchain/gcc.h" + +#include +#include + +void peripheral(void) +{ + bs_bt_utils_setup(); + + int id_a; + int id_b; + + id_a = bt_id_create(NULL, NULL); + ASSERT(id_a >= 0, "bt_id_create id_a failed (err %d)\n", id_a); + + id_b = bt_id_create(NULL, NULL); + ASSERT(id_b >= 0, "bt_id_create id_b failed (err %d)\n", id_b); + + printk("== Bonding id a - global bondable mode ==\n"); + BUILD_ASSERT(CONFIG_BT_BONDABLE, "CONFIG_BT_BONDABLE must be enabled by default."); + enable_bt_conn_set_bondable(false); + advertise_connectable(id_a, NULL); + wait_connected(); + /* Central should bond here and trigger a disconnect. */ + wait_disconnected(); + unpair(id_a); + clear_g_conn(); + + printk("== Bonding id a - bond per-connection true ==\n"); + enable_bt_conn_set_bondable(true); + set_bondable(true); + advertise_connectable(id_a, NULL); + wait_connected(); + /* Central should bond here and trigger a disconnect. */ + wait_disconnected(); + clear_g_conn(); + + printk("== Bonding id b - bond per-connection false ==\n"); + set_bondable(false); + advertise_connectable(id_b, NULL); + wait_connected(); + /* Central should pair without bond here and trigger a disconnect. */ + wait_disconnected(); + + PASS("PASS\n"); +} diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_compile.sh b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_compile.sh new file mode 100755 index 000000000000..f03de68b83f3 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_compile.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +# Read variable definitions output by _env.sh +source "${bash_source_dir}/_env.sh" + +: "${BSIM_COMPONENTS_PATH:?BSIM_COMPONENTS_PATH must be defined}" +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" + +WORK_DIR="${WORK_DIR:-${ZEPHYR_BASE}/bsim_out}" +BOARD="${BOARD:-nrf52_bsim}" +BOARD_ROOT="${BOARD_ROOT:-${ZEPHYR_BASE}}" +INCR_BUILD=1 +mkdir -p ${WORK_DIR} +source ${ZEPHYR_BASE}/tests/bsim/compile.source +app="tests/bsim/bluetooth/$test_name" compile diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_env.sh b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_env.sh new file mode 100755 index 000000000000..173f0d2eedfc --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/_env.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +: "${BSIM_OUT_PATH:?BSIM_OUT_PATH must be defined}" + +test_name="security_bond_per_connection" +bsim_bin="${BSIM_OUT_PATH}/bin" +verbosity_level=2 +BOARD="${BOARD:-nrf52_bsim}" +simulation_id="$test_name" +central_exe="${bsim_bin}/bs_${BOARD}_tests_bsim_bluetooth_host_${test_name}_prj_conf" +peripheral_exe="${central_exe}" + +function print_var { + # Print a shell-sourceable variable definition. + local var_name="$1" + local var_repr="${!var_name@Q}" + echo "$var_name=$var_repr" +} + +print_var test_name +print_var bsim_bin +print_var verbosity_level +print_var BOARD +print_var simulation_id +print_var central_exe +print_var peripheral_exe diff --git a/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/run_test.sh new file mode 100755 index 000000000000..351f44523cc1 --- /dev/null +++ b/tests/bsim/bluetooth/host/security/bond_per_connection/test_scripts/run_test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set -eu +bash_source_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +# Read variable definitions output by _env.sh +source "${bash_source_dir}/_env.sh" +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +EXECUTE_TIMEOUT=30 + +cd ${BSIM_OUT_PATH}/bin + +Execute "$central_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central -RealEncryption=1 + +Execute "$peripheral_exe" \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral -RealEncryption=1 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=60e6 $@ + +wait_for_background_jobs From abd90085ac24dcb6e4e6ce3bd84d7692de76cbbc Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Thu, 6 Jul 2023 13:32:27 +0200 Subject: [PATCH 1014/2042] soc: arm: nrf53: workaround pop lr after wfi crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On nRF5340 net core it was observed that when `wfi` instruction was followed by `pop {r0, lr}` in the `arch_cpu_idle` function, the value of `lr` sometimes got read as 0 from memory despite having correct value stored in the memory. This commit inserts additional `nop` instruction after waking up to delay access to the memory. Signed-off-by: Andrzej Kuroś --- arch/arm/Kconfig | 16 ++++++++++++++++ arch/arm/core/aarch32/cpu_idle.S | 9 +++++++++ soc/arm/nordic_nrf/nrf53/Kconfig.soc | 1 + soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ec82b1e50ee1..e17cf3f9b310 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -53,6 +53,22 @@ config ARM_ON_ENTER_CPU_IDLE_HOOK If needed, this hook can be used to prevent the CPU from actually entering sleep by skipping the WFE/WFI instruction. +config ARM_ON_EXIT_CPU_IDLE + bool + help + Enables a possibility to inject SoC-specific code just after WFI/WFE + instructions of the cpu idle implementation. + + Enabling this option requires that the SoC provides a soc_cpu_idle.h + header file which defines SOC_ON_EXIT_CPU_IDLE macro guarded by + _ASMLANGUAGE. + + The SOC_ON_EXIT_CPU_IDLE macro is expanded just after + WFI/WFE instructions before any memory access is performed. The purpose + of the SOC_ON_EXIT_CPU_IDLE is to perform an action that mitigate issues + observed on some SoCs caused by a memory access following WFI/WFE + instructions. + rsource "core/aarch32/Kconfig" rsource "core/aarch32/Kconfig.vfp" diff --git a/arch/arm/core/aarch32/cpu_idle.S b/arch/arm/core/aarch32/cpu_idle.S index 90f51f476b56..8164959ab291 100644 --- a/arch/arm/core/aarch32/cpu_idle.S +++ b/arch/arm/core/aarch32/cpu_idle.S @@ -13,6 +13,10 @@ #include #include +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) +#include +#endif + _ASM_FILE_PROLOGUE GTEXT(z_arm_cpu_idle_init) @@ -64,6 +68,11 @@ SECTION_FUNC(TEXT, z_arm_cpu_idle_init) dsb \wait_instruction +#if defined(CONFIG_ARM_ON_EXIT_CPU_IDLE) + /* Inline the macro provided by SoC-specific code */ + SOC_ON_EXIT_CPU_IDLE +#endif /* CONFIG_ARM_ON_EXIT_CPU_IDLE */ + #if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK) _skip_\@: #if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 967376088004..67cb8a08a6f7 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -13,6 +13,7 @@ config SOC_NRF5340_CPUAPP config SOC_NRF5340_CPUNET bool select HAS_NO_PM + select ARM_ON_EXIT_CPU_IDLE imply SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED choice diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h new file mode 100644 index 000000000000..b6cd92ca092a --- /dev/null +++ b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC extensions of cpu_idle.S for the Nordic Semiconductor nRF53 processors family. + */ + + +#if defined(_ASMLANGUAGE) + +#define SOC_ON_EXIT_CPU_IDLE \ + nop; \ + nop; \ + nop; \ + nop; + +#endif /* _ASMLANGUAGE */ From e9721db183823b35040cc9fda4e01c3896c5869e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 5 Jul 2023 16:45:38 +0200 Subject: [PATCH 1015/2042] native_simulator: Align with upstream latest with more trampolines Upstream SHA: be3eac6931b49291e51da5d5aa1a99ab58f81541 Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/Makefile | 2 + .../common/src/include/nsi_host_trampolines.h | 10 ++++ .../common/src/nsi_host_trampolines.c | 53 +++++++++++++++++++ .../native_simulator/common/src/nsi_tasks.h | 2 +- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/scripts/native_simulator/Makefile b/scripts/native_simulator/Makefile index 5dc9b409e1f0..6684c9389454 100644 --- a/scripts/native_simulator/Makefile +++ b/scripts/native_simulator/Makefile @@ -10,6 +10,8 @@ NSI_CONFIG_FILE?=nsi_config -include ${NSI_CONFIG_FILE} +#If the file does not exist, we don't use it as a build dependency +NSI_CONFIG_FILE:=$(wildcard ${NSI_CONFIG_FILE}) NSI_PATH?=./ NSI_BUILD_PATH?=$(abspath _build/) 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 53eff33bc99f..f7f7dce877df 100644 --- a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h +++ b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h @@ -22,10 +22,20 @@ extern "C" { #endif +void *nsi_host_calloc(unsigned long nmemb, unsigned long size); +int nsi_host_close(int fd); /* void nsi_host_exit (int status); Use nsi_exit() instead */ +void nsi_host_free(void *ptr); +char *nsi_host_getcwd(char *buf, unsigned long size); +int nsi_host_isatty(int fd); +void *nsi_host_malloc(unsigned long size); +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_srandom(unsigned int seed); +char *nsi_host_strdup(const char *s); +long nsi_host_write(int fd, void *buffer, unsigned long size); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/nsi_host_trampolines.c b/scripts/native_simulator/common/src/nsi_host_trampolines.c index d35dce407590..3feb8482c913 100644 --- a/scripts/native_simulator/common/src/nsi_host_trampolines.c +++ b/scripts/native_simulator/common/src/nsi_host_trampolines.c @@ -7,13 +7,66 @@ */ #include +#include +#include +#include + +void *nsi_host_calloc(unsigned long nmemb, unsigned long size) +{ + return calloc(nmemb, size); +} + +int nsi_host_close(int fd) +{ + return close(fd); +} + +void nsi_host_free(void *ptr) +{ + free(ptr); +} + +char *nsi_host_getcwd(char *buf, unsigned long size) +{ + return getcwd(buf, size); +} + +int nsi_host_isatty(int fd) +{ + return isatty(fd); +} + +void *nsi_host_malloc(unsigned long size) +{ + return malloc(size); +} + +int nsi_host_open(const char *pathname, int flags) +{ + return open(pathname, flags); +} long nsi_host_random(void) { return random(); } +long nsi_host_read(int fd, void *buffer, unsigned long size) +{ + return read(fd, buffer, size); +} + void nsi_host_srandom(unsigned int seed) { srandom(seed); } + +char *nsi_host_strdup(const char *s) +{ + return strdup(s); +} + +long nsi_host_write(int fd, void *buffer, unsigned long size) +{ + return write(fd, buffer, size); +} diff --git a/scripts/native_simulator/common/src/nsi_tasks.h b/scripts/native_simulator/common/src/nsi_tasks.h index ee98ba5ddc10..f3d4ec08ae22 100644 --- a/scripts/native_simulator/common/src/nsi_tasks.h +++ b/scripts/native_simulator/common/src/nsi_tasks.h @@ -42,7 +42,7 @@ extern "C" { * The function must take no parameters and return nothing. */ #define NSI_TASK(fn, level, prio) \ - static void (* const NSI_CONCAT(__nsi_task_, fn))() \ + static void (* const NSI_CONCAT(__nsi_task_, fn))(void) \ __attribute__((__used__)) \ __attribute__((__section__(".nsi_" #level NSI_STRINGIFY(prio) "_task")))\ = fn From 265010a4b6001d93896cabf43ae29b6ab1b3fcc1 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 6 Jul 2023 14:05:46 +0200 Subject: [PATCH 1016/2042] native boards: Make native simulator host trampolines avaliable to all To ease writing common drivers, let's make the host trampolines from the native simulator avaliable to all posix based boards. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/CMakeLists.txt | 1 + .../core/nsi_compat/nsi_host_trampolines.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 arch/posix/core/nsi_compat/nsi_host_trampolines.h diff --git a/arch/posix/core/CMakeLists.txt b/arch/posix/core/CMakeLists.txt index 23802715c1dd..4fbfb617949d 100644 --- a/arch/posix/core/CMakeLists.txt +++ b/arch/posix/core/CMakeLists.txt @@ -18,6 +18,7 @@ if(CONFIG_NATIVE_APPLICATION) posix_core.c nsi_compat/nsi_compat.c ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nce.c + ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nsi_host_trampolines.c ) else() zephyr_library_sources( diff --git a/arch/posix/core/nsi_compat/nsi_host_trampolines.h b/arch/posix/core/nsi_compat/nsi_host_trampolines.h new file mode 100644 index 000000000000..f0a2e06c1caa --- /dev/null +++ b/arch/posix/core/nsi_compat/nsi_host_trampolines.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Note: This is a provisional header which exists to allow + * old POSIX arch based boards (i.e. native_posix) to provide access + * to the host C library as if the native simulator trampolines + * existed. + * + * Boards based on the native simulator do NOT use this file + */ + +#ifndef ARCH_POSIX_CORE_NSI_COMPAT_NSI_HOST_TRAMPOLINES_H +#define ARCH_POSIX_CORE_NSI_COMPAT_NSI_HOST_TRAMPOLINES_H + +#include "../scripts/native_simulator/common/src/include/nsi_host_trampolines.h" + +#endif /* ARCH_POSIX_CORE_NSI_COMPAT_NSI_HOST_TRAMPOLINES_H */ From 8252e996088ec90a1d671880840bdea4d5781ee8 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 21 Jun 2023 14:46:00 +0200 Subject: [PATCH 1017/2042] drivers: entropy native: Refactor to support embedded libCs Refactor the host libC accesses to use the native simulator host trampolines. In this way we support building this driver with embedded libCs. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 2 +- drivers/entropy/Kconfig.native_posix | 1 - drivers/entropy/fake_entropy_native_posix.c | 5 +++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 2c4d53111c41..2f524829b721 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -109,7 +109,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, host libC 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`, host libC + 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`, host libC flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, host libC diff --git a/drivers/entropy/Kconfig.native_posix b/drivers/entropy/Kconfig.native_posix index ea31a5fbbf29..94fd73006705 100644 --- a/drivers/entropy/Kconfig.native_posix +++ b/drivers/entropy/Kconfig.native_posix @@ -4,7 +4,6 @@ config FAKE_ENTROPY_NATIVE_POSIX bool "Native posix entropy driver" default y depends on DT_HAS_ZEPHYR_NATIVE_POSIX_RNG_ENABLED - depends on EXTERNAL_LIBC select ENTROPY_HAS_DRIVER help This option enables the test random number generator for the diff --git a/drivers/entropy/fake_entropy_native_posix.c b/drivers/entropy/fake_entropy_native_posix.c index cccb66f90550..b39c07bbf305 100644 --- a/drivers/entropy/fake_entropy_native_posix.c +++ b/drivers/entropy/fake_entropy_native_posix.c @@ -22,6 +22,7 @@ #include #include "soc.h" #include "cmdline.h" /* native_posix command line options header */ +#include "nsi_host_trampolines.h" static unsigned int seed = 0x5678; @@ -36,7 +37,7 @@ static int entropy_native_posix_get_entropy(const struct device *dev, * Note that only 1 thread (Zephyr thread or HW models), runs at * a time, therefore there is no need to use random_r() */ - long int value = random(); + long value = nsi_host_random(); size_t to_copy = MIN(length, sizeof(long int)); @@ -64,7 +65,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); - srandom(seed); + nsi_host_srandom(seed); posix_print_warning("WARNING: " "Using a test - not safe - entropy source\n"); return 0; From d02a215a149e1241c413ee4866038399940e2dfa Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 30 Jun 2023 15:51:09 +0200 Subject: [PATCH 1018/2042] Bluetooth: BAP: Shell: Add support for TX retry when sending sine Modify lc3_audio_send_data to be triggered on a delayable k_work so that we can retry it with a delay if it fails for whatever reason. This also moves the calculation of the seq_num closer to when it is used, which makes sense as it is based on a timed calculation. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 36 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index fbf74f8f60b0..7e2eff7a298d 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -189,19 +189,17 @@ static int frame_duration_us; static int frame_duration_100us; static int frames_per_sdu; static int octets_per_frame; -static int64_t lc3_start_time; static int32_t lc3_sdu_cnt; static void lc3_audio_send_data(struct k_work *work); -static K_WORK_DEFINE(audio_send_work, lc3_audio_send_data); +static K_WORK_DELAYABLE_DEFINE(audio_send_work, lc3_audio_send_data); static void clear_lc3_sine_data(void) { - lc3_start_time = 0; lc3_sdu_cnt = 0; txing_stream = NULL; - (void)k_work_cancel(&audio_send_work); + (void)k_work_cancel_delayable(&audio_send_work); } /** @@ -288,8 +286,6 @@ static void lc3_audio_send_data(struct k_work *work) return; } - seq_num = get_next_seq_num(txing_stream->qos->interval); - const uint16_t tx_sdu_len = frames_per_sdu * octets_per_frame; struct net_buf *buf; uint8_t *net_buffer; @@ -315,34 +311,45 @@ static void lc3_audio_send_data(struct k_work *work) "LC3 encoder failed - wrong parameters?: %d", lc3_ret); net_buf_unref(buf); + + /* Reschedule for next interval */ + k_work_reschedule(k_work_delayable_from_work(work), + K_USEC(txing_stream->qos->interval)); return; } } + seq_num = get_next_seq_num(txing_stream->qos->interval); err = bt_bap_stream_send(txing_stream, buf, seq_num, BT_ISO_TIMESTAMP_NONE); if (err < 0) { - shell_error(ctx_shell, - "Failed to send LC3 audio data (%d)\n", - err); + shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err); net_buf_unref(buf); + + /* Reschedule for next interval */ + k_work_reschedule(k_work_delayable_from_work(work), + K_USEC(txing_stream->qos->interval)); return; } if ((lc3_sdu_cnt % 100) == 0) { - shell_info(ctx_shell, "[%zu]: TX LC3: %zu\n", - lc3_sdu_cnt, tx_sdu_len); + shell_info(ctx_shell, "[%zu]: TX LC3: %zu", lc3_sdu_cnt, tx_sdu_len); } lc3_sdu_cnt++; } void sdu_sent_cb(struct bt_bap_stream *stream) { + int err; + if (txing_stream == NULL || txing_stream->qos == NULL) { return; } - k_work_submit(&audio_send_work); + err = k_work_schedule(&audio_send_work, K_NO_WAIT); + if (err < 0) { + shell_error(ctx_shell, "Failed to schedule TX: %d", err); + } } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ @@ -2435,7 +2442,10 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) init_lc3(txing_stream); for (size_t i = 0U; i < prime_count; i++) { - k_work_submit(&audio_send_work); + /* Call callback directly as submitted the work item multiple times won't do any + * good + */ + lc3_audio_send_data(&audio_send_work.work); } return 0; From 06dc36d26869fc48866f6c90f3ceeff65465f59a Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 30 Jun 2023 15:54:35 +0200 Subject: [PATCH 1019/2042] Bluetooth: BAP: Shell: Fix formatting in lc3_audio_send_data Some formatting was not compliant with the coding style. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/bap.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 7e2eff7a298d..c85bad9bf080 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -275,9 +275,14 @@ static void init_lc3(const struct bt_bap_stream *stream) static void lc3_audio_send_data(struct k_work *work) { + const uint16_t tx_sdu_len = frames_per_sdu * octets_per_frame; + struct net_buf *buf; + uint8_t *net_buffer; + off_t offset = 0; + int err; + if (lc3_encoder == NULL) { - shell_error(ctx_shell, - "LC3 encoder not setup, cannot encode data"); + shell_error(ctx_shell, "LC3 encoder not setup, cannot encode data"); return; } @@ -286,12 +291,6 @@ static void lc3_audio_send_data(struct k_work *work) return; } - const uint16_t tx_sdu_len = frames_per_sdu * octets_per_frame; - struct net_buf *buf; - uint8_t *net_buffer; - off_t offset = 0; - int err; - buf = net_buf_alloc(&sine_tx_pool, K_FOREVER); net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); @@ -301,15 +300,13 @@ static void lc3_audio_send_data(struct k_work *work) for (int i = 0; i < frames_per_sdu; i++) { int lc3_ret; - lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, - audio_buf, 1, octets_per_frame, - net_buffer + offset); + lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, audio_buf, 1, + octets_per_frame, net_buffer + offset); offset += octets_per_frame; if (lc3_ret == -1) { - shell_error(ctx_shell, - "LC3 encoder failed - wrong parameters?: %d", - lc3_ret); + shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", + lc3_ret); net_buf_unref(buf); /* Reschedule for next interval */ @@ -320,8 +317,7 @@ static void lc3_audio_send_data(struct k_work *work) } seq_num = get_next_seq_num(txing_stream->qos->interval); - err = bt_bap_stream_send(txing_stream, buf, seq_num, - BT_ISO_TIMESTAMP_NONE); + err = bt_bap_stream_send(txing_stream, buf, seq_num, BT_ISO_TIMESTAMP_NONE); if (err < 0) { shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err); net_buf_unref(buf); @@ -335,6 +331,7 @@ static void lc3_audio_send_data(struct k_work *work) if ((lc3_sdu_cnt % 100) == 0) { shell_info(ctx_shell, "[%zu]: TX LC3: %zu", lc3_sdu_cnt, tx_sdu_len); } + lc3_sdu_cnt++; } From d17cde46d150de90400e47dbabceb371e5fc7b16 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 3 Jul 2023 15:55:22 +0200 Subject: [PATCH 1020/2042] Bluetooth: BAP: Shell: Improve handling of PSN when sending Previously the calculation of the PSN was done using just a timer. This would not work correctly when attempting to send multiple packets in a single SDU interval (e.g. to enqueue 2 or more). Previously we only ever attempted to send 1 packet in the `sent` callback but scheduling the work item. However in the case that the `sent` callback was called twice before the work item had been triggered (possible due to the priority of the RX thread being higher than the system workqueue thread). This has been modified so that if we can enqueue more packets in the lc3_audio_send_data function, we re-enqueue the work item. We re-enqueue rather than sending multiple in a single call to avoid blocking other items on the system workqueue from being scheduled. This could cause possible missed intervals (if other workqueue items are processed), but it should be OK from a ISO perspective, and the new PSN calculator handles this much better. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/audio.h | 8 ++ subsys/bluetooth/audio/shell/bap.c | 138 ++++++++++++++++++++------- 2 files changed, 112 insertions(+), 34 deletions(-) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 4c3842616ed1..0daca952b390 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -58,11 +58,19 @@ struct unicast_stream { struct bt_cap_stream stream; struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; +#if defined(CONFIG_BT_AUDIO_TX) + int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ + uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */ +#endif /* defined(CONFIG_BT_AUDIO_TX) */ }; struct broadcast_stream { struct bt_cap_stream stream; struct bt_audio_codec_data data; +#if defined(CONFIG_BT_AUDIO_TX) + int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ + uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */ +#endif /* defined(CONFIG_BT_AUDIO_TX) */ }; struct broadcast_source { diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index c85bad9bf080..55263ba4fc35 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -142,34 +142,70 @@ static bool initialized; #if defined(CONFIG_BT_AUDIO_TX) static struct bt_bap_stream *txing_stream; -static uint16_t seq_num; -static uint16_t get_next_seq_num(uint32_t interval_us) +static uint16_t get_next_seq_num(struct bt_bap_stream *stream) { - static int64_t last_ticks; - int64_t uptime_ticks, delta_ticks; + const uint32_t interval_us = stream->qos->interval; + uint16_t *last_allocated_seq_num_ptr = NULL; + int64_t connected_at_ticks; + int64_t uptime_ticks; + int64_t delta_ticks; uint64_t delta_us; - uint64_t seq_num_incr; - uint64_t next_seq_num; + uint16_t seq_num; - /* Note: This does not handle wrapping of ticks when they go above - * 2^(62-1) - */ +#if defined(CONFIG_BT_BAP_UNICAST) + if (stream->conn != NULL) { /* if unicast */ + struct unicast_stream *uni_stream = + CONTAINER_OF(stream, struct unicast_stream, stream); + + last_allocated_seq_num_ptr = &uni_stream->last_allocated_seq_num; + connected_at_ticks = uni_stream->connected_at_ticks; + } +#endif /* CONFIG_BT_BAP_UNICAST */ + +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + if (stream->conn == NULL) { /* if broadcast */ + struct broadcast_stream *bro_stream = + CONTAINER_OF(stream, struct broadcast_stream, stream); + + last_allocated_seq_num_ptr = &bro_stream->last_allocated_seq_num; + connected_at_ticks = bro_stream->connected_at_ticks; + } +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + + /* Note: This does not handle wrapping of ticks when they go above 2^(62-1) */ uptime_ticks = k_uptime_ticks(); - delta_ticks = uptime_ticks - last_ticks; - last_ticks = uptime_ticks; + delta_ticks = uptime_ticks - connected_at_ticks; delta_us = k_ticks_to_us_near64((uint64_t)delta_ticks); - seq_num_incr = delta_us / interval_us; - next_seq_num = (seq_num_incr + seq_num); + /* Calculate the sequence number by dividing the stream uptime by the SDU interval */ + seq_num = (uint16_t)(delta_us / interval_us); + + /* In the case that we call this multiple times, we need to account for any sequence numbers + * already allocated and send to the controller. Ensuring that the next PSN is 1 higher than + * the last we allocated (assuming that we it was actually sent to the controller). + * + * The additional condition that checks that the difference is smaller than a specific value + * is used to handle the case where seq_num has wrapped. + */ + if (seq_num <= *last_allocated_seq_num_ptr && *last_allocated_seq_num_ptr - seq_num < 100) { + seq_num = *last_allocated_seq_num_ptr + 1; + } + + if (last_allocated_seq_num_ptr != NULL) { + *last_allocated_seq_num_ptr = seq_num; + } - return (uint16_t)next_seq_num; + return seq_num; } #endif /* CONFIG_BT_AUDIO_TX */ #if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX) -NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), +/* For the first call-back we push multiple audio frames to the buffer to use the + * controller ISO buffer to handle jitter. + */ +#define PRIME_COUNT 2U +NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, PRIME_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #include "lc3.h" @@ -279,6 +315,7 @@ static void lc3_audio_send_data(struct k_work *work) struct net_buf *buf; uint8_t *net_buffer; off_t offset = 0; + uint16_t seq_num; int err; if (lc3_encoder == NULL) { @@ -316,7 +353,7 @@ static void lc3_audio_send_data(struct k_work *work) } } - seq_num = get_next_seq_num(txing_stream->qos->interval); + seq_num = get_next_seq_num(txing_stream); err = bt_bap_stream_send(txing_stream, buf, seq_num, BT_ISO_TIMESTAMP_NONE); if (err < 0) { shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err); @@ -329,10 +366,20 @@ static void lc3_audio_send_data(struct k_work *work) } if ((lc3_sdu_cnt % 100) == 0) { - shell_info(ctx_shell, "[%zu]: TX LC3: %zu", lc3_sdu_cnt, tx_sdu_len); + shell_info(ctx_shell, "[%zu]: TX LC3: %zu (seq_num %u)", lc3_sdu_cnt, tx_sdu_len, + seq_num); } lc3_sdu_cnt++; + + /* If we have more buffers available, we reschedule the workqueue item immediately to + * trigger antother encode + TX, but without blocking this call for too long + */ + buf = net_buf_alloc(&sine_tx_pool, K_NO_WAIT); + if (buf != NULL) { + net_buf_unref(buf); + k_work_reschedule(k_work_delayable_from_work(work), K_NO_WAIT); + } } void sdu_sent_cb(struct bt_bap_stream *stream) @@ -485,10 +532,6 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp) { shell_print(ctx_shell, "Start: stream %p", stream); -#if defined(CONFIG_BT_AUDIO_TX) - seq_num = 0; -#endif /* CONFIG_BT_AUDIO_TX */ - return 0; } @@ -1740,6 +1783,40 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) static void stream_started_cb(struct bt_bap_stream *stream) { +#if defined(CONFIG_BT_AUDIO_TX) + int64_t *connected_at_ticks_ptr = NULL; + uint16_t *last_allocated_seq_num_ptr = NULL; + +#if defined(CONFIG_BT_BAP_UNICAST) + if (stream->conn != NULL) { /* if unicast */ + struct unicast_stream *uni_stream = + CONTAINER_OF(stream, struct unicast_stream, stream); + + connected_at_ticks_ptr = &uni_stream->connected_at_ticks; + last_allocated_seq_num_ptr = &uni_stream->last_allocated_seq_num; + } +#endif /* CONFIG_BT_BAP_UNICAST */ + +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + if (stream == NULL) { /* if broadcast */ + struct broadcast_stream *bro_stream = + CONTAINER_OF(stream, struct broadcast_stream, stream); + + connected_at_ticks_ptr = &bro_stream->connected_at_ticks; + last_allocated_seq_num_ptr = &bro_stream->last_allocated_seq_num; + } +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + + if (connected_at_ticks_ptr != NULL) { + *connected_at_ticks_ptr = k_uptime_ticks(); + } + + if (last_allocated_seq_num_ptr != NULL) { + /* Set to max value to support sending the first packet with PSN = 0*/ + *last_allocated_seq_num_ptr = UINT16_MAX; + } +#endif /* CONFIG_BT_AUDIO_TX */ + printk("Stream %p started\n", stream); #if defined(CONFIG_BT_AUDIO_RX) @@ -2389,9 +2466,7 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) net_buf_add_mem(buf, data, len); - seq_num = get_next_seq_num(default_stream->qos->interval); - - ret = bt_bap_stream_send(default_stream, buf, seq_num, + ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(txing_stream), BT_ISO_TIMESTAMP_NONE); if (ret < 0) { shell_print(sh, "Unable to send: %d", -ret); @@ -2409,10 +2484,7 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_LIBLC3) static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) { - /* For the first call-back we push multiple audio frames to the buffer to use the - * controller ISO buffer to handle jitter. - */ - const size_t prime_count = 2U; + int err; if (default_stream == NULL) { shell_error(sh, "Invalid (NULL) stream"); @@ -2438,11 +2510,9 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) init_lc3(txing_stream); - for (size_t i = 0U; i < prime_count; i++) { - /* Call callback directly as submitted the work item multiple times won't do any - * good - */ - lc3_audio_send_data(&audio_send_work.work); + err = k_work_schedule(&audio_send_work, K_NO_WAIT); + if (err < 0) { + shell_error(ctx_shell, "Failed to schedule TX: %d", err); } return 0; From 275c86d399a8408664f6c65a2e756a9ec96204fa Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 7 Jul 2023 12:57:44 +0200 Subject: [PATCH 1021/2042] Bluetooth: BAP: Shell: Merge the unicast and broadcast stream structs Merging the two structs cleans up significant amount of code and makes it easier to expand later. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/audio.h | 21 ++--- subsys/bluetooth/audio/shell/bap.c | 94 ++++++-------------- subsys/bluetooth/audio/shell/cap_initiator.c | 16 ++-- 3 files changed, 40 insertions(+), 91 deletions(-) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 0daca952b390..a146964bc10a 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -54,23 +54,14 @@ struct named_lc3_preset { CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), \ (0)) -struct unicast_stream { +struct shell_stream { struct bt_cap_stream stream; struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; #if defined(CONFIG_BT_AUDIO_TX) int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */ -#endif /* defined(CONFIG_BT_AUDIO_TX) */ -}; - -struct broadcast_stream { - struct bt_cap_stream stream; - struct bt_audio_codec_data data; -#if defined(CONFIG_BT_AUDIO_TX) - int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ - uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */ -#endif /* defined(CONFIG_BT_AUDIO_TX) */ +#endif /* CONFIG_BT_AUDIO_TX */ }; struct broadcast_source { @@ -82,8 +73,8 @@ struct broadcast_source { struct bt_audio_codec_qos qos; }; -extern struct unicast_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + - UNICAST_CLIENT_STREAM_COUNT)]; +extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + + UNICAST_CLIENT_STREAM_COUNT)]; #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) @@ -167,7 +158,7 @@ static inline void print_codec_cfg(const struct shell *sh, } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) -extern struct broadcast_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; +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 */ @@ -227,7 +218,7 @@ static inline void print_base(const struct shell *sh, const struct bt_bap_base * } #endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ -static inline void copy_unicast_stream_preset(struct unicast_stream *stream, +static inline void copy_unicast_stream_preset(struct shell_stream *stream, const struct named_lc3_preset *named_preset) { memcpy(&stream->qos, &named_preset->preset.qos, sizeof(stream->qos)); diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 55263ba4fc35..26727dd25d56 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -34,8 +34,8 @@ #if defined(CONFIG_BT_BAP_UNICAST) -struct unicast_stream unicast_streams[CONFIG_BT_MAX_CONN * - (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; +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); @@ -53,7 +53,7 @@ struct bt_bap_ep *srcs[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_ #endif /* CONFIG_BT_BAP_UNICAST */ #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) -struct broadcast_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; +struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ #if defined(CONFIG_BT_BAP_BROADCAST_SINK) @@ -143,39 +143,20 @@ static bool initialized; #if defined(CONFIG_BT_AUDIO_TX) static struct bt_bap_stream *txing_stream; -static uint16_t get_next_seq_num(struct bt_bap_stream *stream) +static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) { - const uint32_t interval_us = stream->qos->interval; - uint16_t *last_allocated_seq_num_ptr = NULL; - int64_t connected_at_ticks; + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); + const uint32_t interval_us = bap_stream->qos->interval; int64_t uptime_ticks; int64_t delta_ticks; uint64_t delta_us; uint16_t seq_num; -#if defined(CONFIG_BT_BAP_UNICAST) - if (stream->conn != NULL) { /* if unicast */ - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); - - last_allocated_seq_num_ptr = &uni_stream->last_allocated_seq_num; - connected_at_ticks = uni_stream->connected_at_ticks; - } -#endif /* CONFIG_BT_BAP_UNICAST */ - -#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) - if (stream->conn == NULL) { /* if broadcast */ - struct broadcast_stream *bro_stream = - CONTAINER_OF(stream, struct broadcast_stream, stream); - - last_allocated_seq_num_ptr = &bro_stream->last_allocated_seq_num; - connected_at_ticks = bro_stream->connected_at_ticks; - } -#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ - /* Note: This does not handle wrapping of ticks when they go above 2^(62-1) */ uptime_ticks = k_uptime_ticks(); - delta_ticks = uptime_ticks - connected_at_ticks; + delta_ticks = uptime_ticks - sh_stream->connected_at_ticks; delta_us = k_ticks_to_us_near64((uint64_t)delta_ticks); /* Calculate the sequence number by dividing the stream uptime by the SDU interval */ @@ -188,13 +169,12 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *stream) * The additional condition that checks that the difference is smaller than a specific value * is used to handle the case where seq_num has wrapped. */ - if (seq_num <= *last_allocated_seq_num_ptr && *last_allocated_seq_num_ptr - seq_num < 100) { - seq_num = *last_allocated_seq_num_ptr + 1; + if (seq_num <= sh_stream->last_allocated_seq_num && + sh_stream->last_allocated_seq_num - seq_num < 100) { + seq_num = sh_stream->last_allocated_seq_num + 1; } - if (last_allocated_seq_num_ptr != NULL) { - *last_allocated_seq_num_ptr = seq_num; - } + sh_stream->last_allocated_seq_num = seq_num; return seq_num; } @@ -964,7 +944,8 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) { enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED; const struct named_lc3_preset *named_preset; - struct unicast_stream *uni_stream; + struct shell_stream *uni_stream; + struct bt_cap_stream *cap_stream; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep = NULL; unsigned long index; @@ -1071,7 +1052,8 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) } } - uni_stream = CONTAINER_OF(bap_stream, struct unicast_stream, stream); + cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + uni_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); copy_unicast_stream_preset(uni_stream, named_preset); /* If location has been modifed, we update the location in the codec configuration */ @@ -1250,8 +1232,7 @@ static int create_unicast_group(const struct shell *sh) for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { struct bt_bap_stream *stream = &unicast_streams[i].stream.bap_stream; - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + struct shell_stream *uni_stream = &unicast_streams[i]; if (stream->ep != NULL) { struct bt_bap_unicast_group_stream_param *stream_param; @@ -1781,43 +1762,20 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) } } -static void stream_started_cb(struct bt_bap_stream *stream) +static void stream_started_cb(struct bt_bap_stream *bap_stream) { #if defined(CONFIG_BT_AUDIO_TX) - int64_t *connected_at_ticks_ptr = NULL; - uint16_t *last_allocated_seq_num_ptr = NULL; + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); -#if defined(CONFIG_BT_BAP_UNICAST) - if (stream->conn != NULL) { /* if unicast */ - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + sh_stream->connected_at_ticks = k_uptime_ticks(); - connected_at_ticks_ptr = &uni_stream->connected_at_ticks; - last_allocated_seq_num_ptr = &uni_stream->last_allocated_seq_num; - } -#endif /* CONFIG_BT_BAP_UNICAST */ - -#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) - if (stream == NULL) { /* if broadcast */ - struct broadcast_stream *bro_stream = - CONTAINER_OF(stream, struct broadcast_stream, stream); - - connected_at_ticks_ptr = &bro_stream->connected_at_ticks; - last_allocated_seq_num_ptr = &bro_stream->last_allocated_seq_num; - } -#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ - - if (connected_at_ticks_ptr != NULL) { - *connected_at_ticks_ptr = k_uptime_ticks(); - } - - if (last_allocated_seq_num_ptr != NULL) { - /* Set to max value to support sending the first packet with PSN = 0*/ - *last_allocated_seq_num_ptr = UINT16_MAX; - } + /* Set to max value to support sending the first packet with PSN = 0*/ + sh_stream->last_allocated_seq_num = UINT16_MAX; #endif /* CONFIG_BT_AUDIO_TX */ - printk("Stream %p started\n", stream); + printk("Stream %p started\n", bap_stream); #if defined(CONFIG_BT_AUDIO_RX) lost_pkts = 0U; diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 0fabfdf14299..3e93c455c2db 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -234,8 +234,8 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, for (size_t i = 0U; i < sink_cnt; i++) { struct bt_cap_stream *stream = &unicast_streams[start_param.count].stream; - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + struct shell_stream *uni_stream = + CONTAINER_OF(stream, struct shell_stream, stream); struct bt_bap_ep *snk_ep = snks[bt_conn_index(conn)][i]; if (snk_ep == NULL) { @@ -268,8 +268,8 @@ static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc, for (size_t i = 0U; i < source_cnt; i++) { struct bt_cap_stream *stream = &unicast_streams[start_param.count].stream; - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + struct shell_stream *uni_stream = + CONTAINER_OF(stream, struct shell_stream, stream); struct bt_bap_ep *src_ep = srcs[bt_conn_index(conn)][i]; if (src_ep == NULL) { @@ -364,8 +364,8 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, 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 unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + struct shell_stream *uni_stream = + CONTAINER_OF(stream, struct shell_stream, stream); struct bt_bap_ep_info ep_info; if (stream->bap_stream.conn == NULL) { @@ -397,8 +397,8 @@ static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc, } else { for (size_t i = 1U; i < argc; i++) { struct bt_cap_stream *stream = (void *)shell_strtoul(argv[i], 16, &err); - struct unicast_stream *uni_stream = - CONTAINER_OF(stream, struct unicast_stream, stream); + struct shell_stream *uni_stream = + CONTAINER_OF(stream, struct shell_stream, stream); struct bt_bap_ep_info ep_info; if (err != 0) { From 5f0bba7ced041c791561fc49c4af12566f8a8f83 Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Fri, 7 Jul 2023 15:46:21 +0200 Subject: [PATCH 1022/2042] maintainers: Change TF-M maintainer to d3zd3z TF-M will be maintained by d3zd3z moving forward. This PR also includes some cleanup to the collaborator list of subsystems and modules related to TF-M. Signed-off-by: Kevin Townsend --- MAINTAINERS.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 86eae550769c..50bfcf210cdb 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2608,7 +2608,7 @@ Task Watchdog: TF-M Integration: status: maintained maintainers: - - microbuilder + - d3zd3z collaborators: - joerchan files: @@ -3232,11 +3232,10 @@ West: "West project: trusted-firmware-m": status: maintained maintainers: - - microbuilder + - d3zd3z collaborators: - joerchan - SebastianBoe - - theotherjimmy files: - modules/trusted-firmware-m/ labels: @@ -3245,11 +3244,10 @@ West: "West project: tf-m-tests": status: maintained maintainers: - - microbuilder + - d3zd3z collaborators: - joerchan - SebastianBoe - - theotherjimmy files: [] labels: - manifest-tf-m-tests @@ -3269,11 +3267,10 @@ West: "West project: psa-arch-tests": status: maintained maintainers: - - microbuilder + - d3zd3z collaborators: - joerchan - SebastianBoe - - theotherjimmy files: [] labels: - manifest-psa-arch-tests From a2ebec5c64c9d8ee00d1999a7f963308cc7797fe Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:27:06 +0530 Subject: [PATCH 1023/2042] Bluetooth: Controller: Fix coverity issue 318807 [Coverity CID: 318807] Dereference before null check in subsys/bluetooth/controller/ll_sw/ull_iso.c Fixes #59514. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_iso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_iso.c b/subsys/bluetooth/controller/ll_sw/ull_iso.c index 688bbb1b437a..126e3b9b58fe 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_iso.c @@ -235,7 +235,7 @@ uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id, * Identifier (0x02) */ cis = ll_conn_iso_stream_get(handle); - if (!cis->group) { + if (!cis || !cis->group) { /* CIS does not belong to a CIG */ return BT_HCI_ERR_UNKNOWN_CONN_ID; } From bc710a49f150d6cc39f5aeb87f2e4b4a6ac48bf3 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 6 Jul 2023 11:25:05 +0200 Subject: [PATCH 1024/2042] Bluetooth: audio: unicast_server: Do not store metadata if rejected This moves copying of parameters after application return value validation so that the metadata is not stored if rejected. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/bap_unicast_server.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index 54c37649d449..d056128a2505 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -129,16 +129,16 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio err = -ENOTSUP; } - ep = stream->ep; - for (size_t i = 0U; i < meta_count; i++) { - (void)memcpy(&ep->codec_cfg.meta[i], &meta[i], sizeof(ep->codec_cfg.meta[i])); - } - if (err) { LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); return err; } + ep = stream->ep; + for (size_t i = 0U; i < meta_count; i++) { + (void)memcpy(&ep->codec_cfg.meta[i], &meta[i], sizeof(ep->codec_cfg.meta[i])); + } + /* Set the state to the same state to trigger the notifications */ ascs_ep_set_state(ep, ep->status.state); From e6d463f8dd87b8c23341129374449bd8f652bd25 Mon Sep 17 00:00:00 2001 From: Greg Ingram Date: Fri, 7 Jul 2023 13:43:14 -0400 Subject: [PATCH 1025/2042] doc: Updated description grammar in mikro-bus.yaml file Fixed some wording within the description section Signed-off-by: Greg Ingram --- dts/bindings/gpio/mikro-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/gpio/mikro-bus.yaml b/dts/bindings/gpio/mikro-bus.yaml index aabb52aa5d11..806961f39ee4 100644 --- a/dts/bindings/gpio/mikro-bus.yaml +++ b/dts/bindings/gpio/mikro-bus.yaml @@ -25,7 +25,7 @@ description: | VCC-3.3V power - +3.3V +5V - VCC-5V power Reference Ground - GND GND - Reference Ground - Board's silkscreen may vary depending you board, but coherent with + Board's silkscreen may vary depending on your board, but coherent with the description above as it's according to the standard's specification. compatible: "mikro-bus" From 38e2eb8fe60b49b81f2482c766db69517e1a919a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 15:52:16 +0200 Subject: [PATCH 1026/2042] soc: ti: cc13/26xx: clean up include hierarchy Removes duplicate code and inconsistencies in the naming of the cc13xx_cc26xx devicetree and RTC driver hierarchy and alignes it with the actual TI product series naming hierarchy. Signed-off-by: Florian Grandel --- CODEOWNERS | 2 +- drivers/timer/CMakeLists.txt | 2 +- drivers/timer/Kconfig | 2 +- ...2_cc26x2_rtc => Kconfig.cc13xx_cc26xx_rtc} | 6 ++--- ..._rtc_timer.c => cc13xx_cc26xx_rtc_timer.c} | 0 dts/arm/ti/cc1352r.dtsi | 2 +- dts/arm/ti/cc1352r7.dtsi | 2 +- ...{cc13x2_cc26x2.dtsi => cc13xx_cc26xx.dtsi} | 0 dts/arm/ti/cc2652r.dtsi | 25 +------------------ soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/soc.c | 4 +-- tests/kernel/sleep/src/usleep.c | 9 +++---- 11 files changed, 15 insertions(+), 39 deletions(-) rename drivers/timer/{Kconfig.cc13x2_cc26x2_rtc => Kconfig.cc13xx_cc26xx_rtc} (72%) rename drivers/timer/{cc13x2_cc26x2_rtc_timer.c => cc13xx_cc26xx_rtc_timer.c} (100%) rename dts/arm/ti/{cc13x2_cc26x2.dtsi => cc13xx_cc26xx.dtsi} (100%) diff --git a/CODEOWNERS b/CODEOWNERS index 44dd1b51cdc2..a1457cf6d3b1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -445,7 +445,7 @@ /drivers/timer/*riscv_machine* @kgugala @pgielda /drivers/timer/*ite_it8xxx2* @ite /drivers/timer/*xlnx_psttc* @wjliang @stephanosio -/drivers/timer/*cc13x2_cc26x2_rtc* @vanti +/drivers/timer/*cc13xx_cc26xx_rtc* @vanti /drivers/timer/*cavs* @dcpleung /drivers/timer/*stm32_lptim* @FRASTM /drivers/timer/*leon_gptimer* @julius-barendt diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index b026a22b137c..ced74f9559c5 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -8,7 +8,7 @@ zephyr_library_sources_ifdef(CONFIG_APIC_TSC_DEADLINE_TIMER apic_tsc.c) zephyr_library_sources_ifdef(CONFIG_ARCV2_TIMER arcv2_timer0.c) zephyr_library_sources_ifdef(CONFIG_ARM_ARCH_TIMER arm_arch_timer.c) zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_timer.c) -zephyr_library_sources_ifdef(CONFIG_CC13X2_CC26X2_RTC_TIMER cc13x2_cc26x2_rtc_timer.c) +zephyr_library_sources_ifdef(CONFIG_CC13XX_CC26XX_RTC_TIMER cc13xx_cc26xx_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c) zephyr_library_sources_ifdef(CONFIG_ESP32C3_SYS_TIMER esp32c3_sys_timer.c) zephyr_library_sources_ifdef(CONFIG_GECKO_BURTC_TIMER gecko_burtc_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 1b6c48712bd0..3631c55e4942 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -68,7 +68,7 @@ source "drivers/timer/Kconfig.apic" source "drivers/timer/Kconfig.arcv2" source "drivers/timer/Kconfig.arm_arch" source "drivers/timer/Kconfig.cavs" -source "drivers/timer/Kconfig.cc13x2_cc26x2_rtc" +source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc" source "drivers/timer/Kconfig.cortex_m_systick" source "drivers/timer/Kconfig.esp32c3_sys" source "drivers/timer/Kconfig.gecko" diff --git a/drivers/timer/Kconfig.cc13x2_cc26x2_rtc b/drivers/timer/Kconfig.cc13xx_cc26xx_rtc similarity index 72% rename from drivers/timer/Kconfig.cc13x2_cc26x2_rtc rename to drivers/timer/Kconfig.cc13xx_cc26xx_rtc index b734b1f1d3d1..5b4b82aa3f9d 100644 --- a/drivers/timer/Kconfig.cc13x2_cc26x2_rtc +++ b/drivers/timer/Kconfig.cc13xx_cc26xx_rtc @@ -3,13 +3,13 @@ # Copyright (c) 2019 Intel Corp. # SPDX-License-Identifier: Apache-2.0 -config CC13X2_CC26X2_RTC_TIMER - bool "TI SimpleLink CC13x2/CC26x2 RTC timer" +config CC13XX_CC26XX_RTC_TIMER + bool "TI SimpleLink CC13xx/CC26xx RTC system clock timer" default y depends on DT_HAS_TI_CC13XX_CC26XX_RTC_ENABLED select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the TI SimpleLink - CC13X2_CC26X2 series Real Time Counter and provides the standard + CC13XX_CC26XX series Real Time Counter and provides the standard "system clock driver" interfaces. diff --git a/drivers/timer/cc13x2_cc26x2_rtc_timer.c b/drivers/timer/cc13xx_cc26xx_rtc_timer.c similarity index 100% rename from drivers/timer/cc13x2_cc26x2_rtc_timer.c rename to drivers/timer/cc13xx_cc26xx_rtc_timer.c diff --git a/dts/arm/ti/cc1352r.dtsi b/dts/arm/ti/cc1352r.dtsi index 97c7ad3f72b3..34f36ee64022 100644 --- a/dts/arm/ti/cc1352r.dtsi +++ b/dts/arm/ti/cc1352r.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { sram0: memory@20000000 { diff --git a/dts/arm/ti/cc1352r7.dtsi b/dts/arm/ti/cc1352r7.dtsi index 0b098c81c81f..56bcb9678dcf 100644 --- a/dts/arm/ti/cc1352r7.dtsi +++ b/dts/arm/ti/cc1352r7.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { sram0: memory@20000000 { diff --git a/dts/arm/ti/cc13x2_cc26x2.dtsi b/dts/arm/ti/cc13xx_cc26xx.dtsi similarity index 100% rename from dts/arm/ti/cc13x2_cc26x2.dtsi rename to dts/arm/ti/cc13xx_cc26xx.dtsi diff --git a/dts/arm/ti/cc2652r.dtsi b/dts/arm/ti/cc2652r.dtsi index 97c7ad3f72b3..1f6bdf878d4d 100644 --- a/dts/arm/ti/cc2652r.dtsi +++ b/dts/arm/ti/cc2652r.dtsi @@ -5,27 +5,4 @@ */ #include -#include - -/ { - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(80)>; - }; -}; - -&flash0 { - reg = <0x0 DT_SIZE_K(352)>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - /* CCFG registers occupy the last 88 bytes of flash */ - ti_ccfg_partition: partition@57fa8 { - compatible = "zephyr,memory-region"; - reg = <0x57fa8 88>; - zephyr,memory-region = "FLASH_CCFG"; - }; - }; -}; +#include diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/soc.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/soc.c index 9db48d9a354c..8c2ea2f5350d 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/soc.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/soc.c @@ -8,7 +8,7 @@ #include -static int ti_cc13x2_cc26x2_init(void) +static int ti_cc13x7_cc26x7_init(void) { /* Performs necessary trim of the device. */ @@ -17,4 +17,4 @@ static int ti_cc13x2_cc26x2_init(void) return 0; } -SYS_INIT(ti_cc13x2_cc26x2_init, PRE_KERNEL_1, 0); +SYS_INIT(ti_cc13x7_cc26x7_init, PRE_KERNEL_1, 0); diff --git a/tests/kernel/sleep/src/usleep.c b/tests/kernel/sleep/src/usleep.c index e014a84ab73c..67037e593c90 100644 --- a/tests/kernel/sleep/src/usleep.c +++ b/tests/kernel/sleep/src/usleep.c @@ -29,12 +29,11 @@ * nRF51, which has a slow CPU clock. */ #define MAXIMUM_SHORTEST_TICKS (IS_ENABLED(CONFIG_SOC_SERIES_NRF51X) ? 6 : 3) -/* - * Similar situation for TI CC13X2/CC26X2 RTC due to the limitation - * that a value too close to the current time cannot be loaded to - * its comparator. +/* Similar situation for TI CC13XX/CC26XX RTC kernel timer due to the + * limitation that a value too close to the current time cannot be + * loaded to its comparator. */ -#elif defined(CONFIG_CC13X2_CC26X2_RTC_TIMER) && \ +#elif defined(CONFIG_CC13XX_CC26XX_RTC_TIMER) && \ (CONFIG_SYS_CLOCK_TICKS_PER_SEC > 16384) #define MAXIMUM_SHORTEST_TICKS 3 #else From 75c83edc4881e7dd837ab8086870ac73e915a614 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 16:06:19 +0200 Subject: [PATCH 1027/2042] dts: ti: cc13xx_cc26xx: devicetree sysclk alignment This change introduces the "_rtc_timer" suffix for the system tick timer driver "compatible" property and aligns naming conventions with the actual CC13/26xx SoC series product policy. This frees up the "_rtc" namespace to introduce additional APIs based on the same peripheral in the future (not part of this PR): rtc: rtc@... { compatible = "ti,cc13xx-cc26xx-rtc"; ... timer { compatible = "ti,cc13xx-cc26xx-rtc-timer"; ... }; counter { compatible = "ti,cc13xx-cc26xx-rtc-counter"; ... }; pps { compatible = "ti,cc13xx-cc26xx-rtc-pps"; ... }; }; Or alternatively an MFD pattern with similar requirements. Fixing the namespacing now makes sense standalone as it reduces the chance of custom drivers being broken in the future. Redundant extension of the mandatory system clock devicetree node is replaced with a single `status = "okay"` which seems to be the more sensible default to avoid user error when defining custom boards. Knowledgeable users can still override this if really needed. Signed-off-by: Florian Grandel --- boards/arm/beagle_bcf/beagleconnect_freedom.dts | 4 ---- boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts | 4 ---- boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts | 4 ---- boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts | 4 ---- boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts | 4 ---- drivers/timer/Kconfig.cc13xx_cc26xx_rtc | 2 +- drivers/timer/cc13xx_cc26xx_rtc_timer.c | 2 +- dts/arm/ti/cc13xx_cc26xx.dtsi | 5 +++-- dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml | 2 +- 9 files changed, 6 insertions(+), 25 deletions(-) diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index 154928bc8c79..c41d642ebfe7 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -201,10 +201,6 @@ }; }; -&rtc { - status = "okay"; -}; - &ieee802154 { status = "okay"; }; diff --git a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts index 06053065c8fe..50ab7b4fdc4f 100644 --- a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts +++ b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts @@ -131,10 +131,6 @@ cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; }; -&rtc { - status = "okay"; -}; - &radio { status = "okay"; }; diff --git a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts index 71c2214ed942..4f6cc4864b87 100644 --- a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts +++ b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts @@ -111,10 +111,6 @@ cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; }; -&rtc { - status = "okay"; -}; - &radio { status = "okay"; }; diff --git a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts index 0df448d6f31f..0d50b59e778e 100644 --- a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts +++ b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts @@ -141,10 +141,6 @@ /* TODO: "jedec,spi-nor" for the mx25r8035 */ }; -&rtc { - status = "okay"; -}; - &radio { status = "okay"; }; diff --git a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts index 6021603165d3..271e63b920bc 100644 --- a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts +++ b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts @@ -111,10 +111,6 @@ cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; }; -&rtc { - status = "okay"; -}; - &wdt0 { status = "okay"; }; diff --git a/drivers/timer/Kconfig.cc13xx_cc26xx_rtc b/drivers/timer/Kconfig.cc13xx_cc26xx_rtc index 5b4b82aa3f9d..e6fbef0bfabc 100644 --- a/drivers/timer/Kconfig.cc13xx_cc26xx_rtc +++ b/drivers/timer/Kconfig.cc13xx_cc26xx_rtc @@ -6,7 +6,7 @@ config CC13XX_CC26XX_RTC_TIMER bool "TI SimpleLink CC13xx/CC26xx RTC system clock timer" default y - depends on DT_HAS_TI_CC13XX_CC26XX_RTC_ENABLED + depends on DT_HAS_TI_CC13XX_CC26XX_RTC_TIMER_ENABLED select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER help diff --git a/drivers/timer/cc13xx_cc26xx_rtc_timer.c b/drivers/timer/cc13xx_cc26xx_rtc_timer.c index bf0895f32a3c..9a64c779248b 100644 --- a/drivers/timer/cc13xx_cc26xx_rtc_timer.c +++ b/drivers/timer/cc13xx_cc26xx_rtc_timer.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT ti_cc13xx_cc26xx_rtc +#define DT_DRV_COMPAT ti_cc13xx_cc26xx_rtc_timer /* * TI SimpleLink CC13X2/CC26X2 RTC-based system timer diff --git a/dts/arm/ti/cc13xx_cc26xx.dtsi b/dts/arm/ti/cc13xx_cc26xx.dtsi index dd32e43755f9..57c07c2b121d 100644 --- a/dts/arm/ti/cc13xx_cc26xx.dtsi +++ b/dts/arm/ti/cc13xx_cc26xx.dtsi @@ -123,11 +123,12 @@ status = "disabled"; }; + /* The RTC peripheral backs the kernel system clock and tick timer. */ rtc: rtc@40092000 { - compatible = "ti,cc13xx-cc26xx-rtc"; + compatible = "ti,cc13xx-cc26xx-rtc-timer"; reg = <0x40092000 0x1000>; interrupts = <4 0>; /* interrupt #20 = 4 + 16 */ - status = "disabled"; + status = "okay"; /* the system clock timer is mandatory */ }; radio: radio@40040000 { diff --git a/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml b/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml index 93f7912d3cd6..861efc3a8f4c 100644 --- a/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml +++ b/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml @@ -6,7 +6,7 @@ description: TI SimpleLink CC13xx/CC26xx RTC -compatible: "ti,cc13xx-cc26xx-rtc" +compatible: "ti,cc13xx-cc26xx-rtc-timer" include: rtc.yaml From b4ed6c4300a2d20ae201e66ced13a583d0bc9da4 Mon Sep 17 00:00:00 2001 From: "Najumon B.A" Date: Tue, 20 Jun 2023 13:47:42 +0530 Subject: [PATCH 1028/2042] drivers: serial: driver init level based on parent node 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. Signed-off-by: Najumon B.A --- drivers/serial/Kconfig.ns16550 | 10 ++++++++++ drivers/serial/uart_ns16550.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index ae8f866a3e3e..bef4e778d6e7 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -72,6 +72,16 @@ config UART_NS16550_SIMULT_ACCESS When enabled, NS16550 supports IO, MMIO, PCIe UART devices simultaneously. For io-mapped instances, io-mapped DTS property need to be added in dtsi. +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. + menu "NS16550 Workarounds" config UART_NS16550_WA_ISR_REENABLE_INTERRUPT diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 086195615702..0456b354c4e5 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -1248,6 +1248,15 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define DEV_DATA_DLF_INIT(n) \ _CONCAT(DEV_DATA_DLF, DT_INST_NODE_HAS_PROP(n, dlf))(n) +#ifdef CONFIG_UART_NS16550_PARENT_INIT_LEVEL +#define NS16550_BOOT_LEVEL0 PRE_KERNEL_1 +#define NS16550_BOOT_LEVEL1 POST_KERNEL +#define BOOT_LEVEL(n) \ + _CONCAT(NS16550_BOOT_LEVEL, DT_INST_ON_BUS(n, pcie)) +#else +#define BOOT_LEVEL(n) PRE_KERNEL_1 +#endif + #define UART_NS16550_DEVICE_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ DEV_PCIE_DECLARE(n); \ @@ -1283,7 +1292,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, \ - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + BOOT_LEVEL(n), CONFIG_SERIAL_INIT_PRIORITY, \ &uart_ns16550_driver_api); \ UART_NS16550_IRQ_FUNC_DEFINE(n) From fed377f622c9c280016c41b22ea6dc6b8ce0aed4 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 7 Jul 2023 20:19:05 +0000 Subject: [PATCH 1029/2042] drivers: mipi: delay initialization after display drivers Currently MIPI devices are set to initialize before display drivers, which is incoherent with how the mcux mipi-dsi device is declared in the device tree. This is detected with build time priority checking: west build -p -b mimxrt595_evk_cm33 samples/drivers/display \ -DCONFIG_CHECK_INIT_PRIORITIES=y ERROR: /soc/peripheral@50000000/mipi_dsi@31000 POST_KERNEL 40 < /soc/peripheral@50000000/lcdif@210000 POST_KERNEL 85 Note that this also changes the priority of dsi_stm32, though that should be ok since does not appear to have other dependencies in devicetree. Signed-off-by: Fabio Baltieri --- drivers/mipi_dsi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mipi_dsi/Kconfig b/drivers/mipi_dsi/Kconfig index 7da70f4aad2b..dd896de7c981 100644 --- a/drivers/mipi_dsi/Kconfig +++ b/drivers/mipi_dsi/Kconfig @@ -17,7 +17,7 @@ source "subsys/logging/Kconfig.template.log_config" config MIPI_DSI_INIT_PRIORITY int "Initialization priority" - default 40 + default 86 help MIPI-DSI Host Controllers initialization priority. From 694cd5864726083d20dfc54dbda4c73c3050a3c8 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 7 Jul 2023 07:34:53 -0400 Subject: [PATCH 1030/2042] posix: pthread: fixes for coverity 321140 and 321092 The `pthread_once_lock` `k_mutex` is statically initialized and only visible within file scope. Coverity identified it as unsafe because the return values of `pthread_mutex_lock()` and `pthread_mutex_unlock()` were unchecked. However, if those functions were to fail here, it would be indicative that something far worse has happened. In any case, we add assertions that these functions succeed rather than silently ignoring with `(void)`, which ensures that we have coverage when assertions are enabled, in test, while removing unneeded code with assertions disable, in production. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 671ff08d2c8a..652e539e48a3 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -509,14 +509,18 @@ int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *pa */ int pthread_once(pthread_once_t *once, void (*init_func)(void)) { - k_mutex_lock(&pthread_once_lock, K_FOREVER); + __unused int ret; + + ret = k_mutex_lock(&pthread_once_lock, K_FOREVER); + __ASSERT_NO_MSG(ret == 0); if (once->is_initialized != 0 && once->init_executed == 0) { init_func(); once->init_executed = 1; } - k_mutex_unlock(&pthread_once_lock); + ret = k_mutex_unlock(&pthread_once_lock); + __ASSERT_NO_MSG(ret == 0); return 0; } From 78c8176c4d6634dc3a2382260627a3db480d8efb Mon Sep 17 00:00:00 2001 From: Harshil Bhatt Date: Tue, 4 Jul 2023 02:01:32 +0530 Subject: [PATCH 1031/2042] posix: Implement pthread_barrieratter functions Added pthread_barrieratter_init() #59936, pthread_barrieratter_destroy() #59935, pthread_barrieratter_getpshared() #59937 and pthread_barrieratter_setpshared() #59939. Signed-off-by: Harshil Bhatt --- include/zephyr/posix/posix_types.h | 1 + include/zephyr/posix/pthread.h | 37 +++++++++++++++++------------- lib/posix/barrier.c | 34 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 16 deletions(-) diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index a2191f0fece2..fbfc976d6fb9 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -88,6 +88,7 @@ BUILD_ASSERT(sizeof(pthread_condattr_t) >= sizeof(struct pthread_condattr)); typedef uint32_t pthread_barrier_t; typedef struct pthread_barrierattr { + int pshared; } pthread_barrierattr_t; typedef uint32_t pthread_rwlockattr_t; diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index 5b8078807751..b11c61a9f6ed 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -297,6 +297,12 @@ static inline int pthread_mutexattr_destroy(pthread_mutexattr_t *m) #define PTHREAD_BARRIER_SERIAL_THREAD 1 +/* + * Barrier attributes - type + */ +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_PUBLIC 1 + /** * @brief POSIX threading compatibility API * @@ -323,29 +329,30 @@ int pthread_barrier_destroy(pthread_barrier_t *b); * @brief POSIX threading compatibility API * * See IEEE 1003.1 - * - * Note that pthread attribute structs are currently noops in Zephyr. */ -static inline int pthread_barrierattr_init(pthread_barrierattr_t *b) -{ - ARG_UNUSED(b); - - return 0; -} +int pthread_barrierattr_init(pthread_barrierattr_t *b); /** * @brief POSIX threading compatibility API * * See IEEE 1003.1 + */ +int pthread_barrierattr_destroy(pthread_barrierattr_t *b); + +/** + * @brief POSIX threading compatibility API * - * Note that pthread attribute structs are currently noops in Zephyr. + * See IEEE 1003.1 */ -static inline int pthread_barrierattr_destroy(pthread_barrierattr_t *b) -{ - ARG_UNUSED(b); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); - return 0; -} +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *ZRESTRICT attr, + int *ZRESTRICT pshared); /* Predicates and setters for various pthread attribute values that we * don't support (or always support: the "process shared" attribute @@ -370,8 +377,6 @@ int pthread_mutexattr_getrobust(const pthread_mutexattr_t * int *); int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); -int pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *); -int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); */ /* Base Pthread related APIs */ diff --git a/lib/posix/barrier.c b/lib/posix/barrier.c index f6122b13f9e7..7e2598b1bde8 100644 --- a/lib/posix/barrier.c +++ b/lib/posix/barrier.c @@ -161,6 +161,40 @@ int pthread_barrier_destroy(pthread_barrier_t *b) return 0; } +int pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + __ASSERT_NO_MSG(attr != NULL); + + attr->pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_PUBLIC) { + return -EINVAL; + } + + attr->pshared = pshared; + return 0; +} + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr, + int *restrict pshared) +{ + *pshared = attr->pshared; + + return 0; +} + +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + ARG_UNUSED(attr); + + return 0; +} + static int pthread_barrier_pool_init(void) { int err; From 886325cc1d2dc3d1f03dea661fb3451d6d7a7af5 Mon Sep 17 00:00:00 2001 From: Harshil Bhatt Date: Wed, 5 Jul 2023 01:36:49 +0530 Subject: [PATCH 1032/2042] posix: add tests for pthread_barrierattr add test coverage for init, destroy, setpshared and getpshared Signed-off-by: Harshil Bhatt --- tests/posix/common/src/pthread.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 1bf029fb04d5..717b96d8ddcc 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -743,3 +743,31 @@ ZTEST(posix_apis, test_sched_policy) } } } + +ZTEST(posix_apis, test_posix_pthread_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"); +} From 322cd468db280bbed2d6010e06fd83a27139b988 Mon Sep 17 00:00:00 2001 From: Harshil Bhatt Date: Wed, 5 Jul 2023 01:37:58 +0530 Subject: [PATCH 1033/2042] docs: update posix docs with pthread_barrierattr add pthread_barrierattr to supported api list Signed-off-by: Harshil Bhatt --- doc/services/portability/posix.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 23bf17b8f541..887f34258cca 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -140,10 +140,10 @@ multiple processes. pthread_barrier_destroy(),yes pthread_barrier_init(),yes pthread_barrier_wait(),yes - pthread_barrierattr_destroy(), - pthread_barrierattr_getpshared(), - pthread_barrierattr_init(), - pthread_barrierattr_setpshared(), + pthread_barrierattr_destroy(),yes + pthread_barrierattr_getpshared(),yes + pthread_barrierattr_init(),yes + pthread_barrierattr_setpshared(),yes pthread_cancel(),yes pthread_cleanup_pop(), pthread_cleanup_push(), From 43b057a7ce73817633220475e0ef942fe67bd545 Mon Sep 17 00:00:00 2001 From: Daniel Mangum Date: Sat, 8 Jul 2023 19:17:41 -0400 Subject: [PATCH 1034/2042] soc: neorv32: Fix spelling in reset.S Fixes minor misspelling of instruction in the neorv32 reset.S. Signed-off-by: Daniel Mangum --- soc/riscv/riscv-privileged/neorv32/reset.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/riscv/riscv-privileged/neorv32/reset.S b/soc/riscv/riscv-privileged/neorv32/reset.S index fc1a19f82aa5..c92b962e95e1 100644 --- a/soc/riscv/riscv-privileged/neorv32/reset.S +++ b/soc/riscv/riscv-privileged/neorv32/reset.S @@ -16,7 +16,7 @@ SECTION_FUNC(reset, __reset) /* Zerorize zero register */ lui x0, 0 - /* Disable insterrupts */ + /* Disable interrupts */ csrw mstatus, x0 csrw mie, x0 From adc36315b08d315505e3b38b157abd67842918ae Mon Sep 17 00:00:00 2001 From: Jakub Duchniewicz Date: Sun, 9 Jul 2023 17:48:58 +0200 Subject: [PATCH 1035/2042] doc: Fix typos in zbus documentation Fixes a few typos. Signed-off-by: Jakub Duchniewicz --- doc/services/zbus/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index c066d4d5f472..a8d26e5ac860 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -70,7 +70,7 @@ The VDED execution always happens in the publishing's (thread) context. So it ca * At last, the publishing function unlocks the channel. -To illustrate the VDED execution, consider the example illustrated below. We have four threads in ascending priority T1, T2, T3, and T4 (the highest priority); two listeners, L1 and L2; and channel A. Suposing L1, L2, T2, T3, and T4 observer channel A. +To illustrate the VDED execution, consider the example illustrated below. We have four threads in ascending priority T1, T2, T3, and T4 (the highest priority); two listeners, L1 and L2; and channel A. Supposing L1, L2, T2, T3, and T4 observer channel A. .. figure:: images/zbus_publishing_process_example_scenario.svg :alt: Zbus example scenario @@ -155,7 +155,7 @@ Zbus always delivers the messages to the listeners. However, there are no messag Message delivery sequence ------------------------- -The listeners (synchronous observers) will follow the channel definition sequence as the notification and message consumption sequence. However, the subscribers, as they have an asynchronous nature, all will receive the notification as the channel definition sequence but only will consume the data when they execute again, so the delivery respects the order, but the priority assigned to the subscribers will define the reaction sequence. All the listeners (static o dynamic) will receive the message before subscribers receive the notification. The sequence of delivery is: (i) static listeners; (ii) runtime listeners; (iii) static subscribers; at last (iv) runtime subscribers. +The listeners (synchronous observers) will follow the channel definition sequence as the notification and message consumption sequence. However, the subscribers, as they have an asynchronous nature, all will receive the notification as the channel definition sequence but only will consume the data when they execute again, so the delivery respects the order, but the priority assigned to the subscribers will define the reaction sequence. All the listeners (static or dynamic) will receive the message before subscribers receive the notification. The sequence of delivery is: (i) static listeners; (ii) runtime listeners; (iii) static subscribers; at last (iv) runtime subscribers. Usage ***** @@ -214,7 +214,7 @@ The following code defines and initializes a regular channel and its dependencie It is unnecessary to claim/lock a channel before accessing the message inside the listener since the event dispatcher calls listeners with the notifying channel already locked. Subscribers, however, must claim/lock that or use regular read operations to access the message after being notified. -Channels can have a ``validator function`` that enables a channel to accept only valid messages. Publish attempts invalidated by hard channels will return immediately with an error code. This allows original creators of a channel to exert some authority over other developers/publishers who may want to piggy-back on their channels. The following code defines and initializes a :dfn:`hard channel` and its dependencies. Only valid messages can be published to a :dfn:`hard channel`. It is possible because a ``Validator function`` passed to the channel's definition. In this example, only messages with ``move`` equal to 0, -1, and 1 are valid. Publish function will discard all other values to ``move``. +Channels can have a ``validator function`` that enables a channel to accept only valid messages. Publish attempts invalidated by hard channels will return immediately with an error code. This allows original creators of a channel to exert some authority over other developers/publishers who may want to piggy-back on their channels. The following code defines and initializes a :dfn:`hard channel` and its dependencies. Only valid messages can be published to a :dfn:`hard channel`. It is possible because a ``validator function`` was passed to the channel's definition. In this example, only messages with ``move`` equal to 0, -1, and 1 are valid. Publish function will discard all other values to ``move``. .. code-block:: c @@ -388,7 +388,7 @@ It is possible to pass custom data into the channel's ``user_data`` for various Claim and finish a channel -------------------------- -To take more control over channels, two function were added :c:func:`zbus_chan_claim` and :c:func:`zbus_chan_finish`. With these functions, it is possible to access the channel's metadata safely. When a channel is claimed, no actions are available to that channel. After finishing the channel, all the actions are available again. +To take more control over channels, two functions were added :c:func:`zbus_chan_claim` and :c:func:`zbus_chan_finish`. With these functions, it is possible to access the channel's metadata safely. When a channel is claimed, no actions are available to that channel. After finishing the channel, all the actions are available again. .. warning:: Never change the fields of the channel struct directly. It may cause zbus behavior inconsistencies and scheduling issues. From 4580708f5429f1b4c9240abe5da0ff32fc441d95 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 4 Jul 2023 15:15:15 +0800 Subject: [PATCH 1036/2042] posix: implement uname Add implementation for posix uname. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/sys/utsname.h | 27 +++++++++++++++ lib/posix/CMakeLists.txt | 1 + lib/posix/Kconfig | 1 + lib/posix/Kconfig.uname | 26 +++++++++++++++ lib/posix/uname.c | 53 ++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 include/zephyr/posix/sys/utsname.h create mode 100644 lib/posix/Kconfig.uname create mode 100644 lib/posix/uname.c diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 887f34258cca..6028ab508d71 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -355,7 +355,7 @@ process applications. getenv(), setenv(), sysconf(), - uname(), + uname(),yes unsetenv() diff --git a/include/zephyr/posix/sys/utsname.h b/include/zephyr/posix/sys/utsname.h new file mode 100644 index 000000000000..f00497f17f3e --- /dev/null +++ b/include/zephyr/posix/sys/utsname.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_POSIX_SYS_UTSNAME_H_ +#define ZEPHYR_INCLUDE_POSIX_SYS_UTSNAME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct utsname { + char sysname[sizeof("Zephyr")]; + char nodename[CONFIG_POSIX_UNAME_NODENAME_LEN + 1]; + char release[sizeof("99.99.99")]; + char version[CONFIG_POSIX_UNAME_VERSION_LEN + 1]; + char machine[sizeof(CONFIG_ARCH)]; +}; + +int uname(struct utsname *name); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_POSIX_SYS_UTSNAME_H_ */ diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 8b175436486a..d0c1c88910f5 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -29,6 +29,7 @@ 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_UNAME uname.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC barrier.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC cond.c) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 2fcad705d903..15f019d4a30e 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -50,3 +50,4 @@ source "lib/posix/Kconfig.pthread" source "lib/posix/Kconfig.semaphore" source "lib/posix/Kconfig.spinlock" source "lib/posix/Kconfig.timer" +source "lib/posix/Kconfig.uname" diff --git a/lib/posix/Kconfig.uname b/lib/posix/Kconfig.uname new file mode 100644 index 000000000000..d8c29479986f --- /dev/null +++ b/lib/posix/Kconfig.uname @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_UNAME + bool "Support for uname" + default y if POSIX_API + help + The uname() function shall store information identifying the current + system in the structure pointed to by name. + +if POSIX_UNAME +config POSIX_UNAME_VERSION_LEN + int "uname version string length" + default 60 + help + Defines the maximum string length of uname version. + +config POSIX_UNAME_NODENAME_LEN + int "uname nodename string length" + default 6 if !NET_HOSTNAME_UNIQUE + default 22 if NET_HOSTNAME_UNIQUE + help + Defines the maximum string length of nodename version. + +endif # POSIX_UNAME diff --git a/lib/posix/uname.c b/lib/posix/uname.c new file mode 100644 index 000000000000..107126f584ee --- /dev/null +++ b/lib/posix/uname.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "version.h" +#include +#include +#include +#include + +#ifdef CONFIG_NET_HOSTNAME_ENABLE +#define UTSNAME_NODENAME CONFIG_NET_HOSTNAME +#else +#define UTSNAME_NODENAME "zephyr" +#endif + +#if defined(__DATE__) && defined(__TIME__) +#define UTSNAME_VERSION(_ver) _ver " " __DATE__ " " __TIME__ +#else +#define UTSNAME_VERSION(_ver) _ver +#endif + +#ifdef BUILD_VERSION +#define VERSION_BUILD STRINGIFY(BUILD_VERSION) +#else +#define VERSION_BUILD KERNEL_VERSION_STRING +#endif + +#define UTSNAME_INITIALIZER(_sys, _node, _rel, _ver, _mach) \ + { \ + .sysname = _sys, .nodename = _node, .release = _rel, \ + .version = UTSNAME_VERSION(_ver), .machine = _mach, \ + } + +static const struct utsname z_name = UTSNAME_INITIALIZER( + "Zephyr", UTSNAME_NODENAME, KERNEL_VERSION_STRING, VERSION_BUILD, CONFIG_ARCH); + +BUILD_ASSERT(sizeof(z_name.sysname) >= sizeof("Zephyr")); +BUILD_ASSERT(sizeof(z_name.release) >= sizeof(KERNEL_VERSION_STRING)); +BUILD_ASSERT(sizeof(z_name.version) >= sizeof(UTSNAME_VERSION(VERSION_BUILD))); +BUILD_ASSERT(sizeof(z_name.machine) >= sizeof(CONFIG_ARCH)); + +int uname(struct utsname *name) +{ + memcpy(name, &z_name, sizeof(*name)); + if (IS_ENABLED(CONFIG_NET_HOSTNAME_ENABLE)) { + strncpy(name->nodename, net_hostname_get(), sizeof(name->nodename)); + name->nodename[sizeof(name->nodename) - 1] = '\0'; + } + return 0; +} From 59adf0bb74a2b28f4a530d349bd8c656509683d1 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 5 Jul 2023 00:21:37 +0800 Subject: [PATCH 1037/2042] samples: posix: add sample for uname Add a simple, testable sample to print everything in the utsname struct, and added a `uname` shell cmd basically copied from nuttx just for fun. Signed-off-by: Yong Cong Sin --- samples/posix/uname/CMakeLists.txt | 8 ++ samples/posix/uname/prj.conf | 3 + samples/posix/uname/sample.yaml | 22 ++++ samples/posix/uname/src/main.c | 175 +++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 samples/posix/uname/CMakeLists.txt create mode 100644 samples/posix/uname/prj.conf create mode 100644 samples/posix/uname/sample.yaml create mode 100644 samples/posix/uname/src/main.c diff --git a/samples/posix/uname/CMakeLists.txt b/samples/posix/uname/CMakeLists.txt new file mode 100644 index 000000000000..82257e7cc7d8 --- /dev/null +++ b/samples/posix/uname/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(posix_uname) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/posix/uname/prj.conf b/samples/posix/uname/prj.conf new file mode 100644 index 000000000000..47e3b82e5ce9 --- /dev/null +++ b/samples/posix/uname/prj.conf @@ -0,0 +1,3 @@ +CONFIG_POSIX_API=y +CONFIG_SHELL=y +CONFIG_SHELL_GETOPT=y diff --git a/samples/posix/uname/sample.yaml b/samples/posix/uname/sample.yaml new file mode 100644 index 000000000000..cfe990eb127d --- /dev/null +++ b/samples/posix/uname/sample.yaml @@ -0,0 +1,22 @@ +sample: + description: posix uname sample + name: posix uname +common: + tags: posix + filter: not CONFIG_ARCH_POSIX + integration_platforms: + - native_posix_64 + - qemu_riscv64 + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "sysname\\[7\\]: Zephyr" + - "nodename\\[\\d+\\]: .*" + - "release\\[\\d+\\]: \\d+\\.\\d+\\.\\d+" + - "version\\[\\d+\\]: .*" + - "machine\\[\\d+\\]: .*" +tests: + sample.posix.uname: + tags: uname diff --git a/samples/posix/uname/src/main.c b/samples/posix/uname/src/main.c new file mode 100644 index 000000000000..93af0af529db --- /dev/null +++ b/samples/posix/uname/src/main.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include +#include + +int main(void) +{ + struct utsname info; + + 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); + + 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 0736448d37d4323a123033bcf1b8280741f0684e Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Wed, 5 Jul 2023 00:51:22 +0800 Subject: [PATCH 1038/2042] tests: posix: uname: add test add ztest for uname api Signed-off-by: Yong Cong Sin --- tests/posix/common/src/uname.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/posix/common/src/uname.c diff --git a/tests/posix/common/src/uname.c b/tests/posix/common/src/uname.c new file mode 100644 index 000000000000..bda6ce666ea5 --- /dev/null +++ b/tests/posix/common/src/uname.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +ZTEST(posix_apis, test_uname) +{ + struct utsname info; + + zassert_ok(uname(&info)); + zassert_ok(strncmp(info.sysname, "Zephyr", sizeof(info.sysname))); + zassert_ok(strncmp(info.machine, CONFIG_ARCH, sizeof(info.machine))); +} From fbacedaef80f4d93fcf08345fe14b4d0aab6bbdb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Jun 2023 08:52:23 +0100 Subject: [PATCH 1039/2042] mgmt: mcumgr: grp: shell_mgmt: Fix issue with unset variable Fixes an issue where a variable was used without being correctly set by other parts of the code. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c index 067b02d87bef..f6cb3f014ba6 100644 --- a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c @@ -83,9 +83,6 @@ shell_mgmt_exec(struct smp_streamer *ctxt) ok = zcbor_tstr_decode(zsd, &value); if (ok) { - /* TODO: This is original error when failed to collect command line - * to buffer, but should be rather MGMT_ERR_ENOMEM. - */ if ((len + value.len) >= (ARRAY_SIZE(line) - 1)) { ok = smp_add_cmd_ret(zse, MGMT_GROUP_ID_SHELL, SHELL_MGMT_RET_RC_COMMAND_TOO_LONG); @@ -95,7 +92,7 @@ shell_mgmt_exec(struct smp_streamer *ctxt) memcpy(&line[len], value.value, value.len); len += value.len + 1; line[len - 1] = ' '; - } else { + } else if (len > 0) { line[len - 1] = 0; /* Implicit break by while condition */ } From 860515a3ad6ad9c73fd82cce72427e9d9ff49366 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Mon, 26 Jun 2023 14:43:24 +0200 Subject: [PATCH 1040/2042] samples: subsys: usb: webusb: Fix Win10 detection This patch refactors the usage of MS OS 2.0 descriptors in the WebUSB sample. The function subset header was removed since it is not allowed for non-composite devices. Also, a new random GUID was added for automatic driver installation. Signed-off-by: Maximilian Deubel --- include/zephyr/usb/msos_desc.h | 102 +++++++++++++++++++++++++++ samples/subsys/usb/webusb/src/main.c | 76 ++++++++++++-------- 2 files changed, 150 insertions(+), 28 deletions(-) create mode 100644 include/zephyr/usb/msos_desc.h diff --git a/include/zephyr/usb/msos_desc.h b/include/zephyr/usb/msos_desc.h new file mode 100644 index 000000000000..372c8aa5ac51 --- /dev/null +++ b/include/zephyr/usb/msos_desc.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief MS OS 2.0 descriptor definitions + * + */ + +#ifndef ZEPHYR_INCLUDE_USB_MSOS_DESC_H +#define ZEPHYR_INCLUDE_USB_MSOS_DESC_H + +#include + +enum msosv2_descriptor_index { + MS_OS_20_DESCRIPTOR_INDEX = 0x07, + MS_OS_20_SET_ALT_ENUMERATION = 0x08, +}; + +enum msosv2_descriptor_type { + MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00, + MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01, + MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02, + MS_OS_20_FEATURE_COMPATIBLE_ID = 0x03, + MS_OS_20_FEATURE_REG_PROPERTY = 0x04, + MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05, + MS_OS_20_FEATURE_MODEL_ID = 0x06, + MS_OS_20_FEATURE_CCGP_DEVICE = 0x07, + MS_OS_20_FEATURE_VENDOR_REVISION = 0x08 +}; + +enum msosv2_property_data_type { + MS_OS_20_PROPERTY_DATA_RESERVED = 0, + MS_OS_20_PROPERTY_DATA_REG_SZ = 1, + MS_OS_20_PROPERTY_DATA_REG_EXPAND_SZ = 2, + MS_OS_20_PROPERTY_DATA_REG_BINARY = 3, + MS_OS_20_PROPERTY_DATA_REG_DWORD_LITTLE_ENDIAN = 4, + MS_OS_20_PROPERTY_DATA_REG_DWORD_BIG_ENDIAN = 5, + MS_OS_20_PROPERTY_DATA_REG_LINK = 6, + MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ = 7 +}; + +/* Microsoft OS 2.0 descriptor set header */ +struct msosv2_descriptor_set_header { + uint16_t wLength; + uint16_t wDescriptorType; + uint32_t dwWindowsVersion; + uint16_t wTotalLength; +} __packed; + +/* Microsoft OS 2.0 configuration subset header + * This header is for composite devices with multiple configurations. + */ +struct msosv2_configuration_subset_header { + uint16_t wLength; + uint16_t wDescriptorType; + uint8_t bConfigurationValue; + uint8_t bReserved; + uint16_t wTotalLength; +} __packed; + +/* Microsoft OS 2.0 function subset header + * Note: This must be used if your device has multiple interfaces and cannot be used otherwise. + */ +struct msosv2_function_subset_header { + uint16_t wLength; + uint16_t wDescriptorType; + uint8_t bFirstInterface; + uint8_t bReserved; + uint16_t wSubsetLength; +} __packed; + +/* Microsoft OS 2.0 compatible ID descriptor */ +struct msosv2_compatible_id { + uint16_t wLength; + uint16_t wDescriptorType; + uint8_t CompatibleID[8]; + uint8_t SubCompatibleID[8]; +} __packed; + +/* Microsoft OS 2.0 Registry property descriptor: DeviceInterfaceGUIDs */ +struct msosv2_guids_property { + uint16_t wLength; + uint16_t wDescriptorType; + uint16_t wPropertyDataType; + uint16_t wPropertyNameLength; + uint8_t PropertyName[42]; + uint16_t wPropertyDataLength; + uint8_t bPropertyData[80]; +} __packed; + +/* DeviceInterfaceGUIDs */ +#define DEVICE_INTERFACE_GUIDS_PROPERTY_NAME \ + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, \ + 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, \ + 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, \ + 'D', 0x00, 's', 0x00, 0x00, 0x00 + +#endif /* ZEPHYR_INCLUDE_USB_MSOS_DESC_H */ diff --git a/samples/subsys/usb/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index 2f484e3e5c27..d9e40d9b9911 100644 --- a/samples/subsys/usb/webusb/src/main.c +++ b/samples/subsys/usb/webusb/src/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2019 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,33 +21,51 @@ LOG_MODULE_REGISTER(main); #include #include #include +#include #include "webusb.h" -/* Predefined response to control commands related to MS OS 2.0 descriptors */ -static const uint8_t msos2_descriptor[] = { - /* MS OS 2.0 set header descriptor */ - 0x0A, 0x00, /* Descriptor size (10 bytes) */ - 0x00, 0x00, /* MS_OS_20_SET_HEADER_DESCRIPTOR */ - 0x00, 0x00, 0x03, 0x06, /* Windows version (8.1) (0x06030000) */ - (0x0A + 0x14 + 0x08), 0x00, /* Length of the MS OS 2.0 descriptor set */ - - /* MS OS 2.0 function subset ID descriptor - * This means that the descriptors below will only apply to one - * set of interfaces +/* random GUID {FA611CC3-7057-42EE-9D82-4919639562B3} */ +#define WEBUSB_DEVICE_INTERFACE_GUID \ + '{', 0x00, 'F', 0x00, 'A', 0x00, '6', 0x00, '1', 0x00, '1', 0x00, \ + 'C', 0x00, 'C', 0x00, '3', 0x00, '-', 0x00, '7', 0x00, '0', 0x00, \ + '5', 0x00, '7', 0x00, '-', 0x00, '4', 0x00, '2', 0x00, 'E', 0x00, \ + 'E', 0x00, '-', 0x00, '9', 0x00, 'D', 0x00, '8', 0x00, '2', 0x00, \ + '-', 0x00, '4', 0x00, '9', 0x00, '1', 0x00, '9', 0x00, '6', 0x00, \ + '3', 0x00, '9', 0x00, '5', 0x00, '6', 0x00, '2', 0x00, 'B', 0x00, \ + '3', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 + +#define COMPATIBLE_ID_WINUSB \ + 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00 + +static struct msosv2_descriptor_t { + struct msosv2_descriptor_set_header header; + struct msosv2_compatible_id webusb_compatible_id; + struct msosv2_guids_property webusb_guids_property; +} __packed msosv2_descriptor = { + /* Microsoft OS 2.0 descriptor set + * This tells Windows what kind of device this is and to install the WinUSB driver. */ - 0x08, 0x00, /* Descriptor size (8 bytes) */ - 0x02, 0x00, /* MS_OS_20_SUBSET_HEADER_FUNCTION */ - 0x02, /* Index of first interface this subset applies to. */ - 0x00, /* reserved */ - (0x08 + 0x14), 0x00, /* Length of the MS OS 2.0 descriptor subset */ - - /* MS OS 2.0 compatible ID descriptor */ - 0x14, 0x00, /* Descriptor size */ - 0x03, 0x00, /* MS_OS_20_FEATURE_COMPATIBLE_ID */ - /* 8-byte compatible ID string, then 8-byte sub-compatible ID string */ - 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .header = { + .wLength = sizeof(struct msosv2_descriptor_set_header), + .wDescriptorType = MS_OS_20_SET_HEADER_DESCRIPTOR, + .dwWindowsVersion = 0x06030000, + .wTotalLength = sizeof(struct msosv2_descriptor_t), + }, + .webusb_compatible_id = { + .wLength = sizeof(struct msosv2_compatible_id), + .wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID, + .CompatibleID = {COMPATIBLE_ID_WINUSB}, + }, + .webusb_guids_property = { + .wLength = sizeof(struct msosv2_guids_property), + .wDescriptorType = MS_OS_20_FEATURE_REG_PROPERTY, + .wPropertyDataType = MS_OS_20_PROPERTY_DATA_REG_MULTI_SZ, + .wPropertyNameLength = 42, + .PropertyName = {DEVICE_INTERFACE_GUIDS_PROPERTY_NAME}, + .wPropertyDataLength = 80, + .bPropertyData = {WEBUSB_DEVICE_INTERFACE_GUID}, + }, }; USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_webusb_desc { @@ -113,7 +132,8 @@ USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_msosv2_desc { /* Windows version (8.1) (0x06030000) */ .dwWindowsVersion = sys_cpu_to_le32(0x06030000), .wMSOSDescriptorSetTotalLength = - sys_cpu_to_le16(sizeof(msos2_descriptor)), + sys_cpu_to_le16(sizeof(msosv2_descriptor)), + /* Arbitrary code that is used as bRequest for vendor command */ .bMS_VendorCode = 0x02, .bAltEnumCode = 0x00 }, @@ -268,11 +288,11 @@ int vendor_handle_req(struct usb_setup_packet *pSetup, LOG_DBG("Get webusb_origin_url"); return 0; - } else if (pSetup->bRequest == 0x02 && pSetup->wIndex == 0x07) { + } else if (pSetup->bRequest == bos_cap_msosv2.cap.bMS_VendorCode && + pSetup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) { /* Get MS OS 2.0 Descriptors request */ - /* 0x07 means "MS_OS_20_DESCRIPTOR_INDEX" */ - *data = (uint8_t *)(&msos2_descriptor); - *len = sizeof(msos2_descriptor); + *data = (uint8_t *)(&msosv2_descriptor); + *len = sizeof(msosv2_descriptor); LOG_DBG("Get MS OS Descriptors v2"); From f87a589f5d458832240a7c15008cdbd77cbf268c Mon Sep 17 00:00:00 2001 From: Joseph Yates Date: Wed, 28 Jun 2023 13:53:21 +0100 Subject: [PATCH 1041/2042] boards: shields: Adding support for the adafruit can picowbell shield Adding support for the adafruit can picowbell shield for the raspberry pi picoi. Also added nodelable for spi0 called 'pico_spi' as well as an GPIO nexus node 'pico_header' Signed-off-by: Joseph Yates --- boards/arm/rpi_pico/rpi_pico-common.dtsi | 35 +++++ boards/shields/mcp2515/Kconfig.shield | 3 + .../mcp2515/adafruit_can_picowbell.overlay | 32 +++++ .../mcp2515/doc/adafruit_can_picowbell.jpg | Bin 0 -> 41795 bytes boards/shields/mcp2515/doc/index.rst | 132 +++++++++++++++++- .../gpio/raspberrypi,pico-header.yaml | 34 +++++ 6 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 boards/shields/mcp2515/adafruit_can_picowbell.overlay create mode 100644 boards/shields/mcp2515/doc/adafruit_can_picowbell.jpg create mode 100644 dts/bindings/gpio/raspberrypi,pico-header.yaml diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 9ad33f1993a2..4cc49ce5181f 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -32,6 +32,39 @@ aliases { watchdog0 = &wdt0; }; + + 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 */ + }; }; &flash0 { @@ -110,3 +143,5 @@ zephyr_udc0: &usbd { regulator-always-on; regulator-allowed-modes = ; }; + +pico_spi: &spi0 {}; diff --git a/boards/shields/mcp2515/Kconfig.shield b/boards/shields/mcp2515/Kconfig.shield index c791933e6ba2..5cb2ae7d7b90 100644 --- a/boards/shields/mcp2515/Kconfig.shield +++ b/boards/shields/mcp2515/Kconfig.shield @@ -6,3 +6,6 @@ config SHIELD_DFROBOT_CAN_BUS_V2_0 config SHIELD_KEYESTUDIO_CAN_BUS_KS0411 def_bool $(shields_list_contains,keyestudio_can_bus_ks0411) + +config SHIELD_ADAFRUIT_CAN_PICOWBELL + def_bool $(shields_list_contains,adafruit_can_picowbell) diff --git a/boards/shields/mcp2515/adafruit_can_picowbell.overlay b/boards/shields/mcp2515/adafruit_can_picowbell.overlay new file mode 100644 index 000000000000..861839de9c34 --- /dev/null +++ b/boards/shields/mcp2515/adafruit_can_picowbell.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pico_spi { + status = "okay"; + cs-gpios = <&pico_header 20 GPIO_ACTIVE_LOW>; + + mcp2515_adafruit_can_picowbell: can@0 { + compatible = "microchip,mcp2515"; + spi-max-frequency = <1000000>; + int-gpios = <&pico_header 21 GPIO_ACTIVE_LOW>; + status = "okay"; + reg = <0x0>; + osc-freq = <16000000>; + bus-speed = <125000>; + sjw = <1>; + sample-point = <875>; + + can-transceiver { + max-bitrate = <1000000>; + }; + }; +}; + +/ { + chosen { + zephyr,canbus = &mcp2515_adafruit_can_picowbell; + }; +}; diff --git a/boards/shields/mcp2515/doc/adafruit_can_picowbell.jpg b/boards/shields/mcp2515/doc/adafruit_can_picowbell.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2e6f12030e82d5ac89ffd95de3c50f5fd11e813 GIT binary patch literal 41795 zcmeFZWpErz(k?t=W@ct)X0n)>VMHTluxyJhX31h^X0|OHF|%YbgDqyspU&B{@b2Cl z@!k9PZcS8lPIY!ti`I70L0sY7V?e!i;j33z=VMMbNr8Ugb*-)(y4DW(O-1V8%_Tg z&)cN{EXaTI+lBv4X35+5^;>sxb~LwiCubp-cQm&Fk}ElTI=vmZSUETWfOl`_|IqRG zBP;+A4+nsL8)4_BuRWsfdZ``52hlIk>sG$>;<`_&J4HxwtuhzX^drKtMo7 zLdHiy!RMqPrr`WPZoj_+FyH}kfFURdN&qAV1QZ6u?|uN;n@ccnGyTV8|JB|C1q}lW z2akY=^v2MP4uFJ!f`WvGf`Ng4iz!6FAAy9%fWf5TkbuQfH;1Ei#pVo5$cLwrtnb0m zm_DcGvTzGRK*YtvCm^JurK4wHtEX>ZX$7>lv9+^z z_we-c_VM)#4hanl{~QsSn3SB7n)W3jJ^K*LaQz+y_M!tV@oFF*Y_Y$acP|6Sh!6i;!<;O(OmrD+Mk~N z|8p$p|H`v}IQCD!RshIQ5O0$Qg#i!)+&$74d_trzqJ~HkN0QM^+-Z3AM4T9LpVMlm zSnAfw)SXRI!$t9h@1&x{-0|Ks@{W9#t6*F+7~ELKJ(i4GB(;=}_fgB+Ia$1@;XKi< zKi@Gtx=?iG>6aU8Pa2AeK3)5yXmw3>4t_t^5oLQkqUPU?@snFO=luAf_TNxdib zWd*?)ef7QsE}vNoZwq$tqL}7@_mnEh7z4KoA)nevfW(nDLAirslwqQ}42~q?p9cS7 z^#7(031+GK(lqieW7I($f)wm#a7M}UNR)ji3TuxN?fH;_m)5!vTS?&rhjL~76LKo| zRrV7rEaMbJKfS4AOUlmOP zX~pY^k}@mNFA9i!w}z=okNnQX>+b02ro7W1r4r*=rfZ?7b5=G)pEi|q?DGZ})Xj51 zsP0tiR%uJCq5xHAM22ChElz(M^-s*C%fRnL*F(eAhZgPWTNyufEh6HWVk&z!9|N<{ z^62O?3WeR}>^&9v45J*yTyuWtVxk)g=#l`ST?Ee#1S&n|n=v!LhQ+2stCk7ltz_Nl zj`b`Xe~M<<1bn&}MRiSh9oG*xXrKP&R2{R1=Ph*?iC2z=za*|6*`G)ln3R>SUK4wrzX-HK}Vx)+l7C~$#x$H z*2Mg}e?LyBaP-k6ywdh7P1AhAC%j0Zh~x&!5&U-$J&gXFH^dl*o?H76rOR?3YmJxW z%Q#l;tA0{NNbCl}Z|1ZU`|o#}qTY{eU+&8!{wSJ>KyvocgLO{JO}^|S|0E~cwci}0 zlKAvUFhZjKV_LmWSQmr2Zm1?^I(e5cv6<_CmjQ%7>+`+MDq!X50J;Q~J~RHGfpL90 zy=QZ$d>ZI=m42+QZNC9IpsG2R@%3z1CsgG62B;gHZNZ|9u<+ji%+*zTSFDEw=FJpj z-;oq5DsmS${%0n}B-d%mE$lm9)@GcUgBTtb4Tf5M{2ybiRyMLC(6+D}D)5inZE;w3 zkEiEI4|2=f#_i1T=7)wPT*i*6X(i(UFxM^PWli;&5l)0#S_JRtY?9eG{Nomj9hMK# z-nXXtWj8mu8z=0q_8Mo%pyYl@3J!u>1Gf*#m~9uc0$=FnuTiXi5}y!X_uX`Hzp`4m3%L=vK63ilWYN-;13!cCqmgLz%3N{x3QRy2XFoUB zbidnxht<2H{Y*b>3rW=o;D^9=-Pi|U#5PZ^>f3#wwe{#sPMmp`iaR5D1M8YsmppIY$|JJVP*GCaXbW{GQL?=2IPeN8?y)tP=~DiO^^2W6I9nyJH2 zQb8xJ&OYjhrdKHz*xeC&{1R$T8`|ISC{TYE<8^5p9)gAlTuhKJv%57&1iNF6Gz8>M z=qJO)z^h4eVYSD~vb#xaB5Mt=Zd*ov>s6bn^$ZY`30D3lTUVE(LEEVZpn)GmI9sxU z_~|z{eY62&UQs9_8je-FD(-hgg;-m4k9GaE(JY7enfV6Ef3kJ8$Qutv$7gip{Qwy| zxqEOY9Mpq#t=;V%?zuuW_oG+h7_!dZr?eJt&da>4i^T7wAvToJ#TNm6j&fU^X7AV% zwdODpY?_@Jk(@UkRdM%0CPEi!^6)Z&3JhdBp9H&($Uin8*{g5nElDL;%ZZ);Jm& zB4yQ-9Op{`V5wtkR8YCHETLA)4L1fKvv&#cJ2>jE zXur`EsflmO;=k++9o*n>BpKQVsjCJM9AoRE0e40Xaq5Hh5`ESWTy%5L6Is!8WhNjd z;Yiw{s=ew*5(jIEDhrXrG~+?G!}7)iO|y+;GT7Si^aYWCf9;I1<%LTi+`;w7Wm-vo zYPYYOx0Q2haPh~YB=cQp9~N&hqJHq7Kd9-U$?p6HRDUl$dZlRW=#00!G=8br<*r#o zHj-%~r7}4?6f-I4woB$rAxD>m=Q+q>xOXHO<+%;PT;Hh_SHX!hO`CenRXE6It>=k; z+m zP&LEZxfyDWgwM#?7w;mLZ4=zX@}=?szQOdw@`2KBc_&3QY->k$-A0@e&D3|?VpP}Q(o)|_Kkr6;QjrTDmv%;89()fE;Bb@yWaTV!RMOy zx$G5JxnIH1Zt!Pe>P!0_L`3Y>4b#w7AbN9RzjK~OiGJD9(_9WNu0F{uX~IWip1?mb3U^y5YFAk#;g3z=&c z)Z*KE+)O4U&(?O0aVAux=TDniyE~U6pw#fm#`ZSB^`ly98QfOB`j=vK_%PIUpL))61=(PL`?9vtAjHNEL~uL(|5QMRVX^rA56Fze!n*ID;f#9^#Z9PZE zw{cai2_z-O?obGS@*BeP-L zt14Zv)GM~NOcdUEBlOkY$61=lRUVO2oJR%Z=w}&lVIg1eYLThuc5Kuxbnh3mw*>u! z3)-emrNg)K91;taE-$y&NQonwHkt8nE1GpYGqs{_xi>DoLVVe`5dPNvx=7XHQxmK> z^EpiQjHtQ$n>Ebb8AfnYVBo!_x5^R^Z2M-6qIhS3ZXYH`$ool9R=h~#oaf!+0&C_r zNHJ>K8Kuha{T)TdOi z$3|v|(dZju-mNexKW%&GNxs{yPRHlSxt{K9Q&Ig&PVP}#S{GOlg8H;{X0ab)XBvKrtB#?r<$n1M@Ywtb*xW@OQlzO$RV^O2 zp($F%1XB;V56Y#oyZBoMKA*(K>9>bn`df0}rK(v_cL*26v>gC;gFc)e>}~Eu2F&lR z2_jD|D>{=j72&q!2zN!hd9z}NLPsN8)xdh8W*$*n*3TFpYl3}#eNg_I1q)~$Wf%Sp zs3P~+$)l@%zg=&0!K@okMmugW9|S)ZDDP70LgOM%;?pDi7#JbUXH8MxIZdXO;C#?$ z)O#93Sbo6JNuG#CSMC0o(skRqxHzSfrlX#gVMpP(ZUBP-P3JX*u!1VbfAfn&eZPaD zB_+L)FM`EmG>WWgH8|Z$&KLE(xXznu2aXDA4}kiGU9t}C}>^BU1rfaQ{!|KHI(wBWz}%CpW61_puYT$FxnSP{>@#B(hmP|gTa+m zwXQ@xGb8CpX;99mEm=;HciazHDNF9$Rj~^b`yim~Y_-EgI)@#rQ*>~RJanR{&R^Cxw+#`^#fKN03MtueWX}OHGZHjgIz^m`fJJrq`q2f?LUA?x98^sP))O=L1Kk zqBAS}z-rf)Wpm`|8h6BxtE9R(Nm=*VZa>`Y3d3V{r_b_4fmbq|*q)EU&tROLY1))6 zA^*`OW@nQVF`K9}Xz)HHr^4oLH0ryfK{VQ`d+lZxdp%$ao}XiLgs5)vKy=l?{-{6? z6mi^Ck^+{UT?In%qO3m)&d`1EAnrOzi>BYJRi{L6v~^nVx?T$?Si<0{ zFzST+;eoAuVfr0B6=iDG;eQm;JHm$NucQ5lcRKzKH>_XnqnX2}KfMNgXkMO{AK2OAM7gvWYR_;`3Z#II494Q>5EEyCwn6%wiEs?nG_b zvv%+e`hy-A=d5EeycDz`yQtnGUwB+}J`|vJ1KSmBa-Q10d62q2vb}B0@fp_8SDys0 z&ZX`7F@PyYYt5ANY21=~KBr$Wwb>?bZRLp2&z{wRA1L2jRO3rg$Jv+VwG-{Ce`TwR zoY?F18!$72iBR9|tnCizWi^IF&oj;D6(X=q>2Pj9IHK>+mSb)xFBMShK1%)8Zf zQt2Xlm57@UkNsG%@`q{Lm2h|_ht!1op2ziWbnpa>g5M9j$K-{KlSk43M@P|IZ;<~- z8zF9mQk zTYnL+{q+|oz2@o+#;_F#0SiIP;I{Y1T3A_UB67hf>Rut3plv-p5Tdypb1 zHO2~oa>p+op4=PSySluZ#i^;exg-2TRGi?p5K1leWc>GcV7S?o33gf6ar5JK!f&o_ z;~;v|RQ#kd#{ur+N<|6T3iTzmRJzjV1`<`QMblllulkVd zrr9Z#j4@-`*%?!>9^KZok@B@7_0*iF$?SDcq) zLX*WG=~zVBGm#c)yc=CveRuqnEt=pqTa>xVj0#fedOYaAUC~r1_ljb+JWxYorzXh* zzz>tV_**SXZT$vd4419Q@-Xq%cal5l2xzD(kuG2JKZEp!9sIsn?o>se-aNE==6T$S$e!=1JMi}Cx<-c#TbOSYX&`Jj+RhQw8oTXst5)LM+&05~~-b_e;&xhoAc#S7?^UA~8Tg?|D3eRjF~B zE<*`_SJG@CZ6U+unc*ZJ8@n(rKbhe7}Y*6d!-hT$(a-qtqHQ^wvcl3o~D0xj` zZ-TuL3P8FWqMD3YR)QEg%J;2ssh-1kHPaU1 zYIV3BAL&<>65A;_a>Sv&k-!3mcS)Hdx*hqXrdS*uV@oEz-rq9tB|gcD5A}d&p=}b`F1bU24}s=!lk2rhheaX_WmhbtY+qtm*Ba!* zG_#^HqAyhh@VPTY@&swpHIVSJ&qPpV{j_xE3&#dPOkD1A7fPwtqpIo1IiQZJ*xj8V z@fVK!h3x)W<00fK!znME{&hLJ+thS&D0U&P&@(XELSb#tzwsy}scK08 zjG(tYIG2C;sZ!H;eSHK<_>$T+Z&ZjF!l?OuihM0^rh`gQ*TXuhqIu$&!L7`NnAf9;`5lW(Bkm1Nm!ZZG*!?- zzxrTQWK`jFfGf)^3o2d^tweC4B)q^L?@>v9Tf&)oRg2n18bU*0!oSrrRxI0l#X63p ziLrzymScwI=>9h#lwY&uF{c=Y(WP-MQ##1dm{-WxiKdO?oF;iMZf8Am8UPU}V{ePC zF2nvGH?OyKL8kR(LwnvtgC9M_Q}5V^PU1nM!cv<|zX51Ni?3w9#VrIZm>gJguSdiQ zk1wEw!}4V8RzgQogyM~TqJqY}IqPH$o;BLdWT+Hjtem#Zi$NKWUZSWU8cf+zn(ZyK zU*I>J6a$eHH_Z-md?#S#p<+2AkA#&snUu{}E_+f()lRx)F(#kHz3+%$Kv8KLnaZ7t zs#r&guI`RW&P-*(vEkmXzb0pSCh135_v`HqxKwp!Ssk||Sv`h4_zTQdXJM>*dNfxP z`5&W6?=j>tyuudfTIvHKlthGL_s^+e54VJJi3z&uSPPrq#`*8Fp98dIt;bz@;Q`%}!uK=|C#A3PAunQ#BJ4(QHv(;;Bwk zUF4M2`x%VUoNq7otuol-lK=ky`S0Hwn`1EhjGB1wrkJCi*{0(k%g+qB)!@SK3wstj zpc=a@u2d~JTpMY{#QRz=MdwCGpH9Y)N~@ofjKO#k{ae|3JNB)78?q15G3W>jJfga}M zK8_Af?t(rdlz$2re53yuW}_tklf?rhLaC>$MlR*-1|;WZv~$-~@-#mSxO?-Hbe z?v`$LE*^HyPUL?`G`Dc}^bnzZ)BmSomTvC<5c@wOU}^3MbTemhGxuh32YPteIoY`X z84*hIw@U=ynY&B5IlG8Z%9=a411Z_w%w_w_-ap8HxGzfn-}c`K{5Jysjlh2+@ZSjh zHv<3fMc|(W6wv9dYVv+7kN!Z_0ASysE-=uruy24DI9PZ@bVNi11Vn69G-PxA}V5BTykb|Dq1=QMg{^h7IqeTb{cvH`ahvLZ@?Zzctk8jL@atjTtfQ) z788viA7vn~RXhWh(W5G6SH7Prz|Fxf^1+ zDY=WA&))+eE9gXQ42f9$Bx>qc32?Cv8)i+t17|?lvuTEN|0w}tGFLF`%=KYsMea-7 z2B~HLQ0dM02kl)ZdApt2W3E}2%3olmUF(*F#@V9iQlW!uUi;qwgqYQHBM8i4S54~BWx_vFa;M)O#fiuJdX>iGU6Y!dqcB|^KJi#B zQo~Af^v(UKTKs>CghBAfA`(J+C`!rgGX(wmvhHD1l<+0ge)*#LTa(-k5f?{opy{AN z2hlpg23gT?0PpnGD5`b>u9xSJ`bGKF=c<`RHcMljk8Jf#HcJG?vdfQ{|Ed52vy?>Z zn8j%9*M1I4fHP~R=0fWCRfX0=@Pzg4$PL)>&`-y+?x@LkH75D-NzNg_*a1wiVv50; zr?mzwMf{|NbiTaU?w9Bw7gWrYXc)j|}atK0AY3@T*q z!G`{h`~x2-tHygxec&i3@yct#z((B{lo_ROwYxlK*#8n-EVSR8tXo@IJ5gfL%j4?1 znB_Jj_D;?O^EB42(}UjDNrd3Ulo%w)kizbJy92v^;?N1MD+C*kvyC~ojJj1ebxZy; zv=9$jGZYs~-^?D?`4V=-1~W{x*4}-&aC{1DvUgYaW}kHF3})lgGT|H5m#KWXK%MBD zHua{JC$-5zzghSwS;2EE{rGTua)XaXNWTY0J`m=;c&NUxA1`hzt*&us^UFBuK4A5z z%J=*94>zGE^J9BoYD$IPPi)uF>NYl(cSa-)tJ`J+?MUZObmht?6`}+)UaN#9vK@4n z)ZBSV1TU&quO>XJCgb!ACWf##I%LAzG_H%<<}%hD8`p}i7qZ!Qb{bnQOKbIgLQ|Hg zYLX6Ki?4ZjCYJxH6+rBgEAbpYC=`Hpptk{}BdaVfSeN{q-affH-dMHu(1%iSW`2Fx zd(zEww%zfIp+r?w%Xcn-jHogYv8MSoN|m^L56W)8gU&IisqoA6@kR2y{Wo_%;^w+a z;6BTv`06<5?CLA$;^Bu^n{P+G&Ie>1@~pcN_xIo{XdDNtBOipZi|Esc976 zL^Hc_ZrM(cgXyHP%aF)acS6QP5yeg$sA^%q|GrN?cILA2n#l4hyT)&7cE9jC;_T>n z>Z~t8{XjxRdc%yBtGg7{rQ9CWS^2cHy*jzaRWT+$zB;i6dR4tfG&MaIQ+^>0a`?M` z01V&w2XJrFMK)a5Am5_vM7-+QOiXEFaH}TVWpYf8#oXWJo>nu!|73$?dv(tc318d!EEkaqaRYZjyx&gAk(CC4jeSa9;$0=B4= zFNv5S!_#Vpvnw5+s%XvyxcU1(JO*5xn%A2;6-{jLPaTNa2~|WSTrM1R5t20AtcHdt zd$JU3sRrQs@je)P?m3CqE@<~Jzwfle)vNaSjPE-B6|7Q2a8G8OThgX{AlOVTelZ_+ zplcT)mSdrk#MS=zxM6&dn(F^xY6jGGF5vVVZ$S8`W;nF$01n;$+Ut*EBaiqueAhF5 zDBd=H7T%cDV^-DMF4e0_zX6J~5{3_+Ddmr^R;?4g!XGC-h~{+rRMXuBYnB+2iT(z# z<)#ZiDm~ud;RqhvF`Qa}1Xa?L?aJv6xUU2B4Q)MgbS|vPng6L3fU`jVKBMx?$KhAj zym<)_G@=tUR#G@VP$;QaQV7oaA#&Q z2Wgre*AwIHN<1=1+x%9WhBeEF@j~>q55l)U!dIsXsmn|klNQpoMAsRH(Y}yLS2s?t zJX61}G{=}frvIz#HyR>kp5h|sH$dg#CtsZ!NIrma=AZ_g_7mh#eDLkP4ak)J@&;@= zh;znY(I}?)up#prY#Oz$uU(P$@F5qoSULUb@DJql|7;hh7Mvd~%O_m#?!Ria6?6g#uG;!J3ot4)eP;F3uMK>iWS*#0C^3So95quhN`1R$Uk7>#H z(_KVX?qMQ*6id7HvQAZ2IiqB5^X77sL#P3XS;_()?E%W2epdQxr`!xK6T`lfw!ui% zAkfjHzC}$`@QB8tA&%w9?sH&|Ts!f_%lpk__l7Uf%1Qf${(AwZ)foqZ{a#fjexB3% zrh_dG4&Gr%p=iTt)X&p*DE*3~&)Ao_yn$eca^&QbiHan@kqdiwtofN_ zJuLREf_)g*DAXka%Fpk*Dp?$G!&_Hg*=}Jd7#&EZZ!D1-dDBM?U*$ihgPP5bJfxJ~ z+vux{L5v;QclKx+Fj&@lU8GcTA8SQc2FP%qEomHsy86dK7L(2nU|3;1{@Pz*8T$vq z8}AX)js@_97P=e^zQgpv2nmjZ7?v)sUQP$bWyGczLRW#7F2m~k#cHF5NL5NRc1D#o zYp$OpEzdNCtr{!YO0%jP56#y0?KzQ$ENm{^v>u6+G zalu`g43@{aV~%_F;dUV%63{n`wL)H&wSsGfCQYHDpGOt~i_h>{6sm)s7P&GRAzC-m z>ZF7dg9_GQJ8O1`P|mgMRN9I?Th?xc4Yo9Vdl=6Jx zsBT~gE;nkpNy(7SRN#4>=<3S%SkU&vlm@RB`qrbXsh_4Yv$mP6@GM2vHt6it8|vZa z->yMlRrU2&7|j)dqu;&Lt9WPeSjg}_MvtwC$73wYAY~*8B1}!d+YXB)f3I{*<4Bn- zy>ob#S=W3%LZVEKWVAJ>5w1Stjyua0i=V71-xO$8Wz?YMSe|WuYN%MO2V%)YauD1>8tD_|%}SLHKxD`G{x_tCnAJk^TN<#)R2v}-|y zOGiXfQ|9i%aBN24%jlJHhtucOhj6iMtdDCs3E{^4RDuZE-e@pVT#3tp7+X`ZX|YTk zaZA!lxpK-l=?bdCVkx(kZLdOnoPu2op+PhTSc2}>IN2+)$rZ+1mS{A!U78hZsreaq z^Aw34SjSR@RfePq36Hc7EAk4N3#d6Z7I7+Fb_>F-s;0GeFs3A>OZBlgMnJ~MvR(e! z+7Yr?tJc-UoaQ~sZROj& z{KX%u+142~9309~oZsX+a56W)4x}&`3@VoxE!A<3-QD;U{M6(^>{<1!(s(xGWzA1Q z-hpRN>6xvGywUqPV4uk=IBvK3YYoS`1M$bGKczg)y0Nm?CJDyFZAHzH(PF*+WI^?c z5n^wwU#JzuJxtiGInXrzVw_1$eA! zBn@BB-KmesGZ34zD=n?cmC$eXctE_ZH?pTbT916D9lPUf6Ka}MMB}tfU$QWe3Pb37 zHW!wMx#{r1<8i-Fe;yf2U#oK!4EZz0fT_xTEKWR{7@q7(I*d z1Kpf*ehph153nqxK9E@vqHwM=F6iWN%3q-FO5$VTxEL!m*7#BIVJorpU5|A$$ta&= zyK+@;tFkoo0Ggz}O`qd*YGg3C>{UMK%CL-wheNq@2X?+c}4pTOjHwo zJ1Y`emAj@MbN3Ux3M-h$(BU*aYb+1Xq|G5@?If4gjTjAW!eSt}VF6v~23DtG<=hZN ztXbl9Ua1Dj2Z`>_i=f~2#NKTSc|uKTRyo?DVAR}khd>*o*5D20l~s#j77WM(f16SR z&Mr8N+#Ix0Gk7pEC86~jI(<<#cGqK-D2lfV!#R!_O?w)VtuDf89+6-3^xMR>Wsd8v z^P}&mXIxx-xVy=Ft_zmO!^*g08h9|fab%`X2CQcYE(>?%QZdnZ0IO)b*;32}ewY{y zYbAIr8{z_udC&7xmMW3>&st`vwN0u0NGWizSrY8+=_#~kN*{vI(iM}JF?^$O>8`6z zac@)WQLCAAcJk#Ws+nstan6$1lww;=zzmRT>JJM{)jM?y4P7^`Ap}L@+^45Y)Vv7E z#Ivs39rRNsV@qclVclOUUdQ<`(W-u+ZL?I&RDGZJ^p`fKWxDvhj3bU|C5}!ZJm?2( zLST(7;xdGU|0uesVPf8BJSWV-=v%}8FO{9P6Gm3#As#3xv4sO8Bex;Ex?lt(7M-hwiD zBOX6FjnHHrj7k^gaC~xWhnt=P`n@9zk%q)u`pz1rF_})z421B`NQkbTOO{^UahXZN z$`+G`Mn1PIn7frTKw{? z=Cwv0nD^Fym(d-c;R0O=4dyZi8|WIq14|qWa*liuup3+0D*fc3Qx$=)S23Om$-|bo zw{^@Sox8T0nf&r4w7jS_2oiFAxntcmNKodqN!2bX@$xN*wI)pseZ(>qR^#?Z8f$*H znU1v$G44djwH8%*h$vKMK`=?Tp*VQ{uRyryExtkg=2r zm`a~;qq|~WG!ETZ$aa9k92rPzz$y8l)z;3oo(q+%Ci^43jY~}jeoYM*^p*NGq>52$ zpbYhg%s4TgO#C}yaZmz5S%h}uFXPtoye~|65cnEOqWtOjS$v|BB_;62Pu|GL2eJX& zm5WRDExbQ1M$^Y7w_3zAnYTG^@4=_<6uu4}Ff9L)R^1zu9t5kyK+{5}5yoU9)d@b% zx*2FCG1=y$tZ?F=g@z9>N-WdN_%;wIEM@=}l#&eHhY(rG9kYW8Q*|4u)`@VKw3}HQ zm=R8PYCYd_c>$yEDRB9cZrAhj1#I&xil`|fd}u)IGcgxJ|=}9dLaDvKFZHZ zD7};*<&J%m@ao-@o#U{CJf|X{Q1i9x6^9?asE&h98RMtdSyt?ZKhjUOd#k{|J z3Bd*CC-H_gSs_Pq?UqlzP6e#Uhj0}&*$N4PdYQf>S2rIllTlGpi<06s@!4Sr=la(= zz0?d&U_6}lLFpNua8`F{Crh6NQ#?7R-`y^KovWj#XCy3XT38%K^5ytZG&0wW(|?M2 z>Y`?}7amz(vWlPL%2d0Kc&zF)Lcj`*0bXTIgKu@uO56wK5>y@ZMe~ZA6DM!m1U;XH zl{Yv6t|!aXK&fcx69`5B?ptBt|F zDE&8pLbQI4(=!?C$FfoVMu9sFby=wN;+6z8M1^tUWD`kV^h4rf>U@`zo#2Q^YC~)) zUd|`x4}QB=R%YBEMdyLb#%KQa$#?`@uza6t77Jy+FSjIqb4z3-ua3UE)vl_4Y-)!O z2%WDLTeFhofn}6whJ?<#ityAdNGY*}oCs8pY zXJ#GfDy=qZxSWwpnJ)99{wZwNMyY(vhz1O@aWX};){pRj=|kpOZA=Mdlz%*U(jNly zVWqu}ZE{2>-Ah}^%JmMUEFkHoTUGuB2pzS|w-$#h6F%jrob9kI7@Mme@Q6<>9V_!U z#t%546>5`=`Xi;vT;q@85YL#uTp5#e0Gk?7mM?gCZU-bx^CaR7CI>)SQY)FQ!%}wL zh@|NR+wQN;qzW+s4dzN$V(`&f(N_!3UmM&31q3EyuEu#z%MK*8Xia0~8mj0CYG|uh zw}J^D1gujTlCX$yaYauYEqJDwWIS#RJ5tcb;owIup1VQ#u(KoCIW=uZ?RK_!CUm%i ze&y4@0m$K0P`_$KS)Qpj4WFAOS!7|LR(x`5lfCIF??613z^KITP*FEl^&#uD9UD66ZabiW6>cg7$Oo; zIVPG0-;cft%8Z1e_0k-%jPoTsyB)(}7Lf{yWh)#Sc(!Fhbk4#hSs!LB;kjN@Aay_A zNFn12u>|5D72fWG%#<+?bP5c;8rtU7i$>)nGb+G&n-N?9a?9n~lN5VqiWEIKVeJO; z&$690XSr-p23FiR6+ch45^-o_G*43wZV(e1SoaLNQdnupm+?(?K0484^Q>6!e7rsW z)(5?;Z~wDA;lnmYWYMZsC^DJ|b(6nlA}Z2ji!M!C?UZGSp05zo0z}7c!@Q`WdB=+y zv}gS8nPX2~^h7Vv2U%8?kmNV@@23+obDI`H#n1ZxHt zjI&GN>E2)UkJ?W7a@2;hMM-vhD|yussz25lY=o?Fp`e-tRDC0BK)!g zCemw?dAvv?@v(pS%;lq}2htS9QS#qDrQq1IPCIg9?JzDIs#=BVk$55@`9mV{@~!(y zMty4GF_Mvfs~uPpFWz&~`b*YDF|NI4-ZVPI#&%(3S$UGupp)*tO$&-_fTXt5(D0fX zjr%@Bnq40Os9)lg*_-tC8>5;Ui_E)~!TUYlMT0s`r@>xy1XD=-<|KAmSdp1CniV4L zWxbHL5gnbPaY8pkrbrsrBtpU$z4}FT^7?|5Mzh}l#=*QC35bc0P7K7Vo$cbAomJdc zTr&W8o|{j#YfFSBq2+CSS&Q7dG~Av!K^Tx!ECV%oq&FY6Q2K)PS#7G*AmV?-K^T;G z9jOyOa54>4sPf;frr_B!&pJw)VnHbw4bY4Go+KCG{RVt8LxNrC0FCoO(`$h@qme&u z7IftO23(1~tyD0)y@343o7I0`r+8bcfPloHfWqWJrxeE`mtf~qQ>fPx*9yY|G8i*!RhllF z(I)xyXBRs}yiQVQ%m-Dji7EqD*akzt0R`9_uH0XRO_k@PbW$+fY|~_dYKt=o2nHA} zhf8@#<<`#wYN>aNdx;IslQgvCM}ue2>Qxk>J??hxJ1#{Sb^IDCZe^W>3FfQ{u7~Xf z;^d1zV8&0iIC7oamHh@#g05w3XbU1Y*EYIECaHIDdK^{>zaa>6P$&BJR}%FDkPl>Uky zd$6WV--Ww-se-^}0}J2woD``_!XRUHLxArz?1TpS%a;!2D@tlQqESXH+Zkg!alRh! z*R)v?=K}8AH>*4Y3J$2}G{ADyQQvBcn5}Y3c4k3zm63&(zWhf58pZRSw-QB{Dhj5y z>ob0>-|t3~WHmIf9*?GnS>%PerU#<5t1xEWhiQzd81K3jHs|M(Qc?F31@wvMe7JYl zy0A|jqm;E%7h$us9_R?~6cmIrGA3eXQV7HSUkFwx4mRo+%m{L|x=^w*5aK z9<_vlgnGUw8xSY^ur!2bQL3%P5Eok)Y5AOM79t0)4zu0`wKTY^2GWKMx(r)^3aH>H zMH0X7wP`o|L`wR*h0}2ywe9+~23zi04t1z)DN@ZD5juBWYcGQ%v&mM7lKMzfm_+1y z@SSw*k4_neHbV+hmF4xWUu0~`MjXF7%vVraH>#sl!&qRJL7yqtx0IMam=R%(awW z->{UwHM|JnRtWKeTbRTAcz{j7NN#WR>)js-S~2f<&ycPk$TBXd@Q8;DA|6#(S%=Cl zS#)ij*r=O%J1EagbwgN;!9deqmo-aO$~1Rqk7Q03Q`rcqM=aqg@DpLIZV*cGuDuu; zmh$kWqvGy-qM>dC0`GYJBi~5>3my>{mSxiSlKgEIHcbx7&i4r!9~&0fWih)lw-q?+ zMJg%154B@)dYa{9L8@>MzJvz)+&A8q`;WJ7-k3csA`ddv!WcQfWYrpf4P~{wQVXZW zA9J+D&n10?OWdtfz}yYV)IYpakaNVGTMbGrs9#7&QJ$Q(AIy?pHK9$ZYDBxhwz0lB zZw701aOct%*T5S-N0|G>yD@*0=zFBu3zJiIG88J$PW8rip|gLKC0KhL(Ct&_>wzB; zNa$FAAv`SJJ5<0G(zEi|PKnYxEloIfypX2pEZXYav+Am!PS%jTCamwNfj<+99nlzz z7`1`T%6#CHdEQ~V1|nhA$U8Ogn@Il#?9O%$WiV^17OmUicZ^4Y0-!Md*wz9Xi&C9a!yFx(O43#BZEK5qa%wJd3%5kG9x2VBf@vH}mxitL zi@z3+Va47SkGEFmL4K+~265i@^axA;(-wL+kyhyy@JonV35wWps9lBTjsCzRR%bwFkLJ#3RxQQ?R#AY&CUw( zxTMy>TM0^bIc}RT&B={cmM~KhNiqguy*qd_=0(LC%jOthjBIjYSt49dqI5rVd)=R_ za%G|{rg{S2udCuGQ@hr@Szj%7o>ai{X{R=j(Z87A=Z%fmCcnLL0E~bwd|#-?5F7Nd@*S>ZTk{+<@1qu8&=Bo zHdRx^TFq2wRHYkG+|@@DaSiT64yJf!G1&IXI&c(}uw^E}Bb*@0vi_y$)A1LYJ0 z!3duknNaYZ1*-O{@8C5a0l=(nD&nT_q!pt{OZU}4O|k;J3a+o5C#K5!MX6-nNi zh24g=x!7gHY)@Cu1OSKI(*`ADIwycI-BR1xFiTkZ=$a)9$gIaAktEKlm+TcDhN^l8 z5lUe(FrswI8OHCZPA9%V@O5$fe9ddOh&^u2L#g4xP#_k+{e%m7pDe{vnz(mQPB1hDXw&gfshEhS#4R&7@jEs^9A^B^HJ^N6mWIa(X$g z_TmVrfYNwS=oPTlbx_lEO1Z51hPg@FOXgPV{Dx6;h&jRMf6|KEYw; z_Dc|exouIbrcvQBu*C(3CDFZW4NpoReIv(Bv}v05D{BO(owon=n_h*U0N$)m)%TSb zlX%8D;0;FTcQSdaXKUD5Uv-VUk%i>>Oc=Gr7)!qNnrGXz)^7 zMRQ1>guZ5XK4ZvTm#L>=admR1rGfu;iVW+6-77#1yZbD^dz>0FUy7{xcQ_ZsN*_8V<3R*u;1)~w)b}wiyK%^=j zw8Ksa$&Op{D(RNW8o1N*mn%Gh1gvuhjNwPjD`z!tg3(8p!@dlz-lA8M z2G)J@PTR((%fkyfZ-z>!57p(lY`WKCpu0Jx;zQTXSkcm%ar5aJA2~d#f>A*X_O(%P z=xYlkQoPrJ>Yqnc=_SnKFvtnlf9lv4V;7Vf&Q}(zZDKA>*W9nzIOD3mP#tH{d~SI{ z5}u0~FXDh?*0J;|i)jlF-_$HR9<-=$BE5-1+Y{iK?0s-73rsoIc1(t6yvU~7E9#ig z+cMJ3TF19UN-vpWI3zT~y2}WupBUwsg^_bqUGVgt(BuZ;sxmAPo6QtAUkeTL}F+ zB&RvtfDx5X#rOPWZS9AE#nu^% zt!0qQSp|t1Q(WqA06BY@W!PQc=}pi@h0BYxqlKt+i^D7gMDnA;@Fi$S8zXHrxxx#N(CLTo%@TKgX77H|d@+Gm=oT_EVf!k^TT+mCbT@F2 zd8?k63!hwB{|j;+-`+v?s(h(6%}4FMpp?FS=<32%rcC|xbN{{uA37kAb1Y)q+r-q3 z>kEu|+`RN5zn-|rdJ><%%)uPx2KkVZU+ovgP~Kmd-ANIOHjbryVHQoO6@Bt*E?exp z_cp%CH@7xy?_OpRmsR7BSeNjgWL;C^`U-dgeXlP9XbC^5Gi_16cfuARn$Shfs<2@~ z*=MD!Wt({~*!NkY=G*lN#S9(F=`Klzl2bLa+< zE-KY3vI|qG|BtV?j*8=3x`qcQxVyW%y99T4XK*LDyF-95xCeK4x8N?p83F`%g6HFR zpXYtvVVZ-nHu(rvxZ+dZ1J)f;==YuxLY)(H@{?Kqqct|LDxY zx#F4r(AHI9Z?{!YBUh(kTwOR~ZT2QDiZngxSh8NZ(On{uZE-v$4D8hOD!>FE?`X3bEH?2<$VpwZ0UnyU!#lQyYYh<%(W{E&3IIP&X&JK+r|V=19xaBGiF z@GRPS=)YUve|lwMA@`-kc*tJ&$AG`V6Vue#Ud+`y%Wl{P7=>K2T>}VA7~#cBtGmoI zkVBueVZoJVy@R;B_L~}(#4zs-)?O#T8o6^Z0QML%IT z1Auexbj0u=VcTbgiuOz;w+jouM$k}|yrBuo7@DwIxcsKT7i}JME{rmPdvD(|wvVIJf4dKM|+;EuymM z(G^O)%8SGTNGA6Ex+aaa3wL%f!gc%}=}_-7XGogQ#(FoLRmQhl_Fqh-*Jf(z*@g>c z*s^E$1ZfxCU3F{C6iG2b@7j?yc0ZK+Wy-l}o+OrSaVnbX7ubELBu~t1OxgYdrgA;- zN;k~Y3o11Z%N#94Q5SW-2+T4DHlC}1k&BllP@rD`A8q4EDv2$o>2{MSg~z{ZuZgEiTO%b zS{OkaMF+rIPTAGQRT@S?|7F%TN+k0(Ged&!n0Pl-yu-U%cf089dO=3;h)O$%zq<2~ zTBf|c-j-Prrr{hF-GLidF0qihCq|Wp#&K6h3g}oPLK+b7Qt-lCOBh4(CREC->fue?W5cS{ksB8DW^7lGFMge5Rw*QO#E(eM95n_)b=WP z7^_tP9mtRv4OI>O{mNE)TJo$$a*(nj#DMszHXeLGxWv@?h^RZt)F%= z(yRsL)Kqe@$0W za|UPA!HRYdf>LinJc37R8^!gra2Xp+WzVW@WLjm#vY*P9w@S=T^N9L#d%|lKb7I14 z6E^!eSUNY00Nb_!%s@2GkEb45%3c$x@Mn~0#M3!j92He<1J2ZqO}(HIbx}{&&b22dNhV6SCjByt8jQ*aj@lIxB#X^!a!Vg1ns70hA z7XaPf)bUhES@_1AcR5x#)buIACymt1hS4=$?PignzxmNh^QGkYPSm3NbU5jGDEOeO znQ;L2-p7e1mBVMWo+CTy=oTl4>oJU#>+XU=FrI!>Qaui?bh{xx#)Y*gW*V%*lDXl| z|78*6M+^kc=WHonq1GIbSfEB_3k@hIl8IO_sFfRlUJ|q+mIxKb7ZoH;1&=O3Sx$CIcoe5ahjHH zrl*^=)@iAgk+1qY8ZSlQ!V^n!X=V>ZXZKuP*{|LdHkudo>^KtpM;eY++Y*}5a8Js; z*fc6set-U?X|D0rHe>i*jjdrw(b^1Np8Wi9o7)M`?S!VG!*SB{b+1H)^Oqy_maS&n z59O3x0flVug}nKpuu0gT=Wx{Sf`e%?3}pdX(4!?ukF4+3MhZtRR)~jg6BMiBimiFQ zL&00h3ni|@rj-IE=h;N9m@sPAh>w#z^1SExHcKxLY}BSoedu>N0|rHI?d-L>@j}nv zd-u#L23y&0>G5Z`(#!nSC(3(^-1Qo_rqpIkH_!oKLSo7imDkCN_ILkpzbm%Q%9-XE zt?Jz!hPt_NU&k}}!~%?Q>{H+7grOo^_8D zy6wsXf(Xq=(p!jTEcQCNW6x~@e`zd7H-7vGTms?mA`Uhkw8pVvkM<-s&bZW>p&()&Y#Y}pHKSK7QRzO0%U46u zop&Fqfw3?f5`DVYr|a`|t6W$+66Dr@yN|HgR}k;+(POGb-p;Bt4|CjoT(WZNF(VN$ zWU0S24*^Wv#XF<5?cx-yIxgP3vw4HY1YG&R1S!f6lamvRQm>Cj+V03VqA3-XFWn|@ zLU7g>zTsB-?d{ozNh}N~Hax(Vf;#owflGD`hb{@{NNwN*RsaI%5S;)86h-@CtD!KH1eElvYgTduWDA%-jOBrkoBbb+p6>|;OQ%nG^qv4E} z6iUr8Dhkofd5{&{qON)@gSukv=iaN>p!k*dnc*OQi;p`8Dbti*_=waM?=Q0xl2+ZB z>C$Q|3_H?Z3(2I&*WtJANtFrr4E(d+&^fKDxiaNj5JPA0YFzw1D&mak-m+bOzHNLC zx3k}wHERqX1Kp|xRdpmd&*h`_}shDHo~m0KH3(k=Gk5WYN@NOmOq}G&e{yniJC3`CLjJw ztxou3YD<}lx>K2&(D73>%H&kZrX%8_%f`JUG6EH_yH&RpkwKI=4YSO~4t>R+)@Lzm zCNFV7%3v#*$}N3og)6_F(<-_Oq$5FErcG9kGcBw>j;;#-yoZ3gv= zF>uMxd}rG0ZK#*Xj8|etDsN6y!oO=0CXi!`AS>Pcm^z8I^XMlR5>=zv9hlb8>kcK@ zly#E#wr!SFLMUn5Hm(d)d!W=nC6_bHja-CrNb*_E$UF!LpBz{>v=P!m2_?uGx~SS< z9JrXk@`-FP{yOtcA4s#a&XxByGlGL;sc-A-{sq2=BsLXUt4Yc}&Gi-@rw@gJH}E!X zh^&B@twjN1>tHcmeTOb*q!As2XwR}qz0Pk-^ae| z^QVf}e2D?2;t=M~knb7qH)E6TRh~GbQgT6#Jmh)ZCZ`<`MD@4zl~r2Gdz$gPQBZu?7k@Xes$%>L$4{;kk5#m=sA$T-~?Wc zdJdhgDX1CODCE?jc=wnxjU-hcUPCdiiATx8#<49vz!F5G23c3nKIA1xb$+nJ)a!ED z9FUMA_n%IQ$twm=4?qpt7{3p*eVzGpbkNQfEH?-3QH-dcpa;f<+6gjPWzX5S$L}-v z?EeCMRv51>o7yI5AS1KSkr`Hb=0_VCv{ZMNc$0j?AbzBRIsdq665E1i%5F$IX;*js zaoIZ4qs0M!MziL6QAoNsek2<5wXr%@evP2Ga&O;kTKUIoH?ii6XQt(6iY;Tu{e353 z#O)=%I9LC|{45&Rd?AZdK#~D0L$Qs(`>DJ~?4IY6%=bSCe*tVuVi+qITx^tV!(T8n zhee1)&{Fr2l4iI>b(_o8AHxIY30ke)$ULqxzdpbaPMnOfxxMvjkra1iT4^2~BaB2w zcWSGF31@VF(>ch34tq*ghr03~GE@V?5))F&PT4dKsl@vC%-TV|SepqiGsc>!^$}Ir zrNZu<#IPkgsFSwQhT4nJBNxrrUSSz>XH_DM3uV8p1b}ufFA z=kIa;@O(j7h7CB%%G_B?3MZm6yu>L(R7GERuVRxTX_!WjRzbo(NlanBi$A@_?xWYd zR;rC-{fy^Qv`_FSVhHClz@m&@bA!w)HcAU1A2`*>hDr3?A5h)=9R2O2;Ya))Vp&6b zn3_813|QxJAKNXkU%3IFhzsKm#w;5-(Pk@yYMc2M8U(L54c_2;*cLQ3#nb=<;rdvrF4OWR(4s62 zBUAwiAef2{jZ1@oX61$9V?$dN59i29Tg)5R=p)w=xFpHx=%uirMDGwko5jQOTT*l@ zXQqz?u&b~!NiOb#|Dn{FL#=NCBj3SxL7gV{p3D{>K7}b@m2!HBnXYgNqCl-KvH18X z2N_Mf+Kl9T;uGJo0LWyzzkIOu73LPzi!5gtG>5KH%23eUOUnp!ulf^6_!rPTxySN0 zMH^n(TgAa=m+*OHvLvpjOlAc91*#d_yOxa7G4HFef#~~3h;^Sha13#t9p8$z2ytS3 zU6^p?nINkf!)Sijx6puOh$t0NW3EWAcvS42Z4u8KH5pUs#+j0`ey6U<(fGVsyGU$6 zM^Z2N1?H(Og3s3pbK3TjTYLPpZpB=4Y<;21l^E*`{)D-6oQanJyd0?PdvDn}BU^jMqset{05Y@2bwUV9W=M3Q; zmMhItpKpZX>zvGrxNEi|%+fYVBgW@NQ*?E554PiV%LiD92Py_LIFpBSyaQEV_#l7emqPStL! z{B5R2tRm&g7jIYzw`q3uB(HV*9E31TMU~7K(;9JCM75K$jgJg8+<|fykknakG+=Km%cr34FJRo0GQF2raj+QSQ|Q;{O!uX?zkoRy zLqq(;h@V0|rB)tyw2o8tKY|LbW9{Smp6x%t7e=%X8S8%$^`Srb`Ty|rApqzf$cvhp z>j&O4ui7whCANn~cKvUPz9{)$z;)b*+$i+h_~tikJD*r3RF9yH@P?-QmWufb_oh=8 zIw$TG&&O!_S`)M}{;!7P#T$c;5H7~16(ZNH_pt#Zejm6ud)udA#~DQNThWH&_C52(@7}wQ+CW#eW1)vkyYe3IMZ zCnX&!K2EGPe5p*Vx}Fis zZLw5{jDJZ7c`947>e%%HhXTOV$>2J75`+fp!gWfDNwqS)Gpt%?Zs<WZzb1&D5l)m7%~3E3 z9hF;f3YPs>pC$D3MO}vY=Y_!7uN?R{BMuz=y=X~5yzk}O&T*HJ;3jG2*;jR<(R)UM zbkgSm?*qi&Zr^0z-c3cwq&n1xVpf3ps*`AnOIR(dIY{+Qp;+}q-Ac-qLBn+6(|-XH zFo~+W!FSBO$FP9Pw1s*RQgn7#;((L{1Qx8;gygv+_L_I`=tJ#5osQH@Nw-O4f3g;x zC|mQdKegZbiHOC5K>E4`)gsi)zFaCDDtSlIQ^gmeG8()aTIXgQm;{H^TB?L*GUHPL zR_AP*(=Q!}QPnsg%Ug^&hp68cjoq=1=pfV!YPhX|7!gf`njC_z*=-)0MlMve4%ZLL z+0p}zZ|J?p&)L0xR`Xl=jUWh zd6&>gl!B4^C0$4v?$}cHryNA(734vn3<vGK$fhcauY<0D!L%q_^pGabyhFTLEe&2M$+APnrzB{;uBm(pdq~qsz{*V;>Kqgy zKD{xVTFr*tU4Ml3bSwB1B>O@sK^RVYZ_9Y_HDl_xcd#n(RwOp9r!@r|#Ax%rSrl(P z$kp!Vc%NZeXr_`FeN;=clc}bkDD1FKg^-l#T!Gv!%CQXa=m+&{L$O^!77|dXr9@DqiK`8JRe<#np|&dQUbTTQ%-KgPMsAx7_&k=Dva3^~_T7?U z=od$jA4vRi{DhzJRB2MMp#X&a-T*;ST=yN5YQhyJ8NUSyy4sb@7rjBoNE!VW@Y*Q%G* zxA(9cd>wQQ$^*n$qJDLIkljs89z|`wQBXSYQ9$mbv+NkAoQka{K4ZB=LZLk z-B8xKP(PJrT(%_Q7#0)0Ew+J-+l@irdn(8_=GSOFw;L1QvXe}3G}J=3z*4%FK2gv+pnVEC}RZ1P+R{OiYWUOt>z)Bc@d57!C9jS&x;UvPo^2 zNSlR05{*Gl2#ruiSht@B4e<)KTlB0()T~<=};mrwQwG{WhzQc$~mxHP??9dn0#|5sZnbdbZ#Gp@k=TaDEF** zm6};eL5vb^4EWKYLO4XSh*5>HBO_uaVdOS?v1x%ebs4k4aqq%k$L`pp`ZK^M@~b4U zr(0TE1PGVBnD4%y%4fA7(WP+1QW5+9Bjm7sNzNGdTtC>7+Bi-ok;Xxd`g+1%c;v!csi50pmzOX=^i~MvvZt=L{tK0J}PRn-lEREQPu+ZYCTBxsn z{GsIyjX@acaLf5Eq2yX`T}i_OEw*pzcZe#%i*)? z_qp!|8jH8g1o-LY{>kYMR2tZWM$J2oH4-3ABWmpZ3`Ol?kD>dCiJTCR&XoV7^7i5Z*>0I*2?; zFZzDwd_Bz!Pa`3r5d<1%nPygMhY&7p&>n(JxSnvb;5j1N)o(S2u-bV;}lv0imNX78U~un7blLgF5fxhYHa0uSb3OhhI zVC#I5TxPQV$*_dHz6rq5_7$1{1ts}czr+-rE6JOdb}_$TwvW%eU>T8`+=0o z6O^}k0t;3H?b@bcT0k>Q!KaIu4H{~vM35$S%l+;2 zcnQkDgrKwSSv1&1sc$|>l&V~TFX1~aih206&o&4NmD+4aG)c`Dsw}qaV6V9eTCelJ zfYb{zG6fmSFJtW`TCt69QMXWbUZ|H-D+-YLXh}%v9K&S72hK?Jb!-m|qfvE81Gy&x zwofs{!ADF=Cnm~Hnk?x1o77cg=Jan${7cTro?Hr23_^^^JrA?DI|+}#exldi3*{eT zr}OY0KK8DU7i#nZ<&3!%R?ZWFa;IPCO9Y)DZL_tk7pTq#hTyPc?M>o&Tuxg~%UQ}R zJ-EgG>`$H0^@)Y-`=_h7O0RB{ITn>a$Ggu;zAfn@yr40v?~uG(kvFw`^QgbS=8Qv_ zC@!U|E|1z^GLkaB2A&veA(1V{N+(aFZo9Kq=CoMaGxsh&(xll#V@qWrJc2OWU`eAR z;s!D;%-=7?Ux&dPCO_oiwQzn=d|n8e7M;5P%>ReAJWo-ih>xbJP7$MEeCiK0pt?0| zNoKzG;}xM1J8fO#qj61hm-UrMN$#CPKVv6q6}*eD6eMi2^=7|_maEaG$*OIm?=3@s zh$dZRyl|lnLbnQkNPQZ(pJNK2-I=Hf|H7Jnzg+;+EloX_;>ZPL=(k|b%!cPbaCT+) z6o=&qEOR9gInIC|Bfsp3IMbVtM&{qMC=`z-_vV=e3p-ZPo9LyBE!e$;%=+-tz{ZYx zFo>P^td`4ZUaNl&kXPOuAPxc*91o2H_LjWkMd(wP}C!2AXPaZG2J0B_Fu& z$SW?+#-UMOMe2*ubZ1HVc~a$CcB6dtrs{>&}UN7;JPBx@+l=oORR$JzsLRDU-u zx}r@|grv3)4LXT^v-ObDJZ5VYdl!}ou{L3->7`gck9a0Su9^_QX+sRXbbV`Ef*qp+ z1%ZA;ds}~SuXUCrcqq9G4&V0#2!Ale&+G8?h|LHR)ebZF{T}mJgk-2`uVDI(sO6;5 z;&}_`VB_&gAAU7{J5j^bc!7_yW9ZYSH0?uLPwQ12kYg*^cgJeBsuy|6NE#ekIO3wn ziBgpqojIh@8Brj@9pMX(z0U$8iV4>Yh0>`nHB!IsAi?_n@$SReAVpWWfaGFxKtsUH zky_0uCoxkQ!G6CDLm>>TAAo^fC{*n>IArj0B^ywqzX|?1>5^hp_7o$w&&vu`u}I1; zskgM{Z=GaW+*>sl%?+6P3-D{G%W(gy9&vK$(btSgZvbs&jnT;@|JB_v9%l6~fJ%Wl zzE&1I@ey!%vU|<@GFI(5F4Dzc9Yap1nyqZGTGm|o>{EkPaYagzdzFEXgY(SUN{ve; zI6L!<>2t*=*Yt$=h8EWh+IBv;5(K5~CGYbY1E`JTe(S}G zkZ*aqWa#X{S(x{vhao7G^a=bvDUl6(-(uqi+5<8r`Svn8rAfDG{=h**r<9A(yp3An zZtS$1SuXFBQ?1|}jhLo)NcKgA4mdz<56S|GiESisydhqGB1pfRDtI+r7Gu>;NnjPI z14CGh8;vn>w|Udv63{y}=rFT&oiXv(4nxkE99n|t27$W=jB|W4;qzAPz@PHd(Q=UIw1on#Gq;>K1s?8$Y=OT4 zC&e-OnN6E+A%hbdEEeO!Baq3*5lRTbpf8h3w|@bMin_sq^>`*vm(ce=;-ZqCN=a1Y zKBG&IMjb*({yHD}s zk;+8RTQBwMUgIXn;JO$P==e9DvRGIv<#Sx@xfqJJPojbG;L#;B5T?qo?R#x6ka&On z1@Ozpt_@TZr@zX03{#xYtZ^1{u_$MJ-rX9@X9JbyFQ}_;{16HxV=z9YLvt7-#H~n; zjAMB)GnDZY2upISgAF6uHkaso2VfAU1F1&|Ee@3P5JpD?0G;eM53}=~JDS8}2Ro$t5OP-j)Gi-4>QwNiK zU1&8hO!ae=g9W$R1P(~G1?4KeGQwk5g3{aVjNMO{e91VCokXy~B2j(psyH=s7f+c( zYMbV+4P%Nu#qaR2%x-I~W*C3)Tcq=i!RK8M{5wdUj%q!WgZb!y z<4xWK zz0NecKV1xniffP?5TNI_w9E67ok#XM5r7|&_T}qhLmwuTlfwXdnVuLt_E(!f8=~PD z4P2*plzl{=Qp(pG3r2&g7n)|*eqi(Z3eo3vCvC12UnAY|%83!TQVNV4B-4Uj ztA0!yTnozk*@%#=gHLVQ==&t63N6*>bg6nXC%f*OgwIPs}G?5Lkc8m?{ z805J6O>S!JiuF!LIXp*3MYvJ3gur+QniU?+o&3hl$M0)O)4un{6fMh&f_=|?sBadO z8A9rzzWST?#mWz(HoSsR{)t$hcZDBT?Bx-!dSbuf!y0#>KIgE%JWXQNhK zrmP%8Euq!TRlDB47JQ$LCV6pjP%Yp_MD{xBxN|+>6I6waAT4{A5u~B^4VnUqJ4UJY zLdig_Dq?_;{sKCp#wU9+Kt4^W17O11Y0x`OC-k4dahtbn4DjzhrT`|EzksIlT1HO4 zhYaLAT{bd@n!yrQx!IJlSg^h9*5P^Bm@8SG109B&mD2f}+$T&6Ou>hDHu^P}om(g# zMV$So@K@8*pR75ceBw!6)&%9%l(#&Je{ywsyHp7IJ7WAaqAx6OOR*IF z#;`8T$*kOLX0(sx1Z?P5xUiTyt0y|sVpc>)4DcIegX1~|qO7z6z zuzWW*`&ndF#q$@C^bU|ENRIQHr8Cp!a(6}SGk8Y(6f*D^FtEHh@S)S5`B4|~uP&7z zol^k-wA)#s|GyuL%N5s`|JMKx0wY=i-QNG(bb|x+$aJ-nH1~g*_*JkQ z$4R*UZ5m@c>6xDig;$grs9&`Gx$OOK(=4%N{V!Y>EHuJz*YOKC?mZ@~|MPbub~0C~ zS6*)XiEfEPUxEr|cmBu3RQh12FbV;~K}VtN2K$MJ`QN9;Ng&t z{I^Ny3iei*|Km~`v5vF7z(BYvUH;FCLRU@i*3JR4GTbYIfsU}dv$OwU+Q)r0!pN+nAZh_2aM4*VZW{r4eB=cNDtYs$xTrtJS7^H1$11^T~Q!+u2Qf1^+T1wWyQiIb_Z zsk)kl{HwO-pQ1~&zW}X#x&@2;FJzBUF1?%XH^%9$)rv2At$zWtA+4vT&QnplNy?z@ z7#vaS;o*n3Nq*5tU0vbS(iIAvv*-6we|2xu`xdW!Vyhkyzh~YL!rv6_XDVe$XNeJe zFD{>R$M)<^J!LWSa1Pffn{d*DH?GKT#-AhtD5^Ga^7Kvy4-PVyn@~f3aHj_0Go5XZ zE43#LXXZ<~Pu@6o3PrtrAVu-{s?5Ax@4twHzLv>#nhTuQBThba(fZtJ`4gn8tzh!; z1R898^iLoFT6!KdxCsi_()iuMk?+;#6A{t(TmN|#w@wY9t{o$8z6~4hlHMxF+`lt? z!2N@R$P$LfvV)vYbMLX@9`*~#>mJhd=1=B1v#0)TV0020Pizz#X!L0L4Q^=E--?TN z&o*gLg(9zU^7{jClI1K=5Nhn{L)h^$aT{%%B#w(;-5&2xeFWq-Ptsl`rlF;CBYuOi zIMff45An8K(_E4@X1apgqkisRJ8k10JK$)?zX1Iqm8nUZpvywUe;jT+yiuN_C8g&6 z{PY_9volYokR?>A$e2uI5D4V61oh=@~8TkKM#bQd$YP4Z-m*2G3OZ4T62?b~Ju&sHb~g$AL%_dZTA0M3QLM zZPH++pMDV$&kfcf`yfZQcs!Y9NY-P)>Urq*l;+pm#H3FwlgssHC`!-84<8QpAs<|p z;2*A)!IO`RUI1rlhvRnw7jhhgcxeB0hH*A65ohL^{4{}q(~lu@F+mmUZ)qc3BWycFUND#j)-)9_hV2MqMt z-Lw6))P-Dvf`9ud5MMxK8b?Mb403J286)?skbY#uOQIDdsH$f?WBBGK@I}%LH|ht3 zh)Gf=Takg8og1EA9-N92xfj-wR(d=>cQB3{Mu`k1DO(uSw zT=_oZ+*+j+PsW1qEIiGy5v!KixeK89M{YEiAe01zt)Hs%oaE2@*ajZPYX0d#jU+Ud zLey(GvnM!>&kmJB-}HI#8O(ZPqFJBA5PrZdGGJ)!SbcisrGT?xD$gbglX2nlg~uA* zyyTlg5)1r_5CCF+ELV9!vw$qpYdUs2=5Y$4J0t%c86yq-_(U-9gUIDu*A0?4LYk)~ z;ePN^p9U}sn+KXQ`S+bndEMz4+!MwC&dd^X$+a<8n}0}If;h3+xCTCQ{X>dI`Y!M5 zxNAaqqA?0vzwuExL-H@J(h-#5#uCx~AR@G3tybh=I`O`vPk^g$3e5Ju+N29auhK5u zh)vZ@Qi>q!LwGdmcjKJrAQXQFxA5@igoLh5p(q%<1{;u;Z=RK%nR*}H$;5b;oh*oC ze!)8dGs2QFXHv1A^~OY**5(QB;?REZl|4}lD9u@Hnb0F&cxpmqumz?hDI##pi*$k` zx-bq_2GN6l70-*G6`PvbA$lHGowe8}!-u#X^d zOE=Bez(V$;3-lsVMT0*`4jPt4W(O&cA=e)u@)nbu73nBnU30r4Vxg*2%u zm!{01FX!mDJp%;G!DN}_5n&r2Ek{1z!&8Y|em zC86w#6o15w2EKH`%xCEMh}zU_jp?UD(BUewb~H7*&KS#NQ0hR#;^yF<5<+O_)3x_= zYN1^+Y&eS-5C2kjN5w@6mS48t3Onhg;Won3QG#2BVEAQxvv<{xLm}`sAKLmV=Ib$~ zeJ{X?y&LA29i5v9&j?{>vZ*Pa|F?DcZ(D{qzj3&28D zr7R)ziE1+AJbrw2ze@sx2SZs*CW04@GDkhr5b74z`z zHP_=GB1F0>M$>LbB;!}zYxVpE7^F(0%V^1it1b z3n;UC#>##ei&IY{xV&nHfyuR7%RlVSf-qhgVo(STf|<3rhY^M6km5bYDj7S2+?u~u zPi%Do51>o46e8}2O{>4hR((G__0Gs^)KT3#FQ-4Q5gZal;{-MIVv=6~&1&|I)=VRn zezIA0&$IEvtwQU8^$^X6m;uHGfZRs7&Uq*~gdq}tAtwqwXEI-Uk*fflIcw&Rnj7V= z?EuoBSd)E5 z%)kpW`e;1-AUU6f@y)mq2;$n3Hjm5Fe@CJ+n!-SBq1xJdKaNli=BarpR_+mr(C^0FVicC8L6!pks z&f1KlSs>C@YLhI+*%@8ST@Nl02D;3`UX(`ppqS)iY8t$tNp5?JiU=FT?YK>*h&Lu! zQ_ndNN^~cqK?4)Px6xRa3??#d!#)Gb*qWW6<8valPurpihRo=d@HP(d)(N0b5EV#q z@6s)U=q{5h#0TM#EqrCrxVv(jN9y8Sndxn9&FcFI!?Pk8A`*Oj((rO9p4u*uaOE{c zYBE=W3KJ3C{%B-A?cX1d>BF)bR-n1M(sr>Wh+rlU1(m|Shj?*7QUbO|tPH2_PYYF2 zAe!}lUH?2ZIXfpBJB_y$F_a893Wnh8x~Y(U?JV@N3rtBV-BpeX|K58pk+(cGqpyX~ z*_c6(06WpSw{RQ1QYgK&9RWnjxS*G%t#DadG)9)_{-OlbPoz&P-!C99+T1ONPunU# zwy#jrv%wQl914j{B6XBDv?+vo5;240HGfr*kzJ~6>=?EaE-rQ=+&koUVs7b$%J6(L zU|xZ#i(b+QHtEa?gdk+7olYC4A3irb z;(F|L$Uo8JsRq&(UMAkAkQq?^T1`;ai)K57+V;B~I+M`n^-Q`#YlFvObVP`9KP*#h%YqRriw}@kgOo9DS(1FbZjN zv0S$ZRoDwke6fGa2hoCE-$RF5J8otl>}ub{m>>N;NpFR@hJ3C4(s>p963#iLcDZwlwWl9bF{ zs35rMyB_jH7xJ#MWM8!rftt;D!OMhXFt?XSMQ&t&U7>B%lB#H}tSmH;rzt4IZTuTV z@b`%}Uyxpjtq=l1%LqZ5#TBv)xBp85m8H*{gFRTV|25azq1lMTeDixVj~H(f^ouPS>HgcG?uvSrDZ%6Hv~3zrV&nTJn~6Wr=$4FXa#XX zms>I(#=;jwI}b*n=9cLIbYj4-{hb+D#!s|~KwUrZBu8)6a3k@^MTqZ5{mVJ$xpwN7#*(JJ*<_=p~93TTM&ML zp;S=_zZl)!o^bCyFIqp_84Y98Gv`R@VLfK1@r(ThxWmNRY;b-%4!$nK=;pg;EdAyd z_Qh$F7@B-{Ep998DQ?1P1Rv+o9U?>Pqvf!utut4bT>W>EAI8t8Ulw|ODQT&b)q-d( z+qFv=pYdoyEu}B-$6Y_6r*7=Ut?OIXFW&=7^VEkfBk70DB-XKi9-4Y$neR!YZc~#J z(ENrdHX0mtB;&qXfr|pGB{4(1*NA#w)YqFJj{J%)+{hdi?}q$O^oJb0Ut$i;J1d0fCb%Fg)^ z!^5y37*x7E4*_^4K*rj|h4G9|{qBeR<^7J6%D%NZ=BTgug*co%rQrhUhuK~8Q1aQv zm7USH6x99O z7M8SU5D{`92%5NESk&wFM@-;Ct%{f69~xIf^Fprq?*`>-!^(5mWbUgmm{&rwl9I$bo8cwhC_|VRZ5Oid zw=8NHjnbm*e*Dw2A)@~fD?@z5tOia%mLlp7mEi5g5syA(=EUWAJ0X}{W`_L|qavks zbbdB7c`t1u(75QcIZXwy<(i=%LV!5yMH+4bQ+0>Hhngu^pr?*6l==H#06u$pLaoMi zBupp8oSqp`hN@4@SPi{jE9wY&oFJeolm>8G@Ci>`An)gqVhxu9Z*PpLbQJD#U(CyXFK?hiAi3uYB>@ zKF&I#-+$eIf8Z73*w9U4H8zh02PR(LLE5+U!H!kjT^ z2QTw*J1=|D6DACpP^zw&>gZQ@E}@f8g7M5^iy-PaqkXzjU*94yaghjLVloPpGxG%Px5Mf>(4+2$y?^C*OGSMKW;n9%SqH_)igml5 zf%T^Mysi%QKSg6pZlEW+vr?d~y>Q2GnV>oDRcYzHBfDcNh#5h~LkuAmmNSYFi(KUg zz@)?T?tWIT&?+@Ddb5C%h%x(P%nMH*OHfDV<^!_yacG;+dL4tMiJA-}GUPS`o`bc% z>vW@qDv4EjQ$9%J!!AcTw8tJnmaBJn`*c619p97P@R_u?n@{Z=3h{@r-lwB|b`vD8 zJuH!1l6U>A)t%!%CMP+@yLSOBQ4c1%jM@~F^w9im1q(LVEla&%vubDZ(~42f9iOjf zNi1zvMHFEkzfaT+o=m_R`wK8fsO8R%(JmWDQ0y@*DbXuR2z50wXP5&`U@>eQ;=d;& z=7G4U8_eXro98RtWSo9o^9uz2^82=2N2>7p`2@n*6O41uKDS{w(W@V-rRv}h#(5rc z*Z^BEP4ZW0`tgfK?}-qsnZNhW!^=Vnjt1XiOylO3vBIr9Cm2=>#H5$;97g?@2fA~AYEn`Lf`0kY4cGL_z^x| z+*yuLzRd``s^~qIfvn$KK2bw}SV5H6%PIK8Wh}&siHxCvS^YC zp|eYWbi77riBkGV?dq{A7mJWcXm{hn^dwCTci`e~!UBK<|6c%W6qM^cL?p05g7|Ma zxI5@vj+WjCI8q;$IyK8&RH3=xQS|CEap-{H8zoQ8Jp)?JlVx~w(+y@2ke6HGuP|_> zfg1G+qZhI4bL@z3mieIL+6v=h`a3)v%7PfWPK5`i{7M^g?Rf=Mf{f^&u1kbSj9L$# z$#!}g!d*|CAMb_<)E3y-;u`qWhYb#^)Of`Ty77Z=sF{ekyPE*!9|kn%yZj>ka*bz7 zz7nbntTg#nw+a+IXekt3-TeuE9l7Lr{LV!{6mSjs69eG$gr^nm4P?*{?u>$MBg8Yo z>bO77fEhXp{AyUz5IOZced9H(qV2-Chog`+9s|cPuZZOxJ}++NA+TP% zt>y}9l;vgc)G`2P0DN{q{c(MoLgKrErY{}Gsb>_~EZl|Gyr0xz#gwk|`wz4xyE(Pm zbaW8lrEP1|li17{RA74i#Bdckm+P7cS)av(lpb5(67=_Pufbnzx_O5fEjq6VymN~C7&>q;8XsYd&a#;TWMAxz-LP95$ z<>OGA&$7zFT0A9&s0Qe72Rk60dQ$qoPS*rgoRaAA*&G?Le!h>|Trq@?QO)?o2M_(s z4t>k5LADZdCcr0K&;(vaGLEb-8gTj37;UmNJ@C9gd1LX&d83OT6$fwhuJ^&-{6la` zwioe#R$wT?48mWv6{Ktxx(DQk;q6v1 zWx*Ujt4lIUgBwAk#C~Jk0yK0hm>nvxpvFA4YdL#5LiUfEU z2kQ8aL)HqPk_3=X`<(}sw63`<=Dh&dO_{7M3SFUx@E#5)0Ph2&zb%Y^#F zAf9Scr~`|-xrQyQVU2|%z+W%YQ5p<8dA7Au%r-HLdc61XQQ!q_n+nHJuUfXV&wA=) ztH$2tYK~ze905S!i|FE80Gw<}54;gJkgDx?K63=4mYgfknaizMeJ$b^z5vDRw&EJY zkQ0Q*QM4^c;}qZ=#L_0ycyc>qiL-G}+Bx+UM^yp9R}$}(6Hk^_P2nUA(N))SwA_Id z(L%%5%sgUYN0RQkiPdbY@%!>c($ZQ(Pw^2o!Y=*i z_&JFoj6LrLXS=7$vaxD{WDA2NvxRnmAH1UN4K5nDthH zSKe1+=e4zv$#;?q$WiWb|r1*naX`rt-FYhX#W^{{j;3gqJzvSG$C7$7KFE1u40|Bat z#*{tOZ9M5dQCoX?nYch|K~jZ(h=Hi&%pi@5{aQlQ3k?U)WDtsZf#dwZ#NI_8U+Yqc zry{G>P#80~9+6O=0i8;kMqwy9JuM>{Ekb{HNJr3hfgi@8B530m< z6+lLT>;Ax~)Ea(r(_sQ;BCE_dlM%m@ae18yj)g1v9I1b|s zTSPxqQGzQe3;zI-SBUMOz2W23X>D1$sO6Fink(jO@@eJKM7h+2R)4#H{o` zGr)IcPkfLnMRc7wG(<0{lV+aGJ1`c&IjhRRVNeK6*l4|6d)kTh8~VhKlSwq%xoWUh zU>FUX?3K%mXvCll1qJ|mfkjb!)NoWOwlXNUyWHD-!ygbyd2tFoO5iSzrJ1?}Hn>F% zZy&7~2q2Ee8x@9&=`2Z#Xq6PO4*a1~x@IXzC-4z6MyK}j1(5C}$fge?(3Lx@w zK&OovOV{-^w5c<3!aQzcC@mm3K|$eN_X6z|Xb)po52#V1Cp6|elf0;_fyxEdb#08WD?`G8K$N_wluxFi~zV9z*Sph2}jwbMjNRil8tTTHD{peP%) zXV&E&%r)IJPrML+lZTCuMr!XI4|kY3EEec-%B;~cgycEh7F-VDu*hN;R{jfMf8a}d z^)|{+HK;y`3>b-NLYNaT{ZYE5(a98<-dxhkrS8Twpia^pd3%E&Y+HkWtud=Wv5XYR z<{xet{bNcgA2PEJwvS^&<^W*bxIlLC%)TQG0-bic)V;D%5yWQ-pAwnkt#C+n#FjuHeO8>s!WdCz88kvrt(FcieV38;&F!M(0%f5W87o8#Wxc z?mHr=F&q~wxWkue)Ya~=H8Qn!6+ui>#k*ks!=^;uIF7oP_uCQS5%mjXEfT90qZ>!v^8i}+5ox!%+!YYj zY`t?34WMO8K3*lBlSiK?W+IZM5tjIjc%jfq=x?hTAe{6 zCMIu-IfTqTv+n-@5Hv5IHQC3wE;Kq%j-PYPTU9|Rd=>R#){LUG&;eJhLL!!`FOB`7g;TX017ROzYAsnH z-WkWc2qyyYSKv146A)X2z#FAi?qAY)?sCxkFu+P6Ao8R>k)cb9252tVbr9#s`-T_} z`HZsq!C4e>QDs7rB4gXT3)IY@?uw6_zoKMB>n(7*msKwlD5yCm3|t5}=iz}BfSZpp!bzCM8?f@;GDN|1;Kg=#DP9vZqXlCvnFs9!UfUu53`2Jy^*3>@t zNL=66Lto^V#V+X|!vZ37As)t;xtst%;S8h9Wh9|N!*!W|HSoD><0H&W`IXxmDx&qd zZ>6#XU=I%F2m;g3AZ~O7t#I$jznGo8C#BW;fpzcZ4qlFZ#gzJ7yp0$Vr8H_m!ku4A z9=ty?ytV-Knh!7;S@LWPPRoI^@up6PhEY0Nj)cw%L*_PxEO_XNjaKd*kl2-M0ZVc8 zf`*1tmVn!+X%8rU9kB>RCQ4BH%|N=ry^G(dZ5i=~_HS8*;mux{K8G;F$-s9|GP#vd zb9^Bgkg;3MUN@Ad7urtMwk!R5Q3zARIXe{nexES}R-ef7N5b01eGMcFl9At#R^|6l z7Zu*SS5+4TFrJ-ojzb_HLnAa)7o4c(~;gdW6%|N8Q({Y!LGeUSSsz*248pl(Qc!d^mU_&k@qt( zT8|LE2~}OP!UDiw@O;bNTL!qYp{4Vz;h3X;@$6-7beDXp~n_f8JEJpcf>W;P&~NGVgXK8 zpnljiruSS!(O51-_VpJxir-o3aocU?(a(dyDxHkJ9|S9M-Ndk2oWHO(7oI(+h!@?R940`LY1*ks7q zw0K(xFs(3)LrO1g%brj=m3bq#)YH-=Gro){`@=I=EfmEnD|F0Y;LF!5YV z<&Mg?Nl!)7}AxE!UgS~8W4(V^}F&(8YI0q@z zx49W7S7(|q!i`TU#fCnyqEM*mfo111qotmWW!OJywE;0fia1KUGAWuURW=)V&tski=R9|6?nL>4fZnz2(jQ(W5OYasJNtov^DgbLvYLU+Y4+Q zJ!&2sTuya~H1zv!CpV4&sM=9w<}o&u1UFt_siDsmH%y?*F;&2{mr74Cd89LvuQ7VI z2CI_bB#W@b${>LwST7uz&rz+1I;_Yna?>5+B*Cpa|M z?Zh?!&~f`~DlZBQ3V#gn6cdB4jB#Wd<@jI{oy|{dH{M;cXH2!4^q04DFkRL>V>89x zFUmgiGF3+O^nmU5bao$d_Y>FwMjFt6QvHs0ap!4_mJ>@6=?s z>M2nWR#g%CZBX+T07$cu$lin8MBwi_h1iPT%&uFTnTqJoZ{u+SzSfUWGy92XIt7fd zFgXo;t{4jHus=Z^f>_H&i*P(Y67AThf%!GWN7E=>!O2ff95VNB@Gx01f6yXPe{$O%mR@|!niNOB= z1^SH$ZWd75d^?8=V%vUSf)M}>1V4MIacRWK1jXEJCl^{}@fxD4ov2&^73sRZkeLNm zKlPakm=>{H_+gLPw&oR1t1$CO=|ZCj>($?*^=V71XY_C2TxDGsD8qL*Z%+n VgS^T}ZGhPK0bl$Z57Pet|JgD(=3f8+ literal 0 HcmV?d00001 diff --git a/boards/shields/mcp2515/doc/index.rst b/boards/shields/mcp2515/doc/index.rst index 6c25445dd495..fd35aa0b2eb6 100644 --- a/boards/shields/mcp2515/doc/index.rst +++ b/boards/shields/mcp2515/doc/index.rst @@ -219,11 +219,128 @@ For more information about the Keyestudio CAN-BUS shield: - `MCP2515 Datasheet`_ - `MCP2551 Datasheet`_ +Adafruit PiCowbell CAN Bus Shield for Pico +****************************************** + +Overview +-------- + +The Adafruit PiCowbell CAN Bus Shield uses the Microchip MCP2515 controller +with an TJA1051/3 transceiver. This shield is built for the Raspberry Pi Pico +and uses the SPI interface. It also contains a Qwiic connector to add support +for a sensor. + +.. figure:: adafruit_can_picowbell.jpg + :align: center + :alt: Adafruit PiCowbell CAN Bus Shield + + Adafruit PiCowbell CAN Bus Shield + +Hardware +-------- + +- MCP2515 + + - Stand-Alone CAN 2.0B Controller + - Up to 1Mb/s baud rate + - Standard and extended data and remote frames + - 3x Tx Buffers + - 2x Rx Buffers + - 6x 29-bit Filters + - 2x 29-bit Masks + - Interrupt output + - One shot mode + - High speed SPI interface (10 MHz) + +- TJA1051 + + - Fully compatible with the “ISO 11898-2:2016”, "SAE J2284-1" & "SAE J2284-5" standards + - Supports CAN FD + - Fast data rates (up to 5 Mbit/s) + +- Connectivity + + - Terminal Block - 3-pin 3.5mm (CAN) + - Raspberry Pi Pico compatible (SPI) + ++-------+-----------------------+---------------------------+ +| Name | Function | Usage | ++=======+=======================+===========================+ +| GP0 | None | | ++-------+-----------------------+---------------------------+ +| GP1 | None | | ++-------+-----------------------+---------------------------+ +| GP2 | None | | ++-------+-----------------------+---------------------------+ +| GP3 | None | | ++-------+-----------------------+---------------------------+ +| GP4 | None | | ++-------+-----------------------+---------------------------+ +| GP5 | None | | ++-------+-----------------------+---------------------------+ +| GP6 | None | | ++-------+-----------------------+---------------------------+ +| GP7 | None | | ++-------+-----------------------+---------------------------+ +| GP8 | None | | ++-------+-----------------------+---------------------------+ +| GP9 | None | | ++-------+-----------------------+---------------------------+ +| GP10 | None | | ++-------+-----------------------+---------------------------+ +| GP11 | None | | ++-------+-----------------------+---------------------------+ +| GP12 | None | | ++-------+-----------------------+---------------------------+ +| GP13 | None | | ++-------+-----------------------+---------------------------+ +| GP14 | None | | ++-------+-----------------------+---------------------------+ +| GP15 | None | | ++-------+-----------------------+---------------------------+ +| GP16 | SPI-MISO | MCP2515 | ++-------+-----------------------+---------------------------+ +| GP17 | None | | ++-------+-----------------------+---------------------------+ +| GP18 | SPI-SCK | MCP2515 | ++-------+-----------------------+---------------------------+ +| GP19 | SPI-MOSI | MCP2515 | ++-------+-----------------------+---------------------------+ +| GP20 | SPI-CS | MCP2515 | ++-------+-----------------------+---------------------------+ +| GP21 | GPIO_ACTIVE_LOW | MCP2515 - INT | ++-------+-----------------------+---------------------------+ +| GP22 | None | | ++-------+-----------------------+---------------------------+ +| GP23 | None | | ++-------+-----------------------+---------------------------+ +| GP24 | None | | ++-------+-----------------------+---------------------------+ +| GP25 | None | | ++-------+-----------------------+---------------------------+ +| GP26 | None | | ++-------+-----------------------+---------------------------+ +| GP27 | None | | ++-------+-----------------------+---------------------------+ +| GP28 | None | | ++-------+-----------------------+---------------------------+ + + +- Power Supply + + - 3.3V ~ 5V + +For more information about the Adafruit PiCowbell CAN Bus shield: + +- `Adafruit Website`_ +- `MCP2515 Datasheet`_ +- `TJA1051 Datasheet`_ + Programming *********** Set ``-DSHIELD=dfrobot_can_bus_v2_0`` or ``-DSHIELD=keyestudio_can_bus_ks0411`` -when you invoke ``west build`` or ``cmake`` in your Zephyr application. For +or ``-DSHIELD=adafruit_can_picowbell`` when you invoke ``west build`` or ``cmake`` in your Zephyr application. For example: .. zephyr-app-commands:: @@ -240,6 +357,13 @@ example: :shield: keyestudio_can_bus_ks0411 :goals: build flash +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/can/counter + :tool: all + :board: rpi_pico + :shield: adafruit_can_picowbell + :goals: build + .. _DFRobot Website: https://www.dfrobot.com/product-1444.html @@ -263,3 +387,9 @@ example: .. _MCP2551 Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/20001667G.pdf + +.. _Adafruit Website: + https://www.adafruit.com/product/5728#technical-details + +.. _TJA1051 Datasheet: + https://www.nxp.com/docs/en/data-sheet/TJA1051.pdf diff --git a/dts/bindings/gpio/raspberrypi,pico-header.yaml b/dts/bindings/gpio/raspberrypi,pico-header.yaml new file mode 100644 index 000000000000..f89a006d1802 --- /dev/null +++ b/dts/bindings/gpio/raspberrypi,pico-header.yaml @@ -0,0 +1,34 @@ +# Copyright (c) 2023, Joseph Yates +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on Raspberry Pi Pico headers. + + The Raspberry Pi Pico layout provides 2 columns of 20 pins headers + + This binding provides a nexus mapping for the default 26 pins as depicted below: + + 0 GPIO0/UART0_TX VBUS - + 1 GPIO1/UART0_RX VSYS - + - GND GND - + 2 GPIO2 3V3_EN - + 3 GPIO3 3V3_OUT - + 4 GPIO4/I2C0_SDA ADC_VREF - + 5 GPIO5/I2C0_SCL GPIO28/ADC2 28 + - GND GND - + 6 GPIO6 GPIO27/ADC1 27 + 7 GPIO7 GPIO26/ADC0 26 + 8 GPIO8 RUN - + 9 GPIO9 GPIO22 22 + - GND GND - + 10 GPIO10 GPIO21 21 + 11 GPIO11 GPIO20 20 + 12 GPIO12 GPIO19/SPI0_TX 19 + 13 GPIO13 GPIO18/SPI0_SCK 18 + - GND GND - + 14 GPIO14 GPIO17/SPI0_CSn 17 + 15 GPIO15 GPIO16/SPI0_RX 16 + +compatible: "raspberrypi,pico-header" + +include: [gpio-nexus.yaml, base.yaml] From 244c33549fe631988d21b22747b4ad5629991c1a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 13:19:21 +0200 Subject: [PATCH 1042/2042] kernel: spinlock: remove internal function from docs Hides a function marked internal from the documentation. Signed-off-by: Florian Grandel --- include/zephyr/spinlock.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/zephyr/spinlock.h b/include/zephyr/spinlock.h index 826d8050735f..62bbe4776449 100644 --- a/include/zephyr/spinlock.h +++ b/include/zephyr/spinlock.h @@ -261,9 +261,11 @@ static ALWAYS_INLINE void k_spin_unlock(struct k_spinlock *l, arch_irq_unlock(key.key); } -/* Internal function: releases the lock, but leaves local interrupts - * disabled +/** + * @cond INTERNAL_HIDDEN */ + +/* Internal function: releases the lock, but leaves local interrupts disabled */ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) { ARG_UNUSED(l); @@ -275,6 +277,10 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) #endif } +/** + * INTERNAL_HIDDEN @endcond + */ + /** @} */ #ifdef __cplusplus From 816d09c45317992f001e1a35ca9ebf621ef5f6eb Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 30 Jun 2023 16:55:59 +0200 Subject: [PATCH 1043/2042] kernel: spinlock: expose LOCKED macro as public API While the LOCKED pattern is universally useful it can be misused. This change therefore exposes the LOCKED pattern with extensive usage documentation to reduce the risk of abuse or unintended deadlock. Signed-off-by: Florian Grandel --- include/zephyr/spinlock.h | 53 ++++++++++++++++++++++++++++++++ kernel/include/kernel_internal.h | 6 ++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/include/zephyr/spinlock.h b/include/zephyr/spinlock.h index 62bbe4776449..ddbe5a3fe7fa 100644 --- a/include/zephyr/spinlock.h +++ b/include/zephyr/spinlock.h @@ -281,6 +281,59 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) * INTERNAL_HIDDEN @endcond */ +/** + * @brief Leaves a code block guarded with @ref K_SPINLOCK after releasing the + * lock. + * + * See @ref K_SPINLOCK for details. + */ +#define K_SPINLOCK_BREAK continue + +/** + * @brief Guards a code block with the given spinlock, automatically acquiring + * the lock before executing the code block. The lock will be released either + * when reaching the end of the code block or when leaving the block with + * @ref K_SPINLOCK_BREAK. + * + * @details Example usage: + * + * @code{.c} + * K_SPINLOCK(&mylock) { + * + * ...execute statements with the lock held... + * + * if (some_condition) { + * ...release the lock and leave the guarded section prematurely: + * K_SPINLOCK_BREAK; + * } + * + * ...execute statements with the lock held... + * + * } + * @endcode + * + * Behind the scenes this pattern expands to a for-loop whose body is executed + * exactly once: + * + * @code{.c} + * for (k_spinlock_key_t key = k_spin_lock(&mylock); ...; k_spin_unlock(&mylock, key)) { + * ... + * } + * @endcode + * + * @warning The code block must execute to its end or be left by calling + * @ref K_SPINLOCK_BREAK. Otherwise, e.g. if exiting the block with a break, + * goto or return statement, the spinlock will not be released on exit. + * + * @note In user mode the spinlock must be placed in memory accessible to the + * application, see @ref K_APP_DMEM and @ref K_APP_BMEM macros for details. + * + * @param lck Spinlock used to guard the enclosed code block. + */ +#define K_SPINLOCK(lck) \ + for (k_spinlock_key_t __i = {}, __key = k_spin_lock(lck); !__i.key; \ + k_spin_unlock(lck, __key), __i.key = 1) + /** @} */ #ifdef __cplusplus diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index 8ce31b22fbc6..2fe54a4080d1 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -227,10 +227,8 @@ void z_mem_manage_init(void); */ void z_mem_manage_boot_finish(void); -#define LOCKED(lck) for (k_spinlock_key_t __i = {}, \ - __key = k_spin_lock(lck); \ - !__i.key; \ - k_spin_unlock(lck, __key), __i.key = 1) +/* Alias of K_SPINLOCK to keep kernel code concise. */ +#define LOCKED K_SPINLOCK #ifdef CONFIG_PM From 5132022a3cbbc9d01b6e7860737b123b484312f3 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 14:27:08 +0200 Subject: [PATCH 1044/2042] kernel: spinlock: add assertion to protect K_SPINLOCK Adds an assertion for the GCC toolchain to check whether the K_SPINLOCK block was left without unlocking the spinlock, e.g. by calling break, return or goto. Signed-off-by: Florian Grandel --- include/zephyr/spinlock.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/zephyr/spinlock.h b/include/zephyr/spinlock.h index ddbe5a3fe7fa..79965200ef58 100644 --- a/include/zephyr/spinlock.h +++ b/include/zephyr/spinlock.h @@ -277,6 +277,17 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) #endif } +#if defined(CONFIG_SPIN_VALIDATE) && defined(__GNUC__) +static ALWAYS_INLINE void z_spin_onexit(k_spinlock_key_t *k) +{ + __ASSERT(k->key, "K_SPINLOCK exited with goto, break or return, " + "use K_SPINLOCK_BREAK instead."); +} +#define K_SPINLOCK_ONEXIT __attribute__((__cleanup__(z_spin_onexit))) +#else +#define K_SPINLOCK_ONEXIT +#endif + /** * INTERNAL_HIDDEN @endcond */ @@ -331,7 +342,7 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) * @param lck Spinlock used to guard the enclosed code block. */ #define K_SPINLOCK(lck) \ - for (k_spinlock_key_t __i = {}, __key = k_spin_lock(lck); !__i.key; \ + for (k_spinlock_key_t __i K_SPINLOCK_ONEXIT = {}, __key = k_spin_lock(lck); !__i.key; \ k_spin_unlock(lck, __key), __i.key = 1) /** @} */ From e256b7d24413cd675c3d915394bebf990c742429 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 09:12:38 +0200 Subject: [PATCH 1045/2042] kernel: spinlock: LOCKED -> K_SPINLOCK Let the kernel use the new K_SPINLOCK macro and remove the alias. Signed-off-by: Florian Grandel --- arch/arc/core/arc_connect.c | 70 ++++++++++++++++---------------- kernel/include/kernel_internal.h | 3 -- kernel/sched.c | 38 ++++++++--------- kernel/timeout.c | 12 +++--- 4 files changed, 60 insertions(+), 63 deletions(-) diff --git a/arch/arc/core/arc_connect.c b/arch/arc/core/arc_connect.c index c9496e98059d..e3ae3dba5f44 100644 --- a/arch/arc/core/arc_connect.c +++ b/arch/arc/core/arc_connect.c @@ -20,7 +20,7 @@ static struct k_spinlock arc_connect_spinlock; /* Generate an inter-core interrupt to the target core */ void z_arc_connect_ici_generate(uint32_t core) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_GENERATE_IRQ, core); } } @@ -28,7 +28,7 @@ void z_arc_connect_ici_generate(uint32_t core) /* Acknowledge the inter-core interrupt raised by core */ void z_arc_connect_ici_ack(uint32_t core) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_GENERATE_ACK, core); } } @@ -38,7 +38,7 @@ uint32_t z_arc_connect_ici_read_status(uint32_t core) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_READ_STATUS, core); ret = z_arc_connect_cmd_readback(); } @@ -51,7 +51,7 @@ uint32_t z_arc_connect_ici_check_src(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_CHECK_SOURCE, 0); ret = z_arc_connect_cmd_readback(); } @@ -64,7 +64,7 @@ void z_arc_connect_ici_clear(void) { uint32_t cpu, c; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_INTRPT_CHECK_SOURCE, 0); cpu = z_arc_connect_cmd_readback(); /* 1,2,4,8... */ @@ -85,7 +85,7 @@ void z_arc_connect_ici_clear(void) /* Reset the cores in core_mask */ void z_arc_connect_debug_reset(uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_RESET, 0, core_mask); } @@ -94,7 +94,7 @@ void z_arc_connect_debug_reset(uint32_t core_mask) /* Halt the cores in core_mask */ void z_arc_connect_debug_halt(uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_HALT, 0, core_mask); } @@ -103,7 +103,7 @@ void z_arc_connect_debug_halt(uint32_t core_mask) /* Run the cores in core_mask */ void z_arc_connect_debug_run(uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_RUN, 0, core_mask); } @@ -112,7 +112,7 @@ void z_arc_connect_debug_run(uint32_t core_mask) /* Set core mask */ void z_arc_connect_debug_mask_set(uint32_t core_mask, uint32_t mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_SET_MASK, mask, core_mask); } @@ -123,7 +123,7 @@ uint32_t z_arc_connect_debug_mask_read(uint32_t core_mask) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_READ_MASK, 0, core_mask); ret = z_arc_connect_cmd_readback(); @@ -137,7 +137,7 @@ uint32_t z_arc_connect_debug_mask_read(uint32_t core_mask) */ void z_arc_connect_debug_select_set(uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_DEBUG_SET_SELECT, 0, core_mask); } @@ -148,7 +148,7 @@ uint32_t z_arc_connect_debug_select_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_SELECT, 0); ret = z_arc_connect_cmd_readback(); } @@ -161,7 +161,7 @@ uint32_t z_arc_connect_debug_en_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_EN, 0); ret = z_arc_connect_cmd_readback(); } @@ -174,7 +174,7 @@ uint32_t z_arc_connect_debug_cmd_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_CMD, 0); ret = z_arc_connect_cmd_readback(); } @@ -187,7 +187,7 @@ uint32_t z_arc_connect_debug_core_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_DEBUG_READ_CORE, 0); ret = z_arc_connect_cmd_readback(); } @@ -198,7 +198,7 @@ uint32_t z_arc_connect_debug_core_read(void) /* Clear global free running counter */ void z_arc_connect_gfrc_clear(void) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_CLEAR, 0); } } @@ -233,7 +233,7 @@ uint64_t z_arc_connect_gfrc_read(void) /* Enable global free running counter */ void z_arc_connect_gfrc_enable(void) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_ENABLE, 0); } } @@ -241,7 +241,7 @@ void z_arc_connect_gfrc_enable(void) /* Disable global free running counter */ void z_arc_connect_gfrc_disable(void) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_DISABLE, 0); } } @@ -249,7 +249,7 @@ void z_arc_connect_gfrc_disable(void) /* Disable global free running counter */ void z_arc_connect_gfrc_core_set(uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_GFRC_SET_CORE, 0, core_mask); } @@ -260,7 +260,7 @@ uint32_t z_arc_connect_gfrc_halt_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_HALT, 0); ret = z_arc_connect_cmd_readback(); } @@ -273,7 +273,7 @@ uint32_t z_arc_connect_gfrc_core_read(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_GFRC_READ_CORE, 0); ret = z_arc_connect_cmd_readback(); } @@ -284,7 +284,7 @@ uint32_t z_arc_connect_gfrc_core_read(void) /* Enable interrupt distribute unit */ void z_arc_connect_idu_enable(void) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_ENABLE, 0); } } @@ -292,7 +292,7 @@ void z_arc_connect_idu_enable(void) /* Disable interrupt distribute unit */ void z_arc_connect_idu_disable(void) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_DISABLE, 0); } } @@ -302,7 +302,7 @@ uint32_t z_arc_connect_idu_read_enable(void) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_ENABLE, 0); ret = z_arc_connect_cmd_readback(); } @@ -317,7 +317,7 @@ uint32_t z_arc_connect_idu_read_enable(void) void z_arc_connect_idu_set_mode(uint32_t irq_num, uint16_t trigger_mode, uint16_t distri_mode) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_MODE, irq_num, (distri_mode | (trigger_mode << 4))); } @@ -328,7 +328,7 @@ uint32_t z_arc_connect_idu_read_mode(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_MODE, irq_num); ret = z_arc_connect_cmd_readback(); } @@ -342,7 +342,7 @@ uint32_t z_arc_connect_idu_read_mode(uint32_t irq_num) */ void z_arc_connect_idu_set_dest(uint32_t irq_num, uint32_t core_mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_DEST, irq_num, core_mask); } @@ -353,7 +353,7 @@ uint32_t z_arc_connect_idu_read_dest(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_DEST, irq_num); ret = z_arc_connect_cmd_readback(); } @@ -364,7 +364,7 @@ uint32_t z_arc_connect_idu_read_dest(uint32_t irq_num) /* Assert the specified common interrupt */ void z_arc_connect_idu_gen_cirq(uint32_t irq_num) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_GEN_CIRQ, irq_num); } } @@ -372,7 +372,7 @@ void z_arc_connect_idu_gen_cirq(uint32_t irq_num) /* Acknowledge the specified common interrupt */ void z_arc_connect_idu_ack_cirq(uint32_t irq_num) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_ACK_CIRQ, irq_num); } } @@ -382,7 +382,7 @@ uint32_t z_arc_connect_idu_check_status(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_STATUS, irq_num); ret = z_arc_connect_cmd_readback(); } @@ -395,7 +395,7 @@ uint32_t z_arc_connect_idu_check_source(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_SOURCE, irq_num); ret = z_arc_connect_cmd_readback(); } @@ -406,7 +406,7 @@ uint32_t z_arc_connect_idu_check_source(uint32_t irq_num) /* Mask or unmask the specified common interrupt */ void z_arc_connect_idu_set_mask(uint32_t irq_num, uint32_t mask) { - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd_data(ARC_CONNECT_CMD_IDU_SET_MASK, irq_num, mask); } @@ -417,7 +417,7 @@ uint32_t z_arc_connect_idu_read_mask(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_READ_MASK, irq_num); ret = z_arc_connect_cmd_readback(); } @@ -433,7 +433,7 @@ uint32_t z_arc_connect_idu_check_first(uint32_t irq_num) { uint32_t ret = 0; - LOCKED(&arc_connect_spinlock) { + K_SPINLOCK(&arc_connect_spinlock) { z_arc_connect_cmd(ARC_CONNECT_CMD_IDU_CHECK_FIRST, irq_num); ret = z_arc_connect_cmd_readback(); } diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index 2fe54a4080d1..aaee3095d9e9 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -227,9 +227,6 @@ void z_mem_manage_init(void); */ void z_mem_manage_boot_finish(void); -/* Alias of K_SPINLOCK to keep kernel code concise. */ -#define LOCKED K_SPINLOCK - #ifdef CONFIG_PM /* When the kernel is about to go idle, it calls this function to notify the diff --git a/kernel/sched.c b/kernel/sched.c index 2498a0727db4..fd2f52190ce2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -479,7 +479,7 @@ void z_reset_time_slice(struct k_thread *curr) void k_sched_time_slice_set(int32_t slice, int prio) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { slice_ticks = k_ms_to_ticks_ceil32(slice); slice_max_prio = prio; z_reset_time_slice(_current); @@ -490,7 +490,7 @@ void k_sched_time_slice_set(int32_t slice, int prio) void k_thread_time_slice_set(struct k_thread *th, int32_t slice_ticks, k_thread_timeslice_fn_t expired, void *data) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { th->base.slice_ticks = slice_ticks; th->base.slice_expired = expired; th->base.slice_data = data; @@ -617,7 +617,7 @@ static void ready_thread(struct k_thread *thread) void z_ready_thread(struct k_thread *thread) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { if (!thread_active_elsewhere(thread)) { ready_thread(thread); } @@ -626,7 +626,7 @@ void z_ready_thread(struct k_thread *thread) void z_move_thread_to_end_of_prio_q(struct k_thread *thread) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { move_thread_to_end_of_prio_q(thread); } } @@ -651,7 +651,7 @@ void z_impl_k_thread_suspend(struct k_thread *thread) (void)z_abort_thread_timeout(thread); - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { if (z_is_thread_queued(thread)) { dequeue_thread(thread); } @@ -754,7 +754,7 @@ void z_pend_thread(struct k_thread *thread, _wait_q_t *wait_q, k_timeout_t timeout) { __ASSERT_NO_MSG(thread == _current || is_thread_dummy(thread)); - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { pend_locked(thread, wait_q, timeout); } } @@ -768,7 +768,7 @@ static inline void unpend_thread_no_timeout(struct k_thread *thread) ALWAYS_INLINE void z_unpend_thread_no_timeout(struct k_thread *thread) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { if (thread->base.pended_on != NULL) { unpend_thread_no_timeout(thread); } @@ -777,7 +777,7 @@ ALWAYS_INLINE void z_unpend_thread_no_timeout(struct k_thread *thread) void z_sched_wake_thread(struct k_thread *thread, bool is_timeout) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { bool killed = ((thread->base.thread_state & _THREAD_DEAD) || (thread->base.thread_state & _THREAD_ABORTING)); @@ -830,7 +830,7 @@ int z_pend_curr_irqlock(uint32_t key, _wait_q_t *wait_q, k_timeout_t timeout) pending_current = _current; int ret = z_swap_irqlock(key); - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { if (pending_current == _current) { pending_current = NULL; } @@ -867,7 +867,7 @@ struct k_thread *z_unpend1_no_timeout(_wait_q_t *wait_q) { struct k_thread *thread = NULL; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { thread = _priq_wait_best(&wait_q->waitq); if (thread != NULL) { @@ -882,7 +882,7 @@ struct k_thread *z_unpend_first_thread(_wait_q_t *wait_q) { struct k_thread *thread = NULL; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { thread = _priq_wait_best(&wait_q->waitq); if (thread != NULL) { @@ -907,7 +907,7 @@ bool z_set_prio(struct k_thread *thread, int prio) { bool need_sched = 0; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { need_sched = z_is_thread_ready(thread); if (need_sched) { @@ -990,7 +990,7 @@ void z_reschedule_irqlock(uint32_t key) void k_sched_lock(void) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { SYS_PORT_TRACING_FUNC(k_thread, sched_lock); z_sched_lock(); @@ -999,7 +999,7 @@ void k_sched_lock(void) void k_sched_unlock(void) { - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { __ASSERT(_current->base.sched_locked != 0U, ""); __ASSERT(!arch_is_in_isr(), ""); @@ -1079,7 +1079,7 @@ void *z_get_next_switch_handle(void *interrupted) #ifdef CONFIG_SMP void *ret = NULL; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { struct k_thread *old_thread = _current, *new_thread; if (is_aborting(_current)) { @@ -1357,7 +1357,7 @@ void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline) { struct k_thread *thread = tid; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { thread->base.prio_deadline = k_cycle_get_32() + deadline; if (z_is_thread_queued(thread)) { dequeue_thread(thread); @@ -1626,7 +1626,7 @@ static int cpu_mask_mod(k_tid_t thread, uint32_t enable_mask, uint32_t disable_m "Running threads cannot change CPU pin"); #endif - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { if (z_is_thread_prevented_from_running(thread)) { thread->base.cpu_mask |= enable_mask; thread->base.cpu_mask &= ~disable_mask; @@ -1899,7 +1899,7 @@ bool z_sched_wake(_wait_q_t *wait_q, int swap_retval, void *swap_data) struct k_thread *thread; bool ret = false; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { thread = _priq_wait_best(&wait_q->waitq); if (thread != NULL) { @@ -1933,7 +1933,7 @@ int z_sched_waitq_walk(_wait_q_t *wait_q, struct k_thread *thread; int status = 0; - LOCKED(&sched_spinlock) { + K_SPINLOCK(&sched_spinlock) { _WAIT_Q_FOR_EACH(wait_q, thread) { /* diff --git a/kernel/timeout.c b/kernel/timeout.c index a539fb5d6701..67c128429bd0 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -110,7 +110,7 @@ void z_add_timeout(struct _timeout *to, _timeout_func_t fn, __ASSERT(!sys_dnode_is_linked(&to->node), ""); to->fn = fn; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { struct _timeout *t; if (IS_ENABLED(CONFIG_TIMEOUT_64BIT) && @@ -145,7 +145,7 @@ int z_abort_timeout(struct _timeout *to) { int ret = -EINVAL; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { if (sys_dnode_is_linked(&to->node)) { remove_timeout(to); ret = 0; @@ -178,7 +178,7 @@ k_ticks_t z_timeout_remaining(const struct _timeout *timeout) { k_ticks_t ticks = 0; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { ticks = timeout_rem(timeout); } @@ -189,7 +189,7 @@ k_ticks_t z_timeout_expires(const struct _timeout *timeout) { k_ticks_t ticks = 0; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { ticks = curr_tick + timeout_rem(timeout); } @@ -200,7 +200,7 @@ int32_t z_get_next_timeout_expiry(void) { int32_t ret = (int32_t) K_TICKS_FOREVER; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { ret = next_timeout(); } return ret; @@ -261,7 +261,7 @@ int64_t sys_clock_tick_get(void) { uint64_t t = 0U; - LOCKED(&timeout_lock) { + K_SPINLOCK(&timeout_lock) { t = curr_tick + elapsed(); } return t; From 0bf467bbcd35b36771552b08de781fcbc8da3cec Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Wed, 5 Jul 2023 16:01:13 +0200 Subject: [PATCH 1046/2042] mm_drv: tlb: Fix context save for remapped pages In case of remapped reference counter for physical page is differ to zero, but TLB entry for virtual address equal to physical address will be disabled. Valid entry will be somewhere in virtual space where particular physical page is remapped. Since in adsp_mm_save_context() routine we go through physical memory range, we need to include these pages in context save loop. Signed-off-by: Jaroslaw Stelter --- drivers/mm/mm_drv_intel_adsp_mtl_tlb.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index cdce72bbf4ab..6e9b75b11f73 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -331,6 +331,7 @@ int sys_mm_drv_unmap_page(void *virt) { k_spinlock_key_t key; uint32_t entry_idx, bank_idx; + uint16_t entry; uint16_t *tlb_entries = UINT_TO_POINTER(TLB_BASE); uintptr_t pa; int ret = 0; @@ -360,9 +361,11 @@ int sys_mm_drv_unmap_page(void *virt) sys_cache_data_flush_range(virt, CONFIG_MM_DRV_PAGE_SIZE); entry_idx = get_tlb_entry_idx(va); - - /* Simply clear the enable bit */ - tlb_entries[entry_idx] &= ~TLB_ENABLE_BIT; + /* Restore default entry settings */ + entry = pa_to_tlb_entry(va) | TLB_EXEC_BIT | TLB_WRITE_BIT; + /* Clear the enable bit */ + entry &= ~TLB_ENABLE_BIT; + tlb_entries[entry_idx] = entry; pa = tlb_entry_to_pa(tlb_entries[entry_idx]); @@ -723,7 +726,8 @@ static void adsp_mm_save_context(void *storage_buffer) entry_idx = get_tlb_entry_idx(phys_addr); entry = pa_to_tlb_entry(phys_addr); - if ((tlb_entries[entry_idx] & TLB_PADDR_MASK) != entry) { + if (((tlb_entries[entry_idx] & TLB_PADDR_MASK) != entry) || + ((tlb_entries[entry_idx] & TLB_ENABLE_BIT) != TLB_ENABLE_BIT)) { /* this page needs remapping, invalidate cache to avoid stalled data * all cache data has been flushed before * do this for pages to remap only From eb16ab551fe1c7b88085cd89f350e445f2c2b7d1 Mon Sep 17 00:00:00 2001 From: Marcin Gasiorek Date: Thu, 6 Jul 2023 14:21:46 +0200 Subject: [PATCH 1047/2042] tests: net: pkt_filter: Add TCs for new hooks Add new TCs to cover new hooks functionality. These tests implement simple IP filter. Signed-off-by: Marcin Gasiorek --- tests/net/npf/prj.conf | 4 + tests/net/npf/src/main.c | 176 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/tests/net/npf/prj.conf b/tests/net/npf/prj.conf index b1e779aa96e2..57d622130907 100644 --- a/tests/net/npf/prj.conf +++ b/tests/net/npf/prj.conf @@ -12,3 +12,7 @@ CONFIG_NET_BUF_TX_COUNT=20 CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_COMPILER_COLOR_DIAGNOSTICS=n +CONFIG_NET_IPV4=y +CONFIG_NET_PKT_FILTER_IPV4_HOOK=y +CONFIG_NET_IPV6=y +CONFIG_NET_PKT_FILTER_IPV6_HOOK=y diff --git a/tests/net/npf/src/main.c b/tests/net/npf/src/main.c index 992ff535ed6e..39aa63daac20 100644 --- a/tests/net/npf/src/main.c +++ b/tests/net/npf/src/main.c @@ -16,6 +16,9 @@ LOG_MODULE_REGISTER(npf_test, NET_LOG_LEVEL); #include #include +#include "ipv4.h" +#include "ipv6.h" + #include #include @@ -72,6 +75,31 @@ static struct net_pkt *build_test_pkt(int type, int size, struct net_if *iface) return pkt; } +static struct net_pkt *build_test_ip_pkt(void *src, void *dst, + sa_family_t family, struct net_if *iface) +{ + struct net_pkt *pkt; + int ret = -1; + int size; + + size = (family == AF_INET) ? sizeof(struct net_ipv4_hdr) : + (family == AF_INET6) ? sizeof(struct net_ipv6_hdr) : 0U; + + pkt = net_pkt_rx_alloc_with_buffer(iface, size, family, 0, K_NO_WAIT); + zassert_not_null(pkt, ""); + + if (family == AF_INET) { + ret = net_ipv4_create(pkt, (struct in_addr *)src, (struct in_addr *)dst); + } else if (family == AF_INET6) { + ret = net_ipv6_create(pkt, (struct in6_addr *)src, (struct in6_addr *)dst); + } + zassert_equal(ret, 0, "Cannot create %s packet (%d)", + (family == AF_INET) ? "IPv4" : "IPv6", ret); + + DBG("pkt %p: iface %p size %d sa_family %d\n", pkt, iface, size, family); + return pkt; +} + /* * Declare some fake interfaces and test their filter conditions. */ @@ -274,6 +302,8 @@ static void test_npf_eth_mac_address(void) zassert_true(npf_remove_recv_rule(&accept_matched_dst_addr), ""); zassert_false(net_pkt_filter_recv_ok(pkt), ""); zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), ""); + + net_pkt_unref(pkt); } static NPF_ETH_SRC_ADDR_MASK_MATCH(matched_src_addr_mask, mac_address_list, @@ -299,6 +329,8 @@ static void test_npf_eth_mac_addr_mask(void) /* cleanup */ zassert_true(npf_remove_all_recv_rules(), ""); + + net_pkt_unref(pkt); } ZTEST(net_pkt_filter_test_suite, test_npf_address_mask) @@ -307,4 +339,148 @@ ZTEST(net_pkt_filter_test_suite, test_npf_address_mask) test_npf_eth_mac_addr_mask(); } +/* + * IP address filtering + */ + +static struct in_addr ipv4_address_list[4] = { + { { { 192, 168, 1, 1 } } }, + { { { 192, 0, 2, 1 } } }, + { { { 172, 16, 0, 1 } } }, + { { { 10, 49, 0, 252 } } } +}; + +static struct in6_addr ipv6_address_list[4] = { + { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, + { { { 0x20, 0x01, 0x0d, 0xb8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }, +}; + +static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv4_src_addr, (void *)ipv4_address_list, + ARRAY_SIZE(ipv4_address_list), AF_INET); +static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv4_src_addr, (void *)ipv4_address_list, + ARRAY_SIZE(ipv4_address_list), AF_INET); + +static NPF_RULE(ipv4_allowlist, NET_OK, allowlist_ipv4_src_addr); +static NPF_RULE(ipv4_blocklist, NET_OK, blocklist_ipv4_src_addr); + +ZTEST(net_pkt_filter_test_suite, test_npf_ipv4_address_filtering) +{ + struct in_addr dst = { { { 192, 168, 2, 1 } } }; + struct in_addr bad_addr = { { { 192, 168, 2, 3 } } }; + struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &dst, AF_INET, + &dummy_iface_a); + struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &ipv6_address_list[1], + AF_INET6, &dummy_iface_a); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate allowlist */ + npf_insert_ipv4_recv_rule(&ipv4_allowlist); + + for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) { + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it], + sizeof(struct in_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + } + + /* And one not listed */ + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, + &bad_addr, sizeof(struct in_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* Prepare new test */ + zassert_true(npf_remove_all_ipv4_recv_rules(), ""); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate blocklist */ + npf_insert_ipv4_recv_rule(&ipv4_blocklist); + + for (int it = 0; it < ARRAY_SIZE(ipv4_address_list); it++) { + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, &ipv4_address_list[it], + sizeof(struct in_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + } + + /* And one not listed */ + memcpy((struct in_addr *)NET_IPV4_HDR(pkt_v4)->src, + &bad_addr, sizeof(struct in_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + + zassert_true(npf_remove_all_ipv4_recv_rules(), ""); + net_pkt_unref(pkt_v6); + net_pkt_unref(pkt_v4); +} + +static NPF_IP_SRC_ADDR_ALLOWLIST(allowlist_ipv6_src_addr, (void *)ipv6_address_list, + ARRAY_SIZE(ipv6_address_list), AF_INET6); +static NPF_IP_SRC_ADDR_BLOCKLIST(blocklist_ipv6_src_addr, (void *)ipv6_address_list, + ARRAY_SIZE(ipv6_address_list), AF_INET6); + +static NPF_RULE(ipv6_allowlist, NET_OK, allowlist_ipv6_src_addr); +static NPF_RULE(ipv6_blocklist, NET_OK, blocklist_ipv6_src_addr); + +ZTEST(net_pkt_filter_test_suite, test_npf_ipv6_address_filtering) +{ + struct in6_addr dst = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0, + 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02, 0x04 } } }; + struct in6_addr bad_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; + struct net_pkt *pkt_v6 = build_test_ip_pkt(&ipv6_address_list[0], &dst, AF_INET6, + &dummy_iface_a); + struct net_pkt *pkt_v4 = build_test_ip_pkt(&ipv4_address_list[0], &ipv4_address_list[1], + AF_INET, &dummy_iface_a); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate allowlist */ + npf_insert_ipv6_recv_rule(&ipv6_allowlist); + + for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) { + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &ipv6_address_list[it], sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + } + + /* And one not listed */ + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &bad_addr, sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* Prepare new test */ + zassert_true(npf_remove_all_ipv6_recv_rules(), ""); + + /* make sure pkt is initially accepted */ + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v4), ""); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + /* validate blocklist */ + npf_insert_ipv6_recv_rule(&ipv6_blocklist); + + for (int it = 0; it < ARRAY_SIZE(ipv6_address_list); it++) { + memcpy((struct in6_addr *)NET_IPV6_HDR(pkt_v6)->src, + &ipv6_address_list[it], sizeof(struct in6_addr)); + zassert_false(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + } + + /* And one not listed */ + memcpy((struct in6_addr *)NET_IPV4_HDR(pkt_v6)->src, + &bad_addr, sizeof(struct in6_addr)); + zassert_true(net_pkt_filter_ip_recv_ok(pkt_v6), ""); + + zassert_true(npf_remove_all_ipv6_recv_rules(), ""); + net_pkt_unref(pkt_v6); + net_pkt_unref(pkt_v4); +} + ZTEST_SUITE(net_pkt_filter_test_suite, NULL, test_npf_iface, NULL, NULL, NULL); From 5894bec82f7530337eb80fc17037f88dfc6adb21 Mon Sep 17 00:00:00 2001 From: Marcin Gasiorek Date: Thu, 6 Jul 2023 14:17:51 +0200 Subject: [PATCH 1048/2042] net: pkt_filter: Introduce additional hooks for pkt_filter The additional hooks provide infrastructure to construct rules on another network stack levels. Main benefit of this approach is packets are pre-parsed and e.g. IP filter is easier to implement. These hooks are equivalent of prerouting and local_in in linux's netfilter. Signed-off-by: Marcin Gasiorek --- include/zephyr/net/net_pkt.h | 31 +++++++++ include/zephyr/net/net_pkt_filter.h | 81 ++++++++++++++++++++++++ subsys/net/ip/connection.c | 5 ++ subsys/net/ip/ipv4.c | 13 ++-- subsys/net/ip/ipv6.c | 5 ++ subsys/net/pkt_filter/Kconfig | 22 +++++++ subsys/net/pkt_filter/base.c | 98 +++++++++++++++++++++++++++++ 7 files changed, 251 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index 0ffd066981ad..d540a91d9ffa 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -1275,6 +1275,37 @@ static inline bool net_pkt_filter_recv_ok(struct net_pkt *pkt) #endif /* CONFIG_NET_PKT_FILTER */ +#if defined(CONFIG_NET_PKT_FILTER) && \ + (defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK)) + +bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt); + +#else + +static inline bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return true; +} + +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + +#if defined(CONFIG_NET_PKT_FILTER) && defined(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK) + +bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt); + +#else + +static inline bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return true; +} + +#endif /* CONFIG_NET_PKT_FILTER && CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + /* @endcond */ /** diff --git a/include/zephyr/net/net_pkt_filter.h b/include/zephyr/net/net_pkt_filter.h index 735352253000..aa1ad89b0e61 100644 --- a/include/zephyr/net/net_pkt_filter.h +++ b/include/zephyr/net/net_pkt_filter.h @@ -67,6 +67,12 @@ struct npf_rule_list { extern struct npf_rule_list npf_send_rules; /** @brief rule list applied to incoming packets */ extern struct npf_rule_list npf_recv_rules; +/** @brief rule list applied for local incoming packets */ +extern struct npf_rule_list npf_local_in_recv_rules; +/** @brief rule list applied for IPv4 incoming packets */ +extern struct npf_rule_list npf_ipv4_recv_rules; +/** @brief rule list applied for IPv6 incoming packets */ +extern struct npf_rule_list npf_ipv6_recv_rules; /** * @brief Insert a rule at the front of given rule list @@ -111,6 +117,27 @@ bool npf_remove_all_rules(struct npf_rule_list *rules); #define npf_remove_all_send_rules() npf_remove_all_rules(&npf_send_rules) #define npf_remove_all_recv_rules() npf_remove_all_rules(&npf_recv_rules) +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +#define npf_insert_local_in_recv_rule(rule) npf_insert_rule(&npf_local_in_recv_rules, rule) +#define npf_append_local_in_recv_rule(rule) npf_append_rule(&npf_local_in_recv_rules, rule) +#define npf_remove_local_in_recv_rule(rule) npf_remove_rule(&npf_local_in_recv_rules, rule) +#define npf_remove_all_local_in_recv_rules() npf_remove_all_rules(&npf_local_in_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK +#define npf_insert_ipv4_recv_rule(rule) npf_insert_rule(&npf_ipv4_recv_rules, rule) +#define npf_append_ipv4_recv_rule(rule) npf_append_rule(&npf_ipv4_recv_rules, rule) +#define npf_remove_ipv4_recv_rule(rule) npf_remove_rule(&npf_ipv4_recv_rules, rule) +#define npf_remove_all_ipv4_recv_rules() npf_remove_all_rules(&npf_ipv4_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK +#define npf_insert_ipv6_recv_rule(rule) npf_insert_rule(&npf_ipv6_recv_rules, rule) +#define npf_append_ipv6_recv_rule(rule) npf_append_rule(&npf_ipv6_recv_rules, rule) +#define npf_remove_ipv6_recv_rule(rule) npf_remove_rule(&npf_ipv6_recv_rules, rule) +#define npf_remove_all_ipv6_recv_rules() npf_remove_all_rules(&npf_ipv6_recv_rules) +#endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + /** * @brief Statically define one packet filter rule * @@ -296,6 +323,60 @@ extern npf_test_fn_t npf_size_inbounds; .test.fn = npf_size_inbounds, \ } +/** @cond INTERNAL_HIDDEN */ + +struct npf_test_ip { + struct npf_test test; + uint8_t addr_family; + void *ipaddr; + uint32_t ipaddr_num; +}; + +extern npf_test_fn_t npf_ip_src_addr_match; +extern npf_test_fn_t npf_ip_src_addr_unmatch; + +/** @endcond */ + +/** + * @brief Statically define a "ip address allowlist" packet filter condition + * + * This tests if the packet source ip address matches any of the ip + * addresses contained in the provided set. + * + * @param _name Name of the condition + * @param _ip_addr_array Array of struct in_addr or struct in6_addr items to test + *against + * @param _ip_addr_num number of IP addresses in the array + * @param _af Addresses family type (AF_INET / AF_INET6) in the array + */ +#define NPF_IP_SRC_ADDR_ALLOWLIST(_name, _ip_addr_array, _ip_addr_num, _af) \ + struct npf_test_ip _name = { \ + .addr_family = _af, \ + .ipaddr = (_ip_addr_array), \ + .ipaddr_num = _ip_addr_num, \ + .test.fn = npf_ip_src_addr_match, \ + } + +/** + * @brief Statically define a "ip address blocklist" packet filter condition + * + * This tests if the packet source ip address matches any of the ip + * addresses contained in the provided set. + * + * @param _name Name of the condition + * @param _ip_addr_array Array of struct in_addr or struct in6_addr items to test + *against + * @param _ip_addr_num number of IP addresses in the array + * @param _af Addresses family type (AF_INET / AF_INET6) in the array + */ +#define NPF_IP_SRC_ADDR_BLOCKLIST(_name, _ip_addr_array, _ip_addr_num, _af) \ + struct npf_test_ip _name = { \ + .addr_family = _af, \ + .ipaddr = (_ip_addr_array), \ + .ipaddr_num = _ip_addr_num, \ + .test.fn = npf_ip_src_addr_unmatch, \ + } + /** @} */ /** diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index b370bc1835fc..225a3fdbaade 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -576,6 +576,11 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, uint8_t pkt_family = net_pkt_family(pkt); uint16_t src_port = 0U, dst_port = 0U; + if (!net_pkt_filter_local_in_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if (IS_ENABLED(CONFIG_NET_IP) && (pkt_family == AF_INET || pkt_family == AF_INET6)) { if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) { src_port = proto_hdr->udp->src_port; diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 0392e75cec1c..83827303f6e7 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -302,6 +302,15 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) goto drop; } + net_pkt_set_ipv4_ttl(pkt, hdr->ttl); + + net_pkt_set_family(pkt, PF_INET); + + if (!net_pkt_filter_ip_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if ((!net_ipv4_is_my_addr((struct in_addr *)hdr->dst) && !net_ipv4_is_addr_mcast((struct in_addr *)hdr->dst) && !(hdr->proto == IPPROTO_UDP && @@ -326,10 +335,6 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) } } - net_pkt_set_ipv4_ttl(pkt, hdr->ttl); - - net_pkt_set_family(pkt, PF_INET); - if (IS_ENABLED(CONFIG_NET_IPV4_FRAGMENT)) { /* Check if this is a fragmented packet, and if so, handle reassembly */ if ((ntohs(*((uint16_t *)&hdr->offset[0])) & diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 48165099759c..7ef758314060 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_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_HDR(pkt)->hop_limit); net_pkt_set_family(pkt, PF_INET6); + if (!net_pkt_filter_ip_recv_ok(pkt)) { + /* drop the packet */ + return NET_DROP; + } + if (IS_ENABLED(CONFIG_NET_ROUTE_MCAST) && net_ipv6_is_addr_mcast((struct in6_addr *)hdr->dst)) { /* If the packet is a multicast packet and multicast routing diff --git a/subsys/net/pkt_filter/Kconfig b/subsys/net/pkt_filter/Kconfig index ef3a02ad45e7..8b95a67caa63 100644 --- a/subsys/net/pkt_filter/Kconfig +++ b/subsys/net/pkt_filter/Kconfig @@ -12,6 +12,28 @@ config NET_PKT_FILTER transmission and reception. if NET_PKT_FILTER + +config NET_PKT_FILTER_IPV4_HOOK + bool "Additional network packet filtering hook inside IPv4 stack" + depends on NET_IPV4 + help + This additional hook provides infrastructure to construct custom + rules on the IP packet. + +config NET_PKT_FILTER_IPV6_HOOK + bool "Additional network packet filtering hook inside IPv6 stack" + depends on NET_IPV6 + help + This additional hook provides infrastructure to construct custom + rules on the IP packet. + +config NET_PKT_FILTER_LOCAL_IN_HOOK + bool "Additional network packet filtering hook for connection input" + depends on NET_IP + help + This additional hook provides infrastructure to construct custom + rules for e.g. TCP/UDP packets. + module = NET_PKT_FILTER module-dep = NET_LOG module-str = Log level for packet filtering diff --git a/subsys/net/pkt_filter/base.c b/subsys/net/pkt_filter/base.c index e33091e7af74..bb2eb9f085ba 100644 --- a/subsys/net/pkt_filter/base.c +++ b/subsys/net/pkt_filter/base.c @@ -25,6 +25,50 @@ struct npf_rule_list npf_recv_rules = { .lock = { }, }; +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +struct npf_rule_list npf_local_in_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&local_in_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK +struct npf_rule_list npf_ipv4_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&ipv4_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */ + +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK +struct npf_rule_list npf_ipv6_recv_rules = { + .rule_head = SYS_SLIST_STATIC_INIT(&ipv6_recv_rules.rule_head), + .lock = { }, +}; +#endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + +/* + * Helper function + */ +static struct npf_rule_list *get_ip_rules(uint8_t pf) +{ + switch (pf) { + case PF_INET: +#ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK + return &npf_ipv4_recv_rules; +#endif + break; + case PF_INET6: +#ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK + return &npf_ipv6_recv_rules; +#endif + break; + default: + return NULL; + } + + return NULL; +} + /* * Rule application */ @@ -98,6 +142,31 @@ bool net_pkt_filter_recv_ok(struct net_pkt *pkt) return result == NET_OK; } +#ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK +bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt) +{ + enum net_verdict result = lock_evaluate(&npf_local_in_recv_rules, pkt); + + return result == NET_OK; +} +#endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */ + +#if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK) +bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt) +{ + struct npf_rule_list *rules = get_ip_rules(net_pkt_family(pkt)); + + if (!rules) { + NET_DBG("no rules"); + return true; + } + + enum net_verdict result = lock_evaluate(rules, pkt); + + return result == NET_OK; +} +#endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */ + /* * Rule management */ @@ -199,3 +268,32 @@ bool npf_size_inbounds(struct npf_test *test, struct net_pkt *pkt) return pkt_size >= bounds->min && pkt_size <= bounds->max; } + +bool npf_ip_src_addr_match(struct npf_test *test, struct net_pkt *pkt) +{ + struct npf_test_ip *test_ip = + CONTAINER_OF(test, struct npf_test_ip, test); + uint8_t pkt_family = net_pkt_family(pkt); + + for (uint32_t ip_it = 0; ip_it < test_ip->ipaddr_num; ip_it++) { + if (IS_ENABLED(CONFIG_NET_IPV4) && pkt_family == AF_INET) { + struct in_addr *addr = (struct in_addr *)NET_IPV4_HDR(pkt)->src; + + if (net_ipv4_addr_cmp(addr, &((struct in_addr *)test_ip->ipaddr)[ip_it])) { + return true; + } + } else if (IS_ENABLED(CONFIG_NET_IPV6) && pkt_family == AF_INET6) { + struct in6_addr *addr = (struct in6_addr *)NET_IPV6_HDR(pkt)->src; + + if (net_ipv6_addr_cmp(addr, &((struct in6_addr *)test_ip->ipaddr)[ip_it])) { + return true; + } + } + } + return false; +} + +bool npf_ip_src_addr_unmatch(struct npf_test *test, struct net_pkt *pkt) +{ + return !npf_ip_src_addr_match(test, pkt); +} From 415351f46a59aca007e4e1693e601005615e75e1 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 3 Jul 2023 15:41:33 +0200 Subject: [PATCH 1049/2042] net: l2: ieee802154: frag configuration Minor simplification in the definition of IEEE 802.15.4 Kconfig packet fragmentation configuration. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/ieee802154/Kconfig b/subsys/net/l2/ieee802154/Kconfig index 8239d00efa89..244d7f9da01d 100644 --- a/subsys/net/l2/ieee802154/Kconfig +++ b/subsys/net/l2/ieee802154/Kconfig @@ -103,9 +103,10 @@ config NET_L2_IEEE802154_FRAGMENT If IPv6 packets size more than 802.15.4 MTU, packet is fragmented and reassemble incoming packets according to RFC4944/6282. +if NET_L2_IEEE802154_FRAGMENT + config NET_L2_IEEE802154_FRAGMENT_REASS_CACHE_SIZE int "IEEE 802.15.4 Reassembly cache size" - depends on NET_L2_IEEE802154_FRAGMENT default 1 help Simultaneously reassemble 802.15.4 fragments depending on @@ -113,7 +114,6 @@ config NET_L2_IEEE802154_FRAGMENT_REASS_CACHE_SIZE config NET_L2_IEEE802154_REASSEMBLY_TIMEOUT int "IEEE 802.15.4 Reassembly timeout in seconds" - depends on NET_L2_IEEE802154_FRAGMENT default 5 range 1 60 help @@ -121,6 +121,8 @@ config NET_L2_IEEE802154_REASSEMBLY_TIMEOUT from peer. Reassembly should be finished within a given time. Otherwise all accumulated fragments are dropped. +endif # NET_L2_IEEE802154_FRAGMENT + config NET_L2_IEEE802154_SECURITY bool "IEEE 802.15.4 security [EXPERIMENTAL]" select EXPERIMENTAL From 3aa668f3ca7b7d1f551e062e7217e5ef33086e07 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:09 +0200 Subject: [PATCH 1050/2042] net: l2: ieee802154: introduce IEEE 802.15.4-2020 association type The IEEE 802.15.4-2020 standard introduces an association type field to support fast association, see sections 6.4.3 and 7.5.2. We do not yet implement fast association but we introduce the flag to make this obvious. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.h | 6 ++++-- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.h b/subsys/net/l2/ieee802154/ieee802154_frame.h index c76d8df464a3..be9c6b60a411 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.h +++ b/subsys/net/l2/ieee802154/ieee802154_frame.h @@ -327,13 +327,15 @@ struct ieee802154_cmd_assoc_req { uint8_t dev_type : 1; uint8_t power_src : 1; uint8_t rx_on : 1; - uint8_t reserved_2 : 2; + uint8_t association_type : 1; + uint8_t reserved_2 : 1; uint8_t sec_capability : 1; uint8_t alloc_addr : 1; #else uint8_t alloc_addr : 1; uint8_t sec_capability : 1; - uint8_t reserved_2 : 2; + uint8_t reserved_2 : 1; + uint8_t association_type : 1; uint8_t rx_on : 1; uint8_t power_src : 1; uint8_t dev_type : 1; diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index 1bc7c875433f..35bda615f5ff 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -375,6 +375,7 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, cmd->assoc_req.ci.dev_type = 0U; /* RFD */ cmd->assoc_req.ci.power_src = 0U; /* TODO: set right power source */ cmd->assoc_req.ci.rx_on = 1U; /* TODO: that will depends on PM */ + cmd->assoc_req.ci.association_type = 0U; /* normal association */ cmd->assoc_req.ci.reserved_2 = 0U; /* Reserved */ cmd->assoc_req.ci.sec_capability = 0U; /* TODO: security support */ cmd->assoc_req.ci.alloc_addr = 0U; /* TODO: handle short addr */ From 4edf46d86c0082e7b608d6323e0586e9c0ab39bd Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 16:54:14 +0200 Subject: [PATCH 1051/2042] net: l2: ieee802154: radio: fix radio utils naming The IEEE 802.15.4 stack defines radio API helpers that provide simplified and encapsulated access to radio API features. These helpers were missing the `_radio_` infix. This infix is introduced to clearly distinguish between MAC and PHY concerns. While PHY features may be shared between L2 implementations (including the functions concerned here), this is not true for MAC features. Signed-off-by: Florian Grandel --- modules/openthread/platform/radio.c | 2 +- subsys/net/l2/ieee802154/ieee802154.c | 30 ++++++------- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 28 ++++++------- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 4 +- subsys/net/l2/ieee802154/ieee802154_utils.h | 42 +++++++------------ 5 files changed, 49 insertions(+), 57 deletions(-) diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 523d49bd8aa0..16a282ff93f6 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -842,7 +842,7 @@ void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) promiscuous = aEnable; /* TODO: Should check whether the radio driver actually supports * promiscuous mode, see net_if_l2(iface)->get_flags() and - * ieee802154_get_hw_capabilities(iface). + * ieee802154_radio_get_hw_capabilities(iface). */ radio_api->configure(radio_dev, IEEE802154_CONFIG_PROMISCUOUS, &config); } diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 8f06912b1b85..a996cb4e5807 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -72,7 +72,7 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 { struct net_pkt *pkt; - if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_RX_TX_ACK) { + if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_RX_TX_ACK) { return; } @@ -88,7 +88,7 @@ static inline void ieee802154_acknowledge(struct net_if *iface, struct ieee80215 if (ieee802154_create_ack_frame(iface, pkt, mpdu->mhr.fs->sequence)) { /* ACK frames must not use the CSMA/CA procedure, see section 6.2.5.1. */ - ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, pkt->buffer); + ieee802154_radio_tx(iface, IEEE802154_TX_MODE_DIRECT, pkt, pkt->buffer); } net_pkt_unref(pkt); @@ -101,7 +101,7 @@ inline bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt { bool ack_required = ieee802154_is_ar_flag_set(frag); - if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { + if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { return ack_required; } @@ -123,7 +123,7 @@ enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt { struct ieee802154_context *ctx = net_if_l2_data(iface); - if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { + if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK) { __ASSERT_NO_MSG(ctx->ack_seq == 0U); /* TODO: Release packet in L2 as we're taking ownership. */ return NET_OK; @@ -153,7 +153,8 @@ inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) { struct ieee802154_context *ctx = net_if_l2_data(iface); - if (!ack_required || (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { + if (!ack_required || + (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { __ASSERT_NO_MSG(ctx->ack_seq == 0U); return 0; } @@ -178,17 +179,18 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ NET_DBG("frag %p", frag); - if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_RETRANSMISSION) { + if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_RETRANSMISSION) { /* A driver that claims retransmission capability must also be able * to wait for ACK frames otherwise it could not decide whether or * not retransmission is required in a standard conforming way. */ - __ASSERT_NO_MSG(ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK); + __ASSERT_NO_MSG(ieee802154_radio_get_hw_capabilities(iface) & + IEEE802154_HW_TX_RX_ACK); remaining_attempts = 1; } hw_csma = IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) && - ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA; + ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_CSMA; /* Media access (CSMA, ALOHA, ...) and retransmission, see section 6.7.4.4. */ while (remaining_attempts) { @@ -211,7 +213,7 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ * - retransmission on ACK timeout in case the driver has * IEEE802154_HW_RETRANSMISSION capability. */ - ret = ieee802154_tx( + ret = ieee802154_radio_tx( iface, hw_csma ? IEEE802154_TX_MODE_CSMA_CA : IEEE802154_TX_MODE_DIRECT, pkt, frag); if (ret) { @@ -590,10 +592,10 @@ static int ieee802154_enable(struct net_if *iface, bool state) k_sem_give(&ctx->ctx_lock); if (state) { - return ieee802154_start(iface); + return ieee802154_radio_start(iface); } - return ieee802154_stop(iface); + return ieee802154_radio_stop(iface); } static enum net_l2_flags ieee802154_flags(struct net_if *iface) @@ -630,7 +632,7 @@ void ieee802154_init(struct net_if *iface) ctx->channel = IEEE802154_NO_CHANNEL; ctx->flags = NET_L2_MULTICAST; - if (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_PROMISC) { + if (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_PROMISC) { ctx->flags |= NET_L2_PROMISC_MODE; } @@ -661,9 +663,9 @@ void ieee802154_init(struct net_if *iface) #endif sys_memcpy_swap(ctx->ext_addr, eui64_be, IEEE802154_EXT_ADDR_LENGTH); - ieee802154_filter_ieee_addr(iface, ctx->ext_addr); + ieee802154_radio_filter_ieee_addr(iface, ctx->ext_addr); - if (!ieee802154_set_tx_power(iface, tx_power)) { + if (!ieee802154_radio_set_tx_power(iface, tx_power)) { ctx->tx_power = tx_power; } } diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index 35bda615f5ff..2bc392fd54e0 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -138,9 +138,9 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, ret = 0; - ieee802154_filter_pan_id(iface, IEEE802154_BROADCAST_PAN_ID); + ieee802154_radio_filter_pan_id(iface, IEEE802154_BROADCAST_PAN_ID); - if (ieee802154_start(iface)) { + if (ieee802154_radio_start(iface)) { NET_DBG("Could not start device"); ret = -EIO; @@ -157,7 +157,7 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, scan->channel = channel; NET_DBG("Scanning channel %u", channel); - ieee802154_set_channel(iface, channel); + ieee802154_radio_set_channel(iface, channel); /* Active scan sends a beacon request */ if (mgmt_request == NET_REQUEST_IEEE802154_ACTIVE_SCAN) { @@ -190,8 +190,8 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, out: /* Let's come back to context's settings. */ - ieee802154_filter_pan_id(iface, ctx->pan_id); - ieee802154_set_channel(iface, ctx->channel); + ieee802154_radio_filter_pan_id(iface, ctx->pan_id); + ieee802154_radio_set_channel(iface, ctx->channel); ctx->scan_ctx = NULL; k_sem_give(&ctx->scan_ctx_lock); @@ -244,7 +244,7 @@ static inline void set_association(struct net_if *iface, struct ieee802154_conte memcpy(ctx->linkaddr.addr, &short_addr_be, IEEE802154_SHORT_ADDR_LENGTH); update_net_if_link_addr(iface, ctx); - ieee802154_filter_short_addr(iface, ctx->short_addr); + ieee802154_radio_filter_short_addr(iface, ctx->short_addr); } /* Requires the context lock to be held. */ @@ -254,7 +254,7 @@ static inline void remove_association(struct net_if *iface, struct ieee802154_co memset(ctx->coord_ext_addr, 0, IEEE802154_EXT_ADDR_LENGTH); ctx->coord_short_addr = 0U; set_linkaddr_to_ext_addr(iface, ctx); - ieee802154_filter_short_addr(iface, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED); + ieee802154_radio_filter_short_addr(iface, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED); } /* Requires the context lock to be held. */ @@ -386,7 +386,7 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, ieee802154_mac_cmd_finalize(pkt, IEEE802154_CFI_ASSOCIATION_REQUEST); - ieee802154_filter_pan_id(iface, req->pan_id); + ieee802154_radio_filter_pan_id(iface, req->pan_id); if (net_if_send_data(iface, pkt)) { net_pkt_unref(pkt); @@ -442,7 +442,7 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, out: if (ret < 0) { - ieee802154_filter_pan_id(iface, 0); + ieee802154_radio_filter_pan_id(iface, 0); } k_sem_give(&ctx->ctx_lock); @@ -567,12 +567,12 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, if (mgmt_request == NET_REQUEST_IEEE802154_SET_CHANNEL) { if (ctx->channel != value) { - if (!ieee802154_verify_channel(iface, value)) { + if (!ieee802154_radio_verify_channel(iface, value)) { ret = -EINVAL; goto out; } - ret = ieee802154_set_channel(iface, value); + ret = ieee802154_radio_set_channel(iface, value); if (!ret) { ctx->channel = value; } @@ -580,7 +580,7 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_PAN_ID) { if (ctx->pan_id != value) { ctx->pan_id = value; - ieee802154_filter_pan_id(iface, ctx->pan_id); + ieee802154_radio_filter_pan_id(iface, ctx->pan_id); } } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_EXT_ADDR) { if (len != IEEE802154_EXT_ADDR_LENGTH) { @@ -599,7 +599,7 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, set_linkaddr_to_ext_addr(iface, ctx); } - ieee802154_filter_ieee_addr(iface, ctx->ext_addr); + ieee802154_radio_filter_ieee_addr(iface, ctx->ext_addr); } } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_SHORT_ADDR) { if (ctx->short_addr != value) { @@ -611,7 +611,7 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, } } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_TX_POWER) { if (ctx->tx_power != (int16_t)value) { - ret = ieee802154_set_tx_power(iface, (int16_t)value); + ret = ieee802154_radio_set_tx_power(iface, (int16_t)value); if (!ret) { ctx->tx_power = (int16_t)value; } diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index fc43fca9dd3b..aee4a1ddec93 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -32,7 +32,7 @@ static inline int unslotted_csma_ca_channel_access(struct net_if *iface) uint32_t symbol_period, turnaround_time; bool is_subg_phy; - is_subg_phy = ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ; + is_subg_phy = ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ; /* TODO: Move symbol period calculation to radio driver. */ symbol_period = IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy); turnaround_time = IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy); @@ -51,7 +51,7 @@ static inline int unslotted_csma_ca_channel_access(struct net_if *iface) symbol_period)); } - ret = ieee802154_cca(iface); + ret = ieee802154_radio_cca(iface); if (ret == 0) { /* Channel is idle -> CSMA Success */ return 0; diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index 09450dde7786..87c6a28a996a 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -14,8 +14,7 @@ #include -static inline -enum ieee802154_hw_caps ieee802154_get_hw_capabilities(struct net_if *iface) +static inline enum ieee802154_hw_caps ieee802154_radio_get_hw_capabilities(struct net_if *iface) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -27,7 +26,7 @@ enum ieee802154_hw_caps ieee802154_get_hw_capabilities(struct net_if *iface) return radio->get_capabilities(net_if_get_device(iface)); } -static inline int ieee802154_cca(struct net_if *iface) +static inline int ieee802154_radio_cca(struct net_if *iface) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -39,7 +38,7 @@ static inline int ieee802154_cca(struct net_if *iface) return radio->cca(net_if_get_device(iface)); } -static inline int ieee802154_set_channel(struct net_if *iface, uint16_t channel) +static inline int ieee802154_radio_set_channel(struct net_if *iface, uint16_t channel) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -51,7 +50,7 @@ static inline int ieee802154_set_channel(struct net_if *iface, uint16_t channel) return radio->set_channel(net_if_get_device(iface), channel); } -static inline int ieee802154_set_tx_power(struct net_if *iface, int16_t dbm) +static inline int ieee802154_radio_set_tx_power(struct net_if *iface, int16_t dbm) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -63,10 +62,8 @@ static inline int ieee802154_set_tx_power(struct net_if *iface, int16_t dbm) return radio->set_txpower(net_if_get_device(iface), dbm); } -static inline int ieee802154_tx(struct net_if *iface, - enum ieee802154_tx_mode mode, - struct net_pkt *pkt, - struct net_buf *buf) +static inline int ieee802154_radio_tx(struct net_if *iface, enum ieee802154_tx_mode mode, + struct net_pkt *pkt, struct net_buf *buf) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -78,7 +75,7 @@ static inline int ieee802154_tx(struct net_if *iface, return radio->tx(net_if_get_device(iface), mode, pkt, buf); } -static inline int ieee802154_start(struct net_if *iface) +static inline int ieee802154_radio_start(struct net_if *iface) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -90,7 +87,7 @@ static inline int ieee802154_start(struct net_if *iface) return radio->start(net_if_get_device(iface)); } -static inline int ieee802154_stop(struct net_if *iface) +static inline int ieee802154_radio_stop(struct net_if *iface) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -108,7 +105,7 @@ static inline int ieee802154_stop(struct net_if *iface) * @param iface Pointer to the IEEE 802.15.4 interface * @param ieee_addr Pointer to an extended address in little endian byte order */ -static inline void ieee802154_filter_ieee_addr(struct net_if *iface, uint8_t *ieee_addr) +static inline void ieee802154_radio_filter_ieee_addr(struct net_if *iface, uint8_t *ieee_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -127,8 +124,7 @@ static inline void ieee802154_filter_ieee_addr(struct net_if *iface, uint8_t *ie } } -static inline void ieee802154_filter_short_addr(struct net_if *iface, - uint16_t short_addr) +static inline void ieee802154_radio_filter_short_addr(struct net_if *iface, uint16_t short_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -147,8 +143,7 @@ static inline void ieee802154_filter_short_addr(struct net_if *iface, } } -static inline void ieee802154_filter_pan_id(struct net_if *iface, - uint16_t pan_id) +static inline void ieee802154_radio_filter_pan_id(struct net_if *iface, uint16_t pan_id) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -167,8 +162,7 @@ static inline void ieee802154_filter_pan_id(struct net_if *iface, } } -static inline void ieee802154_filter_src_ieee_addr(struct net_if *iface, - uint8_t *ieee_addr) +static inline void ieee802154_radio_filter_src_ieee_addr(struct net_if *iface, uint8_t *ieee_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -187,8 +181,7 @@ static inline void ieee802154_filter_src_ieee_addr(struct net_if *iface, } } -static inline void ieee802154_filter_src_short_addr(struct net_if *iface, - uint16_t short_addr) +static inline void ieee802154_radio_filter_src_short_addr(struct net_if *iface, uint16_t short_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -207,8 +200,7 @@ static inline void ieee802154_filter_src_short_addr(struct net_if *iface, } } -static inline void ieee802154_remove_src_ieee_addr(struct net_if *iface, - uint8_t *ieee_addr) +static inline void ieee802154_radio_remove_src_ieee_addr(struct net_if *iface, uint8_t *ieee_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -227,8 +219,7 @@ static inline void ieee802154_remove_src_ieee_addr(struct net_if *iface, } } -static inline void ieee802154_remove_src_short_addr(struct net_if *iface, - uint16_t short_addr) +static inline void ieee802154_radio_remove_src_short_addr(struct net_if *iface, uint16_t short_addr) { const struct ieee802154_radio_api *radio = net_if_get_device(iface)->api; @@ -247,8 +238,7 @@ static inline void ieee802154_remove_src_short_addr(struct net_if *iface, } } -static inline bool ieee802154_verify_channel(struct net_if *iface, - uint16_t channel) +static inline bool ieee802154_radio_verify_channel(struct net_if *iface, uint16_t channel) { if (channel == IEEE802154_NO_CHANNEL) { return false; From d452ef9863b568e2a991c0d686bc6020d8bfda6d Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 17:10:02 +0200 Subject: [PATCH 1052/2042] net: l2: ieee802154: correctly calculate macResponseWaitTime Calculates macResponseWaitTime and applies it to the association process. As the timing calculation re-uses symbol period calculations and other PHY timing constants previously introduced, these are now shared as utility functions. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154_radio.h | 8 +- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 12 +- .../l2/ieee802154/ieee802154_radio_csma_ca.c | 9 +- subsys/net/l2/ieee802154/ieee802154_utils.h | 140 +++++++++++++++++- 4 files changed, 152 insertions(+), 17 deletions(-) diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index ec8e7f4ae340..3270f334b5a2 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -41,7 +41,7 @@ extern "C" { * https://github.com/zephyrproject-rtos/zephyr/issues/50336#issuecomment-1251122582. * For now we assume PHYs that current drivers actually implement. */ -#define IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy) \ +#define IEEE802154_PHY_SYMBOL_PERIOD_US(is_subg_phy) \ ((is_subg_phy) ? IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_US \ : IEEE802154_PHY_OQPSK_2450MHZ_SYMBOL_PERIOD_US) @@ -69,9 +69,9 @@ extern "C" { * For now we assume PHYs that current drivers actually implement. */ #define IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy) \ - ((is_subg_phy) \ - ? IEEE802154_PHY_A_TURNAROUND_TIME_1MS(IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy)) \ - : IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT) + ((is_subg_phy) ? IEEE802154_PHY_A_TURNAROUND_TIME_1MS( \ + IEEE802154_PHY_SYMBOL_PERIOD_US(is_subg_phy)) \ + : IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT) /* PHY PIB attribute aCcaTime, in PHY symbols, all PHYs except for SUN O-QPSK, * see section 11.3, table 11-1. diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index 2bc392fd54e0..784619a7e2c6 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -394,15 +394,17 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, goto out; } - /* acquire the lock so that the next k_sem_take() blocks */ + /* Acquire the lock so that the next k_sem_take() blocks. */ k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); - /* TODO: current timeout is arbitrary, - * see section 8.4.3.1, table 8-94, macResponseWaitTime + /* Wait macResponseWaitTime PHY symbols for the association response, see + * ieee802154_handle_mac_command() and section 6.4.1. */ - k_sem_take(&ctx->scan_ctx_lock, K_SECONDS(1)); + k_sem_take(&ctx->scan_ctx_lock, K_USEC(ieee802154_get_response_wait_time_us(iface))); - /* release the lock */ + /* Release the scan lock in case an association response was not received + * within macResponseWaitTime and we got a timeout instead. + */ k_sem_give(&ctx->scan_ctx_lock); k_sem_take(&ctx->ctx_lock, K_FOREVER); diff --git a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c index aee4a1ddec93..2457eb503d6a 100644 --- a/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c +++ b/subsys/net/l2/ieee802154/ieee802154_radio_csma_ca.c @@ -28,14 +28,9 @@ BUILD_ASSERT(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE <= /* See section 6.2.5.1. */ static inline int unslotted_csma_ca_channel_access(struct net_if *iface) { + uint32_t turnaround_time = ieee802154_radio_get_a_turnaround_time(iface); + uint32_t symbol_period = ieee802154_radio_get_symbol_period_us(iface); uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE; - uint32_t symbol_period, turnaround_time; - bool is_subg_phy; - - is_subg_phy = ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ; - /* TODO: Move symbol period calculation to radio driver. */ - symbol_period = IEEE802154_PHY_SYMBOL_PERIOD(is_subg_phy); - turnaround_time = IEEE802154_PHY_A_TURNAROUND_TIME(is_subg_phy); for (uint8_t nb = 0U; nb <= CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; nb++) { int ret; diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index 87c6a28a996a..a0f8d6d90404 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -6,13 +6,20 @@ /** * @file - * @brief IEEE 802.15.4 Management + * @brief IEEE 802.15.4 internal MAC and PHY Utils + * + * All references to the standard in this file cite IEEE 802.15.4-2020. */ #ifndef __IEEE802154_UTILS_H__ #define __IEEE802154_UTILS_H__ #include +#include + +/** + * PHY utilities + */ static inline enum ieee802154_hw_caps ieee802154_radio_get_hw_capabilities(struct net_if *iface) { @@ -238,6 +245,60 @@ static inline void ieee802154_radio_remove_src_short_addr(struct net_if *iface, } } +/** + * @brief Calculates the PHY's symbol period in microseconds. + * + * @details The PHY's symbol period depends on the interface's current PHY which + * can be derived from the currently chosen channel page (phyCurrentPage). + * + * Examples: + * * SUN FSK: see section 19.1, table 19-1 + * * O-QPSK: see section 12.3.3 + * * HRP UWB: derived from the preamble symbol period (T_psym), see section + * 11.3, table 11-1 and section 15.2.5, table 15-4 + * + * @note Currently the symbol period can only be calculated for SUN FSK and O-QPSK. + * + * @param iface The interface for which the symbol period should be calculated. + * + * @returns The symbol period for the given interface in microseconds. + */ +static inline uint32_t ieee802154_radio_get_symbol_period_us(struct net_if *iface) +{ + /* TODO: Move symbol period calculation to radio driver. */ + + if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_SUB_GHZ) && + ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ) { + return IEEE802154_PHY_SYMBOL_PERIOD_US(true); + } + + return IEEE802154_PHY_SYMBOL_PERIOD_US(false); +} + +/** + * @brief Calculates the PHY's turnaround time (see section 11.3, table 11-1, + * aTurnaroundTime) in PHY symbols. + * + * @details The PHY's turnaround time is used to calculate - among other + * parameters - the TX-to-RX turnaround time (see section 10.2.2) and the + * RX-to-TX turnaround time (see section 10.2.3). + * + * @note Currently the turnaround time can only be calculated for SUN FSK and O-QPSK. + * + * @param iface The interface for which the turnaround time should be calculated. + * + * @returns The turnaround time for the given interface. + */ +static inline uint32_t ieee802154_radio_get_a_turnaround_time(struct net_if *iface) +{ + if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_SUB_GHZ) && + ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_SUB_GHZ) { + return IEEE802154_PHY_A_TURNAROUND_TIME(true); + } + + return IEEE802154_PHY_A_TURNAROUND_TIME(false); +} + static inline bool ieee802154_radio_verify_channel(struct net_if *iface, uint16_t channel) { if (channel == IEEE802154_NO_CHANNEL) { @@ -264,4 +325,81 @@ static inline bool ieee802154_radio_verify_channel(struct net_if *iface, uint16_ return true; } + +/** + * MAC utilities + * + * Note: While MAC utilities may refer to PHY utilities, + * the inverse is not true. + */ + +/** + * The number of PHY symbols forming a superframe slot when the superframe order + * is equal to zero, see sections 8.4.2, table 8-93, aBaseSlotDuration and 6.2.1. + */ +#define IEEE802154_MAC_A_BASE_SLOT_DURATION 60U + +/** + * The number of slots contained in any superframe, see section 8.4.2, + * table 8-93, aNumSuperframeSlots. + */ +#define IEEE802154_MAC_A_NUM_SUPERFRAME_SLOTS 16U + +/** + * The number of PHY symbols forming a superframe when the superframe order is + * equal to zero, see section 8.4.2, table 8-93, aBaseSuperframeDuration. + */ +#define IEEE802154_MAC_A_BASE_SUPERFRAME_DURATION \ + (IEEE802154_MAC_A_BASE_SLOT_DURATION * IEEE802154_MAC_A_NUM_SUPERFRAME_SLOTS) + +/** + * @brief Calculates the MAC's superframe duration (see section 8.4.2, + * table 8-93, aBaseSuperframeDuration) in microseconds. + * + * @details The number of symbols forming a superframe when the superframe order + * is equal to zero. + * + * @param iface The interface for which the base superframe duration should be + * calculated. + * + * @returns The base superframe duration for the given interface in microseconds. + */ +static inline uint32_t ieee802154_get_a_base_superframe_duration(struct net_if *iface) +{ + return IEEE802154_MAC_A_BASE_SUPERFRAME_DURATION * + ieee802154_radio_get_symbol_period_us(iface); +} + +/** + * Default macResponseWaitTime in multiples of aBaseSuperframeDuration as + * defined in section 8.4.3.1, table 8-94. + */ +#define IEEE802154_MAC_RESONSE_WAIT_TIME_DEFAULT 32U + +/** + * @brief Retrieves macResponseWaitTime, see section 8.4.3.1, table 8-94, + * converted to microseconds. + * + * @details The maximum time, in multiples of aBaseSuperframeDuration converted + * to microseconds, a device shall wait for a response command to be available + * following a request command. + * + * macResponseWaitTime is a network-topology-dependent parameter and may be set + * to match the specific requirements of the network that a device is operating + * on. + * + * @note Currently this parameter is read-only and uses the specified default of 32. + * + * @param iface The interface for which the response wait time should be calculated. + * + * @returns The response wait time for the given interface in microseconds. + */ +static inline uint32_t ieee802154_get_response_wait_time_us(struct net_if *iface) +{ + /* TODO: Make this parameter configurable. */ + return IEEE802154_MAC_RESONSE_WAIT_TIME_DEFAULT * + ieee802154_get_a_base_superframe_duration(iface); +} + + #endif /* __IEEE802154_UTILS_H__ */ From d7d5a53f369c762a2c9cf6ed36e0661e3dcf5a18 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 3 Jul 2023 19:30:35 +0200 Subject: [PATCH 1053/2042] net: l2: ieee802154: mgmt: improve input validation Input validation of some of the IEEE 802.15.4 net_mgmt commands was incomplete and/or inconsistent. This change introduces a consistent approach to input validation that is easier to follow. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 78 +++++++++++++--------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index 784619a7e2c6..b9c7e756fbae 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -95,20 +95,21 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { struct ieee802154_context *ctx = net_if_l2_data(iface); - struct ieee802154_req_params *scan = - (struct ieee802154_req_params *)data; + struct ieee802154_req_params *scan; struct net_pkt *pkt = NULL; uint8_t channel; int ret; + if (len != sizeof(struct ieee802154_req_params) || !data) { + return -EINVAL; + } + + scan = (struct ieee802154_req_params *)data; + NET_DBG("%s scan requested", mgmt_request == NET_REQUEST_IEEE802154_ACTIVE_SCAN ? "Active" : "Passive"); - if (scan == NULL) { - return -EINVAL; - } - k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); if (ctx->scan_ctx) { @@ -117,8 +118,9 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, } if (mgmt_request == NET_REQUEST_IEEE802154_ACTIVE_SCAN) { - struct ieee802154_frame_params params; + struct ieee802154_frame_params params = {0}; + params.dst.len = IEEE802154_SHORT_ADDR_LENGTH; params.dst.short_addr = IEEE802154_BROADCAST_ADDRESS; params.dst.pan_id = IEEE802154_BROADCAST_PAN_ID; @@ -346,13 +348,18 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { struct ieee802154_context *ctx = net_if_l2_data(iface); - struct ieee802154_req_params *req = - (struct ieee802154_req_params *)data; struct ieee802154_frame_params params; + struct ieee802154_req_params *req; struct ieee802154_command *cmd; struct net_pkt *pkt; int ret = 0; + if (len != sizeof(struct ieee802154_req_params) || !data) { + return -EINVAL; + } + + req = (struct ieee802154_req_params *)data; + params.dst.len = req->len; if (params.dst.len == IEEE802154_SHORT_ADDR_LENGTH) { params.dst.short_addr = req->short_addr; @@ -464,6 +471,9 @@ static int ieee802154_disassociate(uint32_t mgmt_request, struct net_if *iface, struct net_pkt *pkt; int ret = 0; + ARG_UNUSED(data); + ARG_UNUSED(len); + k_sem_take(&ctx->ctx_lock, K_FOREVER); if (!is_associated(ctx)) { @@ -552,11 +562,20 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, uint16_t value; int ret = 0; - if (mgmt_request != NET_REQUEST_IEEE802154_SET_EXT_ADDR && - (len != sizeof(uint16_t) || !data)) { + if (!data) { return -EINVAL; } + if (mgmt_request == NET_REQUEST_IEEE802154_SET_EXT_ADDR) { + if (len != IEEE802154_EXT_ADDR_LENGTH) { + return -EINVAL; + } + } else { + if (len != sizeof(uint16_t)) { + return -EINVAL; + } + } + value = *((uint16_t *) data); k_sem_take(&ctx->ctx_lock, K_FOREVER); @@ -585,11 +604,6 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, ieee802154_radio_filter_pan_id(iface, ctx->pan_id); } } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_EXT_ADDR) { - if (len != IEEE802154_EXT_ADDR_LENGTH) { - ret = -EINVAL; - goto out; - } - uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; sys_memcpy_swap(ext_addr_le, data, IEEE802154_EXT_ADDR_LENGTH); @@ -648,11 +662,20 @@ static int ieee802154_get_parameters(uint32_t mgmt_request, uint16_t *value; int ret = 0; - if (mgmt_request != NET_REQUEST_IEEE802154_GET_EXT_ADDR && - (len != sizeof(uint16_t) || !data)) { + if (!data) { return -EINVAL; } + if (mgmt_request == NET_REQUEST_IEEE802154_GET_EXT_ADDR) { + if (len != IEEE802154_EXT_ADDR_LENGTH) { + return -EINVAL; + } + } else { + if (len != sizeof(uint16_t)) { + return -EINVAL; + } + } + value = (uint16_t *)data; k_sem_take(&ctx->ctx_lock, K_FOREVER); @@ -662,11 +685,6 @@ static int ieee802154_get_parameters(uint32_t mgmt_request, } else if (mgmt_request == NET_REQUEST_IEEE802154_GET_PAN_ID) { *value = ctx->pan_id; } else if (mgmt_request == NET_REQUEST_IEEE802154_GET_EXT_ADDR) { - if (len != IEEE802154_EXT_ADDR_LENGTH) { - ret = -EINVAL; - goto out; - } - sys_memcpy_swap(data, ctx->ext_addr, IEEE802154_EXT_ADDR_LENGTH); } else if (mgmt_request == NET_REQUEST_IEEE802154_GET_SHORT_ADDR) { *value = ctx->short_addr; @@ -676,7 +694,6 @@ static int ieee802154_get_parameters(uint32_t mgmt_request, *s_value = ctx->tx_power; } -out: k_sem_give(&ctx->ctx_lock); return ret; } @@ -706,6 +723,12 @@ static int ieee802154_set_security_settings(uint32_t mgmt_request, struct ieee802154_security_params *params; int ret = 0; + if (len != sizeof(struct ieee802154_security_params) || !data) { + return -EINVAL; + } + + params = (struct ieee802154_security_params *)data; + k_sem_take(&ctx->ctx_lock, K_FOREVER); if (is_associated(ctx)) { @@ -713,15 +736,8 @@ static int ieee802154_set_security_settings(uint32_t mgmt_request, goto out; } - if (len != sizeof(struct ieee802154_security_params) || !data) { - ret = -EINVAL; - goto out; - } - ieee802154_security_teardown_session(&ctx->sec_ctx); - params = (struct ieee802154_security_params *)data; - if (ieee802154_security_setup_session(&ctx->sec_ctx, params->level, params->key_mode, params->key, params->key_len)) { From 389f6ac81a51bb4b47e670bcd5b45c7846bfa8eb Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 10:20:03 +0200 Subject: [PATCH 1054/2042] net: l2: ieee802154: endianness of PAN ID Fixes an endianness bug in PAN ID assignment. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 30db890b96d0..f80776e8e9ee 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -598,7 +598,7 @@ static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx, if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) { address_field = (struct ieee802154_address_field *)p_buf; - address_field->plain.pan_id = params->dst.pan_id; + address_field->plain.pan_id = sys_cpu_to_le16(params->dst.pan_id); p_buf += IEEE802154_PAN_ID_LENGTH; if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) { @@ -623,7 +623,7 @@ static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx, if (fs->fc.pan_id_comp) { src_addr = &address_field->comp.addr; } else { - address_field->plain.pan_id = params->pan_id; + address_field->plain.pan_id = sys_cpu_to_le16(params->pan_id); src_addr = &address_field->plain.addr; p_buf += IEEE802154_PAN_ID_LENGTH; } From 3d54e975a73ebe1305c590e6dc702821eeb98d24 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 10:21:18 +0200 Subject: [PATCH 1055/2042] net: l2: ieee802154: association address parsing Fixes an off-by-one bug in the parsing routine of the coordinator address when associating via shell command. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_shell.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_shell.c b/subsys/net/l2/ieee802154/ieee802154_shell.c index 9abba9193c2c..56dcf096f97f 100644 --- a/subsys/net/l2/ieee802154/ieee802154_shell.c +++ b/subsys/net/l2/ieee802154/ieee802154_shell.c @@ -22,7 +22,8 @@ LOG_MODULE_REGISTER(net_ieee802154_shell, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); #include "ieee802154_frame.h" -#define EXT_ADDR_STR_LEN sizeof("xx:xx:xx:xx:xx:xx:xx:xx") +#define EXT_ADDR_STR_SIZE sizeof("xx:xx:xx:xx:xx:xx:xx:xx") +#define EXT_ADDR_STR_LEN (EXT_ADDR_STR_SIZE - 1U) struct ieee802154_req_params params; static struct net_mgmt_event_callback scan_cb; @@ -76,7 +77,7 @@ static int cmd_ieee802154_associate(const struct shell *sh, size_t argc, char *argv[]) { struct net_if *iface = net_if_get_ieee802154(); - char ext_addr[EXT_ADDR_STR_LEN]; + char ext_addr[EXT_ADDR_STR_SIZE]; if (argc < 3) { shell_help(sh); @@ -89,8 +90,9 @@ static int cmd_ieee802154_associate(const struct shell *sh, return -ENOEXEC; } + params = (struct ieee802154_req_params){0}; params.pan_id = atoi(argv[1]); - strncpy(ext_addr, argv[2], EXT_ADDR_STR_LEN - 1); + strncpy(ext_addr, argv[2], sizeof(ext_addr)); if (strlen(ext_addr) == EXT_ADDR_STR_LEN) { parse_extended_address(ext_addr, params.addr); @@ -224,7 +226,7 @@ static int cmd_ieee802154_scan(const struct shell *sh, return -ENOEXEC; } - (void)memset(¶ms, 0, sizeof(struct ieee802154_req_params)); + params = (struct ieee802154_req_params){0}; net_mgmt_init_event_callback(&scan_cb, scan_result_cb, NET_EVENT_IEEE802154_SCAN_RESULT); @@ -467,16 +469,16 @@ static int cmd_ieee802154_get_ext_addr(const struct shell *sh, "Could not get extended address\n"); return -ENOEXEC; } else { - static char ext_addr[EXT_ADDR_STR_LEN]; + static char ext_addr[EXT_ADDR_STR_SIZE]; int i, pos = 0; for (i = 0; i < IEEE802154_EXT_ADDR_LENGTH; i++) { pos += snprintk(ext_addr + pos, - EXT_ADDR_STR_LEN - pos, + EXT_ADDR_STR_SIZE - pos, "%02X:", addr[i]); } - ext_addr[EXT_ADDR_STR_LEN - 1] = '\0'; + ext_addr[EXT_ADDR_STR_SIZE - 1] = '\0'; shell_fprintf(sh, SHELL_NORMAL, "Extended address: %s\n", ext_addr); From 27bfe68204a64d379075369072d9650a6d8f308d Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:09 +0200 Subject: [PATCH 1056/2042] net: l2: ieee802154: mgmt: improve association procedure spec compliance This change introduces test coverage for association request and response. Based on this coverage, several closely related issues were found in the association process which cannot be split into separate changes without breaking the build. Most notably did the associate and disassociate net_mgmt commands send already encoded IEEE 802.15.4 MPDUs to L3 rather than L2. L3 treated them as payload and made L2 wrap them with another LL header/footer which produced invalid packets. The tests also enforce better aligment of the association process with the IEEE 802.15.4-2020 standard: * Association requests now ask for ACK as required by the standard. The fake driver was enhanced to produce ACK packages when requested. * macPanId and macCoordinator* MAC PIB attributes are set in the right order for improved filtering of association responses. * The coordinator may decide not to assign a short address to the end device even when associated. This is now supported. * The coordinator may or may not use a short address. Coordinators choosing not to support short addresses are now supported. * Updating the association will now remove any previously added short address from the hardware filter. * The short address may no longer be changed by the user while associated to a PAN. Only the coordinator is allowed to allocate short addresses. * Validation of outgoing and incoming association request/response packets is improved. All changes are documented by pointers into the spec. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 1 + subsys/net/l2/ieee802154/ieee802154.c | 2 + subsys/net/l2/ieee802154/ieee802154_frame.c | 9 +- subsys/net/l2/ieee802154/ieee802154_frame.h | 2 +- subsys/net/l2/ieee802154/ieee802154_mgmt.c | 306 +++++++++++++----- subsys/net/l2/ieee802154/ieee802154_utils.h | 19 ++ .../l2/src/ieee802154_fake_driver.c | 32 +- .../ieee802154/l2/src/ieee802154_shell_test.c | 158 ++++++++- tests/net/ieee802154/l2/src/ieee802154_test.c | 123 +++++-- 9 files changed, 540 insertions(+), 112 deletions(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index 422c2ea64d51..c8c317b77a3f 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -50,6 +50,7 @@ extern "C" { /* See IEEE 802.15.4-2020, section 7.3.5 */ #define IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED IEEE802154_BROADCAST_ADDRESS +#define IEEE802154_PAN_ID_NOT_ASSOCIATED IEEE802154_BROADCAST_PAN_ID /* MAC PIB attribute aUnitBackoffPeriod, see section 8.4.2, table 8-93, in symbol periods, valid for * all PHYs except SUN PHY in the 920 MHz band. diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index a996cb4e5807..50e11fb479fb 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -636,7 +636,9 @@ void ieee802154_init(struct net_if *iface) ctx->flags |= NET_L2_PROMISC_MODE; } + ctx->pan_id = IEEE802154_PAN_ID_NOT_ASSOCIATED; ctx->short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + ctx->coord_short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; sys_memcpy_swap(ctx->ext_addr, eui64_be, IEEE802154_EXT_ADDR_LENGTH); /* We switch to a link address store that we diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index f80776e8e9ee..b20605936181 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -269,10 +269,10 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b struct ieee802154_command *command = (struct ieee802154_command *)buf; uint8_t len = IEEE802154_CMD_CFI_LENGTH; bool src_pan_brdcst_chk = false; + uint8_t src_bf = 0, dst_bf = 0; bool dst_brdcst_chk = false; bool ack_requested = false; bool has_pan_id = true; - uint8_t src_bf, dst_bf; if (length < len) { return false; @@ -295,13 +295,14 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION: if (command->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) { len += IEEE802154_CMD_DISASSOC_NOTE_LENGTH; + dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT); } __fallthrough; case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION: ack_requested = true; has_pan_id = false; src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); - dst_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); + dst_bf |= BIT(IEEE802154_ADDR_MODE_EXTENDED); break; case IEEE802154_CFI_DATA_REQUEST: @@ -574,7 +575,7 @@ static inline bool data_addr_to_fs_settings(struct net_linkaddr *dst, struct iee params->dst.len = IEEE802154_SHORT_ADDR_LENGTH; } else { __ASSERT_NO_MSG(dst->len == IEEE802154_EXT_ADDR_LENGTH); - params->dst.ext_addr = dst->addr; + memcpy(params->dst.ext_addr, dst->addr, sizeof(params->dst.ext_addr)); params->dst.len = IEEE802154_EXT_ADDR_LENGTH; } } @@ -765,11 +766,11 @@ static inline bool cfi_to_fs_settings(enum ieee802154_cfi cfi, struct ieee802154 { switch (cfi) { case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION: - fs->fc.ar = 1U; fs->fc.pan_id_comp = 1U; __fallthrough; case IEEE802154_CFI_ASSOCIATION_REQUEST: + fs->fc.ar = 1U; fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED; if (params->dst.len == IEEE802154_SHORT_ADDR_LENGTH) { diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.h b/subsys/net/l2/ieee802154/ieee802154_frame.h index be9c6b60a411..a68945a0eab5 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.h +++ b/subsys/net/l2/ieee802154/ieee802154_frame.h @@ -453,7 +453,7 @@ struct ieee802154_mpdu { struct ieee802154_frame_params { struct { union { - uint8_t *ext_addr; /* in big endian */ + uint8_t ext_addr[IEEE802154_EXT_ADDR_LENGTH]; /* in big endian */ uint16_t short_addr; /* in CPU byte order */ }; diff --git a/subsys/net/l2/ieee802154/ieee802154_mgmt.c b/subsys/net/l2/ieee802154/ieee802154_mgmt.c index b9c7e756fbae..e009018c8352 100644 --- a/subsys/net/l2/ieee802154/ieee802154_mgmt.c +++ b/subsys/net/l2/ieee802154/ieee802154_mgmt.c @@ -140,12 +140,14 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, ret = 0; + k_sem_take(&ctx->ctx_lock, K_FOREVER); + ieee802154_radio_remove_pan_id(iface, ctx->pan_id); + k_sem_give(&ctx->ctx_lock); ieee802154_radio_filter_pan_id(iface, IEEE802154_BROADCAST_PAN_ID); if (ieee802154_radio_start(iface)) { NET_DBG("Could not start device"); ret = -EIO; - goto out; } @@ -171,7 +173,6 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, NET_DBG("Could not send Beacon Request (%d)", ret); net_pkt_unref(pkt); - k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); goto out; } } @@ -192,10 +193,16 @@ static int ieee802154_scan(uint32_t mgmt_request, struct net_if *iface, out: /* Let's come back to context's settings. */ + ieee802154_radio_remove_pan_id(iface, IEEE802154_BROADCAST_PAN_ID); + k_sem_take(&ctx->ctx_lock, K_FOREVER); ieee802154_radio_filter_pan_id(iface, ctx->pan_id); ieee802154_radio_set_channel(iface, ctx->channel); + k_sem_give(&ctx->ctx_lock); - ctx->scan_ctx = NULL; + k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); + if (ctx->scan_ctx) { + ctx->scan_ctx = NULL; + } k_sem_give(&ctx->scan_ctx_lock); if (pkt) { @@ -232,37 +239,60 @@ static inline void set_linkaddr_to_ext_addr(struct net_if *iface, struct ieee802 update_net_if_link_addr(iface, ctx); } -/* Requires the context lock to be held. */ +/* Requires the context lock to be held and the PAN ID to be set. */ static inline void set_association(struct net_if *iface, struct ieee802154_context *ctx, uint16_t short_addr) { + uint16_t short_addr_be; + + __ASSERT_NO_MSG(ctx->pan_id != IEEE802154_PAN_ID_NOT_ASSOCIATED); __ASSERT_NO_MSG(short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED); - uint16_t short_addr_be; + ieee802154_radio_remove_src_short_addr(iface, ctx->short_addr); - ctx->linkaddr.len = IEEE802154_SHORT_ADDR_LENGTH; ctx->short_addr = short_addr; - short_addr_be = htons(short_addr); - memcpy(ctx->linkaddr.addr, &short_addr_be, IEEE802154_SHORT_ADDR_LENGTH); - update_net_if_link_addr(iface, ctx); - ieee802154_radio_filter_short_addr(iface, ctx->short_addr); + if (short_addr == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED) { + set_linkaddr_to_ext_addr(iface, ctx); + } else { + ctx->linkaddr.len = IEEE802154_SHORT_ADDR_LENGTH; + short_addr_be = htons(short_addr); + memcpy(ctx->linkaddr.addr, &short_addr_be, IEEE802154_SHORT_ADDR_LENGTH); + update_net_if_link_addr(iface, ctx); + ieee802154_radio_filter_short_addr(iface, ctx->short_addr); + } } /* Requires the context lock to be held. */ static inline void remove_association(struct net_if *iface, struct ieee802154_context *ctx) { + /* An associated device shall disassociate itself by removing all + * references to the PAN; the MLME shall set macPanId, macShortAddress, + * macAssociatedPanCoord [TODO: implement], macCoordShortAddress, and + * macCoordExtendedAddress to the default values, see section 6.4.2. + */ + + ieee802154_radio_remove_pan_id(iface, ctx->pan_id); + ieee802154_radio_remove_src_short_addr(iface, ctx->short_addr); + + ctx->pan_id = IEEE802154_PAN_ID_NOT_ASSOCIATED; ctx->short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; - memset(ctx->coord_ext_addr, 0, IEEE802154_EXT_ADDR_LENGTH); - ctx->coord_short_addr = 0U; + + memset(ctx->coord_ext_addr, 0, sizeof(ctx->coord_ext_addr)); + ctx->coord_short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + set_linkaddr_to_ext_addr(iface, ctx); - ieee802154_radio_filter_short_addr(iface, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED); + + ieee802154_radio_filter_pan_id(iface, IEEE802154_BROADCAST_PAN_ID); + ieee802154_radio_filter_short_addr(iface, IEEE802154_BROADCAST_ADDRESS); } /* Requires the context lock to be held. */ static inline bool is_associated(struct ieee802154_context *ctx) { - return ctx->short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + /* see section 8.4.3.1, table 8-94, macPanId and macShortAddress */ + return ctx->pan_id != IEEE802154_PAN_ID_NOT_ASSOCIATED && + ctx->short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; } enum net_verdict ieee802154_handle_mac_command(struct net_if *iface, @@ -276,23 +306,51 @@ enum net_verdict ieee802154_handle_mac_command(struct net_if *iface, return NET_DROP; } - /* validation of the association response, see section 7.3.3.1 */ - + /* Validation of the association response, see section 7.5.3: + * * The Destination Addressing Mode and Source Addressing Mode + * fields shall each be set to indicate extended addressing. + * * The Frame Pending field shall be set to zero and ignored + * upon reception, and the AR field shall be set to one. + * * The Destination PAN ID field shall contain the value of + * macPanId, while the Source PAN ID field shall be omitted. + * * The Destination Address field shall contain the extended + * address of the device requesting association (has been + * tested during generic filtering already). + * + * Note: Unless the packet is authenticated, it cannot be verified + * that the response comes from the requested coordinator. + */ if (mpdu->mhr.fs->fc.src_addr_mode != IEEE802154_ADDR_MODE_EXTENDED || mpdu->mhr.fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_EXTENDED || mpdu->mhr.fs->fc.ar != 1 || - mpdu->mhr.fs->fc.pan_id_comp != 1) { + mpdu->mhr.fs->fc.pan_id_comp != 1 || + mpdu->mhr.dst_addr->plain.pan_id != sys_cpu_to_le16(ctx->pan_id) || + mpdu->command->assoc_res.short_addr == IEEE802154_PAN_ID_NOT_ASSOCIATED) { return NET_DROP; } k_sem_take(&ctx->ctx_lock, K_FOREVER); + if (is_associated(ctx)) { + k_sem_give(&ctx->ctx_lock); + return NET_DROP; + } + + /* If the Association Status field of the Association Response + * command indicates that the association was successful, the + * device shall store the address contained in the Short Address + * field of the command in macShortAddress, see section 6.4.1. + */ set_association(iface, ctx, sys_le16_to_cpu(mpdu->command->assoc_res.short_addr)); - memcpy(ctx->coord_ext_addr, - mpdu->mhr.src_addr->comp.addr.ext_addr, + /* If the [association request] contained the short address of + * the coordinator, the extended address of the coordinator, + * contained in the MHR of the Association Response command, + * shall be stored in macCoordExtendedAddress, see section 6.4.1. + */ + memcpy(ctx->coord_ext_addr, mpdu->mhr.src_addr->comp.addr.ext_addr, IEEE802154_EXT_ADDR_LENGTH); k_sem_give(&ctx->ctx_lock); @@ -316,14 +374,35 @@ enum net_verdict ieee802154_handle_mac_command(struct net_if *iface, goto out; } - /* validation of the disassociation notification, see section 7.5.4 */ + /* Validation of the disassociation notification, see section 7.5.4: + * * The Source Addressing Mode field shall be set to indicate + * extended addressing. + * * The Frame Pending field shall be set to zero and ignored + * upon reception, and the AR field shall be set to one. + * * The Destination PAN ID field shall contain the value of macPanId. + * * The Source PAN ID field shall be omitted. + * * If the coordinator is disassociating a device from the + * PAN, then the Destination Address field shall contain the + * address of the device being removed from the PAN (asserted + * during generic package filtering). + * + * Note: Unless the packet is authenticated, it cannot be verified + * that the command comes from the requested coordinator. + */ if (mpdu->mhr.fs->fc.src_addr_mode != IEEE802154_ADDR_MODE_EXTENDED || - mpdu->mhr.fs->fc.pan_id_comp != 1) { + mpdu->mhr.fs->fc.ar != 1 || + mpdu->mhr.fs->fc.pan_id_comp != 1 || + mpdu->mhr.dst_addr->plain.pan_id != sys_cpu_to_le16(ctx->pan_id)) { goto out; } + /* If the source address contained in the Disassociation + * Notification command is equal to macCoordExtendedAddress, + * the device should consider itself disassociated, + * see section 6.4.2. + */ if (memcmp(ctx->coord_ext_addr, mpdu->mhr.src_addr->comp.addr.ext_addr, IEEE802154_EXT_ADDR_LENGTH)) { @@ -348,7 +427,7 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { struct ieee802154_context *ctx = net_if_l2_data(iface); - struct ieee802154_frame_params params; + struct ieee802154_frame_params params = {0}; struct ieee802154_req_params *req; struct ieee802154_command *cmd; struct net_pkt *pkt; @@ -360,15 +439,43 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, req = (struct ieee802154_req_params *)data; - params.dst.len = req->len; - if (params.dst.len == IEEE802154_SHORT_ADDR_LENGTH) { + /* Validate the coordinator's PAN ID. */ + if (req->pan_id == IEEE802154_PAN_ID_NOT_ASSOCIATED) { + return -EINVAL; + } + + params.dst.pan_id = req->pan_id; + + /* If the Version field is set to 0b10, the Source PAN ID field is + * omitted. Otherwise, the Source PAN ID field shall contain the + * broadcast PAN ID. + */ + params.pan_id = IEEE802154_BROADCAST_PAN_ID; + + /* Validate the coordinator's short address - if any. */ + if (req->len == IEEE802154_SHORT_ADDR_LENGTH) { + if (req->short_addr == IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED || + req->short_addr == IEEE802154_NO_SHORT_ADDRESS_ASSIGNED) { + return -EINVAL; + } + params.dst.short_addr = req->short_addr; + } else if (req->len == IEEE802154_EXT_ADDR_LENGTH) { + memcpy(params.dst.ext_addr, req->addr, sizeof(params.dst.ext_addr)); } else { - params.dst.ext_addr = req->addr; + return -EINVAL; } - params.dst.pan_id = req->pan_id; - params.pan_id = req->pan_id; + params.dst.len = req->len; + + k_sem_take(&ctx->ctx_lock, K_FOREVER); + + if (is_associated(ctx)) { + k_sem_give(&ctx->ctx_lock); + return -EALREADY; + } + + k_sem_give(&ctx->ctx_lock); pkt = ieee802154_create_mac_cmd_frame( iface, IEEE802154_CFI_ASSOCIATION_REQUEST, ¶ms); @@ -377,35 +484,75 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, goto out; } + k_sem_take(&ctx->ctx_lock, K_FOREVER); + cmd = ieee802154_get_mac_command(pkt); + cmd->assoc_req.ci.reserved_1 = 0U; /* Reserved */ cmd->assoc_req.ci.dev_type = 0U; /* RFD */ cmd->assoc_req.ci.power_src = 0U; /* TODO: set right power source */ - cmd->assoc_req.ci.rx_on = 1U; /* TODO: that will depends on PM */ + cmd->assoc_req.ci.rx_on = 1U; /* TODO: derive from PM settings */ cmd->assoc_req.ci.association_type = 0U; /* normal association */ cmd->assoc_req.ci.reserved_2 = 0U; /* Reserved */ - cmd->assoc_req.ci.sec_capability = 0U; /* TODO: security support */ - cmd->assoc_req.ci.alloc_addr = 0U; /* TODO: handle short addr */ - - k_sem_take(&ctx->ctx_lock, K_FOREVER); - remove_association(iface, ctx); - k_sem_give(&ctx->ctx_lock); +#ifdef CONFIG_NET_L2_IEEE802154_SECURITY + cmd->assoc_req.ci.sec_capability = ctx->sec_ctx.level > IEEE802154_SECURITY_LEVEL_NONE; +#else + cmd->assoc_req.ci.sec_capability = 0U; +#endif + /* request short address + * TODO: support operation with ext addr. + */ + cmd->assoc_req.ci.alloc_addr = 1U; ieee802154_mac_cmd_finalize(pkt, IEEE802154_CFI_ASSOCIATION_REQUEST); + /* section 6.4.1, Association: Set phyCurrentPage [TODO: implement] and + * phyCurrentChannel to the requested channel and channel page + * parameters. + */ + if (ieee802154_radio_set_channel(iface, req->channel)) { + ret = -EIO; + goto release; + } + + /* section 6.4.1, Association: Set macPanId to the coordinator's PAN ID. */ + ieee802154_radio_remove_pan_id(iface, ctx->pan_id); + ctx->pan_id = req->pan_id; ieee802154_radio_filter_pan_id(iface, req->pan_id); - if (net_if_send_data(iface, pkt)) { + /* section 6.4.1, Association: Set macCoordExtendedAddress or + * macCoordShortAddress, depending on which is known from the Beacon + * frame from the coordinator through which the device wishes to + * associate. + */ + if (req->len == IEEE802154_SHORT_ADDR_LENGTH) { + ctx->coord_short_addr = req->short_addr; + } else { + ctx->coord_short_addr = IEEE802154_NO_SHORT_ADDRESS_ASSIGNED; + sys_memcpy_swap(ctx->coord_ext_addr, req->addr, IEEE802154_EXT_ADDR_LENGTH); + } + + k_sem_give(&ctx->ctx_lock); + + /* Acquire the scan lock so that the next k_sem_take() blocks. */ + k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); + + /* section 6.4.1, Association: The MAC sublayer of an unassociated device + * shall initiate the association procedure by sending an Association + * Request command, as described in 7.5.2, to the coordinator of an + * existing PAN. + */ + if (ieee802154_radio_send(iface, pkt, pkt->buffer)) { net_pkt_unref(pkt); ret = -EIO; goto out; } - /* Acquire the lock so that the next k_sem_take() blocks. */ - k_sem_take(&ctx->scan_ctx_lock, K_FOREVER); - /* Wait macResponseWaitTime PHY symbols for the association response, see * ieee802154_handle_mac_command() and section 6.4.1. + * + * TODO: The Association Response command shall be sent to the device + * requesting association using indirect transmission. */ k_sem_take(&ctx->scan_ctx_lock, K_USEC(ieee802154_get_response_wait_time_us(iface))); @@ -423,38 +570,36 @@ static int ieee802154_associate(uint32_t mgmt_request, struct net_if *iface, ctx->coord_short_addr == req->short_addr) { validated = true; } else { - if (req->len == IEEE802154_EXT_ADDR_LENGTH) { - uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; - - sys_memcpy_swap(ext_addr_le, req->addr, - IEEE802154_EXT_ADDR_LENGTH); - if (!memcmp(ctx->coord_ext_addr, ext_addr_le, - IEEE802154_EXT_ADDR_LENGTH)) { - validated = true; - } + uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; + + __ASSERT_NO_MSG(req->len == IEEE802154_EXT_ADDR_LENGTH); + + sys_memcpy_swap(ext_addr_le, req->addr, sizeof(ext_addr_le)); + if (!memcmp(ctx->coord_ext_addr, ext_addr_le, IEEE802154_EXT_ADDR_LENGTH)) { + validated = true; } } if (!validated) { - remove_association(iface, ctx); ret = -EFAULT; - goto out; + goto release; } ctx->channel = req->channel; - ctx->pan_id = req->pan_id; - goto out; - } else { ret = -EACCES; } +release: + k_sem_give(&ctx->ctx_lock); out: - if (ret < 0) { - ieee802154_radio_filter_pan_id(iface, 0); + if (ret) { + k_sem_take(&ctx->ctx_lock, K_FOREVER); + remove_association(iface, ctx); + ieee802154_radio_set_channel(iface, ctx->channel); + k_sem_give(&ctx->ctx_lock); } - k_sem_give(&ctx->ctx_lock); return ret; } @@ -465,11 +610,9 @@ static int ieee802154_disassociate(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { struct ieee802154_context *ctx = net_if_l2_data(iface); - uint8_t ext_addr[IEEE802154_MAX_ADDR_LENGTH]; - struct ieee802154_frame_params params; + struct ieee802154_frame_params params = {0}; struct ieee802154_command *cmd; struct net_pkt *pkt; - int ret = 0; ARG_UNUSED(data); ARG_UNUSED(len); @@ -477,32 +620,40 @@ static int ieee802154_disassociate(uint32_t mgmt_request, struct net_if *iface, k_sem_take(&ctx->ctx_lock, K_FOREVER); if (!is_associated(ctx)) { - ret = -EALREADY; - goto out; + k_sem_give(&ctx->ctx_lock); + return -EALREADY; } - /* See section 7.5.4 */ - + /* See section 7.5.4: + * * The Destination PAN ID field shall contain the value of macPanId. + * * If an associated device is disassociating from the PAN, then the + * Destination Address field shall contain the value of either + * macCoordShortAddress, if the Destination Addressing Mode field is + * set to indicated short addressing, or macCoordExtendedAddress, if + * the Destination Addressing Mode field is set to indicated extended + * addressing. + */ params.dst.pan_id = ctx->pan_id; - if (ctx->coord_short_addr != 0 && + if (ctx->coord_short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED && ctx->coord_short_addr != IEEE802154_NO_SHORT_ADDRESS_ASSIGNED) { params.dst.len = IEEE802154_SHORT_ADDR_LENGTH; params.dst.short_addr = ctx->coord_short_addr; } else { params.dst.len = IEEE802154_EXT_ADDR_LENGTH; - params.dst.ext_addr = ext_addr; sys_memcpy_swap(params.dst.ext_addr, ctx->coord_ext_addr, - IEEE802154_EXT_ADDR_LENGTH); + sizeof(params.dst.ext_addr)); } - params.pan_id = ctx->pan_id; + k_sem_give(&ctx->ctx_lock); + /* If an associated device wants to leave the PAN, the MLME of the device + * shall send a Disassociation Notification command to its coordinator. + */ pkt = ieee802154_create_mac_cmd_frame( iface, IEEE802154_CFI_DISASSOCIATION_NOTIFICATION, ¶ms); if (!pkt) { - ret = -ENOBUFS; - goto out; + return -ENOBUFS; } cmd = ieee802154_get_mac_command(pkt); @@ -511,17 +662,16 @@ static int ieee802154_disassociate(uint32_t mgmt_request, struct net_if *iface, ieee802154_mac_cmd_finalize( pkt, IEEE802154_CFI_DISASSOCIATION_NOTIFICATION); - if (net_if_send_data(iface, pkt)) { + if (ieee802154_radio_send(iface, pkt, pkt->buffer)) { net_pkt_unref(pkt); - ret = -EIO; - goto out; + return -EIO; } + k_sem_take(&ctx->ctx_lock, K_FOREVER); remove_association(iface, ctx); - -out: k_sem_give(&ctx->ctx_lock); - return ret; + + return 0; } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_IEEE802154_DISASSOCIATE, @@ -600,6 +750,7 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, } } else if (mgmt_request == NET_REQUEST_IEEE802154_SET_PAN_ID) { if (ctx->pan_id != value) { + ieee802154_radio_remove_pan_id(iface, ctx->pan_id); ctx->pan_id = value; ieee802154_radio_filter_pan_id(iface, ctx->pan_id); } @@ -622,6 +773,13 @@ static int ieee802154_set_parameters(uint32_t mgmt_request, if (value == IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED) { remove_association(iface, ctx); } else { + /* A PAN is required when associating, + * see section 8.4.3.1, table 8-94. + */ + if (ctx->pan_id == IEEE802154_PAN_ID_NOT_ASSOCIATED) { + ret = -EPERM; + goto out; + } set_association(iface, ctx, value); } } diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index a0f8d6d90404..66ca74e71dc3 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -245,6 +245,25 @@ static inline void ieee802154_radio_remove_src_short_addr(struct net_if *iface, } } +static inline void ieee802154_radio_remove_pan_id(struct net_if *iface, uint16_t pan_id) +{ + const struct ieee802154_radio_api *radio = + net_if_get_device(iface)->api; + + if (radio && (radio->get_capabilities(net_if_get_device(iface)) & + IEEE802154_HW_FILTER)) { + struct ieee802154_filter filter; + + filter.pan_id = pan_id; + + if (radio->filter(net_if_get_device(iface), false, + IEEE802154_FILTER_TYPE_PAN_ID, + &filter) != 0) { + NET_WARN("Could not remove PAN ID filter"); + } + } +} + /** * @brief Calculates the PHY's symbol period in microseconds. * diff --git a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c index 3f6207544a6c..27dd161ad019 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c +++ b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c @@ -10,13 +10,15 @@ LOG_MODULE_REGISTER(net_ieee802154_fake_driver, LOG_LEVEL_DBG); #include #include -#include "net_private.h" - +#include #include /** FAKE ieee802.15.4 driver **/ #include +#include "net_private.h" +#include + struct net_pkt *current_pkt; K_SEM_DEFINE(driver_lock, 0, UINT_MAX); @@ -73,6 +75,29 @@ static int fake_tx(const struct device *dev, insert_frag(pkt, frag); + if (ieee802154_is_ar_flag_set(frag)) { + struct net_if *iface = net_if_lookup_by_dev(dev); + struct ieee802154_context *ctx = net_if_l2_data(iface); + + struct net_pkt *ack_pkt; + + ack_pkt = net_pkt_rx_alloc_with_buffer(iface, IEEE802154_ACK_PKT_LENGTH, AF_UNSPEC, + 0, K_FOREVER); + if (!ack_pkt) { + NET_ERR("*** Could not allocate ack pkt.\n"); + return -ENOMEM; + } + + if (!ieee802154_create_ack_frame(iface, ack_pkt, ctx->ack_seq)) { + NET_ERR("*** Could not create ack frame.\n"); + net_pkt_unref(ack_pkt); + return -EFAULT; + } + + ieee802154_handle_ack(iface, ack_pkt); + net_pkt_unref(ack_pkt); + } + k_sem_give(&driver_lock); return 0; @@ -102,7 +127,8 @@ static void fake_iface_init(struct net_if *iface) ieee802154_init(iface); - ctx->pan_id = 0xabcd; + ctx->pan_id = IEEE802154_PAN_ID_NOT_ASSOCIATED; + ctx->short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; ctx->channel = 26U; ctx->sequence = 62U; diff --git a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c index 35aeb757f83b..359f17d75c72 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(net_ieee802154_mgmt_test, LOG_LEVEL_DBG); #include #include +#include #include #include #include @@ -29,10 +30,16 @@ static struct net_mgmt_event_callback scan_cb; K_SEM_DEFINE(scan_lock, 0, 1); #define EXPECTED_COORDINATOR_LQI 15U + #define EXPECTED_COORDINATOR_PAN_LE 0xcd, 0xab #define EXPECTED_COORDINATOR_PAN_CPU_ORDER 0xabcd -#define EXPECTED_COORDINATOR_ADDR_LE 0xc2, 0xa3, 0x9e, 0x00, 0x00, 0x4b, 0x12, 0x00 -#define EXPECTED_COORDINATOR_ADDR_BE 0x00, 0x12, 0x4b, 0x00, 0x00, 0x9e, 0xa3, 0xc2 +#define EXPECTED_COORDINATOR_PAN_STR "43981" + +#define EXPECTED_COORDINATOR_ADDR_LE 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +#define EXPECTED_COORDINATOR_ADDR_BE 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08 +#define EXPECTED_COORDINATOR_ADDR_STR "0f:0e:0d:0c:0b:0a:09:08" + +#define EXPECTED_ENDDEVICE_SHORT_ADDR 0xaaaa static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) @@ -55,7 +62,7 @@ static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_eve k_sem_give(&scan_lock); } -void test_beacon_request(struct ieee802154_mpdu *mpdu) +static void test_beacon_request(struct ieee802154_mpdu *mpdu) { struct ieee802154_command *cmd = mpdu->command; @@ -69,15 +76,37 @@ void test_beacon_request(struct ieee802154_mpdu *mpdu) "Beacon request: destination PAN should be broadcast PAN."); } -void test_scan_shell_cmd(void) +static void test_association_request(struct ieee802154_mpdu *mpdu) +{ + struct ieee802154_command *cmd = mpdu->command; + + zassert_equal( + mpdu->mhr.fs->fc.frame_version, IEEE802154_VERSION_802154_2006, + "Association Request: currently only IEEE 802.15.4 2006 frame version supported."); + zassert_equal(mpdu->mhr.fs->fc.frame_type, IEEE802154_FRAME_TYPE_MAC_COMMAND, + "Association Request: should be a MAC command."); + zassert_equal(mpdu->mhr.fs->fc.ar, true, "Association Request: must request ACK."); + zassert_equal(mpdu->payload_length, 1U + IEEE802154_CMD_ASSOC_REQ_LENGTH); + + zassert_equal(cmd->cfi, IEEE802154_CFI_ASSOCIATION_REQUEST, + "Association Request: unexpected CFI."); + zassert_equal(cmd->assoc_req.ci.alloc_addr, true, + "Association Request: should allocate short address."); + zassert_equal(cmd->assoc_req.ci.association_type, false, + "Association Request: fast association is not supported."); +} + +static void test_scan_shell_cmd(void) { struct ieee802154_mpdu mpdu = {0}; int ret; + /* The beacon placed into the RX queue will be received and handled as + * soon as this command yields waiting for beacons. + */ ret = shell_execute_cmd(NULL, "ieee802154 scan active 11 500"); zassert_equal(0, ret, "Active scan failed: %d", ret); - /* Expect the beacon to have been received and handled already by the scan command. */ zassert_equal(0, k_sem_take(&scan_lock, K_NO_WAIT), "Active scan: did not receive beacon."); zassert_not_null(current_pkt); @@ -96,6 +125,49 @@ void test_scan_shell_cmd(void) current_pkt->frags = NULL; } +static void test_associate_shell_cmd(struct ieee802154_context *ctx) +{ + uint8_t expected_coord_addr_le[] = {EXPECTED_COORDINATOR_ADDR_LE}; + struct ieee802154_mpdu mpdu = {0}; + struct net_buf *assoc_req; + int ret; + + /* The association response placed into the RX queue will be received and + * handled as soon as this command yields waiting for a response. + */ + ret = shell_execute_cmd(NULL, "ieee802154 associate " EXPECTED_COORDINATOR_PAN_STR + " " EXPECTED_COORDINATOR_ADDR_STR); + zassert_equal(0, ret, "Association failed: %d", ret); + + /* Test that we were associated. */ + zassert_equal(ctx->pan_id, EXPECTED_COORDINATOR_PAN_CPU_ORDER, + "Association: did not get associated to the expected PAN."); + zassert_equal(ctx->short_addr, EXPECTED_ENDDEVICE_SHORT_ADDR, + "Association: did not get the expected short address asigned."); + zassert_equal(ctx->coord_short_addr, IEEE802154_NO_SHORT_ADDRESS_ASSIGNED, + "Association: co-ordinator should not use short address."); + zassert_mem_equal( + ctx->coord_ext_addr, expected_coord_addr_le, sizeof(ctx->coord_ext_addr), + "Association: did not get associated co-ordinator by the expected coordinator."); + + /* Test the association request that should have been sent out. */ + zassert_not_null(current_pkt); + assoc_req = current_pkt->frags; + zassert_not_null(assoc_req); + + if (!ieee802154_validate_frame(assoc_req->data, assoc_req->len, &mpdu)) { + NET_ERR("*** Could not parse association request.\n"); + ztest_test_fail(); + goto release_frag; + } + + test_association_request(&mpdu); + +release_frag: + net_pkt_frag_unref(current_pkt->frags); + current_pkt->frags = NULL; +} + ZTEST(ieee802154_l2_shell, test_active_scan) { uint8_t beacon_pkt[] = { @@ -113,18 +185,17 @@ ZTEST(ieee802154_l2_shell, test_active_scan) pkt = net_pkt_rx_alloc_with_buffer(iface, sizeof(beacon_pkt), AF_UNSPEC, 0, K_FOREVER); if (!pkt) { NET_ERR("*** No buffer to allocate\n"); - ztest_test_fail(); - return; + goto fail; } net_pkt_set_ieee802154_lqi(pkt, EXPECTED_COORDINATOR_LQI); net_buf_add_mem(pkt->buffer, beacon_pkt, sizeof(beacon_pkt)); + /* The packet will be placed in the RX queue but not yet handled. */ if (net_recv_data(iface, pkt) < 0) { NET_ERR("Recv data failed"); net_pkt_unref(pkt); - ztest_test_fail(); - return; + goto fail; } net_mgmt_init_event_callback(&scan_cb, scan_result_cb, NET_EVENT_IEEE802154_SCAN_RESULT); @@ -133,6 +204,72 @@ ZTEST(ieee802154_l2_shell, test_active_scan) test_scan_shell_cmd(); net_mgmt_del_event_callback(&scan_cb); + return; + +fail: + ztest_test_fail(); +} + +ZTEST(ieee802154_l2_shell, test_associate) +{ + uint8_t coord_addr_le[] = {EXPECTED_COORDINATOR_ADDR_LE}; + struct ieee802154_context *ctx = net_if_l2_data(iface); + struct ieee802154_frame_params params = { + .dst = { + .len = IEEE802154_EXT_ADDR_LENGTH, + .pan_id = EXPECTED_COORDINATOR_PAN_CPU_ORDER, + }}; + struct ieee802154_command *cmd; + struct net_pkt *pkt; + + sys_memcpy_swap(params.dst.ext_addr, ctx->ext_addr, sizeof(params.dst.ext_addr)); + + /* Simulate a packet from the coordinator. */ + memcpy(ctx->ext_addr, coord_addr_le, sizeof(ctx->ext_addr)); + + pkt = ieee802154_create_mac_cmd_frame(iface, IEEE802154_CFI_ASSOCIATION_RESPONSE, ¶ms); + if (!pkt) { + NET_ERR("*** Could not create association response\n"); + goto fail; + } + + cmd = ieee802154_get_mac_command(pkt); + cmd->assoc_res.short_addr = sys_cpu_to_le16(EXPECTED_ENDDEVICE_SHORT_ADDR); + cmd->assoc_res.status = IEEE802154_ASF_SUCCESSFUL; + ieee802154_mac_cmd_finalize(pkt, IEEE802154_CFI_ASSOCIATION_RESPONSE); + + /* The packet will be placed in the RX queue but not yet handled. */ + if (net_recv_data(iface, pkt) < 0) { + NET_ERR("Recv assoc resp pkt failed"); + net_pkt_unref(pkt); + goto fail; + } + + /* Restore the end device's extended address. */ + sys_memcpy_swap(ctx->ext_addr, params.dst.ext_addr, sizeof(ctx->ext_addr)); + + test_associate_shell_cmd(ctx); + return; + +fail: + sys_memcpy_swap(ctx->ext_addr, params.dst.ext_addr, sizeof(ctx->ext_addr)); + ztest_test_fail(); +} + +static void reset_fake_driver(void *test_fixture) +{ + struct ieee802154_context *ctx; + + ARG_UNUSED(test_fixture); + + __ASSERT_NO_MSG(iface); + + /* Set initial conditions. */ + ctx = net_if_l2_data(iface); + ctx->pan_id = IEEE802154_PAN_ID_NOT_ASSOCIATED; + ctx->short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + ctx->coord_short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + memset(ctx->coord_ext_addr, 0, sizeof(ctx->coord_ext_addr)); } static void *test_setup(void) @@ -171,4 +308,5 @@ static void test_teardown(void *test_fixture) current_pkt = NULL; } -ZTEST_SUITE(ieee802154_l2_shell, NULL, test_setup, NULL, NULL, test_teardown); +ZTEST_SUITE(ieee802154_l2_shell, NULL, test_setup, reset_fake_driver, reset_fake_driver, + test_teardown); diff --git a/tests/net/ieee802154/l2/src/ieee802154_test.c b/tests/net/ieee802154/l2/src/ieee802154_test.c index c5df0e1c35f4..71cd07959dc7 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_test.c @@ -162,6 +162,8 @@ uint8_t raw_payload[] = { #define RAW_MAC_PAYLOAD_START_INDEX 17 #define RAW_MAC_PAYLOAD_LENGTH 3 +#define MOCK_PAN_ID 0xabcd + extern struct net_pkt *current_pkt; extern struct k_sem driver_lock; @@ -201,36 +203,90 @@ static void ieee_addr_hexdump(uint8_t *addr, uint8_t length) printk("%02x\n", *addr); } +static int disassociate(struct net_if *iface, struct ieee802154_context *ctx) +{ + uint16_t short_addr_not_associated = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; + int ret; + + if (ctx->short_addr == IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED) { + return 0; + } + + ret = net_mgmt(NET_REQUEST_IEEE802154_SET_SHORT_ADDR, iface, &short_addr_not_associated, + sizeof(short_addr_not_associated)); + if (ret) { + NET_ERR("*** Failed to %s.\n", __func__); + return ret; + } + + return 0; +} + +static int associate(struct net_if *iface, struct ieee802154_context *ctx, uint16_t short_addr) +{ + uint16_t mock_pan_id = MOCK_PAN_ID; + int ret; + + if (ctx->short_addr == short_addr) { + return -EALREADY; + } + + ret = net_mgmt(NET_REQUEST_IEEE802154_SET_PAN_ID, iface, &mock_pan_id, + sizeof(mock_pan_id)); + if (ret) { + NET_ERR("*** Failed to set PAN ID in %s.\n", __func__); + return ret; + } + + ret = net_mgmt(NET_REQUEST_IEEE802154_SET_SHORT_ADDR, iface, &short_addr, + sizeof(short_addr)); + if (ret) { + NET_ERR("*** Failed to set short addr in %s.\n", __func__); + return ret; + } + + return 0; +} + static int set_up_short_addr(struct net_if *iface, struct ieee802154_context *ctx) { - uint16_t short_addr = 0x5678; + const uint16_t mock_short_addr = 0x5678; + int ret; + + ret = disassociate(iface, ctx); + if (ret) { + return ret; + } - int ret = net_mgmt(NET_REQUEST_IEEE802154_SET_SHORT_ADDR, iface, &short_addr, - sizeof(short_addr)); + ret = associate(iface, ctx, mock_short_addr); if (ret) { - NET_ERR("*** Failed to set short address\n"); + return ret; } - return ret; + return 0; } static int tear_down_short_addr(struct net_if *iface, struct ieee802154_context *ctx) { - uint16_t short_addr; + uint16_t no_short_addr_assigned = IEEE802154_NO_SHORT_ADDRESS_ASSIGNED; + int ret; if (ctx->linkaddr.len != IEEE802154_SHORT_ADDR_LENGTH) { /* nothing to do */ return 0; } - short_addr = IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED; - int ret = net_mgmt(NET_REQUEST_IEEE802154_SET_SHORT_ADDR, iface, &short_addr, - sizeof(short_addr)); + ret = disassociate(iface, ctx); if (ret) { - NET_ERR("*** Failed to unset short address\n"); + return ret; } - return ret; + ret = associate(iface, ctx, no_short_addr_assigned); + if (ret) { + return ret; + } + + return 0; } static struct net_pkt *get_data_pkt_with_ar(void) @@ -275,12 +331,18 @@ static struct net_pkt *get_data_pkt_with_ar(void) #ifdef CONFIG_NET_SOCKETS static bool set_up_security(uint8_t security_level) { + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint16_t saved_short_addr = ctx->short_addr; struct ieee802154_security_params params; if (security_level == IEEE802154_SECURITY_LEVEL_NONE) { return true; } + if (disassociate(iface, ctx) != 0) { + return false; + } + params = (struct ieee802154_security_params){ .key = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf}, @@ -295,19 +357,38 @@ static bool set_up_security(uint8_t security_level) return false; } + if (saved_short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED && + associate(iface, ctx, saved_short_addr) != 0) { + return false; + } + return true; } -static void tear_down_security(void) +static bool tear_down_security(void) { + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint16_t saved_short_addr = ctx->short_addr; struct ieee802154_security_params params = { .level = IEEE802154_SECURITY_LEVEL_NONE, }; + if (disassociate(iface, ctx) != 0) { + return false; + } + if (net_mgmt(NET_REQUEST_IEEE802154_SET_SECURITY_SETTINGS, iface, ¶ms, sizeof(struct ieee802154_security_params))) { NET_ERR("*** Failed to tear down security settings\n"); + return false; + } + + if (saved_short_addr != IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED && + associate(iface, ctx, saved_short_addr) != 0) { + return false; } + + return true; } static int set_up_recv_socket(enum net_sock_type socket_type) @@ -394,10 +475,8 @@ static bool test_ns_sending(struct ieee802154_pkt_test *t, bool with_short_addr) /* ensure reproducible results */ ctx->sequence = t->sequence; - if (with_short_addr) { - if (set_up_short_addr(iface, ctx)) { - goto out; - } + if (with_short_addr && set_up_short_addr(iface, ctx)) { + goto out; } if (net_ipv6_send_ns(iface, NULL, &t->src, &t->dst, &t->dst, false)) { @@ -633,10 +712,8 @@ static bool test_dgram_packet_sending(void *dst_sll, uint8_t dst_sll_halen, uint bool bind_short_address = pkt_dst_sll.sll_halen == IEEE802154_SHORT_ADDR_LENGTH && security_level == IEEE802154_SECURITY_LEVEL_NONE; - if (bind_short_address) { - if (set_up_short_addr(iface, ctx)) { - goto release_fd; - } + if (bind_short_address && set_up_short_addr(iface, ctx)) { + goto release_fd; } if (bind(fd, (const struct sockaddr *)&socket_sll, sizeof(struct sockaddr_ll))) { @@ -1133,6 +1210,7 @@ static bool test_recv_and_send_ack_reply(struct ieee802154_pkt_test *t) static bool initialize_test_environment(void) { + uint16_t mock_pan_id = MOCK_PAN_ID; const struct device *dev; k_sem_reset(&driver_lock); @@ -1155,6 +1233,11 @@ static bool initialize_test_environment(void) goto release_pkt; } + if (net_mgmt(NET_REQUEST_IEEE802154_SET_PAN_ID, iface, &mock_pan_id, sizeof(mock_pan_id))) { + NET_ERR("*** Failed to set PAN ID in %s.\n", __func__); + goto release_pkt; + } + NET_INFO("Fake IEEE 802.15.4 network interface ready\n"); ieee_addr_hexdump(net_if_get_link_addr(iface)->addr, 8); From 46d4ee326da235592934240d75440a80c06162a9 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 18:22:28 +0200 Subject: [PATCH 1057/2042] net: l2: ieee802154: improve context doc Improves the documentation of `struct ieee802154_context` members. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 82 ++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index c8c317b77a3f..93766f212b19 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -71,17 +71,53 @@ struct ieee802154_security_ctx { uint8_t _unused : 3; }; -/* This not meant to be used by any code but 802.15.4 L2 stack */ +/* This not meant to be used by any code but the IEEE 802.15.4 L2 stack */ struct ieee802154_context { - uint16_t pan_id; /* in CPU byte order */ - uint16_t channel; /* in CPU byte order */ - /* short address: - * 0 == not associated, - * 0xfffe == associated but no short address assigned - * see section 7.4.2 + /* PAN ID + * + * The identifier of the PAN on which the device is operating. If this + * value is 0xffff, the device is not associated. See section 8.4.3.1, + * table 8-94, macPanId. + * + * in CPU byte order */ - uint16_t short_addr; /* in CPU byte order */ - uint8_t ext_addr[IEEE802154_MAX_ADDR_LENGTH]; /* in little endian */ + uint16_t pan_id; + + /* Channel Number + * + * The RF channel to use for all transmissions and receptions, see + * section 11.3, table 11-2, phyCurrentChannel. The allowable range + * of values is PHY dependent as defined in section 10.1.3. + * + * in CPU byte order + */ + uint16_t channel; + + /* Short Address + * + * Range: + * * 0x0000–0xfffd: associated, short address was assigned + * * 0xfffe: associated but no short address assigned + * * 0xffff: not associated (default), + * + * See section 6.4.1, table 6-4 (Usage of the shart address) and + * section 8.4.3.1, table 8-94, macShortAddress. + * + * in CPU byte order + */ + uint16_t short_addr; + + /* Extended Address + * + * The extended address is device specific, usually permanently stored + * on the device and immutable. + * + * See section 8.4.3.1, table 8-94, macExtendedAddress. + * + * in little endian + */ + uint8_t ext_addr[IEEE802154_MAX_ADDR_LENGTH]; + struct net_linkaddr_storage linkaddr; /* in big endian */ #ifdef CONFIG_NET_L2_IEEE802154_SECURITY struct ieee802154_security_ctx sec_ctx; @@ -90,13 +126,35 @@ struct ieee802154_context { struct ieee802154_req_params *scan_ctx; /* guarded by scan_ctx_lock */ struct k_sem scan_ctx_lock; - uint8_t coord_ext_addr[IEEE802154_MAX_ADDR_LENGTH]; /* in little endian */ - uint16_t coord_short_addr; /* in CPU byte order */ + /* see section 8.4.3.1, table 8-94, macCoordExtendedAddress, the address + * of the coordinator through which the device is associated. + * + * A value of zero indicates that a coordinator extended address is + * unknown (default). + * + * in little endian + */ + uint8_t coord_ext_addr[IEEE802154_MAX_ADDR_LENGTH]; + + /* see section 8.4.3.1, table 8-94, macCoordShortAddress, the short + * address assigned to the coordinator through which the device is + * associated. + * + * A value of 0xfffe indicates that the coordinator is only using its + * extended address. A value of 0xffff indicates that this value is + * unknown. + * + * in CPU byte order + */ + uint16_t coord_short_addr; #endif int16_t tx_power; enum net_l2_flags flags; - uint8_t sequence; /* see section 8.4.3.1, table 8-94, macDsn */ + /* The sequence number added to the transmitted Data frame or MAC + * command, see section 8.4.3.1, table 8-94, macDsn. + */ + uint8_t sequence; uint8_t _unused : 6; From 4b6668047770a594e50e592c04b72420ffd920ce Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 6 Jul 2023 18:24:29 +0200 Subject: [PATCH 1058/2042] net: l2: ieee802154: simplify/fix ACK procedure Removes redundant ACK state from `struct ieee802154_context` and simplifies the ACK procedure. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 3 +-- subsys/net/l2/ieee802154/ieee802154.c | 24 ++++++++++++--------- subsys/net/l2/ieee802154/ieee802154_frame.c | 4 ++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index 93766f212b19..e69179863e1e 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -156,9 +156,8 @@ struct ieee802154_context { */ uint8_t sequence; - uint8_t _unused : 6; + uint8_t _unused : 7; - uint8_t ack_received : 1; /* guarded by ack_lock */ uint8_t ack_requested : 1; /* guarded by ack_lock */ uint8_t ack_seq; /* guarded by ack_lock */ struct k_sem ack_lock; diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 50e11fb479fb..543c4a4d43bc 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -110,8 +110,9 @@ inline bool ieee802154_prepare_for_ack(struct net_if *iface, struct net_pkt *pkt struct ieee802154_context *ctx = net_if_l2_data(iface); ctx->ack_seq = fs->sequence; - ctx->ack_received = false; - k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); + if (k_sem_count_get(&ctx->ack_lock) == 1U) { + k_sem_take(&ctx->ack_lock, K_NO_WAIT); + } return true; } @@ -139,7 +140,6 @@ enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt return NET_CONTINUE; } - ctx->ack_received = true; k_sem_give(&ctx->ack_lock); /* TODO: Release packet in L2 as we're taking ownership. */ @@ -152,6 +152,7 @@ enum net_verdict ieee802154_handle_ack(struct net_if *iface, struct net_pkt *pkt inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) { struct ieee802154_context *ctx = net_if_l2_data(iface); + int ret; if (!ack_required || (ieee802154_radio_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) { @@ -159,16 +160,18 @@ inline int ieee802154_wait_for_ack(struct net_if *iface, bool ack_required) return 0; } - if (k_sem_take(&ctx->ack_lock, K_MSEC(10)) == 0) { - /* We reinit the semaphore in case ieee802154_handle_ack() - * got called multiple times. - */ - k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT); + ret = k_sem_take(&ctx->ack_lock, K_MSEC(10)); + if (ret == 0) { + /* no-op */ + } else if (ret == -EAGAIN) { + ret = -ETIME; + } else { + NET_ERR("Error while waiting for ACK."); + ret = -EFAULT; } ctx->ack_seq = 0U; - - return ctx->ack_received ? 0 : -ETIME; + return ret; } int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_buf *frag) @@ -619,6 +622,7 @@ void ieee802154_init(struct net_if *iface) NET_DBG("Initializing IEEE 802.15.4 stack on iface %p", iface); k_sem_init(&ctx->ctx_lock, 1, 1); + k_sem_init(&ctx->ack_lock, 0, 1); /* no need to lock the context here as it has * not been published yet. diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index b20605936181..16d1f1f3d0c2 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -914,8 +914,8 @@ bool ieee802154_create_ack_frame(struct net_if *iface, struct net_pkt *pkt, uint fs = generate_fcf_grounds(&p_buf, false); - fs->fc.dst_addr_mode = 0U; - fs->fc.src_addr_mode = 0U; + fs->fc.dst_addr_mode = IEEE802154_ADDR_MODE_NONE; + fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_NONE; fs->fc.frame_type = IEEE802154_FRAME_TYPE_ACK; fs->sequence = seq; From e1f36c40ebd9dffe1118c34a1d3f300b733f25ba Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 23 Jun 2023 19:14:40 +0000 Subject: [PATCH 1059/2042] west: sign.py: de-duplicate the bootloader condition De-duplicate the `if target in ('imx8', 'imx8m'):` copy/paste/diverge before someone updates one and not the other. Also better to define bootloader always. Zero functional change. Signed-off-by: Marc Herbert --- scripts/west_commands/sign.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index e57b8800b4e2..a61f78adef03 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -430,7 +430,9 @@ def sign(self, command, build_dir, build_conf, formats): if not target: log.die('rimage target not defined') + # TODO: make this a new sign.py --bootloader option. if target in ('imx8', 'imx8m'): + bootloader = None kernel = str(b / 'zephyr' / 'zephyr.elf') out_bin = str(b / 'zephyr' / 'zephyr.ri') out_xman = str(b / 'zephyr' / 'zephyr.ri.xman') @@ -516,7 +518,7 @@ def sign(self, command, build_dir, build_conf, formats): if not args.quiet and args.verbose: sign_base += ['-v'] * args.verbose - components = [ ] if (target in ('imx8', 'imx8m')) else [ bootloader ] + components = [ ] if bootloader is None else [ bootloader ] components += [ kernel ] sign_config_extra_args = config_get_words(command.config, 'rimage.extra-args', []) From dc49a314fd10e8ce289e316c4a98ca7e897ec9a3 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 7 Jul 2023 02:24:21 +0300 Subject: [PATCH 1060/2042] west: sign.py: fix sign when CONFIG_KERNEL_BIN_NAME is used This fixes the following build error: ``` zephyr/zephyr.elf', needed by 'zephyr/zephyr.ri', missing and no known rule to make it ``` This appears when CONFIG_KERNEL_BIN_NAME is used. Therefore, do not use zephyr.elf since some samples might be called based on CONFIG_KERNEL_BIN_NAME. Signed-off-by: Anas Nashif Signed-off-by: Iuliana Prodan --- scripts/west_commands/sign.py | 16 +++++++++------- soc/xtensa/nxp_adsp/CMakeLists.txt | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index a61f78adef03..260adf7db88d 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -427,22 +427,24 @@ def sign(self, command, build_dir, build_conf, formats): # warning: RIMAGE_TARGET is a duplicate of CONFIG_RIMAGE_SIGNING_SCHEMA target = cache.get('RIMAGE_TARGET') + kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr') + if not target: log.die('rimage target not defined') # TODO: make this a new sign.py --bootloader option. if target in ('imx8', 'imx8m'): bootloader = None - kernel = str(b / 'zephyr' / 'zephyr.elf') - out_bin = str(b / 'zephyr' / 'zephyr.ri') - out_xman = str(b / 'zephyr' / 'zephyr.ri.xman') - out_tmp = str(b / 'zephyr' / 'zephyr.rix') + kernel = str(b / 'zephyr' / f'{kernel_name}.elf') + out_bin = str(b / 'zephyr' / f'{kernel_name}.ri') + out_xman = str(b / 'zephyr' / f'{kernel_name}.ri.xman') + out_tmp = str(b / 'zephyr' / f'{kernel_name}.rix') else: bootloader = str(b / 'zephyr' / 'boot.mod') kernel = str(b / 'zephyr' / 'main.mod') - out_bin = str(b / 'zephyr' / 'zephyr.ri') - out_xman = str(b / 'zephyr' / 'zephyr.ri.xman') - out_tmp = str(b / 'zephyr' / 'zephyr.rix') + out_bin = str(b / 'zephyr' / f'{kernel_name}.ri') + out_xman = str(b / 'zephyr' / f'{kernel_name}.ri.xman') + out_tmp = str(b / 'zephyr' / f'{kernel_name}.rix') # Clean any stale output. This is especially important when using --if-tool-available # (but not just) diff --git a/soc/xtensa/nxp_adsp/CMakeLists.txt b/soc/xtensa/nxp_adsp/CMakeLists.txt index 2ca5d100db3f..3586d87ffb74 100644 --- a/soc/xtensa/nxp_adsp/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/CMakeLists.txt @@ -16,5 +16,5 @@ add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri COMMENT "west sign --if-tool-available --tool rimage ..." COMMAND west sign --if-tool-available --tool rimage --build-dir ${CMAKE_BINARY_DIR} - DEPENDS ${CMAKE_BINARY_DIR}/zephyr/zephyr.elf + DEPENDS ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME} ) From a983abe42670eabcf88c2f6281a64ed797b3d43b Mon Sep 17 00:00:00 2001 From: Nikolay Agishev Date: Tue, 4 Jul 2023 18:01:44 +0400 Subject: [PATCH 1061/2042] ARC: Turn off stack checking for hsdk4xd Turn off unsupported configuration for hsdk4xd Signed-off-by: Nikolay Agishev --- soc/arc/snps_arc_hsdk4xd/Kconfig.defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/arc/snps_arc_hsdk4xd/Kconfig.defconfig b/soc/arc/snps_arc_hsdk4xd/Kconfig.defconfig index d5243bfbdab0..1b70bce3721d 100644 --- a/soc/arc/snps_arc_hsdk4xd/Kconfig.defconfig +++ b/soc/arc/snps_arc_hsdk4xd/Kconfig.defconfig @@ -50,4 +50,7 @@ config ARC_HAS_ACCL_REGS config ARC_EARLY_SOC_INIT default y +config ARC_HAS_STACK_CHECKING + default n + endif # SOC_ARC_HS4XD From 4eedd45c8598454bbdec3cdc21161a685da81aff Mon Sep 17 00:00:00 2001 From: Gustavo Silva Date: Fri, 7 Jul 2023 10:29:58 -0300 Subject: [PATCH 1062/2042] drivers: pwm: pwm_mcux: fix for coverity 321142 Fix `PWM_SetupPwm` function being called with `numOfChnls` argument equal to 2, when in fact only one channel is being set up. Also add 'U' suffix to `pwmFreq_Hz` unsigned integer argument in the function call. Signed-off-by: Gustavo Silva --- drivers/pwm/pwm_mcux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm_mcux.c b/drivers/pwm/pwm_mcux.c index a0368fd7c93c..23bbd3d03262 100644 --- a/drivers/pwm/pwm_mcux.c +++ b/drivers/pwm/pwm_mcux.c @@ -96,8 +96,8 @@ static int mcux_pwm_set_cycles(const struct device *dev, uint32_t channel, data->channel[channel].level = level; status = PWM_SetupPwm(config->base, config->index, - &data->channel[channel], CHANNEL_COUNT, - config->mode, 1, clock_freq); + &data->channel[channel], 1U, + config->mode, 1U, clock_freq); if (status != kStatus_Success) { LOG_ERR("Could not set up pwm"); return -ENOTSUP; From 21ada0da8386f87c977658cb773be2e7d4ed8431 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Fri, 7 Jul 2023 22:30:08 +0530 Subject: [PATCH 1063/2042] MAINTAINERS: Add vaishnavachath as maintainer for hal_ti Add myself as a maintainer for TI HAL layer (hal_ti), this update was missed while changing the maintainer details for the rest of TI platforms. Signed-off-by: Vaishnav Achath --- MAINTAINERS.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 50bfcf210cdb..c2817ef93ce0 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2986,7 +2986,9 @@ West: - manifest-hal_telink "West project: hal_ti": - status: odd fixes + status: maintained + maintainers: + - vaishnavachath collaborators: - cfriedt files: [] From 8b2a41904db55a1d428ddce48f8820a59b1a9a14 Mon Sep 17 00:00:00 2001 From: Harshil Bhatt Date: Sat, 8 Jul 2023 01:06:34 +0530 Subject: [PATCH 1064/2042] posix: implement timer_getoverrun() Address missing POSIX function and tests #59956 Signed-off-by: Harshil Bhatt --- include/zephyr/posix/time.h | 1 + lib/posix/Kconfig.timer | 7 +++++++ lib/posix/timer.c | 23 +++++++++++++++++++++++ tests/posix/common/src/timer.c | 26 ++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index a20cf313fcd4..057d55f0e3a7 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -94,6 +94,7 @@ int timer_delete(timer_t timerid); int timer_gettime(timer_t timerid, struct itimerspec *its); int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); +int timer_getoverrun(timer_t timerid); int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); #ifdef __cplusplus diff --git a/lib/posix/Kconfig.timer b/lib/posix/Kconfig.timer index c738064bb106..28173692e0ce 100644 --- a/lib/posix/Kconfig.timer +++ b/lib/posix/Kconfig.timer @@ -14,3 +14,10 @@ config TIMER_CREATE_WAIT help This controls how long to wait for resources to come available to create a new timer in POSIX compliant application + +config TIMER_DELAYTIMER_MAX + int "Maximum count returned my timer_getoverrun() in POSIX application" + default 20 + help + This controls the maximum number of times a timer can overrun before + timer_getoverrun() in POSIX compliant application. diff --git a/lib/posix/timer.c b/lib/posix/timer.c index 2d43ffc2a913..b00250ba50c7 100644 --- a/lib/posix/timer.c +++ b/lib/posix/timer.c @@ -179,6 +179,29 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, return 0; } +/** + * @brief Returns the timer expiration overrun count. + * + * See IEEE 1003.1 + */ +int timer_getoverrun(timer_t timerid) +{ + struct timer_obj *timer = (struct timer_obj *) timerid; + + if (timer == NULL) { + errno = EINVAL; + return -1; + } + + int overruns = k_timer_status_get(&timer->ztimer) - 1; + + if (overruns > CONFIG_TIMER_DELAYTIMER_MAX) { + overruns = CONFIG_TIMER_DELAYTIMER_MAX; + } + + return overruns; +} + /** * @brief Delete a per-process timer. * diff --git a/tests/posix/common/src/timer.c b/tests/posix/common/src/timer.c index c736ace18c70..0b5f07f8fb93 100644 --- a/tests/posix/common/src/timer.c +++ b/tests/posix/common/src/timer.c @@ -68,6 +68,7 @@ ZTEST(posix_apis, test_timer) 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) { @@ -83,7 +84,32 @@ ZTEST(posix_apis, test_timer) (value.it_interval.tv_sec * NSEC_PER_SEC + value.it_interval.tv_nsec)) / NSEC_PER_SEC; + /*TESTPOINT: Check if POSIX timer test passed*/ zassert_equal(total_secs_timer, secs_elapsed, "POSIX timer test has failed"); } + +ZTEST(posix_apis, test_timer_overrun) +{ + timer_t timerid; + struct sigevent sig = { 0 }; + struct itimerspec value; + + sig.sigev_notify = SIGEV_NONE; + + 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); + k_sleep(K_MSEC(2500)); + + int overruns = timer_getoverrun(timerid); + + timer_delete(timerid); + zassert_equal(overruns, 4, "Number of overruns is incorrect"); +} From 5a4fd10624d2bf0e1a1af879ab6fdc3a216948db Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 8 Jul 2023 17:03:57 +0000 Subject: [PATCH 1065/2042] shields: st_b_lcd40_dsi1_mb1166: bump up display init priority MIPI-DSI initialization priority got delayed in fed377f622, but now that's at the same priority as the OTM8009A for this board configuration, and OTM8009A needs MIPI-DSI to be initialized. Being at the same priority means that it may or may not work depending on the linking order, this is exposed with: $ west build -p -b stm32h747i_disco_m7 samples/subsys/display/lvgl \ -DSHIELD=st_b_lcd40_dsi1_mb1166 \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... WARNING: /soc/dsihost@50000000/otm8009a@0 POST_KERNEL 86 == /soc/dsihost@50000000 POST_KERNEL 86 Bumping the display priority up to make sure it still works. Signed-off-by: Fabio Baltieri --- .../st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.conf b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.conf index 09ba121ded8a..d3881d7e2ede 100644 --- a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.conf +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.conf @@ -4,5 +4,5 @@ CONFIG_MEMC=y CONFIG_STM32_LTDC_RGB888=y CONFIG_HEAP_MEM_POOL_SIZE=65536 -# Initialize after LTDC -CONFIG_DISPLAY_OTM8009A_INIT_PRIORITY=86 +# Initialize after LTDC and MIPI-DSI +CONFIG_DISPLAY_OTM8009A_INIT_PRIORITY=87 From 2d3c53f705cc11ae0c2a1b2d43016a030fffdce6 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 22 Jun 2023 13:52:30 +0200 Subject: [PATCH 1066/2042] flash simulator: Refactor native part so it works with emb libC Refactor the part of the flash simulator that interacts with the host when build for native platforms, so it is possible to use it also with the embedded libCs. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 2 +- drivers/flash/CMakeLists.txt | 9 +- drivers/flash/flash_simulator.c | 95 +++----------------- drivers/flash/flash_simulator_native.c | 117 +++++++++++++++++++++++++ drivers/flash/flash_simulator_native.h | 26 ++++++ 5 files changed, 166 insertions(+), 83 deletions(-) create mode 100644 drivers/flash/flash_simulator_native.c create mode 100644 drivers/flash/flash_simulator_native.h diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 2f524829b721..7c692e2affcf 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -112,7 +112,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). 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`, host libC - flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, host libC + flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, all flash, 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 diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 181f16101db1..8266c8c1619d 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -18,7 +18,14 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc2 zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_TELINK_B91 soc_flash_b91.c) zephyr_library_sources_ifdef(CONFIG_SPI_NOR spi_nor.c) zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_SIMULATOR flash_simulator.c) +if(CONFIG_FLASH_SIMULATOR) + zephyr_library_sources(flash_simulator.c) + if(CONFIG_NATIVE_LIBRARY) + target_sources(native_simulator INTERFACE flash_simulator_native.c) + elseif(CONFIG_ARCH_POSIX) + zephyr_library_sources(flash_simulator_native.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c) diff --git a/drivers/flash/flash_simulator.c b/drivers/flash/flash_simulator.c index 1f9aa83c395e..9fe5d230207c 100644 --- a/drivers/flash/flash_simulator.c +++ b/drivers/flash/flash_simulator.c @@ -19,18 +19,9 @@ #ifdef CONFIG_ARCH_POSIX -#include -#include -#include -#include -#include -#include -#include -#include - +#include "flash_simulator_native.h" #include "cmdline.h" #include "soc.h" - #define DEFAULT_FLASH_FILE_PATH "flash.bin" #endif /* CONFIG_ARCH_POSIX */ @@ -384,64 +375,22 @@ static const struct flash_driver_api flash_sim_api = { static int flash_mock_init(const struct device *dev) { - struct stat f_stat; int rc; - ARG_UNUSED(dev); - if (flash_in_ram == true) { - mock_flash = (uint8_t *)malloc(FLASH_SIMULATOR_FLASH_SIZE); - if (mock_flash == NULL) { - posix_print_warning("Could not allocate flash in the process heap %s\n", - strerror(errno)); - return -EIO; - } - } else { - - if (flash_file_path == NULL) { - flash_file_path = DEFAULT_FLASH_FILE_PATH; - } - - flash_fd = open(flash_file_path, O_RDWR | O_CREAT, (mode_t)0600); - if (flash_fd == -1) { - posix_print_warning("Failed to open flash device file " - "%s: %s\n", - flash_file_path, strerror(errno)); - return -EIO; - } - - rc = fstat(flash_fd, &f_stat); - if (rc) { - posix_print_warning("Failed to get status of flash device file " - "%s: %s\n", - flash_file_path, strerror(errno)); - return -EIO; - } - - if (ftruncate(flash_fd, FLASH_SIMULATOR_FLASH_SIZE) == -1) { - posix_print_warning("Failed to resize flash device file " - "%s: %s\n", - flash_file_path, strerror(errno)); - return -EIO; - } - - mock_flash = mmap(NULL, FLASH_SIMULATOR_FLASH_SIZE, - PROT_WRITE | PROT_READ, MAP_SHARED, flash_fd, 0); - if (mock_flash == MAP_FAILED) { - posix_print_warning("Failed to mmap flash device file " - "%s: %s\n", - flash_file_path, strerror(errno)); - return -EIO; - } + if (flash_in_ram == false && flash_file_path == NULL) { + flash_file_path = DEFAULT_FLASH_FILE_PATH; } - if ((flash_erase_at_start == true) || (flash_in_ram == true) || (f_stat.st_size == 0)) { - /* Erase the memory unit by pulling all bits to the configured erase value */ - (void)memset(mock_flash, FLASH_SIMULATOR_ERASE_VALUE, - FLASH_SIMULATOR_FLASH_SIZE); - } + rc = flash_mock_init_native(flash_in_ram, &mock_flash, FLASH_SIMULATOR_FLASH_SIZE, + &flash_fd, flash_file_path, FLASH_SIMULATOR_ERASE_VALUE, + flash_erase_at_start); - return 0; + if (rc < 0) { + return -EIO; + } else { + return 0; + } } #else @@ -477,25 +426,9 @@ DEVICE_DT_INST_DEFINE(0, flash_init, NULL, static void flash_native_posix_cleanup(void) { - if (flash_in_ram == true) { - if (mock_flash != NULL) { - free(mock_flash); - } - return; - } - - if ((mock_flash != MAP_FAILED) && (mock_flash != NULL)) { - munmap(mock_flash, FLASH_SIMULATOR_FLASH_SIZE); - } - - if (flash_fd != -1) { - close(flash_fd); - } - - if ((flash_rm_at_exit == true) && (flash_file_path != NULL)) { - /* We try to remove the file but do not error out if we can't */ - (void) remove(flash_file_path); - } + flash_mock_cleanup_native(flash_in_ram, flash_fd, mock_flash, + FLASH_SIMULATOR_FLASH_SIZE, flash_file_path, + flash_rm_at_exit); } static void flash_native_posix_options(void) diff --git a/drivers/flash/flash_simulator_native.c b/drivers/flash/flash_simulator_native.c new file mode 100644 index 000000000000..b31e42c05e07 --- /dev/null +++ b/drivers/flash/flash_simulator_native.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Part of flash simulator which interacts with the host OS + * + * When building for the native simulator, this file is built in the + * native simulator runner/host context, and not in Zephyr/embedded context. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Initialize the flash buffer. + * And, if the content is to be kept on disk map it to the the buffer to the file. + * + * Returns -1 on failure + * 0 on success + */ +int flash_mock_init_native(bool flash_in_ram, uint8_t **mock_flash, unsigned int size, + int *flash_fd, const char *flash_file_path, + unsigned int erase_value, bool flash_erase_at_start) +{ + struct stat f_stat; + int rc; + + if (flash_in_ram == true) { + *mock_flash = (uint8_t *)malloc(size); + if (*mock_flash == NULL) { + nsi_print_warning("Could not allocate flash in the process heap %s\n", + strerror(errno)); + return -1; + } + } else { + *flash_fd = open(flash_file_path, O_RDWR | O_CREAT, (mode_t)0600); + if (*flash_fd == -1) { + nsi_print_warning("Failed to open flash device file " + "%s: %s\n", + flash_file_path, strerror(errno)); + return -1; + } + + rc = fstat(*flash_fd, &f_stat); + if (rc) { + nsi_print_warning("Failed to get status of flash device file " + "%s: %s\n", + flash_file_path, strerror(errno)); + return -1; + } + + if (ftruncate(*flash_fd, size) == -1) { + nsi_print_warning("Failed to resize flash device file " + "%s: %s\n", + flash_file_path, strerror(errno)); + return -1; + } + + *mock_flash = mmap(NULL, size, + PROT_WRITE | PROT_READ, MAP_SHARED, *flash_fd, 0); + if (*mock_flash == MAP_FAILED) { + nsi_print_warning("Failed to mmap flash device file " + "%s: %s\n", + flash_file_path, strerror(errno)); + return -1; + } + } + + if ((flash_erase_at_start == true) || (flash_in_ram == true) || (f_stat.st_size == 0)) { + /* Erase the memory unit by pulling all bits to the configured erase value */ + (void)memset(*mock_flash, erase_value, size); + } + + return 0; +} + +/* + * If in RAM: Free the mock buffer + * If in disk: unmap the flash file from RAM, close the file, and if configured to do so, + * delete the file. + */ +void flash_mock_cleanup_native(bool flash_in_ram, int flash_fd, uint8_t *mock_flash, + unsigned int size, const char *flash_file_path, + bool flash_rm_at_exit) +{ + + if (flash_in_ram == true) { + if (mock_flash != NULL) { + free(mock_flash); + } + return; + } + + if ((mock_flash != MAP_FAILED) && (mock_flash != NULL)) { + munmap(mock_flash, size); + } + + if (flash_fd != -1) { + close(flash_fd); + } + + if ((flash_rm_at_exit == true) && (flash_file_path != NULL)) { + /* We try to remove the file but do not error out if we can't */ + (void) remove(flash_file_path); + } +} diff --git a/drivers/flash/flash_simulator_native.h b/drivers/flash/flash_simulator_native.h new file mode 100644 index 000000000000..a59136c1c207 --- /dev/null +++ b/drivers/flash/flash_simulator_native.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H +#define DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int flash_mock_init_native(bool flash_in_ram, uint8_t **mock_flash, unsigned int size, + int *flash_fd, const char *flash_file_path, + unsigned int erase_value, bool flash_erase_at_start); + +void flash_mock_cleanup_native(bool flash_in_ram, int flash_fd, uint8_t *mock_flash, + unsigned int size, const char *flash_file_path, + bool flash_rm_at_exit); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H */ From ed27a4fa3d82123d03200ea318d82e7cb31c9444 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 22 Jun 2023 14:16:30 +0200 Subject: [PATCH 1067/2042] tests flash simulator: Enable for native_sim Add overlays for the native_sim boards, and change test filters so they also run for these. Signed-off-by: Alberto Escolar Piedras --- .../flash_simulator/boards/native_posix_64.overlay | 8 ++------ tests/drivers/flash_simulator/boards/native_sim.overlay | 7 +++++++ .../drivers/flash_simulator/boards/native_sim_64.overlay | 7 +++++++ tests/drivers/flash_simulator/testcase.yaml | 6 ++++-- 4 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 tests/drivers/flash_simulator/boards/native_sim.overlay create mode 100644 tests/drivers/flash_simulator/boards/native_sim_64.overlay diff --git a/tests/drivers/flash_simulator/boards/native_posix_64.overlay b/tests/drivers/flash_simulator/boards/native_posix_64.overlay index d1964951d656..3467d3e6b386 100644 --- a/tests/drivers/flash_simulator/boards/native_posix_64.overlay +++ b/tests/drivers/flash_simulator/boards/native_posix_64.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_posix.overlay" diff --git a/tests/drivers/flash_simulator/boards/native_sim.overlay b/tests/drivers/flash_simulator/boards/native_sim.overlay new file mode 100644 index 000000000000..3467d3e6b386 --- /dev/null +++ b/tests/drivers/flash_simulator/boards/native_sim.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" diff --git a/tests/drivers/flash_simulator/boards/native_sim_64.overlay b/tests/drivers/flash_simulator/boards/native_sim_64.overlay new file mode 100644 index 000000000000..59b29bd85126 --- /dev/null +++ b/tests/drivers/flash_simulator/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim.overlay" diff --git a/tests/drivers/flash_simulator/testcase.yaml b/tests/drivers/flash_simulator/testcase.yaml index 8a905de83587..c963a8e99fb7 100644 --- a/tests/drivers/flash_simulator/testcase.yaml +++ b/tests/drivers/flash_simulator/testcase.yaml @@ -8,6 +8,8 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - native_sim + - native_sim_64 - nucleo_f411re integration_platforms: - qemu_x86 @@ -18,11 +20,11 @@ tests: - qemu_x86 drivers.flash.flash_simulator.posix_erase_value_0x00: extra_args: DTC_OVERLAY_FILE=boards/native_posix_ev_0x00.overlay - platform_allow: native_posix + 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 - platform_allow: native_posix_64 + platform_allow: native_posix_64 native_sim_64 integration_platforms: - native_posix_64 From ee268a6d4b5761e8bf2e90b5f8319b5bbec07fac Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 5 Jul 2023 17:41:51 +0200 Subject: [PATCH 1068/2042] posix arch cmake: Add clarification on use of target_link_options Clarify why we use target_link_options() instead of target_link_libraries() Signed-off-by: Alberto Escolar Piedras --- arch/posix/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 9ea21b2a8893..0980ba2bca1e 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -19,6 +19,12 @@ endif() # For ex. target_sources(native_simulator INTERFACE silly.c) # Note that these are built with the host libC and the include directories # the runner is built with. +# 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. +# Check https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_LINK_LIBRARIES.html for more +# info. +# We use target_link_options() instead add_library(native_simulator INTERFACE) if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/${CMAKE_HOST_SYSTEM_NAME}.${CMAKE_HOST_SYSTEM_PROCESSOR}.cmake) From 1842c602ecce49126c2b3e99cc6a8027f2fd7e38 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 5 Jul 2023 16:41:31 +0200 Subject: [PATCH 1069/2042] drivers serial native ptty: Split in top and bottom Split the native ptty serial driver in a top and bottom to enable using it with embedded libCs. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 2 +- drivers/serial/CMakeLists.txt | 7 +- drivers/serial/Kconfig.native_posix | 1 - drivers/serial/uart_native_posix.c | 470 ----------------------- drivers/serial/uart_native_ptty.c | 279 ++++++++++++++ drivers/serial/uart_native_ptty_bottom.c | 242 ++++++++++++ drivers/serial/uart_native_ptty_bottom.h | 34 ++ 7 files changed, 562 insertions(+), 473 deletions(-) delete mode 100644 drivers/serial/uart_native_posix.c create mode 100644 drivers/serial/uart_native_ptty.c create mode 100644 drivers/serial/uart_native_ptty_bottom.c create mode 100644 drivers/serial/uart_native_ptty_bottom.h diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 7c692e2affcf..f3bd75b6b8ce 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -120,7 +120,7 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, all log backend, 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`, host libC + serial, uart native posix/PTTY, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all serial, uart native TTY, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, host libC spi, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, all system tick, native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, all diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 9224c29aa645..365db9eb7423 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -68,7 +68,12 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) if(CONFIG_UART_NATIVE_POSIX) zephyr_library_compile_definitions(NO_POSIX_CHEATS) - zephyr_library_sources(uart_native_posix.c) + zephyr_library_sources(uart_native_ptty.c) + if (CONFIG_NATIVE_APPLICATION) + zephyr_library_sources(uart_native_ptty_bottom.c) + else() + target_sources(native_simulator INTERFACE uart_native_ptty_bottom.c) + endif() endif() if(CONFIG_UART_NATIVE_TTY) diff --git a/drivers/serial/Kconfig.native_posix b/drivers/serial/Kconfig.native_posix index 6873bff5308e..39acf155f9bd 100644 --- a/drivers/serial/Kconfig.native_posix +++ b/drivers/serial/Kconfig.native_posix @@ -4,7 +4,6 @@ config UART_NATIVE_POSIX bool "UART driver for native_posix" default y depends on DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED - depends on EXTERNAL_LIBC select SERIAL_HAS_DRIVER help This enables a UART driver for the POSIX ARCH with up to 2 UARTs. diff --git a/drivers/serial/uart_native_posix.c b/drivers/serial/uart_native_posix.c deleted file mode 100644 index 767df09ec93b..000000000000 --- a/drivers/serial/uart_native_posix.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (c) 2018, Oticon A/S - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT zephyr_native_posix_uart - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cmdline.h" /* native_posix command line options header */ -#include "posix_native_task.h" - -/* - * UART driver for POSIX ARCH based boards. - * It can support up to two UARTs. - * - * For the first UART: - * - * It can either be connected to the process STDIN+STDOUT - * OR - * to a dedicated pseudo terminal - * - * The 2nd option is the recommended one for interactive use, as the pseudo - * terminal driver will be configured in "raw" mode, and will therefore behave - * more like a real UART. - * - * When connected to its own pseudo terminal, it may also auto attach a terminal - * emulator to it, if set so from command line. - */ - -static int np_uart_stdin_poll_in(const struct device *dev, - unsigned char *p_char); -static int np_uart_tty_poll_in(const struct device *dev, - unsigned char *p_char); -static void np_uart_poll_out(const struct device *dev, - unsigned char out_char); - -static bool auto_attach; -static bool wait_pts; -static const char default_cmd[] = CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD; -static char *auto_attach_cmd; - -struct native_uart_status { - int out_fd; /* File descriptor used for output */ - int in_fd; /* File descriptor used for input */ -}; - -static struct native_uart_status native_uart_status_0; - -static struct uart_driver_api np_uart_driver_api_0 = { - .poll_out = np_uart_poll_out, - .poll_in = np_uart_tty_poll_in, -}; - -#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) -static struct native_uart_status native_uart_status_1; - -static struct uart_driver_api np_uart_driver_api_1 = { - .poll_out = np_uart_poll_out, - .poll_in = np_uart_tty_poll_in, -}; -#endif /* CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE */ - -#define ERROR posix_print_error_and_exit -#define WARN posix_print_warning - -/** - * Attempt to connect a terminal emulator to the slave side of the pty - * If -attach_uart_cmd= is provided as a command line option, will be - * used. Otherwise, the default command, - * CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD, will be used instead - */ -static void attach_to_tty(const char *slave_tty) -{ - if (auto_attach_cmd == NULL) { - auto_attach_cmd = (char *)default_cmd; - } - char command[strlen(auto_attach_cmd) + strlen(slave_tty) + 1]; - - sprintf(command, auto_attach_cmd, slave_tty); - - int ret = system(command); - - if (ret != 0) { - WARN("Could not attach to the UART with \"%s\"\n", command); - WARN("The command returned %i\n", WEXITSTATUS(ret)); - } -} - -/** - * Attempt to allocate and open a new pseudoterminal - * - * Returns the file descriptor of the master side - * If auto_attach was set, it will also attempt to connect a new terminal - * emulator to its slave side. - */ -static int open_tty(struct native_uart_status *driver_data, - const char *uart_name, - bool do_auto_attach) -{ - int master_pty; - char *slave_pty_name; - struct termios ter; - struct winsize win; - int err_nbr; - int ret; - int flags; - - win.ws_col = 80; - win.ws_row = 24; - - master_pty = posix_openpt(O_RDWR | O_NOCTTY); - if (master_pty == -1) { - ERROR("Could not open a new TTY for the UART\n"); - } - ret = grantpt(master_pty); - if (ret == -1) { - err_nbr = errno; - close(master_pty); - ERROR("Could not grant access to the slave PTY side (%i)\n", - err_nbr); - } - ret = unlockpt(master_pty); - if (ret == -1) { - err_nbr = errno; - close(master_pty); - ERROR("Could not unlock the slave PTY side (%i)\n", err_nbr); - } - slave_pty_name = ptsname(master_pty); - if (slave_pty_name == NULL) { - err_nbr = errno; - close(master_pty); - ERROR("Error getting slave PTY device name (%i)\n", err_nbr); - } - /* Set the master PTY as non blocking */ - flags = fcntl(master_pty, F_GETFL); - if (flags == -1) { - err_nbr = errno; - close(master_pty); - ERROR("Could not read the master PTY file status flags (%i)\n", - err_nbr); - } - - ret = fcntl(master_pty, F_SETFL, flags | O_NONBLOCK); - if (ret == -1) { - err_nbr = errno; - close(master_pty); - ERROR("Could not set the master PTY as non-blocking (%i)\n", - err_nbr); - } - - (void) err_nbr; - - /* - * Set terminal in "raw" mode: - * Not canonical (no line input) - * No signal generation from Ctr+{C|Z..} - * No echoing, no input or output processing - * No replacing of NL or CR - * No flow control - */ - ret = tcgetattr(master_pty, &ter); - if (ret == -1) { - ERROR("Could not read terminal driver settings\n"); - } - ter.c_cc[VMIN] = 0; - ter.c_cc[VTIME] = 0; - ter.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); - ter.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK - | ISTRIP | IXON | PARMRK); - ter.c_oflag &= ~OPOST; - ret = tcsetattr(master_pty, TCSANOW, &ter); - if (ret == -1) { - ERROR("Could not change terminal driver settings\n"); - } - - posix_print_trace("%s connected to pseudotty: %s\n", - uart_name, slave_pty_name); - - if (wait_pts) { - /* - * This trick sets the HUP flag on the tty master, making it - * possible to detect a client connection using poll. - * The connection of the client would cause the HUP flag to be - * cleared, and in turn set again at disconnect. - */ - ret = open(slave_pty_name, O_RDWR | O_NOCTTY); - if (ret == -1) { - err_nbr = errno; - ERROR("%s: Could not open terminal from the slave side (%i,%s)\n", - __func__, err_nbr, strerror(err_nbr)); - } - ret = close(ret); - if (ret == -1) { - err_nbr = errno; - ERROR("%s: Could not close terminal from the slave side (%i,%s)\n", - __func__, err_nbr, strerror(err_nbr)); - } - } - if (do_auto_attach) { - attach_to_tty(slave_pty_name); - } - - return master_pty; -} - -/** - * @brief Initialize the first native_posix serial port - * - * @param dev UART_0 device struct - * - * @return 0 (if it fails catastrophically, the execution is terminated) - */ -static int np_uart_0_init(const struct device *dev) -{ - struct native_uart_status *d; - - d = (struct native_uart_status *)dev->data; - - if (IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { - int tty_fn = open_tty(d, dev->name, auto_attach); - - d->in_fd = tty_fn; - d->out_fd = tty_fn; - np_uart_driver_api_0.poll_in = np_uart_tty_poll_in; - } else { /* NATIVE_UART_0_ON_STDINOUT */ - d->in_fd = STDIN_FILENO; - d->out_fd = STDOUT_FILENO; - np_uart_driver_api_0.poll_in = np_uart_stdin_poll_in; - - if (isatty(STDIN_FILENO)) { - WARN("The UART driver has been configured to map to the" - " process stdin&out (NATIVE_UART_0_ON_STDINOUT), " - "but stdin seems to be left attached to the shell." - " This will most likely NOT behave as you want it " - "to. This option is NOT meant for interactive use " - "but for piping/feeding from/to files to the UART" - ); - } - } - - return 0; -} - -#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) -/* - * Initialize the 2nd UART port. - * This port will be always attached to its own new pseudoterminal. - */ -static int np_uart_1_init(const struct device *dev) -{ - struct native_uart_status *d; - int tty_fn; - - d = (struct native_uart_status *)dev->data; - - tty_fn = open_tty(d, dev->name, false); - - d->in_fd = tty_fn; - d->out_fd = tty_fn; - - return 0; -} -#endif - -/* - * @brief Output a character towards the serial port - * - * @param dev UART device struct - * @param out_char Character to send. - */ -static void np_uart_poll_out(const struct device *dev, - unsigned char out_char) -{ - int ret; - struct native_uart_status *d = (struct native_uart_status *)dev->data; - - if (wait_pts) { - struct pollfd pfd = { .fd = d->out_fd, .events = POLLHUP }; - - while (1) { - ret = poll(&pfd, 1, 0); - if (ret == -1) { - int err = errno; - /* - * Possible errors are: - * * EINTR :A signal was received => ok - * * EFAULT and EINVAL: parameters/programming error - * * ENOMEM no RAM left - */ - if (err != EINTR) { - ERROR("%s: unexpected error during poll, errno=%i,%s\n", - __func__, err, strerror(err)); - } - } - if (!(pfd.revents & POLLHUP)) { - /* There is now a reader on the slave side */ - break; - } - k_sleep(K_MSEC(100)); - } - } - - /* The return value of write() cannot be ignored (there is a warning) - * but we do not need the return value for anything. - */ - ret = write(d->out_fd, &out_char, 1); - (void) ret; -} - -/** - * @brief Poll the device for input. - * - * @param dev UART device structure. - * @param p_char Pointer to character. - * - * @retval 0 If a character arrived and was stored in p_char - * @retval -1 If no character was available to read - */ -static int np_uart_stdin_poll_in(const struct device *dev, - unsigned char *p_char) -{ - static bool disconnected; - - if (disconnected || feof(stdin)) { - /* - * The stdinput is fed from a file which finished or the user - * pressed Ctrl+D - */ - disconnected = true; - return -1; - } - - int n = -1; - int in_f = ((struct native_uart_status *)dev->data)->in_fd; - - int ready; - fd_set readfds; - static struct timeval timeout; /* just zero */ - - FD_ZERO(&readfds); - FD_SET(in_f, &readfds); - - ready = select(in_f+1, &readfds, NULL, NULL, &timeout); - - if (ready == 0) { - return -1; - } else if (ready == -1) { - ERROR("%s: Error on select ()\n", __func__); - } - - n = read(in_f, p_char, 1); - if ((n == -1) || (n == 0)) { - return -1; - } - - return 0; -} - -/** - * @brief Poll the device for input. - * - * @param dev UART device structure. - * @param p_char Pointer to character. - * - * @retval 0 If a character arrived and was stored in p_char - * @retval -1 If no character was available to read - */ -static int np_uart_tty_poll_in(const struct device *dev, - unsigned char *p_char) -{ - int n = -1; - int in_f = ((struct native_uart_status *)dev->data)->in_fd; - - n = read(in_f, p_char, 1); - if (n == -1) { - return -1; - } - return 0; -} - -DEVICE_DT_INST_DEFINE(0, - &np_uart_0_init, NULL, - (void *)&native_uart_status_0, NULL, - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, - &np_uart_driver_api_0); - -#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) -DEVICE_DT_INST_DEFINE(1, - &np_uart_1_init, NULL, - (void *)&native_uart_status_1, NULL, - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, - &np_uart_driver_api_1); -#endif /* CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE */ - -static void auto_attach_cmd_cb(char *argv, int offset) -{ - ARG_UNUSED(argv); - ARG_UNUSED(offset); - - auto_attach = true; -} - -static void np_add_uart_options(void) -{ - if (!IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { - return; - } - - static struct args_struct_t uart_options[] = { - /* - * Fields: - * manual, mandatory, switch, - * option_name, var_name ,type, - * destination, callback, - * description - */ - {false, false, true, - "attach_uart", "", 'b', - (void *)&auto_attach, NULL, - "Automatically attach to the UART terminal"}, - {false, false, false, - "attach_uart_cmd", "\"cmd\"", 's', - (void *)&auto_attach_cmd, auto_attach_cmd_cb, - "Command used to automatically attach to the terminal" - "(implies auto_attach), by " - "default: '" CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD "'"}, - IF_ENABLED(CONFIG_UART_NATIVE_WAIT_PTS_READY_ENABLE, ( - {false, false, true, - "wait_uart", "", 'b', - (void *)&wait_pts, NULL, - "Hold writes to the uart/pts until a client is " - "connected/ready"},) - ) - ARG_TABLE_ENDMARKER - }; - - native_add_command_line_opts(uart_options); -} - -static void np_cleanup_uart(void) -{ - if (IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { - if (native_uart_status_0.in_fd != 0) { - close(native_uart_status_0.in_fd); - } - } - -#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) - if (native_uart_status_1.in_fd != 0) { - close(native_uart_status_1.in_fd); - } -#endif -} - -NATIVE_TASK(np_add_uart_options, PRE_BOOT_1, 11); -NATIVE_TASK(np_cleanup_uart, ON_EXIT, 99); diff --git a/drivers/serial/uart_native_ptty.c b/drivers/serial/uart_native_ptty.c new file mode 100644 index 000000000000..77f609a6309e --- /dev/null +++ b/drivers/serial/uart_native_ptty.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2018, Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_native_posix_uart + +#include + +#include +#include + +#include "cmdline.h" /* native_posix command line options header */ +#include "posix_native_task.h" +#include "uart_native_ptty_bottom.h" +#include "nsi_host_trampolines.h" + +/* + * UART driver for POSIX ARCH based boards. + * It can support up to two UARTs. + * + * For the first UART: + * + * It can either be connected to the process STDIN+STDOUT + * OR + * to a dedicated pseudo terminal + * + * The 2nd option is the recommended one for interactive use, as the pseudo + * terminal driver will be configured in "raw" mode, and will therefore behave + * more like a real UART. + * + * When connected to its own pseudo terminal, it may also auto attach a terminal + * emulator to it, if set so from command line. + */ + +static int np_uart_stdin_poll_in(const struct device *dev, + unsigned char *p_char); +static int np_uart_tty_poll_in(const struct device *dev, + unsigned char *p_char); +static void np_uart_poll_out(const struct device *dev, + unsigned char out_char); + +static bool auto_attach; +static bool wait_pts; +static char *auto_attach_cmd = CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD; + +struct native_uart_status { + int out_fd; /* File descriptor used for output */ + int in_fd; /* File descriptor used for input */ +}; + +static struct native_uart_status native_uart_status_0; + +static struct uart_driver_api np_uart_driver_api_0 = { + .poll_out = np_uart_poll_out, + .poll_in = np_uart_tty_poll_in, +}; + +#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) +static struct native_uart_status native_uart_status_1; + +static struct uart_driver_api np_uart_driver_api_1 = { + .poll_out = np_uart_poll_out, + .poll_in = np_uart_tty_poll_in, +}; +#endif /* CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE */ + +#define ERROR posix_print_error_and_exit +#define WARN posix_print_warning + + + +/** + * @brief Initialize the first native_posix serial port + * + * @param dev UART_0 device struct + * + * @return 0 (if it fails catastrophically, the execution is terminated) + */ +static int np_uart_0_init(const struct device *dev) +{ + struct native_uart_status *d; + + d = (struct native_uart_status *)dev->data; + + if (IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { + int tty_fn = np_uart_open_ptty(dev->name, auto_attach_cmd, auto_attach, wait_pts); + + d->in_fd = tty_fn; + d->out_fd = tty_fn; + np_uart_driver_api_0.poll_in = np_uart_tty_poll_in; + } else { /* NATIVE_UART_0_ON_STDINOUT */ + d->in_fd = np_uart_ptty_get_stdin_fileno(); + d->out_fd = np_uart_ptty_get_stdout_fileno(); + np_uart_driver_api_0.poll_in = np_uart_stdin_poll_in; + } + + return 0; +} + +#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) +/* + * Initialize the 2nd UART port. + * This port will be always attached to its own new pseudoterminal. + */ +static int np_uart_1_init(const struct device *dev) +{ + struct native_uart_status *d; + int tty_fn; + + d = (struct native_uart_status *)dev->data; + + tty_fn = np_uart_open_ptty(dev->name, NULL, false, wait_pts); + + d->in_fd = tty_fn; + d->out_fd = tty_fn; + + return 0; +} +#endif + +/* + * @brief Output a character towards the serial port + * + * @param dev UART device struct + * @param out_char Character to send. + */ +static void np_uart_poll_out(const struct device *dev, + unsigned char out_char) +{ + int ret; + struct native_uart_status *d = (struct native_uart_status *)dev->data; + + if (wait_pts) { + + while (1) { + int rc = np_uart_slave_connected(d->out_fd); + + if (rc == 1) { + break; + } + k_sleep(K_MSEC(100)); + } + } + + /* The return value of write() cannot be ignored (there is a warning) + * but we do not need the return value for anything. + */ + ret = nsi_host_write(d->out_fd, &out_char, 1); + (void) ret; +} + +/** + * @brief Poll the device for input. + * + * @param dev UART device structure. + * @param p_char Pointer to character. + * + * @retval 0 If a character arrived and was stored in p_char + * @retval -1 If no character was available to read + */ +static int np_uart_stdin_poll_in(const struct device *dev, + unsigned char *p_char) +{ + int in_f = ((struct native_uart_status *)dev->data)->in_fd; + static bool disconnected; + int rc; + + if (disconnected == true) { + return -1; + } + + rc = np_uart_stdin_poll_in_bottom(in_f, p_char); + if (rc == -2) { + disconnected = true; + return -1; + } + + return rc; +} + +/** + * @brief Poll the device for input. + * + * @param dev UART device structure. + * @param p_char Pointer to character. + * + * @retval 0 If a character arrived and was stored in p_char + * @retval -1 If no character was available to read + */ +static int np_uart_tty_poll_in(const struct device *dev, + unsigned char *p_char) +{ + int n = -1; + int in_f = ((struct native_uart_status *)dev->data)->in_fd; + + n = nsi_host_read(in_f, p_char, 1); + if (n == -1) { + return -1; + } + return 0; +} + +DEVICE_DT_INST_DEFINE(0, + &np_uart_0_init, NULL, + (void *)&native_uart_status_0, NULL, + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, + &np_uart_driver_api_0); + +#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) +DEVICE_DT_INST_DEFINE(1, + &np_uart_1_init, NULL, + (void *)&native_uart_status_1, NULL, + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, + &np_uart_driver_api_1); +#endif /* CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE */ + +static void auto_attach_cmd_cb(char *argv, int offset) +{ + auto_attach_cmd = &argv[offset]; + auto_attach = true; +} + +static void np_add_uart_options(void) +{ + if (!IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { + return; + } + + static struct args_struct_t uart_options[] = { + { + .is_switch = true, + .option = "attach_uart", + .type = 'b', + .dest = (void *)&auto_attach, + .descript = "Automatically attach to the UART terminal" + }, + { + .option = "attach_uart_cmd", + .name = "\"cmd\"", + .type = 's', + .call_when_found = auto_attach_cmd_cb, + .descript = "Command used to automatically attach to the terminal (implies " + "auto_attach), by default: " + "'" CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD "'" + }, + IF_ENABLED(CONFIG_UART_NATIVE_WAIT_PTS_READY_ENABLE, ( + { + .is_switch = true, + .option = "wait_uart", + .type = 'b', + .dest = (void *)&wait_pts, + .descript = "Hold writes to the uart/pts until a client is connected/ready" + }, + )) + ARG_TABLE_ENDMARKER + }; + + native_add_command_line_opts(uart_options); +} + +static void np_cleanup_uart(void) +{ + if (IS_ENABLED(CONFIG_NATIVE_UART_0_ON_OWN_PTY)) { + if (native_uart_status_0.in_fd != 0) { + nsi_host_close(native_uart_status_0.in_fd); + } + } + +#if defined(CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE) + if (native_uart_status_1.in_fd != 0) { + nsi_host_close(native_uart_status_1.in_fd); + } +#endif +} + +NATIVE_TASK(np_add_uart_options, PRE_BOOT_1, 11); +NATIVE_TASK(np_cleanup_uart, ON_EXIT, 99); diff --git a/drivers/serial/uart_native_ptty_bottom.c b/drivers/serial/uart_native_ptty_bottom.c new file mode 100644 index 000000000000..51348423cc98 --- /dev/null +++ b/drivers/serial/uart_native_ptty_bottom.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2018, Oticon A/S + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ERROR nsi_print_error_and_exit +#define WARN nsi_print_warning + +/** + * @brief Poll the device for input. + * + * @param in_f Input file descriptor + * @param p_char Pointer to character. + * + * @retval 0 If a character arrived and was stored in p_char + * @retval -1 If no character was available to read + * @retval -2 if the stdin is disconnected + */ +int np_uart_stdin_poll_in_bottom(int in_f, unsigned char *p_char) +{ + if (feof(stdin)) { + /* + * The stdinput is fed from a file which finished or the user + * pressed Ctrl+D + */ + return -2; + } + + int n = -1; + + int ready; + fd_set readfds; + static struct timeval timeout; /* just zero */ + + FD_ZERO(&readfds); + FD_SET(in_f, &readfds); + + ready = select(in_f+1, &readfds, NULL, NULL, &timeout); + + if (ready == 0) { + return -1; + } else if (ready == -1) { + ERROR("%s: Error on select ()\n", __func__); + } + + n = read(in_f, p_char, 1); + if ((n == -1) || (n == 0)) { + return -1; + } + + return 0; +} + +/** + * @brief Check if the output descriptor has something connected to the slave side + * + * @param fd file number + * + * @retval 0 Nothing connected yet + * @retval 1 Something connected to the slave side + */ +int np_uart_slave_connected(int fd) +{ + struct pollfd pfd = { .fd = fd, .events = POLLHUP }; + int ret; + + ret = poll(&pfd, 1, 0); + if (ret == -1) { + int err = errno; + /* + * Possible errors are: + * * EINTR :A signal was received => ok + * * EFAULT and EINVAL: parameters/programming error + * * ENOMEM no RAM left + */ + if (err != EINTR) { + ERROR("%s: unexpected error during poll, errno=%i,%s\n", + __func__, err, strerror(err)); + } + } + if (!(pfd.revents & POLLHUP)) { + /* There is now a reader on the slave side */ + return 1; + } + return 0; +} + +/** + * Attempt to connect a terminal emulator to the slave side of the pty + * If -attach_uart_cmd= is provided as a command line option, will be + * used. Otherwise, the default command, + * CONFIG_NATIVE_UART_AUTOATTACH_DEFAULT_CMD, will be used instead + */ +static void attach_to_tty(const char *slave_tty, const char *auto_attach_cmd) +{ + char command[strlen(auto_attach_cmd) + strlen(slave_tty) + 1]; + + sprintf(command, auto_attach_cmd, slave_tty); + + int ret = system(command); + + if (ret != 0) { + WARN("Could not attach to the UART with \"%s\"\n", command); + WARN("The command returned %i\n", WEXITSTATUS(ret)); + } +} +/** + * Attempt to allocate and open a new pseudoterminal + * + * Returns the file descriptor of the master side + * If auto_attach was set, it will also attempt to connect a new terminal + * emulator to its slave side. + */ +int np_uart_open_ptty(const char *uart_name, const char *auto_attach_cmd, + bool do_auto_attach, bool wait_pts) +{ + int master_pty; + char *slave_pty_name; + struct termios ter; + int err_nbr; + int ret; + int flags; + + master_pty = posix_openpt(O_RDWR | O_NOCTTY); + if (master_pty == -1) { + ERROR("Could not open a new TTY for the UART\n"); + } + ret = grantpt(master_pty); + if (ret == -1) { + err_nbr = errno; + close(master_pty); + ERROR("Could not grant access to the slave PTY side (%i)\n", + err_nbr); + } + ret = unlockpt(master_pty); + if (ret == -1) { + err_nbr = errno; + close(master_pty); + ERROR("Could not unlock the slave PTY side (%i)\n", err_nbr); + } + slave_pty_name = ptsname(master_pty); + if (slave_pty_name == NULL) { + err_nbr = errno; + close(master_pty); + ERROR("Error getting slave PTY device name (%i)\n", err_nbr); + } + /* Set the master PTY as non blocking */ + flags = fcntl(master_pty, F_GETFL); + if (flags == -1) { + err_nbr = errno; + close(master_pty); + ERROR("Could not read the master PTY file status flags (%i)\n", + err_nbr); + } + + ret = fcntl(master_pty, F_SETFL, flags | O_NONBLOCK); + if (ret == -1) { + err_nbr = errno; + close(master_pty); + ERROR("Could not set the master PTY as non-blocking (%i)\n", + err_nbr); + } + + (void) err_nbr; + + /* + * Set terminal in "raw" mode: + * Not canonical (no line input) + * No signal generation from Ctr+{C|Z..} + * No echoing, no input or output processing + * No replacing of NL or CR + * No flow control + */ + ret = tcgetattr(master_pty, &ter); + if (ret == -1) { + ERROR("Could not read terminal driver settings\n"); + } + ter.c_cc[VMIN] = 0; + ter.c_cc[VTIME] = 0; + ter.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO); + ter.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK + | ISTRIP | IXON | PARMRK); + ter.c_oflag &= ~OPOST; + ret = tcsetattr(master_pty, TCSANOW, &ter); + if (ret == -1) { + ERROR("Could not change terminal driver settings\n"); + } + + nsi_print_trace("%s connected to pseudotty: %s\n", + uart_name, slave_pty_name); + + if (wait_pts) { + /* + * This trick sets the HUP flag on the tty master, making it + * possible to detect a client connection using poll. + * The connection of the client would cause the HUP flag to be + * cleared, and in turn set again at disconnect. + */ + ret = open(slave_pty_name, O_RDWR | O_NOCTTY); + if (ret == -1) { + err_nbr = errno; + ERROR("%s: Could not open terminal from the slave side (%i,%s)\n", + __func__, err_nbr, strerror(err_nbr)); + } + ret = close(ret); + if (ret == -1) { + err_nbr = errno; + ERROR("%s: Could not close terminal from the slave side (%i,%s)\n", + __func__, err_nbr, strerror(err_nbr)); + } + } + if (do_auto_attach) { + attach_to_tty(slave_pty_name, auto_attach_cmd); + } + + return master_pty; +} + +int np_uart_ptty_get_stdin_fileno(void) +{ + return STDIN_FILENO; +} + +int np_uart_ptty_get_stdout_fileno(void) +{ + return STDOUT_FILENO; +} diff --git a/drivers/serial/uart_native_ptty_bottom.h b/drivers/serial/uart_native_ptty_bottom.h new file mode 100644 index 000000000000..cc5ec282450f --- /dev/null +++ b/drivers/serial/uart_native_ptty_bottom.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * "Bottom" of native ptty uart driver + * When built with the native_simulator this will be built in the runner context, + * that is, with the host C library, and with the host include paths. + */ + +#ifndef DRIVERS_SERIAL_UART_NATIVE_PTTY_BOTTOM_H +#define DRIVERS_SERIAL_UART_NATIVE_PTTY_BOTTOM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Note: None of these functions are public interfaces. But internal to the native ptty driver */ + +int np_uart_stdin_poll_in_bottom(int in_f, unsigned char *p_char); +int np_uart_slave_connected(int fd); +int np_uart_open_ptty(const char *uart_name, const char *auto_attach_cmd, + bool do_auto_attach, bool wait_pts); +int np_uart_ptty_get_stdin_fileno(void); +int np_uart_ptty_get_stdout_fileno(void); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_SERIAL_UART_NATIVE_PTTY_BOTTOM_H */ From 76e5760545437c3c8538d77e600545fe46bac41e Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 29 Jun 2023 10:54:54 +0200 Subject: [PATCH 1070/2042] drivers/sensor: lis2dh: move h/w reg debug print right after it is read Move LOG_DBG print just after the printed h/w register is read, to avoid coverity complaining about uninitialized variable. Fix: Coverity-CID: 316407 (issue #58591) Signed-off-by: Armando Visconti --- drivers/sensor/lis2dh/lis2dh_trigger.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/sensor/lis2dh/lis2dh_trigger.c b/drivers/sensor/lis2dh/lis2dh_trigger.c index a30536f037a6..774cd884a697 100644 --- a/drivers/sensor/lis2dh/lis2dh_trigger.c +++ b/drivers/sensor/lis2dh/lis2dh_trigger.c @@ -387,6 +387,8 @@ static void lis2dh_thread_cb(const struct device *dev) LOG_ERR("clearing interrupt 2 failed: %d", status); return; } + + LOG_DBG("@tick=%u int2_src=0x%x", k_cycle_get_32(), reg_val); } if (likely(lis2dh->handler_anymotion != NULL)) { @@ -400,9 +402,6 @@ static void lis2dh_thread_cb(const struct device *dev) setup_int2(dev, true); } - LOG_DBG("@tick=%u int2_src=0x%x", k_cycle_get_32(), - reg_val); - return; } } From 4a8d61248aa5855c5afb94119813fcb80f23e3d4 Mon Sep 17 00:00:00 2001 From: Kirill Kobelev Date: Mon, 3 Jul 2023 19:16:05 -0700 Subject: [PATCH 1071/2042] doc: introduction: Improve style and grammar across the chapter The changes are cosmetic and they do not change the meaning of the docs. Signed-off-by: Kirill Kobelev --- doc/introduction/index.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 38c64fd20711..918801fc7d43 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -107,8 +107,8 @@ Zephyr offers a large and ever growing number of features including: **Optimized Device Driver Model** Provides a consistent device model for configuring the drivers that are part of the platform/system and a consistent model for initializing all the - drivers configured into the system and Allows the reuse of drivers across - platforms that have common devices/IP blocks + drivers configured into the system and allows the reuse of drivers across + platforms that have common devices/IP blocks. **Devicetree Support** Use of :ref:`devicetree ` to describe hardware. @@ -125,8 +125,8 @@ Zephyr offers a large and ever growing number of features including: (LE Link Layer). Includes Bluetooth mesh and a Bluetooth qualification-ready Bluetooth controller. - * Generic Access Profile (GAP) with all possible LE roles. - * GATT (Generic Attribute Profile) + * Generic Access Profile (GAP) with all possible LE roles + * Generic Attribute Profile (GATT) * Pairing support, including the Secure Connections feature from Bluetooth 4.2 * Clean HCI driver abstraction @@ -143,7 +143,7 @@ Zephyr offers a large and ever growing number of features including: **Native Linux, macOS, and Windows Development** A command-line CMake build environment runs on popular developer OS - systems. A native POSIX port, lets you build and run Zephyr as a native + systems. A native POSIX port lets you build and run Zephyr as a native application on Linux and other OSes, aiding development and testing. **Virtual File System Interface with LittleFS and FATFS Support** @@ -153,7 +153,7 @@ Zephyr offers a large and ever growing number of features including: **Powerful multi-backend logging Framework** Support for log filtering, object dumping, panic mode, multiple backends - (memory, networking, filesystem, console, ..) and integration with the shell + (memory, networking, filesystem, console, ...) and integration with the shell subsystem. **User friendly and full-featured Shell interface** @@ -163,7 +163,7 @@ Zephyr offers a large and ever growing number of features including: **Settings on non-volatile storage** The settings subsystem gives modules a way to store persistent per-device - configuration and runtime state. Settings items are stored as key-value pair + configuration and runtime state. Settings items are stored as key-value pair strings. **Non-volatile storage (NVS)** From d98656f08196786bbc844b3c60ef6a9c3b1bef69 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 4 Jul 2023 08:01:28 +0100 Subject: [PATCH 1072/2042] doc: kernel: code-relocation: Remove erroneous note The note about required position for the function is not valid. Signed-off-by: Jamie McCrae --- doc/kernel/code-relocation.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index 399a70744ff8..ee534ffe3efa 100644 --- a/doc/kernel/code-relocation.rst +++ b/doc/kernel/code-relocation.rst @@ -62,9 +62,6 @@ for data copy operations from ROM to required memory type. .. note:: function zephyr_code_relocate() can be called as many times as required. - This step has to be performed before calling find_package(Zephyr ...) - in the application's CMakeLists.txt. - Additional Configurations ========================= From c9a4764c10c5354898d8646dc6fe7c69cfe7f68d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Jun 2023 09:03:24 +0100 Subject: [PATCH 1073/2042] mgmt: mcumgt: smp: Fix not checking returned status Fixes not checking if a zcbor operation was successful. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/smp/src/smp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 56c9cc17b3b0..6107ef9ca1e1 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -226,12 +226,18 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp } if (handler_fn) { + bool ok; + *handler_found = true; - zcbor_map_start_encode(cbuf->writer->zs, - CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); + ok = zcbor_map_start_encode(cbuf->writer->zs, + CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES); MGMT_CTXT_SET_RC_RSN(cbuf, NULL); + if (!ok) { + return MGMT_ERR_EMSGSIZE; + } + #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) cmd_recv.group = req_hdr->nh_group; cmd_recv.id = req_hdr->nh_id; @@ -248,8 +254,8 @@ static int smp_handle_single_payload(struct smp_streamer *cbuf, const struct smp if (status == MGMT_CB_ERROR_RC) { rc = ret_rc; } else { - bool ok = smp_add_cmd_ret(cbuf->writer->zs, ret_group, - (uint16_t)ret_rc); + ok = smp_add_cmd_ret(cbuf->writer->zs, ret_group, + (uint16_t)ret_rc); rc = (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); } From 695616c177e98dae63f51854085d26aa62033ea5 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 30 Jun 2023 12:07:23 +0100 Subject: [PATCH 1074/2042] cmake: Fix code relocation functions with absolute paths Fixes an issue whereby absolute paths in libraries would have duplicate paths in the name, causing issues in that they would not be relocated. Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae --- cmake/modules/extensions.cmake | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 5d654ed80369..c5b3c8fd85ad 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -1331,11 +1331,16 @@ function(zephyr_code_relocate) message(FATAL_ERROR "zephyr_code_relocate() requires a LOCATION argument") endif() if(CODE_REL_LIBRARY) - # Use cmake generator expression to convert library to file list + # Use cmake generator expression to convert library to file list, + # supporting relative and absolute paths set(genex_src_dir "$") set(genex_src_list "$") - set(file_list - "${genex_src_dir}/$${genex_src_dir}/>") + set(src_list_abs "$") + set(src_list_rel "$") + set(src_list "${genex_src_dir}/$${genex_src_dir}/>") + set(nonempty_src_list "$<$:${src_list}>") + set(sep_list "$<$,$>:$>") + set(file_list "${src_list_abs}${sep_list}${nonempty_src_list}") else() # Check if CODE_REL_FILES is a generator expression, if so leave it # untouched. From ff8c78154fab68939d8e1543b0d23278aa19bb04 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 4 Jul 2023 12:49:06 +0100 Subject: [PATCH 1075/2042] tests: application_development: code_relocation: Add absolute paths Adds some absolute paths to check that the feature is working correctly. Signed-off-by: Jamie McCrae --- tests/application_development/code_relocation/CMakeLists.txt | 2 +- .../code_relocation/test_lib/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/application_development/code_relocation/CMakeLists.txt b/tests/application_development/code_relocation/CMakeLists.txt index f731fea70edd..132c905895ed 100644 --- a/tests/application_development/code_relocation/CMakeLists.txt +++ b/tests/application_development/code_relocation/CMakeLists.txt @@ -17,7 +17,7 @@ endif() # Code relocation feature zephyr_code_relocate(FILES src/test_file1.c ${SRAM2_PHDR} LOCATION SRAM2) -zephyr_code_relocate(FILES src/test_file2.c ${RAM_PHDR} LOCATION RAM) +zephyr_code_relocate(FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/test_file2.c ${RAM_PHDR} LOCATION RAM) # Add custom library that we can relocate code for add_subdirectory(test_lib) diff --git a/tests/application_development/code_relocation/test_lib/CMakeLists.txt b/tests/application_development/code_relocation/test_lib/CMakeLists.txt index 86fa18b38d6a..d660949a80e9 100644 --- a/tests/application_development/code_relocation/test_lib/CMakeLists.txt +++ b/tests/application_development/code_relocation/test_lib/CMakeLists.txt @@ -2,7 +2,7 @@ # Copyright 2022 NXP add_library(test_lib STATIC "") -target_sources(test_lib PRIVATE test_lib1.c test_lib2.c) +target_sources(test_lib PRIVATE test_lib1.c ${CMAKE_CURRENT_SOURCE_DIR}/test_lib2.c) get_target_property(include_dirs app INCLUDE_DIRECTORIES) target_link_libraries(test_lib PUBLIC zephyr_interface) add_dependencies(test_lib zephyr_generated_headers) From 7fa4570d10fdf1ed952dd5b91ebe1e34d05586f9 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 30 Jun 2023 14:58:51 +0100 Subject: [PATCH 1076/2042] doc: mgmt: mcumgr: Fix date typo Fixes an issue where data was used instead of date Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/smp_groups/smp_group_0.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_0.rst b/doc/services/device_mgmt/smp_groups/smp_group_0.rst index 26cc553d4144..e0d995b1a238 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_0.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_0.rst @@ -318,7 +318,7 @@ Date-time request header fields: The command sends an empty CBOR map as data. -Data-time get response +Date-time get response ---------------------- Date-time get response header fields: @@ -399,7 +399,7 @@ where: | | yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZZZ | +-----------------------+---------------------------------------------------+ -Data-time set response +Date-time set response ---------------------- Date-time set response header fields: From e8095b1a8be19c1d8c3acca5ca68788855e9f0da Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 6 Jul 2023 08:11:42 +0100 Subject: [PATCH 1077/2042] west.yaml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 6a8746d7acd75ff81fb6888d7776f412663f7897 Brings following Zephyr relevant fixes: - 6a8746d boot_serial: fix image number handle in image upload request - f2cb550 boot_serial: fix misuse of 'matched' param from zcbor_map_decode_bulk() - 82feb9a boot_serial: Fix showing images that are not valid - 61962b9 bootutil: fix FIH int conversion for security_cnt - e6e4801 zephyr/boot_serial_extension: Fix zcbor header path - a5db515 bootutil/crypto: SHA256 abort function return state - 0361ad3 bootutil/crypto: SHA256 init functions should return a status - f92a219 bootutil/crypto: Fix minor typos in comments for RSA modules - 4854700 bootutil: Add image_index to additional logging messages - 2f85b7e bootutil/crypto: Fix the common.h header - c321a70 bootutil/crypto: Add a crypto backend for SHA256 based on PSA Crypto APIs - 02bf072 bootutil/crypto: Refactor the RSA signature verification and encryption - ba5fb1c bootutil: Add image_index to common prints Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 96d21ca78aa7..71bffe732c67 100644 --- a/west.yml +++ b/west.yml @@ -271,7 +271,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 74c4d1c52fd51d07904b27a7aa9b2303e896a4e3 + revision: 6a8746d7acd75ff81fb6888d7776f412663f7897 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 368b0e0d16bfaa9bc833c76fbd7945cf5eabcbb3 Mon Sep 17 00:00:00 2001 From: Manoel Brunnen Date: Mon, 10 Jul 2023 12:15:55 +0200 Subject: [PATCH 1078/2042] twister: Initialise unbound 'hardware' variable hardware was referenced as return value, without being declared. When the program goes into the 'except' path, hardware is unbound, but returned, which throws an error: `UnboundLocalError`: local variable 'hardware' referenced before assignment Signed-off-by: Manoel Brunnen --- scripts/pylib/twister/twisterlib/handlers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 5af283cbfc4f..9a74cc2cb5c4 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -452,6 +452,7 @@ def run_custom_script(script, timeout): logger.error("{} timed out".format(script)) def get_hardware(self): + hardware = None try: hardware = self.device_is_available(self.instance) while not hardware: From db22c3bc7b1b7d97ba8a9c9a6914eabed0f309d7 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 7 Jul 2023 21:03:39 +0000 Subject: [PATCH 1079/2042] shields: lmp90100: drop GPIO and EEPROM priority override Drop the GPIO and EEPROM priority override. The current settings have been introduced as part of a major priority refactoring but I don't think they are needed anymore, and they currently result in this error: ERROR: /soc/spi@4002d000 POST_KERNEL 70 < /soc/gpio@400ff100 POST_KERNEL 99 found with: west build -p -b frdm_k64f samples/shields/lmp90100_evb/rtd \ -DCONFIG_CHECK_INIT_PRIORITIES=y Dropping the two overrides should work fine, leaving the ADC override as that seems like is still needed. Signed-off-by: Fabio Baltieri --- boards/shields/lmp90100_evb/Kconfig.defconfig | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/boards/shields/lmp90100_evb/Kconfig.defconfig b/boards/shields/lmp90100_evb/Kconfig.defconfig index 6f7417ff8d0c..0dc0b0c68264 100644 --- a/boards/shields/lmp90100_evb/Kconfig.defconfig +++ b/boards/shields/lmp90100_evb/Kconfig.defconfig @@ -13,18 +13,4 @@ config ADC_INIT_PRIORITY endif # ADC -if GPIO - -config GPIO_INIT_PRIORITY - default 99 - -endif # GPIO - -if EEPROM - -config EEPROM_INIT_PRIORITY - default 75 - -endif # EEPROM - endif # SHIELD_LMP90100_EVB From 0038620b372b6f6b1f35cda2a7ed9d839461eecf Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Fri, 7 Jul 2023 17:53:20 +0200 Subject: [PATCH 1080/2042] soc: xtensa: disable SPIRAM when MCUBOOT Some boards has ESP_SPIRAM enabled by default, which is causing issues when MCUboot is used as 2nd bootloader. Signed-off-by: Marek Matej --- soc/xtensa/esp32/Kconfig.soc | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/esp32/Kconfig.soc index 56949f965992..e6f5a3de42eb 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/esp32/Kconfig.soc @@ -56,6 +56,7 @@ config ESP_HEAP_MEM_POOL_REGION_1_SIZE config ESP_SPIRAM bool "Support for external, SPI-connected RAM" + default n if MCUBOOT help This enables support for an external SPI RAM chip, connected in parallel with the main SPI flash chip. From 490281a1d0d2b6e2118752bf369dbbd61e61680a Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Fri, 7 Jul 2023 12:22:39 +0200 Subject: [PATCH 1081/2042] drivers: adc: fix missing ref_internal in iadc_gecko The adc_driver_api structure provides .ref_internal which previously was unset. Now .ref_internal is set to the proper value. Signed-off-by: Wojciech Sipak --- drivers/adc/iadc_gecko.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/adc/iadc_gecko.c b/drivers/adc/iadc_gecko.c index 73e61ccad6bb..0b9fcb07c8c0 100644 --- a/drivers/adc/iadc_gecko.c +++ b/drivers/adc/iadc_gecko.c @@ -19,6 +19,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 struct adc_gecko_channel_config { IADC_CfgAnalogGain_t gain; @@ -457,6 +458,7 @@ static const struct adc_driver_api api_gecko_adc_driver_api = { #ifdef CONFIG_ADC_ASYNC .read_async = adc_gecko_read_async, #endif + .ref_internal = GECKO_INTERNAL_REFERENCE_mV, }; #define GECKO_IADC_INIT(n) \ From 021923b58a693adf6f626e6c8b106ba9990e9732 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 5 Jul 2023 17:25:52 -0700 Subject: [PATCH 1082/2042] libc/picolibc: Use mutexes instead of semaphores for non-recursive locks Picolibc has both recursive and non-recursive mutex uses. The bulk of the library locking uses the global libc lock, which is a recursive mutex as that greatly simplifies the implementation. The only use of non-recursive mutexes is in the stdio code when dealing with file system I/O via fopen. Using mutexes for both APIs is valid; the assumption picolibc makes is that the non-recursive mutexes are somehow cheaper or faster and should be preferred. However, in Zephyr, recursive mutexes are the default and the non-recursive locks for picolibc were implemented using semaphores. Switch the non-recursive picolibc locks to just invoking the existing recursive functions using mutexes. This avoids pulling in another lock implementation, saving a bit of space. This also lets the kernel.memory_protection.mem_map test work on qemu_x86_tiny where the amount of memory available is 320kB and that is nearly filled by this test case, leaving too little space for allocating pages in the k_mem_map_unmap test. Signed-off-by: Keith Packard --- lib/libc/picolibc/libc-hooks.c | 54 ++++++++++++---------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/lib/libc/picolibc/libc-hooks.c b/lib/libc/picolibc/libc-hooks.c index 33ac8f2f0653..5ad9c2c1f22c 100644 --- a/lib/libc/picolibc/libc-hooks.c +++ b/lib/libc/picolibc/libc-hooks.c @@ -154,22 +154,6 @@ SYS_INIT(picolibc_locks_prepare, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif /* CONFIG_USERSPACE */ -/* Create a new dynamic non-recursive lock */ -void __retarget_lock_init(_LOCK_T *lock) -{ - __ASSERT_NO_MSG(lock != NULL); - - /* Allocate semaphore object */ -#ifndef CONFIG_USERSPACE - *lock = malloc(sizeof(struct k_sem)); -#else - *lock = k_object_alloc(K_OBJ_SEM); -#endif /* !CONFIG_USERSPACE */ - __ASSERT(*lock != NULL, "non-recursive lock allocation failed"); - - k_sem_init((struct k_sem *)*lock, 1, 1); -} - /* Create a new dynamic recursive lock */ void __retarget_lock_init_recursive(_LOCK_T *lock) { @@ -186,15 +170,10 @@ void __retarget_lock_init_recursive(_LOCK_T *lock) k_mutex_init((struct k_mutex *)*lock); } -/* Close dynamic non-recursive lock */ -void __retarget_lock_close(_LOCK_T lock) +/* Create a new dynamic non-recursive lock */ +void __retarget_lock_init(_LOCK_T *lock) { - __ASSERT_NO_MSG(lock != NULL); -#ifndef CONFIG_USERSPACE - free(lock); -#else - k_object_release(lock); -#endif /* !CONFIG_USERSPACE */ + __retarget_lock_init_recursive(lock); } /* Close dynamic recursive lock */ @@ -208,11 +187,10 @@ void __retarget_lock_close_recursive(_LOCK_T lock) #endif /* !CONFIG_USERSPACE */ } -/* Acquiure non-recursive lock */ -void __retarget_lock_acquire(_LOCK_T lock) +/* Close dynamic non-recursive lock */ +void __retarget_lock_close(_LOCK_T lock) { - __ASSERT_NO_MSG(lock != NULL); - k_sem_take((struct k_sem *)lock, K_FOREVER); + __retarget_lock_close_recursive(lock); } /* Acquiure recursive lock */ @@ -222,11 +200,10 @@ void __retarget_lock_acquire_recursive(_LOCK_T lock) k_mutex_lock((struct k_mutex *)lock, K_FOREVER); } -/* Try acquiring non-recursive lock */ -int __retarget_lock_try_acquire(_LOCK_T lock) +/* Acquiure non-recursive lock */ +void __retarget_lock_acquire(_LOCK_T lock) { - __ASSERT_NO_MSG(lock != NULL); - return !k_sem_take((struct k_sem *)lock, K_NO_WAIT); + __retarget_lock_acquire_recursive(lock); } /* Try acquiring recursive lock */ @@ -236,11 +213,10 @@ int __retarget_lock_try_acquire_recursive(_LOCK_T lock) return !k_mutex_lock((struct k_mutex *)lock, K_NO_WAIT); } -/* Release non-recursive lock */ -void __retarget_lock_release(_LOCK_T lock) +/* Try acquiring non-recursive lock */ +int __retarget_lock_try_acquire(_LOCK_T lock) { - __ASSERT_NO_MSG(lock != NULL); - k_sem_give((struct k_sem *)lock); + return __retarget_lock_try_acquire_recursive(lock); } /* Release recursive lock */ @@ -250,6 +226,12 @@ void __retarget_lock_release_recursive(_LOCK_T lock) k_mutex_unlock((struct k_mutex *)lock); } +/* Release non-recursive lock */ +void __retarget_lock_release(_LOCK_T lock) +{ + __retarget_lock_release_recursive(lock); +} + #endif /* CONFIG_MULTITHREADING */ /* This function gets called if static buffer overflow detection is enabled on From 40bc3ec346832a2f761891823365bbd5bc56b58d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 5 Jul 2023 17:40:54 -0700 Subject: [PATCH 1083/2042] subsys/net: Increase management stack size for thread local storage The management thread *barely* fits in 768 bytes of stack; when thread local storage is in use and TLS variables are also allocated from the same region, this stack can overflow. Increase to 800 bytes to leave plenty of room for TLS variables. Signed-off-by: Keith Packard --- subsys/net/ip/Kconfig.mgmt | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/net/ip/Kconfig.mgmt b/subsys/net/ip/Kconfig.mgmt index 281d38c7a488..bb5c9ccc1865 100644 --- a/subsys/net/ip/Kconfig.mgmt +++ b/subsys/net/ip/Kconfig.mgmt @@ -22,6 +22,7 @@ if NET_MGMT_EVENT config NET_MGMT_EVENT_STACK_SIZE int "Stack size for the inner thread handling event callbacks" default 2048 if COVERAGE_GCOV + default 800 if THREAD_LOCAL_STORAGE default 768 help Set the internal stack size for NM to run registered callbacks From 39391b4a160a4e23a2b7f213f94cf04b2c250ad7 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Tue, 4 Jul 2023 13:28:33 +0200 Subject: [PATCH 1084/2042] drivers: spi: replace timeout for STM32 DMA slave mode Replace the timeout for a SPI transceive in slave mode for STM32 DMA operations with a K_FOREVER. Being an SPI slave means we do not know when the transaction will start, hence it does not make sense to have a timeout in such a case. This will resolve issue #60000. Signed-off-by: Benedikt Schmidt --- drivers/spi/spi_ll_stm32.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 418a635589be..8590cc6fd580 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -693,9 +693,20 @@ static int wait_dma_rx_tx_done(const struct device *dev) { struct spi_stm32_data *data = dev->data; int res = -1; + k_timeout_t timeout; + + /* + * In slave mode we do not know when the transaction will start. Hence, + * it doesn't make sense to have timeout in this case. + */ + if (IS_ENABLED(CONFIG_SPI_SLAVE) && spi_context_is_slave(&data->ctx)) { + timeout = K_FOREVER; + } else { + timeout = K_MSEC(1000); + } while (1) { - res = k_sem_take(&data->status_sem, K_MSEC(1000)); + res = k_sem_take(&data->status_sem, timeout); if (res != 0) { return res; } From b6f27cda4cd3638207fa56696757a78242a50c0f Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 3 Jul 2023 17:32:06 +0200 Subject: [PATCH 1085/2042] dts: arm: stm32h5 serie has a full-speed USB 2.0 bus Introduce the stm32H5 USB node for the stm32H5 serie Signed-off-by: Francois Ramu --- dts/arm/st/h5/stm32h5.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index d0388f2ec80e..ef617b46b443 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -495,6 +495,19 @@ dma-offset = <8>; status = "disabled"; }; + + usb: usb@40016000 { + compatible = "st,stm32-usb"; + reg = <0x40016000 0x400>; + interrupts = <74 0>; + interrupt-names = "usb"; + num-bidir-endpoints = <8>; + ram-size = <2048>; + phys = <&usb_fs_phy>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x01000000>, + <&rcc STM32_SRC_HSI48 USB_SEL(3)>; + status = "disabled"; + }; }; die_temp: dietemp { @@ -523,6 +536,11 @@ io-channels = <&adc1 2>; status = "disabled"; }; + + usb_fs_phy: usbphy { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; }; &nvic { From 036c8f6697214860518db8728d9a6a464256d040 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 3 Jul 2023 17:33:20 +0200 Subject: [PATCH 1086/2042] boards: arm: stm32h563 nucleo board with USB bus Enables the USB bus on PA11/PA12 of the nucleo_stm32h563 board Signed-off-by: Francois Ramu --- boards/arm/nucleo_h563zi/doc/index.rst | 2 ++ boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi | 6 ++++++ boards/arm/nucleo_h563zi/nucleo_h563zi.yaml | 2 ++ 3 files changed, 10 insertions(+) diff --git a/boards/arm/nucleo_h563zi/doc/index.rst b/boards/arm/nucleo_h563zi/doc/index.rst index 1c1acf62e0e1..6ed79d8c7b96 100644 --- a/boards/arm/nucleo_h563zi/doc/index.rst +++ b/boards/arm/nucleo_h563zi/doc/index.rst @@ -173,6 +173,8 @@ The Zephyr nucleo_h563zi board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | WATCHDOG | on-chip | independent watchdog | +-----------+------------+-------------------------------------+ +| USB | on-chip | USB full-speed host/device bus | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi b/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi index 6c9c9efec8dc..6b72080177d5 100644 --- a/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi +++ b/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi @@ -166,6 +166,12 @@ }; }; +zephyr_udc0: &usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + &vref { status = "okay"; }; diff --git a/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml b/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml index 39ce37e4f771..1798cf41e595 100644 --- a/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml +++ b/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml @@ -19,3 +19,5 @@ supported: - pwm - counter - spi + - usb_device + - usb From 8a603b2fbfaa8c04af7b935b38d2db5f98e88f50 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 4 Jul 2023 10:51:08 +0200 Subject: [PATCH 1087/2042] boards: arm: stm32h573 disco kit board with USB bus Enables the USB bus on PA11/PA12 of the stm32h573i_dk board Signed-off-by: Francois Ramu --- boards/arm/stm32h573i_dk/doc/index.rst | 2 ++ boards/arm/stm32h573i_dk/stm32h573i_dk.dts | 6 ++++++ boards/arm/stm32h573i_dk/stm32h573i_dk.yaml | 2 ++ 3 files changed, 10 insertions(+) diff --git a/boards/arm/stm32h573i_dk/doc/index.rst b/boards/arm/stm32h573i_dk/doc/index.rst index b179f5867114..f7806f52dde2 100644 --- a/boards/arm/stm32h573i_dk/doc/index.rst +++ b/boards/arm/stm32h573i_dk/doc/index.rst @@ -191,6 +191,8 @@ hardware features: +-----------+------------+-------------------------------------+ | AES | on-chip | crypto | +-----------+------------+-------------------------------------+ +| USB | on-chip | USB full-speed host/device bus | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/arm/stm32h573i_dk/stm32h573i_dk.dts b/boards/arm/stm32h573i_dk/stm32h573i_dk.dts index 64fe87fa2f52..2b0041f3f680 100644 --- a/boards/arm/stm32h573i_dk/stm32h573i_dk.dts +++ b/boards/arm/stm32h573i_dk/stm32h573i_dk.dts @@ -244,6 +244,12 @@ }; }; +zephyr_udc0: &usb { + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + &die_temp { status = "okay"; }; diff --git a/boards/arm/stm32h573i_dk/stm32h573i_dk.yaml b/boards/arm/stm32h573i_dk/stm32h573i_dk.yaml index 9b014f5ed639..e7ed5b5d3cb5 100644 --- a/boards/arm/stm32h573i_dk/stm32h573i_dk.yaml +++ b/boards/arm/stm32h573i_dk/stm32h573i_dk.yaml @@ -20,3 +20,5 @@ supported: - spi - octospi - can + - usb_device + - usb From 2789e6a3c060cbf165c1048dc845040b413a2e2a Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Mon, 3 Jul 2023 16:12:20 +1200 Subject: [PATCH 1088/2042] soc: esp32s3: add TWAI driver configuration Add TWAI configuration for CAN. Signed-off-by: Eric Holmberg --- dts/xtensa/espressif/esp32s3.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dts/xtensa/espressif/esp32s3.dtsi b/dts/xtensa/espressif/esp32s3.dtsi index ca74f4f08201..6c2337a2a5e7 100644 --- a/dts/xtensa/espressif/esp32s3.dtsi +++ b/dts/xtensa/espressif/esp32s3.dtsi @@ -13,6 +13,7 @@ / { chosen { + zephyr,canbus = &twai; zephyr,entropy = &trng0; zephyr,flash-controller = &flash; }; @@ -201,6 +202,17 @@ status = "disabled"; }; + twai: can@6002b000 { + compatible = "espressif,esp32-twai"; + reg = <0x6002b000 DT_SIZE_K(4)>; + interrupts = ; + interrupt-parent = <&intc>; + clocks = <&rtc ESP32_TWAI_MODULE>; + sjw = <1>; + sample-point = <875>; + status = "disabled"; + }; + usb_serial: uart@60038000 { compatible = "espressif,esp32-usb-serial"; reg = <0x60038000 DT_SIZE_K(4)>; From 1b919bbc2871070f4f5ff24c87a3e7873ea25561 Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Thu, 6 Jul 2023 18:06:40 +1200 Subject: [PATCH 1089/2042] tests: drivers: can: api: add virtual CAN TX <-> RX Jumper Remove the need for the can_transceiver fixture by assigning the CAN TX and CAN RX lines to the same GPIO pin to allow for testing without a transceiver or physical jumper. Signed-off-by: Eric Holmberg --- tests/drivers/can/api/testcase.yaml | 4 ---- tests/drivers/can/api/twai-enable.overlay | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index ee240f81a47d..b2536dabed86 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -10,9 +10,5 @@ tests: - drivers - can extra_args: DTC_OVERLAY_FILE=twai-enable.overlay - harness: console - harness_config: - # actual CAN transceiver or shorted CAN RX/TX pins required for board testing - fixture: can_transceiver filter: dt_compat_enabled("espressif,esp32-twai") platform_allow: esp32c3_devkitm diff --git a/tests/drivers/can/api/twai-enable.overlay b/tests/drivers/can/api/twai-enable.overlay index 8ec3077d832e..c98aba18376d 100644 --- a/tests/drivers/can/api/twai-enable.overlay +++ b/tests/drivers/can/api/twai-enable.overlay @@ -4,6 +4,27 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Enable CAN bus */ &twai { - status = "okay"; + status = "okay"; + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; + + can-transceiver { + max-bitrate = <1000000>; + }; +}; + +&pinctrl { + twai_default: twai_default { + group1 { + pinmux = ; + output-enable; /* enable internal loopback */ + }; + group2 { + pinmux = ; + input-enable; /* enable internal loopback */ + }; +}; }; From e408d0ea065068f8f9e4154efeb03a39ef144a88 Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Mon, 3 Jul 2023 20:35:44 +1200 Subject: [PATCH 1090/2042] boards: esp32s3_devkitm: update CAN support Add CAN to supported list and update documentation. Signed-off-by: Eric Holmberg --- boards/xtensa/esp32s3_devkitm/doc/index.rst | 2 ++ boards/xtensa/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi | 7 +++++++ boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts | 6 ++++++ boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml | 1 + tests/drivers/can/api/testcase.yaml | 2 +- 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/boards/xtensa/esp32s3_devkitm/doc/index.rst b/boards/xtensa/esp32s3_devkitm/doc/index.rst index 6236b8fd745e..b0549cb5d3a0 100644 --- a/boards/xtensa/esp32s3_devkitm/doc/index.rst +++ b/boards/xtensa/esp32s3_devkitm/doc/index.rst @@ -92,6 +92,8 @@ Current Zephyr's ESP32-S3-DevKitM board supports the following features: +------------+------------+-------------------------------------+ | SPI Master | on-chip | spi | +------------+------------+-------------------------------------+ +| TWAI/CAN | on-chip | can | ++------------+------------+-------------------------------------+ | Timers | on-chip | counter | +------------+------------+-------------------------------------+ | Watchdog | on-chip | watchdog | diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi index a11f60a023de..34fa6e920c66 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi @@ -63,4 +63,11 @@ output-low; }; }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index 253821bea327..f61034c2d1b7 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -93,6 +93,12 @@ pinctrl-names = "default"; }; +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; +}; + &timer0 { status = "disabled"; }; diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml index 7c9af9dc6f54..b44b2ec93573 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml @@ -9,6 +9,7 @@ supported: - uart - i2c - spi + - can - counter - watchdog - entropy diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index b2536dabed86..16872321671b 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -11,4 +11,4 @@ tests: - can extra_args: DTC_OVERLAY_FILE=twai-enable.overlay filter: dt_compat_enabled("espressif,esp32-twai") - platform_allow: esp32c3_devkitm + platform_allow: esp32c3_devkitm esp32s3_devkitm From 4f88b831e7a70bd6278efe8f0a711b06485fe6be Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Mon, 3 Jul 2023 20:50:28 +1200 Subject: [PATCH 1091/2042] boards: xiao_esp32s3: update CAN support Add CAN to supported list and update documentation. Signed-off-by: Eric Holmberg --- boards/xtensa/xiao_esp32s3/doc/index.rst | 2 ++ boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi | 7 +++++++ boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts | 6 ++++++ boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml | 1 + tests/drivers/can/api/testcase.yaml | 2 +- 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/boards/xtensa/xiao_esp32s3/doc/index.rst b/boards/xtensa/xiao_esp32s3/doc/index.rst index 1f12763646b0..e070b7138c4b 100644 --- a/boards/xtensa/xiao_esp32s3/doc/index.rst +++ b/boards/xtensa/xiao_esp32s3/doc/index.rst @@ -49,6 +49,8 @@ Current Zephyr's XIAO ESP32S3 board supports the following features: +------------+------------+-------------------------------------+ | SPI Master | on-chip | spi | +------------+------------+-------------------------------------+ +| TWAI/CAN | on-chip | can | ++------------+------------+-------------------------------------+ | Timers | on-chip | counter | +------------+------------+-------------------------------------+ | Watchdog | on-chip | watchdog | diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi b/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi index 3f9343d846ef..27097b6bb260 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi @@ -40,4 +40,11 @@ output-high; }; }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index 667cabab6ed9..79e29602f0d1 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -83,6 +83,12 @@ status = "okay"; }; +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; +}; + &timer0 { status = "okay"; }; diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml index 129b25ed8ded..c5d8fec4b14d 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml @@ -9,6 +9,7 @@ supported: - uart - i2c - spi + - can - counter - watchdog - entropy diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index 16872321671b..e5c666fa40a1 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -11,4 +11,4 @@ tests: - can extra_args: DTC_OVERLAY_FILE=twai-enable.overlay filter: dt_compat_enabled("espressif,esp32-twai") - platform_allow: esp32c3_devkitm esp32s3_devkitm + platform_allow: esp32c3_devkitm esp32s3_devkitm xiao_esp32s3 From b6af1ac66efe9026a7d9abeb5a06ce72f2cba5d4 Mon Sep 17 00:00:00 2001 From: Ambroise Vincent Date: Mon, 19 Jun 2023 08:59:37 +0100 Subject: [PATCH 1092/2042] drivers: eth_smsc91x: Implement promiscuous mode Add the RCR_PRMS field to toggle the promiscuous mode in the Ethernet controller. Register a set_config function that can make use of the field when CONFIG_NET_PROMISCUOUS_MODE is enabled. Signed-off-by: Ambroise Vincent --- drivers/ethernet/eth_smsc91x.c | 48 +++++++++++++++++++++++++++-- drivers/ethernet/eth_smsc91x_priv.h | 1 + 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/ethernet/eth_smsc91x.c b/drivers/ethernet/eth_smsc91x.c index c82d9752684f..b36cd5fe969c 100644 --- a/drivers/ethernet/eth_smsc91x.c +++ b/drivers/ethernet/eth_smsc91x.c @@ -678,7 +678,12 @@ static enum ethernet_hw_caps eth_smsc_get_caps(const struct device *dev) { ARG_UNUSED(dev); - return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T; + return (ETHERNET_LINK_10BASE_T + | ETHERNET_LINK_100BASE_T +#if defined(CONFIG_NET_PROMISCUOUS_MODE) + | ETHERNET_PROMISC_MODE +#endif + ); } static int eth_tx(const struct device *dev, struct net_pkt *pkt) @@ -696,6 +701,42 @@ static int eth_tx(const struct device *dev, struct net_pkt *pkt) return smsc_send_pkt(sc, tx_buffer, len); } +static int eth_smsc_set_config(const struct device *dev, + enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct eth_context *data = dev->data; + struct smsc_data *sc = &data->sc; + uint8_t reg_val; + int ret = 0; + + (void) reg_val; + + switch (type) { +#if defined(CONFIG_NET_PROMISCUOUS_MODE) + case ETHERNET_CONFIG_TYPE_PROMISC_MODE: + SMSC_LOCK(sc); + smsc_select_bank(sc, 0); + reg_val = smsc_read_1(sc, RCR); + if (config->promisc_mode && !(reg_val & RCR_PRMS)) { + smsc_write_1(sc, RCR, reg_val | RCR_PRMS); + } else if (!config->promisc_mode && (reg_val & RCR_PRMS)) { + smsc_write_1(sc, RCR, reg_val & ~RCR_PRMS); + } else { + ret = -EALREADY; + } + SMSC_UNLOCK(sc); + break; +#endif + + default: + ret = -ENOTSUP; + break; + } + + return ret; +} + static void eth_initialize(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); @@ -725,9 +766,10 @@ static void eth_initialize(struct net_if *iface) } static const struct ethernet_api api_funcs = { - .iface_api.init = eth_initialize, + .iface_api.init = eth_initialize, .get_capabilities = eth_smsc_get_caps, - .send = eth_tx, + .set_config = eth_smsc_set_config, + .send = eth_tx, }; static void eth_smsc_isr(const struct device *dev) diff --git a/drivers/ethernet/eth_smsc91x_priv.h b/drivers/ethernet/eth_smsc91x_priv.h index ccb7d54c05c4..330948abf142 100644 --- a/drivers/ethernet/eth_smsc91x_priv.h +++ b/drivers/ethernet/eth_smsc91x_priv.h @@ -25,6 +25,7 @@ /* Bank 0, Offset 0x4: Receive Control Register */ #define RCR 0x4 +#define RCR_PRMS 0x0002 /* Promiscuous mode */ #define RCR_RXEN 0x0100 /* Enable/disable receiver */ #define RCR_STRIP_CRC 0x0200 /* Strip CRC from RX packets */ #define RCR_SOFT_RST 0x8000 /* Software reset */ From 55442c15c23c88d41c69b6ab7c3aa48de802097c Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 23 Jun 2023 10:34:07 +0200 Subject: [PATCH 1093/2042] manifest: update LVGL to v8.3.7 Related to zephyrproject-rtos/lvgl#41 Signed-off-by: Fabian Blatz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 71bffe732c67..cb7a8ea616a1 100644 --- a/west.yml +++ b/west.yml @@ -260,7 +260,7 @@ manifest: revision: ce57712f3e426bbbb13acaec97b45369f716f43a path: modules/lib/loramac-node - name: lvgl - revision: 7102083f626cda09e5792420ea60af0525cce9ae + revision: f7cf01d413aa9e76f376e25aa7b5c08dfdbc3c24 path: modules/lib/gui/lvgl - name: lz4 revision: 8e303c264fc21c2116dc612658003a22e933124d From ec46da444ecaa28eaf377917ea69207dd3752bf7 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Mon, 26 Jun 2023 11:11:17 +0200 Subject: [PATCH 1094/2042] tests: lib: gui: lvgl: Reorder screen load and delete Load the default screen before the deleting the newly created one. This used to work in LVGL 8.2.0 but was not intended according to the discussion in https://github.com/zephyrproject-rtos/zephyr/pull/53974. Signed-off-by: Fabian Blatz --- tests/lib/gui/lvgl/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/gui/lvgl/src/main.c b/tests/lib/gui/lvgl/src/main.c index c7dc00827973..5b32e97ed3c2 100644 --- a/tests/lib/gui/lvgl/src/main.c +++ b/tests/lib/gui/lvgl/src/main.c @@ -51,10 +51,10 @@ ZTEST(lvgl_screen, test_add_delete_screen) zassert_equal_ptr(act_screen, new_screen, "New screen not active"); - lv_obj_del(new_screen); - lv_scr_load(default_screen); + lv_obj_del(new_screen); + lv_task_handler(); act_screen = lv_scr_act(); From c81f8d7721cf7f5cf7ac8fe5dd7e4e09e01422bb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 10 Jul 2023 11:52:04 +0100 Subject: [PATCH 1095/2042] doc: mgmt: mcumgr: Fix double maps Fixes an issue where double maps were shown for some items, and one whereby there was excess text. Signed-off-by: Jamie McCrae --- .../device_mgmt/smp_groups/smp_group_1.rst | 24 +++++++------------ .../device_mgmt/smp_groups/smp_group_8.rst | 1 - 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_1.rst b/doc/services/device_mgmt/smp_groups/smp_group_1.rst index 482361178c69..61622ee71b2e 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_1.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_1.rst @@ -223,10 +223,8 @@ CBOR data of request: .. code-block:: none { - { - (str,opt)"hash" : (str) - (str)"confirm" : (bool) - } + (str,opt)"hash" : (str) + (str)"confirm" : (bool) } If "confirm" is false or not provided, an image with the "hash" will be set for @@ -267,14 +265,12 @@ CBOR data of request: .. code-block:: none { - { - (str,opt)"image" : (uint) - (str,opt)"len" : (uint) - (str)"off" : (uint) - (str,opt)"sha" : (byte str) - (str,opt)"data" : (byte str) - (str,opt)"upgrade" : (bool) - } + (str,opt)"image" : (uint) + (str,opt)"len" : (uint) + (str)"off" : (uint) + (str,opt)"sha" : (byte str) + (str,opt)"data" : (byte str) + (str,opt)"upgrade" : (bool) } where: @@ -412,9 +408,7 @@ CBOR data of request: .. code-block:: none { - { - (str,opt)"slot" : (uint) - } + (str,opt)"slot" : (uint) } where: diff --git a/doc/services/device_mgmt/smp_groups/smp_group_8.rst b/doc/services/device_mgmt/smp_groups/smp_group_8.rst index 3ed8add1cc8d..d86208346f85 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_8.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_8.rst @@ -511,7 +511,6 @@ CBOR data of successful response: .. code-block:: none - format (0 = int, 1 = byte array) { (str)"types" : { (str) : { From 3764814831a7e3b4b47c56afa3c08512ef41d82e Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Fri, 10 Feb 2023 13:46:20 +0100 Subject: [PATCH 1096/2042] intel_adsp: boot: d3: hp sram reinit Adding HP SRAM initialization in D3 power state exit procedure. Signed-off-by: Tomasz Leman --- soc/xtensa/intel_adsp/ace/boot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soc/xtensa/intel_adsp/ace/boot.c b/soc/xtensa/intel_adsp/ace/boot.c index 7fc829ea3b4f..a27491d64818 100644 --- a/soc/xtensa/intel_adsp/ace/boot.c +++ b/soc/xtensa/intel_adsp/ace/boot.c @@ -48,6 +48,8 @@ __imr void boot_d3_restore(void) /* reset memory hole */ CAVS_SHIM.l2mecs = 0; #endif + extern void hp_sram_init(uint32_t memory_size); + hp_sram_init(L2_SRAM_SIZE); extern void lp_sram_init(void); lp_sram_init(); From 25c6553edde5faab3565165c27d9c1da94a081f9 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 26 Jun 2023 10:26:48 -0700 Subject: [PATCH 1097/2042] soc: intel_adsp/ace: use functions to do CPU power control Instead of relying on direct memory access via structs to control CPU power and status, using inline functions instead to hide the details. This makes reading the common code a bit cleaner. The function names are generic and not architecture or platform specific, in an attempt to ease future arch or platform additions with code reuse. Or else we would need to rename these. Signed-off-by: Daniel Leung --- .../ace/include/intel_ace15_mtpm/adsp_power.h | 46 +++++++++++++++++++ .../ace/include/intel_ace20_lnl/adsp_power.h | 46 +++++++++++++++++++ soc/xtensa/intel_adsp/ace/multiprocessing.c | 6 +-- soc/xtensa/intel_adsp/ace/power.c | 6 +-- 4 files changed, 98 insertions(+), 6 deletions(-) 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 b16d64bb653e..6efcde4a4913 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 @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include +#include #include #ifndef ZEPHYR_SOC_INTEL_ADSP_POWER_H_ @@ -43,4 +46,47 @@ struct ace_pwrsts { #define ACE_PWRSTS ((volatile struct ace_pwrsts *) &ACE_DfPMCCU.dfpwrsts) +/** + * @brief Power up a specific CPU. + * + * This sets the "not power gating" bit in the power control + * register to disable power gating to CPU, thus powering up + * the CPU. + * + * @param cpu_num CPU to be powered up. + */ +static ALWAYS_INLINE void soc_cpu_power_up(int cpu_num) +{ + ACE_PWRCTL->wpdsphpxpg |= BIT(cpu_num); +} + +/** + * @brief Power down a specific CPU. + * + * This clears the "not power gating" bit in the power control + * register to enable power gating to CPU, thus powering down + * the CPU. + * + * @param cpu_num CPU to be powered down. + */ +static ALWAYS_INLINE void soc_cpu_power_down(int cpu_num) +{ + ACE_PWRCTL->wpdsphpxpg &= ~BIT(cpu_num); +} + +/** + * @brief Test if a CPU is currently powered. + * + * This queries the power status register to see if the CPU + * is currently powered. + * + * @param cpu_num CPU to be queried. + * @return True if CPU is powered, false if now. + */ +static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) +{ + return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); +} + + #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 9210a0a7f835..60631945da30 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 @@ -6,6 +6,10 @@ #ifndef ZEPHYR_SOC_INTEL_ADSP_POWER_H_ #define ZEPHYR_SOC_INTEL_ADSP_POWER_H_ +#include +#include +#include + /* Value used as delay when waiting for hw register state change. */ #define HW_STATE_CHECK_DELAY 64 @@ -42,4 +46,46 @@ struct ace_pwrsts { #define ACE_PWRSTS ((volatile struct ace_pwrsts *)PWRSTS_REG) +/** + * @brief Power up a specific CPU. + * + * This sets the "not power gating" bit in the power control + * register to disable power gating to CPU, thus powering up + * the CPU. + * + * @param cpu_num CPU to be powered up. + */ +static ALWAYS_INLINE void soc_cpu_power_up(int cpu_num) +{ + ACE_PWRCTL->wpdsphpxpg |= BIT(cpu_num); +} + +/** + * @brief Power down a specific CPU. + * + * This clears the "not power gating" bit in the power control + * register to enable power gating to CPU, thus powering down + * the CPU. + * + * @param cpu_num CPU to be powered down. + */ +static ALWAYS_INLINE void soc_cpu_power_down(int cpu_num) +{ + ACE_PWRCTL->wpdsphpxpg &= ~BIT(cpu_num); +} + +/** + * @brief Test if a CPU is currently powered. + * + * This queries the power status register to see if the CPU + * is currently powered. + * + * @param cpu_num CPU to be queried. + * @return True if CPU is powered, false if now. + */ +static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) +{ + return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); +} + #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 51901d3d9c80..94558c2ca755 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -115,9 +115,9 @@ void soc_start_core(int cpu_num) #endif sys_cache_data_flush_range(rom_jump_vector, sizeof(*rom_jump_vector)); - ACE_PWRCTL->wpdsphpxpg |= BIT(cpu_num); + soc_cpu_power_up(cpu_num); - while ((ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == 0) { + while (!soc_cpu_is_powered(cpu_num)) { k_busy_wait(HW_STATE_CHECK_DELAY); } @@ -205,7 +205,7 @@ int soc_adsp_halt_cpu(int id) return -EINVAL; } - ACE_PWRCTL->wpdsphpxpg &= ~BIT(id); + soc_cpu_power_down(id); return 0; } #endif diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 9ac30bfc4cc6..518e0808d3c3 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -294,7 +294,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } else if (state == PM_STATE_RUNTIME_IDLE) { DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPPG; DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG; - ACE_PWRCTL->wpdsphpxpg &= ~BIT(cpu); + soc_cpu_power_down(cpu); if (cpu == 0) { uint32_t battr = DSPCS.bootctl[cpu].battr & (~LPSCTL_BATTR_MASK); @@ -346,9 +346,9 @@ __weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) return; } - ACE_PWRCTL->wpdsphpxpg |= BIT(cpu); + soc_cpu_power_up(cpu); - while ((ACE_PWRSTS->dsphpxpgs & BIT(cpu)) == 0) { + while (!soc_cpu_is_powered(cpu)) { k_busy_wait(HW_STATE_CHECK_DELAY); } From 54155df0c866649139b694bb21bf7c593d8e166b Mon Sep 17 00:00:00 2001 From: Ben Marsh Date: Sat, 3 Jun 2023 11:17:50 +0100 Subject: [PATCH 1098/2042] sys: util: Improve ROUND_UP and ROUND_DOWN macros Improve utility macros ROUND_UP and ROUND_DOWN to work with alignments that are not a power of 2. Signed-off-by: Ben Marsh --- include/zephyr/sys/util.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index 9cd470798202..d8a63a25e9da 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -225,19 +225,17 @@ extern "C" { ((type *)(((char *)(ptr)) - offsetof(type, field))) /** - * @brief Value of @p x rounded up to the next multiple of @p align, - * which must be a power of 2. + * @brief Value of @p x rounded up to the next multiple of @p align. */ #define ROUND_UP(x, align) \ - (((unsigned long)(x) + ((unsigned long)(align) - 1)) & \ - ~((unsigned long)(align) - 1)) + ((((unsigned long)(x) + ((unsigned long)(align) - 1)) / \ + (unsigned long)(align)) * (unsigned long)(align)) /** - * @brief Value of @p x rounded down to the previous multiple of @p - * align, which must be a power of 2. + * @brief Value of @p x rounded down to the previous multiple of @p align. */ #define ROUND_DOWN(x, align) \ - ((unsigned long)(x) & ~((unsigned long)(align) - 1)) + (((unsigned long)(x) / (unsigned long)(align)) * (unsigned long)(align)) /** @brief Value of @p x rounded up to the next word boundary. */ #define WB_UP(x) ROUND_UP(x, sizeof(void *)) From f5e462137f18ffeb85354ae84df4593f87e0e148 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 10 Jul 2023 13:09:32 -0700 Subject: [PATCH 1099/2042] tests/c_lib: Run basic libc tests using newlib and newlib-nano Validate some basic Zephyr requirements from the newlib C library. Signed-off-by: Keith Packard --- tests/lib/c_lib/src/main.c | 13 ++++++++++--- tests/lib/c_lib/src/test_strerror.c | 4 ++++ tests/lib/c_lib/testcase.yaml | 13 +++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/lib/c_lib/src/main.c b/tests/lib/c_lib/src/main.c index f5365d493ea8..6b3e96cbf996 100644 --- a/tests/lib/c_lib/src/main.c +++ b/tests/lib/c_lib/src/main.c @@ -15,6 +15,10 @@ * it guarantee that ALL functionality provided is working correctly. */ +#ifdef CONFIG_NEWLIB_LIBC +#define _POSIX_C_SOURCE 200809 +#endif + #include #include #include @@ -35,6 +39,9 @@ #ifdef CONFIG_PICOLIBC #include #endif +#ifdef CONFIG_NEWLIB_LIBC +#include +#endif #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE) #define LIST_LEN 2 @@ -1083,7 +1090,7 @@ ZTEST(test_c_lib, test_time) */ ZTEST(test_c_lib, test_rand) { -#ifndef CONFIG_PICOLIBC +#ifdef CONFIG_MINIMAL_LIBC int a; a = rand(); @@ -1101,7 +1108,7 @@ ZTEST(test_c_lib, test_rand) */ ZTEST(test_c_lib, test_srand) { -#ifndef CONFIG_PICOLIBC +#ifdef CONFIG_MINIMAL_LIBC int a; srand(0); @@ -1135,7 +1142,7 @@ ZTEST(test_c_lib, test_srand) */ ZTEST(test_c_lib, test_rand_reproducibility) { -#ifndef CONFIG_PICOLIBC +#ifdef CONFIG_MINIMAL_LIBC int a; int b; int c; diff --git a/tests/lib/c_lib/src/test_strerror.c b/tests/lib/c_lib/src/test_strerror.c index fff3d5e1d0d6..25a31df0624f 100644 --- a/tests/lib/c_lib/src/test_strerror.c +++ b/tests/lib/c_lib/src/test_strerror.c @@ -4,6 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#ifdef CONFIG_NEWLIB_LIBC +#define _POSIX_C_SOURCE 200809 +#endif + #include #include diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/testcase.yaml index 51b1e97bbf92..9d083c82b7a7 100644 --- a/tests/lib/c_lib/testcase.yaml +++ b/tests/lib/c_lib/testcase.yaml @@ -14,6 +14,19 @@ tests: ignore_faults: true extra_configs: - CONFIG_PICOLIBC=y + libraries.libc.newlib: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED + tags: newlib + ignore_faults: true + extra_configs: + - CONFIG_NEWLIB_LIBC=y + libraries.libc.newlib_nano: + filter: CONFIG_NEWLIB_LIBC_SUPPORTED and CONFIG_HAS_NEWLIB_LIBC_NANO + tags: newlib + ignore_faults: true + extra_configs: + - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_NANO=y libraries.libc.minimal.strerror_table: tags: minimal_libc extra_configs: From cf29b8caad9f47df66b32337bb21d3d00837cd3a Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Mon, 10 Jul 2023 12:44:42 +0200 Subject: [PATCH 1100/2042] drivers: sensor: mx5837: address integer overflow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid integer overflow in temp_sq calculation. For an analysis of the value ranges for the temp_sq calculation of mx5837-02 see below: calculation: dT = adc_temperature - ((int32_t)(data->t_ref) << 8); data->temperature = 2000 + (dT * data->tempsens) / (1ll << 23); temp_sq = (data->temperature - 2000) * (data->temperature - 2000); given needed storage sizes: t_ref is uint16_t, adc_temperature is uint24_t, data->tempsens is uint16_t, ranges => dT: -16776960 <= dT <= 16777215 (25 bit) => data->temperature (TEMP): intermed.(mult): -1099478073600 <= x <= 1099494785025 (41 bit) TEMP: 2.000 - 131068 <= TEMP <= 2.000 + 131.069 TEMP: -129068 <= TEMP <= 133069 (17 bit) So worst case we need 17 bit for TEMP, so the square of it would overflow an int32_t. The nominal measurement range is only -40 to 85°C, meaning a range of -4000 to 8500. So normally the result for temp_seq would fit into a int32_t, but we cast to be better safe than sorry. Also the 64-bit multiplication won't be the dominating operation of the whole calculation. Fixes #58585 Coverity-CID: 316294 Fixes #58594 Coverity-CID: 316521 Signed-off-by: Thomas Stranger --- drivers/sensor/ms5837/ms5837.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/ms5837/ms5837.c b/drivers/sensor/ms5837/ms5837.c index fdcb3f171aad..3dc645be6e96 100644 --- a/drivers/sensor/ms5837/ms5837.c +++ b/drivers/sensor/ms5837/ms5837.c @@ -73,7 +73,7 @@ static void ms5837_compensate_30(const struct device *dev, * SECOND ORDER TEMPERATURE COMPENSATION */ - temp_sq = (data->temperature - 2000) * (data->temperature - 2000); + temp_sq = (int64_t)(data->temperature - 2000) * (data->temperature - 2000); if (data->temperature < 2000) { Ti = (3ll * dT * dT) / (1ll << 23); OFFi = (3ll * temp_sq) / 1ll; @@ -120,7 +120,7 @@ static void ms5837_compensate_02(const struct device *dev, OFF = ((int64_t)(data->off_t1) << 17) + (dT * data->tco) / (1ll << 6); SENS = ((int64_t)(data->sens_t1) << 16) + (dT * data->tcs) / (1ll << 7); - temp_sq = (data->temperature - 2000) * (data->temperature - 2000); + temp_sq = (int64_t)(data->temperature - 2000) * (data->temperature - 2000); if (data->temperature < 2000) { Ti = (11ll * dT * dT) / (1ll << 35); OFFi = (31ll * temp_sq) / (1ll << 3); From 541482ff20415a84d67ad9c75b7cb4eadc983983 Mon Sep 17 00:00:00 2001 From: Bill Waters Date: Mon, 10 Jul 2023 10:25:26 -0700 Subject: [PATCH 1101/2042] driver: i2c: infineon: Adding XMC4 I2C driver - This includes the driver, test app, and sample app - Only the boards\arm\xmc47_relax_kit board is supported for now Signed-off-by: Bill Waters --- .../arm/xmc47_relax_kit/xmc47_relax_kit.yaml | 1 + drivers/i2c/CMakeLists.txt | 1 + drivers/i2c/Kconfig | 1 + drivers/i2c/Kconfig.ifx_xmc4 | 25 + drivers/i2c/i2c_ifx_xmc4.c | 465 ++++++++++++++++++ .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 121 +++++ dts/bindings/i2c/infineon,cat1-i2c.yaml | 4 +- dts/bindings/i2c/infineon,xmc4-i2c.yaml | 77 +++ .../dt-bindings/pinctrl/xmc4xxx-pinctrl.h | 20 +- modules/Kconfig.infineon | 5 + soc/arm/infineon_xmc/4xxx/Kconfig.series | 1 + .../i2c/i2c_api/boards/xmc47_relax_kit.conf | 1 + .../i2c_api/boards/xmc47_relax_kit.overlay | 35 ++ 13 files changed, 745 insertions(+), 12 deletions(-) create mode 100644 drivers/i2c/Kconfig.ifx_xmc4 create mode 100644 drivers/i2c/i2c_ifx_xmc4.c create mode 100644 dts/bindings/i2c/infineon,xmc4-i2c.yaml create mode 100644 tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf create mode 100644 tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml index e5630bd2821a..09fe856c7669 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -9,6 +9,7 @@ supported: - adc - dma - gpio + - i2c - spi - uart ram: 352 diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 6362ae46ecd2..82b716ac13c7 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -46,6 +46,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_TCA954X i2c_tca954x.c) zephyr_library_sources_ifdef(CONFIG_I2C_XEC_V2 i2c_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_I2C_GD32 i2c_gd32.c) zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_CAT1 i2c_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_XMC4 i2c_ifx_xmc4.c) zephyr_library_sources_ifdef(CONFIG_I2C_ANDES_ATCIIC100 i2c_andes_atciic100.c) zephyr_library_sources_ifdef(CONFIG_I2C_SC18IM704 i2c_sc18im704.c) zephyr_library_sources_ifdef(CONFIG_I2C_SMARTBOND i2c_smartbond.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 159cab781cc5..003b33d8aa5d 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -70,6 +70,7 @@ source "drivers/i2c/Kconfig.rcar" source "drivers/i2c/Kconfig.tca954x" source "drivers/i2c/Kconfig.gd32" source "drivers/i2c/Kconfig.ifx_cat1" +source "drivers/i2c/Kconfig.ifx_xmc4" source "drivers/i2c/Kconfig.andes_atciic100" source "drivers/i2c/Kconfig.sc18im704" source "drivers/i2c/Kconfig.smartbond" diff --git a/drivers/i2c/Kconfig.ifx_xmc4 b/drivers/i2c/Kconfig.ifx_xmc4 new file mode 100644 index 000000000000..52231d48735f --- /dev/null +++ b/drivers/i2c/Kconfig.ifx_xmc4 @@ -0,0 +1,25 @@ +# Infineon XMC4 I2C configuration options + +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig I2C_INFINEON_XMC4 + bool "Infineon XMC4 I2C driver" + default y + depends on DT_HAS_INFINEON_XMC4_I2C_ENABLED + help + This option enables the I2C driver for Infineon XMC4 family. + +if I2C_INFINEON_XMC4 + +config I2C_INFINEON_XMC4_TARGET_BUF + int "I2C Target data buffer length" + depends on I2C_INFINEON_XMC4 + range 1 1024 + default 64 + help + Buffer to receive data as an I2C Target. + +endif # I2C_INFINEON_XMC4 diff --git a/drivers/i2c/i2c_ifx_xmc4.c b/drivers/i2c/i2c_ifx_xmc4.c new file mode 100644 index 000000000000..2a882170519d --- /dev/null +++ b/drivers/i2c/i2c_ifx_xmc4.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief I2C driver for Infineon XMC MCU family. + */ + +#define DT_DRV_COMPAT infineon_xmc4_i2c + +#include +#include + +#include +#include + +#define USIC_IRQ_MIN 84 +#define IRQS_PER_USIC 6 + +#include +LOG_MODULE_REGISTER(i2c_infineon_xmc4, CONFIG_I2C_LOG_LEVEL); + +#define I2C_XMC_EVENTS_MASK ( \ + XMC_I2C_CH_EVENT_RECEIVE_START | \ + XMC_I2C_CH_EVENT_DATA_LOST | \ + XMC_I2C_CH_EVENT_TRANSMIT_SHIFT | \ + XMC_I2C_CH_EVENT_TRANSMIT_BUFFER | \ + XMC_I2C_CH_EVENT_STANDARD_RECEIVE | \ + XMC_I2C_CH_EVENT_ALTERNATIVE_RECEIVE | \ + XMC_I2C_CH_EVENT_BAUD_RATE_GENERATOR | \ + XMC_I2C_CH_EVENT_START_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_REPEATED_START_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_STOP_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_NACK | \ + XMC_I2C_CH_EVENT_ARBITRATION_LOST | \ + XMC_I2C_CH_EVENT_SLAVE_READ_REQUEST | \ + XMC_I2C_CH_EVENT_ERROR | \ + XMC_I2C_CH_EVENT_ACK) + +#define I2C_XMC_STATUS_FLAG_ERROR_MASK ( \ + XMC_I2C_CH_STATUS_FLAG_WRONG_TDF_CODE_FOUND | \ + XMC_I2C_CH_STATUS_FLAG_NACK_RECEIVED | \ + XMC_I2C_CH_STATUS_FLAG_ARBITRATION_LOST | \ + XMC_I2C_CH_STATUS_FLAG_ERROR | \ + XMC_I2C_CH_STATUS_FLAG_DATA_LOST_INDICATION) + +/* I2C speed */ +#define XMC4_I2C_SPEED_STANDARD (100000UL) +#define XMC4_I2C_SPEED_FAST (400000UL) + +/* Data structure */ +struct ifx_xmc4_i2c_data { + XMC_I2C_CH_CONFIG_t cfg; + struct k_sem operation_sem; + struct k_sem target_sem; + struct i2c_target_config *p_target_config; + uint32_t dev_config; + uint8_t target_wr_byte; + uint8_t target_wr_buffer[CONFIG_I2C_INFINEON_XMC4_TARGET_BUF]; + bool ignore_slave_select; +}; + +/* Device config structure */ +struct ifx_xmc4_i2c_config { + XMC_USIC_CH_t *i2c; + const struct pinctrl_dev_config *pcfg; + uint8_t scl_src; + uint8_t sda_src; + uint32_t master_frequency; + void (*irq_config_func)(const struct device *dev); +}; + +static int ifx_xmc4_i2c_configure(const struct device *dev, uint32_t dev_config) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + + if (dev_config != 0) { + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + data->cfg.baudrate = XMC4_I2C_SPEED_STANDARD; + break; + case I2C_SPEED_FAST: + data->cfg.baudrate = XMC4_I2C_SPEED_FAST; + break; + default: + LOG_ERR("Unsupported speed"); + return -ERANGE; + } + + /* This is deprecated and could be ignored in the future */ + if (dev_config & I2C_ADDR_10_BITS) { + LOG_ERR("Use I2C_MSG_ADDR_10_BITS instead of I2C_ADDR_10_BITS"); + return -EIO; + } + } + + data->dev_config = dev_config; + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + /* Configure the I2C resource */ + data->cfg.normal_divider_mode = false; + XMC_I2C_CH_Init(config->i2c, &data->cfg); + XMC_I2C_CH_SetInputSource(config->i2c, XMC_I2C_CH_INPUT_SCL, config->scl_src); + XMC_I2C_CH_SetInputSource(config->i2c, XMC_I2C_CH_INPUT_SDA, config->sda_src); + if (data->dev_config & I2C_MODE_CONTROLLER) { + XMC_USIC_CH_SetFractionalDivider(config->i2c, + XMC_USIC_CH_BRG_CLOCK_DIVIDER_MODE_FRACTIONAL, + 1023U); + } else { + config->irq_config_func(dev); + } + XMC_I2C_CH_Start(config->i2c); + + /* Release semaphore */ + k_sem_give(&data->operation_sem); + + return 0; +} + +static int ifx_xmc4_i2c_get_config(const struct device *dev, uint32_t *dev_config) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + uint32_t config; + + switch (data->cfg.baudrate) { + case XMC4_I2C_SPEED_STANDARD: + config = I2C_SPEED_SET(I2C_SPEED_STANDARD); + break; + case XMC4_I2C_SPEED_FAST: + config = I2C_SPEED_SET(I2C_SPEED_FAST); + break; + default: + LOG_ERR("Unsupported speed"); + return -ERANGE; + } + + if (data->dev_config & I2C_MODE_CONTROLLER) { + config |= I2C_MODE_CONTROLLER; + } + + /* Return current configuration */ + *dev_config = config; + + return 0; +} + +static int ifx_xmc4_i2c_msg_validate(struct i2c_msg *msg, uint8_t num_msgs) +{ + for (uint32_t i = 0u; i < num_msgs; i++) { + if ((I2C_MSG_ADDR_10_BITS & msg[i].flags) || (msg[i].buf == NULL)) { + return -EINVAL; + } + } + return 0; +} + +static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, uint8_t num_msgs, + uint16_t addr) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + XMC_I2C_CH_CMD_t cmd_type; + + if (!num_msgs) { + return 0; + } + + /* Acquire semaphore (block I2C transfer for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + /* This function checks if msg.buf is not NULL and if target address is not 10 bit. */ + if (ifx_xmc4_i2c_msg_validate(msg, num_msgs) != 0) { + k_sem_give(&data->operation_sem); + return -EINVAL; + } + + for (uint32_t msg_index = 0u; msg_index < num_msgs; msg_index++) { + XMC_I2C_CH_ClearStatusFlag(config->i2c, 0xFFFFFFFF); + + if ((msg_index == 0) || (msg[msg_index].flags & I2C_MSG_RESTART)) { + /* Send START conditon */ + cmd_type = ((msg[msg_index].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? + XMC_I2C_CH_CMD_READ : XMC_I2C_CH_CMD_WRITE; + + if (msg[msg_index].flags & I2C_MSG_RESTART) { + XMC_I2C_CH_MasterRepeatedStart(config->i2c, addr << 1, cmd_type); + } else { + XMC_I2C_CH_MasterStart(config->i2c, addr << 1, cmd_type); + } + + /* Wait for acknowledge */ + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U) { + /* wait for ACK from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED); + } + + for (uint32_t buf_index = 0u; buf_index < msg[msg_index].len; buf_index++) { + if (cmd_type == XMC_I2C_CH_CMD_WRITE) { + /* Transmit next command from I2C master to I2C slave */ + XMC_I2C_CH_MasterTransmit(config->i2c, + msg[msg_index].buf[buf_index]); + + /* Wait for acknowledge */ + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U) { + /* wait for ACK from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED); + + /* Wait until TX FIFO is empty */ + while (!XMC_USIC_CH_TXFIFO_IsEmpty(config->i2c)) { + /* wait until all data is sent by HW */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + } else { + if (buf_index == (msg[msg_index].len - 1)) { + XMC_I2C_CH_MasterReceiveNack(config->i2c); + } else { + XMC_I2C_CH_MasterReceiveAck(config->i2c); + } + + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + (XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION)) == 0U) { + /* wait for data byte from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION); + + msg[msg_index].buf[buf_index] = + XMC_I2C_CH_GetReceivedData(config->i2c); + } + } + + /* Send STOP conditon */ + if (msg[msg_index].flags & I2C_MSG_STOP) { + XMC_I2C_CH_MasterStop(config->i2c); + } + } + + /* Release semaphore (After I2C transfer is complete) */ + k_sem_give(&data->operation_sem); + return 0; +} + +static int ifx_xmc4_i2c_init(const struct device *dev) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + int ret; + + /* Configure semaphores */ + ret = k_sem_init(&data->operation_sem, 1, 1); + if (ret) { + return ret; + } + + ret = k_sem_init(&data->target_sem, 1, 1); + if (ret) { + return ret; + } + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int ifx_xmc4_i2c_target_register(const struct device *dev, struct i2c_target_config *cfg) +{ + struct ifx_xmc4_i2c_data *data = (struct ifx_xmc4_i2c_data *)dev->data; + + if (!cfg || + !cfg->callbacks->read_requested || + !cfg->callbacks->read_processed || + !cfg->callbacks->write_requested || + !cfg->callbacks->write_received || + !cfg->callbacks->stop) { + return -EINVAL; + } + + if (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) { + return -ENOTSUP; + } + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->target_sem, K_FOREVER)) { + return -EIO; + } + + data->p_target_config = cfg; + data->cfg.address = cfg->address << 1; + + if (ifx_xmc4_i2c_configure(dev, I2C_SPEED_SET(I2C_SPEED_STANDARD)) != 0) { + /* Release semaphore */ + k_sem_give(&data->target_sem); + return -EIO; + } + + k_sem_give(&data->target_sem); + return 0; +} + +static int ifx_xmc4_i2c_target_unregister(const struct device *dev, struct i2c_target_config *cfg) +{ + struct ifx_xmc4_i2c_data *data = (struct ifx_xmc4_i2c_data *)dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + data->p_target_config = NULL; + XMC_I2C_CH_DisableEvent(config->i2c, I2C_XMC_EVENTS_MASK); + + /* Release semaphore */ + k_sem_give(&data->operation_sem); + return 0; +} + + +static void i2c_xmc4_isr(const struct device *dev) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + const struct i2c_target_callbacks *callbacks = data->p_target_config->callbacks; + uint32_t status = XMC_I2C_CH_GetStatusFlag(config->i2c); + + while (status) { + XMC_I2C_CH_ClearStatusFlag(config->i2c, status); + + if (status & XMC_I2C_CH_STATUS_FLAG_STOP_CONDITION_RECEIVED) { + /* Flush the TX buffer */ + XMC_USIC_CH_SetTransmitBufferStatus(config->i2c, + XMC_USIC_CH_TBUF_STATUS_SET_IDLE); + + callbacks->stop(data->p_target_config); + break; + } + + if (!data->ignore_slave_select && (status & XMC_I2C_CH_STATUS_FLAG_SLAVE_SELECT)) { + data->ignore_slave_select = true; + + /* Start a slave read */ + if (status & XMC_I2C_CH_STATUS_FLAG_SLAVE_READ_REQUESTED) { + callbacks->read_requested(data->p_target_config, + &data->target_wr_byte); + XMC_I2C_CH_SlaveTransmit(config->i2c, data->target_wr_byte); + } else { + callbacks->write_requested(data->p_target_config); + } + } + + /* Continue a slave read */ + if (status & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) { + callbacks->read_processed(data->p_target_config, &data->target_wr_byte); + XMC_I2C_CH_SlaveTransmit(config->i2c, data->target_wr_byte); + } + + /* Start/Continue a slave write */ + if (status & (XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) { + callbacks->write_received(data->p_target_config, + XMC_I2C_CH_GetReceivedData(config->i2c)); + } + + if ((status & XMC_I2C_CH_STATUS_FLAG_START_CONDITION_RECEIVED) || + (status & XMC_I2C_CH_STATUS_FLAG_REPEATED_START_CONDITION_RECEIVED)) { + data->ignore_slave_select = false; + } + + status = XMC_I2C_CH_GetStatusFlag(config->i2c); + } +} + + +/* I2C API structure */ +static const struct i2c_driver_api i2c_xmc4_driver_api = { + .configure = ifx_xmc4_i2c_configure, + .transfer = ifx_xmc4_i2c_transfer, + .get_config = ifx_xmc4_i2c_get_config, + .target_register = ifx_xmc4_i2c_target_register, + .target_unregister = ifx_xmc4_i2c_target_unregister}; + +/* Macros for I2C instance declaration */ +#define XMC4_IRQ_HANDLER_INIT(index) \ + static void i2c_xmc4_irq_setup_##index(const struct device *dev) \ + { \ + const struct ifx_xmc4_i2c_config *config = dev->config; \ + uint8_t irq_num = DT_INST_IRQN(index); \ + uint8_t service_request = (irq_num - USIC_IRQ_MIN) % IRQS_PER_USIC; \ + \ + XMC_I2C_CH_SelectInterruptNodePointer(config->i2c, \ + XMC_I2C_CH_INTERRUPT_NODE_POINTER_RECEIVE, service_request); \ + XMC_I2C_CH_SelectInterruptNodePointer(config->i2c, \ + XMC_I2C_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, service_request); \ + \ + XMC_I2C_CH_EnableEvent(config->i2c, I2C_XMC_EVENTS_MASK); \ + \ + IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), i2c_xmc4_isr, \ + DEVICE_DT_INST_GET(index), 0); \ + \ + irq_enable(irq_num); \ + } + +#define XMC4_IRQ_HANDLER_STRUCT_INIT(index) .irq_config_func = i2c_xmc4_irq_setup_##index + +#define INFINEON_XMC4_I2C_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + XMC4_IRQ_HANDLER_INIT(n) \ + \ + static struct ifx_xmc4_i2c_data ifx_xmc4_i2c_data##n; \ + \ + static const struct ifx_xmc4_i2c_config i2c_xmc4_cfg_##n = { \ + .i2c = (XMC_USIC_CH_t *)DT_INST_REG_ADDR(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .scl_src = DT_INST_ENUM_IDX(n, scl_src), \ + .sda_src = DT_INST_ENUM_IDX(n, sda_src), \ + .master_frequency = DT_INST_PROP_OR(n, clock_frequency, XMC4_I2C_SPEED_STANDARD), \ + XMC4_IRQ_HANDLER_STRUCT_INIT(n) \ + }; \ + \ + I2C_DEVICE_DT_INST_DEFINE(n, ifx_xmc4_i2c_init, NULL, &ifx_xmc4_i2c_data##n, \ + &i2c_xmc4_cfg_##n, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, &i2c_xmc4_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINEON_XMC4_I2C_INIT) diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 537d27b36f51..dd03fad36174 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -593,4 +593,125 @@ pinmux = ; hwctrl = "periph2"; }; + + /omit-if-no-ref/ i2c_controller_scl_p0_8_u0c0: i2c_controller_scl_p0_8_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p1_1_u0c0: i2c_controller_scl_p1_1_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p2_4_u0c1: i2c_controller_scl_p2_4_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p3_0_u0c1: i2c_controller_scl_p3_0_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p6_2_u0c1: i2c_controller_scl_p6_2_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_11_u1c0: i2c_controller_scl_p0_11_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p5_8_u1c0: i2c_controller_scl_p5_8_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_10_u1c1: i2c_controller_scl_p0_10_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_13_u1c1: i2c_controller_scl_p0_13_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p5_2_u2c0: i2c_controller_scl_p5_2_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p3_6_u2c1: i2c_controller_scl_p3_6_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p1_5_u0c0: i2c_controller_sda_p1_5_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p2_5_u0c1: i2c_controller_sda_p2_5_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_13_u0c1: i2c_controller_sda_p3_13_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p0_5_u1c0: i2c_controller_sda_p0_5_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p2_14_u1c0: i2c_controller_sda_p2_14_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_15_u1c1: i2c_controller_sda_p3_15_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p4_2_u1c1: i2c_controller_sda_p4_2_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p5_0_u2c0: i2c_controller_sda_p5_0_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_5_u2c1: i2c_controller_sda_p3_5_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_8_u0c0: i2c_target_scl_p0_8_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p1_1_u0c0: i2c_target_scl_p1_1_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p2_4_u0c1: i2c_target_scl_p2_4_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p3_0_u0c1: i2c_target_scl_p3_0_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p6_2_u0c1: i2c_target_scl_p6_2_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_11_u1c0: i2c_target_scl_p0_11_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p5_8_u1c0: i2c_target_scl_p5_8_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_10_u1c1: i2c_target_scl_p0_10_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_13_u1c1: i2c_target_scl_p0_13_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p5_2_u2c0: i2c_target_scl_p5_2_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p3_6_u2c1: i2c_target_scl_p3_6_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p1_5_u0c0: i2c_target_sda_p1_5_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p2_5_u0c1: i2c_target_sda_p2_5_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_13_u0c1: i2c_target_sda_p3_13_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p0_5_u1c0: i2c_target_sda_p0_5_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p2_14_u1c0: i2c_target_sda_p2_14_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_15_u1c1: i2c_target_sda_p3_15_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p4_2_u1c1: i2c_target_sda_p4_2_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p5_0_u2c0: i2c_target_sda_p5_0_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_5_u2c1: i2c_target_sda_p3_5_u2c1 { + pinmux = ; + }; }; diff --git a/dts/bindings/i2c/infineon,cat1-i2c.yaml b/dts/bindings/i2c/infineon,cat1-i2c.yaml index 2ed002a2c972..fa7ca1b8f4a2 100644 --- a/dts/bindings/i2c/infineon,cat1-i2c.yaml +++ b/dts/bindings/i2c/infineon,cat1-i2c.yaml @@ -21,10 +21,10 @@ properties: pinctrl-0: description: | PORT pin configuration for SCL, SDA signals. - We expect that the phandles will reference pinctrl nodes.These + We expect that the phandles will reference pinctrl nodes. These nodes will have a nodelabel that matches the Infineon SoC Pinctrl defines and have following - format: p__. + format: p___. Examples: pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>; diff --git a/dts/bindings/i2c/infineon,xmc4-i2c.yaml b/dts/bindings/i2c/infineon,xmc4-i2c.yaml new file mode 100644 index 000000000000..7672bdf1b492 --- /dev/null +++ b/dts/bindings/i2c/infineon,xmc4-i2c.yaml @@ -0,0 +1,77 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon XMC4 I2C + +compatible: "infineon,xmc4-i2c" + +include: [i2c-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + type: array + required: true + + scl-src: + description: | + Connects the I2C clock line (USIC DX0 input) to a specific GPIO pin. + The USIC DX0 input is a multiplexer which connects to different GPIO pins. + Refer to the XMC4XXX reference manual for the GPIO pin/mux mappings. + type: string + required: true + enum: + - "DX0A" + - "DX0B" + - "DX0C" + - "DX0D" + - "DX0E" + - "DX0F" + - "DX0G" + + sda-src: + description: | + Connects the I2C data line (USIC DX0 input) to a specific GPIO pin. + The USIC DX0 input is a multiplexer which connects to different GPIO pins. + Refer to the XMC4XXX reference manual for the GPIO pin/mux mappings. + type: string + required: true + enum: + - "DX0A" + - "DX0B" + - "DX0C" + - "DX0D" + - "DX0E" + - "DX0F" + - "DX0G" + + interrupts: + type: array + required: true + description: | + IRQ number and priority to use for interrupt driven by I2C. + Each USIC must use a certain interrupt range: + USIC0 = [84, 89] + USIC1 = [90, 95] + USIC2 = [96, 101] + + pinctrl-0: + description: | + PORT pin configuration for SCL, SDA signals. + We expect that the phandles will reference pinctrl nodes. These + nodes will have a nodelabel that matches the Infineon SoC Pinctrl + defines and have following + format: _p__ + + Examples: + pinctrl-0 = <&i2c_scl_p5_2_u2c0 &i2c_sda_p5_0_u2c0>; + required: true + + pinctrl-names: + required: true + + clock-frequency: + type: int + description: | + Frequency that the I2C bus runs diff --git a/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h index 2fed5aff280a..f209b7192229 100644 --- a/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h @@ -16,33 +16,33 @@ #define XMC4XXX_PIN_MASK 0xf #define XMC4XXX_ALT_POS 8 -#define XMC4XXX_ALT_MASK 0xf +#define XMC4XXX_ALT_MASK 0x1f -#define XMC4XXX_PULL_DOWN_POS 12 +#define XMC4XXX_PULL_DOWN_POS 13 #define XMC4XXX_PULL_DOWN_MASK 0x1 -#define XMC4XXX_PULL_UP_POS 13 +#define XMC4XXX_PULL_UP_POS 14 #define XMC4XXX_PULL_UP_MASK 0x1 -#define XMC4XXX_PUSH_PULL_POS 14 +#define XMC4XXX_PUSH_PULL_POS 15 #define XMC4XXX_PUSH_PULL_MASK 0x1 -#define XMC4XXX_OPEN_DRAIN_POS 15 +#define XMC4XXX_OPEN_DRAIN_POS 16 #define XMC4XXX_OPEN_DRAIN_MASK 0x1 -#define XMC4XXX_OUT_HIGH_POS 16 +#define XMC4XXX_OUT_HIGH_POS 17 #define XMC4XXX_OUT_HIGH_MASK 0x1 -#define XMC4XXX_OUT_LOW_POS 17 +#define XMC4XXX_OUT_LOW_POS 18 #define XMC4XXX_OUT_LOW_MASK 0x1 -#define XMC4XXX_INV_INPUT_POS 18 +#define XMC4XXX_INV_INPUT_POS 19 #define XMC4XXX_INV_INPUT_MASK 0x1 -#define XMC4XXX_DRIVE_POS 19 +#define XMC4XXX_DRIVE_POS 20 #define XMC4XXX_DRIVE_MASK 0x7 -#define XMC4XXX_HWCTRL_POS 22 +#define XMC4XXX_HWCTRL_POS 23 #define XMC4XXX_HWCTRL_MASK 0x3 /* Setters and getters */ diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 0268a8db0089..87d140bc9af4 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -40,4 +40,9 @@ config HAS_XMCLIB_SPI help Enable XMCLIB SPI +config HAS_XMCLIB_I2C + bool + help + Enable XMCLIB I2C + endif # HAS_XMCLIB diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 4e130ba35630..66a93102352c 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_VADC select HAS_XMCLIB_DMA select HAS_XMCLIB_SPI + select HAS_XMCLIB_I2C help Enable support for XMC 4xxx MCU series diff --git a/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf new file mode 100644 index 000000000000..9ef6cbaaa500 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf @@ -0,0 +1 @@ +CONFIG_I2C_INFINEON_XMC4_TARGET_BUF=128 diff --git a/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay new file mode 100644 index 000000000000..9403069a596d --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2c-0 = &usic0ch1; + }; +}; + +&i2c_controller_scl_p6_2_u0c1 { + drive-strength = "strong-sharp-edge"; + hwctrl = "disabled"; +}; + +&i2c_controller_sda_p3_13_u0c1 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; + +&usic0ch1 { + compatible = "infineon,xmc4-i2c"; + pinctrl-0 = <&i2c_controller_scl_p6_2_u0c1 &i2c_controller_sda_p3_13_u0c1>; + pinctrl-names = "default"; + scl-src = "DX0C"; + sda-src = "DX0D"; + interrupts = <86 1>; + + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +}; From c7b5da33265ce2b4a4de2ecb668fe3cc44405c32 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 10 Jul 2023 18:43:29 +0300 Subject: [PATCH 1102/2042] doc: acpi: Correct ACPI documentation Correct several typos and make documentation more readable. Signed-off-by: Andrei Emeltchenko --- include/zephyr/acpi/acpi.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h index b3e46ef52cd4..dc6a25c8ea89 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -20,15 +20,15 @@ struct acpi_dev { }; /** - * @brief retrieve legacy interrupt number for a PCI device. + * @brief Retrieve a legacy interrupt number for a PCI device. * * @param bdf the BDF of endpoint/PCI device - * @return return IRQ number or UINT_MAX if not fund + * @return return IRQ number or UINT_MAX if not found */ uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf); /** - * @brief retrieve current resource setting of a device. + * @brief Retrieve the current resource settings of a device. * * @param dev_name the name of the device * @param res the list of acpi resource list @@ -37,7 +37,7 @@ uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf); int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res); /** - * @brief retrieve possible resource setting of a device. + * @brief Retrieve possible resource settings of a device. * * @param dev_name the name of the device * @param res the list of acpi resource list @@ -46,8 +46,8 @@ int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res); int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res); /** - * @brief Free current resource list memory which is retrived by - * acpi_current_resource_get. + * @brief Free current resource list memory which is retrieved by + * acpi_current_resource_get(). * * @param res the list of acpi resource list * @return return 0 on success or error code @@ -55,7 +55,7 @@ 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. + * @brief Retrieve IRQ routing table of a bus. * * @param bus_name the name of the bus * @param rt_table the IRQ routing table @@ -66,7 +66,7 @@ int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size); /** - * @brief parse resource table for given resource type. + * @brief Parse resource table for a given resource type. * * @param res the list of acpi resource list * @param res_type the acpi resource type @@ -75,7 +75,7 @@ int acpi_get_irq_routing_table(char *bus_name, 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 @@ -84,7 +84,7 @@ ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type); struct acpi_dev *acpi_device_get(char *hid, int inst); /** - * @brief retrieve acpi device info form index. + * @brief Retrieve acpi device info from the index. * * @param index the device index of an acpi child device * @return acpi child device info on success or NULL @@ -92,7 +92,7 @@ struct acpi_dev *acpi_device_get(char *hid, int inst); struct acpi_dev *acpi_device_by_index_get(int index); /** - * @brief parse resource table for irq info. + * @brief Parse resource table for irq info. * * @param res_lst the list of acpi resource list * @return irq resource list on success or NULL @@ -105,7 +105,7 @@ static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst) } /** - * @brief parse resource table for identify resource type. + * @brief Parse resource table for identify resource type. * * @param res the list of acpi resource list * @return resource type on success or invalid resource type @@ -113,7 +113,7 @@ static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst) int acpi_device_type_get(ACPI_RESOURCE *res); /** - * @brief retrieve acpi table for the given signature. + * @brief Retrieve acpi table for the given signature. * * @param signature pointer to the 4-character ACPI signature for the requested table * @param inst instance number for the requested table From b21a5379862684d0404f44f371db2cee56e06f80 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 10 Jul 2023 16:32:16 +0200 Subject: [PATCH 1103/2042] tfm: Fix board selection for Musca B1 board Fix board selection for Musca B1 board. The platform path in TF-M was changed in the TF-M 1.7.0 update. 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 2a22e0b30dbb..a7276d79374c 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -18,7 +18,7 @@ config TFM_BOARD default "stm/b_u585i_iot02a" if BOARD_B_U585I_IOT02A default "stm/nucleo_l552ze_q" if BOARD_NUCLEO_L552ZE_Q default "stm/stm32l562e_dk" if BOARD_STM32L562E_DK - default "arm/musca_b1/sse_200" if BOARD_MUSCA_B1 + 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 help From f629f2c270cd11907da663b84b5dab3c6ae01ffc Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Mon, 26 Jun 2023 22:18:22 -0400 Subject: [PATCH 1104/2042] drivers: dma: stm32u5: enable error interrupts Enable DMA error interrupts so that transfer errors are logged and reported to the callback. Signed-off-by: Brett Witherspoon --- drivers/dma/dma_stm32u5.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dma_stm32u5.c b/drivers/dma/dma_stm32u5.c index db58dbd2170f..38a5cfdd85ef 100644 --- a/drivers/dma/dma_stm32u5.c +++ b/drivers/dma/dma_stm32u5.c @@ -98,6 +98,24 @@ void dma_stm32_clear_tc(DMA_TypeDef *DMAx, uint32_t id) LL_DMA_ClearFlag_TC(DMAx, dma_stm32_id_to_stream(id)); } +/* data transfer error */ +static inline bool dma_stm32_is_dte_active(DMA_TypeDef *dma, uint32_t id) +{ + return LL_DMA_IsActiveFlag_DTE(dma, dma_stm32_id_to_stream(id)); +} + +/* link transfer error */ +static inline bool dma_stm32_is_ule_active(DMA_TypeDef *dma, uint32_t id) +{ + return LL_DMA_IsActiveFlag_ULE(dma, dma_stm32_id_to_stream(id)); +} + +/* user setting error */ +static inline bool dma_stm32_is_use_active(DMA_TypeDef *dma, uint32_t id) +{ + return LL_DMA_IsActiveFlag_USE(dma, dma_stm32_id_to_stream(id)); +} + /* transfer error either a data or user or link error */ bool dma_stm32_is_te_active(DMA_TypeDef *DMAx, uint32_t id) { @@ -127,10 +145,13 @@ void dma_stm32_clear_ht(DMA_TypeDef *DMAx, uint32_t id) void stm32_dma_dump_stream_irq(DMA_TypeDef *dma, uint32_t id) { - LOG_INF("tc: %d, ht: %d, te: %d", + LOG_INF("tc: %d, ht: %d, dte: %d, ule: %d, use: %d", dma_stm32_is_tc_active(dma, id), dma_stm32_is_ht_active(dma, id), - dma_stm32_is_te_active(dma, id)); + dma_stm32_is_dte_active(dma, id), + dma_stm32_is_ule_active(dma, id), + dma_stm32_is_use_active(dma, id) + ); } /* Check if nsecure masked interrupt is active on channel */ @@ -487,6 +508,9 @@ static int dma_stm32_configure(const struct device *dev, LL_DMA_Init(dma, dma_stm32_id_to_stream(id), &DMA_InitStruct); LL_DMA_EnableIT_TC(dma, dma_stm32_id_to_stream(id)); + LL_DMA_EnableIT_USE(dma, dma_stm32_id_to_stream(id)); + LL_DMA_EnableIT_ULE(dma, dma_stm32_id_to_stream(id)); + LL_DMA_EnableIT_DTE(dma, dma_stm32_id_to_stream(id)); /* Enable Half-Transfer irq if circular mode is enabled */ if (config->head_block->source_reload_en) { @@ -631,6 +655,9 @@ static int dma_stm32_stop(const struct device *dev, uint32_t id) } LL_DMA_DisableIT_TC(dma, dma_stm32_id_to_stream(id)); + LL_DMA_DisableIT_USE(dma, dma_stm32_id_to_stream(id)); + LL_DMA_DisableIT_ULE(dma, dma_stm32_id_to_stream(id)); + LL_DMA_DisableIT_DTE(dma, dma_stm32_id_to_stream(id)); dma_stm32_clear_stream_irq(dev, id); dma_stm32_disable_stream(dma, id); From 6d9d44e2a56f34ad8ed91140ae767b97487022c8 Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Mon, 26 Jun 2023 22:16:20 -0400 Subject: [PATCH 1105/2042] drivers: dma: stm32u5: use correct tables for data width The tables for the dest and src data width constants were incorrectly swapped. This commit uses the correct constants and renames the tables. This change is only cosmetic for the stm32u5 since these constants are the same but the existing names were probably inherited from another driver where the p_*/m_* prefix was more appropriate. Signed-off-by: Brett Witherspoon --- drivers/dma/dma_stm32u5.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/dma/dma_stm32u5.c b/drivers/dma/dma_stm32u5.c index 38a5cfdd85ef..253a154e09a4 100644 --- a/drivers/dma/dma_stm32u5.c +++ b/drivers/dma/dma_stm32u5.c @@ -24,13 +24,13 @@ LOG_MODULE_REGISTER(dma_stm32, CONFIG_DMA_LOG_LEVEL); #define DT_DRV_COMPAT st_stm32u5_dma -static const uint32_t table_m_size[] = { +static const uint32_t table_src_size[] = { LL_DMA_SRC_DATAWIDTH_BYTE, LL_DMA_SRC_DATAWIDTH_HALFWORD, LL_DMA_SRC_DATAWIDTH_WORD, }; -static const uint32_t table_p_size[] = { +static const uint32_t table_dst_size[] = { LL_DMA_DEST_DATAWIDTH_BYTE, LL_DMA_DEST_DATAWIDTH_HALFWORD, LL_DMA_DEST_DATAWIDTH_WORD, @@ -489,10 +489,10 @@ static int dma_stm32_configure(const struct device *dev, /* Set the data width, when source_data_size equals dest_data_size */ int index = find_lsb_set(config->source_data_size) - 1; - DMA_InitStruct.SrcDataWidth = table_p_size[index]; + DMA_InitStruct.SrcDataWidth = table_src_size[index]; index = find_lsb_set(config->dest_data_size) - 1; - DMA_InitStruct.DestDataWidth = table_m_size[index]; + DMA_InitStruct.DestDataWidth = table_dst_size[index]; if (stream->source_periph) { DMA_InitStruct.BlkDataLength = config->head_block->block_size / From 3bb5062faefd57057c8fec3bdfbad674450a1e86 Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Mon, 26 Jun 2023 22:23:59 -0400 Subject: [PATCH 1106/2042] tests: drivers: adc: adc_dma: add nucleo_u575zi_q Add the nucleo_u575zi_q board to the ADC DMA tests. Signed-off-by: Brett Witherspoon --- .../adc/adc_dma/boards/nucleo_u575zi_q.conf | 8 ++++++ .../adc_dma/boards/nucleo_u575zi_q.overlay | 26 +++++++++++++++++++ tests/drivers/adc/adc_dma/src/test_adc.c | 11 ++++++++ tests/drivers/adc/adc_dma/testcase.yaml | 1 + 4 files changed, 46 insertions(+) create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.conf create mode 100644 tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.overlay diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.conf b/tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.conf new file mode 100644 index 000000000000..0203963c25c6 --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.conf @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023 Brett Witherspoon +# +# 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_u575zi_q.overlay b/tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.overlay new file mode 100644 index 000000000000..e884dbc072ae --- /dev/null +++ b/tests/drivers/adc/adc_dma/boards/nucleo_u575zi_q.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Brett Witherspoon + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&adc1 { + dmas = <&gpdma1 0 0 (STM32_DMA_PERIPH_TO_MEMORY | + STM32_DMA_MEM_INC | STM32_DMA_MEM_16BITS | STM32_DMA_PERIPH_16BITS) >; + dma-names = "dmamux"; + + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +test_dma: &gpdma1 { + 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 935f65b83aaf..c9a1ac4b0dc9 100644 --- a/tests/drivers/adc/adc_dma/src/test_adc.c +++ b/tests/drivers/adc/adc_dma/src/test_adc.c @@ -50,6 +50,17 @@ #define ALIGNMENT 32 #define BUFFER_MEM_REGION __attribute__((__section__("SRAM4.dma"))) +#elif defined(CONFIG_BOARD_NUCLEO_U575ZI_Q) + +#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 diff --git a/tests/drivers/adc/adc_dma/testcase.yaml b/tests/drivers/adc/adc_dma/testcase.yaml index d526e7fcd3c7..daf073bab5c3 100644 --- a/tests/drivers/adc/adc_dma/testcase.yaml +++ b/tests/drivers/adc/adc_dma/testcase.yaml @@ -12,5 +12,6 @@ tests: - frdm_k82f - frdm_k64f - nucleo_h743zi + - nucleo_u575zi_q integration_platforms: - frdm_k82f From 33cb179b4f2e5bf6fdefccc38dc1cf57ff76e8d6 Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Mon, 26 Jun 2023 22:20:19 -0400 Subject: [PATCH 1107/2042] drivers: dma: stm32u5: set data length in bytes The block data length field should be in bytes. Setting this to a value that is not a multiple of the data size results in a user setting error. Running the ADC DMA test prior to this commit: west build -p -b nucleo_u575zi_q zephyr/tests/drivers/adc/adc_dma E: Transfer Error. I: tc: 0, ht: 0, dte: 0, ule: 0, use: 1 E: DMA sampling complete, but DMA reported error -5 Existing tests using DMA on the nucleo_u575zi_q were not effected because they only use a data size of one and continue to function as expected: west build -p -b nucleo_u575zi_q zephyr/tests/drivers/spi/spi_loopback \ -DOVERLAY_CONFIG="overlay-stm32-spi-dma.conf" SUITE PASS - 100.00% [spi_loopback]: pass = 1, fail = 0, ... west build -p -b nucleo_u575zi_q zephyr/tests/drivers/dma/loop_transfer SUITE PASS - 100.00% [dma_m2m_loop]: pass = 3, fail = 0, ... Signed-off-by: Brett Witherspoon --- drivers/dma/dma_stm32u5.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/dma/dma_stm32u5.c b/drivers/dma/dma_stm32u5.c index 253a154e09a4..88ab979df625 100644 --- a/drivers/dma/dma_stm32u5.c +++ b/drivers/dma/dma_stm32u5.c @@ -494,13 +494,7 @@ static int dma_stm32_configure(const struct device *dev, index = find_lsb_set(config->dest_data_size) - 1; DMA_InitStruct.DestDataWidth = table_dst_size[index]; - if (stream->source_periph) { - DMA_InitStruct.BlkDataLength = config->head_block->block_size / - config->source_data_size; - } else { - DMA_InitStruct.BlkDataLength = config->head_block->block_size / - config->dest_data_size; - } + DMA_InitStruct.BlkDataLength = config->head_block->block_size; /* The request ID is stored in the dma_slot */ DMA_InitStruct.Request = config->dma_slot; From 7fc6e331d8a79bc84e5d17e41e684c654d13f841 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Thu, 6 Jul 2023 17:44:43 +0530 Subject: [PATCH 1108/2042] drivers: mm: Add support for TI RAT module using system_mm API Added Region based Address Translation (RAT) module driver. Required by a few Texas Instruments SoCs to fucntion. Uses sys_mm_drv_page_phys_get() API with device_map() for address translation. Signed-off-by: L Lakshmanan --- drivers/mm/CMakeLists.txt | 2 + drivers/mm/Kconfig | 19 ++++ drivers/mm/mm_drv_ti_rat.c | 143 +++++++++++++++++++++++++++++++ include/zephyr/drivers/mm/rat.h | 87 +++++++++++++++++++ include/zephyr/sys/device_mmio.h | 11 ++- 5 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 drivers/mm/mm_drv_ti_rat.c create mode 100644 include/zephyr/drivers/mm/rat.h diff --git a/drivers/mm/CMakeLists.txt b/drivers/mm/CMakeLists.txt index e04fb70d2868..98781346a9e3 100644 --- a/drivers/mm/CMakeLists.txt +++ b/drivers/mm/CMakeLists.txt @@ -15,3 +15,5 @@ zephyr_sources_ifdef( mm_drv_intel_adsp_regions.c mm_drv_intel_adsp_mtl_tlb.c ) + +zephyr_sources_ifdef(CONFIG_MM_TI_RAT mm_drv_ti_rat.c) diff --git a/drivers/mm/Kconfig b/drivers/mm/Kconfig index 15c418c78a4b..f53312b84703 100644 --- a/drivers/mm/Kconfig +++ b/drivers/mm/Kconfig @@ -44,4 +44,23 @@ config MM_DRV_INTEL_ADSP_TLB Driver for the translation lookup buffer on Intel Audio DSP hardware. +config EXTERNAL_ADDRESS_TRANSLATION + bool "Support for external address translation modules" + depends on !MMU + help + This config is intended to support an external address + translation module if required for an SoC. Uses the + sys_mm_drv_page_phys_get() function from the system_mm API. + +if EXTERNAL_ADDRESS_TRANSLATION + +config MM_TI_RAT + bool "Texas Instruments RAT module" + depends on EXTERNAL_ADDRESS_TRANSLATION + help + Enables Region based address translation support + functions specific to TI SoCs. + +endif # EXTERNAL_ADDRESS_TRANSLATION + endif # MM_DRV diff --git a/drivers/mm/mm_drv_ti_rat.c b/drivers/mm/mm_drv_ti_rat.c new file mode 100644 index 000000000000..19fdb6cbb2d2 --- /dev/null +++ b/drivers/mm/mm_drv_ti_rat.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * Copyright (c) 2023 L Lakshmanan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Driver handling Region based Address Translation (RAT) + * related functions + * + * RAT is a module that is used by certain Texas Instruments SoCs + * to allow some cores with a 32 bit address space to access + * the full 48 bit SoC address space. This is required for the + * core to be able to use peripherals. + * + * The driver uses the sys_mm_drv_page_phys_get() API to access + * the address space. + */ + +#include +#include +#include + +static struct address_trans_params translate_config; + +/** + * @brief Set registers for the address regions being used + * + * @param addr_translate_config Pointer to config struct for the RAT module + * @param region_num Number of regions being initialised + * @param enable Region status + */ + +static void address_trans_set_region(struct address_trans_params *addr_translate_config, + uint16_t region_num, uint32_t enable) +{ + uint32_t rat_base_addr = addr_translate_config->rat_base_addr; + uint64_t system_addr = addr_translate_config->region_config[region_num].system_addr; + uint32_t local_addr = addr_translate_config->region_config[region_num].local_addr; + uint32_t size = addr_translate_config->region_config[region_num].size; + uint32_t system_addrL, system_addrH; + + if (size > address_trans_region_size_4G) { + size = address_trans_region_size_4G; + } + system_addrL = (uint32_t)(system_addr & ~((uint32_t)((BIT64_MASK(size))))); + system_addrH = (uint32_t)((system_addr >> 32) & 0xFFFF); + local_addr = local_addr & ~((uint32_t)(BIT64_MASK(size))); + + sys_write32(0, RAT_CTRL(rat_base_addr, region_num)); + sys_write32(local_addr, RAT_BASE(rat_base_addr, region_num)); + sys_write32(system_addrL, RAT_TRANS_L(rat_base_addr, region_num)); + sys_write32(system_addrH, RAT_TRANS_H(rat_base_addr, region_num)); + sys_write32(RAT_CTRL_W(enable, size), RAT_CTRL(rat_base_addr, region_num)); +} + +static void address_trans_init(struct address_trans_params *params) +{ + uint32_t i; + + if (params != NULL) { + translate_config = *params; + } + + __ASSERT(translate_config.num_regions < ADDR_TRANSLATE_MAX_REGIONS, + "Exceeding maximum number of regions"); + + for (i = 0; i < translate_config.num_regions; i++) { + __ASSERT(translate_config.rat_base_addr != 0, "RAT base address cannot be 0"); + __ASSERT(translate_config.region_config != NULL, + "RAT region config cannot be NULL"); + + /* enable regions setup by user */ + address_trans_set_region(&translate_config, i, 1); + } +} + +/** + * @brief Initialise RAT module + * + * @param region_config Pointer to config struct for the regions + * @param rat_base_addr Base address for the RAT module + * @param translate_regions Number of regions being initialised + */ + +void sys_mm_drv_ti_rat_init(void *region_config, uint64_t rat_base_addr, uint8_t translate_regions) +{ + translate_config.num_regions = translate_regions; + translate_config.rat_base_addr = rat_base_addr; + translate_config.region_config = (struct address_trans_region_config *)region_config; + + address_trans_init(&translate_config); +} + +int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) +{ + if (virt == NULL) { + return -EINVAL; + } + uint64_t pa = ((uint64_t) (virt)); + uintptr_t *va = phys; + + uint32_t found, regionId; + + __ASSERT(translate_config.num_regions < address_trans_MAX_REGIONS, + "Exceeding maximum number of regions"); + + found = 0; + + for (regionId = 0; regionId < translate_config.num_regions; regionId++) { + uint64_t start_addr, end_addr; + uint32_t size_mask; + + size_mask = + ((uint32_t)((BIT64_MASK(translate_config.region_config[regionId].size)))); + + start_addr = translate_config.region_config[regionId].system_addr; + + end_addr = start_addr + size_mask; + + if (pa >= start_addr && pa <= end_addr) { + found = 1; + break; + } + } + if (found) { + /* translate input address to output address */ + uint32_t offset = + pa - translate_config.region_config[regionId].system_addr; + + *va = (void *)(translate_config.region_config[regionId].local_addr + offset); + } else { + /* no mapping found, set output = input with 32b truncation */ + *va = (void *)pa; + } + + if (va == NULL) { + return -EFAULT; + } + return 0; +} diff --git a/include/zephyr/drivers/mm/rat.h b/include/zephyr/drivers/mm/rat.h new file mode 100644 index 000000000000..984c4ef01d47 --- /dev/null +++ b/include/zephyr/drivers/mm/rat.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * Copyright (c) 2023 L Lakshmanan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_RAT_H_ +#define ZEPHYR_INCLUDE_RAT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define ADDR_TRANSLATE_MAX_REGIONS (16u) +#define RAT_CTRL(base_addr, i) (volatile uint32_t *)(base_addr + 0x20 + 0x10 * (i)) +#define RAT_BASE(base_addr, i) (volatile uint32_t *)(base_addr + 0x24 + 0x10 * (i)) +#define RAT_TRANS_L(base_addr, i) (volatile uint32_t *)(base_addr + 0x28 + 0x10 * (i)) +#define RAT_TRANS_H(base_addr, i) (volatile uint32_t *)(base_addr + 0x2C + 0x10 * (i)) +#define RAT_CTRL_W(enable, size) (((enable & 0x1) << 31u) | (size & 0x3F)) + +/** + * @brief Enum's to represent different possible region size for the address translate module + */ +enum address_trans_region_size { + address_trans_region_size_1 = 0x0, + address_trans_region_size_2, + address_trans_region_size_4, + address_trans_region_size_8, + address_trans_region_size_16, + address_trans_region_size_32, + address_trans_region_size_64, + address_trans_region_size_128, + address_trans_region_size_256, + address_trans_region_size_512, + address_trans_region_size_1K, + address_trans_region_size_2K, + address_trans_region_size_4K, + address_trans_region_size_8K, + address_trans_region_size_16K, + address_trans_region_size_32K, + address_trans_region_size_64K, + address_trans_region_size_128K, + address_trans_region_size_256K, + address_trans_region_size_512K, + address_trans_region_size_1M, + address_trans_region_size_2M, + address_trans_region_size_4M, + address_trans_region_size_8M, + address_trans_region_size_16M, + address_trans_region_size_32M, + address_trans_region_size_64M, + address_trans_region_size_128M, + address_trans_region_size_256M, + address_trans_region_size_512M, + address_trans_region_size_1G, + address_trans_region_size_2G, + address_trans_region_size_4G +}; + +/** + * @brief Region config structure + */ +struct address_trans_region_config { + uint64_t system_addr; + uint32_t local_addr; + uint32_t size; +}; + +/** + * @brief Parameters for address_trans_init + */ +struct address_trans_params { + uint32_t num_regions; + uint32_t rat_base_addr; + struct address_trans_region_config *region_config; +}; + +void sys_mm_drv_ti_rat_init(void *region_config, uint64_t rat_base_addr, uint8_t translate_regions); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_RAT_H_ */ diff --git a/include/zephyr/sys/device_mmio.h b/include/zephyr/sys/device_mmio.h index bc28c3e91e44..4358e246339d 100644 --- a/include/zephyr/sys/device_mmio.h +++ b/include/zephyr/sys/device_mmio.h @@ -33,10 +33,14 @@ * If we have PCIE enabled, this does mean that non-PCIE drivers may waste * a bit of RAM, but systems with PCI express are not RAM constrained. */ -#if defined(CONFIG_MMU) || defined(CONFIG_PCIE) +#if defined(CONFIG_MMU) || defined(CONFIG_PCIE) || defined(CONFIG_EXTERNAL_ADDRESS_TRANSLATION) #define DEVICE_MMIO_IS_IN_RAM #endif +#if defined(CONFIG_EXTERNAL_ADDRESS_TRANSLATION) +#include +#endif + #ifndef _ASMLANGUAGE #include #include @@ -101,8 +105,11 @@ static inline void device_map(mm_reg_t *virt_addr, uintptr_t phys_addr, #else ARG_UNUSED(size); ARG_UNUSED(flags); - +#ifdef CONFIG_EXTERNAL_ADDRESS_TRANSLATION + sys_mm_drv_page_phys_get((void *) phys_addr, virt_addr); +#else *virt_addr = phys_addr; +#endif /* CONFIG_EXTERNAL_ADDRESS_TRANSLATION */ #endif /* CONFIG_MMU */ } #else From cb9d1607b33b566df932c034c6ad7e63948279ed Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 14 Mar 2023 23:00:25 +0200 Subject: [PATCH 1109/2042] drivers: uart_rcar: do MMIO mapping inside driver Add MMIO mapping for UART Renesas driver in order to avoid mappings inside mmu_regions.c file(s). There are a lot of changes inside SCIF driver inside this commit, because reg addr and size may be stored in RAM or ROM and appropriately in different driver structures data or cfg, and, because the name of field reg base is changed. Note: it is common approach according to Zephyr documentation. Signed-off-by: Mykola Kvach --- drivers/serial/uart_rcar.c | 133 ++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 74 deletions(-) diff --git a/drivers/serial/uart_rcar.c b/drivers/serial/uart_rcar.c index 821a4f26ff86..b8011244a469 100644 --- a/drivers/serial/uart_rcar.c +++ b/drivers/serial/uart_rcar.c @@ -17,7 +17,7 @@ #include struct uart_rcar_cfg { - uint32_t reg_addr; + DEVICE_MMIO_ROM; /* Must be first */ const struct device *clock_dev; struct rcar_cpg_clk mod_clk; struct rcar_cpg_clk bus_clk; @@ -28,6 +28,7 @@ struct uart_rcar_cfg { }; struct uart_rcar_data { + DEVICE_MMIO_RAM; /* Must be first */ struct uart_config current_config; uint32_t clk_rate; struct k_spinlock lock; @@ -103,38 +104,36 @@ struct uart_rcar_data { #define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ -static void uart_rcar_write_8(const struct uart_rcar_cfg *config, +static void uart_rcar_write_8(const struct device *dev, uint32_t offs, uint8_t value) { - sys_write8(value, config->reg_addr + offs); + sys_write8(value, DEVICE_MMIO_GET(dev) + offs); } -static uint16_t uart_rcar_read_16(const struct uart_rcar_cfg *config, +static uint16_t uart_rcar_read_16(const struct device *dev, uint32_t offs) { - return sys_read16(config->reg_addr + offs); + return sys_read16(DEVICE_MMIO_GET(dev) + offs); } -static void uart_rcar_write_16(const struct uart_rcar_cfg *config, +static void uart_rcar_write_16(const struct device *dev, uint32_t offs, uint16_t value) { - sys_write16(value, config->reg_addr + offs); + sys_write16(value, DEVICE_MMIO_GET(dev) + offs); } static void uart_rcar_set_baudrate(const struct device *dev, uint32_t baud_rate) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint8_t reg_val; reg_val = ((data->clk_rate + 16 * baud_rate) / (32 * baud_rate) - 1); - uart_rcar_write_8(config, SCBRR, reg_val); + uart_rcar_write_8(dev, SCBRR, reg_val); } static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; int ret = 0; @@ -142,16 +141,16 @@ static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) k_spinlock_key_t key = k_spin_lock(&data->lock); /* Receive FIFO empty */ - if (!((uart_rcar_read_16(config, SCFSR)) & SCFSR_RDF)) { + if (!((uart_rcar_read_16(dev, SCFSR)) & SCFSR_RDF)) { ret = -1; goto unlock; } - *p_char = uart_rcar_read_16(config, SCFRDR); + *p_char = uart_rcar_read_16(dev, SCFRDR); - reg_val = uart_rcar_read_16(config, SCFSR); + reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~SCFSR_RDF; - uart_rcar_write_16(config, SCFSR, reg_val); + uart_rcar_write_16(dev, SCFSR, reg_val); unlock: k_spin_unlock(&data->lock, key); @@ -161,20 +160,19 @@ static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) static void uart_rcar_poll_out(const struct device *dev, unsigned char out_char) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); /* Wait for empty space in transmit FIFO */ - while (!(uart_rcar_read_16(config, SCFSR) & SCFSR_TDFE)) { + while (!(uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE)) { } - uart_rcar_write_8(config, SCFTDR, out_char); + uart_rcar_write_8(dev, SCFTDR, out_char); - reg_val = uart_rcar_read_16(config, SCFSR); + reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_TDFE | SCFSR_TEND); - uart_rcar_write_16(config, SCFSR, reg_val); + uart_rcar_write_16(dev, SCFSR, reg_val); k_spin_unlock(&data->lock, key); } @@ -182,7 +180,6 @@ static void uart_rcar_poll_out(const struct device *dev, unsigned char out_char) static int uart_rcar_configure(const struct device *dev, const struct uart_config *cfg) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; @@ -198,50 +195,50 @@ static int uart_rcar_configure(const struct device *dev, key = k_spin_lock(&data->lock); /* Disable Transmit and Receive */ - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_TE | SCSCR_RE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); /* Emptying Transmit and Receive FIFO */ - reg_val = uart_rcar_read_16(config, SCFCR); + reg_val = uart_rcar_read_16(dev, SCFCR); reg_val |= (SCFCR_TFRST | SCFCR_RFRST); - uart_rcar_write_16(config, SCFCR, reg_val); + uart_rcar_write_16(dev, SCFCR, reg_val); /* Resetting Errors Registers */ - reg_val = uart_rcar_read_16(config, SCFSR); + reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_ER | SCFSR_DR | SCFSR_BRK | SCFSR_RDF); - uart_rcar_write_16(config, SCFSR, reg_val); + uart_rcar_write_16(dev, SCFSR, reg_val); - reg_val = uart_rcar_read_16(config, SCLSR); + reg_val = uart_rcar_read_16(dev, SCLSR); reg_val &= ~(SCLSR_TO | SCLSR_ORER); - uart_rcar_write_16(config, SCLSR, reg_val); + uart_rcar_write_16(dev, SCLSR, reg_val); /* Select internal clock */ - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_CKE1 | SCSCR_CKE0); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); /* Serial Configuration (8N1) & Clock divider selection */ - reg_val = uart_rcar_read_16(config, SCSMR); + reg_val = uart_rcar_read_16(dev, SCSMR); reg_val &= ~(SCSMR_C_A | SCSMR_CHR | SCSMR_PE | SCSMR_O_E | SCSMR_STOP | SCSMR_CKS1 | SCSMR_CKS0); - uart_rcar_write_16(config, SCSMR, reg_val); + uart_rcar_write_16(dev, SCSMR, reg_val); /* Set baudrate */ uart_rcar_set_baudrate(dev, cfg->baudrate); /* FIFOs data count trigger configuration */ - reg_val = uart_rcar_read_16(config, SCFCR); + reg_val = uart_rcar_read_16(dev, SCFCR); reg_val &= ~(SCFCR_RTRG1 | SCFCR_RTRG0 | SCFCR_TTRG1 | SCFCR_TTRG0 | SCFCR_MCE | SCFCR_TFRST | SCFCR_RFRST); - uart_rcar_write_16(config, SCFCR, reg_val); + uart_rcar_write_16(dev, SCFCR, reg_val); /* Enable Transmit & Receive + disable Interrupts */ - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_TE | SCSCR_RE); reg_val &= ~(SCSCR_TIE | SCSCR_RIE | SCSCR_TEIE | SCSCR_REIE | SCSCR_TOIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); data->current_config = *cfg; @@ -291,6 +288,8 @@ static int uart_rcar_init(const struct device *dev) return ret; } + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + ret = uart_rcar_configure(dev, &data->current_config); if (ret != 0) { return ret; @@ -308,29 +307,26 @@ static int uart_rcar_init(const struct device *dev) static bool uart_rcar_irq_is_enabled(const struct device *dev, uint32_t irq) { - const struct uart_rcar_cfg *config = dev->config; - - return !!(uart_rcar_read_16(config, SCSCR) & irq); + return !!(uart_rcar_read_16(dev, SCSCR) & irq); } static int uart_rcar_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; int num_tx = 0; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); while (((len - num_tx) > 0) && - (uart_rcar_read_16(config, SCFSR) & SCFSR_TDFE)) { + (uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE)) { /* Send current byte */ - uart_rcar_write_8(config, SCFTDR, tx_data[num_tx]); + uart_rcar_write_8(dev, SCFTDR, tx_data[num_tx]); - reg_val = uart_rcar_read_16(config, SCFSR); + reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_TDFE | SCFSR_TEND); - uart_rcar_write_16(config, SCFSR, reg_val); + uart_rcar_write_16(dev, SCFSR, reg_val); num_tx++; } @@ -343,20 +339,19 @@ static int uart_rcar_fifo_fill(const struct device *dev, static int uart_rcar_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; int num_rx = 0; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); while (((size - num_rx) > 0) && - (uart_rcar_read_16(config, SCFSR) & SCFSR_RDF)) { + (uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF)) { /* Receive current byte */ - rx_data[num_rx++] = uart_rcar_read_16(config, SCFRDR); + rx_data[num_rx++] = uart_rcar_read_16(dev, SCFRDR); - reg_val = uart_rcar_read_16(config, SCFSR); + reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_RDF); - uart_rcar_write_16(config, SCFSR, reg_val); + uart_rcar_write_16(dev, SCFSR, reg_val); } @@ -367,104 +362,94 @@ static int uart_rcar_fifo_read(const struct device *dev, uint8_t *rx_data, static void uart_rcar_irq_tx_enable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_TIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_tx_disable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_TIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_irq_tx_ready(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; - - return !!(uart_rcar_read_16(config, SCFSR) & SCFSR_TDFE); + return !!(uart_rcar_read_16(dev, SCFSR) & SCFSR_TDFE); } static void uart_rcar_irq_rx_enable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_RIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_rx_disable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_RIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static int uart_rcar_irq_rx_ready(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; - - return !!(uart_rcar_read_16(config, SCFSR) & SCFSR_RDF); + return !!(uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF); } static void uart_rcar_irq_err_enable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val |= (SCSCR_REIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } static void uart_rcar_irq_err_disable(const struct device *dev) { - const struct uart_rcar_cfg *config = dev->config; struct uart_rcar_data *data = dev->data; uint16_t reg_val; k_spinlock_key_t key = k_spin_lock(&data->lock); - reg_val = uart_rcar_read_16(config, SCSCR); + reg_val = uart_rcar_read_16(dev, SCSCR); reg_val &= ~(SCSCR_REIE); - uart_rcar_write_16(config, SCSCR, reg_val); + uart_rcar_write_16(dev, SCSCR, reg_val); k_spin_unlock(&data->lock, key); } @@ -536,7 +521,7 @@ static const struct uart_driver_api uart_rcar_driver_api = { #define UART_RCAR_DECLARE_CFG(n, IRQ_FUNC_INIT) \ PINCTRL_DT_INST_DEFINE(n); \ static const struct uart_rcar_cfg uart_rcar_cfg_##n = { \ - .reg_addr = DT_INST_REG_ADDR(n), \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .mod_clk.module = \ DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module), \ From de639ed34ccd143325a1d77e3a5cbe2ea14a040b Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 14 Mar 2023 23:22:36 +0200 Subject: [PATCH 1110/2042] drivers: pfc_rcar: do MMIO mapping inside driver Add MMIO mapping for PFC Renesas driver in order to avoid mappings inside mmu_regions.c file. Add a new system init function pfc_rcar_driver_init to PFC Renesas driver for invoking a memory mapping macro. Note: PFC Renesas driver doesn't use Zephyr Device Model. Signed-off-by: Mykola Kvach --- drivers/pinctrl/pfc_rcar.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 624df1c051d4..50908fbd2f8e 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -12,8 +12,11 @@ #include #include #include +#include -#define PFC_REG_BASE DT_INST_REG_ADDR(0) +DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); + +#define PFC_REG_BASE DEVICE_MMIO_TOPLEVEL_GET(pfc) #define PFC_RCAR_PMMR 0x0 #define PFC_RCAR_GPSR 0x100 #define PFC_RCAR_IPSR 0x200 @@ -214,3 +217,11 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, return ret; } + +__boot_func static int pfc_rcar_driver_init(void) +{ + DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE); + return 0; +} + +SYS_INIT(pfc_rcar_driver_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From e747e236ec95db74cc60189c44e8567fed70b2a7 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Mon, 24 Apr 2023 10:49:46 +0300 Subject: [PATCH 1111/2042] drivers: rcar_cpg: move cpg log module declare to common rcar cpg file Move cpg log module declare to common rcar cpg file. If the module consists of multiple files, then LOG_MODULE_REGISTER should appear in exactly one of them. Each other file should use LOG_MODULE_DECLARE to declare its membership in the module. Signed-off-by: Mykola Kvach --- drivers/clock_control/clock_control_r8a7795_cpg_mssr.c | 6 +++--- drivers/clock_control/clock_control_renesas_cpg_mssr.c | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index ecd2da94b169..d3a1484e2405 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -17,10 +17,10 @@ #include #include #include "clock_control_renesas_cpg_mssr.h" - -#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL #include -LOG_MODULE_REGISTER(clock_control_rcar); + +LOG_MODULE_DECLARE(clock_control_rcar); + struct r8a7795_cpg_mssr_config { mm_reg_t base_address; diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.c b/drivers/clock_control/clock_control_renesas_cpg_mssr.c index aa45465268af..b108eca83de7 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.c +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.c @@ -11,6 +11,10 @@ #include #include "clock_control_renesas_cpg_mssr.h" +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(clock_control_rcar); + static void rcar_cpg_reset(uint32_t base_address, uint32_t reg, uint32_t bit) { rcar_cpg_write(base_address, srcr[reg], BIT(bit)); From 6f24edf5c8ae5062c26cf4a344eefb9fd74c3e3b Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 4 Apr 2023 19:29:45 +0300 Subject: [PATCH 1112/2042] drivers: rcar_cpg: add generic Renesas functions for get/set rate Add associated tables of clocks and API for working with these tables, from this moment the relationship between clocks and their divider are built. After set rate of some Core clock, driver has to update all in/out rates of all childrens recursively. During get/set rate calls if out rate is unknown, we try to get parent in/out rates and its divider, in case when parent doesn't have valid in/out rates we get parent of parent and so on until we get parent with a valid in or out rates. Add generic Renesas functions for get/set rate of CPG. Signed-off-by: Mykola Kvach --- .../clock_control_r8a7795_cpg_mssr.c | 1 - .../clock_control_renesas_cpg_mssr.c | 371 ++++++++++++++++++ .../clock_control_renesas_cpg_mssr.h | 80 ++++ 3 files changed, 451 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index d3a1484e2405..6f1281dbc346 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.c b/drivers/clock_control/clock_control_renesas_cpg_mssr.c index b108eca83de7..c1b453906014 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.c +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.c @@ -10,6 +10,7 @@ #include #include #include "clock_control_renesas_cpg_mssr.h" +#include #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL #include @@ -58,3 +59,373 @@ int rcar_cpg_mstp_clock_endisable(uint32_t base_address, uint32_t module, bool e return 0; } + +static int cmp_cpg_clk_info_table_items(const void *key, const void *element) +{ + const struct cpg_clk_info_table *e = element; + uint32_t module = (uintptr_t)key; + + if (e->module == module) { + return 0; + } else if (e->module < module) { + return 1; + } else { + return -1; + } +} + +struct cpg_clk_info_table * +rcar_cpg_find_clk_info_by_module_id(const struct device *dev, uint32_t domain, uint32_t id) +{ + struct rcar_cpg_mssr_data *data = dev->data; + struct cpg_clk_info_table *item; + struct cpg_clk_info_table *table = data->clk_info_table[domain]; + uint32_t table_size = data->clk_info_table_size[domain]; + uintptr_t uintptr_id = id; + + item = bsearch((void *)uintptr_id, table, table_size, sizeof(*item), + cmp_cpg_clk_info_table_items); + if (!item) { + LOG_ERR("%s: can't find clk info (domain %u module %u)", dev->name, domain, id); + } + + return item; +} + +static uint32_t rcar_cpg_get_divider(const struct device *dev, struct cpg_clk_info_table *clk_info) +{ + mem_addr_t reg_addr; + mm_reg_t reg_val; + uint32_t divider = RCAR_CPG_NONE; + struct rcar_cpg_mssr_data *data = dev->data; + + if (clk_info->domain == CPG_MOD) { + return 1; + } + + reg_addr = clk_info->offset; + if (reg_addr == RCAR_CPG_NONE) { + /* if we don't have valid offset, in is equal to out */ + return 1; + } + + reg_addr += data->base_addr; + reg_val = sys_read32(reg_addr); + + if (data->get_div_helper) { + divider = data->get_div_helper(reg_val, clk_info->module); + } + + if (!divider) { + return RCAR_CPG_NONE; + } + + return divider; +} + +static int rcar_cpg_update_out_freq(const struct device *dev, struct cpg_clk_info_table *clk_info) +{ + uint32_t divider = rcar_cpg_get_divider(dev, clk_info); + + if (divider == RCAR_CPG_NONE) { + return -EINVAL; + } + + clk_info->out_freq = clk_info->in_freq / divider; + return 0; +} + +static int64_t rcar_cpg_get_in_update_out_freq(const struct device *dev, + struct cpg_clk_info_table *clk_info) +{ + int64_t freq = -ENOTSUP; + struct cpg_clk_info_table *parent_clk; + + if (!clk_info) { + return freq; + } + + if (clk_info->in_freq != RCAR_CPG_NONE) { + if (clk_info->out_freq == RCAR_CPG_NONE) { + if (rcar_cpg_update_out_freq(dev, clk_info) < 0) { + return freq; + } + } + return clk_info->in_freq; + } + + parent_clk = clk_info->parent; + + freq = rcar_cpg_get_in_update_out_freq(dev, parent_clk); + if (freq < 0) { + return freq; + } + + clk_info->in_freq = parent_clk->out_freq; + + freq = rcar_cpg_update_out_freq(dev, clk_info); + if (freq < 0) { + return freq; + } + + return clk_info->in_freq; +} + +static int64_t rcar_cpg_get_out_freq(const struct device *dev, struct cpg_clk_info_table *clk_info) +{ + int64_t freq; + + if (clk_info->out_freq != RCAR_CPG_NONE) { + return clk_info->out_freq; + } + + freq = rcar_cpg_get_in_update_out_freq(dev, clk_info); + if (freq < 0) { + return freq; + } + + return clk_info->out_freq; +} + +static void rcar_cpg_change_children_in_out_freq(const struct device *dev, + struct cpg_clk_info_table *parent) +{ + struct cpg_clk_info_table *children_list = parent->children_list; + + while (children_list) { + children_list->in_freq = parent->out_freq; + + if (rcar_cpg_update_out_freq(dev, children_list) < 0) { + /* + * Why it can happen: + * - divider is zero (with current implementation of board specific + * divider helper function it is impossible); + * - we don't have board specific implementation of get divider helper + * function; + * - we don't have this module in a table (for some of call chains of + * this function it is impossible); + * - impossible value is set in clock register divider bits. + */ + LOG_ERR("%s: error during getting divider from clock register, domain %u " + "module %u! Please, revise logic related to obtaining divider or " + "check presentence of clock inside appropriate clk_info_table", + dev->name, children_list->domain, children_list->module); + k_panic(); + return; + } + + /* child can have childrens */ + rcar_cpg_change_children_in_out_freq(dev, children_list); + children_list = children_list->next_sibling; + } +} + +int rcar_cpg_get_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *rate) +{ + int64_t ret; + struct rcar_cpg_mssr_data *data; + struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; + k_spinlock_key_t key; + + struct cpg_clk_info_table *clk_info; + + if (!dev || !sys || !rate) { + LOG_ERR("%s: received null ptr input arg(s) dev %p sys %p rate %p", + __func__, dev, sys, rate); + return -EINVAL; + } + + clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); + if (clk_info == NULL) { + return -EINVAL; + } + + data = dev->data; + + key = k_spin_lock(&data->lock); + ret = rcar_cpg_get_out_freq(dev, clk_info); + k_spin_unlock(&data->lock, key); + + if (ret < 0) { + LOG_ERR("%s: clk (domain %u module %u) error (%lld) during getting out frequency", + dev->name, clk->domain, clk->module, ret); + return -EINVAL; + } else if (ret > UINT_MAX) { + LOG_ERR("%s: clk (domain %u module %u) frequency bigger then max uint value", + dev->name, clk->domain, clk->module); + return -EINVAL; + } + + *rate = ret; + return 0; +} + +int rcar_cpg_set_rate(const struct device *dev, clock_control_subsys_t sys, + clock_control_subsys_rate_t rate) +{ + int ret = -ENOTSUP; + k_spinlock_key_t key; + struct cpg_clk_info_table *clk_info; + struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; + struct rcar_cpg_mssr_data *data; + int64_t in_freq; + uint32_t divider; + uint32_t div_mask; + uint32_t module; + uintptr_t u_rate = (uintptr_t)rate; + + if (!dev || !sys || !rate) { + LOG_ERR("%s: received null ptr input arg(s) dev %p sys %p rate %p", + __func__, dev, sys, rate); + return -EINVAL; + } + + clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); + if (clk_info == NULL) { + return -EINVAL; + } + + if (clk_info->domain == CPG_MOD) { + if (!clk_info->parent) { + LOG_ERR("%s: parent isn't present for module clock, module id %u", + dev->name, clk_info->module); + k_panic(); + } + clk_info = clk_info->parent; + } + + module = clk_info->module; + data = dev->data; + + key = k_spin_lock(&data->lock); + in_freq = rcar_cpg_get_in_update_out_freq(dev, clk_info); + if (in_freq < 0) { + ret = in_freq; + goto unlock; + } + + divider = in_freq / u_rate; + if (divider * u_rate != in_freq) { + ret = -EINVAL; + goto unlock; + } + + if (!data->set_rate_helper) { + ret = -ENOTSUP; + goto unlock; + } + + ret = data->set_rate_helper(module, ÷r, &div_mask); + if (!ret) { + int64_t out_rate; + uint32_t reg = sys_read32(clk_info->offset + data->base_addr); + + reg &= ~div_mask; + rcar_cpg_write(data->base_addr, clk_info->offset, reg | divider); + + clk_info->out_freq = RCAR_CPG_NONE; + + out_rate = rcar_cpg_get_out_freq(dev, clk_info); + if (out_rate < 0 || out_rate != u_rate) { + ret = -EINVAL; + LOG_ERR("%s: clock (domain %u module %u) register cfg freq (%lld) " + "isn't equal to requested %lu", + dev->name, clk->domain, clk->module, out_rate, u_rate); + goto unlock; + } + + rcar_cpg_change_children_in_out_freq(dev, clk_info); + } + +unlock: + k_spin_unlock(&data->lock, key); + return ret; +} + +void rcar_cpg_build_clock_relationship(const struct device *dev) +{ + uint32_t domain; + k_spinlock_key_t key; + struct rcar_cpg_mssr_data *data = dev->data; + + if (!data) { + return; + } + + key = k_spin_lock(&data->lock); + for (domain = 0; domain < CPG_NUM_DOMAINS; domain++) { + uint32_t idx; + uint32_t prev_mod_id = 0; + struct cpg_clk_info_table *item = data->clk_info_table[domain]; + + for (idx = 0; idx < data->clk_info_table_size[domain]; idx++, item++) { + struct cpg_clk_info_table *parent; + + /* check if an array is sorted by module id or not */ + if (prev_mod_id >= item->module) { + LOG_ERR("%s: clocks have to be sorted inside clock table in " + "ascending order by module id field, domain %u " + "module id %u", + dev->name, item->domain, item->module); + k_panic(); + } + + prev_mod_id = item->module; + + if (item->parent_id == RCAR_CPG_NONE) { + continue; + } + + parent = rcar_cpg_find_clk_info_by_module_id(dev, CPG_CORE, + item->parent_id); + if (!parent) { + LOG_ERR("%s: can't find parent for clock with valid parent id, " + "domain %u module id %u", + dev->name, item->domain, item->module); + k_panic(); + } + + if (item->parent != NULL) { + LOG_ERR("%s: trying to set another parent for a clock, domain %u " + "module id %u, parent for the clock has been already set", + dev->name, item->domain, item->module); + k_panic(); + } + + item->parent = parent; + + /* insert in the head of the children list of the parent */ + item->next_sibling = parent->children_list; + parent->children_list = item; + } + } + k_spin_unlock(&data->lock, key); +} + +void rcar_cpg_update_all_in_out_freq(const struct device *dev) +{ + uint32_t domain; + k_spinlock_key_t key; + struct rcar_cpg_mssr_data *data = dev->data; + + if (!data) { + return; + } + + key = k_spin_lock(&data->lock); + for (domain = 0; domain < CPG_NUM_DOMAINS; domain++) { + uint32_t idx; + struct cpg_clk_info_table *item = data->clk_info_table[domain]; + + for (idx = 0; idx < data->clk_info_table_size[domain]; idx++, item++) { + if (rcar_cpg_get_in_update_out_freq(dev, item) < 0) { + LOG_ERR("%s: can't update in/out freq for clock during init, " + "domain %u module %u! Please, review correctness of data " + "inside clk_info_table", + dev->name, item->domain, item->module); + k_panic(); + } + } + } + k_spin_unlock(&data->lock, key); +} diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index bd5a237ee0cc..a20e67609933 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -7,6 +7,73 @@ #ifndef ZEPHYR_DRIVERS_RENESAS_RENESAS_CPG_MSSR_H_ #define ZEPHYR_DRIVERS_RENESAS_RENESAS_CPG_MSSR_H_ +#include +#include +#include + +#define CPG_NUM_DOMAINS 2 + +struct cpg_clk_info_table { + uint32_t domain; + uint32_t module; + mem_addr_t offset; + uint32_t parent_id; + + int64_t in_freq; + int64_t out_freq; + + /* TODO: add setting of this field and add function for getting status */ + enum clock_control_status status; + + struct cpg_clk_info_table *parent; + struct cpg_clk_info_table *children_list; + struct cpg_clk_info_table *next_sibling; +}; + +struct rcar_cpg_mssr_data { + mem_addr_t base_addr; + + struct cpg_clk_info_table *clk_info_table[CPG_NUM_DOMAINS]; + const uint32_t clk_info_table_size[CPG_NUM_DOMAINS]; + + struct k_spinlock lock; + + uint32_t (*get_div_helper)(uint32_t reg, uint32_t module); + int (*set_rate_helper)(uint32_t module, uint32_t *div, uint32_t *div_mask); +}; + +#define RCAR_CPG_NONE -1 +#define RCAR_CPG_KHZ(khz) ((khz) * 1000U) +#define RCAR_CPG_MHZ(mhz) (RCAR_CPG_KHZ(mhz) * 1000U) + +#define RCAR_CORE_CLK_INFO_ITEM(id, off, par_id, in_frq) \ + { \ + .domain = CPG_CORE, \ + .module = id, \ + .offset = off, \ + .parent_id = par_id, \ + .in_freq = in_frq, \ + .out_freq = RCAR_CPG_NONE, \ + .status = CLOCK_CONTROL_STATUS_UNKNOWN, \ + .parent = NULL, \ + .children_list = NULL, \ + .next_sibling = NULL, \ + } + +#define RCAR_MOD_CLK_INFO_ITEM(id, par_id) \ + { \ + .domain = CPG_MOD, \ + .module = id, \ + .offset = RCAR_CPG_NONE, \ + .parent_id = par_id, \ + .in_freq = RCAR_CPG_NONE, \ + .out_freq = RCAR_CPG_NONE, \ + .status = CLOCK_CONTROL_STATUS_UNKNOWN, \ + .parent = NULL, \ + .children_list = NULL, \ + .next_sibling = NULL, \ + } + #ifdef CONFIG_SOC_SERIES_RCAR_GEN3 /* Software Reset Clearing Register offsets */ #define SRSTCLR(i) (0x940 + (i) * 4) @@ -47,4 +114,17 @@ void rcar_cpg_write(uint32_t base_address, uint32_t reg, uint32_t val); int rcar_cpg_mstp_clock_endisable(uint32_t base_address, uint32_t module, bool enable); +struct cpg_clk_info_table *rcar_cpg_find_clk_info_by_module_id(const struct device *dev, + uint32_t domain, + uint32_t id); + +void rcar_cpg_build_clock_relationship(const struct device *dev); + +void rcar_cpg_update_all_in_out_freq(const struct device *dev); + +int rcar_cpg_get_rate(const struct device *dev, clock_control_subsys_t sys, uint32_t *rate); + +int rcar_cpg_set_rate(const struct device *dev, clock_control_subsys_t sys, + clock_control_subsys_rate_t rate); + #endif /* ZEPHYR_DRIVERS_RENESAS_RENESAS_CPG_MSSR_H_ */ From 32e09e7c004aaeea5bf479ba8963ac5b1cf7d8c7 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 4 Apr 2023 19:44:28 +0300 Subject: [PATCH 1113/2042] drivers: rcar_cpg: redesign cpg driver for r8a7795 Add associative tables for core and mod clocks. Add possibility to enable/disable any of core clocks which presents in the associative table. Add handler for setting rate to driver and use generic rcar cpg function for getting rate. Signed-off-by: Mykola Kvach --- .../clock_control_r8a7795_cpg_mssr.c | 293 ++++++++++++++---- 1 file changed, 226 insertions(+), 67 deletions(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index 6f1281dbc346..ea933a0351ec 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -20,134 +20,293 @@ LOG_MODULE_DECLARE(clock_control_rcar); +#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_DIV_SHIFT 2 + +#define R8A7795_CLK_CANFD_STOP_BIT 8 +#define R8A7795_CLK_CANFD_DIV_MASK 0x3f struct r8a7795_cpg_mssr_config { mm_reg_t base_address; }; -int r8a7795_cpg_core_clock_endisable(uint32_t base_address, uint32_t module, - uint32_t rate, bool enable) +struct r8a7795_cpg_mssr_data { + struct rcar_cpg_mssr_data cmn; +}; + +/* 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_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)), + + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD1H, 0x0078, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD1, 0x0078, R8A7795_CLK_SD1H, RCAR_CPG_MHZ(800)), + + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD2H, 0x0268, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD2, 0x0268, R8A7795_CLK_SD2H, RCAR_CPG_MHZ(800)), + + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD3H, 0x026C, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD3, 0x026C, R8A7795_CLK_SD3H, RCAR_CPG_MHZ(800)), + + 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)), +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table mod_props[] = { + RCAR_MOD_CLK_INFO_ITEM(310, R8A7795_CLK_S3D4), + + RCAR_MOD_CLK_INFO_ITEM(311, R8A7795_CLK_SD3), + RCAR_MOD_CLK_INFO_ITEM(312, R8A7795_CLK_SD2), + RCAR_MOD_CLK_INFO_ITEM(313, R8A7795_CLK_SD1), + RCAR_MOD_CLK_INFO_ITEM(314, R8A7795_CLK_SD0), +}; + +static int r8a7795_cpg_enable_disable_core(const struct r8a7795_cpg_mssr_config *cfg, + struct cpg_clk_info_table *clk_info, + uint32_t enable) { - uint32_t divider; - unsigned int key; int ret = 0; + uint32_t reg; - /* Only support CANFD core clock at the moment */ - if (module != R8A7795_CLK_CANFD) { - return -EINVAL; + enable = !!enable; + + switch (clk_info->module) { + case R8A7795_CLK_SD0: + case R8A7795_CLK_SD1: + case R8A7795_CLK_SD2: + case R8A7795_CLK_SD3: + reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset); + reg &= ~(1 << R8A7795_CLK_SD_STOP_BIT); + reg |= (!enable << R8A7795_CLK_SD_STOP_BIT); + break; + case R8A7795_CLK_SD0H: + case R8A7795_CLK_SD1H: + case R8A7795_CLK_SD2H: + case R8A7795_CLK_SD3H: + reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset); + reg &= ~(1 << R8A7795_CLK_SDH_STOP_BIT); + reg |= (!enable << R8A7795_CLK_SDH_STOP_BIT); + break; + case R8A7795_CLK_CANFD: + reg = sys_read32(DEVICE_MMIO_GET(dev) + clk_info->offset); + reg &= ~(1 << R8A7795_CLK_CANFD_STOP_BIT); + reg |= (!enable << R8A7795_CLK_CANFD_STOP_BIT); + break; + default: + ret = -ENOTSUP; + break; } - key = irq_lock(); + if (!ret) { + rcar_cpg_write(cfg->base_address, clk_info->offset, reg); + } + return ret; +} + +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; + const struct r8a7795_cpg_mssr_config *cfg = dev->config; + 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) { + return -EINVAL; + } if (enable) { - if (rate > 0) { - if ((CANFDCKCR_PARENT_CLK_RATE % rate) != 0) { - LOG_ERR("Can not generate %u from CANFD parent clock", rate); - ret = -EINVAL; - goto unlock; - } + if (clk->rate > 0) { + uintptr_t rate = clk->rate; - divider = (CANFDCKCR_PARENT_CLK_RATE / rate) - 1; - if (divider > CANFDCKCR_DIVIDER_MASK) { - LOG_ERR("Can not generate %u from CANFD parent clock", rate); - ret = -EINVAL; - goto unlock; + ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, + (clock_control_subsys_rate_t)rate); + if (ret < 0) { + return ret; } - - rcar_cpg_write(base_address, CANFDCKCR, divider); - } else { - LOG_ERR("Can not enable a clock at %u Hz", rate); - ret = -EINVAL; } - } else { - rcar_cpg_write(base_address, CANFDCKCR, CANFDCKCR_CKSTP); } -unlock: - irq_unlock(key); + key = k_spin_lock(&data->cmn.lock); + r8a7795_cpg_enable_disable_core(cfg, clk_info, enable); + k_spin_unlock(&data->cmn.lock, key); + return ret; } -int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) +static int r8a7795_cpg_mssr_start_stop(const struct device *dev, + clock_control_subsys_t sys, + bool enable) { - const struct r8a7795_cpg_mssr_config *config = dev->config; struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; int ret = -EINVAL; + if (!dev || !sys) { + return -EINVAL; + } + if (clk->domain == CPG_MOD) { + const struct r8a7795_cpg_mssr_config *config = dev->config; + struct r8a7795_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->cmn.lock); ret = rcar_cpg_mstp_clock_endisable(config->base_address, clk->module, enable); + k_spin_unlock(&data->cmn.lock, key); } else if (clk->domain == CPG_CORE) { - ret = r8a7795_cpg_core_clock_endisable(config->base_address, clk->module, clk->rate, - enable); + ret = r8a7795_cpg_core_clock_endisable(dev, clk, enable); } return ret; } -static int r8a7795_cpg_mssr_start(const struct device *dev, - clock_control_subsys_t sys) +static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module) { - return r8a7795_cpg_mssr_start_stop(dev, sys, true); -} + uint32_t divider = RCAR_CPG_NONE; -static int r8a7795_cpg_mssr_stop(const struct device *dev, - clock_control_subsys_t sys) -{ - return r8a7795_cpg_mssr_start_stop(dev, sys, false); + switch (module) { + case R8A7795_CLK_SD0H: + case R8A7795_CLK_SD1H: + case R8A7795_CLK_SD2H: + case R8A7795_CLK_SD3H: + 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); + } + 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; + 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; + case R8A7795_CLK_S3D4: + case R8A7795_CLK_S0D12: + divider = 1; + break; + default: + break; + } + + return divider; } -static int r8a7795_cpg_get_rate(const struct device *dev, - clock_control_subsys_t sys, - uint32_t *rate) +static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) { - const struct r8a7795_cpg_mssr_config *config = dev->config; - struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; - uint32_t val; - int ret = 0; - - if (clk->domain != CPG_CORE) { - return -ENOTSUP; - } + int ret = -ENOTSUP; - switch (clk->module) { - case R8A7795_CLK_CANFD: - val = sys_read32(config->base_address + CANFDCKCR); - if (val & CANFDCKCR_CKSTP) { - *rate = 0; + switch (module) { + case R8A7795_CLK_SD0: + case R8A7795_CLK_SD1: + case R8A7795_CLK_SD2: + case R8A7795_CLK_SD3: + /* possible to have only 2 or 4 */ + if (*divider == 2 || *divider == 4) { + /* convert 2/4 to 0/1 */ + *divider >>= 2; + *div_mask = R8A7795_CLK_SD_DIV_MASK << R8A7795_CLK_SD_DIV_SHIFT; + ret = 0; } else { - val &= CANFDCKCR_DIVIDER_MASK; - *rate = CANFDCKCR_PARENT_CLK_RATE / (val + 1); + ret = -EINVAL; } break; - case R8A7795_CLK_S3D4: - *rate = S3D4_CLK_RATE; + 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; + 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; - case R8A7795_CLK_S0D12: - *rate = S0D12_CLK_RATE; + 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; + } else { + ret = -EINVAL; + } break; default: - ret = -ENOTSUP; break; } return ret; } +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) +{ + return r8a7795_cpg_mssr_start_stop(dev, sys, false); +} + +static int r8a7795_cpg_mssr_init(const struct device *dev) +{ + rcar_cpg_build_clock_relationship(dev); + rcar_cpg_update_all_in_out_freq(dev); + return 0; +} + static const struct clock_control_driver_api r8a7795_cpg_mssr_api = { .on = r8a7795_cpg_mssr_start, .off = r8a7795_cpg_mssr_stop, - .get_rate = r8a7795_cpg_get_rate, + .get_rate = rcar_cpg_get_rate, + .set_rate = rcar_cpg_set_rate, }; #define R8A7795_MSSR_INIT(inst) \ static struct r8a7795_cpg_mssr_config r8a7795_cpg_mssr##inst##_config = { \ - .base_address = DT_INST_REG_ADDR(inst) \ + .base_address = DT_INST_REG_ADDR(inst), \ + }; \ + \ + static struct r8a7795_cpg_mssr_data r8a7795_cpg_mssr##inst##_data = { \ + .cmn.base_addr = DT_INST_REG_ADDR(inst), \ + .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 = r8a7795_get_div_helper, \ + .cmn.set_rate_helper = r8a7795_set_rate_helper \ }; \ \ DEVICE_DT_INST_DEFINE(inst, \ + r8a7795_cpg_mssr_init, \ NULL, \ - NULL, \ - NULL, &r8a7795_cpg_mssr##inst##_config, \ + &r8a7795_cpg_mssr##inst##_data, \ + &r8a7795_cpg_mssr##inst##_config, \ PRE_KERNEL_1, \ CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ &r8a7795_cpg_mssr_api); From f66212022d68c7233fc6c165f0021dfb0de1cafd Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 4 Apr 2023 20:03:24 +0300 Subject: [PATCH 1114/2042] drivers: rcar_cpg: delete irq lock/unlock from mstp_clock_endisable Delete IRQ lock/unlock calls from 'rcar_cpg_mstp_clock_endisable', because 'rcar_cpg_mstp_clock_endisable' function is always called under spin lock. Signed-off-by: Mykola Kvach --- drivers/clock_control/clock_control_renesas_cpg_mssr.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.c b/drivers/clock_control/clock_control_renesas_cpg_mssr.c index c1b453906014..4cde5de25eeb 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.c +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.c @@ -36,13 +36,10 @@ int rcar_cpg_mstp_clock_endisable(uint32_t base_address, uint32_t module, bool e uint32_t bit = module % 100; uint32_t bitmask = BIT(bit); uint32_t reg_val; - unsigned int key; __ASSERT((bit < 32) && reg < ARRAY_SIZE(mstpcr), "Invalid module number for cpg clock: %d", module); - key = irq_lock(); - reg_val = sys_read32(base_address + mstpcr[reg]); if (enable) { reg_val &= ~bitmask; @@ -55,8 +52,6 @@ int rcar_cpg_mstp_clock_endisable(uint32_t base_address, uint32_t module, bool e rcar_cpg_reset(base_address, reg, bit); } - irq_unlock(key); - return 0; } From 644b38a3b7906e1f042bb1f8e0731ea6f409c293 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Wed, 5 Apr 2023 01:17:42 +0300 Subject: [PATCH 1115/2042] drivers: rcar_cpg: do MMIO mapping inside driver Add MMIO mapping for Renesas CPG driver in order to avoid mappings inside mmu_regions.c file. Remove MMU region for Renesas CPG driver. Signed-off-by: Mykola Kvach --- .../clock_control_r8a7795_cpg_mssr.c | 19 +++++++++---------- .../clock_control_renesas_cpg_mssr.c | 6 +++--- .../clock_control_renesas_cpg_mssr.h | 3 ++- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index ea933a0351ec..9ce5fe42795f 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -32,11 +32,11 @@ LOG_MODULE_DECLARE(clock_control_rcar); #define R8A7795_CLK_CANFD_DIV_MASK 0x3f struct r8a7795_cpg_mssr_config { - mm_reg_t base_address; + DEVICE_MMIO_ROM; /* Must be first */ }; struct r8a7795_cpg_mssr_data { - struct rcar_cpg_mssr_data cmn; + struct rcar_cpg_mssr_data cmn; /* Must be first */ }; /* NOTE: the array MUST be sorted by module field */ @@ -72,7 +72,7 @@ static struct cpg_clk_info_table mod_props[] = { RCAR_MOD_CLK_INFO_ITEM(314, R8A7795_CLK_SD0), }; -static int r8a7795_cpg_enable_disable_core(const struct r8a7795_cpg_mssr_config *cfg, +static int r8a7795_cpg_enable_disable_core(const struct device *dev, struct cpg_clk_info_table *clk_info, uint32_t enable) { @@ -109,7 +109,7 @@ static int r8a7795_cpg_enable_disable_core(const struct r8a7795_cpg_mssr_config } if (!ret) { - rcar_cpg_write(cfg->base_address, clk_info->offset, reg); + rcar_cpg_write(DEVICE_MMIO_GET(dev), clk_info->offset, reg); } return ret; } @@ -119,7 +119,6 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, bool enable) { struct cpg_clk_info_table *clk_info; - const struct r8a7795_cpg_mssr_config *cfg = dev->config; struct r8a7795_cpg_mssr_data *data = dev->data; k_spinlock_key_t key; int ret = 0; @@ -142,7 +141,7 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, } key = k_spin_lock(&data->cmn.lock); - r8a7795_cpg_enable_disable_core(cfg, clk_info, enable); + r8a7795_cpg_enable_disable_core(dev, clk_info, enable); k_spin_unlock(&data->cmn.lock, key); return ret; @@ -160,12 +159,11 @@ static int r8a7795_cpg_mssr_start_stop(const struct device *dev, } if (clk->domain == CPG_MOD) { - const struct r8a7795_cpg_mssr_config *config = dev->config; struct r8a7795_cpg_mssr_data *data = dev->data; k_spinlock_key_t key; key = k_spin_lock(&data->cmn.lock); - ret = rcar_cpg_mstp_clock_endisable(config->base_address, clk->module, enable); + 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 = r8a7795_cpg_core_clock_endisable(dev, clk, enable); @@ -275,6 +273,8 @@ static int r8a7795_cpg_mssr_stop(const struct device *dev, static int r8a7795_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; @@ -289,11 +289,10 @@ static const struct clock_control_driver_api r8a7795_cpg_mssr_api = { #define R8A7795_MSSR_INIT(inst) \ static struct r8a7795_cpg_mssr_config r8a7795_cpg_mssr##inst##_config = { \ - .base_address = DT_INST_REG_ADDR(inst), \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ }; \ \ static struct r8a7795_cpg_mssr_data r8a7795_cpg_mssr##inst##_data = { \ - .cmn.base_addr = DT_INST_REG_ADDR(inst), \ .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, \ diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.c b/drivers/clock_control/clock_control_renesas_cpg_mssr.c index 4cde5de25eeb..b133a6904f5c 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.c +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.c @@ -104,7 +104,7 @@ static uint32_t rcar_cpg_get_divider(const struct device *dev, struct cpg_clk_in return 1; } - reg_addr += data->base_addr; + reg_addr += DEVICE_MMIO_GET(dev); reg_val = sys_read32(reg_addr); if (data->get_div_helper) { @@ -313,10 +313,10 @@ int rcar_cpg_set_rate(const struct device *dev, clock_control_subsys_t sys, ret = data->set_rate_helper(module, ÷r, &div_mask); if (!ret) { int64_t out_rate; - uint32_t reg = sys_read32(clk_info->offset + data->base_addr); + uint32_t reg = sys_read32(clk_info->offset + DEVICE_MMIO_GET(dev)); reg &= ~div_mask; - rcar_cpg_write(data->base_addr, clk_info->offset, reg | divider); + rcar_cpg_write(DEVICE_MMIO_GET(dev), clk_info->offset, reg | divider); clk_info->out_freq = RCAR_CPG_NONE; diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index a20e67609933..13d3cbeeb4e4 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -10,6 +10,7 @@ #include #include #include +#include #define CPG_NUM_DOMAINS 2 @@ -31,7 +32,7 @@ struct cpg_clk_info_table { }; struct rcar_cpg_mssr_data { - mem_addr_t base_addr; + DEVICE_MMIO_RAM; /* Must be first */ struct cpg_clk_info_table *clk_info_table[CPG_NUM_DOMAINS]; const uint32_t clk_info_table_size[CPG_NUM_DOMAINS]; From d0472aae7a3396489b8578906c12bfa1bc50acff Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Fri, 10 Feb 2023 10:01:12 +0200 Subject: [PATCH 1116/2042] soc: arm64: add Renesas Rcar Gen3 SoC support Add files for supporting arm64 Renesas r8a77951 SoC. Add config option CPU_CORTEX_A57. Enable build of clock_control_r8a7795_cpg_mssr.c for a new ARM64 SoC R8A77951. Signed-off-by: Mykola Kvach --- arch/arm64/core/Kconfig | 7 ++ .../clock_control_r8a7795_cpg_mssr.c | 1 - drivers/pinctrl/pfc_rcar.c | 1 - dts/arm64/renesas/r8a77951.dtsi | 88 +++++++++++++++++++ soc/arm64/renesas_rcar/CMakeLists.txt | 4 + soc/arm64/renesas_rcar/Kconfig | 17 ++++ soc/arm64/renesas_rcar/Kconfig.defconfig | 4 + soc/arm64/renesas_rcar/Kconfig.soc | 6 ++ soc/arm64/renesas_rcar/gen3/CMakeLists.txt | 4 + .../gen3/Kconfig.defconfig.r8a77951 | 9 ++ .../gen3/Kconfig.defconfig.series | 15 ++++ soc/arm64/renesas_rcar/gen3/Kconfig.series | 13 +++ soc/arm64/renesas_rcar/gen3/Kconfig.soc | 11 +++ soc/arm64/renesas_rcar/gen3/linker.ld | 7 ++ soc/arm64/renesas_rcar/gen3/mmu_regions.c | 25 ++++++ .../grp/os_mgmt/include/os_mgmt_processor.h | 2 + 16 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 dts/arm64/renesas/r8a77951.dtsi create mode 100644 soc/arm64/renesas_rcar/CMakeLists.txt create mode 100644 soc/arm64/renesas_rcar/Kconfig create mode 100644 soc/arm64/renesas_rcar/Kconfig.defconfig create mode 100644 soc/arm64/renesas_rcar/Kconfig.soc create mode 100644 soc/arm64/renesas_rcar/gen3/CMakeLists.txt create mode 100644 soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77951 create mode 100644 soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series create mode 100644 soc/arm64/renesas_rcar/gen3/Kconfig.series create mode 100644 soc/arm64/renesas_rcar/gen3/Kconfig.soc create mode 100644 soc/arm64/renesas_rcar/gen3/linker.ld create mode 100644 soc/arm64/renesas_rcar/gen3/mmu_regions.c diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index ad9531d60979..1b0ad478595a 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -43,6 +43,13 @@ config CPU_CORTEX_A55 help This option signifies the use of a Cortex-A55 CPU +config CPU_CORTEX_A57 + bool + select CPU_CORTEX_A + select ARMV8_A + help + This option signifies the use of a Cortex-A57 CPU + config CPU_CORTEX_A72 bool select CPU_CORTEX_A diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index 9ce5fe42795f..26b0b1959c6f 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -9,7 +9,6 @@ #define DT_DRV_COMPAT renesas_r8a7795_cpg_mssr #include -#include #include #include #include diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 50908fbd2f8e..14529d42fe9a 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/dts/arm64/renesas/r8a77951.dtsi b/dts/arm64/renesas/r8a77951.dtsi new file mode 100644 index 000000000000..e199a303a620 --- /dev/null +++ b/dts/arm64/renesas/r8a77951.dtsi @@ -0,0 +1,88 @@ +/* + * Device Tree Source for the R-Car H3 (R8A77951) SoC + * + * Copyright (C) 2023 EPAM Systems. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +/ { + compatible = "renesas,r8a77951"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + a57_0: cpu@0 { + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0x0>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; + method = "smc"; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f1010000 { + compatible = "arm,gic-400", "arm,gic" ; + #interrupt-cells = <4>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0xf1010000 0 0x1000>, + <0 0xf1020000 0 0x20000>; + status = "okay"; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a7795-cpg-mssr"; + reg = <0 0xe6150000 0 0x1000>; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; + + pfc: pin-controller@e6060000 { + compatible = "renesas,rcar-pfc"; + reg = <0 0xe6060000 0 0x50c>; + }; + + scif2: serial@e6e88000 { + compatible = "renesas,rcar-scif"; + reg = <0 0xe6e88000 0 0x64>; + interrupt-parent = <&gic>; + clocks = <&cpg CPG_MOD 310>, + <&cpg CPG_CORE R8A7795_CLK_S3D4>; + interrupts = ; + current-speed = <115200>; + interrupt-names = "irq_0"; + status = "disabled"; + }; + }; +}; diff --git a/soc/arm64/renesas_rcar/CMakeLists.txt b/soc/arm64/renesas_rcar/CMakeLists.txt new file mode 100644 index 000000000000..ce47b609a9aa --- /dev/null +++ b/soc/arm64/renesas_rcar/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm64/renesas_rcar/Kconfig b/soc/arm64/renesas_rcar/Kconfig new file mode 100644 index 000000000000..413523e23a75 --- /dev/null +++ b/soc/arm64/renesas_rcar/Kconfig @@ -0,0 +1,17 @@ +# Renesas R-Car SoC line + +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_RCAR + bool + +if SOC_FAMILY_RCAR + +config SOC_FAMILY + string + default "renesas_rcar" + +source "soc/arm64/renesas_rcar/*/Kconfig.soc" + +endif # SOC_FAMILY_RCAR diff --git a/soc/arm64/renesas_rcar/Kconfig.defconfig b/soc/arm64/renesas_rcar/Kconfig.defconfig new file mode 100644 index 000000000000..fa39233d8dce --- /dev/null +++ b/soc/arm64/renesas_rcar/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm64/renesas_rcar/*/Kconfig.defconfig.series" diff --git a/soc/arm64/renesas_rcar/Kconfig.soc b/soc/arm64/renesas_rcar/Kconfig.soc new file mode 100644 index 000000000000..3e191b56f356 --- /dev/null +++ b/soc/arm64/renesas_rcar/Kconfig.soc @@ -0,0 +1,6 @@ +# Renesas R-Car SoC line + +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm64/renesas_rcar/*/Kconfig.series" diff --git a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt new file mode 100644 index 000000000000..3431ebacf890 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77951 b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77951 new file mode 100644 index 000000000000..3df374f28937 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77951 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_ARM64_R8A77951 + +config SOC + default "r8a77951" + +endif # SOC_ARM64_R8A77951 diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series new file mode 100644 index 000000000000..4988a24691a3 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series @@ -0,0 +1,15 @@ +# Renesas R-Car Gen3 SoC line + +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RCAR_GEN3 + +config SOC_SERIES + default "gen3" + +config NUM_IRQS + int + default 240 + +endif # SOC_SERIES_RCAR_GEN3 diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.series b/soc/arm64/renesas_rcar/gen3/Kconfig.series new file mode 100644 index 000000000000..49465fa741e5 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RCAR_GEN3 + bool "Renesas RCAR Gen3 Cortex A" + select ARM64 + select CPU_CORTEX_A57 + select GIC_V2 + select SOC_FAMILY_RCAR + select ARM_ARCH_TIMER + select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL + help + Enable support for Renesas RCar Gen3 SoC series diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.soc b/soc/arm64/renesas_rcar/gen3/Kconfig.soc new file mode 100644 index 000000000000..783fce021a23 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renesas RCar SoC Selection" + depends on SOC_SERIES_RCAR_GEN3 + +config SOC_ARM64_R8A77951 + bool "R8A77951" + +endchoice diff --git a/soc/arm64/renesas_rcar/gen3/linker.ld b/soc/arm64/renesas_rcar/gen3/linker.ld new file mode 100644 index 000000000000..0deb8cd27942 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm64/renesas_rcar/gen3/mmu_regions.c b/soc/arm64/renesas_rcar/gen3/mmu_regions.c new file mode 100644 index 000000000000..64cfa4797850 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/mmu_regions.c @@ -0,0 +1,25 @@ +/* + * Copyright 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +static const struct arm_mmu_region mmu_regions[] = { + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_INST(0, arm_gic), 0), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 0), + MT_DEVICE_nGnRnE | MT_RW | MT_NS), + + MMU_REGION_FLAT_ENTRY("GIC", + DT_REG_ADDR_BY_IDX(DT_INST(0, arm_gic), 1), + DT_REG_SIZE_BY_IDX(DT_INST(0, arm_gic), 1), + MT_DEVICE_nGnRnE | MT_RW | MT_NS), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h index 3eebd3fa19d1..7dc072f0eeb1 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -91,6 +91,8 @@ extern "C" { #define PROCESSOR_NAME "cortex-a53" #elif defined(CONFIG_CPU_CORTEX_A55) #define PROCESSOR_NAME "cortex-a55" +#elif defined(CONFIG_CPU_CORTEX_A57) +#define PROCESSOR_NAME "cortex-a57" #elif defined(CONFIG_CPU_CORTEX_A72) #define PROCESSOR_NAME "cortex-a72" #elif defined(CONFIG_CPU_CORTEX_R82) From e0cf31483be60e6599dc184f3428de7e3e9cc02d Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 2 May 2023 16:55:57 +0300 Subject: [PATCH 1117/2042] soc: arm64: add PFC files to Renesas r8a77951 Gen3 SoC Add Pin Function Controller tables of registers and their bits for ARM64 Renesas R-Car family. With this changes we can use Renesas PFC driver for configuring bias and driving capabilities. Note: some of files copy-pasted from Renesas Arm 32 SoC directory and this commit is a temporary solution, we need to rework it in order to use the same source files for both architectures. Signed-off-by: Mykola Kvach --- soc/arm64/renesas_rcar/gen3/CMakeLists.txt | 1 + .../gen3/Kconfig.defconfig.series | 3 + soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c | 538 ++++++++++++++++++ soc/arm64/renesas_rcar/gen3/pinctrl_soc.h | 117 ++++ 4 files changed, 659 insertions(+) create mode 100644 soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c create mode 100644 soc/arm64/renesas_rcar/gen3/pinctrl_soc.h diff --git a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt index 3431ebacf890..9fe52fe0d595 100644 --- a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt +++ b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2023 EPAM Systems # SPDX-License-Identifier: Apache-2.0 +zephyr_library_sources_ifdef(CONFIG_SOC_ARM64_R8A77951 pfc_r8a77951.c) zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series index 4988a24691a3..369d1beedb8d 100644 --- a/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.series @@ -12,4 +12,7 @@ config NUM_IRQS int default 240 +config PINCTRL + default y + endif # SOC_SERIES_RCAR_GEN3 diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c new file mode 100644 index 000000000000..c59be6cfe6fd --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2021 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "pinctrl_soc.h" +#include + +const struct pfc_drive_reg pfc_drive_regs[] = { + /* DRVCTRL0 */ + { 0x0300, { + { PIN_QSPI0_SPCLK, 28, 2 }, /* QSPI0_SPCLK */ + { PIN_QSPI0_MOSI_IO0, 24, 2 }, /* QSPI0_MOSI_IO0 */ + { PIN_QSPI0_MISO_IO1, 20, 2 }, /* QSPI0_MISO_IO1 */ + { PIN_QSPI0_IO2, 16, 2 }, /* QSPI0_IO2 */ + { PIN_QSPI0_IO3, 12, 2 }, /* QSPI0_IO3 */ + { PIN_QSPI0_SSL, 8, 2 }, /* QSPI0_SSL */ + { PIN_QSPI1_SPCLK, 4, 2 }, /* QSPI1_SPCLK */ + { PIN_QSPI1_MOSI_IO0, 0, 2 }, /* QSPI1_MOSI_IO0 */ + } }, + /* DRVCTRL1 */ + { 0x0304, { + { PIN_QSPI1_MISO_IO1, 28, 2 }, /* QSPI1_MISO_IO1 */ + { PIN_QSPI1_IO2, 24, 2 }, /* QSPI1_IO2 */ + { PIN_QSPI1_IO3, 20, 2 }, /* QSPI1_IO3 */ + { PIN_QSPI1_SSL, 16, 2 }, /* QSPI1_SSL */ + { PIN_RPC_INT_N, 12, 2 }, /* RPC_INT# */ + { PIN_RPC_WP_N, 8, 2 }, /* RPC_WP# */ + { PIN_RPC_RESET_N, 4, 2 }, /* RPC_RESET# */ + { PIN_AVB_RX_CTL, 0, 3 }, /* AVB_RX_CTL */ + } }, + /* DRVCTRL2 */ + { 0x0308, { + { PIN_AVB_RXC, 28, 3 }, /* AVB_RXC */ + { PIN_AVB_RD0, 24, 3 }, /* AVB_RD0 */ + { PIN_AVB_RD1, 20, 3 }, /* AVB_RD1 */ + { PIN_AVB_RD2, 16, 3 }, /* AVB_RD2 */ + { PIN_AVB_RD3, 12, 3 }, /* AVB_RD3 */ + { PIN_AVB_TX_CTL, 8, 3 }, /* AVB_TX_CTL */ + { PIN_AVB_TXC, 4, 3 }, /* AVB_TXC */ + { PIN_AVB_TD0, 0, 3 }, /* AVB_TD0 */ + } }, + /* DRVCTRL3 */ + { 0x030c, { + { PIN_AVB_TD1, 28, 3 }, /* AVB_TD1 */ + { PIN_AVB_TD2, 24, 3 }, /* AVB_TD2 */ + { PIN_AVB_TD3, 20, 3 }, /* AVB_TD3 */ + { PIN_AVB_TXCREFCLK, 16, 3 }, /* AVB_TXCREFCLK */ + { PIN_AVB_MDIO, 12, 3 }, /* AVB_MDIO */ + { RCAR_GP_PIN(2, 9), 8, 3 }, /* AVB_MDC */ + { RCAR_GP_PIN(2, 10), 4, 3 }, /* AVB_MAGIC */ + { RCAR_GP_PIN(2, 11), 0, 3 }, /* AVB_PHY_INT */ + } }, + /* DRVCTRL4 */ + { 0x0310, { + { RCAR_GP_PIN(2, 12), 28, 3 }, /* AVB_LINK */ + { RCAR_GP_PIN(2, 13), 24, 3 }, /* AVB_AVTP_MATCH */ + { RCAR_GP_PIN(2, 14), 20, 3 }, /* AVB_AVTP_CAPTURE */ + { RCAR_GP_PIN(2, 0), 16, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(2, 1), 12, 3 }, /* IRQ1 */ + { RCAR_GP_PIN(2, 2), 8, 3 }, /* IRQ2 */ + { RCAR_GP_PIN(2, 3), 4, 3 }, /* IRQ3 */ + { RCAR_GP_PIN(2, 4), 0, 3 }, /* IRQ4 */ + } }, + /* DRVCTRL5 */ + { 0x0314, { + { RCAR_GP_PIN(2, 5), 28, 3 }, /* IRQ5 */ + { RCAR_GP_PIN(2, 6), 24, 3 }, /* PWM0 */ + { RCAR_GP_PIN(2, 7), 20, 3 }, /* PWM1 */ + { RCAR_GP_PIN(2, 8), 16, 3 }, /* PWM2 */ + { RCAR_GP_PIN(1, 0), 12, 3 }, /* A0 */ + { RCAR_GP_PIN(1, 1), 8, 3 }, /* A1 */ + { RCAR_GP_PIN(1, 2), 4, 3 }, /* A2 */ + { RCAR_GP_PIN(1, 3), 0, 3 }, /* A3 */ + } }, + /* DRVCTRL6 */ + { 0x0318, { + { RCAR_GP_PIN(1, 4), 28, 3 }, /* A4 */ + { RCAR_GP_PIN(1, 5), 24, 3 }, /* A5 */ + { RCAR_GP_PIN(1, 6), 20, 3 }, /* A6 */ + { RCAR_GP_PIN(1, 7), 16, 3 }, /* A7 */ + { RCAR_GP_PIN(1, 8), 12, 3 }, /* A8 */ + { RCAR_GP_PIN(1, 9), 8, 3 }, /* A9 */ + { RCAR_GP_PIN(1, 10), 4, 3 }, /* A10 */ + { RCAR_GP_PIN(1, 11), 0, 3 }, /* A11 */ + } }, + /* DRVCTRL7 */ + { 0x031c, { + { RCAR_GP_PIN(1, 12), 28, 3 }, /* A12 */ + { RCAR_GP_PIN(1, 13), 24, 3 }, /* A13 */ + { RCAR_GP_PIN(1, 14), 20, 3 }, /* A14 */ + { RCAR_GP_PIN(1, 15), 16, 3 }, /* A15 */ + { RCAR_GP_PIN(1, 16), 12, 3 }, /* A16 */ + { RCAR_GP_PIN(1, 17), 8, 3 }, /* A17 */ + { RCAR_GP_PIN(1, 18), 4, 3 }, /* A18 */ + { RCAR_GP_PIN(1, 19), 0, 3 }, /* A19 */ + } }, + /* DRVCTRL8 */ + { 0x0320, { + { RCAR_GP_PIN(1, 28), 28, 3 }, /* CLKOUT */ + { RCAR_GP_PIN(1, 20), 24, 3 }, /* CS0 */ + { RCAR_GP_PIN(1, 21), 20, 3 }, /* CS1_A26 */ + { RCAR_GP_PIN(1, 22), 16, 3 }, /* BS */ + { RCAR_GP_PIN(1, 23), 12, 3 }, /* RD */ + { RCAR_GP_PIN(1, 24), 8, 3 }, /* RD_WR */ + { RCAR_GP_PIN(1, 25), 4, 3 }, /* WE0 */ + { RCAR_GP_PIN(1, 26), 0, 3 }, /* WE1 */ + } }, + /* DRVCTRL9 */ + { 0x0324, { + { RCAR_GP_PIN(1, 27), 28, 3 }, /* EX_WAIT0 */ + { PIN_PRESETOUT_N, 24, 3 }, /* PRESETOUT# */ + { RCAR_GP_PIN(0, 0), 20, 3 }, /* D0 */ + { RCAR_GP_PIN(0, 1), 16, 3 }, /* D1 */ + { RCAR_GP_PIN(0, 2), 12, 3 }, /* D2 */ + { RCAR_GP_PIN(0, 3), 8, 3 }, /* D3 */ + { RCAR_GP_PIN(0, 4), 4, 3 }, /* D4 */ + { RCAR_GP_PIN(0, 5), 0, 3 }, /* D5 */ + } }, + /* DRVCTRL10 */ + { 0x0328, { + { RCAR_GP_PIN(0, 6), 28, 3 }, /* D6 */ + { RCAR_GP_PIN(0, 7), 24, 3 }, /* D7 */ + { RCAR_GP_PIN(0, 8), 20, 3 }, /* D8 */ + { RCAR_GP_PIN(0, 9), 16, 3 }, /* D9 */ + { RCAR_GP_PIN(0, 10), 12, 3 }, /* D10 */ + { RCAR_GP_PIN(0, 11), 8, 3 }, /* D11 */ + { RCAR_GP_PIN(0, 12), 4, 3 }, /* D12 */ + { RCAR_GP_PIN(0, 13), 0, 3 }, /* D13 */ + } }, + /* DRVCTRL11 */ + { 0x032c, { + { RCAR_GP_PIN(0, 14), 28, 3 }, /* D14 */ + { RCAR_GP_PIN(0, 15), 24, 3 }, /* D15 */ + { RCAR_GP_PIN(7, 0), 20, 3 }, /* AVS1 */ + { RCAR_GP_PIN(7, 1), 16, 3 }, /* AVS2 */ + { RCAR_GP_PIN(7, 2), 12, 3 }, /* GP7_02 */ + { RCAR_GP_PIN(7, 3), 8, 3 }, /* GP7_03 */ + { PIN_DU_DOTCLKIN0, 4, 2 }, /* DU_DOTCLKIN0 */ + { PIN_DU_DOTCLKIN1, 0, 2 }, /* DU_DOTCLKIN1 */ + } }, + /* DRVCTRL12 */ + { 0x0330, { + { PIN_DU_DOTCLKIN2, 28, 2 }, /* DU_DOTCLKIN2 */ + { PIN_DU_DOTCLKIN3, 24, 2 }, /* DU_DOTCLKIN3 */ + { PIN_FSCLKST_N, 20, 2 }, /* FSCLKST# */ + { PIN_TMS, 4, 2 }, /* TMS */ + } }, + /* DRVCTRL13 */ + { 0x0334, { + { PIN_TDO, 28, 2 }, /* TDO */ + { PIN_ASEBRK, 24, 2 }, /* ASEBRK */ + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + } }, + /* DRVCTRL14 */ + { 0x0338, { + { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ + { RCAR_GP_PIN(3, 7), 24, 3 }, /* SD1_CMD */ + { RCAR_GP_PIN(3, 8), 20, 3 }, /* SD1_DAT0 */ + { RCAR_GP_PIN(3, 9), 16, 3 }, /* SD1_DAT1 */ + { RCAR_GP_PIN(3, 10), 12, 3 }, /* SD1_DAT2 */ + { RCAR_GP_PIN(3, 11), 8, 3 }, /* SD1_DAT3 */ + { RCAR_GP_PIN(4, 0), 4, 3 }, /* SD2_CLK */ + { RCAR_GP_PIN(4, 1), 0, 3 }, /* SD2_CMD */ + } }, + /* DRVCTRL15 */ + { 0x033c, { + { RCAR_GP_PIN(4, 2), 28, 3 }, /* SD2_DAT0 */ + { RCAR_GP_PIN(4, 3), 24, 3 }, /* SD2_DAT1 */ + { RCAR_GP_PIN(4, 4), 20, 3 }, /* SD2_DAT2 */ + { RCAR_GP_PIN(4, 5), 16, 3 }, /* SD2_DAT3 */ + { RCAR_GP_PIN(4, 6), 12, 3 }, /* SD2_DS */ + { RCAR_GP_PIN(4, 7), 8, 3 }, /* SD3_CLK */ + { RCAR_GP_PIN(4, 8), 4, 3 }, /* SD3_CMD */ + { RCAR_GP_PIN(4, 9), 0, 3 }, /* SD3_DAT0 */ + } }, + /* DRVCTRL16 */ + { 0x0340, { + { RCAR_GP_PIN(4, 10), 28, 3 }, /* SD3_DAT1 */ + { RCAR_GP_PIN(4, 11), 24, 3 }, /* SD3_DAT2 */ + { RCAR_GP_PIN(4, 12), 20, 3 }, /* SD3_DAT3 */ + { RCAR_GP_PIN(4, 13), 16, 3 }, /* SD3_DAT4 */ + { RCAR_GP_PIN(4, 14), 12, 3 }, /* SD3_DAT5 */ + { RCAR_GP_PIN(4, 15), 8, 3 }, /* SD3_DAT6 */ + { RCAR_GP_PIN(4, 16), 4, 3 }, /* SD3_DAT7 */ + { RCAR_GP_PIN(4, 17), 0, 3 }, /* SD3_DS */ + } }, + /* DRVCTRL17 */ + { 0x0344, { + { RCAR_GP_PIN(3, 12), 28, 3 }, /* SD0_CD */ + { RCAR_GP_PIN(3, 13), 24, 3 }, /* SD0_WP */ + { RCAR_GP_PIN(3, 14), 20, 3 }, /* SD1_CD */ + { RCAR_GP_PIN(3, 15), 16, 3 }, /* SD1_WP */ + { RCAR_GP_PIN(5, 0), 12, 3 }, /* SCK0 */ + { RCAR_GP_PIN(5, 1), 8, 3 }, /* RX0 */ + { RCAR_GP_PIN(5, 2), 4, 3 }, /* TX0 */ + { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ + } }, + /* DRVCTRL18 */ + { 0x0348, { + { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0 */ + { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ + { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ + { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ + { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1 */ + { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ + { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ + { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ + } }, + /* DRVCTRL19 */ + { 0x034c, { + { RCAR_GP_PIN(5, 12), 28, 3 }, /* HSCK0 */ + { RCAR_GP_PIN(5, 13), 24, 3 }, /* HRX0 */ + { RCAR_GP_PIN(5, 14), 20, 3 }, /* HTX0 */ + { RCAR_GP_PIN(5, 15), 16, 3 }, /* HCTS0 */ + { RCAR_GP_PIN(5, 16), 12, 3 }, /* HRTS0 */ + { RCAR_GP_PIN(5, 17), 8, 3 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(5, 18), 4, 3 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(5, 19), 0, 3 }, /* MSIOF0_SS1 */ + } }, + /* DRVCTRL20 */ + { 0x0350, { + { RCAR_GP_PIN(5, 20), 28, 3 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(5, 21), 24, 3 }, /* MSIOF0_SS2 */ + { RCAR_GP_PIN(5, 22), 20, 3 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(5, 23), 16, 3 }, /* MLB_CLK */ + { RCAR_GP_PIN(5, 24), 12, 3 }, /* MLB_SIG */ + { RCAR_GP_PIN(5, 25), 8, 3 }, /* MLB_DAT */ + { PIN_MLB_REF, 4, 3 }, /* MLB_REF */ + { RCAR_GP_PIN(6, 0), 0, 3 }, /* SSI_SCK01239 */ + } }, + /* DRVCTRL21 */ + { 0x0354, { + { RCAR_GP_PIN(6, 1), 28, 3 }, /* SSI_WS01239 */ + { RCAR_GP_PIN(6, 2), 24, 3 }, /* SSI_SDATA0 */ + { RCAR_GP_PIN(6, 3), 20, 3 }, /* SSI_SDATA1 */ + { RCAR_GP_PIN(6, 4), 16, 3 }, /* SSI_SDATA2 */ + { RCAR_GP_PIN(6, 5), 12, 3 }, /* SSI_SCK349 */ + { RCAR_GP_PIN(6, 6), 8, 3 }, /* SSI_WS349 */ + { RCAR_GP_PIN(6, 7), 4, 3 }, /* SSI_SDATA3 */ + { RCAR_GP_PIN(6, 8), 0, 3 }, /* SSI_SCK4 */ + } }, + /* DRVCTRL22 */ + { 0x0358, { + { RCAR_GP_PIN(6, 9), 28, 3 }, /* SSI_WS4 */ + { RCAR_GP_PIN(6, 10), 24, 3 }, /* SSI_SDATA4 */ + { RCAR_GP_PIN(6, 11), 20, 3 }, /* SSI_SCK5 */ + { RCAR_GP_PIN(6, 12), 16, 3 }, /* SSI_WS5 */ + { RCAR_GP_PIN(6, 13), 12, 3 }, /* SSI_SDATA5 */ + { RCAR_GP_PIN(6, 14), 8, 3 }, /* SSI_SCK6 */ + { RCAR_GP_PIN(6, 15), 4, 3 }, /* SSI_WS6 */ + { RCAR_GP_PIN(6, 16), 0, 3 }, /* SSI_SDATA6 */ + } }, + /* DRVCTRL23 */ + { 0x035c, { + { RCAR_GP_PIN(6, 17), 28, 3 }, /* SSI_SCK78 */ + { RCAR_GP_PIN(6, 18), 24, 3 }, /* SSI_WS78 */ + { RCAR_GP_PIN(6, 19), 20, 3 }, /* SSI_SDATA7 */ + { RCAR_GP_PIN(6, 20), 16, 3 }, /* SSI_SDATA8 */ + { RCAR_GP_PIN(6, 21), 12, 3 }, /* SSI_SDATA9 */ + { RCAR_GP_PIN(6, 22), 8, 3 }, /* AUDIO_CLKA */ + { RCAR_GP_PIN(6, 23), 4, 3 }, /* AUDIO_CLKB */ + { RCAR_GP_PIN(6, 24), 0, 3 }, /* USB0_PWEN */ + } }, + /* DRVCTRL24 */ + { 0x0360, { + { RCAR_GP_PIN(6, 25), 28, 3 }, /* USB0_OVC */ + { RCAR_GP_PIN(6, 26), 24, 3 }, /* USB1_PWEN */ + { RCAR_GP_PIN(6, 27), 20, 3 }, /* USB1_OVC */ + { RCAR_GP_PIN(6, 28), 16, 3 }, /* USB30_PWEN */ + { RCAR_GP_PIN(6, 29), 12, 3 }, /* USB30_OVC */ + { RCAR_GP_PIN(6, 30), 8, 3 }, /* GP6_30/USB2_CH3_PWEN */ + { RCAR_GP_PIN(6, 31), 4, 3 }, /* GP6_31/USB2_CH3_OVC */ + } }, + { }, +}; + +#define PFC_BIAS_REG(r1, r2) \ + .puen = r1, \ + .pud = r2, \ + .pins = + +const struct pfc_bias_reg pfc_bias_regs[] = { + { PFC_BIAS_REG(0x0400, 0x0440) { /* PUEN0, PUD0 */ + [0] = PIN_QSPI0_SPCLK, /* QSPI0_SPCLK */ + [1] = PIN_QSPI0_MOSI_IO0, /* QSPI0_MOSI_IO0 */ + [2] = PIN_QSPI0_MISO_IO1, /* QSPI0_MISO_IO1 */ + [3] = PIN_QSPI0_IO2, /* QSPI0_IO2 */ + [4] = PIN_QSPI0_IO3, /* QSPI0_IO3 */ + [5] = PIN_QSPI0_SSL, /* QSPI0_SSL */ + [6] = PIN_QSPI1_SPCLK, /* QSPI1_SPCLK */ + [7] = PIN_QSPI1_MOSI_IO0, /* QSPI1_MOSI_IO0 */ + [8] = PIN_QSPI1_MISO_IO1, /* QSPI1_MISO_IO1 */ + [9] = PIN_QSPI1_IO2, /* QSPI1_IO2 */ + [10] = PIN_QSPI1_IO3, /* QSPI1_IO3 */ + [11] = PIN_QSPI1_SSL, /* QSPI1_SSL */ + [12] = PIN_RPC_INT_N, /* RPC_INT# */ + [13] = PIN_RPC_WP_N, /* RPC_WP# */ + [14] = PIN_RPC_RESET_N, /* RPC_RESET# */ + [15] = PIN_AVB_RX_CTL, /* AVB_RX_CTL */ + [16] = PIN_AVB_RXC, /* AVB_RXC */ + [17] = PIN_AVB_RD0, /* AVB_RD0 */ + [18] = PIN_AVB_RD1, /* AVB_RD1 */ + [19] = PIN_AVB_RD2, /* AVB_RD2 */ + [20] = PIN_AVB_RD3, /* AVB_RD3 */ + [21] = PIN_AVB_TX_CTL, /* AVB_TX_CTL */ + [22] = PIN_AVB_TXC, /* AVB_TXC */ + [23] = PIN_AVB_TD0, /* AVB_TD0 */ + [24] = PIN_AVB_TD1, /* AVB_TD1 */ + [25] = PIN_AVB_TD2, /* AVB_TD2 */ + [26] = PIN_AVB_TD3, /* AVB_TD3 */ + [27] = PIN_AVB_TXCREFCLK, /* AVB_TXCREFCLK */ + [28] = PIN_AVB_MDIO, /* AVB_MDIO */ + [29] = RCAR_GP_PIN(2, 9), /* AVB_MDC */ + [30] = RCAR_GP_PIN(2, 10), /* AVB_MAGIC */ + [31] = RCAR_GP_PIN(2, 11), /* AVB_PHY_INT */ + } }, + { PFC_BIAS_REG(0x0404, 0x0444) { /* PUEN1, PUD1 */ + [0] = RCAR_GP_PIN(2, 12), /* AVB_LINK */ + [1] = RCAR_GP_PIN(2, 13), /* AVB_AVTP_MATCH_A */ + [2] = RCAR_GP_PIN(2, 14), /* AVB_AVTP_CAPTURE_A */ + [3] = RCAR_GP_PIN(2, 0), /* IRQ0 */ + [4] = RCAR_GP_PIN(2, 1), /* IRQ1 */ + [5] = RCAR_GP_PIN(2, 2), /* IRQ2 */ + [6] = RCAR_GP_PIN(2, 3), /* IRQ3 */ + [7] = RCAR_GP_PIN(2, 4), /* IRQ4 */ + [8] = RCAR_GP_PIN(2, 5), /* IRQ5 */ + [9] = RCAR_GP_PIN(2, 6), /* PWM0 */ + [10] = RCAR_GP_PIN(2, 7), /* PWM1_A */ + [11] = RCAR_GP_PIN(2, 8), /* PWM2_A */ + [12] = RCAR_GP_PIN(1, 0), /* A0 */ + [13] = RCAR_GP_PIN(1, 1), /* A1 */ + [14] = RCAR_GP_PIN(1, 2), /* A2 */ + [15] = RCAR_GP_PIN(1, 3), /* A3 */ + [16] = RCAR_GP_PIN(1, 4), /* A4 */ + [17] = RCAR_GP_PIN(1, 5), /* A5 */ + [18] = RCAR_GP_PIN(1, 6), /* A6 */ + [19] = RCAR_GP_PIN(1, 7), /* A7 */ + [20] = RCAR_GP_PIN(1, 8), /* A8 */ + [21] = RCAR_GP_PIN(1, 9), /* A9 */ + [22] = RCAR_GP_PIN(1, 10), /* A10 */ + [23] = RCAR_GP_PIN(1, 11), /* A11 */ + [24] = RCAR_GP_PIN(1, 12), /* A12 */ + [25] = RCAR_GP_PIN(1, 13), /* A13 */ + [26] = RCAR_GP_PIN(1, 14), /* A14 */ + [27] = RCAR_GP_PIN(1, 15), /* A15 */ + [28] = RCAR_GP_PIN(1, 16), /* A16 */ + [29] = RCAR_GP_PIN(1, 17), /* A17 */ + [30] = RCAR_GP_PIN(1, 18), /* A18 */ + [31] = RCAR_GP_PIN(1, 19), /* A19 */ + } }, + { PFC_BIAS_REG(0x0408, 0x0448) { /* PUEN2, PUD2 */ + [0] = RCAR_GP_PIN(1, 28), /* CLKOUT */ + [1] = RCAR_GP_PIN(1, 20), /* CS0_N */ + [2] = RCAR_GP_PIN(1, 21), /* CS1_N */ + [3] = RCAR_GP_PIN(1, 22), /* BS_N */ + [4] = RCAR_GP_PIN(1, 23), /* RD_N */ + [5] = RCAR_GP_PIN(1, 24), /* RD_WR_N */ + [6] = RCAR_GP_PIN(1, 25), /* WE0_N */ + [7] = RCAR_GP_PIN(1, 26), /* WE1_N */ + [8] = RCAR_GP_PIN(1, 27), /* EX_WAIT0_A */ + [9] = PIN_PRESETOUT_N, /* PRESETOUT# */ + [10] = RCAR_GP_PIN(0, 0), /* D0 */ + [11] = RCAR_GP_PIN(0, 1), /* D1 */ + [12] = RCAR_GP_PIN(0, 2), /* D2 */ + [13] = RCAR_GP_PIN(0, 3), /* D3 */ + [14] = RCAR_GP_PIN(0, 4), /* D4 */ + [15] = RCAR_GP_PIN(0, 5), /* D5 */ + [16] = RCAR_GP_PIN(0, 6), /* D6 */ + [17] = RCAR_GP_PIN(0, 7), /* D7 */ + [18] = RCAR_GP_PIN(0, 8), /* D8 */ + [19] = RCAR_GP_PIN(0, 9), /* D9 */ + [20] = RCAR_GP_PIN(0, 10), /* D10 */ + [21] = RCAR_GP_PIN(0, 11), /* D11 */ + [22] = RCAR_GP_PIN(0, 12), /* D12 */ + [23] = RCAR_GP_PIN(0, 13), /* D13 */ + [24] = RCAR_GP_PIN(0, 14), /* D14 */ + [25] = RCAR_GP_PIN(0, 15), /* D15 */ + [26] = RCAR_GP_PIN(7, 0), /* AVS1 */ + [27] = RCAR_GP_PIN(7, 1), /* AVS2 */ + [28] = RCAR_GP_PIN(7, 2), /* GP7_02 */ + [29] = RCAR_GP_PIN(7, 3), /* GP7_03 */ + [30] = PIN_DU_DOTCLKIN0, /* DU_DOTCLKIN0 */ + [31] = PIN_DU_DOTCLKIN1, /* DU_DOTCLKIN1 */ + } }, + { PFC_BIAS_REG(0x040c, 0x044c) { /* PUEN3, PUD3 */ + [0] = PIN_DU_DOTCLKIN2, /* DU_DOTCLKIN2 */ + [1] = PIN_DU_DOTCLKIN3, /* DU_DOTCLKIN3 */ + [2] = PIN_FSCLKST_N, /* FSCLKST# */ + [3] = PIN_EXTALR, /* EXTALR*/ + [4] = PIN_TRST_N, /* TRST# */ + [5] = PIN_TCK, /* TCK */ + [6] = PIN_TMS, /* TMS */ + [7] = PIN_TDI, /* TDI */ + [8] = PIN_NONE, + [9] = PIN_ASEBRK, /* ASEBRK */ + [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ + [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ + [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ + [13] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ + [14] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ + [15] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ + [16] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ + [17] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ + [18] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ + [19] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ + [20] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ + [21] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ + [22] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ + [23] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ + [24] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ + [25] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ + [26] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ + [27] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ + [28] = RCAR_GP_PIN(4, 6), /* SD2_DS */ + [29] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ + [30] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ + [31] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ + } }, + { PFC_BIAS_REG(0x0410, 0x0450) { /* PUEN4, PUD4 */ + [0] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ + [1] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ + [2] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ + [3] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ + [4] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ + [5] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ + [6] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ + [7] = RCAR_GP_PIN(4, 17), /* SD3_DS */ + [8] = RCAR_GP_PIN(3, 12), /* SD0_CD */ + [9] = RCAR_GP_PIN(3, 13), /* SD0_WP */ + [10] = RCAR_GP_PIN(3, 14), /* SD1_CD */ + [11] = RCAR_GP_PIN(3, 15), /* SD1_WP */ + [12] = RCAR_GP_PIN(5, 0), /* SCK0 */ + [13] = RCAR_GP_PIN(5, 1), /* RX0 */ + [14] = RCAR_GP_PIN(5, 2), /* TX0 */ + [15] = RCAR_GP_PIN(5, 3), /* CTS0_N */ + [16] = RCAR_GP_PIN(5, 4), /* RTS0_N */ + [17] = RCAR_GP_PIN(5, 5), /* RX1_A */ + [18] = RCAR_GP_PIN(5, 6), /* TX1_A */ + [19] = RCAR_GP_PIN(5, 7), /* CTS1_N */ + [20] = RCAR_GP_PIN(5, 8), /* RTS1_N */ + [21] = RCAR_GP_PIN(5, 9), /* SCK2 */ + [22] = RCAR_GP_PIN(5, 10), /* TX2_A */ + [23] = RCAR_GP_PIN(5, 11), /* RX2_A */ + [24] = RCAR_GP_PIN(5, 12), /* HSCK0 */ + [25] = RCAR_GP_PIN(5, 13), /* HRX0 */ + [26] = RCAR_GP_PIN(5, 14), /* HTX0 */ + [27] = RCAR_GP_PIN(5, 15), /* HCTS0_N */ + [28] = RCAR_GP_PIN(5, 16), /* HRTS0_N */ + [29] = RCAR_GP_PIN(5, 17), /* MSIOF0_SCK */ + [30] = RCAR_GP_PIN(5, 18), /* MSIOF0_SYNC */ + [31] = RCAR_GP_PIN(5, 19), /* MSIOF0_SS1 */ + } }, + { PFC_BIAS_REG(0x0414, 0x0454) { /* PUEN5, PUD5 */ + [0] = RCAR_GP_PIN(5, 20), /* MSIOF0_TXD */ + [1] = RCAR_GP_PIN(5, 21), /* MSIOF0_SS2 */ + [2] = RCAR_GP_PIN(5, 22), /* MSIOF0_RXD */ + [3] = RCAR_GP_PIN(5, 23), /* MLB_CLK */ + [4] = RCAR_GP_PIN(5, 24), /* MLB_SIG */ + [5] = RCAR_GP_PIN(5, 25), /* MLB_DAT */ + [6] = PIN_MLB_REF, /* MLB_REF */ + [7] = RCAR_GP_PIN(6, 0), /* SSI_SCK01239 */ + [8] = RCAR_GP_PIN(6, 1), /* SSI_WS01239 */ + [9] = RCAR_GP_PIN(6, 2), /* SSI_SDATA0 */ + [10] = RCAR_GP_PIN(6, 3), /* SSI_SDATA1_A */ + [11] = RCAR_GP_PIN(6, 4), /* SSI_SDATA2_A */ + [12] = RCAR_GP_PIN(6, 5), /* SSI_SCK349 */ + [13] = RCAR_GP_PIN(6, 6), /* SSI_WS349 */ + [14] = RCAR_GP_PIN(6, 7), /* SSI_SDATA3 */ + [15] = RCAR_GP_PIN(6, 8), /* SSI_SCK4 */ + [16] = RCAR_GP_PIN(6, 9), /* SSI_WS4 */ + [17] = RCAR_GP_PIN(6, 10), /* SSI_SDATA4 */ + [18] = RCAR_GP_PIN(6, 11), /* SSI_SCK5 */ + [19] = RCAR_GP_PIN(6, 12), /* SSI_WS5 */ + [20] = RCAR_GP_PIN(6, 13), /* SSI_SDATA5 */ + [21] = RCAR_GP_PIN(6, 14), /* SSI_SCK6 */ + [22] = RCAR_GP_PIN(6, 15), /* SSI_WS6 */ + [23] = RCAR_GP_PIN(6, 16), /* SSI_SDATA6 */ + [24] = RCAR_GP_PIN(6, 17), /* SSI_SCK78 */ + [25] = RCAR_GP_PIN(6, 18), /* SSI_WS78 */ + [26] = RCAR_GP_PIN(6, 19), /* SSI_SDATA7 */ + [27] = RCAR_GP_PIN(6, 20), /* SSI_SDATA8 */ + [28] = RCAR_GP_PIN(6, 21), /* SSI_SDATA9_A */ + [29] = RCAR_GP_PIN(6, 22), /* AUDIO_CLKA_A */ + [30] = RCAR_GP_PIN(6, 23), /* AUDIO_CLKB_B */ + [31] = RCAR_GP_PIN(6, 24), /* USB0_PWEN */ + } }, + { PFC_BIAS_REG(0x0418, 0x0458) { /* PUEN6, PUD6 */ + [0] = RCAR_GP_PIN(6, 25), /* USB0_OVC */ + [1] = RCAR_GP_PIN(6, 26), /* USB1_PWEN */ + [2] = RCAR_GP_PIN(6, 27), /* USB1_OVC */ + [3] = RCAR_GP_PIN(6, 28), /* USB30_PWEN */ + [4] = RCAR_GP_PIN(6, 29), /* USB30_OVC */ + [5] = RCAR_GP_PIN(6, 30), /* USB2_CH3_PWEN */ + [6] = RCAR_GP_PIN(6, 31), /* USB2_CH3_OVC */ + [7] = PIN_NONE, + [8] = PIN_NONE, + [9] = PIN_NONE, + [10] = PIN_NONE, + [11] = PIN_NONE, + [12] = PIN_NONE, + [13] = PIN_NONE, + [14] = PIN_NONE, + [15] = PIN_NONE, + [16] = PIN_NONE, + [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, + } }, + { /* 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; +} diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h new file mode 100644 index 000000000000..92f7aa507a44 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#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) + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ */ From 1de9794e126a2185cdc77a8a015de81150511796 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Thu, 9 Feb 2023 18:42:34 +0200 Subject: [PATCH 1118/2042] boards: arm64: add Renesas H3ULCB CA57 board support Add basic functionality for supporting h3ulcb board: * add documentation for h3ulcb board; * add pinctrl dtsi for scif driver; * add dts, yaml and configuration files. Signed-off-by: Mykola Kvach --- boards/arm64/rcar_h3ulcb_ca57/Kconfig.board | 6 ++ .../arm64/rcar_h3ulcb_ca57/Kconfig.defconfig | 12 +++ .../doc/img/rcar_h3ulcb_bottom.jpg | Bin 0 -> 69302 bytes .../doc/img/rcar_h3ulcb_top.jpg | Bin 0 -> 71197 bytes boards/arm64/rcar_h3ulcb_ca57/doc/index.rst | 86 ++++++++++++++++++ .../rcar_h3ulcb_ca57-pinctrl.dtsi | 17 ++++ .../rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.dts | 32 +++++++ .../rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.yaml | 17 ++++ .../rcar_h3ulcb_ca57_defconfig | 21 +++++ .../fuel_gauge/sbs_gauge/testcase.yaml | 1 + 10 files changed, 192 insertions(+) create mode 100644 boards/arm64/rcar_h3ulcb_ca57/Kconfig.board create mode 100644 boards/arm64/rcar_h3ulcb_ca57/Kconfig.defconfig create mode 100644 boards/arm64/rcar_h3ulcb_ca57/doc/img/rcar_h3ulcb_bottom.jpg create mode 100644 boards/arm64/rcar_h3ulcb_ca57/doc/img/rcar_h3ulcb_top.jpg create mode 100644 boards/arm64/rcar_h3ulcb_ca57/doc/index.rst create mode 100644 boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57-pinctrl.dtsi create mode 100644 boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.dts create mode 100644 boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.yaml create mode 100644 boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig diff --git a/boards/arm64/rcar_h3ulcb_ca57/Kconfig.board b/boards/arm64/rcar_h3ulcb_ca57/Kconfig.board new file mode 100644 index 000000000000..7367501632bc --- /dev/null +++ b/boards/arm64/rcar_h3ulcb_ca57/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RCAR_H3ULCB_CA57 + bool "Renesas H3ULCB" + depends on SOC_ARM64_R8A77951 diff --git a/boards/arm64/rcar_h3ulcb_ca57/Kconfig.defconfig b/boards/arm64/rcar_h3ulcb_ca57/Kconfig.defconfig new file mode 100644 index 000000000000..fefd6e1259d3 --- /dev/null +++ b/boards/arm64/rcar_h3ulcb_ca57/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RCAR_H3ULCB_CA57 + +config BOARD + default "rcar_h3ulcb_ca57" + +config BUILD_OUTPUT_BIN + default y + +endif # BOARD_RCAR_H3ULCB_CA57 diff --git a/boards/arm64/rcar_h3ulcb_ca57/doc/img/rcar_h3ulcb_bottom.jpg b/boards/arm64/rcar_h3ulcb_ca57/doc/img/rcar_h3ulcb_bottom.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55f8ccde660fc5f507f00d18147343e60b756f53 GIT binary patch literal 69302 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 fQ|&DsU-m02Z&&6D0jWMQu-8yMMF;y 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 + +&pfc { + scif2_data_a_tx_default: scif2_data_a_tx_default { + pin = ; + }; + + scif2_data_a_rx_default: scif2_data_a_rx_default { + pin = ; + }; +}; diff --git a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.dts b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.dts new file mode 100644 index 000000000000..7c1f153325de --- /dev/null +++ b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.dts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include +#include "rcar_h3ulcb_ca57-pinctrl.dtsi" + +/ { + model = "H3ULCB CA57"; + + chosen { + zephyr,sram = &ram; + zephyr,console = &scif2; + zephyr,shell-uart = &scif2; + }; + + ram: memory@48000000 { + device_type = "mmio-sram"; + reg = <0x0 0x48000000 0x0 DT_SIZE_M(512)>; + }; +}; + +&scif2 { + pinctrl-0 = <&scif2_data_a_tx_default &scif2_data_a_rx_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.yaml b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.yaml new file mode 100644 index 000000000000..7229a0b0ceef --- /dev/null +++ b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57.yaml @@ -0,0 +1,17 @@ +identifier: rcar_h3ulcb_ca57 +name: Renesas H3ULCB based on r8a77951 +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +ram: 512 +supported: + - clock_control + - uart +testing: + default: true + ignore_tags: + - net + - bluetooth + - isotp diff --git a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig new file mode 100644 index 000000000000..a312d33601ab --- /dev/null +++ b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig @@ -0,0 +1,21 @@ +CONFIG_SOC_ARM64_R8A77951=y +CONFIG_SOC_SERIES_RCAR_GEN3=y +CONFIG_BOARD_RCAR_H3ULCB_CA57=y + +# Cache management +CONFIG_CACHE_MANAGEMENT=y + +# Enable UART driver +CONFIG_SERIAL=y +CONFIG_AARCH64_IMAGE_HEADER=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 +CONFIG_XIP=n + +CONFIG_MAX_XLAT_TABLES=24 + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable clock control +CONFIG_CLOCK_CONTROL=y diff --git a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml index e03a2c7512aa..e1a873536243 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml +++ b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml @@ -17,6 +17,7 @@ tests: - qemu_kvm_arm64 - xenvm - xenvm_gicv3 + - rcar_h3ulcb_ca57 integration_platforms: - qemu_x86 drivers.sbs_gauge_new_api.emulated_64_bit_i2c_addr: From 38675f2b92c8084367fb8c6e04c02c77e00e584b Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 2 May 2023 13:36:34 +0300 Subject: [PATCH 1119/2042] soc: arm64: add support of r8a77961 Add support of r8a77961 SoC to gen3 series. Create a dtsi file with a common part for both r8a77951 and r8a77961. Signed-off-by: Mykola Kvach --- drivers/clock_control/CMakeLists.txt | 2 +- dts/arm64/renesas/r8a77951.dtsi | 68 +-------------- dts/arm64/renesas/r8a77961.dtsi | 28 +++++++ dts/arm64/renesas/rcar_gen3_ca57.dtsi | 84 +++++++++++++++++++ .../gen3/Kconfig.defconfig.r8a77961 | 9 ++ soc/arm64/renesas_rcar/gen3/Kconfig.soc | 3 + 6 files changed, 129 insertions(+), 65 deletions(-) create mode 100644 dts/arm64/renesas/r8a77961.dtsi create mode 100644 dts/arm64/renesas/rcar_gen3_ca57.dtsi create mode 100644 soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77961 diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 97d033164ee0..c2542965ead1 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -63,7 +63,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_AGILEX clock_agilex.c) if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) zephyr_library_sources(clock_control_renesas_cpg_mssr.c) - zephyr_library_sources_ifdef(CONFIG_SOC_R8A77951 clock_control_r8a7795_cpg_mssr.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED clock_control_r8a7795_cpg_mssr.c) endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) diff --git a/dts/arm64/renesas/r8a77951.dtsi b/dts/arm64/renesas/r8a77951.dtsi index e199a303a620..afd2e6cd8c66 100644 --- a/dts/arm64/renesas/r8a77951.dtsi +++ b/dts/arm64/renesas/r8a77951.dtsi @@ -5,15 +5,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include +#include "rcar_gen3_ca57.dtsi" / { compatible = "renesas,r8a77951"; - #address-cells = <2>; - #size-cells = <2>; cpus { #address-cells = <1>; @@ -26,63 +21,8 @@ enable-method = "psci"; }; }; +}; - psci { - compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; - method = "smc"; - }; - - arch_timer: timer { - compatible = "arm,armv8-timer"; - interrupt-parent = <&gic>; - interrupts = , - , - , - ; - }; - - gic: interrupt-controller@f1010000 { - compatible = "arm,gic-400", "arm,gic" ; - #interrupt-cells = <4>; - #address-cells = <0>; - interrupt-controller; - reg = <0 0xf1010000 0 0x1000>, - <0 0xf1020000 0 0x20000>; - status = "okay"; - }; - - soc: soc { - compatible = "simple-bus"; - interrupt-parent = <&gic>; - - #address-cells = <2>; - #size-cells = <2>; - ranges; - - cpg: clock-controller@e6150000 { - compatible = "renesas,r8a7795-cpg-mssr"; - reg = <0 0xe6150000 0 0x1000>; - #clock-cells = <2>; - #power-domain-cells = <0>; - #reset-cells = <1>; - }; - - pfc: pin-controller@e6060000 { - compatible = "renesas,rcar-pfc"; - reg = <0 0xe6060000 0 0x50c>; - }; - - scif2: serial@e6e88000 { - compatible = "renesas,rcar-scif"; - reg = <0 0xe6e88000 0 0x64>; - interrupt-parent = <&gic>; - clocks = <&cpg CPG_MOD 310>, - <&cpg CPG_CORE R8A7795_CLK_S3D4>; - interrupts = ; - current-speed = <115200>; - interrupt-names = "irq_0"; - status = "disabled"; - }; - }; +&cpg { + compatible = "renesas,r8a7795-cpg-mssr"; }; diff --git a/dts/arm64/renesas/r8a77961.dtsi b/dts/arm64/renesas/r8a77961.dtsi new file mode 100644 index 000000000000..48f9ca145374 --- /dev/null +++ b/dts/arm64/renesas/r8a77961.dtsi @@ -0,0 +1,28 @@ +/* + * Device Tree Source for the R-Car M3 (R8A77961) SoC + * + * Copyright (C) 2023 EPAM Systems. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "rcar_gen3_ca57.dtsi" + +/ { + compatible = "renesas,r8a77961"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + a57_0: cpu@0 { + compatible = "arm,cortex-a57", "arm,armv8"; + reg = <0x0>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; +}; + +&cpg { + compatible = "renesas,r8a7795-cpg-mssr"; +}; diff --git a/dts/arm64/renesas/rcar_gen3_ca57.dtsi b/dts/arm64/renesas/rcar_gen3_ca57.dtsi new file mode 100644 index 000000000000..d9bba53f2a35 --- /dev/null +++ b/dts/arm64/renesas/rcar_gen3_ca57.dtsi @@ -0,0 +1,84 @@ +/* + * Device Tree Source for the R-Car H3/M3 (R8A77951/R8A77961) SoC + * + * Copyright (C) 2023 EPAM Systems. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; + method = "smc"; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + gic: interrupt-controller@f1010000 { + compatible = "arm,gic-400", "arm,gic" ; + #interrupt-cells = <4>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0xf1010000 0 0x1000>, + <0 0xf1020000 0 0x20000>; + status = "okay"; + }; + + soc: soc { + compatible = "simple-bus"; + interrupt-parent = <&gic>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cpg: clock-controller@e6150000 { + reg = <0 0xe6150000 0 0x1000>; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; + + emmc2: mmc@ee140000 { + compatible = "renesas,rcar-mmc"; + reg = <0 0xee140000 0 0x2000>; + interrupts = ; + clocks = <&cpg CPG_MOD 312>; + max-frequency = <200000000>; + status = "disabled"; + }; + + pfc: pin-controller@e6060000 { + compatible = "renesas,rcar-pfc"; + reg = <0 0xe6060000 0 0x50c>; + }; + + scif2: serial@e6e88000 { + compatible = "renesas,rcar-scif"; + reg = <0 0xe6e88000 0 0x64>; + interrupt-parent = <&gic>; + clocks = <&cpg CPG_MOD 310>, + <&cpg CPG_CORE R8A7795_CLK_S3D4>; + interrupts = ; + current-speed = <115200>; + interrupt-names = "irq_0"; + status = "disabled"; + }; + }; +}; diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77961 b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77961 new file mode 100644 index 000000000000..573e7b102fbc --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.defconfig.r8a77961 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +if SOC_R8A77961 + +config SOC + default "r8a77961" + +endif # SOC_R8A77961 diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.soc b/soc/arm64/renesas_rcar/gen3/Kconfig.soc index 783fce021a23..4be06397bd1b 100644 --- a/soc/arm64/renesas_rcar/gen3/Kconfig.soc +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.soc @@ -8,4 +8,7 @@ choice config SOC_ARM64_R8A77951 bool "R8A77951" +config SOC_R8A77961 + bool "R8A77961" + endchoice From 634e73dd2157990160dea9f164b6e32a795879fd Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 2 May 2023 14:53:39 +0300 Subject: [PATCH 1120/2042] soc: arm64: add PFC files to Renesas r8a77961 Gen3 SoC Add Pin Function Controller tables of registers and their bits for ARM64 Renesas R-Car family. With this changes we can use Renesas PFC driver for configuring bias and driving capabilities. Add only needed driver strength and bias pins to PFC, e.g. SDx and UART TX/RX pins. Signed-off-by: Mykola Kvach --- .../pinctrl/renesas/pinctrl-r8a77961.h | 112 ++++++++++++++ soc/arm64/renesas_rcar/gen3/CMakeLists.txt | 1 + soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c | 146 ++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a77961.h create mode 100644 soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a77961.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a77961.h new file mode 100644 index 000000000000..3703d2f3c59d --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a77961.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A77961_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A77961_H_ + +#include "pinctrl-rcar-common.h" + +/* Pins declaration */ +#define PIN_NONE -1 + +#define PIN_SD0_CLK RCAR_GP_PIN(3, 0) +#define PIN_SD0_CMD RCAR_GP_PIN(3, 1) +#define PIN_SD0_DATA0 RCAR_GP_PIN(3, 2) +#define PIN_SD0_DATA1 RCAR_GP_PIN(3, 3) +#define PIN_SD0_DATA2 RCAR_GP_PIN(3, 4) +#define PIN_SD0_DATA3 RCAR_GP_PIN(3, 5) +#define PIN_SD0_CD RCAR_GP_PIN(3, 12) +#define PIN_SD0_WP RCAR_GP_PIN(3, 13) + +#define PIN_SD1_CLK RCAR_GP_PIN(3, 6) +#define PIN_SD1_CMD RCAR_GP_PIN(3, 7) +/* + * note: the next data pins shared with SD2, + * and for SD2 they represent DATA4-DATA7 + */ +#define PIN_SD1_DATA0 RCAR_GP_PIN(3, 8) +#define PIN_SD1_DATA1 RCAR_GP_PIN(3, 9) +#define PIN_SD1_DATA2 RCAR_GP_PIN(3, 10) +#define PIN_SD1_DATA3 RCAR_GP_PIN(3, 11) + +#define PIN_SD1_CD RCAR_GP_PIN(3, 14) +#define PIN_SD1_WP RCAR_GP_PIN(3, 15) + +#define PIN_SD2_CLK RCAR_GP_PIN(4, 0) +#define PIN_SD2_CMD RCAR_GP_PIN(4, 1) +#define PIN_SD2_DATA0 RCAR_GP_PIN(4, 2) +#define PIN_SD2_DATA1 RCAR_GP_PIN(4, 3) +#define PIN_SD2_DATA2 RCAR_GP_PIN(4, 4) +#define PIN_SD2_DATA3 RCAR_GP_PIN(4, 5) +#define PIN_SD2_DS RCAR_GP_PIN(4, 6) + +#define PIN_SD3_CLK RCAR_GP_PIN(4, 7) +#define PIN_SD3_CMD RCAR_GP_PIN(4, 8) +#define PIN_SD3_DATA0 RCAR_GP_PIN(4, 9) +#define PIN_SD3_DATA1 RCAR_GP_PIN(4, 10) +#define PIN_SD3_DATA2 RCAR_GP_PIN(4, 11) +#define PIN_SD3_DATA3 RCAR_GP_PIN(4, 12) +#define PIN_SD3_DATA4 RCAR_GP_PIN(4, 13) +#define PIN_SD3_DATA5 RCAR_GP_PIN(4, 14) +#define PIN_SD3_DATA6 RCAR_GP_PIN(4, 15) +#define PIN_SD3_DATA7 RCAR_GP_PIN(4, 16) +#define PIN_SD3_DS RCAR_GP_PIN(4, 17) + +#define PIN_TX2_A RCAR_GP_PIN(5, 10) +#define PIN_RX2_A RCAR_GP_PIN(5, 11) + +/* Pinmux function declarations */ +#define FUNC_SD0_CLK IPSR(7, 12, 0) +#define FUNC_SD0_CMD IPSR(7, 16, 0) +#define FUNC_SD0_DAT0 IPSR(7, 20, 0) +#define FUNC_SD0_DAT1 IPSR(7, 24, 0) +#define FUNC_SD0_DAT2 IPSR(8, 0, 0) +#define FUNC_SD0_DAT3 IPSR(8, 4, 0) +#define FUNC_SD0_CD IPSR(11, 8, 0) +#define FUNC_SD0_WP IPSR(11, 12, 0) + +#define FUNC_SD1_CLK IPSR(8, 8, 0) +#define FUNC_SD1_CMD IPSR(8, 12, 0) +#define FUNC_SD1_DAT0 IPSR(8, 16, 0) +#define FUNC_SD1_DAT1 IPSR(8, 20, 0) +#define FUNC_SD1_DAT2 IPSR(8, 24, 0) +#define FUNC_SD1_DAT3 IPSR(8, 28, 0) +#define FUNC_SD1_CD IPSR(11, 16, 0) +#define FUNC_SD1_WP IPSR(11, 20, 0) + +#define FUNC_SD2_CLK IPSR(9, 0, 0) +#define FUNC_SD2_CMD IPSR(9, 4, 0) +#define FUNC_SD2_DAT0 IPSR(9, 8, 0) +#define FUNC_SD2_DAT1 IPSR(9, 12, 0) +#define FUNC_SD2_DAT2 IPSR(9, 16, 0) +#define FUNC_SD2_DAT3 IPSR(9, 20, 0) +#define FUNC_SD2_DAT4 IPSR(8, 16, 1) +#define FUNC_SD2_DAT5 IPSR(8, 20, 1) +#define FUNC_SD2_DAT6 IPSR(8, 24, 1) +#define FUNC_SD2_DAT7 IPSR(8, 28, 1) +#define FUNC_SD2_CD_A IPSR(10, 20, 1) +#define FUNC_SD2_WP_A IPSR(10, 24, 1) +#define FUNC_SD2_CD_B IPSR(13, 0, 3) +#define FUNC_SD2_WP_B IPSR(13, 4, 3) +#define FUNC_SD2_DS IPSR(9, 24, 0) + +#define FUNC_SD3_CLK IPSR(9, 28, 0) +#define FUNC_SD3_CMD IPSR(10, 0, 0) +#define FUNC_SD3_DAT0 IPSR(10, 4, 0) +#define FUNC_SD3_DAT1 IPSR(10, 8, 0) +#define FUNC_SD3_DAT2 IPSR(10, 12, 0) +#define FUNC_SD3_DAT3 IPSR(10, 16, 0) +#define FUNC_SD3_DAT4 IPSR(10, 20, 0) +#define FUNC_SD3_DAT5 IPSR(10, 24, 0) +#define FUNC_SD3_DAT6 IPSR(10, 28, 0) +#define FUNC_SD3_DAT7 IPSR(11, 0, 0) +#define FUNC_SD3_CD IPSR(10, 28, 1) +#define FUNC_SD3_WP IPSR(11, 0, 1) +#define FUNC_SD3_DS IPSR(11, 4, 0) + +#define FUNC_TX2_A IPSR(13, 0, 0) +#define FUNC_RX2_A IPSR(13, 4, 0) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A77961_H_ */ diff --git a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt index 9fe52fe0d595..23315289c610 100644 --- a/soc/arm64/renesas_rcar/gen3/CMakeLists.txt +++ b/soc/arm64/renesas_rcar/gen3/CMakeLists.txt @@ -2,4 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources_ifdef(CONFIG_SOC_ARM64_R8A77951 pfc_r8a77951.c) +zephyr_library_sources_ifdef(CONFIG_SOC_R8A77961 pfc_r8a77961.c) zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c new file mode 100644 index 000000000000..c130dd510a83 --- /dev/null +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "pinctrl_soc.h" +#include + +const struct pfc_drive_reg pfc_drive_regs[] = { + /* DRVCTRL13 */ + { 0x0334, { + { RCAR_GP_PIN(3, 0), 20, 3 }, /* SD0_CLK */ + { RCAR_GP_PIN(3, 1), 16, 3 }, /* SD0_CMD */ + { RCAR_GP_PIN(3, 2), 12, 3 }, /* SD0_DAT0 */ + { RCAR_GP_PIN(3, 3), 8, 3 }, /* SD0_DAT1 */ + { RCAR_GP_PIN(3, 4), 4, 3 }, /* SD0_DAT2 */ + { RCAR_GP_PIN(3, 5), 0, 3 }, /* SD0_DAT3 */ + } }, + /* DRVCTRL14 */ + { 0x0338, { + { RCAR_GP_PIN(3, 6), 28, 3 }, /* SD1_CLK */ + { RCAR_GP_PIN(3, 7), 24, 3 }, /* SD1_CMD */ + { RCAR_GP_PIN(3, 8), 20, 3 }, /* SD1_DAT0 */ + { RCAR_GP_PIN(3, 9), 16, 3 }, /* SD1_DAT1 */ + { RCAR_GP_PIN(3, 10), 12, 3 }, /* SD1_DAT2 */ + { RCAR_GP_PIN(3, 11), 8, 3 }, /* SD1_DAT3 */ + { RCAR_GP_PIN(4, 0), 4, 3 }, /* SD2_CLK */ + { RCAR_GP_PIN(4, 1), 0, 3 }, /* SD2_CMD */ + } }, + /* DRVCTRL15 */ + { 0x033c, { + { RCAR_GP_PIN(4, 2), 28, 3 }, /* SD2_DAT0 */ + { RCAR_GP_PIN(4, 3), 24, 3 }, /* SD2_DAT1 */ + { RCAR_GP_PIN(4, 4), 20, 3 }, /* SD2_DAT2 */ + { RCAR_GP_PIN(4, 5), 16, 3 }, /* SD2_DAT3 */ + { RCAR_GP_PIN(4, 6), 12, 3 }, /* SD2_DS */ + { RCAR_GP_PIN(4, 7), 8, 3 }, /* SD3_CLK */ + { RCAR_GP_PIN(4, 8), 4, 3 }, /* SD3_CMD */ + { RCAR_GP_PIN(4, 9), 0, 3 }, /* SD3_DAT0 */ + } }, + /* DRVCTRL16 */ + { 0x0340, { + { RCAR_GP_PIN(4, 10), 28, 3 }, /* SD3_DAT1 */ + { RCAR_GP_PIN(4, 11), 24, 3 }, /* SD3_DAT2 */ + { RCAR_GP_PIN(4, 12), 20, 3 }, /* SD3_DAT3 */ + { RCAR_GP_PIN(4, 13), 16, 3 }, /* SD3_DAT4 */ + { RCAR_GP_PIN(4, 14), 12, 3 }, /* SD3_DAT5 */ + { RCAR_GP_PIN(4, 15), 8, 3 }, /* SD3_DAT6 */ + { RCAR_GP_PIN(4, 16), 4, 3 }, /* SD3_DAT7 */ + { RCAR_GP_PIN(4, 17), 0, 3 }, /* SD3_DS */ + } }, + /* DRVCTRL17 */ + { 0x0344, { + { RCAR_GP_PIN(3, 12), 28, 3 }, /* SD0_CD */ + { RCAR_GP_PIN(3, 13), 24, 3 }, /* SD0_WP */ + { RCAR_GP_PIN(3, 14), 20, 3 }, /* SD1_CD */ + { RCAR_GP_PIN(3, 15), 16, 3 }, /* SD1_WP */ + { RCAR_GP_PIN(5, 0), 12, 3 }, /* SCK0 */ + { RCAR_GP_PIN(5, 1), 8, 3 }, /* RX0 */ + { RCAR_GP_PIN(5, 2), 4, 3 }, /* TX0 */ + { RCAR_GP_PIN(5, 3), 0, 3 }, /* CTS0 */ + } }, + /* DRVCTRL18 */ + { 0x0348, { + { RCAR_GP_PIN(5, 4), 28, 3 }, /* RTS0 */ + { RCAR_GP_PIN(5, 5), 24, 3 }, /* RX1 */ + { RCAR_GP_PIN(5, 6), 20, 3 }, /* TX1 */ + { RCAR_GP_PIN(5, 7), 16, 3 }, /* CTS1 */ + { RCAR_GP_PIN(5, 8), 12, 3 }, /* RTS1 */ + { RCAR_GP_PIN(5, 9), 8, 3 }, /* SCK2 */ + { RCAR_GP_PIN(5, 10), 4, 3 }, /* TX2 */ + { RCAR_GP_PIN(5, 11), 0, 3 }, /* RX2 */ + } }, + { }, +}; + +#define PFC_BIAS_REG(r1, r2) \ + .puen = r1, \ + .pud = r2, \ + .pins = + +const struct pfc_bias_reg pfc_bias_regs[] = { + { PFC_BIAS_REG(0x040c, 0x044c) { /* PUEN3, PUD3 */ + [0 ... 9] = PIN_NONE, + [10] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ + [11] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ + [12] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ + [13] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ + [14] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ + [15] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ + [16] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ + [17] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ + [18] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ + [19] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ + [20] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ + [21] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ + [22] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ + [23] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ + [24] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ + [25] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ + [26] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ + [27] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ + [28] = RCAR_GP_PIN(4, 6), /* SD2_DS */ + [29] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ + [30] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ + [31] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ + } }, + { PFC_BIAS_REG(0x0410, 0x0450) { /* PUEN4, PUD4 */ + [0] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ + [1] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ + [2] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ + [3] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ + [4] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ + [5] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ + [6] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ + [7] = RCAR_GP_PIN(4, 17), /* SD3_DS */ + [8] = RCAR_GP_PIN(3, 12), /* SD0_CD */ + [9] = RCAR_GP_PIN(3, 13), /* SD0_WP */ + [10] = RCAR_GP_PIN(3, 14), /* SD1_CD */ + [11] = RCAR_GP_PIN(3, 15), /* SD1_WP */ + [12] = RCAR_GP_PIN(5, 0), /* SCK0 */ + [13] = RCAR_GP_PIN(5, 1), /* RX0 */ + [14] = RCAR_GP_PIN(5, 2), /* TX0 */ + [15] = RCAR_GP_PIN(5, 3), /* CTS0_N */ + [16] = RCAR_GP_PIN(5, 4), /* RTS0_N */ + [17] = RCAR_GP_PIN(5, 5), /* RX1_A */ + [18] = RCAR_GP_PIN(5, 6), /* TX1_A */ + [19] = RCAR_GP_PIN(5, 7), /* CTS1_N */ + [20] = RCAR_GP_PIN(5, 8), /* RTS1_N */ + [21] = RCAR_GP_PIN(5, 9), /* SCK2 */ + [22] = RCAR_GP_PIN(5, 10), /* TX2_A */ + [23] = RCAR_GP_PIN(5, 11), /* RX2_A */ + [24 ... 31] = PIN_NONE, + } }, + { /* 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; +} From 7471c0ca0fe77611e7c5871de64d11fdd62f81ea Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 2 May 2023 15:33:33 +0300 Subject: [PATCH 1121/2042] boards: arm64: add support of Salvator XS M3 board Add support of 'rcar_salvator_xs_m3' board: minimal dts and configuration. Signed-off-by: Mykola Kvach --- .../arm64/rcar_salvator_xs_m3/Kconfig.board | 6 ++ .../rcar_salvator_xs_m3/Kconfig.defconfig | 12 ++++ .../arm64/rcar_salvator_xs_m3/doc/index.rst | 69 +++++++++++++++++++ .../rcar_salvator_xs_m3.dts | 32 +++++++++ .../rcar_salvator_xs_m3.yaml | 17 +++++ .../rcar_salvator_xs_m3_defconfig | 21 ++++++ .../salvator_xs_m3-pinctrl.dtsi | 17 +++++ .../fuel_gauge/sbs_gauge/testcase.yaml | 1 + 8 files changed, 175 insertions(+) create mode 100644 boards/arm64/rcar_salvator_xs_m3/Kconfig.board create mode 100644 boards/arm64/rcar_salvator_xs_m3/Kconfig.defconfig create mode 100644 boards/arm64/rcar_salvator_xs_m3/doc/index.rst create mode 100644 boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.dts create mode 100644 boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.yaml create mode 100644 boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig create mode 100644 boards/arm64/rcar_salvator_xs_m3/salvator_xs_m3-pinctrl.dtsi diff --git a/boards/arm64/rcar_salvator_xs_m3/Kconfig.board b/boards/arm64/rcar_salvator_xs_m3/Kconfig.board new file mode 100644 index 000000000000..032514dac7a4 --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RCAR_SALVATOR_XS_M3 + bool "Renesas Salvator XS M3" + depends on SOC_R8A77961 diff --git a/boards/arm64/rcar_salvator_xs_m3/Kconfig.defconfig b/boards/arm64/rcar_salvator_xs_m3/Kconfig.defconfig new file mode 100644 index 000000000000..7230474a1d7f --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RCAR_SALVATOR_XS_M3 + +config BOARD + default "rcar_salvator_xs_m3" + +config BUILD_OUTPUT_BIN + default y + +endif # BOARD_RCAR_SALVATOR_XS_M3 diff --git a/boards/arm64/rcar_salvator_xs_m3/doc/index.rst b/boards/arm64/rcar_salvator_xs_m3/doc/index.rst new file mode 100644 index 000000000000..b89c71d4ecd8 --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/doc/index.rst @@ -0,0 +1,69 @@ +.. _rcar_salvator_xs_m3: + +R-CAR Salvator XS M3 ARM CA57 (ARMv8) +##################################### + +Overview +******** +The R-Car M3-W is an SOC that features the basic functions for next-generation +car navigation systems. + +Hardware +******** +The R-Car M3-W includes: + +* two 1.5-GHz ARM Cortex-A57 MPCore cores; +* four 1.3-GHz ARM Cortex-A53 MPCore cores, +* memory controller for LPDDR4-3200 with 32 bits x 2 channels; +* 1 channels for HDMI1.4b output and 1 channel for RGB888 output and 1channel for LVDS; +* 2 channels MIPI-CSI2 Video Input, 2 channels digital Video Input; +* USB3.0 x 1ch and USB2.0 x 2ch interfaces; +* 800-MHz ARM Cortex-R7 core; +* two- and three-dimensional graphics engines; +* video processing units; +* sound processing units; +* MediaLB interface; +* SD card host interface; +* USB3.0 and USB2.0 interfaces; +* PCI Express interface; +* CAN interface; +* EtherAVB. + +Supported Features +================== +The Renesas rcar_salvator_xs_m3 board configuration supports the following +hardware features: + ++-----------+------------------------------+--------------------------------+ +| Interface | Driver/components | Support level | ++===========+==============================+================================+ +| PINCTRL | pinctrl | | ++-----------+------------------------------+--------------------------------+ +| CLOCK | clock_control | | ++-----------+------------------------------+--------------------------------+ +| UART | uart | serial port-polling | ++-----------+------------------------------+--------------------------------+ + +Other hardware features have not been enabled yet for this board. + +The default configuration can be found in the defconfig file: + + ``boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig`` + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +References +********** + +- `Renesas R-Car Development Support website`_ +- `eLinux Salvator-XS page`_ + +.. _Renesas R-Car Development Support website: + https://www.renesas.com/us/en/support/partners/r-car-consortium/r-car-development-support + +.. _eLinux Salvator-XS page: + https://elinux.org/R-Car/Boards/Salvator-XS diff --git a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.dts b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.dts new file mode 100644 index 000000000000..15fae0ca9656 --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.dts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include +#include "salvator_xs_m3-pinctrl.dtsi" + +/ { + model = "Salvator XS M3"; + + chosen { + zephyr,sram = &ram; + zephyr,console = &scif2; + zephyr,shell-uart = &scif2; + }; + + ram: memory@48000000 { + device_type = "mmio-sram"; + reg = <0x0 0x48000000 0x0 DT_SIZE_M(512)>; + }; +}; + +&scif2 { + pinctrl-0 = <&scif2_data_a_tx_default &scif2_data_a_rx_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.yaml b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.yaml new file mode 100644 index 000000000000..413e33258bf2 --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3.yaml @@ -0,0 +1,17 @@ +identifier: rcar_salvator_xs_m3 +name: Renesas Salvator XS M3 based on r8a77961 +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile +ram: 512 +supported: + - clock_control + - uart +testing: + default: true + ignore_tags: + - net + - bluetooth + - isotp 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 new file mode 100644 index 000000000000..3dca6448ac47 --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig @@ -0,0 +1,21 @@ +CONFIG_SOC_R8A77961=y +CONFIG_SOC_SERIES_RCAR_GEN3=y +CONFIG_BOARD_RCAR_SALVATOR_XS_M3=y + +# Cache management +CONFIG_CACHE_MANAGEMENT=y + +# Enable UART driver +CONFIG_SERIAL=y +CONFIG_AARCH64_IMAGE_HEADER=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 +CONFIG_XIP=n + +CONFIG_MAX_XLAT_TABLES=24 + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable clock control +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm64/rcar_salvator_xs_m3/salvator_xs_m3-pinctrl.dtsi b/boards/arm64/rcar_salvator_xs_m3/salvator_xs_m3-pinctrl.dtsi new file mode 100644 index 000000000000..69529f233ace --- /dev/null +++ b/boards/arm64/rcar_salvator_xs_m3/salvator_xs_m3-pinctrl.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 EPAM Systems + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pfc { + scif2_data_a_tx_default: scif2_data_a_tx_default { + pin = ; + }; + + scif2_data_a_rx_default: scif2_data_a_rx_default { + pin = ; + }; +}; diff --git a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml index e1a873536243..5e8500a8dece 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml +++ b/tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml @@ -18,6 +18,7 @@ tests: - xenvm - xenvm_gicv3 - rcar_h3ulcb_ca57 + - rcar_salvator_xs_m3 integration_platforms: - qemu_x86 drivers.sbs_gauge_new_api.emulated_64_bit_i2c_addr: From 832e1e256e6e4362f2554a90ce9c4da331d87fec Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Tue, 27 Jun 2023 13:37:50 +0300 Subject: [PATCH 1122/2042] MAINTAINERS: Renesas R-Car ARM64: add entry Renesas R-Car ARM64 platforms entry has been added to maintainers list. lorc (Volodymyr Babchuk ) will be a maintainer of the Renesas R-Car boards based on ARMv8. Signed-off-by: Mykola Kvach Acked-by: Volodymyr Babchuk --- MAINTAINERS.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c2817ef93ce0..400ba9661673 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2406,6 +2406,20 @@ Renesas R-Car Platforms: Renesas R-Car SOCs, dts files and related drivers. Renesas boards based on R-Car SOCs. +Renesas R-Car ARM64 Platforms: + status: maintained + maintainers: + - lorc + files: + - boards/arm64/rcar_*/ + - dts/arm64/renesas/ + - soc/arm64/renesas_rcar/ + labels: + - "platform: Renesas R-Car ARM64" + description: >- + Renesas R-Car SOCs and dts files, ARMv8 side. Zephyr running on ARMv8 CPUs on Renesas + boards based on R-Car SOCs. + STM32 Platforms: status: maintained maintainers: From 15b8bff8325e7d3832a9f78c95c963571fcd2ec9 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 30 Mar 2023 12:56:45 +0200 Subject: [PATCH 1123/2042] mainfest: west.yml: Update version of SEGGER RTT library Bumped segger libary version up to version 3.40 Signed-off-by: Sigvart Hovland --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index cb7a8ea616a1..fa0ba27c9f88 100644 --- a/west.yml +++ b/west.yml @@ -299,7 +299,7 @@ manifest: path: modules/lib/picolibc revision: d07c38ff051386f8e09a143ea0a6c1d6d66dd1d8 - name: segger - revision: 4bfaf28a11c3e5ec29badac744fab6d2f342749e + revision: 5792675a2470d0f3857de1e77bff57b38c28de3b path: modules/debug/segger groups: - debug From 1ddc41e7ddce29d7c4d097350190d4266ffd0ec1 Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Mon, 12 Jun 2023 16:15:25 +0200 Subject: [PATCH 1124/2042] drivers: i2c: tca954x: Add build assert avoiding prio issues In order for TCA954X driver to work well, we know that mux root must be initialized before channels. (see #37786). This commit is: - Ensuring that this condition is met at build. - Document needed values for menuconfig to help user. - Edit these values for TCA954X test sample Fixes #40833 Signed-off-by: Aymeric Aillet --- drivers/i2c/Kconfig.tca954x | 4 ++++ drivers/i2c/i2c_tca954x.c | 3 +++ tests/drivers/i2c/i2c_tca954x/prj.conf | 2 ++ 3 files changed, 9 insertions(+) diff --git a/drivers/i2c/Kconfig.tca954x b/drivers/i2c/Kconfig.tca954x index 344f108fb51b..dcf5abcdfcfa 100644 --- a/drivers/i2c/Kconfig.tca954x +++ b/drivers/i2c/Kconfig.tca954x @@ -13,9 +13,13 @@ if I2C_TCA954X config I2C_TCA954X_ROOT_INIT_PRIO int "TCA954x root driver init priority" default I2C_INIT_PRIORITY + help + Should be lower than `I2C_TCA954X_CHANNEL_INIT_PRIO` config I2C_TCA954X_CHANNEL_INIT_PRIO int "TCA954x channel driver init priority" default I2C_INIT_PRIORITY + help + Should be higher than `I2C_TCA954X_ROOT_INIT_PRIO` endif diff --git a/drivers/i2c/i2c_tca954x.c b/drivers/i2c/i2c_tca954x.c index 603ba79ed454..7bbb1f59ca39 100644 --- a/drivers/i2c/i2c_tca954x.c +++ b/drivers/i2c/i2c_tca954x.c @@ -156,6 +156,9 @@ const struct i2c_driver_api tca954x_api_funcs = { .transfer = tca954x_transfer, }; +BUILD_ASSERT(CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO > CONFIG_I2C_TCA954X_ROOT_INIT_PRIO, + "I2C multiplexer channels must be initialized after their root"); + #define TCA954x_CHILD_DEFINE(node_id, n) \ static const struct tca954x_channel_config \ tca##n##a_down_config_##node_id = { \ diff --git a/tests/drivers/i2c/i2c_tca954x/prj.conf b/tests/drivers/i2c/i2c_tca954x/prj.conf index 72fff9bd78b8..fc01984ad47e 100644 --- a/tests/drivers/i2c/i2c_tca954x/prj.conf +++ b/tests/drivers/i2c/i2c_tca954x/prj.conf @@ -1,3 +1,5 @@ CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_I2C=y +CONFIG_I2C_TCA954X_ROOT_INIT_PRIO=61 +CONFIG_I2C_TCA954X_CHANNEL_INIT_PRIO=62 From a132487fec5b8bba3a0a891aac664ac5e827a434 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 14 Jun 2023 01:34:14 +0530 Subject: [PATCH 1125/2042] net: wifi: Move Wi-Fi ops to a separate struct Decouple interface and Wi-Fi APIs, Wi-Fi APIs are common independent of Wi-Fi offload or implemented natively (This is preparation for introducing Native Wi-Fi). Signed-off-by: Chaitanya Tata --- drivers/wifi/esp32/src/esp_wifi_drv.c | 24 ++++++---- drivers/wifi/esp_at/esp.c | 19 +++++--- drivers/wifi/eswifi/eswifi_core.c | 18 ++++--- drivers/wifi/simplelink/simplelink.c | 12 +++-- drivers/wifi/winc1500/wifi_winc1500.c | 15 +++--- include/zephyr/net/wifi_mgmt.h | 29 ++++++------ subsys/net/l2/wifi/wifi_mgmt.c | 67 +++++++++++++++++---------- 7 files changed, 112 insertions(+), 72 deletions(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 647f91b28909..177b8e739aee 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -624,18 +624,22 @@ static int esp32_wifi_dev_init(const struct device *dev) return 0; } +static const struct wifi_mgmt_ops esp32_wifi_mgmt = { + .scan = esp32_wifi_scan, + .connect = esp32_wifi_connect, + .disconnect = esp32_wifi_disconnect, + .ap_enable = esp32_wifi_ap_enable, + .ap_disable = esp32_wifi_ap_disable, + .iface_status = esp32_wifi_status, +#if defined(CONFIG_NET_STATISTICS_WIFI) + .get_stats = esp32_wifi_stats, +#endif +}; + static const struct net_wifi_mgmt_offload esp32_api = { - .wifi_iface.iface_api.init = esp32_wifi_init, + .wifi_iface.iface_api.init = esp32_wifi_init, .wifi_iface.send = esp32_wifi_send, -#if defined(CONFIG_NET_STATISTICS_WIFI) - .get_stats = esp32_wifi_stats, - #endif - .scan = esp32_wifi_scan, - .connect = esp32_wifi_connect, - .disconnect = esp32_wifi_disconnect, - .ap_enable = esp32_wifi_ap_enable, - .ap_disable = esp32_wifi_ap_disable, - .iface_status = esp32_wifi_status, + .wifi_mgmt_api = &esp32_wifi_mgmt, }; NET_DEVICE_DT_INST_DEFINE(0, diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index ef3022eb1d47..df20caae5b66 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -1246,15 +1246,20 @@ static enum offloaded_net_if_types esp_offload_get_type(void) { return L2_OFFLOADED_NET_IF_TYPE_WIFI; } + +static const struct wifi_mgmt_ops esp_mgmt_ops = { + .scan = esp_mgmt_scan, + .connect = esp_mgmt_connect, + .disconnect = esp_mgmt_disconnect, + .ap_enable = esp_mgmt_ap_enable, + .ap_disable = esp_mgmt_ap_disable, + .iface_status = esp_mgmt_iface_status, +}; + static const struct net_wifi_mgmt_offload esp_api = { .wifi_iface.iface_api.init = esp_iface_init, - .wifi_iface.get_type = esp_offload_get_type, - .scan = esp_mgmt_scan, - .connect = esp_mgmt_connect, - .disconnect = esp_mgmt_disconnect, - .ap_enable = esp_mgmt_ap_enable, - .ap_disable = esp_mgmt_ap_disable, - .iface_status = esp_mgmt_iface_status, + .wifi_iface.get_type = esp_offload_get_type, + .wifi_mgmt_api = &esp_mgmt_ops, }; static int esp_init(const struct device *dev); diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index 44c911831dfe..b05c980500d0 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -786,15 +786,19 @@ static enum offloaded_net_if_types eswifi_get_type(void) return L2_OFFLOADED_NET_IF_TYPE_WIFI; } +static const struct wifi_mgmt_ops eswifi_mgmt_api = { + .scan = eswifi_mgmt_scan, + .connect = eswifi_mgmt_connect, + .disconnect = eswifi_mgmt_disconnect, + .ap_enable = eswifi_mgmt_ap_enable, + .ap_disable = eswifi_mgmt_ap_disable, + .iface_status = eswifi_mgmt_iface_status, +}; + static const struct net_wifi_mgmt_offload eswifi_offload_api = { .wifi_iface.iface_api.init = eswifi_iface_init, - .wifi_iface.get_type = eswifi_get_type, - .scan = eswifi_mgmt_scan, - .connect = eswifi_mgmt_connect, - .disconnect = eswifi_mgmt_disconnect, - .ap_enable = eswifi_mgmt_ap_enable, - .ap_disable = eswifi_mgmt_ap_disable, - .iface_status = eswifi_mgmt_iface_status, + .wifi_iface.get_type = eswifi_get_type, + .wifi_mgmt_api = &eswifi_mgmt_api, }; NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, eswifi_init, NULL, diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index c7e7e9ab725a..6e89275ee6fc 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -272,12 +272,16 @@ static enum offloaded_net_if_types simplelink_get_type(void) return L2_OFFLOADED_NET_IF_TYPE_WIFI; } +static const struct wifi_mgmt_ops simplelink_mgmt = { + .scan = simplelink_mgmt_scan, + .connect = simplelink_mgmt_connect, + .disconnect = simplelink_mgmt_disconnect, +}; + static const struct net_wifi_mgmt_offload simplelink_api = { .wifi_iface.iface_api.init = simplelink_iface_init, - .wifi_iface.get_type = simplelink_get_type, - .scan = simplelink_mgmt_scan, - .connect = simplelink_mgmt_connect, - .disconnect = simplelink_mgmt_disconnect, + .wifi_iface.get_type = simplelink_get_type, + .wifi_mgmt_api = &simplelink_mgmt, }; static int simplelink_init(const struct device *dev) diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index acab7e94d006..264882936283 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -1108,14 +1108,17 @@ static enum offloaded_net_if_types winc1500_get_wifi_type(void) return L2_OFFLOADED_NET_IF_TYPE_WIFI; } +static const struct wifi_mgmt_ops winc1500_mgmt_ops = { + .scan = winc1500_mgmt_scan, + .connect = winc1500_mgmt_connect, + .disconnect = winc1500_mgmt_disconnect, + .ap_enable = winc1500_mgmt_ap_enable, + .ap_disable = winc1500_mgmt_ap_disable, +}; static const struct net_wifi_mgmt_offload winc1500_api = { .wifi_iface.iface_api.init = winc1500_iface_init, - .wifi_iface.get_type = winc1500_get_wifi_type, - .scan = winc1500_mgmt_scan, - .connect = winc1500_mgmt_connect, - .disconnect = winc1500_mgmt_disconnect, - .ap_enable = winc1500_mgmt_ap_enable, - .ap_disable = winc1500_mgmt_ap_disable, + .wifi_iface.get_type = winc1500_get_wifi_type, + .wifi_mgmt_api = &winc1500_mgmt_ops, }; static int winc1500_init(const struct device *dev) diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index b303d01fc1bd..fdb2814408b1 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -314,19 +314,7 @@ typedef void (*scan_result_cb_t)(struct net_if *iface, int status, typedef void (*raw_scan_result_cb_t)(struct net_if *iface, int status, struct wifi_raw_scan_result *entry); #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ -struct net_wifi_mgmt_offload { - /** - * Mandatory to get in first position. - * A network device should indeed provide a pointer on such - * net_if_api structure. So we make current structure pointer - * that can be casted to a net_if_api structure pointer. - */ -#ifdef CONFIG_WIFI_USE_NATIVE_NETWORKING - struct ethernet_api wifi_iface; -#else - struct offloaded_if_api wifi_iface; -#endif - +struct wifi_mgmt_ops { /* cb parameter is the cb that should be called for each * result by the driver. The wifi mgmt part will take care of * raising the necessary event etc... @@ -350,6 +338,21 @@ struct net_wifi_mgmt_offload { int (*reg_domain)(const struct device *dev, struct wifi_reg_domain *reg_domain); }; +struct net_wifi_mgmt_offload { + /** + * Mandatory to get in first position. + * A network device should indeed provide a pointer on such + * net_if_api structure. So we make current structure pointer + * that can be casted to a net_if_api structure pointer. + */ +#ifdef CONFIG_WIFI_USE_NATIVE_NETWORKING + struct ethernet_api wifi_iface; +#else + struct offloaded_if_api wifi_iface; +#endif + const struct wifi_mgmt_ops *const wifi_mgmt_api; +}; + /* Make sure that the network interface API is properly setup inside * Wifi mgmt offload API struct (it is the first one). */ diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index c3bc788132c3..e0444d8477c5 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -12,6 +12,15 @@ LOG_MODULE_REGISTER(net_wifi_mgmt, CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL); #include #include #include +#include +static const struct wifi_mgmt_ops *const get_wifi_api(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct net_wifi_mgmt_offload *off_api = + (struct net_wifi_mgmt_offload *) dev->api; + + return off_api ? off_api->wifi_mgmt_api : NULL; +} static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) @@ -21,8 +30,9 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; - if (off_api == NULL || off_api->connect == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->connect == NULL) { return -ENOTSUP; } @@ -49,7 +59,7 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->connect(dev, params); + return wifi_mgmt_api->connect(dev, params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_CONNECT, wifi_connect); @@ -82,11 +92,10 @@ static int wifi_scan(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; struct wifi_scan_params *params = data; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; - if (off_api == NULL || off_api->scan == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->scan == NULL) { return -ENOTSUP; } @@ -96,24 +105,24 @@ static int wifi_scan(uint32_t mgmt_request, struct net_if *iface, #endif } - return off_api->scan(dev, params, scan_result_cb); + return wifi_mgmt_api->scan(dev, params, scan_result_cb); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_SCAN, wifi_scan); - static int wifi_disconnect(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; - if (off_api == NULL || off_api->disconnect == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->disconnect == NULL) { return -ENOTSUP; } - return off_api->disconnect(dev); + return wifi_mgmt_api->disconnect(dev); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_DISCONNECT, wifi_disconnect); @@ -148,12 +157,13 @@ static int wifi_ap_enable(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; - if (off_api == NULL || off_api->ap_enable == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; } - return off_api->ap_enable(dev, params); + return wifi_mgmt_api->ap_enable(dev, params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_ENABLE, wifi_ap_enable); @@ -164,12 +174,13 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; - if (off_api == NULL || off_api->ap_enable == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; } - return off_api->ap_disable(dev); + return wifi_mgmt_api->ap_disable(dev); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_DISABLE, wifi_ap_disable); @@ -180,9 +191,10 @@ static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct wifi_iface_status *status = data; - if (off_api == NULL || off_api->iface_status == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->iface_status == NULL) { return -ENOTSUP; } @@ -190,7 +202,7 @@ static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->iface_status(dev, status); + return wifi_mgmt_api->iface_status(dev, status); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_IFACE_STATUS, wifi_iface_status); @@ -209,9 +221,10 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct net_stats_wifi *stats = data; - if (off_api == NULL || off_api->get_stats == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_stats == NULL) { return -ENOTSUP; } @@ -219,7 +232,7 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->get_stats(dev, stats); + return wifi_mgmt_api->get_stats(dev, stats); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_WIFI, wifi_iface_stats); #endif /* CONFIG_NET_STATISTICS_WIFI */ @@ -230,10 +243,11 @@ static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct wifi_ps_params *ps_params = data; struct wifi_iface_status info = { 0 }; - if (off_api == NULL || off_api->set_power_save == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_power_save == NULL) { return -ENOTSUP; } @@ -263,7 +277,7 @@ static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface, return -ENOTSUP; } - return off_api->set_power_save(dev, ps_params); + return wifi_mgmt_api->set_power_save(dev, ps_params); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS, wifi_set_power_save); @@ -274,9 +288,10 @@ static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *ifac const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct wifi_ps_config *ps_config = data; - if (off_api == NULL || off_api->get_power_save_config == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_power_save_config == NULL) { return -ENOTSUP; } @@ -284,7 +299,7 @@ static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *ifac return -EINVAL; } - return off_api->get_power_save_config(dev, ps_config); + return wifi_mgmt_api->get_power_save_config(dev, ps_config); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_CONFIG, wifi_get_power_save_config); @@ -295,10 +310,11 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct wifi_twt_params *twt_params = data; struct wifi_iface_status info = { 0 }; - if (off_api == NULL || off_api->set_twt == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_twt == NULL) { twt_params->fail_reason = WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED; return -ENOTSUP; @@ -345,7 +361,7 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, goto fail; } - return off_api->set_twt(dev, twt_params); + return wifi_mgmt_api->set_twt(dev, twt_params); fail: return -ENOEXEC; @@ -366,9 +382,10 @@ static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; + const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; struct wifi_reg_domain *reg_domain = data; - if (off_api == NULL || off_api->reg_domain == NULL) { + if (wifi_mgmt_api == NULL || wifi_mgmt_api->reg_domain == NULL) { return -ENOTSUP; } @@ -376,7 +393,7 @@ static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, return -EINVAL; } - return off_api->reg_domain(dev, reg_domain); + return wifi_mgmt_api->reg_domain(dev, reg_domain); } NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN, wifi_reg_domain); From 38fc560f2172b8b62e5bfc3bdc67f616fae8f34a Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 14 Jun 2023 02:20:54 +0530 Subject: [PATCH 1126/2042] net: wifi: Introduce Wi-Fi network managers This introduces support for Wi-Fi network managers in Zephyr. The motivation is for the Wi-Fi management layer to work with both Network managers and offloaded Wi-Fi drivers. The device driver decides which one to use. network manager : Apps -> Wi-Fi Mgmt -> Network Manager -> Wi-Fi interface offloaded : Apps -> Wi-Fi Mgmt -> Wi-Fi offloaded interface Support for multiple network managers has been added, each device can choose its own network manager and there can be mix and match: wlan0 - Offloaded wlan1 - Network manager 1 wlan2 - Network manager 2 Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi_nm.h | 100 ++++++++++++++++++++++++++++++ subsys/net/l2/wifi/CMakeLists.txt | 7 +++ subsys/net/l2/wifi/Kconfig | 22 +++++++ subsys/net/l2/wifi/wifi_nm.c | 75 ++++++++++++++++++++++ subsys/net/l2/wifi/wifi_nm.ld | 7 +++ 5 files changed, 211 insertions(+) create mode 100644 include/zephyr/net/wifi_nm.h create mode 100644 subsys/net/l2/wifi/wifi_nm.c create mode 100644 subsys/net/l2/wifi/wifi_nm.ld diff --git a/include/zephyr/net/wifi_nm.h b/include/zephyr/net/wifi_nm.h new file mode 100644 index 000000000000..dd97fcdd8b61 --- /dev/null +++ b/include/zephyr/net/wifi_nm.h @@ -0,0 +1,100 @@ +/** @file + * @brief Wi-Fi Network manager API + * + * This file contains the Wi-Fi network manager API. These APIs are used by the + * any network management application to register as a Wi-Fi network manager. + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ + +#include +#include +#include +#include +#include +/** + * @brief Wi-Fi Network manager API + * @defgroup wifi_nm Wi-Fi Network Manager API + * @ingroup networking + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief WiFi Network manager instance + */ +struct wifi_nm_instance { + /** Name of the Network manager instance */ + const char *name; + /** Wi-Fi Management operations */ + const struct wifi_mgmt_ops *ops; + /** List of Managed interfaces */ + struct net_if *mgd_ifaces[CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES]; +}; + +#define WIFI_NM_NAME(name) wifi_nm_##name + +#define DEFINE_WIFI_NM_INSTANCE(_name, _ops) \ + static STRUCT_SECTION_ITERABLE(wifi_nm_instance, WIFI_NM_NAME(_name)) = { \ + .name = STRINGIFY(_name), \ + .ops = _ops, \ + .mgd_ifaces = { NULL }, \ + } + +/** + * @brief Get a Network manager instance for a given name + * + * @param name Name of the Network manager instance + * + */ +struct wifi_nm_instance *wifi_nm_get_instance(const char *name); + +/** + * @brief Get a Network manager instance for a given interface + * + * @param iface Interface + * + */ +struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface); + +/** + * @brief Register a managed interface + * + * @param nm Pointer to Network manager instance + * @param iface Managed interface + * + * @retval 0 If successful. + * @retval -EINVAL If invalid parameters were passed. + * @retval -ENOTSUP If the interface is not a Wi-Fi interface. + * @retval -ENOMEM If the maximum number of managed interfaces has been reached. + */ +int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface); + +/** + * @brief Unregister managed interface + * + * @param nm Pointer to Network manager instance + * @param iface Interface + * @return int 0 for OK; -EINVAL for invalid parameters; -ENOENT if interface is not registered + * with the Network manager. + */ +int wifi_nm_unregister_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* ZEPHYR_INCLUDE_ZEPHYR_NET_WIFI_NM_H_ */ diff --git a/subsys/net/l2/wifi/CMakeLists.txt b/subsys/net/l2/wifi/CMakeLists.txt index 3fb8eebd6150..6935d4e2a45c 100644 --- a/subsys/net/l2/wifi/CMakeLists.txt +++ b/subsys/net/l2/wifi/CMakeLists.txt @@ -8,3 +8,10 @@ zephyr_library_compile_definitions_ifdef( zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_MGMT wifi_mgmt.c) zephyr_library_sources_ifdef(CONFIG_NET_L2_WIFI_SHELL wifi_shell.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM wifi_nm.c) + +# Linker section placement for wifi_nm_instance iterable structure +zephyr_linker_sources_ifdef(CONFIG_WIFI_NM DATA_SECTIONS wifi_nm.ld) +if (CONFIG_WIFI_NM) +zephyr_iterable_section(NAME wifi_nm_instance GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +endif() diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index ade546fac7d0..ea55a499d18c 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -46,3 +46,25 @@ config WIFI_MGMT_FORCED_PASSIVE_SCAN the scan type is always sent as passive. This doesn't guarantee that passive scan will be used, it depends on the underlying chip implementation to support and honour scan type. + +config WIFI_NM + bool "Wi-Fi Network manager support" + help + This option enables using the Wi-Fi Network managers (e.g. wpa_supplicant) to + manage the Wi-Fi network interfaces. + +if WIFI_NM + +config WIFI_NM_MAX_MANAGED_INTERFACES + int "Maximum number of managed interfaces per Wi-Fi network manager" + default 1 + help + This option defines the maximum number of managed interfaces per Wi-Fi + network manager instance that can be used simultaneously. + +module = WIFI_NM +module-dep = NET_LOG +module-str = Log level for Wi-Fi Network manager module +module-help = Enables using the Wi-Fi Network managers to manage the Wi-Fi network interfaces. +source "subsys/net/Kconfig.template.log_config.net" +endif # WIFI_NM diff --git a/subsys/net/l2/wifi/wifi_nm.c b/subsys/net/l2/wifi/wifi_nm.c new file mode 100644 index 000000000000..4f3e2d239a1a --- /dev/null +++ b/subsys/net/l2/wifi/wifi_nm.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(wifi_nm, CONFIG_WIFI_NM_LOG_LEVEL); + +#include +#include + +struct wifi_nm_instance *wifi_nm_get_instance(const char *name) +{ + STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { + if (!strcmp(nm->name, name)) { + return nm; + } + } + + return NULL; +} + +struct wifi_nm_instance *wifi_nm_get_instance_iface(struct net_if *iface) +{ + if (!iface || !net_if_is_wifi(iface)) { + return false; + } + + STRUCT_SECTION_FOREACH(wifi_nm_instance, nm) { + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (nm->mgd_ifaces[i] == iface) { + return nm; + } + } + } + + return NULL; +} + +int wifi_nm_register_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface) +{ + if (!nm || !iface) { + return -EINVAL; + } + + if (!net_if_is_wifi(iface)) { + return -ENOTSUP; + } + + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (!nm->mgd_ifaces[i]) { + nm->mgd_ifaces[i] = iface; + return 0; + } + } + + return -ENOMEM; +} + +int wifi_nm_unregister_mgd_iface(struct wifi_nm_instance *nm, struct net_if *iface) +{ + if (!nm || !iface) { + return -EINVAL; + } + + for (int i = 0; i < CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES; i++) { + if (nm->mgd_ifaces[i] == iface) { + nm->mgd_ifaces[i] = NULL; + return 0; + } + } + + return -ENOENT; +} diff --git a/subsys/net/l2/wifi/wifi_nm.ld b/subsys/net/l2/wifi/wifi_nm.ld new file mode 100644 index 000000000000..73bc53f881a5 --- /dev/null +++ b/subsys/net/l2/wifi/wifi_nm.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +ITERABLE_SECTION_RAM(wifi_nm_instance, 4) From 69a144210e0626678648f369936a32b1e153a0bd Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 14 Jun 2023 20:27:22 +0530 Subject: [PATCH 1127/2042] net: wifi: Add support to handle Wi-Fi NM's in Wi-Fi management Check if a network interface is managed by a network manager before falling back to offload API. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_mgmt.c | 56 ++++++++++++++-------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index e0444d8477c5..59e40304d83f 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -12,13 +12,22 @@ LOG_MODULE_REGISTER(net_wifi_mgmt, CONFIG_NET_L2_WIFI_MGMT_LOG_LEVEL); #include #include #include -#include +#ifdef CONFIG_WIFI_NM +#include +#endif /* CONFIG_WIFI_NM */ + static const struct wifi_mgmt_ops *const get_wifi_api(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct net_wifi_mgmt_offload *off_api = (struct net_wifi_mgmt_offload *) dev->api; +#ifdef CONFIG_WIFI_NM + struct wifi_nm_instance *nm = wifi_nm_get_instance_iface(iface); + if (nm) { + return nm->ops; + } +#endif /* CONFIG_WIFI_NM */ return off_api ? off_api->wifi_mgmt_api : NULL; } @@ -28,9 +37,8 @@ static int wifi_connect(uint32_t mgmt_request, struct net_if *iface, struct wifi_connect_req_params *params = (struct wifi_connect_req_params *)data; const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); if (wifi_mgmt_api == NULL || wifi_mgmt_api->connect == NULL) { return -ENOTSUP; @@ -93,7 +101,7 @@ static int wifi_scan(uint32_t mgmt_request, struct net_if *iface, { const struct device *dev = net_if_get_device(iface); struct wifi_scan_params *params = data; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); if (wifi_mgmt_api == NULL || wifi_mgmt_api->scan == NULL) { return -ENOTSUP; @@ -114,9 +122,7 @@ static int wifi_disconnect(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); if (wifi_mgmt_api == NULL || wifi_mgmt_api->disconnect == NULL) { return -ENOTSUP; @@ -155,9 +161,7 @@ static int wifi_ap_enable(uint32_t mgmt_request, struct net_if *iface, struct wifi_connect_req_params *params = (struct wifi_connect_req_params *)data; const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; @@ -172,9 +176,7 @@ static int wifi_ap_disable(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); if (wifi_mgmt_api == NULL || wifi_mgmt_api->ap_enable == NULL) { return -ENOTSUP; @@ -189,9 +191,7 @@ static int wifi_iface_status(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_iface_status *status = data; if (wifi_mgmt_api == NULL || wifi_mgmt_api->iface_status == NULL) { @@ -219,9 +219,7 @@ static int wifi_iface_stats(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct net_stats_wifi *stats = data; if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_stats == NULL) { @@ -241,9 +239,7 @@ static int wifi_set_power_save(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_ps_params *ps_params = data; struct wifi_iface_status info = { 0 }; @@ -286,9 +282,7 @@ static int wifi_get_power_save_config(uint32_t mgmt_request, struct net_if *ifac void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_ps_config *ps_config = data; if (wifi_mgmt_api == NULL || wifi_mgmt_api->get_power_save_config == NULL) { @@ -308,9 +302,7 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_twt_params *twt_params = data; struct wifi_iface_status info = { 0 }; @@ -321,7 +313,7 @@ static int wifi_set_twt(uint32_t mgmt_request, struct net_if *iface, } if (twt_params->operation == WIFI_TWT_TEARDOWN) { - return off_api->set_twt(dev, twt_params); + return wifi_mgmt_api->set_twt(dev, twt_params); } if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &info, @@ -380,9 +372,7 @@ static int wifi_reg_domain(uint32_t mgmt_request, struct net_if *iface, void *data, size_t len) { const struct device *dev = net_if_get_device(iface); - struct net_wifi_mgmt_offload *off_api = - (struct net_wifi_mgmt_offload *) dev->api; - const struct wifi_mgmt_ops *const wifi_mgmt_api = off_api ? off_api->wifi_mgmt_api : NULL; + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); struct wifi_reg_domain *reg_domain = data; if (wifi_mgmt_api == NULL || wifi_mgmt_api->reg_domain == NULL) { From 980ad00f104a9ef539370011cd12c6ad691e7b2a Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 16 Jun 2023 00:47:54 +0530 Subject: [PATCH 1128/2042] tests: wifi: Add Wi-Fi test suite This adds Wi-Fi tests for both offloaded and newly introduced network manager managed interface. Only scan op is used to verify the network manager code. Signed-off-by: Chaitanya Tata --- tests/net/wifi/wifi_nm/CMakeLists.txt | 8 ++ tests/net/wifi/wifi_nm/Kconfig | 14 ++ tests/net/wifi/wifi_nm/prj.conf | 19 +++ tests/net/wifi/wifi_nm/src/main.c | 186 ++++++++++++++++++++++++++ tests/net/wifi/wifi_nm/testcase.yaml | 6 + 5 files changed, 233 insertions(+) create mode 100644 tests/net/wifi/wifi_nm/CMakeLists.txt create mode 100644 tests/net/wifi/wifi_nm/Kconfig create mode 100644 tests/net/wifi/wifi_nm/prj.conf create mode 100644 tests/net/wifi/wifi_nm/src/main.c create mode 100644 tests/net/wifi/wifi_nm/testcase.yaml diff --git a/tests/net/wifi/wifi_nm/CMakeLists.txt b/tests/net/wifi/wifi_nm/CMakeLists.txt new file mode 100644 index 000000000000..4a2a6013031f --- /dev/null +++ b/tests/net/wifi/wifi_nm/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(wifi_nm) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/net/wifi/wifi_nm/Kconfig b/tests/net/wifi/wifi_nm/Kconfig new file mode 100644 index 000000000000..57e1217d10a0 --- /dev/null +++ b/tests/net/wifi/wifi_nm/Kconfig @@ -0,0 +1,14 @@ +# Configuration opions for Wi-Fi test + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + + +source "Kconfig.zephyr" + +# The purpose of this Kconfig is to select the hidden symbol +config WIFI_TEST_ENABLE + bool "Enable Wi-Fi test" + default y + select WIFI + select WIFI_USE_NATIVE_NETWORKING diff --git a/tests/net/wifi/wifi_nm/prj.conf b/tests/net/wifi/wifi_nm/prj.conf new file mode 100644 index 000000000000..abeb08fca4fa --- /dev/null +++ b/tests/net/wifi/wifi_nm/prj.conf @@ -0,0 +1,19 @@ +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_WIFI_NM=y +CONFIG_NET_LOG=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y + +# Disable internal ethernet drivers as the test is self contained +# and does not need the on board driver to function. +CONFIG_ETH_DRIVER=n diff --git a/tests/net/wifi/wifi_nm/src/main.c b/tests/net/wifi/wifi_nm/src/main.c new file mode 100644 index 000000000000..0ca9e6335531 --- /dev/null +++ b/tests/net/wifi/wifi_nm/src/main.c @@ -0,0 +1,186 @@ +/* main.c - Application main entry point */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define NET_LOG_LEVEL CONFIG_NET_L2_ETHERNET_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#if NET_LOG_LEVEL >= LOG_LEVEL_DBG +#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__) +#else +#define DBG(fmt, ...) +#endif + +struct wifi_drv_context { + struct net_if *iface; + uint8_t mac_addr[6]; + enum ethernet_if_types eth_if_type; +}; + +static struct wifi_drv_context wifi_context; + +bool wifi_nm_op_called; +bool wifi_offload_op_called; + +static void wifi_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct wifi_drv_context *context = dev->data; + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + + net_if_set_link_addr(iface, context->mac_addr, + sizeof(context->mac_addr), + NET_LINK_ETHERNET); + + eth_ctx->eth_if_type = L2_ETH_IF_TYPE_WIFI; + + ethernet_init(iface); +} + +static int wifi_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + ARG_UNUSED(dev); + ARG_UNUSED(params); + ARG_UNUSED(cb); + + wifi_offload_op_called = true; + + return 0; +} + +static struct wifi_mgmt_ops wifi_mgmt_api = { + .scan = wifi_scan, +}; + +static struct net_wifi_mgmt_offload api_funcs = { + .wifi_iface.iface_api.init = wifi_iface_init, + .wifi_mgmt_api = &wifi_mgmt_api, +}; + +static void generate_mac(uint8_t *mac_addr) +{ + /* 00-00-5E-00-53-xx Documentation RFC 7042 */ + mac_addr[0] = 0x00; + mac_addr[1] = 0x00; + mac_addr[2] = 0x5E; + mac_addr[3] = 0x00; + mac_addr[4] = 0x53; + mac_addr[5] = sys_rand32_get(); +} + +static int wifi_init(const struct device *dev) +{ + struct wifi_drv_context *context = dev->data; + + context->eth_if_type = L2_ETH_IF_TYPE_WIFI; + + generate_mac(context->mac_addr); + + return 0; +} + +ETH_NET_DEVICE_INIT(wlan0, "wifi_test", + wifi_init, NULL, + &wifi_context, NULL, CONFIG_ETH_INIT_PRIORITY, + &api_funcs, NET_ETH_MTU); + +static int wifi_nm_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + ARG_UNUSED(dev); + ARG_UNUSED(params); + ARG_UNUSED(cb); + + wifi_nm_op_called = true; + + return 0; +} + +static struct wifi_mgmt_ops wifi_nm_test_ops = { + .scan = wifi_nm_scan, +}; + +DEFINE_WIFI_NM_INSTANCE(test, &wifi_nm_test_ops); + +static int request_scan(void) +{ + struct net_if *iface = net_if_get_first_wifi(); + + if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, NULL, 0)) { + printk("Scan request failed\n"); + + return -ENOEXEC; + } + + return 0; +} + +ZTEST(net_wifi, test_wifi_offload) +{ + + int ret; +#ifdef CONFIG_WIFI_NM + struct wifi_nm_instance *nm = wifi_nm_get_instance("test"); + + if (wifi_nm_get_instance_iface(net_if_get_first_wifi())) { + ret = wifi_nm_unregister_mgd_iface(nm, net_if_get_first_wifi()); + zassert_equal(ret, 0, "Failed to unregister managed interface"); + } +#endif /* CONFIG_WIFI_NM */ + + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_offload_op_called, "Scan callback not called"); +} + +ZTEST(net_wifi, test_wifi_nm_managed) +{ + + int ret; + struct wifi_nm_instance *nm = wifi_nm_get_instance("test"); + + zassert_equal(nm->ops, &wifi_nm_test_ops, + "Invalid wifi nm ops"); + + /* Offload: in presence of registered NM but with no managed + * interfaces. + */ + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_offload_op_called, "Scan callback not called"); + + ret = wifi_nm_register_mgd_iface(nm, net_if_get_first_wifi()); + zassert_equal(ret, 0, "Failed to register managed interface"); + + zassert_equal(nm->ops, &wifi_nm_test_ops, + "Invalid wifi nm ops"); + + ret = request_scan(); + zassert_equal(ret, 0, "Scan request failed"); + zassert_true(wifi_nm_op_called, "Scan callback not called"); +} + + +ZTEST_SUITE(net_wifi, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/net/wifi/wifi_nm/testcase.yaml b/tests/net/wifi/wifi_nm/testcase.yaml new file mode 100644 index 000000000000..227f39feaac1 --- /dev/null +++ b/tests/net/wifi/wifi_nm/testcase.yaml @@ -0,0 +1,6 @@ +common: + depends_on: netif +tests: + net.wifi: + min_ram: 32 + tags: wifi From ea0084bfb9a18ede058370bbfec507755f84d8af Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 16 Jun 2023 01:00:02 +0530 Subject: [PATCH 1129/2042] doc: net: Add an entry for Wi-Fi Management This was missing all along. Signed-off-by: Chaitanya Tata --- doc/connectivity/networking/overview.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index 5c885e9d287a..32d08015abc2 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -99,12 +99,16 @@ can be disabled if not needed. listen management events generated by core stack when for example IP address is added to the device, or network interface is coming up etc. +* **Wi-Fi Management API.** Applications can use Wi-Fi management API to + manage the interface, in example to connect to Wi-Fi network and to scan + available Wi-Fi networks. + * **Multiple Network Technologies.** The Zephyr OS can be configured to support multiple network technologies at the same time simply by enabling - them in Kconfig: for example, Ethernet and 802.15.4 support. Note that no - automatic IP routing functionality is provided between these technologies. - Applications can send data according to their needs to desired network - interface. + them in Kconfig: for example, Ethernet, Wi-Fi and 802.15.4 support. Note + that no automatic IP routing functionality is provided between these + technologies. Applications can send data according to their needs to desired + network interface. * **Minimal Copy Network Buffer Management.** It is possible to have minimal copy network data path. This means that the system tries to avoid copying From 521e1295283e3467f3b8e83e159e6b739d543839 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 16 Jun 2023 01:03:28 +0530 Subject: [PATCH 1130/2042] doc: net: Add an entry about Wi-Fi Network managers Add the entry to convey support for Wi-Fi Network Managers in Zephyr. Signed-off-by: Chaitanya Tata --- doc/connectivity/networking/overview.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/connectivity/networking/overview.rst b/doc/connectivity/networking/overview.rst index 32d08015abc2..c339632fdf18 100644 --- a/doc/connectivity/networking/overview.rst +++ b/doc/connectivity/networking/overview.rst @@ -103,6 +103,10 @@ can be disabled if not needed. manage the interface, in example to connect to Wi-Fi network and to scan available Wi-Fi networks. +* **Wi-Fi Network Manager API.** Wi-Fi Network Managers can now register + themselves to the Wi-Fi stack. The Network Managers can then implement + the Wi-Fi Management API and manage the Wi-Fi interface. + * **Multiple Network Technologies.** The Zephyr OS can be configured to support multiple network technologies at the same time simply by enabling them in Kconfig: for example, Ethernet, Wi-Fi and 802.15.4 support. Note From 6fc3903bbe44c6a742480f68a449a943ccd99985 Mon Sep 17 00:00:00 2001 From: Jaxson Han Date: Thu, 19 Jan 2023 17:21:14 +0800 Subject: [PATCH 1131/2042] arch: arm64: mpu: Fix some minor CHECKIF issues There are two CHECKIFs whose check condition is wrong. Signed-off-by: Jaxson Han --- arch/arm64/core/cortex_r/arm_mpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/core/cortex_r/arm_mpu.c b/arch/arm64/core/cortex_r/arm_mpu.c index d801ce3b5e4f..f8490216dbe3 100644 --- a/arch/arm64/core/cortex_r/arm_mpu.c +++ b/arch/arm64/core/cortex_r/arm_mpu.c @@ -448,8 +448,9 @@ static int configure_dynamic_mpu_regions(struct k_thread *thread) partition->start, partition->size, &partition->attr); - CHECKIF(ret2 != 0) { + CHECKIF(ret2 < 0) { ret = ret2; + goto out; } region_num = (uint8_t)ret2; @@ -465,8 +466,9 @@ static int configure_dynamic_mpu_regions(struct k_thread *thread) thread->stack_info.start, thread->stack_info.size, &K_MEM_PARTITION_P_RW_U_RW); - CHECKIF(ret2 != 0) { + CHECKIF(ret2 < 0) { ret = ret2; + goto out; } region_num = (uint8_t)ret2; From 5d643ecd24960987e04cc9c0f0f069928277eefb Mon Sep 17 00:00:00 2001 From: Jaxson Han Date: Fri, 20 Jan 2023 09:50:11 +0800 Subject: [PATCH 1132/2042] arch: arm64: Fix z_arm64_fatal_error declaration error The z_arm64_fatal_error should be extern void z_arm64_fatal_error(unsigned int reason, z_arch_esf_t *esf); Signed-off-by: Jaxson Han --- arch/arm64/include/kernel_arch_func.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/kernel_arch_func.h b/arch/arm64/include/kernel_arch_func.h index 014c166db005..3b028b10b377 100644 --- a/arch/arm64/include/kernel_arch_func.h +++ b/arch/arm64/include/kernel_arch_func.h @@ -43,7 +43,7 @@ static inline void arch_switch(void *switch_to, void **switched_from) z_arm64_context_switch(new, old); } -extern void z_arm64_fatal_error(z_arch_esf_t *esf, unsigned int reason); +extern void z_arm64_fatal_error(unsigned int reason, z_arch_esf_t *esf); extern void z_arm64_set_ttbr0(uint64_t ttbr0); extern void z_arm64_mem_cfg_ipi(void); From d7e5c012a9013e95289c4f25ca943980644acbd4 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 7 Jul 2023 10:59:33 +0200 Subject: [PATCH 1133/2042] west.yml: update west.yml to use stm32wba hal Use latest version of stm32_hal to be able to access STM32WBA HAL Signed-off-by: Guillaume Gautier --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index fa0ba27c9f88..e1df29a24c8c 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: c865374fc83d93416c0f380e6310368ff55d6ce2 + revision: 65b641345a5bfccd93de1fc21103d69c4a9ff1d6 path: modules/hal/stm32 groups: - hal From 3bd3f8d1c6199aeb9c441244fc0a389eb928e6cb Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 10 Jun 2022 09:35:59 +0200 Subject: [PATCH 1134/2042] soc: arm: st_stm32: stm32wba: Add soc config for STM32WBA Add soc config for STM32WBA SoC series Signed-off-by: Guillaume Gautier --- soc/arm/st_stm32/stm32wba/CMakeLists.txt | 6 +++ .../stm32wba/Kconfig.defconfig.series | 13 +++++ .../stm32wba/Kconfig.defconfig.stm32wba52xx | 14 ++++++ soc/arm/st_stm32/stm32wba/Kconfig.series | 19 +++++++ soc/arm/st_stm32/stm32wba/Kconfig.soc | 13 +++++ soc/arm/st_stm32/stm32wba/linker.ld | 9 ++++ soc/arm/st_stm32/stm32wba/soc.c | 50 +++++++++++++++++++ soc/arm/st_stm32/stm32wba/soc.h | 22 ++++++++ 8 files changed, 146 insertions(+) create mode 100644 soc/arm/st_stm32/stm32wba/CMakeLists.txt create mode 100644 soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series create mode 100644 soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba52xx create mode 100644 soc/arm/st_stm32/stm32wba/Kconfig.series create mode 100644 soc/arm/st_stm32/stm32wba/Kconfig.soc create mode 100644 soc/arm/st_stm32/stm32wba/linker.ld create mode 100644 soc/arm/st_stm32/stm32wba/soc.c create mode 100644 soc/arm/st_stm32/stm32wba/soc.h diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt new file mode 100644 index 000000000000..ac3ba70ace6e --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(${ZEPHYR_BASE}/drivers) +zephyr_sources( + soc.c + ) diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series new file mode 100644 index 000000000000..e3dfeab20189 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -0,0 +1,13 @@ +# ST Microelectronics STM32WBA MCU line + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_STM32WBAX + +source "soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba*" + +config SOC_SERIES + default "stm32wba" + +endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba52xx b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba52xx new file mode 100644 index 000000000000..b9d54cdfc727 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba52xx @@ -0,0 +1,14 @@ +# ST Microelectronics STM32WBA52XX MCU + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32WBA52XX + +config SOC + default "stm32wba52xx" + +config NUM_IRQS + default 70 + +endif # SOC_STM32WBA52XX diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.series new file mode 100644 index 000000000000..7bb4cc44f184 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.series @@ -0,0 +1,19 @@ +# ST Microelectronics STM32WBA MCU series + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_STM32WBAX + bool "STM32WBAx Series MCU" + select ARM + select CPU_CORTEX_M33 + select SOC_FAMILY_STM32 + select ARM_TRUSTZONE_M + select CPU_HAS_ARM_SAU + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select ARMV8_M_DSP + select CPU_CORTEX_M_HAS_DWT + select HAS_STM32CUBE + help + Enable support for STM32WBA MCU series diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.soc b/soc/arm/st_stm32/stm32wba/Kconfig.soc new file mode 100644 index 000000000000..6e8586d8f3d1 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.soc @@ -0,0 +1,13 @@ +# ST Microelectronics STM32WBA MCU line + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "STM32WBAx MCU Selection" +depends on SOC_SERIES_STM32WBAX + +config SOC_STM32WBA52XX + bool "STM32WBA52XX" + +endchoice diff --git a/soc/arm/st_stm32/stm32wba/linker.ld b/soc/arm/st_stm32/stm32wba/linker.ld new file mode 100644 index 000000000000..8bd989bc732f --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/linker.ld @@ -0,0 +1,9 @@ +/* linker.ld - Linker command/script file */ + +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/st_stm32/stm32wba/soc.c b/soc/arm/st_stm32/stm32wba/soc.c new file mode 100644 index 000000000000..c5eb75a3454b --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/soc.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for STM32WBA processor + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(soc); + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + * So the init priority has to be 0 (zero). + * + * @return 0 + */ +static int stm32wba_init(void) +{ + /* Enable instruction cache in 1-way (direct mapped cache) */ + LL_ICACHE_SetMode(LL_ICACHE_1WAY); + LL_ICACHE_Enable(); + + /* Update CMSIS SystemCoreClock variable (HCLK) */ + /* At reset, system core clock is set to 16 MHz from HSI */ + SystemCoreClock = 16000000; + + /* Enable PWR */ + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); + + return 0; +} + +SYS_INIT(stm32wba_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/st_stm32/stm32wba/soc.h b/soc/arm/st_stm32/stm32wba/soc.h new file mode 100644 index 000000000000..ef41f7adf8a1 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/soc.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the STM32WBA series processors. + * + */ + + +#ifndef _STM32WBA_SOC_H_ +#define _STM32WBA_SOC_H_ + +#ifndef _ASMLANGUAGE + +#include + +#endif /* !_ASMLANGUAGE */ + +#endif /* _STM32WBA_SOC_H_ */ From 14b4d3ddb248cc61d88c4439c9cb73b1aa4d9113 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 11:29:13 +0200 Subject: [PATCH 1135/2042] dts: bindings: clocks: Add st,stm32wba clock bindings Add bindings for wba specific clocks, osc and controllers: - hse - pll - rcc Signed-off-by: Guillaume Gautier --- dts/bindings/clock/st,stm32wba-hse-clock.yaml | 15 ++ dts/bindings/clock/st,stm32wba-pll-clock.yaml | 65 ++++++++ dts/bindings/clock/st,stm32wba-rcc.yaml | 139 ++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 dts/bindings/clock/st,stm32wba-hse-clock.yaml create mode 100644 dts/bindings/clock/st,stm32wba-pll-clock.yaml create mode 100644 dts/bindings/clock/st,stm32wba-rcc.yaml diff --git a/dts/bindings/clock/st,stm32wba-hse-clock.yaml b/dts/bindings/clock/st,stm32wba-hse-clock.yaml new file mode 100644 index 000000000000..620412f48a72 --- /dev/null +++ b/dts/bindings/clock/st,stm32wba-hse-clock.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STM32WBA HSE Clock + +compatible: "st,stm32wba-hse-clock" + +include: [fixed-clock.yaml] + +properties: + hse-div2: + type: boolean + description: | + When set HSE output clock is divided by 2. + Otherwise, no prescaler is used. diff --git a/dts/bindings/clock/st,stm32wba-pll-clock.yaml b/dts/bindings/clock/st,stm32wba-pll-clock.yaml new file mode 100644 index 000000000000..03a755f0ee3f --- /dev/null +++ b/dts/bindings/clock/st,stm32wba-pll-clock.yaml @@ -0,0 +1,65 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + PLL node binding for STM32WBA devices + + It can be used to describe PLL1 + + This PLL could take one of clk_hse or clk_hsi as input clock, with + an input frequency from 4 to 16 MHz. PLLM factor is used to set the input + clock in this acceptable range. + + PLL1 can have up to 3 output clocks and for each output clock, the + frequency can be computed with the following formula: + + f(PLL_P) = f(VCO clock) / PLLP + f(PLL_Q) = f(VCO clock) / PLLQ + f(PLL_R) = f(VCO clock) / PLLR + + with f(VCO clock) = f(PLL clock input) × (PLLN / PLLM) + + Note: VCOx frequency range is 128 to 544 MHz. To reduce the power consumption, + it is recommended to configure the VCO to the lowest frequency. + + The PLL output frequency must not exceed 100 MHz. + +compatible: "st,stm32wba-pll-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + + "#clock-cells": + const: 0 + + clocks: + required: true + + div-m: + type: int + required: true + description: | + Prescaler for PLLx + input clock + Valid range: 1 - 8 + + mul-n: + type: int + required: true + description: | + PLLx multiplication factor for VCO + Valid range: 4 - 512 + + div-q: + type: int + description: | + PLLx DIVQ division factor + Valid range: 1 - 128 + + div-r: + type: int + required: true + description: | + PLLx DIVR division factor + Valid range: 1 - 128 diff --git a/dts/bindings/clock/st,stm32wba-rcc.yaml b/dts/bindings/clock/st,stm32wba-rcc.yaml new file mode 100644 index 000000000000..d85ba13ad207 --- /dev/null +++ b/dts/bindings/clock/st,stm32wba-rcc.yaml @@ -0,0 +1,139 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32 Reset and Clock controller node. + This node is in charge of system clock ('SYSCLK') source selection and controlling + clocks for AHB (Advanced High Performance) and APB (Advanced Peripheral) bus domains. + + Configuring STM32 Reset and Clock controller node: + + System clock source should be selected amongst the clock nodes available in "clocks" + node (typically 'clk_hse, clk_hsi', 'pll'). + Core clock frequency should also be defined, using "clock-frequency" property. + Note: + Core clock frequency = SYSCLK / AHB prescaler + Last, peripheral bus clocks (typically PCLK1, PCLK2, PCLK7) should be configured using + matching prescaler properties. + Here is an example of correctly configured rcc node: + &rcc { + clocks = <&pll>; /* Select pll as SYSCLK source */ + ahb-prescaler = <2>; + clock-frequency = ; /* = SYSCLK / AHB prescaler */ + apb1-presacler = <1>; + apb2-presacler = <1>; + apb7-presacler = <7>; + } + + Specifying a gated clock: + + To specify a gated clock, a peripheral should define a "clocks" property encoded + in the following way: + ... { + ... + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000020>; + ... + } + After the phandle referring to rcc node, the first index specifies the registers of + the bus controlling the peripheral and the second index specifies the bit used to + control the peripheral clock in that bus register. + + Specifying an alternate clock source: + + Specifying an alternate source clock could be done by adding a clock specifier to the + clock property: + ... { + ... + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000020>, + <&rcc STM32_SRC_HSI I2C1_SEL(2)>; + ... + } + 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 + accordance with clock_control API specifications. + +compatible: "st,stm32wba-rcc" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 2 + + clock-frequency: + required: true + type: int + description: | + default frequency in Hz for clock output (HCLK1) + + ahb-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + description: | + Common AHB1, AHB2, AHB4 prescaler. Defines actual core clock frequency + (HCLK) based on system frequency input. AKA HPRE. + The HCLK clocks CPU, AHB1, AHB2, memories and DMA. + + ahb5-prescaler: + type: int + enum: + - 1 + - 2 + - 3 + - 4 + - 6 + description: | + AHB5 prescaler. Defines actual core clock frequency (HCLK5) based on + system frequency input. It is used to limit HCLK5 below 32MHz. + Only required when SysClock source is PLL1. + AKA HPRE5. + + apb1-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + + apb2-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + + apb7-prescaler: + type: int + required: true + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + + ahb5-div: + type: boolean + description: | + AHB5 divider. Applies only when SysClock source is HSI16 or HSE32. + When enabled, AHB5 clock is SysClock / 2. + When disabled, SysClock is not divided. + +clock-cells: + - bus + - bits From daef7c9d1ba33a9e00007c9cc502b7565003dc4a Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 14:44:38 +0200 Subject: [PATCH 1136/2042] drivers: clock_control: stm32: Add stm32wba clock control driver Add clock control driver on STM32WBA. Signed-off-by: Guillaume Gautier --- drivers/clock_control/CMakeLists.txt | 2 + drivers/clock_control/clock_stm32_ll_wba.c | 568 ++++++++++++++++++ .../clock_control/stm32_clock_control.h | 28 +- .../zephyr/dt-bindings/clock/stm32wba_clock.h | 94 +++ 4 files changed, 685 insertions(+), 7 deletions(-) create mode 100644 drivers/clock_control/clock_stm32_ll_wba.c create mode 100644 include/zephyr/dt-bindings/clock/stm32wba_clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index c2542965ead1..95b0180310e7 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -38,6 +38,8 @@ elseif(CONFIG_SOC_SERIES_STM32H5X) zephyr_library_sources(clock_stm32_ll_h5.c) elseif(CONFIG_SOC_SERIES_STM32U5X) zephyr_library_sources(clock_stm32_ll_u5.c) +elseif(CONFIG_SOC_SERIES_STM32WBAX) + zephyr_library_sources(clock_stm32_ll_wba.c) else() zephyr_library_sources(clock_stm32_ll_common.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_STM32C0X clock_stm32c0.c) diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c new file mode 100644 index 000000000000..f9b4945e411d --- /dev/null +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stm32_hsem.h" + +/* Macros to fill up prescaler values */ +#define fn_ahb_prescaler(v) LL_RCC_SYSCLK_DIV_ ## v +#define ahb_prescaler(v) fn_ahb_prescaler(v) + +#define fn_ahb5_prescaler(v) LL_RCC_AHB5_DIV_ ## v +#define ahb5_prescaler(v) fn_ahb5_prescaler(v) + +#define fn_apb1_prescaler(v) LL_RCC_APB1_DIV_ ## v +#define apb1_prescaler(v) fn_apb1_prescaler(v) + +#define fn_apb2_prescaler(v) LL_RCC_APB2_DIV_ ## v +#define apb2_prescaler(v) fn_apb2_prescaler(v) + +#define fn_apb7_prescaler(v) LL_RCC_APB7_DIV_ ## v +#define apb7_prescaler(v) fn_apb7_prescaler(v) + +#define RCC_CALC_FLASH_FREQ __LL_RCC_CALC_HCLK_FREQ +#define GET_CURRENT_FLASH_PRESCALER LL_RCC_GetAHBPrescaler + +static uint32_t get_bus_clock(uint32_t clock, uint32_t prescaler) +{ + return clock / prescaler; +} + +/** @brief Verifies clock is part of active clock configuration */ +__unused +static int enabled_clock(uint32_t src_clk) +{ + if ((src_clk == STM32_SRC_SYSCLK) || + ((src_clk == STM32_SRC_HSE) && IS_ENABLED(STM32_HSE_ENABLED)) || + ((src_clk == STM32_SRC_HSI16) && IS_ENABLED(STM32_HSI_ENABLED)) || + ((src_clk == STM32_SRC_LSE) && IS_ENABLED(STM32_LSE_ENABLED)) || + ((src_clk == STM32_SRC_LSI) && IS_ENABLED(STM32_LSI_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_P) && IS_ENABLED(STM32_PLL_P_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_Q) && IS_ENABLED(STM32_PLL_Q_ENABLED)) || + ((src_clk == STM32_SRC_PLL1_R) && IS_ENABLED(STM32_PLL_R_ENABLED))) { + return 0; + } + + return -ENOTSUP; +} + +static inline int stm32_clock_control_on(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) == 0) { + /* Attemp to toggle a wrong periph clock bit */ + return -ENOTSUP; + } + + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, + pclken->enr); + return 0; +} + +static inline int stm32_clock_control_off(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) == 0) { + /* Attemp to toggle a wrong periph clock bit */ + return -ENOTSUP; + } + + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus, + pclken->enr); + + return 0; +} + +static inline int stm32_clock_control_configure(const struct device *dev, + clock_control_subsys_t sub_system, + void *data) +{ +#if defined(STM32_SRC_CLOCK_MIN) + /* At least one alt src clock available */ + struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); + int err; + + ARG_UNUSED(dev); + ARG_UNUSED(data); + + err = enabled_clock(pclken->bus); + if (err < 0) { + /* Attempt to configure a src clock not available or not valid */ + return err; + } + + sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), + STM32_CLOCK_MASK_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_CLOCK_REG_GET(pclken->enr), + STM32_CLOCK_VAL_GET(pclken->enr) << STM32_CLOCK_SHIFT_GET(pclken->enr)); + + return 0; +#else + /* No src clock available: Not supported */ + return -ENOTSUP; +#endif +} + +__unused +static uint32_t get_pllsrc_frequency(void) +{ + + if (IS_ENABLED(STM32_PLL_SRC_HSI)) { + return STM32_HSI_FREQ; + } else if (IS_ENABLED(STM32_PLL_SRC_HSE)) { + return STM32_HSE_FREQ; + } + + __ASSERT(0, "No PLL Source configured"); + return 0; +} + +__unused +static uint32_t get_pllsrc(void) +{ + + if (IS_ENABLED(STM32_PLL_SRC_HSI)) { + return LL_RCC_PLL1SOURCE_HSI; + } else if (IS_ENABLED(STM32_PLL_SRC_HSE)) { + return LL_RCC_PLL1SOURCE_HSE; + } + + __ASSERT(0, "No PLL Source configured"); + return 0; +} + +static int stm32_clock_control_get_subsys_rate(const struct device *dev, + clock_control_subsys_t sub_system, + uint32_t *rate) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system); + /* + * Get AHB Clock (= SystemCoreClock = SYSCLK/prescaler) + * SystemCoreClock is preferred to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC + * since it will be updated after clock configuration and hence + * more likely to contain actual clock speed + */ + uint32_t ahb_clock = SystemCoreClock; + uint32_t apb1_clock = get_bus_clock(ahb_clock, STM32_APB1_PRESCALER); + uint32_t apb2_clock = get_bus_clock(ahb_clock, STM32_APB2_PRESCALER); + uint32_t apb7_clock = get_bus_clock(ahb_clock, STM32_APB7_PRESCALER); + uint32_t ahb5_clock; + + ARG_UNUSED(dev); + + if (IS_ENABLED(STM32_SYSCLK_SRC_PLL)) { + /* PLL is the SYSCLK source, use 'ahb5-prescaler' */ + ahb5_clock = get_bus_clock(ahb_clock * STM32_AHB_PRESCALER, + STM32_AHB5_PRESCALER); + } else { + /* PLL is not the SYSCLK source, use 'ahb5-div'(if set) */ + if (IS_ENABLED(STM32_AHB5_DIV)) { + ahb5_clock = ahb_clock * STM32_AHB_PRESCALER / 2; + } else { + ahb5_clock = ahb_clock * STM32_AHB_PRESCALER; + } + + } + + __ASSERT(ahb5_clock <= MHZ(32), "AHB5 clock frequency exceeds 32 MHz"); + + switch (pclken->bus) { + case STM32_CLOCK_BUS_AHB1: + case STM32_CLOCK_BUS_AHB2: + case STM32_CLOCK_BUS_AHB4: + *rate = ahb_clock; + break; + case STM32_CLOCK_BUS_AHB5: + *rate = ahb5_clock; + break; + case STM32_CLOCK_BUS_APB1: + case STM32_CLOCK_BUS_APB1_2: + *rate = apb1_clock; + break; + case STM32_CLOCK_BUS_APB2: + *rate = apb2_clock; + break; + case STM32_CLOCK_BUS_APB7: + *rate = apb7_clock; + break; + case STM32_SRC_SYSCLK: + *rate = SystemCoreClock * STM32_CORE_PRESCALER; + break; +#if defined(STM32_PLL_ENABLED) + case STM32_SRC_PLL1_P: + *rate = __LL_RCC_CALC_PLL1PCLK_FREQ(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_P_DIVISOR); + break; + case STM32_SRC_PLL1_Q: + *rate = __LL_RCC_CALC_PLL1QCLK_FREQ(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_Q_DIVISOR); + break; + case STM32_SRC_PLL1_R: + *rate = __LL_RCC_CALC_PLL1RCLK_FREQ(get_pllsrc_frequency(), + STM32_PLL_M_DIVISOR, + STM32_PLL_N_MULTIPLIER, + STM32_PLL_R_DIVISOR); + break; +#endif /* STM32_PLL_ENABLED */ +#if defined(STM32_LSE_ENABLED) + case STM32_SRC_LSE: + *rate = STM32_LSE_FREQ; + break; +#endif +#if defined(STM32_LSI_ENABLED) + case STM32_SRC_LSI: + *rate = STM32_LSI_FREQ; + break; +#endif +#if defined(STM32_HSI_ENABLED) + case STM32_SRC_HSI16: + *rate = STM32_HSI_FREQ; + break; +#endif +#if defined(STM32_HSE_ENABLED) + case STM32_SRC_HSE: + if (IS_ENABLED(STM32_HSE_DIV2)) { + *rate = STM32_HSE_FREQ / 2; + } else { + *rate = STM32_HSE_FREQ; + } + + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +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, + .configure = stm32_clock_control_configure, +}; + +__unused +static int get_vco_input_range(uint32_t m_div, uint32_t *range) +{ + uint32_t vco_freq; + + vco_freq = get_pllsrc_frequency() / m_div; + + 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; + } else { + return -ERANGE; + } + + return 0; +} + +static void set_regu_voltage(uint32_t hclk_freq) +{ + if (hclk_freq < MHZ(16)) { + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE2); + } else { + LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1); + } + while (LL_PWR_IsActiveFlag_VOS() == 0) { + } +} + +/* + * Unconditionally switch the system clock source to HSI. + */ +__unused +static void stm32_clock_switch_to_hsi(void) +{ + /* Enable HSI if not enabled */ + if (LL_RCC_HSI_IsReady() != 1) { + /* Enable HSI */ + LL_RCC_HSI_Enable(); + while (LL_RCC_HSI_IsReady() != 1) { + /* Wait for HSI ready */ + } + } + + /* Set HSI as SYSCLCK source */ + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) { + } +} + +__unused +static int set_up_plls(void) +{ +#if defined(STM32_PLL_ENABLED) + int r; + uint32_t vco_input_range; + + /* + * Case of chain-loaded applications: + * Switch to HSI and disable the PLL before configuration. + * (Switching to HSI makes sure we have a SYSCLK source in + * case we're currently running from the PLL we're about to + * turn off and reconfigure.) + * + */ + if (LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R) { + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + stm32_clock_switch_to_hsi(); + } + + LL_RCC_PLL1_Disable(); + + /* Configure PLL source */ + /* Can be HSE, HSI */ + if (IS_ENABLED(STM32_PLL_SRC_HSE)) { + /* Main PLL configuration and activation */ + LL_RCC_PLL1_SetMainSource(LL_RCC_PLL1SOURCE_HSE); + } else if (IS_ENABLED(STM32_PLL_SRC_HSI)) { + /* Main PLL configuration and activation */ + LL_RCC_PLL1_SetMainSource(LL_RCC_PLL1SOURCE_HSI); + } else { + return -ENOTSUP; + } + + r = get_vco_input_range(STM32_PLL_M_DIVISOR, &vco_input_range); + if (r < 0) { + return r; + } + + LL_RCC_PLL1_SetDivider(STM32_PLL_M_DIVISOR); + + LL_RCC_PLL1_SetVCOInputRange(vco_input_range); + + LL_RCC_PLL1_SetN(STM32_PLL_N_MULTIPLIER); + + LL_RCC_PLL1FRACN_Disable(); + + if (IS_ENABLED(STM32_PLL_P_ENABLED)) { + LL_RCC_PLL1_SetP(STM32_PLL_P_DIVISOR); + LL_RCC_PLL1_EnableDomain_PLL1P(); + } + + if (IS_ENABLED(STM32_PLL_Q_ENABLED)) { + LL_RCC_PLL1_SetQ(STM32_PLL_Q_DIVISOR); + LL_RCC_PLL1_EnableDomain_PLL1Q(); + } + + if (IS_ENABLED(STM32_PLL_R_ENABLED)) { + LL_RCC_PLL1_SetR(STM32_PLL_R_DIVISOR); + + LL_RCC_PLL1_EnableDomain_PLL1R(); + } + + /* Enable PLL */ + LL_RCC_PLL1_Enable(); + while (LL_RCC_PLL1_IsReady() != 1U) { + /* Wait for PLL ready */ + } +#else + /* Init PLL source to None */ + LL_RCC_PLL1_SetMainSource(LL_RCC_PLL1SOURCE_NONE); +#endif /* STM32_PLL_ENABLED */ + + return 0; +} + +static void set_up_fixed_clock_sources(void) +{ + + if (IS_ENABLED(STM32_HSE_ENABLED)) { + if (IS_ENABLED(STM32_HSE_DIV2)) { + LL_RCC_HSE_EnablePrescaler(); + } + + /* Enable HSE */ + LL_RCC_HSE_Enable(); + while (LL_RCC_HSE_IsReady() != 1) { + /* Wait for HSE ready */ + } + } + + if (IS_ENABLED(STM32_HSI_ENABLED)) { + /* Enable HSI if not enabled */ + if (LL_RCC_HSI_IsReady() != 1) { + /* Enable HSI */ + LL_RCC_HSI_Enable(); + while (LL_RCC_HSI_IsReady() != 1) { + /* Wait for HSI ready */ + } + } + } + + if (IS_ENABLED(STM32_LSI_ENABLED)) { + LL_RCC_LSI1_Enable(); + while (LL_RCC_LSI1_IsReady() != 1) { + } + } + + if (IS_ENABLED(STM32_LSE_ENABLED)) { + /* LSE belongs to the back-up domain, enable access.*/ + + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + + /* Set the DBP bit in the Power control register 1 (PWR_CR1) */ + LL_PWR_EnableBkUpAccess(); + while (!LL_PWR_IsEnabledBkUpAccess()) { + /* Wait for Backup domain access */ + } + + /* Configure driving capability */ + LL_RCC_LSE_SetDriveCapability(STM32_LSE_DRIVING << RCC_BDCR1_LSEDRV_Pos); + + /* Enable LSE Oscillator (32.768 kHz) */ + LL_RCC_LSE_Enable(); + while (!LL_RCC_LSE_IsReady()) { + /* Wait for LSE ready */ + } + + /* Enable LSESYS additionnally */ + LL_RCC_LSE_EnablePropagation(); + /* Wait till LSESYS is ready */ + while (!LL_RCC_LSE_IsPropagationReady()) { + } + + LL_PWR_DisableBkUpAccess(); + + z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); + } +} + +/** + * @brief Initialize clocks for the stm32 + * + * This routine is called to enable and configure the clocks and PLL + * of the soc on the board. It depends on the board definition. + * This function is called on the startup and also to restore the config + * when exiting for low power mode. + * + * @param dev clock device struct + * + * @return 0 + */ +int stm32_clock_control_init(const struct device *dev) +{ + uint32_t old_flash_freq; + int r = 0; + + ARG_UNUSED(dev); + + old_flash_freq = RCC_CALC_FLASH_FREQ(HAL_RCC_GetSysClockFreq(), + GET_CURRENT_FLASH_PRESCALER()); + + + + /* Set up individual enabled clocks */ + set_up_fixed_clock_sources(); + + /* Set voltage regulator to comply with targeted system frequency */ + set_regu_voltage(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + + /* If required, apply max step freq for Sysclock w/ PLL input */ + if (IS_ENABLED(STM32_SYSCLK_SRC_PLL)) { + LL_RCC_PLL1_SetPLL1RCLKDivisionStep(LL_RCC_PLL1RCLK_2_STEP_DIV); + + /* Send 2 pulses on CLKPRE like it is done in STM32Cube HAL */ + LL_RCC_PLL1_DisablePLL1RCLKDivision(); + LL_RCC_PLL1_EnablePLL1RCLKDivision(); + LL_RCC_PLL1_DisablePLL1RCLKDivision(); + LL_RCC_PLL1_EnablePLL1RCLKDivision(); + } + + /* Set up PLLs */ + r = set_up_plls(); + if (r < 0) { + return r; + } + + /* If freq increases, set flash latency before any clock setting */ + if (old_flash_freq < CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) { + LL_SetFlashLatency(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + } + + LL_RCC_SetAHBPrescaler(ahb_prescaler(STM32_CORE_PRESCALER)); + + if (IS_ENABLED(STM32_SYSCLK_SRC_PLL)) { + /* PLL is the SYSCLK source, use 'ahb5-prescaler' */ + LL_RCC_SetAHB5Prescaler(ahb5_prescaler(STM32_AHB5_PRESCALER)); + } else { + /* PLL is not the SYSCLK source, use 'ahb5-div'(if set) */ + if (IS_ENABLED(STM32_AHB5_DIV)) { + LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_2); + } else { + LL_RCC_SetAHB5Divider(LL_RCC_AHB5_DIVIDER_1); + } + } + + if (IS_ENABLED(STM32_SYSCLK_SRC_PLL)) { + /* Set PLL as System Clock Source */ + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1R); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1R) { + } + LL_RCC_PLL1_DisablePLL1RCLKDivision(); + while (LL_RCC_PLL1_IsPLL1RCLKDivisionReady() == 0) { + } + } else if (IS_ENABLED(STM32_SYSCLK_SRC_HSE)) { + /* Set HSE as SYSCLCK source */ + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE); + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) { + } + } else if (IS_ENABLED(STM32_SYSCLK_SRC_HSI)) { + stm32_clock_switch_to_hsi(); + } + + /* If freq not increased, set flash latency after all clock setting */ + if (old_flash_freq >= CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) { + LL_SetFlashLatency(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + } + + SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; + + /* Set bus prescalers prescaler */ + LL_RCC_SetAPB1Prescaler(apb1_prescaler(STM32_APB1_PRESCALER)); + LL_RCC_SetAPB2Prescaler(apb2_prescaler(STM32_APB2_PRESCALER)); + LL_RCC_SetAPB7Prescaler(apb7_prescaler(STM32_APB7_PRESCALER)); + + return 0; +} + +/** + * @brief RCC device, note that priority is intentionally set to 1 so + * that the device init runs just after SOC init + */ +DEVICE_DT_DEFINE(DT_NODELABEL(rcc), + &stm32_clock_control_init, + NULL, + NULL, NULL, + PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &stm32_clock_control_api); diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index c35fcd4475c5..41be8d14996b 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -3,6 +3,7 @@ * Copyright (c) 2016 BayLibre, SAS * Copyright (c) 2017-2022 Linaro Limited. * Copyright (c) 2017 RnDity Sp. z o.o. + * Copyright (c) 2023 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -45,6 +46,8 @@ #include #elif defined(CONFIG_SOC_SERIES_STM32U5X) #include +#elif defined(CONFIG_SOC_SERIES_STM32WBAX) +#include #else #include #endif @@ -58,8 +61,10 @@ #define STM32_APB1_PRESCALER DT_PROP(DT_NODELABEL(rcc), apb1_prescaler) #define STM32_APB2_PRESCALER DT_PROP(DT_NODELABEL(rcc), apb2_prescaler) #define STM32_APB3_PRESCALER DT_PROP(DT_NODELABEL(rcc), apb3_prescaler) +#define STM32_APB7_PRESCALER DT_PROP(DT_NODELABEL(rcc), apb7_prescaler) #define STM32_AHB3_PRESCALER DT_PROP(DT_NODELABEL(rcc), ahb3_prescaler) #define STM32_AHB4_PRESCALER DT_PROP(DT_NODELABEL(rcc), ahb4_prescaler) +#define STM32_AHB5_PRESCALER DT_PROP_OR(DT_NODELABEL(rcc), ahb5_prescaler, 1) #define STM32_CPU1_PRESCALER DT_PROP(DT_NODELABEL(rcc), cpu1_prescaler) #define STM32_CPU2_PRESCALER DT_PROP(DT_NODELABEL(rcc), cpu2_prescaler) @@ -77,6 +82,7 @@ #define STM32_FLASH_PRESCALER STM32_CORE_PRESCALER #endif +/** STM2H7 specifics RCC dividers */ #define STM32_D1CPRE DT_PROP(DT_NODELABEL(rcc), d1cpre) #define STM32_HPRE DT_PROP(DT_NODELABEL(rcc), hpre) #define STM32_D2PPRE1 DT_PROP(DT_NODELABEL(rcc), d2ppre1) @@ -84,6 +90,9 @@ #define STM32_D1PPRE DT_PROP(DT_NODELABEL(rcc), d1ppre) #define STM32_D3PPRE DT_PROP(DT_NODELABEL(rcc), d3ppre) +/** STM2WBA specifics RCC dividers */ +#define STM32_AHB5_DIV DT_PROP(DT_NODELABEL(rcc), ahb5_div) + #define DT_RCC_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(rcc)) /* To enable use of IS_ENABLED utility macro, these symbols @@ -112,13 +121,14 @@ /** PLL node related symbols */ #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f2_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f4_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f7_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32g0_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32g4_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32l4_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32u5_pll_clock, okay) || \ - DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32wb_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f4_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f7_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32g0_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32g4_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32l4_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32u5_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32wb_pll_clock, okay) || \ + DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32wba_pll_clock, okay) || \ DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32h7_pll_clock, okay) #define STM32_PLL_ENABLED 1 #define STM32_PLL_M_DIVISOR DT_PROP(DT_NODELABEL(pll), div_m) @@ -354,6 +364,10 @@ #define STM32_HSE_TCXO DT_PROP(DT_NODELABEL(clk_hse), hse_tcxo) #define STM32_HSE_DIV2 DT_PROP(DT_NODELABEL(clk_hse), hse_div2) #define STM32_HSE_FREQ DT_PROP(DT_NODELABEL(clk_hse), clock_frequency) +#elif DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hse), st_stm32wba_hse_clock, okay) +#define STM32_HSE_ENABLED 1 +#define STM32_HSE_DIV2 DT_PROP(DT_NODELABEL(clk_hse), hse_div2) +#define STM32_HSE_FREQ DT_PROP(DT_NODELABEL(clk_hse), clock_frequency) #else #define STM32_HSE_FREQ 0 #endif diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h new file mode 100644 index 000000000000..757cb8a05524 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_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 +/** 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 + + +#define STM32_SRC_CLOCK_MIN STM32_SRC_PLL1_P +#define STM32_SRC_CLOCK_MAX STM32_SRC_SYSCLK + +/** Bus clocks (Register address offsets) */ +#define STM32_CLOCK_BUS_AHB1 0x088 +#define STM32_CLOCK_BUS_AHB2 0x08C +#define STM32_CLOCK_BUS_AHB4 0x094 +#define STM32_CLOCK_BUS_AHB5 0x098 +#define STM32_CLOCK_BUS_APB1 0x09C +#define STM32_CLOCK_BUS_APB1_2 0x0A0 +#define STM32_CLOCK_BUS_APB2 0x0A4 +#define STM32_CLOCK_BUS_APB7 0x0A8 + +#define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 +#define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB7 + +/** + * @brief STM32WBA clock configuration bit field. + * + * - reg (1/2/3) [ 0 : 7 ] + * - shift (0..31) [ 8 : 12 ] + * - mask (0x1, 0x3, 0x7) [ 13 : 15 ] + * - val (0..7) [ 16 : 18 ] + * + * @param reg RCC_CCIPRx register offset + * @param shift Position within RCC_CCIPRx. + * @param mask Mask for the RCC_CCIPRx field. + * @param val Clock value (0, 1, ... 7). + */ + +#define STM32_CLOCK_REG_MASK 0xFFU +#define STM32_CLOCK_REG_SHIFT 0U +#define STM32_CLOCK_SHIFT_MASK 0x1FU +#define STM32_CLOCK_SHIFT_SHIFT 8U +#define STM32_CLOCK_MASK_MASK 0x7U +#define STM32_CLOCK_MASK_SHIFT 13U +#define STM32_CLOCK_VAL_MASK 0x7U +#define STM32_CLOCK_VAL_SHIFT 16U + +#define STM32_CLOCK(val, mask, shift, reg) \ + ((((reg) & STM32_CLOCK_REG_MASK) << STM32_CLOCK_REG_SHIFT) | \ + (((shift) & STM32_CLOCK_SHIFT_MASK) << STM32_CLOCK_SHIFT_SHIFT) | \ + (((mask) & STM32_CLOCK_MASK_MASK) << STM32_CLOCK_MASK_SHIFT) | \ + (((val) & STM32_CLOCK_VAL_MASK) << STM32_CLOCK_VAL_SHIFT)) + +/** @brief RCC_CCIPRx register offset (RM0493.pdf) */ +#define CCIPR1_REG 0xE0 +#define CCIPR2_REG 0xE4 +#define CCIPR3_REG 0xE8 + +/** @brief Device clk sources selection helpers */ +/** CCIPR1 devices */ +#define USART1_SEL(val) STM32_CLOCK(val, 3, 0, CCIPR1_REG) +#define USART2_SEL(val) STM32_CLOCK(val, 3, 2, CCIPR1_REG) +#define I2C1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR1_REG) +#define LPTIM2_SEL(val) STM32_CLOCK(val, 3, 18, CCIPR1_REG) +#define SPI1_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR1_REG) +#define SYSTICK_SEL(val) STM32_CLOCK(val, 3, 22, CCIPR1_REG) +#define TIMIC_SEL(val) STM32_CLOCK(val, 1, 31, CCIPR1_REG) +/** CCIPR2 devices */ +#define RNG_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR2_REG) +/** CCIPR3 devices */ +#define LPUART1_SEL(val) STM32_CLOCK(val, 3, 0, CCIPR3_REG) +#define SPI3_SEL(val) STM32_CLOCK(val, 3, 3, CCIPR3_REG) +#define I2C3_SEL(val) STM32_CLOCK(val, 3, 6, CCIPR3_REG) +#define LPTIM1_SEL(val) STM32_CLOCK(val, 3, 10, CCIPR3_REG) +#define ADC_SEL(val) STM32_CLOCK(val, 7, 12, CCIPR3_REG) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ */ From cbf9f3d4c2c245847ff6fda0fcf290487bfef285 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 7 Jul 2023 14:59:13 +0200 Subject: [PATCH 1137/2042] drivers: flash: stm32: add stm32wba support Add Flash STM32WBA support Signed-off-by: Guillaume Gautier --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/flash_stm32.c | 11 +- drivers/flash/flash_stm32.h | 11 ++ drivers/flash/flash_stm32wbax.c | 309 ++++++++++++++++++++++++++++++++ 4 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 drivers/flash/flash_stm32wbax.c diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 8266c8c1619d..c34a62804ea1 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -77,6 +77,7 @@ if(CONFIG_SOC_FLASH_STM32) 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) endif() endif() diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index c9fc4b979fdc..f6daea97fe30 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -269,8 +269,7 @@ static int flash_stm32_write_protection(const struct device *dev, bool enable) regs->NSKEYR = FLASH_KEY2; } } -#else /* FLASH_SECURITY_SEC | FLASH_SECURITY_NA */ -#if defined(FLASH_CR_LOCK) +#elif defined(FLASH_CR_LOCK) if (enable) { regs->CR |= FLASH_CR_LOCK; } else { @@ -296,7 +295,6 @@ static int flash_stm32_write_protection(const struct device *dev, bool enable) rc = -EIO; } } -#endif #endif /* FLASH_SECURITY_NS */ if (enable) { @@ -357,6 +355,13 @@ int flash_stm32_option_bytes_lock(const struct device *dev, bool enable) regs->OPTKEYR = FLASH_OPTKEY1; regs->OPTKEYR = FLASH_OPTKEY2; } +#elif defined(FLASH_NSCR1_OPTLOCK) /* WBA */ + if (enable) { + regs->NSCR1 |= FLASH_NSCR1_OPTLOCK; + } else if (regs->NSCR1 & FLASH_NSCR1_OPTLOCK) { + regs->OPTKEYR = FLASH_OPTKEY1; + regs->OPTKEYR = FLASH_OPTKEY2; + } #endif /* Lock CR/PECR/NSCR register if needed. */ if (enable) { diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index 88abe9d07a27..dd8628f81d77 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -105,6 +105,17 @@ struct flash_stm32_priv { #define FLASH_STM32_NSPNB_POS FLASH_NSCR_NSPNB_Pos #define FLASH_STM32_NSPNB FLASH_NSCR_NSPNB #define FLASH_STM32_NSSTRT FLASH_NSCR_NSSTRT +#elif defined(CONFIG_SOC_SERIES_STM32WBAX) +#define NSCR NSCR1 +#define FLASH_STM32_NSLOCK FLASH_NSCR1_LOCK +#define FLASH_STM32_NSPG FLASH_NSCR1_PG +#define FLASH_STM32_NSBKER_MSK FLASH_NSCR1_BKER_Msk +#define FLASH_STM32_NSBKER FLASH_NSCR1_BKER +#define FLASH_STM32_NSPER FLASH_NSCR1_PER +#define FLASH_STM32_NSPNB_MSK FLASH_NSCR1_PNB_Msk +#define FLASH_STM32_NSPNB_POS FLASH_NSCR1_PNB_Pos +#define FLASH_STM32_NSPNB FLASH_NSCR1_PNB +#define FLASH_STM32_NSSTRT FLASH_NSCR1_STRT #endif /* CONFIG_SOC_SERIES_STM32U5X */ #if defined(FLASH_OPTR_DBANK) #define FLASH_STM32_DBANK FLASH_OPTR_DBANK diff --git a/drivers/flash/flash_stm32wbax.c b/drivers/flash/flash_stm32wbax.c new file mode 100644 index 000000000000..605b727ddfbc --- /dev/null +++ b/drivers/flash/flash_stm32wbax.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_DOMAIN flash_stm32wba +#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_DOMAIN); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flash_stm32.h" + +#define STM32_SERIES_MAX_FLASH 1024 + +#define ICACHE_DISABLE_TIMEOUT_VALUE 1U /* 1ms */ +#define ICACHE_INVALIDATE_TIMEOUT_VALUE 1U /* 1ms */ + +static int stm32_icache_disable(void) +{ + int status = 0; + uint32_t tickstart; + + LOG_DBG("I-cache Disable"); + /* Clear BSYENDF flag first and then disable the instruction cache + * that starts a cache invalidation procedure + */ + CLEAR_BIT(ICACHE->FCR, ICACHE_FCR_CBSYENDF); + + LL_ICACHE_Disable(); + + /* Get tick */ + tickstart = k_uptime_get_32(); + + /* Wait for instruction cache to get disabled */ + while (LL_ICACHE_IsEnabled()) { + if ((k_uptime_get_32() - tickstart) > + ICACHE_DISABLE_TIMEOUT_VALUE) { + /* New check to avoid false timeout detection in case + * of preemption. + */ + if (LL_ICACHE_IsEnabled()) { + status = -ETIMEDOUT; + break; + } + } + } + + return status; +} + +static void stm32_icache_enable(void) +{ + LOG_DBG("I-cache Enable"); + LL_ICACHE_Enable(); +} + +static int icache_wait_for_invalidate_complete(void) +{ + int status = -EIO; + uint32_t tickstart; + + /* Check if ongoing invalidation operation */ + if (LL_ICACHE_IsActiveFlag_BUSY()) { + /* Get tick */ + tickstart = k_uptime_get_32(); + + /* Wait for end of cache invalidation */ + while (!LL_ICACHE_IsActiveFlag_BSYEND()) { + if ((k_uptime_get_32() - tickstart) > + ICACHE_INVALIDATE_TIMEOUT_VALUE) { + break; + } + } + } + + /* Clear any pending flags */ + if (LL_ICACHE_IsActiveFlag_BSYEND()) { + LOG_DBG("I-cache Invalidation complete"); + + LL_ICACHE_ClearFlag_BSYEND(); + status = 0; + } else { + LOG_ERR("I-cache Invalidation timeout"); + + status = -ETIMEDOUT; + } + + if (LL_ICACHE_IsActiveFlag_ERR()) { + LOG_ERR("I-cache error"); + + LL_ICACHE_ClearFlag_ERR(); + status = -EIO; + } + + return status; +} + +/* + * offset and len must be aligned on 16 for write, + * positive and not beyond end of flash + */ +bool flash_stm32_valid_range(const struct device *dev, off_t offset, + uint32_t len, + bool write) +{ + return (!write || (offset % 16 == 0 && len % 16 == 0U)) && + flash_stm32_range_exists(dev, offset, len); +} + +static int write_qword(const struct device *dev, off_t offset, const uint32_t *buff) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + volatile uint32_t *flash = (uint32_t *)(offset + + CONFIG_FLASH_BASE_ADDRESS); + uint32_t tmp; + int rc; + + /* if the non-secure control register is locked, do not fail silently */ + if (regs->NSCR & FLASH_STM32_NSLOCK) { + LOG_ERR("NSCR locked\n"); + return -EIO; + } + + /* Check that no Flash main memory operation is ongoing */ + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + /* Check if this double word is erased */ + if ((flash[0] != 0xFFFFFFFFUL) || (flash[1] != 0xFFFFFFFFUL) || + (flash[2] != 0xFFFFFFFFUL) || (flash[3] != 0xFFFFFFFFUL)) { + LOG_ERR("Word at offs %ld not erased", (long)offset); + return -EIO; + } + + /* Set the NSPG bit */ + regs->NSCR |= FLASH_STM32_NSPG; + + /* Flush the register write */ + tmp = regs->NSCR; + + /* Perform the data write operation at the desired memory address */ + flash[0] = buff[0]; + flash[1] = buff[1]; + flash[2] = buff[2]; + flash[3] = buff[3]; + + /* Wait until the NSBSY bit is cleared */ + rc = flash_stm32_wait_flash_idle(dev); + + /* Clear the NSPG bit */ + regs->NSCR &= (~FLASH_STM32_NSPG); + + return rc; +} + +static int erase_page(const struct device *dev, unsigned int offset) +{ + FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); + uint32_t tmp; + int rc; + int page; + + /* if the non-secure control register is locked,do not fail silently */ + if (regs->NSCR & FLASH_STM32_NSLOCK) { + LOG_ERR("NSCR locked\n"); + return -EIO; + } + + /* Check that no Flash memory operation is ongoing */ + rc = flash_stm32_wait_flash_idle(dev); + if (rc < 0) { + return rc; + } + + page = offset / FLASH_PAGE_SIZE; + LOG_DBG("Erase page %d\n", page); + + /* Set the NSPER bit and select the page you wish to erase */ + regs->NSCR |= FLASH_STM32_NSPER; + regs->NSCR &= ~FLASH_STM32_NSPNB_MSK; + regs->NSCR |= (page << FLASH_STM32_NSPNB_POS); + + /* Set the NSSTRT bit */ + regs->NSCR |= FLASH_STM32_NSSTRT; + + /* flush the register write */ + tmp = regs->NSCR; + + /* Wait for the NSBSY bit */ + rc = flash_stm32_wait_flash_idle(dev); + + regs->NSCR &= ~(FLASH_STM32_NSPER); + + return rc; +} + +int flash_stm32_block_erase_loop(const struct device *dev, + unsigned int offset, + unsigned int len) +{ + unsigned int address = offset; + int rc = 0; + bool icache_enabled = LL_ICACHE_IsEnabled(); + + if (icache_enabled) { + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + rc = stm32_icache_disable(); + if (rc != 0) { + return rc; + } + } + + for (; address <= offset + len - 1 ; address += FLASH_PAGE_SIZE) { + rc = erase_page(dev, address); + if (rc < 0) { + break; + } + } + + if (icache_enabled) { + /* Since i-cache was disabled, this would start the + * invalidation procedure, so wait for completion. + */ + rc = icache_wait_for_invalidate_complete(); + + /* I-cache should be enabled only after the + * invalidation is complete. + */ + stm32_icache_enable(); + } + + return rc; +} + +int flash_stm32_write_range(const struct device *dev, unsigned int offset, + const void *data, unsigned int len) +{ + int i, rc = 0; + bool icache_enabled = LL_ICACHE_IsEnabled(); + + if (icache_enabled) { + /* Disable icache, this will start the invalidation procedure. + * All changes(erase/write) to flash memory should happen when + * i-cache is disabled. A write to flash performed without + * disabling i-cache will set ERRF error flag in SR register. + */ + rc = stm32_icache_disable(); + if (rc != 0) { + return rc; + } + } + + for (i = 0; i < len; i += 16) { + rc = write_qword(dev, offset + i, ((const uint32_t *) data + (i>>2))); + if (rc < 0) { + break; + } + } + + if (icache_enabled) { + /* Since i-cache was disabled, this would start the + * invalidation procedure, so wait for completion. + */ + rc = icache_wait_for_invalidate_complete(); + + /* I-cache should be enabled only after the + * invalidation is complete. + */ + stm32_icache_enable(); + } + + return rc; +} + +void flash_stm32_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; +} From 2af4d1aa00a582166f819599dce36f7c4c7e6b2b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 22 Mar 2023 17:28:41 +0100 Subject: [PATCH 1138/2042] dts: bindings: Add stm32wba flash controller binding Required to compile wba variant of stm32 flash controller Signed-off-by: Erwan Gouriou --- .../flash_controller/st,stm32wba-flash-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dts/bindings/flash_controller/st,stm32wba-flash-controller.yaml diff --git a/dts/bindings/flash_controller/st,stm32wba-flash-controller.yaml b/dts/bindings/flash_controller/st,stm32wba-flash-controller.yaml new file mode 100644 index 000000000000..5ef97c10ece9 --- /dev/null +++ b/dts/bindings/flash_controller/st,stm32wba-flash-controller.yaml @@ -0,0 +1,5 @@ +description: STM32 WBA flash controller + +compatible: "st,stm32wba-flash-controller" + +include: flash-controller.yaml From 85aa3e1731fda1069551e68c755fb335a8aa1501 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 1 Mar 2023 16:55:54 +0100 Subject: [PATCH 1139/2042] include: dt-bindings: reset: Add bindings for stm32WBA Add reset bindings for STM32WBA SoCs. Signed-off-by: Erwan Gouriou --- .../zephyr/dt-bindings/reset/stm32wba_reset.h | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 include/zephyr/dt-bindings/reset/stm32wba_reset.h diff --git a/include/zephyr/dt-bindings/reset/stm32wba_reset.h b/include/zephyr/dt-bindings/reset/stm32wba_reset.h new file mode 100644 index 000000000000..1ea75a2a13d8 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/stm32wba_reset.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32WBA_RESET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32WBA_RESET_H_ + +#include "stm32-common.h" + +/* RCC bus reset register offset */ +#define STM32_RESET_BUS_AHB1 0x60 +#define STM32_RESET_BUS_AHB2 0x64 +#define STM32_RESET_BUS_AHB4 0x6C +#define STM32_RESET_BUS_AHB5 0x70 +#define STM32_RESET_BUS_APB1L 0x74 +#define STM32_RESET_BUS_APB1H 0x78 +#define STM32_RESET_BUS_APB2 0x7C +#define STM32_RESET_BUS_APB7 0x80 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_STM32WBA_RESET_H_ */ From 21a23681376ee534718029e874789fea503f0e7e Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 14:54:07 +0200 Subject: [PATCH 1140/2042] dts: stm32: Add base device tree description for stm32wba Add basic device tree description fro stm32wba soc series. This includes Flash/RAM clocks and clock control nodes Signed-off-by: Guillaume Gautier --- dts/arm/st/wba/stm32wba.dtsi | 246 +++++++++++++++++++++++++++++++ dts/arm/st/wba/stm32wba52Xg.dtsi | 21 +++ 2 files changed, 267 insertions(+) create mode 100644 dts/arm/st/wba/stm32wba.dtsi create mode 100644 dts/arm/st/wba/stm32wba52Xg.dtsi diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi new file mode 100644 index 000000000000..bbf085365726 --- /dev/null +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include +#include +#include + +#include + +/ { + chosen { + zephyr,flash-controller = &flash; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m33"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv8m-mpu"; + reg = <0xe000ed90 0x40>; + arm,num-mpu-regions = <8>; + }; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + clocks { + clk_hse: clk-hse { + #clock-cells = <0>; + compatible = "st,stm32wba-hse-clock"; + clock-frequency = ; + status = "disabled"; + }; + + clk_hsi: clk-hsi { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "disabled"; + }; + + clk_lse: clk-lse { + #clock-cells = <0>; + compatible = "st,stm32-lse-clock"; + clock-frequency = <32768>; + driving-capability = <1>; + status = "disabled"; + }; + + clk_lsi: clk-lsi { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "disabled"; + }; + + pll1: pll: pll { + #clock-cells = <0>; + compatible = "st,stm32wba-pll-clock"; + status = "disabled"; + }; + }; + + soc { + flash: flash-controller@40022000 { + compatible = "st,stm32-flash-controller", "st,stm32wba-flash-controller"; + reg = <0x40022000 0x400>; + interrupts = <6 0>; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@8000000 { + compatible = "st,stm32-nv-flash", "soc-nv-flash"; + + write-block-size = <16>; + erase-block-size = <8192>; + /* maximum erase time(ms) for a 8K sector */ + max-erase-time = <5>; + }; + }; + + rcc: rcc@46020c00 { + compatible = "st,stm32wba-rcc"; + clocks-controller; + #clock-cells = <2>; + reg = <0x46020c00 0x400>; + + rctl: reset-controller { + compatible = "st,stm32-rcc-rctl"; + #reset-cells = <1>; + }; + }; + + exti: interrupt-controller@46022000 { + compatible = "st,stm32g0-exti", "st,stm32-exti"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x46022000 0x400>; + num-lines = <16>; + interrupts = <11 0>, <12 0>, <13 0>, <14 0>, + <15 0>, <16 0>, <17 0>, <18 0>, + <19 0>, <20 0>, <21 0>, <22 0>, + <23 0>, <24 0>, <25 0>, <26 0>; + interrupt-names = "line0", "line1", "line2", "line3", + "line4", "line5", "line6", "line7", + "line8", "line9", "line10", "line11", + "line12", "line13", "line14", "line15"; + line-ranges = <0 1>, <1 1>, <2 1>, <3 1>, + <4 1>, <5 1>, <6 1>, <7 1>, + <8 1>, <9 1>, <10 1>, <11 1>, + <12 1>, <13 1>, <14 1>, <15 1>; + }; + + pinctrl: pin-controller@42020000 { + compatible = "st,stm32-pinctrl"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x42020000 0x2000>; + + gpioa: gpio@42020000 { + compatible = "st,stm32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x42020000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000001>; + }; + + gpiob: gpio@42020400 { + compatible = "st,stm32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x42020400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000002>; + }; + + gpioc: gpio@42020800 { + compatible = "st,stm32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x42020800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000004>; + }; + + gpioh: gpio@42021c00 { + compatible = "st,stm32-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x42021c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000080>; + }; + }; + + usart1: serial@40013800 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40013800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>; + resets = <&rctl STM32_RESET(APB2, 14U)>; + interrupts = <46 0>; + status = "disabled"; + }; + + usart2: serial@40004400 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40004400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00020000>; + resets = <&rctl STM32_RESET(APB1L, 17U)>; + interrupts = <47 0>; + status = "disabled"; + }; + + lpuart1: serial@46002400 { + compatible = "st,stm32-lpuart", "st,stm32-uart"; + reg = <0x46002400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000040>; + resets = <&rctl STM32_RESET(APB7, 6U)>; + interrupts = <48 0>; + status = "disabled"; + }; + + spi1: spi@40013000 { + compatible = "st,stm32h7-spi", "st,stm32-spi-fifo", "st,stm32-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40013000 0x400>; + interrupts = <45 5>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>; + status = "disabled"; + }; + + spi3: spi@46002000 { + compatible = "st,stm32h7-spi", "st,stm32-spi-fifo", "st,stm32-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x46002000 0x400>; + interrupts = <63 5>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000020>; + status = "disabled"; + }; + + i2c1: i2c@40005400 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40005400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00200000>; + interrupts = <43 0>, <44 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + + i2c3: i2c@46002800 { + compatible = "st,stm32-i2c-v2"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x46002800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000080>; + interrupts = <54 0>, <55 0>; + interrupt-names = "event", "error"; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; diff --git a/dts/arm/st/wba/stm32wba52Xg.dtsi b/dts/arm/st/wba/stm32wba52Xg.dtsi new file mode 100644 index 000000000000..49724f35e5c4 --- /dev/null +++ b/dts/arm/st/wba/stm32wba52Xg.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 05ba84814799310fd42a3dcbb93f6d1e2c923f00 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 15:44:04 +0200 Subject: [PATCH 1141/2042] boards: arm: nucleo_wba52cg: Add board definition Add nucleo_wba52cg with basic peripherals. Signed-off-by: Guillaume Gautier --- boards/arm/nucleo_wba52cg/Kconfig.board | 8 + boards/arm/nucleo_wba52cg/Kconfig.defconfig | 16 ++ .../nucleo_wba52cg/arduino_r3_connector.dtsi | 39 +++ boards/arm/nucleo_wba52cg/board.cmake | 3 + .../nucleo_wba52cg/doc/img/nucleowba52cg.jpg | Bin 0 -> 87801 bytes .../arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst | 261 ++++++++++++++++++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 109 ++++++++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml | 16 ++ .../nucleo_wba52cg/nucleo_wba52cg_defconfig | 26 ++ 9 files changed, 478 insertions(+) create mode 100644 boards/arm/nucleo_wba52cg/Kconfig.board create mode 100644 boards/arm/nucleo_wba52cg/Kconfig.defconfig create mode 100644 boards/arm/nucleo_wba52cg/arduino_r3_connector.dtsi create mode 100644 boards/arm/nucleo_wba52cg/board.cmake create mode 100644 boards/arm/nucleo_wba52cg/doc/img/nucleowba52cg.jpg create mode 100644 boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst create mode 100644 boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts create mode 100644 boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml create mode 100644 boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig diff --git a/boards/arm/nucleo_wba52cg/Kconfig.board b/boards/arm/nucleo_wba52cg/Kconfig.board new file mode 100644 index 000000000000..819c5e1b1f01 --- /dev/null +++ b/boards/arm/nucleo_wba52cg/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WBA52CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NUCLEO_WBA52CG + bool "Nucleo WBA52CG Development Board" + depends on SOC_STM32WBA52XX diff --git a/boards/arm/nucleo_wba52cg/Kconfig.defconfig b/boards/arm/nucleo_wba52cg/Kconfig.defconfig new file mode 100644 index 000000000000..dfdac1bba98b --- /dev/null +++ b/boards/arm/nucleo_wba52cg/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WBA52CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics + +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NUCLEO_WBA52CG + +config BOARD + default "nucleo_wba52cg" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_NUCLEO_WBA52CG diff --git a/boards/arm/nucleo_wba52cg/arduino_r3_connector.dtsi b/boards/arm/nucleo_wba52cg/arduino_r3_connector.dtsi new file mode 100644 index 000000000000..619cebea62a4 --- /dev/null +++ b/boards/arm/nucleo_wba52cg/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_wba52cg/board.cmake b/boards/arm/nucleo_wba52cg/board.cmake new file mode 100644 index 000000000000..50f543d4e6ab --- /dev/null +++ b/boards/arm/nucleo_wba52cg/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_wba52cg/doc/img/nucleowba52cg.jpg b/boards/arm/nucleo_wba52cg/doc/img/nucleowba52cg.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_wba52cg/doc/nucleo_wba52cg.rst b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst new file mode 100644 index 000000000000..b8433afbbc44 --- /dev/null +++ b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst @@ -0,0 +1,261 @@ +.. _nucleo_wba52cg_board: + +ST Nucleo WBA52CG +################# + +Overview +******** + +NUCLEO-WBA52CG 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 STM32WBA52CG 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/nucleowba52cg.jpg + :align: center + :alt: Nucleo WBA52CG + +More information about the board can be found at the `Nucleo WBA52CG website`_. + +Hardware +******** + +The STM32WBA52xx 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 STM32WB55RG can be found here: + +- `STM32WBA52CG on www.st.com`_ +- `STM32WBA52CG datasheet`_ +- `STM32WBA52CG reference manual`_ + +Supported Features +================== + +The Zephyr nucleo_wba52cg 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 | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig file: +``boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig`` + +Connections and IOs +=================== + +Nucleo WBA52CG 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 WBA52CG 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 WBA52CG board has 1 U(S)ARTs. The Zephyr console output is assigned to USART1. +Default settings are 115200 8N1. + + +Programming and Debugging +************************* + +Flashing +======== + +Nucleo WBA52CG board includes an ST-LINK/V3 embedded debug tool interface. +For now, only STM32CubeProgrammer is available for flashing. It is configured +as flashing tool by default. + +Flashing an application to Nucleo WBA52CG +----------------------------------------- + +Here is an example for the :ref:`blinky-sample` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: nucleo_wba52cg + :goals: build flash + +You will see the LED blinking every second. + +Debugging +========= + +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 + +.. _Nucleo WBA52CG website: + https://www.st.com/en/evaluation-tools/nucleo-wba52cg.html + +.. _STM32WBA52CG on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wba52cg.html + +.. _STM32WBA52CG datasheet: + https://www.st.com/resource/en/datasheet/stm32wba52cg.pdf + +.. _STM32WBA52CG reference manual: + https://www.st.com/resource/en/reference_manual/rm0493-multiprotocol-wireless-bluetooth-lowenergy-armbased-32bit-mcu-stmicroelectronics.pdf diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts new file mode 100644 index 000000000000..7565b43c55af --- /dev/null +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "arduino_r3_connector.dtsi" + +/ { + model = "STMicroelectronics STM32WBA52CG-NUCLEO board"; + compatible = "st,stm32wba52cg-nucleo"; + + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + }; + + 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>; + }; + }; + + aliases { + led0 = &blue_led_1; + sw0 = &user_button; + }; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hse { + status = "okay"; +}; + +&pll1 { + div-m = <8>; + mul-n = <100>; + div-q = <2>; + div-r = <4>; + 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>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; + 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 = ; +}; diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml new file mode 100644 index 000000000000..bf0d55459f94 --- /dev/null +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml @@ -0,0 +1,16 @@ +identifier: nucleo_wba52cg +name: ST Nucleo WBA52CG +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - i2c + - spi + - arduino_gpio + - arduino_i2c + - arduino_spi +ram: 128 +flash: 1024 diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig new file mode 100644 index 000000000000..9b917b0fc69c --- /dev/null +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32WBAX=y +CONFIG_SOC_STM32WBA52XX=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 From 2abdeab768901213d47a810aedc523d1ed405dd8 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 6 Jul 2023 12:06:20 +0200 Subject: [PATCH 1142/2042] Bluetooth: audio: ascs: Refactor ASE Release handler This removes code duplicates. The ASE Release operation handler has been refactored by moving the state validation check to the ase_release function body and providing the `rsp` pointer that is later filled. ascs_cp_rsp_add is not called from ase_release explicitly, so the contents of the respons buffer are not changed in case the ase_release is called from non control point context e.g. `disconnected` callback. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 71 ++++++++++----------- subsys/bluetooth/audio/ascs_internal.h | 1 + subsys/bluetooth/audio/bap_unicast_server.c | 28 +------- 3 files changed, 36 insertions(+), 64 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index c6a72aa8e9bb..f3c5960ad7e9 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -54,6 +54,7 @@ BUILD_ASSERT(CONFIG_BT_ASCS_MAX_ACTIVE_ASES <= MAX(MAX_ASES_SESSIONS, #define ASE_UUID(_id) \ (_id > CONFIG_BT_ASCS_ASE_SNK_COUNT ? BT_UUID_ASCS_ASE_SRC : BT_UUID_ASCS_ASE_SNK) #define ASE_COUNT (CONFIG_BT_ASCS_ASE_SNK_COUNT + CONFIG_BT_ASCS_ASE_SRC_COUNT) +#define BT_BAP_ASCS_RSP_NULL ((struct bt_bap_ascs_rsp[]) { BT_BAP_ASCS_RSP(0, 0) }) static struct bt_ascs_ase { struct bt_conn *conn; @@ -919,46 +920,49 @@ static void ascs_cp_rsp_success(uint8_t id) ascs_cp_rsp_add(id, BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); } -static void ase_release(struct bt_ascs_ase *ase) +static int ase_release(struct bt_ascs_ase *ase, uint8_t reason, struct bt_bap_ascs_rsp *rsp) { - uint8_t ase_id = ASE_ID(ase); - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); + enum bt_bap_ep_state state = ascs_ep_get_state(&ase->ep); int err; - LOG_DBG("ase %p state %s", ase, bt_bap_ep_state_str(ase->ep.status.state)); - - if (ase->ep.status.state == BT_BAP_EP_STATE_RELEASING) { - /* already releasing */ - return; + if (state == BT_BAP_EP_STATE_IDLE || state == BT_BAP_EP_STATE_RELEASING) { + LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(state)); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, + BT_BAP_ASCS_REASON_NONE); + return -EBADMSG; } - if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) { - err = unicast_server_cb->release(ase->ep.stream, &rsp); - } else { - err = -ENOTSUP; - rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, - BT_BAP_ASCS_REASON_NONE); + if (unicast_server_cb == NULL || unicast_server_cb->release == NULL) { + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, + BT_BAP_ASCS_REASON_NONE); + return -ENOTSUP; } + err = unicast_server_cb->release(ase->ep.stream, 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); + 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("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); - ascs_cp_rsp_add(ase_id, rsp.code, rsp.reason); - return; + LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp->code, rsp->reason); + return err; } /* Set reason in case this exits the streaming state */ - ase->ep.reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + ase->ep.reason = reason; ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_RELEASING); - /* At this point, `ase` object might have been free'd if automously went to Idle */ - ascs_cp_rsp_success(ase_id); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); + return 0; +} + +int bt_ascs_release_ase(struct bt_bap_ep *ep) +{ + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + + return ase_release(ase, BT_HCI_ERR_LOCALHOST_TERM_CONN, BT_BAP_ASCS_RSP_NULL); } static void ase_disable(struct bt_ascs_ase *ase) @@ -1032,8 +1036,7 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) } if (ase->ep.status.state != BT_BAP_EP_STATE_IDLE) { - ase->ep.reason = reason; - ase_release(ase); + ase_release(ase, reason, BT_BAP_ASCS_RSP_NULL); /* At this point, `ase` object have been free'd */ } } @@ -2719,8 +2722,10 @@ static ssize_t ascs_release(struct bt_conn *conn, struct net_buf_simple *buf) LOG_DBG("num_ases %u", req->num_ases); for (i = 0; i < req->num_ases; i++) { - uint8_t id; + struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, + BT_BAP_ASCS_REASON_NONE); struct bt_ascs_ase *ase; + uint8_t id; id = net_buf_simple_pull_u8(buf); @@ -2741,16 +2746,8 @@ static ssize_t ascs_release(struct bt_conn *conn, struct net_buf_simple *buf) continue; } - if (ase->ep.status.state == BT_BAP_EP_STATE_IDLE || - ase->ep.status.state == BT_BAP_EP_STATE_RELEASING) { - LOG_WRN("Invalid operation in state: %s", - bt_bap_ep_state_str(ase->ep.status.state)); - ascs_cp_rsp_add(id, BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, - BT_BAP_ASCS_REASON_NONE); - continue; - } - - ase_release(ase); + ase_release(ase, BT_HCI_ERR_REMOTE_USER_TERM_CONN, &rsp); + ascs_cp_rsp_add(id, rsp.code, rsp.reason); } return buf->size; diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index ec8f763ba157..a3ebbe7d2510 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -345,5 +345,6 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state); int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg, const struct bt_audio_codec_qos_pref *qos_pref); +int bt_ascs_release_ase(struct bt_bap_ep *ep); void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data); diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index d056128a2505..ce18198c4df9 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -182,33 +182,7 @@ int bt_bap_unicast_server_disable(struct bt_bap_stream *stream) int bt_bap_unicast_server_release(struct bt_bap_stream *stream) { - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); - struct bt_bap_ep *ep; - int err; - - if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) { - err = unicast_server_cb->release(stream, &rsp); - } else { - err = -ENOTSUP; - } - - if (err != 0) { - LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); - return err; - } - - ep = stream->ep; - - /* Set reason in case this exits the streaming state */ - ep->reason = BT_HCI_ERR_LOCALHOST_TERM_CONN; - - /* ase_process will set the state to IDLE after sending the - * notification, finalizing the release - */ - ascs_ep_set_state(ep, BT_BAP_EP_STATE_RELEASING); - - return 0; + return bt_ascs_release_ase(stream->ep); } int bt_bap_unicast_server_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, From 0af2a75a7e8cc3194142f3d743e4cdf8b9ec3870 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 6 Jul 2023 12:06:43 +0200 Subject: [PATCH 1143/2042] Bluetooth: audio: ascs: Refactor ASE Disable handler This removes code duplicates. ASE Disable operation handler has been refactored by providing the `rsp` pointer as one of the function parameters. ascs_cp_rsp_add is not called from ase_disable explicitly, so the contents of the response buffer are not changed in case the ase_disable is called from non control point context. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 51 +++++++++++---------- subsys/bluetooth/audio/ascs_internal.h | 1 + subsys/bluetooth/audio/bap_unicast_server.c | 32 +------------ 3 files changed, 30 insertions(+), 54 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index f3c5960ad7e9..5dc93544b1cb 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -965,12 +965,10 @@ int bt_ascs_release_ase(struct bt_bap_ep *ep) return ase_release(ase, BT_HCI_ERR_LOCALHOST_TERM_CONN, BT_BAP_ASCS_RSP_NULL); } -static void ase_disable(struct bt_ascs_ase *ase) +static int ase_disable(struct bt_ascs_ase *ase, uint8_t reason, struct bt_bap_ascs_rsp *rsp) { struct bt_bap_stream *stream; struct bt_bap_ep *ep; - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); int err; LOG_DBG("ase %p", ase); @@ -985,34 +983,31 @@ static void ase_disable(struct bt_ascs_ase *ase) break; default: LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state)); - ascs_cp_rsp_add(ASE_ID(ase), BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, - BT_BAP_ASCS_REASON_NONE); - return; + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, + BT_BAP_ASCS_REASON_NONE); + return -EBADMSG; } stream = ep->stream; - if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) { - err = unicast_server_cb->disable(stream, &rsp); - } else { - err = -ENOTSUP; - rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, - BT_BAP_ASCS_REASON_NONE); + if (unicast_server_cb == NULL || unicast_server_cb->disable == NULL) { + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); + return -ENOTSUP; } + err = unicast_server_cb->disable(stream, 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); + 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("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); - ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); - return; + LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp->code, rsp->reason); + return err; } /* Set reason in case this exits the streaming state */ - ep->reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + ep->reason = reason; /* The ASE state machine goes into different states from this operation * based on whether it is a source or a sink ASE. @@ -1023,7 +1018,15 @@ static void ase_disable(struct bt_ascs_ase *ase) ascs_ep_set_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); } - ascs_cp_rsp_success(ASE_ID(ase)); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); + return 0; +} + +int bt_ascs_disable_ase(struct bt_bap_ep *ep) +{ + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + + return ase_disable(ase, BT_HCI_ERR_LOCALHOST_TERM_CONN, BT_BAP_ASCS_RSP_NULL); } static void disconnected(struct bt_conn *conn, uint8_t reason) @@ -2416,7 +2419,6 @@ static bool is_valid_disable_len(struct net_buf_simple *buf) static ssize_t ascs_disable(struct bt_conn *conn, struct net_buf_simple *buf) { const struct bt_ascs_disable_op *req; - int i; if (!is_valid_disable_len(buf)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); @@ -2426,7 +2428,9 @@ static ssize_t ascs_disable(struct bt_conn *conn, struct net_buf_simple *buf) LOG_DBG("num_ases %u", req->num_ases); - for (i = 0; i < req->num_ases; i++) { + for (uint8_t i = 0; i < req->num_ases; i++) { + struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, + BT_BAP_ASCS_REASON_NONE); struct bt_ascs_ase *ase; uint8_t id; @@ -2449,7 +2453,8 @@ static ssize_t ascs_disable(struct bt_conn *conn, struct net_buf_simple *buf) continue; } - ase_disable(ase); + ase_disable(ase, BT_HCI_ERR_REMOTE_USER_TERM_CONN, &rsp); + ascs_cp_rsp_add(id, rsp.code, rsp.reason); } return buf->size; diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index a3ebbe7d2510..bad0b2bb527e 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -345,6 +345,7 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state); int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg, const struct bt_audio_codec_qos_pref *qos_pref); +int bt_ascs_disable_ase(struct bt_bap_ep *ep); int bt_ascs_release_ase(struct bt_bap_ep *ep); void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_data); diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index ce18198c4df9..48e5beb79a56 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -147,37 +147,7 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio int bt_bap_unicast_server_disable(struct bt_bap_stream *stream) { - struct bt_bap_ep *ep; - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); - int err; - - if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) { - err = unicast_server_cb->disable(stream, &rsp); - } else { - err = -ENOTSUP; - } - - if (err != 0) { - LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason); - return err; - } - - ep = stream->ep; - - /* Set reason in case this exits the streaming state */ - ep->reason = BT_HCI_ERR_LOCALHOST_TERM_CONN; - - /* The ASE state machine goes into different states from this operation - * based on whether it is a source or a sink ASE. - */ - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_DISABLING); - } else { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); - } - - return 0; + return bt_ascs_disable_ase(stream->ep); } int bt_bap_unicast_server_release(struct bt_bap_stream *stream) From abf6fc37d0ce0854c2dea82782ac62e1e6876f60 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 4 Jul 2023 14:12:51 +0200 Subject: [PATCH 1144/2042] Bluetooth: audio: ascs: Remove redundant ase_cleanup function This removes redundant ase_cleanup function, as bt_ascs_release_ase can be called instead. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 5dc93544b1cb..5135a2408539 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -2885,37 +2885,14 @@ int bt_ascs_init(const struct bt_bap_unicast_server_cb *cb) return 0; } -static void ase_cleanup(struct bt_ascs_ase *ase) -{ - struct bt_bap_ascs_rsp rsp; - struct bt_bap_stream *stream; - enum bt_bap_ep_state state; - - state = ascs_ep_get_state(&ase->ep); - if (state == BT_BAP_EP_STATE_IDLE || state == BT_BAP_EP_STATE_RELEASING) { - return; - } - - stream = ase->ep.stream; - __ASSERT(stream != NULL, "ep.stream is NULL"); - - if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) { - unicast_server_cb->release(stream, &rsp); - } - - ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_RELEASING); -} - void bt_ascs_cleanup(void) { for (size_t i = 0; i < ARRAY_SIZE(ase_pool); i++) { struct bt_ascs_ase *ase = &ase_pool[i]; - if (ase->conn == NULL) { - continue; + if (ase->conn != NULL) { + bt_ascs_release_ase(&ase->ep); } - - ase_cleanup(ase); } if (unicast_server_cb != NULL) { From 36f35f8335248b995abf2f083a9ea77b12c4b959 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 5 Jul 2023 14:00:16 +0200 Subject: [PATCH 1145/2042] Bluetooth: audio: ascs: Fix possible ASE leak This fixes possible ASE leak in bt_ascs_config_ase in case ascs_ep_set_codec function returns an error. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 5135a2408539..b4c77b0c84e3 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1468,7 +1468,7 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, const struct bt_audio_codec_qos_pref *qos_pref) { int err; - struct bt_ascs_ase *ase; + struct bt_ascs_ase *ase = NULL; struct bt_bap_ep *ep; struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); @@ -1487,8 +1487,7 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, /* Get a free ASE or NULL if all ASE instances are aready in use */ for (int i = 1; i <= ASE_COUNT; i++) { - ase = ase_find(conn, i); - if (ase == NULL) { + if (ase_find(conn, i) == NULL) { ase = ase_new(conn, i); break; } @@ -1501,14 +1500,10 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, ep = &ase->ep; - if (ep->status.state != BT_BAP_EP_STATE_IDLE) { - LOG_ERR("Invalid state: %s", bt_bap_ep_state_str(ep->status.state)); - return -EBADMSG; - } - err = ascs_ep_set_codec(ep, codec_cfg->id, sys_le16_to_cpu(codec_cfg->cid), sys_le16_to_cpu(codec_cfg->vid), NULL, 0, &rsp); if (err) { + ase_free(ase); return err; } From 2a4acb2c4232f89890456527e0f62167d91ec6d8 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Wed, 21 Jun 2023 17:42:42 -0700 Subject: [PATCH 1146/2042] drivers: spi: mcux_flexcomm: fix chip select bug w/ dma transfers Fix for bug: https://github.com/zephyrproject-rtos/zephyr/issues/59575 The dma version of the version of the driver can invoke multiple intermediate dma transfers, like when the spi_buf_set count is greater than one. However, there is a bug where chip select is not kept asserted for all intermediate dma transfers required to process the entire spi_buf_set. Signed-off-by: Mike J. Chen --- drivers/spi/spi_mcux_flexcomm.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 427704892ce8..3667849c8c35 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -610,6 +610,10 @@ static int transceive_dma(const struct device *dev, while (data->ctx.rx_len > 0 || data->ctx.tx_len > 0) { size_t dma_len; + + /* last is used to deassert chip select if this + * is the last transfer in the set. + */ bool last = false; if (data->ctx.rx_len == 0) { @@ -626,6 +630,34 @@ static int transceive_dma(const struct device *dev, last = false; } + /* at this point, last just means whether or not + * this transfer will completely cover + * the current tx/rx buffer in data->ctx + * or require additional transfers because the + * the two buffers are not the same size. + * + * if it covers the current ctx tx/rx buffers, then + * we'll move to the next pair of buffers (if any) + * after the transfer, but if there are + * no more buffer pairs, then this is the last + * transfer in the set and we need to deassert CS. + */ + if (last) { + /* this dma transfer should cover + * the entire current data->ctx set + * of buffers. if there are more + * buffers in the set, then we don't + * want to deassert CS. + */ + if ((data->ctx.tx_count > 1) || + (data->ctx.rx_count > 1)) { + /* more buffers to transfer so + * this isn't last + */ + last = false; + } + } + data->status_flags = 0; ret = spi_mcux_dma_move_buffers(dev, dma_len, spi_cfg, last); From f4aeafd288b855cb82aed8d3c42aac1702b7bb17 Mon Sep 17 00:00:00 2001 From: David Bongartz Date: Fri, 2 Jun 2023 20:22:51 +0200 Subject: [PATCH 1147/2042] drivers: display: add check for set_orientation API implementation Some drivers do not implement set_orientation(). To prevent crashes, just error out when not implemented. Fixes: #57277 Signed-off-by: David Bongartz --- include/zephyr/drivers/display.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index 7d9a943850ec..a72534b4e50b 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -420,6 +421,10 @@ static inline int display_set_orientation(const struct device *dev, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_orientation == NULL) { + return -ENOSYS; + } + return api->set_orientation(dev, orientation); } From 27e2ec8a95e9de227e1cd1ef599cffed5b8e28b3 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Mon, 12 Dec 2022 15:46:25 +0800 Subject: [PATCH 1148/2042] drivers/i2c: Add callback functions to support buffer mode in header file Add buf_write_received and buf_read_requested callback functions to support buffer mode. Signed-off-by: Tim Lin --- drivers/i2c/target/Kconfig | 6 +++++ include/zephyr/drivers/i2c.h | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/drivers/i2c/target/Kconfig b/drivers/i2c/target/Kconfig index 679bdc98f4d9..6894d12bef44 100644 --- a/drivers/i2c/target/Kconfig +++ b/drivers/i2c/target/Kconfig @@ -19,6 +19,12 @@ config I2C_TARGET_INIT_PRIORITY help I2C Target device driver initialization priority. +config I2C_TARGET_BUFFER_MODE + bool "I2C target driver for buffer mode [EXPERIMENTAL]" + select EXPERIMENTAL + help + This is an option to enable buffer mode. + source "drivers/i2c/target/Kconfig.eeprom" endif # I2C_TARGET diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index ecb1eaa7c21d..ef96c2ee1748 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -352,6 +352,49 @@ typedef int (*i2c_target_read_requested_cb_t)( typedef int (*i2c_target_read_processed_cb_t)( struct i2c_target_config *config, uint8_t *val); +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE +/** @brief Function called when a write to the device is completed. + * + * This function is invoked by the controller when it completes + * reception of data from the source buffer to the destination + * buffer in an ongoing write operation to the device. + * + * @param config the configuration structure associated with the + * device to which the operation is addressed. + * + * @param ptr pointer to the buffer that contains the data to be transferred. + * + * @param len the length of the data to be transferred. + */ +typedef void (*i2c_target_buf_write_received_cb_t)( + struct i2c_target_config *config, uint8_t *ptr, uint32_t len); + +/** @brief Function called when a read from the device is initiated. + * + * This function is invoked by the controller when the bus is ready to + * provide additional data by buffer for a read operation from the address + * associated with the device. + * + * The value returned in @p **ptr and @p *len will be transmitted. A success + * return shall cause the controller to react to additional read operations. + * An error return shall cause the controller to ignore bus operations until + * a new start condition is received. + * + * @param config the configuration structure associated with the + * device to which the operation is addressed. + * + * @param ptr pointer to storage for the address of data buffer to return + * for the read request. + * + * @param len pointer to storage for the length of the data to be transferred + * for the read request. + * + * @return 0 if data has been provided, or a negative error code. + */ +typedef int (*i2c_target_buf_read_requested_cb_t)( + struct i2c_target_config *config, uint8_t **ptr, uint32_t *len); +#endif + /** @brief Function called when a stop condition is observed after a * start condition addressed to a particular device. * @@ -379,6 +422,10 @@ struct i2c_target_callbacks { i2c_target_read_requested_cb_t read_requested; i2c_target_write_received_cb_t write_received; i2c_target_read_processed_cb_t read_processed; +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + i2c_target_buf_write_received_cb_t buf_write_received; + i2c_target_buf_read_requested_cb_t buf_read_requested; +#endif i2c_target_stop_cb_t stop; }; From 42e9dd8fe9e668c08ef9b11ba34dfcb190378b16 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Wed, 31 May 2023 18:39:02 +0800 Subject: [PATCH 1149/2042] drivers/i2c/target/eeprom_target: Add buffer mode callback function Add the callback functions of buf_write_received and buf_read_requested to support buffer mode. Signed-off-by: Tim Lin --- drivers/i2c/target/eeprom_target.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/i2c/target/eeprom_target.c b/drivers/i2c/target/eeprom_target.c index b1fc2c2a0b21..8cef8ea25531 100644 --- a/drivers/i2c/target/eeprom_target.c +++ b/drivers/i2c/target/eeprom_target.c @@ -167,6 +167,32 @@ static int eeprom_target_stop(struct i2c_target_config *config) return 0; } +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE +static void eeprom_target_buf_write_received(struct i2c_target_config *config, + uint8_t *ptr, uint32_t len) +{ + struct i2c_eeprom_target_data *data = CONTAINER_OF(config, + struct i2c_eeprom_target_data, + config); + /* The first byte is offset */ + data->buffer_idx = *ptr; + memcpy(&data->buffer[data->buffer_idx], ptr + 1, len - 1); +} + +static int eeprom_target_buf_read_requested(struct i2c_target_config *config, + uint8_t **ptr, uint32_t *len) +{ + struct i2c_eeprom_target_data *data = CONTAINER_OF(config, + struct i2c_eeprom_target_data, + config); + + *ptr = &data->buffer[data->buffer_idx]; + *len = data->buffer_size; + + return 0; +} +#endif + static int eeprom_target_register(const struct device *dev) { const struct i2c_eeprom_target_config *cfg = dev->config; @@ -193,6 +219,10 @@ static const struct i2c_target_callbacks eeprom_callbacks = { .read_requested = eeprom_target_read_requested, .write_received = eeprom_target_write_received, .read_processed = eeprom_target_read_processed, +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + .buf_write_received = eeprom_target_buf_write_received, + .buf_read_requested = eeprom_target_buf_read_requested, +#endif .stop = eeprom_target_stop, }; From 0960bb3066f4f24972bad6691fce91bce799c53f Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Mon, 29 May 2023 17:25:39 +0800 Subject: [PATCH 1150/2042] ITE: drivers/i2c: Add I2C target driver used buffer mode Add I2C target driver used buffer mode. The maximum accessible buffer is 2044 bytes, the default is 256 bytes. Signed-off-by: Tim Lin --- drivers/i2c/Kconfig.it8xxx2 | 12 + drivers/i2c/i2c_ite_enhance.c | 380 ++++++++++++++++++--- dts/bindings/i2c/ite,enhance-i2c.yaml | 7 + soc/riscv/riscv-ite/common/chip_chipregs.h | 23 +- 4 files changed, 364 insertions(+), 58 deletions(-) diff --git a/drivers/i2c/Kconfig.it8xxx2 b/drivers/i2c/Kconfig.it8xxx2 index 370282a2e71e..149dc23f5e41 100644 --- a/drivers/i2c/Kconfig.it8xxx2 +++ b/drivers/i2c/Kconfig.it8xxx2 @@ -56,3 +56,15 @@ config I2C_CQ_MODE_MAX_PAYLOAD_SIZE up to 2k bytes. endif # I2C_ITE_ENHANCE + +if I2C_TARGET + +config I2C_TARGET_IT8XXX2_MAX_BUF_SIZE + int "It is allowed to configure the size up to 2044 bytes." + range 4 2044 + default 256 + +config I2C_TARGET_BUFFER_MODE + default y + +endif # I2C_TARGET diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index b7d4be20a682..d15b9cb0bf9a 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -71,6 +71,7 @@ struct i2c_enhance_config { const struct pinctrl_dev_config *pcfg; uint8_t prescale_scl_low; uint32_t clock_gate_offset; + bool target_enable; }; enum i2c_pin_fun { @@ -85,6 +86,31 @@ enum i2c_ch_status { I2C_CH_WAIT_NEXT_XFER, }; +#ifdef CONFIG_I2C_IT8XXX2_CQ_MODE +struct i2c_host_cq_buffer { + /* Command queue tx payload. */ + uint8_t i2c_cq_mode_tx_dlm[CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE] __aligned(4); + /* Command queue rx payload. */ + uint8_t i2c_cq_mode_rx_dlm[CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE] __aligned(4); +}; +#endif +#ifdef CONFIG_I2C_TARGET +/* + * When accessing data exceeds the maximum buffer, the actual reload address + * is one byte more than the maximum buffer size. Therefore, it is necessary to + * have a buffer in place to prevent overwriting other memory. + */ +#define PROTECT_MEM_BUF 4 +struct i2c_target_dma_buffer { + /* Target mode DMA output buffer. */ + uint8_t __aligned(4) + out_buffer[CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE + PROTECT_MEM_BUF]; + /* Target mode DMA input buffer. */ + uint8_t __aligned(4) + in_buffer[CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE + PROTECT_MEM_BUF]; +}; +#endif + struct i2c_enhance_data { enum i2c_ch_status i2ccs; struct i2c_msg *active_msg; @@ -107,11 +133,20 @@ struct i2c_enhance_data { #ifdef CONFIG_I2C_IT8XXX2_CQ_MODE /* Store command queue mode messages. */ struct i2c_msg *cq_msgs; - /* Command queue tx payload. */ - uint8_t i2c_cq_mode_tx_dlm[CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE] __aligned(4); - /* Command queue rx payload. */ - uint8_t i2c_cq_mode_rx_dlm[CONFIG_I2C_CQ_MODE_MAX_PAYLOAD_SIZE] __aligned(4); #endif +#ifdef CONFIG_I2C_TARGET + struct i2c_target_config *target_cfg; + uint32_t buffer_size; + bool target_attached; +#endif + union { +#ifdef CONFIG_I2C_IT8XXX2_CQ_MODE + struct i2c_host_cq_buffer host_buffer; +#endif +#ifdef CONFIG_I2C_TARGET + struct i2c_target_dma_buffer target_buffer; +#endif + }; }; enum enhanced_i2c_transfer_direct { @@ -174,6 +209,15 @@ enum i2c_reset_cause { I2C_RC_TIMEOUT, }; +enum enhanced_i2c_target_status { + /* Time out error */ + E_TARGET_TMOE = 0x08, + /* Arbitration lost */ + E_TARGET_ARB = 0x10, + /* Time out or lost arbitration */ + E_TARGET_ANY_ERROR = (E_TARGET_TMOE | E_TARGET_ARB), +}; + static int i2c_parsing_return_value(const struct device *dev) { struct i2c_enhance_data *data = dev->data; @@ -596,17 +640,18 @@ static void enhanced_i2c_set_cmd_addr_regs(const struct device *dev) { const struct i2c_enhance_config *config = dev->config; struct i2c_enhance_data *data = dev->data; + struct i2c_host_cq_buffer *host_buffer = &data->host_buffer; uint32_t dlm_base; uint8_t *base = config->base; /* Set "Address Register" to store the I2C data. */ - dlm_base = (uint32_t)data->i2c_cq_mode_rx_dlm & 0xffffff; + dlm_base = (uint32_t)host_buffer->i2c_cq_mode_rx_dlm & 0xffffff; IT8XXX2_I2C_RAMH2A(base) = (dlm_base >> 16) & 0xff; IT8XXX2_I2C_RAMHA(base) = (dlm_base >> 8) & 0xff; IT8XXX2_I2C_RAMLA(base) = dlm_base & 0xff; /* Set "Command Address Register" to get commands. */ - dlm_base = (uint32_t)data->i2c_cq_mode_tx_dlm & 0xffffff; + dlm_base = (uint32_t)host_buffer->i2c_cq_mode_tx_dlm & 0xffffff; IT8XXX2_I2C_CMD_ADDH2(base) = (dlm_base >> 16) & 0xff; IT8XXX2_I2C_CMD_ADDH(base) = (dlm_base >> 8) & 0xff; IT8XXX2_I2C_CMD_ADDL(base) = dlm_base & 0xff; @@ -615,11 +660,12 @@ static void enhanced_i2c_set_cmd_addr_regs(const struct device *dev) static void enhanced_i2c_cq_write(const struct device *dev) { struct i2c_enhance_data *data = dev->data; + struct i2c_host_cq_buffer *host_buffer = &data->host_buffer; struct i2c_cq_packet *i2c_cq_pckt; uint8_t num_bit_2_0 = (data->cq_msgs[0].len - 1) & I2C_CQ_CMD_L_NUM_BIT_2_0; uint8_t num_bit_10_3 = ((data->cq_msgs[0].len - 1) >> 3) & 0xff; - i2c_cq_pckt = (struct i2c_cq_packet *)data->i2c_cq_mode_tx_dlm; + i2c_cq_pckt = (struct i2c_cq_packet *)host_buffer->i2c_cq_mode_tx_dlm; /* Set commands in RAM. */ i2c_cq_pckt->id = data->addr_16bit << 1; i2c_cq_pckt->cmd_l = I2C_CQ_CMD_L_P | I2C_CQ_CMD_L_E | num_bit_2_0; @@ -632,11 +678,12 @@ static void enhanced_i2c_cq_write(const struct device *dev) static void enhanced_i2c_cq_read(const struct device *dev) { struct i2c_enhance_data *data = dev->data; + struct i2c_host_cq_buffer *host_buffer = &data->host_buffer; struct i2c_cq_packet *i2c_cq_pckt; uint8_t num_bit_2_0 = (data->cq_msgs[0].len - 1) & I2C_CQ_CMD_L_NUM_BIT_2_0; uint8_t num_bit_10_3 = ((data->cq_msgs[0].len - 1) >> 3) & 0xff; - i2c_cq_pckt = (struct i2c_cq_packet *)data->i2c_cq_mode_tx_dlm; + i2c_cq_pckt = (struct i2c_cq_packet *)host_buffer->i2c_cq_mode_tx_dlm; /* Set commands in RAM. */ i2c_cq_pckt->id = data->addr_16bit << 1; i2c_cq_pckt->cmd_l = I2C_CQ_CMD_L_RW | I2C_CQ_CMD_L_P | @@ -647,12 +694,13 @@ static void enhanced_i2c_cq_read(const struct device *dev) static void enhanced_i2c_cq_write_to_read(const struct device *dev) { struct i2c_enhance_data *data = dev->data; + struct i2c_host_cq_buffer *host_buffer = &data->host_buffer; struct i2c_cq_packet *i2c_cq_pckt; uint8_t num_bit_2_0 = (data->cq_msgs[0].len - 1) & I2C_CQ_CMD_L_NUM_BIT_2_0; uint8_t num_bit_10_3 = ((data->cq_msgs[0].len - 1) >> 3) & 0xff; int i; - i2c_cq_pckt = (struct i2c_cq_packet *)data->i2c_cq_mode_tx_dlm; + i2c_cq_pckt = (struct i2c_cq_packet *)host_buffer->i2c_cq_mode_tx_dlm; /* Set commands in RAM. (command byte for write) */ i2c_cq_pckt->id = data->addr_16bit << 1; i2c_cq_pckt->cmd_l = num_bit_2_0; @@ -672,6 +720,7 @@ static void enhanced_i2c_cq_write_to_read(const struct device *dev) static int enhanced_i2c_cq_isr(const struct device *dev) { struct i2c_enhance_data *data = dev->data; + struct i2c_host_cq_buffer *host_buffer = &data->host_buffer; const struct i2c_enhance_config *config = dev->config; uint8_t *base = config->base; @@ -682,7 +731,7 @@ static int enhanced_i2c_cq_isr(const struct device *dev) /* Get data if this is a read transaction. */ for (int i = 0; i < data->cq_msgs[msgs_idx].len; i++) { data->cq_msgs[msgs_idx].buf[i] = - data->i2c_cq_mode_rx_dlm[i]; + host_buffer->i2c_cq_mode_rx_dlm[i]; } } else { /* Device 1 error have occurred. eg. nack, timeout... */ @@ -856,6 +905,12 @@ static int i2c_enhance_transfer(const struct device *dev, struct i2c_enhance_data *data = dev->data; int ret; +#ifdef CONFIG_I2C_TARGET + if (data->target_attached) { + LOG_ERR("Device is registered as target"); + return -EBUSY; + } +#endif /* Lock mutex of i2c controller */ k_mutex_lock(&data->mutex, K_FOREVER); @@ -899,29 +954,115 @@ static int i2c_enhance_transfer(const struct device *dev, return ret; } +#ifdef CONFIG_I2C_TARGET +static void target_i2c_isr(const struct device *dev) +{ + struct i2c_enhance_data *data = dev->data; + struct i2c_target_dma_buffer *target_buffer = &data->target_buffer; + const struct i2c_enhance_config *config = dev->config; + const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; + uint8_t *base = config->base; + uint8_t target_status = IT8XXX2_I2C_STR(base); + + /* Any error */ + if (target_status & E_TARGET_ANY_ERROR) { + /* Hardware reset */ + IT8XXX2_I2C_CTR(base) |= IT8XXX2_I2C_HALT; + /* Interrupt pending */ + } else if (target_status & IT8XXX2_I2C_INT_PEND) { + uint8_t interrupt_status = IT8XXX2_I2C_IRQ_ST(base); + + /* Byte counter enable */ + if (interrupt_status & IT8XXX2_I2C_IDW_CLR) { + IT8XXX2_I2C_BYTE_CNT_L(base) |= + (IT8XXX2_I2C_DMA_ADDR_RELOAD | + IT8XXX2_I2C_BYTE_CNT_ENABLE); + } + /* The number of received data exceeds the byte counter setting */ + if (interrupt_status & IT8XXX2_I2C_CNT_HOLD) { + LOG_ERR("The excess data written starts " + "from the memory address:%p", + target_buffer->in_buffer + + CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE); + } + /* Controller to write data */ + if (interrupt_status & IT8XXX2_I2C_SLVDATAFLG) { + /* Number of receive data in target mode */ + data->buffer_size = + ((IT8XXX2_I2C_SLV_NUM_H(base) << 8) | + IT8XXX2_I2C_SLV_NUM_L(base)) + 1; + + /* Write data done callback function */ + target_cb->buf_write_received(data->target_cfg, + target_buffer->in_buffer, data->buffer_size); + } + /* Controller to read data */ + if (interrupt_status & IT8XXX2_I2C_IDR_CLR) { + uint32_t len; + uint8_t *rdata = NULL; + + /* Clear byte counter setting */ + IT8XXX2_I2C_BYTE_CNT_L(base) &= + ~(IT8XXX2_I2C_DMA_ADDR_RELOAD | + IT8XXX2_I2C_BYTE_CNT_ENABLE); + /* Read data callback function */ + target_cb->buf_read_requested(data->target_cfg, + &rdata, &len); + + if (len > CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE) { + LOG_ERR("The bufffer size exceeds " + "I2C_TARGET_IT8XXX2_MAX_BUF_SIZE: len=%d", + len); + } else { + memcpy(target_buffer->out_buffer, rdata, len); + } + } + /* Peripheral finish */ + if (interrupt_status & IT8XXX2_I2C_P_CLR) { + /* Transfer done callback function */ + target_cb->stop(data->target_cfg); + /* Hardware reset */ + IT8XXX2_I2C_CTR(base) |= IT8XXX2_I2C_HALT; + } + /* Write clear the peripheral status */ + IT8XXX2_I2C_IRQ_ST(base) = interrupt_status; + } + /* Write clear the target status */ + IT8XXX2_I2C_STR(base) = target_status; +} +#endif + static void i2c_enhance_isr(void *arg) { struct device *dev = (struct device *)arg; struct i2c_enhance_data *data = dev->data; const struct i2c_enhance_config *config = dev->config; +#ifdef CONFIG_I2C_TARGET + if (data->target_attached) { + target_i2c_isr(dev); + } else { +#endif #ifdef CONFIG_I2C_IT8XXX2_CQ_MODE - uint8_t *base = config->base; + uint8_t *base = config->base; - /* If done doing work, wake up the task waiting for the transfer */ - if (IT8XXX2_I2C_CTR1(base) & IT8XXX2_I2C_COMQ_EN) { - if (enhanced_i2c_cq_isr(dev)) { - return; - } - } else + /* If done doing work, wake up the task waiting for the transfer */ + if (IT8XXX2_I2C_CTR1(base) & IT8XXX2_I2C_COMQ_EN) { + if (enhanced_i2c_cq_isr(dev)) { + return; + } + } else #endif - { - if (i2c_transaction(dev)) { - return; + { + if (i2c_transaction(dev)) { + return; + } } + irq_disable(config->i2c_irq_base); + k_sem_give(&data->device_sync_sem); +#ifdef CONFIG_I2C_TARGET } - irq_disable(config->i2c_irq_base); - k_sem_give(&data->device_sync_sem); +#endif } static int i2c_enhance_init(const struct device *dev) @@ -932,47 +1073,53 @@ static int i2c_enhance_init(const struct device *dev) uint32_t bitrate_cfg; int error, status; - /* Initialize mutex and semaphore */ - k_mutex_init(&data->mutex); - k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); - - /* Enable clock to specified peripheral */ - volatile uint8_t *reg = (volatile uint8_t *) - (IT8XXX2_ECPM_BASE + (config->clock_gate_offset >> 8)); - uint8_t reg_mask = config->clock_gate_offset & 0xff; - *reg &= ~reg_mask; - - /* Enable I2C function */ - /* Software reset */ - IT8XXX2_I2C_DHTR(base) |= IT8XXX2_I2C_SOFT_RST; - IT8XXX2_I2C_DHTR(base) &= ~IT8XXX2_I2C_SOFT_RST; - /* reset i2c port */ - i2c_reset(dev); - /* bit1, Module enable */ - IT8XXX2_I2C_CTR1(base) = 0; +#ifdef CONFIG_I2C_TARGET + if (!config->target_enable) { +#endif + /* Initialize mutex and semaphore */ + k_mutex_init(&data->mutex); + k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); + + /* Enable clock to specified peripheral */ + volatile uint8_t *reg = (volatile uint8_t *) + (IT8XXX2_ECPM_BASE + (config->clock_gate_offset >> 8)); + uint8_t reg_mask = config->clock_gate_offset & 0xff; + *reg &= ~reg_mask; + + /* Enable I2C function */ + /* Software reset */ + IT8XXX2_I2C_DHTR(base) |= IT8XXX2_I2C_SOFT_RST; + IT8XXX2_I2C_DHTR(base) &= ~IT8XXX2_I2C_SOFT_RST; + /* reset i2c port */ + i2c_reset(dev); + /* bit1, Module enable */ + IT8XXX2_I2C_CTR1(base) = 0; #ifdef CONFIG_I2C_IT8XXX2_CQ_MODE - /* Set command address registers. */ - enhanced_i2c_set_cmd_addr_regs(dev); + /* Set command address registers. */ + enhanced_i2c_set_cmd_addr_regs(dev); #endif - /* Set clock frequency for I2C ports */ - if (config->bitrate == I2C_BITRATE_STANDARD || - config->bitrate == I2C_BITRATE_FAST || - config->bitrate == I2C_BITRATE_FAST_PLUS) { - bitrate_cfg = i2c_map_dt_bitrate(config->bitrate); - } else { - /* Device tree specified speed */ - bitrate_cfg = I2C_SPEED_DT << I2C_SPEED_SHIFT; - } + /* Set clock frequency for I2C ports */ + if (config->bitrate == I2C_BITRATE_STANDARD || + config->bitrate == I2C_BITRATE_FAST || + config->bitrate == I2C_BITRATE_FAST_PLUS) { + bitrate_cfg = i2c_map_dt_bitrate(config->bitrate); + } else { + /* Device tree specified speed */ + bitrate_cfg = I2C_SPEED_DT << I2C_SPEED_SHIFT; + } - error = i2c_enhance_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); - data->i2ccs = I2C_CH_NORMAL; + error = i2c_enhance_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); + data->i2ccs = I2C_CH_NORMAL; - if (error) { - LOG_ERR("i2c: failure initializing"); - return error; + if (error) { + LOG_ERR("i2c: failure initializing"); + return error; + } +#ifdef CONFIG_I2C_TARGET } +#endif /* Set the pin to I2C alternate function. */ status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); @@ -1047,13 +1194,133 @@ static int i2c_enhance_recover_bus(const struct device *dev) return 0; } +#ifdef CONFIG_I2C_TARGET +static int i2c_enhance_target_register(const struct device *dev, + struct i2c_target_config *target_cfg) +{ + const struct i2c_enhance_config *config = dev->config; + struct i2c_enhance_data *data = dev->data; + struct i2c_target_dma_buffer *target_buffer = &data->target_buffer; + uint32_t in_data_addr, out_data_addr; + uint8_t *base = config->base; + + if (!target_cfg) { + return -EINVAL; + } + + if (target_cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) { + return -ENOTSUP; + } + + if (data->target_attached) { + return -EBUSY; + } + + data->target_cfg = target_cfg; + data->target_attached = true; + + /* Software reset */ + IT8XXX2_I2C_DHTR(base) |= IT8XXX2_I2C_SOFT_RST; + IT8XXX2_I2C_DHTR(base) &= ~IT8XXX2_I2C_SOFT_RST; + /* + * Set time out register. + * I2C D/E/F clock/data low timeout. + */ + IT8XXX2_I2C_TOR(base) = I2C_CLK_LOW_TIMEOUT; + /* Bit stretching */ + IT8XXX2_I2C_TOS(base) |= IT8XXX2_I2C_CLK_STRETCH; + /* Peripheral address(8-bit) */ + IT8XXX2_I2C_IDR(base) = target_cfg->address << 1; + /* I2C interrupt enable and set acknowledge */ + IT8XXX2_I2C_CTR(base) = IT8XXX2_I2C_INT_EN | IT8XXX2_I2C_HALT | + IT8XXX2_I2C_ACK; + /* Interrupt status write clear */ + IT8XXX2_I2C_IRQ_ST(base) = 0xff; + + /* Clear read and write data buffer of DMA */ + memset(target_buffer->in_buffer, 0, CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE); + memset(target_buffer->out_buffer, 0, CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE); + + in_data_addr = (uint32_t)target_buffer->in_buffer & 0xffffff; + out_data_addr = (uint32_t)target_buffer->out_buffer & 0xffffff; + /* + * DMA write target address register + * for high order byte + */ + IT8XXX2_I2C_RAMH2A(base) = in_data_addr >> 16; + IT8XXX2_I2C_RAMHA(base) = in_data_addr >> 8; + IT8XXX2_I2C_RAMLA(base) = in_data_addr; + /* + * DMA read target address register + * for high order byte + */ + IT8XXX2_I2C_CMD_ADDH2(base) = out_data_addr >> 16; + IT8XXX2_I2C_RAMHA2(base) = out_data_addr >> 8; + IT8XXX2_I2C_RAMLA2(base) = out_data_addr; + + /* Byte counter setting */ + /* This register indicates byte count[10:3]. */ + IT8XXX2_I2C_BYTE_CNT_H(base) = CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE >> 3; + /* This register indicates byte count[2:0]. */ + IT8XXX2_I2C_BYTE_CNT_L(base) = CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE & + GENMASK(2, 0); + + /* + * The EC processor(CPU) cannot be in the k_cpu_idle() and power + * policy during the transactions with the CQ mode(DMA mode). + * Otherwise, the EC processor would be clock gated. + */ + chip_block_idle(); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + + /* I2C module enable and command queue mode */ + IT8XXX2_I2C_CTR1(base) = IT8XXX2_I2C_COMQ_EN | IT8XXX2_I2C_MDL_EN; + + ite_intc_isr_clear(config->i2c_irq_base); + irq_enable(config->i2c_irq_base); + + return 0; +} + +static int i2c_enhance_target_unregister(const struct device *dev, + struct i2c_target_config *cfg) +{ + const struct i2c_enhance_config *config = dev->config; + struct i2c_enhance_data *data = dev->data; + + if (!data->target_attached) { + return -EINVAL; + } + + irq_disable(config->i2c_irq_base); + + /* Permit to enter power policy and idle mode. */ + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + chip_permit_idle(); + + data->target_cfg = NULL; + data->target_attached = false; + + return 0; +} +#endif + static const struct i2c_driver_api i2c_enhance_driver_api = { .configure = i2c_enhance_configure, .get_config = i2c_enhance_get_config, .transfer = i2c_enhance_transfer, .recover_bus = i2c_enhance_recover_bus, +#ifdef CONFIG_I2C_TARGET + .target_register = i2c_enhance_target_register, + .target_unregister = i2c_enhance_target_unregister, +#endif }; +#ifdef CONFIG_I2C_TARGET +BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE), + "When I2C target config is enabled, the buffer mode must be used."); +#endif + #define I2C_ITE_ENHANCE_INIT(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \ @@ -1077,6 +1344,7 @@ static const struct i2c_driver_api i2c_enhance_driver_api = { .prescale_scl_low = DT_INST_PROP_OR(inst, prescale_scl_low, 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), \ }; \ \ static struct i2c_enhance_data i2c_enhance_data_##inst; \ diff --git a/dts/bindings/i2c/ite,enhance-i2c.yaml b/dts/bindings/i2c/ite,enhance-i2c.yaml index c9f0adf19861..98e3e4ec46b5 100644 --- a/dts/bindings/i2c/ite,enhance-i2c.yaml +++ b/dts/bindings/i2c/ite,enhance-i2c.yaml @@ -17,3 +17,10 @@ properties: The resulting SCL cycle time is given by the following formula: SCL cycle = 2 * (psr + prescale_tweak + 2) * SMBus clock cycle + + target-enable: + type: boolean + description: | + This option is used when the I2C target is enabled. It is + necessary to prevent the target port from being configured + with I2C host related initialization. diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index 39588f48cdf1..78ac458e4915 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -1244,10 +1244,13 @@ enum chip_pll_mode { #define IT8XXX2_I2C_DTR(base) ECREG(base + 0x08) #define IT8XXX2_I2C_CTR(base) ECREG(base + 0x09) #define IT8XXX2_I2C_CTR1(base) ECREG(base + 0x0A) +#define IT8XXX2_I2C_BYTE_CNT_H(base) ECREG(base + 0x0B) #define IT8XXX2_I2C_BYTE_CNT_L(base) ECREG(base + 0x0C) #define IT8XXX2_I2C_IRQ_ST(base) ECREG(base + 0x0D) #define IT8XXX2_I2C_IDR(base) ECREG(base + 0x06) #define IT8XXX2_I2C_TOS(base) ECREG(base + 0x07) +#define IT8XXX2_I2C_SLV_NUM_H(base) ECREG(base + 0x10) +#define IT8XXX2_I2C_SLV_NUM_L(base) ECREG(base + 0x11) #define IT8XXX2_I2C_STR2(base) ECREG(base + 0x12) #define IT8XXX2_I2C_NST(base) ECREG(base + 0x13) #define IT8XXX2_I2C_TO_ARB_ST(base) ECREG(base + 0x18) @@ -1259,8 +1262,8 @@ enum chip_pll_mode { #define IT8XXX2_I2C_CTR2(base) ECREG(base + 0x20) #define IT8XXX2_I2C_RAMHA(base) ECREG(base + 0x23) #define IT8XXX2_I2C_RAMLA(base) ECREG(base + 0x24) -#define IT8XXX2_I2C_RAMHA2(base) ECREG(base + 0x2B) -#define IT8XXX2_I2C_RAMLA2(base) ECREG(base + 0x2C) +#define IT8XXX2_I2C_RAMHA2(base) ECREG(base + 0x2C) +#define IT8XXX2_I2C_RAMLA2(base) ECREG(base + 0x2D) #define IT8XXX2_I2C_CMD_ADDH(base) ECREG(base + 0x25) #define IT8XXX2_I2C_CMD_ADDL(base) ECREG(base + 0x26) #define IT8XXX2_I2C_RAMH2A(base) ECREG(base + 0x50) @@ -1313,14 +1316,30 @@ enum chip_pll_mode { #define IT8XXX2_SMB_SMHEN BIT(0) /* 0x55: Slave A FIFO Control */ #define IT8XXX2_SMB_HSAPE BIT(1) +/* 0x03: Status Register */ +#define IT8XXX2_I2C_INT_PEND BIT(1) /* 0x04: Data Hold Time */ #define IT8XXX2_I2C_SOFT_RST BIT(7) /* 0x07: Time Out Status */ +#define IT8XXX2_I2C_CLK_STRETCH BIT(7) #define IT8XXX2_I2C_SCL_IN BIT(2) #define IT8XXX2_I2C_SDA_IN BIT(0) +/* 0x09: Control Register */ +#define IT8XXX2_I2C_INT_EN BIT(6) +#define IT8XXX2_I2C_ACK BIT(3) +#define IT8XXX2_I2C_HALT BIT(0) /* 0x0A: Control 1 */ #define IT8XXX2_I2C_COMQ_EN BIT(7) #define IT8XXX2_I2C_MDL_EN BIT(1) +/* 0x0C: Byte count */ +#define IT8XXX2_I2C_DMA_ADDR_RELOAD BIT(5) +#define IT8XXX2_I2C_BYTE_CNT_ENABLE BIT(3) +/* 0x0D: Interrupt Status */ +#define IT8XXX2_I2C_CNT_HOLD BIT(4) +#define IT8XXX2_I2C_IDW_CLR BIT(3) +#define IT8XXX2_I2C_IDR_CLR BIT(2) +#define IT8XXX2_I2C_SLVDATAFLG BIT(1) +#define IT8XXX2_I2C_P_CLR BIT(0) /* 0x13: Nack Status */ #define IT8XXX2_I2C_NST_CNS BIT(7) #define IT8XXX2_I2C_NST_ID_NACK BIT(3) From cc5c141fb19a66b2d957fe3d188720fb7f664c98 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Fri, 2 Jun 2023 11:19:08 +0800 Subject: [PATCH 1151/2042] test: drivers: i2c_target_api: Add I2C target mode support for it8xxx2 Add I2C target mode support for it8xxx2 I2C driver. Verified with i2c_target_api test on it8xxx2_evb. Signed-off-by: Tim Lin --- .../i2c_target_api/boards/it8xxx2_evb.conf | 1 + .../i2c_target_api/boards/it8xxx2_evb.overlay | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.conf b/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.conf new file mode 100644 index 000000000000..70e009fae68a --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.conf @@ -0,0 +1 @@ +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.overlay b/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.overlay new file mode 100644 index 000000000000..bfcf2d392652 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/it8xxx2_evb.overlay @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 ITE Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c4 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c4_clk_gpe0_default + &i2c4_data_gpe7_default>; + pinctrl-names = "default"; + + eeprom1: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <256>; + }; +}; + +&i2c5 { + status = "okay"; + pinctrl-0 = <&i2c5_clk_gpa4_default + &i2c5_data_gpa5_default>; + pinctrl-names = "default"; + + target-enable; + eeprom0: eeprom@52 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x52>; + size = <256>; + }; +}; From b7f9fb8f829126b27992fe4cfe6c582e13a2709c Mon Sep 17 00:00:00 2001 From: Alvaro Garcia Date: Tue, 13 Jun 2023 14:12:10 +0200 Subject: [PATCH 1152/2042] drivers: added support for clock PCF8563 Added driver support Signed-off-by: Alvaro Garcia --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.pcf8563 | 12 + drivers/rtc/rtc_pcf8563.c | 478 ++++++++++++++++++++++++++++++ dts/bindings/rtc/nxp,pcf8563.yaml | 19 ++ 5 files changed, 511 insertions(+) create mode 100644 drivers/rtc/Kconfig.pcf8563 create mode 100644 drivers/rtc/rtc_pcf8563.c create mode 100644 dts/bindings/rtc/nxp,pcf8563.yaml diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 6272b12a41e9..267347fc664c 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -8,4 +8,5 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) zephyr_library_sources_ifdef(CONFIG_RTC_EMUL rtc_emul.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) +zephyr_library_sources_ifdef(CONFIG_RTC_PCF8563 rtc_pcf8563.c) zephyr_library_sources_ifdef(CONFIG_RTC_MOTOROLA_MC146818 rtc_mc146818.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a2f39c0b60fe..25e135438bcc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -37,6 +37,7 @@ config RTC_CALIBRATION source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.pcf8523" +source "drivers/rtc/Kconfig.pcf8563" source "drivers/rtc/Kconfig.mc146818" endif # RTC diff --git a/drivers/rtc/Kconfig.pcf8563 b/drivers/rtc/Kconfig.pcf8563 new file mode 100644 index 000000000000..00005a4a68be --- /dev/null +++ b/drivers/rtc/Kconfig.pcf8563 @@ -0,0 +1,12 @@ +# NXP PCF8523 RTC + +# Copyright (c) 2023 Alvaro Garcia Gomez +# SPDX-License-Identifier: Apache-2.0 + +config RTC_PCF8563 + bool "NXP PCF8563 RTC driver" + default y + depends on DT_HAS_NXP_PCF8563_ENABLED + select I2C + help + Enable the NXP PCF8563 RTC driver. diff --git a/drivers/rtc/rtc_pcf8563.c b/drivers/rtc/rtc_pcf8563.c new file mode 100644 index 000000000000..4b16707dee8e --- /dev/null +++ b/drivers/rtc/rtc_pcf8563.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2023 Alvaro Garcia Gomez + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(pcf8563); + +#define DT_DRV_COMPAT nxp_pcf8563 + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int1_gpios) && \ + (defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE)) +/* The user may need only alarms but not interrupts so we will only + * include all the interrupt code if the user configured it in the dts + */ +#define PCF8563_INT1_GPIOS_IN_USE 1 +#endif + +/* The device registers */ +#define PCF8563_TIME_DATE_REGISTER 0x02 +#define PCF8563_ALARM_REGISTER 0x09 +#define PCF8563_CONTROL1_REGISTER 0x00 +#define PCF8563_CONTROL2_REGISTER 0x01 +#define PCF8563_CONTROL2_REGISTER_TIE_EN (1 << 0) +#define PCF8563_CONTROL2_REGISTER_AIE_EN (1 << 1) + +/* These masks were retrieved from the datasheet + * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf + * page 6, section 8.2 Register organization. + * Basically, I clean the unused bits and the bits used + * for other stuff + */ +#define PCF8563_SECONDS_MASK GENMASK(6, 0) +#define PCF8563_MINUTES_MASK GENMASK(6, 0) +#define PCF8563_HOURS_MASK GENMASK(5, 0) +#define PCF8563_DAYS_MASK GENMASK(5, 0) +#define PCF8563_WEEKDAYS_MASK GENMASK(2, 0) +#define PCF8563_MONTHS_MASK GENMASK(4, 0) + + +/* RTC alarm time fields supported by the PCF8563, page 7 of the datasheet */ +#define PCF8563_RTC_ALARM_TIME_MASK \ + (RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY | \ + RTC_ALARM_TIME_MASK_WEEKDAY) + +struct pcf8563_config { + const struct i2c_dt_spec i2c; + #ifdef PCF8563_INT1_GPIOS_IN_USE + const struct gpio_dt_spec int1; + #endif +}; + + +#ifdef PCF8563_INT1_GPIOS_IN_USE +/* This work will run the user callback function */ +void callback_work_handler(struct k_work *work); +K_WORK_DEFINE(callback_work, callback_work_handler); +#endif + +struct pcf8563_data { +#ifdef PCF8563_INT1_GPIOS_IN_USE + rtc_alarm_callback alarm_callback; + void *alarm_user_data; + const struct device *dev; + struct gpio_callback int1_callback; + struct k_work callback_work; +#endif +}; + +/** + * The format described below is described in the datasheet + * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf page 10 starting + * with 8.4.2 Register Minutes. + * + * For seconds, first bit is ignored (it is used to check the clock integrity). + * The the upper digit takes the next 3 bits for the tens place and then the rest + * bits for the unit + * So for example, value 43 is 40 * 10 + 3, so the tens digit is 4 and unit digit is 3. + * Then we put the number 3 in the last 4 bits and the number 4 in next 3 bits + * It uses BCD notation so the number 3 is 0011 and the number for is 100 so the final + * byte is 0 (ignored bit) 100 (the 4) 0011 (the 3) -> 0100001 + * Luckily, zephyr provides a couple of functions to do exactlly this: bin2bcd and bcd2bin, + * but we will take care about the bits marked as non used in + * the datasheet because they may contain unexpected values. Applying a mask will help us + * to sanitize the read values + */ +int pcf8563_set_time(const struct device *dev, const struct rtc_time *new_time) +{ + const struct pcf8563_config *config = dev->config; + int ret = 0; + uint8_t raw_time[7] = {0}; + + /* Set seconds */ + raw_time[0] = bin2bcd(new_time->tm_sec); + + /* Set minutes */ + raw_time[1] = bin2bcd(new_time->tm_min); + + /* Set hours */ + raw_time[2] = bin2bcd(new_time->tm_hour); + + /* Set days */ + raw_time[3] = bin2bcd(new_time->tm_mday); + + /* Set weekdays */ + raw_time[4] = new_time->tm_wday; + + /*Set month */ + raw_time[5] = bin2bcd(new_time->tm_mon); + + /* Set year */ + raw_time[6] = bin2bcd(new_time->tm_year); + + /* Write to device */ + ret = i2c_burst_write_dt(&config->i2c, PCF8563_TIME_DATE_REGISTER, + raw_time, sizeof(raw_time)); + if (ret) { + LOG_ERR("Error when setting time: %i", ret); + return ret; + } + + return 0; +} + +int pcf8563_get_time(const struct device *dev, struct rtc_time *dest_time) +{ + const struct pcf8563_config *config = dev->config; + int ret = 0; + uint8_t raw_time[7] = {0}; + + ret = i2c_burst_read_dt(&config->i2c, PCF8563_TIME_DATE_REGISTER, + raw_time, sizeof(raw_time)); + if (ret) { + LOG_ERR("Unable to get time. Err: %i", ret); + return ret; + } + + /* Check integrity, if the first bit is 1 it is ok */ + if (raw_time[0] & BIT(7)) { + LOG_WRN("Clock integrity failed"); + return -ENODATA; + } + + /* Nanoseconds */ + dest_time->tm_nsec = 0; + + /* Get seconds */ + dest_time->tm_sec = bcd2bin(raw_time[0] & PCF8563_SECONDS_MASK); + + /* Get minutes */ + dest_time->tm_min = bcd2bin(raw_time[1] & PCF8563_MINUTES_MASK); + + /* Get hours */ + dest_time->tm_hour = bcd2bin(raw_time[2] & PCF8563_HOURS_MASK); + + /* Get days */ + dest_time->tm_mday = bcd2bin(raw_time[3] & PCF8563_DAYS_MASK); + + /* Get weekdays */ + dest_time->tm_wday = raw_time[4] & PCF8563_WEEKDAYS_MASK; + + /* Get month */ + dest_time->tm_mon = bcd2bin(raw_time[5] & PCF8563_MONTHS_MASK); + + /* Get year */ + dest_time->tm_year = bcd2bin(raw_time[6]); + + /* Day number not used */ + dest_time->tm_yday = -1; + + /* DST not used */ + dest_time->tm_isdst = -1; + + return 0; +} + + + +#ifdef CONFIG_RTC_ALARM + +static int pcf8563_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + ARG_UNUSED(dev); + + /* This device only has one channel*/ + if (id != 0) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + *mask = PCF8563_RTC_ALARM_TIME_MASK; + + return 0; +} + +static int pcf8563_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + const struct pcf8563_config *config = dev->config; + uint8_t regs[4]; + int ret; + + if (id != 0) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + if ((mask & ~(PCF8563_RTC_ALARM_TIME_MASK)) != 0) { + LOG_ERR("invalid alarm field mask 0x%04x", mask); + return -EINVAL; + } + + /* + * The first bit is used as enabled/disabled flag. + * The mask will clean it and also the unused bits + */ + if ((mask & RTC_ALARM_TIME_MASK_MINUTE) != 0) { + regs[0] = bin2bcd(timeptr->tm_min) & PCF8563_MINUTES_MASK; + } else { + /* First bit to 1 is alarm disabled */ + regs[0] = BIT(7); + } + + if ((mask & RTC_ALARM_TIME_MASK_HOUR) != 0) { + regs[1] = bin2bcd(timeptr->tm_hour) & PCF8563_HOURS_MASK; + } else { + regs[1] = BIT(7); + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) != 0) { + regs[2] = bin2bcd(timeptr->tm_mday) & PCF8563_DAYS_MASK; + } else { + regs[2] = BIT(7); + } + + if ((mask & RTC_ALARM_TIME_MASK_WEEKDAY) != 0) { + regs[3] = bin2bcd(timeptr->tm_wday) & PCF8563_WEEKDAYS_MASK; + } else { + regs[3] = BIT(7); + } + + ret = i2c_burst_write_dt(&config->i2c, PCF8563_ALARM_REGISTER, regs, sizeof(regs)); + if (ret) { + LOG_ERR("Error when setting alarm: %i", ret); + return ret; + } + + /* Dont forget to enable interrupts */ + i2c_reg_write_byte_dt( + &config->i2c, + PCF8563_CONTROL2_REGISTER, + PCF8563_CONTROL2_REGISTER_TIE_EN | PCF8563_CONTROL2_REGISTER_AIE_EN + ); + + return 0; +} + +static int pcf8563_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + const struct pcf8563_config *config = dev->config; + uint8_t regs[4]; + int err; + + if (id != 0) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + err = i2c_burst_read_dt(&config->i2c, PCF8563_ALARM_REGISTER, regs, sizeof(regs)); + if (err) { + LOG_ERR("Error when getting alarm time: %i", err); + return err; + } + + /* Initialize data structure and mask */ + memset(timeptr, 0U, sizeof(*timeptr)); + *mask = 0U; + + /* The first bit is the enabled flag */ + if (regs[0] & BIT(7)) { + timeptr->tm_min = bcd2bin(regs[0] & GENMASK(6, 0)); + *mask |= RTC_ALARM_TIME_MASK_MINUTE; + } + + if (regs[1] & BIT(7)) { + timeptr->tm_hour = bcd2bin(regs[1] & GENMASK(5, 0)); + *mask |= RTC_ALARM_TIME_MASK_HOUR; + } + + if (regs[2] & BIT(7)) { + timeptr->tm_mday = bcd2bin(regs[2] & GENMASK(5, 0)); + *mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + } + + if (regs[3] & BIT(7)) { + timeptr->tm_wday = bcd2bin(regs[3] & GENMASK(2, 0)); + *mask |= RTC_ALARM_TIME_MASK_WEEKDAY; + } + + return 0; +} + +static int pcf8563_alarm_is_pending(const struct device *dev, uint16_t id) +{ + /* The description of this register is at page 7, section 8.3.2 Register Control_status_2 + * There are several kinds of alarms, but here we only need to know that anything but 0 + * means that there was some kind of alarm active + */ + const struct pcf8563_config *config = dev->config; + uint8_t reg; + int err; + + if (id != 0) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + err = i2c_reg_read_byte_dt(&config->i2c, PCF8563_CONTROL2_REGISTER, ®); + if (err) { + LOG_ERR("Error when getting the control register 2: %i", err); + return err; + } + + /* Only the last bits use useful here */ + if (reg & GENMASK(3, 2)) { + /* Clean the alarm */ + err = i2c_reg_write_byte_dt(&config->i2c, PCF8563_CONTROL2_REGISTER, GENMASK(1, 0)); + if (err) { + LOG_ERR("Error when clearing alarms: %d", err); + return err; + } + /* There was an alarm */ + return 1; + } + /* No alarms */ + return 0; +} +#endif + +#ifdef PCF8563_INT1_GPIOS_IN_USE +/* The logic related to the pin interrupt logic */ + +void callback_work_handler(struct k_work *work) +{ + /* This function is run as a work so the user can spend here all the necessary time */ + struct pcf8563_data *data = CONTAINER_OF(work, struct pcf8563_data, callback_work); + + if (data->alarm_callback == NULL) { + LOG_WRN("No PCF8563 alarm callback function provided"); + } else { + data->alarm_callback(data->dev, 0, data->alarm_user_data); + } +} + + +/* The function called when the clock alarm activates the interrupt*/ +void gpio_callback_function(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct pcf8563_data *data = CONTAINER_OF(cb, struct pcf8563_data, int1_callback); + + LOG_DBG("PCF8563 interrupt detected"); + /* By using a work we are able to to run "heavier" code */ + k_work_submit(&(data->callback_work)); + +} + +static int pcf8563_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + const struct pcf8563_config *config = dev->config; + struct pcf8563_data *data = dev->data; + int ret; + + if (id != 0) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + data->alarm_callback = callback; + data->alarm_user_data = user_data; + data->dev = dev; + + /* The PCF8563 int pin requires a pull up to work */ + ret = gpio_pin_configure_dt(&config->int1, GPIO_INPUT | GPIO_PULL_UP); + if (ret < 0) { + LOG_ERR("Error %d: failed to configure %s pin %d", + ret, config->int1.port->name, config->int1.pin); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->int1, GPIO_INT_EDGE_FALLING); + if (ret < 0) { + LOG_ERR("Error %d: failed to configure interrupt on %s pin %d", + ret, config->int1.port->name, config->int1.pin); + return ret; + } + + + gpio_init_callback(&data->int1_callback, gpio_callback_function, BIT(config->int1.pin)); + gpio_add_callback(config->int1.port, &data->int1_callback); + LOG_DBG("Alarm set"); + return 0; +} +#endif + +static const struct rtc_driver_api pcf8563_driver_api = { + .set_time = pcf8563_set_time, + .get_time = pcf8563_get_time, +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = pcf8563_alarm_get_supported_fields, + .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 +}; + + +int pcf8563_init(const struct device *dev) +{ + const struct pcf8563_config *config = dev->config; + int ret; + uint8_t reg; + #ifdef PCF8563_INT1_GPIOS_IN_USE + struct pcf8563_data *data = dev->data; + + data->callback_work = callback_work; + #endif + + if (!device_is_ready(config->i2c.bus)) { + LOG_ERR("Failed to get pointer to %s device!", config->i2c.bus->name); + return -EINVAL; + } + + /* Check if it's alive. */ + ret = i2c_reg_read_byte_dt(&config->i2c, PCF8563_CONTROL1_REGISTER, ®); + if (ret) { + LOG_ERR("Failed to read from PCF85063! (err %i)", ret); + return -EIO; + } + + LOG_INF("%s is initialized!", dev->name); + + return 0; +} + +#define PCF8563_INIT(inst) \ + static const struct pcf8563_config pcf8563_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + IF_ENABLED(PCF8563_INT1_GPIOS_IN_USE, \ + (.int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, {0}))) \ + }; \ + \ + static struct pcf8563_data pcf8563_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &pcf8563_init, NULL, \ + &pcf8563_data_##inst, &pcf8563_config_##inst, POST_KERNEL, \ + CONFIG_RTC_INIT_PRIORITY, &pcf8563_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PCF8563_INIT) diff --git a/dts/bindings/rtc/nxp,pcf8563.yaml b/dts/bindings/rtc/nxp,pcf8563.yaml new file mode 100644 index 000000000000..95ca4a793a4b --- /dev/null +++ b/dts/bindings/rtc/nxp,pcf8563.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Alvaro Garcia Gomez +# SPDX-License-Identifier: Apache-2.0 + +description: NXP PCF8563 RTC + +compatible: "nxp,pcf8563" + +include: + - name: rtc-device.yaml + - name: i2c-device.yaml + - name: pm.yaml + property-allowlist: + - wakeup-source + +properties: + int1-gpios: + type: phandle-array + description: | + GPIO connected to the PC8563 INT1 interrupt output. This signal is open-drain, active low. From 618a71c1970a992ec7d5e310207086e6c23594a1 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 6 Mar 2023 11:22:40 -0600 Subject: [PATCH 1153/2042] boards: shields: add rk055hdmipi4m shield definition Add rk055hdmipi4m shield definition. This shield contains a 1080x720 display driven by an RM68200 IC, with a GT911 touch controller. The display is supported by a 40 pin FFC connector present on NXP's RT1170 and RT595 EVKs. Signed-off-by: Daniel DeGrasse --- .../shields/rk055hdmipi4m/Kconfig.defconfig | 53 +++++++++++ boards/shields/rk055hdmipi4m/Kconfig.shield | 5 ++ .../boards/mimxrt595_evk_cm33.conf | 13 +++ .../boards/mimxrt595_evk_cm33.overlay | 18 ++++ boards/shields/rk055hdmipi4m/doc/index.rst | 68 ++++++++++++++ .../rk055hdmipi4m/rk055hdmipi4m.overlay | 88 +++++++++++++++++++ 6 files changed, 245 insertions(+) create mode 100644 boards/shields/rk055hdmipi4m/Kconfig.defconfig create mode 100644 boards/shields/rk055hdmipi4m/Kconfig.shield create mode 100644 boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf create mode 100644 boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay create mode 100644 boards/shields/rk055hdmipi4m/doc/index.rst create mode 100644 boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay diff --git a/boards/shields/rk055hdmipi4m/Kconfig.defconfig b/boards/shields/rk055hdmipi4m/Kconfig.defconfig new file mode 100644 index 000000000000..4a95cdbd9655 --- /dev/null +++ b/boards/shields/rk055hdmipi4m/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_RK055HDMIPI4M + +if DISPLAY + +# Enable MIPI DSI, as this display controller requires it. + +config MIPI_DSI + default y + +endif # DISPLAY + +if LVGL + +# Configure LVGL to use touchscreen with KSCAN API + +config KSCAN + default y + +config KSCAN_GT911_INTERRUPT + default y + +config LV_Z_POINTER_KSCAN + default y + +# LVGL should allocate buffers equal to size of display +config LV_Z_VDB_SIZE + default 100 + +# Enable double buffering +config LV_Z_DOUBLE_VDB + default y + +# Force full refresh. This prevents memory copy associated with partial +# display refreshes, which is not necessary for the eLCDIF driver +config LV_Z_FULL_REFRESH + default y + +config LV_Z_BITS_PER_PIXEL + default 16 + +config LV_DPI_DEF + default 128 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 +endchoice + +endif # LVGL + +endif # SHIELD_RK055HDMIPI4M diff --git a/boards/shields/rk055hdmipi4m/Kconfig.shield b/boards/shields/rk055hdmipi4m/Kconfig.shield new file mode 100644 index 000000000000..1556c0cee7ab --- /dev/null +++ b/boards/shields/rk055hdmipi4m/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_RK055HDMIPI4M + def_bool $(shields_list_contains,rk055hdmipi4m) diff --git a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf new file mode 100644 index 000000000000..68157838ef52 --- /dev/null +++ b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf @@ -0,0 +1,13 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Use external framebuffer memory +CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM=y +# Use FlexSPI2 for framebuffer (pSRAM is present on this bus) +CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_ADDR=0x38400000 +# M33 core and LCDIF both access FlexSPI2 through the same cache, +# so coherency does not need to be managed. +CONFIG_MCUX_DCNANO_LCDIF_MAINTAIN_CACHE=n diff --git a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 000000000000..40a3b02036fa --- /dev/null +++ b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Configure FlexSPI2 to use 1KB of AHB RX buffer for GPU/Display master. + * This will improve performance when using external pSRAM. + */ +&flexspi2 { + rx-buffer-config = <1 7 11 1024>; +}; + +/* GT911 IRQ GPIO is active low on this board */ +&touch_controller { + irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; +}; diff --git a/boards/shields/rk055hdmipi4m/doc/index.rst b/boards/shields/rk055hdmipi4m/doc/index.rst new file mode 100644 index 000000000000..03b50e31f065 --- /dev/null +++ b/boards/shields/rk055hdmipi4m/doc/index.rst @@ -0,0 +1,68 @@ +.. _rk055hdmipi4m: + +RK055HDMIPI4M MIPI Display +########################## + +Overview +******** + +The Rocktech RK055HDMIPI4M MIPI Display is a 5.5 inch TFT 720x1280 pixels +panel with LED backlighting, full viewing angle, MIPI interface and +capacitive touch panel from Rocktech. + +More information about the shield can be found +at the `RK055HDMIPI4M product page`_. + +This display uses a 40 pin FPC interface, which is available on many +NXP EVKs. + +Pins Assignment of the Rocktech RK055HDMIPI4M MIPI Display +========================================================== + ++-----------------------+------------------------+ +| FPC Connector Pin | Function | ++=======================+========================+ +| 1 | LED backlight cathode | ++-----------------------+------------------------+ +| 21 | Controller reset | ++-----------------------+------------------------+ +| 22 | Controller LPTE | ++-----------------------+------------------------+ +| 26 | Touch ctrl I2C SDA | ++-----------------------+------------------------+ +| 27 | Touch ctrl I2C SCL | ++-----------------------+------------------------+ +| 28 | Touch ctrl reset | ++-----------------------+------------------------+ +| 29 | Touch ctrl interrupt | ++-----------------------+------------------------+ +| 32 | LCD power enable | ++-----------------------+------------------------+ +| 34 | Backlight power enable | ++-----------------------+------------------------+ + +Requirements +************ + +This shield can only be used with a board which provides a configuration +for the 40 pin FPC interface + +Programming +*********** + +Set ``-DSHIELD=rk055hdmipi4m`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/display + :board: mixmrt1170_evk_cm7 + :shield: rk055hdmipi4m + :goals: build + +References +********** + +.. target-notes:: + +.. _RK055HDMIPI4M product page: + https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/5-5-lcd-panel:RK055HDMIPI4M diff --git a/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay new file mode 100644 index 000000000000..709048f8b734 --- /dev/null +++ b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay @@ -0,0 +1,88 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/{ + aliases { + kscan0 = &touch_controller; + }; + + chosen { + zephyr,display = &lcdif; + zephyr,keyboard-scan = &touch_controller; + }; + + en_mipi_display: enable-mipi-display { + compatible = "regulator-fixed"; + regulator-name = "en_mipi_display"; + enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; +}; + +&nxp_mipi_i2c { + status = "okay"; + touch_controller: gt911@5d { + compatible = "goodix,gt911"; + reg = <0x5d>; + irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_HIGH>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + }; +}; + +&zephyr_lcdif { + status = "okay"; + width = <720>; + height = <1280>; + display-timings { + compatible = "zephyr,panel-timing"; + hsync-len = <8>; + hfront-porch = <32>; + hback-porch = <32>; + vsync-len = <2>; + vfront-porch = <16>; + vback-porch = <14>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + /* + * Pixel clock is given by the following formula: + * (height + vsync-len + vfront-porch + vback-porch) * + * (width + hsync-len + hfront-porch + hback-porch) * frame rate + */ + clock-frequency = <62346240>; + }; + pixel-format = ; + data-bus-width = "24-bit"; + backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; +}; + +&zephyr_mipi_dsi { + status = "okay"; + nxp,lcdif = <&lcdif>; + dpi-color-coding = "24-bit"; + dpi-pixel-packet = "24-bit"; + dpi-video-mode = "burst"; + dpi-bllp-mode = "low-power"; + autoinsert-eotp; + /* + * PHY clock is given by the following formula: + * (pixel clock * bits per pixel) / MIPI data lanes + */ + phy-clock = <748154880>; + rm68200@0 { + status = "okay"; + compatible = "raydium,rm68200"; + reg = <0x0>; + reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; + data-lanes = <2>; + width = <720>; + height = <1280>; + pixel-format = ; + }; +}; From a8c2ec005b06022f2384be2ca536f0de6c4c0323 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 6 Mar 2023 11:24:35 -0600 Subject: [PATCH 1154/2042] boards: arm: mimxrt1170_evk: remove RK055HDMIPI4M display definition Remove display definition from RT1170 EVK, as this can now be handled via a shield. Add gpio nexus defining GPIO routing to the FFC connector. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/Kconfig.defconfig | 50 ---------- boards/arm/mimxrt1170_evk/doc/index.rst | 3 +- .../arm/mimxrt1170_evk/mimxrt1170_evk_cm7.dts | 94 +++++-------------- 3 files changed, 27 insertions(+), 120 deletions(-) diff --git a/boards/arm/mimxrt1170_evk/Kconfig.defconfig b/boards/arm/mimxrt1170_evk/Kconfig.defconfig index 00d7f158ce61..ed3de4d0d3a7 100644 --- a/boards/arm/mimxrt1170_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1170_evk/Kconfig.defconfig @@ -49,16 +49,6 @@ endchoice endif #FLASH -config KSCAN - default y if LVGL - -if KSCAN - -config KSCAN_GT911_INTERRUPT - default y - -endif # KSCAN - if NETWORKING config NET_L2_ETHERNET @@ -69,44 +59,4 @@ config ETH_MCUX_PHY_RESET endif # NETWORKING -if DISPLAY - -config MIPI_DSI - default y - -config REGULATOR - default y - -endif # DISPLAY - -if LVGL - -config LV_Z_POINTER_KSCAN - default y - -# LVGL should allocate buffers equal to size of display -config LV_Z_VDB_SIZE - default 100 - -# Enable double buffering -config LV_Z_DOUBLE_VDB - default y - -# Force full refresh. This prevents memory copy associated with partial -# display refreshes, which is not necessary for the eLCDIF driver -config LV_Z_FULL_REFRESH - default y - -config LV_Z_BITS_PER_PIXEL - default 16 - -config LV_DPI_DEF - default 128 - -choice LV_COLOR_DEPTH - default LV_COLOR_DEPTH_16 -endchoice - -endif # LVGL - endif diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 4483f35ea901..033f2d823bc0 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -130,7 +130,8 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) +-----------+------------+-------------------------------------+-----------------+-----------------+ | HWINFO | on-chip | Unique device serial number | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ -| DISPLAY | on-chip | display | Supported (M7) | Supported (M7) | +| DISPLAY | on-chip | eLCDIF; MIPI-DSI. Tested with | Supported (M7) | Supported (M7) | +| | | :ref:`rk055hdmipi4m` shield | | | +-----------+------------+-------------------------------------+-----------------+-----------------+ | ACMP | on-chip | analog comparator | Supported | No support | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7.dts index fee8e7dafe50..6de99062d8e3 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk_cm7.dts @@ -8,7 +8,6 @@ #include #include "mimxrt1170_evk.dtsi" -#include / { model = "NXP MIMXRT1170-EVK board"; @@ -17,7 +16,6 @@ aliases { mipi-dsi = &mipi_dsi; watchdog0 = &wdog1; - kscan0 = &touch_controller; }; chosen { @@ -30,8 +28,6 @@ zephyr,flash-controller = &is25wp128; zephyr,flash = &is25wp128; zephyr,code-partition = &slot0_partition; - zephyr,display = &lcdif; - zephyr,keyboard-scan = &touch_controller; zephyr,cpu1-region = &ocram; zephyr,ipc = &mailbox_a; }; @@ -42,67 +38,33 @@ reg = <0x80000000 DT_SIZE_M(64)>; }; - en_mipi_display: enable-mipi-display { - compatible = "regulator-fixed"; - regulator-name = "en_mipi_display"; - enable-gpios = <&gpio11 16 GPIO_ACTIVE_HIGH>; - regulator-boot-on; + /* + * This node describes the GPIO pins of the MIPI FPC interface, + * J48 on the EVK. This interface is standard to several + * NXP EVKs, and is used with several MIPI displays + * (available as zephyr shields) + */ + nxp_mipi_connector: mipi-connector { + compatible = "gpio-nexus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio9 29 0>, /* Pin 1, LEDK */ + <21 0 &gpio9 1 0>, /* Pin 21, RESET */ + <22 0 &gpio9 4 0>, /* Pin 22, LPTE */ + <26 0 &gpio6 4 0>, /* Pin 26, CTP_I2C SDA */ + <27 0 &gpio6 5 0>, /* Pin 27, CTP_I2C SCL */ + <28 0 &gpio9 0 0>, /* Pin 28, CTP_RST */ + <29 0 &gpio2 31 0>, /* Pin 29, CTP_INT */ + <32 0 &gpio11 16 0>, /* Pin 32, PWR_EN */ + <34 0 &gpio9 29 0>; /* Pin 34, BL_PWM */ }; }; -&lcdif { - status = "okay"; - pixel-format = ; - data-bus-width = "24-bit"; - backlight-gpios = <&gpio9 29 GPIO_ACTIVE_HIGH>; - width = <720>; - height = <1280>; - - display-timings { - compatible = "zephyr,panel-timing"; - hsync-len = <8>; - hfront-porch = <32>; - hback-porch = <32>; - vsync-len = <2>; - vfront-porch = <16>; - vback-porch = <14>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <0>; - /* - * Pixel clock is given by the following formula: - * (height + vsync-len + vfront-porch + vback-porch) * - * (width + hsync-len + hfront-porch + hback-porch) * frame rate - */ - clock-frequency = <62346240>; - }; -}; +zephyr_lcdif: &lcdif {}; -&mipi_dsi { - status = "okay"; - nxp,lcdif = <&lcdif>; - dpi-color-coding = "24-bit"; - dpi-pixel-packet = "24-bit"; - dpi-video-mode = "burst"; - dpi-bllp-mode = "low-power"; - autoinsert-eotp; +zephyr_mipi_dsi: &mipi_dsi { dphy-ref-frequency = <24000000>; - /* - * PHY clock is given by the following formula: - * (pixel clock * bits per pixel) / MIPI data lanes - */ - phy-clock = <748154880>; - rm68200@0 { - status = "okay"; - compatible = "raydium,rm68200"; - reg = <0x0>; - reset-gpios = <&gpio9 1 GPIO_ACTIVE_HIGH>; - data-lanes = <2>; - width = <720>; - height = <1280>; - pixel-format = ; - }; }; &lpuart1 { @@ -123,17 +85,11 @@ status = "okay"; }; -&lpi2c5 { - status = "okay"; +nxp_mipi_i2c: &lpi2c5 { pinctrl-0 = <&pinmux_lpi2c5>; pinctrl-names = "default"; - - touch_controller: gt911@5d { - compatible = "goodix,gt911"; - reg = <0x5d>; - irq-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio9 0 GPIO_ACTIVE_HIGH>; - }; + #address-cells = <1>; + #size-cells = <0>; }; &lpadc0 { From 933c9f4351f7398e922620060548a85b7d21ccec Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 6 Mar 2023 16:38:25 -0600 Subject: [PATCH 1155/2042] boards: arm: mimxrt595_evk: remove RK055HDMIPI4M display definition Remove display definition from RT595 EVK, as this is now supported by the shield. Add gpio nexus for the FFC connector on this EVK. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt595_evk/Kconfig.defconfig | 74 ++------------ boards/arm/mimxrt595_evk/doc/index.rst | 8 +- .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 98 ++++++------------- samples/drivers/display/sample.yaml | 1 + 4 files changed, 41 insertions(+), 140 deletions(-) diff --git a/boards/arm/mimxrt595_evk/Kconfig.defconfig b/boards/arm/mimxrt595_evk/Kconfig.defconfig index 6cc3f949607f..fa01c5ac93fc 100644 --- a/boards/arm/mimxrt595_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt595_evk/Kconfig.defconfig @@ -19,75 +19,19 @@ config FXOS8700_DRDY_INT1 default y depends on FXOS8700_TRIGGER -if DISPLAY - -# Enable MIPI display driver - -config MIPI_DSI - default y - -# Use external framebuffer memory for the LCDIF framebuffer -config MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM - default y -# Use FlexSPI2 base address for framebuffer (pSRAM is present on this bus) -config MCUX_DCNANO_LCDIF_EXTERNAL_FB_ADDR - # Move DCNANO framebuffer if LVGL framebuffers are also in PSRAM - default 0x38400000 if LV_Z_VBD_CUSTOM_SECTION - default 0x38000000 -# M33 core and LCDIF both access FlexSPI2 through the same cache, -# so coherency does not need to be managed. -config MCUX_DCNANO_LCDIF_MAINTAIN_CACHE - depends on !MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM - -endif # DISPLAY - -config KSCAN - default y if LVGL - -if LVGL - -# LVGL should allocate buffers equal to size of display -config LV_Z_VDB_SIZE - default 100 - -# Enable double buffering -config LV_Z_DOUBLE_VDB - default y - -# Force full refresh. This prevents memory copy associated with partial -# display refreshes, which is not necessary for the eLCDIF driver -config LV_Z_FULL_REFRESH - default y - -config LV_DPI_DEF - default 128 - -config LV_Z_BITS_PER_PIXEL - default 16 - -# Force display buffers to be aligned for DCNANO LCDIF (128 byte alignment) -config LV_Z_VDB_ALIGN - default 128 - -# LVGL display buffers will be too large for internal SRAM, locate in -# custom section within PSRAM +# Allocate LVGL buffers in custom section config LV_Z_VBD_CUSTOM_SECTION - default y - -config LV_Z_POINTER_KSCAN - default y - -config LV_Z_VDB_SIZE - default 16 + default y if LVGL -config LV_DPI_DEF - default 128 +if DMA_MCUX_LPC -choice LV_COLOR_DEPTH - default LV_COLOR_DEPTH_16 -endchoice +# 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 + default 4096 -endif # LVGL +endif # DMA_MCUX_LPC if PM # Turn on Device Level Power Management as we wish diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index c98333523be1..c5c215b41bd9 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -107,9 +107,8 @@ already supported, which can also be re-used on this mimxrt595_evk board: +-----------+------------+-------------------------------------+ | I2S | on-chip | i2s | +-----------+------------+-------------------------------------+ -| DISPLAY | on-chip | LCDIF; MIPI-DSI. Tested with RM68200| -| | | based MIPI display | -| | | (`RK055HDMIPI4M`_) | +| DISPLAY | on-chip | LCDIF; MIPI-DSI. Tested with | +| | | :ref:`rk055hdmipi4m` shield | +-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: @@ -303,6 +302,3 @@ steps: .. _i.MX RT595 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT500RM - -.. _RK055HDMIPI4M: - https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/5-5-lcd-panel:RK055HDMIPI4M diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index 25b6c6050371..2d8802c996b5 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -10,7 +10,6 @@ #include "mimxrt595_evk_cm33-pinctrl.dtsi" -#include / { model = "NXP MIMXRT595-EVK board"; @@ -27,7 +26,6 @@ magn0 = &fxos8700; accel0 = &fxos8700; sdhc0 = &usdhc0; - kscan0 = &touch_controller; pwm-0 = &sc_timer; }; @@ -39,7 +37,6 @@ zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,display = &lcdif; - zephyr,keyboard-scan = &touch_controller; }; gpio_keys { @@ -99,6 +96,28 @@ <21 0 &gpio4 21 0>; /* D15 */ }; + /* + * This node describes the GPIO pins of the MIPI FPC interface, + * J44 on the EVK. This interface is standard to several + * NXP EVKs, and is used with several MIPI displays + * (available as zephyr shields) + */ + nxp_mipi_connector: mipi-connector { + compatible = "gpio-nexus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 12 0>, /* Pin 1, LEDK */ + <21 0 &gpio3 21 0>, /* Pin 21, RESET */ + <22 0 &gpio3 18 0>, /* Pin 22, LPTE */ + <26 0 &gpio0 30 0>, /* Pin 26, CTP_I2C SDA */ + <27 0 &gpio0 29 0>, /* Pin 27, CTP_I2C SCL */ + <28 0 &gpio4 4 0>, /* Pin 28, CTP_RST */ + <29 0 &gpio3 19 0>, /* Pin 29, CTP_INT */ + <32 0 &gpio3 15 0>, /* Pin 32, PWR_EN */ + <34 0 &gpio0 12 0>; /* Pin 34, BL_PWM */ + }; + power-states { /* This is the setting Sleep Mode */ idle: idle { @@ -156,60 +175,6 @@ status = "okay"; }; -&lcdif { - status = "okay"; - width = <720>; - height = <1280>; - display-timings { - compatible = "zephyr,panel-timing"; - hsync-len = <8>; - hfront-porch = <32>; - hback-porch = <32>; - vsync-len = <2>; - vfront-porch = <16>; - vback-porch = <14>; - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - /* - * Pixel clock is given by the following formula: - * (height + vsync-len + vfront-porch + vback-porch) * - * (width + hsync-len + hfront-porch + hback-porch) * frame rate - */ - clock-frequency = <62346240>; - }; - backlight-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; - data-bus-width = "24-bit"; - pixel-format = ; -}; - -&mipi_dsi { - status = "okay"; - nxp,lcdif = <&lcdif>; - dpi-color-coding = "24-bit"; - dpi-pixel-packet = "24-bit"; - dpi-video-mode = "burst"; - dpi-bllp-mode = "low-power"; - autoinsert-eotp; - /* - * PHY clock is given by the following formula: - * (pixel clock * bits per pixel) / MIPI data lanes - */ - phy-clock = <748154880>; - - rm68200@0 { - status = "okay"; - compatible = "raydium,rm68200"; - reg = <0x0>; - reset-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; - data-lanes = <2>; - width = <720>; - height = <1280>; - pixel-format = ; - }; -}; - &flexcomm0 { compatible = "nxp,lpc-usart"; status = "okay"; @@ -235,15 +200,15 @@ arduino_i2c: &flexcomm4 { int1-gpios = <&gpio0 22 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; }; - - touch_controller: gt911@5d { - compatible = "goodix,gt911"; - reg = <0x5d>; - irq-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; - reset-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>; - }; }; +nxp_mipi_i2c: &arduino_i2c {}; + +zephyr_mipi_dsi: &mipi_dsi {}; + +zephyr_lcdif: &lcdif {}; + + hs_spi1: &hs_lspi1 { compatible = "nxp,lpc-spi"; pinctrl-0 = <&pinmux_flexcomm16_spi>; @@ -495,10 +460,6 @@ zephyr_udc0: &usbhs { }; }; -/* - * Configure FlexSPI2 to use 1KB of AHB RX buffer for GPU/Display master. - * This will improve performance when using external pSRAM with the LCDIF. - */ &flexspi2 { status = "okay"; pinctrl-0 = <&pinmux_flexspi2>; @@ -508,7 +469,6 @@ zephyr_udc0: &usbhs { ahb-bufferable; ahb-cacheable; ahb-read-addr-opt; - rx-buffer-config = <1 7 11 1024>; aps6408l: aps6408l@0 { compatible = "nxp,imx-flexspi-aps6408l"; /* APS6408L is 8MB, 64MBit pSRAM */ diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index aaa229355e3f..f2cc9d0a89d4 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -98,6 +98,7 @@ tests: platform_allow: mimxrt595_evk_cm33 tags: display harness: console + extra_args: SHIELD=rk055hdmipi4m harness_config: fixture: fixture_display sample.display.sdl: From 158feb641a25ce3f7a17019e952073bdcc63b175 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 6 Mar 2023 16:58:35 -0600 Subject: [PATCH 1156/2042] samples: drivers: kscan: enable logging, and add RK055HDMIPI4M shield Enable logging by default in kscan sample, so that user will see output even if they do not have a keyboard connected that follows the keymap. Add a specific testcase for boards that support the RK055HDMIPI4M display. Signed-off-by: Daniel DeGrasse --- samples/drivers/kscan/prj.conf | 2 +- samples/drivers/kscan/sample.yaml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/samples/drivers/kscan/prj.conf b/samples/drivers/kscan/prj.conf index 2d22a5d071dc..e55038ab5586 100644 --- a/samples/drivers/kscan/prj.conf +++ b/samples/drivers/kscan/prj.conf @@ -1,4 +1,4 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_PRINTK=y CONFIG_KSCAN=y - +CONFIG_LOG=y diff --git a/samples/drivers/kscan/sample.yaml b/samples/drivers/kscan/sample.yaml index 4fffd7bcdc58..be0ea2e485a0 100644 --- a/samples/drivers/kscan/sample.yaml +++ b/samples/drivers/kscan/sample.yaml @@ -13,3 +13,16 @@ tests: - "kb data(.*)" fixture: fixture_connect_keyboard depends_on: kscan + filter: dt_chosen_enabled("zephyr,keyboard-scan") + sample.drivers.kscan.rk055hdmipi4m: + tags: drivers kscan + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "kb data(.*)" + fixture: fixture_connect_rk055hdmipi4m + depends_on: kscan + extra_args: SHIELD="rk055hdmipi4m" + platform_allow: mimxrt1170_evk_cm7 mimxrt595_evk_cm33 From 40849e4efce2e7312657fb968027b93a3759d808 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Mon, 6 Mar 2023 17:07:58 -0600 Subject: [PATCH 1157/2042] tests: drivers: kscan: add RK055HDMIPI4M shield Add a specific testcase for boards that support the RK055HDMIPI4M display. Signed-off-by: Daniel DeGrasse --- tests/drivers/kscan/kscan_api/testcase.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/drivers/kscan/kscan_api/testcase.yaml b/tests/drivers/kscan/kscan_api/testcase.yaml index 3b9b6f50438d..a4b390f73452 100644 --- a/tests/drivers/kscan/kscan_api/testcase.yaml +++ b/tests/drivers/kscan/kscan_api/testcase.yaml @@ -6,6 +6,7 @@ tests: - userspace depends_on: kscan platform_exclude: mec15xxevb_assy6853 + filter: dt_alias_exists("kscan0") drivers.kscan.mec15xxevb_assy6853: depends_on: kscan tags: @@ -13,3 +14,8 @@ tests: - kscan extra_args: CONF_FILE="mec15xxevb_assy6853.conf" platform_allow: mec15xxevb_assy6853 + drivers.kscan.rk055hdmipi4m: + tags: drivers kscan userspace + depends_on: kscan + extra_args: SHIELD="rk055hdmipi4m" + platform_allow: mimxrt1170_evk_cm7 mimxrt595_evk_cm33 From 4774a02b3b60f4e6be366d923600b090bc909894 Mon Sep 17 00:00:00 2001 From: Dong Wang Date: Wed, 21 Jun 2023 11:34:47 +0800 Subject: [PATCH 1158/2042] arch/x86: add more arch dcache functions Adapt to the reworked zephyr cache API. Fix build errors when building tests/kernel/cache with CACHE_MANAGEMENT and CPU_HAS_DCACHE enabled for x86 SoCs Signed-off-by: Dong Wang --- arch/x86/core/cache.c | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/x86/core/cache.c b/arch/x86/core/cache.c index 28a028ecd746..cd0bbb8e16d4 100644 --- a/arch/x86/core/cache.c +++ b/arch/x86/core/cache.c @@ -18,6 +18,58 @@ #include #include +static inline void z_x86_wbinvd(void) +{ + __asm__ volatile("wbinvd;\n\t" : : : "memory"); +} + +void arch_dcache_enable(void) +{ + uint32_t cr0; + + /* 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)); +} + +void arch_dcache_disable(void) +{ + uint32_t cr0; + + /* 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)); + + /* Flush all caches */ + z_x86_wbinvd(); +} + +int arch_dcache_flush_all(void) +{ + z_x86_wbinvd(); + + return 0; +} + +int arch_dcache_invd_all(void) +{ + z_x86_wbinvd(); + + return 0; +} + +int arch_dcache_flush_and_invd_all(void) +{ + z_x86_wbinvd(); + + return 0; +} + /** * No alignment is required for either or , but since * sys_cache_flush() iterates on the cache lines, a cache line alignment for @@ -49,3 +101,13 @@ int arch_dcache_flush_range(void *start_addr, size_t size) #endif return 0; } + +int arch_dcache_invd_range(void *start_addr, size_t size) +{ + return arch_dcache_flush_range(start_addr, size); +} + +int arch_dcache_flush_and_invd_range(void *start_addr, size_t size) +{ + return arch_dcache_flush_range(start_addr, size); +} From 8a686cac53ac88c74de80256dfc68d2ed310bfb7 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 23 Jun 2023 11:20:19 -0500 Subject: [PATCH 1159/2042] docs: flash_debug: host_tools: Fix reference to jlink host tools Fix reference to JLink host tools to be located in correct section, so that output documentation fills in the correct header name when this section is referenced. Signed-off-by: Daniel DeGrasse --- doc/develop/flash_debug/host-tools.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index 7eb6f6804cb1..1d0b915f5635 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -14,7 +14,6 @@ more information on these commands. .. _atmel_sam_ba_bootloader: - SAM Boot Assistant (SAM-BA) *************************** @@ -182,10 +181,9 @@ As a quick reference, see these three board documentation pages: - :ref:`arduino_nano_33_iot` (Arduino bootloader) - :ref:`arduino_nano_33_ble` (Arduino legacy bootloader) -.. _jlink-debug-host-tools: - Enabling BOSSAC on Windows Native [Experimental] ------------------------------------------------ + Zephyr SDK´s bossac is only currenty support on Linux and macOS. Windows support can be achieved by using the bossac version from `BOSSA oficial releases`_. After installing using default options, the :file:`bossac.exe` must be added to @@ -200,6 +198,9 @@ Windows PATH. A specific bossac executable can be used by passing the WSL is not currently supported. + +.. _jlink-debug-host-tools: + J-Link Debug Host Tools *********************** From 4e83af0dd9a7eb87b228bcf171318e02ddb9570e Mon Sep 17 00:00:00 2001 From: Alperen Sener Date: Tue, 4 Jul 2023 16:57:42 +0200 Subject: [PATCH 1160/2042] Bluetooth: Mesh: Fix OOB info and URI hash in scan report message OOB information should be in little endian in scan report messages. URI hash should be retrieved as it is from unprovisioned device beacon and encoded likewise into scan report messages like we do for UUID. Signed-off-by: Alperen Sener --- subsys/bluetooth/mesh/rpr_cli.c | 4 ++-- subsys/bluetooth/mesh/rpr_srv.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/mesh/rpr_cli.c b/subsys/bluetooth/mesh/rpr_cli.c index 0bf6df54d3eb..3ebd3afcd6a1 100644 --- a/subsys/bluetooth/mesh/rpr_cli.c +++ b/subsys/bluetooth/mesh/rpr_cli.c @@ -290,9 +290,9 @@ static int handle_scan_report(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx dev.rssi = net_buf_simple_pull_u8(buf); memcpy(dev.uuid, net_buf_simple_pull_mem(buf, 16), 16); - dev.oob = net_buf_simple_pull_be16(buf); + dev.oob = net_buf_simple_pull_le16(buf); if (buf->len == 4) { - dev.hash = net_buf_simple_pull_be32(buf); + memcpy(&dev.hash, net_buf_simple_pull_mem(buf, 4), 4); dev.flags = BT_MESH_RPR_UNPROV_HASH; } else if (buf->len) { return -EINVAL; diff --git a/subsys/bluetooth/mesh/rpr_srv.c b/subsys/bluetooth/mesh/rpr_srv.c index 5b66ac441c42..51da876824fa 100644 --- a/subsys/bluetooth/mesh/rpr_srv.c +++ b/subsys/bluetooth/mesh/rpr_srv.c @@ -237,9 +237,9 @@ static void scan_report_send(void) bt_mesh_model_msg_init(&buf, RPR_OP_SCAN_REPORT); net_buf_simple_add_u8(&buf, dev->rssi); net_buf_simple_add_mem(&buf, dev->uuid, 16); - net_buf_simple_add_be16(&buf, dev->oob); + net_buf_simple_add_le16(&buf, dev->oob); if (dev->flags & BT_MESH_RPR_UNPROV_HASH) { - net_buf_simple_add_be32(&buf, dev->hash); + net_buf_simple_add_mem(&buf, &dev->hash, 4); } atomic_set_bit(srv.flags, SCAN_REPORT_PENDING); @@ -1066,7 +1066,7 @@ adv_handle_beacon(const struct bt_le_scan_recv_info *info, dev->rssi = info->rssi; if (ad->data_len == 23) { - dev->hash = sys_get_le32(&ad->data[19]); + memcpy(&dev->hash, &ad->data[19], 4); dev->flags |= BT_MESH_RPR_UNPROV_HASH; } From 75cfa344814d130adebc42572a404b668f6d1b6d Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Mon, 10 Jul 2023 16:45:08 +0800 Subject: [PATCH 1161/2042] Bluetooth: Mesh: Discard iv update 1 0 --> 1 1 According spec, for the same iv index, iv update flag should trans to false, when iv update procedure complete. When local environment has attack-node to store old network beacon(1,1), and re-send same network beacon(1,1) after 192hours, will cause whole bluetooth mesh network broke. Signed-off-by: Lingao Meng --- subsys/bluetooth/mesh/net.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 94b2acfdbbab..3f1aedef0437 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -278,6 +278,12 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } + /* Discard [iv, false] --> [iv, true] */ + if (iv_index == bt_mesh.iv_index && iv_update) { + LOG_DBG("Ignore previous IV update procedure"); + return false; + } + if ((iv_index > bt_mesh.iv_index + 1) || (iv_index == bt_mesh.iv_index + 1 && (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) || !iv_update))) { From c16647d02ad75cc42d0053a91703ccdabde997fe Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 11 Jul 2023 11:01:11 +0800 Subject: [PATCH 1162/2042] tests: bluetooth: Add iv[1 0 --> 1 1] test cast Add testcast for 1, 1 --> 1, 0 Signed-off-by: Lingao Meng --- tests/bsim/bluetooth/mesh/src/test_iv_index.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/bsim/bluetooth/mesh/src/test_iv_index.c b/tests/bsim/bluetooth/mesh/src/test_iv_index.c index 466f0fb7b56b..276e7220c537 100644 --- a/tests/bsim/bluetooth/mesh/src/test_iv_index.c +++ b/tests/bsim/bluetooth/mesh/src/test_iv_index.c @@ -111,6 +111,9 @@ static void test_ivu_normal(void) ASSERT_EQUAL(TEST_IV_IDX, bt_mesh.iv_index); ASSERT_EQUAL(0, bt_mesh.seq); + /* Ignore same iv index but iv in progress */ + ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_PROGRESS)); + bt_mesh.seq = 100; /* update before minimum duration */ ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 1, BCN_IV_IN_PROGRESS)); From 5d75940ae3b987bee78ce2fd7538d6c20ef90080 Mon Sep 17 00:00:00 2001 From: Tim-Marek Thomas Date: Tue, 11 Jul 2023 13:39:33 +0200 Subject: [PATCH 1163/2042] boards: riscv: neorv32: Updates compatibility to neoverse v1.8.6 With NEORV32 v1.8.2 the UART module was changed to a simpler implementation. This updates the UART driver for the open-source NEORV32 RISC-V compatible processor system (SOC). Signed-off-by: Tim-Marek Thomas --- boards/riscv/neorv32/doc/index.rst | 2 + ...{neorv32_1_6_1.conf => neorv32_1_8_6.conf} | 2 +- boards/riscv/neorv32/revision.cmake | 2 +- drivers/serial/uart_neorv32.c | 78 ++++++------------- .../riscv-privileged/neorv32/Kconfig.soc | 6 +- soc/riscv/riscv-privileged/neorv32/reset.S | 2 +- 6 files changed, 33 insertions(+), 59 deletions(-) rename boards/riscv/neorv32/{neorv32_1_6_1.conf => neorv32_1_8_6.conf} (79%) diff --git a/boards/riscv/neorv32/doc/index.rst b/boards/riscv/neorv32/doc/index.rst index 44045544debc..6626c24d0d02 100644 --- a/boards/riscv/neorv32/doc/index.rst +++ b/boards/riscv/neorv32/doc/index.rst @@ -16,6 +16,8 @@ For more information about the NEORV32, see the following websites: - `The NEORV32 RISC-V Processor Datasheet`_ - `The NEORV32 RISC-V Processor User Guide`_ +The currently supported version is 1.8.6. + Supported Features ================== diff --git a/boards/riscv/neorv32/neorv32_1_6_1.conf b/boards/riscv/neorv32/neorv32_1_8_6.conf similarity index 79% rename from boards/riscv/neorv32/neorv32_1_6_1.conf rename to boards/riscv/neorv32/neorv32_1_8_6.conf index 877d6b335cb3..b1852631eeb6 100644 --- a/boards/riscv/neorv32/neorv32_1_6_1.conf +++ b/boards/riscv/neorv32/neorv32_1_8_6.conf @@ -1,4 +1,4 @@ # Copyright (c) 2021 Henrik Brix Andersen # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_NEORV32_V1_6_1=y +CONFIG_SOC_NEORV32_V1_8_6=y diff --git a/boards/riscv/neorv32/revision.cmake b/boards/riscv/neorv32/revision.cmake index a09db094dbef..b09cf3696111 100644 --- a/boards/riscv/neorv32/revision.cmake +++ b/boards/riscv/neorv32/revision.cmake @@ -3,5 +3,5 @@ board_check_revision( FORMAT MAJOR.MINOR.PATCH - DEFAULT_REVISION 1.6.1 + DEFAULT_REVISION 1.8.6 ) diff --git a/drivers/serial/uart_neorv32.c b/drivers/serial/uart_neorv32.c index 70823f137756..668f05305ca3 100644 --- a/drivers/serial/uart_neorv32.c +++ b/drivers/serial/uart_neorv32.c @@ -21,23 +21,26 @@ LOG_MODULE_REGISTER(uart_neorv32, CONFIG_UART_LOG_LEVEL); #define NEORV32_UART_DATA_OFFSET 0x04 /* UART_CTRL register bits */ -#define NEORV32_UART_CTRL_BAUD_MASK BIT_MASK(12) -#define NEORV32_UART_CTRL_BAUD_POS 0U -#define NEORV32_UART_CTRL_PRSC_MASK BIT_MASK(3) -#define NEORV32_UART_CTRL_PRSC_POS 24U -#define NEORV32_UART_CTRL_RTS_EN BIT(20) -#define NEORV32_UART_CTRL_CTS_EN BIT(21) -#define NEORV32_UART_CTRL_PMODE_NONE BIT(22) -#define NEORV32_UART_CTRL_PMODE_EVEN BIT(23) -#define NEORV32_UART_CTRL_PMODE_ODD (BIT(22) | BIT(23)) -#define NEORV32_UART_CTRL_EN BIT(28) -#define NEORV32_UART_CTRL_TX_BUSY BIT(31) - -/* UART_DATA register status bits */ -#define NEORV32_UART_DATA_PERR BIT(28) -#define NEORV32_UART_DATA_FERR BIT(29) -#define NEORV32_UART_DATA_OVERR BIT(30) -#define NEORV32_UART_DATA_AVAIL BIT(31) +#define NEORV32_UART_CTRL_EN BIT(0) +#define NEORV32_UART_CTRL_SIM_MODE BIT(1) +#define NEORV32_UART_CTRL_HWFC_EN BIT(2) +#define NEORV32_UART_CTRL_PRSC_POS 3U +#define NEORV32_UART_CTRL_PRSC_MASK BIT_MASK(3) +#define NEORV32_UART_CTRL_BAUD_POS 6U +#define NEORV32_UART_CTRL_BAUD_MASK BIT_MASK(10) +#define NEORV32_UART_CTRL_RX_NEMPTY BIT(16) +#define NEORV32_UART_CTRL_RX_HALF BIT(17) +#define NEORV32_UART_CTRL_RX_FULL BIT(18) +#define NEORV32_UART_CTRL_TX_NEMPTY BIT(19) +#define NEORV32_UART_CTRL_TX_HALF BIT(20) +#define NEORV32_UART_CTRL_TX_FULL BIT(21) +#define NEORV32_UART_CTRL_IRQ_RX_NEMPTY BIT(22) +#define NEORV32_UART_CTRL_IRQ_RX_HALF BIT(23) +#define NEORV32_UART_CTRL_IRQ_RX_FULL BIT(24) +#define NEORV32_UART_CTRL_IRQ_TX_EMPTY BIT(25) +#define NEORV32_UART_CTRL_IRQ_TX_NHALF BIT(26) +#define NEORV32_UART_CTRL_RX_OVER BIT(30) +#define NEORV32_UART_CTRL_TX_BUSY BIT(31) struct neorv32_uart_config { const struct device *syscon; @@ -100,7 +103,7 @@ static int neorv32_uart_poll_in(const struct device *dev, unsigned char *c) data = neorv32_uart_read_data(dev); - if ((data & NEORV32_UART_DATA_AVAIL) != 0) { + if ((data & NEORV32_UART_CTRL_RX_NEMPTY) != 0) { *c = data & BIT_MASK(8); return 0; } @@ -116,29 +119,6 @@ static void neorv32_uart_poll_out(const struct device *dev, unsigned char c) neorv32_uart_write_data(dev, c); } -static int neorv32_uart_err_check(const struct device *dev) -{ - struct neorv32_uart_data *data = dev->data; - int err = 0; - - if ((data->last_data & NEORV32_UART_DATA_OVERR) != 0) { - err |= UART_ERROR_OVERRUN; - } - - if ((data->last_data & NEORV32_UART_DATA_PERR) != 0) { - err |= UART_ERROR_PARITY; - } - - if ((data->last_data & NEORV32_UART_DATA_FERR) != 0) { - err |= UART_ERROR_FRAMING; - } - - data->last_data &= ~(NEORV32_UART_DATA_OVERR | NEORV32_UART_DATA_PERR | - NEORV32_UART_DATA_FERR); - - return err; -} - static int neorv32_uart_configure(const struct device *dev, const struct uart_config *cfg) { const struct neorv32_uart_config *config = dev->config; @@ -163,13 +143,6 @@ static int neorv32_uart_configure(const struct device *dev, const struct uart_co switch (cfg->parity) { case UART_CFG_PARITY_NONE: - ctrl |= NEORV32_UART_CTRL_PMODE_NONE; - break; - case UART_CFG_PARITY_ODD: - ctrl |= NEORV32_UART_CTRL_PMODE_ODD; - break; - case UART_CFG_PARITY_EVEN: - ctrl |= NEORV32_UART_CTRL_PMODE_EVEN; break; default: LOG_ERR("unsupported parity mode %d", cfg->parity); @@ -181,7 +154,7 @@ static int neorv32_uart_configure(const struct device *dev, const struct uart_co ctrl |= 0; break; case UART_CFG_FLOW_CTRL_RTS_CTS: - ctrl |= NEORV32_UART_CTRL_RTS_EN | NEORV32_UART_CTRL_CTS_EN; + ctrl |= NEORV32_UART_CTRL_HWFC_EN; break; default: LOG_ERR("unsupported flow control mode %d", cfg->flow_ctrl); @@ -270,9 +243,9 @@ static int neorv32_uart_fifo_read(const struct device *dev, uint8_t *rx_data, co __ASSERT_NO_MSG(rx_data != NULL); - while ((data->last_data & NEORV32_UART_DATA_AVAIL) != 0) { + while ((data->last_data & NEORV32_UART_CTRL_RX_NEMPTY) != 0) { rx_data[count++] = data->last_data & BIT_MASK(8); - data->last_data &= ~(NEORV32_UART_DATA_AVAIL); + data->last_data &= ~(NEORV32_UART_CTRL_RX_NEMPTY); if (count >= size) { break; @@ -367,7 +340,7 @@ static int neorv32_uart_irq_rx_ready(const struct device *dev) return 0; } - return (data->last_data & NEORV32_UART_DATA_AVAIL) != 0; + return (data->last_data & NEORV32_UART_CTRL_RX_NEMPTY) != 0; } static int neorv32_uart_irq_is_pending(const struct device *dev) @@ -467,7 +440,6 @@ static int neorv32_uart_pm_action(const struct device *dev, static const struct uart_driver_api neorv32_uart_driver_api = { .poll_in = neorv32_uart_poll_in, .poll_out = neorv32_uart_poll_out, - .err_check = neorv32_uart_err_check, .configure = neorv32_uart_configure, .config_get = neorv32_uart_config_get, #ifdef CONFIG_UART_INTERRUPT_DRIVEN diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc b/soc/riscv/riscv-privileged/neorv32/Kconfig.soc index 9dcbbad2fefa..93c9da8cc3d4 100644 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc +++ b/soc/riscv/riscv-privileged/neorv32/Kconfig.soc @@ -5,8 +5,8 @@ choice prompt "NEORV32 Version" depends on SOC_SERIES_NEORV32 -config SOC_NEORV32_V1_6_1 - bool "v1.6.1" +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 @@ -16,7 +16,7 @@ if SOC_SERIES_NEORV32 config SOC_NEORV32_VERSION hex - default 0x01060100 if SOC_NEORV32_V1_6_1 + 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) diff --git a/soc/riscv/riscv-privileged/neorv32/reset.S b/soc/riscv/riscv-privileged/neorv32/reset.S index c92b962e95e1..ca91f0376b1a 100644 --- a/soc/riscv/riscv-privileged/neorv32/reset.S +++ b/soc/riscv/riscv-privileged/neorv32/reset.S @@ -26,7 +26,7 @@ SECTION_FUNC(reset, __reset) #endif /* CONFIG_USERSPACE */ /* Allow mcycle and minstret counters to increment */ - li x11, ~5 + li x11, ~2 csrw mcountinhibit, x11 /* Zerorize counters */ From 934c6d7b335949f4b2f75a672aae7422c210c16c Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Tue, 11 Jul 2023 16:40:16 +0530 Subject: [PATCH 1164/2042] drivers: mm: Fix cast warnings on build for RAT Removed the unneccessary casts in the functions to remove warnings during build for SoCs using RAT. Functionality reamins the same, tested on board. Signed-off-by: L Lakshmanan --- drivers/mm/mm_drv_ti_rat.c | 6 +++--- include/zephyr/drivers/mm/rat.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mm/mm_drv_ti_rat.c b/drivers/mm/mm_drv_ti_rat.c index 19fdb6cbb2d2..e21561e079fb 100644 --- a/drivers/mm/mm_drv_ti_rat.c +++ b/drivers/mm/mm_drv_ti_rat.c @@ -99,7 +99,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) if (virt == NULL) { return -EINVAL; } - uint64_t pa = ((uint64_t) (virt)); + uintptr_t pa = (uintptr_t) virt; uintptr_t *va = phys; uint32_t found, regionId; @@ -130,10 +130,10 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) uint32_t offset = pa - translate_config.region_config[regionId].system_addr; - *va = (void *)(translate_config.region_config[regionId].local_addr + offset); + *va = (translate_config.region_config[regionId].local_addr + offset); } else { /* no mapping found, set output = input with 32b truncation */ - *va = (void *)pa; + *va = pa; } if (va == NULL) { diff --git a/include/zephyr/drivers/mm/rat.h b/include/zephyr/drivers/mm/rat.h index 984c4ef01d47..216142a2680b 100644 --- a/include/zephyr/drivers/mm/rat.h +++ b/include/zephyr/drivers/mm/rat.h @@ -15,10 +15,10 @@ extern "C" { #include #define ADDR_TRANSLATE_MAX_REGIONS (16u) -#define RAT_CTRL(base_addr, i) (volatile uint32_t *)(base_addr + 0x20 + 0x10 * (i)) -#define RAT_BASE(base_addr, i) (volatile uint32_t *)(base_addr + 0x24 + 0x10 * (i)) -#define RAT_TRANS_L(base_addr, i) (volatile uint32_t *)(base_addr + 0x28 + 0x10 * (i)) -#define RAT_TRANS_H(base_addr, i) (volatile uint32_t *)(base_addr + 0x2C + 0x10 * (i)) +#define RAT_CTRL(base_addr, i) (base_addr + 0x20 + 0x10 * (i)) +#define RAT_BASE(base_addr, i) (base_addr + 0x24 + 0x10 * (i)) +#define RAT_TRANS_L(base_addr, i) (base_addr + 0x28 + 0x10 * (i)) +#define RAT_TRANS_H(base_addr, i) (base_addr + 0x2C + 0x10 * (i)) #define RAT_CTRL_W(enable, size) (((enable & 0x1) << 31u) | (size & 0x3F)) /** From 7fba7d395750ba565ddc4064d32944f174ec3860 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 11 Jul 2023 21:37:30 +0800 Subject: [PATCH 1165/2042] shell: mqtt: fix uint32_t compared against 0 Fix unsigned compared against 0 reported by coverity check. CID: 321096 Signed-off-by: Yong Cong Sin --- subsys/shell/backends/shell_mqtt.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/subsys/shell/backends/shell_mqtt.c b/subsys/shell/backends/shell_mqtt.c index 58654dcf4000..a1f933c580d1 100644 --- a/subsys/shell/backends/shell_mqtt.c +++ b/subsys/shell/backends/shell_mqtt.c @@ -564,7 +564,9 @@ static void mqtt_evt_handler(struct mqtt_client *const client, const struct mqtt case MQTT_EVT_PUBLISH: { const struct mqtt_publish_param *pub = &evt->param.publish; - uint32_t size, payload_left; + uint32_t payload_left; + size_t size; + int rc; payload_left = pub->message.payload.len; @@ -581,18 +583,19 @@ static void mqtt_evt_handler(struct mqtt_client *const client, const struct mqtt while (payload_left > 0) { /* Attempt to claim `payload_left` bytes of buffer in rb */ - size = ring_buf_put_claim(&sh_mqtt->rx_rb, &sh_mqtt->rx_rb_ptr, - payload_left); + size = (size_t)ring_buf_put_claim(&sh_mqtt->rx_rb, &sh_mqtt->rx_rb_ptr, + payload_left); /* Read `size` bytes of payload from mqtt */ - size = mqtt_read_publish_payload_blocking(client, sh_mqtt->rx_rb_ptr, size); + rc = mqtt_read_publish_payload_blocking(client, sh_mqtt->rx_rb_ptr, size); /* errno value, return */ - if (size < 0) { + if (rc < 0) { (void)ring_buf_put_finish(&sh_mqtt->rx_rb, 0U); sh_mqtt_rx_rb_flush(); return; } + size = (size_t)rc; /* Indicate that `size` bytes of payload has been written into rb */ (void)ring_buf_put_finish(&sh_mqtt->rx_rb, size); /* Update `payload_left` */ From 8fd1ce7579d3c21b724365826e3e9c834d7a327e Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Mon, 10 Jul 2023 22:40:42 -0600 Subject: [PATCH 1166/2042] emul: Only add enabled DT nodes to bus emulators The eSPI, I2C, and SPI emulators use devicetree macros to build an array of devices on the virtual bus. Currently, they will add device nodes that are not status-okay. This leads to linker errors because the respective device drivers would not have instantiated device structs for these nodes --assuming the driver was even compiled. This can be frustrating if nodes need to be disabled for debugging or configuration purposes. Update the bus emulators to only consider status-okay nodes by changing the macros used to iterate over bus devices. Signed-off-by: Tristan Honscheid --- drivers/espi/espi_emul.c | 4 ++-- drivers/i2c/i2c_emul.c | 4 ++-- drivers/spi/spi_emul.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/espi/espi_emul.c b/drivers/espi/espi_emul.c index bf9d50afc978..f0ab7c80642b 100644 --- a/drivers/espi/espi_emul.c +++ b/drivers/espi/espi_emul.c @@ -232,8 +232,8 @@ static struct emul_espi_driver_api emul_espi_driver_api = { }, #define ESPI_EMUL_INIT(n) \ - static const struct emul_link_for_bus emuls_##n[] = { DT_FOREACH_CHILD( \ - DT_DRV_INST(n), EMUL_LINK_AND_COMMA) }; \ + static const struct emul_link_for_bus emuls_##n[] = { \ + DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(n), EMUL_LINK_AND_COMMA)}; \ static struct emul_list_for_bus espi_emul_cfg_##n = { \ .children = emuls_##n, \ .num_children = ARRAY_SIZE(emuls_##n), \ diff --git a/drivers/i2c/i2c_emul.c b/drivers/i2c/i2c_emul.c index 98d5c965a952..4324f6792c62 100644 --- a/drivers/i2c/i2c_emul.c +++ b/drivers/i2c/i2c_emul.c @@ -144,8 +144,8 @@ static struct i2c_driver_api i2c_emul_api = { }, #define I2C_EMUL_INIT(n) \ - static const struct emul_link_for_bus emuls_##n[] = { DT_FOREACH_CHILD( \ - DT_DRV_INST(n), EMUL_LINK_AND_COMMA) }; \ + static const struct emul_link_for_bus emuls_##n[] = { \ + DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(n), EMUL_LINK_AND_COMMA)}; \ static struct emul_list_for_bus i2c_emul_cfg_##n = { \ .children = emuls_##n, \ .num_children = ARRAY_SIZE(emuls_##n), \ diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index 98445319b991..9c8f3a6cd70b 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -119,8 +119,8 @@ static struct spi_driver_api spi_emul_api = { }, #define SPI_EMUL_INIT(n) \ - static const struct emul_link_for_bus emuls_##n[] = { DT_FOREACH_CHILD( \ - DT_DRV_INST(n), EMUL_LINK_AND_COMMA) }; \ + static const struct emul_link_for_bus emuls_##n[] = { \ + DT_FOREACH_CHILD_STATUS_OKAY(DT_DRV_INST(n), EMUL_LINK_AND_COMMA)}; \ static struct emul_list_for_bus spi_emul_cfg_##n = { \ .children = emuls_##n, \ .num_children = ARRAY_SIZE(emuls_##n), \ From 0df7bd26eddd57d6cc9bd23237964a3d71f6f8ac Mon Sep 17 00:00:00 2001 From: Jaxson Han Date: Mon, 10 Jul 2023 22:04:05 +0800 Subject: [PATCH 1167/2042] lib: posix: pthread_rwlock: Fix a racy issue Multiple reader threads unlocking the read lock simultaneously might cause the program hang because it's possible that no thread is identified as the last one to active the writer thread. To fix the issue, swap the k_sem_give sequence. Signed-off-by: Jaxson Han --- lib/posix/rwlock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/posix/rwlock.c b/lib/posix/rwlock.c index 45d4af694583..60039fb088a0 100644 --- a/lib/posix/rwlock.c +++ b/lib/posix/rwlock.c @@ -200,13 +200,13 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) k_sem_give(&rwlock->wr_sem); } else { /* Read unlock */ + k_sem_give(&rwlock->rd_sem); + if (k_sem_count_get(&rwlock->rd_sem) == - (CONCURRENT_READER_LIMIT - 1)) { + CONCURRENT_READER_LIMIT) { /* Last read lock, unlock writer */ k_sem_give(&rwlock->reader_active); } - - k_sem_give(&rwlock->rd_sem); } return 0; } From c2d049f56e53395a9016f4a61f257a9d26330f0f Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 10 Jul 2023 15:27:36 +0000 Subject: [PATCH 1168/2042] intc_gicv3_its: anticipate initialization priority The intc_gicv3_its driver is currently initializing in POST_KERNEL, but PCIe device nodes depends on it and are initialized earlier. Change the init level to PRE_KERNEL_1 to sort that out, and also put the driver in line with other interrupt controller drivers. Signed-off-by: Fabio Baltieri --- drivers/interrupt_controller/intc_gicv3_its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_gicv3_its.c b/drivers/interrupt_controller/intc_gicv3_its.c index 4b4149c52d73..c8e754e1752b 100644 --- a/drivers/interrupt_controller/intc_gicv3_its.c +++ b/drivers/interrupt_controller/intc_gicv3_its.c @@ -676,7 +676,7 @@ struct its_driver_api gicv3_its_api = { DEVICE_DT_INST_DEFINE(n, &gicv3_its_init, NULL, \ &gicv3_its_data##n, \ &gicv3_its_config##n, \ - POST_KERNEL, \ + PRE_KERNEL_1, \ CONFIG_INTC_INIT_PRIORITY, \ &gicv3_its_api); From 5ea3f9a24e32826d3f40cd9fd55e0cba044b2c70 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 10 Jul 2023 15:29:35 +0000 Subject: [PATCH 1169/2042] drivers: pcie: initialize after interrupt controllers PCIe devices refer to interrupt nodes, but are initialized with the same priority, making the sequence depending on the linking order. Add a new symbol and set it to one unit after intc to ensure that the initialization sequence is stable. Found with: west build -p -b qemu_cortex_a53 \ samples/drivers/virtualization/ivshmem/doorbell \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /soc/pcie@4010000000 PRE_KERNEL_1 40 < /soc/interrupt-controller@8000000/its@8080000 POST_KERNEL 40 Signed-off-by: Fabio Baltieri --- drivers/pcie/host/Kconfig | 6 ++++++ drivers/pcie/host/pcie.c | 2 +- drivers/pcie/host/pcie_ecam.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/pcie/host/Kconfig b/drivers/pcie/host/Kconfig index a3d7fc6b5c3a..809256577023 100644 --- a/drivers/pcie/host/Kconfig +++ b/drivers/pcie/host/Kconfig @@ -14,6 +14,12 @@ module = PCIE module-str = pcie source "subsys/logging/Kconfig.template.log_config" +config PCIE_INIT_PRIORITY + int "PCIe initialization priority" + default 41 + help + PCIe host drivers initialization priority. + config PCIE_CONTROLLER bool "PCIe Controller management" help diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 5b2198b52784..89f05ac1238e 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -554,4 +554,4 @@ static int pcie_init(void) #define PCIE_SYS_INIT_LEVEL PRE_KERNEL_1 #endif -SYS_INIT(pcie_init, PCIE_SYS_INIT_LEVEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(pcie_init, PCIE_SYS_INIT_LEVEL, CONFIG_PCIE_INIT_PRIORITY); diff --git a/drivers/pcie/host/pcie_ecam.c b/drivers/pcie/host/pcie_ecam.c index 4ba8889378d6..15a52b3247dc 100644 --- a/drivers/pcie/host/pcie_ecam.c +++ b/drivers/pcie/host/pcie_ecam.c @@ -403,7 +403,7 @@ static const struct pcie_ctrl_driver_api pcie_ecam_api = { &pcie_ecam_data##n, \ &pcie_ecam_config##n, \ PRE_KERNEL_1, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + CONFIG_PCIE_INIT_PRIORITY, \ &pcie_ecam_api); DT_INST_FOREACH_STATUS_OKAY(PCIE_ECAM_INIT) From f4356f3b2e6307e5e4293a7d90a2e6a19b281179 Mon Sep 17 00:00:00 2001 From: Elisabeth Friedrich Date: Thu, 6 Jul 2023 20:20:14 +0200 Subject: [PATCH 1170/2042] drivers: lpadc: fix ADC command chaining When reading multiple ADC channel in parallel, an ADC command chain will be build. This is similar to a linked list, as every command references the next command. Before this patch every ADC command after the first, would always reference this initial command. So that during execution only two commands (the last and first) would be executed which resulted in readout of only two analog values. As Zephyr expected more to come in, the `read_adc` function would block endlessly. The patch fixes the behaviour and allows a correct chain to build up. Signed-off-by: Elisabeth Friedrich --- drivers/adc/adc_mcux_lpadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/adc_mcux_lpadc.c b/drivers/adc/adc_mcux_lpadc.c index 4640155b419a..c9ea7197c2b2 100644 --- a/drivers/adc/adc_mcux_lpadc.c +++ b/drivers/adc/adc_mcux_lpadc.c @@ -238,8 +238,8 @@ static int mcux_lpadc_start_read(const struct device *dev, } else { /* End of chain */ data->cmd_config[channel].chainedNextCommandNumber = 0; - last_enabled = channel; } + last_enabled = channel; LPADC_SetConvCommandConfig(config->base, channel + 1, &data->cmd_config[channel]); } From ff2b5cebb70dfabad8042d9a585e38cee4e4a464 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 10 Jul 2023 13:23:20 +0200 Subject: [PATCH 1171/2042] drivers: rtc: rtc_emul: replace mutex with spinlock Replaces the mutex with a lightweight spinlock. Fixes: #59901 Signed-off-by: Florian Grandel --- drivers/rtc/rtc_emul.c | 128 +++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 70 deletions(-) diff --git a/drivers/rtc/rtc_emul.c b/drivers/rtc/rtc_emul.c index 9471d9cd6cba..f8f92447485b 100644 --- a/drivers/rtc/rtc_emul.c +++ b/drivers/rtc/rtc_emul.c @@ -30,7 +30,7 @@ struct rtc_emul_data { struct rtc_time datetime; - struct k_mutex lock; + struct k_spinlock lock; struct rtc_emul_work_delayable dwork; @@ -253,19 +253,17 @@ static void rtc_emul_update(struct k_work *work) k_work_schedule(&work_delayable->dwork, K_MSEC(1000)); - k_mutex_lock(&data->lock, K_FOREVER); - - rtc_emul_increment_tm(&data->datetime); + K_SPINLOCK(&data->lock) { + rtc_emul_increment_tm(&data->datetime); #ifdef CONFIG_RTC_ALARM - rtc_emul_test_alarms(dev); + rtc_emul_test_alarms(dev); #endif /* CONFIG_RTC_ALARM */ #ifdef CONFIG_RTC_UPDATE - rtc_emul_invoke_update_callback(dev); + rtc_emul_invoke_update_callback(dev); #endif /* CONFIG_RTC_UPDATE */ - - k_mutex_unlock(&data->lock); + } } static int rtc_emul_set_time(const struct device *dev, const struct rtc_time *timeptr) @@ -277,15 +275,14 @@ static int rtc_emul_set_time(const struct device *dev, const struct rtc_time *ti return -EINVAL; } - k_mutex_lock(&data->lock, K_FOREVER); - - data->datetime = (*timeptr); - data->datetime.tm_isdst = -1; - data->datetime.tm_nsec = 0; - - data->datetime_set = true; + K_SPINLOCK(&data->lock) + { + data->datetime = (*timeptr); + data->datetime.tm_isdst = -1; + data->datetime.tm_nsec = 0; - k_mutex_unlock(&data->lock); + data->datetime_set = true; + } return 0; } @@ -293,26 +290,26 @@ static int rtc_emul_set_time(const struct device *dev, const struct rtc_time *ti static int rtc_emul_get_time(const struct device *dev, struct rtc_time *timeptr) { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; + int ret = 0; /* Validate arguments */ if (timeptr == NULL) { return -EINVAL; } - k_mutex_lock(&data->lock, K_FOREVER); + K_SPINLOCK(&data->lock) + { + /* Validate RTC time is set */ + if (data->datetime_set == false) { + ret = -ENODATA; - /* Validate RTC time is set */ - if (data->datetime_set == false) { - k_mutex_unlock(&data->lock); + K_SPINLOCK_BREAK; + } - return -ENODATA; + (*timeptr) = data->datetime; } - (*timeptr) = data->datetime; - - k_mutex_unlock(&data->lock); - - return 0; + return ret; } #ifdef CONFIG_RTC_ALARM @@ -354,16 +351,15 @@ static int rtc_emul_alarm_set_time(const struct device *dev, uint16_t id, uint16 } } - k_mutex_lock(&data->lock, K_FOREVER); + K_SPINLOCK(&data->lock) + { + data->alarms[id].mask = mask; - data->alarms[id].mask = mask; - - if (timeptr != NULL) { - data->alarms[id].datetime = *timeptr; + if (timeptr != NULL) { + data->alarms[id].datetime = *timeptr; + } } - k_mutex_unlock(&data->lock); - return 0; } @@ -376,12 +372,11 @@ static int rtc_emul_alarm_get_time(const struct device *dev, uint16_t id, uint16 return -EINVAL; } - k_mutex_lock(&data->lock, K_FOREVER); - - (*timeptr) = data->alarms[id].datetime; - (*mask) = data->alarms[id].mask; - - k_mutex_unlock(&data->lock); + K_SPINLOCK(&data->lock) + { + (*timeptr) = data->alarms[id].datetime; + (*mask) = data->alarms[id].mask; + } return 0; } @@ -389,19 +384,18 @@ static int rtc_emul_alarm_get_time(const struct device *dev, uint16_t id, uint16 static int rtc_emul_alarm_is_pending(const struct device *dev, uint16_t id) { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; - int ret; + int ret = 0; if (data->alarms_count <= id) { return -EINVAL; } - k_mutex_lock(&data->lock, K_FOREVER); + K_SPINLOCK(&data->lock) + { + ret = (data->alarms[id].pending == true) ? 1 : 0; - ret = (data->alarms[id].pending == true) ? 1 : 0; - - data->alarms[id].pending = false; - - k_mutex_unlock(&data->lock); + data->alarms[id].pending = false; + } return ret; } @@ -415,12 +409,11 @@ static int rtc_emul_alarm_set_callback(const struct device *dev, uint16_t id, return -EINVAL; } - k_mutex_lock(&data->lock, K_FOREVER); - - data->alarms[id].callback = callback; - data->alarms[id].user_data = user_data; - - k_mutex_unlock(&data->lock); + K_SPINLOCK(&data->lock) + { + data->alarms[id].callback = callback; + data->alarms[id].user_data = user_data; + } return 0; } @@ -432,12 +425,11 @@ static int rtc_emul_update_set_callback(const struct device *dev, { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; - k_mutex_lock(&data->lock, K_FOREVER); - - data->update_callback = callback; - data->update_callback_user_data = user_data; - - k_mutex_unlock(&data->lock); + K_SPINLOCK(&data->lock) + { + data->update_callback = callback; + data->update_callback_user_data = user_data; + } return 0; } @@ -448,11 +440,10 @@ static int rtc_emul_set_calibration(const struct device *dev, int32_t calibratio { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; - k_mutex_lock(&data->lock, K_FOREVER); - - data->calibration = calibration; - - k_mutex_unlock(&data->lock); + K_SPINLOCK(&data->lock) + { + data->calibration = calibration; + } return 0; } @@ -461,11 +452,10 @@ static int rtc_emul_get_calibration(const struct device *dev, int32_t *calibrati { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; - k_mutex_lock(&data->lock, K_FOREVER); - - (*calibration) = data->calibration; - - k_mutex_unlock(&data->lock); + K_SPINLOCK(&data->lock) + { + (*calibration) = data->calibration; + } return 0; } @@ -494,8 +484,6 @@ int rtc_emul_init(const struct device *dev) { struct rtc_emul_data *data = (struct rtc_emul_data *)dev->data; - k_mutex_init(&data->lock); - data->dwork.dev = dev; k_work_init_delayable(&data->dwork.dwork, rtc_emul_update); From 78dc3950dcd4ac1b6356e6390c4c9cb2497d5f54 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 2 Jul 2023 11:38:22 +0200 Subject: [PATCH 1172/2042] tests: drivers: rtc: zassert_true -> zassert_equal Using the more specialized zassert_equal() macro where appropriate. Signed-off-by: Florian Grandel --- tests/drivers/rtc/rtc_api/src/test_alarm.c | 28 +++++++-------- .../rtc/rtc_api/src/test_alarm_callback.c | 28 +++++++-------- .../drivers/rtc/rtc_api/src/test_calibrate.c | 8 ++--- tests/drivers/rtc/rtc_api/src/test_time.c | 8 ++--- .../rtc/rtc_api/src/test_time_incrementing.c | 4 +-- .../rtc/rtc_api/src/test_update_callback.c | 8 ++--- .../rtc_api_helpers/src/test_rtc_time_to_tm.c | 36 +++++++++---------- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/tests/drivers/rtc/rtc_api/src/test_alarm.c b/tests/drivers/rtc/rtc_api/src/test_alarm.c index dc224c9e465c..c78f327513d7 100644 --- a/tests/drivers/rtc/rtc_api/src/test_alarm.c +++ b/tests/drivers/rtc/rtc_api/src/test_alarm.c @@ -37,7 +37,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_true(ret == 0, "Failed to clear alarm time"); + zassert_ok(ret, "Failed to clear alarm time"); } /* Disable alarm callback */ @@ -52,7 +52,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported); - zassert_true(ret == 0, "Failed to get supported alarm fields"); + zassert_ok(ret, "Failed to get supported alarm fields"); /* Skip test if alarm does not support the minute and hour fields */ if (((RTC_ALARM_TIME_MASK_MINUTE & alarm_time_mask_supported) == 0) || @@ -69,23 +69,23 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, alarm_time_mask_set, &alarm_time_set); - zassert_true(ret == 0, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm time"); } /* Validate alarm time */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_time(rtc, i, &alarm_time_mask_get, &alarm_time_get); - zassert_true(ret == 0, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm time"); - zassert_true(alarm_time_mask_get == alarm_time_mask_set, - "Incorrect alarm time mask"); + zassert_equal(alarm_time_mask_get, alarm_time_mask_set, + "Incorrect alarm time mask"); - zassert_true(alarm_time_get.tm_min == alarm_time_get.tm_min, - "Incorrect alarm time minute field"); + zassert_equal(alarm_time_get.tm_min, alarm_time_get.tm_min, + "Incorrect alarm time minute field"); - zassert_true(alarm_time_get.tm_hour == alarm_time_get.tm_hour, - "Incorrect alarm time hour field"); + zassert_equal(alarm_time_get.tm_hour, alarm_time_get.tm_hour, + "Incorrect alarm time hour field"); } /* Initialize RTC time to set */ @@ -100,7 +100,7 @@ ZTEST(rtc_api, test_alarm) /* Set RTC time */ ret = rtc_set_time(rtc, &time_set); - zassert_true(ret == 0, "Failed to set time"); + zassert_ok(ret, "Failed to set time"); /* Clear alarm pending status */ for (uint16_t i = 0; i < alarms_count; i++) { @@ -116,7 +116,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret == 0, "Alarm should not be pending"); + zassert_ok(ret, "Alarm should not be pending"); } /* Wait for alarm to trigger */ @@ -126,7 +126,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_is_pending(rtc, i); - zassert_true(ret == 1, "Alarm should be pending"); + zassert_equal(ret, 1, "Alarm should be pending"); } } @@ -134,7 +134,7 @@ ZTEST(rtc_api, test_alarm) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_true(ret == 0, "Failed to disable alarm"); + zassert_ok(ret, "Failed to disable alarm"); ret = rtc_alarm_is_pending(rtc, i); diff --git a/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c b/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c index 9dfa73eaacee..c0eedd67e805 100644 --- a/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c +++ b/tests/drivers/rtc/rtc_api/src/test_alarm_callback.c @@ -54,14 +54,14 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_callback(rtc, i, NULL, NULL); - zassert_true(ret == 0, "Failed to clear and disable alarm"); + zassert_ok(ret, "Failed to clear and disable alarm"); } /* Validate alarms supported fields */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_get_supported_fields(rtc, i, &alarm_time_mask_supported); - zassert_true(ret == 0, "Failed to get supported alarm fields"); + zassert_ok(ret, "Failed to get supported alarm fields"); /* Skip test if alarm does not support the minute and hour fields */ if (((RTC_ALARM_TIME_MASK_MINUTE & alarm_time_mask_supported) == 0) || @@ -78,7 +78,7 @@ ZTEST(rtc_api, test_alarm_callback) for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_time(rtc, i, alarm_time_mask_set, &alarm_time_set); - zassert_true(ret == 0, "Failed to set alarm time"); + zassert_ok(ret, "Failed to set alarm time"); } /* Initialize RTC time to set */ @@ -92,7 +92,7 @@ ZTEST(rtc_api, test_alarm_callback) /* Set RTC time */ ret = rtc_set_time(rtc, &time_set); - zassert_true(ret == 0, "Failed to set time"); + zassert_ok(ret, "Failed to set time"); /* Clear alarm pending status */ for (uint16_t i = 0; i < alarms_count; i++) { @@ -113,7 +113,7 @@ ZTEST(rtc_api, test_alarm_callback) &callback_user_data_even); } - zassert_true(ret == 0, "Failed to set alarm callback"); + zassert_ok(ret, "Failed to set alarm callback"); } for (uint8_t i = 0; i < 2; i++) { @@ -128,10 +128,10 @@ ZTEST(rtc_api, test_alarm_callback) callback_called_mask_status_odd = atomic_get(&callback_called_mask_odd); callback_called_mask_status_even = atomic_get(&callback_called_mask_even); - zassert_true(callback_called_mask_status_odd == 0, - "Alarm callback called prematurely"); - zassert_true(callback_called_mask_status_even == 0, - "Alarm callback called prematurely"); + zassert_equal(callback_called_mask_status_odd, 0, + "Alarm callback called prematurely"); + zassert_equal(callback_called_mask_status_even, 0, + "Alarm callback called prematurely"); /* Wait for alarm to trigger */ k_sleep(K_SECONDS(RTC_TEST_ALARM_TEST_CALLED_DELAY)); @@ -142,25 +142,25 @@ ZTEST(rtc_api, test_alarm_callback) (i % 2) ? atomic_test_bit(&callback_called_mask_odd, i) : atomic_test_bit(&callback_called_mask_even, i); - zassert_true(callback_called_status == true, - "Alarm callback should have been called"); + zassert_equal(callback_called_status, true, + "Alarm callback should have been called"); } /* Reset RTC time */ ret = rtc_set_time(rtc, &time_set); - zassert_true(ret == 0, "Failed to set time"); + zassert_ok(ret, "Failed to set time"); } /* Disable and clear alarms */ for (uint16_t i = 0; i < alarms_count; i++) { ret = rtc_alarm_set_callback(rtc, i, NULL, NULL); - zassert_true(ret == 0, "Failed to disable alarm callback"); + zassert_ok(ret, "Failed to disable alarm callback"); ret = rtc_alarm_set_time(rtc, i, 0, NULL); - zassert_true(ret == 0, "Failed to disable alarm"); + zassert_ok(ret, "Failed to disable alarm"); ret = rtc_alarm_is_pending(rtc, i); diff --git a/tests/drivers/rtc/rtc_api/src/test_calibrate.c b/tests/drivers/rtc/rtc_api/src/test_calibrate.c index 381f003ee0b8..f0d89dc7973c 100644 --- a/tests/drivers/rtc/rtc_api/src/test_calibrate.c +++ b/tests/drivers/rtc/rtc_api/src/test_calibrate.c @@ -28,12 +28,12 @@ static int test_set_get_calibration(int32_t calibrate_set) } /* Validate calibration was set */ - zassert_true(ret == 0, "Failed to set calibration"); + zassert_ok(ret, "Failed to set calibration"); ret = rtc_get_calibration(rtc, &calibrate_get); /* Validate calibration was gotten */ - zassert_true(ret == 0, "Failed to get calibration"); + zassert_ok(ret, "Failed to get calibration"); /* Print comparison between set and get values */ printk("Calibrate (set,get): %i, %i\n", calibrate_set, calibrate_get); @@ -51,12 +51,12 @@ ZTEST(rtc_api, test_set_get_calibration) ret = rtc_set_calibration(rtc, 0); /* Validate calibration was set */ - zassert_true(ret == 0, "Failed to set calibration"); + zassert_ok(ret, "Failed to set calibration"); ret = rtc_get_calibration(rtc, &calibrate_get); /* Validate calibration was gotten */ - zassert_true(ret == 0, "Failed to get calibration"); + zassert_ok(ret, "Failed to get calibration"); /* Validate edge values (0 already tested) */ test_set_get_calibration(1); diff --git a/tests/drivers/rtc/rtc_api/src/test_time.c b/tests/drivers/rtc/rtc_api/src/test_time.c index 832502d954b9..5b8573e5919a 100644 --- a/tests/drivers/rtc/rtc_api/src/test_time.c +++ b/tests/drivers/rtc/rtc_api/src/test_time.c @@ -29,10 +29,10 @@ ZTEST(rtc_api, test_set_get_time) memset(&datetime_get, 0xFF, sizeof(datetime_get)); - zassert_true(rtc_set_time(rtc, &datetime_set) == 0, "Failed to set time"); + zassert_equal(rtc_set_time(rtc, &datetime_set), 0, "Failed to set time"); - zassert_true(rtc_get_time(rtc, &datetime_get) == 0, - "Failed to get time using rtc_time_get()"); + zassert_equal(rtc_get_time(rtc, &datetime_get), 0, + "Failed to get time using rtc_time_get()"); zassert_true((datetime_get.tm_sec > -1) && (datetime_get.tm_sec < 60), "Invalid tm_sec"); @@ -55,7 +55,7 @@ ZTEST(rtc_api, test_set_get_time) zassert_true((datetime_get.tm_yday > -2) && (datetime_get.tm_yday < 366), "Invalid tm_yday"); - zassert_true((datetime_get.tm_isdst == -1), "Invalid tm_isdst"); + zassert_equal(datetime_get.tm_isdst, -1, "Invalid tm_isdst"); zassert_true((datetime_get.tm_nsec > -1) && (datetime_get.tm_yday < 1000000000), "Invalid tm_yday"); diff --git a/tests/drivers/rtc/rtc_api/src/test_time_incrementing.c b/tests/drivers/rtc/rtc_api/src/test_time_incrementing.c index b1680f2eca7c..a5fccd9471b9 100644 --- a/tests/drivers/rtc/rtc_api/src/test_time_incrementing.c +++ b/tests/drivers/rtc/rtc_api/src/test_time_incrementing.c @@ -29,11 +29,11 @@ ZTEST(rtc_api, test_time_counting) gmtime_r(&timer_set, (struct tm *)(&datetime_set)); - zassert_true(rtc_set_time(rtc, &datetime_set) == 0, "Failed to set time"); + zassert_equal(rtc_set_time(rtc, &datetime_set), 0, "Failed to set time"); for (i = 0; i < RTC_TEST_TIME_COUNTING_POLL_LIMIT; i++) { /* Get time */ - zassert_true(rtc_get_time(rtc, &datetime_get) == 0, "Failed to get time"); + zassert_equal(rtc_get_time(rtc, &datetime_get), 0, "Failed to get time"); timer_get = timeutil_timegm((struct tm *)(&datetime_get)); diff --git a/tests/drivers/rtc/rtc_api/src/test_update_callback.c b/tests/drivers/rtc/rtc_api/src/test_update_callback.c index d20ddb9eaea4..6cddd3b045e5 100644 --- a/tests/drivers/rtc/rtc_api/src/test_update_callback.c +++ b/tests/drivers/rtc/rtc_api/src/test_update_callback.c @@ -29,7 +29,7 @@ ZTEST(rtc_api, test_update_callback) ret = rtc_update_set_callback(rtc, NULL, NULL); - zassert_true(ret == 0, "Failed to clear and disable update callback"); + zassert_ok(ret, "Failed to clear and disable update callback"); atomic_set(&callback_called_counter, 0); @@ -37,11 +37,11 @@ ZTEST(rtc_api, test_update_callback) counter = atomic_get(&callback_called_counter); - zassert_true(counter == 0, "Update callback should not have been called"); + zassert_equal(counter, 0, "Update callback should not have been called"); ret = rtc_update_set_callback(rtc, test_rtc_update_callback_handler, &test_user_data); - zassert_true(ret == 0, "Failed to set and enable update callback"); + zassert_ok(ret, "Failed to set and enable update callback"); k_msleep(10000); @@ -51,5 +51,5 @@ ZTEST(rtc_api, test_update_callback) zassert_true(counter < 12 && counter > 8, "Invalid update callback called counter"); - zassert_true(address == ((uint32_t)(&test_user_data)), "Incorrect user data"); + zassert_equal(address, (uint32_t)(&test_user_data), "Incorrect user data"); } diff --git a/tests/drivers/rtc/rtc_api_helpers/src/test_rtc_time_to_tm.c b/tests/drivers/rtc/rtc_api_helpers/src/test_rtc_time_to_tm.c index bba11d79c947..93b1d3f09ea8 100644 --- a/tests/drivers/rtc/rtc_api_helpers/src/test_rtc_time_to_tm.c +++ b/tests/drivers/rtc/rtc_api_helpers/src/test_rtc_time_to_tm.c @@ -10,32 +10,32 @@ ZTEST(rtc_api_helpers, test_validate_rtc_time_compat_with_tm) { - zassert(offsetof(struct rtc_time, tm_sec) == offsetof(struct tm, tm_sec), - "Offset of tm_sec in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_sec), offsetof(struct tm, tm_sec), + "Offset of tm_sec in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_min) == offsetof(struct tm, tm_min), - "Offset of tm_min in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_min), offsetof(struct tm, tm_min), + "Offset of tm_min in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_hour) == offsetof(struct tm, tm_hour), - "Offset of tm_hour in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_hour), offsetof(struct tm, tm_hour), + "Offset of tm_hour in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_mday) == offsetof(struct tm, tm_mday), - "Offset of tm_mday in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_mday), offsetof(struct tm, tm_mday), + "Offset of tm_mday in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_mon) == offsetof(struct tm, tm_mon), - "Offset of tm_mon in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_mon), offsetof(struct tm, tm_mon), + "Offset of tm_mon in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_year) == offsetof(struct tm, tm_year), - "Offset of tm_year in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_year), offsetof(struct tm, tm_year), + "Offset of tm_year in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_wday) == offsetof(struct tm, tm_wday), - "Offset of tm_wday in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_wday), offsetof(struct tm, tm_wday), + "Offset of tm_wday in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_yday) == offsetof(struct tm, tm_yday), - "Offset of tm_yday in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_yday), offsetof(struct tm, tm_yday), + "Offset of tm_yday in struct rtc_time does not match struct tm"); - zassert(offsetof(struct rtc_time, tm_isdst) == offsetof(struct tm, tm_isdst), - "Offset of tm_isdts in struct rtc_time does not match struct tm"); + zassert_equal(offsetof(struct rtc_time, tm_isdst), offsetof(struct tm, tm_isdst), + "Offset of tm_isdts in struct rtc_time does not match struct tm"); } ZTEST(rtc_api_helpers, test_validate_rtc_time_to_tm) From 5c4ec518ab5d23003cfe99e32bebbbc27c281775 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Mon, 10 Jul 2023 13:35:04 +0200 Subject: [PATCH 1173/2042] driver: rtc: rtc_emul: remove redundant brackets Change due to review comment: remove redundant brackets for pointer value access. Signed-off-by: Florian Grandel --- drivers/rtc/rtc_emul.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc_emul.c b/drivers/rtc/rtc_emul.c index f8f92447485b..bf95fa87813b 100644 --- a/drivers/rtc/rtc_emul.c +++ b/drivers/rtc/rtc_emul.c @@ -277,7 +277,7 @@ static int rtc_emul_set_time(const struct device *dev, const struct rtc_time *ti K_SPINLOCK(&data->lock) { - data->datetime = (*timeptr); + data->datetime = *timeptr; data->datetime.tm_isdst = -1; data->datetime.tm_nsec = 0; @@ -306,7 +306,7 @@ static int rtc_emul_get_time(const struct device *dev, struct rtc_time *timeptr) K_SPINLOCK_BREAK; } - (*timeptr) = data->datetime; + *timeptr = data->datetime; } return ret; @@ -322,7 +322,7 @@ static int rtc_emul_alarm_get_supported_fields(const struct device *dev, uint16 return -EINVAL; } - (*mask) = (RTC_ALARM_TIME_MASK_SECOND + *mask = (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY @@ -374,8 +374,8 @@ static int rtc_emul_alarm_get_time(const struct device *dev, uint16_t id, uint16 K_SPINLOCK(&data->lock) { - (*timeptr) = data->alarms[id].datetime; - (*mask) = data->alarms[id].mask; + *timeptr = data->alarms[id].datetime; + *mask = data->alarms[id].mask; } return 0; @@ -454,7 +454,7 @@ static int rtc_emul_get_calibration(const struct device *dev, int32_t *calibrati K_SPINLOCK(&data->lock) { - (*calibration) = data->calibration; + *calibration = data->calibration; } return 0; From 5a36d380b5e7bc4eb4e81ae7e928cfee1f750c7f Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Fri, 30 Jun 2023 15:52:38 +0200 Subject: [PATCH 1174/2042] shields: semtech_sx1276mb1mas: new shield Add Arduino compatible LoRaWAN shield based on SX1276 tranceiver from Semtech. Provide minimal documentation on how to use it. Tested with `nucleo_l073rz` platform. Signed-off-by: Marcin Niestroj --- .../semtech_sx1276mb1mas/Kconfig.shield | 5 ++ .../semtech_sx1276mb1mas/doc/index.rst | 76 +++++++++++++++++++ .../semtech_sx1276mb1mas.overlay | 34 +++++++++ 3 files changed, 115 insertions(+) create mode 100644 boards/shields/semtech_sx1276mb1mas/Kconfig.shield create mode 100644 boards/shields/semtech_sx1276mb1mas/doc/index.rst create mode 100644 boards/shields/semtech_sx1276mb1mas/semtech_sx1276mb1mas.overlay diff --git a/boards/shields/semtech_sx1276mb1mas/Kconfig.shield b/boards/shields/semtech_sx1276mb1mas/Kconfig.shield new file mode 100644 index 000000000000..11c3e4af6059 --- /dev/null +++ b/boards/shields/semtech_sx1276mb1mas/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Marcin Niestroj +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_SEMTECH_SX1276MB1MAS + def_bool $(shields_list_contains,semtech_sx1276mb1mas) diff --git a/boards/shields/semtech_sx1276mb1mas/doc/index.rst b/boards/shields/semtech_sx1276mb1mas/doc/index.rst new file mode 100644 index 000000000000..bfdb9e41e674 --- /dev/null +++ b/boards/shields/semtech_sx1276mb1mas/doc/index.rst @@ -0,0 +1,76 @@ +.. _semtech_sx1276mb1mas: + +Semtech SX1276MB1MAS LoRa Shield +################################ + +Overview +******** + +The Semtech SX1276MB1MAS LoRa shield is an Arduino compatible shield based on +the SX1276 LoRa transceiver from Semtech. + +More information about the shield can be found at the `mbed SX1276MB1xAS +website`_. + +Pins Assignment of the Semtech SX1276MB1MAS LoRa Shield +======================================================= + ++-----------------------+-----------------+ +| Shield Connector Pin | Function | ++=======================+=================+ +| A0 | SX1276 RESET | ++-----------------------+-----------------+ +| A3 | SX1276 DIO4 (1) | ++-----------------------+-----------------+ +| A4 | Antenna RX/TX | ++-----------------------+-----------------+ +| D2 | SX1276 DIO0 | ++-----------------------+-----------------+ +| D3 | SX1276 DIO1 | ++-----------------------+-----------------+ +| D4 | SX1276 DIO2 | ++-----------------------+-----------------+ +| D5 | SX1276 DIO3 | ++-----------------------+-----------------+ +| D8 | SX1276 DIO4 (1) | ++-----------------------+-----------------+ +| D9 | SX1276 DIO5 | ++-----------------------+-----------------+ +| D10 | SX1276 SPI NSS | ++-----------------------+-----------------+ +| D11 | SX1276 SPI MOSI | ++-----------------------+-----------------+ +| D12 | SX1276 SPI MISO | ++-----------------------+-----------------+ +| D13 | SX1276 SPI SCK | ++-----------------------+-----------------+ + +(1) SX1276 DIO4 is configured on D8 by default. It is possible to reconfigure it + in devicetree to A3 if needed. + +Requirements +************ + +This shield can only be used with a board which provides a configuration for +Arduino connectors and defines node aliases for SPI and GPIO interfaces (see +:ref:`shields` for more details). + +Programming +*********** + +Set ``-DSHIELD=semtech_sx1271mb1mas`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/lorawan/class_a + :board: nucleo_l073rz + :shield: semtech_sx1276mb1mas + :goals: build + +References +********** + +.. target-notes:: + +.. _mbed SX1276MB1xAS website: + https://os.mbed.com/components/SX1276MB1xAS/ diff --git a/boards/shields/semtech_sx1276mb1mas/semtech_sx1276mb1mas.overlay b/boards/shields/semtech_sx1276mb1mas/semtech_sx1276mb1mas.overlay new file mode 100644 index 000000000000..230531d5559e --- /dev/null +++ b/boards/shields/semtech_sx1276mb1mas/semtech_sx1276mb1mas.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + lora0 = &lora_semtech_sx1276mb1mas; + }; +}; + +&arduino_spi { + status = "okay"; + + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ + + lora_semtech_sx1276mb1mas: lora@0 { + compatible = "semtech,sx1276"; + reg = <0x0>; + spi-max-frequency = ; + + reset-gpios = <&arduino_header 0 GPIO_ACTIVE_LOW>; /* A0 */ + + dio-gpios = <&arduino_header 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, /* DIO0 is D2 */ + <&arduino_header 9 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, /* DIO1 is D3 */ + <&arduino_header 10 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, /* DIO2 is D4 */ + <&arduino_header 11 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, /* DIO3 is D5 */ + <&arduino_header 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, /* DIO4 is D8 */ + <&arduino_header 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; /* DIO5 is D9 */ + + rfo-enable-gpios = <&arduino_header 4 GPIO_ACTIVE_HIGH>; /* RXTX_EXT is A4 */ + }; +}; From 7a479eec0df33d603b4c5d8cc3a30c07f9cebad9 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Mon, 12 Jun 2023 07:58:50 +0000 Subject: [PATCH 1175/2042] mgmt: ec_host_cmd: save result of IN_PROGRESS command Add a config to save the final result of a last host command that has sent EC_HOST_CMD_IN_PROGRESS response. To get the final result use the ec_host_cmd_send_in_progress_status function. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 25 +++++++++ subsys/mgmt/ec_host_cmd/Kconfig | 8 +++ subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 54 +++++++++++++++++++ 3 files changed, 87 insertions(+) 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 72f0d7325d84..e6f908355c00 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -282,6 +282,31 @@ const struct ec_host_cmd *ec_host_cmd_get_hc(void); FUNC_NORETURN void ec_host_cmd_task(void); #endif +#ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS +/** + * @brief Check if a Host Command that sent EC_HOST_CMD_IN_PROGRESS status has ended. + * + * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result. + * The final result can be get with the ec_host_cmd_send_in_progress_status function. + * + * @retval true if the Host Command endded + */ +bool ec_host_cmd_send_in_progress_ended(void); + +/** + * @brief Get final result of a last Host Command that has sent EC_HOST_CMD_IN_PROGRESS status. + * + * A Host Command that sends EC_HOST_CMD_IN_PROGRESS status doesn't send a final result. + * Get the saved status with this function. The status can be get only once. Futher calls return + * EC_HOST_CMD_UNAVAILABLE. + * + * Saving status of Host Commands that send response data is not supported. + * + * @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); +#endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ + /** * @} */ diff --git a/subsys/mgmt/ec_host_cmd/Kconfig b/subsys/mgmt/ec_host_cmd/Kconfig index f71e9a6122c1..8ca3d3607cf4 100644 --- a/subsys/mgmt/ec_host_cmd/Kconfig +++ b/subsys/mgmt/ec_host_cmd/Kconfig @@ -87,6 +87,14 @@ config EC_HOST_CMD_DEDICATED_THREAD The ec_host_cmd_init function creates a new thread dedicated for Host Command. Otherwise the ec_host_cmd_task function has to be called within another thread. +config EC_HOST_CMD_IN_PROGRESS_STATUS + bool "Save status of last IN_PROGRESS command" + default y if EC_HOST_CMD_BACKEND_SHI + help + Enable support for saving final status of a last command that has sent + EC_HOST_CMD_IN_PROGRESS status. The saved status can be get with the + ec_host_cmd_send_in_progress_status function. + source "subsys/mgmt/ec_host_cmd/Kconfig.logging" source "subsys/mgmt/ec_host_cmd/backends/Kconfig" 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 c160246dd7e9..448058fdf30e 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -51,6 +51,14 @@ static struct ec_host_cmd ec_host_cmd = { }, }; +#ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS +/* Indicates that a command has sent EC_HOST_CMD_IN_PROGRESS but hasn't sent a final status */ +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 uint8_t cal_checksum(const uint8_t *const buffer, const uint16_t size) { uint8_t checksum = 0; @@ -61,6 +69,22 @@ static uint8_t cal_checksum(const uint8_t *const buffer, const uint16_t size) return (uint8_t)(-checksum); } +#ifdef CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS +bool ec_host_cmd_send_in_progress_ended(void) +{ + return !cmd_in_progress; +} + +enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void) +{ + enum ec_host_cmd_status ret = saved_status; + + saved_status = EC_HOST_CMD_UNAVAILABLE; + + return ret; +} +#endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ + static void send_status_response(const struct ec_host_cmd_backend *backend, struct ec_host_cmd_tx_buf *tx, const enum ec_host_cmd_status status) @@ -161,6 +185,36 @@ 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; From 1b6d6fb135d46a0d247c06aee7eecb2e96812ef8 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 13 Jun 2023 07:23:53 +0000 Subject: [PATCH 1176/2042] mgmt: ec_host_cmd: add function to signal a new command Add a function to signal a new host command by a backend. Use a function instead of giving semaphore, because it allows more actions on rx event, common for all backends. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/backend.h | 5 ----- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 13 +++++++++++++ .../ec_host_cmd/backends/ec_host_cmd_backend_espi.c | 2 +- .../backends/ec_host_cmd_backend_shi_ite.c | 2 +- .../backends/ec_host_cmd_backend_shi_npcx.c | 2 +- .../backends/ec_host_cmd_backend_simulator.c | 2 +- .../ec_host_cmd/backends/ec_host_cmd_backend_uart.c | 2 +- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 11 +++++++++-- 8 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/zephyr/mgmt/ec_host_cmd/backend.h b/include/zephyr/mgmt/ec_host_cmd/backend.h index b9e3ac849c7c..38806647cc6a 100644 --- a/include/zephyr/mgmt/ec_host_cmd/backend.h +++ b/include/zephyr/mgmt/ec_host_cmd/backend.h @@ -47,11 +47,6 @@ struct ec_host_cmd_rx_ctx { uint8_t *buf; /** Number of bytes written to @a buf by backend. */ size_t len; - /** - * The backend gives @a handler_owns, when data in @a buf are ready. - * The handler takes @a handler_owns to read data in @a buf. - */ - struct k_sem handler_owns; }; /** 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 e6f908355c00..0d167a11b2bb 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -24,6 +24,11 @@ struct ec_host_cmd { struct ec_host_cmd_rx_ctx rx_ctx; struct ec_host_cmd_tx_buf tx; struct ec_host_cmd_backend *backend; + /** + * The backend gives rx_ready (by calling the ec_host_cmd_send_receive function), + * when data in rx_ctx are ready. The handler takes rx_ready to read data in rx_ctx. + */ + struct k_sem rx_ready; #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD struct k_thread thread; #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */ @@ -260,6 +265,14 @@ int ec_host_cmd_init(struct ec_host_cmd_backend *backend); int ec_host_cmd_send_response(enum ec_host_cmd_status status, const struct ec_host_cmd_handler_args *args); +/** + * @brief Signal a new host command + * + * Signal that a new host command has been received. The function should be called by a backend + * after copying data to the rx buffer and setting the length. + */ +void ec_host_cmd_rx_notify(void); + /** * @brief Get the main ec host command structure * diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c index 41ea6fa02fce..dd7dfa9099c6 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_espi.c @@ -89,7 +89,7 @@ static void espi_handler(const struct device *dev, struct espi_callback *cb, /* Even in case of errors, let the general handler send response */ hc_espi->state = ESPI_STATE_PROCESSING; - k_sem_give(&hc_espi->rx_ctx->handler_owns); + ec_host_cmd_rx_notify(); } static int ec_host_cmd_espi_init(const struct ec_host_cmd_backend *backend, diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c index abba6b649452..e84b7d351e33 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_ite.c @@ -263,7 +263,7 @@ static void shi_ite_parse_header(const struct device *dev) shi_ite_host_request_data(data->rx_ctx->buf + sizeof(*r), data->rx_ctx->len - sizeof(*r)); - k_sem_give(&data->rx_ctx->handler_owns); + ec_host_cmd_rx_notify(); } else { /* Invalid version number */ LOG_ERR("Invalid version number"); 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 9b8e19cf988c..86f40f0eed80 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 @@ -349,7 +349,7 @@ static void shi_npcx_handle_host_package(const struct device *dev) data->out_msg[0] = EC_SHI_FRAME_START; /* Wake-up the HC handler thread */ - k_sem_give(&data->rx_ctx->handler_owns); + ec_host_cmd_rx_notify(); } static int shi_npcx_host_request_expected_size(const struct ec_host_cmd_request_header *r) diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c index 5cde38a6a817..a0369cf1ef2b 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_simulator.c @@ -71,7 +71,7 @@ int ec_host_cmd_backend_sim_data_received(const uint8_t *buffer, size_t len) memcpy(hc_sim->rx_ctx->buf, buffer, len); hc_sim->rx_ctx->len = len; - k_sem_give(&hc_sim->rx_ctx->handler_owns); + ec_host_cmd_rx_notify(); return 0; } diff --git a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_uart.c b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_uart.c index d7f4cbe00363..a15eecfc4e79 100644 --- a/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_uart.c +++ b/subsys/mgmt/ec_host_cmd/backends/ec_host_cmd_backend_uart.c @@ -200,7 +200,7 @@ static void uart_callback(const struct device *dev, struct uart_event *evt, void */ hc_uart->state = UART_HOST_CMD_PROCESSING; - k_sem_give(&hc_uart->rx_ctx->handler_owns); + ec_host_cmd_rx_notify(); } else if (hc_uart->rx_ctx->len > expected_len) { /* Overrun error, set the state and wait for timeout */ hc_uart->state = UART_HOST_CMD_RX_OVERRUN; 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 448058fdf30e..6d0c3ee2da95 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -239,6 +239,13 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, return hc->backend->api->send(hc->backend); } +void ec_host_cmd_rx_notify(void) +{ + struct ec_host_cmd *hc = &ec_host_cmd; + + k_sem_give(&hc->rx_ready); +} + static void ec_host_cmd_log_request(const uint8_t *rx_buf) { static uint16_t prev_cmd; @@ -293,7 +300,7 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * while (1) { /* Wait until RX messages is received on host interface */ - k_sem_take(&rx->handler_owns, K_FOREVER); + k_sem_take(&hc->rx_ready, K_FOREVER); ec_host_cmd_log_request(rx->buf); status = verify_rx(rx); @@ -358,7 +365,7 @@ int ec_host_cmd_init(struct ec_host_cmd_backend *backend) hc->backend = backend; /* Allow writing to rx buff at startup */ - k_sem_init(&hc->rx_ctx.handler_owns, 0, 1); + k_sem_init(&hc->rx_ready, 0, 1); handler_tx_buf = hc->tx.buf; handler_rx_buf = hc->rx_ctx.buf; From b6a3254d8bad78a749eed165c9f76043485c7b52 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 13 Jun 2023 10:37:46 +0000 Subject: [PATCH 1177/2042] mgmt: ec_host_cmd: verify a command before passing it to handler Verify validity of a received command before passing it to the general handler. It allows performing some actions, right after receiving the command. The context switch is not needed. Such feature may be needed for overloaded system, where instant reboot is required. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 2 ++ subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 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 0d167a11b2bb..11566b4faccd 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -29,6 +29,8 @@ struct ec_host_cmd { * when data in rx_ctx are ready. The handler takes rx_ready to read data in rx_ctx. */ struct k_sem rx_ready; + /** Status of the rx data checked in the ec_host_cmd_send_received function. */ + enum ec_host_cmd_status rx_status; #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD struct k_thread thread; #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */ 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 6d0c3ee2da95..61aaa262f30f 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -242,6 +242,9 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, void ec_host_cmd_rx_notify(void) { struct ec_host_cmd *hc = &ec_host_cmd; + struct ec_host_cmd_rx_ctx *rx = &hc->rx_ctx; + + hc->rx_status = verify_rx(rx); k_sem_give(&hc->rx_ready); } @@ -303,9 +306,12 @@ FUNC_NORETURN static void ec_host_cmd_thread(void *hc_handle, void *arg2, void * k_sem_take(&hc->rx_ready, K_FOREVER); ec_host_cmd_log_request(rx->buf); - status = verify_rx(rx); - if (status != EC_HOST_CMD_SUCCESS) { - ec_host_cmd_send_response(status, &args); + + /* Check status of the rx data, that has been verified in + * ec_host_cmd_send_received. + */ + if (hc->rx_status != EC_HOST_CMD_SUCCESS) { + ec_host_cmd_send_response(hc->rx_status, &args); continue; } From b04692b74764715bde5839e016bd0c551df55f49 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 13 Jun 2023 10:30:37 +0000 Subject: [PATCH 1178/2042] mgmt: ec_host_cmd: add user callback for a new command Add a user possibility to set a callback for receiving a new function. It allows instant performing some actions, that need to be done before context switch. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 126 +++++++++++------- subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 12 ++ 2 files changed, 88 insertions(+), 50 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 11566b4faccd..30bb04e8ee4f 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -20,6 +20,66 @@ #include #include +/** + * @brief Host command response codes (16-bit). + */ +enum ec_host_cmd_status { + /** Host command was successful. */ + EC_HOST_CMD_SUCCESS = 0, + /** The specified command id is not recognized or supported. */ + EC_HOST_CMD_INVALID_COMMAND = 1, + /** Generic Error. */ + EC_HOST_CMD_ERROR = 2, + /** One of more of the input request parameters is invalid. */ + EC_HOST_CMD_INVALID_PARAM = 3, + /** Host command is not permitted. */ + EC_HOST_CMD_ACCESS_DENIED = 4, + /** Response was invalid (e.g. not version 3 of header). */ + EC_HOST_CMD_INVALID_RESPONSE = 5, + /** Host command id version unsupported. */ + EC_HOST_CMD_INVALID_VERSION = 6, + /** Checksum did not match. */ + EC_HOST_CMD_INVALID_CHECKSUM = 7, + /** A host command is currently being processed. */ + EC_HOST_CMD_IN_PROGRESS = 8, + /** Requested information is currently unavailable. */ + EC_HOST_CMD_UNAVAILABLE = 9, + /** Timeout during processing. */ + EC_HOST_CMD_TIMEOUT = 10, + /** Data or table overflow. */ + EC_HOST_CMD_OVERFLOW = 11, + /** Header is invalid or unsupported (e.g. not version 3 of header). */ + EC_HOST_CMD_INVALID_HEADER = 12, + /** Did not receive all expected request data. */ + EC_HOST_CMD_REQUEST_TRUNCATED = 13, + /** Response was too big to send within one response packet. */ + EC_HOST_CMD_RESPONSE_TOO_BIG = 14, + /** Error on underlying communication bus. */ + EC_HOST_CMD_BUS_ERROR = 15, + /** System busy. Should retry later. */ + EC_HOST_CMD_BUSY = 16, + /** Header version invalid. */ + EC_HOST_CMD_INVALID_HEADER_VERSION = 17, + /** Header CRC invalid. */ + EC_HOST_CMD_INVALID_HEADER_CRC = 18, + /** Data CRC invalid. */ + EC_HOST_CMD_INVALID_DATA_CRC = 19, + /** Can't resend response. */ + EC_HOST_CMD_DUP_UNAVAILABLE = 20, + + EC_HOST_CMD_MAX = UINT16_MAX /* Force enum to be 16 bits. */ +} __packed; + +enum ec_host_cmd_log_level { + EC_HOST_CMD_DEBUG_OFF, /* No Host Command debug output */ + EC_HOST_CMD_DEBUG_NORMAL, /* Normal output mode; skips repeated commands */ + EC_HOST_CMD_DEBUG_EVERY, /* Print every command */ + EC_HOST_CMD_DEBUG_PARAMS, /* ... and print params for request/response */ + EC_HOST_CMD_DEBUG_MODES /* Number of host command debug modes */ +}; + +typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data); + struct ec_host_cmd { struct ec_host_cmd_rx_ctx rx_ctx; struct ec_host_cmd_tx_buf tx; @@ -31,6 +91,12 @@ struct ec_host_cmd { struct k_sem rx_ready; /** Status of the rx data checked in the ec_host_cmd_send_received function. */ enum ec_host_cmd_status rx_status; + /** + * User callback after receiving a command. It is called by the ec_host_cmd_send_received + * function. + */ + ec_host_cmd_user_cb_t user_cb; + void *user_data; #ifdef CONFIG_EC_HOST_CMD_DEDICATED_THREAD struct k_thread thread; #endif /* CONFIG_EC_HOST_CMD_DEDICATED_THREAD */ @@ -185,56 +251,6 @@ struct ec_host_cmd_response_header { uint16_t reserved; } __packed; -/* - * Host command response codes (16-bit). - */ -enum ec_host_cmd_status { - /** Host command was successful. */ - EC_HOST_CMD_SUCCESS = 0, - /** The specified command id is not recognized or supported. */ - EC_HOST_CMD_INVALID_COMMAND = 1, - /** Generic Error. */ - EC_HOST_CMD_ERROR = 2, - /** One of more of the input request parameters is invalid. */ - EC_HOST_CMD_INVALID_PARAM = 3, - /** Host command is not permitted. */ - EC_HOST_CMD_ACCESS_DENIED = 4, - /** Response was invalid (e.g. not version 3 of header). */ - EC_HOST_CMD_INVALID_RESPONSE = 5, - /** Host command id version unsupported. */ - EC_HOST_CMD_INVALID_VERSION = 6, - /** Checksum did not match. */ - EC_HOST_CMD_INVALID_CHECKSUM = 7, - /** A host command is currently being processed. */ - EC_HOST_CMD_IN_PROGRESS = 8, - /** Requested information is currently unavailable. */ - EC_HOST_CMD_UNAVAILABLE = 9, - /** Timeout during processing. */ - EC_HOST_CMD_TIMEOUT = 10, - /** Data or table overflow. */ - EC_HOST_CMD_OVERFLOW = 11, - /** Header is invalid or unsupported (e.g. not version 3 of header). */ - EC_HOST_CMD_INVALID_HEADER = 12, - /** Did not receive all expected request data. */ - EC_HOST_CMD_REQUEST_TRUNCATED = 13, - /** Response was too big to send within one response packet. */ - EC_HOST_CMD_RESPONSE_TOO_BIG = 14, - /** Error on underlying communication bus. */ - EC_HOST_CMD_BUS_ERROR = 15, - /** System busy. Should retry later. */ - EC_HOST_CMD_BUSY = 16, - /** Header version invalid. */ - EC_HOST_CMD_INVALID_HEADER_VERSION = 17, - /** Header CRC invalid. */ - EC_HOST_CMD_INVALID_HEADER_CRC = 18, - /** Data CRC invalid. */ - EC_HOST_CMD_INVALID_DATA_CRC = 19, - /** Can't resend response. */ - EC_HOST_CMD_DUP_UNAVAILABLE = 20, - - EC_HOST_CMD_MAX = UINT16_MAX /* Force enum to be 16 bits. */ -} __packed; - /** * @brief Initialize the host command subsystem * @@ -275,6 +291,16 @@ int ec_host_cmd_send_response(enum ec_host_cmd_status status, */ void ec_host_cmd_rx_notify(void); +/** + * @brief Install a user callback for receiving a host command + * + * It allows installing a custom procedure needed by a user after receiving a command. + * + * @param[in] cb A callback to be installed. + * @param[in] user_data User data to be passed to the callback. + */ +void ec_host_cmd_set_user_cb(ec_host_cmd_user_cb_t cb, void *user_data); + /** * @brief Get the main ec host command structure * 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 61aaa262f30f..9335b3f593e3 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -179,6 +179,14 @@ static enum ec_host_cmd_status prepare_response(struct ec_host_cmd_tx_buf *tx, u return EC_HOST_CMD_SUCCESS; } +void ec_host_cmd_set_user_cb(ec_host_cmd_user_cb_t cb, void *user_data) +{ + struct ec_host_cmd *hc = &ec_host_cmd; + + hc->user_cb = cb; + hc->user_data = user_data; +} + int ec_host_cmd_send_response(enum ec_host_cmd_status status, const struct ec_host_cmd_handler_args *args) { @@ -246,6 +254,10 @@ void ec_host_cmd_rx_notify(void) hc->rx_status = verify_rx(rx); + if (!hc->rx_status && hc->user_cb) { + hc->user_cb(rx, hc->user_data); + } + k_sem_give(&hc->rx_ready); } From beb94af459c5c22adf3b1888187b2abf9f508256 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 28 Jun 2023 11:11:37 -0500 Subject: [PATCH 1179/2042] dts: lpc55S6X: Set DMA num otrigs at SOC level Set the DMA number of otrigs DT property at the SOC level instead of the board DTS because it is an SOC property and does not change on different boards. Signed-off-by: Declan Snyder --- boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi | 1 - boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts | 2 -- dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 2 ++ 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi index 28686359bc1c..d53158ea47e4 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi @@ -191,7 +191,6 @@ mikrobus_spi: &hs_lspi { * memory. */ dma-channels = <20>; - nxp,dma-num-of-otrigs = <4>; status = "okay"; }; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts index 239e0a2eb85d..281b1af7816a 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts @@ -146,13 +146,11 @@ * memory. */ dma-channels = <20>; - nxp,dma-num-of-otrigs = <4>; status = "okay"; }; &dma1 { dma-channels = <10>; - nxp,dma-num-of-otrigs = <4>; status = "okay"; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 6f1abfac048f..863e8d9c355b 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -179,6 +179,7 @@ compatible = "nxp,lpc-dma"; reg = <0x82000 0x1000>; interrupts = <1 0>; + nxp,dma-num-of-otrigs = <4>; nxp,dma-otrig-base-address = ; nxp,dma-itrig-base-address = ; status = "disabled"; @@ -189,6 +190,7 @@ compatible = "nxp,lpc-dma"; reg = <0xa7000 0x1000>; interrupts = <58 0>; + nxp,dma-num-of-otrigs = <4>; nxp,dma-otrig-base-address = ; nxp,dma-itrig-base-address = ; status = "disabled"; From f1b3c8a9ac349ab1f85b3643b9624907cbb21229 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 28 Jun 2023 12:06:24 -0500 Subject: [PATCH 1180/2042] dts: lpc dma: Use dma-channels prop correctly Current erroneous usages of dma-channels prop by lpc-dma nodes: * dma-channels devicetree property should describe the number of channels supported by the dma controller, not the number of channels in use. * LPC55SXX and RTXXX SOCs should be setting dma channels prop at SOC level, not board level, since it is an SOC property, not a board property. * lpc55s28 has 23 channels for dma0, not 20. * lpc55s28 has 10 channels for dma1, not 0. * lpc55s69 has 23 channels for dma0, not 20. * rt5xx has 37 channels for dma1, not 0. * rt6xx has 33 channels for dma0, not 20. * rt6xx has 33 channels for dma1, not 0. Fix all of these issues Signed-off-by: Declan Snyder --- .../arm/lpcxpresso55s28/lpcxpresso55s28.dts | 9 ------- .../arm/lpcxpresso55s69/lpcxpresso55s69.dtsi | 13 ---------- .../lpcxpresso55s69/lpcxpresso55s69_cpu0.dts | 26 ++++++------------- .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 9 ------- .../arm/mimxrt685_evk/mimxrt685_evk_cm33.dts | 9 ------- dts/arm/nxp/nxp_lpc55S2x_common.dtsi | 2 ++ dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 2 ++ dts/arm/nxp/nxp_rt5xx_common.dtsi | 2 ++ dts/arm/nxp/nxp_rt6xx_common.dtsi | 2 ++ 9 files changed, 16 insertions(+), 58 deletions(-) diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts index fe0054f645f0..28fd94003c66 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts @@ -87,15 +87,6 @@ }; &dma0 { - /* - * The total number of dma channels available is defined by - * FSL_FEATURE_DMA_NUMBER_OF_CHANNELS in the SoC features file. - * Since memory from the heap pool is allocated based on the number - * of DMA channels, set this property to as many channels is needed - * for the platform. Adjust HEAP_MEM_POOL_SIZE in case you need more - * memory. - */ - dma-channels = <20>; status = "okay"; }; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi index d53158ea47e4..11b3263c3aa9 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69.dtsi @@ -181,19 +181,6 @@ mikrobus_serial: &flexcomm2 { mikrobus_spi: &hs_lspi { }; -&dma0 { - /* - * The total number of dma channels available is defined by - * FSL_FEATURE_DMA_NUMBER_OF_CHANNELS in the SoC features file. - * Since memory from the heap pool is allocated based on the number - * of DMA channels, set this property to as many channels is needed - * for the platform. Adjust HEAP_MEM_POOL_SIZE in case you need more - * memory. - */ - dma-channels = <20>; - status = "okay"; -}; - &flexcomm0 { pinctrl-0 = <&pinmux_flexcomm0_usart>; pinctrl-names = "default"; diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts index 281b1af7816a..d53a1a68af47 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts @@ -136,24 +136,6 @@ pinctrl-names = "default"; }; -&dma0 { - /* - * The total number of dma channels available is defined by - * FSL_FEATURE_DMA_NUMBER_OF_CHANNELS in the SoC features file. - * Since memory from the heap pool is allocated based on the number - * of DMA channels, set this property to as many channels is needed - * for the platform. Adjust HEAP_MEM_POOL_SIZE in case you need more - * memory. - */ - dma-channels = <20>; - status = "okay"; -}; - -&dma1 { - dma-channels = <10>; - status = "okay"; -}; - &mailbox0 { status = "okay"; }; @@ -210,3 +192,11 @@ i2s1: &flexcomm7 { &sc_timer { status = "okay"; }; + +&dma0 { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index 2d8802c996b5..c82a526a6546 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -364,15 +364,6 @@ arduino_serial: &flexcomm12 { }; &dma0 { - /* - * The total number of dma channels available is defined by - * FSL_FEATURE_DMA_NUMBER_OF_CHANNELS in the SoC features file. - * Since memory from the heap pool is allocated based on the number - * of DMA channels, set this property to as many channels is needed - * for the platform. Adjust HEAP_MEM_POOL_SIZE in case you need more - * memory. - */ - dma-channels = <37>; status = "okay"; }; diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts index 6c36982d91f5..9d9c26875c1c 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts @@ -311,15 +311,6 @@ i2s1: &flexcomm3 { }; &dma0 { - /* - * The total number of dma channels available is defined by - * FSL_FEATURE_DMA_NUMBER_OF_CHANNELS in the SoC features file. - * Since memory from the heap pool is allocated based on the number - * of DMA channels, set this property to as many channels is needed - * for the platform. Adjust HEAP_MEM_POOL_SIZE in case you need more - * memory. - */ - dma-channels = <20>; status = "okay"; }; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 3aca92e41dcd..1098449163fe 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -159,6 +159,7 @@ compatible = "nxp,lpc-dma"; reg = <0x82000 0x1000>; interrupts = <1 0>; + dma-channels = <23>; status = "disabled"; #dma-cells = <1>; }; @@ -167,6 +168,7 @@ compatible = "nxp,lpc-dma"; reg = <0xa7000 0x1000>; interrupts = <58 0>; + dma-channels = <10>; status = "disabled"; #dma-cells = <1>; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 863e8d9c355b..f4ccfde8b2b2 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -179,6 +179,7 @@ compatible = "nxp,lpc-dma"; reg = <0x82000 0x1000>; interrupts = <1 0>; + dma-channels = <23>; nxp,dma-num-of-otrigs = <4>; nxp,dma-otrig-base-address = ; nxp,dma-itrig-base-address = ; @@ -190,6 +191,7 @@ compatible = "nxp,lpc-dma"; reg = <0xa7000 0x1000>; interrupts = <58 0>; + dma-channels = <10>; nxp,dma-num-of-otrigs = <4>; nxp,dma-otrig-base-address = ; nxp,dma-itrig-base-address = ; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index b9a3de432c42..a180a80117a7 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -326,6 +326,7 @@ compatible = "nxp,lpc-dma"; reg = <0x104000 0x1000>; interrupts = <1 0>; + dma-channels = <37>; status = "disabled"; #dma-cells = <1>; }; @@ -334,6 +335,7 @@ compatible = "nxp,lpc-dma"; reg = <0x105000 0x1000>; interrupts = <54 0>; + dma-channels = <37>; status = "disabled"; #dma-cells = <1>; }; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index fe77c0d121a9..62fdd0ca705d 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -258,6 +258,7 @@ compatible = "nxp,lpc-dma"; reg = <0x104000 0x1000>; interrupts = <1 0>; + dma-channels = <33>; status = "disabled"; #dma-cells = <1>; }; @@ -266,6 +267,7 @@ compatible = "nxp,lpc-dma"; reg = <0x105000 0x1000>; interrupts = <54 0>; + dma-channels = <33>; status = "disabled"; #dma-cells = <1>; }; From bb74b311fe8b24afc2c6f7e5eb373fdc9ff02f6a Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 26 Jun 2023 10:36:17 -0500 Subject: [PATCH 1181/2042] drivers: dma_mcux_lpc: remove SDK based macro remove the sdk based TOTAL_DMA_CHANNELS macro and instead just use the zephyr driver's num_of_channels field Signed-off-by: Declan Snyder --- drivers/dma/dma_mcux_lpc.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 65716cc5262a..c5de9bdc8991 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -266,7 +266,6 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, struct dma_mcux_lpc_dma_data *dma_data; struct dma_block_config *block_config; uint32_t virtual_channel; - uint32_t total_dma_channels; uint8_t otrig_index; uint8_t src_inc, dst_inc; bool is_periph = true; @@ -298,14 +297,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, return -EINVAL; } -#if defined FSL_FEATURE_DMA_NUMBER_OF_CHANNELS - total_dma_channels = FSL_FEATURE_DMA_NUMBER_OF_CHANNELS; -#else - total_dma_channels = FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(DEV_BASE(dev)); -#endif - /* Check if the dma channel number is valid */ - if (channel >= total_dma_channels) { + if (channel >= dev_config->num_of_channels) { LOG_ERR("invalid DMA channel number %d", channel); return -EINVAL; } @@ -676,7 +669,6 @@ static int dma_mcux_lpc_init(const struct device *dev) { const struct dma_mcux_lpc_config *config = dev->config; struct dma_mcux_lpc_dma_data *data = dev->data; - int total_dma_channels; /* Indicate that the Otrig Muxes are not connected */ for (int i = 0; i < config->num_of_otrigs; i++) { @@ -684,17 +676,11 @@ static int dma_mcux_lpc_init(const struct device *dev) data->otrig_array[i].linked_channel = EMPTY_OTRIG; } -#if defined FSL_FEATURE_DMA_NUMBER_OF_CHANNELS - total_dma_channels = FSL_FEATURE_DMA_NUMBER_OF_CHANNELS; -#else - total_dma_channels = FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn(DEV_BASE(dev)); -#endif - /* * Initialize to -1 to indicate dma channel does not have a slot * assigned to store dma channel data */ - for (int i = 0; i < total_dma_channels; i++) { + for (int i = 0; i < config->num_of_channels; i++) { data->channel_index[i] = -1; } @@ -739,13 +725,6 @@ static const struct dma_mcux_lpc_config dma_##n##_config = { \ IRQ_FUNC_INIT \ } -#ifdef FSL_FEATURE_DMA_NUMBER_OF_CHANNELS -#define TOTAL_DMA_CHANNELS FSL_FEATURE_DMA_NUMBER_OF_CHANNELS -#else -#define TOTAL_DMA_CHANNELS FSL_FEATURE_DMA_NUMBER_OF_CHANNELSn \ - ((DMA_Type *)DT_INST_REG_ADDR(n)) -#endif - #define DMA_INIT(n) \ \ static const struct dma_mcux_lpc_config dma_##n##_config; \ @@ -757,7 +736,8 @@ static const struct dma_mcux_lpc_config dma_##n##_config = { \ [DT_INST_PROP_OR(n, nxp_dma_num_of_otrigs, 0)]; \ \ static int8_t \ - dma_##n##_channel_index_arr[TOTAL_DMA_CHANNELS] = {0}; \ + dma_##n##_channel_index_arr \ + [DT_INST_PROP(n, dma_channels)] = {0}; \ \ static struct dma_mcux_lpc_dma_data dma_data_##n = { \ .channel_data = dma_##n##_channel_data_arr, \ From 1601725354e0e099d3b3d90f334bcf49a9300fdf Mon Sep 17 00:00:00 2001 From: Marek Pieta Date: Tue, 11 Jul 2023 15:26:22 +0200 Subject: [PATCH 1182/2042] drivers: sensor: qdec_nrfx: Workaround spurious samplerdy event The underlying HAL driver may improperly forward an samplerdy event even if it's disabled in the configuration. Ignore the event to prevent error logs until the issue is fixed in HAL. Signed-off-by: Marek Pieta --- drivers/sensor/qdec_nrfx/qdec_nrfx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/sensor/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/qdec_nrfx/qdec_nrfx.c index c8c053f29af3..7d8f71cede20 100644 --- a/drivers/sensor/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/qdec_nrfx/qdec_nrfx.c @@ -135,6 +135,13 @@ static void qdec_nrfx_event_handler(nrfx_qdec_event_t event, void *p_context) unsigned int key; switch (event.type) { + case NRF_QDEC_EVENT_SAMPLERDY: + /* The underlying HAL driver may improperly forward an samplerdy event even if it's + * disabled in the configuration. Ignore the event to prevent error logs until the + * issue is fixed in HAL. + */ + break; + case NRF_QDEC_EVENT_REPORTRDY: accumulate(dev_data, event.data.report.acc); From 5e2588052536941b003a932ea2309962e555dc4d Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 16:43:01 +0200 Subject: [PATCH 1183/2042] dts: arm: st: wba: Add timer support for STM32WBA Add timer support for STM32WBA Signed-off-by: Guillaume Gautier --- dts/arm/st/wba/stm32wba.dtsi | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index bbf085365726..dabe82c77d7e 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -238,6 +238,60 @@ interrupt-names = "event", "error"; status = "disabled"; }; + + timers1: timers@40012c00 { + compatible = "st,stm32-timers"; + reg = <0x40012c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000800>; + resets = <&rctl STM32_RESET(APB2, 11U)>; + interrupts = <37 0>, <38 0>, <39 0>, <40 0>; + interrupt-names = "brk", "up", "trgcom", "cc"; + st,prescaler = <0>; + status = "disabled"; + }; + + timers2: timers@40000000 { + compatible = "st,stm32-timers"; + reg = <0x40000000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000001>; + resets = <&rctl STM32_RESET(APB1L, 0U)>; + interrupts = <41 0>; + interrupt-names = "global"; + st,prescaler = <0>; + status = "disabled"; + }; + + timers3: timers@40000400 { + compatible = "st,stm32-timers"; + reg = <0x40000400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000002>; + resets = <&rctl STM32_RESET(APB1L, 1U)>; + interrupts = <42 0>; + interrupt-names = "global"; + st,prescaler = <0>; + status = "disabled"; + }; + + timers16: timers@40014400 { + compatible = "st,stm32-timers"; + reg = <0x40014400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00020000>; + resets = <&rctl STM32_RESET(APB2, 17U)>; + interrupts = <51 0>; + interrupt-names = "global"; + status = "disabled"; + }; + + timers17: timers@40014800 { + compatible = "st,stm32-timers"; + reg = <0x40014800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00040000>; + resets = <&rctl STM32_RESET(APB2, 18U)>; + interrupts = <52 0>; + interrupt-names = "global"; + status = "disabled"; + }; + }; }; From 1c26ba1968c9f9290418c935e45feaa9d718341b Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 11 Jul 2023 16:01:40 +0200 Subject: [PATCH 1184/2042] dts: arm: st: wba: add pwm support Add PWM support for STM32WBA Signed-off-by: Guillaume Gautier --- dts/arm/st/wba/stm32wba.dtsi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index dabe82c77d7e..c8c76e7b5ca2 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -248,6 +249,12 @@ interrupt-names = "brk", "up", "trgcom", "cc"; st,prescaler = <0>; status = "disabled"; + + pwm { + compatible = "st,stm32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; }; timers2: timers@40000000 { @@ -259,6 +266,12 @@ interrupt-names = "global"; st,prescaler = <0>; status = "disabled"; + + pwm { + compatible = "st,stm32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; }; timers3: timers@40000400 { @@ -270,6 +283,12 @@ interrupt-names = "global"; st,prescaler = <0>; status = "disabled"; + + pwm { + compatible = "st,stm32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; }; timers16: timers@40014400 { @@ -280,6 +299,12 @@ interrupts = <51 0>; interrupt-names = "global"; status = "disabled"; + + pwm { + compatible = "st,stm32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; }; timers17: timers@40014800 { @@ -290,6 +315,12 @@ interrupts = <52 0>; interrupt-names = "global"; status = "disabled"; + + pwm { + compatible = "st,stm32-pwm"; + status = "disabled"; + #pwm-cells = <3>; + }; }; }; From efd5360954624d3409dd712b6a4fb1b72e437f4f Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 6 Mar 2023 17:04:43 +0100 Subject: [PATCH 1185/2042] dts: arm: st: wba: add counter support Add counter nodes to STM32WBA Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index c8c76e7b5ca2..cf46417aaaf3 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -267,6 +267,11 @@ st,prescaler = <0>; status = "disabled"; + counter { + compatible = "st,stm32-counter"; + status = "disabled"; + }; + pwm { compatible = "st,stm32-pwm"; status = "disabled"; @@ -284,6 +289,11 @@ st,prescaler = <0>; status = "disabled"; + counter { + compatible = "st,stm32-counter"; + status = "disabled"; + }; + pwm { compatible = "st,stm32-pwm"; status = "disabled"; @@ -300,6 +310,11 @@ interrupt-names = "global"; status = "disabled"; + counter { + compatible = "st,stm32-counter"; + status = "disabled"; + }; + pwm { compatible = "st,stm32-pwm"; status = "disabled"; @@ -316,6 +331,11 @@ interrupt-names = "global"; status = "disabled"; + counter { + compatible = "st,stm32-counter"; + status = "disabled"; + }; + pwm { compatible = "st,stm32-pwm"; status = "disabled"; From 829fa5e70a2a7c217193fc95e1324f4ca598c4bb Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 6 Mar 2023 17:06:21 +0100 Subject: [PATCH 1186/2042] drivers: counter: stm32wba: Avoid warning at build STM32WBA LL API defines non const TIM_TypeDef. Signed-off-by: Erwan Gouriou --- drivers/counter/counter_ll_stm32_timer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index 6308412d6eb0..c3bffe3f7c2b 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -48,7 +48,8 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32L1X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) + !defined(CONFIG_SOC_SERIES_STM32MP1X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_OC_GetCompareCH1, LL_TIM_OC_GetCompareCH2, LL_TIM_OC_GetCompareCH3, LL_TIM_OC_GetCompareCH4, @@ -79,7 +80,8 @@ static void(*const disable_it[TIMER_MAX_CH])(TIM_TypeDef *) = { !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32L1X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) + !defined(CONFIG_SOC_SERIES_STM32MP1X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) static uint32_t(*const check_it_enabled[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_IsEnabledIT_CC1, LL_TIM_IsEnabledIT_CC2, LL_TIM_IsEnabledIT_CC3, LL_TIM_IsEnabledIT_CC4, From d15f3448b5a865453eb8a91229ebcae46617d717 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 24 Jun 2022 14:44:54 +0200 Subject: [PATCH 1187/2042] drivers: adc: Update ADC driver for STM32WBA series Update ADC driver for STM32WBA series Signed-off-by: Guillaume Gautier --- drivers/adc/adc_stm32.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index dd617bf5d2cd..fbd9c1169c09 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -76,6 +76,7 @@ LOG_MODULE_REGISTER(adc_stm32); !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !defined(CONFIG_SOC_SERIES_STM32G0X) && \ !defined(CONFIG_SOC_SERIES_STM32L0X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ !defined(CONFIG_SOC_SERIES_STM32WLX) #define RANK(n) LL_ADC_REG_RANK_##n static const uint32_t table_rank[] = { @@ -376,7 +377,8 @@ static void adc_stm32_calib(const struct device *dev) DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) || \ defined(CONFIG_SOC_SERIES_STM32G0X) || \ defined(CONFIG_SOC_SERIES_STM32L0X) || \ - defined(CONFIG_SOC_SERIES_STM32WLX) + defined(CONFIG_SOC_SERIES_STM32WLX) || \ + defined(CONFIG_SOC_SERIES_STM32WBAX) LL_ADC_StartCalibration(adc); #elif defined(CONFIG_SOC_SERIES_STM32U5X) LL_ADC_StartCalibration(adc, LL_ADC_CALIB_OFFSET); @@ -420,6 +422,7 @@ static void adc_stm32_disable(ADC_TypeDef *adc) !DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) && \ !defined(CONFIG_SOC_SERIES_STM32G0X) && \ !defined(CONFIG_SOC_SERIES_STM32L0X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ !defined(CONFIG_SOC_SERIES_STM32WLX) if (LL_ADC_INJ_IsConversionOngoing(adc)) { LL_ADC_INJ_StopConversion(adc); @@ -845,6 +848,7 @@ static int start_read(const struct device *dev, !defined(CONFIG_SOC_SERIES_STM32F0X) && \ !defined(CONFIG_SOC_SERIES_STM32G0X) && \ !defined(CONFIG_SOC_SERIES_STM32L0X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) && \ !defined(CONFIG_SOC_SERIES_STM32WLX) if (data->channel_count > ARRAY_SIZE(table_seq_len)) { LOG_ERR("Too many channels for sequencer. Max: %d", ARRAY_SIZE(table_seq_len)); @@ -917,6 +921,12 @@ static int start_read(const struct device *dev, while (LL_ADC_IsActiveFlag_CCRDY(adc) == 0) { } LL_ADC_ClearFlag_CCRDY(adc); +#elif defined(CONFIG_SOC_SERIES_STM32WBAX) + LL_ADC_REG_StopConversion(adc); + while (LL_ADC_REG_IsStopConversionOngoing(adc) != 0) { + } + LL_ADC_REG_SetSequencerChannels(adc, channel); + LL_ADC_REG_SetSequencerConfigurable(adc, LL_ADC_REG_SEQ_FIXED); #elif defined(CONFIG_SOC_SERIES_STM32U5X) if (adc != ADC4) { LL_ADC_REG_SetSequencerRanks(adc, table_rank[channel_index], channel); @@ -1313,7 +1323,8 @@ static int adc_stm32_init(const struct device *dev) LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc), LL_ADC_CLOCK_SYNC_PCLK_DIV2); #elif defined(CONFIG_SOC_SERIES_STM32L1X) || \ - defined(CONFIG_SOC_SERIES_STM32U5X) + defined(CONFIG_SOC_SERIES_STM32U5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBAX) LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc), LL_ADC_CLOCK_ASYNC_DIV4); #endif From 2ca3d262055db21e2888f38fdc15865337a8843d Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 24 Jun 2022 14:45:47 +0200 Subject: [PATCH 1188/2042] dts: arm: st: wba: add adc support Add ADC4 in STM32WBA dts file Signed-off-by: Guillaume Gautier --- dts/arm/st/wba/stm32wba.dtsi | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index cf46417aaaf3..45decd8fa6d4 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -343,6 +345,23 @@ }; }; + adc4: adc@46021000 { + compatible = "st,stm32-adc"; + reg = <0x46021000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB4 0x00000020>; + interrupts = <65 0>; + status = "disabled"; + #io-channel-cells = <1>; + temp-channel = <19>; + vref-channel = <0>; + vbat-channel = <18>; + resolutions = ; + sampling-times = <2 4 8 13 20 40 80 815>; + num-sampling-time-common-channels = <2>; + }; }; }; From 52bd7fc147cf83166781e13a0710e04b9ab6a552 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 5 Jul 2022 14:31:58 +0200 Subject: [PATCH 1189/2042] dts: arm: st: wba: Add LPTIM for STM32WBA Add LPTIM support for STM32WBA Signed-off-by: Guillaume Gautier Signed-off-by: Alexandre Bourdiol --- dts/arm/st/wba/stm32wba.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 45decd8fa6d4..0f8c5ba2cbd4 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -362,6 +362,28 @@ sampling-times = <2 4 8 13 20 40 80 815>; num-sampling-time-common-channels = <2>; }; + + lptim1: timers@46004400 { + compatible = "st,stm32-lptim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x46004400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>; + interrupts = <49 1>; + interrupt-names = "wakeup"; + status = "disabled"; + }; + + lptim2: timers@40009400 { + compatible = "st,stm32-lptim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40009400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000020>; + interrupts = <50 1>; + interrupt-names = "wakeup"; + status = "disabled"; + }; }; }; From 38722ce9d037090efd13d9052d87a507a9821764 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 13 Jul 2022 17:13:16 +0200 Subject: [PATCH 1190/2042] soc: arm: st_stm32: stm32wba: Add Power support Add Power support Signed-off-by: Guillaume Gautier --- soc/arm/st_stm32/stm32wba/CMakeLists.txt | 4 + soc/arm/st_stm32/stm32wba/power.c | 120 +++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 soc/arm/st_stm32/stm32wba/power.c diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt index ac3ba70ace6e..59be7817eab8 100644 --- a/soc/arm/st_stm32/stm32wba/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -4,3 +4,7 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) + +zephyr_sources_ifdef(CONFIG_PM + power.c + ) diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c new file mode 100644 index 000000000000..51bc737858a1 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +void set_mode_stop(uint8_t substate_id) +{ + switch (substate_id) { + case 1: /* enter STOP0 mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); + break; + case 2: /* enter STOP1 mode */ + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1); + break; + default: + LOG_DBG("Unsupported power state substate-id %u", substate_id); + break; + } +} + +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 */ +__weak 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); + break; + case PM_STATE_STANDBY: + /* To be tested */ + set_mode_standby(substate_id); + break; + 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(); +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +__weak 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) { + 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(); + case PM_STATE_SOFT_OFF: + /* We should not get there */ + __fallthrough; + case PM_STATE_ACTIVE: + __fallthrough; + case PM_STATE_SUSPEND_TO_RAM: + __fallthrough; + case PM_STATE_SUSPEND_TO_DISK: + __fallthrough; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } + /* need to restore the clock */ + stm32_clock_control_init(NULL); + + /* + * System is now in active mode. + * Reenable interrupts which were disabled + * when OS started idling code. + */ + irq_unlock(0); +} + +/* Initialize STM32 Power */ +static int stm32_power_init(void) +{ + /* enable Power clock */ + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); + +#ifdef CONFIG_DEBUG + /* Enable the Debug Module during all and any Low power mode */ + LL_DBGMCU_EnableDBGStopMode(); +#endif /* CONFIG_DEBUG */ + + return 0; +} + +SYS_INIT(stm32_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 8432081f515bb5a08992e32b998fc97dcd5f5826 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 13 Jul 2022 17:26:43 +0200 Subject: [PATCH 1191/2042] soc: arm: st_stm32: stm32wba: Add LPTIM to Kconfig For STM32WBA, enable LPTIM if Power management is enabled Signed-off-by: Guillaume Gautier --- soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index e3dfeab20189..e6d57729a092 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -10,4 +10,7 @@ source "soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba*" config SOC_SERIES default "stm32wba" +config STM32_LPTIM_TIMER + default y if PM + endif # SOC_SERIES_STM32WBAX From 3359259a6927e56b8b41c042471033047445f88e Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 1 Mar 2023 16:14:55 +0100 Subject: [PATCH 1192/2042] drivers: timers: Add LPTIM support for STM32WBA Add LPTIM support for STM32WBA Signed-off-by: Erwan Gouriou --- drivers/timer/stm32_lptim_timer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index 05a8c611bc1f..e8938399db77 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -343,6 +343,8 @@ static int sys_clock_driver_init(void) LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_LPTIM1); #elif defined(LL_APB3_GRP1_PERIPH_LPTIM1) LL_SRDAMR_GRP1_EnableAutonomousClock(LL_SRDAMR_GRP1_PERIPH_LPTIM1AMEN); +#elif defined(LL_APB7_GRP1_PERIPH_LPTIM1) + LL_APB7_GRP1_ReleaseReset(LL_APB7_GRP1_PERIPH_LPTIM1); #endif /* Enable LPTIM clock source */ @@ -413,7 +415,8 @@ static int sys_clock_driver_init(void) 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)); -#ifdef CONFIG_SOC_SERIES_STM32U5X +#if defined(CONFIG_SOC_SERIES_STM32U5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBAX) LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1, LL_LPTIM_OUTPUT_POLARITY_REGULAR); #else @@ -425,7 +428,8 @@ static int sys_clock_driver_init(void) /* counting start is initiated by software */ LL_LPTIM_TrigSw(LPTIM); -#ifdef CONFIG_SOC_SERIES_STM32U5X +#if defined(CONFIG_SOC_SERIES_STM32U5X) || \ + defined(CONFIG_SOC_SERIES_STM32WBAX) /* Enable the LPTIM before proceeding with configuration */ LL_LPTIM_Enable(LPTIM); @@ -451,7 +455,8 @@ static int sys_clock_driver_init(void) accumulated_lptim_cnt = 0; -#ifndef CONFIG_SOC_SERIES_STM32U5X +#if !defined(CONFIG_SOC_SERIES_STM32U5X) && \ + !defined(CONFIG_SOC_SERIES_STM32WBAX) /* Enable the LPTIM counter */ LL_LPTIM_Enable(LPTIM); #endif From 51b02512846f6ba3de99e34c3710a5aa43ff3da0 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 11 Jul 2023 16:14:26 +0200 Subject: [PATCH 1193/2042] boards: arm: nucleo_wba52cg: add adc, lptim and power states Add ADC, LPTIM and power states to the Nucleo WBA52CG board Signed-off-by: Guillaume Gautier --- boards/arm/nucleo_wba52cg/Kconfig.defconfig | 4 ++++ boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst | 2 ++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 16 ++++++++++++++++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml | 1 + 4 files changed, 23 insertions(+) diff --git a/boards/arm/nucleo_wba52cg/Kconfig.defconfig b/boards/arm/nucleo_wba52cg/Kconfig.defconfig index dfdac1bba98b..36f0e77818b0 100644 --- a/boards/arm/nucleo_wba52cg/Kconfig.defconfig +++ b/boards/arm/nucleo_wba52cg/Kconfig.defconfig @@ -13,4 +13,8 @@ config SPI_STM32_INTERRUPT default y depends on SPI +# LPTIM clocked by LSE, force tick freq to 4096 for tick accuracy +config SYS_CLOCK_TICKS_PER_SEC + default 4096 if STM32_LPTIM_TIMER + endif # BOARD_NUCLEO_WBA52CG diff --git a/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst index b8433afbbc44..6fa83ae8856f 100644 --- a/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst +++ b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst @@ -173,6 +173,8 @@ The Zephyr nucleo_wba52cg board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | SPI | on-chip | spi | +-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index 7565b43c55af..f59b38eaeed5 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -87,6 +87,10 @@ apb7-prescaler = <1>; }; +&cpu0 { + cpu-power-states = <&stop0 &stop1>; +}; + &usart1 { pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; @@ -107,3 +111,15 @@ status = "okay"; clock-frequency = ; }; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + pinctrl-names = "default"; + status = "okay"; +}; + +&lptim1 { + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; + status = "okay"; +}; diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml index bf0d55459f94..08aa1bec15fa 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml @@ -9,6 +9,7 @@ supported: - gpio - i2c - spi + - adc - arduino_gpio - arduino_i2c - arduino_spi From aa826ce64d0faa2e26c4f23d53c5db2193fe5c37 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Wed, 12 Jul 2023 09:14:17 +0200 Subject: [PATCH 1194/2042] tests: drivers: adc: adc_api: add stm32wba overlay for adc test Add Nucleo WBA52CG overlay for adc_api test Signed-off-by: Guillaume Gautier --- .../adc/adc_api/boards/nucleo_wba52cg.overlay | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay diff --git a/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay b/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000..6b96b54ef63f --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nucleo_wba52cg.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) Benjamin Björnsson + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; + +&adc4 { + #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 b5970d21f3729b79b5799d7a0c0e7c4c4007f926 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 10 Jul 2023 16:19:25 +0000 Subject: [PATCH 1195/2042] drivers: mbox: initialize before ipc Change the default mbox initialization priority so that it initializes before ipc, as some ipc drivers depends on it. Found with: $ west build -p -b nrf5340dk_nrf5340_cpuapp \ samples/subsys/ipc/ipc_service/icmsg_me \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /ipc/ipc1 POST_KERNEL 46 < /soc/peripheral@50000000/mbox@2a000 POST_KERNEL 50 ERROR: /ipc/ipc0 POST_KERNEL 46 < /soc/peripheral@50000000/mbox@2a000 POST_KERNEL 50 Signed-off-by: Fabio Baltieri --- drivers/mbox/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index 58dd92f208a3..79f220794917 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -16,7 +16,7 @@ source "drivers/mbox/Kconfig.nxp_s32" config MBOX_INIT_PRIORITY int "MBOX init priority" - default KERNEL_INIT_PRIORITY_DEVICE + default 40 help MBOX driver device initialization priority. From e4ca936551aff44b827e3e78f08c78bd845c469f Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 5 Jul 2023 18:20:37 +0100 Subject: [PATCH 1196/2042] doc: Remove sphinx warning bt_ots_init pattern The bt_ots_init struct has been renamed to bt_ots_init_param in commit: cf0ff30b530a9897c34fb5106c2716d3c13945d6 That was previously triggering a warning in Sphinx, due to the same name being used for a struct and function, and this pattern was designed to silence it. We don't need the pattern any more as the warning is gone. Signed-off-by: Michael Jones --- doc/known-warnings.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/known-warnings.txt b/doc/known-warnings.txt index 623e89e423b4..abe8e7eca13f 100644 --- a/doc/known-warnings.txt +++ b/doc/known-warnings.txt @@ -7,7 +7,6 @@ .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*dmic_trigger.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: dma_config'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: net_if_mcast_monitor'.* -.*Duplicate C declaration.*\n.*'\.\. c:struct:: bt_ots_init'.* # Struct and typedef name .*Duplicate C declaration.*\n.*'\.\. c:.*:: zsock_fd_set'.* From 563b4540faffb03823dfdab6a3c61cb6abf07544 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 15 Jun 2023 11:07:39 +0100 Subject: [PATCH 1197/2042] drivers: retained_mem: Allow disabling mutex support Changes the Kconfig option to allow disabling mutex support, this is to allow other Kconfig options to disable the feature. Signed-off-by: Jamie McCrae --- drivers/retained_mem/Kconfig | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/retained_mem/Kconfig b/drivers/retained_mem/Kconfig index 8f134f94560b..4ea7dcd89492 100644 --- a/drivers/retained_mem/Kconfig +++ b/drivers/retained_mem/Kconfig @@ -16,13 +16,18 @@ config RETAINED_MEM_INIT_PRIORITY Retained memory devices initialization priority, config RETAINED_MEM_MUTEXES - bool "Retained memory mutex support" + bool default y depends on MULTITHREADING + depends on !RETAINED_MEM_MUTEX_FORCE_DISABLE + +config RETAINED_MEM_MUTEX_FORCE_DISABLE + bool "Disable retained memory mutex support" + depends on MULTITHREADING help - Use mutexes to prevent issues with concurrent retained memory access. - Should only be disabled whereby retained memory access is required - in an ISR or for special use cases. + Disable use of mutexes which prevent issues with concurrent retained + memory access. This option should only be enabled when retained + memory access is required in an ISR or for special use cases. module = RETAINED_MEM module-str = retained_mem From 566fd8cb7cbeb6a61ad5f76a738b0323acb720a6 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 15 Jun 2023 11:08:53 +0100 Subject: [PATCH 1198/2042] retention: Allow disabling mutex support Changes the Kconfig option to allow disabling mutex support, this is to allow other Kconfig options to disable the feature. Signed-off-by: Jamie McCrae --- subsys/retention/Kconfig | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/subsys/retention/Kconfig b/subsys/retention/Kconfig index 1081e236f02b..5322a1168491 100644 --- a/subsys/retention/Kconfig +++ b/subsys/retention/Kconfig @@ -20,13 +20,18 @@ config RETENTION_INIT_PRIORITY priorities for retained memory drivers. config RETENTION_MUTEXES - bool "Retention mutex support" + bool default y depends on MULTITHREADING + depends on !RETENTION_MUTEX_FORCE_DISABLE + +config RETENTION_MUTEX_FORCE_DISABLE + bool "Disable retention mutex support" + depends on MULTITHREADING help - Use mutexes to prevent issues with concurrent retention device - access. Should only be disabled whereby retained memory access is - required in an ISR or for special use cases. + Disable use of mutexes which prevent issues with concurrent retention + device access. This option should only be enabled when retention + access is required in an ISR or for special use cases. config RETENTION_BUFFER_SIZE int "Retention stack buffer sizes" From a22fbfd1eb6f67ed20a8ce3401d829c278039c0c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 17 Jun 2023 15:43:59 +0100 Subject: [PATCH 1199/2042] input: add some basic debugging utilities Add two input subsystem options: one for dumping input events, one for triggering input reports from the shell. The two are independent from each other, so dumping can be enabled on any application that has no shell, but if the shell command is present logging can be toggled on and off with a shell command. Signed-off-by: Fabio Baltieri --- subsys/input/CMakeLists.txt | 1 + subsys/input/Kconfig | 14 ++++ subsys/input/input_utils.c | 129 ++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 subsys/input/input_utils.c diff --git a/subsys/input/CMakeLists.txt b/subsys/input/CMakeLists.txt index 593123774bba..bd26093228b6 100644 --- a/subsys/input/CMakeLists.txt +++ b/subsys/input/CMakeLists.txt @@ -3,5 +3,6 @@ zephyr_library() zephyr_library_sources(input.c) +zephyr_library_sources(input_utils.c) zephyr_library_sources_ifdef(CONFIG_INPUT_LONGPRESS input_longpress.c) diff --git a/subsys/input/Kconfig b/subsys/input/Kconfig index 6282841759eb..a32ebc03afbb 100644 --- a/subsys/input/Kconfig +++ b/subsys/input/Kconfig @@ -67,6 +67,20 @@ config INPUT_THREAD_STACK_SIZE endif # INPUT_MODE_THREAD +config INPUT_EVENT_DUMP + bool "Log all input events" + depends on LOG + help + Dump all input devents using log info messages, has to be enabled + with "input dump on" if INPUT_SHELL is used. + +config INPUT_SHELL + bool "Input shell" + depends on SHELL + help + Enable the input shell, for interacting with the input subsystem + through the shell interface. + config INPUT_LONGPRESS bool "Input longpress" default y diff --git a/subsys/input/input_utils.c b/subsys/input/input_utils.c new file mode 100644 index 000000000000..6d0a9085c6df --- /dev/null +++ b/subsys/input/input_utils.c @@ -0,0 +1,129 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(input); + +#ifdef CONFIG_INPUT_EVENT_DUMP +#ifdef CONFIG_INPUT_SHELL +static atomic_t dump_enable; + +static bool input_dump_enabled(void) +{ + return atomic_get(&dump_enable); +} + +static int input_cmd_dump(const struct shell *sh, size_t argc, char *argv[]) +{ + bool enabled; + int err = 0; + + enabled = shell_strtobool(argv[1], 0, &err); + if (err) { + shell_error(sh, "Invalid argument: %s", argv[1]); + return err; + } + + if (enabled) { + shell_info(sh, "Input event dumping enabled"); + atomic_set(&dump_enable, 1); + } else { + atomic_set(&dump_enable, 0); + } + + return 0; +} +#else +static bool input_dump_enabled(void) +{ + return true; +} +#endif /* CONFIG_INPUT_SHELL */ + +static void input_cb(struct input_event *evt) +{ + if (!input_dump_enabled()) { + return; + } + + LOG_INF("input event: dev=%-16s %3s type=%2x code=%3d value=%d", + evt->dev ? evt->dev->name : "NULL", + evt->sync ? "SYN" : "", + evt->type, + evt->code, + evt->value); +} +INPUT_LISTENER_CB_DEFINE(NULL, input_cb); +#endif /* CONFIG_INPUT_EVENT_DUMP */ + +#ifdef CONFIG_INPUT_SHELL +static int input_cmd_report(const struct shell *sh, size_t argc, char *argv[]) +{ + bool sync; + int err = 0; + uint32_t type, code, value; + + if (argc == 5) { + sync = shell_strtobool(argv[4], 0, &err); + if (err) { + shell_error(sh, "Invalid argument: %s", argv[4]); + return err; + } + } else { + sync = true; + } + + type = shell_strtoul(argv[1], 0, &err); + if (err) { + shell_error(sh, "Invalid argument: %s", argv[1]); + return err; + } + if (type > UINT8_MAX) { + shell_error(sh, "Out of range: %s", argv[1]); + return -EINVAL; + } + + code = shell_strtoul(argv[2], 0, &err); + if (err) { + shell_error(sh, "Invalid argument: %s", argv[2]); + return err; + } + if (code > UINT16_MAX) { + shell_error(sh, "Out of range: %s", argv[2]); + return -EINVAL; + } + + value = shell_strtoul(argv[3], 0, &err); + if (err) { + shell_error(sh, "Invalid argument: %s", argv[3]); + return err; + } + + input_report(NULL, type, code, value, sync, K_FOREVER); + + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_input_cmds, +#ifdef CONFIG_INPUT_EVENT_DUMP + SHELL_CMD_ARG(dump, NULL, + "Enable event dumping\n" + "usage: dump ", + input_cmd_dump, 2, 0), +#endif /* CONFIG_INPUT_EVENT_DUMP */ + SHELL_CMD_ARG(report, NULL, + "Trigger an input report event\n" + "usage: report []", + input_cmd_report, 4, 1), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(input, &sub_input_cmds, "Input commands", NULL); +#endif /* CONFIG_INPUT_SHELL */ From 15f78fa54501374394f48968e7ab3daa0221011e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 17 Jun 2023 15:50:18 +0100 Subject: [PATCH 1200/2042] samples: input_dump: use CONFIG_INPUT_EVENT_DUMP Now that input dump functionalities are at subsystem level, drop the custom code from the sample, just enable CONFIG_INPUT_EVENT_DUMP. Signed-off-by: Fabio Baltieri --- samples/subsys/input/input_dump/prj.conf | 4 ++++ samples/subsys/input/input_dump/src/main.c | 12 ------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/samples/subsys/input/input_dump/prj.conf b/samples/subsys/input/input_dump/prj.conf index de103d88fedb..e4c7fb97d5dd 100644 --- a/samples/subsys/input/input_dump/prj.conf +++ b/samples/subsys/input/input_dump/prj.conf @@ -1 +1,5 @@ +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y + CONFIG_INPUT=y +CONFIG_INPUT_EVENT_DUMP=y diff --git a/samples/subsys/input/input_dump/src/main.c b/samples/subsys/input/input_dump/src/main.c index 18effd39f4b3..8321cc74140f 100644 --- a/samples/subsys/input/input_dump/src/main.c +++ b/samples/subsys/input/input_dump/src/main.c @@ -5,18 +5,6 @@ */ #include -#include - -static void input_cb(struct input_event *evt) -{ - printf("input event: dev=%-16s %3s type=%2x code=%3d value=%d\n", - evt->dev ? evt->dev->name : "NULL", - evt->sync ? "SYN" : "", - evt->type, - evt->code, - evt->value); -} -INPUT_LISTENER_CB_DEFINE(NULL, input_cb); int main(void) { From b1bccc2ca84975bf4c0eefae4ba4d3c8074f7521 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 20 Jun 2023 15:06:05 +0100 Subject: [PATCH 1201/2042] tests: input_shell: add an input shell test Add a test to validate the input shell command and event dump output. Signed-off-by: Fabio Baltieri --- tests/subsys/input/input_shell/CMakeLists.txt | 8 ++++ tests/subsys/input/input_shell/prj.conf | 11 +++++ tests/subsys/input/input_shell/src/main.c | 41 +++++++++++++++++++ tests/subsys/input/input_shell/testcase.yaml | 14 +++++++ 4 files changed, 74 insertions(+) create mode 100644 tests/subsys/input/input_shell/CMakeLists.txt create mode 100644 tests/subsys/input/input_shell/prj.conf create mode 100644 tests/subsys/input/input_shell/src/main.c create mode 100644 tests/subsys/input/input_shell/testcase.yaml diff --git a/tests/subsys/input/input_shell/CMakeLists.txt b/tests/subsys/input/input_shell/CMakeLists.txt new file mode 100644 index 000000000000..86be092e6630 --- /dev/null +++ b/tests/subsys/input/input_shell/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_shell) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/input/input_shell/prj.conf b/tests/subsys/input/input_shell/prj.conf new file mode 100644 index 000000000000..c9239e22376c --- /dev/null +++ b/tests/subsys/input/input_shell/prj.conf @@ -0,0 +1,11 @@ +# 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_EVENT_DUMP=y +CONFIG_INPUT_SHELL=y diff --git a/tests/subsys/input/input_shell/src/main.c b/tests/subsys/input/input_shell/src/main.c new file mode 100644 index 000000000000..4f1b9a051066 --- /dev/null +++ b/tests/subsys/input/input_shell/src/main.c @@ -0,0 +1,41 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define SLEEP_TIME_MS 200 +#define CMD_BUF_LEN 128 + +int main(void) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + bool val = false; + int err; + char buf[CMD_BUF_LEN]; + + err = shell_execute_cmd(sh, "input dump on"); + if (err) { + printf("Failed to execute the shell command: %d.\n", + err); + } + + while (true) { + snprintf(buf, 128, "input report 1 2 %d", val); + err = shell_execute_cmd(sh, buf); + if (err) { + printf("Failed to execute the shell command: %d.\n", + err); + } + + val = !val; + + k_msleep(SLEEP_TIME_MS); + } + + return 0; +} diff --git a/tests/subsys/input/input_shell/testcase.yaml b/tests/subsys/input/input_shell/testcase.yaml new file mode 100644 index 000000000000..e226780164f7 --- /dev/null +++ b/tests/subsys/input/input_shell/testcase.yaml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +tests: + input.input_shell: + tags: input + platform_allow: + - native_posix + - native_posix_64 + harness: console + harness_config: + type: multi_line + regex: + - "I: input event: dev=NULL SYN type= 1 code= 2 value=0" + - "I: input event: dev=NULL SYN type= 1 code= 2 value=1" From d982ea54b6868b538326b65e5378a6cb6f32aab7 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 26 Jun 2023 20:46:22 +0530 Subject: [PATCH 1202/2042] drivers: pwm: Add support for pch intel blink driver This patch adds support for PWM blink which is found in intel's PCH hardwares. Signed-off-by: Anisetti Avinash Krishna --- drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.intel_blinky | 11 +++ drivers/pwm/pwm_intel_blinky.c | 129 +++++++++++++++++++++++++ dts/bindings/pwm/intel,blinky-pwm.yaml | 35 +++++++ 5 files changed, 178 insertions(+) create mode 100644 drivers/pwm/Kconfig.intel_blinky create mode 100644 drivers/pwm/pwm_intel_blinky.c create mode 100644 dts/bindings/pwm/intel,blinky-pwm.yaml diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index fcd0075eeed1..981428ff3140 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -32,6 +32,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_PCA9685 pwm_pca9685.c) zephyr_library_sources_ifdef(CONFIG_PWM_TEST pwm_test.c) zephyr_library_sources_ifdef(CONFIG_PWM_RPI_PICO pwm_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c) +zephyr_library_sources_ifdef(CONFIG_PWM_INTEL_BLINKY pwm_intel_blinky.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c) zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 021ad308033a..f205dbb525a0 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -85,4 +85,6 @@ source "drivers/pwm/Kconfig.test" source "drivers/pwm/Kconfig.rpi_pico" +source "drivers/pwm/Kconfig.intel_blinky" + endif # PWM diff --git a/drivers/pwm/Kconfig.intel_blinky b/drivers/pwm/Kconfig.intel_blinky new file mode 100644 index 000000000000..51d192f099e1 --- /dev/null +++ b/drivers/pwm/Kconfig.intel_blinky @@ -0,0 +1,11 @@ +# Intel Blinky PWM configuration options + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config PWM_INTEL_BLINKY + bool "Blinky PWM driver" + default y + depends on DT_HAS_INTEL_BLINKY_PWM_ENABLED + help + Enable the INTEL PCH PWM driver found on Intel SoCs diff --git a/drivers/pwm/pwm_intel_blinky.c b/drivers/pwm/pwm_intel_blinky.c new file mode 100644 index 000000000000..cf6df303a741 --- /dev/null +++ b/drivers/pwm/pwm_intel_blinky.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT intel_blinky_pwm + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PWM_ENABLE 0x80000000 +#define PWM_SWUP 0x40000000 +#define PWM_FREQ_INT_SHIFT 8 +#define PWM_BASE_UNIT_FRACTION 14 +#define PWM_FREQ_MAX 0x100 +#define PWM_DUTY_MAX 0x100 + +struct bk_intel_config { + DEVICE_MMIO_NAMED_ROM(reg_base); + uint32_t reg_offset; + uint32_t clock_freq; + uint32_t max_pins; +}; + +struct bk_intel_runtime { + DEVICE_MMIO_NAMED_RAM(reg_base); +}; + +static int bk_intel_set_cycles(const struct device *dev, uint32_t pin, + uint32_t period_cycles, uint32_t pulse_cycles, + pwm_flags_t flags) +{ + struct bk_intel_runtime *rt = dev->data; + const struct bk_intel_config *cfg = dev->config; + uint32_t ret = 0; + uint32_t val = 0; + uint32_t duty; + float period; + float out_freq; + uint32_t base_unit; + + if (pin >= cfg->max_pins) { + ret = -EINVAL; + goto err; + } + + out_freq = cfg->clock_freq / (float) period_cycles; + period = (out_freq * PWM_FREQ_MAX) / cfg->clock_freq; + base_unit = (uint32_t) (period * (1 << PWM_BASE_UNIT_FRACTION)); + duty = (pulse_cycles * PWM_DUTY_MAX) / period_cycles; + + if (duty) { + val = PWM_DUTY_MAX - duty; + val |= (base_unit << PWM_FREQ_INT_SHIFT); + } else { + val = PWM_DUTY_MAX - 1; + } + + val |= PWM_ENABLE | PWM_SWUP; + + if (period >= PWM_FREQ_MAX) { + ret = -EINVAL; + goto err; + } + + if (duty > PWM_DUTY_MAX) { + ret = -EINVAL; + goto err; + } + + sys_write32(val, rt->reg_base + cfg->reg_offset); +err: + return ret; +} + +static int bk_intel_get_cycles_per_sec(const struct device *dev, uint32_t pin, + uint64_t *cycles) +{ + const struct bk_intel_config *cfg = dev->config; + + if (pin >= cfg->max_pins) { + return -EINVAL; + } + + *cycles = cfg->clock_freq; + + return 0; +} + +static const struct pwm_driver_api api_funcs = { + .set_cycles = bk_intel_set_cycles, + .get_cycles_per_sec = bk_intel_get_cycles_per_sec, +}; + +static int bk_intel_init(const struct device *dev) +{ + struct bk_intel_runtime *runtime = dev->data; + const struct bk_intel_config *config = dev->config; + + device_map(&runtime->reg_base, + config->reg_base.phys_addr & ~0xFFU, + config->reg_base.size, + K_MEM_CACHE_NONE); + + return 0; +} + +#define BK_INTEL_DEV_CFG(n) \ + static const struct bk_intel_config bk_cfg_##n = { \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ + .reg_offset = DT_INST_PROP(n, reg_offset), \ + .max_pins = DT_INST_PROP(n, max_pins), \ + .clock_freq = DT_INST_PROP(n, clock_frequency), \ + }; \ + \ + static struct bk_intel_runtime bk_rt_##n; \ + DEVICE_DT_INST_DEFINE(n, &bk_intel_init, NULL, \ + &bk_rt_##n, &bk_cfg_##n, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &api_funcs); \ + +DT_INST_FOREACH_STATUS_OKAY(BK_INTEL_DEV_CFG) diff --git a/dts/bindings/pwm/intel,blinky-pwm.yaml b/dts/bindings/pwm/intel,blinky-pwm.yaml new file mode 100644 index 000000000000..10822317c09b --- /dev/null +++ b/dts/bindings/pwm/intel,blinky-pwm.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Intel blinky PWM + +compatible: "intel,blinky-pwm" + +include: [pwm-controller.yaml, base.yaml] + +properties: + reg: + required: true + + reg-offset: + type: int + required: true + description: PWM control register offset from base + + clock-frequency: + type: int + required: true + description: PWM Peripheral Clock frequency in Hz + + max-pins: + type: int + required: true + description: Maximum number of pins supported by platform + + "#pwm-cells": + const: 2 + +pwm-cells: + - channel + - period From 1fa341687e8973f5fd26a68f20ea2def08ebc80a Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 26 Jun 2023 20:53:14 +0530 Subject: [PATCH 1203/2042] dts: raptor_lake: Add pwm node for raptorlake Adds pwm node for intel raptorlake pch pwm blink IP Signed-off-by: Anisetti Avinash Krishna --- dts/x86/intel/raptor_lake.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index 7dc528aede02..1d0cf6aee5f5 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -496,6 +496,16 @@ status = "okay"; }; + pwm0: pwm@e06a0000 { + compatible = "intel,blinky-pwm"; + reg = <0xe06a0000 0x400>; + reg-offset = <0x304>; + clock-frequency = <32768>; + max-pins = <1>; + #pwm-cells = <2>; + status = "okay"; + }; + rtc: counter: rtc@70 { compatible = "motorola,mc146818"; reg = <0x70 0x0D 0x71 0x0D>; From c9cd273f7e23bc3e50fd1ae19f39907bf09b1c05 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Mon, 26 Jun 2023 21:17:44 +0530 Subject: [PATCH 1204/2042] tests: drivers: pwm: pwm_api: Enable pwm test for intel blinky Enable pwm api test for intel blinky on rpl_crb board. Signed-off-by: Anisetti Avinash Krishna --- boards/x86/rpl_crb/rpl_crb.yaml | 1 + tests/drivers/pwm/pwm_api/src/test_pwm.c | 8 ++++++++ tests/drivers/pwm/pwm_api/testcase.yaml | 1 + 3 files changed, 10 insertions(+) diff --git a/boards/x86/rpl_crb/rpl_crb.yaml b/boards/x86/rpl_crb/rpl_crb.yaml index 807ca8d8d3be..d46c99e487e1 100644 --- a/boards/x86/rpl_crb/rpl_crb.yaml +++ b/boards/x86/rpl_crb/rpl_crb.yaml @@ -10,6 +10,7 @@ supported: - smbus - watchdog - rtc + - pwm testing: ignore_tags: - net diff --git a/tests/drivers/pwm/pwm_api/src/test_pwm.c b/tests/drivers/pwm/pwm_api/src/test_pwm.c index 1ca33efe1d09..21f1b10960d7 100644 --- a/tests/drivers/pwm/pwm_api/src/test_pwm.c +++ b/tests/drivers/pwm/pwm_api/src/test_pwm.c @@ -47,6 +47,9 @@ #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_ftm_pwm) #define PWM_DEV_NODE DT_INST(0, nxp_kinetis_ftm_pwm) +#elif DT_HAS_COMPAT_STATUS_OKAY(intel_blinky_pwm) +#define PWM_DEV_NODE DT_INST(0, intel_blinky_pwm) + #else #error "Define a PWM device" #endif @@ -58,6 +61,11 @@ #define DEFAULT_PULSE_CYCLE 512 #define DEFAULT_PERIOD_NSEC 2000000 #define DEFAULT_PULSE_NSEC 500000 +#elif DT_HAS_COMPAT_STATUS_OKAY(intel_blinky_pwm) +#define DEFAULT_PERIOD_CYCLE 32768 +#define DEFAULT_PULSE_CYCLE 16384 +#define DEFAULT_PERIOD_NSEC 2000000 +#define DEFAULT_PULSE_NSEC 500000 #else #define DEFAULT_PERIOD_CYCLE 64000 #define DEFAULT_PULSE_CYCLE 32000 diff --git a/tests/drivers/pwm/pwm_api/testcase.yaml b/tests/drivers/pwm/pwm_api/testcase.yaml index 9e9e8fd815c4..608a4d0a0e1f 100644 --- a/tests/drivers/pwm/pwm_api/testcase.yaml +++ b/tests/drivers/pwm/pwm_api/testcase.yaml @@ -6,4 +6,5 @@ tests: - userspace filter: dt_alias_exists("pwm-0") or dt_alias_exists("pwm-1") or dt_alias_exists("pwm-2") or dt_alias_exists("pwm-3") or dt_compat_enabled("st,stm32-pwm") + or dt_compat_enabled("intel,blinky-pwm") depends_on: pwm From b9c16c9cdd0aecf24ed95316d35c0fcd6256906b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 12 Jul 2023 10:58:12 +0200 Subject: [PATCH 1205/2042] Bluetooth: ISO: Add comment for peripheral SDU size Adds a comment stating the state of the peripheral SDU size and why it is being assigned the PDU size on CIS established. Signed-off-by: Emil Gydesen --- subsys/bluetooth/host/iso.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 9becf9ff1e9f..1df70878c50b 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -1014,6 +1014,12 @@ void hci_le_cis_established(struct net_buf *buf) rx = chan->qos->rx; tx = chan->qos->tx; + /* As of BT Core 5.4, there is no way for the peripheral to get the actual + * SDU size or SDU interval without the use of higher layer profiles such as + * the Basic Audio Profile (BAP). The best we can do is use the PDU size + * until https://bluetooth.atlassian.net/browse/ES-18552 has been resolved + * and incorporated + */ if (rx != NULL) { rx->phy = bt_get_phy(evt->c_phy); rx->sdu = sys_le16_to_cpu(evt->c_max_pdu); From 81c584e3e7ac3b5ab1925f6c2564bd2bda6bda53 Mon Sep 17 00:00:00 2001 From: Franciszek Zdobylak Date: Wed, 12 Jul 2023 09:10:32 +0200 Subject: [PATCH 1206/2042] dts: arm: silabs: Fix efr32bg22 usart node Remove duplicated property and unnecessary newlines. Signed-off-by: Franciszek Zdobylak --- dts/arm/silabs/efr32bg2x.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index 776383e682f6..bb6a0d847af1 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -109,11 +109,8 @@ compatible = "silabs,gecko-spi-usart"; reg = <0x5005C000 0x400>; interrupt-names = "rx", "tx"; - status = "disabled"; - #address-cells = <1>; #size-cells = <0>; - status = "disabled"; }; From c793764549b2d141ce426f7e3cf56171ca05a6ff Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Mon, 19 Jun 2023 11:37:07 +0100 Subject: [PATCH 1207/2042] drivers: mfd: mfd_npm1300: Added timer configuration function Timer configuration function added Signed-off-by: Andy Sinclair --- drivers/mfd/mfd_npm1300.c | 30 ++++++++++++++++++++++++++++ include/zephyr/drivers/mfd/npm1300.h | 15 ++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index 57b10201308d..7cacfc30e390 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -9,8 +9,17 @@ #include #include +#include #include +#define TIME_BASE 0x07U + +#define TIME_OFFSET_LOAD 0x03U +#define TIME_OFFSET_TIMER 0x08U + +#define TIMER_PRESCALER_MS 16U +#define TIMER_MAX 0xFFFFFFU + struct mfd_npm1300_config { struct i2c_dt_spec i2c; }; @@ -85,6 +94,27 @@ int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offse return ret; } +int mfd_npm1300_set_timer(const struct device *dev, uint32_t time_ms) +{ + const struct mfd_npm1300_config *config = dev->config; + uint8_t buff[5] = {TIME_BASE, TIME_OFFSET_TIMER}; + uint32_t ticks = time_ms / TIMER_PRESCALER_MS; + + if (ticks > TIMER_MAX) { + return -EINVAL; + } + + sys_put_be24(ticks, &buff[2]); + + int ret = i2c_write_dt(&config->i2c, buff, sizeof(buff)); + + if (ret != 0) { + return ret; + } + + return mfd_npm1300_reg_write(dev, TIME_BASE, TIME_OFFSET_LOAD, 1U); +} + #define MFD_NPM1300_DEFINE(inst) \ static struct mfd_npm1300_data data_##inst; \ \ diff --git a/include/zephyr/drivers/mfd/npm1300.h b/include/zephyr/drivers/mfd/npm1300.h index 372ab725ed9d..4463bafa3a17 100644 --- a/include/zephyr/drivers/mfd/npm1300.h +++ b/include/zephyr/drivers/mfd/npm1300.h @@ -32,8 +32,8 @@ extern "C" { * @retval 0 If successful * @retval -errno In case of any bus error (see i2c_write_read_dt()) */ -int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, - void *data, size_t len); +int mfd_npm1300_reg_read_burst(const struct device *dev, uint8_t base, uint8_t offset, void *data, + size_t len); /** * @brief Read single register from npm1300 @@ -87,6 +87,17 @@ int mfd_npm1300_reg_write2(const struct device *dev, uint8_t base, uint8_t offse int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offset, uint8_t data, uint8_t mask); +/** + * @brief Write npm1300 timer register + * + * @param dev npm1300 mfd device + * @param time_ms timer value in ms + * @retval 0 If successful + * @retval -EINVAL if time value is too large + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_set_timer(const struct device *dev, uint32_t time_ms); + /** @} */ #ifdef __cplusplus From 4048348e3e29adc6afb4420e7edf6ca5f4b08bfd Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Thu, 6 Jul 2023 16:25:57 +0100 Subject: [PATCH 1208/2042] drivers: gpio: gpio_npm1300: Added reset and power loss modes Added configuration of nPM1300 GPIO pins as reset or power loss warning. Signed-off-by: Andy Sinclair --- drivers/gpio/gpio_npm1300.c | 6 +++ .../dt-bindings/gpio/nordic-npm1300-gpio.h | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/drivers/gpio/gpio_npm1300.c b/drivers/gpio/gpio_npm1300.c index 76850cf59f2f..37e7f99c9366 100644 --- a/drivers/gpio/gpio_npm1300.c +++ b/drivers/gpio/gpio_npm1300.c @@ -120,6 +120,12 @@ static inline int gpio_npm1300_configure(const struct device *dev, gpio_pin_t pi if ((flags & GPIO_INPUT) != 0U) { ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, NPM1300_GPIO_GPIINPUT); + } else if ((flags & NPM1300_GPIO_WDT_RESET_ON) != 0U) { + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, + NPM1300_GPIO_GPORESET); + } else if ((flags & NPM1300_GPIO_PWRLOSSWARN_ON) != 0U) { + ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, + NPM1300_GPIO_GPOPWRLOSSWARN); } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { ret = mfd_npm1300_reg_write(config->mfd, NPM_GPIO_BASE, NPM_GPIO_OFFSET_MODE + pin, NPM1300_GPIO_GPOLOGIC1); diff --git a/include/zephyr/dt-bindings/gpio/nordic-npm1300-gpio.h b/include/zephyr/dt-bindings/gpio/nordic-npm1300-gpio.h index c59ee4419d1c..fed166e651a2 100644 --- a/include/zephyr/dt-bindings/gpio/nordic-npm1300-gpio.h +++ b/include/zephyr/dt-bindings/gpio/nordic-npm1300-gpio.h @@ -15,6 +15,8 @@ * * - Bit 8: Drive strength (0=1mA, 1=6mA) * - Bit 9: Debounce (0=OFF, 1=ON) + * - Bit 10: Watchdog reset (0=OFF, 1=ON) + * - Bit 11: Power loss warning (0=OFF, 1=ON) * * @ingroup gpio_interface * @{ @@ -56,6 +58,42 @@ /** @} */ +/** + * @name nPM1300 GPIO watchdog reset flags + * @brief nPM1300 GPIO watchdog reset flags + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ +/** watchdog reset field mask */ +#define NPM1300_GPIO_WDT_RESET_MSK 0x0400U +/** @endcond */ + +/** Off */ +#define NPM1300_GPIO_WDT_RESET_OFF (0U << 10U) +/** On */ +#define NPM1300_GPIO_WDT_RESET_ON (1U << 10U) + +/** @} */ + +/** + * @name nPM1300 GPIO power loss warning flags + * @brief nPM1300 GPIO power loss warning flags + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ +/** power loss warning field mask */ +#define NPM1300_GPIO_PWRLOSSWARN_MSK 0x0800U +/** @endcond */ + +/** Off */ +#define NPM1300_GPIO_PWRLOSSWARN_OFF (0U << 11U) +/** On */ +#define NPM1300_GPIO_PWRLOSSWARN_ON (1U << 11U) + +/** @} */ + /** @} */ #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_NORDIC_NPM1300_GPIO_H_ */ From 910d43805b7d4d67df7101889bfc9fe6c129816a Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Wed, 5 Jul 2023 11:38:05 +0100 Subject: [PATCH 1209/2042] drivers: watchdog: npm1300: Added watchdog driver Added watchdog driver for nPM1300 Signed-off-by: Andy Sinclair --- drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.npm1300 | 19 ++ drivers/watchdog/wdt_npm1300.c | 168 ++++++++++++++++++ dts/bindings/watchdog/nordic,npm1300-wdt.yaml | 13 ++ 5 files changed, 203 insertions(+) create mode 100644 drivers/watchdog/Kconfig.npm1300 create mode 100644 drivers/watchdog/wdt_npm1300.c create mode 100644 dts/bindings/watchdog/nordic,npm1300-wdt.yaml diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index e06eb3d407c5..0870f0a66ef2 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -22,6 +22,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WDOG wdt_mcux_wdog.c) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WDOG32 wdt_mcux_wdog32.c) zephyr_library_sources_ifdef(CONFIG_WDT_MCUX_WWDT wdt_mcux_wwdt.c) zephyr_library_sources_ifdef(CONFIG_WDT_NPCX wdt_npcx.c) +zephyr_library_sources_ifdef(CONFIG_WDT_NPM1300 wdt_npm1300.c) zephyr_library_sources_ifdef(CONFIG_WDT_NPM6001 wdt_npm6001.c) zephyr_library_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c) zephyr_library_sources_ifdef(CONFIG_WDT_RPI_PICO wdt_rpi_pico.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 950c8c4e7c2e..52359b1cd775 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -90,6 +90,8 @@ source "drivers/watchdog/Kconfig.rpi_pico" source "drivers/watchdog/Kconfig.gd32" +source "drivers/watchdog/Kconfig.npm1300" + source "drivers/watchdog/Kconfig.npm6001" source "drivers/watchdog/Kconfig.nxp_s32" diff --git a/drivers/watchdog/Kconfig.npm1300 b/drivers/watchdog/Kconfig.npm1300 new file mode 100644 index 000000000000..8e9cd65024d1 --- /dev/null +++ b/drivers/watchdog/Kconfig.npm1300 @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config WDT_NPM1300 + bool "nPM1300 Watchdog driver" + default y + depends on DT_HAS_NORDIC_NPM1300_WDT_ENABLED + select I2C + select MFD + help + Enable nPM1300 Watchdog driver + +config WDT_NPM1300_INIT_PRIORITY + int "nPM1300 Watchdog driver initialization priority" + depends on WDT_NPM1300 + default 75 + help + Initialization priority for the nPM1300 Watchdog driver. + It must be greater than GPIO_NPM1300_INIT_PRIORITY. diff --git a/drivers/watchdog/wdt_npm1300.c b/drivers/watchdog/wdt_npm1300.c new file mode 100644 index 000000000000..418d1a87d4bc --- /dev/null +++ b/drivers/watchdog/wdt_npm1300.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_npm1300_wdt + +#include + +#include +#include +#include +#include +#include + +/* nPM1300 TIMER base address */ +#define TIME_BASE 0x07U + +/* nPM1300 timer register offsets */ +#define TIME_OFFSET_START 0x00U +#define TIME_OFFSET_STOP 0x01U +#define TIME_OFFSET_WDOG_KICK 0x04U +#define TIME_OFFSET_MODE 0x05U + +/* nPM1300 timer modes */ +#define TIME_MODE_BOOT 0x00U +#define TIME_MODE_WARN 0x01U +#define TIME_MODE_RESET 0x02U +#define TIME_MODE_GEN 0x03U + +struct wdt_npm1300_config { + const struct device *mfd; + struct gpio_dt_spec reset_gpios; +}; + +struct wdt_npm1300_data { + bool timeout_valid; +}; + +static int wdt_npm1300_setup(const struct device *dev, uint8_t options) +{ + const struct wdt_npm1300_config *config = dev->config; + struct wdt_npm1300_data *data = dev->data; + + if (!data->timeout_valid) { + return -EINVAL; + } + + return mfd_npm1300_reg_write(config->mfd, TIME_BASE, TIME_OFFSET_START, 1U); +} + +static int wdt_npm1300_disable(const struct device *dev) +{ + const struct wdt_npm1300_config *config = dev->config; + struct wdt_npm1300_data *data = dev->data; + int ret; + + ret = mfd_npm1300_reg_write(config->mfd, TIME_BASE, TIME_OFFSET_STOP, 1U); + if (ret < 0) { + return ret; + } + + data->timeout_valid = false; + + return 0; +} + +static int wdt_npm1300_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *timeout) +{ + const struct wdt_npm1300_config *config = dev->config; + struct wdt_npm1300_data *data = dev->data; + uint8_t mode; + int ret; + + if (data->timeout_valid) { + return -ENOMEM; + } + + if (timeout->window.min != 0U) { + return -EINVAL; + } + + ret = mfd_npm1300_set_timer(config->mfd, timeout->window.max); + if (ret < 0) { + return ret; + } + + switch (timeout->flags & WDT_FLAG_RESET_MASK) { + case WDT_FLAG_RESET_NONE: + /* Watchdog expiry causes warn event only, and does not reset */ + mode = TIME_MODE_GEN; + break; + case WDT_FLAG_RESET_CPU_CORE: + /* Watchdog expiry causes warn event, then asserts reset output */ + mode = TIME_MODE_WARN; + break; + case WDT_FLAG_RESET_SOC: + /* Watchdog expiry causes warn event, then full power cycle */ + mode = TIME_MODE_RESET; + break; + default: + return -EINVAL; + } + + ret = mfd_npm1300_reg_write(config->mfd, TIME_BASE, TIME_OFFSET_MODE, mode); + if (ret < 0) { + return ret; + } + + data->timeout_valid = true; + + return 0; +} + +static int wdt_npm1300_feed(const struct device *dev, int channel_id) +{ + const struct wdt_npm1300_config *config = dev->config; + + if (channel_id != 0) { + return -EINVAL; + } + + return mfd_npm1300_reg_write(config->mfd, TIME_BASE, TIME_OFFSET_WDOG_KICK, 1U); +} + +static const struct wdt_driver_api wdt_npm1300_api = { + .setup = wdt_npm1300_setup, + .disable = wdt_npm1300_disable, + .install_timeout = wdt_npm1300_install_timeout, + .feed = wdt_npm1300_feed, +}; + +static int wdt_npm1300_init(const struct device *dev) +{ + const struct wdt_npm1300_config *config = dev->config; + int ret; + + if (!device_is_ready(config->mfd)) { + return -ENODEV; + } + + if (config->reset_gpios.port != NULL) { + if (!gpio_is_ready_dt(&config->reset_gpios)) { + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset_gpios, NPM1300_GPIO_WDT_RESET_ON); + if (ret != 0) { + return ret; + } + } + + return 0; +} + +#define WDT_NPM1300_DEFINE(n) \ + static struct wdt_npm1300_data data##n; \ + \ + static const struct wdt_npm1300_config config##n = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .reset_gpios = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &wdt_npm1300_init, NULL, &data##n, &config##n, POST_KERNEL, \ + CONFIG_WDT_NPM1300_INIT_PRIORITY, &wdt_npm1300_api); + +DT_INST_FOREACH_STATUS_OKAY(WDT_NPM1300_DEFINE) diff --git a/dts/bindings/watchdog/nordic,npm1300-wdt.yaml b/dts/bindings/watchdog/nordic,npm1300-wdt.yaml new file mode 100644 index 000000000000..0dca26056443 --- /dev/null +++ b/dts/bindings/watchdog/nordic,npm1300-wdt.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: nPM1300 Watchdog + +compatible: "nordic,npm1300-wdt" + +include: base.yaml + +properties: + reset-gpios: + type: phandle-array + description: nPM1300 pin used as NRESETOUT From 8c7ffac4a6964e8ffd67fdd92093b8f3cd27b0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 5 Jul 2023 14:52:55 +0200 Subject: [PATCH 1210/2042] Bluetooth: Mesh: Fix err in mod_app_list packing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes erroneous packing/unpacking of model app list messages in the configuration client and server. According to the mesh 1.1 protcol spec (4.3.1.1) two app indexes shall be packed in a 3 octet interleaved format. The current implementation packs them in 4 octets. This commit also provide a helper function for unpacking key indexes as public API to facilitate future config model callback API. Signed-off-by: Anders Storrø --- include/zephyr/bluetooth/mesh/cfg_cli.h | 13 +++ subsys/bluetooth/mesh/cfg_cli.c | 133 +++++++++++++++--------- subsys/bluetooth/mesh/cfg_srv.c | 56 +++++----- subsys/bluetooth/mesh/foundation.h | 6 +- 4 files changed, 129 insertions(+), 79 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index 6a827be3805f..ea48c3b30d5c 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -1644,6 +1644,19 @@ struct bt_mesh_comp_p1_model_item *bt_mesh_comp_p1_item_pull( struct bt_mesh_comp_p1_ext_item *bt_mesh_comp_p1_pull_ext_item( struct bt_mesh_comp_p1_model_item *item, struct bt_mesh_comp_p1_ext_item *ext_item); +/** @brief Unpack a list of key index entries from a buffer. + * + * On success, @c dst_cnt is set to the amount of unpacked key index entries. + * + * @param buf Message buffer containing encoded AppKey or NetKey Indexes. + * @param dst_arr Destination array for the unpacked list. + * @param dst_cnt Size of the destination array. + * + * @return 0 on success. + * @return -EMSGSIZE if dst_arr size is to small to parse full message. + */ +int bt_mesh_key_idx_unpack_list(struct net_buf_simple *buf, uint16_t *dst_arr, size_t *dst_cnt); + /** @cond INTERNAL_HIDDEN */ extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index 200d6d93538d..167d1c642640 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -308,38 +308,48 @@ struct net_key_list_param { size_t *key_cnt; }; +int bt_mesh_key_idx_unpack_list(struct net_buf_simple *buf, uint16_t *dst_arr, + size_t *dst_cnt) +{ + size_t i; + + if (!dst_cnt) { + return 0; + } + + for (i = 0; (i + 1) < *dst_cnt && buf->len >= 3; i += 2) { + key_idx_unpack_pair(buf, &dst_arr[i], &dst_arr[i + 1]); + } + + if (i < *dst_cnt && buf->len >= 2) { + dst_arr[i++] = net_buf_simple_pull_le16(buf) & 0xfff; + } + + *dst_cnt = i; + + return buf->len > 0 ? -EMSGSIZE : 0; +} + static int net_key_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_key_list_param *param; - int i; LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, - (void **)¶m)) { + if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, (void **)¶m)) { if (param->keys && param->key_cnt) { - for (i = 0; i < *param->key_cnt && buf->len >= 3; i += 2) { - key_idx_unpack(buf, ¶m->keys[i], - ¶m->keys[i + 1]); - } - - if (i < *param->key_cnt && buf->len >= 2) { - param->keys[i++] = - net_buf_simple_pull_le16(buf) & 0xfff; - } + int err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); - if (buf->len > 0) { + if (err) { LOG_ERR("The message size for the application opcode is " "incorrect."); - return -EMSGSIZE; + return err; } - - *param->key_cnt = i; } bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); @@ -392,7 +402,7 @@ static int app_key_status(struct bt_mesh_model *model, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); - key_idx_unpack(buf, &net_idx, &app_idx); + key_idx_unpack_pair(buf, &net_idx, &app_idx); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_STATUS, ctx->addr, (void **)¶m)) { @@ -435,7 +445,6 @@ static int app_key_list(struct bt_mesh_model *model, struct app_key_list_param *param; uint16_t net_idx; uint8_t status; - int i; LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); @@ -453,22 +462,13 @@ static int app_key_list(struct bt_mesh_model *model, if (param->keys && param->key_cnt) { - for (i = 0; i < *param->key_cnt && buf->len >= 3; i += 2) { - key_idx_unpack(buf, ¶m->keys[i], - ¶m->keys[i + 1]); - } - - if (i < *param->key_cnt && buf->len == 2) { - param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; - } + int err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); - if (buf->len > 0U) { + if (err) { LOG_ERR("The message size for the application opcode is " "incorrect."); - return -EMSGSIZE; + return err; } - - *param->key_cnt = i; } if (param->status) { @@ -555,20 +555,14 @@ struct mod_member_list_param { size_t *member_cnt; }; -static int mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, uint16_t op, - bool vnd) +static int mod_sub_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t op, + bool vnd) { struct mod_member_list_param *param; uint16_t elem_addr, mod_id, cid; uint8_t status; int i; - if ((vnd && buf->len < 7U) || (buf->len < 5U)) { - LOG_ERR("The message size for the application opcode is incorrect."); - return -EMSGSIZE; - } - status = net_buf_simple_pull_u8(buf); elem_addr = net_buf_simple_pull_le16(buf); if (vnd) { @@ -577,11 +571,10 @@ static int mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, mod_id = net_buf_simple_pull_le16(buf); - if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op, ctx->addr, - (void **)¶m)) { + if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op, ctx->addr, (void **)¶m)) { if (param->elem_addr != elem_addr || param->mod_id != mod_id || - (vnd && param->cid != cid)) { + (vnd && param->cid != cid)) { LOG_WRN("Model Member List parameters did not match"); return -ENOENT; } @@ -609,13 +602,57 @@ static int mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, return 0; } +static int mod_app_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t op, + bool vnd) +{ + struct mod_member_list_param *param; + uint16_t elem_addr, mod_id, cid; + uint8_t status; + + status = net_buf_simple_pull_u8(buf); + elem_addr = net_buf_simple_pull_le16(buf); + if (vnd) { + cid = net_buf_simple_pull_le16(buf); + } + + mod_id = net_buf_simple_pull_le16(buf); + + if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op, ctx->addr, (void **)¶m)) { + + if (param->elem_addr != elem_addr || param->mod_id != mod_id || + (vnd && param->cid != cid)) { + LOG_WRN("Model Member List parameters did not match"); + return -ENOENT; + } + + if (param->member_cnt && param->members) { + + int err = + bt_mesh_key_idx_unpack_list(buf, param->members, param->member_cnt); + + if (err) { + LOG_ERR("The message size for the application opcode is " + "incorrect."); + return err; + } + } + + if (param->status) { + *param->status = status; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + } + return 0; +} + static int mod_app_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - return mod_member_list_handle(ctx, buf, OP_SIG_MOD_APP_LIST, false); + return mod_app_list_handle(ctx, buf, OP_SIG_MOD_APP_LIST, false); } static int mod_app_list_vnd(struct bt_mesh_model *model, @@ -625,7 +662,7 @@ static int mod_app_list_vnd(struct bt_mesh_model *model, LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - return mod_member_list_handle(ctx, buf, OP_VND_MOD_APP_LIST, true); + return mod_app_list_handle(ctx, buf, OP_VND_MOD_APP_LIST, true); } struct mod_pub_param { @@ -777,7 +814,7 @@ static int mod_sub_list(struct bt_mesh_model *model, LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - return mod_member_list_handle(ctx, buf, OP_MOD_SUB_LIST, false); + return mod_sub_list_handle(ctx, buf, OP_MOD_SUB_LIST, false); } static int mod_sub_list_vnd(struct bt_mesh_model *model, @@ -787,7 +824,7 @@ static int mod_sub_list_vnd(struct bt_mesh_model *model, LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - return mod_member_list_handle(ctx, buf, OP_MOD_SUB_LIST_VND, true); + return mod_sub_list_handle(ctx, buf, OP_MOD_SUB_LIST_VND, true); } struct hb_sub_param { @@ -1315,7 +1352,7 @@ int bt_mesh_cfg_cli_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_ne }; bt_mesh_model_msg_init(&msg, OP_APP_KEY_ADD); - key_idx_pack(&msg, key_net_idx, key_app_idx); + key_idx_pack_pair(&msg, key_net_idx, key_app_idx); net_buf_simple_add_mem(&msg, app_key, 16); return bt_mesh_msg_ackd_send(cli->model, &ctx, &msg, !status ? NULL : &rsp); @@ -1339,7 +1376,7 @@ int bt_mesh_cfg_cli_app_key_update(uint16_t net_idx, uint16_t addr, uint16_t key }; bt_mesh_model_msg_init(&msg, OP_APP_KEY_UPDATE); - key_idx_pack(&msg, key_net_idx, key_app_idx); + key_idx_pack_pair(&msg, key_net_idx, key_app_idx); net_buf_simple_add_mem(&msg, app_key, 16); return bt_mesh_msg_ackd_send(cli->model, &ctx, &msg, !status ? NULL : &rsp); @@ -1409,7 +1446,7 @@ int bt_mesh_cfg_cli_app_key_del(uint16_t net_idx, uint16_t addr, uint16_t key_ne }; bt_mesh_model_msg_init(&msg, OP_APP_KEY_DEL); - key_idx_pack(&msg, key_net_idx, key_app_idx); + key_idx_pack_pair(&msg, key_net_idx, key_app_idx); return bt_mesh_msg_ackd_send(cli->model, &ctx, &msg, !status ? NULL : &rsp); } diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 512f2eb57f9a..09eee4af3a03 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -280,6 +280,28 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st return STATUS_SUCCESS; } +static void key_idx_pack_list(struct net_buf_simple *buf, uint16_t *arr, size_t cnt) +{ + uint16_t *idx = NULL; + + for (int i = 0; i < cnt; i++) { + if (arr[i] != BT_MESH_KEY_UNUSED) { + if (!idx) { + idx = &arr[i]; + continue; + } + + key_idx_pack_pair(buf, *idx, arr[i]); + idx = NULL; + } + } + + if (idx) { + net_buf_simple_add_le16(buf, *idx); + } + +} + static int send_app_key_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, @@ -289,7 +311,7 @@ static int send_app_key_status(struct bt_mesh_model *model, bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); net_buf_simple_add_u8(&msg, status); - key_idx_pack(&msg, net_idx, app_idx); + key_idx_pack_pair(&msg, net_idx, app_idx); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { LOG_ERR("Unable to send App Key Status response"); @@ -305,7 +327,7 @@ static int app_key_add(struct bt_mesh_model *model, uint16_t key_net_idx, key_app_idx; uint8_t status; - key_idx_unpack(buf, &key_net_idx, &key_app_idx); + key_idx_unpack_pair(buf, &key_net_idx, &key_app_idx); LOG_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); @@ -321,7 +343,7 @@ static int app_key_update(struct bt_mesh_model *model, uint16_t key_net_idx, key_app_idx; uint8_t status; - key_idx_unpack(buf, &key_net_idx, &key_app_idx); + key_idx_unpack_pair(buf, &key_net_idx, &key_app_idx); LOG_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); @@ -357,7 +379,7 @@ static int app_key_del(struct bt_mesh_model *model, uint16_t key_net_idx, key_app_idx; uint8_t status; - key_idx_unpack(buf, &key_net_idx, &key_app_idx); + key_idx_unpack_pair(buf, &key_net_idx, &key_app_idx); LOG_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); @@ -379,7 +401,6 @@ static int app_key_get(struct bt_mesh_model *model, uint16_t get_idx; uint8_t status; ssize_t count; - int i; get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { @@ -409,13 +430,7 @@ static int app_key_get(struct bt_mesh_model *model, count = ARRAY_SIZE(app_idx); } - for (i = 0; i < count - 1; i += 2) { - key_idx_pack(&msg, app_idx[i], app_idx[i + 1]); - } - - if (i < count) { - net_buf_simple_add_le16(&msg, app_idx[i]); - } + key_idx_pack_list(&msg, app_idx, count); send_status: if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -1731,7 +1746,6 @@ static int net_key_get(struct bt_mesh_model *model, IDX_LEN(CONFIG_BT_MESH_SUBNET_COUNT)); uint16_t net_idx[CONFIG_BT_MESH_SUBNET_COUNT]; ssize_t count; - int i; bt_mesh_model_msg_init(&msg, OP_NET_KEY_LIST); @@ -1740,13 +1754,7 @@ static int net_key_get(struct bt_mesh_model *model, count = ARRAY_SIZE(net_idx); } - for (i = 0; i < count - 1; i += 2) { - key_idx_pack(&msg, net_idx[i], net_idx[i + 1]); - } - - if (i < count) { - net_buf_simple_add_le16(&msg, net_idx[i]); - } + key_idx_pack_list(&msg, net_idx, count); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { LOG_ERR("Unable to send NetKey List"); @@ -2037,13 +2045,7 @@ static int mod_app_get(struct bt_mesh_model *model, } if (mod) { - int i; - - for (i = 0; i < mod->keys_cnt; i++) { - if (mod->keys[i] != BT_MESH_KEY_UNUSED) { - net_buf_simple_add_le16(&msg, mod->keys[i]); - } - } + key_idx_pack_list(&msg, mod->keys, mod->keys_cnt); } if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { diff --git a/subsys/bluetooth/mesh/foundation.h b/subsys/bluetooth/mesh/foundation.h index 164ff0cb5aa4..01cbf93c39e5 100644 --- a/subsys/bluetooth/mesh/foundation.h +++ b/subsys/bluetooth/mesh/foundation.h @@ -154,15 +154,13 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); #include -static inline void key_idx_pack(struct net_buf_simple *buf, - uint16_t idx1, uint16_t idx2) +static inline void key_idx_pack_pair(struct net_buf_simple *buf, uint16_t idx1, uint16_t idx2) { net_buf_simple_add_le16(buf, idx1 | ((idx2 & 0x00f) << 12)); net_buf_simple_add_u8(buf, idx2 >> 4); } -static inline void key_idx_unpack(struct net_buf_simple *buf, - uint16_t *idx1, uint16_t *idx2) +static inline void key_idx_unpack_pair(struct net_buf_simple *buf, uint16_t *idx1, uint16_t *idx2) { *idx1 = sys_get_le16(&buf->data[0]) & 0xfff; *idx2 = sys_get_le16(&buf->data[1]) >> 4; From 83b1a983a92e994f6e3770a31844ea22f82ec798 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 12 Jul 2023 14:41:24 +1000 Subject: [PATCH 1211/2042] net: lib: tls_credentials: earlier initialisation The TLS credentials libraries are purely software constructs with no external dependencies, run them immediately after the kernel setup to allow other initialisation functions to add credentials without the requirement to run in the back half of the `APPLICATION` priority. Signed-off-by: Jordan Yates --- subsys/net/lib/tls_credentials/tls_credentials.c | 2 +- subsys/net/lib/tls_credentials/tls_credentials_trusted.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/tls_credentials/tls_credentials.c b/subsys/net/lib/tls_credentials/tls_credentials.c index 6f31cf70787b..133d29671604 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials.c +++ b/subsys/net/lib/tls_credentials/tls_credentials.c @@ -24,7 +24,7 @@ static int credentials_init(void) return 0; } -SYS_INIT(credentials_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(credentials_init, POST_KERNEL, 0); static struct tls_credential *unused_credential_get(void) { diff --git a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c index 9d3464c3c713..ef105715b07c 100644 --- a/subsys/net/lib/tls_credentials/tls_credentials_trusted.c +++ b/subsys/net/lib/tls_credentials/tls_credentials_trusted.c @@ -164,7 +164,7 @@ static int credentials_init(void) return 0; } -SYS_INIT(credentials_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(credentials_init, POST_KERNEL, 0); static struct tls_credential *unused_credential_get(void) { From 8d6f74ad1f84df4eb17e28cfed28a50e17af2f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 11 Jul 2023 16:55:04 +0200 Subject: [PATCH 1212/2042] pm: Supplement pm_device_is_powered doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supplement the documentation pm_device_is_powered() adding that a device is assumed powered in case the device does not support PM or is not on a power domain. Signed-off-by: Marcel Krüger --- include/zephyr/pm/device.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index 2c6734a95b48..734f6c08a60f 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -576,7 +576,8 @@ int pm_device_power_domain_remove(const struct device *dev, * * @param dev Device instance. * - * @retval true If device is currently powered + * @retval true If device is currently powered, or is assumed to be powered + * (i.e. it does not support PM or is not under a PM domain) * @retval false If device is not currently powered */ bool pm_device_is_powered(const struct device *dev); From a211469734b6eb12b575fd33ba48eeb0d75fda8e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 10:55:23 +0200 Subject: [PATCH 1213/2042] ci: doc-build: use zephyr-runner-linux-x64-4xlarge This should allow us to observe faster build times when using parallelization. Signed-off-by: Gerard Marull-Paretas --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index ec6e11497b93..f42a1967885a 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -35,7 +35,7 @@ env: jobs: doc-build-html: name: "Documentation Build (HTML)" - runs-on: ubuntu-22.04 + runs-on: zephyr-runner-linux-x64-4xlarge timeout-minutes: 45 concurrency: group: doc-build-html-${{ github.ref }} From 85ec85384ac48089ad1d32114283d7dbdd11470a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 3 Jul 2023 12:20:12 +0200 Subject: [PATCH 1214/2042] doc: add -W --keep-going to the default SPHINXOPTS list Run Sphinx in warnings as error mode, but keep going so that all issues are reported to the user. Signed-off-by: Gerard Marull-Paretas --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 7c03af46d8c0..cd4ceeb6f8b5 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -12,7 +12,7 @@ message(STATUS "Zephyr base: ${ZEPHYR_BASE}") #------------------------------------------------------------------------------- # Options -set(SPHINXOPTS "-j auto" CACHE STRING "Default Sphinx Options") +set(SPHINXOPTS "-j auto -W --keep-going" CACHE STRING "Default Sphinx Options") set(LATEXMKOPTS "-halt-on-error -no-shell-escape" CACHE STRING "Default latexmk options") set(DT_TURBO_MODE OFF CACHE BOOL "Enable DT turbo mode") set(DOC_TAG "development" CACHE STRING "Documentation tag") From 2c89bf57983782593dedc0f34f105fcde735677f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 10:49:09 +0200 Subject: [PATCH 1215/2042] doc: add cmake SPHINXOPTS_EXTRA option Add a new CMake option to append options to SPHINXOPTS. This allows us to easily extend default SPHINXOPTS. This patch also restores the "-j auto" option in CI (now that we use a custom runner). Signed-off-by: Gerard Marull-Paretas --- .github/workflows/doc-build.yml | 2 +- doc/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index f42a1967885a..6801fc24f81b 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -85,7 +85,7 @@ jobs: DOC_TARGET="html" fi - DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -W --keep-going -t publish" make -C doc ${DOC_TARGET} + DOC_TAG=${DOC_TAG} SPHINXOPTS_EXTRA="-q -t publish" make -C doc ${DOC_TARGET} - name: compress-docs run: | diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index cd4ceeb6f8b5..3fd775147fe5 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -13,12 +13,14 @@ message(STATUS "Zephyr base: ${ZEPHYR_BASE}") # Options set(SPHINXOPTS "-j auto -W --keep-going" CACHE STRING "Default Sphinx Options") +set(SPHINXOPTS_EXTRA "" CACHE STRING "Extra Sphinx Options (added to defaults)") set(LATEXMKOPTS "-halt-on-error -no-shell-escape" CACHE STRING "Default latexmk options") set(DT_TURBO_MODE OFF CACHE BOOL "Enable DT turbo mode") set(DOC_TAG "development" CACHE STRING "Documentation tag") set(DTS_ROOTS "${ZEPHYR_BASE}" CACHE STRING "DT bindings root folders") separate_arguments(SPHINXOPTS) +separate_arguments(SPHINXOPTS_EXTRA) separate_arguments(LATEXMKOPTS) #------------------------------------------------------------------------------- @@ -145,6 +147,7 @@ add_doc_target( -w ${DOCS_BUILD_DIR}/html.log -t ${DOC_TAG} ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_HTML_DIR} USES_TERMINAL @@ -173,6 +176,7 @@ add_doc_target( -t ${DOC_TAG} -t svgconvert ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_LATEX_DIR} USES_TERMINAL @@ -223,6 +227,7 @@ add_doc_target( -w ${DOCS_BUILD_DIR}/linkcheck.log -t ${DOC_TAG} ${SPHINXOPTS} + ${SPHINXOPTS_EXTRA} ${DOCS_SRC_DIR} ${DOCS_LINKCHECK_DIR} USES_TERMINAL From d3d93d4399dc232a574a547c7d64a61ceb5943bf Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 10:56:18 +0200 Subject: [PATCH 1216/2042] doc: enable Sphinx tracebacks When something goes wrong in Sphinx or extensions, we'll get a detailed traceback, so we can easily debug issues in CI. Signed-off-by: Gerard Marull-Paretas --- doc/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 3fd775147fe5..5cfce578a4a9 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -12,7 +12,7 @@ message(STATUS "Zephyr base: ${ZEPHYR_BASE}") #------------------------------------------------------------------------------- # Options -set(SPHINXOPTS "-j auto -W --keep-going" CACHE STRING "Default Sphinx Options") +set(SPHINXOPTS "-j auto -W --keep-going -T" CACHE STRING "Default Sphinx Options") set(SPHINXOPTS_EXTRA "" CACHE STRING "Extra Sphinx Options (added to defaults)") set(LATEXMKOPTS "-halt-on-error -no-shell-escape" CACHE STRING "Default latexmk options") set(DT_TURBO_MODE OFF CACHE BOOL "Enable DT turbo mode") From b990a5fdb6f20c4136339f3ee72b486ed1e367ff Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 11:02:36 +0200 Subject: [PATCH 1217/2042] doc: update sphinx/docleaf requirements Update Sphinx and docleaf. Note that Sphinx 7 is not an option because rtd_theme requires <= 6 (see https://github.com/readthedocs/sphinx_rtd_theme/issues/1463). Signed-off-by: Gerard Marull-Paretas --- scripts/requirements-doc.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/requirements-doc.txt b/scripts/requirements-doc.txt index c26c7da69672..b11f5aae5271 100644 --- a/scripts/requirements-doc.txt +++ b/scripts/requirements-doc.txt @@ -1,7 +1,7 @@ # DOC: used to generate docs -docleaf==0.8.0 -sphinx~=5.0,!=5.2.0.post0 +docleaf==0.8.1 +sphinx~=6.0 sphinx_rtd_theme~=1.0 sphinx-tabs sphinxcontrib-svg2pdfconverter From 7f9215da0ead2fa5e6ac0a0e0c063f8b4bc6d6c3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 29 Jun 2023 11:11:34 +0200 Subject: [PATCH 1218/2042] doc: move requirements to doc/ Zephyr scripts do not require documentation dependencies, so let's move them from scripts/ to doc/. Signed-off-by: Gerard Marull-Paretas --- .github/workflows/doc-build.yml | 10 +++++----- doc/contribute/documentation/generation.rst | 2 +- scripts/requirements-doc.txt => doc/requirements.txt | 0 scripts/requirements.txt | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) rename scripts/requirements-doc.txt => doc/requirements.txt (100%) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 6801fc24f81b..40e170ddc8a0 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -22,7 +22,7 @@ on: - 'west.yml' - '.github/workflows/doc-build.yml' - 'scripts/dts/**' - - 'scripts/requirements-doc.txt' + - 'doc/requirements.txt' env: # NOTE: west docstrings will be extracted from the version listed here @@ -57,12 +57,12 @@ jobs: uses: actions/cache@v3 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('doc/requirements.txt') }} - name: install-pip run: | sudo pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r doc/requirements.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} @@ -137,7 +137,7 @@ jobs: uses: actions/cache@v3 with: path: ~/.cache/pip - key: pip-${{ hashFiles('scripts/requirements-doc.txt') }} + key: pip-${{ hashFiles('doc/requirements.txt') }} - name: setup-venv run: | @@ -148,7 +148,7 @@ jobs: - name: install-pip run: | pip3 install -U setuptools wheel pip - pip3 install -r scripts/requirements-doc.txt + pip3 install -r doc/requirements.txt pip3 install west==${WEST_VERSION} pip3 install cmake==${CMAKE_VERSION} diff --git a/doc/contribute/documentation/generation.rst b/doc/contribute/documentation/generation.rst index 7f2b6ef2d05f..756c1c2a7029 100644 --- a/doc/contribute/documentation/generation.rst +++ b/doc/contribute/documentation/generation.rst @@ -80,7 +80,7 @@ Our documentation processing has been tested to run with: * Graphviz 2.43 * Latexmk version 4.56 * All Python dependencies listed in the repository file - ``scripts/requirements-doc.txt`` + ``doc/requirements.txt`` In order to install the documentation tools, first install Zephyr as described in :ref:`getting_started`. Then install additional tools diff --git a/scripts/requirements-doc.txt b/doc/requirements.txt similarity index 100% rename from scripts/requirements-doc.txt rename to doc/requirements.txt diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 7bb405afaaa1..e10831d8d605 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,6 +1,5 @@ -r requirements-base.txt -r requirements-build-test.txt --r requirements-doc.txt -r requirements-run-test.txt -r requirements-extras.txt -r requirements-compliance.txt From 8c81cc7179207d647a55bfe3d8b85ad3d659db50 Mon Sep 17 00:00:00 2001 From: Jaxson Han Date: Wed, 7 Jun 2023 17:53:16 +0800 Subject: [PATCH 1219/2042] tests: subsys: rtio: Reset the spsc before the test starts The test case test_spsc_throughput reuse spsc without reset. Fix it by resetting the spsc before the test case starts. Signed-off-by: Jaxson Han --- tests/subsys/rtio/rtio_api/src/test_rtio_spsc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/subsys/rtio/rtio_api/src/test_rtio_spsc.c b/tests/subsys/rtio/rtio_api/src/test_rtio_spsc.c index 35ee2846727b..a161b9fab077 100644 --- a/tests/subsys/rtio/rtio_api/src/test_rtio_spsc.c +++ b/tests/subsys/rtio/rtio_api/src/test_rtio_spsc.c @@ -247,5 +247,11 @@ ZTEST(rtio_spsc, test_spsc_throughput) THROUGHPUT_ITERS, ns/THROUGHPUT_ITERS); } +static void rtio_spsc_before(void *data) +{ + ARG_UNUSED(data); + + rtio_spsc_reset(&spsc); +} -ZTEST_SUITE(rtio_spsc, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(rtio_spsc, NULL, NULL, rtio_spsc_before, NULL, NULL); From ae22ff648c1677a19ed6f713a57c9070a9b89fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 15:59:26 +0200 Subject: [PATCH 1220/2042] emul: doc: Fix SBS Gauge emulator doc typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Capitalized group name to preserve alphabetical order in device driver APIs list, and fixed minor typo (backed->backend) Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/emul_fuel_gauge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/emul_fuel_gauge.h b/include/zephyr/drivers/emul_fuel_gauge.h index 812de61a79f2..47044d09318e 100644 --- a/include/zephyr/drivers/emul_fuel_gauge.h +++ b/include/zephyr/drivers/emul_fuel_gauge.h @@ -22,7 +22,7 @@ extern "C" { /** * @brief Fuel gauge backend emulator APIs - * @defgroup fuel_gauge_emulator_backend fuel gauge backed emulator APIs + * @defgroup fuel_gauge_emulator_backend Fuel gauge backend emulator APIs * @ingroup io_interfaces * @{ */ From 7c6a340413b6321f02beb5281b15b61ba6318590 Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Mon, 10 Jul 2023 11:29:25 +0200 Subject: [PATCH 1221/2042] drivers: sensor: tmd2620: coverity 316443 unchecked return value The return value is consciously not checked, because the operation is expected to fail. And the real request is executed afterwards. Fixes #58593 Coverity-CID: 316443 Signed-off-by: Thomas Stranger --- drivers/sensor/tmd2620/tmd2620.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/tmd2620/tmd2620.c b/drivers/sensor/tmd2620/tmd2620.c index eb056b1c1634..daa28d4be81f 100644 --- a/drivers/sensor/tmd2620/tmd2620.c +++ b/drivers/sensor/tmd2620/tmd2620.c @@ -175,7 +175,7 @@ static int tmd2620_sensor_setup(const struct device *dev) /* trying to read the id twice, as the sensor does not answer the first request */ /* because of this no return code is checked in this line */ - i2c_reg_read_byte_dt(&config->i2c, TMD2620_ID_REG, &chip_id); + (void)i2c_reg_read_byte_dt(&config->i2c, TMD2620_ID_REG, &chip_id); ret = i2c_reg_read_byte_dt(&config->i2c, TMD2620_ID_REG, &chip_id); if (ret < 0) { From ce74b60d7710d6570cbfa66e93e36dc41442c47e Mon Sep 17 00:00:00 2001 From: Thomas Stranger Date: Mon, 10 Jul 2023 12:04:34 +0200 Subject: [PATCH 1222/2042] drivers: sensor: adxl362: coverity: 316152 unchecked return value Check and propagate two return values. Don't need to check return of the part id request, but make sure that the value is initialized before the comparison. Fixes #58575 Coverity-CID: 316152 Signed-off-by: Thomas Stranger --- drivers/sensor/adxl362/adxl362.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/sensor/adxl362/adxl362.c b/drivers/sensor/adxl362/adxl362.c index d560087ade73..9d3878811821 100644 --- a/drivers/sensor/adxl362/adxl362.c +++ b/drivers/sensor/adxl362/adxl362.c @@ -223,15 +223,18 @@ static int adxl362_set_range(const struct device *dev, uint8_t range) static int adxl362_set_output_rate(const struct device *dev, uint8_t out_rate) { + int ret; uint8_t old_filter_ctl; uint8_t new_filter_ctl; - adxl362_get_reg(dev, &old_filter_ctl, ADXL362_REG_FILTER_CTL, 1); + ret = adxl362_get_reg(dev, &old_filter_ctl, ADXL362_REG_FILTER_CTL, 1); + if (ret) { + return ret; + } + new_filter_ctl = old_filter_ctl & ~ADXL362_FILTER_CTL_ODR(0x7); new_filter_ctl = new_filter_ctl | ADXL362_FILTER_CTL_ODR(out_rate); - adxl362_set_reg(dev, new_filter_ctl, ADXL362_REG_FILTER_CTL, 1); - - return 0; + return adxl362_set_reg(dev, new_filter_ctl, ADXL362_REG_FILTER_CTL, 1); } @@ -705,7 +708,7 @@ static int adxl362_chip_init(const struct device *dev) static int adxl362_init(const struct device *dev) { const struct adxl362_config *config = dev->config; - uint8_t value; + uint8_t value = 0; int err; if (!spi_is_ready_dt(&config->bus)) { @@ -722,7 +725,7 @@ static int adxl362_init(const struct device *dev) k_sleep(K_MSEC(5)); - adxl362_get_reg(dev, &value, ADXL362_REG_PARTID, 1); + (void)adxl362_get_reg(dev, &value, ADXL362_REG_PARTID, 1); if (value != ADXL362_PART_ID) { LOG_ERR("wrong part_id: %d", value); return -ENODEV; From f9773859c4a2b2d1f4156837d9e29a65935f858b Mon Sep 17 00:00:00 2001 From: Kacper Dalach Date: Tue, 11 Jul 2023 08:30:49 +0200 Subject: [PATCH 1223/2042] drivers: clock_control: stm32h5: boot_clock_assert_fix When the image is chain-loaded, clocks may already by initialized. The driver was lacking support for already configured HSE and PLL sources. When CONFIG_ASSERT=y get_startup_frequency was failing since it did not recognize these sources. It's the same issue that was addressed in #58109 for stm32u5. Signed-off-by: Kacper Dalach --- drivers/clock_control/clock_stm32_ll_h5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index e4c4d28fb125..ebb2766f4e0a 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -74,6 +74,10 @@ static uint32_t get_startup_frequency(void) return STM32_CSI_FREQ; case LL_RCC_SYS_CLKSOURCE_STATUS_HSI: return STM32_HSI_FREQ; + case LL_RCC_SYS_CLKSOURCE_STATUS_HSE: + return STM32_HSE_FREQ; + case LL_RCC_SYS_CLKSOURCE_STATUS_PLL1: + return get_pllsrc_frequency(PLL1_ID); default: __ASSERT(0, "Unexpected startup freq"); return 0; From f1a992c87a9e40420af3b940715fc82ccb6f339f Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 10 Nov 2022 23:04:47 -0800 Subject: [PATCH 1224/2042] drivers: sensors: bmi08x: add initial support for bmi08x This adds support for the bosch bmi085 and bmi088. This also includes support for data sync mode. Signed-off-by: Ryan McClelland --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/bmi08x/CMakeLists.txt | 9 + drivers/sensor/bmi08x/Kconfig | 95 ++ drivers/sensor/bmi08x/bmi08x.c | 74 ++ drivers/sensor/bmi08x/bmi08x.h | 593 +++++++++++++ drivers/sensor/bmi08x/bmi08x_accel.c | 812 ++++++++++++++++++ drivers/sensor/bmi08x/bmi08x_accel_trigger.c | 171 ++++ drivers/sensor/bmi08x/bmi08x_config_file.h | 424 +++++++++ drivers/sensor/bmi08x/bmi08x_gyro.c | 484 +++++++++++ drivers/sensor/bmi08x/bmi08x_gyro_trigger.c | 135 +++ .../sensor/bosch,bmi08x-accel-i2c.yaml | 8 + .../sensor/bosch,bmi08x-accel-spi.yaml | 8 + dts/bindings/sensor/bosch,bmi08x-accel.yaml | 84 ++ .../sensor/bosch,bmi08x-gyro-i2c.yaml | 8 + .../sensor/bosch,bmi08x-gyro-spi.yaml | 8 + dts/bindings/sensor/bosch,bmi08x-gyro.yaml | 62 ++ tests/drivers/build_all/sensor/i2c.dtsi | 22 + .../sensor/sensors_trigger_global.conf | 2 + .../sensor/sensors_trigger_none.conf | 2 + .../build_all/sensor/sensors_trigger_own.conf | 2 + tests/drivers/build_all/sensor/spi.dtsi | 24 + 22 files changed, 3029 insertions(+) create mode 100644 drivers/sensor/bmi08x/CMakeLists.txt create mode 100644 drivers/sensor/bmi08x/Kconfig create mode 100644 drivers/sensor/bmi08x/bmi08x.c create mode 100644 drivers/sensor/bmi08x/bmi08x.h create mode 100644 drivers/sensor/bmi08x/bmi08x_accel.c create mode 100644 drivers/sensor/bmi08x/bmi08x_accel_trigger.c create mode 100644 drivers/sensor/bmi08x/bmi08x_config_file.h create mode 100644 drivers/sensor/bmi08x/bmi08x_gyro.c create mode 100644 drivers/sensor/bmi08x/bmi08x_gyro_trigger.c create mode 100644 dts/bindings/sensor/bosch,bmi08x-accel-i2c.yaml create mode 100644 dts/bindings/sensor/bosch,bmi08x-accel-spi.yaml create mode 100644 dts/bindings/sensor/bosch,bmi08x-accel.yaml create mode 100644 dts/bindings/sensor/bosch,bmi08x-gyro-i2c.yaml create mode 100644 dts/bindings/sensor/bosch,bmi08x-gyro-spi.yaml create mode 100644 dts/bindings/sensor/bosch,bmi08x-gyro.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 4aac5ac9f2ed..1bd8ee07f171 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn) add_subdirectory_ifdef(CONFIG_BME280 bme280) add_subdirectory_ifdef(CONFIG_BME680 bme680) add_subdirectory_ifdef(CONFIG_BMG160 bmg160) +add_subdirectory_ifdef(CONFIG_BMI08X bmi08x) add_subdirectory_ifdef(CONFIG_BMI160 bmi160) add_subdirectory_ifdef(CONFIG_BMI270 bmi270) add_subdirectory_ifdef(CONFIG_BMI323 bmi323) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index a91ea8824bd0..d86e198a6a90 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -74,6 +74,7 @@ source "drivers/sensor/bmc150_magn/Kconfig" source "drivers/sensor/bme280/Kconfig" source "drivers/sensor/bme680/Kconfig" source "drivers/sensor/bmg160/Kconfig" +source "drivers/sensor/bmi08x/Kconfig" source "drivers/sensor/bmi160/Kconfig" source "drivers/sensor/bmi270/Kconfig" source "drivers/sensor/bmi323/Kconfig" diff --git a/drivers/sensor/bmi08x/CMakeLists.txt b/drivers/sensor/bmi08x/CMakeLists.txt new file mode 100644 index 000000000000..a3a13c2390ac --- /dev/null +++ b/drivers/sensor/bmi08x/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_BMI08X bmi08x_accel.c) +zephyr_library_sources_ifdef(CONFIG_BMI08X bmi08x_gyro.c) +zephyr_library_sources_ifdef(CONFIG_BMI08X bmi08x.c) +zephyr_library_sources_ifdef(CONFIG_BMI08X_ACCEL_TRIGGER bmi08x_accel_trigger.c) +zephyr_library_sources_ifdef(CONFIG_BMI08X_GYRO_TRIGGER bmi08x_gyro_trigger.c) diff --git a/drivers/sensor/bmi08x/Kconfig b/drivers/sensor/bmi08x/Kconfig new file mode 100644 index 000000000000..dad1abb28967 --- /dev/null +++ b/drivers/sensor/bmi08x/Kconfig @@ -0,0 +1,95 @@ +# Bosch BMI08X inertial measurement configuration options + +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates +# SPDX-License-Identifier: Apache-2.0 + +menuconfig BMI08X + bool "Bosch BMI08X inertial measurement unit" + default y + depends on DT_HAS_BOSCH_BMI08X_ACCEL_ENABLED || DT_HAS_BOSCH_BMI08X_GYRO_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_ACCEL),i2c) \ + || $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_GYRO),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_ACCEL),spi) \ + || $(dt_compat_on_bus,$(DT_COMPAT_BOSCH_BMI08X_GYRO),spi) + help + Enable Bosch BMI08X inertial measurement unit that provides acceleration + and angular rate measurements. + +if BMI08X + +choice BMI08X_ACCEL_TRIGGER_MODE + prompt "Accelerometer trigger mode" + default BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config BMI08X_ACCEL_TRIGGER_NONE + bool "No trigger" + +config BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + select BMI08X_ACCEL_TRIGGER + +config BMI08X_ACCEL_TRIGGER_OWN_THREAD + bool "Use own thread" + select BMI08X_ACCEL_TRIGGER +endchoice + +config BMI08X_ACCEL_TRIGGER + bool + +config BMI08X_ACCEL_THREAD_PRIORITY + int "Accelerometer own thread priority" + depends on BMI08X_ACCEL_TRIGGER_OWN_THREAD + default 10 + help + The priority of the thread used for handling interrupts. + +config BMI08X_ACCEL_THREAD_STACK_SIZE + int "Accelerometer own thread stack size" + depends on BMI08X_ACCEL_TRIGGER_OWN_THREAD + default 1536 + help + The thread stack size. + +choice BMI08X_GYRO_TRIGGER_MODE + prompt "Gyroscope trigger mode" + default BMI08X_GYRO_TRIGGER_NONE + default BMI08X_GYRO_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config BMI08X_GYRO_TRIGGER_NONE + bool "No trigger" + +config BMI08X_GYRO_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + select BMI08X_GYRO_TRIGGER + +config BMI08X_GYRO_TRIGGER_OWN_THREAD + bool "Use own thread" + select BMI08X_GYRO_TRIGGER +endchoice + +config BMI08X_GYRO_TRIGGER + bool + +config BMI08X_GYRO_THREAD_PRIORITY + int "Own thread priority" + depends on BMI08X_GYRO_TRIGGER_OWN_THREAD + default 10 + help + The priority of the thread used for handling interrupts. + +config BMI08X_GYRO_THREAD_STACK_SIZE + int "Own thread stack size" + depends on BMI08X_GYRO_TRIGGER_OWN_THREAD + default 1536 + help + The thread stack size. + +config BMI08X_I2C_WRITE_BURST_SIZE + int "Maximum length of single i2c write" + default 16 + +endif # BMI08X diff --git a/drivers/sensor/bmi08x/bmi08x.c b/drivers/sensor/bmi08x/bmi08x.c new file mode 100644 index 000000000000..0cf47ef7ab8f --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x.c @@ -0,0 +1,74 @@ +/* Bosch BMI08X inertial measurement unit driver + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "bmi08x.h" + +/* + * Output data rate map with allowed frequencies: + * freq = freq_int + freq_milli / 1000 + * + * Since we don't need a finer frequency resolution than milliHz, use uint16_t + * to save some flash. + */ +static const struct { + uint16_t freq_int; + uint16_t freq_milli; /* User should convert to uHz before setting the + * SENSOR_ATTR_SAMPLING_FREQUENCY attribute. + */ +} bmi08x_odr_map[] = { + {0, 0}, {0, 780}, {1, 562}, {3, 120}, {6, 250}, {12, 500}, {25, 0}, + {50, 0}, {100, 0}, {200, 0}, {400, 0}, {800, 0}, {1600, 0}, {3200, 0}, +}; + +int bmi08x_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli) +{ + size_t i; + + /* An ODR of 0 Hz is not allowed */ + if (freq_int == 0U && freq_milli == 0U) { + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(bmi08x_odr_map); i++) { + if (freq_int < bmi08x_odr_map[i].freq_int || + (freq_int == bmi08x_odr_map[i].freq_int && + freq_milli <= bmi08x_odr_map[i].freq_milli)) { + return i; + } + } + + return -EINVAL; +} + +int32_t bmi08x_range_to_reg_val(uint16_t range, const struct bmi08x_range *range_map, + uint16_t range_map_size) +{ + int i; + + for (i = 0; i < range_map_size; i++) { + if (range <= range_map[i].range) { + return range_map[i].reg_val; + } + } + + return -EINVAL; +} + +int32_t bmi08x_reg_val_to_range(uint8_t reg_val, const struct bmi08x_range *range_map, + uint16_t range_map_size) +{ + int i; + + for (i = 0; i < range_map_size; i++) { + if (reg_val == range_map[i].reg_val) { + return range_map[i].range; + } + } + + return -EINVAL; +} diff --git a/drivers/sensor/bmi08x/bmi08x.h b/drivers/sensor/bmi08x/bmi08x.h new file mode 100644 index 000000000000..3bb2d59579a9 --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x.h @@ -0,0 +1,593 @@ +/* Bosch BMI08X inertial measurement unit header + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI08X_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI08X_H_ + +#include +#include +#include +#include +#include + +/* Accel Chip Id register */ +#define BMI08X_REG_ACCEL_CHIP_ID 0x00 + +/* Accel Error condition register */ +#define BMI08X_REG_ACCEL_ERR 0x02 + +/* Accel Status flag register */ +#define BMI08X_REG_ACCEL_STATUS 0x03 + +/* Accel X LSB data register */ +#define BMI08X_REG_ACCEL_X_LSB 0x12 + +/* Accel X MSB data register */ +#define BMI08X_REG_ACCEL_X_MSB 0x13 + +/* Accel Y LSB data register */ +#define BMI08X_REG_ACCEL_Y_LSB 0x14 + +/* Accel Y MSB data register */ +#define BMI08X_REG_ACCEL_Y_MSB 0x15 + +/* Accel Z LSB data register */ +#define BMI08X_REG_ACCEL_Z_LSB 0x16 + +/* Accel Z MSB data register */ +#define BMI08X_REG_ACCEL_Z_MSB 0x17 + +/* Sensor time byte 0 register */ +#define BMI08X_REG_ACCEL_SENSORTIME_0 0x18 + +/* Sensor time byte 1 register */ +#define BMI08X_REG_ACCEL_SENSORTIME_1 0x19 + +/* Sensor time byte 2 register */ +#define BMI08X_REG_ACCEL_SENSORTIME_2 0x1A + +/* Accel Interrupt status0 register */ +#define BMI08X_REG_ACCEL_INT_STAT_0 0x1C + +/* Accel Interrupt status1 register */ +#define BMI08X_REG_ACCEL_INT_STAT_1 0x1D + +/* Accel general purpose register 0*/ +#define BMI08X_REG_ACCEL_GP_0 0x1E + +/* Sensor temperature MSB data register */ +#define BMI08X_REG_TEMP_MSB 0x22 + +/* Sensor temperature LSB data register */ +#define BMI08X_REG_TEMP_LSB 0x23 + +/* Accel general purpose register 4*/ +#define BMI08X_REG_ACCEL_GP_4 0x27 + +/* Accel Internal status register */ +#define BMI08X_REG_ACCEL_INTERNAL_STAT 0x2A + +/* Accel configuration register */ +#define BMI08X_REG_ACCEL_CONF 0x40 + +/* Accel range setting register */ +#define BMI08X_REG_ACCEL_RANGE 0x41 + +/* Accel Interrupt pin 1 configuration register */ +#define BMI08X_REG_ACCEL_INT1_IO_CONF 0x53 + +/* Accel Interrupt pin 2 configuration register */ +#define BMI08X_REG_ACCEL_INT2_IO_CONF 0x54 + +/* Accel Interrupt latch configuration register */ +#define BMI08X_REG_ACCEL_INT_LATCH_CONF 0x55 + +/* Accel Interrupt pin1 mapping register */ +#define BMI08X_REG_ACCEL_INT1_MAP 0x56 + +/* Accel Interrupt pin2 mapping register */ +#define BMI08X_REG_ACCEL_INT2_MAP 0x57 + +/* Accel Interrupt map register */ +#define BMI08X_REG_ACCEL_INT1_INT2_MAP_DATA 0x58 + +/* Accel Init control register */ +#define BMI08X_REG_ACCEL_INIT_CTRL 0x59 + +/* Accel Self test register */ +#define BMI08X_REG_ACCEL_SELF_TEST 0x6D + +/* Accel Power mode configuration register */ +#define BMI08X_REG_ACCEL_PWR_CONF 0x7C + +/* Accel Power control (switch on or off register */ +#define BMI08X_REG_ACCEL_PWR_CTRL 0x7D + +/* Accel Soft reset register */ +#define BMI08X_REG_ACCEL_SOFTRESET 0x7E + +/* BMI085 Accel unique chip identifier */ +#define BMI085_ACCEL_CHIP_ID 0x1F + +/* BMI088 Accel unique chip identifier */ +#define BMI088_ACCEL_CHIP_ID 0x1E + +/* Feature Config related Registers */ +#define BMI08X_ACCEL_RESERVED_5B_REG 0x5B +#define BMI08X_ACCEL_RESERVED_5C_REG 0x5C +#define BMI08X_ACCEL_FEATURE_CFG_REG 0x5E + +/* Interrupt masks */ +#define BMI08X_ACCEL_DATA_READY_INT 0x80 + +/* Accel Bandwidth */ +#define BMI08X_ACCEL_BW_OSR4 0x00 +#define BMI08X_ACCEL_BW_OSR2 0x01 +#define BMI08X_ACCEL_BW_NORMAL 0x02 + +/* BMI085 Accel Range */ +#define BMI085_ACCEL_RANGE_2G 0x00 +#define BMI085_ACCEL_RANGE_4G 0x01 +#define BMI085_ACCEL_RANGE_8G 0x02 +#define BMI085_ACCEL_RANGE_16G 0x03 + +/**\name BMI088 Accel Range */ +#define BMI088_ACCEL_RANGE_3G 0x00 +#define BMI088_ACCEL_RANGE_6G 0x01 +#define BMI088_ACCEL_RANGE_12G 0x02 +#define BMI088_ACCEL_RANGE_24G 0x03 + +/* Accel Output data rate */ +#define BMI08X_ACCEL_ODR_12_5_HZ 0x05 +#define BMI08X_ACCEL_ODR_25_HZ 0x06 +#define BMI08X_ACCEL_ODR_50_HZ 0x07 +#define BMI08X_ACCEL_ODR_100_HZ 0x08 +#define BMI08X_ACCEL_ODR_200_HZ 0x09 +#define BMI08X_ACCEL_ODR_400_HZ 0x0A +#define BMI08X_ACCEL_ODR_800_HZ 0x0B +#define BMI08X_ACCEL_ODR_1600_HZ 0x0C + +/* Accel Init Ctrl */ +#define BMI08X_ACCEL_INIT_CTRL_DISABLE 0x00 +#define BMI08X_ACCEL_INIT_CTRL_ENABLE 0x01 + +/* Accel Self test */ +#define BMI08X_ACCEL_SWITCH_OFF_SELF_TEST 0x00 +#define BMI08X_ACCEL_POSITIVE_SELF_TEST 0x0D +#define BMI08X_ACCEL_NEGATIVE_SELF_TEST 0x09 + +/* Accel Power mode */ +#define BMI08X_ACCEL_PM_ACTIVE 0x00 +#define BMI08X_ACCEL_PM_SUSPEND 0x03 + +/* Accel Power control settings */ +#define BMI08X_ACCEL_POWER_DISABLE 0x00 +#define BMI08X_ACCEL_POWER_ENABLE 0x04 + +/* Accel internal interrupt pin mapping */ +#define BMI08X_ACCEL_INTA_DISABLE 0x00 +#define BMI08X_ACCEL_INTA_ENABLE 0x01 +#define BMI08X_ACCEL_INTB_DISABLE 0x00 +#define BMI08X_ACCEL_INTB_ENABLE 0x02 +#define BMI08X_ACCEL_INTC_DISABLE 0x00 +#define BMI08X_ACCEL_INTC_ENABLE 0x04 + +/* Accel Soft reset delay */ +#define BMI08X_ACCEL_SOFTRESET_DELAY_MS 1 + +/* Mask definitions for ACCEL_ERR_REG register */ +#define BMI08X_FATAL_ERR_MASK 0x01 +#define BMI08X_ERR_CODE_MASK 0x1C + +/* Position definitions for ACCEL_ERR_REG register */ +#define BMI08X_CMD_ERR_POS 1 +#define BMI08X_ERR_CODE_POS 2 + +/* Mask definition for ACCEL_STATUS_REG register */ +#define BMI08X_ACCEL_STATUS_MASK 0x80 + +/* Position definitions for ACCEL_STATUS_REG */ +#define BMI08X_ACCEL_STATUS_POS 7 + +/* Mask definitions for odr, bandwidth and range */ +#define BMI08X_ACCEL_ODR_MASK 0x0F +#define BMI08X_ACCEL_BW_MASK 0x70 +#define BMI08X_ACCEL_RANGE_MASK 0x03 + +/* Position definitions for odr, bandwidth and range */ +#define BMI08X_ACCEL_BW_POS 4 + +/* Mask definitions for INT1_IO_CONF register */ +#define BMI08X_ACCEL_INT_EDGE_MASK 0x01 +#define BMI08X_ACCEL_INT_LVL_MASK 0x02 +#define BMI08X_ACCEL_INT_OD_MASK 0x04 +#define BMI08X_ACCEL_INT_IO_MASK 0x08 +#define BMI08X_ACCEL_INT_IN_MASK 0x10 + +/* Position definitions for INT1_IO_CONF register */ +#define BMI08X_ACCEL_INT_EDGE_POS 0 +#define BMI08X_ACCEL_INT_LVL_POS 1 +#define BMI08X_ACCEL_INT_OD_POS 2 +#define BMI08X_ACCEL_INT_IO_POS 3 +#define BMI08X_ACCEL_INT_IN_POS 4 + +/* Mask definitions for INT1/INT2 mapping register */ +#define BMI08X_ACCEL_MAP_INTA_MASK 0x01 + +/* Mask definitions for INT1/INT2 mapping register */ +#define BMI08X_ACCEL_MAP_INTA_POS 0x00 + +/* Mask definitions for INT1_INT2_MAP_DATA register */ +#define BMI08X_ACCEL_INT1_DRDY_MASK 0x04 +#define BMI08X_ACCEL_INT2_DRDY_MASK 0x40 + +/* Position definitions for INT1_INT2_MAP_DATA register */ +#define BMI08X_ACCEL_INT1_DRDY_POS 2 +#define BMI08X_ACCEL_INT2_DRDY_POS 6 + +/* Asic Initialization value */ +#define BMI08X_ASIC_INITIALIZED 0x01 + +#define BMI08X_TEMP_OFFSET 32 + +/*************************** BMI08 Gyroscope Macros *****************************/ +/** Register map */ +/* Gyro registers */ + +/* Gyro Chip Id register */ +#define BMI08X_REG_GYRO_CHIP_ID 0x00 + +/* Gyro X LSB data register */ +#define BMI08X_REG_GYRO_X_LSB 0x02 + +/* Gyro X MSB data register */ +#define BMI08X_REG_GYRO_X_MSB 0x03 + +/* Gyro Y LSB data register */ +#define BMI08X_REG_GYRO_Y_LSB 0x04 + +/* Gyro Y MSB data register */ +#define BMI08X_REG_GYRO_Y_MSB 0x05 + +/* Gyro Z LSB data register */ +#define BMI08X_REG_GYRO_Z_LSB 0x06 + +/* Gyro Z MSB data register */ +#define BMI08X_REG_GYRO_Z_MSB 0x07 + +/* Gyro Interrupt status register */ +#define BMI08X_REG_GYRO_INT_STAT_1 0x0A + +/* Gyro Range register */ +#define BMI08X_REG_GYRO_RANGE 0x0F + +/* Gyro Bandwidth register */ +#define BMI08X_REG_GYRO_BANDWIDTH 0x10 + +/* Gyro Power register */ +#define BMI08X_REG_GYRO_LPM1 0x11 + +/* Gyro Soft reset register */ +#define BMI08X_REG_GYRO_SOFTRESET 0x14 + +/* Gyro Interrupt control register */ +#define BMI08X_REG_GYRO_INT_CTRL 0x15 + +/* Gyro Interrupt Pin configuration register */ +#define BMI08X_REG_GYRO_INT3_INT4_IO_CONF 0x16 + +/* Gyro Interrupt Map register */ +#define BMI08X_REG_GYRO_INT3_INT4_IO_MAP 0x18 + +/* Gyro Self test register */ +#define BMI08X_REG_GYRO_SELF_TEST 0x3C + +/* Gyro unique chip identifier */ +#define BMI08X_GYRO_CHIP_ID 0x0F + +/* Gyro Range */ +#define BMI08X_GYRO_RANGE_2000_DPS 0x00 +#define BMI08X_GYRO_RANGE_1000_DPS 0x01 +#define BMI08X_GYRO_RANGE_500_DPS 0x02 +#define BMI08X_GYRO_RANGE_250_DPS 0x03 +#define BMI08X_GYRO_RANGE_125_DPS 0x04 + +/* Gyro Output data rate and bandwidth */ +#define BMI08X_GYRO_BW_532_ODR_2000_HZ 0x00 +#define BMI08X_GYRO_BW_230_ODR_2000_HZ 0x01 +#define BMI08X_GYRO_BW_116_ODR_1000_HZ 0x02 +#define BMI08X_GYRO_BW_47_ODR_400_HZ 0x03 +#define BMI08X_GYRO_BW_23_ODR_200_HZ 0x04 +#define BMI08X_GYRO_BW_12_ODR_100_HZ 0x05 +#define BMI08X_GYRO_BW_64_ODR_200_HZ 0x06 +#define BMI08X_GYRO_BW_32_ODR_100_HZ 0x07 +#define BMI08X_GYRO_ODR_RESET_VAL 0x80 + +/* Gyro Power mode */ +#define BMI08X_GYRO_PM_NORMAL 0x00 +#define BMI08X_GYRO_PM_DEEP_SUSPEND 0x20 +#define BMI08X_GYRO_PM_SUSPEND 0x80 + +/* Gyro data ready interrupt enable value */ +#define BMI08X_GYRO_DRDY_INT_DISABLE_VAL 0x00 +#define BMI08X_GYRO_DRDY_INT_ENABLE_VAL 0x80 + +/* Gyro data ready map values */ +#define BMI08X_GYRO_MAP_DRDY_TO_INT3 0x01 +#define BMI08X_GYRO_MAP_DRDY_TO_INT4 0x80 +#define BMI08X_GYRO_MAP_DRDY_TO_BOTH_INT3_INT4 0x81 + +/* Gyro Soft reset delay */ +#define BMI08X_GYRO_SOFTRESET_DELAY 30 + +/* Gyro power mode config delay */ +#define BMI08X_GYRO_POWER_MODE_CONFIG_DELAY 30 + +/** Mask definitions for range, bandwidth and power */ +#define BMI08X_GYRO_RANGE_MASK 0x07 +#define BMI08X_GYRO_BW_MASK 0x0F +#define BMI08X_GYRO_POWER_MASK 0xA0 + +/** Position definitions for range, bandwidth and power */ +#define BMI08X_GYRO_POWER_POS 5 + +/* Mask definitions for BMI08X_GYRO_INT_CTRL_REG register */ +#define BMI08X_GYRO_DATA_EN_MASK 0x80 + +/* Position definitions for BMI08X_GYRO_INT_CTRL_REG register */ +#define BMI08X_GYRO_DATA_EN_POS 7 + +/* Mask definitions for BMI08X_GYRO_INT3_INT4_IO_CONF_REG register */ +#define BMI08X_GYRO_INT3_LVL_MASK 0x01 +#define BMI08X_GYRO_INT3_OD_MASK 0x02 +#define BMI08X_GYRO_INT4_LVL_MASK 0x04 +#define BMI08X_GYRO_INT4_OD_MASK 0x08 + +/* Position definitions for BMI08X_GYRO_INT3_INT4_IO_CONF_REG register */ +#define BMI08X_GYRO_INT3_OD_POS 1 +#define BMI08X_GYRO_INT4_LVL_POS 2 +#define BMI08X_GYRO_INT4_OD_POS 3 + +/* Mask definitions for BMI08X_GYRO_INT_EN_REG register */ +#define BMI08X_GYRO_INT_EN_MASK 0x80 + +/* Position definitions for BMI08X_GYRO_INT_EN_REG register */ +#define BMI08X_GYRO_INT_EN_POS 7 + +/* Mask definitions for BMI088_GYRO_INT_MAP_REG register */ +#define BMI08X_GYRO_INT3_MAP_MASK 0x01 +#define BMI08X_GYRO_INT4_MAP_MASK 0x80 + +/* Position definitions for BMI088_GYRO_INT_MAP_REG register */ +#define BMI08X_GYRO_INT3_MAP_POS 0 +#define BMI08X_GYRO_INT4_MAP_POS 7 + +/* Mask definitions for BMI088_GYRO_INT_MAP_REG register */ +#define BMI088_GYRO_INT3_MAP_MASK 0x01 +#define BMI088_GYRO_INT4_MAP_MASK 0x80 + +/* Position definitions for BMI088_GYRO_INT_MAP_REG register */ +#define BMI088_GYRO_INT3_MAP_POS 0 +#define BMI088_GYRO_INT4_MAP_POS 7 + +/* Mask definitions for GYRO_SELF_TEST register */ +#define BMI08X_GYRO_SELF_TEST_EN_MASK 0x01 +#define BMI08X_GYRO_SELF_TEST_RDY_MASK 0x02 +#define BMI08X_GYRO_SELF_TEST_RESULT_MASK 0x04 +#define BMI08X_GYRO_SELF_TEST_FUNCTION_MASK 0x08 + +/* Position definitions for GYRO_SELF_TEST register */ +#define BMI08X_GYRO_SELF_TEST_RDY_POS 1 +#define BMI08X_GYRO_SELF_TEST_RESULT_POS 2 +#define BMI08X_GYRO_SELF_TEST_FUNCTION_POS 3 + +/*************************** Common Macros for both Accel and Gyro *****************************/ +/** Soft reset Value */ +#define BMI08X_SOFT_RESET_CMD 0xB6 + +/* Constant values macros */ +#define BMI08X_SENSOR_DATA_SYNC_TIME_MS 1 +#define BMI08X_DELAY_BETWEEN_WRITES_MS 1 +#define BMI08X_SELF_TEST_DELAY_MS 3 +#define BMI08X_POWER_CONFIG_DELAY 5 +#define BMI08X_SENSOR_SETTLE_TIME_MS 30 +#define BMI08X_SELF_TEST_DATA_READ_MS 50 +#define BMI08X_ASIC_INIT_TIME_MS 150 + +/* allowed ODR values */ +enum bmi08x_odr { + BMI08X_ODR_25_2, + BMI08X_ODR_25, + BMI08X_ODR_50, + BMI08X_ODR_100, + BMI08X_ODR_200, + BMI08X_ODR_400, + BMI08X_ODR_800, + BMI08X_ODR_1600, +}; + +/* Range values for accelerometer */ +#define BMI08X_ACC_RANGE_2G_3G 0x0 +#define BMI08X_ACC_RANGE_4G_6G 0x1 +#define BMI08X_ACC_RANGE_8G_12G 0x2 +#define BMI08X_ACC_RANGE_16G_24G 0x3 + +/* Range values for gyro */ +#define BMI08X_GYR_RANGE_2000DPS 0 +#define BMI08X_GYR_RANGE_1000DPS 1 +#define BMI08X_GYR_RANGE_500DPS 2 +#define BMI08X_GYR_RANGE_250DPS 3 +#define BMI08X_GYR_RANGE_125DPS 4 + +#define BMI08X_ACC_SCALE(range_g) ((2 * range_g * SENSOR_G) / 65536LL) +#define BMI08X_GYR_SCALE(range_dps) ((2 * range_dps * SENSOR_PI) / 180LL / 65536LL) + +/* report of data sync is selected */ +#define BMI08X_ACCEL_DATA_SYNC_EN(inst) DT_NODE_HAS_STATUS(DT_INST_PHANDLE(inst, data_sync), okay) +/* Macro used for compile time optimization to compile in/out code used for data-sync + * if at least 1 bmi08x has data-sync enabled + */ +#define ACCEL_HELPER(inst) BMI08X_ACCEL_DATA_SYNC_EN(inst) || +#define BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC DT_INST_FOREACH_STATUS_OKAY(ACCEL_HELPER) 0 +#define GYRO_HELPER(inst) DT_INST_PROP(inst, data_sync) || +#define BMI08X_GYRO_ANY_INST_HAS_DATA_SYNC DT_INST_FOREACH_STATUS_OKAY(GYRO_HELPER) 0 + +struct bmi08x_range { + uint16_t range; + uint8_t reg_val; +}; + +union bmi08x_bus { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif +}; + +struct bmi08x_accel_bus_io { + int (*check)(const union bmi08x_bus *bus); + int (*bus_init)(const struct device *dev); + int (*transceive)(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length); +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + int (*write_config_file)(const struct device *dev); +#endif +}; + +struct bmi08x_gyro_bus_io { + int (*check)(const union bmi08x_bus *bus); + int (*transceive)(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length); +}; + +struct bmi08x_accel_config { + union bmi08x_bus bus; + const struct bmi08x_accel_bus_io *api; +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) + struct gpio_dt_spec int_gpio; +#endif +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) || BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + uint8_t int1_map; + uint8_t int2_map; + uint8_t int1_conf_io; + uint8_t int2_conf_io; +#endif + uint8_t accel_hz; + uint8_t accel_fs; +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + uint8_t data_sync; +#endif +}; + +struct bmi08x_gyro_config { + union bmi08x_bus bus; + const struct bmi08x_gyro_bus_io *api; +#if defined(CONFIG_BMI08X_GYRO_TRIGGER) + struct gpio_dt_spec int_gpio; +#endif +#if defined(CONFIG_BMI08X_GYRO_TRIGGER) || BMI08X_GYRO_ANY_INST_HAS_DATA_SYNC + uint8_t int3_4_map; + uint8_t int3_4_conf_io; +#endif + uint8_t gyro_hz; + uint8_t gyro_fs; +}; + +struct bmi08x_accel_data { +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER) + struct gpio_callback gpio_cb; +#endif + uint16_t acc_sample[3]; + uint16_t scale; /* micro m/s^2/lsb */ + +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_BMI08X_ACCEL_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem sem; +#elif defined(CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD) + struct k_work work; + const struct device *dev; +#endif + +#ifdef CONFIG_BMI08X_ACCEL_TRIGGER + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *drdy_trig_acc; +#endif /* CONFIG_BMI08X_ACCEL_TRIGGER */ + uint8_t accel_chip_id; +}; + +struct bmi08x_gyro_data { +#if defined(CONFIG_BMI08X_GYRO_TRIGGER) + struct gpio_callback gpio_cb; +#endif + uint16_t gyr_sample[3]; + uint16_t scale; /* micro radians/s/lsb */ + +#if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem sem; +#elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD) + struct k_work work; + const struct device *dev; +#endif + +#ifdef CONFIG_BMI08X_GYRO_TRIGGER + sensor_trigger_handler_t handler_drdy_gyr; + const struct sensor_trigger *drdy_trig_gyr; +#endif /* CONFIG_BMI08X_GYRO_TRIGGER */ +}; + +/* common functions for accel and gyro */ +int bmi08x_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli); +int32_t bmi08x_range_to_reg_val(uint16_t range, const struct bmi08x_range *range_map, + uint16_t range_map_size); +int32_t bmi08x_reg_val_to_range(uint8_t reg_val, const struct bmi08x_range *range_map, + uint16_t range_map_size); + +int bmi08x_accel_read(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint8_t len); +int bmi08x_accel_write(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint16_t len); +int bmi08x_accel_byte_read(const struct device *dev, uint8_t reg_addr, uint8_t *byte); +int bmi08x_accel_byte_write(const struct device *dev, uint8_t reg_addr, uint8_t byte); +int bmi08x_accel_word_write(const struct device *dev, uint8_t reg_addr, uint16_t word); +int bmi08x_accel_reg_field_update(const struct device *dev, uint8_t reg_addr, uint8_t pos, + uint8_t mask, uint8_t val); +static inline int bmi08x_accel_reg_update(const struct device *dev, uint8_t reg_addr, uint8_t mask, + uint8_t val) +{ + return bmi08x_accel_reg_field_update(dev, reg_addr, 0, mask, val); +} + +int bmi08x_gyro_read(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint8_t len); +int bmi08x_gyro_byte_read(const struct device *dev, uint8_t reg_addr, uint8_t *byte); +int bmi08x_gyro_byte_write(const struct device *dev, uint8_t reg_addr, uint8_t byte); +int bmi08x_gyro_word_write(const struct device *dev, uint8_t reg_addr, uint16_t word); +int bmi08x_gyro_reg_field_update(const struct device *dev, uint8_t reg_addr, uint8_t pos, + uint8_t mask, uint8_t val); +static inline int bmi08x_gyro_reg_update(const struct device *dev, uint8_t reg_addr, uint8_t mask, + uint8_t val) +{ + return bmi08x_gyro_reg_field_update(dev, reg_addr, 0, mask, val); +} + +int bmi08x_acc_trigger_mode_init(const struct device *dev); +int bmi08x_trigger_set_acc(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +int bmi08x_acc_slope_config(const struct device *dev, enum sensor_attribute attr, + const struct sensor_value *val); +int32_t bmi08x_acc_reg_val_to_range(uint8_t reg_val); + +int bmi08x_gyr_trigger_mode_init(const struct device *dev); +int bmi08x_trigger_set_gyr(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +int bmi08x_gyr_slope_config(const struct device *dev, enum sensor_attribute attr, + const struct sensor_value *val); +int32_t bmi08x_gyr_reg_val_to_range(uint8_t reg_val); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI08X_H_ */ diff --git a/drivers/sensor/bmi08x/bmi08x_accel.c b/drivers/sensor/bmi08x/bmi08x_accel.c new file mode 100644 index 000000000000..3af5128dfd12 --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x_accel.c @@ -0,0 +1,812 @@ +/* Bosch BMI08X inertial measurement unit driver + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_accel +#include "bmi08x.h" +#include "bmi08x_config_file.h" + +LOG_MODULE_REGISTER(BMI08X_ACCEL, CONFIG_SENSOR_LOG_LEVEL); + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +static int bmi08x_accel_transceive_i2c(const struct device *dev, uint8_t reg, bool write, + void *data, size_t length) +{ + const struct bmi08x_accel_config *bmi08x = dev->config; + + if (!write) { + return i2c_write_read_dt(&bmi08x->bus.i2c, ®, 1, data, length); + } + if (length > CONFIG_BMI08X_I2C_WRITE_BURST_SIZE) { + return -EINVAL; + } + uint8_t buf[1 + CONFIG_BMI08X_I2C_WRITE_BURST_SIZE]; + + buf[0] = reg; + memcpy(&buf[1], data, length); + return i2c_write_dt(&bmi08x->bus.i2c, buf, 1 + length); +} + +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC +static int bmi08x_stream_transfer_write_i2c(const struct device *dev, uint16_t index, + const uint8_t *stream_data, uint16_t stream_length) +{ + uint8_t asic_msb = (uint8_t)((index / 2) >> 4); + uint8_t asic_lsb = ((index / 2) & 0x0F); + int ret; + + ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5B_REG, asic_lsb); + if (ret != 0) { + LOG_ERR("Cannot write index"); + return ret; + } + ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5C_REG, asic_msb); + if (ret != 0) { + LOG_ERR("Cannot write index"); + return ret; + } + ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, (uint8_t *)stream_data, + stream_length); + if (ret != 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return ret; + } + return ret; +} + +static int bmi08x_write_config_file_i2c(const struct device *dev) +{ + const uint8_t *data = bmi08x_config_file; + uint16_t length = sizeof(bmi08x_config_file); + uint16_t index = 0; + int ret = 0; + + while (length != 0) { + uint16_t len1 = length; + + if (len1 > CONFIG_BMI08X_I2C_WRITE_BURST_SIZE) { + len1 = CONFIG_BMI08X_I2C_WRITE_BURST_SIZE; + } + ret = bmi08x_stream_transfer_write_i2c(dev, index, data, len1); + if (ret != 0) { + return ret; + } + index += len1; + data += len1; + length -= len1; + } + return ret; +} +#endif + +static int bmi08x_bus_check_i2c(const union bmi08x_bus *bus) +{ + return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV; +} + +static const struct bmi08x_accel_bus_io bmi08x_i2c_api = {.check = bmi08x_bus_check_i2c, + .transceive = bmi08x_accel_transceive_i2c, +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + .write_config_file = + bmi08x_write_config_file_i2c +#endif +}; + +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +static int bmi08x_accel_transceive_spi(const struct device *dev, uint8_t reg, bool write, + void *data, size_t length) +{ + const struct bmi08x_accel_config *bmi08x = dev->config; + const struct spi_buf tx_buf[2] = {{.buf = ®, .len = 1}, {.buf = data, .len = length}}; + const struct spi_buf_set tx = {.buffers = tx_buf, .count = write ? 2 : 1}; + + if (!write) { + uint16_t dummy; + const struct spi_buf rx_buf[2] = {{.buf = &dummy, .len = 2}, + {.buf = data, .len = length}}; + const struct spi_buf_set rx = {.buffers = rx_buf, .count = 2}; + + return spi_transceive_dt(&bmi08x->bus.spi, &tx, &rx); + } + + return spi_write_dt(&bmi08x->bus.spi, &tx); +} + +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC +static int bmi08x_write_config_file_spi(const struct device *dev) +{ + int ret; + + ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5B_REG, 0); + if (ret < 0) { + LOG_ERR("Cannot write index"); + return ret; + } + ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5C_REG, 0); + if (ret < 0) { + LOG_ERR("Cannot write index"); + return ret; + } + /* write config file */ + ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, (uint8_t *)bmi08x_config_file, + sizeof(bmi08x_config_file)); + if (ret < 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return ret; + } + return ret; +} +#endif + +static int bmi08x_bus_check_spi(const union bmi08x_bus *bus) +{ + return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; +} + +static int bmi08x_bus_init_spi(const struct device *dev) +{ + uint8_t val; + int ret; + /* do a dummy read from 0x7F to activate SPI */ + ret = bmi08x_accel_byte_read(dev, 0x7F, &val); + if (ret < 0) { + LOG_ERR("Cannot read from 0x7F.."); + return ret; + } + + k_usleep(100); + + return ret; +} + +static const struct bmi08x_accel_bus_io bmi08x_spi_api = {.check = bmi08x_bus_check_spi, + .bus_init = bmi08x_bus_init_spi, + .transceive = bmi08x_accel_transceive_spi, +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + .write_config_file = + bmi08x_write_config_file_spi +#endif +}; + +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +static inline int bmi08x_bus_check(const struct device *dev) +{ + const struct bmi08x_accel_config *config = dev->config; + + return config->api->check(&config->bus); +} + +static inline int bmi08x_bus_init(const struct device *dev) +{ + const struct bmi08x_accel_config *config = dev->config; + + /* optional, only needed to initialize SPI according to datasheet */ + if (config->api->bus_init) { + return config->api->bus_init(dev); + } + return 0; +} + +static int bmi08x_accel_transceive(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length) +{ + const struct bmi08x_accel_config *config = dev->config; + + return config->api->transceive(dev, reg, write, data, length); +} + +int bmi08x_accel_read(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint8_t len) +{ + return bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, data, len); +} + +int bmi08x_accel_write(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + return bmi08x_accel_transceive(dev, reg_addr, true, data, len); +} + +int bmi08x_accel_byte_read(const struct device *dev, uint8_t reg_addr, uint8_t *byte) +{ + return bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, byte, 1); +} + +static int bmi08x_accel_word_read(const struct device *dev, uint8_t reg_addr, uint16_t *word) +{ + int ret; + + ret = bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, word, 2); + if (ret != 0) { + return ret; + } + + *word = sys_le16_to_cpu(*word); + + return ret; +} + +int bmi08x_accel_byte_write(const struct device *dev, uint8_t reg_addr, uint8_t byte) +{ + return bmi08x_accel_transceive(dev, reg_addr & 0x7F, true, &byte, 1); +} + +int bmi08x_accel_word_write(const struct device *dev, uint8_t reg_addr, uint16_t word) +{ + uint8_t tx_word[2] = {(uint8_t)(word & 0xff), (uint8_t)(word >> 8)}; + + return bmi08x_accel_transceive(dev, reg_addr & 0x7F, true, tx_word, 2); +} + +int bmi08x_accel_reg_field_update(const struct device *dev, uint8_t reg_addr, uint8_t pos, + uint8_t mask, uint8_t val) +{ + uint8_t old_val; + int ret; + + ret = bmi08x_accel_byte_read(dev, reg_addr, &old_val); + if (ret < 0) { + return ret; + } + + return bmi08x_accel_byte_write(dev, reg_addr, (old_val & ~mask) | ((val << pos) & mask)); +} + +static int bmi08x_acc_odr_set(const struct device *dev, uint16_t freq_int, uint16_t freq_milli) +{ + int odr = bmi08x_freq_to_odr_val(freq_int, freq_milli); + + if (odr < BMI08X_ACCEL_ODR_12_5_HZ) { + return odr; + } + + return bmi08x_accel_reg_field_update(dev, BMI08X_REG_ACCEL_CONF, 0, BMI08X_ACCEL_ODR_MASK, + (uint8_t)odr); +} + +static const struct bmi08x_range bmi085_acc_range_map[] = { + {2, BMI085_ACCEL_RANGE_2G}, + {4, BMI085_ACCEL_RANGE_4G}, + {8, BMI085_ACCEL_RANGE_8G}, + {16, BMI085_ACCEL_RANGE_16G}, +}; +#define BMI085_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi085_acc_range_map) + +static const struct bmi08x_range bmi088_acc_range_map[] = { + {3, BMI088_ACCEL_RANGE_3G}, + {6, BMI088_ACCEL_RANGE_6G}, + {12, BMI088_ACCEL_RANGE_12G}, + {24, BMI088_ACCEL_RANGE_24G}, +}; +#define BMI088_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi088_acc_range_map) + +static int bmi08x_acc_range_set(const struct device *dev, int32_t range) +{ + struct bmi08x_accel_data *data = dev->data; + int32_t reg_val = -1; + int ret; + + if (data->accel_chip_id == BMI085_ACCEL_CHIP_ID) { + reg_val = bmi08x_range_to_reg_val(range, bmi085_acc_range_map, + BMI085_ACC_RANGE_MAP_SIZE); + } else if (data->accel_chip_id == BMI088_ACCEL_CHIP_ID) { + reg_val = bmi08x_range_to_reg_val(range, bmi088_acc_range_map, + BMI088_ACC_RANGE_MAP_SIZE); + } else { + return -ENODEV; + } + + if (reg_val < 0) { + return reg_val; + } + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_RANGE, reg_val & 0xff); + if (ret < 0) { + return ret; + } + + data->scale = BMI08X_ACC_SCALE(range); + + return ret; +} + +static int bmi08x_acc_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 bmi08x_acc_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return bmi08x_acc_odr_set(dev, val->val1, val->val2 / 1000); + default: + LOG_ERR("Accel attribute not supported."); + return -ENOTSUP; + } +} + +static int bmi08x_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ +#ifdef 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_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + return bmi08x_acc_config(dev, chan, attr, val); + default: + LOG_ERR("attr_set() not supported on this channel."); + return -ENOTSUP; + } +} + +static int bmi08x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct bmi08x_accel_data *data = dev->data; + size_t i; + int ret; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_ACCEL_XYZ) { + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + +#ifdef CONFIG_PM_DEVICE + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_ACTIVE) { + return -EBUSY; + } +#endif + + pm_device_busy_set(dev); + + ret = bmi08x_accel_read(dev, BMI08X_REG_ACCEL_X_LSB, (uint8_t *)data->acc_sample, + sizeof(data->acc_sample)); + if (ret < 0) { + pm_device_busy_clear(dev); + return ret; + } + + /* convert samples to cpu endianness */ + for (i = 0; i < ARRAY_SIZE(data->acc_sample); i++) { + data->acc_sample[i] = sys_le16_to_cpu(data->acc_sample[i]); + } + + pm_device_busy_clear(dev); + return ret; +} + +static void bmi08x_to_fixed_point(int16_t raw_val, uint16_t scale, struct sensor_value *val) +{ + int32_t converted_val; + + /* + * 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 bmi08x_channel_convert(enum sensor_channel chan, uint16_t scale, uint16_t *raw_xyz, + struct sensor_value *val) +{ + int i; + uint8_t ofs_start, ofs_stop; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + ofs_start = ofs_stop = 0U; + break; + case SENSOR_CHAN_ACCEL_Y: + ofs_start = ofs_stop = 1U; + break; + case SENSOR_CHAN_ACCEL_Z: + ofs_start = ofs_stop = 2U; + break; + default: + ofs_start = 0U; + ofs_stop = 2U; + break; + } + + for (i = ofs_start; i <= ofs_stop; i++, val++) { + bmi08x_to_fixed_point(raw_xyz[i], scale, val); + } +} + +static inline void bmi08x_acc_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct bmi08x_accel_data *data = dev->data; + + bmi08x_channel_convert(chan, data->scale, data->acc_sample, val); +} + +static int bmi08x_temp_channel_get(const struct device *dev, struct sensor_value *val) +{ + uint16_t temp_raw = 0U; + int32_t temp_micro = 0; + int ret; + + ret = bmi08x_accel_word_read(dev, BMI08X_REG_TEMP_MSB, &temp_raw); + if (ret < 0) { + return ret; + } + + /* the scale is 1/2^5/LSB = 31250 micro degrees */ + temp_micro = BMI08X_TEMP_OFFSET * 1000000ULL + temp_raw * 31250ULL; + + val->val1 = temp_micro / 1000000ULL; + val->val2 = temp_micro % 1000000ULL; + + return ret; +} + +static int bmi08x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ +#ifdef 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 ((int16_t)chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + bmi08x_acc_channel_get(dev, chan, val); + return 0; + case SENSOR_CHAN_DIE_TEMP: + return bmi08x_temp_channel_get(dev, val); + default: + LOG_ERR("Channel not supported."); + return -ENOTSUP; + } + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int bmi08x_accel_pm_action(const struct device *dev, enum pm_device_action action) +{ + uint8_t conf_reg_val; + uint8_t ctrl_reg_val; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + conf_reg_val = BMI08X_ACCEL_PM_ACTIVE; + ctrl_reg_val = BMI08X_ACCEL_POWER_ENABLE; + break; + case PM_DEVICE_ACTION_SUSPEND: + conf_reg_val = BMI08X_ACCEL_PM_SUSPEND; + ctrl_reg_val = BMI08X_ACCEL_POWER_DISABLE; + break; + default: + return -ENOTSUP; + } + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, conf_reg_val); + if (ret < 0) { + LOG_ERR("Failed to set conf power mode"); + return ret; + } + k_msleep(BMI08X_POWER_CONFIG_DELAY); + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, ctrl_reg_val); + if (ret < 0) { + LOG_ERR("Failed to set ctrl power mode"); + return ret; + } + k_msleep(BMI08X_POWER_CONFIG_DELAY); + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + +static const struct sensor_driver_api bmi08x_api = { + .attr_set = bmi08x_attr_set, +#ifdef CONFIG_BMI08X_ACCEL_TRIGGER + .trigger_set = bmi08x_trigger_set_acc, +#endif + .sample_fetch = bmi08x_sample_fetch, + .channel_get = bmi08x_channel_get, +}; + +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC +static int bmi08x_apply_sync_binary_config(const struct device *dev) +{ + const struct bmi08x_accel_config *config = dev->config; + int ret; + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE); + if (ret < 0) { + LOG_ERR("Cannot deactivate advanced power save mode."); + return ret; + } + /* required when switching power modes */ + k_msleep(BMI08X_POWER_CONFIG_DELAY); + + /* deactivate accel, otherwise post processing can not be enabled safely */ + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_DISABLE); + if (ret < 0) { + LOG_ERR("Cannot deactivate accel."); + return ret; + } + /* required when switching power modes */ + k_msleep(BMI08X_POWER_CONFIG_DELAY); + /* disable config loading */ + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL, + BMI08X_ACCEL_INIT_CTRL_DISABLE); + if (ret < 0) { + LOG_ERR("Cannot disable config loading."); + return ret; + } + + if (config->api->write_config_file(dev) != 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return -EIO; + } + k_msleep(5U); + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL, + BMI08X_ACCEL_INIT_CTRL_ENABLE); + if (ret < 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return ret; + } + k_msleep(BMI08X_ASIC_INIT_TIME_MS); + + /* check config initialization status */ + uint8_t val; + + ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_INTERNAL_STAT, &val); + if (ret < 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return ret; + } + if (val != 1) { + LOG_ERR("Configuration stream error."); + return -EIO; + } + + /* write feature configuration */ + uint8_t fdata[8]; + + ret = bmi08x_accel_read(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6); + if (ret < 0) { + LOG_ERR("Cannot read configuration for accelerometer."); + return ret; + } + fdata[4] = config->data_sync; + fdata[5] = 0x00; + ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6); + if (ret < 0) { + LOG_ERR("Cannot write configuration for accelerometer."); + return ret; + } + k_msleep(100U); + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE); + if (ret < 0) { + LOG_ERR("Cannot activate accel."); + return ret; + } + /* required when switching power modes */ + k_msleep(BMI08X_POWER_CONFIG_DELAY); + + return ret; +} +#endif + +int bmi08x_accel_init(const struct device *dev) +{ + const struct bmi08x_accel_config *config = dev->config; + struct bmi08x_accel_data *data = dev->data; + uint8_t val = 0U; + int ret; + + ret = bmi08x_bus_check(dev); + if (ret < 0) { + LOG_ERR("Bus not ready for '%s'", dev->name); + return ret; + } + + /* reboot the chip */ + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_SOFTRESET, BMI08X_SOFT_RESET_CMD); + if (ret < 0) { + LOG_ERR("Cannot reboot chip."); + return ret; + } + + k_msleep(BMI08X_ACCEL_SOFTRESET_DELAY_MS); + + ret = bmi08x_bus_init(dev); + if (ret < 0) { + LOG_ERR("Can't initialize bus for %s", dev->name); + return ret; + } + + ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_CHIP_ID, &val); + if (ret < 0) { + LOG_ERR("Failed to read chip id."); + return ret; + } + + if ((val != BMI085_ACCEL_CHIP_ID) && (val != BMI088_ACCEL_CHIP_ID)) { + LOG_ERR("Unsupported chip detected (0x%02x)!", val); + return -ENODEV; + } + data->accel_chip_id = val; + + /* enable power */ + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE); + if (ret < 0) { + LOG_ERR("Failed to set conf power mode"); + return ret; + } + k_msleep(BMI08X_POWER_CONFIG_DELAY); + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE); + if (ret < 0) { + LOG_ERR("Failed to set ctrl power mode"); + return ret; + } + k_msleep(BMI08X_POWER_CONFIG_DELAY); + +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + if (config->data_sync != 0) { + ret = bmi08x_apply_sync_binary_config(dev); + if (ret < 0) { + return ret; + } + } +#endif + + /* set accelerometer default range, divide by two because the dts contains both bmi085 and + * bmi088 valid values even values in the enum are for the bmi085 and odd values are for the + * bmi088 + */ + ret = bmi08x_acc_range_set(dev, config->accel_fs); + if (ret < 0) { + LOG_ERR("Cannot set default range for accelerometer."); + return ret; + } + + /* set accelerometer default odr */ + /* add 5 to offset from the dts enum */ + ret = bmi08x_accel_reg_field_update(dev, BMI08X_REG_ACCEL_CONF, 0, BMI08X_ACCEL_ODR_MASK, + config->accel_hz); + if (ret < 0) { + LOG_ERR("Failed to set accel's default ODR."); + return ret; + } + +#ifdef CONFIG_BMI08X_ACCEL_TRIGGER + ret = bmi08x_acc_trigger_mode_init(dev); + if (ret < 0) { + LOG_ERR("Cannot set up trigger mode."); + return ret; + } +#endif + + return ret; +} + +#define BMI08X_CONFIG_SPI(inst) \ + .bus.spi = SPI_DT_SPEC_INST_GET( \ + inst, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 2), + +#define BMI08X_CONFIG_I2C(inst) .bus.i2c = I2C_DT_SPEC_INST_GET(inst), + +#define BMI08X_ACCEL_TRIG(inst) \ + .int1_map = DT_INST_PROP(inst, int1_map_io), .int2_map = DT_INST_PROP(inst, int2_map_io), \ + .int1_conf_io = DT_INST_PROP(inst, int1_conf_io), \ + .int2_conf_io = DT_INST_PROP(inst, int2_conf_io), + +/* verify the bmi08x-accel is paired with a bmi08x-gyro */ +#define BMI08X_VERIFY_DATA_SYNC(inst) \ + BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_INST_PHANDLE(inst, data_sync), bosch_bmi08x_gyro) != 0, \ + "bmi08x-accel data sync not paired with a bmi08x-gyro") +/* + * verify data sync odr, the only valid odr combinitions with the gyro are + * (gyro-hz == "400_47" and accel-hz == "400") or (gyro-hz == "1000_116" and accel-hz == "800") + * or ((gyro-hz == "2000_230" or gyro-hz == "2000_532") and accel-hz == "1600") + */ +#define BMI08X_GYRO_ODR(inst) DT_ENUM_IDX(DT_INST_PHANDLE(inst, data_sync), gyro_hz) +#define BMI08X_ACCEL_ODR(inst) DT_INST_ENUM_IDX(inst, accel_hz) +/* As the dts uses strings to define the definition, ints must be used for comparision */ +#define BMI08X_VERIFY_DATA_SYNC_ODR(inst) \ + BUILD_ASSERT((BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5) || \ + (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) || \ + ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) && \ + BMI08X_ACCEL_ODR(inst) == 7), \ + "Invalid gyro and accel odr for data-sync") +/* Assert if the gyro does not have data-sync enabled */ +#define BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst) \ + BUILD_ASSERT(DT_PROP(DT_INST_PHANDLE(inst, data_sync), data_sync), \ + "paired bmi08x-gyro does not have data-sync enabled") + +/* infer the data-sync value from the gyro and accel odr 2000=1, 1000=2, 400=3, otherwise it is 0 if + * it is not enabled. the build_assert should prevent any invalid values when it is enabled + */ +#define BMI08X_DATA_SYNC_REG_VAL(inst) \ + (BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5) ? 3 \ + : (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) ? 2 \ + : ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) && \ + BMI08X_ACCEL_ODR(inst) == 7) \ + ? 1 \ + : 0 + +/* define the .data_sync in the driver config */ +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC +/* if another bmi08x as the data sync enabled, and one doesn't, it will get the value of 0 and won't + * have the config file sent over + */ +#define BMI08X_DATA_SYNC_REG(inst) \ + .data_sync = COND_CODE_1(BMI08X_ACCEL_DATA_SYNC_EN(inst), \ + (BMI08X_DATA_SYNC_REG_VAL(inst)), (0)), +#define BMI08X_ACCEL_TRIGGER_PINS(inst) BMI08X_ACCEL_TRIG(inst) +#else +#define BMI08X_DATA_SYNC_REG(inst) +#define BMI08X_ACCEL_TRIGGER_PINS(inst) \ + IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER, (BMI08X_ACCEL_TRIG(inst))) +#endif + +#define BMI08X_CREATE_INST(inst) \ + \ + IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC(inst);)) \ + IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC_ODR(inst);)) \ + IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst);)) \ + \ + static struct bmi08x_accel_data bmi08x_drv_##inst; \ + \ + static const struct bmi08x_accel_config bmi08x_config_##inst = { \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)), \ + (BMI08X_CONFIG_I2C(inst))) \ + .api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api), \ + (&bmi08x_i2c_api)), \ + IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),)) \ + BMI08X_ACCEL_TRIGGER_PINS(inst) \ + .accel_hz = DT_INST_ENUM_IDX(inst, accel_hz) + 5, \ + .accel_fs = DT_INST_PROP(inst, accel_fs), BMI08X_DATA_SYNC_REG(inst)}; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_pm_action); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_init, PM_DEVICE_DT_INST_GET(inst), \ + &bmi08x_drv_##inst, &bmi08x_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &bmi08x_api); + +/* Create the struct device for every status "okay" node in the devicetree. */ +DT_INST_FOREACH_STATUS_OKAY(BMI08X_CREATE_INST) diff --git a/drivers/sensor/bmi08x/bmi08x_accel_trigger.c b/drivers/sensor/bmi08x/bmi08x_accel_trigger.c new file mode 100644 index 000000000000..223b3df7f740 --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x_accel_trigger.c @@ -0,0 +1,171 @@ +/* Bosch BMI08X inertial measurement unit driver, trigger implementation + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_accel +#include "bmi08x.h" + +#include +LOG_MODULE_DECLARE(BMI08X_ACCEL, CONFIG_SENSOR_LOG_LEVEL); + +static void bmi08x_handle_drdy_acc(const struct device *dev) +{ + struct bmi08x_accel_data *data = dev->data; + +#ifdef CONFIG_PM_DEVICE + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_ACTIVE) { + return; + } +#endif + + if (data->handler_drdy_acc) { + data->handler_drdy_acc(dev, data->drdy_trig_acc); + } +} + +static void bmi08x_handle_interrupts_acc(void *arg) +{ + const struct device *dev = (const struct device *)arg; + + bmi08x_handle_drdy_acc(dev); +} + +#ifdef CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD +static void bmi08x_acc_thread_main(void *arg1, void *unused1, void *unused2) +{ + k_thread_name_set(NULL, "bmi08x_acc_trig"); + + ARG_UNUSED(unused1); + ARG_UNUSED(unused2); + + const struct device *dev = (const struct device *)arg1; + struct bmi08x_accel_data *data = dev->data; + + while (1) { + k_sem_take(&data->sem, K_FOREVER); + bmi08x_handle_interrupts_acc((void *)dev); + } +} +#endif + +#ifdef CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD +static void bmi08x_acc_work_handler(struct k_work *work) +{ + struct bmi08x_accel_data *data = CONTAINER_OF(work, struct bmi08x_accel_data, work); + + bmi08x_handle_interrupts_acc((void *)data->dev); +} +#endif + +static void bmi08x_acc_gpio_callback(const struct device *port, struct gpio_callback *cb, + uint32_t pin) +{ + struct bmi08x_accel_data *data = CONTAINER_OF(cb, struct bmi08x_accel_data, gpio_cb); + + ARG_UNUSED(port); + ARG_UNUSED(pin); + +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD) + k_sem_give(&data->sem); +#elif defined(CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +int bmi08x_trigger_set_acc(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct bmi08x_accel_data *data = dev->data; + + if ((trig->chan == SENSOR_CHAN_ACCEL_XYZ) && (trig->type == SENSOR_TRIG_DATA_READY)) { + data->handler_drdy_acc = handler; + data->drdy_trig_acc = trig; + return 0; + } + + return -ENOTSUP; +} + +int bmi08x_acc_trigger_mode_init(const struct device *dev) +{ + struct bmi08x_accel_data *data = dev->data; + const struct bmi08x_accel_config *cfg = dev->config; + int ret = 0; + + if (!gpio_is_ready_dt(&cfg->int_gpio)) { + LOG_ERR("GPIO device not ready"); + return -ENODEV; + } + +#if defined(CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD) + k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&data->thread, data->thread_stack, + CONFIG_BMI08X_ACCEL_THREAD_STACK_SIZE, bmi08x_acc_thread_main, (void *)dev, + NULL, NULL, K_PRIO_COOP(CONFIG_BMI08X_ACCEL_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD) + data->work.handler = bmi08x_acc_work_handler; + data->dev = dev; +#endif + +#if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC + if (config->data_sync != 0) { + /* set accel ints */ + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INT1_MAP, cfg->int1_map); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INT2_MAP, cfg->int2_map); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + } else +#endif + { + uint8_t map_data = ((cfg->int2_map << BMI08X_ACCEL_INT2_DRDY_POS) | + (cfg->int1_map << BMI08X_ACCEL_INT1_DRDY_POS)); + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INT1_INT2_MAP_DATA, map_data); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + } + + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INT1_IO_CONF, cfg->int1_conf_io); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INT2_IO_CONF, cfg->int2_conf_io); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + + gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + + gpio_init_callback(&data->gpio_cb, bmi08x_acc_gpio_callback, BIT(cfg->int_gpio.pin)); + + ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb); + + if (ret < 0) { + LOG_ERR("Failed to set gpio callback."); + return ret; + } + gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + + return ret; +} diff --git a/drivers/sensor/bmi08x/bmi08x_config_file.h b/drivers/sensor/bmi08x/bmi08x_config_file.h new file mode 100644 index 000000000000..67f0a7e3a6ae --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x_config_file.h @@ -0,0 +1,424 @@ +/* Bosch BMI08X inertial measurement unit header + * + * Copyright (c) 2022 Bosch Sensortec GmbH. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BMI08X_BMI08X_CONFIG_FILE_H_ +#define BMI08X_BMI08X_CONFIG_FILE_H_ + +/* Source : https://github.com/BoschSensortec/BMI08x-Sensor-API/blob/bmi08x_v1.5.8/bmi08a.c#L69 */ +const uint8_t bmi08x_config_file[] = { + 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x48, 0xb4, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x6d, + 0xb4, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0xd4, 0xb3, 0x80, 0x2e, 0xb0, 0xb3, 0x80, 0x2e, + 0x12, 0xb4, 0x50, 0x39, 0x21, 0x2e, 0xb0, 0xf0, 0x10, 0x30, 0x21, 0x2e, 0x16, 0xf0, 0x80, + 0x2e, 0xfe, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, + 0x79, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x03, 0xb1, 0x12, 0x24, 0x67, 0x00, 0x90, 0x42, + 0x81, 0x42, 0xba, 0x82, 0xd1, 0x7f, 0xe2, 0x7f, 0x98, 0x2e, 0x3c, 0xb0, 0xd1, 0x6f, 0x00, + 0x2e, 0x41, 0x40, 0x40, 0xb2, 0x4c, 0x2f, 0xe1, 0x6f, 0x44, 0x86, 0x03, 0x2e, 0x67, 0x00, + 0xc2, 0x40, 0xf7, 0x86, 0x4a, 0x04, 0xc1, 0x42, 0x00, 0x2e, 0xc2, 0x40, 0x80, 0xac, 0x01, + 0x2f, 0x23, 0x2e, 0x63, 0x00, 0xd1, 0x40, 0xd2, 0x40, 0x0a, 0x0f, 0x01, 0x2f, 0x40, 0xac, + 0x02, 0x2f, 0x01, 0x30, 0x23, 0x2e, 0x63, 0x00, 0xfe, 0x82, 0xc2, 0x40, 0x43, 0x40, 0xd3, + 0x04, 0x46, 0x84, 0xc3, 0x7f, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80, 0x44, 0x40, 0xc1, 0x6f, + 0xc3, 0x40, 0xe0, 0x7f, 0xd1, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x00, 0xb0, 0xe1, + 0x6f, 0x72, 0x84, 0x40, 0x42, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80, 0x44, 0x40, 0xc3, 0x40, + 0xd1, 0x6f, 0xe0, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x00, 0xb0, 0xe1, 0x6f, 0x72, + 0x84, 0x40, 0x42, 0x85, 0x86, 0xc5, 0x82, 0x45, 0x80, 0x44, 0x40, 0xc3, 0x40, 0xd1, 0x6f, + 0xe0, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x00, 0xb0, 0xe1, 0x6f, 0x00, 0x2e, 0x40, + 0x42, 0x98, 0x2e, 0xa5, 0xb0, 0x11, 0x30, 0x23, 0x2e, 0x5e, 0xf0, 0xfb, 0x6f, 0xc0, 0x5f, + 0xb8, 0x2e, 0xaa, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0xed, + 0x8f, 0xd9, 0x31, 0x00, 0x00, 0xc6, 0x01, 0x8c, 0x03, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0x50, 0xf0, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x01, 0x01, 0x02, 0xbc, + 0x0f, 0xb8, 0xe0, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x01, 0x01, 0x01, 0xbc, 0x0f, 0xb8, 0xd0, + 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x01, 0x01, 0x0f, 0xb8, 0xc0, 0x7f, 0x02, 0x30, 0xe6, 0x6f, + 0xd4, 0x6f, 0xc3, 0x6f, 0x80, 0x91, 0x04, 0x2f, 0x00, 0x91, 0x02, 0x2f, 0xc0, 0xb2, 0x90, + 0x2e, 0xf6, 0x01, 0xf0, 0x6f, 0x0b, 0x2e, 0x24, 0x00, 0x01, 0x82, 0x40, 0x91, 0x14, 0x2f, + 0x41, 0x87, 0x27, 0x2e, 0x24, 0x00, 0x00, 0x40, 0x21, 0x2e, 0x1b, 0x00, 0x53, 0x40, 0x10, + 0x24, 0x1c, 0x00, 0x13, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x01, 0x42, 0x25, 0x2e, 0x18, 0x00, + 0x25, 0x2e, 0x19, 0x00, 0x25, 0x2e, 0x1e, 0x00, 0x50, 0x5f, 0xb8, 0x2e, 0x0b, 0x2e, 0x00, + 0x01, 0xd5, 0xbe, 0xd5, 0xba, 0xb5, 0x7f, 0x00, 0x2e, 0x0b, 0x2e, 0x01, 0x01, 0xd3, 0xbe, + 0xd3, 0xba, 0xa5, 0x7f, 0x00, 0x2e, 0x0b, 0x2e, 0x00, 0x01, 0xd4, 0xbe, 0xdf, 0xba, 0x95, + 0x7f, 0x00, 0x2e, 0x95, 0x6f, 0x0f, 0x2e, 0x1a, 0x00, 0x3d, 0x1a, 0x05, 0x2f, 0x25, 0x2e, + 0x18, 0x00, 0x25, 0x2e, 0x19, 0x00, 0x2b, 0x2e, 0x1a, 0x00, 0x80, 0x91, 0x01, 0x2f, 0x06, + 0x30, 0x07, 0x2d, 0x06, 0x40, 0x0f, 0x2e, 0x1b, 0x00, 0xb7, 0x05, 0x80, 0xa9, 0xd6, 0x05, + 0xb7, 0x23, 0x86, 0x7f, 0x00, 0x91, 0x01, 0x2f, 0x04, 0x30, 0x07, 0x2d, 0x44, 0x40, 0x0d, + 0x2e, 0x1c, 0x00, 0x26, 0x05, 0x00, 0xa9, 0x94, 0x05, 0x26, 0x23, 0x74, 0x7f, 0xc0, 0x90, + 0x01, 0x2f, 0x00, 0x2e, 0x09, 0x2d, 0x02, 0x86, 0x00, 0x2e, 0xc3, 0x40, 0x09, 0x2e, 0x1d, + 0x00, 0xdc, 0x04, 0xc0, 0xa8, 0x93, 0x04, 0x9a, 0x22, 0x62, 0x7f, 0x12, 0x30, 0x84, 0x6f, + 0xb3, 0x6f, 0x63, 0x0f, 0x14, 0x30, 0x08, 0x2f, 0x74, 0x6f, 0x63, 0x0f, 0x14, 0x30, 0x04, + 0x2f, 0x64, 0x6f, 0x63, 0x0f, 0x14, 0x30, 0x00, 0x2f, 0x04, 0x30, 0x54, 0x7f, 0x40, 0x91, + 0x0b, 0x2e, 0x18, 0x00, 0x54, 0x6f, 0xa3, 0x6f, 0x6a, 0x29, 0x1d, 0x2f, 0x00, 0x91, 0x06, + 0x30, 0x14, 0x24, 0x1c, 0x00, 0x0d, 0x2f, 0x2d, 0x2e, 0x18, 0x00, 0x05, 0x2e, 0x19, 0x00, + 0x81, 0x84, 0x25, 0x2e, 0x19, 0x00, 0x05, 0x2e, 0x19, 0x00, 0x53, 0x0e, 0x2b, 0x2f, 0x2d, + 0x2e, 0x1e, 0x00, 0x29, 0x2d, 0x2b, 0x2e, 0x18, 0x00, 0x2d, 0x2e, 0x19, 0x00, 0x0b, 0x2e, + 0x18, 0x00, 0x6b, 0x0e, 0x20, 0x2f, 0x25, 0x2e, 0x1e, 0x00, 0x1e, 0x2d, 0x00, 0xb3, 0x05, + 0x2f, 0x02, 0x30, 0x25, 0x2e, 0x18, 0x00, 0x25, 0x2e, 0x1e, 0x00, 0x08, 0x2d, 0x2b, 0x2e, + 0x18, 0x00, 0x09, 0x2e, 0x18, 0x00, 0x63, 0x0e, 0x01, 0x2f, 0x25, 0x2e, 0x1e, 0x00, 0x02, + 0x40, 0x25, 0x2e, 0x1b, 0x00, 0x31, 0x25, 0x00, 0x2e, 0xd5, 0x40, 0x12, 0x24, 0x1c, 0x00, + 0x42, 0x25, 0x95, 0x42, 0x00, 0x2e, 0xc3, 0x40, 0x83, 0x42, 0x00, 0x2e, 0x05, 0x2e, 0x1e, + 0x00, 0x80, 0xb2, 0x0d, 0x2f, 0x00, 0x40, 0x21, 0x2e, 0x1b, 0x00, 0x50, 0x40, 0x10, 0x43, + 0x00, 0x2e, 0x40, 0x40, 0x00, 0x43, 0x20, 0x30, 0x21, 0x2e, 0x5e, 0xf0, 0x02, 0x2d, 0x25, + 0x2e, 0x24, 0x00, 0x50, 0x5f, 0xb8, 0x2e, 0x40, 0x30, 0x21, 0x2e, 0xba, 0xf0, 0xb8, 0x2e, + 0x80, 0x2e, 0x18, 0x00, 0x70, 0x50, 0xf4, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc1, 0x7f, 0x12, + 0x30, 0x03, 0x2e, 0x66, 0x00, 0x91, 0x14, 0x92, 0x7f, 0x00, 0x31, 0xc4, 0x6f, 0x95, 0x6f, + 0xe3, 0x6f, 0xa5, 0x0f, 0x70, 0x84, 0x01, 0x04, 0x14, 0x2f, 0xd5, 0x6f, 0x00, 0xa9, 0x01, + 0x2f, 0xa5, 0x7f, 0x21, 0x2d, 0xdd, 0x04, 0xb3, 0x7f, 0x40, 0xb2, 0xb3, 0x6f, 0x1c, 0x18, + 0x06, 0x2f, 0x50, 0xa0, 0x01, 0x2f, 0xba, 0x11, 0x03, 0x2d, 0x71, 0x12, 0xb8, 0x14, 0x8a, + 0x0b, 0x6e, 0x00, 0xa1, 0x7f, 0x11, 0x2d, 0xf7, 0x6f, 0xfb, 0x05, 0xb7, 0x7f, 0x25, 0x05, + 0xb5, 0x6f, 0x2c, 0x18, 0x40, 0xb2, 0x06, 0x2f, 0x50, 0xa0, 0x01, 0x2f, 0xba, 0x11, 0x03, + 0x2d, 0x71, 0x12, 0xb8, 0x14, 0x8a, 0x0b, 0x5e, 0x00, 0xa1, 0x7f, 0x00, 0x2e, 0xa0, 0x6f, + 0x90, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0x02, 0x01, 0x8e, 0xbc, 0x01, 0x2e, 0x62, 0x00, 0x9e, + 0xb8, 0x01, 0x1a, 0x5f, 0x2f, 0x01, 0x2e, 0x02, 0x01, 0x0e, 0xbc, 0x0e, 0xb8, 0x21, 0x2e, + 0x62, 0x00, 0x03, 0x2e, 0x62, 0x00, 0x43, 0xb2, 0x10, 0x24, 0x65, 0x00, 0x3c, 0x2f, 0x42, + 0xb2, 0x22, 0x2f, 0x41, 0xb2, 0x06, 0x2f, 0x01, 0x30, 0x11, 0x42, 0x01, 0x42, 0x3e, 0x80, + 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x2e, 0x9d, 0x00, 0x5f, 0x90, 0x62, 0x30, 0x11, + 0x24, 0x81, 0x00, 0x07, 0x2f, 0x30, 0x25, 0x34, 0x37, 0xd4, 0x42, 0xc2, 0x42, 0xfe, 0x86, + 0x00, 0x2e, 0xc1, 0x42, 0x00, 0x2e, 0x07, 0x2e, 0x9d, 0x00, 0xde, 0x90, 0x35, 0x2f, 0x63, + 0x36, 0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x03, 0x2e, + 0x9d, 0x00, 0x5f, 0xb2, 0x52, 0x30, 0x21, 0x32, 0x0a, 0x2f, 0x07, 0x2e, 0x9d, 0x00, 0xde, + 0x90, 0x24, 0x2f, 0x23, 0x31, 0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, + 0xb8, 0x2e, 0x03, 0x32, 0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x01, 0x42, 0xb8, + 0x2e, 0x03, 0x2e, 0x9d, 0x00, 0x5f, 0xb2, 0x42, 0x30, 0x11, 0x31, 0x0a, 0x2f, 0x07, 0x2e, + 0x9d, 0x00, 0xde, 0x90, 0x0c, 0x2f, 0xa3, 0x30, 0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, + 0x2e, 0x01, 0x42, 0xb8, 0x2e, 0x63, 0x31, 0x13, 0x42, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, + 0x01, 0x42, 0xb8, 0x2e, 0x10, 0x24, 0x78, 0x00, 0x11, 0x24, 0x52, 0xf0, 0x12, 0x40, 0x52, + 0x42, 0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x12, 0x40, 0x42, 0x42, 0x42, 0x82, 0x00, 0x40, + 0x50, 0x42, 0x08, 0xb4, 0x40, 0x42, 0x7e, 0x80, 0xa8, 0xb4, 0x01, 0x42, 0xb8, 0x2e, 0x12, + 0x24, 0x71, 0x00, 0x90, 0x40, 0x84, 0x82, 0x20, 0x50, 0x50, 0x42, 0x77, 0x80, 0x82, 0x40, + 0x42, 0x42, 0xfb, 0x7f, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, + 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x77, 0x84, 0x00, 0x2e, + 0x90, 0x40, 0x84, 0x82, 0x82, 0x40, 0x50, 0x42, 0x77, 0x80, 0x42, 0x42, 0x05, 0x82, 0x00, + 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, 0x00, 0x40, 0x40, 0x42, 0x7c, 0x80, 0x05, 0x82, + 0x00, 0x40, 0x40, 0x42, 0x7c, 0x82, 0xe1, 0x7f, 0x98, 0x2e, 0x03, 0xb1, 0xe2, 0x6f, 0x00, + 0x2e, 0x90, 0x42, 0x81, 0x42, 0xbc, 0x82, 0x10, 0x24, 0x33, 0xf0, 0x23, 0x40, 0x02, 0x40, + 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80, 0x52, 0x42, 0x00, 0x2e, 0x23, 0x40, 0x02, 0x40, 0xb8, + 0xbd, 0x9a, 0x0a, 0x03, 0x80, 0x52, 0x42, 0x00, 0x2e, 0x22, 0x40, 0x00, 0x40, 0x28, 0xbd, + 0x10, 0x0a, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e, 0x11, 0x24, 0x28, + 0xf0, 0x50, 0x50, 0x60, 0x40, 0xf0, 0x7f, 0x51, 0x25, 0x60, 0x40, 0xe0, 0x7f, 0x00, 0x2e, + 0x41, 0x40, 0xd1, 0x7f, 0x00, 0x2e, 0xe2, 0x6f, 0xd0, 0x6f, 0x00, 0xb2, 0xf3, 0x6f, 0xa8, + 0xb8, 0x28, 0xbe, 0x59, 0x0a, 0x20, 0x0a, 0x01, 0x2f, 0xb0, 0x5f, 0xb8, 0x2e, 0x45, 0x41, + 0xc5, 0x7f, 0x00, 0x2e, 0xc5, 0x6f, 0x40, 0x91, 0x09, 0x2f, 0x05, 0x2e, 0x28, 0xf0, 0xb2, + 0x7f, 0x00, 0x2e, 0xb2, 0x6f, 0x1a, 0x1a, 0x07, 0x2f, 0xf0, 0x3f, 0x13, 0x25, 0x05, 0x2d, + 0x15, 0x1a, 0x02, 0x2f, 0x10, 0x24, 0xff, 0x00, 0x20, 0x0a, 0xb0, 0x5f, 0xb8, 0x2e, 0x01, + 0x2e, 0x03, 0x01, 0x8f, 0xbc, 0x01, 0x2e, 0x1f, 0x00, 0x9f, 0xb8, 0x01, 0x1a, 0x12, 0x2f, + 0x01, 0x2e, 0x03, 0x01, 0x0f, 0xbc, 0x0f, 0xb8, 0x21, 0x2e, 0x1f, 0x00, 0x11, 0x30, 0x05, + 0x2e, 0x1f, 0x00, 0x51, 0x08, 0xd2, 0x3f, 0x01, 0x2e, 0x07, 0xf0, 0x02, 0x08, 0x91, 0xbc, + 0x01, 0x0a, 0x21, 0x2e, 0x07, 0xf0, 0xb8, 0x2e, 0xb8, 0x2e, 0x50, 0x50, 0xf2, 0x7f, 0xe1, + 0x7f, 0x01, 0x30, 0xd1, 0x7f, 0xc1, 0x7f, 0x10, 0x24, 0x91, 0x04, 0xf2, 0x6f, 0xe3, 0x6f, + 0x1c, 0x2d, 0xc4, 0x6f, 0x9c, 0x01, 0xd5, 0x6f, 0x86, 0x41, 0x6e, 0x0d, 0xd5, 0x7f, 0xb1, + 0x7f, 0x0e, 0x2d, 0xd6, 0x6f, 0xef, 0xba, 0x61, 0xbf, 0x40, 0x91, 0x01, 0x2f, 0xd6, 0x7f, + 0x03, 0x2d, 0x70, 0x0d, 0xd5, 0x7f, 0x00, 0x2e, 0xb5, 0x6f, 0x41, 0x8b, 0xb5, 0x7f, 0x00, + 0x2e, 0xb5, 0x6f, 0x50, 0xa3, 0xee, 0x2f, 0x01, 0x89, 0xc4, 0x7f, 0x00, 0x2e, 0xc4, 0x6f, + 0x62, 0x0e, 0xe0, 0x2f, 0xd0, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0x90, 0x50, 0xd3, 0x7f, 0xfb, + 0x7f, 0xc2, 0x7f, 0xb1, 0x7f, 0x11, 0x30, 0xa1, 0x7f, 0x1a, 0x25, 0xc2, 0x6f, 0x72, 0x7f, + 0x77, 0x82, 0xb2, 0x6f, 0x82, 0x7f, 0xe2, 0x7f, 0x22, 0x30, 0x98, 0x2e, 0x4d, 0xb1, 0x90, + 0x7f, 0x00, 0x2e, 0xe1, 0x6f, 0xd0, 0x6f, 0x41, 0x16, 0x92, 0x6f, 0x01, 0x08, 0x51, 0x08, + 0x48, 0x1a, 0x01, 0x2f, 0x01, 0x30, 0xa1, 0x7f, 0x00, 0x2e, 0xfb, 0x6f, 0xa0, 0x6f, 0x70, + 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0xe3, 0x7f, 0xfb, 0x7f, 0xc1, 0x7f, 0xd2, 0x7f, 0x1a, 0x25, + 0xc0, 0x6f, 0xd2, 0x6f, 0x90, 0x7f, 0xa2, 0x7f, 0x79, 0x82, 0xe2, 0x6f, 0xb2, 0x7f, 0x32, + 0x30, 0x98, 0x2e, 0x4d, 0xb1, 0xfb, 0x6f, 0x90, 0x5f, 0xb8, 0x2e, 0xb0, 0x50, 0xa4, 0x7f, + 0xfb, 0x7f, 0x93, 0x7f, 0x82, 0x7f, 0x71, 0x7f, 0x00, 0x30, 0xa1, 0x6f, 0xe1, 0x7f, 0x40, + 0x42, 0x00, 0x2e, 0x92, 0x6f, 0x83, 0x6f, 0x71, 0x6f, 0xd3, 0x7f, 0xc2, 0x7f, 0xb1, 0x7f, + 0x98, 0x2e, 0x7a, 0xb1, 0x60, 0x7f, 0x00, 0x2e, 0x60, 0x6f, 0x01, 0xb2, 0x1e, 0x2f, 0xb1, + 0x6f, 0xf2, 0x30, 0x8a, 0x08, 0x13, 0x24, 0xf0, 0x00, 0x4b, 0x08, 0x24, 0xbd, 0x94, 0xb8, + 0x51, 0x0a, 0x51, 0x7f, 0x00, 0x2e, 0x51, 0x6f, 0x81, 0x16, 0xd3, 0x6f, 0x9a, 0x08, 0xc4, + 0x6f, 0xe1, 0x08, 0xe1, 0x6f, 0x93, 0x0a, 0x42, 0x42, 0x12, 0x24, 0x00, 0xff, 0x43, 0x40, + 0x9a, 0x08, 0x14, 0x24, 0xff, 0x00, 0xdc, 0x08, 0xb8, 0xbd, 0x28, 0xb9, 0x9a, 0x0a, 0x42, + 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0x50, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0xd4, 0x7f, 0xfb, 0x7f, + 0xc3, 0x7f, 0xa1, 0x7f, 0xb2, 0x7f, 0x02, 0x30, 0x92, 0x7f, 0x00, 0x2e, 0x05, 0x2e, 0x20, + 0x00, 0xc4, 0x6f, 0x80, 0xb2, 0x0c, 0x2f, 0x81, 0x90, 0x1a, 0x2f, 0xd2, 0x6f, 0x07, 0x2e, + 0x21, 0x00, 0xa1, 0x32, 0x98, 0x2e, 0xaf, 0xb1, 0x02, 0x30, 0x25, 0x2e, 0x20, 0x00, 0x92, + 0x7f, 0x10, 0x2d, 0xa1, 0x6f, 0xb2, 0x6f, 0xe4, 0x7f, 0xa3, 0x32, 0x98, 0x2e, 0x9c, 0xb1, + 0x21, 0x2e, 0x21, 0x00, 0xe2, 0x6f, 0x03, 0x2e, 0x21, 0x00, 0x81, 0x42, 0x12, 0x30, 0x25, + 0x2e, 0x20, 0x00, 0x92, 0x7f, 0x00, 0x2e, 0xfb, 0x6f, 0x90, 0x6f, 0x90, 0x5f, 0xb8, 0x2e, + 0x10, 0x50, 0x00, 0x30, 0xf0, 0x7f, 0x12, 0x24, 0x86, 0x00, 0x1b, 0x2d, 0xf1, 0x6f, 0xd1, + 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0x8c, 0x84, + 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0x8c, + 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, 0xbc, 0x84, 0xd1, 0x00, 0x00, 0x2e, 0xc0, 0x42, + 0x41, 0x82, 0xf1, 0x7f, 0xb4, 0x84, 0xf1, 0x6f, 0x43, 0xa2, 0xe1, 0x2f, 0xf0, 0x5f, 0xb8, + 0x2e, 0xc0, 0x50, 0x92, 0x7f, 0xfb, 0x7f, 0x81, 0x7f, 0x00, 0x30, 0x60, 0x7f, 0x70, 0x7f, + 0x50, 0x7f, 0x00, 0x2e, 0x03, 0x2e, 0x04, 0x01, 0x9d, 0xbc, 0x9e, 0xb8, 0x41, 0x7f, 0x00, + 0x2e, 0x42, 0x6f, 0x52, 0x7f, 0xe2, 0x7f, 0x00, 0x2e, 0x83, 0x6f, 0xc4, 0x82, 0xd3, 0x7f, + 0x0c, 0x2d, 0x55, 0x6f, 0x7f, 0x89, 0xdc, 0x01, 0x9d, 0x01, 0xcb, 0x41, 0x8b, 0x43, 0xcc, + 0x01, 0x4d, 0x01, 0xc7, 0x41, 0x47, 0x43, 0x54, 0x7f, 0x00, 0x2e, 0x54, 0x6f, 0x00, 0xab, + 0xf0, 0x2f, 0x9b, 0x6f, 0x8a, 0x00, 0x4b, 0x42, 0xc2, 0x7f, 0xb1, 0x7f, 0x50, 0x7f, 0x7c, + 0x80, 0xa0, 0x7f, 0x13, 0x24, 0x09, 0x01, 0x3f, 0x2d, 0x50, 0x6f, 0x18, 0x01, 0xc8, 0x84, + 0xc8, 0x00, 0x50, 0x00, 0x05, 0x41, 0xc7, 0x40, 0x44, 0x40, 0x61, 0x6f, 0x73, 0x6f, 0x2f, + 0x18, 0x00, 0xb3, 0x0b, 0x2f, 0x10, 0xa1, 0x03, 0x2f, 0x30, 0x89, 0xbc, 0x11, 0xce, 0x17, + 0x06, 0x2d, 0x74, 0x13, 0x06, 0x31, 0xb4, 0x05, 0xbe, 0x15, 0xfc, 0x11, 0xae, 0x0b, 0x4e, + 0x00, 0xdf, 0x02, 0x61, 0x7f, 0x73, 0x7f, 0xb4, 0x84, 0x01, 0x82, 0xd1, 0x00, 0x88, 0x80, + 0xa2, 0x6f, 0x11, 0x01, 0x81, 0x00, 0xc3, 0x40, 0x05, 0x41, 0x84, 0x40, 0x1d, 0x18, 0x72, + 0x6f, 0x00, 0xb3, 0x63, 0x6f, 0x0b, 0x2f, 0x10, 0xa1, 0x03, 0x2f, 0x30, 0x89, 0xbc, 0x11, + 0xce, 0x17, 0x06, 0x2d, 0x74, 0x13, 0x06, 0x31, 0xb4, 0x05, 0xbe, 0x15, 0xfc, 0x11, 0xae, + 0x0b, 0xde, 0x04, 0x97, 0x06, 0x63, 0x7f, 0x72, 0x7f, 0x51, 0x7f, 0x3c, 0x86, 0xb1, 0x6f, + 0xe2, 0x6f, 0x50, 0x6f, 0x42, 0x0e, 0xbc, 0x2f, 0xe0, 0x6f, 0xc8, 0x82, 0x98, 0x00, 0x48, + 0x00, 0xc0, 0x6f, 0x83, 0x40, 0x04, 0x40, 0x42, 0x40, 0x61, 0x6f, 0x70, 0x6f, 0x80, 0xb2, + 0x1c, 0x18, 0x0b, 0x2f, 0x90, 0xa0, 0x03, 0x2f, 0xb0, 0x84, 0xba, 0x11, 0xce, 0x17, 0x06, + 0x2d, 0x03, 0x31, 0xda, 0x04, 0xfb, 0x14, 0x32, 0x13, 0xfa, 0x11, 0xa3, 0x0b, 0x4e, 0x00, + 0x07, 0x02, 0x61, 0x7f, 0x70, 0x7f, 0x00, 0x2e, 0x72, 0x6f, 0x80, 0xa8, 0x60, 0x6f, 0xd1, + 0x6f, 0x13, 0x2f, 0x80, 0x90, 0x03, 0x2f, 0x13, 0x24, 0xff, 0x7f, 0x43, 0x0f, 0x0d, 0x2f, + 0xbf, 0xa0, 0x07, 0x2f, 0xbf, 0x90, 0x03, 0x2f, 0x12, 0x24, 0x00, 0x80, 0x42, 0x0e, 0x01, + 0x2f, 0x40, 0x42, 0x07, 0x2d, 0x10, 0x24, 0x00, 0x80, 0x40, 0x42, 0x03, 0x2d, 0x10, 0x24, + 0xff, 0x7f, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0x40, 0x5f, 0x40, 0x40, 0xb8, 0x2e, 0x11, + 0x24, 0x7b, 0x00, 0x30, 0x50, 0x10, 0x30, 0x50, 0x42, 0xfb, 0x7f, 0x10, 0x24, 0x33, 0xf0, + 0x23, 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80, 0x52, 0x42, 0x00, 0x2e, 0x23, + 0x40, 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x03, 0x80, 0x52, 0x42, 0x00, 0x2e, 0x23, 0x40, + 0x02, 0x40, 0xb8, 0xbd, 0x9a, 0x0a, 0x3c, 0x80, 0x42, 0x42, 0x7e, 0x84, 0xe0, 0x7f, 0x86, + 0x82, 0xd1, 0x7f, 0x00, 0x2e, 0x82, 0x40, 0x98, 0x2e, 0x40, 0xb2, 0xd1, 0x6f, 0x7d, 0x82, + 0x00, 0x2e, 0x40, 0x42, 0x7e, 0x80, 0x0d, 0x82, 0x02, 0x40, 0xd1, 0x7f, 0x98, 0x2e, 0x40, + 0xb2, 0xd1, 0x6f, 0x76, 0x82, 0x00, 0x2e, 0x40, 0x42, 0x7e, 0x80, 0x14, 0x82, 0x02, 0x40, + 0xd1, 0x7f, 0x98, 0x2e, 0x40, 0xb2, 0xd1, 0x6f, 0x6f, 0x82, 0x00, 0x2e, 0x40, 0x42, 0x7e, + 0x80, 0xe1, 0x6f, 0x12, 0x40, 0x52, 0x42, 0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x12, 0x40, + 0x52, 0x42, 0x28, 0xb5, 0x52, 0x42, 0x00, 0x2e, 0x00, 0x40, 0x50, 0x42, 0x08, 0xb4, 0x40, + 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0xd0, 0x5f, 0xb8, 0x2e, 0x10, 0x50, 0x01, 0x2e, 0x55, 0xf0, + 0xf0, 0x7f, 0x00, 0x2e, 0xf0, 0x6f, 0x21, 0x2e, 0x55, 0xf0, 0xf0, 0x5f, 0xb8, 0x2e, 0x20, + 0x50, 0x00, 0x30, 0xe0, 0x7f, 0xfb, 0x7f, 0x11, 0x24, 0xb1, 0xf0, 0x42, 0x40, 0x43, 0x30, + 0x93, 0x0a, 0x42, 0x42, 0x58, 0x82, 0x12, 0x24, 0xaf, 0x00, 0x62, 0x42, 0x12, 0x24, 0xff, + 0x00, 0x42, 0x42, 0x69, 0x82, 0x72, 0x3c, 0x43, 0x40, 0x9a, 0x08, 0x83, 0x32, 0x93, 0x0a, + 0x42, 0x42, 0x42, 0x82, 0x02, 0x3f, 0x43, 0x40, 0x9a, 0x08, 0x52, 0x42, 0x0b, 0x31, 0x4b, + 0x42, 0x7e, 0x82, 0x72, 0x31, 0x42, 0x42, 0x00, 0x2e, 0x03, 0x2e, 0x40, 0xf0, 0x5f, 0xb2, + 0x03, 0x2f, 0x03, 0x2e, 0x40, 0xf0, 0x5e, 0x90, 0x27, 0x2f, 0x11, 0x24, 0x00, 0x02, 0x12, + 0x24, 0x05, 0x80, 0x13, 0x24, 0xff, 0xb7, 0x1b, 0x24, 0x00, 0xb0, 0x04, 0x30, 0x05, 0x30, + 0x56, 0x32, 0x6e, 0x1a, 0x00, 0x2f, 0x25, 0x36, 0x69, 0x1a, 0x01, 0x2f, 0x5b, 0x25, 0x00, + 0x2e, 0x56, 0x41, 0x26, 0x0d, 0x06, 0x30, 0xcf, 0xbb, 0x41, 0xbe, 0xc0, 0x91, 0x01, 0x2f, + 0x00, 0x2e, 0x01, 0x2d, 0x22, 0x0d, 0x81, 0x8d, 0x90, 0xa1, 0xf5, 0x2f, 0xeb, 0x0e, 0xe8, + 0x2f, 0x01, 0x2e, 0x25, 0x00, 0x20, 0x1a, 0x05, 0x2f, 0x20, 0x30, 0xe0, 0x7f, 0x03, 0x2d, + 0x30, 0x30, 0xe0, 0x7f, 0x00, 0x2e, 0xe0, 0x6f, 0x00, 0xb2, 0x06, 0x2f, 0x21, 0x2e, 0x59, + 0xf0, 0x98, 0x2e, 0x43, 0xb3, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0xfb, 0x6f, 0xe0, 0x5f, + 0xb8, 0x2e, 0xa0, 0x50, 0x80, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, + 0x7f, 0x91, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x43, 0xf0, 0x08, 0xbc, + 0x0f, 0xb8, 0x60, 0x7f, 0x00, 0x2e, 0x60, 0x6f, 0x00, 0xb2, 0x01, 0x2f, 0x98, 0x2e, 0xb9, + 0xb0, 0x40, 0x30, 0x21, 0x2e, 0xb8, 0xf0, 0xf6, 0x6f, 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, + 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f, 0x7b, 0x6f, 0x80, 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0xa0, + 0x50, 0x80, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0x91, 0x7f, + 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x29, 0xf0, 0x08, 0xbc, 0x0f, 0xb8, 0x60, + 0x7f, 0x00, 0x2e, 0x60, 0x6f, 0x01, 0x90, 0x1b, 0x2f, 0x01, 0x2e, 0x02, 0x01, 0x0e, 0xbc, + 0x0e, 0xb8, 0x00, 0x90, 0x05, 0x2f, 0x01, 0x2e, 0x04, 0x01, 0x0f, 0xbc, 0x0f, 0xb8, 0x01, + 0xb2, 0x0d, 0x2f, 0x01, 0x2e, 0x7b, 0x00, 0x01, 0x90, 0x04, 0x2f, 0x98, 0x2e, 0x1a, 0xb2, + 0x00, 0x30, 0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x37, 0xf0, 0x21, 0x2e, 0x37, 0xf0, 0x02, + 0x2d, 0x98, 0x2e, 0xf3, 0xb2, 0x80, 0x30, 0x21, 0x2e, 0xb8, 0xf0, 0xf6, 0x6f, 0x91, 0x6f, + 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f, 0x7b, 0x6f, 0x80, 0x6f, 0x60, + 0x5f, 0xc8, 0x2e, 0x60, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x36, 0x30, 0x0f, 0x2e, 0x01, 0xf0, + 0xfe, 0xbf, 0xfe, 0xbb, 0xb7, 0x05, 0xa6, 0x7f, 0xd3, 0x7f, 0xc4, 0x7f, 0xb5, 0x7f, 0x14, + 0x24, 0x89, 0xf0, 0x3f, 0x8b, 0x03, 0x41, 0x44, 0x41, 0xb8, 0xbd, 0x9c, 0x0b, 0xa3, 0x6f, + 0x14, 0x24, 0x9a, 0x00, 0xb3, 0x11, 0x43, 0x8b, 0x16, 0x43, 0x00, 0x2e, 0x67, 0x41, 0x46, + 0x41, 0xf8, 0xbf, 0xbe, 0x0b, 0xb3, 0x11, 0x16, 0x43, 0x43, 0x8d, 0x00, 0x2e, 0xa5, 0x41, + 0x86, 0x41, 0xd8, 0xbe, 0x6e, 0x0b, 0xeb, 0x10, 0x03, 0x43, 0x13, 0x30, 0x27, 0x2e, 0x22, + 0x00, 0x03, 0x31, 0x27, 0x2e, 0xb8, 0xf0, 0xf6, 0x6f, 0xe7, 0x6f, 0xc4, 0x6f, 0xb5, 0x6f, + 0xd3, 0x6f, 0xa0, 0x5f, 0xc8, 0x2e, 0xa0, 0x50, 0x80, 0x7f, 0x91, 0x7f, 0xe7, 0x7f, 0xd5, + 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, + 0xb9, 0xf0, 0x60, 0x7f, 0x10, 0x30, 0x61, 0x6f, 0x08, 0x08, 0x00, 0xb2, 0x01, 0x2f, 0x98, + 0x2e, 0x9e, 0x00, 0x10, 0x30, 0x21, 0x2e, 0xb9, 0xf0, 0x21, 0x2e, 0x5f, 0xf0, 0xf6, 0x6f, + 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f, 0x7b, 0x6f, 0x80, + 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x56, 0x32, 0x0f, 0x2e, + 0x58, 0xf0, 0x7e, 0x1a, 0x02, 0x2f, 0x16, 0x30, 0x2d, 0x2e, 0x23, 0x00, 0x16, 0x24, 0x80, + 0x00, 0x2d, 0x2e, 0xb9, 0xf0, 0xe7, 0x6f, 0xf6, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e, 0x30, 0x50, + 0x04, 0x30, 0xd4, 0x7f, 0xe4, 0x7f, 0xfb, 0x7f, 0x13, 0x24, 0x26, 0xf0, 0xc2, 0x40, 0xc1, + 0x86, 0xe4, 0x7f, 0xd2, 0x7f, 0x00, 0x2e, 0xd1, 0x40, 0x18, 0xbc, 0x18, 0xba, 0xd2, 0x6f, + 0xe1, 0x6f, 0x90, 0x0a, 0x0c, 0x0b, 0xd2, 0x7f, 0xe4, 0x7f, 0x00, 0x2e, 0xe4, 0x6f, 0xc3, + 0x40, 0xe3, 0x0a, 0xdb, 0x6f, 0xdb, 0x7f, 0xe3, 0x7f, 0x13, 0x24, 0x15, 0x01, 0xe2, 0x6f, + 0x09, 0x2e, 0x16, 0x01, 0xd1, 0x6f, 0x98, 0x2e, 0xea, 0xb1, 0x21, 0x2e, 0x58, 0xf0, 0x98, + 0x2e, 0x43, 0xb3, 0xfb, 0x6f, 0xd0, 0x5f, 0xb8, 0x2e, 0x98, 0x2e, 0x4d, 0xb3, 0x20, 0x26, + 0x98, 0x2e, 0xfa, 0x01, 0x98, 0x2e, 0xf5, 0xb4, 0x98, 0x2e, 0xf1, 0xb4, 0x98, 0x2e, 0xde, + 0xb4, 0x98, 0x2e, 0xf9, 0xb4, 0x01, 0x2e, 0x40, 0xf0, 0x21, 0x2e, 0x9d, 0x00, 0x10, 0x30, + 0x21, 0x2e, 0x59, 0xf0, 0x98, 0x2e, 0x43, 0xb3, 0x21, 0x30, 0x10, 0x24, 0x9a, 0x00, 0x00, + 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x05, 0x2e, 0x22, 0x00, 0x80, 0xb2, 0x02, 0x30, 0x05, 0x2f, + 0x23, 0x2e, 0x5f, 0xf0, 0x25, 0x2e, 0x22, 0x00, 0x98, 0x2e, 0x17, 0x01, 0x98, 0x2e, 0x31, + 0xb1, 0x01, 0x2e, 0x23, 0x00, 0x01, 0x90, 0x00, 0x30, 0xe7, 0x2f, 0x21, 0x2e, 0x23, 0x00, + 0x98, 0x2e, 0x80, 0xb4, 0xe3, 0x2d, 0x80, 0x30, 0x21, 0x2e, 0xba, 0xf0, 0x10, 0x24, 0x80, + 0x00, 0x03, 0x2e, 0x06, 0xf0, 0x08, 0x0a, 0x21, 0x2e, 0x06, 0xf0, 0x00, 0x3e, 0x03, 0x2e, + 0x06, 0xf0, 0x08, 0x08, 0x51, 0x30, 0x01, 0x0a, 0x21, 0x2e, 0x06, 0xf0, 0xb8, 0x2e, 0x00, + 0x31, 0x21, 0x2e, 0xba, 0xf0, 0xb8, 0x2e, 0x10, 0x30, 0x21, 0x2e, 0xbb, 0xf0, 0xb8, 0x2e, + 0x10, 0x24, 0x80, 0x00, 0x21, 0x2e, 0xbb, 0xf0, 0xb8, 0x2e, 0x1a, 0x24, 0x26, 0x00, 0x80, + 0x2e, 0xab, 0xb4, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, + 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, + 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, + 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, + 0x00, 0x80, 0x2e, 0x18, 0x00, 0x80, 0x2e, 0x18, 0x00}; + +#endif /* BMI08X_BMI08X_CONFIG_FILE_H_ */ diff --git a/drivers/sensor/bmi08x/bmi08x_gyro.c b/drivers/sensor/bmi08x/bmi08x_gyro.c new file mode 100644 index 000000000000..84cdaa7ac8d6 --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x_gyro.c @@ -0,0 +1,484 @@ +/* Bosch BMI08X inertial measurement unit driver + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_gyro +#include "bmi08x.h" + +LOG_MODULE_REGISTER(BMI08X_GYRO, CONFIG_SENSOR_LOG_LEVEL); + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +static int bmi08x_gyro_transceive_i2c(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length) +{ + const struct bmi08x_gyro_config *bmi08x = dev->config; + + if (!write) { + return i2c_write_read_dt(&bmi08x->bus.i2c, ®, 1, data, length); + } + if (length > CONFIG_BMI08X_I2C_WRITE_BURST_SIZE) { + return -EINVAL; + } + uint8_t buf[1 + CONFIG_BMI08X_I2C_WRITE_BURST_SIZE]; + + buf[0] = reg; + memcpy(&buf[1], data, length); + return i2c_write_dt(&bmi08x->bus.i2c, buf, 1 + length); +} + +static int bmi08x_bus_check_i2c(const union bmi08x_bus *bus) +{ + return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV; +} + +static const struct bmi08x_gyro_bus_io bmi08x_i2c_api = { + .check = bmi08x_bus_check_i2c, + .transceive = bmi08x_gyro_transceive_i2c, +}; + +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +static int bmi08x_gyro_transceive_spi(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length) +{ + const struct bmi08x_gyro_config *bmi08x = dev->config; + const struct spi_buf tx_buf[2] = {{.buf = ®, .len = 1}, {.buf = data, .len = length}}; + const struct spi_buf_set tx = {.buffers = tx_buf, .count = write ? 2 : 1}; + + if (!write) { + uint16_t dummy; + const struct spi_buf rx_buf[2] = {{.buf = &dummy, .len = 1}, + {.buf = data, .len = length}}; + const struct spi_buf_set rx = {.buffers = rx_buf, .count = 2}; + + return spi_transceive_dt(&bmi08x->bus.spi, &tx, &rx); + } + + return spi_write_dt(&bmi08x->bus.spi, &tx); +} + +static int bmi08x_bus_check_spi(const union bmi08x_bus *bus) +{ + return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; +} + +static const struct bmi08x_gyro_bus_io bmi08x_spi_api = { + .check = bmi08x_bus_check_spi, + .transceive = bmi08x_gyro_transceive_spi, +}; + +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +static inline int bmi08x_bus_check(const struct device *dev) +{ + const struct bmi08x_gyro_config *config = dev->config; + + return config->api->check(&config->bus); +} + +static int bmi08x_gyro_transceive(const struct device *dev, uint8_t reg, bool write, void *data, + size_t length) +{ + const struct bmi08x_gyro_config *cfg = dev->config; + + return cfg->api->transceive(dev, reg, write, data, length); +} + +int bmi08x_gyro_read(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint8_t len) +{ + return bmi08x_gyro_transceive(dev, reg_addr | BIT(7), false, data, len); +} + +int bmi08x_gyro_byte_read(const struct device *dev, uint8_t reg_addr, uint8_t *byte) +{ + return bmi08x_gyro_transceive(dev, reg_addr | BIT(7), false, byte, 1); +} + +int bmi08x_gyro_byte_write(const struct device *dev, uint8_t reg_addr, uint8_t byte) +{ + return bmi08x_gyro_transceive(dev, reg_addr & 0x7F, true, &byte, 1); +} + +int bmi08x_gyro_word_write(const struct device *dev, uint8_t reg_addr, uint16_t word) +{ + uint8_t tx_word[2] = {(uint8_t)(word & 0xff), (uint8_t)(word >> 8)}; + + return bmi08x_gyro_transceive(dev, reg_addr & 0x7F, true, tx_word, 2); +} + +int bmi08x_gyro_reg_field_update(const struct device *dev, uint8_t reg_addr, uint8_t pos, + uint8_t mask, uint8_t val) +{ + uint8_t old_val; + int ret; + + ret = bmi08x_gyro_byte_read(dev, reg_addr, &old_val); + if (ret < 0) { + return ret; + } + + return bmi08x_gyro_byte_write(dev, reg_addr, (old_val & ~mask) | ((val << pos) & mask)); +} + +static const struct bmi08x_range bmi08x_gyr_range_map[] = { + {125, BMI08X_GYR_RANGE_125DPS}, {250, BMI08X_GYR_RANGE_250DPS}, + {500, BMI08X_GYR_RANGE_500DPS}, {1000, BMI08X_GYR_RANGE_1000DPS}, + {2000, BMI08X_GYR_RANGE_2000DPS}, +}; +#define BMI08X_GYR_RANGE_MAP_SIZE ARRAY_SIZE(bmi08x_gyr_range_map) + +int32_t bmi08x_gyr_reg_val_to_range(uint8_t reg_val) +{ + return bmi08x_reg_val_to_range(reg_val, bmi08x_gyr_range_map, BMI08X_GYR_RANGE_MAP_SIZE); +} + +static int bmi08x_gyr_odr_set(const struct device *dev, uint16_t freq_int, uint16_t freq_milli) +{ + int odr = bmi08x_freq_to_odr_val(freq_int, freq_milli); + + if (odr < 0) { + return odr; + } + + if (odr < BMI08X_GYRO_BW_532_ODR_2000_HZ || odr > BMI08X_GYRO_BW_32_ODR_100_HZ) { + return -ENOTSUP; + } + + return bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_BANDWIDTH, (uint8_t)odr); +} + +static int bmi08x_gyr_range_set(const struct device *dev, uint16_t range) +{ + struct bmi08x_gyro_data *bmi08x = dev->data; + int32_t reg_val = + bmi08x_range_to_reg_val(range, bmi08x_gyr_range_map, BMI08X_GYR_RANGE_MAP_SIZE); + int ret; + + if (reg_val < 0) { + return reg_val; + } + + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_RANGE, reg_val); + if (ret < 0) { + return ret; + } + + bmi08x->scale = BMI08X_GYR_SCALE(range); + + return ret; +} + +static int bmi08x_gyr_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 bmi08x_gyr_range_set(dev, sensor_rad_to_degrees(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return bmi08x_gyr_odr_set(dev, val->val1, val->val2 / 1000); + default: + LOG_ERR("Gyro attribute not supported."); + return -ENOTSUP; + } +} + +static int bmi08x_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ +#ifdef 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_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + return bmi08x_gyr_config(dev, chan, attr, val); + default: + LOG_ERR("attr_set() not supported on this channel."); + return -ENOTSUP; + } +} + +static int bmi08x_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct bmi08x_gyro_data *bmi08x = dev->data; + size_t i; + int ret; + + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_GYRO_XYZ) { + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + + ret = bmi08x_gyro_read(dev, BMI08X_REG_GYRO_X_LSB, (uint8_t *)bmi08x->gyr_sample, + sizeof(bmi08x->gyr_sample)); + if (ret < 0) { + return ret; + } + + /* convert samples to cpu endianness */ + for (i = 0; i < ARRAY_SIZE(bmi08x->gyr_sample); i++) { + bmi08x->gyr_sample[i] = sys_le16_to_cpu(bmi08x->gyr_sample[i]); + } + + return ret; +} + +static void bmi08x_to_fixed_point(int16_t raw_val, uint16_t scale, struct sensor_value *val) +{ + int32_t converted_val; + + /* + * 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 bmi08x_channel_convert(enum sensor_channel chan, uint16_t scale, uint16_t *raw_xyz, + struct sensor_value *val) +{ + int i; + uint8_t ofs_start, ofs_stop; + + switch (chan) { + case SENSOR_CHAN_GYRO_X: + ofs_start = ofs_stop = 0U; + break; + case SENSOR_CHAN_GYRO_Y: + ofs_start = ofs_stop = 1U; + break; + case SENSOR_CHAN_GYRO_Z: + ofs_start = ofs_stop = 2U; + break; + default: + ofs_start = 0U; + ofs_stop = 2U; + break; + } + + for (i = ofs_start; i <= ofs_stop; i++, val++) { + bmi08x_to_fixed_point(raw_xyz[i], scale, val); + } +} + +static inline void bmi08x_gyr_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct bmi08x_gyro_data *bmi08x = dev->data; + + bmi08x_channel_convert(chan, bmi08x->scale, bmi08x->gyr_sample, val); +} + +static int bmi08x_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ +#ifdef 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 ((int16_t)chan) { + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + bmi08x_gyr_channel_get(dev, chan, val); + return 0; + default: + LOG_ERR("Channel not supported."); + return -ENOTSUP; + } +} + +#ifdef CONFIG_PM_DEVICE +static int bmi08x_gyro_pm_action(const struct device *dev, enum pm_device_action action) +{ + uint8_t reg_val; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + reg_val = BMI08X_GYRO_PM_NORMAL; + break; + case PM_DEVICE_ACTION_SUSPEND: + reg_val = BMI08X_GYRO_PM_SUSPEND; + break; + default: + return -ENOTSUP; + } + + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_LPM1, reg_val); + if (ret < 0) { + LOG_ERR("Failed to set power mode"); + return ret; + } + k_msleep(BMI08X_GYRO_POWER_MODE_CONFIG_DELAY); + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + +static const struct sensor_driver_api bmi08x_api = { + .attr_set = bmi08x_attr_set, +#ifdef CONFIG_BMI08X_GYRO_TRIGGER + .trigger_set = bmi08x_trigger_set_gyr, +#endif + .sample_fetch = bmi08x_sample_fetch, + .channel_get = bmi08x_channel_get, +}; + +int bmi08x_gyro_init(const struct device *dev) +{ + const struct bmi08x_gyro_config *config = dev->config; + uint8_t val = 0U; + int ret; + + ret = bmi08x_bus_check(dev); + if (ret < 0) { + LOG_ERR("Bus not ready for '%s'", dev->name); + return ret; + } + + /* reboot the chip */ + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_SOFTRESET, BMI08X_SOFT_RESET_CMD); + if (ret < 0) { + LOG_ERR("Cannot reboot chip."); + return ret; + } + + k_msleep(BMI08X_GYRO_SOFTRESET_DELAY); + + ret = bmi08x_gyro_byte_read(dev, BMI08X_REG_GYRO_CHIP_ID, &val); + if (ret < 0) { + LOG_ERR("Failed to read chip id."); + return ret; + } + + if (val != BMI08X_GYRO_CHIP_ID) { + LOG_ERR("Unsupported chip detected (0x%02x)!", val); + return -ENODEV; + } + + /* set gyro default range */ + ret = bmi08x_gyr_range_set(dev, config->gyro_fs); + if (ret < 0) { + LOG_ERR("Cannot set default range for gyroscope."); + return ret; + } + + /* set gyro default bandwidth */ + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_BANDWIDTH, config->gyro_hz); + if (ret < 0) { + LOG_ERR("Failed to set gyro's default ODR."); + return ret; + } + +#ifdef CONFIG_BMI08X_GYRO_TRIGGER + ret = bmi08x_gyr_trigger_mode_init(dev); + if (ret < 0) { + LOG_ERR("Cannot set up trigger mode."); + return ret; + } +#endif +/* with BMI08X_DATA_SYNC set, it is expected that the INT3 or INT4 is wired to either INT1 + * or INT2 + */ +#if defined(CONFIG_BMI08X_GYRO_TRIGGER) || BMI08X_GYRO_ANY_INST_HAS_DATA_SYNC + /* set gyro ints */ + /* set ints */ + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_INT_CTRL, 0x80); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_INT3_INT4_IO_CONF, + config->int3_4_conf_io); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } + ret = bmi08x_gyro_byte_write(dev, BMI08X_REG_GYRO_INT3_INT4_IO_MAP, config->int3_4_map); + if (ret < 0) { + LOG_ERR("Failed to map interrupts."); + return ret; + } +#endif + + return ret; +} + +#define BMI08X_CONFIG_SPI(inst) \ + .bus.spi = SPI_DT_SPEC_INST_GET( \ + inst, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 2), + +#define BMI08X_CONFIG_I2C(inst) .bus.i2c = I2C_DT_SPEC_INST_GET(inst), + +#define BMI08X_GYRO_TRIG(inst) \ + .int3_4_map = DT_INST_PROP(inst, int3_4_map_io), \ + .int3_4_conf_io = DT_INST_PROP(inst, int3_4_conf_io), + +#if BMI08X_GYRO_ANY_INST_HAS_DATA_SYNC +/* the bmi08x-gyro should not have trigger mode with data-sync enabled */ +BUILD_ASSERT(CONFIG_BMI08X_GYRO_TRIGGER_NONE, + "Only none trigger type allowed for bmi08x-gyro with data-sync enabled"); +/* with data-sync, one of the int pins should be wired directory to the accel's int pins, their + * config should be defined + */ +#define BMI08X_GYRO_TRIGGER_PINS(inst) BMI08X_GYRO_TRIG(inst) +#else +#define BMI08X_GYRO_TRIGGER_PINS(inst) \ + IF_ENABLED(CONFIG_BMI08X_GYRO_TRIGGER, (BMI08X_GYRO_TRIG(inst))) +#endif + +#define BMI08X_CREATE_INST(inst) \ + \ + static struct bmi08x_gyro_data bmi08x_drv_##inst; \ + \ + static const struct bmi08x_gyro_config bmi08x_config_##inst = { \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)), \ + (BMI08X_CONFIG_I2C(inst))) \ + .api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api), \ + (&bmi08x_i2c_api)), \ + IF_ENABLED(CONFIG_BMI08X_GYRO_TRIGGER, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),)) \ + .gyro_hz = DT_INST_ENUM_IDX(inst, gyro_hz), \ + BMI08X_GYRO_TRIGGER_PINS(inst).gyro_fs = DT_INST_ENUM_IDX(inst, gyro_fs), \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_gyro_pm_action); \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, bmi08x_gyro_init, PM_DEVICE_DT_INST_GET(inst), \ + &bmi08x_drv_##inst, &bmi08x_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &bmi08x_api); + +/* Create the struct device for every status "okay" node in the devicetree. */ +DT_INST_FOREACH_STATUS_OKAY(BMI08X_CREATE_INST) diff --git a/drivers/sensor/bmi08x/bmi08x_gyro_trigger.c b/drivers/sensor/bmi08x/bmi08x_gyro_trigger.c new file mode 100644 index 000000000000..8be14312abb0 --- /dev/null +++ b/drivers/sensor/bmi08x/bmi08x_gyro_trigger.c @@ -0,0 +1,135 @@ +/* Bosch BMI08X inertial measurement unit driver, trigger implementation + * + * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmi08x_gyro +#include "bmi08x.h" + +#include +LOG_MODULE_DECLARE(BMI08X_GYRO, CONFIG_SENSOR_LOG_LEVEL); + +static void bmi08x_handle_drdy_gyr(const struct device *dev) +{ + struct bmi08x_gyro_data *data = dev->data; + +#ifdef CONFIG_PM_DEVICE + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_ACTIVE) { + return; + } +#endif + + if (data->handler_drdy_gyr) { + data->handler_drdy_gyr(dev, data->drdy_trig_gyr); + } +} + +static void bmi08x_handle_interrupts_gyr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + + bmi08x_handle_drdy_gyr(dev); +} + +#ifdef CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD +static void bmi08x_gyr_thread_main(void *arg1, void *unused1, void *unused2) +{ + k_thread_name_set(NULL, "bmi08x_gyr_trig"); + + ARG_UNUSED(unused1); + ARG_UNUSED(unused2); + + const struct device *dev = (const struct device *)arg1; + struct bmi08x_gyro_data *data = dev->data; + + while (1) { + k_sem_take(&data->sem, K_FOREVER); + bmi08x_handle_interrupts_gyr((void *)dev); + } +} +#endif + +#ifdef CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD +static void bmi08x_gyr_work_handler(struct k_work *work) +{ + struct bmi08x_gyro_data *data = CONTAINER_OF(work, struct bmi08x_gyro_data, work); + + bmi08x_handle_interrupts_gyr((void *)data->dev); +} +#endif + +static void bmi08x_gyr_gpio_callback(const struct device *port, struct gpio_callback *cb, + uint32_t pin) +{ + struct bmi08x_gyro_data *data = CONTAINER_OF(cb, struct bmi08x_gyro_data, gpio_cb); + + ARG_UNUSED(port); + ARG_UNUSED(pin); + +#if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD) + k_sem_give(&data->sem); +#elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD) + k_work_submit(&data->work); +#endif +} + +int bmi08x_trigger_set_gyr(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct bmi08x_gyro_data *data = dev->data; + + if ((trig->chan == SENSOR_CHAN_GYRO_XYZ) && (trig->type == SENSOR_TRIG_DATA_READY)) { + data->handler_drdy_gyr = handler; + data->drdy_trig_gyr = trig; + return 0; + } + + return -ENOTSUP; +} + +int bmi08x_gyr_trigger_mode_init(const struct device *dev) +{ + struct bmi08x_gyro_data *data = dev->data; + const struct bmi08x_gyro_config *cfg = dev->config; + int ret; + + if (!gpio_is_ready_dt(&cfg->int_gpio)) { + LOG_ERR("GPIO device not ready"); + return -ENODEV; + } + +#if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD) + k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&data->thread, data->thread_stack, + CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE, bmi08x_gyr_thread_main, (void *)dev, + NULL, NULL, K_PRIO_COOP(CONFIG_BMI08X_GYRO_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD) + data->work.handler = bmi08x_gyr_work_handler; + data->dev = dev; +#endif + + gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT); + + gpio_init_callback(&data->gpio_cb, bmi08x_gyr_gpio_callback, BIT(cfg->int_gpio.pin)); + + ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb); + + if (ret < 0) { + LOG_ERR("Failed to set gpio callback."); + return ret; + } + gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + + return ret; +} diff --git a/dts/bindings/sensor/bosch,bmi08x-accel-i2c.yaml b/dts/bindings/sensor/bosch,bmi08x-accel-i2c.yaml new file mode 100644 index 000000000000..375d8d8dcc52 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-accel-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Accel inertial measurement unit + +compatible: "bosch,bmi08x-accel" + +include: [i2c-device.yaml, "bosch,bmi08x-accel.yaml"] diff --git a/dts/bindings/sensor/bosch,bmi08x-accel-spi.yaml b/dts/bindings/sensor/bosch,bmi08x-accel-spi.yaml new file mode 100644 index 000000000000..924f9d567e88 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-accel-spi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Accel inertial measurement unit + +compatible: "bosch,bmi08x-accel" + +include: [spi-device.yaml, "bosch,bmi08x-accel.yaml"] diff --git a/dts/bindings/sensor/bosch,bmi08x-accel.yaml b/dts/bindings/sensor/bosch,bmi08x-accel.yaml new file mode 100644 index 000000000000..2bd311df0f53 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-accel.yaml @@ -0,0 +1,84 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Accel inertial measurement unit + +include: sensor-device.yaml + +properties: + int-gpios: + type: phandle-array + description: | + This property specifies the connection for INT, because the + Zephyr driver maps all interrupts to INT. The signal defaults + to output low when produced by the sensor. + + int1-map-io: + type: int + description: | + Bit[0]: Map Interrupt A to INT1, Accel Data Ready + Bit[1]: Map Interrupt B to INT1 + Bit[2]: Map Interrupt C to INT1 + + int2-map-io: + type: int + description: | + Bit[0]: Map Interrupt A to INT2, Accel Data Ready + Bit[1]: Map Interrupt B to INT2 + Bit[2]: Map Interrupt C to INT2 + + int1-conf-io: + type: int + description: | + Bit[0]: reserved + Bit[1]: if set to 1, INT1 is active high, otherwise it's active low + Bit[2]: if set to 1, INT1 is open-drain, otherwise it's push-pull + Bit[3]: if set to 1, enable INT1 as an output pin + Bit[4]: if set to 1, enable INT1 as an input pin + Bit[7:5] : reserved + + int2-conf-io: + type: int + description: | + Bit[0]: reserved + Bit[1]: if set to 1, INT2 is active high, otherwise it's active low + Bit[2]: if set to 1, INT2 is open-drain, otherwise it's push-pull + Bit[3]: if set to 1, enable INT2 as an output pin + Bit[4]: if set to 1, enable INT2 as an input pin + Bit[7:5] : reserved + + accel-hz: + type: string + required: true + description: | + Default frequency of accelerometer. (Unit - Hz) + enum: + - "12.5" + - "25" + - "50" + - "100" + - "200" + - "400" + - "800" + - "1600" + + accel-fs: + type: int + required: true + description: | + Default full scale of accelerometer. (Unit - g) + enum: + - 2 + - 3 + - 4 + - 6 + - 8 + - 12 + - 16 + - 24 + + data-sync: + type: phandle + description: | + Enables data sync if defined. This is to point to the bmi08x-gyro definition + that is within the same IC as the bmi08x-accel. diff --git a/dts/bindings/sensor/bosch,bmi08x-gyro-i2c.yaml b/dts/bindings/sensor/bosch,bmi08x-gyro-i2c.yaml new file mode 100644 index 000000000000..66a2515e4869 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-gyro-i2c.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Gyro inertial measurement unit + +compatible: "bosch,bmi08x-gyro" + +include: [i2c-device.yaml, "bosch,bmi08x-gyro.yaml"] diff --git a/dts/bindings/sensor/bosch,bmi08x-gyro-spi.yaml b/dts/bindings/sensor/bosch,bmi08x-gyro-spi.yaml new file mode 100644 index 000000000000..b7aa1fd02b48 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-gyro-spi.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Gyro inertial measurement unit + +compatible: "bosch,bmi08x-gyro" + +include: [spi-device.yaml, "bosch,bmi08x-gyro.yaml"] diff --git a/dts/bindings/sensor/bosch,bmi08x-gyro.yaml b/dts/bindings/sensor/bosch,bmi08x-gyro.yaml new file mode 100644 index 000000000000..0a3086d8417c --- /dev/null +++ b/dts/bindings/sensor/bosch,bmi08x-gyro.yaml @@ -0,0 +1,62 @@ +# Copyright (c) 2022 Meta Platforms, Inc. and its affiliates. +# SPDX-License-Identifier: Apache-2.0 + +description: BMI08X Gyro inertial measurement unit + +include: sensor-device.yaml + +properties: + int-gpios: + type: phandle-array + description: | + This property specifies the connection for INT, because the + Zephyr driver maps all interrupts to INT. The signal defaults + to output low when produced by the sensor. + + int3-4-map-io: + type: int + description: | + Bit[0] will map the data ready interrupt on INT3 + Bit[2] will map the fifo interrupt on INT3 + Bit[5] will map the fifo interrupt on INT4 + Bit[7] will enable the data ready interrupt on INT4 + + int3-4-conf-io: + type: int + description: | + Bit[0]: if set to 1, INT3 is active high, otherwise it's active low + Bit[1]: if set to 1, INT3 is open-drain, otherwise it's push-pull + Bit[2]: if set to 1, INT4 is active high, otherwise it's active low + Bit[3]: if set to 1, INT4 is open-drain, otherwise it's push-pull + + gyro-hz: + type: string + required: true + description: | + Default frequency of accelerometer. (Unit - Hz) + enum: + - "2000_532" + - "2000_230" + - "1000_116" + - "400_47" + - "200_23" + - "100_12" + - "200_64" + - "100_32" + + gyro-fs: + type: int + required: true + description: | + Default full scale of accelerometer. (Unit - g) + enum: + - 2000 + - 1000 + - 500 + - 250 + - 125 + + data-sync: + type: boolean + description: | + Enables data sync if defined. Must be set if bmi08x-accel data-sync is set as well. diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 487f0c3d3aea..b81009e154d0 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -745,3 +745,25 @@ test_tcn75a: tcn75a@73 { reg = <0x73>; alert-gpios = <&test_gpio 0 0>; }; + +test_i2c_bmi08x_accel: bmi08x@74 { + compatible = "bosch,bmi08x-accel"; + reg = <0x74>; + int-gpios = <&test_gpio 0 0>; + int1-map-io = <0x01>; + int2-map-io = <0x00>; + int1-conf-io = <0x0A>; + int2-conf-io = <0x17>; + accel-hz = "800"; + accel-fs = <4>; +}; + +test_i2c_bmi08x_gyro: bmi08x@75 { + compatible = "bosch,bmi08x-gyro"; + reg = <0x75>; + int-gpios = <&test_gpio 0 0>; + int3-4-map-io = <0x01>; + int3-4-conf-io = <0x01>; + gyro-hz = "1000_116"; + gyro-fs = <1000>; +}; diff --git a/tests/drivers/build_all/sensor/sensors_trigger_global.conf b/tests/drivers/build_all/sensor/sensors_trigger_global.conf index 28b1663f1bce..a18d55ab42ea 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_global.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_global.conf @@ -6,6 +6,8 @@ CONFIG_AMG88XX_TRIGGER_GLOBAL_THREAD=y CONFIG_APDS9960_TRIGGER_GLOBAL_THREAD=y CONFIG_BMA280_TRIGGER_GLOBAL_THREAD=y CONFIG_BMG160_TRIGGER_GLOBAL_THREAD=y +CONFIG_BMI08X_ACCEL_TRIGGER_GLOBAL_THREAD=y +CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD=y CONFIG_BMI160_TRIGGER_GLOBAL_THREAD=y CONFIG_BMI270_TRIGGER_GLOBAL_THREAD=y CONFIG_BMP388_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 6fffb6ef623a..b374ff865250 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_none.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_none.conf @@ -6,6 +6,8 @@ CONFIG_AMG88XX_TRIGGER_NONE=y CONFIG_APDS9960_TRIGGER_NONE=y CONFIG_BMA280_TRIGGER_NONE=y CONFIG_BMG160_TRIGGER_NONE=y +CONFIG_BMI08X_ACCEL_TRIGGER_NONE=y +CONFIG_BMI08X_GYRO_TRIGGER_NONE=y CONFIG_BMI160_TRIGGER_NONE=y CONFIG_BMI270_TRIGGER_NONE=y CONFIG_BMP388_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 f3bb63056727..04892cf8ad5e 100644 --- a/tests/drivers/build_all/sensor/sensors_trigger_own.conf +++ b/tests/drivers/build_all/sensor/sensors_trigger_own.conf @@ -5,6 +5,8 @@ CONFIG_ADXL372_TRIGGER_OWN_THREAD=y CONFIG_AMG88XX_TRIGGER_OWN_THREAD=y CONFIG_BMA280_TRIGGER_OWN_THREAD=y CONFIG_BMG160_TRIGGER_OWN_THREAD=y +CONFIG_BMI08X_ACCEL_TRIGGER_OWN_THREAD=y +CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD=y CONFIG_BMI160_TRIGGER_OWN_THREAD=y CONFIG_BMI270_TRIGGER_OWN_THREAD=y CONFIG_BMP388_TRIGGER_OWN_THREAD=y diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 8cdf2ef214bb..6afc3958474d 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -395,3 +395,27 @@ test_spi_lsm6dsv16x: lsm6dsv16x@30 { spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; }; + +test_spi_bmi08x_accel: bmi08x@31 { + compatible = "bosch,bmi08x-accel"; + reg = <0x31>; + spi-max-frequency = <0>; + int-gpios = <&test_gpio 0 0>; + int1-map-io = <0x01>; + int2-map-io = <0x00>; + int1-conf-io = <0x0A>; + int2-conf-io = <0x17>; + accel-hz = "800"; + accel-fs = <4>; +}; + +test_spi_bmi08x_gyro: bmi08x@32 { + compatible = "bosch,bmi08x-gyro"; + reg = <0x32>; + spi-max-frequency = <0>; + int-gpios = <&test_gpio 0 0>; + int3-4-map-io = <0x01>; + int3-4-conf-io = <0x01>; + gyro-hz = "1000_116"; + gyro-fs = <1000>; +}; From 74dcbaba3281d178a51dcfad17e58977519528dc Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 8 Jul 2023 15:19:29 +0200 Subject: [PATCH 1225/2042] dts: ti: cc13xx_cc26xx: align binding file name Aligns the filename of TI's CC13/26xx system timer peripheral devicetree binding to its compatible string. Signed-off-by: Florian Grandel --- ...{ti,cc13xx-cc26xx-rtc.yaml => ti,cc13xx-cc26xx-rtc-timer.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dts/bindings/rtc/{ti,cc13xx-cc26xx-rtc.yaml => ti,cc13xx-cc26xx-rtc-timer.yaml} (100%) diff --git a/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml b/dts/bindings/rtc/ti,cc13xx-cc26xx-rtc-timer.yaml similarity index 100% rename from dts/bindings/rtc/ti,cc13xx-cc26xx-rtc.yaml rename to dts/bindings/rtc/ti,cc13xx-cc26xx-rtc-timer.yaml From 8d2b461e6c2a30e1c822384fa912fec3b1f7c932 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 8 Jul 2023 15:22:33 +0200 Subject: [PATCH 1226/2042] doc: release-notes: remove typo Removes a misplaced heading from the driver API list. Signed-off-by: Florian Grandel --- doc/releases/release-notes-3.5.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index c3df09560b58..e919d67dd477 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -190,8 +190,6 @@ Drivers and Sensors * PECI -Trusted Firmware-M -****************** * Pin control * PWM From 390b119885f79a6c9a3ec91669dd83e3ab29812a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sat, 8 Jul 2023 15:17:33 +0200 Subject: [PATCH 1227/2042] doc: release-notes: document cc13/26xx timer change Documents the changes to the naming of the cc13/26xx timer compatible and Kconfig options. Signed-off-by: Florian Grandel --- doc/releases/release-notes-3.5.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index e919d67dd477..117171f99293 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -210,6 +210,12 @@ Drivers and Sensors * Timer + * The TI CC13xx/26xx system clock timer compatible was changed from + :dtcompatible:`ti,cc13xx-cc26xx-rtc` to :dtcompatible:`ti,cc13xx-cc26xx-rtc-timer` + and the corresponding Kconfig option from :kconfig:option:`CC13X2_CC26X2_RTC_TIMER` + to :kconfig:option:`CC13XX_CC26XX_RTC_TIMER` for improved consistency and + extensibility. No action is required unless the internal timer was modified. + * USB * W1 From 7c418a065cfe483c464d9a6e2615afdad68568d1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 12 Jul 2023 20:47:14 +0200 Subject: [PATCH 1228/2042] doc: requirements: update Sphinx and rtd theme rtd_theme 1.2.x is required when using Sphinx >= 6.0, otherwise certain features like search are broken. Note that jQuery support needs to be enabled manually now using `sphinxcontrib.jquery` extension. Also update Sphinx to latest 6.x release, 6.2 as it contains some fixes. Signed-off-by: Gerard Marull-Paretas --- doc/conf.py | 1 + doc/requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 2d5f97a9f1a7..c29335d3012d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -72,6 +72,7 @@ "sphinx.ext.extlinks", "sphinx.ext.autodoc", "sphinx.ext.graphviz", + "sphinxcontrib.jquery", "zephyr.application", "zephyr.html_redirects", "zephyr.kconfig", diff --git a/doc/requirements.txt b/doc/requirements.txt index b11f5aae5271..2bd19422dca5 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,8 +1,8 @@ # DOC: used to generate docs docleaf==0.8.1 -sphinx~=6.0 -sphinx_rtd_theme~=1.0 +sphinx~=6.2 +sphinx_rtd_theme~=1.2 sphinx-tabs sphinxcontrib-svg2pdfconverter pygments>=2.9 From 986d0c9e897a4efe7a7721f50cba7d7e6f5ec1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 17:51:08 +0200 Subject: [PATCH 1229/2042] doc: doxygen: Enable Doxygen autobrief MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable Doxygen AUTOBRIEF feature for both Javadoc and Qt style documentation blocks. This treats the first sentence of a documentation block as a brief description even when no @brief tag is present. This makes the overview sections of the generated documentation much more useful. See https://www.doxygen.nl/manual/config.html#cfg_javadoc_autobrief and https://www.doxygen.nl/manual/config.html#cfg_qt_autobrief Signed-off-by: Benjamin Cabé --- doc/zephyr.doxyfile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 60f2c1846157..a66110b6d05c 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -199,7 +199,7 @@ SHORT_NAMES = NO # description.) # The default value is: NO. -JAVADOC_AUTOBRIEF = NO +JAVADOC_AUTOBRIEF = YES # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as @@ -217,7 +217,7 @@ JAVADOC_BANNER = NO # requiring an explicit \brief command for a brief description.) # The default value is: NO. -QT_AUTOBRIEF = NO +QT_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as From 3544e9163debd532a8ff5eb396ef98a4d64988b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 15:14:01 +0200 Subject: [PATCH 1230/2042] include: sys: util_macro: fix bogus UTIL_X2 defs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed some invalid defines in the UTIL_X2_*** series. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/util_internal.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/zephyr/sys/util_internal.h b/include/zephyr/sys/util_internal.h index fdc786f5cd9a..1b1e96177967 100644 --- a/include/zephyr/sys/util_internal.h +++ b/include/zephyr/sys/util_internal.h @@ -1006,11 +1006,11 @@ #define UTIL_X2_72 144 #define UTIL_X2_73 146 #define UTIL_X2_74 148 -#define UTIL_X2_75 140 -#define UTIL_X2_76 142 -#define UTIL_X2_77 144 -#define UTIL_X2_78 146 -#define UTIL_X2_79 148 +#define UTIL_X2_75 150 +#define UTIL_X2_76 152 +#define UTIL_X2_77 154 +#define UTIL_X2_78 156 +#define UTIL_X2_79 158 #define UTIL_X2_80 160 #define UTIL_X2_81 162 #define UTIL_X2_82 164 @@ -1026,11 +1026,11 @@ #define UTIL_X2_92 184 #define UTIL_X2_93 186 #define UTIL_X2_94 188 -#define UTIL_X2_95 180 -#define UTIL_X2_96 182 -#define UTIL_X2_97 184 -#define UTIL_X2_98 186 -#define UTIL_X2_99 188 +#define UTIL_X2_95 190 +#define UTIL_X2_96 192 +#define UTIL_X2_97 194 +#define UTIL_X2_98 196 +#define UTIL_X2_99 198 #define UTIL_X2_100 200 #define UTIL_X2_101 202 #define UTIL_X2_102 204 @@ -1186,6 +1186,6 @@ #define UTIL_X2_252 504 #define UTIL_X2_253 506 #define UTIL_X2_254 508 -#define UTIL_X2_255 512 +#define UTIL_X2_255 510 #endif /* ZEPHYR_INCLUDE_SYS_UTIL_INTERNAL_H_ */ From 262b72a2fab7475bd5488c5b5b7a4428b0a4448d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 15:15:29 +0200 Subject: [PATCH 1231/2042] include: sys: util_macro: remove duplicate DEFINEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some UTIL_INC_*** DEFINEs were incorrectly appearing twice. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/util_internal.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/zephyr/sys/util_internal.h b/include/zephyr/sys/util_internal.h index 1b1e96177967..acd77fed8210 100644 --- a/include/zephyr/sys/util_internal.h +++ b/include/zephyr/sys/util_internal.h @@ -467,16 +467,6 @@ #define UTIL_INC_57 58 #define UTIL_INC_58 59 #define UTIL_INC_59 60 -#define UTIL_INC_50 51 -#define UTIL_INC_51 52 -#define UTIL_INC_52 53 -#define UTIL_INC_53 54 -#define UTIL_INC_54 55 -#define UTIL_INC_55 56 -#define UTIL_INC_56 57 -#define UTIL_INC_57 58 -#define UTIL_INC_58 59 -#define UTIL_INC_59 60 #define UTIL_INC_60 61 #define UTIL_INC_61 62 #define UTIL_INC_62 63 From 5fe47c255b3568c897a5ff2157f008bfeaa113fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 15:20:09 +0200 Subject: [PATCH 1232/2042] include: sys: util_macro: Add UTIL_DEC(x) doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing Doxygen documentation for UTIL_DEC(x) macro. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/util_macro.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index 1eb8ae7d6751..1fbc3944be83 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -370,9 +370,16 @@ extern "C" { * @brief UTIL_INC(x) for an integer literal x from 0 to 255 expands to an * integer literal whose value is x+1. * - * Similarly, UTIL_DEC(x) is (x-1) as an integer literal. + * @see UTIL_DEC(x) */ #define UTIL_INC(x) UTIL_PRIMITIVE_CAT(UTIL_INC_, x) + +/** + * @brief UTIL_DEC(x) for an integer literal x from 0 to 255 expands to an + * integer literal whose value is x-1. + * + * @see UTIL_INC(x) + */ #define UTIL_DEC(x) UTIL_PRIMITIVE_CAT(UTIL_DEC_, x) /** From cf3b0381ae23453d76c99118b1a1a971172074c6 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Fri, 7 Jul 2023 09:03:21 +0200 Subject: [PATCH 1233/2042] mgmt: ec_host_cmd: fix init of npxc shi backend Make sure not to access not assigned pointer at the begining of the initialization. Signed-off-by: Dawid Niedzwiecki --- .../mgmt/ec_host_cmd/backends/ec_host_cmd_backend_shi_npcx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 86f40f0eed80..9e4c6b08dd23 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 @@ -687,7 +687,9 @@ static void shi_npcx_reset_prepare(const struct device *dev) data->tx_msg = data->out_msg; data->rx_buf = inst->IBUF; data->tx_buf = inst->OBUF; - data->rx_ctx->len = 0; + if (data->rx_ctx) { + data->rx_ctx->len = 0; + } data->sz_sending = 0; data->sz_request = 0; data->sz_response = 0; From 8ce048b8e1c59a1bce60489c51693ad29aa32d6e Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 12 Jul 2023 11:45:53 +0200 Subject: [PATCH 1234/2042] drivers: spi: fix CS documentation `spi_cs_control` `cs` field is no longer a pointer, but a struct member. Clarify it must be zero-initialized if not used. Remove confusing comment about the need to use `device_is_ready()` on `cs` field, `spi_is_ready_dt()` is the only thing users need to do. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/drivers/spi.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index ccb460a0e70d..766187ad7513 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -287,8 +287,8 @@ struct spi_cs_control { * lines [ 16 : 17 ] - MISO lines: Single/Dual/Quad/Octal. * reserved [ 18 : 31 ] - reserved for future use. * @param slave is the slave number from 0 to host controller slave limit. - * @param cs is a valid pointer on a struct spi_cs_control is CS line is - * emulated through a gpio line, or NULL otherwise. + * @param cs GPIO chip-select line (optional, must be initialized to zero if not + * used). * @warning Most drivers use pointer comparison to determine whether a * passed configuration is different from one used in a previous * transaction. Changes to fields in the structure may not be @@ -315,10 +315,6 @@ struct spi_config { * spi_config by reading the relevant @p frequency, @p slave, and * @p cs data from the devicetree. * - * Important: the @p cs field is initialized using - * SPI_CS_CONTROL_INIT(). The @p gpio_dev value pointed to by this - * structure must be checked using device_is_ready() before use. - * * @param node_id Devicetree node identifier for the SPI device whose * struct spi_config to create an initializer for * @param operation_ the desired @p operation field in the struct spi_config From 2c3165d1876fc96f2ce93ce45c5259903ec62280 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 12 Jul 2023 12:05:05 +0200 Subject: [PATCH 1235/2042] drivers: spi: add opaque type to encode SPI operation flags Since flags can use either 16/32-bit depending on CONFIG_SPI_EXTENDED_MODES, add a new opaque type that uses the correct bit-width depending on that option. This allows us to simplify the structure layout. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/drivers/spi.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 766187ad7513..a5dd90fc4f16 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -268,6 +268,16 @@ struct spi_cs_control { #define SPI_CS_CONTROL_INIT_INST(inst, delay_) \ SPI_CS_CONTROL_INIT(DT_DRV_INST(inst), delay_) +/** + * @typedef spi_operation_t + * Opaque type to hold the SPI operation flags. + */ +#if defined(CONFIG_SPI_EXTENDED_MODES) +typedef uint32_t spi_operation_t; +#else +typedef uint16_t spi_operation_t; +#endif + /** * @brief SPI controller configuration structure * @@ -296,15 +306,8 @@ struct spi_cs_control { */ struct spi_config { uint32_t frequency; -#if defined(CONFIG_SPI_EXTENDED_MODES) - uint32_t operation; + spi_operation_t operation; uint16_t slave; - uint16_t _unused; -#else - uint16_t operation; - uint16_t slave; -#endif /* CONFIG_SPI_EXTENDED_MODES */ - struct spi_cs_control cs; }; From 4c4e2c5213c523b34d3a4f5e4ddd1c5b49f7f374 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 12 Jul 2023 12:12:47 +0200 Subject: [PATCH 1236/2042] drivers: spi: fix spi_config structure documentation `@param` can't be used to document struct fields. Inline each field documentation and improve it. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/drivers/spi.h | 55 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index a5dd90fc4f16..37647a8d4edf 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -280,34 +280,37 @@ typedef uint16_t spi_operation_t; /** * @brief SPI controller configuration structure - * - * @param frequency is the bus frequency in Hertz - * @param operation is a bit field with the following parts: - * - * operational mode [ 0 ] - master or slave. - * mode [ 1 : 3 ] - Polarity, phase and loop mode. - * transfer [ 4 ] - LSB or MSB first. - * word_size [ 5 : 10 ] - Size of a data frame in bits. - * duplex [ 11 ] - full/half duplex. - * cs_hold [ 12 ] - Hold on the CS line if possible. - * lock_on [ 13 ] - Keep resource locked for the caller. - * cs_active_high [ 14 ] - Active high CS logic. - * format [ 15 ] - Motorola or TI frame format (optional). - * if @kconfig{CONFIG_SPI_EXTENDED_MODES} is defined: - * lines [ 16 : 17 ] - MISO lines: Single/Dual/Quad/Octal. - * reserved [ 18 : 31 ] - reserved for future use. - * @param slave is the slave number from 0 to host controller slave limit. - * @param cs GPIO chip-select line (optional, must be initialized to zero if not - * used). - * @warning Most drivers use pointer comparison to determine whether a - * passed configuration is different from one used in a previous - * transaction. Changes to fields in the structure may not be - * detected. */ struct spi_config { - uint32_t frequency; - spi_operation_t operation; - uint16_t slave; + /** @brief Bus frequency in Hertz. */ + uint32_t frequency; + /** + * @brief Operation flags. + * + * It is a bit field with the following parts: + * + * - 0: Master or slave. + * - 1..3: Polarity, phase and loop mode. + * - 4: LSB or MSB first. + * - 5..10: Size of a data frame in bits. + * - 11: Full/half duplex. + * - 12: Hold on the CS line if possible. + * - 13: Keep resource locked for the caller. + * - 14: Active high CS logic. + * - 15: Motorola or TI frame format (optional). + * + * If @kconfig{CONFIG_SPI_EXTENDED_MODES} is enabled: + * + * - 16..17: MISO lines (Single/Dual/Quad/Octal). + * - 18..31: Reserved for future use. + */ + spi_operation_t operation; + /** @brief Slave number from 0 to host controller slave limit. */ + uint16_t slave; + /** + * @brief GPIO chip-select line (optional, must be initialized to zero + * if not used). + */ struct spi_cs_control cs; }; From f2ba0b7ae23b42227c17ef893e4f9bda39ab8cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Wed, 12 Jul 2023 09:03:30 +0200 Subject: [PATCH 1237/2042] drivers: fuel_gauge: max17048: Remov unused var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused variable 'data' from function max17048_emul_transfer_i2c() Signed-off-by: Marcel Krüger --- drivers/fuel_gauge/max17048/emul_max17048.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/fuel_gauge/max17048/emul_max17048.c b/drivers/fuel_gauge/max17048/emul_max17048.c index 98f97e320f75..3ae1565cb475 100644 --- a/drivers/fuel_gauge/max17048/emul_max17048.c +++ b/drivers/fuel_gauge/max17048/emul_max17048.c @@ -69,13 +69,10 @@ static int max17048_emul_transfer_i2c(const struct emul *target, struct i2c_msg int num_msgs, int addr) { /* Largely copied from emul_bmi160.c */ - struct max17048_emul_data *data; unsigned int val; int reg; int rc; - data = target->data; - __ASSERT_NO_MSG(msgs && num_msgs); i2c_dump_msgs_rw("emul", msgs, num_msgs, addr, false); From 965d30537f9aa9a694557c068b9a864875f8ae52 Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Tue, 4 Jul 2023 13:41:14 +0100 Subject: [PATCH 1238/2042] arch: arm: cortex_m: fault: Improve handling of fault escalation on armv6-m The current implementation causes a lockup of the core when the exception originates from an invalid/unreachable pc. This fix first verifies on armv6-m and armv8-m.base that pc was in an expected runnable region, namely: - .text - .ramfunc - .itcm Signed-off-by: Wilfried Chauveau --- arch/arm/core/aarch32/cortex_m/fault.c | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm/core/aarch32/cortex_m/fault.c b/arch/arm/core/aarch32/cortex_m/fault.c index 569101e00244..7c13d5760dbe 100644 --- a/arch/arm/core/aarch32/cortex_m/fault.c +++ b/arch/arm/core/aarch32/cortex_m/fault.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -729,6 +730,30 @@ static inline bool z_arm_is_synchronous_svc(z_arch_esf_t *esf) return false; } +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +static inline bool z_arm_is_pc_valid(uintptr_t pc) +{ + /* Is it in valid text region */ + if ((((uintptr_t)&__text_region_start) <= pc) && (pc < ((uintptr_t)&__text_region_end))) { + return true; + } + + /* Is it in valid ramfunc range */ + if ((((uintptr_t)&__ramfunc_start) <= pc) && (pc < ((uintptr_t)&__ramfunc_end))) { + return true; + } + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) + /* Is it in the ITCM */ + if ((((uintptr_t)&__itcm_start) <= pc) && (pc < ((uintptr_t)&__itcm_end))) { + return true; + } +#endif + + return false; +} +#endif + /** * * @brief Dump hard fault information @@ -752,8 +777,8 @@ static uint32_t hard_fault(z_arch_esf_t *esf, bool *recoverable) * priority. We handle the case of Kernel OOPS and Stack * Fail here. */ - if (z_arm_is_synchronous_svc(esf)) { + if (z_arm_is_pc_valid((uintptr_t)esf->basic.pc) && z_arm_is_synchronous_svc(esf)) { PR_EXC("ARCH_EXCEPT with reason %x\n", esf->basic.r0); reason = esf->basic.r0; } From 76c1a2019a94adff300a946d1a0e252ce239e42d Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 9 Jul 2023 17:01:10 +1000 Subject: [PATCH 1239/2042] drivers: modem: skip quoted delimiters Given the following response: `+CIPSTA:ip6ll:"FE80::EDC:7EFF:FEDD:110C"` The response delimiter is `:`, but there is also a quoted string that contains the delimiter character. These delimiters should not be considered when searching for the end of a parameter. Signed-off-by: Jordan Yates --- drivers/modem/modem_cmd_handler.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/modem/modem_cmd_handler.c b/drivers/modem/modem_cmd_handler.c index 20ab94210886..1eae992642ca 100644 --- a/drivers/modem/modem_cmd_handler.c +++ b/drivers/modem/modem_cmd_handler.c @@ -112,6 +112,7 @@ static int parse_params(struct modem_cmd_handler_data *data, size_t match_len, { int count = 0; size_t begin, end, i; + bool quoted = false; if (!data || !data->match_buf || !match_len || !cmd || !argv || !argc) { return -EINVAL; @@ -120,6 +121,15 @@ static int parse_params(struct modem_cmd_handler_data *data, size_t match_len, begin = cmd->cmd_len; end = cmd->cmd_len; while (end < match_len) { + /* Don't look for delimiters in the middle of a quoted parameter */ + if (data->match_buf[end] == '"') { + quoted = !quoted; + } + if (quoted) { + end++; + continue; + } + /* Look for delimiter characters */ for (i = 0; i < strlen(cmd->delim); i++) { if (data->match_buf[end] == cmd->delim[i]) { /* mark a parameter beginning */ From 1c2dba2107252e2632f58439c5b74f27505d4723 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 9 Jul 2023 17:09:16 +1000 Subject: [PATCH 1240/2042] drivers: modem: cache delimiter string length Cache the delimiter string length in `parse_params`, instead of calculating it on each character in the match buffer. Signed-off-by: Jordan Yates --- drivers/modem/modem_cmd_handler.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/modem/modem_cmd_handler.c b/drivers/modem/modem_cmd_handler.c index 1eae992642ca..02306554d30c 100644 --- a/drivers/modem/modem_cmd_handler.c +++ b/drivers/modem/modem_cmd_handler.c @@ -111,7 +111,7 @@ static int parse_params(struct modem_cmd_handler_data *data, size_t match_len, uint8_t **argv, size_t argv_len, uint16_t *argc) { int count = 0; - size_t begin, end, i; + size_t delim_len, begin, end, i; bool quoted = false; if (!data || !data->match_buf || !match_len || !cmd || !argv || !argc) { @@ -120,6 +120,7 @@ static int parse_params(struct modem_cmd_handler_data *data, size_t match_len, begin = cmd->cmd_len; end = cmd->cmd_len; + delim_len = strlen(cmd->delim); while (end < match_len) { /* Don't look for delimiters in the middle of a quoted parameter */ if (data->match_buf[end] == '"') { @@ -130,7 +131,7 @@ static int parse_params(struct modem_cmd_handler_data *data, size_t match_len, continue; } /* Look for delimiter characters */ - for (i = 0; i < strlen(cmd->delim); i++) { + for (i = 0; i < delim_len; i++) { if (data->match_buf[end] == cmd->delim[i]) { /* mark a parameter beginning */ argv[*argc] = &data->match_buf[begin]; From 1ca75e3b6e5e0ded2a983d10e320007bf0a6c564 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Thu, 6 Jul 2023 17:07:48 +0200 Subject: [PATCH 1241/2042] Bluetooth: audio: ascs: Fix invalid memset of QoS parameters This fixes invalid memset of QoS parameters that may happen if Config Qos operation is requested on ASE in QoS Configured state. In such case if the requested parameters have been rejected, the ASE QoS parameters shall remain unchanged (were memset instead). Otherwise, the stack shall send QoS Configured state notification with cleaned up parameters (all zero's) which was not done. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 60 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index b4c77b0c84e3..cf703b7d3593 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1711,7 +1711,9 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo bt_bap_iso_unref(iso); } - stream->qos = qos; + /* Store the QoS once accepted */ + ep->qos = *qos; + stream->qos = &ep->qos; /* We setup the data path here, as this is the earliest where * we have the ISO <-> EP coupling completed (due to setting @@ -1732,44 +1734,29 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo return 0; } -static void ase_qos(struct bt_ascs_ase *ase, const struct bt_ascs_qos *qos) +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; - struct bt_audio_codec_qos *cqos = &ep->qos; - const uint8_t cig_id = qos->cig; - const uint8_t cis_id = qos->cis; - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); int err; - cqos->interval = sys_get_le24(qos->interval); - cqos->framing = qos->framing; - cqos->phy = qos->phy; - cqos->sdu = sys_le16_to_cpu(qos->sdu); - cqos->rtn = qos->rtn; - cqos->latency = sys_le16_to_cpu(qos->latency); - cqos->pd = sys_get_le24(qos->pd); - - 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, qos->cig, - qos->cis, cqos->interval, cqos->framing, cqos->phy, cqos->sdu, - cqos->rtn, cqos->latency, cqos->pd); + 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); + 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); + 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); - memset(cqos, 0, sizeof(*cqos)); - ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); + LOG_ERR("QoS failed: err %d, code %u, reason %u", err, rsp->code, rsp->reason); return; } - ascs_cp_rsp_success(ASE_ID(ase)); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); } static bool is_valid_qos_len(struct net_buf_simple *buf) @@ -1812,8 +1799,6 @@ static bool is_valid_qos_len(struct net_buf_simple *buf) static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) { const struct bt_ascs_qos_op *req; - const struct bt_ascs_qos *qos; - int i; if (!is_valid_qos_len(buf)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); @@ -1823,7 +1808,11 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) LOG_DBG("num_ases %u", req->num_ases); - for (i = 0; i < req->num_ases; i++) { + for (uint8_t i = 0; i < req->num_ases; i++) { + struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, + BT_BAP_ASCS_REASON_NONE); + struct bt_audio_codec_qos cqos; + const struct bt_ascs_qos *qos; struct bt_ascs_ase *ase; qos = net_buf_simple_pull_mem(buf, sizeof(*qos)); @@ -1845,7 +1834,16 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) continue; } - ase_qos(ase, qos); + cqos.interval = sys_get_le24(qos->interval); + cqos.framing = qos->framing; + cqos.phy = qos->phy; + cqos.sdu = sys_le16_to_cpu(qos->sdu); + cqos.rtn = qos->rtn; + cqos.latency = sys_le16_to_cpu(qos->latency); + cqos.pd = sys_get_le24(qos->pd); + + ase_qos(ase, qos->cig, qos->cis, &cqos, &rsp); + ascs_cp_rsp_add(qos->ase, rsp.code, rsp.reason); } return buf->size; From fc89a85c29c31af454411774a46f7043ceaed52f Mon Sep 17 00:00:00 2001 From: Wei-Tai Lee Date: Thu, 8 Jun 2023 10:35:40 +0800 Subject: [PATCH 1242/2042] drivers: i2c: add thread-safe semaphore Add a semaphore to ensure that only one transaction happens at a time when threads want to transfer simultaneously. Signed-off-by: Wei-Tai Lee --- drivers/i2c/i2c_andes_atciic100.c | 28 ++++++++++++---------------- drivers/i2c/i2c_andes_atciic100.h | 3 ++- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/i2c_andes_atciic100.c b/drivers/i2c/i2c_andes_atciic100.c index 7811a4b2e87c..17ced4dd0da6 100644 --- a/drivers/i2c/i2c_andes_atciic100.c +++ b/drivers/i2c/i2c_andes_atciic100.c @@ -44,7 +44,8 @@ static void i2c_atciic100_default_control(const struct device *dev) struct i2c_atciic100_dev_data_t *dev_data = dev->data; uint32_t reg = 0; - k_sem_init(&dev_data->i2c_busy_sem, 1, 1); + k_sem_init(&dev_data->bus_lock, 1, 1); + k_sem_init(&dev_data->device_sync_sem, 0, 1); /* Reset I2C bus */ reg = sys_read32(I2C_CMD(dev)); @@ -140,7 +141,7 @@ static int i2c_atciic100_configure(const struct device *dev, dev_data->driver_state |= I2C_DRV_CFG_PARAM; unlock: - k_sem_give(&dev_data->i2c_busy_sem); + k_sem_give(&dev_data->bus_lock); return ret; } @@ -154,6 +155,8 @@ static int i2c_atciic100_transfer(const struct device *dev, uint8_t burst_write_len = msgs[0].len + msgs[1].len; uint8_t burst_write_buf[I2C_MAX_COUNT + BURST_CMD_COUNT]; + k_sem_take(&dev_data->bus_lock, K_FOREVER); + if ((msgs[0].flags == I2C_MSG_WRITE) && (msgs[1].flags == (I2C_MSG_WRITE | I2C_MSG_STOP))) { @@ -186,14 +189,7 @@ static int i2c_atciic100_transfer(const struct device *dev, exit: /* Wait for transfer complete */ - k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER); - - if (dev_data->status.target_ack != 1) { - k_sem_give(&dev_data->i2c_busy_sem); - return -EIO; - } - dev_data->status.target_ack = 0; - k_sem_give(&dev_data->i2c_busy_sem); + k_sem_give(&dev_data->bus_lock); return ret; } @@ -213,8 +209,6 @@ static int i2c_atciic100_controller_send(const struct device *dev, return -EIO; } - k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER); - /* Disable all I2C interrupts */ reg = sys_read32(I2C_INTE(dev)); reg &= (~IEN_ALL); @@ -301,6 +295,7 @@ static int i2c_atciic100_controller_send(const struct device *dev, reg |= (CMD_ISSUE_TRANSACTION); sys_write32(reg, I2C_CMD(dev)); + k_sem_take(&dev_data->device_sync_sem, K_FOREVER); return 0; } @@ -319,8 +314,6 @@ static int i2c_atciic100_controller_receive(const struct device *dev, return -EIO; } - k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER); - /* Disable all I2C interrupts */ reg = sys_read32(I2C_INTE(dev)); reg &= (~IEN_ALL); @@ -394,6 +387,7 @@ static int i2c_atciic100_controller_receive(const struct device *dev, reg |= (CMD_ISSUE_TRANSACTION); sys_write32(reg, I2C_CMD(dev)); + k_sem_take(&dev_data->device_sync_sem, K_FOREVER); return 0; } @@ -533,6 +527,8 @@ static void i2c_cmpl_handler(const struct device *dev, uint32_t reg_stat) /* Clear & set driver state to controller rx complete */ dev_data->driver_state = I2C_DRV_CONTROLLER_RX_CMPL; } + + k_sem_give(&dev_data->device_sync_sem); } #if defined(CONFIG_I2C_TARGET) @@ -578,7 +574,6 @@ static void i2c_cmpl_handler(const struct device *dev, uint32_t reg_stat) dev_data->status.arbitration_lost = 0; #endif - k_sem_give(&dev_data->i2c_busy_sem); } #if defined(CONFIG_I2C_TARGET) @@ -594,7 +589,7 @@ static void andes_i2c_target_event(const struct device *dev, * A new I2C data transaction(START-ADDRESS-DATA-STOP) */ if (reg_stat & STATUS_ADDR_HIT) { - if (k_sem_take(&dev_data->i2c_busy_sem, K_NO_WAIT) != 0) { + if (k_sem_take(&dev_data->bus_lock, K_NO_WAIT) != 0) { return; } @@ -637,6 +632,7 @@ static void andes_i2c_target_event(const struct device *dev, if (reg_stat & STATUS_CMPL) { i2c_cmpl_handler(dev, reg_stat); + k_sem_give(&dev_data->bus_lock); } } diff --git a/drivers/i2c/i2c_andes_atciic100.h b/drivers/i2c/i2c_andes_atciic100.h index fad7d7c4af51..1aa0ff6f3970 100644 --- a/drivers/i2c/i2c_andes_atciic100.h +++ b/drivers/i2c/i2c_andes_atciic100.h @@ -223,7 +223,8 @@ struct _i2c_status { }; struct i2c_atciic100_dev_data_t { - struct k_sem i2c_busy_sem; + struct k_sem bus_lock; + struct k_sem device_sync_sem; volatile uint32_t driver_state; uint8_t *middleware_rx_buf; uint8_t *middleware_tx_buf; From f2e0f787bf83da84cd8f31d86ca214ef290c8d70 Mon Sep 17 00:00:00 2001 From: Wei-Tai Lee Date: Thu, 8 Jun 2023 10:40:10 +0800 Subject: [PATCH 1243/2042] drivers: i2c: add error handling Return errors when failing at consecutive transactions and missing targets. Signed-off-by: Wei-Tai Lee --- drivers/i2c/i2c_andes_atciic100.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/i2c/i2c_andes_atciic100.c b/drivers/i2c/i2c_andes_atciic100.c index 17ced4dd0da6..918048ee9853 100644 --- a/drivers/i2c/i2c_andes_atciic100.c +++ b/drivers/i2c/i2c_andes_atciic100.c @@ -185,6 +185,10 @@ static int i2c_atciic100_transfer(const struct device *dev, ret = i2c_atciic100_controller_receive(dev, addr, msgs[i].buf, msgs[i].len, msgs[i].flags); } + + if (ret < 0) { + goto exit; + } } exit: @@ -296,6 +300,11 @@ static int i2c_atciic100_controller_send(const struct device *dev, sys_write32(reg, I2C_CMD(dev)); k_sem_take(&dev_data->device_sync_sem, K_FOREVER); + + if (dev_data->status.target_ack != 1) { + return -EIO; + } + dev_data->status.target_ack = 0; return 0; } @@ -388,6 +397,10 @@ static int i2c_atciic100_controller_receive(const struct device *dev, sys_write32(reg, I2C_CMD(dev)); k_sem_take(&dev_data->device_sync_sem, K_FOREVER); + if (dev_data->status.target_ack != 1) { + return -EIO; + } + dev_data->status.target_ack = 0; return 0; } From 82024ad5cf31bf3b2b9848754e89b4014811b4d6 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 10 Jul 2023 14:57:36 +0200 Subject: [PATCH 1244/2042] tests: arch: arm: Use a more common SHA algorithm The profile type "not set" uses the "default crypto config" header. However platform may set their own crypto configuration headers. SHA-512 algorithm is not the most common algorithm to support and are for example disabled in profile types medium and small. Change to SHA-256 which is much more common and is even needed internally by TF-M for protected storage and sub-key derivation. Update the QEMU icount setting to make the interrupt occur during the secure call to TF-M. Signed-off-by: Joakim Andersson --- tests/arch/arm/arm_thread_swap_tz/prj.conf | 3 ++- tests/arch/arm/arm_thread_swap_tz/src/main.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/arch/arm/arm_thread_swap_tz/prj.conf b/tests/arch/arm/arm_thread_swap_tz/prj.conf index 6692bc1d03de..5839417932f7 100644 --- a/tests/arch/arm/arm_thread_swap_tz/prj.conf +++ b/tests/arch/arm/arm_thread_swap_tz/prj.conf @@ -10,5 +10,6 @@ CONFIG_BUILD_WITH_TFM=y CONFIG_TFM_IPC=y CONFIG_FPU=y CONFIG_FPU_SHARING=y -CONFIG_TFM_PROFILE_TYPE_NOT_SET=y # Needed for SHA512 functionality +CONFIG_TFM_PROFILE_TYPE_NOT_SET=y CONFIG_ZTEST_NEW_API=y +CONFIG_QEMU_ICOUNT_SHIFT=8 diff --git a/tests/arch/arm/arm_thread_swap_tz/src/main.c b/tests/arch/arm/arm_thread_swap_tz/src/main.c index d06a9213cbe3..ebb18fafded6 100644 --- a/tests/arch/arm/arm_thread_swap_tz/src/main.c +++ b/tests/arch/arm/arm_thread_swap_tz/src/main.c @@ -13,7 +13,7 @@ #define EXC_RETURN_S (0x00000040UL) #endif -#define HASH_LEN 64 +#define HASH_LEN 32 static struct k_work_delayable interrupting_work; static volatile bool work_done; @@ -27,7 +27,7 @@ static void do_hash(char *hash) size_t len; /* Calculate correct hash. */ - psa_status_t status = psa_hash_compute(PSA_ALG_SHA_512, dummy_string, + psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string), hash, HASH_LEN, &len); zassert_equal(PSA_SUCCESS, status, "psa_hash_compute_fail: %d\n", status); @@ -70,7 +70,7 @@ static void work_func(struct k_work *work) /* Call a secure service here as well, to test the added complexity of * calling secure services from two threads. */ - psa_status_t status = psa_hash_compare(PSA_ALG_SHA_512, dummy_string, + psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string), dummy_digest_correct, HASH_LEN); zassert_equal(PSA_SUCCESS, status, "psa_hash_compare failed\n"); From e8e2b53849588268a2f0e335ad0353265f7cb187 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Sun, 1 Jan 2023 14:22:53 +0100 Subject: [PATCH 1245/2042] drivers: usb: udc: add STM32 UDC driver Add UDC driver for STM32 based MCU, relying on HAL/PCD. This has been tested with cdc_acm sample on the following boards: - 96b_carbon (STM32F4) - disco_l475_iot1 (STM32L4) - nucleo_wb55rg (STM32WB) - nucleo_h723zg (STM32H7) - stm32f3_disco (STM32F3) This fails at runtime for the following: - b_u585i_iot2a (STM32U5) Signed-off-by: Loic Poulain --- drivers/usb/udc/CMakeLists.txt | 1 + drivers/usb/udc/Kconfig | 1 + drivers/usb/udc/Kconfig.stm32 | 14 + drivers/usb/udc/udc_stm32.c | 1142 ++++++++++++++++++++++++++++++++ 4 files changed, 1158 insertions(+) create mode 100644 drivers/usb/udc/Kconfig.stm32 create mode 100644 drivers/usb/udc/udc_stm32.c diff --git a/drivers/usb/udc/CMakeLists.txt b/drivers/usb/udc/CMakeLists.txt index 584d7e6a0b6a..f4f729cb1818 100644 --- a/drivers/usb/udc/CMakeLists.txt +++ b/drivers/usb/udc/CMakeLists.txt @@ -8,3 +8,4 @@ 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) zephyr_library_sources_ifdef(CONFIG_UDC_VIRTUAL udc_virtual.c) +zephyr_library_sources_ifdef(CONFIG_UDC_STM32 udc_stm32.c) diff --git a/drivers/usb/udc/Kconfig b/drivers/usb/udc/Kconfig index fd37abcb7f85..ef1e01d82d26 100644 --- a/drivers/usb/udc/Kconfig +++ b/drivers/usb/udc/Kconfig @@ -51,5 +51,6 @@ source "drivers/usb/udc/Kconfig.nrf" source "drivers/usb/udc/Kconfig.kinetis" source "drivers/usb/udc/Kconfig.skeleton" source "drivers/usb/udc/Kconfig.virtual" +source "drivers/usb/udc/Kconfig.stm32" endif # UDC_DRIVER diff --git a/drivers/usb/udc/Kconfig.stm32 b/drivers/usb/udc/Kconfig.stm32 new file mode 100644 index 000000000000..39e22b1d5c43 --- /dev/null +++ b/drivers/usb/udc/Kconfig.stm32 @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +config UDC_STM32 + bool "STM32 USB device controller driver" + depends on DT_HAS_ST_STM32_OTGFS_ENABLED \ + || DT_HAS_ST_STM32_OTGHS_ENABLED \ + || DT_HAS_ST_STM32_USB_ENABLED + select USE_STM32_LL_USB + select USE_STM32_HAL_PCD + select USE_STM32_HAL_PCD_EX + default y + help + STM32 USB device controller driver. diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c new file mode 100644 index 000000000000..88070329cc30 --- /dev/null +++ b/drivers/usb/udc/udc_stm32.c @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2023 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file udc_stm32.c + * @brief STM32 USB device controller (UDC) driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "udc_common.h" + +#include "stm32_hsem.h" + +#include +LOG_MODULE_REGISTER(udc_stm32, CONFIG_UDC_DRIVER_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) +#define DT_DRV_COMPAT st_stm32_otghs +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) +#define DT_DRV_COMPAT st_stm32_otgfs +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usb) +#define DT_DRV_COMPAT st_stm32_usb +#endif + +struct udc_stm32_data { + PCD_HandleTypeDef pcd; + const struct device *dev; + uint32_t irq; + uint32_t occupied_mem; + void (*pcd_prepare)(const struct device *dev); + int (*clk_enable)(void); + int (*clk_disable)(void); +}; + +struct udc_stm32_config { + uint32_t num_endpoints; + uint32_t pma_offset; + uint32_t dram_size; + uint16_t ep0_mps; + uint16_t ep_mps; +}; + +static int udc_stm32_lock(const struct device *dev) +{ + return udc_lock_internal(dev, K_FOREVER); +} + +static int udc_stm32_unlock(const struct device *dev) +{ + return udc_unlock_internal(dev); +} + +#define hpcd2data(hpcd) CONTAINER_OF(hpcd, struct udc_stm32_data, pcd); + +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + const struct device *dev = priv->dev; + const struct udc_stm32_config *cfg = dev->config; + struct udc_ep_config *ep; + + /* Re-Enable control endpoints */ + ep = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT); + if (ep && ep->stat.enabled) { + HAL_PCD_EP_Open(&priv->pcd, USB_CONTROL_EP_OUT, cfg->ep0_mps, + EP_TYPE_CTRL); + } + + ep = udc_get_ep_cfg(dev, USB_CONTROL_EP_IN); + if (ep && ep->stat.enabled) { + HAL_PCD_EP_Open(&priv->pcd, USB_CONTROL_EP_IN, cfg->ep0_mps, + EP_TYPE_CTRL); + } + + udc_submit_event(priv->dev, UDC_EVT_RESET, 0); +} + +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + + udc_submit_event(priv->dev, UDC_EVT_VBUS_READY, 0); +} + +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + + udc_submit_event(priv->dev, UDC_EVT_VBUS_REMOVED, 0); +} + +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + + udc_set_suspended(priv->dev, true); + udc_submit_event(priv->dev, UDC_EVT_SUSPEND, 0); +} + +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + + udc_set_suspended(priv->dev, false); + udc_submit_event(priv->dev, UDC_EVT_RESUME, 0); +} + +static int usbd_ctrl_feed_dout(const struct device *dev, const size_t length) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + struct udc_ep_config *cfg = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT); + struct net_buf *buf; + + buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, length); + if (buf == NULL) { + return -ENOMEM; + } + + net_buf_put(&cfg->fifo, buf); + + HAL_PCD_EP_Receive(&priv->pcd, cfg->addr, buf->data, buf->size); + + return 0; +} + +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + struct usb_setup_packet *setup = (void *)priv->pcd.Setup; + const struct device *dev = priv->dev; + struct net_buf *buf; + int err; + + buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, + sizeof(struct usb_setup_packet)); + if (buf == NULL) { + LOG_ERR("Failed to allocate for setup"); + return; + } + + udc_ep_buf_set_setup(buf); + memcpy(buf->data, setup, 8); + net_buf_add(buf, 8); + + udc_ctrl_update_stage(dev, buf); + + if (!buf->len) { + return; + } + + if (setup->bRequest == USB_SREQ_SET_ADDRESS) { + /* HAL requires we set the address before submitting status */ + HAL_PCD_SetAddress(&priv->pcd, setup->wValue); + } + + if (udc_ctrl_stage_is_data_out(dev)) { + /* Allocate and feed buffer for data OUT stage */ + err = usbd_ctrl_feed_dout(dev, udc_data_stage_length(buf)); + if (err == -ENOMEM) { + udc_submit_ep_event(dev, buf, err); + } + } else if (udc_ctrl_stage_is_data_in(dev)) { + udc_ctrl_submit_s_in_status(dev); + } else { + udc_ctrl_submit_s_status(dev); + } +} + +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + + udc_submit_event(priv->dev, UDC_EVT_SOF, 0); +} + +static int udc_stm32_tx(const struct device *dev, uint8_t ep, + struct net_buf *buf) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + uint8_t *data; uint32_t len; + HAL_StatusTypeDef status; + + LOG_DBG("TX ep 0x%02x len %u", ep, buf->len); + + if (udc_ep_is_busy(dev, ep)) { + return 0; + } + + data = buf->data; + len = buf->len; + + if (ep == USB_CONTROL_EP_IN) { + len = MIN(cfg->ep0_mps, buf->len); + } + + buf->data += len; + buf->len -= len; + + status = HAL_PCD_EP_Transmit(&priv->pcd, ep, data, len); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_Transmit failed(0x%02x), %d", ep, (int)status); + return -EIO; + } + + udc_ep_set_busy(dev, ep, true); + + if (ep == USB_CONTROL_EP_IN && len > 0) { + /* Wait for an empty package from the host. + * This also flushes the TX FIFO to the host. + */ + usbd_ctrl_feed_dout(dev, 0); + } + + return 0; +} + +static int udc_stm32_rx(const struct device *dev, uint8_t ep, + struct net_buf *buf) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("RX ep 0x%02x len %u", ep, buf->size); + + if (udc_ep_is_busy(dev, ep)) { + return 0; + } + + status = HAL_PCD_EP_Receive(&priv->pcd, ep, buf->data, buf->size); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_Receive failed(0x%02x), %d", ep, (int)status); + return -EIO; + } + + udc_ep_set_busy(dev, ep, true); + + return 0; +} + +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + uint32_t rx_count = HAL_PCD_EP_GetRxCount(hpcd, epnum); + struct udc_stm32_data *priv = hpcd2data(hpcd); + const struct device *dev = priv->dev; + uint8_t ep = epnum | USB_EP_DIR_OUT; + struct net_buf *buf; + + LOG_DBG("DataOut ep 0x%02x", ep); + + udc_ep_set_busy(dev, ep, false); + + buf = udc_buf_get(dev, ep); + if (unlikely(buf == NULL)) { + LOG_ERR("ep 0x%02x queue is empty", ep); + return; + } + + net_buf_add(buf, rx_count); + + if (ep == USB_CONTROL_EP_OUT) { + if (udc_ctrl_stage_is_status_out(dev)) { + udc_ctrl_update_stage(dev, buf); + udc_ctrl_submit_status(dev, buf); + } else { + udc_ctrl_update_stage(dev, buf); + } + + if (udc_ctrl_stage_is_status_in(dev)) { + udc_ctrl_submit_s_out_status(dev, buf); + } + } else { + udc_submit_ep_event(dev, buf, 0); + } + + buf = udc_buf_peek(dev, ep); + if (buf) { + udc_stm32_rx(dev, ep, buf); + } +} + +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + struct udc_stm32_data *priv = hpcd2data(hpcd); + const struct device *dev = priv->dev; + uint8_t ep = epnum | USB_EP_DIR_IN; + struct net_buf *buf; + + LOG_DBG("DataIn ep 0x%02x", ep); + + udc_ep_set_busy(dev, ep, false); + + buf = udc_buf_peek(dev, ep); + if (unlikely(buf == NULL)) { + return; + } + + if (ep == USB_CONTROL_EP_IN && buf->len) { + const struct udc_stm32_config *cfg = dev->config; + uint32_t len = MIN(cfg->ep0_mps, buf->len); + + HAL_PCD_EP_Transmit(&priv->pcd, ep, buf->data, len); + + buf->len -= len; + buf->data += len; + + return; + } + + udc_buf_get(dev, ep); + + if (ep == 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; + } + + udc_submit_ep_event(dev, buf, 0); + + buf = udc_buf_peek(dev, ep); + if (buf) { + udc_stm32_tx(dev, ep, buf); + } +} + +static void udc_stm32_irq(const struct device *dev) +{ + const struct udc_stm32_data *priv = udc_get_private(dev); + + /* HAL irq handler will call the related above callback */ + HAL_PCD_IRQHandler((PCD_HandleTypeDef *)&priv->pcd); +} + +int udc_stm32_init(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + if (priv->clk_enable && priv->clk_enable()) { + LOG_ERR("Error enabling clock(s)"); + return -EIO; + } + + priv->pcd_prepare(dev); + + status = HAL_PCD_Init(&priv->pcd); + if (status != HAL_OK) { + LOG_ERR("PCD_Init failed, %d", (int)status); + return -EIO; + } + + HAL_PCD_Stop(&priv->pcd); + + return 0; +} + +#if defined(USB) || defined(USB_DRD_FS) +static inline void udc_stm32_mem_init(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + + priv->occupied_mem = cfg->pma_offset; +} + +static int udc_stm32_ep_mem_config(const struct device *dev, + struct udc_ep_config *ep, + bool enable) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + uint32_t size; + + size = MIN(ep->mps, cfg->ep_mps); + + if (!enable) { + priv->occupied_mem -= size; + return 0; + } + + if (priv->occupied_mem + size >= cfg->dram_size) { + LOG_ERR("Unable to allocate FIFO for 0x%02x", ep->addr); + return -ENOMEM; + } + + /* Configure PMA offset for the endpoint */ + HAL_PCDEx_PMAConfig(&priv->pcd, ep->addr, PCD_SNG_BUF, + priv->occupied_mem); + + priv->occupied_mem += size; + + return 0; +} +#else +static void udc_stm32_mem_init(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + int words; + + LOG_DBG("DRAM size: %ub", cfg->dram_size); + + if (cfg->ep_mps % 4 || cfg->ep0_mps % 4) { + LOG_ERR("Not a 32-bit word multiple: ep0(%u)|ep(%u)", + cfg->ep0_mps, cfg->ep_mps); + return; + } + + /* The documentation is not clear at all about RX FiFo size requirement, + * Allocate a minimum of 0x40 words, which seems to work reliably. + */ + words = MAX(0x40, cfg->ep_mps / 4); + HAL_PCDEx_SetRxFiFo(&priv->pcd, words); + priv->occupied_mem = words * 4; + + /* For EP0 TX, reserve only one MPS */ + HAL_PCDEx_SetTxFiFo(&priv->pcd, 0, cfg->ep0_mps / 4); + priv->occupied_mem += cfg->ep0_mps; + + /* Reset TX allocs */ + for (unsigned int i = 1U; i < cfg->num_endpoints; i++) { + HAL_PCDEx_SetTxFiFo(&priv->pcd, i, 0); + } +} + +static int udc_stm32_ep_mem_config(const struct device *dev, + struct udc_ep_config *ep, + bool enable) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + unsigned int words; + + if (!(ep->addr & USB_EP_DIR_IN) || !USB_EP_GET_IDX(ep->addr)) { + return 0; + } + + if (!enable) { + HAL_PCDEx_SetTxFiFo(&priv->pcd, USB_EP_GET_IDX(ep->addr), 0); + return 0; + } + + words = MIN(ep->mps, cfg->ep_mps) / 4; + words = (words <= 64) ? words * 2 : words; + + if (cfg->dram_size - priv->occupied_mem < words * 4) { + LOG_ERR("Unable to allocate FIFO for 0x%02x", ep->addr); + return -ENOMEM; + } + + HAL_PCDEx_SetTxFiFo(&priv->pcd, USB_EP_GET_IDX(ep->addr), words); + + priv->occupied_mem += words * 4; + + return 0; +} +#endif + +static int udc_stm32_enable(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + HAL_StatusTypeDef status; + int ret; + + LOG_DBG("Enable UDC"); + + udc_stm32_mem_init(dev); + + status = HAL_PCD_Start(&priv->pcd); + if (status != HAL_OK) { + LOG_ERR("PCD_Start failed, %d", (int)status); + return -EIO; + } + + ret = udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, + USB_EP_TYPE_CONTROL, cfg->ep0_mps, 0); + if (ret) { + LOG_ERR("Failed enabling ep 0x%02x", USB_CONTROL_EP_OUT); + return ret; + } + + ret |= udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, + USB_EP_TYPE_CONTROL, cfg->ep0_mps, 0); + if (ret) { + LOG_ERR("Failed enabling ep 0x%02x", USB_CONTROL_EP_IN); + return ret; + } + + irq_enable(priv->irq); + + return 0; +} + +static int udc_stm32_disable(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + irq_disable(DT_INST_IRQN(0)); + + status = HAL_PCD_Stop(&priv->pcd); + if (status != HAL_OK) { + LOG_ERR("PCD_Stop failed, %d", (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_shutdown(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + status = HAL_PCD_DeInit(&priv->pcd); + if (status != HAL_OK) { + LOG_ERR("PCD_DeInit failed, %d", (int)status); + /* continue anyway */ + } + + if (priv->clk_disable && priv->clk_disable()) { + LOG_ERR("Error disabling clock(s)"); + /* continue anyway */ + } + + if (irq_is_enabled(priv->irq)) { + irq_disable(priv->irq); + } + + return 0; +} + +static int udc_stm32_set_address(const struct device *dev, const uint8_t addr) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("Set Address %u", addr); + + status = HAL_PCD_SetAddress(&priv->pcd, addr); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_SetAddress failed(0x%02x), %d", + addr, (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_host_wakeup(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + status = HAL_PCD_ActivateRemoteWakeup(&priv->pcd); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_ActivateRemoteWakeup, %d", (int)status); + return -EIO; + } + + /* Must be active from 1ms to 15ms as per reference manual. */ + k_sleep(K_MSEC(2)); + + status = HAL_PCD_DeActivateRemoteWakeup(&priv->pcd); + if (status != HAL_OK) { + return -EIO; + } + + return 0; +} + +static inline int eptype2hal(enum usb_dc_ep_transfer_type eptype) +{ + switch (eptype) { + case USB_DC_EP_CONTROL: + return EP_TYPE_CTRL; + case USB_DC_EP_ISOCHRONOUS: + return EP_TYPE_ISOC; + case USB_DC_EP_BULK: + return EP_TYPE_BULK; + case USB_DC_EP_INTERRUPT: + return EP_TYPE_INTR; + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int udc_stm32_ep_enable(const struct device *dev, + struct udc_ep_config *ep) +{ + enum usb_dc_ep_transfer_type type = ep->attributes & USB_EP_TRANSFER_TYPE_MASK; + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + int ret; + + LOG_DBG("Enable ep 0x%02x", ep->addr); + + ret = udc_stm32_ep_mem_config(dev, ep, true); + if (ret) { + return ret; + } + + status = HAL_PCD_EP_Open(&priv->pcd, ep->addr, ep->mps, + eptype2hal(type)); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_Open failed(0x%02x), %d", + ep->addr, (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_ep_disable(const struct device *dev, + struct udc_ep_config *ep) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("Disable ep 0x%02x", ep->addr); + + status = HAL_PCD_EP_Close(&priv->pcd, ep->addr); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_Close failed(0x%02x), %d", + ep->addr, (int)status); + return -EIO; + } + + return udc_stm32_ep_mem_config(dev, ep, false); +} + +static int udc_stm32_ep_set_halt(const struct device *dev, + struct udc_ep_config *cfg) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("Halt ep 0x%02x", cfg->addr); + + status = HAL_PCD_EP_SetStall(&priv->pcd, cfg->addr); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_SetStall failed(0x%02x), %d", + cfg->addr, (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_ep_clear_halt(const struct device *dev, + struct udc_ep_config *cfg) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("Clear halt for ep 0x%02x", cfg->addr); + + status = HAL_PCD_EP_ClrStall(&priv->pcd, cfg->addr); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_ClrStall failed(0x%02x), %d", + cfg->addr, (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_ep_flush(const struct device *dev, + struct udc_ep_config *cfg) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + HAL_StatusTypeDef status; + + LOG_DBG("Flush ep 0x%02x", cfg->addr); + + status = HAL_PCD_EP_Flush(&priv->pcd, cfg->addr); + if (status != HAL_OK) { + LOG_ERR("HAL_PCD_EP_Flush failed(0x%02x), %d", + cfg->addr, (int)status); + return -EIO; + } + + return 0; +} + +static int udc_stm32_ep_enqueue(const struct device *dev, + struct udc_ep_config *epcfg, + struct net_buf *buf) +{ + unsigned int lock_key; + int ret; + + udc_buf_put(epcfg, buf); + + lock_key = irq_lock(); + + if (USB_EP_DIR_IS_IN(epcfg->addr)) { + ret = udc_stm32_tx(dev, epcfg->addr, buf); + } else { + ret = udc_stm32_rx(dev, epcfg->addr, buf); + } + + irq_unlock(lock_key); + + return ret; +} + +static int udc_stm32_ep_dequeue(const struct device *dev, + struct udc_ep_config *epcfg) +{ + struct net_buf *buf; + + udc_stm32_ep_flush(dev, epcfg); + + buf = udc_buf_get_all(dev, epcfg->addr); + if (buf) { + udc_submit_ep_event(dev, buf, -ECONNABORTED); + } + + udc_ep_set_busy(dev, epcfg->addr, false); + + return 0; +} + +static const struct udc_api udc_stm32_api = { + .lock = udc_stm32_lock, + .unlock = udc_stm32_unlock, + .init = udc_stm32_init, + .enable = udc_stm32_enable, + .disable = udc_stm32_disable, + .shutdown = udc_stm32_shutdown, + .set_address = udc_stm32_set_address, + .host_wakeup = udc_stm32_host_wakeup, + .ep_try_config = NULL, + .ep_enable = udc_stm32_ep_enable, + .ep_disable = udc_stm32_ep_disable, + .ep_set_halt = udc_stm32_ep_set_halt, + .ep_clear_halt = udc_stm32_ep_clear_halt, + .ep_enqueue = udc_stm32_ep_enqueue, + .ep_dequeue = udc_stm32_ep_dequeue, +}; + +/* ----------------- Instance/Device specific data ----------------- */ + +/* + * USB, USB_OTG_FS and USB_DRD_FS are defined in STM32Cube HAL and allows to + * distinguish between two kind of USB DC. STM32 F0, F3, L0 and G4 series + * support USB device controller. STM32 F4 and F7 series support USB_OTG_FS + * device controller. STM32 F1 and L4 series support either USB or USB_OTG_FS + * device controller.STM32 G0 series supports USB_DRD_FS device controller. + * + * WARNING: Don't mix USB defined in STM32Cube HAL and CONFIG_USB_* from Zephyr + * Kconfig system. + */ +#define USB_NUM_BIDIR_ENDPOINTS DT_INST_PROP(0, num_bidir_endpoints) + +#if defined(USB) || defined(USB_DRD_FS) +#define EP0_MPS 64U +#define EP_MPS 64U +#define USB_BTABLE_SIZE (8 * USB_NUM_BIDIR_ENDPOINTS) +#define USB_RAM_SIZE DT_INST_PROP(0, ram_size) +#else /* USB_OTG_FS */ +#define EP0_MPS USB_OTG_MAX_EP0_SIZE +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) +#define EP_MPS USB_OTG_HS_MAX_PACKET_SIZE +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) || DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usb) +#define EP_MPS USB_OTG_FS_MAX_PACKET_SIZE +#endif +#define USB_RAM_SIZE DT_INST_PROP(0, ram_size) +#define USB_BTABLE_SIZE 0 +#endif /* USB */ + +#define USB_OTG_HS_EMB_PHY (DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) && \ + DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs)) + +#define USB_OTG_HS_ULPI_PHY (DT_HAS_COMPAT_STATUS_OKAY(usb_ulpi_phy) && \ + DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs)) + +static struct udc_stm32_data udc0_priv; + +static struct udc_data udc0_data = { + .mutex = Z_MUTEX_INITIALIZER(udc0_data.mutex), + .priv = &udc0_priv, +}; + +static const struct udc_stm32_config udc0_cfg = { + .num_endpoints = USB_NUM_BIDIR_ENDPOINTS, + .dram_size = USB_RAM_SIZE, + .pma_offset = USB_BTABLE_SIZE, + .ep0_mps = EP0_MPS, + .ep_mps = EP_MPS, +}; + +#if defined(USB_OTG_FS) || defined(USB_OTG_HS) +static uint32_t usb_dc_stm32_get_maximum_speed(void) +{ +/* + * STM32L4 series USB LL API doesn't provide HIGH and HIGH_IN_FULL speed + * defines. + */ +#if defined(CONFIG_SOC_SERIES_STM32L4X) +#define USB_OTG_SPEED_HIGH 0U +#define USB_OTG_SPEED_HIGH_IN_FULL 1U +#endif /* CONFIG_SOC_SERIES_STM32L4X */ +/* + * If max-speed is not passed via DT, set it to USB controller's + * maximum hardware capability. + */ +#if USB_OTG_HS_EMB_PHY || USB_OTG_HS_ULPI_PHY + uint32_t speed = USB_OTG_SPEED_HIGH; +#else + uint32_t speed = USB_OTG_SPEED_FULL; +#endif + +#ifdef USB_MAXIMUM_SPEED + + if (!strncmp(USB_MAXIMUM_SPEED, "high-speed", 10)) { + speed = USB_OTG_SPEED_HIGH; + } else if (!strncmp(USB_MAXIMUM_SPEED, "full-speed", 10)) { +#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(USB_OTG_HS_EMB_PHY) + speed = USB_OTG_SPEED_HIGH_IN_FULL; +#else + speed = USB_OTG_SPEED_FULL; +#endif + } else { + LOG_DBG("Unsupported maximum speed defined in device tree. " + "USB controller will default to its maximum HW " + "capability"); + } +#endif + + return speed; +} +#endif /* USB_OTG_FS || USB_OTG_HS */ + +static void priv_pcd_prepare(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + + memset(&priv->pcd, 0, sizeof(priv->pcd)); + + /* Default values */ + priv->pcd.Init.dev_endpoints = cfg->num_endpoints; + priv->pcd.Init.ep0_mps = cfg->ep0_mps; + priv->pcd.Init.speed = PCD_SPEED_FULL; + priv->pcd.Init.low_power_enable = 0; + priv->pcd.Init.Sof_enable = 0; /* Usually not needed */ + + /* Per controller/Phy values */ +#if defined(USB) + priv->pcd.Instance = USB; +#elif defined(USB_DRD_FS) + priv->pcd.Instance = USB_DRD_FS; +#elif defined(USB_OTG_FS) || defined(USB_OTG_HS) + priv->pcd.Init.speed = usb_dc_stm32_get_maximum_speed(); + priv->pcd.Init.vbus_sensing_enable = DISABLE; +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) + priv->pcd.Instance = USB_OTG_HS; +#else + priv->pcd.Instance = USB_OTG_FS; +#endif +#if USB_OTG_HS_EMB_PHY + priv->pcd.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; +#elif USB_OTG_HS_ULPI_PHY + priv->pcd.Init.phy_itface = USB_OTG_ULPI_PHY; +#else + priv->pcd.Init.phy_itface = PCD_PHY_EMBEDDED; +#endif +#endif +} + +static const struct stm32_pclken pclken[] = STM32_DT_INST_CLOCKS(0); + +static int priv_clock_enable(void) +{ + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + + if (!device_is_ready(clk)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + +#ifdef CONFIG_SOC_SERIES_STM32U5X + /* VDDUSB independent USB supply (PWR clock is on) */ + LL_PWR_EnableVDDUSB(); +#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#if defined(CONFIG_SOC_SERIES_STM32H7X) + LL_PWR_EnableUSBVoltageDetector(); + + /* Per AN2606: USBREGEN not supported when running in FS mode. */ + LL_PWR_DisableUSBReg(); + while (!LL_PWR_IsActiveFlag_USB()) { + LOG_INF("PWR not active yet"); + k_sleep(K_MSEC(100)); + } +#endif + + if (DT_INST_NUM_CLOCKS(0) > 1) { + if (clock_control_configure(clk, (clock_control_subsys_t *)&pclken[1], + NULL) != 0) { + LOG_ERR("Could not select USB domain clock"); + return -EIO; + } + } + + if (clock_control_on(clk, (clock_control_subsys_t *)&pclken[0]) != 0) { + LOG_ERR("Unable to enable USB clock"); + return -EIO; + } + + if (IS_ENABLED(CONFIG_USB_DC_STM32_CLOCK_CHECK)) { + uint32_t usb_clock_rate; + + if (clock_control_get_rate(clk, + (clock_control_subsys_t *)&pclken[1], + &usb_clock_rate) != 0) { + LOG_ERR("Failed to get USB domain clock rate"); + return -EIO; + } + + if (usb_clock_rate != MHZ(48)) { + LOG_ERR("USB Clock is not 48MHz (%d)", usb_clock_rate); + return -ENOTSUP; + } + } + + /* Previous check won't work in case of F1/F3. Add build time check */ +#if defined(RCC_CFGR_OTGFSPRE) || defined(RCC_CFGR_USBPRE) + +#if (MHZ(48) == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) && !defined(STM32_PLL_USBPRE) + /* PLL output clock is set to 48MHz, it should not be divided */ +#warning USBPRE/OTGFSPRE should be set in rcc node +#endif + +#endif /* RCC_CFGR_OTGFSPRE / RCC_CFGR_USBPRE */ + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usbphyc) + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_OTGHSULPI); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_OTGPHYC); +#elif defined(CONFIG_SOC_SERIES_STM32H7X) +#if !USB_OTG_HS_ULPI_PHY + /* Disable ULPI interface (for external high-speed PHY) clock in sleep + * mode. + */ + LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB1OTGHSULPI); +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) + /* The USB2 controller only works in FS mode, but the ULPI clock needs + * to be disabled in sleep mode for it to work. + */ + LL_AHB1_GRP1_DisableClockSleep(LL_AHB1_GRP1_PERIPH_USB2OTGHSULPI); +#endif +#else + /* Disable ULPI interface (for external high-speed PHY) clock in low + * power mode. It is disabled by default in run power mode, no need to + * disable it. + */ + LL_AHB1_GRP1_DisableClockLowPower(LL_AHB1_GRP1_PERIPH_OTGHSULPI); +#endif +#endif + + return 0; +} + +static int priv_clock_disable(void) +{ + const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + + if (clock_control_off(clk, (clock_control_subsys_t *)&pclken[0]) != 0) { + LOG_ERR("Unable to disable USB clock"); + return -EIO; + } + + return 0; +} + +static struct udc_ep_config ep_cfg_in[DT_INST_PROP(0, num_bidir_endpoints)]; +static struct udc_ep_config ep_cfg_out[DT_INST_PROP(0, num_bidir_endpoints)]; + +PINCTRL_DT_INST_DEFINE(0); +static const struct pinctrl_dev_config *usb_pcfg = + PINCTRL_DT_INST_DEV_CONFIG_GET(0); + +#if USB_OTG_HS_ULPI_PHY +static const struct gpio_dt_spec ulpi_reset = + GPIO_DT_SPEC_GET_OR(DT_PHANDLE(DT_INST(0, st_stm32_otghs), phys), reset_gpios, {0}); +#endif + +static int udc_stm32_driver_init0(const struct device *dev) +{ + struct udc_stm32_data *priv = udc_get_private(dev); + const struct udc_stm32_config *cfg = dev->config; + struct udc_data *data = dev->data; + int err; + + for (unsigned int i = 0; i < ARRAY_SIZE(ep_cfg_out); i++) { + ep_cfg_out[i].caps.out = 1; + if (i == 0) { + ep_cfg_out[i].caps.control = 1; + ep_cfg_out[i].caps.mps = cfg->ep0_mps; + } else { + ep_cfg_out[i].caps.bulk = 1; + ep_cfg_out[i].caps.interrupt = 1; + ep_cfg_out[i].caps.iso = 1; + ep_cfg_out[i].caps.mps = cfg->ep_mps; + } + + ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; + err = udc_register_ep(dev, &ep_cfg_out[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + for (unsigned int i = 0; i < ARRAY_SIZE(ep_cfg_in); i++) { + ep_cfg_in[i].caps.in = 1; + if (i == 0) { + ep_cfg_in[i].caps.control = 1; + ep_cfg_in[i].caps.mps = cfg->ep0_mps; + } else { + ep_cfg_in[i].caps.bulk = 1; + ep_cfg_in[i].caps.interrupt = 1; + ep_cfg_in[i].caps.iso = 1; + ep_cfg_in[i].caps.mps = 1023; + } + + ep_cfg_in[i].addr = USB_EP_DIR_IN | i; + err = udc_register_ep(dev, &ep_cfg_in[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + data->caps.rwup = true; + data->caps.out_ack = false; + data->caps.mps0 = UDC_MPS0_64; + + priv->dev = dev; + priv->irq = DT_INST_IRQN(0); + priv->clk_enable = priv_clock_enable; + priv->clk_disable = priv_clock_disable; + priv->pcd_prepare = priv_pcd_prepare; + + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), udc_stm32_irq, + DEVICE_DT_INST_GET(0), 0); + + err = pinctrl_apply_state(usb_pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + LOG_ERR("USB pinctrl setup failed (%d)", err); + return err; + } + +#ifdef SYSCFG_CFGR1_USB_IT_RMP + /* + * STM32F302/F303: USB IRQ collides with CAN_1 IRQ (§14.1.3, RM0316) + * Remap IRQ by default to enable use of both IPs simultaneoulsy + * This should be done before calling any HAL function + */ + if (LL_APB2_GRP1_IsEnabledClock(LL_APB2_GRP1_PERIPH_SYSCFG)) { + LL_SYSCFG_EnableRemapIT_USB(); + } else { + LOG_ERR("System Configuration Controller clock is " + "disabled. Unable to enable IRQ remapping."); + } +#endif + +#if USB_OTG_HS_ULPI_PHY + if (ulpi_reset.port != NULL) { + if (!gpio_is_ready_dt(&ulpi_reset)) { + LOG_ERR("Reset GPIO device not ready"); + return -EINVAL; + } + if (gpio_pin_configure_dt(&ulpi_reset, GPIO_OUTPUT_INACTIVE)) { + LOG_ERR("Couldn't configure reset pin"); + return -EIO; + } + } +#endif + + /*cd + * Required for at least STM32L4 devices as they electrically + * isolate USB features from VDDUSB. It must be enabled before + * USB can function. Refer to section 5.1.3 in DM00083560 or + * DM00310109. + */ +#ifdef PWR_CR2_USV +#if defined(LL_APB1_GRP1_PERIPH_PWR) + if (LL_APB1_GRP1_IsEnabledClock(LL_APB1_GRP1_PERIPH_PWR)) { + LL_PWR_EnableVddUSB(); + } else { + LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); + LL_PWR_EnableVddUSB(); + LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_PWR); + } + #else + LL_PWR_EnableVddUSB(); +#endif /* defined(LL_APB1_GRP1_PERIPH_PWR) */ +#endif /* PWR_CR2_USV */ + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, udc_stm32_driver_init0, NULL, &udc0_data, &udc0_cfg, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &udc_stm32_api); From df7749129f7272ab79fa6fdd3ac8a6f9c453098a Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 6 Mar 2023 17:32:08 +0100 Subject: [PATCH 1246/2042] samples: cdc_acm: Add 96b_carbon to usbd-next board This board can rely on udc_stm32 usbd-next driver. Signed-off-by: Loic Poulain --- samples/subsys/usb/cdc_acm/sample.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/subsys/usb/cdc_acm/sample.yaml b/samples/subsys/usb/cdc_acm/sample.yaml index ebe4e796e87c..60d6ab46fffd 100644 --- a/samples/subsys/usb/cdc_acm/sample.yaml +++ b/samples/subsys/usb/cdc_acm/sample.yaml @@ -17,6 +17,7 @@ tests: platform_allow: - nrf52840dk_nrf52840 - frdm_k64f + - 96b_carbon harness: console harness_config: type: one_line From 9be7b59b4a1f7a44efb198548de11d8f1dd8114a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 6 Jul 2023 15:56:45 +0200 Subject: [PATCH 1247/2042] ctf tracing: native/host backend: Refactor to support embedded C libraries Split this tracing backend in a top and bottom to enable building it with embedded libCs with the native simulator. Signed-off-by: Alberto Escolar Piedras --- boards/posix/native_sim/doc/index.rst | 2 +- subsys/tracing/CMakeLists.txt | 12 ++++--- subsys/tracing/tracing_backend_posix.c | 14 +++----- subsys/tracing/tracing_backend_posix_bottom.c | 33 +++++++++++++++++++ subsys/tracing/tracing_backend_posix_bottom.h | 27 +++++++++++++++ 5 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 subsys/tracing/tracing_backend_posix_bottom.c create mode 100644 subsys/tracing/tracing_backend_posix_bottom.h diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index f3bd75b6b8ce..22d3b6b8c31e 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -124,5 +124,5 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`). serial, uart native TTY, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, host libC 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`, host libC + tracing, Posix tracing backend, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, all usb, USB native posix, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC diff --git a/subsys/tracing/CMakeLists.txt b/subsys/tracing/CMakeLists.txt index 1c0cca52319c..6d9bb689f001 100644 --- a/subsys/tracing/CMakeLists.txt +++ b/subsys/tracing/CMakeLists.txt @@ -27,10 +27,14 @@ zephyr_sources_ifdef( tracing_backend_uart.c ) -zephyr_sources_ifdef( - CONFIG_TRACING_BACKEND_POSIX - tracing_backend_posix.c - ) +if (CONFIG_TRACING_BACKEND_POSIX) + zephyr_sources(tracing_backend_posix.c) + if (CONFIG_NATIVE_APPLICATION) + zephyr_library_sources(tracing_backend_posix_bottom.c) + else() + target_sources(native_simulator INTERFACE tracing_backend_posix_bottom.c) + endif() +endif() zephyr_sources_ifdef( CONFIG_TRACING_BACKEND_RAM diff --git a/subsys/tracing/tracing_backend_posix.c b/subsys/tracing/tracing_backend_posix.c index 28f9ec8928f6..e0f753f96c0e 100644 --- a/subsys/tracing/tracing_backend_posix.c +++ b/subsys/tracing/tracing_backend_posix.c @@ -5,11 +5,9 @@ */ #include -#include -#include #include -#include #include +#include "tracing_backend_posix_bottom.h" static void *out_stream; static const char *file_name; @@ -20,20 +18,16 @@ static void tracing_backend_posix_init(void) file_name = "channel0_0"; } - out_stream = (void *)fopen(file_name, "wb"); - - __ASSERT(out_stream != NULL, "posix backend init failed"); + out_stream = tracing_backend_posix_init_bottom(file_name); } static void tracing_backend_posix_output( const struct tracing_backend *backend, uint8_t *data, uint32_t length) { - fwrite(data, length, 1, (FILE *)out_stream); + ARG_UNUSED(backend); - if (!k_is_in_isr()) { - fflush((FILE *)out_stream); - } + tracing_backend_posix_output_bottom(data, length, out_stream); } const struct tracing_backend_api tracing_backend_posix_api = { diff --git a/subsys/tracing/tracing_backend_posix_bottom.c b/subsys/tracing/tracing_backend_posix_bottom.c new file mode 100644 index 000000000000..bdbb1e9069e6 --- /dev/null +++ b/subsys/tracing/tracing_backend_posix_bottom.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "nsi_tracing.h" + +void *tracing_backend_posix_init_bottom(const char *file_name) +{ + FILE *f; + + f = fopen(file_name, "wb"); + if (f == NULL) { + nsi_print_error_and_exit("%s: Could not open CTF backend file %s\n", + __func__, file_name); + } + + return (void *)f; +} + +void tracing_backend_posix_output_bottom(const void *data, unsigned long length, void *out_stream) +{ + int rc = fwrite(data, length, 1, (FILE *)out_stream); + + if (rc != 1) { + nsi_print_warning("%s: Failure writing to CTF backend file\n", __func__); + } + + fflush((FILE *)out_stream); +} diff --git a/subsys/tracing/tracing_backend_posix_bottom.h b/subsys/tracing/tracing_backend_posix_bottom.h new file mode 100644 index 000000000000..1732e9a3b5ec --- /dev/null +++ b/subsys/tracing/tracing_backend_posix_bottom.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * "Bottom" of the CTF tracing backend for the native/hosted targets. + * When built with the native_simulator this will be built in the runner context, + * that is, with the host C library, and with the host include paths. + * + * Note: None of these functions are public interfaces. But internal to this CTF backend. + */ + +#ifndef DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H +#define DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void *tracing_backend_posix_init_bottom(const char *file_name); +void tracing_backend_posix_output_bottom(const void *data, unsigned long length, void *out_stream); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_FLASH_FLASH_SIMULATOR_NATIVE_H */ From 41c33d7f32658d0e0f80af11ad7817e8893ff55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 13 Jul 2023 08:57:48 +0200 Subject: [PATCH 1248/2042] drivers: flash: nrf_qspi_nor: Fix writing from unaligned RAM buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flash API states that drivers should support write requests without any restrictions on location or alignment of the source buffer. Due to hardware limitations of the QSPI peripheral, the nrf_qspi_nor driver currently fails to perform a write from a RAM buffer that is not word-aligned. Fix this by using in such case the same mechanism that is used when the source buffer is located in the internal flash (copy data to a buffer located on stack). Also correct the length parameter for writes from this stack-based buffer to be the actual data chunk length, not always the size of the buffer (as for CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE > 4 this may lead to overwriting of some data located next in the flash). Signed-off-by: Andrzej Głąbek --- drivers/flash/Kconfig.nordic_qspi_nor | 15 ++++++++------- drivers/flash/nrf_qspi_nor.c | 11 ++++++----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/flash/Kconfig.nordic_qspi_nor b/drivers/flash/Kconfig.nordic_qspi_nor index ca0058e6aed1..16252e0812c3 100644 --- a/drivers/flash/Kconfig.nordic_qspi_nor +++ b/drivers/flash/Kconfig.nordic_qspi_nor @@ -28,14 +28,15 @@ config NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE size (65536). Other option include the sector size (4096). config NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE - int "Size of a stack-based buffer to support writes from NVMC" + int "Size of a stack-based buffer to handle writes not supported by QSPI" default 4 help - The QSPI peripheral uses DMA and cannot write data that is - read from the internal flash. A non-zero value here enables - a stack buffer into which data is copied to allow the write - to proceed. Multiple transfers will be initiated if the - data is larger than the configured limit. Must be a - multiple of 4. The feature is disabled when set to 0. + The QSPI peripheral uses DMA and can only write data that is read + from a word-aligned location in RAM. A non-zero value here enables + a stack buffer to be used for any source data that does not meet + these restrictions. Such data will be copied into this buffer to + allow the write to proceed. Multiple transfers will be initiated + if the data is larger than the configured size. + Must be a multiple of 4. When set to 0, the feature is disabled. endif # NORDIC_QSPI_NOR diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index facd37fb3046..2986c819e0fc 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1060,8 +1060,8 @@ BUILD_ASSERT((CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE % 4) == 0, * * If not enabled return the error the peripheral would have produced. */ -static inline nrfx_err_t write_from_nvmc(const struct device *dev, off_t addr, - const void *sptr, size_t slen) +static nrfx_err_t write_through_buffer(const struct device *dev, off_t addr, + const void *sptr, size_t slen) { nrfx_err_t res = NRFX_SUCCESS; @@ -1073,7 +1073,7 @@ static inline nrfx_err_t write_from_nvmc(const struct device *dev, off_t addr, size_t len = MIN(slen, sizeof(buf)); memcpy(buf, sp, len); - res = nrfx_qspi_write(buf, sizeof(buf), addr); + res = nrfx_qspi_write(buf, len, addr); qspi_wait_for_completion(dev, res); if (res == NRFX_SUCCESS) { @@ -1131,8 +1131,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr, if (!res) { if (size < 4U) { res = write_sub_word(dev, addr, src, size); - } else if (!nrfx_is_in_ram(src)) { - res = write_from_nvmc(dev, addr, src, size); + } else if (!nrfx_is_in_ram(src) || + !nrfx_is_word_aligned(src)) { + res = write_through_buffer(dev, addr, src, size); } else { res = nrfx_qspi_write(src, size, addr); qspi_wait_for_completion(dev, res); From c35d97534fd19ba4070684ef8f2b033b98943c26 Mon Sep 17 00:00:00 2001 From: Andrey VOLKOV Date: Sun, 4 Jun 2023 23:19:33 +0200 Subject: [PATCH 1249/2042] include: util_internal: add Z_SPARSE_LIST_{ODD|EVEN}_NUMBERS Add auxiliary lists Z_SPARSE_LIST_ODD_NUMBERS and Z_SPARSE_LIST_EVEN_NUMBERS. These lists were originally created for GPIO_DT_RESERVED_RANGES_NGPIOS macro, but may be useful for others applications too. Signed-off-by: Andrey VOLKOV --- include/zephyr/sys/util_internal.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/zephyr/sys/util_internal.h b/include/zephyr/sys/util_internal.h index acd77fed8210..7850886b54bc 100644 --- a/include/zephyr/sys/util_internal.h +++ b/include/zephyr/sys/util_internal.h @@ -407,6 +407,34 @@ #define Z_IS_254_EQ_254(...) \, #define Z_IS_255_EQ_255(...) \, +/* + * Generic sparse list of odd numbers (check the implementation of + * GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example) + */ +#define Z_SPARSE_LIST_ODD_NUMBERS \ + EMPTY, 1, EMPTY, 3, EMPTY, 5, EMPTY, 7, \ + EMPTY, 9, EMPTY, 11, EMPTY, 13, EMPTY, 15, \ + EMPTY, 17, EMPTY, 19, EMPTY, 21, EMPTY, 23, \ + EMPTY, 25, EMPTY, 27, EMPTY, 29, EMPTY, 31, \ + EMPTY, 33, EMPTY, 35, EMPTY, 37, EMPTY, 39, \ + EMPTY, 41, EMPTY, 43, EMPTY, 45, EMPTY, 47, \ + EMPTY, 49, EMPTY, 51, EMPTY, 53, EMPTY, 55, \ + EMPTY, 57, EMPTY, 59, EMPTY, 61, EMPTY, 63 + +/* + * Generic sparse list of even numbers (check the implementation of + * GPIO_DT_RESERVED_RANGES_NGPIOS as a usage example) + */ +#define Z_SPARSE_LIST_EVEN_NUMBERS \ + 0, EMPTY, 2, EMPTY, 4, EMPTY, 6, EMPTY, \ + 8, EMPTY, 10, EMPTY, 12, EMPTY, 14, EMPTY, \ + 16, EMPTY, 18, EMPTY, 20, EMPTY, 22, EMPTY, \ + 24, EMPTY, 26, EMPTY, 28, EMPTY, 30, EMPTY, \ + 32, EMPTY, 34, EMPTY, 36, EMPTY, 38, EMPTY, \ + 40, EMPTY, 42, EMPTY, 44, EMPTY, 46, EMPTY, \ + 48, EMPTY, 50, EMPTY, 52, EMPTY, 54, EMPTY, \ + 56, EMPTY, 58, EMPTY, 60, EMPTY, 62, EMPTY + #define UTIL_INC_0 1 #define UTIL_INC_1 2 #define UTIL_INC_2 3 From 6587fccd65ec100c141e90f442e539b223b8615d Mon Sep 17 00:00:00 2001 From: Andrey VOLKOV Date: Sun, 4 Jun 2023 23:19:38 +0200 Subject: [PATCH 1250/2042] drivers: gpio: add "gpio-reserved-ranges" property support Added * GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, ngpios), * GPIO_DT_RESERVED_RANGES(node_id), * GPIO_DT_INST_RESERVED_RANGES_NGPIOS(inst, ngpios) and * GPIO_DT_INST_RESERVED_RANGES(inst) as DT gpio's "gpio-reserved-ranges" property missing support. The array of pins range pairs as shown below now works. Also implemented paired extended versions of GPIO_PORT_PIN_MASK_FROM_NGPIOS macro: * GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(node_id, ngpios) and * GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(inst, ngpios) with reserved (ie EXCluded) pins support too. The implementation constraint is inherited from common DT limitations: a maximum of 64 pairs can be used, i.e. theoretically no more than 128-bit gpio ports are supported (but resulted bitmask is actually limited by the size of gpio_port_pins_t type). Usage example: The reserved mask, defined in the device tree as: gpio0: gpio0 { .... ngpios=<32>; gpio-reserved-ranges = <0 8>, <9 5>, <15 16>; .... }; and used in driver configuration as: { ... .gpio_reserved = GPIO_DT_RESERVED_RANGES(DT_NODELABEL(gpio0)), .pin_port_mask = GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC( DT_NODELABEL(gpio0), DT_PROP(DT_NODELABEL(gpio0), ngpios)), ... } correctly converts to: .gpio_reserved = 0x7fffbeff, 0b01111111 11111111 10111110 11111111) .pin_port_mask = 0x80004100, 0b10000000 00000000 01000001 00000000) Signed-off-by: Andrey VOLKOV --- include/zephyr/drivers/gpio.h | 243 ++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/include/zephyr/drivers/gpio.h b/include/zephyr/drivers/gpio.h index 112a448e056c..9ea274128f14 100644 --- a/include/zephyr/drivers/gpio.h +++ b/include/zephyr/drivers/gpio.h @@ -432,6 +432,249 @@ struct gpio_dt_spec { #define GPIO_DT_SPEC_INST_GET_OR(inst, prop, default_value) \ GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, prop, 0, default_value) +/* + * @cond INTERNAL_HIDDEN + */ + +/** + * Auxiliary conditional macro that generates a bitmask for the range + * from @p "prop" array defined by the (off_idx, sz_idx) pair, + * or 0 if the range does not exist. + * + * @param node_id devicetree node identifier + * @param prop lowercase-and-underscores array property name + * @param off_idx logical index of bitmask offset value into "prop" array + * @param sz_idx logical index of bitmask size value into "prop" array + */ +#define Z_GPIO_GEN_BITMASK_COND(node_id, prop, off_idx, sz_idx) \ + COND_CODE_1(DT_PROP_HAS_IDX(node_id, prop, off_idx), \ + (COND_CODE_0(DT_PROP_BY_IDX(node_id, prop, sz_idx), \ + (0), \ + (GENMASK64(DT_PROP_BY_IDX(node_id, prop, off_idx) + \ + DT_PROP_BY_IDX(node_id, prop, sz_idx) - 1, \ + DT_PROP_BY_IDX(node_id, prop, off_idx)))) \ + ), (0)) + +/** + * A helper conditional macro returning generated bitmask for one element + * from @p "gpio-reserved-ranges" + * + * @param odd_it the value of an odd sequential iterator + * @param node_id devicetree node identifier + */ +#define Z_GPIO_GEN_RESERVED_RANGES_COND(odd_it, node_id) \ + COND_CODE_1(DT_PROP_HAS_IDX(node_id, gpio_reserved_ranges, odd_it), \ + (Z_GPIO_GEN_BITMASK_COND(node_id, \ + gpio_reserved_ranges, \ + GET_ARG_N(odd_it, Z_SPARSE_LIST_EVEN_NUMBERS), \ + odd_it)), \ + (0)) + +/** + * @endcond + */ + +/** + * @brief Makes a bitmask of reserved GPIOs from DT @p "gpio-reserved-ranges" + * property and @p "ngpios" argument + * + * This macro returns the value as a bitmask of the @p "gpio-reserved-ranges" + * property. This property defines the disabled (or 'reserved') GPIOs in the + * range @p 0...ngpios-1 and is specified as an array of value's pairs that + * define the start offset and size of the reserved ranges. + * + * For example, setting "gpio-reserved-ranges = <3 2>, <10 1>;" + * means that GPIO offsets 3, 4 and 10 cannot be used even if @p ngpios = <18>. + * + * The implementation constraint is inherited from common DT limitations: + * a maximum of 64 pairs can be used (with result limited to bitsize + * of gpio_port_pins_t type). + * + * NB: Due to the nature of C macros, some incorrect tuple definitions + * (for example, overlapping or out of range) will produce undefined results. + * + * Also be aware that if @p ngpios is less than 32 (bit size of DT int type), + * then all unused MSBs outside the range defined by @p ngpios will be + * marked as reserved too. + * + * Example devicetree fragment: + * + * @code{.dts} + * a { + * compatible = "some,gpio-controller"; + * ngpios = <32>; + * gpio-reserved-ranges = <0 4>, <5 3>, <9 5>, <11 2>, <15 2>, + * <18 2>, <21 1>, <23 1>, <25 4>, <30 2>; + * }; + * + * b { + * compatible = "some,gpio-controller"; + * ngpios = <18>; + * gpio-reserved-ranges = <3 2>, <10 1>; + * }; + * + * @endcode + * + * Example usage: + * + * @code{.c} + * struct some_config { + * uint32_t ngpios; + * uint32_t gpios_reserved; + * }; + * + * static const struct some_config dev_cfg_a = { + * .ngpios = DT_PROP_OR(DT_LABEL(a), ngpios, 0), + * .gpios_reserved = GPIO_DT_RESERVED_RANGES_NGPIOS(DT_LABEL(a), + * DT_PROP(DT_LABEL(a), ngpios)), + * }; + * + * static const struct some_config dev_cfg_b = { + * .ngpios = DT_PROP_OR(DT_LABEL(b), ngpios, 0), + * .gpios_reserved = GPIO_DT_RESERVED_RANGES_NGPIOS(DT_LABEL(b), + * DT_PROP(DT_LABEL(b), ngpios)), + * }; + *@endcode + * + * This expands to: + * + * @code{.c} + * struct some_config { + * uint32_t ngpios; + * uint32_t gpios_reserved; + * }; + * + * static const struct some_config dev_cfg_a = { + * .ngpios = 32, + * .gpios_reserved = 0xdeadbeef, + * // 0b1101 1110 1010 1101 1011 1110 1110 1111 + * + * static const struct some_config dev_cfg_b = { + * .ngpios = 18, + * .gpios_reserved = 0xfffc0418, + * // 0b1111 1111 1111 1100 0000 0100 0001 1000 + * // unused MSBs were marked as reserved too + * }; + * @endcode + * + * @param node_id GPIO controller node identifier. + * @param ngpios number of GPIOs. + * @return the bitmask of reserved gpios + */ +#define GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, ngpios) \ + ((gpio_port_pins_t) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, gpio_reserved_ranges), \ + (GENMASK64(BITS_PER_LONG_LONG - 1, ngpios) \ + | FOR_EACH_FIXED_ARG(Z_GPIO_GEN_RESERVED_RANGES_COND, \ + (|), \ + node_id, \ + LIST_DROP_EMPTY(Z_SPARSE_LIST_ODD_NUMBERS))), \ + (0))) + +/** + * @brief Makes a bitmask of reserved GPIOs from the @p "gpio-reserved-ranges" + * and @p "ngpios" DT properties values + * + * @param node_id GPIO controller node identifier. + * @return the bitmask of reserved gpios + */ +#define GPIO_DT_RESERVED_RANGES(node_id) \ + GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, DT_PROP(node_id, ngpios)) + +/** + * @brief Makes a bitmask of reserved GPIOs from a DT_DRV_COMPAT instance's + * @p "gpio-reserved-ranges" property and @p "ngpios" argument + * + * @param inst DT_DRV_COMPAT instance number + * @return the bitmask of reserved gpios + * @param ngpios number of GPIOs + * @see GPIO_DT_RESERVED_RANGES() + */ +#define GPIO_DT_INST_RESERVED_RANGES_NGPIOS(inst, ngpios) \ + GPIO_DT_RESERVED_RANGES_NGPIOS(DT_DRV_INST(inst), ngpios) + +/** + * @brief Make a bitmask of reserved GPIOs from a DT_DRV_COMPAT instance's GPIO + * @p "gpio-reserved-ranges" and @p "ngpios" properties + * + * @param inst DT_DRV_COMPAT instance number + * @return the bitmask of reserved gpios + * @see GPIO_DT_RESERVED_RANGES() + */ +#define GPIO_DT_INST_RESERVED_RANGES(inst) \ + GPIO_DT_RESERVED_RANGES(DT_DRV_INST(inst)) + +/** + * @brief Makes a bitmask of allowed GPIOs from DT @p "gpio-reserved-ranges" + * property and @p "ngpios" argument + * + * This macro is paired with GPIO_DT_RESERVED_RANGES_NGPIOS(), however unlike + * the latter, it returns a bitmask of ALLOWED gpios. + * + * Example devicetree fragment: + * + * @code{.dts} + * a { + * compatible = "some,gpio-controller"; + * ngpios = <32>; + * gpio-reserved-ranges = <0 8>, <9 5>, <15 16>; + * }; + * + * @endcode + * + * Example usage: + * + * @code{.c} + * struct some_config { + * uint32_t port_pin_mask; + * }; + * + * static const struct some_config dev_cfg = { + * .port_pin_mask = GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC( + * DT_LABEL(a), 32), + * }; + * @endcode + * + * This expands to: + * + * @code{.c} + * struct some_config { + * uint32_t port_pin_mask; + * }; + * + * static const struct some_config dev_cfg = { + * .port_pin_mask = 0x80004100, + * // 0b1000 0000 0000 0000 0100 0001 00000 000 + * }; + * @endcode + * + * @param node_id GPIO controller node identifier. + * @param ngpios number of GPIOs + * @return the bitmask of allowed gpios + */ +#define GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(node_id, ngpios) \ + ((gpio_port_pins_t) \ + COND_CODE_0(ngpios, \ + (0), \ + (COND_CODE_1(DT_NODE_HAS_PROP(node_id, gpio_reserved_ranges), \ + ((GENMASK64(ngpios - 1, 0) & \ + ~GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, ngpios))), \ + (GENMASK64(ngpios - 1, 0))) \ + ) \ + )) + +/** + * @brief Makes a bitmask of allowed GPIOs from a DT_DRV_COMPAT instance's + * @p "gpio-reserved-ranges" property and @p "ngpios" argument + * + * @param inst DT_DRV_COMPAT instance number + * @param ngpios number of GPIOs + * @return the bitmask of allowed gpios + * @see GPIO_DT_NGPIOS_PORT_PIN_MASK_EXC() + */ +#define GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(inst, ngpios) \ + GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(DT_DRV_INST(inst), ngpios) + /** * @brief Maximum number of pins that are supported by `gpio_port_pins_t`. */ From 9e526dba97279d333f08d370553f00f40b2aa7d2 Mon Sep 17 00:00:00 2001 From: Andrey VOLKOV Date: Sun, 4 Jun 2023 23:19:43 +0200 Subject: [PATCH 1251/2042] gpio: add "gpio-reserved-ranges" support to GPIO_PORT_PIN_MASK_XX Updated the implementation of the GPIO_PORT_PIN_MASK_FROM_DT_NODE and GPIO_PORT_PIN_MASK_FROM_DT_INST macros to support "gpio-reserved-ranges" device tree property. Signed-off-by: Andrey VOLKOV --- include/zephyr/drivers/gpio/gpio_utils.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/gpio/gpio_utils.h b/include/zephyr/drivers/gpio/gpio_utils.h index 753640f4fb57..43818f4148af 100644 --- a/include/zephyr/drivers/gpio/gpio_utils.h +++ b/include/zephyr/drivers/gpio/gpio_utils.h @@ -20,11 +20,27 @@ #define GPIO_PORT_PIN_MASK_FROM_NGPIOS(ngpios) \ ((gpio_port_pins_t)(((uint64_t)1 << (ngpios)) - 1U)) +/** + * @brief Makes a bitmask of allowed GPIOs from the @p "gpio-reserved-ranges" + * and @p "ngpios" DT properties values + * + * @param node_id GPIO controller node identifier. + * @return the bitmask of allowed gpios + * @see GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC() + */ #define GPIO_PORT_PIN_MASK_FROM_DT_NODE(node_id) \ - GPIO_PORT_PIN_MASK_FROM_NGPIOS(DT_PROP(node_id, ngpios)) + GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(node_id, DT_PROP(node_id, ngpios)) +/** + * @brief Make a bitmask of allowed GPIOs from a DT_DRV_COMPAT instance's GPIO + * @p "gpio-reserved-ranges" and @p "ngpios" DT properties values + * + * @param inst DT_DRV_COMPAT instance number + * @return the bitmask of allowed gpios + * @see GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC() + */ #define GPIO_PORT_PIN_MASK_FROM_DT_INST(inst) \ - GPIO_PORT_PIN_MASK_FROM_NGPIOS(DT_INST_PROP(inst, ngpios)) + GPIO_PORT_PIN_MASK_FROM_DT_NODE(DT_DRV_INST(inst)) /** * @brief Generic function to insert or remove a callback from a callback list From abfd23406057e0c9648db7b4b620710bf8190eca Mon Sep 17 00:00:00 2001 From: Andrey VOLKOV Date: Sun, 4 Jun 2023 23:19:50 +0200 Subject: [PATCH 1252/2042] tests: gpio: add tests for GPIO_DT_RESERVED_RANGES_NGPIOS et al Added basic test coverage for the: * GPIO_DT_RESERVED_RANGES_NGPIOS, * GPIO_DT_RESERVED_RANGES, * GPIO_DT_INST_RESERVED_RANGES_NGPIOS, * GPIO_DT_INST_RESERVED_RANGES, * GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC, * GPIO_PORT_PIN_MASK_FROM_DT_NODE, * GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC and * GPIO_PORT_PIN_MASK_FROM_DT_INST macros. Signed-off-by: Andrey VOLKOV --- .../gpio/gpio_reserved_ranges/CMakeLists.txt | 8 + .../boards/native_posix.overlay | 77 ++++++++++ .../boards/native_posix_64.overlay | 6 + .../gpio/gpio_reserved_ranges/prj.conf | 4 + .../gpio/gpio_reserved_ranges/src/main.c | 144 ++++++++++++++++++ .../gpio/gpio_reserved_ranges/testcase.yaml | 9 ++ 6 files changed, 248 insertions(+) create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/CMakeLists.txt create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix.overlay create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/prj.conf create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/src/main.c create mode 100644 tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml diff --git a/tests/drivers/gpio/gpio_reserved_ranges/CMakeLists.txt b/tests/drivers/gpio/gpio_reserved_ranges/CMakeLists.txt new file mode 100644 index 000000000000..6820d2679a8a --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/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(gpio_basic_api) + +FILE(GLOB app_sources src/main.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix.overlay b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix.overlay new file mode 100644 index 000000000000..3e0fc23501e2 --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix.overlay @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 MUNIC SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + test { + compatible = "test-gpio-reserved-ranges"; + + #address-cells = <1>; + #size-cells = <1>; + + test_gpio_1: gpio@deadbeef { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0xdeadbeef 0x10>; + #gpio-cells = < 0x2 >; + status = "okay"; + + gpio-reserved-ranges = <0 4>, <5 3>, <9 5>, <11 2>, + <15 2>, <18 2>, <21 1>, <23 1>, + <25 4>, <30 2>; + }; + + test_gpio_2: gpio@abcd1234 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0xabcd1234 0x10>; + #gpio-cells = < 0x2 >; + status = "okay"; + + gpio-reserved-ranges = <0 8>, <9 5>, <14 0>, <15 16>; + }; + + test_gpio_3: gpio@1234 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0x1234 0x10 >; + #gpio-cells = < 0x2 >; + status = "okay"; + + ngpios = <18>; + gpio-reserved-ranges = <0 0>, <3 2>, <10 1>; + }; + + test_gpio_4: gpio@5678 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0x5678 0x10 >; + #gpio-cells = < 0x2 >; + status = "okay"; + + ngpios = <16>; + gpio-reserved-ranges = <4 16>; + }; + + test_gpio_5: gpio@8765 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0x8765 0x10 >; + #gpio-cells = < 0x2 >; + status = "okay"; + + ngpios = <0>; + gpio-reserved-ranges = <0 0>; + }; + + test_gpio_6: gpio@3210 { + compatible = "vnd,gpio-device"; + gpio-controller; + reg = < 0x3210 0x10 >; + #gpio-cells = < 0x2 >; + status = "okay"; + }; + }; +}; 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 new file mode 100644 index 000000000000..0d3e3ea93f2f --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/boards/native_posix_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023 MUNIC SA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_posix.overlay" diff --git a/tests/drivers/gpio/gpio_reserved_ranges/prj.conf b/tests/drivers/gpio/gpio_reserved_ranges/prj.conf new file mode 100644 index 000000000000..66f87b668e84 --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/prj.conf @@ -0,0 +1,4 @@ +CONFIG_GPIO=y +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +#CONFIG_TEST_USERSPACE=y diff --git a/tests/drivers/gpio/gpio_reserved_ranges/src/main.c b/tests/drivers/gpio/gpio_reserved_ranges/src/main.c new file mode 100644 index 000000000000..1a56df9adc07 --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/src/main.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023 MUNIC SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include +#include +#include +#include + +#define TEST_GPIO_1 DT_NODELABEL(test_gpio_1) +#define TEST_GPIO_2 DT_NODELABEL(test_gpio_2) +#define TEST_GPIO_3 DT_NODELABEL(test_gpio_3) +#define TEST_GPIO_4 DT_NODELABEL(test_gpio_4) +#define TEST_GPIO_5 DT_NODELABEL(test_gpio_5) +#define TEST_GPIO_6 DT_NODELABEL(test_gpio_6) + +#define DT_DRV_COMPAT vnd_gpio_device + +ZTEST(gpio_reserved_ranges, test_path_props) +{ + zassert_true(DT_NODE_HAS_PROP(TEST_GPIO_1, gpio_reserved_ranges), ""); + zassert_true(DT_NODE_HAS_PROP(TEST_GPIO_2, gpio_reserved_ranges), ""); + zassert_true(DT_NODE_HAS_PROP(TEST_GPIO_3, gpio_reserved_ranges), ""); + zassert_true(DT_NODE_HAS_PROP(TEST_GPIO_4, gpio_reserved_ranges), ""); + zassert_true(DT_NODE_HAS_PROP(TEST_GPIO_5, gpio_reserved_ranges), ""); + zassert_false(DT_NODE_HAS_PROP(TEST_GPIO_6, gpio_reserved_ranges), ""); +} + +ZTEST(gpio_reserved_ranges, test_has_status) +{ + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_1, okay), 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_2, okay), 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_3, okay), 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_4, okay), 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_5, okay), 1, ""); + zassert_equal(DT_NODE_HAS_STATUS(TEST_GPIO_6, okay), 1, ""); +} + +ZTEST(gpio_reserved_ranges, test_reserved_ranges) +{ + /* GPIO_DT_INST_RESERVED_RANGES_NGPIOS */ + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_1, 32), + 0xdeadbeef, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_2, 32), + 0x7fffbeff, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_3, 18), + 0xfffc0418, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_4, 16), + 0xfffffff0, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_5, 0), + 0xffffffff, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES_NGPIOS(TEST_GPIO_6, 32), + 0, ""); + + /* GPIO_DT_INST_RESERVED_RANGES_NGPIOS */ + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(0, 32), 0xdeadbeef, + ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(1, 32), 0x7fffbeff, + ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(2, 18), 0xfffc0418, + ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(3, 16), 0xfffffff0, + ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(4, 0), 0xffffffff, + ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES_NGPIOS(5, 32), 0, ""); + + /* GPIO_DT_RESERVED_RANGES */ + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_1), 0xdeadbeef, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_2), 0x7fffbeff, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_3), 0xfffc0418, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_4), 0xfffffff0, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_5), 0xffffffff, ""); + zassert_equal(GPIO_DT_RESERVED_RANGES(TEST_GPIO_6), 0x0, ""); + + /* GPIO_DT_INST_RESERVED_RANGES */ + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(0), 0xdeadbeef, ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(1), 0x7fffbeff, ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(2), 0xfffc0418, ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(3), 0xfffffff0, ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(4), 0xffffffff, ""); + zassert_equal(GPIO_DT_INST_RESERVED_RANGES(5), 0x0, ""); +} + +ZTEST(gpio_reserved_ranges, test_port_pin_mask_exc) +{ + /* GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC */ + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_1, 32), + 0x21524110, ""); + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_2, 32), + 0x80004100, ""); + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_3, 18), + 0x0003fbe7, ""); + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_4, 16), + 0x0000000f, ""); + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_5, 0), + 0x00000000, ""); + zassert_equal(GPIO_DT_PORT_PIN_MASK_NGPIOS_EXC(TEST_GPIO_6, 32), + 0xffffffff, ""); + + /* GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC */ + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(0, 32), 0x21524110, + ""); + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(1, 32), 0x80004100, + ""); + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(2, 18), 0x0003fbe7, + ""); + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(3, 16), 0x0000000f, + ""); + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(4, 0), 0x00000000, + ""); + zassert_equal(GPIO_DT_INST_PORT_PIN_MASK_NGPIOS_EXC(5, 16), 0x0000ffff, + ""); + + /* GPIO_PORT_PIN_MASK_FROM_DT_NODE */ + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_1), + 0x21524110, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_2), + 0x80004100, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_3), + 0x0003fbe7, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_4), + 0x0000000f, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_5), + 0x00000000, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_NODE(TEST_GPIO_6), + 0xffffffff, ""); + + /* GPIO_PORT_PIN_MASK_FROM_DT_INST */ + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(0), 0x21524110, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(1), 0x80004100, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(2), 0x0003fbe7, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(3), 0x0000000f, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(4), 0x00000000, ""); + zassert_equal(GPIO_PORT_PIN_MASK_FROM_DT_INST(5), 0xffffffff, ""); +} + +/* Test GPIO port configuration */ +ZTEST_SUITE(gpio_reserved_ranges, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml new file mode 100644 index 000000000000..57c6f2c291a1 --- /dev/null +++ b/tests/drivers/gpio/gpio_reserved_ranges/testcase.yaml @@ -0,0 +1,9 @@ +tests: + drivers.gpio.reserved_ranges: + tags: drivers gpio + depends_on: gpio + filter: dt_compat_enabled("test-gpio-reserved-ranges") + platform_allow: native_posix native_posix_64 + integration_platforms: + - native_posix + - native_posix_64 From 2460967c5b4de5a20db54f5b4ddec2501d6baf85 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 29 Jun 2023 09:31:56 +0200 Subject: [PATCH 1253/2042] manifest: hal_nordic: Update hal_nordic revision Pull in nrfx 3.1.0 release Signed-off-by: Adam Wojasinski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index e1df29a24c8c..12e7f340242c 100644 --- a/west.yml +++ b/west.yml @@ -173,7 +173,7 @@ manifest: groups: - hal - name: hal_nordic - revision: a1c3e0fbaafda091139b8744becd4853ada2f747 + revision: 20ae0a7be9030dd58fb59db1c74315a60efb076f path: modules/hal/nordic groups: - hal From 6f201f03f60c3965ebf891077f7cffc14095be02 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 29 Jun 2023 09:36:25 +0200 Subject: [PATCH 1254/2042] drivers: pwm: pwm_nrfx: Revert workaround for stopping PWM instance This reverts commit 36f4226b2f3d84954a2ed5000d0c24d918ce52b4. Signed-off-by: Adam Wojasinski --- drivers/pwm/pwm_nrfx.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 1b13572dddd4..1a671aaf731d 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -198,13 +198,7 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel, * and till that moment, it ignores any start requests, * so ensure here that it is stopped. */ - /* TODO: Remove nrfy_pwm_events_process() that is temporarly - * added as a workaround for missing functionality in - * nrfx_pwm_stopped_check() - */ - while (!nrfx_pwm_stopped_check(&config->pwm) && - !nrfy_pwm_events_process(config->pwm.p_reg, - NRFY_EVENT_TO_INT_BITMASK(NRF_PWM_EVENT_STOPPED))) { + while (!nrfx_pwm_stopped_check(&config->pwm)) { } } From 9aeb49732171358e2c8a125c2dcaf0bfa339b654 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Tue, 11 Jul 2023 16:07:24 +0200 Subject: [PATCH 1255/2042] modules: hal_nordic: nrfx_config: Align to updates in nrfx 3.1.0 Align config files to templates introduced with nrfx 3.1.0 release Signed-off-by: Adam Wojasinski --- modules/hal_nordic/nrfx/nrfx_config_nrf51.h | 51 +++++++++++++++++++ .../hal_nordic/nrfx/nrfx_config_nrf52805.h | 6 +-- .../hal_nordic/nrfx/nrfx_config_nrf52810.h | 6 +-- .../hal_nordic/nrfx/nrfx_config_nrf52811.h | 6 +-- .../hal_nordic/nrfx/nrfx_config_nrf52820.h | 6 +-- .../hal_nordic/nrfx/nrfx_config_nrf52832.h | 15 ++---- .../hal_nordic/nrfx/nrfx_config_nrf52833.h | 6 +-- .../hal_nordic/nrfx/nrfx_config_nrf52840.h | 6 +-- modules/hal_nordic/nrfx/nrfx_config_nrf91.h | 6 +-- 9 files changed, 76 insertions(+), 32 deletions(-) diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf51.h b/modules/hal_nordic/nrfx/nrfx_config_nrf51.h index 3e8f51ca1f4c..51d8bb1b8a51 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf51.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf51.h @@ -280,6 +280,57 @@ #define NRFX_PPI_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_QDEC_ENABLED * diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h index 46867f13ad59..33074008de43 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52805.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h index 6004836bea5b..ebd63c25ed80 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52810.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h index 4eb1a2cd0a97..01169f7b9839 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52811.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h index 9b3248ddd095..bfa743224582 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52820.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h index 6b1a3d359e76..4e5fe9d58351 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52832.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ @@ -626,14 +626,7 @@ * @brief NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE - EGU instance used by the nRF52 Anomaly 109 * workaround for PWM. * - * Integer value. - * Supported values: - * - EGU0 = 0 - * - EGU1 = 1 - * - EGU2 = 2 - * - EGU3 = 3 - * - EGU4 = 4 - * - EGU5 = 5 + * Integer value. Minimum: 0 Maximum: 5 */ #ifndef NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE #define NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE 5 diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h index d842b4c9f728..fc415c59dc3f 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52833.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h b/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h index f35c716c57fa..ac7a62fc9312 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf52840.h @@ -35,9 +35,9 @@ * * Integer value. * Supported values: - * - RC = 0 - * - XTAL = 1 - * - Synth = 2 + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 * - External Low Swing = 131073 * - External Full Swing = 196609 */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h index cc787ceee185..873be583a35b 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h @@ -109,8 +109,8 @@ * * Integer value. * Supported values: - * - RC = 1 - * - XTAL = 2 + * - RC = 1 + * - XTAL = 2 */ #ifndef NRFX_CLOCK_CONFIG_LF_SRC #define NRFX_CLOCK_CONFIG_LF_SRC 2 @@ -278,7 +278,7 @@ * Integer value. Minimum: 0 Maximum: 7 */ #ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY -#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY 3 +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY #endif /** From 913920a06fe2da98288e69cd35ea36efb294b614 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 6 Jul 2023 10:16:05 +0200 Subject: [PATCH 1256/2042] ztests: Enable native specific functionality with embedded libCs When building with the native simulator instead of attempting to call directly to the host libC, use the trampolines provided by the runner. In this way we can build this code even if we are building Zephyr with an embedded C library. Signed-off-by: Alberto Escolar Piedras --- subsys/testsuite/ztest/CMakeLists.txt | 2 +- subsys/testsuite/ztest/src/ztest_posix.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/subsys/testsuite/ztest/CMakeLists.txt b/subsys/testsuite/ztest/CMakeLists.txt index a0cf16151599..c9c933289858 100644 --- a/subsys/testsuite/ztest/CMakeLists.txt +++ b/subsys/testsuite/ztest/CMakeLists.txt @@ -24,7 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_ZTEST_MOCKING src/ztest_mock.c) zephyr_library_sources_ifdef(CONFIG_ZTRESS src/ztress.c) -if(CONFIG_ARCH_POSIX AND CONFIG_EXTERNAL_LIBC) +if(CONFIG_ARCH_POSIX) zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_posix.c) else() zephyr_library_sources_ifdef(CONFIG_ZTEST_NEW_API src/ztest_defaults.c) diff --git a/subsys/testsuite/ztest/src/ztest_posix.c b/subsys/testsuite/ztest/src/ztest_posix.c index fd8789a89c74..fbfb3ed41377 100644 --- a/subsys/testsuite/ztest/src/ztest_posix.c +++ b/subsys/testsuite/ztest/src/ztest_posix.c @@ -6,11 +6,11 @@ #include #include -#include #include "cmdline.h" /* native_posix command line options header */ #include "soc.h" #include #include +#include "nsi_host_trampolines.h" static const char *test_args; static bool list_tests; @@ -57,7 +57,7 @@ const char *ztest_relative_filename(const char *file) const char *cwd; char buf[200]; - cwd = getcwd(buf, sizeof(buf)); + cwd = nsi_host_getcwd(buf, sizeof(buf)); if (cwd && strlen(file) > strlen(cwd) && !strncmp(file, cwd, strlen(cwd))) { return file + strlen(cwd) + 1; /* move past the trailing '/' */ } @@ -146,7 +146,7 @@ void z_ztest_run_all(const void *state) static bool z_ztest_testargs_contains(const char *suite_name, const char *test_name) { bool found = false; - char *test_args_local = strdup(test_args); + char *test_args_local = nsi_host_strdup(test_args); char *suite_test_pair; char *last_suite_test_pair; char *suite_arg; @@ -168,7 +168,7 @@ static bool z_ztest_testargs_contains(const char *suite_name, const char *test_n suite_test_pair = strtok_r(NULL, ",", &last_suite_test_pair); } - free(test_args_local); + nsi_host_free(test_args_local); return found; } From a36af82f64ccd898eebc8ecd121fb8fbc7daa76f Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Fri, 30 Jun 2023 17:05:42 +0200 Subject: [PATCH 1257/2042] scripts: tests: Twister test expansion - quarantine Here we achieve 100% coverage for the quarantine module, thanks to unit tests for QuarantineElement and QuarantineData dataclasses. Implemented PR suggestions of gchwier. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_quarantine.py | 275 +++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 scripts/tests/twister/test_quarantine.py diff --git a/scripts/tests/twister/test_quarantine.py b/scripts/tests/twister/test_quarantine.py new file mode 100644 index 000000000000..8988d7978ca9 --- /dev/null +++ b/scripts/tests/twister/test_quarantine.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for quarantine.py classes' methods +""" + +import mock +import os +import pytest +import textwrap + +from twisterlib.quarantine import QuarantineException, \ + QuarantineElement, \ + QuarantineData + + +TESTDATA_1 = [ + ( + ['dummy scenario', 'another scenario'], + ['dummy platform', 'another platform'], + ['dummy architecture', 'another architecture'], + ['dummy simulation', 'another simulation'], + None, + [] + ), + ( + ['all'], + ['dummy platform', 'another platform'], + ['dummy architecture', 'another architecture'], + ['dummy simulation', 'another simulation'], + None, + ['scenarios'] + ), + ( + ['dummy scenario', 'another scenario'], + ['dummy platform', 'all'], + ['all', 'another architecture'], + ['dummy simulation', 'another simulation'], + None, + ['platforms', 'architectures'] + ), + ( + ['all', 'another scenario'], + [], + [], + ['all', 'all'], + QuarantineException, + ['scenarios', 'platforms', 'architectures', 'simulations'] + ), +] + + +@pytest.mark.parametrize( + 'scenarios, platforms, architectures, ' \ + 'simulations, expected_exception, empty_filter_attrs', + TESTDATA_1, + ids=[ + 'no empties', + 'all scenarios', + 'all platforms and architectures', + 'exception' + ] +) +def test_quarantineelement_post_init( + scenarios, + platforms, + architectures, + simulations, + expected_exception, + empty_filter_attrs +): + if expected_exception: + with pytest.raises(expected_exception): + quarantine_element = QuarantineElement( + scenarios=scenarios, + platforms=platforms, + architectures=architectures, + simulations=simulations + ) + else: + quarantine_element = QuarantineElement( + scenarios=scenarios, + platforms=platforms, + architectures=architectures, + simulations=simulations + ) + + for attr in ['scenarios', 'platforms', 'architectures', 'simulations']: + if attr in empty_filter_attrs: + assert getattr(quarantine_element, attr) == [] + else: + assert getattr(quarantine_element, attr) != [] + + +def test_quarantinedata_post_init(): + quarantine_element_dict = { + 'scenarios': ['all'], + 'platforms': ['dummy platform'], + 'architectures': [], + 'simulations': ['dummy simulation', 'another simulation'] + } + + quarantine_element = QuarantineElement( + platforms=['dummy platform'], + architectures=[] + ) + quarantine_element.scenarios = [] + quarantine_element.simulations = ['dummy simulation', 'another simulation'] + + quarantine_data_qlist = [quarantine_element, quarantine_element_dict] + + quarantine_data = QuarantineData(quarantine_data_qlist) + + assert quarantine_data.qlist[0] == quarantine_data.qlist[1] + + +TESTDATA_2 = [ + ( + '', + QuarantineData() + ), + ( + textwrap.dedent(""" + [ + { + \"scenarios\": [\"all\"], + \"platforms\": [\"dummy platform\"], + \"architectures\": [], + \"simulations\": [\"dummy simulation\", \"another simulation\"] + } + ] + """), + QuarantineData( + [ + QuarantineElement( + scenarios=[], + platforms=['dummy platform'], + architectures=[], + simulations=['dummy simulation', 'another simulation'] + ) + ] + ) + ), + ( + textwrap.dedent(""" + [ + { + \"I\": [\"am\"], + \"not\": \"a\", + \"valid\": [], + \"JSON\": [\"for\", \"this\"] + } + ] + """), + QuarantineException + ) +] + + +@pytest.mark.parametrize( + 'file_contents, expected', + TESTDATA_2, + ids=['empty', 'valid', 'not valid'] +) +def test_quarantinedata_load_data_from_yaml(file_contents, expected): + with mock.patch('builtins.open', mock.mock_open(read_data=file_contents)): + if isinstance(expected, type) and issubclass(expected, Exception): + with pytest.raises(expected): + res = QuarantineData.load_data_from_yaml( + os.path.join('dummy', 'path') + ) + else: + res = QuarantineData.load_data_from_yaml( + os.path.join('dummy', 'path') + ) + + assert res == expected + + +TESTDATA_3 = [ + ( + 'good scenario', + 'good platform', + 'good arch', + 'good sim', + None + ), + ( + 'good scenario', + 'very bad dummy platform', + 'good arch', + 'good sim', + 0 + ), + ( + 'bad scenario 1', + 'good platform', + 'good arch', + 'bad sim', + 1 + ), + ( + 'bad scenario 1', + 'good platform', + 'good arch', + 'sim for scenario 1', + None + ), + ( + 'good scenario', + 'good platform', + 'unsupported arch 1', + 'good sim', + 2 + ) +] + + +@pytest.mark.parametrize( + 'scenario, platform, architecture, simulation, expected_idx', + TESTDATA_3, + ids=[ + 'not quarantined', + 'quarantined platform', + 'quarantined scenario with sim', + 'not quarantined with bad scenario', + 'quarantined arch' + ] +) +def test_quarantinedata_get_matched_quarantine( + scenario, + platform, + architecture, + simulation, + expected_idx +): + qlist = [ + QuarantineElement( + scenarios=['all'], + platforms=['very bad dummy platform'], + architectures=['all'], + simulations=['all'] + ), + QuarantineElement( + scenarios=['bad scenario 1', 'bad scenario 2'], + platforms=['all'], + architectures=['all'], + simulations=['bad sim'] + ), + QuarantineElement( + scenarios=['all'], + platforms=['all'], + architectures=['unsupported arch 1'], + simulations=['all'] + ), + ] + + quarantine_data = QuarantineData(qlist) + + if expected_idx is None: + assert quarantine_data.get_matched_quarantine( + scenario=scenario, + platform=platform, + architecture=architecture, + simulation=simulation + ) is None + else: + assert quarantine_data.get_matched_quarantine( + scenario=scenario, + platform=platform, + architecture=architecture, + simulation=simulation + ) == qlist[expected_idx] From 35e8e6fa03fa5742947ed54f2e448466444e7071 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Fri, 2 Jun 2023 20:26:10 +0000 Subject: [PATCH 1258/2042] soc/xtensa/nxp_adsp/CMakeLists.txt: use new WEST_SIGN_OPTS variable Align `soc/nxp_adsp` with new `WEST_SIGN_OPTS` option added to `soc/intel_adsp` by recent commit d98a7c2f8ddb ("soc: xtensa: cmake: add new WEST_SIGN_OPTS variable"). This allows per-board rimage customization at the CMake level. Example in `zephyr/boards/xtensa/nxp_adsp_NEWBOARD/board.cmake`: set(WEST_SIGN_OPTS -- -c rimage/config/special.toml) Signed-off-by: Marc Herbert --- soc/xtensa/nxp_adsp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/xtensa/nxp_adsp/CMakeLists.txt b/soc/xtensa/nxp_adsp/CMakeLists.txt index 3586d87ffb74..f317b0b7054d 100644 --- a/soc/xtensa/nxp_adsp/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/CMakeLists.txt @@ -15,6 +15,6 @@ add_custom_target(zephyr.ri ALL add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/zephyr/zephyr.ri COMMENT "west sign --if-tool-available --tool rimage ..." - COMMAND west sign --if-tool-available --tool rimage --build-dir ${CMAKE_BINARY_DIR} + COMMAND west sign --if-tool-available --tool rimage --build-dir ${CMAKE_BINARY_DIR} ${WEST_SIGN_OPTS} DEPENDS ${CMAKE_BINARY_DIR}/zephyr/${KERNEL_ELF_NAME} ) From 908865ef4ba360977f410d394541c3048674b9d7 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 13 Jul 2023 12:10:47 +0200 Subject: [PATCH 1259/2042] bluetooth: conn: remove trailing dot It was causing Doxygen issues (End of list marker found without any preceding list items). Signed-off-by: Gerard Marull-Paretas --- include/zephyr/bluetooth/conn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 5487e3e2cfeb..031818fd6b51 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -745,7 +745,7 @@ int bt_conn_le_create_synced(const struct bt_le_ext_adv *adv, const struct bt_conn_le_create_synced_param *synced_param, const struct bt_le_conn_param *conn_param, struct bt_conn **conn); -/** @brief Automatically connect to remote devices in the filter accept list.. +/** @brief Automatically connect to remote devices in the filter accept list. * * This uses the Auto Connection Establishment procedure. * The procedure will continue until a single connection is established or the From 77aafa51a1b5c643d95938b37fd4c9b60baa2516 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 13 Jul 2023 12:01:42 +0200 Subject: [PATCH 1260/2042] doc: align pseudo-Makefile with latest CMake changes The SPHINXOPTS option was not aligned with latest changes in CMake, and SPHINXOPTS_EXTRA was not present. Signed-off-by: Gerard Marull-Paretas --- doc/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/Makefile b/doc/Makefile index c9ae0e700978..321a1b92cc40 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -4,7 +4,8 @@ BUILDDIR ?= _build DOC_TAG ?= development -SPHINXOPTS ?= -j auto +SPHINXOPTS ?= -j auto -W --keep-going -T +SPHINXOPTS_EXTRA ?= LATEXMKOPTS ?= -halt-on-error -no-shell-escape DT_TURBO_MODE ?= 0 @@ -26,6 +27,7 @@ configure: -S. \ -DDOC_TAG=${DOC_TAG} \ -DSPHINXOPTS="${SPHINXOPTS}" \ + -DSPHINXOPTS_EXTRA="${SPHINXOPTS_EXTRA}" \ -DLATEXMKOPTS="${LATEXMKOPTS}" \ -DDT_TURBO_MODE=${DT_TURBO_MODE} From db53c3fd2c1f85f51704631b9fc39f97d63a702d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 14:18:49 +0200 Subject: [PATCH 1261/2042] doc: Drop asterisk from Doxygen @param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name for Doxygen params that are pointers should not include an asterisk. Signed-off-by: Benjamin Cabé --- .../interrupt_controller/intc_exti_stm32.c | 2 +- drivers/modem/hl7800.c | 4 +- drivers/modem/modem_cmd_handler.h | 60 +++++++++---------- drivers/modem/modem_context.c | 4 +- drivers/modem/modem_context.h | 4 +- drivers/modem/modem_iface_uart.h | 4 +- drivers/modem/modem_iface_uart_interrupt.c | 4 +- drivers/modem/modem_receiver.c | 10 ++-- drivers/modem/modem_receiver.h | 16 ++--- include/zephyr/sensing/sensing.h | 4 +- include/zephyr/sensing/sensing_sensor.h | 2 +- include/zephyr/sys/crc.h | 6 +- 12 files changed, 60 insertions(+), 60 deletions(-) diff --git a/drivers/interrupt_controller/intc_exti_stm32.c b/drivers/interrupt_controller/intc_exti_stm32.c index 99788bad29f1..064d23cae207 100644 --- a/drivers/interrupt_controller/intc_exti_stm32.c +++ b/drivers/interrupt_controller/intc_exti_stm32.c @@ -168,7 +168,7 @@ void stm32_exti_trigger(int line, int trigger) * * Check EXTI lines in exti_range for pending interrupts * - * @param *exti_range Pointer to a exti_range structure + * @param exti_range Pointer to a exti_range structure */ static void stm32_exti_isr(const void *exti_range) { diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index e8975c852f1a..2fcd000a0faf 100644 --- a/drivers/modem/hl7800.c +++ b/drivers/modem/hl7800.c @@ -5004,8 +5004,8 @@ static int modem_boot_handler(char *reason) /** * @brief compares two version strings with any delimiter * - * @param *v1: version string 1 - * @param *v2: version string 2 + * @param v1: version string 1 + * @param v2: version string 2 * * @retval 0 if equal, < 0 if v1 < v2, > 0 if v1 > v2. */ diff --git a/drivers/modem/modem_cmd_handler.h b/drivers/modem/modem_cmd_handler.h index 102d61e20f7e..017097b2346c 100644 --- a/drivers/modem/modem_cmd_handler.h +++ b/drivers/modem/modem_cmd_handler.h @@ -126,7 +126,7 @@ struct modem_cmd_handler_data { /** * @brief get the last error code * - * @param *data: command handler data reference + * @param data: command handler data reference * * @retval last handled error. */ @@ -135,8 +135,8 @@ int modem_cmd_handler_get_error(struct modem_cmd_handler_data *data); /** * @brief set the last error code * - * @param *data: command handler data reference - * @param *error_code: error + * @param data: command handler data reference + * @param error_code: error * * @retval 0 if ok, < 0 if error. */ @@ -146,8 +146,8 @@ int modem_cmd_handler_set_error(struct modem_cmd_handler_data *data, /** * @brief update the parser's handler commands * - * @param *data: handler data to use - * @param *handler_cmds: commands to attach + * @param data: handler data to use + * @param handler_cmds: commands to attach * @param handler_cmds_len: size of commands array * @param reset_error_flag: reset last error code * @@ -165,12 +165,12 @@ int modem_cmd_handler_update_cmds(struct modem_cmd_handler_data *data, * specific behavior regarding acquiring tx_lock, setting and unsetting * @a handler_cmds. * - * @param *iface: interface to use - * @param *handler: command handler to use - * @param *handler_cmds: commands to attach + * @param iface: interface to use + * @param handler: command handler to use + * @param handler_cmds: commands to attach * @param handler_cmds_len: size of commands array - * @param *buf: NULL terminated send buffer - * @param *sem: wait for response semaphore + * @param buf: NULL terminated send buffer + * @param sem: wait for response semaphore * @param timeout: timeout of command * @param flags: flags which influence behavior of command sending * @@ -185,12 +185,12 @@ int modem_cmd_send_ext(struct modem_iface *iface, /** * @brief send AT command to interface w/o locking TX * - * @param *iface: interface to use - * @param *handler: command handler to use - * @param *handler_cmds: commands to attach + * @param iface: interface to use + * @param handler: command handler to use + * @param handler_cmds: commands to attach * @param handler_cmds_len: size of commands array - * @param *buf: NULL terminated send buffer - * @param *sem: wait for response semaphore + * @param buf: NULL terminated send buffer + * @param sem: wait for response semaphore * @param timeout: timeout of command * * @retval 0 if ok, < 0 if error. @@ -210,12 +210,12 @@ static inline int modem_cmd_send_nolock(struct modem_iface *iface, /** * @brief send AT command to interface w/ a TX lock * - * @param *iface: interface to use - * @param *handler: command handler to use - * @param *handler_cmds: commands to attach + * @param iface: interface to use + * @param handler: command handler to use + * @param handler_cmds: commands to attach * @param handler_cmds_len: size of commands array - * @param *buf: NULL terminated send buffer - * @param *sem: wait for response semaphore + * @param buf: NULL terminated send buffer + * @param sem: wait for response semaphore * @param timeout: timeout of command * * @retval 0 if ok, < 0 if error. @@ -233,11 +233,11 @@ static inline int modem_cmd_send(struct modem_iface *iface, /** * @brief send a series of AT commands w/ a TX lock * - * @param *iface: interface to use - * @param *handler: command handler to use - * @param *cmds: array of setup commands to send + * @param iface: interface to use + * @param handler: command handler to use + * @param cmds: array of setup commands to send * @param cmds_len: size of the setup command array - * @param *sem: wait for response semaphore + * @param sem: wait for response semaphore * @param timeout: timeout of command * * @retval 0 if ok, < 0 if error. @@ -250,11 +250,11 @@ int modem_cmd_handler_setup_cmds(struct modem_iface *iface, /** * @brief send a series of AT commands w/o locking TX * - * @param *iface: interface to use - * @param *handler: command handler to use - * @param *cmds: array of setup commands to send + * @param iface: interface to use + * @param handler: command handler to use + * @param cmds: array of setup commands to send * @param cmds_len: size of the setup command array - * @param *sem: wait for response semaphore + * @param sem: wait for response semaphore * @param timeout: timeout of command * * @retval 0 if ok, < 0 if error. @@ -325,7 +325,7 @@ int modem_cmd_handler_init(struct modem_cmd_handler *handler, * when one needs to prevent threads from sending UART data to the modem for an * extended period of time (for example during modem reset). * - * @param *handler: command handler to lock + * @param handler: command handler to lock * @param timeout: give up after timeout * * @retval 0 if ok, < 0 if error. @@ -336,7 +336,7 @@ int modem_cmd_handler_tx_lock(struct modem_cmd_handler *handler, /** * @brief Unlock the modem for sending cmds * - * @param *handler: command handler to unlock + * @param handler: command handler to unlock */ void modem_cmd_handler_tx_unlock(struct modem_cmd_handler *handler); diff --git a/drivers/modem/modem_context.c b/drivers/modem/modem_context.c index 777f988fd521..01cd1ced6a5c 100644 --- a/drivers/modem/modem_context.c +++ b/drivers/modem/modem_context.c @@ -76,7 +76,7 @@ int modem_context_get_addr_port(const struct sockaddr *addr, uint16_t *port) /** * @brief Finds modem context which owns the iface device. * - * @param *dev: device used by the modem iface. + * @param dev: device used by the modem iface. * * @retval Modem context or NULL. */ @@ -99,7 +99,7 @@ struct modem_context *modem_context_from_iface_dev(const struct device *dev) * @note Amount of stored modem contexts is determined by * CONFIG_MODEM_CONTEXT_MAX_NUM. * - * @param *ctx: modem context to persist. + * @param ctx: modem context to persist. * * @retval 0 if ok, < 0 if error. */ diff --git a/drivers/modem/modem_context.h b/drivers/modem/modem_context.h index f93fafd10817..de76b0a4c605 100644 --- a/drivers/modem/modem_context.h +++ b/drivers/modem/modem_context.h @@ -105,7 +105,7 @@ struct modem_context *modem_context_from_id(int id); /** * @brief Finds modem context which owns the iface device. * - * @param *dev: device used by the modem iface. + * @param dev: device used by the modem iface. * * @retval Modem context or NULL. */ @@ -116,7 +116,7 @@ struct modem_context *modem_context_from_iface_dev(const struct device *dev); * * @note Prepares modem context to be used. * - * @param *ctx: modem context to register. + * @param ctx: modem context to register. * * @retval 0 if ok, < 0 if error. */ diff --git a/drivers/modem/modem_iface_uart.h b/drivers/modem/modem_iface_uart.h index 871c0649748d..91b94da33750 100644 --- a/drivers/modem/modem_iface_uart.h +++ b/drivers/modem/modem_iface_uart.h @@ -42,8 +42,8 @@ struct modem_iface_uart_data { * * @details This can be called after the init if the UART is changed. * - * @param *iface: modem interface to initialize. - * @param *dev_name: name of the UART device to use + * @param iface: modem interface to initialize. + * @param dev_name: name of the UART device to use * * @retval 0 if ok, < 0 if error. */ diff --git a/drivers/modem/modem_iface_uart_interrupt.c b/drivers/modem/modem_iface_uart_interrupt.c index 220dfe685c88..985e2d5d4068 100644 --- a/drivers/modem/modem_iface_uart_interrupt.c +++ b/drivers/modem/modem_iface_uart_interrupt.c @@ -24,7 +24,7 @@ LOG_MODULE_REGISTER(modem_iface_uart, CONFIG_MODEM_LOG_LEVEL); * * @note Discards remaining data. * - * @param *iface: modem interface. + * @param iface: modem interface. * * @retval None. */ @@ -43,7 +43,7 @@ static void modem_iface_uart_flush(struct modem_iface *iface) * @note Fills interfaces ring buffer with received data. * When ring buffer is full the data is discarded. * - * @param *uart_dev: uart device. + * @param uart_dev: uart device. * * @retval None. */ diff --git a/drivers/modem/modem_receiver.c b/drivers/modem/modem_receiver.c index 27ac8413741b..0d2cb627c067 100644 --- a/drivers/modem/modem_receiver.c +++ b/drivers/modem/modem_receiver.c @@ -30,7 +30,7 @@ static struct mdm_receiver_context *contexts[MAX_MDM_CTX]; /** * @brief Finds receiver context which manages provided device. * - * @param *dev: device used by the receiver context. + * @param dev: device used by the receiver context. * * @retval Receiver context or NULL. */ @@ -53,7 +53,7 @@ static struct mdm_receiver_context *context_from_dev(const struct device *dev) * @note Amount of stored receiver contexts is determined by * MAX_MDM_CTX. * - * @param *ctx: receiver context to persist. + * @param ctx: receiver context to persist. * * @retval 0 if ok, < 0 if error. */ @@ -76,7 +76,7 @@ static int mdm_receiver_get(struct mdm_receiver_context *ctx) * * @note Discards remaining data. * - * @param *ctx: receiver context. + * @param ctx: receiver context. * * @retval None. */ @@ -98,7 +98,7 @@ static void mdm_receiver_flush(struct mdm_receiver_context *ctx) * @note Fills contexts ring buffer with received data. * When ring buffer is full the data is discarded. * - * @param *uart_dev: uart device. + * @param uart_dev: uart device. * * @retval None. */ @@ -138,7 +138,7 @@ static void mdm_receiver_isr(const struct device *uart_dev, void *user_data) /** * @brief Configures receiver context and assigned device. * - * @param *ctx: receiver context. + * @param ctx: receiver context. * * @retval None. */ diff --git a/drivers/modem/modem_receiver.h b/drivers/modem/modem_receiver.h index b4b60a78ae10..e08839e88f9c 100644 --- a/drivers/modem/modem_receiver.h +++ b/drivers/modem/modem_receiver.h @@ -52,10 +52,10 @@ struct mdm_receiver_context *mdm_receiver_context_from_id(int id); /** * @brief Get received data. * - * @param *ctx: receiver context. - * @param *buf: buffer to copy the received data to. + * @param ctx: receiver context. + * @param buf: buffer to copy the received data to. * @param size: buffer size. - * @param *bytes_read: amount of received bytes + * @param bytes_read: amount of received bytes * * @retval 0 if ok, < 0 if error. */ @@ -65,8 +65,8 @@ int mdm_receiver_recv(struct mdm_receiver_context *ctx, /** * @brief Sends the data over specified receiver context. * - * @param *ctx: receiver context. - * @param *buf: buffer with the data to send. + * @param ctx: receiver context. + * @param buf: buffer with the data to send. * @param size: the amount of data to send. * * @retval 0 if ok, < 0 if error. @@ -79,9 +79,9 @@ int mdm_receiver_send(struct mdm_receiver_context *ctx, * * @note Acquires receivers device, and prepares the context to be used. * - * @param *ctx: receiver context to register. - * @param *uart_dev: communication device for the receiver context. - * @param *buf: rx buffer to use for received data. + * @param ctx: receiver context to register. + * @param uart_dev: communication device for the receiver context. + * @param buf: rx buffer to use for received data. * @param size: rx buffer size. * * @retval 0 if ok, < 0 if error. diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index 3b11d1b410ca..e29b1aa76247 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -188,7 +188,7 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf * * @param cb_list callback list to be registered to sensing. * - * @param *handle The opened instance handle, if failed will be set to NULL. + * @param handle The opened instance handle, if failed will be set to NULL. * * @return 0 on success or negative error value on failure. */ @@ -209,7 +209,7 @@ int sensing_open_sensor( * * @param cb_list callback list to be registered to sensing. * - * @param *handle The opened instance handle, if failed will be set to NULL. + * @param handle The opened instance handle, if failed will be set to NULL. * * @return 0 on success or negative error value on failure. */ diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index e7716a317d8e..39d94d71fb3e 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -169,7 +169,7 @@ int sensing_sensor_post_data( * @param max_handles The max count of the \p reporter_handles array input. Can * get real count number via \ref sensing_sensor_get_reporters_count * - * @param *reporter_handles Input handles array for receiving found reporter + * @param reporter_handles Input handles array for receiving found reporter * sensor instances * * @return number of reporters found, 0 returned if not found. diff --git a/include/zephyr/sys/crc.h b/include/zephyr/sys/crc.h index 3da3a52d8b84..7c131f4cbfd8 100644 --- a/include/zephyr/sys/crc.h +++ b/include/zephyr/sys/crc.h @@ -215,7 +215,7 @@ static inline uint16_t crc16_ansi(const uint8_t *src, size_t len) /** * @brief Generate IEEE conform CRC32 checksum. * - * @param *data Pointer to data on which the CRC should be calculated. + * @param data Pointer to data on which the CRC should be calculated. * @param len Data length. * * @return CRC32 value. @@ -227,7 +227,7 @@ uint32_t crc32_ieee(const uint8_t *data, size_t len); * @brief Update an IEEE conforming CRC32 checksum. * * @param crc CRC32 checksum that needs to be updated. - * @param *data Pointer to data on which the CRC should be calculated. + * @param data Pointer to data on which the CRC should be calculated. * @param len Data length. * * @return CRC32 value. @@ -239,7 +239,7 @@ uint32_t crc32_ieee_update(uint32_t crc, const uint8_t *data, size_t len); * @brief Calculate CRC32C (Castagnoli) checksum. * * @param crc CRC32C checksum that needs to be updated. - * @param *data Pointer to data on which the CRC should be calculated. + * @param data Pointer to data on which the CRC should be calculated. * @param len Data length. * @param first_pkt Whether this is the first packet in the stream. * @param last_pkt Whether this is the last packet in the stream. From c89be9527490c0718e309785a4963b8d04e529be Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 12 Jul 2023 13:03:41 +0200 Subject: [PATCH 1262/2042] Bluetooth: Mesh: Fix comment for BT_MESH_DFU_PHASE_UNKNOWN The phase was added to the spec, so it is not metaphase anymore. Signed-off-by: Pavel Vasilyev --- include/zephyr/bluetooth/mesh/dfu.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/dfu.h b/include/zephyr/bluetooth/mesh/dfu.h index b9162936bea1..91f36cdbaeb4 100644 --- a/include/zephyr/bluetooth/mesh/dfu.h +++ b/include/zephyr/bluetooth/mesh/dfu.h @@ -66,11 +66,7 @@ enum bt_mesh_dfu_phase { /** Firmware applying failed. */ BT_MESH_DFU_PHASE_APPLY_FAIL, - /** The current phase is unknown. - * - * This is a metaphase, used by the Firmware Update Client to keep track of - * the Target state, and is not defined by the specification. - */ + /** Phase of a node was not yet retrieved. */ BT_MESH_DFU_PHASE_UNKNOWN, }; From fd54a9ab6ef7a8fd58b58f9b83665e3e533f2cd0 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 13 Jul 2023 11:18:52 +0200 Subject: [PATCH 1263/2042] dts: bindings: adc: fix description of ADS114S08 Fix the description in the binding of the ADS114S08. Signed-off-by: Benedikt Schmidt --- dts/bindings/adc/ti,ads114s08.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/bindings/adc/ti,ads114s08.yaml b/dts/bindings/adc/ti,ads114s08.yaml index 7fce19d9a1db..a172439e0517 100644 --- a/dts/bindings/adc/ti,ads114s08.yaml +++ b/dts/bindings/adc/ti,ads114s08.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2023 SILA Embedded Solutions GmbH # SPDX-License-Identifier: Apache-2.0 -description: Texas Instrument 12 channels 16 bit I2C ADC +description: Texas Instrument 12 channels 16 bit SPI ADC compatible: "ti,ads114s08" From 04e0e458c831686892de282c9f6472008ce591be Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 7 Jul 2023 18:03:54 +0100 Subject: [PATCH 1264/2042] input: convert gt911 from kscan Convert the GT911 driver to the input subsystem, fix the existing boards to work in the default config. Signed-off-by: Fabio Baltieri --- .../shields/rk055hdmipi4m/Kconfig.defconfig | 5 +- .../rk055hdmipi4m/rk055hdmipi4m.overlay | 8 +- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/{kscan => input}/Kconfig.gt911 | 18 ++-- .../kscan_gt911.c => input/input_gt911.c} | 86 +++++-------------- drivers/kscan/CMakeLists.txt | 1 - drivers/kscan/Kconfig | 1 - .../{kscan => input}/goodix,gt911.yaml | 2 +- samples/drivers/kscan/sample.yaml | 12 --- tests/drivers/build_all/input/app.overlay | 7 ++ tests/drivers/kscan/kscan_api/testcase.yaml | 5 -- 12 files changed, 51 insertions(+), 96 deletions(-) rename drivers/{kscan => input}/Kconfig.gt911 (57%) rename drivers/{kscan/kscan_gt911.c => input/input_gt911.c} (83%) rename dts/bindings/{kscan => input}/goodix,gt911.yaml (85%) diff --git a/boards/shields/rk055hdmipi4m/Kconfig.defconfig b/boards/shields/rk055hdmipi4m/Kconfig.defconfig index 4a95cdbd9655..2ee4791d4d40 100644 --- a/boards/shields/rk055hdmipi4m/Kconfig.defconfig +++ b/boards/shields/rk055hdmipi4m/Kconfig.defconfig @@ -19,7 +19,10 @@ if LVGL config KSCAN default y -config KSCAN_GT911_INTERRUPT +config INPUT + default y if KSCAN + +config INPUT_GT911_INTERRUPT default y config LV_Z_POINTER_KSCAN diff --git a/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay index 709048f8b734..ae1c42a52148 100644 --- a/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay +++ b/boards/shields/rk055hdmipi4m/rk055hdmipi4m.overlay @@ -8,12 +8,12 @@ /{ aliases { - kscan0 = &touch_controller; + kscan0 = &kscan_input_gt911; }; chosen { zephyr,display = &lcdif; - zephyr,keyboard-scan = &touch_controller; + zephyr,keyboard-scan = &kscan_input_gt911; }; en_mipi_display: enable-mipi-display { @@ -31,6 +31,10 @@ reg = <0x5d>; irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_HIGH>; reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + + kscan_input_gt911: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; }; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 32280c42e1e7..3872f182b3cd 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_XPT2046 input_xpt2046.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 6e1d8abf5e89..226c9c9d6c5a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -8,6 +8,7 @@ menu "Input drivers" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_keys" source "drivers/input/Kconfig.gpio_qdec" +source "drivers/input/Kconfig.gt911" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.sdl" source "drivers/input/Kconfig.xpt2046" diff --git a/drivers/kscan/Kconfig.gt911 b/drivers/input/Kconfig.gt911 similarity index 57% rename from drivers/kscan/Kconfig.gt911 rename to drivers/input/Kconfig.gt911 index 9179bb98d02e..e4857463d258 100644 --- a/drivers/kscan/Kconfig.gt911 +++ b/drivers/input/Kconfig.gt911 @@ -2,28 +2,28 @@ # Copyright (c) 2020 Teslabs Engineering S.L. # SPDX-License-Identifier: Apache-2.0 -menuconfig KSCAN_GT911 +menuconfig INPUT_GT911 bool "GT9xx / GT9xxx capacitive touch panel driver" default y depends on DT_HAS_GOODIX_GT911_ENABLED select I2C help - Enable driver for multiple Goodix capacitive touch panel - controllers. This driver should support gt9110, gt912, - gt927, gt9271, gt928, gt967 + Enable driver for multiple Goodix capacitive touch panel controllers. + This driver should support gt9110, gt912, gt927, gt9271, gt928, + gt967. -if KSCAN_GT911 +if INPUT_GT911 -config KSCAN_GT911_PERIOD +config INPUT_GT911_PERIOD_MS int "Sample period" - depends on !KSCAN_GT911_INTERRUPT + depends on !INPUT_GT911_INTERRUPT default 10 help Sample period in milliseconds when in polling mode. -config KSCAN_GT911_INTERRUPT +config INPUT_GT911_INTERRUPT bool "Interrupt" help Enable interrupt support (requires GPIO). -endif # KSCAN_GT911 +endif # INPUT_GT911 diff --git a/drivers/kscan/kscan_gt911.c b/drivers/input/input_gt911.c similarity index 83% rename from drivers/kscan/kscan_gt911.c rename to drivers/input/input_gt911.c index ba4e87501898..e2fd67188ecd 100644 --- a/drivers/kscan/kscan_gt911.c +++ b/drivers/input/input_gt911.c @@ -8,13 +8,13 @@ #define DT_DRV_COMPAT goodix_gt911 -#include -#include #include +#include +#include #include #include -LOG_MODULE_REGISTER(gt911, CONFIG_KSCAN_LOG_LEVEL); +LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); /* GT911 used registers */ #define DEVICE_ID __bswap_16(0x8140U) @@ -45,11 +45,9 @@ struct gt911_config { struct gt911_data { /** Device pointer. */ const struct device *dev; - /** KSCAN Callback. */ - kscan_callback_t callback; /** Work queue (for deferred read). */ struct k_work work; -#ifdef CONFIG_KSCAN_GT911_INTERRUPT +#ifdef CONFIG_INPUT_GT911_INTERRUPT /** Interrupt GPIO callback. */ struct gpio_callback int_gpio_cb; #else @@ -73,7 +71,6 @@ struct gt911_point_reg_t { static int gt911_process(const struct device *dev) { const struct gt911_config *config = dev->config; - struct gt911_data *data = dev->data; int r; uint16_t reg_addr; @@ -124,7 +121,13 @@ static int gt911_process(const struct device *dev) LOG_DBG("pressed: %d, row: %d, col: %d", pressed, row, col); - data->callback(dev, row, col, pressed); + if (pressed) { + 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, 1, true, K_FOREVER); + } else { + input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); + } return 0; } @@ -136,7 +139,7 @@ static void gt911_work_handler(struct k_work *work) gt911_process(data->dev); } -#ifdef CONFIG_KSCAN_GT911_INTERRUPT +#ifdef CONFIG_INPUT_GT911_INTERRUPT static void gt911_isr_handler(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { @@ -153,52 +156,6 @@ static void gt911_timer_handler(struct k_timer *timer) } #endif -static int gt911_configure(const struct device *dev, - kscan_callback_t callback) -{ - struct gt911_data *data = dev->data; - - if (!callback) { - LOG_ERR("Invalid callback (NULL)"); - return -EINVAL; - } - - data->callback = callback; - - return 0; -} - -static int gt911_enable_callback(const struct device *dev) -{ - struct gt911_data *data = dev->data; - -#ifdef CONFIG_KSCAN_GT911_INTERRUPT - const struct gt911_config *config = dev->config; - - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); -#else - k_timer_start(&data->timer, K_MSEC(CONFIG_KSCAN_GT911_PERIOD), - K_MSEC(CONFIG_KSCAN_GT911_PERIOD)); -#endif - - return 0; -} - -static int gt911_disable_callback(const struct device *dev) -{ - struct gt911_data *data = dev->data; - -#ifdef CONFIG_KSCAN_GT911_INTERRUPT - const struct gt911_config *config = dev->config; - - gpio_remove_callback(config->int_gpio.port, &data->int_gpio_cb); -#else - k_timer_stop(&data->timer); -#endif - - return 0; -} - static uint8_t gt911_get_firmware_checksum(const uint8_t *firmware) { uint8_t sum = 0; @@ -269,7 +226,7 @@ static int gt911_init(const struct device *dev) return r; } -#ifdef CONFIG_KSCAN_GT911_INTERRUPT +#ifdef CONFIG_INPUT_GT911_INTERRUPT r = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); if (r < 0) { @@ -320,15 +277,16 @@ static int gt911_init(const struct device *dev) return r; } +#ifdef CONFIG_INPUT_GT911_INTERRUPT + gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); +#else + k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_GT911_PERIOD_MS), + K_MSEC(CONFIG_INPUT_GT911_PERIOD_MS)); +#endif + return 0; } -static const struct kscan_driver_api gt911_driver_api = { - .config = gt911_configure, - .enable_callback = gt911_enable_callback, - .disable_callback = gt911_disable_callback, -}; - #define GT911_INIT(index) \ static const struct gt911_config gt911_config_##index = { \ .bus = I2C_DT_SPEC_INST_GET(index), \ @@ -338,7 +296,7 @@ static const struct kscan_driver_api gt911_driver_api = { static struct gt911_data gt911_data_##index; \ DEVICE_DT_INST_DEFINE(index, gt911_init, NULL, \ >911_data_##index, >911_config_##index, \ - POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ - >911_driver_api); + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); DT_INST_FOREACH_STATUS_OKAY(GT911_INIT) diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index b9b150873c47..2f27d65ff232 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -4,7 +4,6 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/kscan.h) zephyr_library() -zephyr_library_sources_ifdef(CONFIG_KSCAN_GT911 kscan_gt911.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index c5fcee278d55..4c08a2d88878 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -10,7 +10,6 @@ menuconfig KSCAN if KSCAN -source "drivers/kscan/Kconfig.gt911" source "drivers/kscan/Kconfig.it8xxx2" source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" diff --git a/dts/bindings/kscan/goodix,gt911.yaml b/dts/bindings/input/goodix,gt911.yaml similarity index 85% rename from dts/bindings/kscan/goodix,gt911.yaml rename to dts/bindings/input/goodix,gt911.yaml index b363cb76e2b7..1222032f7255 100644 --- a/dts/bindings/kscan/goodix,gt911.yaml +++ b/dts/bindings/input/goodix,gt911.yaml @@ -5,7 +5,7 @@ description: GT9xx / GT9xxx capacitive touch panels compatible: "goodix,gt911" -include: [kscan.yaml, i2c-device.yaml] +include: i2c-device.yaml properties: irq-gpios: diff --git a/samples/drivers/kscan/sample.yaml b/samples/drivers/kscan/sample.yaml index be0ea2e485a0..e276641711ab 100644 --- a/samples/drivers/kscan/sample.yaml +++ b/samples/drivers/kscan/sample.yaml @@ -14,15 +14,3 @@ tests: fixture: fixture_connect_keyboard depends_on: kscan filter: dt_chosen_enabled("zephyr,keyboard-scan") - sample.drivers.kscan.rk055hdmipi4m: - tags: drivers kscan - harness: console - harness_config: - type: multi_line - ordered: true - regex: - - "kb data(.*)" - fixture: fixture_connect_rk055hdmipi4m - depends_on: kscan - extra_args: SHIELD="rk055hdmipi4m" - platform_allow: mimxrt1170_evk_cm7 mimxrt595_evk_cm33 diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 746b8a6e5452..686da3a4180e 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -57,6 +57,13 @@ reg = <0x0>; int-gpios = <&test_gpio 0 0>; }; + + gt911@1 { + compatible = "goodix,gt911"; + reg = <0x1>; + irq-gpios = <&gpio0 0 0>; + reset-gpios = <&gpio0 0 0>; + }; }; spi@2 { diff --git a/tests/drivers/kscan/kscan_api/testcase.yaml b/tests/drivers/kscan/kscan_api/testcase.yaml index a4b390f73452..2f37671d4c26 100644 --- a/tests/drivers/kscan/kscan_api/testcase.yaml +++ b/tests/drivers/kscan/kscan_api/testcase.yaml @@ -14,8 +14,3 @@ tests: - kscan extra_args: CONF_FILE="mec15xxevb_assy6853.conf" platform_allow: mec15xxevb_assy6853 - drivers.kscan.rk055hdmipi4m: - tags: drivers kscan userspace - depends_on: kscan - extra_args: SHIELD="rk055hdmipi4m" - platform_allow: mimxrt1170_evk_cm7 mimxrt595_evk_cm33 From 18636af6d6658cf66e5f055901ffe2515116d329 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 13 Jul 2023 09:03:26 +0200 Subject: [PATCH 1265/2042] arm64: Add frame-pointer based stack unwinding Add the frame-pointer based stack unwinding on ARM64. This is a typical output with the feature enabled: *** Booting Zephyr OS build zephyr-v3.4.0-1029-gae22ff648c16 *** E: ELR_ELn: 0x00000000400011c8 E: ESR_ELn: 0x0000000096000046 E: EC: 0x25 (Data Abort taken without a change in Exception level) E: IL: 0x1 E: ISS: 0x46 E: FAR_ELn: 0x0000000000000000 E: TPIDRRO: 0x0100000040011650 E: x0: 0x0000000000000000 x1: 0x0000000000000003 E: x2: 0x0000000000000003 x3: 0x000000004005c6a0 E: x4: 0x0000000000000000 x5: 0x000000004005c7f0 E: x6: 0x0000000048000000 x7: 0x0000000048000000 E: x8: 0x0000000000000005 x9: 0x0000000000000000 E: x10: 0x0000000000000000 x11: 0x0000000000000000 E: x12: 0x0000000000000000 x13: 0x0000000000000000 E: x14: 0x0000000000000000 x15: 0x0000000000000000 E: x16: 0x0000000040004290 x17: 0x0000000000000000 E: x18: 0x0000000000000000 lr: 0x0000000040001208 E: E: backtrace 0: fp: 0x000000004005c690 lr: 0x0000000040001270 E: backtrace 1: fp: 0x000000004005c6b0 lr: 0x0000000040001290 E: backtrace 2: fp: 0x000000004005c7d0 lr: 0x0000000040004ac0 E: backtrace 3: fp: 0x000000004005c7f0 lr: 0x00000000400013a4 E: backtrace 4: fp: 0x000000004005c800 lr: 0x0000000000000000 E: E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 E: Current thread: 0x40011310 (unknown) E: Halting system Signed-off-by: Carlo Caione --- arch/arm64/core/Kconfig | 9 +++++++ arch/arm64/core/fatal.c | 43 +++++++++++++++++++++++++++++++ arch/arm64/core/offsets/offsets.c | 4 +++ arch/arm64/core/vector_table.S | 8 ++++++ include/zephyr/arch/arm64/exc.h | 5 +++- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index 1b0ad478595a..bd13eed7478b 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -128,6 +128,15 @@ config ARM64_SAFE_EXCEPTION_STACK used for user stack overflow checking, because kernel stack support the checking work. +config ARM64_ENABLE_FRAME_POINTER + bool + default y + depends on OVERRIDE_FRAME_POINTER_DEFAULT && !OMIT_FRAME_POINTER + help + Hidden option to simplify access to OVERRIDE_FRAME_POINTER_DEFAULT + and OMIT_FRAME_POINTER. It is automatically enabled when the frame + pointer unwinding is enabled. + config ARM64_SAFE_EXCEPTION_STACK_SIZE int "The stack size of the safe exception stack" default 4096 diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index 96211f14c67f..f986aa033e63 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -191,6 +191,45 @@ static void esf_dump(const z_arch_esf_t *esf) LOG_ERR("x16: 0x%016llx x17: 0x%016llx", esf->x16, esf->x17); LOG_ERR("x18: 0x%016llx lr: 0x%016llx", esf->x18, esf->lr); } + +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER +static void esf_unwind(const z_arch_esf_t *esf) +{ + /* + * For GCC: + * + * ^ +-----------------+ + * | | | + * | | | + * | | | + * | | | + * | | function stack | + * | | | + * | | | + * | | | + * | | | + * | +-----------------+ + * | | LR | + * | +-----------------+ + * | | previous FP | <---+ FP + * + +-----------------+ + */ + + uint64_t *fp = (uint64_t *) esf->fp; + unsigned int count = 0; + uint64_t lr; + + LOG_ERR(""); + while (fp != NULL) { + lr = fp[1]; + LOG_ERR("backtrace %2d: fp: 0x%016llx lr: 0x%016llx", + count++, (uint64_t) fp, lr); + fp = (uint64_t *) fp[0]; + } + LOG_ERR(""); +} +#endif + #endif /* CONFIG_EXCEPTION_DEBUG */ static bool is_recoverable(z_arch_esf_t *esf, uint64_t esr, uint64_t far, @@ -261,6 +300,10 @@ void z_arm64_fatal_error(unsigned int reason, z_arch_esf_t *esf) if (esf != NULL) { esf_dump(esf); } + +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER + esf_unwind(esf); +#endif /* CONFIG_ARM64_ENABLE_FRAME_POINTER */ #endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); diff --git a/arch/arm64/core/offsets/offsets.c b/arch/arm64/core/offsets/offsets.c index eb07df728e5e..4268692c498b 100644 --- a/arch/arm64/core/offsets/offsets.c +++ b/arch/arm64/core/offsets/offsets.c @@ -40,6 +40,10 @@ GEN_NAMED_OFFSET_SYM(_callee_saved_t, x27, x27_x28); GEN_NAMED_OFFSET_SYM(_callee_saved_t, x29, x29_sp_el0); GEN_NAMED_OFFSET_SYM(_callee_saved_t, sp_elx, sp_elx_lr); +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER +GEN_NAMED_OFFSET_SYM(_esf_t, fp, fp); +#endif + GEN_NAMED_OFFSET_SYM(_esf_t, spsr, spsr_elr); GEN_NAMED_OFFSET_SYM(_esf_t, x18, x18_lr); GEN_NAMED_OFFSET_SYM(_esf_t, x16, x16_x17); diff --git a/arch/arm64/core/vector_table.S b/arch/arm64/core/vector_table.S index b32e07fd6726..1a1b649d4f29 100644 --- a/arch/arm64/core/vector_table.S +++ b/arch/arm64/core/vector_table.S @@ -72,6 +72,10 @@ _ASM_FILE_PROLOGUE .endif #endif +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER + str x29, [sp, ___esf_t_fp_OFFSET] +#endif + mrs \xreg0, spsr_el1 mrs \xreg1, elr_el1 stp \xreg0, \xreg1, [sp, ___esf_t_spsr_elr_OFFSET] @@ -335,6 +339,10 @@ SECTION_FUNC(TEXT, z_arm64_exit_exc) ldp x16, x17, [sp, ___esf_t_x16_x17_OFFSET] ldp x18, lr, [sp, ___esf_t_x18_lr_OFFSET] +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER + ldr x29, [sp, ___esf_t_fp_OFFSET] +#endif + add sp, sp, ___esf_t_SIZEOF /* diff --git a/include/zephyr/arch/arm64/exc.h b/include/zephyr/arch/arm64/exc.h index ccbb903360cb..f4145f449779 100644 --- a/include/zephyr/arch/arm64/exc.h +++ b/include/zephyr/arch/arm64/exc.h @@ -47,10 +47,13 @@ struct __esf { uint64_t lr; uint64_t spsr; uint64_t elr; +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER + uint64_t fp; +#endif #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK uint64_t sp; #endif -} __aligned(16); +} __packed __aligned(16); typedef struct __esf z_arch_esf_t; From db939b6650c7018065ab9aa04afb2e0c4591a213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 15:19:15 +0200 Subject: [PATCH 1266/2042] lib: os: doc: fix sys_hashmap_api doc typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for sys_hashmap_api has an extra (leftover?) param. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_map_api.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/zephyr/sys/hash_map_api.h b/include/zephyr/sys/hash_map_api.h index cbdb065ce2cd..c677bd4c534c 100644 --- a/include/zephyr/sys/hash_map_api.h +++ b/include/zephyr/sys/hash_map_api.h @@ -164,7 +164,6 @@ typedef bool (*sys_hashmap_get_t)(const struct sys_hashmap *map, uint64_t key, u * @brief Generic Hashmap API * * @param iter Iterator constructor (in-place) - * @param next Forward-incrementer for iterator * @param clear Clear the hash table, freeing all resources * @param insert Insert a key-value pair into the Hashmap * @param remove Remove a key-value pair from the Hashmap From ad0f2a697ccc45d11a1c89b706c28d058e21d9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 15:24:09 +0200 Subject: [PATCH 1267/2042] lib: os: doc: cleanup Doxygen doc for structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Doxygen comments for structs. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_map_api.h | 40 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/include/zephyr/sys/hash_map_api.h b/include/zephyr/sys/hash_map_api.h index c677bd4c534c..9e2b88c675c1 100644 --- a/include/zephyr/sys/hash_map_api.h +++ b/include/zephyr/sys/hash_map_api.h @@ -37,22 +37,21 @@ extern "C" { * * @note @a next should not be used without first checking * @ref sys_hashmap_iterator_has_next - * - * @param map Pointer to the associated Hashmap - * @param next Modify the iterator in-place to point to the next Hashmap entry - * @param state Implementation-specific iterator state - * @param key Key associated with the current entry - * @param value Value associated with the current entry - * @param size Number of entries in the map - * @param pos Number of entries already iterated */ struct sys_hashmap_iterator { + /** Pointer to the associated Hashmap */ const struct sys_hashmap *map; + /** Modify the iterator in-place to point to the next Hashmap entry */ void (*next)(struct sys_hashmap_iterator *it); + /** Implementation-specific iterator state */ void *state; + /** Key associated with the current entry */ uint64_t key; + /** Value associated with the current entry */ uint64_t value; + /** Number of entries in the map */ const size_t size; + /** Number of entries already iterated */ size_t pos; }; @@ -162,18 +161,17 @@ typedef bool (*sys_hashmap_get_t)(const struct sys_hashmap *map, uint64_t key, u /** * @brief Generic Hashmap API - * - * @param iter Iterator constructor (in-place) - * @param clear Clear the hash table, freeing all resources - * @param insert Insert a key-value pair into the Hashmap - * @param remove Remove a key-value pair from the Hashmap - * @param get Retrieve a the value associated with a given key from the Hashmap */ struct sys_hashmap_api { + /** Iterator constructor (in-place) */ sys_hashmap_iterator_t iter; + /** Clear the hash table, freeing all resources */ sys_hashmap_clear_t clear; + /** Insert a key-value pair into the Hashmap */ sys_hashmap_insert_t insert; + /** Remove a key-value pair from the Hashmap */ sys_hashmap_remove_t remove; + /** Retrieve the value associated with a given key from the Hashmap */ sys_hashmap_get_t get; }; @@ -192,14 +190,13 @@ struct sys_hashmap_api { * The @a initial_n_buckets is defined as the number of buckets to allocate * when moving from size 0 to size 1 such that the maximum @a load_factor * property is preserved. - * - * @param max_size Maximum number of entries - * @param load_factor Maximum load factor of expressed in hundredths - * @param initial_n_buckets Initial number of buckets to allocate */ struct sys_hashmap_config { + /** Maximum number of entries */ size_t max_size; + /** Maximum load factor expressed in hundredths */ uint8_t load_factor; + /** Initial number of buckets to allocate */ uint8_t initial_n_buckets; }; @@ -221,14 +218,13 @@ struct sys_hashmap_config { * @brief Generic Hashmap data * * @note When @a size is zero, @a buckets should be `NULL`. - * - * @param buckets Pointer for implementation-specific Hashmap storage - * @param n_buckets The number of buckets currently allocated - * @param size The number of entries currently in the Hashmap */ struct sys_hashmap_data { + /** Pointer for implementation-specific Hashmap storage */ void *buckets; + /** The number of buckets currently allocated */ size_t n_buckets; + /** The number of entries currently in the Hashmap */ size_t size; }; From 8c32950de9873d34e8b72bb0c4096f2694809a91 Mon Sep 17 00:00:00 2001 From: ferar alashkar Date: Fri, 26 May 2023 16:35:16 -0400 Subject: [PATCH 1268/2042] device: add explicit macro/variable unsigned suffix add explicit unsigned suffix to 'Z_DEVICE_MAX_NAME_LEN' macro, matching it to return type of sizeof (size_t), thus the comparison operator '<=' has the same essential types, complying with required [misra-c2012-10.4] rule which states; Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category. Found as a coding guideline violation (Rule 10.4) by static code scanning tool. Note: Tested on STM32L5 Nucleo-144 board (stm32l552xx). Signed-off-by: ferar alashkar --- include/zephyr/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index b9bff1c603a7..2ea95a2d563a 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -854,7 +854,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * The maximum length is set so that device_get_binding() can be used from * userspace. */ -#define Z_DEVICE_MAX_NAME_LEN 48 +#define Z_DEVICE_MAX_NAME_LEN 48U /** * @brief Compile time check for device name length From 7b1b2576ac9a9ffa3dee03f137e6812c2edcbdbb Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 27 Jun 2022 23:43:32 -0400 Subject: [PATCH 1269/2042] kernel: support dynamic thread stack allocation Add support for dynamic thread stack allocation Signed-off-by: Christopher Friedt --- include/zephyr/kernel.h | 29 +++++++ kernel/CMakeLists.txt | 6 ++ kernel/Kconfig | 62 +++++++++++++++ kernel/dynamic.c | 162 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 kernel/dynamic.c diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index d3a435a4d38a..9a88baeb5bdf 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -265,6 +265,35 @@ extern void k_thread_foreach_unlocked( /* end - thread options */ #if !defined(_ASMLANGUAGE) +/** + * @brief Dynamically allocate a thread stack. + * + * Relevant stack creation flags include: + * - @ref K_USER allocate a userspace thread (requires `CONFIG_USERSPACE=y`) + * + * @param size Stack size in bytes. + * @param flags Stack creation flags, or 0. + * + * @retval the allocated thread stack on success. + * @retval NULL on failure. + * + * @see CONFIG_DYNAMIC_THREAD + */ +__syscall k_thread_stack_t *k_thread_stack_alloc(size_t size, int flags); + +/** + * @brief Free a dynamically allocated thread stack. + * + * @param stack Pointer to the thread stack. + * + * @retval 0 on success. + * @retval -EBUSY if the thread stack is in use. + * @retval -EINVAL if @p stack is invalid. + * + * @see CONFIG_DYNAMIC_THREAD + */ +__syscall int k_thread_stack_free(k_thread_stack_t *stack); + /** * @brief Create a thread. * diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 7b4781e4fd33..82427e83ba88 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -122,6 +122,12 @@ target_sources_ifdef( userspace.c ) +target_sources_ifdef( + CONFIG_DYNAMIC_THREAD + kernel PRIVATE + dynamic.c + ) + target_include_directories(kernel PRIVATE ${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include diff --git a/kernel/Kconfig b/kernel/Kconfig index e553553b1c74..12cd7b8f836b 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -203,6 +203,68 @@ config THREAD_USERSPACE_LOCAL_DATA depends on USERSPACE default y if ERRNO && !ERRNO_IN_TLS +config DYNAMIC_THREAD + bool "Support for dynamic threads [EXPERIMENTAL]" + select EXPERIMENTAL + depends on THREAD_STACK_INFO + select DYNAMIC_OBJECTS if USERSPACE + help + Enable support for dynamic threads and stacks. + +if DYNAMIC_THREAD + +config DYNAMIC_THREAD_STACK_SIZE + int "Size of each pre-allocated thread stack" + default 1024 if !64BIT + default 2048 if 64BIT + help + Default stack size (in bytes) for dynamic threads. + +config DYNAMIC_THREAD_ALLOC + bool "Support heap-allocated thread objects and stacks" + help + Select this option to enable allocating thread object and + thread stacks from the system heap. + + Only use this type of allocation in situations + where malloc is permitted. + +config DYNAMIC_THREAD_POOL_SIZE + int "Number of statically pre-allocated threads" + default 0 + range 0 8192 + help + Pre-allocate a fixed number of thread objects and + stacks at build time. + + This type of "dynamic" stack is usually suitable in + situations where malloc is not permitted. + +choice DYNAMIC_THREAD_PREFER + prompt "Preferred dynamic thread allocator" + default DYNAMIC_THREAD_PREFER_POOL + help + If both CONFIG_DYNAMIC_THREAD_ALLOC=y and + CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0, then the user may + specify the order in which allocation is attmpted. + +config DYNAMIC_THREAD_PREFER_ALLOC + bool "Prefer heap-based allocation" + depends on DYNAMIC_THREAD_ALLOC + help + Select this option to attempt a heap-based allocation + prior to any pool-based allocation. + +config DYNAMIC_THREAD_PREFER_POOL + bool "Prefer pool-based allocation" + help + Select this option to attempt a pool-based allocation + prior to any heap-based allocation. + +endchoice # DYNAMIC_THREAD_PREFER + +endif # DYNAMIC_THREADS + config LIBC_ERRNO bool help diff --git a/kernel/dynamic.c b/kernel/dynamic.c new file mode 100644 index 000000000000..6f9c1f6adcfe --- /dev/null +++ b/kernel/dynamic.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2022, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "kernel_internal.h" + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +#if CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0 +#define BA_SIZE CONFIG_DYNAMIC_THREAD_POOL_SIZE +#else +#define BA_SIZE 1 +#endif + +struct dyn_cb_data { + k_tid_t tid; + k_thread_stack_t *stack; +}; + +static K_THREAD_STACK_ARRAY_DEFINE(dynamic_stack, CONFIG_DYNAMIC_THREAD_POOL_SIZE, + CONFIG_DYNAMIC_THREAD_STACK_SIZE); +SYS_BITARRAY_DEFINE_STATIC(dynamic_ba, BA_SIZE); + +static k_thread_stack_t *z_thread_stack_alloc_dyn(size_t align, size_t size) +{ + return z_thread_aligned_alloc(align, size); +} + +static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size) +{ + int rv; + size_t offset; + k_thread_stack_t *stack; + + if (size > CONFIG_DYNAMIC_THREAD_STACK_SIZE) { + LOG_DBG("stack size %zu is > pool stack size %d", size, + CONFIG_DYNAMIC_THREAD_STACK_SIZE); + return NULL; + } + + rv = sys_bitarray_alloc(&dynamic_ba, 1, &offset); + if (rv < 0) { + LOG_DBG("unable to allocate stack from pool"); + return NULL; + } + + __ASSERT_NO_MSG(offset < CONFIG_DYNAMIC_THREAD_POOL_SIZE); + + stack = (k_thread_stack_t *)&dynamic_stack[offset]; + + return stack; +} + +k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) +{ + size_t align = 0; + size_t obj_size = 0; + k_thread_stack_t *stack = NULL; + +#ifdef CONFIG_USERSPACE + if ((flags & K_USER) != 0) { + align = Z_THREAD_STACK_OBJ_ALIGN(size); + obj_size = Z_THREAD_STACK_SIZE_ADJUST(size); + } else +#endif + { + align = Z_KERNEL_STACK_OBJ_ALIGN; + obj_size = Z_KERNEL_STACK_SIZE_ADJUST(size); + } + + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) { + stack = z_thread_stack_alloc_dyn(align, obj_size); + if (stack == NULL && CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { + stack = z_thread_stack_alloc_pool(size); + } + } else if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL) && + CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { + stack = z_thread_stack_alloc_pool(size); + if (stack == NULL && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + stack = z_thread_stack_alloc_dyn(align, obj_size); + } + } else { + return NULL; + } + + return stack; +} + +#ifdef CONFIG_USERSPACE +static inline k_thread_stack_t *z_vrfy_k_thread_stack_alloc(size_t size, int flags) +{ + return z_impl_k_thread_stack_alloc(size, flags); +} +#include +#endif + +static void dyn_cb(const struct k_thread *thread, void *user_data) +{ + struct dyn_cb_data *const data = (struct dyn_cb_data *)user_data; + + if (data->stack == (k_thread_stack_t *)thread->stack_info.start) { + __ASSERT(data->tid == NULL, "stack %p is associated with more than one thread!"); + data->tid = (k_tid_t)thread; + } +} + +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)) { + LOG_ERR("tid %p is in use!", data.tid); + return -EBUSY; + } + } + + if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { + if (IS_ARRAY_ELEMENT(dynamic_stack, stack)) { + if (sys_bitarray_free(&dynamic_ba, 1, ARRAY_INDEX(dynamic_stack, stack))) { + LOG_ERR("stack %p is not allocated!", stack); + return -EINVAL; + } + + return 0; + } + } + + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + k_free(stack); + } else { + LOG_ERR("Invalid stack %p", stack); + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +static inline int z_vrfy_k_thread_stack_free(k_thread_stack_t *stack) +{ + return z_impl_k_thread_stack_free(stack); +} +#include +#endif From 1323b1ac6071460b46f18e69cf4fcbca93ed4fa0 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 27 Jun 2022 23:43:38 -0400 Subject: [PATCH 1270/2042] tests: kernel: threads: add a testcase for dynamic thread stacks Test that automatic thread stack allocation works for both user and kernel threads. Signed-off-by: Christopher Friedt --- .../dynamic_thread_stack/CMakeLists.txt | 8 + .../threads/dynamic_thread_stack/prj.conf | 14 ++ .../threads/dynamic_thread_stack/src/main.c | 142 ++++++++++++++++++ .../dynamic_thread_stack/testcase.yaml | 76 ++++++++++ 4 files changed, 240 insertions(+) create mode 100644 tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt create mode 100644 tests/kernel/threads/dynamic_thread_stack/prj.conf create mode 100644 tests/kernel/threads/dynamic_thread_stack/src/main.c create mode 100644 tests/kernel/threads/dynamic_thread_stack/testcase.yaml diff --git a/tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt b/tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt new file mode 100644 index 000000000000..871a66a45279 --- /dev/null +++ b/tests/kernel/threads/dynamic_thread_stack/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(dynamic_thread_stack) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/kernel/threads/dynamic_thread_stack/prj.conf b/tests/kernel/threads/dynamic_thread_stack/prj.conf new file mode 100644 index 000000000000..4377c2ec60b4 --- /dev/null +++ b/tests/kernel/threads/dynamic_thread_stack/prj.conf @@ -0,0 +1,14 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_INIT_STACKS=y +CONFIG_THREAD_STACK_INFO=y +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=16384 +CONFIG_ZTEST_STACK_SIZE=2048 +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_HW_STACK_PROTECTION=n +CONFIG_TEST_HW_STACK_PROTECTION=n diff --git a/tests/kernel/threads/dynamic_thread_stack/src/main.c b/tests/kernel/threads/dynamic_thread_stack/src/main.c new file mode 100644 index 000000000000..86848e4249ee --- /dev/null +++ b/tests/kernel/threads/dynamic_thread_stack/src/main.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2022, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define TIMEOUT_MS 500 + +#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) + +ZTEST_DMEM bool flag[CONFIG_DYNAMIC_THREAD_POOL_SIZE]; + +static void func(void *arg1, void *arg2, void *arg3) +{ + bool *flag = (bool *)arg1; + + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + printk("Hello, dynamic world!\n"); + + *flag = true; +} + +/** @brief Exercise the pool-based thread stack allocator */ +ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_pool) +{ + static k_tid_t tid[CONFIG_DYNAMIC_THREAD_POOL_SIZE]; + static struct k_thread th[CONFIG_DYNAMIC_THREAD_POOL_SIZE]; + static k_thread_stack_t *stack[CONFIG_DYNAMIC_THREAD_POOL_SIZE]; + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL)) { + ztest_test_skip(); + } + + /* allocate all thread stacks from the pool */ + for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) { + stack[i] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0); + + zassert_not_null(stack[i]); + } + + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + /* ensure 1 thread can be allocated from the heap when the pool is depleted */ + zassert_ok(k_thread_stack_free( + k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0))); + } else { + /* ensure that no more thread stacks can be allocated from the pool */ + zassert_is_null(k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0)); + } + + /* spawn our threads */ + for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) { + tid[i] = k_thread_create(&th[i], stack[i], + CONFIG_DYNAMIC_THREAD_STACK_SIZE, func, + &flag[i], NULL, NULL, 0, + K_USER | K_INHERIT_PERMS, K_NO_WAIT); + } + + /* join all threads and check that flags have been set */ + for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) { + zassert_ok(k_thread_join(tid[i], K_MSEC(TIMEOUT_MS))); + zassert_true(flag[i]); + } + + /* clean up stacks allocated from the pool */ + for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) { + zassert_ok(k_thread_stack_free(stack[i])); + } +} + +/** @brief Exercise the heap-based thread stack allocator */ +ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc) +{ + size_t N; + static k_tid_t tid[MAX_HEAP_STACKS]; + static bool flag[MAX_HEAP_STACKS]; + static struct k_thread th[MAX_HEAP_STACKS]; + static k_thread_stack_t *stack[MAX_HEAP_STACKS]; + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) { + ztest_test_skip(); + } + + if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + ztest_test_skip(); + } + + /* allocate all thread stacks from the heap */ + for (N = 0; N < MAX_HEAP_STACKS; ++N) { + stack[N] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0); + zassert_not_null(stack[N]); + } + + if (CONFIG_DYNAMIC_THREAD_POOL_SIZE == 0) { + /* ensure that no more thread stacks can be allocated from the heap */ + zassert_is_null(k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, + IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0)); + } + + /* spwan our threads */ + for (size_t i = 0; i < N; ++i) { + tid[i] = k_thread_create(&th[i], stack[i], 0, func, &flag[i], NULL, NULL, 0, + K_USER | K_INHERIT_PERMS, K_NO_WAIT); + } + + /* join all threads and check that flags have been set */ + for (size_t i = 0; i < N; ++i) { + zassert_ok(k_thread_join(tid[i], K_MSEC(TIMEOUT_MS))); + zassert_true(flag[i]); + } + + /* clean up stacks allocated from the heap */ + for (size_t i = 0; i < N; ++i) { + zassert_ok(k_thread_stack_free(stack[i])); + } +} + +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 + + return NULL; +} + +ZTEST_SUITE(dynamic_thread_stack, NULL, dynamic_thread_stack_setup, NULL, NULL, NULL); diff --git a/tests/kernel/threads/dynamic_thread_stack/testcase.yaml b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml new file mode 100644 index 000000000000..3bf7d892b579 --- /dev/null +++ b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml @@ -0,0 +1,76 @@ +common: + tags: kernel security + min_ram: 32 + integration_platforms: + - qemu_x86 + - qemu_x86_nommu + - qemu_x86_64 + - qemu_cortex_a53 + - qemu_cortex_a53_smp + - qemu_cortex_m3 + - qemu_riscv32 + - qemu_riscv32e + - qemu_riscv64 + - qemu_riscv64_smp + +# Permutations of (pool | alloc | user) +tests: + kernel.threads.dynamic_thread.stack.no_pool.no_alloc.no_user: + extra_configs: + # 000 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + - CONFIG_DYNAMIC_THREAD_ALLOC=n + - CONFIG_USERSPACE=n + + # kernel.threads.dynamic_thread.stack.no_pool.no_alloc.user: + # tags: userspace + # extra_configs: + # # 001 + # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + # - CONFIG_DYNAMIC_THREAD_ALLOC=n + # - CONFIG_USERSPACE=y + + kernel.threads.dynamic_thread.stack.no_pool.alloc.no_user: + extra_configs: + # 010 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_USERSPACE=n + + # kernel.threads.dynamic_thread.stack.no_pool.alloc.user: + # tags: userspace + # extra_configs: + # # 011 + # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + # - CONFIG_DYNAMIC_THREAD_ALLOC=y + # - CONFIG_USERSPACE=y + + kernel.threads.dynamic_thread.stack.pool.no_alloc.no_user: + extra_configs: + # 100 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 + - CONFIG_DYNAMIC_THREAD_ALLOC=n + - CONFIG_USERSPACE=n + + # kernel.threads.dynamic_thread.stack.pool.no_alloc.user: + # tags: userspace + # extra_configs: + # # 101 + # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 + # - CONFIG_DYNAMIC_THREAD_ALLOC=n + # - CONFIG_USERSPACE=y + + kernel.threads.dynamic_thread.stack.pool.alloc.no_user: + extra_configs: + # 110 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 + - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_USERSPACE=n + +# kernel.threads.dynamic_thread.stack.pool.alloc.user: +# tags: userspace +# extra_configs: +# # 111 +# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 +# - CONFIG_DYNAMIC_THREAD_ALLOC=y +# - CONFIG_USERSPACE=y From 44dd4114db4c165ba977ae0d856aa230bd21d22a Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 13 Jul 2023 17:52:09 +0200 Subject: [PATCH 1271/2042] arm64: Remove __packed from ESF Packing the ESF is actually wrong, remove the attribute. Signed-off-by: Carlo Caione --- include/zephyr/arch/arm64/exc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/arch/arm64/exc.h b/include/zephyr/arch/arm64/exc.h index f4145f449779..5a46671d157b 100644 --- a/include/zephyr/arch/arm64/exc.h +++ b/include/zephyr/arch/arm64/exc.h @@ -53,7 +53,7 @@ struct __esf { #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK uint64_t sp; #endif -} __packed __aligned(16); +} __aligned(16); typedef struct __esf z_arch_esf_t; From 440af3ecc887b01c485da93f3bbb037f441efe4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Thu, 13 Jul 2023 15:17:44 +0200 Subject: [PATCH 1272/2042] modules: hal_nordic: nrfx: Make ISO IN ZLP configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nRF USBD ISOINCONFIG register controls USBD behavior after receiving IN token addressed to ISO IN endpoint when the endpoint was not armed with data. The options are: * NoResp, in which case there is no response (i.e. bus timeout) * ZeroData, in which case device responds with ZLP This commit both makes the ISOINCONFIG value configurable and changes the default from NoResp to ZeroData. For reference, DWC_otg controller will always send ZLP in such case and does not have NoResp equivalent. Automatically sending ZLP when ISO IN endpoint is not armed resolves periodic audio dropouts observed on Mac OS with USB Audio headset sample. Apple USB Audio class driver will attempt recovery (abort all pending URBs, switch to alternate config 0, switch to active alternate config and submit new URBs) every time it sees kIOReturnNotResponding status code. During recovery no audio data can be transferred and therefore there are gaps in the audio stream. Apple USB Audio driver sees kIOReturnNotResponding when there is bus timeout (i.e. IN token was sent to nRF when the endpoint was not armed and NoResp option was active). Activating ZeroData option results in perfectly fine (albeit short) packet that does not trigger interface recovery and thus fixes the USB Audio issues on Mac OS. Signed-off-by: Tomasz Moń --- modules/hal_nordic/nrfx/Kconfig | 9 +++++++++ modules/hal_nordic/nrfx/nrfx_config.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index a681d64d5303..3a7517d86560 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -381,6 +381,15 @@ config NRFX_USBD bool "USBD driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_USBD)) +config NRFX_USBD_ISO_IN_ZLP + bool "Send ZLP on ISO IN when not ready" + depends on NRFX_USBD + default y + help + Controls the response of the ISO IN endpoint to an IN token when no + data is ready to be sent. When enabled, ZLP is sent when no data is + ready. When disabled, no response is sent (bus timeout occurs). + 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 511b4db4570c..049d5c687170 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -364,6 +364,10 @@ #define NRFX_USBD_ENABLED 1 #endif +#ifdef CONFIG_NRFX_USBD_ISO_IN_ZLP +#define NRFX_USBD_CONFIG_ISO_IN_ZLP 1 +#endif + #ifdef CONFIG_NRFX_USBREG #define NRFX_USBREG_ENABLED 1 #endif From cc81dca5566c5cddbb8a92675579398dae01740d Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 13 Jul 2023 13:33:16 +0200 Subject: [PATCH 1273/2042] net: if: Fix if_ipv4_get_addr() locking net_if_lock() should be called only after iface pointer is verified not to be NULL, otherwise we can end up dereferencing NULL pointer in certain corner cases. Signed-off-by: Robert Lubos --- subsys/net/ip/net_if.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 9ae49b5830af..62ebe17eefaf 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -3285,12 +3285,12 @@ static struct in_addr *if_ipv4_get_addr(struct net_if *iface, struct net_if_ipv4 *ipv4; int i; - net_if_lock(iface); - if (!iface) { - goto out; + return NULL; } + net_if_lock(iface); + ipv4 = iface->config.ip.ipv4; if (!ipv4) { goto out; From c15e3d448c0ec801a48ba7683fe14c0c22a39caf Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 11 Jul 2023 14:05:28 +0200 Subject: [PATCH 1274/2042] net: conn_mgr: Create conn_mgr thread dynamically Statically created threads with K_THREAD_DEFINE() are launched only after the SYS_INIT phase. This does not play well with NET_CONFIG library, which may block during SYS_INIT until network interface is UP and RUNNING. In order to be able to connect to L2 network and thus mark the network interface as running and unblock NET_CONFIG, we need to be able to run conn_mgr thread during SYS_INIT. This can be achieved, by starting the thread dynamically during SYS_INIT phase, instead of relying on static thread creation. Signed-off-by: Robert Lubos --- subsys/net/conn_mgr/conn_mgr.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/subsys/net/conn_mgr/conn_mgr.c b/subsys/net/conn_mgr/conn_mgr.c index b202c8745664..3374a1acf604 100644 --- a/subsys/net/conn_mgr/conn_mgr.c +++ b/subsys/net/conn_mgr/conn_mgr.c @@ -23,6 +23,10 @@ LOG_MODULE_REGISTER(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_LOG_LEVEL); #define THREAD_PRIORITY K_PRIO_PREEMPT(7) #endif +static K_THREAD_STACK_DEFINE(conn_mgr_thread_stack, + CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE); +static struct k_thread conn_mgr_thread; + /* Internal state array tracking readiness, flags, and other state information for all available * ifaces. Note that indexing starts at 0, whereas Zephyr iface indices start at 1. * conn_mgr_get_if_by_index and conn_mgr_get_index_for_if are used to go back and forth between @@ -212,10 +216,6 @@ static void conn_mgr_handler(void) } } -K_THREAD_DEFINE(conn_mgr, CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE, - (k_thread_entry_t)conn_mgr_handler, NULL, NULL, NULL, - THREAD_PRIORITY, 0, 0); - void conn_mgr_resend_status(void) { k_mutex_lock(&conn_mgr_lock, K_FOREVER); @@ -326,12 +326,14 @@ static int conn_mgr_init(void) { int i; - for (i = 0; i < ARRAY_SIZE(iface_states); i++) { iface_states[i] = 0; } - k_thread_start(conn_mgr); + k_thread_create(&conn_mgr_thread, conn_mgr_thread_stack, + CONFIG_NET_CONNECTION_MANAGER_STACK_SIZE, + (k_thread_entry_t)conn_mgr_handler, + NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT); return 0; } From 24759511f4e94807c7d4c695cb460110254e42ae Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Thu, 13 Jul 2023 14:17:11 +0530 Subject: [PATCH 1275/2042] drivers: uart: Add support for UART_NS16550 TI K3 variant TI K3 family of SoCs requires an extended set of registers to operate. Extended functionality of the current driver to support the variant. Signed-off-by: L Lakshmanan --- drivers/serial/Kconfig.ns16550 | 7 +++++++ drivers/serial/uart_ns16550.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index bef4e778d6e7..22988f5f699f 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -82,6 +82,13 @@ config UART_NS16550_PARENT_INIT_LEVEL 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 + Enabling this configuration allows the users to use the UART port in + Texas Instruments K3 SoCs by enabling a vendor specific extended register + set. + menu "NS16550 Workarounds" config UART_NS16550_WA_ISR_REENABLE_INTERRUPT diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 0456b354c4e5..885c38389280 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -68,6 +68,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define REG_MSR 0x06 /* Modem status reg. */ #define REG_DLF 0xC0 /* Divisor Latch Fraction */ #define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */ +#define REG_MDR1 0x08 /* Mode control reg. (TI_K3) */ /* equates for interrupt enable register */ @@ -99,6 +100,22 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define PCP_UPDATE 0x80000000 /* update clock */ #define PCP_EN 0x00000001 /* enable clock output */ +/* Fields for TI K3 UART module */ + +#define MDR1_MODE_SELECT_FIELD_MASK BIT_MASK(3) +#define MDR1_MODE_SELECT_FIELD_SHIFT BIT_MASK(0) + +/* Modes available for TI K3 UART module */ + +#define MDR1_STD_MODE (0) +#define MDR1_SIR_MODE (1) +#define MDR1_UART_16X (2) +#define MDR1_UART_13X (3) +#define MDR1_MIR_MODE (4) +#define MDR1_FIR_MODE (5) +#define MDR1_CIR_MODE (6) +#define MDR1_DISABLE (7) + /* * Per PC16550D (Literature Number: SNLS378B): * @@ -199,6 +216,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define MDC(dev) (get_port(dev) + REG_MDC * reg_interval(dev)) #define LSR(dev) (get_port(dev) + REG_LSR * reg_interval(dev)) #define MSR(dev) (get_port(dev) + REG_MSR * reg_interval(dev)) +#define MDR1(dev) (get_port(dev) + REG_MDR1 * reg_interval(dev)) #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) @@ -421,6 +439,13 @@ static int uart_ns16550_configure(const struct device *dev, } #endif +#ifdef CONFIG_UART_NS16550_TI_K3 + uint32_t mdr = ns16550_inbyte(dev_cfg, MDR1(dev)); + + mdr = ((mdr & ~MDR1_MODE_SELECT_FIELD_MASK) | ((((MDR1_STD_MODE) << + MDR1_MODE_SELECT_FIELD_SHIFT)) & MDR1_MODE_SELECT_FIELD_MASK)); + ns16550_outbyte(dev_cfg, MDR1(dev), mdr); +#endif /* * set clock frequency from clock_frequency property if valid, * otherwise, get clock frequency from clock manager From 8fca1cdb29290434e0b98f51f0e7fbd31ce06c34 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Thu, 13 Jul 2023 11:56:00 +0530 Subject: [PATCH 1276/2042] drivers: mm: Fix macro call in RAT driver The macro used in an assert statement in the `sys_mm_drv_page_phys_get()` function was using an older version of the naming scheme, fixed now. Signed-off-by: L Lakshmanan --- drivers/mm/mm_drv_ti_rat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mm/mm_drv_ti_rat.c b/drivers/mm/mm_drv_ti_rat.c index e21561e079fb..da085b72f233 100644 --- a/drivers/mm/mm_drv_ti_rat.c +++ b/drivers/mm/mm_drv_ti_rat.c @@ -104,7 +104,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) uint32_t found, regionId; - __ASSERT(translate_config.num_regions < address_trans_MAX_REGIONS, + __ASSERT(translate_config.num_regions < ADDR_TRANSLATE_MAX_REGIONS, "Exceeding maximum number of regions"); found = 0; From 81c1f19f1b3d63aa29c3b4c5af43c4aba8903a5a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 11:43:19 +0200 Subject: [PATCH 1277/2042] net: l2: ieee802154: shell set_ext_addr test coverage Introduces an integration test that covers the set_ext_addr shell command. Signed-off-by: Florian Grandel --- .../l2/src/ieee802154_fake_driver.c | 6 ++-- .../ieee802154/l2/src/ieee802154_shell_test.c | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c index 27dd161ad019..0d3d15d6c698 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c +++ b/tests/net/ieee802154/l2/src/ieee802154_fake_driver.c @@ -22,6 +22,8 @@ LOG_MODULE_REGISTER(net_ieee802154_fake_driver, LOG_LEVEL_DBG); struct net_pkt *current_pkt; K_SEM_DEFINE(driver_lock, 0, UINT_MAX); +uint8_t mock_ext_addr_be[8] = {0x00, 0x12, 0x4b, 0x00, 0x00, 0x9e, 0xa3, 0xc2}; + static enum ieee802154_hw_caps fake_get_capabilities(const struct device *dev) { return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ; @@ -120,10 +122,8 @@ static int fake_stop(const struct device *dev) static void fake_iface_init(struct net_if *iface) { struct ieee802154_context *ctx = net_if_l2_data(iface); - static uint8_t mac[8] = { 0x00, 0x12, 0x4b, 0x00, - 0x00, 0x9e, 0xa3, 0xc2 }; - net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154); + net_if_set_link_addr(iface, mock_ext_addr_be, 8, NET_LINK_IEEE802154); ieee802154_init(iface); diff --git a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c index 359f17d75c72..6738bcc86dae 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(net_ieee802154_mgmt_test, LOG_LEVEL_DBG); extern struct net_pkt *current_pkt; extern struct k_sem driver_lock; +extern uint8_t mock_ext_addr_be[8]; static struct net_if *iface; @@ -39,6 +40,8 @@ K_SEM_DEFINE(scan_lock, 0, 1); #define EXPECTED_COORDINATOR_ADDR_BE 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08 #define EXPECTED_COORDINATOR_ADDR_STR "0f:0e:0d:0c:0b:0a:09:08" +#define EXPECTED_ENDDEVICE_EXT_ADDR_LE 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +#define EXPECTED_ENDDEVICE_EXT_ADDR_STR "08:07:06:05:04:03:02:01" #define EXPECTED_ENDDEVICE_SHORT_ADDR 0xaaaa static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, @@ -256,6 +259,31 @@ ZTEST(ieee802154_l2_shell, test_associate) ztest_test_fail(); } +ZTEST(ieee802154_l2_shell, test_set_ext_addr) +{ + uint8_t expected_ext_addr_le[] = {EXPECTED_ENDDEVICE_EXT_ADDR_LE}; + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint8_t initial_ext_addr_le[sizeof(mock_ext_addr_be)]; + int ret; + + sys_memcpy_swap(initial_ext_addr_le, mock_ext_addr_be, sizeof(initial_ext_addr_le)); + zassert_equal(ctx->pan_id, IEEE802154_PAN_ID_NOT_ASSOCIATED, + "Setting Ext Addr: PAN should not be set initially."); + zassert_equal(ctx->short_addr, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED, + "Setting Ext Addr: Short addr should not be set initially."); + zassert_mem_equal(ctx->ext_addr, initial_ext_addr_le, sizeof(ctx->coord_ext_addr), + "Setting Ext Addr: Ext addr should be the mock addr initially."); + + ret = shell_execute_cmd(NULL, "ieee802154 set_ext_addr " EXPECTED_ENDDEVICE_EXT_ADDR_STR); + zassert_equal(0, ret, "Setting the external address failed: %d", ret); + + zassert_mem_equal( + ctx->ext_addr, expected_ext_addr_le, sizeof(ctx->coord_ext_addr), + "Setting Ext Addr: failed."); + + memcpy(ctx->ext_addr, initial_ext_addr_le, sizeof(ctx->ext_addr)); +} + static void reset_fake_driver(void *test_fixture) { struct ieee802154_context *ctx; From 111a87efb1a06bb839e9ce0738905d4a5e6f1f25 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 14:09:12 +0200 Subject: [PATCH 1278/2042] net: l2: ieee802154: test enddevice disassociation Adds test coverage for the disassociation shell command that disassociates the enddevice by notifying its coordinator. Signed-off-by: Florian Grandel --- .../ieee802154/l2/src/ieee802154_shell_test.c | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c index 6738bcc86dae..770b47d30007 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c @@ -39,6 +39,7 @@ K_SEM_DEFINE(scan_lock, 0, 1); #define EXPECTED_COORDINATOR_ADDR_LE 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f #define EXPECTED_COORDINATOR_ADDR_BE 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08 #define EXPECTED_COORDINATOR_ADDR_STR "0f:0e:0d:0c:0b:0a:09:08" +#define EXPECTED_COORDINATOR_SHORT_ADDR 0xbbbb #define EXPECTED_ENDDEVICE_EXT_ADDR_LE 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 #define EXPECTED_ENDDEVICE_EXT_ADDR_STR "08:07:06:05:04:03:02:01" @@ -99,6 +100,25 @@ static void test_association_request(struct ieee802154_mpdu *mpdu) "Association Request: fast association is not supported."); } +static void test_disassociation_notification(struct ieee802154_mpdu *mpdu) +{ + struct ieee802154_command *cmd = mpdu->command; + + zassert_equal(mpdu->mhr.fs->fc.frame_version, IEEE802154_VERSION_802154_2006, + "Disassociation Notification: currently only IEEE 802.15.4 2006 frame " + "version supported."); + zassert_equal(mpdu->mhr.fs->fc.frame_type, IEEE802154_FRAME_TYPE_MAC_COMMAND, + "Disassociation Notification: should be a MAC command."); + zassert_equal(mpdu->mhr.fs->fc.ar, true, "Disassociation Notification: must request ACK."); + zassert_equal(mpdu->payload_length, 1U + IEEE802154_CMD_DISASSOC_NOTE_LENGTH); + + zassert_equal(cmd->cfi, IEEE802154_CFI_DISASSOCIATION_NOTIFICATION, + "Disassociation Notification: unexpected CFI."); + zassert_equal( + cmd->disassoc_note.reason, IEEE802154_DRF_DEVICE_WISH, + "Disassociation Notification: notification should be initiated by the enddevice."); +} + static void test_scan_shell_cmd(void) { struct ieee802154_mpdu mpdu = {0}; @@ -259,6 +279,51 @@ ZTEST(ieee802154_l2_shell, test_associate) ztest_test_fail(); } +ZTEST(ieee802154_l2_shell, test_initiate_disassociation_from_enddevice) +{ + uint8_t expected_coord_addr_le[] = {EXPECTED_COORDINATOR_ADDR_LE}; + uint8_t empty_coord_addr[IEEE802154_EXT_ADDR_LENGTH] = {0}; + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint8_t mock_ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; + struct ieee802154_mpdu mpdu = {0}; + int ret; + + /* Simulate an associated device. */ + ctx->pan_id = EXPECTED_COORDINATOR_PAN_CPU_ORDER; + ctx->short_addr = EXPECTED_ENDDEVICE_SHORT_ADDR; + ctx->coord_short_addr = EXPECTED_COORDINATOR_SHORT_ADDR; + memcpy(ctx->coord_ext_addr, expected_coord_addr_le, sizeof(ctx->coord_ext_addr)); + + ret = shell_execute_cmd(NULL, "ieee802154 disassociate"); + zassert_equal(0, ret, "Initiating disassociation from the enddevice failed: %d", ret); + + /* Ensure we've been disassociated. */ + zassert_mem_equal(ctx->coord_ext_addr, empty_coord_addr, sizeof(ctx->coord_ext_addr), + "Disassociation: coordinator address should be unset."); + zassert_equal(ctx->pan_id, IEEE802154_PAN_ID_NOT_ASSOCIATED, + "Disassociation: PAN should be unset."); + zassert_equal(ctx->short_addr, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED, + "Disassociation: Short addr should be unset."); + sys_memcpy_swap(mock_ext_addr_le, mock_ext_addr_be, sizeof(mock_ext_addr_le)); + zassert_mem_equal(ctx->ext_addr, mock_ext_addr_le, sizeof(ctx->ext_addr), + "Disassociation: Ext addr should be unaffected."); + + zassert_not_null(current_pkt); + + if (!ieee802154_validate_frame(net_pkt_data(current_pkt), net_pkt_get_len(current_pkt), + &mpdu)) { + NET_ERR("*** Could not parse disassociation notification.\n"); + ztest_test_fail(); + goto release_frag; + } + + test_disassociation_notification(&mpdu); + +release_frag: + net_pkt_frag_unref(current_pkt->frags); + current_pkt->frags = NULL; +} + ZTEST(ieee802154_l2_shell, test_set_ext_addr) { uint8_t expected_ext_addr_le[] = {EXPECTED_ENDDEVICE_EXT_ADDR_LE}; From ea04e80aa1e21f1bced63051a6b353e7d841a911 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 19:47:30 +0200 Subject: [PATCH 1279/2042] net: l2: ieee802154: introduce device roles Introduces IEEE 802.15.4 device roles for use in later change sets. In the near term this will be used for coordinator-role support in tests. Then additional coordinator-specific features will be gradually introduced without exposing them to the user API, yet. Once a reasonable feature set has been collected for coordinators, it will be exposed in public APIs for use in applications. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/ieee802154.h b/include/zephyr/net/ieee802154.h index e69179863e1e..a17405b10002 100644 --- a/include/zephyr/net/ieee802154.h +++ b/include/zephyr/net/ieee802154.h @@ -71,6 +71,12 @@ struct ieee802154_security_ctx { uint8_t _unused : 3; }; +enum ieee802154_device_role { + IEEE802154_DEVICE_ROLE_ENDDEVICE, + IEEE802154_DEVICE_ROLE_COORDINATOR, + IEEE802154_DEVICE_ROLE_PAN_COORDINATOR, +}; + /* This not meant to be used by any code but the IEEE 802.15.4 L2 stack */ struct ieee802154_context { /* PAN ID @@ -156,7 +162,16 @@ struct ieee802154_context { */ uint8_t sequence; - uint8_t _unused : 7; + /* See section 6.1: A device may be operating as end device + * (0 - default), coordinator (1), or PAN coordinator (2). + * + * A value of 3 is undefined. + * + * Can be read/set via enum ieee802154_device_role. + */ + uint8_t device_role : 2; + + uint8_t _unused : 5; uint8_t ack_requested : 1; /* guarded by ack_lock */ uint8_t ack_seq; /* guarded by ack_lock */ From cffb1a448ee9996d86ed4a045d3cf23d457b9e08 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 17:55:34 +0200 Subject: [PATCH 1280/2042] net: l2: ieee802154: test disassociation from coordinator Introduces an integration test that simulates an incoming disassociaton notification from a coordinator. Signed-off-by: Florian Grandel --- .../ieee802154/l2/src/ieee802154_shell_test.c | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c index 770b47d30007..58881c2e0656 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c @@ -324,6 +324,84 @@ ZTEST(ieee802154_l2_shell, test_initiate_disassociation_from_enddevice) current_pkt->frags = NULL; } +ZTEST(ieee802154_l2_shell, test_initiate_disassociation_from_coordinator) +{ + uint8_t expected_coord_addr_le[] = {EXPECTED_COORDINATOR_ADDR_LE}; + uint8_t empty_coord_addr[IEEE802154_EXT_ADDR_LENGTH] = {0}; + struct ieee802154_context *ctx = net_if_l2_data(iface); + uint8_t mock_ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; + struct ieee802154_frame_params params = { + .dst = { + .len = IEEE802154_EXT_ADDR_LENGTH, + .pan_id = EXPECTED_COORDINATOR_PAN_CPU_ORDER, + }}; + struct ieee802154_command *cmd; + struct net_pkt *pkt; + + /* Simulate an associated device. */ + + sys_memcpy_swap(params.dst.ext_addr, ctx->ext_addr, sizeof(params.dst.ext_addr)); + + /* Simulate a packet from the coordinator. */ + ctx->device_role = IEEE802154_DEVICE_ROLE_PAN_COORDINATOR; + ctx->pan_id = EXPECTED_COORDINATOR_PAN_CPU_ORDER; + ctx->short_addr = EXPECTED_COORDINATOR_SHORT_ADDR; + memcpy(ctx->ext_addr, expected_coord_addr_le, sizeof(ctx->ext_addr)); + + /* Create and send an incoming disassociation notification. */ + pkt = ieee802154_create_mac_cmd_frame(iface, IEEE802154_CFI_DISASSOCIATION_NOTIFICATION, + ¶ms); + if (!pkt) { + NET_ERR("*** Could not create association response\n"); + goto fail; + } + + cmd = ieee802154_get_mac_command(pkt); + cmd->disassoc_note.reason = IEEE802154_DRF_COORDINATOR_WISH; + ieee802154_mac_cmd_finalize(pkt, IEEE802154_CFI_DISASSOCIATION_NOTIFICATION); + + /* Restore the end device's state and simulate an associated device. */ + ctx->device_role = IEEE802154_DEVICE_ROLE_ENDDEVICE; + ctx->short_addr = EXPECTED_ENDDEVICE_SHORT_ADDR; + sys_memcpy_swap(ctx->ext_addr, params.dst.ext_addr, sizeof(ctx->ext_addr)); + ctx->coord_short_addr = EXPECTED_COORDINATOR_SHORT_ADDR; + memcpy(ctx->coord_ext_addr, expected_coord_addr_le, sizeof(ctx->coord_ext_addr)); + + if (net_recv_data(iface, pkt) < 0) { + NET_ERR("Recv assoc resp pkt failed"); + net_pkt_unref(pkt); + goto fail; + } + + /* We need to yield, so that the packet is actually being received from the RX thread. */ + k_yield(); + + /* We should have received an ACK packet. */ + zassert_not_null(current_pkt); + zassert_not_null(current_pkt->frags); + zassert_equal(net_pkt_get_len(current_pkt), IEEE802154_ACK_PKT_LENGTH, + "Did not receive the expected ACK packet."); + net_pkt_frag_unref(current_pkt->frags); + current_pkt->frags = NULL; + + /* Ensure we've been disassociated. */ + zassert_mem_equal(ctx->coord_ext_addr, empty_coord_addr, sizeof(ctx->coord_ext_addr), + "Disassociation: coordinator address should be unset."); + zassert_equal(ctx->pan_id, IEEE802154_PAN_ID_NOT_ASSOCIATED, + "Disassociation: PAN should be unset."); + zassert_equal(ctx->short_addr, IEEE802154_SHORT_ADDRESS_NOT_ASSOCIATED, + "Disassociation: Short addr should be unset."); + sys_memcpy_swap(mock_ext_addr_le, mock_ext_addr_be, sizeof(mock_ext_addr_le)); + zassert_mem_equal(ctx->ext_addr, mock_ext_addr_le, sizeof(ctx->ext_addr), + "Disassociation: Ext addr should be unaffected."); + + return; + +fail: + sys_memcpy_swap(ctx->ext_addr, params.dst.ext_addr, sizeof(ctx->ext_addr)); + ztest_test_fail(); +} + ZTEST(ieee802154_l2_shell, test_set_ext_addr) { uint8_t expected_ext_addr_le[] = {EXPECTED_ENDDEVICE_EXT_ADDR_LE}; From b106c21acdb6616a5cc62f05f8bd83410c961d2a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 7 Jul 2023 14:38:07 +0200 Subject: [PATCH 1281/2042] net: l2: ieee802154: unified assertion order Small refactoring that unifies the assertion order for improved consistency across tests - placing the SUT before the expected value everywhere. Signed-off-by: Florian Grandel --- .../ieee802154/l2/src/ieee802154_shell_test.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c index 58881c2e0656..910848c7a789 100644 --- a/tests/net/ieee802154/l2/src/ieee802154_shell_test.c +++ b/tests/net/ieee802154/l2/src/ieee802154_shell_test.c @@ -55,12 +55,12 @@ static void scan_result_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_eve /* No need for scan_ctx locking as we should execute exclusively. */ zassert_not_null(scan_ctx); - zassert_equal(EXPECTED_COORDINATOR_PAN_CPU_ORDER, scan_ctx->pan_id, + zassert_equal(scan_ctx->pan_id, EXPECTED_COORDINATOR_PAN_CPU_ORDER, "Scan did not receive correct PAN id."); - zassert_equal(IEEE802154_EXT_ADDR_LENGTH, scan_ctx->len, + zassert_equal(scan_ctx->len, IEEE802154_EXT_ADDR_LENGTH, "Scan did not receive correct co-ordinator address length."); - zassert_mem_equal(expected_coordinator_address, scan_ctx->addr, IEEE802154_EXT_ADDR_LENGTH); - zassert_equal(EXPECTED_COORDINATOR_LQI, scan_ctx->lqi, + zassert_mem_equal(scan_ctx->addr, expected_coordinator_address, IEEE802154_EXT_ADDR_LENGTH); + zassert_equal(scan_ctx->lqi, EXPECTED_COORDINATOR_LQI, "Scan did not receive correct link quality indicator."); k_sem_give(&scan_lock); @@ -70,13 +70,13 @@ static void test_beacon_request(struct ieee802154_mpdu *mpdu) { struct ieee802154_command *cmd = mpdu->command; - zassert_equal(1U, mpdu->payload_length, "Beacon request: invalid payload length."); - zassert_equal(IEEE802154_CFI_BEACON_REQUEST, cmd->cfi, "Not a beacon request."); - zassert_equal(IEEE802154_ADDR_MODE_SHORT, mpdu->mhr.fs->fc.dst_addr_mode, + zassert_equal(mpdu->payload_length, 1U, "Beacon request: invalid payload length."); + zassert_equal(cmd->cfi, IEEE802154_CFI_BEACON_REQUEST, "Not a beacon request."); + zassert_equal(mpdu->mhr.fs->fc.dst_addr_mode, IEEE802154_ADDR_MODE_SHORT, "Beacon request: invalid destination address mode."); - zassert_equal(IEEE802154_BROADCAST_ADDRESS, mpdu->mhr.dst_addr->plain.addr.short_addr, + zassert_equal(mpdu->mhr.dst_addr->plain.addr.short_addr, IEEE802154_BROADCAST_ADDRESS, "Beacon request: destination address should be broadcast address."); - zassert_equal(IEEE802154_BROADCAST_PAN_ID, mpdu->mhr.dst_addr->plain.pan_id, + zassert_equal(mpdu->mhr.dst_addr->plain.pan_id, IEEE802154_BROADCAST_PAN_ID, "Beacon request: destination PAN should be broadcast PAN."); } From c590c5c1ee217ae6d6196b3ee1c51f7450844115 Mon Sep 17 00:00:00 2001 From: Dawid Niedzwiecki Date: Tue, 11 Jul 2023 08:27:45 +0200 Subject: [PATCH 1282/2042] mgmt: ec_host_cmd: add suppressing commands Add a feature to suppress commands. The suppressed commands are not logged on the command reception. Signed-off-by: Dawid Niedzwiecki --- include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h | 11 +++ subsys/mgmt/ec_host_cmd/Kconfig.logging | 19 ++++++ subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c | 67 +++++++++++++++++++ 3 files changed, 97 insertions(+) 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 30bb04e8ee4f..5b03ae7c5f32 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -348,6 +348,17 @@ bool ec_host_cmd_send_in_progress_ended(void); enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void); #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ +/** + * @brief Add a suppressed command. + * + * Suppressed commands are not logged. Add a command to be suppressed. + * + * @param[in] cmd_id A command id to be suppressed. + * + * @retval 0 if successful, -EIO if exceeded max number of suppressed commands. + */ +int ec_host_cmd_add_suppressed(uint16_t cmd_id); + /** * @} */ diff --git a/subsys/mgmt/ec_host_cmd/Kconfig.logging b/subsys/mgmt/ec_host_cmd/Kconfig.logging index 2fdd6c59c527..96de59e39cd0 100644 --- a/subsys/mgmt/ec_host_cmd/Kconfig.logging +++ b/subsys/mgmt/ec_host_cmd/Kconfig.logging @@ -10,3 +10,22 @@ config EC_HOST_CMD_LOG_DBG_BUFFERS Every command is logged with the debug logging level. Use this config to decide, if full reqest and response buffers are logged alongside other command parameters. + +config EC_HOST_CMD_LOG_SUPPRESSED_NUMBER + int "Maximum number of suppressed commands" + default 8 + help + Suppressed commands are not logged on host command reception. Set + the maximum number of the suppressed commands. Set 0 to disable + suppressing commands. + +config EC_HOST_CMD_LOG_SUPPRESSED_INTERVAL_SECS + int "Interval of logging suppressed commands" + default 3600 + help + Once every interval the suppressed commands are logged with the + suppression number. + +config EC_HOST_CMD_LOG_SUPPRESSED + bool + default y if (EC_HOST_CMD_LOG_SUPPRESSED_NUMBER > 0) 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 9335b3f593e3..1699d9dae8ec 100644 --- a/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c +++ b/subsys/mgmt/ec_host_cmd/ec_host_cmd_handler.c @@ -59,6 +59,13 @@ static bool cmd_in_progress; static enum ec_host_cmd_status saved_status = EC_HOST_CMD_UNAVAILABLE; #endif +#ifdef CONFIG_EC_HOST_CMD_LOG_SUPPRESSED +static uint16_t suppressed_cmds[CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_NUMBER]; +static uint16_t suppressed_cmds_count[CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_NUMBER]; +static int64_t suppressed_cmds_deadline = CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_INTERVAL_SECS * 1000U; +static size_t suppressed_cmds_number; +#endif /* CONFIG_EC_HOST_CMD_LOG_SUPPRESSED */ + static uint8_t cal_checksum(const uint8_t *const buffer, const uint16_t size) { uint8_t checksum = 0; @@ -85,6 +92,58 @@ enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void) } #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ +#ifdef CONFIG_EC_HOST_CMD_LOG_SUPPRESSED +int ec_host_cmd_add_suppressed(uint16_t cmd_id) +{ + if (suppressed_cmds_number >= CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_NUMBER) { + return -EIO; + } + + suppressed_cmds[suppressed_cmds_number] = cmd_id; + ++suppressed_cmds_number; + + return 0; +} + +static bool ec_host_cmd_is_suppressed(uint16_t cmd_id) +{ + int i; + + for (i = 0; i < suppressed_cmds_number; i++) { + if (suppressed_cmds[i] == cmd_id) { + suppressed_cmds_count[i]++; + + return true; + } + } + + return false; +} + +void ec_host_cmd_dump_suppressed(void) +{ + int i; + int64_t uptime = k_uptime_get(); + + LOG_PRINTK("[%llds HC Suppressed:", uptime / 1000U); + for (i = 0; i < suppressed_cmds_number; i++) { + LOG_PRINTK(" 0x%x=%d", suppressed_cmds[i], suppressed_cmds_count[i]); + suppressed_cmds_count[i] = 0; + } + LOG_PRINTK("]\n"); + + /* Reset the timer */ + suppressed_cmds_deadline = uptime + CONFIG_EC_HOST_CMD_LOG_SUPPRESSED_INTERVAL_SECS * 1000U; +} + +static void ec_host_cmd_check_suppressed(void) +{ + if (k_uptime_get() >= suppressed_cmds_deadline) { + ec_host_cmd_dump_suppressed(); + } +} +#endif /* CONFIG_EC_HOST_CMD_LOG_SUPPRESSED */ + static void send_status_response(const struct ec_host_cmd_backend *backend, struct ec_host_cmd_tx_buf *tx, const enum ec_host_cmd_status status) @@ -267,6 +326,14 @@ static void ec_host_cmd_log_request(const uint8_t *rx_buf) const struct ec_host_cmd_request_header *const rx_header = (const struct ec_host_cmd_request_header *const)rx_buf; +#ifdef CONFIG_EC_HOST_CMD_LOG_SUPPRESSED + if (ec_host_cmd_is_suppressed(rx_header->cmd_id)) { + ec_host_cmd_check_suppressed(); + + return; + } +#endif /* CONFIG_EC_HOST_CMD_LOG_SUPPRESSED */ + if (IS_ENABLED(CONFIG_EC_HOST_CMD_LOG_DBG_BUFFERS)) { if (rx_header->data_len) { const uint8_t *rx_data = rx_buf + RX_HEADER_SIZE; From 616561de7f1f947be2c88dc1aa4943efd2e7cd3f Mon Sep 17 00:00:00 2001 From: Hake Huang Date: Wed, 12 Jul 2023 14:31:46 +0800 Subject: [PATCH 1283/2042] dma: fix the DMA_TCD_QUEUE_SIZE setting issue in test this test need more queue size, so set to CONFIG_DMA_TCD_QUEUE_SIZE=4 fixing: #60196 Signed-off-by: Hake Huang --- tests/drivers/dma/scatter_gather/boards/frdm_k64f.conf | 1 + tests/drivers/dma/scatter_gather/boards/mimxrt1060_evk.conf | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/drivers/dma/scatter_gather/boards/frdm_k64f.conf create mode 100644 tests/drivers/dma/scatter_gather/boards/mimxrt1060_evk.conf diff --git a/tests/drivers/dma/scatter_gather/boards/frdm_k64f.conf b/tests/drivers/dma/scatter_gather/boards/frdm_k64f.conf new file mode 100644 index 000000000000..61f2d18ca3c7 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/frdm_k64f.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/tests/drivers/dma/scatter_gather/boards/mimxrt1060_evk.conf b/tests/drivers/dma/scatter_gather/boards/mimxrt1060_evk.conf new file mode 100644 index 000000000000..61f2d18ca3c7 --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/mimxrt1060_evk.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 From 20a2e40a5e2e566f01324fba49b0508326c70207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 11 Jul 2023 11:43:02 -0300 Subject: [PATCH 1284/2042] tests: code_relocation: restrict Arm test to NXP platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently tests.application_development.code_relocation and tests.application_development.code_relocation_kinetis scenarios are restricted to specific NXP platforms only, so make filters more strict. Also for frdm_k64f, which lacks of ITCM, relocation to ITCM must be disabled. Fixes #60167 Signed-off-by: Manuel Argüelles --- .../application_development/code_relocation/testcase.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/application_development/code_relocation/testcase.yaml b/tests/application_development/code_relocation/testcase.yaml index c02ef6b6ee96..befb9f3a3e95 100644 --- a/tests/application_development/code_relocation/testcase.yaml +++ b/tests/application_development/code_relocation/testcase.yaml @@ -6,12 +6,15 @@ tests: arch_allow: arm extra_configs: - CONFIG_RELOCATE_TO_ITCM=y + platform_allow: + - mimxrt1060_evk tests.application_development.code_relocation_kinetis: - filter: CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") + filter: CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC arch_allow: arm extra_configs: - - CONFIG_RELOCATE_TO_ITCM=y - CONFIG_MPU_ALLOW_FLASH_WRITE=y + platform_allow: + - frdm_k64f tests.application_development.code_relocation.no_itcm: filter: not CONFIG_CPU_HAS_NXP_MPU and not dt_chosen_enabled("zephyr,itcm") arch_allow: arm From 17f345780df595481baa676edae830e1bc16bf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Wed, 12 Jul 2023 11:30:16 -0300 Subject: [PATCH 1285/2042] tests: code_relocation: use per-SoC linker file for Arm tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to support more Arm SoCs, extend the SoC-specific linker file instead of the default arch linker file. Fixes #60165 Signed-off-by: Manuel Argüelles --- .../code_relocation/linker_arm_sram2.ld | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/application_development/code_relocation/linker_arm_sram2.ld b/tests/application_development/code_relocation/linker_arm_sram2.ld index 97f7d95bd374..deb2c6f5aca6 100644 --- a/tests/application_development/code_relocation/linker_arm_sram2.ld +++ b/tests/application_development/code_relocation/linker_arm_sram2.ld @@ -36,4 +36,5 @@ MEMORY #endif } -#include +/* Include the SoC-specific linker file */ +#include From bed68af4894f732d7d5225cba0a87fa2e317942f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Tue, 11 Jul 2023 11:46:04 -0300 Subject: [PATCH 1286/2042] tests: code_relocation: support mr_canhubk3 boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test scenario for NXP S32 platforms, for now only ported to mr_canhubk3. In some platforms the MPU region used for NULL pointer detection conflicts with the ITCM region, causing access fault. Make disabling the null pointer exception detection the default behavior for this scenario. Signed-off-by: Manuel Argüelles --- .../application_development/code_relocation/testcase.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/application_development/code_relocation/testcase.yaml b/tests/application_development/code_relocation/testcase.yaml index befb9f3a3e95..ab18b1cfefc5 100644 --- a/tests/application_development/code_relocation/testcase.yaml +++ b/tests/application_development/code_relocation/testcase.yaml @@ -15,6 +15,14 @@ tests: - CONFIG_MPU_ALLOW_FLASH_WRITE=y platform_allow: - frdm_k64f + tests.application_development.code_relocation.nxp_s32: + filter: not CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") + arch_allow: arm + extra_configs: + - CONFIG_RELOCATE_TO_ITCM=y + - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + platform_allow: + - mr_canhubk3 tests.application_development.code_relocation.no_itcm: filter: not CONFIG_CPU_HAS_NXP_MPU and not dt_chosen_enabled("zephyr,itcm") arch_allow: arm From 298456572249ba92e7a18c3aba2a925356b3c300 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Thu, 13 Jul 2023 22:53:04 -0700 Subject: [PATCH 1287/2042] drivers: fix double promotion warning in sensor_value_from_float fix double promotion warning when compiling when compiling with -Wdouble-promotion Signed-off-by: Ryan McClelland --- include/zephyr/drivers/sensor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index 9a74a5369499..1e51755b5d64 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -1107,7 +1107,7 @@ static inline int sensor_value_from_double(struct sensor_value *val, double inp) */ static inline int sensor_value_from_float(struct sensor_value *val, float inp) { - float val2 = (inp - (int32_t)inp) * 1000000.0; + float val2 = (inp - (int32_t)inp) * 1000000.0f; if (val2 < INT32_MIN || val2 > (float)(INT32_MAX - 1)) { return -ERANGE; From c9a68afede31f83ea3238ece11a168614cbdd905 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 13 Jul 2023 23:01:59 +0200 Subject: [PATCH 1288/2042] arm64: Set FP to NULL before jumping to C code When the frame-pointer based unwinding is enabled, the stop condition for the stack backtrace is (FP == NULL). Set FP to 0 before jumping to C code. Signed-off-by: Carlo Caione --- arch/arm64/core/reset.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/core/reset.S b/arch/arm64/core/reset.S index 35f760717caf..387e82b341a2 100644 --- a/arch/arm64/core/reset.S +++ b/arch/arm64/core/reset.S @@ -90,6 +90,9 @@ out: /* Initialize stack */ mov sp, x24 + /* fp = NULL */ + mov fp, xzr + ret x23 /* From 5824e95b1e513fef259716e876f3d594a8e91895 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 13 Jul 2023 18:51:53 +0200 Subject: [PATCH 1289/2042] Bluetooth: Host: Introduce BT_CONN_PARAM_ANY Some controllers support additional connection parameter ranges beyond what is described in the specification. Enabling this new option allows the application to set any value to all connection parameters. Tbe Host will perform no limits nor consistency checks on any of the connection parameters (conn interval min and max, latency and timeou). However, the Host will still use numerical comparisons between the min and max connection intervals in order to verify whether the desired parameters have been established in the connection. Signed-off-by: Carles Cufi --- subsys/bluetooth/host/Kconfig | 12 ++++++++++++ subsys/bluetooth/host/Kconfig.gatt | 8 ++++---- subsys/bluetooth/host/hci_core.c | 4 ++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 00ed7718a321..19754705200e 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -299,6 +299,18 @@ config BT_CONN_TX_MAX callback. Normally this can be left to the default value, which is equal to the number of TX buffers in the stack-internal pool. +config BT_CONN_PARAM_ANY + bool "Accept any values for connection parameters" + help + Some controllers support additional connection parameter ranges + beyond what is described in the specification. Enabling this option + allows the application to set any value to all connection parameters. + Tbe Host will perform no limits nor consistency checks on any of the + connection parameters (conn interval min and max, latency and timeout). + However, the Host will still use numerical comparisons between the + min and max connection intervals in order to verify whether the + desired parameters have been established in the connection. + config BT_USER_PHY_UPDATE bool "User control of PHY Update Procedure" depends on BT_PHY_UPDATE diff --git a/subsys/bluetooth/host/Kconfig.gatt b/subsys/bluetooth/host/Kconfig.gatt index d3cf7146db34..e405a56d1473 100644 --- a/subsys/bluetooth/host/Kconfig.gatt +++ b/subsys/bluetooth/host/Kconfig.gatt @@ -223,26 +223,26 @@ if BT_GAP_PERIPHERAL_PREF_PARAMS config BT_PERIPHERAL_PREF_MIN_INT int "Peripheral preferred minimum connection interval in 1.25ms units" default 24 - range 6 65535 + range 6 65535 if !BT_CONN_PARAM_ANY help Range 3200 to 65534 is invalid. 65535 represents no specific value. config BT_PERIPHERAL_PREF_MAX_INT int "Peripheral preferred maximum connection interval in 1.25ms units" default 40 - range 6 65535 + range 6 65535 if !BT_CONN_PARAM_ANY help Range 3200 to 65534 is invalid. 65535 represents no specific value. config BT_PERIPHERAL_PREF_LATENCY int "Peripheral preferred peripheral latency in Connection Intervals" default 0 - range 0 499 + range 0 499 if !BT_CONN_PARAM_ANY config BT_PERIPHERAL_PREF_TIMEOUT int "Peripheral preferred supervision timeout in 10ms units" default 42 - range 10 65535 + range 10 65535 if !BT_CONN_PARAM_ANY help It is up to user to provide valid timeout which pass required minimum value: in milliseconds it shall be larger than diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 994cfe32e101..4e9d402d58a4 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1699,6 +1699,10 @@ static void le_phy_update_complete(struct net_buf *buf) bool bt_le_conn_params_valid(const struct bt_le_conn_param *param) { + if (IS_ENABLED(CONFIG_BT_CONN_PARAM_ANY)) { + return true; + } + /* All limits according to BT Core spec 5.0 [Vol 2, Part E, 7.8.12] */ if (param->interval_min > param->interval_max || From cab341d29cb83368cd0241db4e33ae3a3529eb58 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Fri, 26 May 2023 13:47:08 +0200 Subject: [PATCH 1290/2042] arch/common: Fix moving location counter backwards when using LLD In GNU LD, the location counter (the 'dot' variable) always refers to the byte offset from the start of current object as mentioned in documentation[1]: ``` '.' actually refers to the byte offset from the start of the current containing object. Normally this is the SECTIONS statement, whose start address is 0, hence '.' can be used as an absolute address. If '.' is used inside a section description however, it refers to the byte offset from the start of that section, not an absolute address. ``` For example, if the section 'rom_start': rom_start : { . = 0x400; _vector_start = ABSOLUTE(.); } > FLASH has a starting address of 0x8000000, then _vector_start will be 0x8000400 However, behavior of LLVM LLD is quite different, the value of the location counter is always absolute (see discussion [2]), so in the example above, the linker will return error, because it will interpret '. = 0x400' as an attempt to move the location counter backwards. It could be fixed by changing line to '. += 0x400' (#54796) which will move the location counter by 0x400 for both linkers, but it would work only when we are at the beginning of section. Consider the following example: rom_start : { . = 0x400; KEEP(*(.boot_hdr.conf)) . = 0x1000; KEEP(*(.boot_hdr.ivt)) KEEP(*(.boot_hdr.data)) KEEP(*(.boot_hdr.dcd_data)) . = 0x2000; _vector_start = .; } > FLASH In this case, _vector_start will be 0x2000, but if we change '. = 0x2000' to '. += 0x2000', then the value of _vector_start depends on size of data in input sections (but it's 0x3000 at least). Actually, this example comes from final linker script when compiling firmware for mimxrt1170_evk_cm7 board. This board failed to boot (#55296) after #54796 was merged. This patch introduces method compatible with both linkers. We calculate relative offset from the beginning of the section and use that value to calculate number of bytes by which we should move the location counter to get CONFIG_ROM_START_OFFSET. [1] https://sourceware.org/binutils/docs/ld/Location-Counter.html [2] https://discourse.llvm.org/t/lld-location-counter-inside-objects Signed-off-by: Patryk Duda --- arch/common/CMakeLists.txt | 3 +++ arch/common/rom_start_address.ld | 11 +++++++++++ arch/common/rom_start_offset.ld | 15 ++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 arch/common/rom_start_address.ld diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index 401cc82148c6..21ddbd24ea49 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -52,6 +52,9 @@ zephyr_linker_sources_ifdef(CONFIG_NOCACHE_MEMORY # Only ARM, X86 and OPENISA_RV32M1_RISCV32 use ROM_START_OFFSET. if (DEFINED CONFIG_ARM OR DEFINED CONFIG_X86 OR DEFINED CONFIG_ARM64 OR DEFINED CONFIG_SOC_OPENISA_RV32M1_RISCV32) + # Exclamation mark is printable character with lowest number in ASCII table. + # We are sure that this file will be included as a first. + zephyr_linker_sources(ROM_START SORT_KEY ! rom_start_address.ld) zephyr_linker_sources(ROM_START SORT_KEY 0x0 rom_start_offset.ld) # Handled in ld.cmake endif() diff --git a/arch/common/rom_start_address.ld b/arch/common/rom_start_address.ld new file mode 100644 index 000000000000..afebcb606fec --- /dev/null +++ b/arch/common/rom_start_address.ld @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023, Google, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * To provide correct value, this file must be the first file included in + * snippets-rom-start.ld. This variable is used in rom_start_offset.ld + */ +HIDDEN(__rom_start_address = .); diff --git a/arch/common/rom_start_offset.ld b/arch/common/rom_start_offset.ld index 2e82f30d7188..e141a162b295 100644 --- a/arch/common/rom_start_offset.ld +++ b/arch/common/rom_start_offset.ld @@ -4,5 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -. = CONFIG_ROM_START_OFFSET; +/* + * The line below this comment is equivalent to '. = CONFIG_ROM_START_OFFSET' + * as interpreted by GNU LD, but also compatible with LLVM LLD. + * + * Simple assignment doesn't work for LLVM LLD, because the dot inside section + * is absolute, so assigning offset here results in moving location counter + * backwards. + * + * We can't use '. += CONFIG_ROM_START_OFFSET' here because there might be some + * other files included before this file. + * + * Symbol __rom_start_address is defined in rom_start_address.ld + */ +. += CONFIG_ROM_START_OFFSET - (. - __rom_start_address); . = ALIGN(4); From 770e6dfaefa2fb907a96b9660ee40294dc6b5f7c Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 24 Jun 2023 21:24:00 +0800 Subject: [PATCH 1291/2042] drivers: auxdisplay: Add driver for PTC PT6314 VFD controller Adds the driver for PT6314 dot character VFD controller/driver IC. Signed-off-by: Chen Xingyu --- drivers/auxdisplay/CMakeLists.txt | 1 + drivers/auxdisplay/Kconfig | 1 + drivers/auxdisplay/Kconfig.pt6314 | 10 + drivers/auxdisplay/auxdisplay_pt6314.c | 336 ++++++++++++++++++++++++ dts/bindings/auxdisplay/ptc,pt6314.yaml | 20 ++ dts/bindings/vendor-prefixes.txt | 1 + 6 files changed, 369 insertions(+) create mode 100644 drivers/auxdisplay/Kconfig.pt6314 create mode 100644 drivers/auxdisplay/auxdisplay_pt6314.c create mode 100644 dts/bindings/auxdisplay/ptc,pt6314.yaml diff --git a/drivers/auxdisplay/CMakeLists.txt b/drivers/auxdisplay/CMakeLists.txt index 654d68921c72..da8b1dcd3998 100644 --- a/drivers/auxdisplay/CMakeLists.txt +++ b/drivers/auxdisplay/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_HD44780 auxdisplay_hd44780.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_ITRON auxdisplay_itron.c) zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_JHD1313 auxdisplay_jhd1313.c) +zephyr_library_sources_ifdef(CONFIG_AUXDISPLAY_PT6314 auxdisplay_pt6314.c) diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 4b3c21cbbb71..f28b463a633c 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -23,5 +23,6 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/auxdisplay/Kconfig.hd44780" source "drivers/auxdisplay/Kconfig.itron" source "drivers/auxdisplay/Kconfig.jhd1313" +source "drivers/auxdisplay/Kconfig.pt6314" endif # AUXDISPLAY diff --git a/drivers/auxdisplay/Kconfig.pt6314 b/drivers/auxdisplay/Kconfig.pt6314 new file mode 100644 index 000000000000..7add427e9759 --- /dev/null +++ b/drivers/auxdisplay/Kconfig.pt6314 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +config AUXDISPLAY_PT6314 + bool "PTC PT6314 dot character VFD driver" + default y + select SPI + depends on DT_HAS_PTC_PT6314_ENABLED + help + Enable driver for PTC PT6314. diff --git a/drivers/auxdisplay/auxdisplay_pt6314.c b/drivers/auxdisplay/auxdisplay_pt6314.c new file mode 100644 index 000000000000..f3676be9b4e6 --- /dev/null +++ b/drivers/auxdisplay/auxdisplay_pt6314.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2015 Intel Corporation + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Jamie McCrae + * Copyright (c) 2023 Chen Xingyu + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ptc_pt6314 + +#include +#include +#include +#include +#include +#include +#include + +/* Defines for the PT6314_INST_DISPLAY_ON_OFF */ +#define PT6314_DO_BLINKING_ON (1 << 0) +#define PT6314_DO_CURSOR_ON (1 << 1) +#define PT6314_DO_DISPLAY_ON (1 << 2) + +/* Defines for the PT6314_INST_FUNCTION_SET */ +#define PT6314_FS_BRIGHTNESS(BR) (4 - (BR & BIT_MASK(2))) +#define PT6314_FS_ROWS_1 (0 << 3) +#define PT6314_FS_ROWS_2 (1 << 3) +#define PT6314_FS_8BIT_MODE (1 << 4) + +#define PT6314_BRIGHTNESS_MIN 1 +#define PT6314_BRIGHTNESS_MAX 4 + +/* Defines for the PT6314_INST_DDRAM_ADDRESS_SET */ +#define PT6314_DA_BASE_ROW_1 (0x00) +#define PT6314_DA_BASE_ROW_2 (0x40) + +/* Display Commands */ +#define PT6314_INST_CLEAR_DISPLAY BIT(0) +#define PT6314_INST_CURSOR_HOME BIT(1) +#define PT6314_INST_ENTRY_MODE_SET BIT(2) +#define PT6314_INST_DISPLAY_ON_OFF BIT(3) +#define PT6314_INST_CURSOR_OR_DISPLAY_SHIFT BIT(4) +#define PT6314_INST_FUNCTION_SET BIT(5) +#define PT6314_INST_CGRAM_ADDRESS_SET BIT(6) +#define PT6314_INST_DDRAM_ADDRESS_SET BIT(7) + +/* Start Byte */ +#define PT6314_SB_RS_INST (0 << 1) +#define PT6314_SB_RS_DATA (1 << 1) +#define PT6314_SB_RW_WRITE (0 << 2) +#define PT6314_SB_RW_READ (1 << 2) +#define PT6314_SB_SYNC_BITS (BIT_MASK(5) << 3) + +struct auxdisplay_pt6314_data { + bool power; + bool cursor; + bool blinking; + uint8_t brightness; + uint16_t cursor_x; + uint16_t cursor_y; +}; + +struct auxdisplay_pt6314_config { + struct auxdisplay_capabilities capabilities; + struct spi_dt_spec bus; +}; + +static int auxdisplay_pt6314_spi_write(const struct device *dev, uint8_t flags, uint8_t val) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + + uint8_t buf[2] = {PT6314_SB_SYNC_BITS | PT6314_SB_RW_WRITE | flags, val}; + + struct spi_buf tx_buf[] = {{.buf = buf, .len = sizeof(buf)}}; + const struct spi_buf_set tx = {.buffers = tx_buf, .count = 1}; + + return spi_write_dt(&config->bus, &tx); +} + +static inline int auxdisplay_pt6314_inst(const struct device *dev, uint8_t inst) +{ + return auxdisplay_pt6314_spi_write(dev, PT6314_SB_RS_INST, inst); +} + +static inline int auxdisplay_pt6314_data(const struct device *dev, uint8_t data) +{ + return auxdisplay_pt6314_spi_write(dev, PT6314_SB_RS_DATA, data); +} + +static int auxdisplay_pt6314_display_on_off(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = (data->power ? PT6314_DO_DISPLAY_ON : 0) | (data->cursor ? PT6314_DO_CURSOR_ON : 0) | + (data->blinking ? PT6314_DO_BLINKING_ON : 0); + + return auxdisplay_pt6314_inst(dev, PT6314_INST_DISPLAY_ON_OFF | inst); +} + +static int auxdisplay_pt6314_function_set(const struct device *dev) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = PT6314_FS_8BIT_MODE | + (config->capabilities.rows == 2 ? PT6314_FS_ROWS_2 : PT6314_FS_ROWS_1) | + PT6314_FS_BRIGHTNESS(data->brightness); + + return auxdisplay_pt6314_inst(dev, PT6314_INST_FUNCTION_SET | inst); +} + +static int auxdisplay_pt6314_ddram_address_set(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + inst = (data->cursor_y == 0 ? PT6314_DA_BASE_ROW_1 : PT6314_DA_BASE_ROW_2) + data->cursor_x; + + return auxdisplay_pt6314_inst(dev, PT6314_INST_DDRAM_ADDRESS_SET | inst); +} + +static int auxdisplay_pt6314_display_on(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->power = true; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_display_off(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->power = false; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_cursor_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->cursor = enable; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_position_blinking_set_enabled(const struct device *dev, bool enable) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->blinking = enable; + + return auxdisplay_pt6314_display_on_off(dev); +} + +static int auxdisplay_pt6314_cursor_position_set(const struct device *dev, + enum auxdisplay_position type, int16_t x, + int16_t y) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + if (type == AUXDISPLAY_POSITION_RELATIVE) { + x += data->cursor_x; + y += data->cursor_y; + } else if (type == AUXDISPLAY_POSITION_RELATIVE_DIRECTION) { + return -EINVAL; + } + + if (x < 0 || y < 0) { + return -EINVAL; + } else if (x >= config->capabilities.columns || y >= config->capabilities.rows) { + return -EINVAL; + } + + data->cursor_x = (uint16_t)x; + data->cursor_y = (uint16_t)y; + + return auxdisplay_pt6314_ddram_address_set(dev); +} + +static int auxdisplay_pt6314_cursor_position_get(const struct device *dev, int16_t *x, int16_t *y) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + *x = (int16_t)data->cursor_x; + *y = (int16_t)data->cursor_y; + + return 0; +} + +static int auxdisplay_pt6314_capabilities_get(const struct device *dev, + struct auxdisplay_capabilities *capabilities) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + + memcpy(capabilities, &config->capabilities, sizeof(struct auxdisplay_capabilities)); + + return 0; +} + +static int auxdisplay_pt6314_clear(const struct device *dev) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + data->cursor_x = 0; + data->cursor_y = 0; + + return auxdisplay_pt6314_inst(dev, PT6314_INST_CLEAR_DISPLAY); +} + +static int auxdisplay_pt6314_brightness_set(const struct device *dev, uint8_t brightness) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + if (brightness < PT6314_BRIGHTNESS_MIN || brightness > PT6314_BRIGHTNESS_MAX) { + return -EINVAL; + } + + data->brightness = brightness; + + return auxdisplay_pt6314_function_set(dev); +} + +static int auxdisplay_pt6314_brightness_get(const struct device *dev, uint8_t *brightness) +{ + struct auxdisplay_pt6314_data *data = dev->data; + + *brightness = data->brightness; + + return 0; +} + +static int auxdisplay_pt6314_write(const struct device *dev, const uint8_t *text, uint16_t len) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + int ret; + int16_t i; + + for (i = 0; i < len; i++) { + ret = auxdisplay_pt6314_data(dev, text[i]); + if (ret) { + return ret; + } + + data->cursor_x++; + + if (data->cursor_x == config->capabilities.columns) { + data->cursor_x = 0; + data->cursor_y++; + + if (data->cursor_y == config->capabilities.rows) { + data->cursor_y = 0; + } + + ret = auxdisplay_pt6314_ddram_address_set(dev); + if (ret) { + return ret; + } + } + } + + return 0; +} + +static int auxdisplay_pt6314_init(const struct device *dev) +{ + const struct auxdisplay_pt6314_config *config = dev->config; + struct auxdisplay_pt6314_data *data = dev->data; + uint8_t inst; + + if (!device_is_ready(config->bus.bus)) { + return -ENODEV; + } + + auxdisplay_pt6314_function_set(dev); + auxdisplay_pt6314_display_on_off(dev); + auxdisplay_pt6314_clear(dev); + + return 0; +} + +static const struct auxdisplay_driver_api auxdisplay_pt6314_auxdisplay_api = { + .display_on = auxdisplay_pt6314_display_on, + .display_off = auxdisplay_pt6314_display_off, + .cursor_set_enabled = auxdisplay_pt6314_cursor_set_enabled, + .position_blinking_set_enabled = auxdisplay_pt6314_position_blinking_set_enabled, + .cursor_position_set = auxdisplay_pt6314_cursor_position_set, + .cursor_position_get = auxdisplay_pt6314_cursor_position_get, + .capabilities_get = auxdisplay_pt6314_capabilities_get, + .clear = auxdisplay_pt6314_clear, + .brightness_get = auxdisplay_pt6314_brightness_get, + .brightness_set = auxdisplay_pt6314_brightness_set, + .write = auxdisplay_pt6314_write, +}; + +#define AUXDISPLAY_PT6314_INST(n) \ + static const struct auxdisplay_pt6314_config auxdisplay_pt6314_config_##n = { \ + .capabilities = \ + { \ + .columns = DT_INST_PROP(n, columns), \ + .rows = DT_INST_PROP(n, rows), \ + .mode = 0, \ + .brightness.minimum = PT6314_BRIGHTNESS_MIN, \ + .brightness.maximum = PT6314_BRIGHTNESS_MAX, \ + .backlight.minimum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .backlight.maximum = AUXDISPLAY_LIGHT_NOT_SUPPORTED, \ + .custom_characters = 0, \ + }, \ + .bus = SPI_DT_SPEC_INST_GET(n, \ + SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | \ + SPI_TRANSFER_MSB | SPI_WORD_SET(8), \ + 0), \ + }; \ + \ + static struct auxdisplay_pt6314_data auxdisplay_pt6314_data_##n = { \ + .power = true, \ + .cursor = false, \ + .blinking = false, \ + .brightness = PT6314_BRIGHTNESS_MAX, \ + .cursor_x = 0, \ + .cursor_y = 0, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &auxdisplay_pt6314_init, NULL, &auxdisplay_pt6314_data_##n, \ + &auxdisplay_pt6314_config_##n, POST_KERNEL, \ + CONFIG_AUXDISPLAY_INIT_PRIORITY, &auxdisplay_pt6314_auxdisplay_api); + +DT_INST_FOREACH_STATUS_OKAY(AUXDISPLAY_PT6314_INST) diff --git a/dts/bindings/auxdisplay/ptc,pt6314.yaml b/dts/bindings/auxdisplay/ptc,pt6314.yaml new file mode 100644 index 000000000000..56324ba14660 --- /dev/null +++ b/dts/bindings/auxdisplay/ptc,pt6314.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Chen Xingyu +# SPDX-License-Identifier: Apache-2.0 + +description: PTC PT6314 Dot Character VFD Controller/Driver IC + +compatible: "ptc,pt6314" + +include: [auxdisplay-device.yaml, spi-device.yaml] + +properties: + columns: + enum: + - 16 + - 20 + - 24 + + rows: + enum: + - 1 + - 2 diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index c70b9b6e0537..d5c32b0a54f4 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -481,6 +481,7 @@ powervr PowerVR (deprecated, use img) primux Primux Trading, S.L. probox2 PROBOX2 (by W2COMP Co., Ltd.) prt Protonic Holland +ptc Princeton Technology Corp. pulsedlight PulsedLight, Inc purism Purism, SPC qca Qualcomm Atheros, Inc. From 18d60b9c5dee2635e7b4060ca75c2a046b3463a9 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 24 Jun 2023 23:26:33 +0800 Subject: [PATCH 1292/2042] samples: driver: auxdisplay: Add overlay for PT6314 on esp32c3_devkitm This demo is done on a Futaba M202MD15FA module, wired as: * STB -> PIN5 * SCK -> PIN6 * SI/SO -> PIN7 Signed-off-by: Chen Xingyu --- .../auxdisplay/boards/esp32c3_devkitm.overlay | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 samples/drivers/auxdisplay/boards/esp32c3_devkitm.overlay diff --git a/samples/drivers/auxdisplay/boards/esp32c3_devkitm.overlay b/samples/drivers/auxdisplay/boards/esp32c3_devkitm.overlay new file mode 100644 index 000000000000..35d0523fcf16 --- /dev/null +++ b/samples/drivers/auxdisplay/boards/esp32c3_devkitm.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Chen Xingyu + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&spi2 { + cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + + auxdisplay_0: auxdisplay@0 { + reg = <0>; + spi-max-frequency = ; + compatible = "ptc,pt6314"; + status = "okay"; + columns = <20>; + rows = <2>; + }; +}; From c3b25040d4d82c4579af430df06ba901712ede21 Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 24 Jun 2023 23:32:25 +0800 Subject: [PATCH 1293/2042] CODEOWNERS: Add self as PT6314 maintainer Add myself as PT6314 maintainer. Signed-off-by: Chen Xingyu --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index a1457cf6d3b1..a4376eb54cc3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -236,6 +236,7 @@ /drivers/adc/adc_ads1x1x.c @XenuIsWatching /drivers/adc/adc_stm32.c @cybertale /drivers/audio/*nrfx* @anangl +/drivers/auxdisplay/*pt6314* @xingrz /drivers/auxdisplay/* @thedjnK /drivers/bbram/* @yperess @sjg20 @jackrosenthal /drivers/bluetooth/ @alwa-nordic @jhedberg @Vudentz @@ -571,6 +572,7 @@ /dts/bindings/i3c/ @dcpleung /dts/bindings/pm_cpu_ops/* @carlocaione /dts/bindings/ethernet/*gem.yaml @ibirnbaum +/dts/bindings/auxdisplay/*pt6314.yaml @xingrz /dts/bindings/auxdisplay/* @thedjnK /dts/posix/ @aescolar @daor-oti /dts/bindings/sensor/*bme680* @BoschSensortec From 1a4c8e6f83b6287cce9eb9e5b72ca33c3a6fbc6e Mon Sep 17 00:00:00 2001 From: Chen Xingyu Date: Sat, 24 Jun 2023 23:34:33 +0800 Subject: [PATCH 1294/2042] MAINTAINERS: Add self as aux display collaborator Add myself as auxiliary display collaborator. Signed-off-by: Chen Xingyu --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 400ba9661673..1310a5799d5d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -671,6 +671,8 @@ Release Notes: status: maintained maintainers: - thedjnK + collaborators: + - xingrz files: - include/zephyr/drivers/auxdisplay.h - drivers/auxdisplay/* From 8c022fca8766c005ee68f18a650b1a37484c00e0 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 30 Jun 2023 01:08:34 +0530 Subject: [PATCH 1295/2042] net: wifi: Remove obsolete comment Support for legacy types has been added primarily to identify in scan results. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 9c65f3197901..a21f7874239e 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -19,9 +19,6 @@ #define WIFI_LISTEN_INTERVAL_MIN 0 #define WIFI_LISTEN_INTERVAL_MAX 65535 -/* Not having support for legacy types is deliberate to enforce - * higher security. - */ enum wifi_security_type { WIFI_SECURITY_TYPE_NONE = 0, WIFI_SECURITY_TYPE_PSK, From 5ec3650d9fa5ed0183aa4c51db62e9cfb72df7a5 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 30 Jun 2023 01:32:34 +0530 Subject: [PATCH 1296/2042] net: wifi: Add doxygen style comments Fix doxygen formatting and add comments. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi.h | 167 ++++++++++++++---- include/zephyr/net/wifi_mgmt.h | 306 +++++++++++++++++++++++++++++---- 2 files changed, 412 insertions(+), 61 deletions(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index a21f7874239e..0278680cd1db 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -6,7 +6,12 @@ /** * @file - * @brief General WiFi Definitions + * @brief IEEE 802.11 protocol and general Wi-Fi definitions. + */ + +/** + * @addtogroup wifi_mgmt + * @{ */ #ifndef ZEPHYR_INCLUDE_NET_WIFI_H_ @@ -19,14 +24,23 @@ #define WIFI_LISTEN_INTERVAL_MIN 0 #define WIFI_LISTEN_INTERVAL_MAX 65535 +/** IEEE 802.11 security types. */ enum wifi_security_type { + /** No security. */ WIFI_SECURITY_TYPE_NONE = 0, + /** WPA2-PSK security. */ WIFI_SECURITY_TYPE_PSK, + /** WPA2-PSK-SHA256 security. */ WIFI_SECURITY_TYPE_PSK_SHA256, + /** WPA3-SAE security. */ WIFI_SECURITY_TYPE_SAE, + /** GB 15629.11-2003 WAPI security. */ WIFI_SECURITY_TYPE_WAPI, + /** EAP security - Enterprise. */ WIFI_SECURITY_TYPE_EAP, + /** WEP security. */ WIFI_SECURITY_TYPE_WEP, + /** WPA-PSK security. */ WIFI_SECURITY_TYPE_WPA_PSK, __WIFI_SECURITY_TYPE_AFTER_LAST, @@ -34,9 +48,7 @@ enum wifi_security_type { WIFI_SECURITY_TYPE_UNKNOWN }; -/** - * wifi_security_txt - Get the security type as a text string - */ +/** Helper function to get user-friendly security type name. */ static inline const char *wifi_security_txt(enum wifi_security_type security) { switch (security) { @@ -62,10 +74,13 @@ static inline const char *wifi_security_txt(enum wifi_security_type security) } } -/* Management frame protection (IEEE 802.11w) options */ +/** IEEE 802.11w - Management frame protection. */ enum wifi_mfp_options { + /** MFP disabled. */ WIFI_MFP_DISABLE = 0, + /** MFP optional. */ WIFI_MFP_OPTIONAL, + /** MFP required. */ WIFI_MFP_REQUIRED, __WIFI_MFP_AFTER_LAST, @@ -73,9 +88,7 @@ enum wifi_mfp_options { WIFI_MFP_UNKNOWN }; -/** - * wifi_mfp_txt - Get the MFP as a text string - */ +/** Helper function to get user-friendly MFP name.*/ static inline const char *wifi_mfp_txt(enum wifi_mfp_options mfp) { switch (mfp) { @@ -91,9 +104,13 @@ static inline const char *wifi_mfp_txt(enum wifi_mfp_options mfp) } } +/** IEEE 802.11 operational frequency bands (not exhaustive). */ enum wifi_frequency_bands { + /** 2.4GHz band. */ WIFI_FREQ_BAND_2_4_GHZ = 0, + /** 5GHz band. */ WIFI_FREQ_BAND_5_GHZ, + /** 6GHz band (Wi-Fi 6E, also extends to 7GHz). */ WIFI_FREQ_BAND_6_GHZ, __WIFI_FREQ_BAND_AFTER_LAST, @@ -101,9 +118,7 @@ enum wifi_frequency_bands { WIFI_FREQ_BAND_UNKNOWN }; -/** - * wifi_mode_txt - Get the interface mode type as a text string - */ +/** Helper function to get user-friendly frequency band name. */ static inline const char *wifi_band_txt(enum wifi_frequency_bands band) { switch (band) { @@ -126,17 +141,30 @@ static inline const char *wifi_band_txt(enum wifi_frequency_bands band) #define WIFI_CHANNEL_MAX 233 #define WIFI_CHANNEL_ANY 255 -/* Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc */ +/** Wi-Fi interface states. + * + * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc + */ enum wifi_iface_state { + /** Interface is disconnected. */ WIFI_STATE_DISCONNECTED = 0, + /** Interface is disabled (administratively). */ WIFI_STATE_INTERFACE_DISABLED, + /** No enabled networks in the configuration. */ WIFI_STATE_INACTIVE, + /** Interface is scanning for networks. */ WIFI_STATE_SCANNING, + /** Authentication with a network is in progress. */ WIFI_STATE_AUTHENTICATING, + /** Association with a network is in progress. */ WIFI_STATE_ASSOCIATING, + /** Association with a network completed. */ WIFI_STATE_ASSOCIATED, + /** 4-way handshake with a network is in progress. */ WIFI_STATE_4WAY_HANDSHAKE, + /** Group Key exchange with a network is in progress. */ WIFI_STATE_GROUP_HANDSHAKE, + /** All authentication completed, ready to pass data. */ WIFI_STATE_COMPLETED, __WIFI_STATE_AFTER_LAST, @@ -144,9 +172,7 @@ enum wifi_iface_state { WIFI_STATE_UNKNOWN }; -/** - * wifi_state_txt - Get the connection state name as a text string - */ +/** Helper function to get user-friendly interface state name. */ static inline const char *wifi_state_txt(enum wifi_iface_state state) { switch (state) { @@ -176,13 +202,22 @@ static inline const char *wifi_state_txt(enum wifi_iface_state state) } } -/* Based on https://w1.fi/wpa_supplicant/devel/structwpa__ssid.html#a625821e2acfc9014f3b3de6e6593ffb7 */ +/** Wi-Fi interface modes. + * + * Based on https://w1.fi/wpa_supplicant/devel/defs_8h.html#a4aeb27c1e4abd046df3064ea9756f0bc + */ enum wifi_iface_mode { + /** Infrastructure station mode. */ WIFI_MODE_INFRA = 0, + /** IBSS (ad-hoc) station mode. */ WIFI_MODE_IBSS = 1, + /** AP mode. */ WIFI_MODE_AP = 2, + /** P2P group owner mode. */ WIFI_MODE_P2P_GO = 3, + /** P2P group formation mode. */ WIFI_MODE_P2P_GROUP_FORMATION = 4, + /** 802.11s Mesh mode. */ WIFI_MODE_MESH = 5, __WIFI_MODE_AFTER_LAST, @@ -190,9 +225,7 @@ enum wifi_iface_mode { WIFI_MODE_UNKNOWN }; -/** - * wifi_mode_txt - Get the interface mode type as a text string - */ +/** Helper function to get user-friendly interface mode name. */ static inline const char *wifi_mode_txt(enum wifi_iface_mode mode) { switch (mode) { @@ -214,16 +247,28 @@ static inline const char *wifi_mode_txt(enum wifi_iface_mode mode) } } -/* As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations */ +/** Wi-Fi link operating modes + * + * As per https://en.wikipedia.org/wiki/Wi-Fi#Versions_and_generations. + */ enum wifi_link_mode { + /** 802.11 (legacy). */ WIFI_0 = 0, + /** 802.11b. */ WIFI_1, + /** 802.11a. */ WIFI_2, + /** 802.11g. */ WIFI_3, + /** 802.11n. */ WIFI_4, + /** 802.11ac. */ WIFI_5, + /** 802.11ax. */ WIFI_6, + /** 802.11ax 6GHz. */ WIFI_6E, + /** 802.11be. */ WIFI_7, __WIFI_LINK_MODE_AFTER_LAST, @@ -231,9 +276,7 @@ enum wifi_link_mode { WIFI_LINK_MODE_UNKNOWN }; -/** - * wifi_link_mode_txt - Get the link mode type as a text string - */ +/** Helper function to get user-friendly link mode name. */ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode) { switch (link_mode) { @@ -261,13 +304,19 @@ static inline const char *wifi_link_mode_txt(enum wifi_link_mode link_mode) } } +/** Wi-Fi scanning types. */ enum wifi_scan_type { + /** Active scanning (default). */ WIFI_SCAN_TYPE_ACTIVE = 0, + /** Passive scanning. */ WIFI_SCAN_TYPE_PASSIVE, }; +/** Wi-Fi power save states. */ enum wifi_ps { + /** Power save disabled. */ WIFI_PS_DISABLED = 0, + /** Power save enabled. */ WIFI_PS_ENABLED, }; @@ -276,11 +325,14 @@ static const char * const wifi_ps2str[] = { [WIFI_PS_ENABLED] = "Power save enabled", }; +/** Wi-Fi power save modes. */ enum wifi_ps_mode { + /** Legacy power save mode. */ WIFI_PS_MODE_LEGACY = 0, /* This has to be configured before connecting to the AP, * as support for ADDTS action frames is not available. */ + /** WMM power save mode. */ WIFI_PS_MODE_WMM, }; @@ -289,8 +341,11 @@ static const char * const wifi_ps_mode2str[] = { [WIFI_PS_MODE_WMM] = "WMM power save", }; +/** Wi-Fi Target Wake Time (TWT) operations. */ enum wifi_twt_operation { + /* TWT setup operation */ WIFI_TWT_SETUP = 0, + /* TWT teardown operation */ WIFI_TWT_TEARDOWN, }; @@ -299,9 +354,13 @@ static const char * const wifi_twt_operation2str[] = { [WIFI_TWT_TEARDOWN] = "TWT teardown", }; +/** Wi-Fi Target Wake Time (TWT) negotiation types. */ enum wifi_twt_negotiation_type { + /* TWT individual negotiation */ WIFI_TWT_INDIVIDUAL = 0, + /* TWT broadcast negotiation */ WIFI_TWT_BROADCAST, + /* TWT wake TBTT negotiation */ WIFI_TWT_WAKE_TBTT }; @@ -311,25 +370,32 @@ static const char * const wifi_twt_negotiation_type2str[] = { [WIFI_TWT_WAKE_TBTT] = "TWT wake TBTT negotiation", }; +/** Wi-Fi Target Wake Time (TWT) setup commands. */ enum wifi_twt_setup_cmd { - /* TWT Requests */ + /** TWT Requests */ + /* TWT setup request */ WIFI_TWT_SETUP_CMD_REQUEST = 0, + /* TWT setup suggest (parameters can be changed by AP) */ WIFI_TWT_SETUP_CMD_SUGGEST, + /* TWT setup demand (parameters can not be changed by AP) */ WIFI_TWT_SETUP_CMD_DEMAND, - /* TWT Responses */ + /** TWT Responses */ + /* TWT setup grouping (grouping of TWT flows) */ WIFI_TWT_SETUP_CMD_GROUPING, + /* TWT setup accept (parameters accepted by AP) */ WIFI_TWT_SETUP_CMD_ACCEPT, + /* TWT setup alternate (alternate parameters suggested by AP) */ WIFI_TWT_SETUP_CMD_ALTERNATE, + /* TWT setup dictate (parameters dictated by AP) */ WIFI_TWT_SETUP_CMD_DICTATE, + /* TWT setup reject (parameters rejected by AP) */ WIFI_TWT_SETUP_CMD_REJECT, }; static const char * const wifi_twt_setup_cmd2str[] = { - /* TWT Requests */ [WIFI_TWT_SETUP_CMD_REQUEST] = "TWT request", [WIFI_TWT_SETUP_CMD_SUGGEST] = "TWT suggest", [WIFI_TWT_SETUP_CMD_DEMAND] = "TWT demand", - /* TWT Responses */ [WIFI_TWT_SETUP_CMD_GROUPING] = "TWT grouping", [WIFI_TWT_SETUP_CMD_ACCEPT] = "TWT accept", [WIFI_TWT_SETUP_CMD_ALTERNATE] = "TWT alternate", @@ -337,23 +403,37 @@ static const char * const wifi_twt_setup_cmd2str[] = { [WIFI_TWT_SETUP_CMD_REJECT] = "TWT reject", }; +/** Wi-Fi Target Wake Time (TWT) negotiation status. */ enum wifi_twt_setup_resp_status { - /* TWT Setup response status */ + /** TWT response received for TWT request */ WIFI_TWT_RESP_RECEIVED = 0, + /** TWT response not received for TWT request */ WIFI_TWT_RESP_NOT_RECEIVED, }; +/** Target Wake Time (TWT) error codes. */ enum wifi_twt_fail_reason { + /** Unspecified error */ WIFI_TWT_FAIL_UNSPECIFIED, + /** Command execution failed */ WIFI_TWT_FAIL_CMD_EXEC_FAIL, + /** Operation not supported */ WIFI_TWT_FAIL_OPERATION_NOT_SUPPORTED, + /** Unable to get interface status */ WIFI_TWT_FAIL_UNABLE_TO_GET_IFACE_STATUS, + /** Device not connected to AP */ WIFI_TWT_FAIL_DEVICE_NOT_CONNECTED, + /** Peer not HE (802.11ax/Wi-Fi 6) capable */ WIFI_TWT_FAIL_PEER_NOT_HE_CAPAB, + /** Peer not TWT capable */ WIFI_TWT_FAIL_PEER_NOT_TWT_CAPAB, + /** A TWT flow is already in progress */ WIFI_TWT_FAIL_OPERATION_IN_PROGRESS, + /** Invalid negotiated flow id */ WIFI_TWT_FAIL_INVALID_FLOW_ID, + /** IP address not assigned or configured */ WIFI_TWT_FAIL_IP_NOT_ASSIGNED, + /** Flow already exists */ WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS, }; @@ -378,6 +458,7 @@ static const char * const twt_err_code_tbl[] = { "Flow already exists", }; +/** Helper function to get user-friendly TWT error code name. */ static inline const char *get_twt_err_code_str(int16_t err_no) { if ((err_no) < (int16_t)ARRAY_SIZE(twt_err_code_tbl)) { @@ -387,16 +468,25 @@ static inline const char *get_twt_err_code_str(int16_t err_no) return ""; } +/** Wi-Fi power save parameters. */ enum ps_param_type { + /** Power save state. */ WIFI_PS_PARAM_STATE, + /** Power save listen interval. */ WIFI_PS_PARAM_LISTEN_INTERVAL, + /** Power save wakeup mode. */ WIFI_PS_PARAM_WAKEUP_MODE, + /** Power save mode. */ WIFI_PS_PARAM_MODE, + /** Power save timeout. */ WIFI_PS_PARAM_TIMEOUT, }; +/** Wi-Fi power save modes. */ enum wifi_ps_wakeup_mode { + /** DTIM based wakeup. */ WIFI_PS_WAKEUP_MODE_DTIM = 0, + /** Listen interval based wakeup. */ WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL, }; @@ -405,31 +495,40 @@ static const char * const wifi_ps_wakeup_mode2str[] = { [WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL] = "PS wakeup mode listen interval", }; +/** Wi-Fi power save error codes. */ enum wifi_config_ps_param_fail_reason { + /** Unspecified error */ WIFI_PS_PARAM_FAIL_UNSPECIFIED, + /** Command execution failed */ WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL, + /** Parameter not supported */ WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED, + /** Unable to get interface status */ WIFI_PS_PARAM_FAIL_UNABLE_TO_GET_IFACE_STATUS, + /** Device not connected to AP */ WIFI_PS_PARAM_FAIL_DEVICE_NOT_CONNECTED, + /** Device already connected to AP */ WIFI_PS_PARAM_FAIL_DEVICE_CONNECTED, + /** Listen interval out of range */ WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID, }; static const char * const ps_param_config_err_code_tbl[] = { - [WIFI_PS_PARAM_FAIL_UNSPECIFIED] = "Unspecfied", + [WIFI_PS_PARAM_FAIL_UNSPECIFIED] = "Unspecified", [WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL] = "Command Execution failed", [WIFI_PS_PARAM_FAIL_OPERATION_NOT_SUPPORTED] = "Operation not supported", [WIFI_PS_PARAM_FAIL_UNABLE_TO_GET_IFACE_STATUS] = "Unable to get iface status", [WIFI_PS_PARAM_FAIL_DEVICE_NOT_CONNECTED] = - "Can not set while device not connected", + "Cannot set parameters while device not connected", [WIFI_PS_PARAM_FAIL_DEVICE_CONNECTED] = - "Can not set while device already connected", + "Cannot set parameters while device connected", [WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID] = - "Can not set due to invalid range", + "Parameter out of range", }; +/** Helper function to get user-friendly power save error code name. */ static inline const char *get_ps_config_err_code_str(int16_t err_no) { if ((err_no) < (int16_t)ARRAY_SIZE(ps_param_config_err_code_tbl)) { @@ -438,4 +537,8 @@ static inline const char *get_ps_config_err_code_str(int16_t err_no) return ""; } + +/** + * @} + */ #endif /* ZEPHYR_INCLUDE_NET_WIFI_H_ */ diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index fdb2814408b1..09d875f1394f 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -21,6 +21,11 @@ extern "C" { #endif +/** + * @addtogroup wifi_mgmt + * @{ + */ + /* Management part definitions */ #define _NET_WIFI_LAYER NET_MGMT_LAYER_L2 @@ -30,18 +35,31 @@ extern "C" { NET_MGMT_LAYER_CODE(_NET_WIFI_CODE)) #define _NET_WIFI_EVENT (_NET_WIFI_BASE | NET_MGMT_EVENT_BIT) +/** Wi-Fi management commands */ enum net_request_wifi_cmd { + /** Scan for Wi-Fi networks */ NET_REQUEST_WIFI_CMD_SCAN = 1, + /** Connect to a Wi-Fi network */ NET_REQUEST_WIFI_CMD_CONNECT, + /** Disconnect from a Wi-Fi network */ NET_REQUEST_WIFI_CMD_DISCONNECT, + /** Enable AP mode */ NET_REQUEST_WIFI_CMD_AP_ENABLE, + /** Disable AP mode */ NET_REQUEST_WIFI_CMD_AP_DISABLE, + /** Get interface status */ NET_REQUEST_WIFI_CMD_IFACE_STATUS, + /** Set power save status */ NET_REQUEST_WIFI_CMD_PS, + /** Set power save mode */ NET_REQUEST_WIFI_CMD_PS_MODE, + /** Setup or teardown TWT flow */ NET_REQUEST_WIFI_CMD_TWT, + /** Get power save config */ NET_REQUEST_WIFI_CMD_PS_CONFIG, + /** Set or get regulatory domain */ NET_REQUEST_WIFI_CMD_REG_DOMAIN, + /** Set power save timeout */ NET_REQUEST_WIFI_CMD_PS_TIMEOUT, NET_REQUEST_WIFI_CMD_MAX }; @@ -105,15 +123,27 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_REG_DOMAIN); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_PS_TIMEOUT); +/** Wi-Fi management events */ enum net_event_wifi_cmd { + /** Scan results available */ NET_EVENT_WIFI_CMD_SCAN_RESULT = 1, + /** Scan done */ NET_EVENT_WIFI_CMD_SCAN_DONE, + /** Connect result */ NET_EVENT_WIFI_CMD_CONNECT_RESULT, + /** Disconnect result */ NET_EVENT_WIFI_CMD_DISCONNECT_RESULT, + /** Interface status */ NET_EVENT_WIFI_CMD_IFACE_STATUS, + /** TWT events */ NET_EVENT_WIFI_CMD_TWT, + /** TWT sleep status: awake or sleeping, can be used by application + * to determine if it can send data or not. + */ NET_EVENT_WIFI_CMD_TWT_SLEEP_STATE, + /** Raw scan results available */ NET_EVENT_WIFI_CMD_RAW_SCAN_RESULT, + /** Disconnect complete */ NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE, }; @@ -144,8 +174,11 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_DISCONNECT_COMPLETE \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE) +/** Wi-Fi scan parameters */ struct wifi_scan_params { - /* The scan_type is only a hint to the underlying Wi-Fi chip for the + /** Scan type, see enum wifi_scan_type. + * + * The scan_type is only a hint to the underlying Wi-Fi chip for the * preferred mode of scan. The actual mode of scan can depend on factors * such as the Wi-Fi chip implementation support, regulatory domain * restrictions etc. @@ -153,102 +186,155 @@ struct wifi_scan_params { enum wifi_scan_type scan_type; }; -/* Each result is provided to the net_mgmt_event_callback +/** Wi-Fi scan result, each result is provided to the net_mgmt_event_callback * via its info attribute (see net_mgmt.h) */ struct wifi_scan_result { + /** SSID */ uint8_t ssid[WIFI_SSID_MAX_LEN]; + /** SSID length */ uint8_t ssid_length; - + /** Frequency band */ uint8_t band; + /** Channel */ uint8_t channel; + /** Security type */ enum wifi_security_type security; + /** MFP options */ enum wifi_mfp_options mfp; + /** RSSI */ int8_t rssi; - + /** BSSID */ uint8_t mac[WIFI_MAC_ADDR_LEN]; + /** BSSID length */ uint8_t mac_length; }; +/** Wi-Fi connect request parameters */ struct wifi_connect_req_params { + /** SSID */ const uint8_t *ssid; + /** SSID length */ uint8_t ssid_length; /* Max 32 */ - + /** Pre-shared key */ uint8_t *psk; + /** Pre-shared key length */ uint8_t psk_length; /* Min 8 - Max 64 */ - - uint8_t *sae_password; /* Optional with fallback to psk */ + /** SAE password (same as PSK but with no length restrictions), optional */ + uint8_t *sae_password; + /** SAE password length */ uint8_t sae_password_length; /* No length restrictions */ - + /** Frequency band */ uint8_t band; + /** Channel */ uint8_t channel; + /** Security type */ enum wifi_security_type security; + /** MFP options */ enum wifi_mfp_options mfp; - int timeout; /* SYS_FOREVER_MS for no timeout */ + /** Connect timeout in seconds, SYS_FOREVER_MS for no timeout */ + int timeout; }; +/** Generic Wi-Fi status for commands and events */ struct wifi_status { int status; }; +/** Wi-Fi interface status */ struct wifi_iface_status { - int state; /* enum wifi_iface_state */ + /** Interface state, see enum wifi_iface_state */ + int state; + /** SSID length */ unsigned int ssid_len; + /** SSID */ char ssid[WIFI_SSID_MAX_LEN]; + /** BSSID */ char bssid[WIFI_MAC_ADDR_LEN]; + /** Frequency band */ enum wifi_frequency_bands band; + /** Channel */ unsigned int channel; + /** Interface mode, see enum wifi_iface_mode */ enum wifi_iface_mode iface_mode; + /** Link mode, see enum wifi_link_mode */ enum wifi_link_mode link_mode; + /** Security type, see enum wifi_security_type */ enum wifi_security_type security; + /** MFP options, see enum wifi_mfp_options */ enum wifi_mfp_options mfp; + /** RSSI */ int rssi; + /** DTIM period */ unsigned char dtim_period; + /** Beacon interval */ unsigned short beacon_interval; + /** is TWT capable? */ bool twt_capable; }; +/** Wi-Fi power save parameters */ struct wifi_ps_params { + /* Power save state */ enum wifi_ps enabled; + /* Listen interval */ unsigned short listen_interval; + /** Wi-Fi power save wakeup mode */ enum wifi_ps_wakeup_mode wakeup_mode; + /** Wi-Fi power save mode */ enum wifi_ps_mode mode; - /* This is the time out to wait after sending a TX packet + /** Wi-Fi power save timeout + * + * This is the time out to wait after sending a TX packet * before going back to power save (in ms) to receive any replies * from the AP. Zero means this feature is disabled. * * It's a tradeoff between power consumption and latency. */ unsigned int timeout_ms; + /** Wi-Fi power save type */ enum ps_param_type type; + /** Wi-Fi power save fail reason */ enum wifi_config_ps_param_fail_reason fail_reason; }; +/** Wi-Fi TWT parameters */ struct wifi_twt_params { + /** TWT operation, see enum wifi_twt_operation */ enum wifi_twt_operation operation; + /** TWT negotiation type, see enum wifi_twt_negotiation_type */ enum wifi_twt_negotiation_type negotiation_type; + /** TWT setup command, see enum wifi_twt_setup_cmd */ 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; - /* Map requests to responses */ + /** Dialog token, used to map requests to responses */ uint8_t dialog_token; - /* Map setup with teardown */ + /** Flow ID, used to map setup with teardown */ uint8_t flow_id; union { + /** Setup specific parameters */ struct { - /* Interval = Wake up time + Sleeping time */ + /**Interval = Wake up time + Sleeping time */ uint64_t twt_interval; + /** Requestor or responder */ bool responder; + /** Trigger enabled or disabled */ bool trigger; + /** Implicit or explicit */ bool implicit; + /** Announced or unannounced */ bool announce; - /* Wake up time */ + /** Wake up time */ uint32_t twt_wake_interval; } setup; + /** Teardown specific parameters */ struct { - /* Only for Teardown */ + /** Teardown all flows */ bool teardown_all; } teardown; }; + /** TWT fail reason, see enum wifi_twt_fail_reason */ enum wifi_twt_fail_reason fail_reason; }; @@ -257,87 +343,201 @@ struct wifi_twt_params { #define WIFI_MAX_TWT_INTERVAL_US (LONG_MAX - 1) /* 256 (u8) * 1TU */ #define WIFI_MAX_TWT_WAKE_INTERVAL_US 262144 + +/** Wi-Fi TWT flow information */ struct wifi_twt_flow_info { - /* Interval = Wake up time + Sleeping time */ + /** Interval = Wake up time + Sleeping time */ uint64_t twt_interval; - /* Map requests to responses */ + /** Dialog token, used to map requests to responses */ uint8_t dialog_token; - /* Map setup with teardown */ + /** Flow ID, used to map setup with teardown */ uint8_t flow_id; + /** TWT negotiation type, see enum wifi_twt_negotiation_type */ enum wifi_twt_negotiation_type negotiation_type; + /** Requestor or responder */ bool responder; + /** Trigger enabled or disabled */ bool trigger; + /** Implicit or explicit */ bool implicit; + /** Announced or unannounced */ bool announce; - /* Wake up time */ + /** Wake up time */ uint32_t twt_wake_interval; }; +/** Wi-Fi power save configuration */ struct wifi_ps_config { + /** Number of TWT flows */ char num_twt_flows; + /** TWT flow details */ struct wifi_twt_flow_info twt_flows[WIFI_MAX_TWT_FLOWS]; + /** Power save configuration */ struct wifi_ps_params ps_params; }; -/* Generic get/set operation for any command*/ +/** Generic get/set operation for any command*/ enum wifi_mgmt_op { + /** Get operation */ WIFI_MGMT_GET = 0, + /** Set operation */ WIFI_MGMT_SET = 1, }; +/** Regulatory domain information or configuration */ struct wifi_reg_domain { + /* Regulatory domain operation */ enum wifi_mgmt_op oper; - /* Ignore all other regulatory hints */ + /** Ignore all other regulatory hints over this one */ bool force; + /** Country code: ISO/IEC 3166-1 alpha-2 */ uint8_t country_code[WIFI_COUNTRY_CODE_LEN]; }; +/** Wi-Fi TWT sleep states */ enum wifi_twt_sleep_state { + /** TWT sleep state: sleeping */ WIFI_TWT_STATE_SLEEP = 0, + /** TWT sleep state: awake */ WIFI_TWT_STATE_AWAKE = 1, }; -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS +#if defined(CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS) || defined(__DOXYGEN__) +/** Wi-Fi raw scan result */ struct wifi_raw_scan_result { + /** RSSI */ int8_t rssi; + /** Frame length */ int frame_length; + /** Frequency */ unsigned short frequency; + /** Raw scan data */ uint8_t data[CONFIG_WIFI_MGMT_RAW_SCAN_RESULT_LENGTH]; }; #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ #include +/** Scan result callback + * + * @param iface Network interface + * @param status Scan result status + * @param entry Scan result entry + */ typedef void (*scan_result_cb_t)(struct net_if *iface, int status, struct wifi_scan_result *entry); #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS +/** Raw scan result callback + * + * @param iface Network interface + * @param status Raw scan result status + * @param entry Raw scan result entry + */ typedef void (*raw_scan_result_cb_t)(struct net_if *iface, int status, struct wifi_raw_scan_result *entry); #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ + +/** Wi-Fi management API */ struct wifi_mgmt_ops { - /* cb parameter is the cb that should be called for each - * result by the driver. The wifi mgmt part will take care of - * raising the necessary event etc... + /** Scan for Wi-Fi networks + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Scan parameters + * @param cb Callback to be called for each result + * cb parameter is the cb that should be called for each + * result by the driver. The wifi mgmt part will take care of + * raising the necessary event etc. + * + * @return 0 if ok, < 0 if error */ int (*scan)(const struct device *dev, struct wifi_scan_params *params, scan_result_cb_t cb); + /** Connect to a Wi-Fi network + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Connect parameters + * + * @return 0 if ok, < 0 if error + */ int (*connect)(const struct device *dev, struct wifi_connect_req_params *params); + /** Disconnect from a Wi-Fi network + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return 0 if ok, < 0 if error + */ int (*disconnect)(const struct device *dev); + /** Enable AP mode + * + * @param dev Pointer to the device structure for the driver instance. + * @param params AP mode parameters + * + * @return 0 if ok, < 0 if error + */ int (*ap_enable)(const struct device *dev, struct wifi_connect_req_params *params); + /** Disable AP mode + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return 0 if ok, < 0 if error + */ int (*ap_disable)(const struct device *dev); + /** Get interface status + * + * @param dev Pointer to the device structure for the driver instance. + * @param status Interface status + * + * @return 0 if ok, < 0 if error + */ int (*iface_status)(const struct device *dev, struct wifi_iface_status *status); -#ifdef CONFIG_NET_STATISTICS_WIFI +#if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) + /** Get Wi-Fi statistics + * + * @param dev Pointer to the device structure for the driver instance. + * @param stats Wi-Fi statistics + * + * @return 0 if ok, < 0 if error + */ int (*get_stats)(const struct device *dev, struct net_stats_wifi *stats); #endif /* CONFIG_NET_STATISTICS_WIFI */ + /** Set power save status + * + * @param dev Pointer to the device structure for the driver instance. + * @param params Power save parameters + * + * @return 0 if ok, < 0 if error + */ int (*set_power_save)(const struct device *dev, struct wifi_ps_params *params); + /** Setup or teardown TWT flow + * + * @param dev Pointer to the device structure for the driver instance. + * @param params TWT parameters + * + * @return 0 if ok, < 0 if error + */ int (*set_twt)(const struct device *dev, struct wifi_twt_params *params); + /** Get power save config + * + * @param dev Pointer to the device structure for the driver instance. + * @param config Power save config + * + * @return 0 if ok, < 0 if error + */ int (*get_power_save_config)(const struct device *dev, struct wifi_ps_config *config); + /** Set or get regulatory domain + * + * @param dev Pointer to the device structure for the driver instance. + * @param reg_domain Regulatory domain + * + * @return 0 if ok, < 0 if error + */ int (*reg_domain)(const struct device *dev, struct wifi_reg_domain *reg_domain); }; +/** Wi-Fi management offload API */ struct net_wifi_mgmt_offload { /** * Mandatory to get in first position. @@ -345,11 +545,14 @@ struct net_wifi_mgmt_offload { * net_if_api structure. So we make current structure pointer * that can be casted to a net_if_api structure pointer. */ -#ifdef CONFIG_WIFI_USE_NATIVE_NETWORKING +#if defined(CONFIG_WIFI_USE_NATIVE_NETWORKING) || defined(__DOXYGEN__) + /** Ethernet API */ struct ethernet_api wifi_iface; #else + /** Offloaded network device API */ struct offloaded_if_api wifi_iface; #endif + /** Wi-Fi management API */ const struct wifi_mgmt_ops *const wifi_mgmt_api; }; @@ -358,18 +561,63 @@ struct net_wifi_mgmt_offload { */ BUILD_ASSERT(offsetof(struct net_wifi_mgmt_offload, wifi_iface) == 0); +/** Wi-Fi management connect result event + * + * @param iface Network interface + * @param status Connect result status + */ void wifi_mgmt_raise_connect_result_event(struct net_if *iface, int status); + +/** Wi-Fi management disconnect result event + * + * @param iface Network interface + * @param status Disconnect result status + */ void wifi_mgmt_raise_disconnect_result_event(struct net_if *iface, int status); + +/** Wi-Fi management interface status event + * + * @param iface Network interface + * @param iface_status Interface status + */ void wifi_mgmt_raise_iface_status_event(struct net_if *iface, struct wifi_iface_status *iface_status); + +/** Wi-Fi management TWT event + * + * @param iface Network interface + * @param twt_params TWT parameters + */ void wifi_mgmt_raise_twt_event(struct net_if *iface, struct wifi_twt_params *twt_params); + +/** Wi-Fi management TWT sleep state event + * + * @param iface Network interface + * @param twt_sleep_state TWT sleep state + */ void wifi_mgmt_raise_twt_sleep_state(struct net_if *iface, int twt_sleep_state); -#ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS + +#if defined(CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS) || defined(__DOXYGEN__) +/** Wi-Fi management raw scan result event + * + * @param iface Network interface + * @param raw_scan_info Raw scan result + */ void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_info); #endif /* CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS */ + +/** Wi-Fi management disconnect complete event + * + * @param iface Network interface + * @param status Disconnect complete status + */ void wifi_mgmt_raise_disconnect_complete_event(struct net_if *iface, int status); + +/** + * @} + */ #ifdef __cplusplus } #endif From 3e1681eaa1f7fd47307028794ff7592396e20b3c Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Fri, 30 Jun 2023 02:20:49 +0530 Subject: [PATCH 1297/2042] doc: net: Add Wi-Fi management Add Wi-Fi management docs and APIs. Signed-off-by: Chaitanya Tata --- doc/connectivity/networking/api/net_tech.rst | 1 + doc/connectivity/networking/api/wifi.rst | 30 ++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 doc/connectivity/networking/api/wifi.rst diff --git a/doc/connectivity/networking/api/net_tech.rst b/doc/connectivity/networking/api/net_tech.rst index 3575db974b54..910ec4e0cce5 100644 --- a/doc/connectivity/networking/api/net_tech.rst +++ b/doc/connectivity/networking/api/net_tech.rst @@ -10,3 +10,4 @@ Networking Technologies ieee802154.rst thread.rst ppp.rst + wifi.rst diff --git a/doc/connectivity/networking/api/wifi.rst b/doc/connectivity/networking/api/wifi.rst new file mode 100644 index 000000000000..be29d9f8ddaa --- /dev/null +++ b/doc/connectivity/networking/api/wifi.rst @@ -0,0 +1,30 @@ +.. _wifi_mgmt: + +Wi-Fi Management +################ + +Overview +======== + +The Wi-Fi management API is used to manage Wi-Fi networks. It supports below modes: + +* IEEE802.11 Station (STA) +* IEEE802.11 Access Point (AP) + +Only personal mode security is supported with below types: + +* Open +* WPA2-PSK +* WPA3-PSK-256 +* WPA3-SAE + +The Wi-Fi management API is implemented in the `wifi_mgmt` module as a part of the networking L2 stack. +Currently, two types of Wi-Fi drivers are supported: + +* Networking or socket offloaded drivers +* Native L2 Ethernet drivers + +API Reference +************* + +.. doxygengroup:: wifi_mgmt From 9a92e90e0a980c19dfc965f0fdc5f23a818e1dad Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 14 Jul 2023 10:33:09 +0200 Subject: [PATCH 1298/2042] boards: adafruit_itsybitsy_nrf52840: enable ieee802154 Adds a chosen ieee802154 node and enables it. Signed-off-by: Florian Grandel --- .../adafruit_itsybitsy_nrf52840.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boards/arm/adafruit_itsybitsy_nrf52840/adafruit_itsybitsy_nrf52840.dts b/boards/arm/adafruit_itsybitsy_nrf52840/adafruit_itsybitsy_nrf52840.dts index 2b05371899b9..51b199649724 100644 --- a/boards/arm/adafruit_itsybitsy_nrf52840/adafruit_itsybitsy_nrf52840.dts +++ b/boards/arm/adafruit_itsybitsy_nrf52840/adafruit_itsybitsy_nrf52840.dts @@ -21,6 +21,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &code_partition; + zephyr,ieee802154 = &ieee802154; }; leds { @@ -122,6 +123,10 @@ }; }; +&ieee802154 { + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; From 1ec02e92153bcba6d89a3a7cf804c1a351a3ae49 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Fri, 14 Jul 2023 22:22:37 +1000 Subject: [PATCH 1299/2042] MAINTAINERS: add myself to Power Management Add myself to the collaborators on the Power Management subsystem. Signed-off-by: Jordan Yates --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1310a5799d5d..0da4de1a70e0 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1987,6 +1987,7 @@ Power management: - gmarull - teburd - tmleman + - JordanYates files: - include/zephyr/pm/ - samples/subsys/pm/ From d9db00636bba14e07cecbf052d2cbeda885e6e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 12:44:00 +0200 Subject: [PATCH 1300/2042] drivers: video: doc: fix documentation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation for video_format_cap had typos. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/video.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index 5ff3eab1c691..43d7240258f9 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -56,11 +56,11 @@ struct video_format { * * Used to describe a video endpoint format capability. * - * @param pixelformat is a list of supported pixel formats (0 terminated). + * @param pixelformat is the fourcc pixel format value. * @param width_min is the minimum supported frame width. * @param width_max is the maximum supported frame width. - * @param height_min is the minimum supported frame width. - * @param height_max is the maximum supported frame width. + * @param height_min is the minimum supported frame height. + * @param height_max is the maximum supported frame height. * @param width_step is the width step size. * @param height_step is the height step size. */ From 39836e7702e622365f1598d93003a977998c2d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 13:18:30 +0200 Subject: [PATCH 1301/2042] drivers: video: doc: Cleanup Doxygen documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed several missing documentation comments, cleanup struct documentation, and group pixel formats. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/video-controls.h | 40 +++++-- include/zephyr/drivers/video.h | 147 +++++++++++++++++------- 2 files changed, 138 insertions(+), 49 deletions(-) diff --git a/include/zephyr/drivers/video-controls.h b/include/zephyr/drivers/video-controls.h index 1cb37ce86873..7912ab0d91cd 100644 --- a/include/zephyr/drivers/video-controls.h +++ b/include/zephyr/drivers/video-controls.h @@ -29,18 +29,35 @@ extern "C" { #endif -/* Control classes */ -#define VIDEO_CTRL_CLASS_GENERIC 0x00000000 /* Generic class controls */ -#define VIDEO_CTRL_CLASS_CAMERA 0x00010000 /* Camera class controls */ -#define VIDEO_CTRL_CLASS_MPEG 0x00020000 /* MPEG-compression controls */ -#define VIDEO_CTRL_CLASS_JPEG 0x00030000 /* JPEG-compression controls */ -#define VIDEO_CTRL_CLASS_VENDOR 0xFFFF0000 /* Vendor-specific class controls */ +/** + * @name Control classes + * @{ + */ +#define VIDEO_CTRL_CLASS_GENERIC 0x00000000 /**< Generic class controls */ +#define VIDEO_CTRL_CLASS_CAMERA 0x00010000 /**< Camera class controls */ +#define VIDEO_CTRL_CLASS_MPEG 0x00020000 /**< MPEG-compression controls */ +#define VIDEO_CTRL_CLASS_JPEG 0x00030000 /**< JPEG-compression controls */ +#define VIDEO_CTRL_CLASS_VENDOR 0xFFFF0000 /**< Vendor-specific class controls */ +/** + * @} + */ -/* Generic class control IDs */ -#define VIDEO_CID_HFLIP (VIDEO_CTRL_CLASS_GENERIC + 0) /* Mirror the picture horizontally */ -#define VIDEO_CID_VFLIP (VIDEO_CTRL_CLASS_GENERIC + 1) /* Mirror the picture vertically */ +/** + * @name Generic class control IDs + * @{ + */ +/** Mirror the picture horizontally */ +#define VIDEO_CID_HFLIP (VIDEO_CTRL_CLASS_GENERIC + 0) +/** Mirror the picture vertically */ +#define VIDEO_CID_VFLIP (VIDEO_CTRL_CLASS_GENERIC + 1) +/** + * @} + */ -/* Camera class control IDs */ +/** + * @name Camera class control IDs + * @{ + */ #define VIDEO_CID_CAMERA_EXPOSURE (VIDEO_CTRL_CLASS_CAMERA + 0) #define VIDEO_CID_CAMERA_GAIN (VIDEO_CTRL_CLASS_CAMERA + 1) #define VIDEO_CID_CAMERA_ZOOM (VIDEO_CTRL_CLASS_CAMERA + 2) @@ -50,6 +67,9 @@ extern "C" { #define VIDEO_CID_CAMERA_CONTRAST (VIDEO_CTRL_CLASS_CAMERA + 6) #define VIDEO_CID_CAMERA_COLORBAR (VIDEO_CTRL_CLASS_CAMERA + 7) #define VIDEO_CID_CAMERA_QUALITY (VIDEO_CTRL_CLASS_CAMERA + 8) +/** + * @} + */ #ifdef __cplusplus } diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index 43d7240258f9..9a29d9f055ef 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -33,85 +33,92 @@ extern "C" { /** - * @brief video format structure + * @struct video_format + * @brief Video format structure * * Used to configure frame format. - * - * @param pixelformat is the fourcc pixel format value. - * @param width is the frame width in pixels. - * @param height is the frame height in pixels. - * @param pitch is the line stride, the number of bytes that needs to be added - * to the address in the first pixel of a row in order to go to the address - * of the first pixel of the next row (>=width). */ struct video_format { + /** FourCC pixel format value (\ref video_pixel_formats) */ uint32_t pixelformat; + /** frame width in pixels. */ uint32_t width; + /** frame height in pixels. */ uint32_t height; + /** + * @brief line stride. + * + * This is the number of bytes that needs to be added to the address in the + * first pixel of a row in order to go to the address of the first pixel of + * the next row (>=width). + */ uint32_t pitch; }; + /** - * @brief video format capability + * @struct video_format_cap + * @brief Video format capability * * Used to describe a video endpoint format capability. - * - * @param pixelformat is the fourcc pixel format value. - * @param width_min is the minimum supported frame width. - * @param width_max is the maximum supported frame width. - * @param height_min is the minimum supported frame height. - * @param height_max is the maximum supported frame height. - * @param width_step is the width step size. - * @param height_step is the height step size. */ struct video_format_cap { + /** FourCC pixel format value (\ref video_pixel_formats). */ uint32_t pixelformat; + /** minimum supported frame width in pixels. */ uint32_t width_min; + /** maximum supported frame width in pixels. */ uint32_t width_max; + /** minimum supported frame height in pixels. */ uint32_t height_min; + /** maximum supported frame height in pixels. */ uint32_t height_max; + /** width step size in pixels. */ uint16_t width_step; + /** height step size in pixels. */ uint16_t height_step; }; /** - * @brief video capabilities + * @struct video_caps + * @brief Video format capabilities * * Used to describe video endpoint capabilities. - * - * @param format_caps is a list of video format capabilities (zero terminated). - * @param min_vbuf_count is the minimal count of video buffers to enqueue - * before being able to start the stream. */ struct video_caps { + /** list of video format capabilities (zero terminated). */ const struct video_format_cap *format_caps; + /** minimal count of video buffers to enqueue before being able to start + * the stream. + */ uint8_t min_vbuf_count; }; /** - * @brief video buffer structure + * @struct video_buffer + * @brief Video buffer structure * * Represent a video frame. - * - * @param driver_data is a pointer to driver specific data. - * @param buffer is a pointer to the start of the buffer. - * @param size is the size in bytes of the buffer. - * @param bytesused is the number of bytes occupied by the valid data in - * the buffer. - * @param timestamp is a time reference in milliseconds at which the last data - * byte was actually received for input endpoints or to be consumed for - * output endpoints. */ struct video_buffer { + /** pointer to driver specific data. */ void *driver_data; + /** pointer to the start of the buffer. */ uint8_t *buffer; + /** size of the buffer in bytes. */ uint32_t size; + /** number of bytes occupied by the valid data in the buffer. */ uint32_t bytesused; + /** time reference in milliseconds at which the last data byte was + * actually received for input endpoints or to be consumed for output + * endpoints. + */ uint32_t timestamp; }; /** * @brief video_endpoint_id enum + * * Identify the video device endpoint. */ enum video_endpoint_id { @@ -123,6 +130,7 @@ enum video_endpoint_id { /** * @brief video_event enum + * * Identify video event. */ enum video_signal_result { @@ -134,6 +142,7 @@ enum video_signal_result { /** * @typedef video_api_set_format_t * @brief Set video format + * * See video_set_format() for argument descriptions. */ typedef int (*video_api_set_format_t)(const struct device *dev, @@ -142,7 +151,8 @@ typedef int (*video_api_set_format_t)(const struct device *dev, /** * @typedef video_api_get_format_t - * @brief get current video format + * @brief Get current video format + * * See video_get_format() for argument descriptions. */ typedef int (*video_api_get_format_t)(const struct device *dev, @@ -152,6 +162,7 @@ typedef int (*video_api_get_format_t)(const struct device *dev, /** * @typedef video_api_enqueue_t * @brief Enqueue a buffer in the driver’s incoming queue. + * * See video_enqueue() for argument descriptions. */ typedef int (*video_api_enqueue_t)(const struct device *dev, @@ -161,6 +172,7 @@ typedef int (*video_api_enqueue_t)(const struct device *dev, /** * @typedef video_api_dequeue_t * @brief Dequeue a buffer from the driver’s outgoing queue. + * * See video_dequeue() for argument descriptions. */ typedef int (*video_api_dequeue_t)(const struct device *dev, @@ -172,6 +184,7 @@ typedef int (*video_api_dequeue_t)(const struct device *dev, * @typedef video_api_flush_t * @brief Flush endpoint buffers, buffer are moved from incoming queue to * outgoing queue. + * * See video_flush() for argument descriptions. */ typedef int (*video_api_flush_t)(const struct device *dev, @@ -181,6 +194,7 @@ typedef int (*video_api_flush_t)(const struct device *dev, /** * @typedef video_api_stream_start_t * @brief Start the capture or output process. + * * See video_stream_start() for argument descriptions. */ typedef int (*video_api_stream_start_t)(const struct device *dev); @@ -188,13 +202,15 @@ typedef int (*video_api_stream_start_t)(const struct device *dev); /** * @typedef video_api_stream_stop_t * @brief Stop the capture or output process. + * * See video_stream_stop() for argument descriptions. */ typedef int (*video_api_stream_stop_t)(const struct device *dev); /** * @typedef video_api_set_ctrl_t - * @brief set a video control value. + * @brief Set a video control value. + * * See video_set_ctrl() for argument descriptions. */ typedef int (*video_api_set_ctrl_t)(const struct device *dev, @@ -203,7 +219,8 @@ typedef int (*video_api_set_ctrl_t)(const struct device *dev, /** * @typedef video_api_get_ctrl_t - * @brief get a video control value. + * @brief Get a video control value. + * * See video_get_ctrl() for argument descriptions. */ typedef int (*video_api_get_ctrl_t)(const struct device *dev, @@ -213,6 +230,7 @@ typedef int (*video_api_get_ctrl_t)(const struct device *dev, /** * @typedef video_api_get_caps_t * @brief Get capabilities of a video endpoint. + * * See video_get_caps() for argument descriptions. */ typedef int (*video_api_get_caps_t)(const struct device *dev, @@ -222,6 +240,7 @@ typedef int (*video_api_get_caps_t)(const struct device *dev, /** * @typedef video_api_set_signal_t * @brief Register/Unregister poll signal for buffer events. + * * See video_set_signal() for argument descriptions. */ typedef int (*video_api_set_signal_t)(const struct device *dev, @@ -560,21 +579,71 @@ void video_buffer_release(struct video_buffer *buf); #define video_fourcc(a, b, c, d)\ ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) -/* Raw bayer formats */ + +/** + * @defgroup video_pixel_formats Video pixel formats + * @{ + */ + +/** + * @name Bayer formats + * @{ + */ + +/** BGGR8 pixel format */ #define VIDEO_PIX_FMT_BGGR8 video_fourcc('B', 'G', 'G', 'R') /* 8 BGBG.. GRGR.. */ +/** GBRG8 pixel format */ #define VIDEO_PIX_FMT_GBRG8 video_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ +/** GRBG8 pixel format */ #define VIDEO_PIX_FMT_GRBG8 video_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ +/** RGGB8 pixel format */ #define VIDEO_PIX_FMT_RGGB8 video_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ -/* RGB formats */ +/** + * @} + */ + +/** + * @name RGB formats + * @{ + */ + +/** RGB565 pixel format */ #define VIDEO_PIX_FMT_RGB565 video_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ -/* YUV formats */ +/** + * @} + */ + +/** + * @name YUV formats + * @{ + */ + +/** YUYV pixel format */ #define VIDEO_PIX_FMT_YUYV video_fourcc('Y', 'U', 'Y', 'V') /* 16 Y0-Cb0 Y1-Cr0 */ -/* JPEG formats */ +/** + * + * @} + */ + +/** + * @name JPEG formats + * @{ + */ + +/** JPEG pixel format */ #define VIDEO_PIX_FMT_JPEG video_fourcc('J', 'P', 'E', 'G') /* 8 JPEG */ +/** + * @} + */ + +/** + * @} + */ + #ifdef __cplusplus } #endif From c238bb2699b3827177e72f5956c5e577f909be95 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 13 Jul 2023 11:25:59 +0000 Subject: [PATCH 1302/2042] MAINTAINER: update collaborators in some areas Some collaborators moved away or changed responsibilities, so adapt file accordingly. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 0da4de1a70e0..f5d282c09791 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1675,7 +1675,6 @@ Logging: maintainers: - nordic-krch collaborators: - - aasthagr - dcpleung files: - include/zephyr/logging/ @@ -2253,9 +2252,7 @@ Intel Platforms (X86): - jhedberg collaborators: - tbursztyka - - aasthagr - laurenmurphyx64 - - MaureenHelm files: - boards/x86/ - dts/x86/intel/ @@ -2275,7 +2272,6 @@ Intel Platforms (Xtensa): - lgirdwood - marc-hb - kv2019i - - MaureenHelm - ceolin - aborisovich - tmleman @@ -3347,7 +3343,6 @@ x86 arch: - nashif - dcpleung - ceolin - - aasthagr - laurenmurphyx64 files: - arch/x86/ From 3f61dfb4d63c393971ebe15f777ae3d394a17f59 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 13 Jul 2023 11:27:25 +0000 Subject: [PATCH 1303/2042] CODEOWNERS: remove inactive owners Remove inactive owners. Signed-off-by: Anas Nashif --- CODEOWNERS | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a4376eb54cc3..69c4c894d214 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -72,7 +72,7 @@ /soc/arm64/intel_socfpga/* @siclim /soc/Kconfig @tejlmand @galak @nashif @nordicjm /submanifests/* @mbolivar-nordic -/arch/x86/ @jhedberg @nashif @aasthagr +/arch/x86/ @jhedberg @nashif /arch/nios2/ @nashif /arch/posix/ @aescolar @daor-oti /arch/riscv/ @kgugala @pgielda @@ -84,7 +84,7 @@ /soc/riscv/riscv-privileged/neorv32/ @henrikbrixandersen /soc/riscv/riscv-privileged/gd32vf103/ @soburi /soc/riscv/riscv-privileged/niosv/ @sweeaun -/soc/x86/ @dcpleung @nashif @aasthagr +/soc/x86/ @dcpleung @nashif /arch/xtensa/ @dcpleung @andyross @nashif /soc/xtensa/ @dcpleung @andyross @nashif /arch/sparc/ @julius-barendt @@ -184,7 +184,7 @@ /boards/shields/atmel_rf2xx/ @nandojve /boards/shields/esp_8266/ @nandojve /boards/shields/inventek_eswifi/ @nandojve -/boards/x86/ @dcpleung @nashif @aasthagr +/boards/x86/ @dcpleung @nashif /boards/x86/acrn/ @enjiamai /boards/xtensa/ @nashif @dcpleung /boards/xtensa/odroid_go/ @ydamigos @@ -404,7 +404,7 @@ /drivers/serial/*b91* @andy-liu-telink /drivers/serial/uart_altera_jtag.c @nashif @gohshunjing /drivers/serial/uart_altera.c @gohshunjing -/drivers/serial/*ns16550* @dcpleung @nashif @aasthagr +/drivers/serial/*ns16550* @dcpleung @nashif /drivers/serial/*nrfx* @anangl /drivers/serial/uart_liteuart.c @mateusz-holenko @kgugala @pgielda /drivers/serial/Kconfig.mcux_iuart @Mani-Sadhasivam @@ -777,7 +777,6 @@ scripts/build/gen_image_info.py @tejlmand /scripts/build/gen_relocate_app.py @dcpleung /scripts/generate_usb_vif/ @madhurimaparuchuri /scripts/requirements*.txt @mbolivar-nordic @galak @nashif -/scripts/tests/twister/ @aasthagr /scripts/tests/build/test_subfolder_list.py @rmstoi /scripts/tracing/ @nashif /scripts/pylib/twister/ @nashif From ca2533aea1649ede691ffbc4d6fcea97b567df3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 12 Jul 2023 17:06:03 +0200 Subject: [PATCH 1304/2042] doc: Drop Zephyr 2.2 from supported releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of June 30, 2023, Zephyr 3.2.0 is not supported anymore. Signed-off-by: Benjamin Cabé --- doc/conf.py | 1 - doc/releases/index.rst | 4 ---- 2 files changed, 5 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index c29335d3012d..51b4dd593dfd 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -162,7 +162,6 @@ ("latest", "/"), ("3.4.0", "/3.4.0/"), ("3.3.0", "/3.3.0/"), - ("3.2.0", "/3.2.0/"), ("2.7.5 (LTS)", "/2.7.5/"), ), "display_vcs_link": True, diff --git a/doc/releases/index.rst b/doc/releases/index.rst index 27571f65b315..f9cef3349614 100644 --- a/doc/releases/index.rst +++ b/doc/releases/index.rst @@ -56,9 +56,6 @@ Supported Releases +-----------------+----------------+---------------+ | `Zephyr 3.3.0`_ | 2023-02-19 | 2023-10-31 | +-----------------+----------------+---------------+ -| `Zephyr 3.2.0`_ | 2022-09-30 | 2023-06-30 | -+-----------------+----------------+---------------+ - As of 2022-01-01, LTS1 (1.14.x) is not supported and has reached end of life (EOL). @@ -95,6 +92,5 @@ specific release and can be found at https://docs.zephyrproject.org/. .. _`GitHub repository`: https://github.com/zephyrproject-rtos/zephyr .. _`GitHub tagged releases`: https://github.com/zephyrproject-rtos/zephyr/tags .. _`Zephyr 2.7.5`: https://docs.zephyrproject.org/2.7.5/ -.. _`Zephyr 3.2.0`: https://docs.zephyrproject.org/3.2.0/ .. _`Zephyr 3.3.0`: https://docs.zephyrproject.org/3.3.0/ .. _`Zephyr 3.4.0`: https://docs.zephyrproject.org/3.4.0/ From 5443d4127bfe38f3f698ec626907b51569b27eaa Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Fri, 14 Jul 2023 12:28:22 +0200 Subject: [PATCH 1305/2042] drivers: ieee802154: nrf5: Add transmission with multiple CCA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Kconfig IEEE802154_NRF5_MULTIPLE_CCA option is added. The new functions `z_ieee802154_nrf5_extra_cca_attempts_set` and `z_ieee802154_nrf5_extra_cca_attempts_get` are added. The ieee802154_nrf5.c is updated allowing to pass extra cca attempts to nRF 802.15.4 Radio Driver. Signed-off-by: Andrzej Kuroś --- drivers/ieee802154/Kconfig.nrf5 | 11 ++++++++++ drivers/ieee802154/ieee802154_nrf5.c | 24 ++++++++++++++++++-- drivers/ieee802154/ieee802154_nrf5.h | 33 ++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/Kconfig.nrf5 b/drivers/ieee802154/Kconfig.nrf5 index 3ab0d19c3991..1ce67332db00 100644 --- a/drivers/ieee802154/Kconfig.nrf5 +++ b/drivers/ieee802154/Kconfig.nrf5 @@ -88,4 +88,15 @@ config IEEE802154_NRF5_LOG_RX_FAILURES It can be helpful for the network traffic analyze but it generates also a lot of log records in a stress environment. +config IEEE802154_NRF5_MULTIPLE_CCA + bool "Support for multiple CCA attempts before transmission" + help + This is an optional extension not conforming to IEEE Std. 802.15.4-2015. + When this option is enabled the user of ieee802154_nrf5 has possibility + to express the maximum number of extra CCA attempts for a transmission. + The CCA procedure is repeated back-to-back either until it returns + idle channel and the transmission starts, or until 1 + `extra cca attempts` + CCA attempts are performed. Because of that the moment of transmission can be + delayed by the time taken by the extra CCA operations performed. + endif diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index a6a78580dbe5..3c69d5fb4392 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -546,7 +546,8 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) return result; } -static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) +static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, + uint8_t *payload, bool cca) { nrf_802154_transmit_at_metadata_t metadata = { .frame_props = { @@ -561,6 +562,9 @@ static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) .power = net_pkt_ieee802154_txpwr(pkt), #endif }, +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + .extra_cca_attempts = nrf5_radio->extra_cca_attempts +#endif }; uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); @@ -601,7 +605,7 @@ static int nrf5_tx(const struct device *dev, case IEEE802154_TX_MODE_TXTIME: case IEEE802154_TX_MODE_TXTIME_CCA: __ASSERT_NO_MSG(pkt); - ret = nrf5_tx_at(pkt, nrf5_radio->tx_psdu, + ret = nrf5_tx_at(nrf5_radio, pkt, nrf5_radio->tx_psdu, mode == IEEE802154_TX_MODE_TXTIME_CCA); break; #endif /* CONFIG_NET_PKT_TXTIME */ @@ -1157,6 +1161,22 @@ void nrf_802154_serialization_error(const nrf_802154_ser_err_data_t *err) } #endif +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) +void ieee802154_nrf5_extra_cca_attempts_set(const struct device *dev, uint8_t value) +{ + struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); + + nrf5_radio->extra_cca_attempts = value; +} + +uint8_t ieee802154_nrf5_extra_cca_attempts_get(const struct device *dev) +{ + struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); + + return nrf5_radio->extra_cca_attempts; +} +#endif /* defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) */ + static const struct nrf5_802154_config nrf5_radio_cfg = { .irq_config_func = nrf5_irq_config, }; diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index b5a39ce8dfd5..482e4a2e82af 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -89,6 +89,39 @@ struct nrf5_802154_data { /* Indicates if currently processed TX frame has dynamic data updated. */ bool tx_frame_mac_hdr_rdy; + +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + /* The maximum number of extra CCA attempts to be performed before transmission. */ + uint8_t extra_cca_attempts; +#endif }; +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) +/** + * @brief Sets the maximum number of extra CCA attempts to be performed by a transmit operation + * + * The default value of extra cca attempts is 0. + * + * The maximum number of extra cca attempts set by this function is applied to transmissions + * requested with mode IEEE802154_TX_MODE_TXTIME_CCA only. This might change in the future, so + * it is recommended to restore previously used value after each transmission. See + * @ref ieee802154_nrf5_extra_cca_attempts_get. + * + * @param dev Pointer to a ieee802154_nrf5 device + * @param value Value to set. Allowed range is 0...254. + */ +void ieee802154_nrf5_extra_cca_attempts_set(const struct device *dev, uint8_t value); + +/** + * @brief Gets the maximum number of extra CCA attempts to be performed by a transmit operation. + * + * @sa @ref ieee802154_nrf5_extra_cca_attempts_set + * + * @param dev Pointer to a ieee802154_nrf5 device + * @return Maximum number of extra CCA attempts. + */ +uint8_t ieee802154_nrf5_extra_cca_attempts_get(const struct device *dev); + +#endif /* defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) */ + #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ From cb4aa46faffbd715f0266d22d31632e48fe7a69e Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 23 Jun 2023 20:23:42 +0000 Subject: [PATCH 1306/2042] mgmt/MCUmgr/img: Fix img_mgmt_get_other_slot Fix conditional compilation within img_mgmt_get_other_slot, where CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER has been incorrectly checked and #endif incorrectly placed. Signed-off-by: Dominik Ermel --- subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 72262363f5a2..e66293a6c285 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -302,13 +302,13 @@ img_mgmt_get_other_slot(void) switch (slot) { case 1: return 0; -#if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER +#if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER > 2 case 2: return 3; case 3: return 2; - } #endif + } return 1; } From ebaa1458187b43208f85341b7bd4beae1551243f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 23 Jun 2023 19:40:50 +0000 Subject: [PATCH 1307/2042] mgmt/MCUmgr/img: Fix build issue with slot0_ns_partition The commit fixes build issue when building for two application images in board that does not have slot0_ns_partition. Signed-off-by: Dominik Ermel --- .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 48 +++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index e66293a6c285..502ed779f76b 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -40,13 +40,40 @@ #endif #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label) \ - (FIXED_PARTITION_OFFSET(label) == CONFIG_FLASH_LOAD_OFFSET) + (FIXED_PARTITION_OFFSET(label) == CONFIG_FLASH_LOAD_OFFSET) -#if !(FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition) || \ - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot2_partition)) -#error "Unsupported chosen zephyr,code-partition for boot application." +#if FIXED_PARTITION_EXISTS(slot0_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot0_ns_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot1_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition) +#define NUMBER_OF_ACTIVE_IMAGE 0 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot2_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot2_partition) +#define NUMBER_OF_ACTIVE_IMAGE 1 +#endif +#endif + +#if !defined(NUMBER_OF_ACTIVE_IMAGE) && FIXED_PARTITION_EXISTS(slot3_partition) +#if FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot3_partition) +#define NUMBER_OF_ACTIVE_IMAGE 1 +#endif +#endif + +#ifndef NUMBER_OF_ACTIVE_IMAGE +#error "Unsupported code parition is set as active application partition" #endif LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); @@ -124,14 +151,7 @@ int img_mgmt_active_slot(int image) int img_mgmt_active_image(void) { -#if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 2 - if (!(FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition) || - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition) || - FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition))) { - return 1; - } -#endif - return 0; + return NUMBER_OF_ACTIVE_IMAGE; } /* From 7dae27a90df003ba56487b6b9de76a16927ba1ee Mon Sep 17 00:00:00 2001 From: Lawrence King Date: Sat, 15 Apr 2023 11:43:56 -0400 Subject: [PATCH 1308/2042] libc: minimal: math sqrt: sqrtf: fix numeric accuracy of sqrt and sqrtf. Changed initial guess from a simple x/3 to dividing the exponent by 2. This makes large or small numbers like 10e10 and 01e-10 converge in a few loops. Added a loop counter to ensure that the algorithm breaks out of the loop in the case that the algorithm doesn't converge (toggling between two numbers). Added test cases for sqrt and sqrtf in libc. Tested with a range of numbers between 10e10 and 10e-10. Verify good accuracy in test case. Closes: #55962 Signed-off-by: Lawrence King --- lib/libc/minimal/source/math/sqrt.c | 47 +++++- lib/libc/minimal/source/math/sqrtf.c | 48 ++++-- tests/lib/c_lib/src/test_sqrt.c | 233 +++++++++++++++++++++++++++ 3 files changed, 311 insertions(+), 17 deletions(-) create mode 100644 tests/lib/c_lib/src/test_sqrt.c diff --git a/lib/libc/minimal/source/math/sqrt.c b/lib/libc/minimal/source/math/sqrt.c index 4ed372aaddf9..df0f8c0315c4 100644 --- a/lib/libc/minimal/source/math/sqrt.c +++ b/lib/libc/minimal/source/math/sqrt.c @@ -5,19 +5,52 @@ */ #include +#include +#include +#include +#include -double sqrt(double value) +#define MAX_D_ITTERATIONS 8 /* usually converges in 5 loops */ + /* this ensures we break out of the loop */ +#define MAX_D_ERROR_COUNT 5 /* when result almost converges, stop */ +#define EXP_MASK64 GENMASK64(62, 52) + +double sqrt(double square) { - double sqrt = value / 3; int i; + int64_t exponent; + double root; + double last; + int64_t *p_square = (int64_t *)□ + int64_t *p_root = (int64_t *)&root; + int64_t *p_last = (int64_t *)&last; - if (value <= 0) { - return 0; + if (square == 0.0) { + return square; + } + if (square < 0.0) { + return (square - square) / (square - square); } - for (i = 0; i < 6; i++) { - sqrt = (sqrt + value / sqrt) / 2; + /* we need a good starting guess so that this will converge quickly, + * we can do this by dividing the exponent part of the float by 2 + * this assumes IEEE-754 format doubles + */ + exponent = ((*p_square & EXP_MASK64)>>52)-1023; + if (exponent == 0x7FF-1023) { + /* the number is a NAN or inf, return NaN or inf */ + return square + square; } + exponent /= 2; + *p_root = (*p_square & ~EXP_MASK64) | (exponent+1023)<<52; - return sqrt; + for (i = 0; i < MAX_D_ITTERATIONS; i++) { + last = root; + root = (root + square / root) * 0.5; + /* if (llabs(*p_root-*p_last) +#include +#include +#include +#include -#define MINDIFF 2.25e-308 +#define MAX_F_ITTERATIONS 6 /* usually converges in 4 loops */ + /* this ensures we break out of the loop */ +#define MAX_F_ERROR_COUNT 3 /* when result almost converges, stop */ +#define EXP_MASK32 GENMASK(30, 23) float sqrtf(float square) { - float root, last, diff; + int i; + float root; + float last; + int32_t exponent; + int32_t *p_square = (int32_t *)□ + int32_t *p_root = (int32_t *)&root; + int32_t *p_last = (int32_t *)&last; - root = square / 3.0; + if (square == 0.0f) { + return square; + } + if (square < 0.0f) { + return (square - square) / (square - square); + } - if (square <= 0) { - return 0; + /* we need a good starting guess so that this will converge quickly, + * we can do this by dividing the exponent part of the float by 2 + * this assumes IEEE-754 format doubles + */ + exponent = ((*p_square & EXP_MASK32)>>23)-127; + if (exponent == 0xFF-127) { + /* the number is a NAN or inf, return NaN or inf */ + return square + square; } + exponent /= 2; + *p_root = (*p_square & ~EXP_MASK32) | (exponent+127) << 23; - do { + for (i = 0; i < MAX_F_ITTERATIONS; i++) { last = root; - root = (root + square / root) / 2.0; - diff = root - last; - } while (diff > MINDIFF || diff < -MINDIFF); - + root = (root + square / root) * 0.5f; + /* if (labs(*p_root - *p_last) < MAX_F_ERROR_COUNT) */ + if ((*p_root ^ *p_last) < MAX_F_ERROR_COUNT) { + break; + } + } return root; } diff --git a/tests/lib/c_lib/src/test_sqrt.c b/tests/lib/c_lib/src/test_sqrt.c new file mode 100644 index 000000000000..ce7fd4f58594 --- /dev/null +++ b/tests/lib/c_lib/src/test_sqrt.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Lawrence King + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include + + +#define local_abs(x) (((x) < 0) ? -(x) : (x)) + +#ifndef NAN +#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()) +#endif + +static float test_floats[] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, /* numbers across the decade */ + 3.14159265359f, 2.718281828f, /* irrational numbers pi and e */ + 123.4f, 0.025f, 0.10f, 1.875f /* numbers with infinite */ + /* repeating binary representation */ + }; +#define NUM_TEST_FLOATS (sizeof(test_floats)/sizeof(float)) + + static double test_doubles[] = { + 1.0, 2.0, 3.0, 4.0, + 5.0, 6.0, 7.0, 8.0, 9.0, /* numbers across the decade */ + 3.14159265359, 2.718281828, /* irrational numbers pi and e */ + 123.4, 0.025, 0.10, 1.875 /* numbers with infinite */ + /* repeating binary representationa */ +}; +#define NUM_TEST_DOUBLES (sizeof(test_floats)/sizeof(float)) + +#ifndef isinf +static int isinf(double x) +{ + union { uint64_t u; double d; } ieee754; + ieee754.d = x; + ieee754.u &= ~0x8000000000000000; /* ignore the sign */ + return ((ieee754.u >> 52) == 0x7FF) && + ((ieee754.u & 0x000fffffffffffff) == 0); +} +#endif + +#ifndef isnan +static int isnan(double x) +{ + union { uint64_t u; double d; } ieee754; + ieee754.d = x; + ieee754.u &= ~0x8000000000000000; /* ignore the sign */ + return ((ieee754.u >> 52) == 0x7FF) && + ((ieee754.u & 0x000fffffffffffff) != 0); +} +#endif + +#ifndef isinff +static int isinff(float x) +{ + union { uint32_t u; float f; } ieee754; + ieee754.f = x; + ieee754.u &= ~0x80000000; /* ignore the sign */ + return ((ieee754.u >> 23) == 0xFF) && + ((ieee754.u & 0x7FFFFF) == 0); +} +#endif + +#ifndef isnanf +static int isnanf(float x) +{ + union { uint32_t u; float f; } ieee754; + ieee754.f = x; + ieee754.u &= ~0x80000000; /* ignore the sign */ + return ((ieee754.u >> 23) == 0xFF) && + ((ieee754.u & 0x7FFFFF) != 0); +} +#endif + +/* small errors are expected, computed as percentage error */ +#define MAX_FLOAT_ERROR_PERCENT (3.5e-5) +#define MAX_DOUBLE_ERROR_PERCENT (4.5e-14) + +ZTEST(test_c_lib, test_sqrtf) +{ +int i; +float exponent, resf, square, root_squared; +double error; +uint32_t max_error; +int32_t ierror; +int32_t *p_square = (int32_t *)□ +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 native POSIX. + */ + if (!(IS_ENABLED(CONFIG_FPU) + || IS_ENABLED(CONFIG_BOARD_NATIVE_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)"); + zassert_true(isnanf(sqrtf(NANF)), "sqrt(nan)"); +#ifdef issignallingf + zassert_true(issignallingf(sqrtf(NANF)), "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(-10.0f)), "isnanf(sqrt(-10.0))"); + + for (exponent = 1.0e-10f; exponent < 1.0e10f; exponent *= 10.0f) { + for (i = 0; i < NUM_TEST_FLOATS; i++) { + square = test_floats[i] * exponent; + resf = sqrtf(square); + root_squared = resf * resf; + zassert_true((resf > 0.0f) && (resf < INFF), + "sqrtf out of range"); + if ((resf > 0.0f) && (resf < INFF)) { + error = (square - root_squared) / + square * 100; + if (error < 0.0) { + error = -error; + } + /* square and root_squared should be almost identical + * except the last few bits, the EXOR will only set + * the bits that are different + */ + ierror = (*p_square - *p_root_squared); + ierror = local_abs(ierror); + if (ierror > max_error) { + max_error = ierror; + } + } else { + /* negative, +NaN, -NaN, inf or -inf */ + error = 0.0; + } + zassert_true(error < MAX_FLOAT_ERROR_PERCENT, + "max sqrtf error exceeded"); + } + } + zassert_true(max_error < 0x03, "huge errors in sqrt implementation"); + /* print the max error */ + TC_PRINT("test_sqrtf max error %d counts\n", max_error); +} + +ZTEST(test_c_lib, test_sqrt) +{ +int i; +float exponent; +double resd, error, square, root_squared; +uint64_t max_error; +int64_t ierror; +int64_t *p_square = (int64_t *)□ +int64_t *p_root_squared = (int64_t *)&root_squared; + + + max_error = 0; + /* + * sqrt is not supported without FPU except on native POSIX. + */ + if (!(IS_ENABLED(CONFIG_FPU) + || IS_ENABLED(CONFIG_BOARD_NATIVE_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)"); + zassert_true(isnan(sqrt(NAN)), "sqrt(nan)"); +#ifdef issignalling + zassert_true(issignalling(sqrt(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(-10.0)), "isnan(sqrt(-10.0))"); + + for (exponent = 1.0e-10; exponent < 1.0e10; exponent *= 10.0) { + for (i = 0; i < NUM_TEST_DOUBLES; i++) { + square = test_doubles[i] * exponent; + resd = sqrt(square); + root_squared = resd * resd; + zassert_true((resd > 0.0) && (resd < INF), + "sqrt out of range"); + if ((resd > 0.0) && (resd < INF)) { + error = (square - root_squared) / + square * 100; + if (error < 0.0) { + error = -error; + } + /* square and root_squared should be almost identical + * except the last few bits, the EXOR will only set + * the bits that are different + */ + ierror = (*p_square - *p_root_squared); + ierror = local_abs(ierror); + if (ierror > max_error) { + max_error = ierror; + } + } else { + /* negative, +NaN, -NaN, inf or -inf */ + error = 0.0; + } + zassert_true(error < MAX_DOUBLE_ERROR_PERCENT, + "max sqrt error exceeded"); + } + } + zassert_true(max_error < 0x04, "huge errors in sqrt implementation"); + /* print the max error */ + TC_PRINT("test_sqrt max error %d counts\n", (uint32_t)max_error); +} From 983864e4d80ff382df4941e8f286384b0458138b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 3 Jul 2023 21:41:38 +0200 Subject: [PATCH 1309/2042] Bluetooth: BAP: Shell: Add support for multiple TX streams Add support for transmitting on multiple streams, e.g. with the simple `send` command or with the sine generator. This extends the start and stop sine to take a "all" paramter to start sending on all streams. This also fixes an issue with the seq_num when multiple streams are transmitting, since the timing may get delayed which then delays the seq_num which are then scheduled too late. The fix here is to only use the timer for the inital sequence number when starting to send the sine way, and then increment it per TX. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/audio.h | 18 +- subsys/bluetooth/audio/shell/bap.c | 393 ++++++++++++++++++--------- 2 files changed, 275 insertions(+), 136 deletions(-) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index a146964bc10a..e1e39d892a5c 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -59,9 +59,23 @@ struct shell_stream { struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; #if defined(CONFIG_BT_AUDIO_TX) - int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ - uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */ + int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ + uint16_t seq_num; + struct k_work_delayable audio_send_work; + bool tx_active; +#if defined(CONFIG_LIBLC3) + atomic_t lc3_enqueue_cnt; + size_t lc3_sdu_cnt; +#endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ +#if defined(CONFIG_BT_AUDIO_RX) + struct bt_iso_recv_info last_info; + size_t lost_pkts; + size_t err_pkts; + size_t dup_psn; + size_t rx_cnt; + size_t dup_ts; +#endif /* CONFIG_BT_AUDIO_RX */ }; struct broadcast_source { diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 26727dd25d56..7f30567035c6 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -140,14 +140,20 @@ const struct named_lc3_preset *default_source_preset = &lc3_unicast_presets[3]; static const struct named_lc3_preset *default_broadcast_source_preset = &lc3_broadcast_presets[3]; static bool initialized; -#if defined(CONFIG_BT_AUDIO_TX) -static struct bt_bap_stream *txing_stream; - -static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) +static struct shell_stream *shell_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); struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); + + return sh_stream; +} + +#if defined(CONFIG_BT_AUDIO_TX) + +static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) +{ + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); const uint32_t interval_us = bap_stream->qos->interval; int64_t uptime_ticks; int64_t delta_ticks; @@ -162,20 +168,6 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) /* Calculate the sequence number by dividing the stream uptime by the SDU interval */ seq_num = (uint16_t)(delta_us / interval_us); - /* In the case that we call this multiple times, we need to account for any sequence numbers - * already allocated and send to the controller. Ensuring that the next PSN is 1 higher than - * the last we allocated (assuming that we it was actually sent to the controller). - * - * The additional condition that checks that the difference is smaller than a specific value - * is used to handle the case where seq_num has wrapped. - */ - if (seq_num <= sh_stream->last_allocated_seq_num && - sh_stream->last_allocated_seq_num - seq_num < 100) { - seq_num = sh_stream->last_allocated_seq_num + 1; - } - - sh_stream->last_allocated_seq_num = seq_num; - return seq_num; } #endif /* CONFIG_BT_AUDIO_TX */ @@ -185,7 +177,8 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) * controller ISO buffer to handle jitter. */ #define PRIME_COUNT 2U -NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, PRIME_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), +NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #include "lc3.h" @@ -200,22 +193,18 @@ NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, PRIME_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_ static int16_t audio_buf[MAX_NUM_SAMPLES]; static lc3_encoder_t lc3_encoder; static lc3_encoder_mem_48k_t lc3_encoder_mem; -static int freq_hz; -static int frame_duration_us; -static int frame_duration_100us; -static int frames_per_sdu; -static int octets_per_frame; -static int32_t lc3_sdu_cnt; +static int lc3_freq_hz; +static int lc3_frame_duration_us; +static int lc3_frame_duration_100us; +static int lc3_frames_per_sdu; +static int lc3_octets_per_frame; -static void lc3_audio_send_data(struct k_work *work); -static K_WORK_DELAYABLE_DEFINE(audio_send_work, lc3_audio_send_data); - -static void clear_lc3_sine_data(void) +static void clear_lc3_sine_data(struct bt_bap_stream *bap_stream) { - lc3_sdu_cnt = 0; - txing_stream = NULL; + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); - (void)k_work_cancel_delayable(&audio_send_work); + sh_stream->tx_active = false; + (void)k_work_cancel_delayable(&sh_stream->audio_send_work); } /** @@ -248,40 +237,39 @@ static void init_lc3(const struct bt_bap_stream *stream) return; } - freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg); - frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); - octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); - frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); - octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); + lc3_freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg); + lc3_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg); + lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); + lc3_frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); + lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); - if (freq_hz < 0) { + if (lc3_freq_hz < 0) { printk("Error: Codec frequency not set, cannot start codec."); return; } - if (frame_duration_us < 0) { + if (lc3_frame_duration_us < 0) { printk("Error: Frame duration not set, cannot start codec."); return; } - if (octets_per_frame < 0) { + if (lc3_octets_per_frame < 0) { printk("Error: Octets per frame not set, cannot start codec."); return; } - frame_duration_100us = frame_duration_us / 100; + lc3_frame_duration_100us = lc3_frame_duration_us / 100; /* Fill audio buffer with Sine wave only once and repeat encoding the same tone frame */ - fill_audio_buf_sin(audio_buf, frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, freq_hz); + fill_audio_buf_sin(audio_buf, lc3_frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, lc3_freq_hz); - num_samples = ((frame_duration_us * freq_hz) / USEC_PER_SEC); + num_samples = ((lc3_frame_duration_us * lc3_freq_hz) / USEC_PER_SEC); for (size_t i = 0; i < num_samples; i++) { printk("%zu: %6i\n", i, audio_buf[i]); } /* Create the encoder instance. This shall complete before stream_started() is called. */ - lc3_encoder = lc3_setup_encoder(frame_duration_us, freq_hz, - 0, /* No resampling */ + lc3_encoder = lc3_setup_encoder(lc3_frame_duration_us, lc3_freq_hz, 0, /* No resampling */ &lc3_encoder_mem); if (lc3_encoder == NULL) { @@ -291,35 +279,51 @@ static void init_lc3(const struct bt_bap_stream *stream) static void lc3_audio_send_data(struct k_work *work) { - const uint16_t tx_sdu_len = frames_per_sdu * octets_per_frame; + struct shell_stream *sh_stream = CONTAINER_OF(k_work_delayable_from_work(work), + struct shell_stream, audio_send_work); + struct bt_bap_stream *bap_stream = &sh_stream->stream.bap_stream; + const uint16_t tx_sdu_len = lc3_frames_per_sdu * lc3_octets_per_frame; struct net_buf *buf; uint8_t *net_buffer; off_t offset = 0; - uint16_t seq_num; int err; + if (!sh_stream->tx_active) { + /* TX has been aborted */ + return; + } + if (lc3_encoder == NULL) { shell_error(ctx_shell, "LC3 encoder not setup, cannot encode data"); return; } - if (txing_stream == NULL || txing_stream->qos == NULL) { + if (bap_stream == NULL || bap_stream->qos == NULL) { shell_error(ctx_shell, "invalid stream, aborting"); return; } + if (atomic_get(&sh_stream->lc3_enqueue_cnt) == 0U) { + shell_error(ctx_shell, "Stream %p enqueue count was 0", bap_stream); + + /* Reschedule for next interval */ + k_work_reschedule(k_work_delayable_from_work(work), + K_USEC(bap_stream->qos->interval)); + return; + } + buf = net_buf_alloc(&sine_tx_pool, K_FOREVER); net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); net_buffer = net_buf_tail(buf); buf->len += tx_sdu_len; - for (int i = 0; i < frames_per_sdu; i++) { + for (int i = 0; i < lc3_frames_per_sdu; i++) { int lc3_ret; lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, audio_buf, 1, - octets_per_frame, net_buffer + offset); - offset += octets_per_frame; + lc3_octets_per_frame, net_buffer + offset); + offset += lc3_octets_per_frame; if (lc3_ret == -1) { shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", @@ -328,51 +332,54 @@ static void lc3_audio_send_data(struct k_work *work) /* Reschedule for next interval */ k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(txing_stream->qos->interval)); + K_USEC(bap_stream->qos->interval)); return; } } - seq_num = get_next_seq_num(txing_stream); - err = bt_bap_stream_send(txing_stream, buf, seq_num, BT_ISO_TIMESTAMP_NONE); + err = bt_bap_stream_send(bap_stream, buf, sh_stream->seq_num, BT_ISO_TIMESTAMP_NONE); if (err < 0) { shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err); net_buf_unref(buf); /* Reschedule for next interval */ k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(txing_stream->qos->interval)); + K_USEC(bap_stream->qos->interval)); return; } - if ((lc3_sdu_cnt % 100) == 0) { - shell_info(ctx_shell, "[%zu]: TX LC3: %zu (seq_num %u)", lc3_sdu_cnt, tx_sdu_len, - seq_num); + if ((sh_stream->lc3_sdu_cnt % 100) == 0) { + shell_info(ctx_shell, "[%zu]: stream %p : TX LC3: %zu (seq_num %u)", + sh_stream->lc3_sdu_cnt, bap_stream, tx_sdu_len, sh_stream->seq_num); } - lc3_sdu_cnt++; + sh_stream->lc3_sdu_cnt++; + sh_stream->seq_num++; + atomic_dec(&sh_stream->lc3_enqueue_cnt); - /* If we have more buffers available, we reschedule the workqueue item immediately to - * trigger antother encode + TX, but without blocking this call for too long - */ - buf = net_buf_alloc(&sine_tx_pool, K_NO_WAIT); - if (buf != NULL) { - net_buf_unref(buf); + if (atomic_get(&sh_stream->lc3_enqueue_cnt) > 0) { + /* If we have more buffers available, we reschedule the workqueue item immediately + * to trigger another encode + TX, but without blocking this call for too long + */ k_work_reschedule(k_work_delayable_from_work(work), K_NO_WAIT); } } -void sdu_sent_cb(struct bt_bap_stream *stream) +void sdu_sent_cb(struct bt_bap_stream *bap_stream) { + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); int err; - if (txing_stream == NULL || txing_stream->qos == NULL) { + atomic_inc(&sh_stream->lc3_enqueue_cnt); + + if (!sh_stream->tx_active) { + /* TX has been aborted */ return; } - err = k_work_schedule(&audio_send_work, K_NO_WAIT); + err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT); if (err < 0) { - shell_error(ctx_shell, "Failed to schedule TX: %d", err); + shell_error(ctx_shell, "Failed to schedule TX for stream %p: %d", bap_stream, err); } } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ @@ -945,7 +952,6 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED; const struct named_lc3_preset *named_preset; struct shell_stream *uni_stream; - struct bt_cap_stream *cap_stream; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep = NULL; unsigned long index; @@ -1052,8 +1058,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) } } - cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - uni_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); + uni_stream = shell_stream_from_bap_stream(bap_stream); copy_unicast_stream_preset(uni_stream, named_preset); /* If location has been modifed, we update the location in the codec configuration */ @@ -1683,45 +1688,41 @@ static struct bt_bap_broadcast_sink_cb sink_cbs = { #if defined(CONFIG_BT_AUDIO_RX) static unsigned long recv_stats_interval = 100U; -static size_t lost_pkts; -static size_t err_pkts; -static size_t dup_psn; -static size_t rx_cnt; -static size_t dup_ts; static void audio_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - static struct bt_iso_recv_info last_info; + struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); - rx_cnt++; + sh_stream->rx_cnt++; - if (info->ts == last_info.ts) { - dup_ts++; + if (info->ts == sh_stream->last_info.ts) { + sh_stream->dup_ts++; } - if (info->seq_num == last_info.seq_num) { - dup_psn++; + if (info->seq_num == sh_stream->last_info.seq_num) { + sh_stream->dup_psn++; } if (info->flags & BT_ISO_FLAGS_ERROR) { - err_pkts++; + sh_stream->err_pkts++; } if (info->flags & BT_ISO_FLAGS_LOST) { - lost_pkts++; + sh_stream->lost_pkts++; } - if ((rx_cnt % recv_stats_interval) == 0) { + if ((sh_stream->rx_cnt % recv_stats_interval) == 0) { shell_print(ctx_shell, "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u " "(dup ts %zu; dup psn %zu, err_pkts %zu, lost_pkts %zu)", - rx_cnt, stream, buf->len, info->ts, info->seq_num, info->flags, dup_ts, - dup_psn, err_pkts, lost_pkts); + sh_stream->rx_cnt, stream, buf->len, info->ts, info->seq_num, + info->flags, sh_stream->dup_ts, sh_stream->dup_psn, sh_stream->err_pkts, + sh_stream->lost_pkts); } - (void)memcpy(&last_info, info, sizeof(last_info)); + (void)memcpy(&sh_stream->last_info, info, sizeof(sh_stream->last_info)); } #endif /* CONFIG_BT_AUDIO_RX */ @@ -1764,25 +1765,24 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) static void stream_started_cb(struct bt_bap_stream *bap_stream) { -#if defined(CONFIG_BT_AUDIO_TX) - struct bt_cap_stream *cap_stream = - CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream); + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); +#if defined(CONFIG_BT_AUDIO_TX) sh_stream->connected_at_ticks = k_uptime_ticks(); - - /* Set to max value to support sending the first packet with PSN = 0*/ - sh_stream->last_allocated_seq_num = UINT16_MAX; +#if defined(CONFIG_LIBLC3) + atomic_set(&sh_stream->lc3_enqueue_cnt, PRIME_COUNT); + sh_stream->lc3_sdu_cnt = 0U; +#endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ printk("Stream %p started\n", bap_stream); #if defined(CONFIG_BT_AUDIO_RX) - lost_pkts = 0U; - err_pkts = 0U; - dup_psn = 0U; - rx_cnt = 0U; - dup_ts = 0U; + sh_stream->lost_pkts = 0U; + sh_stream->err_pkts = 0U; + sh_stream->dup_psn = 0U; + sh_stream->rx_cnt = 0U; + sh_stream->dup_ts = 0U; #endif } @@ -1791,9 +1791,7 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) printk("Stream %p stopped with reason 0x%02X\n", stream, reason); #if defined(CONFIG_LIBLC3) - if (stream == default_stream) { - clear_lc3_sine_data(); - } + clear_lc3_sine_data(stream); #endif /* CONFIG_LIBLC3 */ } @@ -1840,9 +1838,7 @@ static void stream_released_cb(struct bt_bap_stream *stream) #if defined(CONFIG_LIBLC3) /* stop sending */ - if (stream == default_stream) { - clear_lc3_sine_data(); - } + clear_lc3_sine_data(stream); #endif /* CONFIG_LIBLC3 */ } #endif /* CONFIG_BT_BAP_UNICAST */ @@ -2394,12 +2390,6 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (txing_stream != NULL) { - shell_error(sh, "A stream %p is already TXing", txing_stream); - - return -ENOEXEC; - } - if (default_stream->qos == NULL) { shell_error(sh, "NULL stream QoS"); @@ -2424,7 +2414,7 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) net_buf_add_mem(buf, data, len); - ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(txing_stream), + ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(default_stream), BT_ISO_TIMESTAMP_NONE); if (ret < 0) { shell_print(sh, "Unable to send: %d", -ret); @@ -2440,37 +2430,134 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) } #if defined(CONFIG_LIBLC3) -static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) +static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream) { + int stream_frame_duration_us; + struct bt_bap_ep_info info; + int stream_freq_hz; int err; - if (default_stream == NULL) { - shell_error(sh, "Invalid (NULL) stream"); + if (bap_stream == NULL || bap_stream->qos == NULL) { + return false; + } - return -ENOEXEC; + err = bt_bap_ep_get_info(bap_stream->ep, &info); + if (err != 0) { + return false; } - if (txing_stream == NULL) { - txing_stream = default_stream; - } else { - shell_error(sh, "A stream %p is already TXing", txing_stream); + if (info.state != BT_BAP_EP_STATE_STREAMING) { + return false; + } - return -ENOEXEC; + stream_freq_hz = bt_audio_codec_cfg_get_freq(bap_stream->codec_cfg); + if (stream_freq_hz != lc3_freq_hz) { + return false; + } + + stream_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(bap_stream->codec_cfg); + if (stream_frame_duration_us != lc3_frame_duration_us) { + return false; } - if (txing_stream->qos == NULL) { - shell_error(ctx_shell, "NULL stream QoS"); + return true; +} +static int stream_start_sine(struct bt_bap_stream *bap_stream) +{ + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); + int err; - txing_stream = NULL; + k_work_init_delayable(&sh_stream->audio_send_work, lc3_audio_send_data); + err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT); + if (err < 0) { return -ENOEXEC; } - init_lc3(txing_stream); + sh_stream->tx_active = true; + sh_stream->seq_num = get_next_seq_num(bap_stream); - err = k_work_schedule(&audio_send_work, K_NO_WAIT); - if (err < 0) { - shell_error(ctx_shell, "Failed to schedule TX: %d", err); + return 0; +} + +static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) +{ + bool start_all = false; + int err; + + if (argc > 1) { + if (strcmp(argv[1], "all") == 0) { + start_all = true; + } else { + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; + } + } + + if (start_all) { + bool lc3_initialized = false; + + for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { + struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream; + + if (!lc3_initialized) { + init_lc3(bap_stream); + lc3_initialized = true; + } + + if (!stream_start_sine_verify(bap_stream)) { + continue; + } + + err = stream_start_sine(bap_stream); + if (err != 0) { + shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream, + err); + return err; + } + + shell_print(sh, "Started transmitting on unicast stream %p", bap_stream); + } + + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { + struct bt_bap_stream *bap_stream = + &broadcast_source_streams[i].stream.bap_stream; + + if (!lc3_initialized) { + init_lc3(bap_stream); + lc3_initialized = true; + } + + if (!stream_start_sine_verify(bap_stream)) { + continue; + } + + err = stream_start_sine(bap_stream); + if (err != 0) { + shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream, + err); + return err; + } + + 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; + } + + init_lc3(default_stream); + + err = stream_start_sine(default_stream); + if (err != 0) { + shell_error(sh, "Failed to start TX for stream %p: %d", default_stream, + err); + return err; + } + + shell_print(sh, "Started transmitting on default_stream %p", default_stream); } return 0; @@ -2478,7 +2565,44 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[]) { - clear_lc3_sine_data(); + bool stop_all = false; + + if (argc > 1) { + if (strcmp(argv[1], "all") == 0) { + stop_all = true; + } else { + shell_help(sh); + + return SHELL_CMD_HELP_PRINTED; + } + } + + if (stop_all) { + for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) { + struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream; + + if (unicast_streams[i].tx_active) { + clear_lc3_sine_data(bap_stream); + shell_print(sh, "Stopped transmitting on stream %p", bap_stream); + } + } + + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) { + struct bt_bap_stream *bap_stream = + &broadcast_source_streams[i].stream.bap_stream; + if (unicast_streams[i].tx_active) { + clear_lc3_sine_data(bap_stream); + shell_print(sh, "Stopped transmitting on stream %p", bap_stream); + } + } + } else { + struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream); + + if (sh_stream->tx_active) { + clear_lc3_sine_data(default_stream); + shell_print(sh, "Stopped transmitting on stream %p", default_stream); + } + } return 0; } @@ -2583,9 +2707,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE( #if defined(CONFIG_BT_AUDIO_TX) SHELL_CMD_ARG(send, NULL, "Send to Audio Stream [data]", cmd_send, 1, 1), #if defined(CONFIG_LIBLC3) - SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave", cmd_start_sine, 1, - 0), - SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave", cmd_stop_sine, 1, 0), + SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave [all]", + cmd_start_sine, 1, 1), + SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave [all]", cmd_stop_sine, + 1, 1), #endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ #if defined(CONFIG_BT_AUDIO_RX) From 388af8fda4672c50b5ccc0a255fa61b959ac6bf6 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 11 Jul 2023 15:15:03 +0200 Subject: [PATCH 1310/2042] Bluetooth: BAP: Remove stream->dir field The BAP stream object should not have a dir field. The dir field should be stored in the EP only (to avoid having two fields storing the same value, causing possible issues). The field was removed, and the places that use it has been updated. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/audio/bap.h | 3 --- subsys/bluetooth/audio/bap_iso.c | 14 ++++++------ subsys/bluetooth/audio/bap_iso.h | 6 ++++-- subsys/bluetooth/audio/bap_unicast_client.c | 24 ++++++++++++++------- tests/bluetooth/tester/src/btp_bap.c | 9 +++++++- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index eb5829a67b88..f917f5c35a92 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -445,9 +445,6 @@ int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info); * connected isochronous stream. */ struct bt_bap_stream { - /** Stream direction */ - enum bt_audio_dir dir; - /** Connection reference */ struct bt_conn *conn; diff --git a/subsys/bluetooth/audio/bap_iso.c b/subsys/bluetooth/audio/bap_iso.c index 3478f91a24c4..cb68a8032f51 100644 --- a/subsys/bluetooth/audio/bap_iso.c +++ b/subsys/bluetooth/audio/bap_iso.c @@ -234,7 +234,8 @@ struct bt_bap_ep *bt_bap_iso_get_paired_ep(const struct bt_bap_ep *ep) } #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) -void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream) +void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream, + enum bt_audio_dir dir) { struct bt_bap_iso_dir *bap_iso_ep; @@ -243,10 +244,10 @@ void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *st __ASSERT(stream->bap_iso == NULL, "stream %p bound with bap_iso %p already", stream, stream->bap_iso); - LOG_DBG("bap_iso %p stream %p dir %s", bap_iso, stream, bt_audio_dir_str(stream->dir)); + LOG_DBG("bap_iso %p stream %p dir %s", bap_iso, stream, bt_audio_dir_str(dir)); /* For the unicast client, the direction and tx/rx is reversed */ - if (stream->dir == BT_AUDIO_DIR_SOURCE) { + if (dir == BT_AUDIO_DIR_SOURCE) { bap_iso_ep = &bap_iso->rx; } else { bap_iso_ep = &bap_iso->tx; @@ -259,7 +260,8 @@ void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *st stream->bap_iso = bt_bap_iso_ref(bap_iso); } -void bt_bap_iso_unbind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream) +void bt_bap_iso_unbind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream, + enum bt_audio_dir dir) { struct bt_bap_iso_dir *bap_iso_ep; @@ -267,10 +269,10 @@ void bt_bap_iso_unbind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream * __ASSERT_NO_MSG(bap_iso != NULL); __ASSERT(stream->bap_iso != NULL, "stream %p not bound with an bap_iso", stream); - LOG_DBG("bap_iso %p stream %p dir %s", bap_iso, stream, bt_audio_dir_str(stream->dir)); + LOG_DBG("bap_iso %p stream %p dir %s", bap_iso, stream, bt_audio_dir_str(dir)); /* For the unicast client, the direction and tx/rx is reversed */ - if (stream->dir == BT_AUDIO_DIR_SOURCE) { + if (dir == BT_AUDIO_DIR_SOURCE) { bap_iso_ep = &bap_iso->rx; } else { bap_iso_ep = &bap_iso->tx; diff --git a/subsys/bluetooth/audio/bap_iso.h b/subsys/bluetooth/audio/bap_iso.h index abc586b9c0fd..a849285475d8 100644 --- a/subsys/bluetooth/audio/bap_iso.h +++ b/subsys/bluetooth/audio/bap_iso.h @@ -47,6 +47,8 @@ struct bt_bap_ep *bt_bap_iso_get_ep(bool unicast_client, struct bt_bap_iso *iso, struct bt_bap_ep *bt_bap_iso_get_paired_ep(const struct bt_bap_ep *ep); /* Unicast client-only functions*/ -void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream); -void bt_bap_iso_unbind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream); +void bt_bap_iso_bind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream, + enum bt_audio_dir dir); +void bt_bap_iso_unbind_stream(struct bt_bap_iso *bap_iso, struct bt_bap_stream *stream, + enum bt_audio_dir dir); struct bt_bap_stream *bt_bap_iso_get_stream(struct bt_bap_iso *iso, enum bt_audio_dir dir); diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index 0e9964a3a240..2720f903c142 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -2511,11 +2511,10 @@ static void unicast_group_add_stream(struct bt_bap_unicast_group *group, __ASSERT_NO_MSG(stream->ep == NULL || (stream->ep != NULL && stream->ep->iso == NULL)); stream->qos = qos; - stream->dir = dir; stream->group = group; /* iso initialized already */ - bt_bap_iso_bind_stream(iso, stream); + bt_bap_iso_bind_stream(iso, stream, dir); if (stream->ep != NULL) { bt_bap_iso_bind_ep(iso, stream->ep); } @@ -2561,7 +2560,7 @@ static int unicast_group_add_stream_pair(struct bt_bap_unicast_group *group, } static void unicast_group_del_stream(struct bt_bap_unicast_group *group, - struct bt_bap_stream *stream) + struct bt_bap_stream *stream, enum bt_audio_dir dir) { __ASSERT_NO_MSG(group != NULL); __ASSERT_NO_MSG(stream != NULL); @@ -2570,7 +2569,7 @@ static void unicast_group_del_stream(struct bt_bap_unicast_group *group, struct bt_bap_ep *ep = stream->ep; if (stream->bap_iso != NULL) { - bt_bap_iso_unbind_stream(stream->bap_iso, stream); + bt_bap_iso_unbind_stream(stream->bap_iso, stream, dir); } if (ep != NULL && ep->iso != NULL) { @@ -2592,12 +2591,12 @@ static void unicast_group_del_stream_pair(struct bt_bap_unicast_group *group, if (param->rx_param != NULL) { __ASSERT_NO_MSG(param->rx_param->stream); - unicast_group_del_stream(group, param->rx_param->stream); + unicast_group_del_stream(group, param->rx_param->stream, BT_AUDIO_DIR_SOURCE); } if (param->tx_param != NULL) { __ASSERT_NO_MSG(param->tx_param->stream); - unicast_group_del_stream(group, param->tx_param->stream); + unicast_group_del_stream(group, param->tx_param->stream, BT_AUDIO_DIR_SINK); } } @@ -2628,11 +2627,20 @@ static void unicast_group_free(struct bt_bap_unicast_group *group) __ASSERT_NO_MSG(group != NULL); SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&group->streams, stream, next, _node) { + struct bt_bap_iso *bap_iso = stream->bap_iso; struct bt_bap_ep *ep = stream->ep; stream->group = NULL; - if (stream->bap_iso != NULL) { - bt_bap_iso_unbind_stream(stream->bap_iso, stream); + if (bap_iso != NULL) { + if (bap_iso->rx.stream == stream) { + bt_bap_iso_unbind_stream(stream->bap_iso, stream, + BT_AUDIO_DIR_SOURCE); + } else if (bap_iso->tx.stream == stream) { + bt_bap_iso_unbind_stream(stream->bap_iso, stream, + BT_AUDIO_DIR_SINK); + } else { + __ASSERT_PRINT("stream %p has invalid bap_iso %p", stream, bap_iso); + } } if (ep != NULL && ep->iso != NULL) { diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index ee3b55ccc9fc..8591c43de042 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -561,10 +561,17 @@ static void stream_released(struct bt_bap_stream *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; + int err; LOG_DBG("Started stream %p", stream); - if (stream->dir == BT_AUDIO_DIR_SINK) { + err = bt_bap_ep_get_info(stream->ep, &info); + if (err) { + LOG_ERR("Could not get EP info for stream %p", stream); + } + + if (info.dir == BT_AUDIO_DIR_SINK) { /* 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. */ From 29d0cef49f073a871f4e925b91e3d1c512a51d72 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 13 Jul 2023 10:25:05 +0000 Subject: [PATCH 1311/2042] pinctrl: rv32m1: delay init priority after the clock controller The rv32m1 pinctrl driver depends on clock controller, add a new symbol and set it so it gets initialized after that, and before other devices. Fixes: $ west build -p -b rv32m1_vega_ri5cy tests/kernel/common \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /soc/pinmux@41037000 PRE_KERNEL_1 1 < \ /soc/clock-controller@41027000 PRE_KERNEL_1 30 Signed-off-by: Fabio Baltieri --- drivers/pinctrl/Kconfig.rv32m1 | 7 +++++++ drivers/pinctrl/pinctrl_rv32m1.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig.rv32m1 b/drivers/pinctrl/Kconfig.rv32m1 index 4b50821d8093..dfdb0c65e4c3 100644 --- a/drivers/pinctrl/Kconfig.rv32m1 +++ b/drivers/pinctrl/Kconfig.rv32m1 @@ -7,3 +7,10 @@ config PINCTRL_RV32M1 depends on DT_HAS_OPENISA_RV32M1_PINMUX_ENABLED help Enable the RV32M1 pin controller driver. + +config PINCTRL_RV32M1_INIT_PRIORITY + int "RV32M1 initialization priority" + default 35 + depends on PINCTRL_RV32M1 + help + RV32M1 pin controller initialization priority. diff --git a/drivers/pinctrl/pinctrl_rv32m1.c b/drivers/pinctrl/pinctrl_rv32m1.c index 5660b11725bf..7351cec9496f 100644 --- a/drivers/pinctrl/pinctrl_rv32m1.c +++ b/drivers/pinctrl/pinctrl_rv32m1.c @@ -61,7 +61,7 @@ static int pinctrl_rv32m1_init(const struct device *dev) NULL, \ NULL, &pinctrl_rv32m1_##n##_config, \ PRE_KERNEL_1, \ - 1, \ + CONFIG_PINCTRL_RV32M1_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(PINCTRL_RV32M1_INIT) From 76663444c1faa8618ddf0cef735b77ffffce4700 Mon Sep 17 00:00:00 2001 From: Prashanth S Date: Fri, 14 Jul 2023 08:52:28 +0530 Subject: [PATCH 1312/2042] include: zephyr: Fix build error in spinlock.h In function z_spin_onexit, when CONFIG_FORCE_NO_ASSERT=y and CONFIG_SPIN_VALIDATE=y the function parameter becomes unused. This generates a build error (unused parameter 'k'). Add __maybe_unused to fix this error. Signed-off-by: Prashanth S --- include/zephyr/spinlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/spinlock.h b/include/zephyr/spinlock.h index 79965200ef58..d97bda761d51 100644 --- a/include/zephyr/spinlock.h +++ b/include/zephyr/spinlock.h @@ -278,7 +278,7 @@ static ALWAYS_INLINE void k_spin_release(struct k_spinlock *l) } #if defined(CONFIG_SPIN_VALIDATE) && defined(__GNUC__) -static ALWAYS_INLINE void z_spin_onexit(k_spinlock_key_t *k) +static ALWAYS_INLINE void z_spin_onexit(__maybe_unused k_spinlock_key_t *k) { __ASSERT(k->key, "K_SPINLOCK exited with goto, break or return, " "use K_SPINLOCK_BREAK instead."); From c59b04299fbca7d40597d383e428c9a892cc1ee8 Mon Sep 17 00:00:00 2001 From: Mike Fikes Date: Fri, 14 Jul 2023 14:15:50 -0400 Subject: [PATCH 1313/2042] doc: isotp introduce CF abbreviation Introduce the CF abbreviation as is done for other abbreviations (like FF) before first use. Signed-off-by: Mike Fikes --- doc/hardware/peripherals/canbus/isotp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/hardware/peripherals/canbus/isotp.rst b/doc/hardware/peripherals/canbus/isotp.rst index 6953a04a92e0..325a45cc0366 100644 --- a/doc/hardware/peripherals/canbus/isotp.rst +++ b/doc/hardware/peripherals/canbus/isotp.rst @@ -28,7 +28,7 @@ Packets smaller or equal to seven bytes on Classical CAN are called single-frames (SF). They don't need to fragment and do not have any flow-control. Packets larger than that are segmented into a first-frame (FF) and as many -consecutive-frames as required. The FF contains information about the length of +consecutive-frames (CF) as required. The FF contains information about the length of the entire payload data and additionally, the first few bytes of payload data. The receiving peer sends back a flow-control-frame (FC) to either deny, postpone, or accept the following consecutive frames. From 0e97c9d14de0d6a6e75ec86b676b63862b5e8812 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Tue, 11 Jul 2023 11:12:14 +0530 Subject: [PATCH 1314/2042] soc: ti_k3: Added SoC files for Cortex M4F on ti_am62x_sk Added SoC support files for the Cortex M4F core on the TI AM62X SK EVM. Signed-off-by: L Lakshmanan --- soc/arm/ti_k3/CMakeLists.txt | 8 +++ soc/arm/ti_k3/Kconfig | 19 +++++++ soc/arm/ti_k3/Kconfig.defconfig | 8 +++ soc/arm/ti_k3/Kconfig.soc | 8 +++ soc/arm/ti_k3/am62x_m4/CMakeLists.txt | 11 ++++ .../ti_k3/am62x_m4/Kconfig.defconfig.am62xm4 | 13 +++++ .../ti_k3/am62x_m4/Kconfig.defconfig.series | 52 +++++++++++++++++++ soc/arm/ti_k3/am62x_m4/Kconfig.series | 22 ++++++++ soc/arm/ti_k3/am62x_m4/Kconfig.soc | 28 ++++++++++ soc/arm/ti_k3/am62x_m4/linker.ld | 18 +++++++ soc/arm/ti_k3/am62x_m4/soc.c | 49 +++++++++++++++++ soc/arm/ti_k3/am62x_m4/soc.h | 7 +++ 12 files changed, 243 insertions(+) create mode 100644 soc/arm/ti_k3/CMakeLists.txt create mode 100644 soc/arm/ti_k3/Kconfig create mode 100644 soc/arm/ti_k3/Kconfig.defconfig create mode 100644 soc/arm/ti_k3/Kconfig.soc create mode 100644 soc/arm/ti_k3/am62x_m4/CMakeLists.txt create mode 100644 soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62xm4 create mode 100644 soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.series create mode 100644 soc/arm/ti_k3/am62x_m4/Kconfig.series create mode 100644 soc/arm/ti_k3/am62x_m4/Kconfig.soc create mode 100644 soc/arm/ti_k3/am62x_m4/linker.ld create mode 100644 soc/arm/ti_k3/am62x_m4/soc.c create mode 100644 soc/arm/ti_k3/am62x_m4/soc.h diff --git a/soc/arm/ti_k3/CMakeLists.txt b/soc/arm/ti_k3/CMakeLists.txt new file mode 100644 index 000000000000..4f789e9b56ef --- /dev/null +++ b/soc/arm/ti_k3/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/arm/ti_k3/Kconfig b/soc/arm/ti_k3/Kconfig new file mode 100644 index 000000000000..501654fec1ac --- /dev/null +++ b/soc/arm/ti_k3/Kconfig @@ -0,0 +1,19 @@ +# Texas Instruments K3 Family +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_TI_K3 + bool + +if SOC_FAMILY_TI_K3 + +config SOC_FAMILY + string + default "ti_k3" + +source "soc/arm/ti_k3/*/Kconfig.soc" + +endif # SOC_FAMILY_TI_K3 diff --git a/soc/arm/ti_k3/Kconfig.defconfig b/soc/arm/ti_k3/Kconfig.defconfig new file mode 100644 index 000000000000..668e287ccf7c --- /dev/null +++ b/soc/arm/ti_k3/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Texas Instruments K3 Family +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/ti_k3/*/Kconfig.defconfig.series" diff --git a/soc/arm/ti_k3/Kconfig.soc b/soc/arm/ti_k3/Kconfig.soc new file mode 100644 index 000000000000..65d1506917b6 --- /dev/null +++ b/soc/arm/ti_k3/Kconfig.soc @@ -0,0 +1,8 @@ +# Texas Instruments K3 Family +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/ti_k3/*/Kconfig.series" diff --git a/soc/arm/ti_k3/am62x_m4/CMakeLists.txt b/soc/arm/ti_k3/am62x_m4/CMakeLists.txt new file mode 100644 index 000000000000..e8d816988de5 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) + +if(CONFIG_OPENAMP_RSC_TABLE) + zephyr_linker_section(NAME .resource_table GROUP ROM_REGION NOINPUT) + zephyr_linker_section_configure(SECTION .resource_table KEEP INPUT ".resource_table*") +endif() diff --git a/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62xm4 b/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62xm4 new file mode 100644 index 000000000000..688efcd841fb --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62xm4 @@ -0,0 +1,13 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AM62x_M4 + +config SOC + default "am62x_m4" + +endif diff --git a/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.series b/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.series new file mode 100644 index 000000000000..d85c54d9c007 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.series @@ -0,0 +1,52 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_AM62X_M4 + +source "soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62xm4*" + +config SOC_SERIES + default "am62x_m4" + +DT_CHOSEN_Z_FLASH := zephyr,flash + +config FLASH_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_FLASH),0,K) + +config FLASH_BASE_ADDRESS + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) + +config NUM_IRQS + default 64 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 400000000 + +config PINCTRL + default y + +if SERIAL + +config UART_NS16550 + default y + +config UART_NS16550_TI_K3 + default y + +choice UART_NS16550_VARIANT + default UART_NS16550_VARIANT_NS16750 +endchoice + +endif # SERIAL + +config BUILD_OUTPUT_BIN + default n + +source "soc/arm/ti_k3/am62x_m4/Kconfig.defconfig.am62*" + +endif # SOC_SERIES_AM62X_M4 diff --git a/soc/arm/ti_k3/am62x_m4/Kconfig.series b/soc/arm/ti_k3/am62x_m4/Kconfig.series new file mode 100644 index 000000000000..0e6759500678 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/Kconfig.series @@ -0,0 +1,22 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_AM62X_M4 + bool "TI AM62X M4 Core Series" + select SOC_FAMILY_TI_K3 + select ARM + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_SYSTICK + select DYNAMIC_INTERRUPTS + select CPU_CORTEX_M_HAS_DWT + select OPENAMP_RSC_TABLE + select UART_NS16550_ACCESS_WORD_ONLY + select EXTERNAL_ADDRESS_TRANSLATION + select MM_DRV + select MM_TI_RAT + help + Enable support for AM62X M4 Series. diff --git a/soc/arm/ti_k3/am62x_m4/Kconfig.soc b/soc/arm/ti_k3/am62x_m4/Kconfig.soc new file mode 100644 index 000000000000..b0eec320f175 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/Kconfig.soc @@ -0,0 +1,28 @@ +# Texas Instruments Sitara AM62x-SK-M4 +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "TI AM62X M4 Selection" +depends on SOC_SERIES_AM62X_M4 + +config SOC_AM62x_M4 + bool "TI AM62x M4" + select SOC_PART_NUMBER_AM62x + +endchoice + +config SOC_PART_NUMBER_AM62x + bool + +config SOC_PART_NUMBER_AM62X_M4 + string + default "AM62x" if SOC_PART_NUMBER_AM62x + help + Full part number of the SoC. Do not select directly. + +config SOC_PART_NUMBER + default SOC_PART_NUMBER_AM62X_M4 if SOC_SERIES_AM62X_M4 diff --git a/soc/arm/ti_k3/am62x_m4/linker.ld b/soc/arm/ti_k3/am62x_m4/linker.ld new file mode 100644 index 000000000000..793177b7f724 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/linker.ld @@ -0,0 +1,18 @@ +/* linker.ld - Linker command/script file + * + * Copyright (c) 2023 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +SECTIONS +{ +#ifdef CONFIG_OPENAMP_RSC_TABLE + SECTION_PROLOGUE(.resource_table,, SUBALIGN(4)) + { + KEEP(*(.resource_table*)) + } GROUP_LINK_IN(DDR) +#endif +} diff --git a/soc/arm/ti_k3/am62x_m4/soc.c b/soc/arm/ti_k3/am62x_m4/soc.c new file mode 100644 index 000000000000..29c76ec35508 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/soc.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define ADDR_TRANSLATE_RAT_BASE_ADDR (0x044200000u) + +static struct address_trans_region_config region_config[] = { + { + .system_addr = 0x0u, + .local_addr = 0x80000000u, + .size = address_trans_region_size_512M, + }, + { + .local_addr = 0xA0000000u, + .system_addr = 0x20000000u, + .size = address_trans_region_size_512M, + }, + { + .local_addr = 0xC0000000u, + .system_addr = 0x40000000u, + .size = address_trans_region_size_512M, + }, + { + .local_addr = 0x60000000u, + .system_addr = 0x60000000u, + .size = address_trans_region_size_512M, + }, + +/* + * Add regions here if you want to map more memory. + */ +}; + +static int am62x_m4_init(void) +{ + sys_mm_drv_ti_rat_init( + region_config, ADDR_TRANSLATE_RAT_BASE_ADDR, ARRAY_SIZE(region_config)); + return 0; +} + +SYS_INIT(am62x_m4_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/ti_k3/am62x_m4/soc.h b/soc/arm/ti_k3/am62x_m4/soc.h new file mode 100644 index 000000000000..089479dc6fd5 --- /dev/null +++ b/soc/arm/ti_k3/am62x_m4/soc.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include From 5b210fe35ad18de2398ce139e0194c13d521ff03 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Tue, 11 Jul 2023 11:13:37 +0530 Subject: [PATCH 1315/2042] dts: ti_am62x_sk: Added base devicetree file for AM62X SK Added the base devicetree file for the TI AM62X SK EVM board. Signed-off-by: L Lakshmanan --- dts/arm/ti/am62x_sk_m4.dtsi | 65 +++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 dts/arm/ti/am62x_sk_m4.dtsi diff --git a/dts/arm/ti/am62x_sk_m4.dtsi b/dts/arm/ti/am62x_sk_m4.dtsi new file mode 100644 index 000000000000..22de7a14f82b --- /dev/null +++ b/dts/arm/ti/am62x_sk_m4.dtsi @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + sram0: memory@0 { + compatible = "mmio-sram"; + reg = <0x0 DT_SIZE_K(192)>; /* 192 KB of SRAM (I-Code) */ + }; + + sram1: memory1@40000 { + compatible = "mmio-sram"; + reg = <0x40000 DT_SIZE_K(64)>; /* 64 KB of SRAM (D-Code) */ + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = <400000000>; + #clock-cells = <0>; + }; + + pinctrl: pinctrl@4084000 { + compatible = "ti,k3-pinctrl"; + reg = <0x04084000 0x88>; + status = "okay"; + }; + + uart0: serial@4a00000 { + compatible = "ns16550"; + reg = <0x04a00000 0x200>; + interrupts = <24 4>; + interrupt-parent = <&nvic>; + clock-frequency = <48000000>; + current-speed = <115200>; + reg-shift = <2>; + status = "disabled"; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&systick { + status = "okay"; +}; From 71244acd227d6fe40f55d3dd23a1f5490122bb57 Mon Sep 17 00:00:00 2001 From: L Lakshmanan Date: Tue, 11 Jul 2023 12:08:13 +0530 Subject: [PATCH 1316/2042] board: ti_am62x_sk_m4: Added board files for TI AM62X SK Added configuration and documentation files for the AM62x board M4 core. Signed-off-by: L Lakshmanan --- boards/arm/ti_am62x_sk_m4/Kconfig.board | 10 ++ boards/arm/ti_am62x_sk_m4/Kconfig.defconfig | 13 ++ .../doc/img/sk_am62_angled.webp | Bin 0 -> 99382 bytes boards/arm/ti_am62x_sk_m4/doc/index.rst | 141 ++++++++++++++++++ boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.dts | 50 +++++++ boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.yaml | 7 + .../ti_am62x_sk_m4/ti_am62x_sk_m4_defconfig | 25 ++++ soc/arm/ti_k3/am62x_m4/soc.c | 24 +++ soc/arm/ti_k3/pinctrl_soc.h | 37 +++++ 9 files changed, 307 insertions(+) create mode 100644 boards/arm/ti_am62x_sk_m4/Kconfig.board create mode 100644 boards/arm/ti_am62x_sk_m4/Kconfig.defconfig create mode 100644 boards/arm/ti_am62x_sk_m4/doc/img/sk_am62_angled.webp create mode 100644 boards/arm/ti_am62x_sk_m4/doc/index.rst create mode 100644 boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.dts create mode 100644 boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.yaml create mode 100644 boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4_defconfig create mode 100644 soc/arm/ti_k3/pinctrl_soc.h diff --git a/boards/arm/ti_am62x_sk_m4/Kconfig.board b/boards/arm/ti_am62x_sk_m4/Kconfig.board new file mode 100644 index 000000000000..e225bed5fded --- /dev/null +++ b/boards/arm/ti_am62x_sk_m4/Kconfig.board @@ -0,0 +1,10 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TI_AM62X_SK_M4 + bool "TI_AM62X_SK_M4" + depends on SOC_SERIES_AM62X_M4 diff --git a/boards/arm/ti_am62x_sk_m4/Kconfig.defconfig b/boards/arm/ti_am62x_sk_m4/Kconfig.defconfig new file mode 100644 index 000000000000..71cb13a24da3 --- /dev/null +++ b/boards/arm/ti_am62x_sk_m4/Kconfig.defconfig @@ -0,0 +1,13 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_TI_AM62X_SK_M4 + +config BOARD + default "ti_am62x_sk_m4" + +endif # BOARD_TI_AM62X_SK_M4 diff --git a/boards/arm/ti_am62x_sk_m4/doc/img/sk_am62_angled.webp b/boards/arm/ti_am62x_sk_m4/doc/img/sk_am62_angled.webp new file mode 100644 index 0000000000000000000000000000000000000000..7d707eb36471bd45fad48c72eb98a04f9a43f126 GIT binary patch literal 99382 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 O00000000000001f(Tu + +/ { + model = "TI AM62X SK EVALUATION BOARD"; + compatible = "ti,ti_am62x_sk_m4"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram1 = &ddr0; + }; + + cpus { + cpu@0 { + status = "okay"; + clock-frequency = <400000000>; + }; + }; + + ddr0:memory@9CC00000{ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x9CC00000 DT_SIZE_K(4)>; + zephyr,memory-region = "DDR"; + }; +}; + +&pinctrl { + mcu_uart0_rx_default: mcu_uart0_rx_default { + pinmux = ; + }; + mcu_uart0_tx_default: mcu_uart0_tx_default { + pinmux = ; + }; +}; + +&uart0 { + current-speed = <115200>; + pinctrl-0 = <&mcu_uart0_rx_default &mcu_uart0_tx_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.yaml b/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.yaml new file mode 100644 index 000000000000..fe06582678c2 --- /dev/null +++ b/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4.yaml @@ -0,0 +1,7 @@ +identifier: ti_am62x_sk_m4 +name: TI AM62X SK M4 +type: mcu +arch: arm +toolchain: + - zephyr +ram: 192 diff --git a/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4_defconfig b/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4_defconfig new file mode 100644 index 000000000000..b64482894b28 --- /dev/null +++ b/boards/arm/ti_am62x_sk_m4/ti_am62x_sk_m4_defconfig @@ -0,0 +1,25 @@ +# Texas Instruments Sitara AM62x-SK-M4 EVM +# +# Copyright (c) 2023 Texas Instruments Incorporated +# Copyright (c) 2023 L Lakshmanan +# +# SPDX-License-Identifier: Apache-2.0 + +# Platform Configuration +CONFIG_SOC_SERIES_AM62X_M4=y +CONFIG_SOC_AM62x_M4=y +CONFIG_BOARD_TI_AM62X_SK_M4=y +CONFIG_CORTEX_M_SYSTICK=y + +# Zephyr Kernel Configuration +CONFIG_XIP=n + +# Enable Pinctrl +CONFIG_PINCTRL=y + +# Serial Driver +CONFIG_SERIAL=y + +# Enable Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/soc/arm/ti_k3/am62x_m4/soc.c b/soc/arm/ti_k3/am62x_m4/soc.c index 29c76ec35508..1010e045ea59 100644 --- a/soc/arm/ti_k3/am62x_m4/soc.c +++ b/soc/arm/ti_k3/am62x_m4/soc.c @@ -11,6 +11,11 @@ #include #define ADDR_TRANSLATE_RAT_BASE_ADDR (0x044200000u) +#define PINCTRL_BASE_ADDR (0x4080000u) +#define KICK0_UNLOCK_VAL (0x68EF3490U) +#define KICK1_UNLOCK_VAL (0xD172BC5AU) +#define CSL_MCU_PADCONFIG_LOCK0_KICK0_OFFSET (0x1008) +#define CSL_MCU_PADCONFIG_LOCK1_KICK0_OFFSET (0x5008) static struct address_trans_region_config region_config[] = { { @@ -39,10 +44,29 @@ static struct address_trans_region_config region_config[] = { */ }; +static void mmr_unlock(void) +{ + uint32_t baseAddr = PINCTRL_BASE_ADDR; + uintptr_t kickAddr; + + /* Lock 0 */ + kickAddr = baseAddr + CSL_MCU_PADCONFIG_LOCK0_KICK0_OFFSET; + sys_write32(KICK0_UNLOCK_VAL, kickAddr); /* KICK 0 */ + kickAddr = kickAddr + sizeof(uint32_t *); + sys_write32(KICK1_UNLOCK_VAL, kickAddr); /* KICK 1 */ + + /* Lock 1 */ + kickAddr = baseAddr + CSL_MCU_PADCONFIG_LOCK1_KICK0_OFFSET; + sys_write32(KICK0_UNLOCK_VAL, kickAddr); /* KICK 0 */ + kickAddr = kickAddr + sizeof(uint32_t *); + sys_write32(KICK1_UNLOCK_VAL, kickAddr); /* KICK 1 */ +} + static int am62x_m4_init(void) { sys_mm_drv_ti_rat_init( region_config, ADDR_TRANSLATE_RAT_BASE_ADDR, ARRAY_SIZE(region_config)); + mmr_unlock(); return 0; } diff --git a/soc/arm/ti_k3/pinctrl_soc.h b/soc/arm/ti_k3/pinctrl_soc.h new file mode 100644 index 000000000000..fb9fcfa5a7e5 --- /dev/null +++ b/soc/arm/ti_k3/pinctrl_soc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Texas Instruments Incorporated + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_TI_K3_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_TI_K3_PINCTRL_SOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct pinctrl_soc_pin { + uint32_t offset; + uint32_t value; +}; + +typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; + +#define TI_K3_DT_PIN(node_id) \ + { \ + .offset = DT_PROP_BY_IDX(node_id, pinmux, 0), \ + .value = DT_PROP_BY_IDX(node_id, pinmux, 1) \ + }, + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + TI_K3_DT_PIN(DT_PROP_BY_IDX(node_id, prop, idx)) + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_TI_K3_PINCTRL_SOC_H_ */ From 79e3dda5ff3e959ed42565cb93d365bceceb0eb7 Mon Sep 17 00:00:00 2001 From: Pavlo Havrylyuk Date: Wed, 5 Jul 2023 15:11:14 -0700 Subject: [PATCH 1317/2042] dts: infineon: Update ADC register Changed ADC registers to correct addresses Signed-off-by: Pavlo Havrylyuk --- dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi | 4 ++-- dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi | 4 ++-- dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi index 975cc988f0e5..382f6043b910 100644 --- a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi @@ -205,9 +205,9 @@ status = "disabled"; }; - adc0: adc@411f0000 { + adc0: adc@411d0000 { compatible = "infineon,cat1-adc"; - reg = <0x411f0000 0x10000>; + reg = <0x411d0000 0x10000>; interrupts = <138 6>; status = "disabled"; #io-channel-cells = <1>; diff --git a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi index 09771a8a78ec..8e8ada040d2c 100644 --- a/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_03/psoc6_03.dtsi @@ -178,9 +178,9 @@ status = "disabled"; }; - adc0: adc@409f0000 { + adc0: adc@409d0000 { compatible = "infineon,cat1-adc"; - reg = <0x409f0000 0x10000>; + reg = <0x409d0000 0x10000>; interrupts = <155 6>; status = "disabled"; }; diff --git a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi index 31238ef26d9a..73282624e3f9 100644 --- a/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_04/psoc6_04.dtsi @@ -186,15 +186,15 @@ status = "disabled"; }; - adc0: adc@409f0000 { + adc0: adc@409b0000 { compatible = "infineon,cat1-adc"; - reg = <0x409f0000 0x10000>; + reg = <0x409b0000 0x10000>; interrupts = <39 6>; status = "disabled"; }; - adc1: adc@409f0000 { + adc1: adc@409c0000 { compatible = "infineon,cat1-adc"; - reg = <0x409f0000 0x10000>; + reg = <0x409c0000 0x10000>; interrupts = <40 6>; status = "disabled"; }; From ea2aac6e5131bf916abd1e37334e94cc3481e1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 13 Jul 2023 14:48:33 +0200 Subject: [PATCH 1318/2042] shell: doc: misc Doxygen fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed several incorrect uses of Doxygen, in particular improper use of /*!< ... */ syntax which is meant to document the *previous* element. Signed-off-by: Benjamin Cabé --- include/zephyr/shell/shell.h | 33 +++++++++++++++--------------- include/zephyr/shell/shell_types.h | 18 ++++++++-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 360d789dbccc..437169fd281f 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -93,10 +93,10 @@ typedef void (*shell_dynamic_get)(size_t idx, * @brief Shell command descriptor. */ union shell_cmd_entry { - /*!< Pointer to function returning dynamic commands.*/ + /** Pointer to function returning dynamic commands.*/ shell_dynamic_get dynamic_get; - /*!< Pointer to array of static commands. */ + /** Pointer to array of static commands. */ const struct shell_static_entry *entry; }; @@ -606,6 +606,7 @@ typedef void (*shell_bypass_cb_t)(const struct shell *sh, struct shell_transport; /** + * @struct shell_transport_api * @brief Unified shell transport interface. */ struct shell_transport_api { @@ -665,8 +666,8 @@ struct shell_transport_api { /** * @brief Function for reading data from the transport interface. * - * @param[in] p_transport Pointer to the transfer instance. - * @param[in] p_data Pointer to the destination buffer. + * @param[in] transport Pointer to the transfer instance. + * @param[in] data Pointer to the destination buffer. * @param[in] length Destination buffer length. * @param[out] cnt Pointer to the received bytes counter. * @@ -780,21 +781,21 @@ struct shell_ctx { enum shell_state state; /*!< Internal module state.*/ enum shell_receive_state receive_state;/*!< Escape sequence indicator.*/ - /*!< Currently executed command.*/ + /** Currently executed command.*/ struct shell_static_entry active_cmd; - /* New root command. If NULL shell uses default root commands. */ + /** New root command. If NULL shell uses default root commands. */ const struct shell_static_entry *selected_cmd; - /*!< VT100 color and cursor position, terminal width.*/ + /** VT100 color and cursor position, terminal width.*/ struct shell_vt100_ctx vt100_ctx; - /*!< Callback called from shell thread context when unitialization is + /** Callback called from shell thread context when unitialization is * completed just before aborting shell thread. */ shell_uninit_cb_t uninit_cb; - /*!< When bypass is set, all incoming data is passed to the callback. */ + /** When bypass is set, all incoming data is passed to the callback. */ shell_bypass_cb_t bypass; #if defined CONFIG_SHELL_GETOPT @@ -807,13 +808,13 @@ struct shell_ctx { uint16_t cmd_tmp_buff_len; /*!< Command length in tmp buffer.*/ - /*!< Command input buffer.*/ + /** Command input buffer.*/ char cmd_buff[CONFIG_SHELL_CMD_BUFF_SIZE]; - /*!< Command temporary buffer.*/ + /** Command temporary buffer.*/ char temp_buff[CONFIG_SHELL_CMD_BUFF_SIZE]; - /*!< Printf buffer size.*/ + /** Printf buffer size.*/ char printf_buff[CONFIG_SHELL_PRINTF_BUFF_SIZE]; volatile union shell_backend_cfg cfg; @@ -821,7 +822,7 @@ struct shell_ctx { struct k_poll_signal signals[SHELL_SIGNALS]; - /*!< Events that should be used only internally by shell thread. + /** Events that should be used only internally by shell thread. * Event for SHELL_SIGNAL_TXDONE is initialized but unused. */ struct k_poll_event events[SHELL_SIGNALS]; @@ -837,8 +838,8 @@ extern const struct log_backend_api log_backend_shell_api; * @brief Flags for setting shell output newline sequence. */ enum shell_flag { - SHELL_FLAG_CRLF_DEFAULT = (1<<0), /* Do not map CR or LF */ - SHELL_FLAG_OLF_CRLF = (1<<1) /* Map LF to CRLF on output */ + SHELL_FLAG_CRLF_DEFAULT = (1<<0), /*!< Do not map CR or LF */ + SHELL_FLAG_OLF_CRLF = (1<<1) /*!< Map LF to CRLF on output */ }; /** @@ -1116,7 +1117,7 @@ int shell_prompt_change(const struct shell *sh, const char *prompt); */ void shell_help(const struct shell *sh); -/* @brief Command's help has been printed */ +/** @brief Command's help has been printed */ #define SHELL_CMD_HELP_PRINTED (1) /** @brief Execute command. diff --git a/include/zephyr/shell/shell_types.h b/include/zephyr/shell/shell_types.h index ab37a6b52fb7..a45f0c1753ab 100644 --- a/include/zephyr/shell/shell_types.h +++ b/include/zephyr/shell/shell_types.h @@ -27,24 +27,24 @@ enum shell_vt100_color { }; struct shell_vt100_colors { - enum shell_vt100_color col; /* Text color. */ - enum shell_vt100_color bgcol; /* Background color. */ + enum shell_vt100_color col; /*!< Text color. */ + enum shell_vt100_color bgcol; /*!< Background color. */ }; struct shell_multiline_cons { - uint16_t cur_x; /* horizontal cursor position in edited command line.*/ - uint16_t cur_x_end; /* horizontal cursor position at the end of command.*/ - uint16_t cur_y; /* vertical cursor position in edited command.*/ - uint16_t cur_y_end; /* vertical cursor position at the end of command.*/ - uint16_t terminal_hei; /* terminal screen height.*/ - uint16_t terminal_wid; /* terminal screen width.*/ + uint16_t cur_x; /*!< horizontal cursor position in edited command line.*/ + uint16_t cur_x_end; /*!< horizontal cursor position at the end of command.*/ + uint16_t cur_y; /*!< vertical cursor position in edited command.*/ + uint16_t cur_y_end; /*!< vertical cursor position at the end of command.*/ + uint16_t terminal_hei; /*!< terminal screen height.*/ + uint16_t terminal_wid; /*!< terminal screen width.*/ uint8_t name_len; /*! Date: Mon, 19 Jun 2023 11:24:13 +0800 Subject: [PATCH 1319/2042] dts: riscv: andes_v5: update andes_v5_ae350.dtsi Fix mtimer lack of interrupts-extended and make syscon compatilbe to atcsmu100. Signed-off-by: Jimmy Zheng --- dts/riscv/andes/andes_v5_ae350.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index ad4900eb5c4d..9c5ad76422da 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -201,11 +201,13 @@ compatible = "andestech,machine-timer"; reg = <0xe6000000 0x10>; interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7 - &CPU2_intc 7 &CPU3_intc 7>; + &CPU2_intc 7 &CPU3_intc 7 + &CPU4_intc 7 &CPU5_intc 7 + &CPU6_intc 7 &CPU7_intc 7>; }; syscon: syscon@f0100000 { - compatible = "syscon"; + compatible = "syscon", "andestech,atcsmu100"; reg = <0xf0100000 0x1000>; status = "disabled"; }; From de1cd06294cb0b58d3177521e4e717be10b9bf9f Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Wed, 21 Jun 2023 09:57:33 +0800 Subject: [PATCH 1320/2042] soc: riscv: andes_v5: update ae350 linker.ld Synchronize ae350 linker.ld with riscv generic linker.ld and workaround kernel object address may be 0x0 in XIP system. Signed-off-by: Jimmy Zheng --- .../riscv-privileged/andes_v5/CMakeLists.txt | 2 + .../riscv-privileged/andes_v5/ae350/linker.ld | 85 +++++++++++++++---- .../andes_v5/common_linker/init.ld | 7 ++ .../common_linker/ram_start_nonzero.ld | 16 ++++ 4 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld create mode 100644 soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt index 4df3e1ffc44b..b3e8f14209e8 100644 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt @@ -9,6 +9,8 @@ zephyr_sources( ) zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_PMA pma.c) +zephyr_linker_sources(ROM_START SORT_KEY 0x0 common_linker/init.ld) +zephyr_linker_sources_ifdef(CONFIG_XIP RAM_SECTIONS SORT_KEY 0x0 common_linker/ram_start_nonzero.ld) # Note: AndeStar V5 DSP needs custom Andes V5 toolchain if(CONFIG_SOC_ANDES_V5_HWDSP) diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld index 9e613a0d9301..55cf3181f68c 100644 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld +++ b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld @@ -40,7 +40,7 @@ #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)) -#elif DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), jedec_spi_nor, okay) +#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. @@ -73,9 +73,21 @@ _region_min_align = 4; . = ALIGN(_region_min_align); \ . = ALIGN( 1 << LOG2CEIL(region_size)) #else -#define MPU_MIN_SIZE_ALIGN -#define MPU_ALIGN(region_size) \ - . = ALIGN(_region_min_align) +#ifdef CONFIG_RISCV_PMP + #define MPU_MIN_SIZE CONFIG_PMP_GRANULARITY + #define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE); + #if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) + #define MPU_ALIGN(region_size) \ + . = ALIGN(MPU_MIN_SIZE); \ + . = ALIGN( 1 << LOG2CEIL(region_size)) + #else + #define MPU_ALIGN(region_size) \ + . = ALIGN(MPU_MIN_SIZE) + #endif +#else + #define MPU_MIN_SIZE_ALIGN + #define MPU_ALIGN(region_size) . = ALIGN(4) +#endif #endif MEMORY @@ -118,13 +130,16 @@ SECTIONS SECTION_PROLOGUE(rom_start,,) { . = ALIGN(16); - KEEP(*(.init.*)) /* Located in generated directory. This file is populated by calling * zephyr_linker_sources(ROM_START ...). */ #include } GROUP_LINK_IN(ROMABLE_REGION) +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + SECTION_PROLOGUE(_RESET_SECTION_NAME,,) { KEEP(*(.reset.*)) @@ -176,18 +191,40 @@ SECTIONS #include __rodata_region_end = .; - MPU_ALIGN(__rodata_region_end - __rom_region_start); + + /* For non-XIP system, __rom_region_end symbol should be set to + * the end of common ROMABLE_REGIONs (text and rodata) instead of + * the linker script end, so it wouldn't mistakenly contain + * RAMABLE_REGION in it. + */ +#ifndef CONFIG_XIP +#ifdef CONFIG_RISCV_PMP + SECTION_PROLOGUE(rom_mpu_padding,,) + { + MPU_ALIGN(__rodata_region_end - __rom_region_start); + } GROUP_LINK_IN(ROMABLE_REGION) +#endif /* CONFIG_RISCV_PMP */ + + __rom_region_end = .; + __rom_region_size = __rom_region_end - __rom_region_start; +#endif /* CONFIG_XIP */ GROUP_END(ROMABLE_REGION) GROUP_START(RAMABLE_REGION) + . = RAM_BASE; + _image_ram_start = .; +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + #if defined(CONFIG_USERSPACE) #define APP_SHARED_ALIGN MPU_MIN_SIZE_ALIGN #define SMEM_PARTITION_ALIGN MPU_ALIGN #include - _image_ram_start = _app_smem_start; _app_smem_size = _app_smem_end - _app_smem_start; _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); #endif /* CONFIG_USERSPACE */ @@ -201,13 +238,17 @@ SECTIONS */ . = ALIGN(4); __bss_start = .; - _image_ram_start = .; __kernel_ram_start = .; *(.sbss) *(".sbss.*") *(.bss) *(".bss.*") COMMON_SYMBOLS + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + /* * As memory is cleared in words only, it is simpler to ensure the BSS * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. @@ -216,14 +257,12 @@ SECTIONS } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) #include -#include - - __data_region_start = .; SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) { . = ALIGN(4); /* _image_ram_start = .; */ + __data_region_start = .; __data_start = .; *(.data) @@ -251,6 +290,11 @@ SECTIONS * zephyr_linker_sources() Cmake function. */ #include + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + __data_end = .; } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) @@ -261,11 +305,7 @@ SECTIONS #include #include - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include +#include /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. @@ -289,7 +329,7 @@ GROUP_START(ITCM) } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) __itcm_size = __itcm_end - __itcm_start; - __itcm_rom_start = LOADADDR(_ITCM_SECTION_NAME); + __itcm_load_start = LOADADDR(_ITCM_SECTION_NAME); GROUP_END(ITCM) #endif @@ -324,7 +364,7 @@ GROUP_START(DTCM) __dtcm_end = .; - __dtcm_data_rom_start = LOADADDR(_DTCM_DATA_SECTION_NAME); + __dtcm_data_load_start = LOADADDR(_DTCM_DATA_SECTION_NAME); GROUP_END(DTCM) #endif @@ -350,6 +390,14 @@ GROUP_END(DTCM) KEEP(*(.gnu.attributes)) } + /* Sections generated from 'zephyr,memory-region' nodes */ + LINKER_DT_SECTIONS() + +/* Because ROMABLE_REGION != RAMABLE_REGION in XIP-system, it is valid + * to set __rom_region_end symbol at the end of linker script and + * doesn't mistakenly contain the RAMABLE_REGION in it. + */ +#ifdef CONFIG_XIP /* Must be last in romable region */ SECTION_PROLOGUE(.last_section,,) { @@ -364,5 +412,6 @@ SECTION_PROLOGUE(.last_section,,) * calculate this value here. */ __rom_region_end = LOADADDR(.last_section) + SIZEOF(.last_section); __rom_region_size = __rom_region_end - __rom_region_start; +#endif } diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld b/soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld new file mode 100644 index 000000000000..0feb828931ba --- /dev/null +++ b/soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +KEEP(*(.init.*)) diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld b/soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld new file mode 100644 index 000000000000..760ce73f6b7a --- /dev/null +++ b/soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Workaround for RAM_BASE is zero in XIP system, kernel object + * address maybe zero(NULL) and break some test case assertions. + * ex: tests/kernel/queue, k_queue_get() return k_queue address + * 0x0, but treat as NULL fail. + */ +SECTION_DATA_PROLOGUE(ram_start_nonzero,(NOLOAD),) +{ + . = ABSOLUTE(.) ? . : . + 0x8; +} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) From bf0e01bee2af188a4b19857dfebfe151c782f1d4 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Wed, 21 Jun 2023 13:56:55 +0800 Subject: [PATCH 1321/2042] soc: riscv: andes_v5: refine Andes PMA Refine PMA driver and define MPU_ALIGN() to PMA granularity in RAM_SECTIONS, otherwise MPU_ALIGN() is defined to PMP granularity. Signed-off-by: Jimmy Zheng --- .../riscv-privileged/andes_v5/ae350/linker.ld | 31 ++--- soc/riscv/riscv-privileged/andes_v5/pma.c | 125 ++++++------------ 2 files changed, 57 insertions(+), 99 deletions(-) diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld index 55cf3181f68c..28a081aa7093 100644 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld +++ b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld @@ -57,22 +57,6 @@ #define RAM_BASE CONFIG_SRAM_BASE_ADDRESS #define RAM_SIZE KB(CONFIG_SRAM_SIZE) -/* Make linker section alignment comply with PMA granularity. */ -#if defined(CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE) -_region_min_align = CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE; -#else -_region_min_align = 4; -#endif - -#if defined(CONFIG_SOC_ANDES_V5_PMA) -/* - * Andes-V5 PMA needs power-of-2 alignment. - */ -#define MPU_MIN_SIZE_ALIGN . = ALIGN(_region_min_align); -#define MPU_ALIGN(region_size) \ - . = ALIGN(_region_min_align); \ - . = ALIGN( 1 << LOG2CEIL(region_size)) -#else #ifdef CONFIG_RISCV_PMP #define MPU_MIN_SIZE CONFIG_PMP_GRANULARITY #define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE); @@ -88,7 +72,6 @@ _region_min_align = 4; #define MPU_MIN_SIZE_ALIGN #define MPU_ALIGN(region_size) . = ALIGN(4) #endif -#endif MEMORY { @@ -214,11 +197,25 @@ SECTIONS . = RAM_BASE; _image_ram_start = .; + +#ifdef CONFIG_SOC_ANDES_V5_PMA +#pragma push_macro("MPU_ALIGN") +#undef MPU_ALIGN +/* Make linker section alignment comply with PMA granularity. */ +#define MPU_ALIGN(region_size) \ + . = ALIGN(CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE); \ + . = ALIGN( 1 << LOG2CEIL(region_size)) +#endif + /* Located in generated directory. This file is populated by the * zephyr_linker_sources() Cmake function. */ #include +#ifdef CONFIG_SOC_ANDES_V5_PMA +#pragma pop_macro("MPU_ALIGN") +#endif + #if defined(CONFIG_USERSPACE) #define APP_SHARED_ALIGN MPU_MIN_SIZE_ALIGN #define SMEM_PARTITION_ALIGN MPU_ALIGN diff --git a/soc/riscv/riscv-privileged/andes_v5/pma.c b/soc/riscv/riscv-privileged/andes_v5/pma.c index 8737bdca01a6..46807bf0739f 100644 --- a/soc/riscv/riscv-privileged/andes_v5/pma.c +++ b/soc/riscv/riscv-privileged/andes_v5/pma.c @@ -8,6 +8,7 @@ #include #include #include +#include #ifndef CONFIG_ASSERT #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL @@ -16,14 +17,14 @@ LOG_MODULE_REGISTER(pma_init, LOG_LEVEL); #endif /* Programmable PMA mechanism is supported */ -#define MMSC_CFG_PPMA (1 << 30) +#define MMSC_CFG_PPMA BIT(30) /* * PMA Configuration (PMACFG) bitfields */ /* ETYPE: Entry address matching mode */ -#define PMACFG_ETYPE_MASK 3 +#define PMACFG_ETYPE_MASK BIT_MASK(2) #define PMACFG_ETYPE_OFF 0 #define PMACFG_ETYPE_TOR 1 #define PMACFG_ETYPE_NA4 2 @@ -41,9 +42,7 @@ LOG_MODULE_REGISTER(pma_init, LOG_LEVEL); /* The base address is aligned to size */ #define NAPOT_BASE(start, size) TO_PMA_ADDR((start) & ~((size) - 1)) -/* The encoding of size is 0b01...1 - * (change the leading bit of bitmask to 0) - */ +/* The encoding of size is 0b01...1, (change the leading bit of bitmask to 0) */ #define NAPOT_SIZE(size) TO_PMA_ADDR(((size) - 1) >> 1) #define NA4_ENCODING(start) TO_PMA_ADDR(start) @@ -58,12 +57,6 @@ LOG_MODULE_REGISTER(pma_init, LOG_LEVEL); #endif #define PMACFG_SHIFT(index) ((index % RV_REGSIZE) * 8) -/* Wrappers of inline assembly */ -#define read_csr(var, csr) \ - ({ __asm__ volatile ("csrr %0, %1" : "=r" (var) : "i" (csr)); }) -#define write_csr(csr, val) \ - ({ __asm__ volatile ("csrw %0, %1" :: "i" (csr), "r" (val)); }) - struct pma_region_attr { /* Attributes belonging to pmacfg{i} */ uint8_t pmacfg; @@ -80,62 +73,32 @@ struct pma_region { */ static void write_pmaaddr_csr(const uint32_t index, unsigned long value) { + #define SWITCH_CASE_PMAADDR_WRITE(x) \ + case (x): \ + csr_write(NDS_PMAADDR##x, value); break; + switch (index) { - case 0: - write_csr(NDS_PMAADDR0, value); break; - case 1: - write_csr(NDS_PMAADDR1, value); break; - case 2: - write_csr(NDS_PMAADDR2, value); break; - case 3: - write_csr(NDS_PMAADDR3, value); break; - case 4: - write_csr(NDS_PMAADDR4, value); break; - case 5: - write_csr(NDS_PMAADDR5, value); break; - case 6: - write_csr(NDS_PMAADDR6, value); break; - case 7: - write_csr(NDS_PMAADDR7, value); break; - case 8: - write_csr(NDS_PMAADDR8, value); break; - case 9: - write_csr(NDS_PMAADDR9, value); break; - case 10: - write_csr(NDS_PMAADDR10, value); break; - case 11: - write_csr(NDS_PMAADDR11, value); break; - case 12: - write_csr(NDS_PMAADDR12, value); break; - case 13: - write_csr(NDS_PMAADDR13, value); break; - case 14: - write_csr(NDS_PMAADDR14, value); break; - case 15: - write_csr(NDS_PMAADDR15, value); break; + FOR_EACH(SWITCH_CASE_PMAADDR_WRITE, (;), 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15); } } /* * Write value to pma{i}cfg entry which are packed into CSRs pmacfg{j} */ -static void write_pmacfg_entry(const uint32_t entry_index, - uint8_t entry_value) +static void write_pmacfg_entry(const uint32_t entry_index, uint8_t entry_value) { /* 1-byte pma{i}cfg entries are packed into XLEN-byte CSRs pmacfg{j} */ uint32_t index = PMACFG_NUM(entry_index); uint8_t shift = PMACFG_SHIFT(entry_index); unsigned long pmacfg = 0; + #define SWITCH_CASE_PMACFG_READ(x) \ + case (x): \ + pmacfg = csr_read(NDS_PMACFG##x); break; + switch (index) { - case 0: - read_csr(pmacfg, NDS_PMACFG0); break; - case 1: - read_csr(pmacfg, NDS_PMACFG1); break; - case 2: - read_csr(pmacfg, NDS_PMACFG2); break; - case 3: - read_csr(pmacfg, NDS_PMACFG3); break; + FOR_EACH(SWITCH_CASE_PMACFG_READ, (;), 0, 1, 2, 3); } /* clear old value in pmacfg entry */ @@ -143,15 +106,12 @@ static void write_pmacfg_entry(const uint32_t entry_index, /* set new value to pmacfg entry value */ pmacfg |= entry_value << shift; + #define SWITCH_CASE_PMACFG_WRITE(x) \ + case (x): \ + csr_write(NDS_PMACFG##x, pmacfg); break; + switch (index) { - case 0: - write_csr(NDS_PMACFG0, pmacfg); break; - case 1: - write_csr(NDS_PMACFG1, pmacfg); break; - case 2: - write_csr(NDS_PMACFG2, pmacfg); break; - case 3: - write_csr(NDS_PMACFG3, pmacfg); break; + FOR_EACH(SWITCH_CASE_PMACFG_WRITE, (;), 0, 1, 2, 3); } } @@ -185,19 +145,18 @@ static void region_init(const uint32_t index, */ static int pma_region_is_valid(const struct pma_region *region) { - /* Region size must be power-of-two, - * and greater or equal to the minimum - * PMA region size. Start address of the - * region must align with size. - */ - int region_is_valid = - ((region->size & (region->size - 1)) == 0U) - && - (region->size >= CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE) - && - ((region->start & (region->size - 1)) == 0U); - - if (!region_is_valid) { + /* Region size must greater or equal to the minimum PMA region size */ + if (region->size < CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE) { + return -EINVAL; + } + + /* Region size must be power-of-two */ + if (region->size & (region->size - 1)) { + return -EINVAL; + } + + /* Start address of the region must align with size */ + if (region->start & (region->size - 1)) { return -EINVAL; } @@ -213,11 +172,13 @@ static void configure_nocache_region(void) .attr = {PMACFG_MTYPE_MEMORY_NOCACHE_BUFFERABLE}, }; - if (nocache_region.size != 0) { - if (pma_region_is_valid(&nocache_region) == -EINVAL) { - __ASSERT(0, "Configuring PMA region of nocache region failed\n"); + if (pma_region_is_valid(&nocache_region)) { + /* Skip PMA configuration if nocache region size is 0 */ + if (nocache_region.size != 0) { + __ASSERT(0, "Configuring PMA region of nocache region " + "failed\n"); } - + } else { /* Initialize nocache region at PMA region 0 */ region_init(0, &nocache_region); } @@ -242,7 +203,7 @@ static int pma_init(void) { unsigned long mmsc_cfg; - __asm__ volatile ("csrr %0, %1" : "=r" (mmsc_cfg) : "i" (NDS_MMSC_CFG)); + mmsc_cfg = csr_read(NDS_MMSC_CFG); if (!(mmsc_cfg & MMSC_CFG_PPMA)) { /* This CPU doesn't support PMA */ @@ -250,7 +211,8 @@ static int pma_init(void) __ASSERT(0, "CPU doesn't support PMA. " "Please disable CONFIG_SOC_ANDES_V5_PMA\n"); #ifndef CONFIG_ASSERT - LOG_ERR("CPU doesn't support PMA. Please disable CONFIG_SOC_ANDES_V5_PMA"); + LOG_ERR("CPU doesn't support PMA. " + "Please disable CONFIG_SOC_ANDES_V5_PMA"); #endif return -ENODEV; } @@ -260,5 +222,4 @@ static int pma_init(void) return 0; } -SYS_INIT(pma_init, PRE_KERNEL_2, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(pma_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); From 9c7f0376b89757ca7a965429f67c16a1815113d0 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 11:02:40 +0800 Subject: [PATCH 1322/2042] soc: riscv: andes_v5: support PMP and USERSPACE Enable PMP and set PMP granularity to 8 for most of ae350 bitstream. This commit also make MPU_ALIGN() apply to __rom_region_end in XIP system. Signed-off-by: Jimmy Zheng --- boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig | 3 +++ .../riscv-privileged/andes_v5/Kconfig.defconfig.ae350 | 3 +++ soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 1 + soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld | 11 ++++++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 680c35034742..4c925de1672e 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -33,6 +33,9 @@ CONFIG_HWINFO_ANDES=y #CONFIG_FLOAT_HARD=y #CONFIG_DOUBLE_PRECISION_FPU=y +# PMP granularity options +CONFIG_PMP_GRANULARITY=8 + # HW DSP options #CONFIG_SOC_ANDES_V5_HWDSP=y diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 index 1ff59bf69dc5..fa473f4b06a0 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 @@ -15,6 +15,9 @@ config MAIN_STACK_SIZE config IDLE_STACK_SIZE default 1536 +config PRIVILEGED_STACK_SIZE + default 2048 if 64BIT + config TEST_EXTRA_STACK_SIZE default 1024 diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index a9448b02ec3d..4ecda6306e80 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -11,6 +11,7 @@ config SOC_RISCV_ANDES_AE350 select INCLUDE_RESET_VECTOR select RISCV_ISA_EXT_M select RISCV_ISA_EXT_A + select RISCV_PMP endchoice diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld index 28a081aa7093..a47aceb60389 100644 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld +++ b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld @@ -108,11 +108,12 @@ SECTIONS } GROUP_START(ROMABLE_REGION) - __rom_region_start = ROM_BASE; SECTION_PROLOGUE(rom_start,,) { . = ALIGN(16); + MPU_ALIGN(__rom_region_size); + __rom_region_start = .; /* Located in generated directory. This file is populated by calling * zephyr_linker_sources(ROM_START ...). */ @@ -405,9 +406,17 @@ SECTION_PROLOGUE(.last_section,,) #endif } GROUP_LINK_IN(ROMABLE_REGION) +#ifndef CONFIG_RISCV_PMP /* To provide the image size as a const expression, * calculate this value here. */ __rom_region_end = LOADADDR(.last_section) + SIZEOF(.last_section); +#else +SECTION_PROLOGUE(rom_mpu_padding,(NOLOAD),) +{ + MPU_ALIGN(__rom_region_size); + __rom_region_end = .; +} GROUP_LINK_IN(ROMABLE_REGION) +#endif /* !CONFIG_RISCV_PMP */ __rom_region_size = __rom_region_end - __rom_region_start; #endif From d5c4bd683018e2fa3715ca961dc54dead5aef246 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 17:23:53 +0800 Subject: [PATCH 1323/2042] soc: riscv: andes_v5: support RISC-V C extension Enable RISC-V C extension for Andes core. Signed-off-by: Jimmy Zheng --- soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 1 + 1 file changed, 1 insertion(+) diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index 4ecda6306e80..376abcb4697b 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -11,6 +11,7 @@ config SOC_RISCV_ANDES_AE350 select INCLUDE_RESET_VECTOR select RISCV_ISA_EXT_M select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C select RISCV_PMP endchoice From 004e00a0bd0551a49c2d9c9045a0064289e2f155 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 17:36:02 +0800 Subject: [PATCH 1324/2042] soc: riscv: andes_v5: add RV32E_CPU option Add CONFIG_RV32E_CPU for AE350 platform integrated with Andes RV32E core, such as N22, D23 core. Signed-off-by: Jimmy Zheng --- soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index 376abcb4697b..b201e5a338eb 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -28,6 +28,12 @@ config RV32I_CPU select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI +config RV32E_CPU + bool "RISCV32E CPU ISA" + select RISCV_ISA_RV32E + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + config RV64I_CPU bool "RISCV64 CPU ISA" select RISCV_ISA_RV64I From 65edd8433c42257cb096c39ed26edb869189c5e5 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 17:01:40 +0800 Subject: [PATCH 1325/2042] soc: riscv: andes_v5: add Andes EXEC.IT option Andes EXEC.IT (Execution on Instruction Table) is supported by Andes toolchain only. Andes toolchain will replaces suitable 32-bit instructions with the 16-bit "exec.it " in which points to a corresponding 32-bit instruction in look up table. Signed-off-by: Jimmy Zheng --- boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig | 3 +++ soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt | 7 +++++++ soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 10 ++++++++++ .../riscv-privileged/andes_v5/common_linker/execit.ld | 8 ++++++++ soc/riscv/riscv-privileged/andes_v5/soc_v5.h | 1 + soc/riscv/riscv-privileged/andes_v5/start.S | 4 ++-- 6 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 4c925de1672e..cb45049b4c5f 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -39,6 +39,9 @@ CONFIG_PMP_GRANULARITY=8 # HW DSP options #CONFIG_SOC_ANDES_V5_HWDSP=y +# EXEC.IT options +#CONFIG_SOC_ANDES_V5_EXECIT=y + # Cache options CONFIG_CACHE_ENABLE=y diff --git a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt index b3e8f14209e8..38e1320bf7dd 100644 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt @@ -10,9 +10,16 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_PMA pma.c) zephyr_linker_sources(ROM_START SORT_KEY 0x0 common_linker/init.ld) +zephyr_linker_sources_ifdef(CONFIG_SOC_ANDES_V5_EXECIT RODATA SORT_KEY 0x0 common_linker/execit.ld) zephyr_linker_sources_ifdef(CONFIG_XIP RAM_SECTIONS SORT_KEY 0x0 common_linker/ram_start_nonzero.ld) # Note: AndeStar V5 DSP needs custom Andes V5 toolchain if(CONFIG_SOC_ANDES_V5_HWDSP) zephyr_cc_option(-mext-dsp) endif() + +# Note: AndeStar V5 EXEC.IT needs custom Andes V5 toolchain +if(CONFIG_SOC_ANDES_V5_EXECIT) + zephyr_cc_option(-mexecit) + zephyr_ld_options(-Wl,--mexecit) +endif() diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index b201e5a338eb..58a8e22fff58 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -80,6 +80,16 @@ config SOC_ANDES_V5_PFT The PowerBrake extension throttles performance by reducing instruction executing rate. +config SOC_ANDES_V5_EXECIT + bool "Andes V5 EXEC.IT extension" + depends on RISCV_ISA_EXT_C + depends on !RISCV_GENERIC_TOOLCHAIN + depends on !LINKER_USE_NO_RELAX + help + The EXEC.IT extension (Execution on Instruction Table) generate + a look-up table and replaces suitable 32-bit instructions with + the 16-bit "exec.it ". + config SOC_ANDES_V5_PMA bool "Andes V5 Physical Memory Attribute (PMA)" select ARCH_HAS_NOCACHE_MEMORY_SUPPORT diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld b/soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld new file mode 100644 index 000000000000..64fa46a02c38 --- /dev/null +++ b/soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +. = ALIGN(4); +KEEP(*(.exec.itable)) diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_v5.h b/soc/riscv/riscv-privileged/andes_v5/soc_v5.h index 2e4ffa6ffa60..09d7ddca9034 100644 --- a/soc/riscv/riscv-privileged/andes_v5/soc_v5.h +++ b/soc/riscv/riscv-privileged/andes_v5/soc_v5.h @@ -12,6 +12,7 @@ #define NDS_MCACHE_CTL 0x7CA #define NDS_MMSC_CFG 0xFC2 #define NDS_MXSTATUS 0x7C4 +#define NDS_UITB 0x800 #define NDS_UCODE 0x801 /* Control and Status Registers (CSRs) available for Andes V5 PMA */ diff --git a/soc/riscv/riscv-privileged/andes_v5/start.S b/soc/riscv/riscv-privileged/andes_v5/start.S index ddf5cc174a18..2841061ca55a 100644 --- a/soc/riscv/riscv-privileged/andes_v5/start.S +++ b/soc/riscv/riscv-privileged/andes_v5/start.S @@ -15,10 +15,10 @@ SECTION_FUNC(init, entry) .option push .option norelax -#ifdef __nds_execit +#ifdef CONFIG_SOC_ANDES_V5_EXECIT /* Initialize EXECIT table */ la t0, _ITB_BASE_ - csrw uitb, t0 + csrw NDS_UITB, t0 #endif #ifdef CONFIG_CACHE_ENABLE From a1665cbf1c1bec9c7cb259f3d1c77060b4933c0d Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 18:11:38 +0800 Subject: [PATCH 1326/2042] soc: riscv: andes_v5: refine Andes L2 cache Refine source code and flush all I/D-Cache before update L2 cache register. Signed-off-by: Jimmy Zheng --- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts | 4 + .../riscv-privileged/andes_v5/CMakeLists.txt | 2 +- .../riscv-privileged/andes_v5/Kconfig.soc | 7 ++ .../riscv-privileged/andes_v5/l2_cache.c | 92 +++++++++---------- 4 files changed, 53 insertions(+), 52 deletions(-) diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts index 011e8e5597c4..2f77b50228c7 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.dts @@ -133,6 +133,10 @@ }; }; +&l2_cache { + status = "okay"; +}; + &syscon { status = "okay"; }; diff --git a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt index 38e1320bf7dd..3de7b8c8841a 100644 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt @@ -5,10 +5,10 @@ zephyr_include_directories(${CONFIG_SOC}) zephyr_sources( start.S soc_irq.S - l2_cache.c ) zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_PMA pma.c) +zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_L2C l2_cache.c) zephyr_linker_sources(ROM_START SORT_KEY 0x0 common_linker/init.ld) zephyr_linker_sources_ifdef(CONFIG_SOC_ANDES_V5_EXECIT RODATA SORT_KEY 0x0 common_linker/execit.ld) zephyr_linker_sources_ifdef(CONFIG_XIP RAM_SECTIONS SORT_KEY 0x0 common_linker/ram_start_nonzero.ld) diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index 58a8e22fff58..c575d3358265 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -107,4 +107,11 @@ config SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE Minimum size (and alignment) of an PMA region. Use this symbol to guarantee minimum size and alignment of PMA regions. +# Workaround for not being able to have commas in macro arguments +DT_ANDESTECH_L2C := andestech,l2c + +config SOC_ANDES_V5_L2C + bool + default $(dt_compat_enabled,$(DT_ANDESTECH_L2C)) + endif # SOC_SERIES_RISCV_ANDES_V5 diff --git a/soc/riscv/riscv-privileged/andes_v5/l2_cache.c b/soc/riscv/riscv-privileged/andes_v5/l2_cache.c index 47bceadea815..69e8d00b9473 100644 --- a/soc/riscv/riscv-privileged/andes_v5/l2_cache.c +++ b/soc/riscv/riscv-privileged/andes_v5/l2_cache.c @@ -15,103 +15,93 @@ #include #include #include -LOG_MODULE_REGISTER(andes_v5_l2_cache, CONFIG_SOC_LOG_LEVEL); - -#if DT_NODE_EXISTS(DT_INST(0, andestech_l2c)) - -/* SMU Configuration Register offset */ -#define SMU_SYSTEMCFG 0x08 +#include -/* Register bitmask */ -#define SMU_SYSTEMCFG_L2C BIT(8) - -/* - * L2C Register Base Address - */ +LOG_MODULE_REGISTER(andes_v5_l2_cache, CONFIG_SOC_LOG_LEVEL); +/* L2C Register Base Address */ #define ANDES_V5_L2C_BASE DT_INST_REG_ADDR(0) -/* - * L2C Register Offset - */ - -#define L2C_CONFIG 0x00 -#define L2C_CTRL 0x08 +/* L2C Register Offset */ +#define L2C_CONFIG (ANDES_V5_L2C_BASE + 0x00) +#define L2C_CTRL (ANDES_V5_L2C_BASE + 0x08) -/* - * L2C Helper Constant - */ - -/* L2 cache version */ -#define L2C_CONFIG_VERSION_SHIFT 24 - -/* enable L2C */ +/* L2C Helper Constant */ +#define L2C_CONFIG_VER GENMASK64(31, 24) #define L2C_CTRL_CEN BIT(0) -/* instruction prefetch depth */ +/* Instruction prefetch depth */ #define IPFDPT_FIELD(x) (x << 3) #define L2C_CTRL_IPFDPT_0 IPFDPT_FIELD(0) #define L2C_CTRL_IPFDPT_1 IPFDPT_FIELD(1) #define L2C_CTRL_IPFDPT_2 IPFDPT_FIELD(2) #define L2C_CTRL_IPFDPT_3 IPFDPT_FIELD(3) -/* data prefetch depth */ +/* Data prefetch depth */ #define DPFDPT_FIELD(x) (x << 5) #define L2C_CTRL_DPFDPT_0 DPFDPT_FIELD(0) #define L2C_CTRL_DPFDPT_2 DPFDPT_FIELD(1) #define L2C_CTRL_DPFDPT_4 DPFDPT_FIELD(2) #define L2C_CTRL_DPFDPT_8 DPFDPT_FIELD(3) +#if DT_HAS_COMPAT_STATUS_OKAY(andestech_atcsmu100) +/* SMU Register offset */ +#define SMU_SYSTEMCFG 0x08 + +/* SMU Helper Constant */ +#define SMU_SYSTEMCFG_L2C BIT(8) +#endif + static void andes_v5_l2c_enable(void) { - unsigned long mcache_ctl; - volatile uint64_t *l2c_ctrl = - INT_TO_POINTER(ANDES_V5_L2C_BASE + L2C_CTRL); + uint32_t l2c_ctrl = sys_read32(L2C_CTRL); - __asm__ volatile ("csrr %0, %1" - : "=r" (mcache_ctl) : "i" (NDS_MCACHE_CTL)); + /* Enable L2C if I-cache or D-cache is enabled */ + if (csr_read(NDS_MCACHE_CTL) & BIT_MASK(2)) { + uint32_t l2c_config = sys_read32(L2C_CONFIG); - /* Enable L2 cache if L1 I/D cache enabled */ - if (mcache_ctl & (BIT(1) | BIT(0))) { - volatile uint64_t *l2c_config = - INT_TO_POINTER(ANDES_V5_L2C_BASE + L2C_CONFIG); + /* Memory barrier, flush all I/D-Cache before setting L2C */ + __asm__ volatile ("fence.i"); - *l2c_ctrl |= (L2C_CTRL_IPFDPT_3 | L2C_CTRL_DPFDPT_8); + l2c_ctrl |= (L2C_CTRL_IPFDPT_3 | L2C_CTRL_DPFDPT_8); + sys_write32(l2c_ctrl, L2C_CTRL); - /* Enable L2 cache manually if device version less than 0xF0 */ - if (!((*l2c_config >> L2C_CONFIG_VERSION_SHIFT) & 0xF0)) { - *l2c_ctrl |= L2C_CTRL_CEN; + /* Enable L2C for Gen1 L2C, Gen2 L2C defaults to enable */ + if ((l2c_config & L2C_CONFIG_VER) < (16 << 24)) { + l2c_ctrl = sys_read32(L2C_CTRL); + l2c_ctrl |= L2C_CTRL_CEN; + sys_write32(l2c_ctrl, L2C_CTRL); } } else { - /* Disable L2 cache */ - *l2c_ctrl &= ~L2C_CTRL_CEN; + /* Disable L2C */ + l2c_ctrl &= ~L2C_CTRL_CEN; + sys_write32(l2c_ctrl, L2C_CTRL); } } static int andes_v5_l2c_init(void) { -#if DT_NODE_HAS_STATUS(DT_INST(0, syscon), okay) - uint32_t system_cfg; +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(syscon), andestech_atcsmu100, okay) const struct device *const syscon_dev = DEVICE_DT_GET(DT_NODELABEL(syscon)); - if (device_is_ready(syscon_dev)) { + uint32_t system_cfg; + syscon_read_reg(syscon_dev, SMU_SYSTEMCFG, &system_cfg); + /* Platform doesn't have L2C */ if (!(system_cfg & SMU_SYSTEMCFG_L2C)) { - /* This SoC doesn't have L2 cache */ return -ENODEV; } } else { - LOG_DBG("Init might fail for some hardware combinations " - "if syscon driver isn't ready\n"); + LOG_ERR("Syscon driver should be initialized before L2 Cache " + "initialization."); } #endif andes_v5_l2c_enable(); + return 0; } SYS_INIT(andes_v5_l2c_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - -#endif /* DT_NODE_EXISTS(DT_INST(0, andestech_l2c)) */ From b6122c358aad46f62eddcf5ea15c55bbd657935d Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Mon, 26 Jun 2023 18:29:41 +0800 Subject: [PATCH 1327/2042] soc: riscv: andes_v5: add Andes I/O Coherence Port option Add CONFIG_SOC_ANDES_V5_IOCP to indicate Andes I/O Coherence Port handle cache coherency between cache and external non-caching master, such as DMA controller. Signed-off-by: Jimmy Zheng --- boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig | 3 +++ soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index cb45049b4c5f..605692be070f 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -48,3 +48,6 @@ CONFIG_CACHE_ENABLE=y # Nocache memory options #CONFIG_SOC_ANDES_V5_PMA=y #CONFIG_NOCACHE_MEMORY=y + +# I/O Coherence Port options +#CONFIG_SOC_ANDES_V5_IOCP=y diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index c575d3358265..e579ef0773ea 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -114,4 +114,13 @@ config SOC_ANDES_V5_L2C bool default $(dt_compat_enabled,$(DT_ANDESTECH_L2C)) +config SOC_ANDES_V5_IOCP + bool "Andes V5 I/O Coherence Port (IOCP)" + depends on SOC_ANDES_V5_L2C + depends on CACHE_ENABLE + help + Support Andes V5 I/O Coherence Port to handle cache coherency + between cache and external non-caching master, such as DMA + controller. + endif # SOC_SERIES_RISCV_ANDES_V5 From e6b1251b0df8082de83a38b2d354d47c1131dd48 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Tue, 27 Jun 2023 13:49:52 +0800 Subject: [PATCH 1328/2042] soc: riscv: andes_v5: enlarge TEST_EXTRA_STACK_SIZE Enlarge TEST_EXTRA_STACK_SIZE for AE350 RV64 bitstream. Signed-off-by: Jimmy Zheng --- soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 index fa473f4b06a0..4b949c29677e 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 @@ -19,7 +19,7 @@ config PRIVILEGED_STACK_SIZE default 2048 if 64BIT config TEST_EXTRA_STACK_SIZE - default 1024 + default 2048 if 64BIT config MP_MAX_NUM_CPUS default 1 From 82c2f388ee924302f995f0e6fb514244df94d107 Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Wed, 28 Jun 2023 14:45:49 +0800 Subject: [PATCH 1329/2042] tests: kernel: gen_isr_table.riscv_direct: exclude adp_xc7k_ae350 Exclude adp_xc7k_ae350 because Andes core doesn't support RISC-V vectored mode from csr $mtvec. Signed-off-by: Jimmy Zheng --- tests/kernel/gen_isr_table/testcase.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/kernel/gen_isr_table/testcase.yaml b/tests/kernel/gen_isr_table/testcase.yaml index 63735a6993f6..28da46e7db09 100644 --- a/tests/kernel/gen_isr_table/testcase.yaml +++ b/tests/kernel/gen_isr_table/testcase.yaml @@ -50,7 +50,9 @@ tests: arch_allow: - riscv32 - riscv64 - platform_exclude: m2gl025_miv + platform_exclude: + - m2gl025_miv + - adp_xc7k_ae350 filter: CONFIG_SOC_FAMILY_RISCV_PRIVILEGED extra_configs: - CONFIG_GEN_IRQ_VECTOR_TABLE=y From 4f26203b59589cfbc8d39f01367e0709f01a3e9c Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Fri, 30 Jun 2023 13:53:11 +0800 Subject: [PATCH 1330/2042] soc: riscv: andes_v5: remove redundant CONFIG_CACHE_ENABLE Replace redundant CONFIG_CACHE_ENABLE by generic Kconfig CONFIG_ICACHE, CONFIG_DCACHE. Signed-off-by: Jimmy Zheng --- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig | 3 --- .../andes_v5/Kconfig.defconfig.ae350 | 2 +- soc/riscv/riscv-privileged/andes_v5/Kconfig.soc | 8 +++----- soc/riscv/riscv-privileged/andes_v5/start.S | 15 ++++++++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 605692be070f..3f7f1f727c6c 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -42,9 +42,6 @@ CONFIG_PMP_GRANULARITY=8 # EXEC.IT options #CONFIG_SOC_ANDES_V5_EXECIT=y -# Cache options -CONFIG_CACHE_ENABLE=y - # Nocache memory options #CONFIG_SOC_ANDES_V5_PMA=y #CONFIG_NOCACHE_MEMORY=y diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 index 4b949c29677e..5d652057a38b 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 @@ -7,7 +7,7 @@ config SOC default "ae350" config SYS_CLOCK_TICKS_PER_SEC - default 100 if (!CACHE_ENABLE || XIP) + default 100 if (!ICACHE || XIP) config MAIN_STACK_SIZE default 2048 diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc index e579ef0773ea..19f215e2c5ac 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc @@ -12,6 +12,8 @@ config SOC_RISCV_ANDES_AE350 select RISCV_ISA_EXT_M select RISCV_ISA_EXT_A select RISCV_ISA_EXT_C + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE select RISCV_PMP endchoice @@ -60,10 +62,6 @@ config DOUBLE_PRECISION_FPU endchoice -config CACHE_ENABLE - bool "Cache" - default n - config SOC_ANDES_V5_HWDSP bool "AndeStar V5 DSP ISA" select RISCV_SOC_CONTEXT_SAVE @@ -117,7 +115,7 @@ config SOC_ANDES_V5_L2C config SOC_ANDES_V5_IOCP bool "Andes V5 I/O Coherence Port (IOCP)" depends on SOC_ANDES_V5_L2C - depends on CACHE_ENABLE + depends on DCACHE help Support Andes V5 I/O Coherence Port to handle cache coherency between cache and external non-caching master, such as DMA diff --git a/soc/riscv/riscv-privileged/andes_v5/start.S b/soc/riscv/riscv-privileged/andes_v5/start.S index 2841061ca55a..84e0d91cb91b 100644 --- a/soc/riscv/riscv-privileged/andes_v5/start.S +++ b/soc/riscv/riscv-privileged/andes_v5/start.S @@ -21,15 +21,20 @@ SECTION_FUNC(init, entry) csrw NDS_UITB, t0 #endif -#ifdef CONFIG_CACHE_ENABLE +#ifdef CONFIG_ICACHE + /* Enable I cache with HW prefetcher. */ + li t0, (1 << 9) | (1 << 0) + csrs NDS_MCACHE_CTL, t0 +#endif + +#ifdef CONFIG_DCACHE /* - * Enable I/D cache with HW prefetcher, - * D-cache write-around (threshold: 4 cache lines), - * and CM (Coherence Manager). + * Enable D cache with HW prefetcher, D-cache write-around + * (threshold: 4 cache lines), and CM (Coherence Manager). */ li t0, (0x3 << 13) csrc NDS_MCACHE_CTL, t0 - li t0, (1 << 19) | (1 << 13) | (1 << 10) | (1 << 9) | (0x3) + li t0, (1 << 19) | (1 << 13) | (1 << 10) | (1 << 1) csrs NDS_MCACHE_CTL, t0 /* Check if CPU support CM or not. */ From a612ee931205b5e17d2b2ab168a4d74b9150ab83 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sat, 20 May 2023 13:39:24 -0400 Subject: [PATCH 1331/2042] boards: arm: xmc47_relax_kit: Add arduino_r3_connector Adds arduino_r3_connector mappings. Signed-off-by: Andriy Gelman --- .../xmc47_relax_kit/arduino_r3_connector.dtsi | 57 +++++++++++++++++++ .../xmc47_relax_kit-pinctrl.dtsi | 28 +++++++++ .../arm/xmc47_relax_kit/xmc47_relax_kit.dts | 28 +++++++++ .../arm/xmc47_relax_kit/xmc47_relax_kit.yaml | 2 + 4 files changed, 115 insertions(+) create mode 100644 boards/arm/xmc47_relax_kit/arduino_r3_connector.dtsi diff --git a/boards/arm/xmc47_relax_kit/arduino_r3_connector.dtsi b/boards/arm/xmc47_relax_kit/arduino_r3_connector.dtsi new file mode 100644 index 000000000000..45a836f692c8 --- /dev/null +++ b/boards/arm/xmc47_relax_kit/arduino_r3_connector.dtsi @@ -0,0 +1,57 @@ +/* Copyright (c) 2023 Andriy Gelman + * + * 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 &gpio14 0 0>, /* A0 */ + <1 0 &gpio14 1 0>, /* A1 */ + <2 0 &gpio14 2 0>, /* A2 */ + <3 0 &gpio14 3 0>, /* A3 */ + <4 0 &gpio14 4 0>, /* A4 */ + <5 0 &gpio14 5 0>, /* A5 */ + <6 0 &gpio2 15 0>, /* D0 */ + <7 0 &gpio2 14 0>, /* D1 */ + <8 0 &gpio1 0 0>, /* D2 */ + <9 0 &gpio1 1 0>, /* D3 */ + <10 0 &gpio1 8 0>, /* D4 */ + <11 0 &gpio2 12 0>, /* D5 */ + <12 0 &gpio2 11 0>, /* D6 */ + <13 0 &gpio1 9 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 11 0>, /* D9 */ + <16 0 &gpio3 10 0>, /* D10 */ + <17 0 &gpio3 8 0>, /* D11 */ + <18 0 &gpio3 7 0>, /* D12 */ + <19 0 &gpio3 9 0>, /* D13 */ + <20 0 &gpio3 15 0>, /* D14 */ + <21 0 &gpio3 13 0>; /* D15 */ + }; +}; + +&gpio14 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio3 { + status = "okay"; +}; + +arduino_spi: &usic2ch0 {}; +arduino_serial: &usic1ch0 {}; +/* The drivers for i2c not yet implemented. Add placeholder in the */ +/* correct usic channel. */ +arduino_i2c: &usic1ch1 {}; 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 7c20e5e283e9..9a4b8fde34d8 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -15,3 +15,31 @@ drive-strength = "strong-soft-edge"; hwctrl = "disabled"; }; + +&uart_tx_p2_14_u1c0 { + drive-strength = "strong-soft-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&uart_rx_p2_15_u1c0 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; + +&spi_mosi_p3_8_u2c0 { + drive-strength = "strong-soft-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&spi_miso_p3_7_u2c0 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; + +&spi_sclk_p3_9_u2c0 { + drive-strength = "strong-soft-edge"; + drive-push-pull; + 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 c2e271e5591a..c02b4215d91e 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -10,6 +10,7 @@ #include #include #include "xmc47_relax_kit-pinctrl.dtsi" +#include "arduino_r3_connector.dtsi" / { model = "Infineon XMC4700 Relax Kit board"; @@ -88,6 +89,33 @@ status = "okay"; }; +&usic1ch0 { + compatible = "infineon,xmc4xxx-uart"; + current-speed = <115200>; + pinctrl-0 = <&uart_tx_p2_14_u1c0 &uart_rx_p2_15_u1c0>; + pinctrl-names = "default"; + input-src = "DX0C"; + interrupts = <92 1 93 1>; + interrupt-names = "tx", "rx"; + fifo-start-offset = <0>; + fifo-tx-size = <0>; + fifo-rx-size = <0>; + status = "okay"; +}; + +&usic2ch0 { + compatible = "infineon,xmc4xxx-spi"; + pinctrl-0 = <&spi_mosi_p3_8_u2c0 &spi_miso_p3_7_u2c0 &spi_sclk_p3_9_u2c0>; + pinctrl-names = "default"; + miso-src = "DX0C"; + interrupts = <96 1 97 1>; + interrupt-names = "tx", "rx"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; +}; + &adc0 { vref-internal-mv = <3300>; }; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml index 09fe856c7669..d1b96e3635b2 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -12,5 +12,7 @@ supported: - i2c - spi - uart + - arduino_spi + - arduino_serial ram: 352 flash: 2048 From 78c18c0bae805245448818d4fbe9da39d615d6f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 11 Jul 2023 14:43:50 +0200 Subject: [PATCH 1332/2042] dts: arm: st: f4: fix stm32f4 adc2 and 3 Adds the missing resolutions and sampling times properties to STM32F405 ADC2 and ADC3. Signed-off-by: Guillaume Gautier --- dts/arm/st/f4/stm32f405.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/arm/st/f4/stm32f405.dtsi b/dts/arm/st/f4/stm32f405.dtsi index 04d5cd2ea9b6..a3264e2bf4cf 100644 --- a/dts/arm/st/f4/stm32f405.dtsi +++ b/dts/arm/st/f4/stm32f405.dtsi @@ -252,6 +252,11 @@ interrupts = <18 0>; status = "disabled"; #io-channel-cells = <1>; + resolutions = ; + sampling-times = <3 15 28 56 84 112 144 480>; }; adc3: adc@40012200 { @@ -261,6 +266,11 @@ interrupts = <18 0>; status = "disabled"; #io-channel-cells = <1>; + resolutions = ; + sampling-times = <3 15 28 56 84 112 144 480>; }; dac1: dac@40007400 { From 0e35bbbfd2cd64cd59af823067a78c561ba08b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Thu, 13 Jul 2023 13:26:53 +0200 Subject: [PATCH 1333/2042] Bluetooth: Mesh: Add missing CBs for cfg_cli msg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds callback API for the following config client status messages: - Composition data status - Model publication status - SIG model subscription list - Vendor model subscription list - Netkey list - Appkey list - SIG model app list - Vendor model app list - Key refresh status - Heartbeat publication status - Heartbeat subscription status Signed-off-by: Anders Storrø --- include/zephyr/bluetooth/mesh/cfg_cli.h | 142 ++++++++++++++++++++++++ subsys/bluetooth/mesh/cfg_cli.c | 125 ++++++++++++++++----- 2 files changed, 239 insertions(+), 28 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/cfg_cli.h b/include/zephyr/bluetooth/mesh/cfg_cli.h index ea48c3b30d5c..e6fd31d7c3ac 100644 --- a/include/zephyr/bluetooth/mesh/cfg_cli.h +++ b/include/zephyr/bluetooth/mesh/cfg_cli.h @@ -25,9 +25,45 @@ extern "C" { #endif struct bt_mesh_cfg_cli; +struct bt_mesh_cfg_cli_hb_pub; +struct bt_mesh_cfg_cli_hb_sub; +struct bt_mesh_cfg_cli_mod_pub; /** Mesh Configuration Client Status messages callback */ struct bt_mesh_cfg_cli_cb { + + /** @brief Optional callback for Composition data messages. + * + * Handles received Composition data messages from a server. + * + * @note For decoding @c buf, please refer to + * @ref bt_mesh_comp_p0_get and + * @ref bt_mesh_comp_p1_elem_pull. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param page Composition data page. + * @param buf Composition data buffer. + */ + void (*comp_data)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t page, + struct net_buf_simple *buf); + + /** @brief Optional callback for Model Pub status messages. + * + * Handles received Model Pub status messages from a server. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param elem_addr Address of the element. + * @param mod_id Model ID. + * @param cid Company ID. + * @param pub Publication configuration parameters. + */ + void (*mod_pub_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, + uint16_t elem_addr, uint16_t mod_id, uint16_t cid, + struct bt_mesh_cfg_cli_mod_pub *pub); + /** @brief Optional callback for Model Sub Status messages. * * Handles received Model Sub Status messages from a server. @@ -43,6 +79,26 @@ struct bt_mesh_cfg_cli_cb { uint8_t status, uint16_t elem_addr, uint16_t sub_addr, uint32_t mod_id); + /** @brief Optional callback for Model Sub list messages. + * + * Handles received Model Sub list messages from a server. + * + * @note The @c buf parameter should be decoded using + * @ref net_buf_simple_pull_le16 in iteration, as long + * as @c buf->len is greater than or equal to 2. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param elem_addr Address of the element. + * @param mod_id Model ID. + * @param cid Company ID. + * @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); + /** @brief Optional callback for Node Reset Status messages. * * Handles received Node Reset Status messages from a server. @@ -131,6 +187,20 @@ struct bt_mesh_cfg_cli_cb { void (*net_key_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, uint16_t net_idx); + /** @brief Optional callback for Netkey list messages. + * + * Handles received Netkey list messages from a server. + * + * @note The @c buf parameter should be decoded using the + * @ref bt_mesh_key_idx_unpack_list helper function. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @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); + /** @brief Optional callback for AppKey Status messages. * * Handles received AppKey Status messages from a server. @@ -145,6 +215,22 @@ struct bt_mesh_cfg_cli_cb { uint8_t status, uint16_t net_idx, uint16_t app_idx); + /** @brief Optional callback for Appkey list messages. + * + * Handles received Appkey list messages from a server. + * + * @note The @c buf parameter should be decoded using the + * @ref bt_mesh_key_idx_unpack_list helper function. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param net_idx The index of the NetKey. + * @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); + /** @brief Optional callback for Model App Status messages. * * Handles received Model App Status messages from a server. @@ -160,6 +246,25 @@ struct bt_mesh_cfg_cli_cb { uint8_t status, uint16_t elem_addr, uint16_t app_idx, uint32_t mod_id); + /** @brief Optional callback for Model App list messages. + * + * Handles received Model App list messages from a server. + * + * @note The @c buf parameter should be decoded using the + * @ref bt_mesh_key_idx_unpack_list helper function. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param elem_addr Address of the element. + * @param mod_id Model ID. + * @param cid Company ID. + * @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); + /** @brief Optional callback for Node Identity Status messages. * * Handles received Node Identity Status messages from a server. @@ -185,6 +290,43 @@ struct bt_mesh_cfg_cli_cb { */ void (*lpn_timeout_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint16_t elem_addr, uint32_t timeout); + + /** @brief Optional callback for Key Refresh Phase status messages. + * + * Handles received Key Refresh Phase status messages from a server. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param net_idx The index of the NetKey. + * @param phase Phase of the KRP. + */ + void (*krp_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, + uint16_t net_idx, uint8_t phase); + + /** @brief Optional callback for Heartbeat pub status messages. + * + * Handles received Heartbeat pub status messages from a server. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @param pub HB publication configuration parameters. + */ + void (*hb_pub_status)(struct bt_mesh_cfg_cli *cli, uint16_t addr, uint8_t status, + struct bt_mesh_cfg_cli_hb_pub *pub); + + /** @brief Optional callback for Heartbeat Sub status messages. + * + * Handles received Heartbeat Sub status messages from a server. + * + * @param cli Client that received the status message. + * @param addr Address of the sender. + * @param status Status code for the message. + * @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); }; /** Mesh Configuration Client Model Context */ diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index 167d1c642640..7234770ac914 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -52,6 +52,7 @@ static int comp_data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct net_buf_simple_state state; struct comp_data *param; size_t to_copy; uint8_t page; @@ -61,6 +62,7 @@ static int comp_data_status(struct bt_mesh_model *model, page = net_buf_simple_pull_u8(buf); + net_buf_simple_save(buf, &state); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_DEV_COMP_DATA_STATUS, ctx->addr, (void **)¶m)) { if (param->page) { @@ -74,6 +76,12 @@ static int comp_data_status(struct bt_mesh_model *model, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } + + net_buf_simple_restore(buf, &state); + if (cli->cb && cli->cb->comp_data) { + cli->cb->comp_data(cli, ctx->addr, page, buf); + } + return 0; } @@ -173,6 +181,7 @@ struct krp_param { static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + int err = 0; struct krp_param *param; uint16_t net_idx; uint8_t status, phase; @@ -186,7 +195,8 @@ static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_KRP_STATUS, ctx->addr, (void **)¶m)) { if (param->net_idx != net_idx) { - return -ENOENT; + err = -ENOENT; + goto done; } if (param->status) { @@ -200,7 +210,12 @@ static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; +done: + if (cli->cb && cli->cb->krp_status) { + cli->cb->krp_status(cli, ctx->addr, status, net_idx, phase); + } + + return err; } struct relay_param { @@ -334,28 +349,36 @@ static int net_key_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + int err = 0; struct net_key_list_param *param; + struct net_buf_simple_state state; LOG_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); + net_buf_simple_save(buf, &state); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, (void **)¶m)) { - if (param->keys && param->key_cnt) { - int err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); + err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); if (err) { LOG_ERR("The message size for the application opcode is " "incorrect."); - return err; + goto done; } } bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; +done: + net_buf_simple_restore(buf, &state); + if (cli->cb && cli->cb->net_key_list) { + cli->cb->net_key_list(cli, ctx->addr, buf); + } + + return err; } static int node_reset_status(struct bt_mesh_model *model, @@ -442,6 +465,8 @@ static int app_key_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + int err = 0; + struct net_buf_simple_state state; struct app_key_list_param *param; uint16_t net_idx; uint8_t status; @@ -451,6 +476,7 @@ static int app_key_list(struct bt_mesh_model *model, status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; + net_buf_simple_save(buf, &state); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_LIST, ctx->addr, (void **)¶m)) { @@ -462,12 +488,12 @@ static int app_key_list(struct bt_mesh_model *model, if (param->keys && param->key_cnt) { - int err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); + err = bt_mesh_key_idx_unpack_list(buf, param->keys, param->key_cnt); if (err) { LOG_ERR("The message size for the application opcode is " "incorrect."); - return err; + goto done; } } @@ -477,7 +503,14 @@ static int app_key_list(struct bt_mesh_model *model, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; + +done: + net_buf_simple_restore(buf, &state); + if (cli->cb && cli->cb->app_key_list) { + cli->cb->app_key_list(cli, ctx->addr, status, net_idx, buf); + } + + return err; } struct mod_app_param { @@ -558,33 +591,34 @@ struct mod_member_list_param { static int mod_sub_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t op, bool vnd) { + int err = 0; struct mod_member_list_param *param; + struct net_buf_simple_state state; uint16_t elem_addr, mod_id, cid; uint8_t status; - int i; status = net_buf_simple_pull_u8(buf); elem_addr = net_buf_simple_pull_le16(buf); - if (vnd) { - cid = net_buf_simple_pull_le16(buf); - } + cid = vnd ? net_buf_simple_pull_le16(buf) : CID_NVAL; mod_id = net_buf_simple_pull_le16(buf); + if (buf->len % 2) { + LOG_WRN("Model Member List invalid length"); + return -EMSGSIZE; + } + net_buf_simple_save(buf, &state); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op, ctx->addr, (void **)¶m)) { if (param->elem_addr != elem_addr || param->mod_id != mod_id || (vnd && param->cid != cid)) { LOG_WRN("Model Member List parameters did not match"); - return -ENOENT; - } - - if (buf->len % 2) { - LOG_WRN("Model Member List invalid length"); - return -EMSGSIZE; + err = -ENOENT; + goto done; } if (param->member_cnt && param->members) { + int i; for (i = 0; i < *param->member_cnt && buf->len; i++) { param->members[i] = net_buf_simple_pull_le16(buf); @@ -599,24 +633,33 @@ static int mod_sub_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simpl bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; + +done: + net_buf_simple_restore(buf, &state); + if (cli->cb && cli->cb->mod_sub_list) { + cli->cb->mod_sub_list(cli, ctx->addr, status, elem_addr, mod_id, cid, buf); + } + + return err; + } static int mod_app_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf, uint16_t op, bool vnd) { + int err = 0; + struct net_buf_simple_state state; struct mod_member_list_param *param; uint16_t elem_addr, mod_id, cid; uint8_t status; status = net_buf_simple_pull_u8(buf); elem_addr = net_buf_simple_pull_le16(buf); - if (vnd) { - cid = net_buf_simple_pull_le16(buf); - } + cid = vnd ? net_buf_simple_pull_le16(buf) : CID_NVAL; mod_id = net_buf_simple_pull_le16(buf); + net_buf_simple_save(buf, &state); if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, op, ctx->addr, (void **)¶m)) { if (param->elem_addr != elem_addr || param->mod_id != mod_id || @@ -633,7 +676,7 @@ static int mod_app_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simpl if (err) { LOG_ERR("The message size for the application opcode is " "incorrect."); - return err; + goto done; } } @@ -643,7 +686,14 @@ static int mod_app_list_handle(struct bt_mesh_msg_ctx *ctx, struct net_buf_simpl bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; + +done: + net_buf_simple_restore(buf, &state); + if (cli->cb && cli->cb->mod_app_list) { + cli->cb->mod_app_list(cli, ctx->addr, status, elem_addr, mod_id, cid, buf); + } + + return err; } static int mod_app_list(struct bt_mesh_model *model, @@ -677,6 +727,7 @@ static int mod_pub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + int err = 0; struct mod_pub_param *param; uint16_t mod_id, cid, elem_addr; struct bt_mesh_cfg_cli_mod_pub pub; @@ -714,12 +765,14 @@ static int mod_pub_status(struct bt_mesh_model *model, (void **)¶m)) { if (mod_id != param->mod_id || cid != param->cid) { LOG_WRN("Mod Pub Model ID or Company ID mismatch"); - return -ENOENT; + err = -ENOENT; + goto done; } if (elem_addr != param->elem_addr) { LOG_WRN("Model Pub Status for unexpected element (0x%04x)", elem_addr); - return -ENOENT; + err = -ENOENT; + goto done; } if (param->status) { @@ -737,7 +790,13 @@ static int mod_pub_status(struct bt_mesh_model *model, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } - return 0; + +done: + if (cli->cb && cli->cb->mod_pub_status) { + cli->cb->mod_pub_status(cli, ctx->addr, status, elem_addr, mod_id, cid, &pub); + } + + return err; } struct mod_sub_param { @@ -863,6 +922,11 @@ static int hb_sub_status(struct bt_mesh_model *model, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } + + if (cli->cb && cli->cb->hb_sub_status) { + cli->cb->hb_sub_status(cli, ctx->addr, status, &sub); + } + return 0; } @@ -902,6 +966,11 @@ static int hb_pub_status(struct bt_mesh_model *model, bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } + + if (cli->cb && cli->cb->hb_pub_status) { + cli->cb->hb_pub_status(cli, ctx->addr, status, &pub); + } + return 0; } From f68cee94057a7a9e75ccda78aee952ded51f8156 Mon Sep 17 00:00:00 2001 From: Kevin Townsend Date: Fri, 14 Jul 2023 00:47:55 +0200 Subject: [PATCH 1334/2042] kconfig: Set `BOOTLOADER_SRAM_SIZE` default to 0 The current default value for `BOOTLOADER_SRAM_SIZE` is set to an arbitrary-seeming value of `16`, which feels like a random magic number. Given that adding an offset in SRAM for a bootloader should always be a conscious choice for a specific platform, this PR sets the default to `0`. An appropriate value can be set at the SoC or board level, overriding this default. Signed-off-by: Kevin Townsend --- Kconfig.zephyr | 2 +- doc/releases/release-notes-3.5.rst | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 0fa8ff2db82c..809565ee507c 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -827,7 +827,7 @@ config IS_BOOTLOADER config BOOTLOADER_SRAM_SIZE int "SRAM reserved for bootloader" - default 16 + default 0 depends on !XIP || IS_BOOTLOADER depends on ARM || XTENSA help diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 117171f99293..807511b95d9d 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -20,6 +20,10 @@ API Changes Changes in this release ======================= +* Set :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE` default value to ``0`` (was + ``16``). Bootloaders that use a part of the SRAM should set this value to an + appropriate size. :github:`60371` + Removed APIs in this release ============================ From 54c991b8f2ee4c482e8f650c97ec4f846838eadf Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Fri, 14 Jul 2023 09:17:19 +0200 Subject: [PATCH 1335/2042] net: openthread: regular openthread upmerge to `f7690fe` Adding new kconfig option: CONFIG_OPENTHREAD_TX_QUEUE_STATISTICS 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 267e1a443cda..67acbe00decd 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -458,6 +458,12 @@ 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() diff --git a/modules/openthread/Kconfig.features b/modules/openthread/Kconfig.features index a6834ce924fa..61b0efc921bb 100644 --- a/modules/openthread/Kconfig.features +++ b/modules/openthread/Kconfig.features @@ -292,6 +292,9 @@ config OPENTHREAD_TREL config OPENTHREAD_TX_BEACON_PAYLOAD bool "TX beacon payload support" +config OPENTHREAD_TX_QUEUE_STATISTICS + bool "TX queue statistics support" + config OPENTHREAD_UDP_FORWARD bool "UDP forward support" diff --git a/west.yml b/west.yml index 12e7f340242c..018f32ce4351 100644 --- a/west.yml +++ b/west.yml @@ -293,7 +293,7 @@ manifest: revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad path: modules/lib/open-amp - name: openthread - revision: 37fb77098982d17555dd7a3f58832714bb9df56e + revision: f7690fe7e9d638341921808cba6a3e695ec0131e path: modules/lib/openthread - name: picolibc path: modules/lib/picolibc From 5b2d716e76809776596f36f06253fff76dce7217 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 15 Jul 2023 14:46:59 +0200 Subject: [PATCH 1336/2042] arm64: Keep the frame pointer in leaf functions It helps with debugging and usually on ARM64 we don't care about a small increase in code size. Signed-off-by: Carlo Caione --- arch/arm64/core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/core/CMakeLists.txt b/arch/arm64/core/CMakeLists.txt index 25cd7f8df6b8..56d6413034e5 100644 --- a/arch/arm64/core/CMakeLists.txt +++ b/arch/arm64/core/CMakeLists.txt @@ -43,6 +43,7 @@ if ((CONFIG_MP_MAX_NUM_CPUS GREATER 1) OR (CONFIG_SMP)) endif () zephyr_cc_option_ifdef(CONFIG_USERSPACE -mno-outline-atomics) +zephyr_cc_option_ifdef(CONFIG_ARM64_ENABLE_FRAME_POINTER -mno-omit-leaf-frame-pointer) # GCC may generate ldp/stp instructions with the Advanced SIMD Qn registers for # consecutive 32-byte loads and stores. Saving and restoring the Advanced SIMD From 94e0e10193ca2ea12984b564068b2478cd113e95 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 16 Jul 2023 00:31:06 +0530 Subject: [PATCH 1337/2042] wifi: Fix doxygen comments Fix TWT comment to conform to doxygen style. Signed-off-by: Chaitanya Tata --- include/zephyr/net/wifi.h | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index 0278680cd1db..e7388fe6f6fe 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -343,9 +343,9 @@ static const char * const wifi_ps_mode2str[] = { /** Wi-Fi Target Wake Time (TWT) operations. */ enum wifi_twt_operation { - /* TWT setup operation */ + /** TWT setup operation */ WIFI_TWT_SETUP = 0, - /* TWT teardown operation */ + /** TWT teardown operation */ WIFI_TWT_TEARDOWN, }; @@ -356,11 +356,11 @@ static const char * const wifi_twt_operation2str[] = { /** Wi-Fi Target Wake Time (TWT) negotiation types. */ enum wifi_twt_negotiation_type { - /* TWT individual negotiation */ + /** TWT individual negotiation */ WIFI_TWT_INDIVIDUAL = 0, - /* TWT broadcast negotiation */ + /** TWT broadcast negotiation */ WIFI_TWT_BROADCAST, - /* TWT wake TBTT negotiation */ + /** TWT wake TBTT negotiation */ WIFI_TWT_WAKE_TBTT }; @@ -372,23 +372,21 @@ static const char * const wifi_twt_negotiation_type2str[] = { /** Wi-Fi Target Wake Time (TWT) setup commands. */ enum wifi_twt_setup_cmd { - /** TWT Requests */ - /* TWT setup request */ + /** TWT setup request */ WIFI_TWT_SETUP_CMD_REQUEST = 0, - /* TWT setup suggest (parameters can be changed by AP) */ + /** TWT setup suggest (parameters can be changed by AP) */ WIFI_TWT_SETUP_CMD_SUGGEST, - /* TWT setup demand (parameters can not be changed by AP) */ + /** TWT setup demand (parameters can not be changed by AP) */ WIFI_TWT_SETUP_CMD_DEMAND, - /** TWT Responses */ - /* TWT setup grouping (grouping of TWT flows) */ + /** TWT setup grouping (grouping of TWT flows) */ WIFI_TWT_SETUP_CMD_GROUPING, - /* TWT setup accept (parameters accepted by AP) */ + /** TWT setup accept (parameters accepted by AP) */ WIFI_TWT_SETUP_CMD_ACCEPT, - /* TWT setup alternate (alternate parameters suggested by AP) */ + /** TWT setup alternate (alternate parameters suggested by AP) */ WIFI_TWT_SETUP_CMD_ALTERNATE, - /* TWT setup dictate (parameters dictated by AP) */ + /** TWT setup dictate (parameters dictated by AP) */ WIFI_TWT_SETUP_CMD_DICTATE, - /* TWT setup reject (parameters rejected by AP) */ + /** TWT setup reject (parameters rejected by AP) */ WIFI_TWT_SETUP_CMD_REJECT, }; From 0f645b445c262b10a30b061f2b20ace2fa3779d3 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 16 Jul 2023 21:59:10 +1000 Subject: [PATCH 1338/2042] drivers: adc: add adc_is_ready_dt helper function Add adc_is_ready_dt() Signed-off-by: Nick Ward --- include/zephyr/drivers/adc.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/zephyr/drivers/adc.h b/include/zephyr/drivers/adc.h index 8dd3af3b3632..c230a14655b6 100644 --- a/include/zephyr/drivers/adc.h +++ b/include/zephyr/drivers/adc.h @@ -846,6 +846,18 @@ static inline int adc_sequence_init_dt(const struct adc_dt_spec *spec, return 0; } +/** + * @brief Validate that the ADC device is ready. + * + * @param spec ADC specification from devicetree + * + * @retval true if the ADC device is ready for use and false otherwise. + */ +static inline bool adc_is_ready_dt(const struct adc_dt_spec *spec) +{ + return device_is_ready(spec->dev); +} + /** * @} */ From 371f0f250386de882a99d06cb209ddaf8fdf4879 Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 16 Jul 2023 22:04:41 +1000 Subject: [PATCH 1339/2042] drivers: adc: use adc_is_ready_dt helper function Update `struct adc_dt_spec` use with adc_is_ready_dt() Signed-off-by: Nick Ward --- drivers/sensor/mcp970x/mcp970x.c | 2 +- drivers/sensor/ntc_thermistor/ntc_thermistor.c | 2 +- samples/drivers/adc/src/main.c | 2 +- tests/drivers/adc/adc_api/src/test_adc.c | 4 ++-- tests/drivers/adc/adc_rescale/src/main.c | 2 +- tests/drivers/regulator/voltage/src/main.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/sensor/mcp970x/mcp970x.c b/drivers/sensor/mcp970x/mcp970x.c index 8086cfc9b587..61d95fc55057 100644 --- a/drivers/sensor/mcp970x/mcp970x.c +++ b/drivers/sensor/mcp970x/mcp970x.c @@ -102,7 +102,7 @@ static int init(const struct device *dev) struct mcp970x_data *data = dev->data; int ret; - if (!device_is_ready(config->adc.dev)) { + if (!adc_is_ready_dt(&config->adc)) { LOG_ERR("ADC is not ready"); return -ENODEV; } diff --git a/drivers/sensor/ntc_thermistor/ntc_thermistor.c b/drivers/sensor/ntc_thermistor/ntc_thermistor.c index 67f2318d4a4f..4730c5fbabd4 100644 --- a/drivers/sensor/ntc_thermistor/ntc_thermistor.c +++ b/drivers/sensor/ntc_thermistor/ntc_thermistor.c @@ -83,7 +83,7 @@ static int ntc_thermistor_init(const struct device *dev) const struct ntc_thermistor_config *cfg = dev->config; int err; - if (!device_is_ready(cfg->adc_channel.dev)) { + if (!adc_is_ready_dt(&cfg->adc_channel)) { LOG_ERR("ADC controller device is not ready\n"); return -ENODEV; } diff --git a/samples/drivers/adc/src/main.c b/samples/drivers/adc/src/main.c index 79b1d8a66e5a..50f54455de63 100644 --- a/samples/drivers/adc/src/main.c +++ b/samples/drivers/adc/src/main.c @@ -42,7 +42,7 @@ int main(void) /* Configure channels individually prior to sampling. */ for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { - if (!device_is_ready(adc_channels[i].dev)) { + if (!adc_is_ready_dt(&adc_channels[i])) { printk("ADC controller device %s not ready\n", adc_channels[i].dev->name); return 0; } diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index ff86532ad830..e1da937926b3 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -35,7 +35,7 @@ static const int adc_channels_count = ARRAY_SIZE(adc_channels); const struct device *get_adc_device(void) { - if (!device_is_ready(adc_channels[0].dev)) { + if (!adc_is_ready_dt(&adc_channels[0])) { printk("ADC device is not ready\n"); return NULL; } @@ -47,7 +47,7 @@ static void init_adc(void) { int i, ret; - zassert_true(device_is_ready(adc_channels[0].dev), "ADC device is not ready"); + zassert_true(adc_is_ready_dt(&adc_channels[0]), "ADC device is not ready"); for (int i = 0; i < adc_channels_count; i++) { ret = adc_channel_setup_dt(&adc_channels[i]); diff --git a/tests/drivers/adc/adc_rescale/src/main.c b/tests/drivers/adc/adc_rescale/src/main.c index e8af4d4f58a1..4bc9c3cccd87 100644 --- a/tests/drivers/adc/adc_rescale/src/main.c +++ b/tests/drivers/adc/adc_rescale/src/main.c @@ -37,7 +37,7 @@ static int init_adc(const struct adc_dt_spec *spec, int input_mv) { int ret; - zassert_true(device_is_ready(spec->dev), "ADC device is not ready"); + zassert_true(adc_is_ready_dt(spec), "ADC device is not ready"); ret = adc_channel_setup_dt(spec); zassert_equal(ret, 0, "Setting up of the first channel failed with code %d", ret); diff --git a/tests/drivers/regulator/voltage/src/main.c b/tests/drivers/regulator/voltage/src/main.c index 7d815c57aef1..37db851d2378 100644 --- a/tests/drivers/regulator/voltage/src/main.c +++ b/tests/drivers/regulator/voltage/src/main.c @@ -114,7 +114,7 @@ void *setup(void) for (size_t i = 0U; i < ARRAY_SIZE(regs); i++) { zassert_true(device_is_ready(regs[i])); - zassert_true(device_is_ready(adc_chs[i].dev)); + zassert_true(adc_is_ready_dt(&adc_chs[i])); zassert_equal(adc_channel_setup_dt(&adc_chs[i]), 0); } From 2bf091f8af5b62416e134bf8eb81e48c9607571f Mon Sep 17 00:00:00 2001 From: Nick Ward Date: Sun, 16 Jul 2023 22:12:34 +1000 Subject: [PATCH 1340/2042] drivers: usb-c: fix - check if adc_channel is ready before use This will protect a user of this driver against driver initialisation order misconfiguration. Signed-off-by: Nick Ward --- drivers/usb_c/vbus/usbc_vbus_adc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb_c/vbus/usbc_vbus_adc.c b/drivers/usb_c/vbus/usbc_vbus_adc.c index 557dafdff629..6ed645795d29 100644 --- a/drivers/usb_c/vbus/usbc_vbus_adc.c +++ b/drivers/usb_c/vbus/usbc_vbus_adc.c @@ -139,6 +139,11 @@ static int adc_vbus_init(const struct device *dev) const struct gpio_dt_spec *gcd = &config->discharge_gpios; int ret; + if (!adc_is_ready_dt(&config->adc_channel)) { + LOG_ERR("ADC controller device is not ready"); + return -ENODEV; + } + /* Configure VBUS Measurement enable pin if defined */ if (gcp->port) { ret = device_is_ready(gcp->port); From 0001e23e52de46ffde545375dbca1d89605bf512 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 17 Jul 2023 10:25:34 +0100 Subject: [PATCH 1341/2042] tests: mgmt: mcumgr: all_options: Fix missing Kconfig Fixes a missing Kconfig enabling MCUboot, which causes the test to now fail to build. Signed-off-by: Jamie McCrae --- tests/subsys/mgmt/mcumgr/all_options/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/mgmt/mcumgr/all_options/prj.conf b/tests/subsys/mgmt/mcumgr/all_options/prj.conf index d1ee6537d419..e44d2420909f 100644 --- a/tests/subsys/mgmt/mcumgr/all_options/prj.conf +++ b/tests/subsys/mgmt/mcumgr/all_options/prj.conf @@ -59,3 +59,4 @@ CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=y CONFIG_MCUMGR_GRP_FS_FILE_STATUS=y CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y CONFIG_MCUMGR_GRP_OS_TASKSTAT=y +CONFIG_BOOTLOADER_MCUBOOT=y From 9ca543d7ae2a8bed8b4ecfd3379b3e222b81b8ae Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Sun, 16 Jul 2023 02:29:01 +0000 Subject: [PATCH 1342/2042] drivers: reset: kconfig: Change default init priority to 35 from 40 Setting higher priority to reset controller to initialize it before other dependent drivers running at CONFIG_KERNEL_INIT_PRIORITY_DEFAULT priority which is 40. Signed-off-by: Girisha Dengi --- drivers/reset/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 719b57f0748b..44117852ade4 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -18,7 +18,7 @@ if RESET config RESET_INIT_PRIORITY int "Reset Controller driver init priority" - default 40 + default 35 help This option controls the priority of the reset controller device initialization. Higher priority ensures that the device is From 5f6ceefb8ed4ec26cdb4f51114a5985f785ac7a1 Mon Sep 17 00:00:00 2001 From: Wei-Tai Lee Date: Wed, 24 May 2023 17:32:49 +0800 Subject: [PATCH 1343/2042] drivers: hwinfo: andes: Improve hwinfo_andes driver Check the driver's readiness at boot and in each function that depends on the syscon driver. Signed-off-by: Wei-Tai Lee --- drivers/hwinfo/hwinfo_andes.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/hwinfo/hwinfo_andes.c b/drivers/hwinfo/hwinfo_andes.c index 08a7e52a76ea..173922d1bfca 100644 --- a/drivers/hwinfo/hwinfo_andes.c +++ b/drivers/hwinfo/hwinfo_andes.c @@ -8,6 +8,7 @@ #include #include #include +#include /* * SMU(System Management Unit) Registers for hwinfo driver @@ -26,13 +27,18 @@ #define ANDES_RESET_STATUS_MASK BIT_MASK(5) +static const struct device *const syscon_dev = + DEVICE_DT_GET(DT_NODELABEL(syscon)); + ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) { int ret = 0; uint8_t id[3]; uint32_t ver; - const struct device *const syscon_dev = - DEVICE_DT_GET(DT_NODELABEL(syscon)); + + if (!device_is_ready(syscon_dev)) { + return -ENODEV; + } ret = syscon_read_reg(syscon_dev, SMU_SYSTEMVER, &ver); if (ret < 0) { @@ -43,9 +49,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) length = sizeof(id); } - id[0] = (uint8_t)(ver >> 16); - id[1] = (uint8_t)(ver >> 8); - id[2] = (uint8_t)(ver >> 0); + sys_put_le24(ver, id); memcpy(buffer, id, length); @@ -56,8 +60,10 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) { int ret = 0; uint32_t reason, flags = 0; - const struct device *const syscon_dev = - DEVICE_DT_GET(DT_NODELABEL(syscon)); + + if (!device_is_ready(syscon_dev)) { + return -ENODEV; + } ret = syscon_read_reg(syscon_dev, SMU_WRSR, &reason); if (ret < 0) { @@ -89,8 +95,10 @@ int z_impl_hwinfo_clear_reset_cause(void) { int ret = 0; uint32_t reason; - const struct device *const syscon_dev = - DEVICE_DT_GET(DT_NODELABEL(syscon)); + + if (!device_is_ready(syscon_dev)) { + return -ENODEV; + } ret = syscon_write_reg(syscon_dev, SMU_WRSR, ANDES_RESET_STATUS_MASK); if (ret < 0) { From 8fdb0fb1cae259883f4567a8ff20c1a13db80abf Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 10 Jul 2023 19:30:28 +0200 Subject: [PATCH 1344/2042] footprint: Add BT TMAP samples Add the BT Telephony and Media Audio Profile samples. These reflect devices that control telephone and media audio of LE Audio. The central is typically a more resourceful device, and the peripheral a resource-constrained device. Signed-off-by: Emil Gydesen --- scripts/footprint/plan.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/footprint/plan.txt b/scripts/footprint/plan.txt index 3c46c629eddb..36ad9d122007 100644 --- a/scripts/footprint/plan.txt +++ b/scripts/footprint/plan.txt @@ -21,6 +21,8 @@ bt_mesh_demo,default,bbc_microbit,samples/bluetooth/mesh_demo, bt_hap_ha,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/hap_ha, bt_unicast_audio_client,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/unicast_audio_client, bt_unicast_audio_server,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/unicast_audio_server, +bt_tmap_central,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_central, +bt_tmap_peripheral,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_peripheral, bt_hci_rpmsg,default,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg, bt_hci_rpmsg,iso-broadcast,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf bt_hci_rpmsg,iso-receive,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf From 7a6288a87150e27d6a9d7882725406ee71d2e53c Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sun, 16 Jul 2023 01:13:49 +0530 Subject: [PATCH 1345/2042] net: l2: wifi: Fix printing of TWT parameters Use the macro to print to handle for cases where shell context is NULL, this is possible because in this net management event handler shell context is not passed. Signed-off-by: Chaitanya Tata --- subsys/net/l2/wifi/wifi_shell.c | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 299619b1f888..a520dc798bfd 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -241,25 +241,25 @@ static void print_twt_params(uint8_t dialog_token, uint8_t flow_id, bool trigger, uint32_t twt_wake_interval, uint64_t twt_interval) { - shell_fprintf(context.sh, SHELL_NORMAL, "TWT Dialog token: %d\n", - dialog_token); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT flow ID: %d\n", - flow_id); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT negotiation type: %s\n", - wifi_twt_negotiation_type2str[negotiation_type]); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT responder: %s\n", - responder ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT implicit: %s\n", - implicit ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT announce: %s\n", - announce ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT trigger: %s\n", - trigger ? "true" : "false"); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT wake interval: %d us\n", - twt_wake_interval); - shell_fprintf(context.sh, SHELL_NORMAL, "TWT interval: %lld us\n", - twt_interval); - shell_fprintf(context.sh, SHELL_NORMAL, "========================\n"); + print(context.sh, SHELL_NORMAL, "TWT Dialog token: %d\n", + dialog_token); + print(context.sh, SHELL_NORMAL, "TWT flow ID: %d\n", + flow_id); + print(context.sh, SHELL_NORMAL, "TWT negotiation type: %s\n", + wifi_twt_negotiation_type2str[negotiation_type]); + print(context.sh, SHELL_NORMAL, "TWT responder: %s\n", + responder ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT implicit: %s\n", + implicit ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT announce: %s\n", + announce ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT trigger: %s\n", + trigger ? "true" : "false"); + print(context.sh, SHELL_NORMAL, "TWT wake interval: %d us\n", + twt_wake_interval); + print(context.sh, SHELL_NORMAL, "TWT interval: %lld us\n", + twt_interval); + print(context.sh, SHELL_NORMAL, "========================\n"); } static void handle_wifi_twt_event(struct net_mgmt_event_callback *cb) From 96893e84cea3959bb134c4069d67460ed11a2756 Mon Sep 17 00:00:00 2001 From: Przemyslaw Bida Date: Mon, 17 Jul 2023 08:47:42 +0200 Subject: [PATCH 1346/2042] net: openthread: Refactor openthread entropy `otPlatEntropyGet`. This commit replaces direct entropy device driver class with `sys_csrand_get`, which is recommended way of getting crypto secure random buffer. Signed-off-by: Przemyslaw Bida --- modules/openthread/platform/entropy.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/modules/openthread/platform/entropy.c b/modules/openthread/platform/entropy.c index e8790908494e..fd5d797a4698 100644 --- a/modules/openthread/platform/entropy.c +++ b/modules/openthread/platform/entropy.c @@ -5,22 +5,17 @@ */ #include -#include -#include +#include #include #include -#include "platform-zephyr.h" - LOG_MODULE_REGISTER(net_otPlat_entropy, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #if !defined(CONFIG_ENTROPY_HAS_DRIVER) #error OpenThread requires an entropy source for a TRNG #endif -static const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); - otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) { int err; @@ -29,12 +24,7 @@ otError otPlatEntropyGet(uint8_t *aOutput, uint16_t aOutputLength) return OT_ERROR_INVALID_ARGS; } - if (!device_is_ready(dev)) { - LOG_ERR("Entropy device not ready"); - return OT_ERROR_FAILED; - } - - err = entropy_get_entropy(dev, aOutput, aOutputLength); + err = sys_csrand_get(aOutput, aOutputLength); if (err != 0) { LOG_ERR("Failed to obtain entropy, err %d", err); return OT_ERROR_FAILED; From 9603c0ce7553de9ef21daaf40a6c1b20ca71f757 Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Fri, 14 Jul 2023 21:26:49 -0700 Subject: [PATCH 1347/2042] samples: sensor: lsm6dso: fix double promotion warning fix double promotion warning when compiling with -Wdouble-promotion Signed-off-by: Ryan McClelland --- samples/sensor/lsm6dso/src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/sensor/lsm6dso/src/main.c b/samples/sensor/lsm6dso/src/main.c index 8a075fd28eee..41eb88115a70 100644 --- a/samples/sensor/lsm6dso/src/main.c +++ b/samples/sensor/lsm6dso/src/main.c @@ -28,7 +28,7 @@ static void fetch_and_display(const struct device *dev) sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &z); printf("accel x:%f ms/2 y:%f ms/2 z:%f ms/2\n", - out_ev(&x), out_ev(&y), out_ev(&z)); + (double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z)); /* lsm6dso gyro */ sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); @@ -37,7 +37,7 @@ static void fetch_and_display(const struct device *dev) sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &z); printf("gyro x:%f rad/s y:%f rad/s z:%f rad/s\n", - out_ev(&x), out_ev(&y), out_ev(&z)); + (double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z)); printf("trig_cnt:%d\n\n", trig_cnt); } From c6e3bac4f20a659143a56bda0166a111629d79b1 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 11 Jan 2023 17:40:46 -0600 Subject: [PATCH 1348/2042] soc: arm: lpc55xxx: Updated clock init Updated the clock init to reflect the sdk also updated the clock frequencies to reflect the respective soc clock values, this file originally contained unexpected clock values, updated comments to reflect changes and got rid of doxygen style comments Signed-off-by: Emilio Benavente --- soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc | 10 ++- soc/arm/nxp_lpc/lpc55xxx/soc.c | 129 ++++++++++++++++++++------- 2 files changed, 104 insertions(+), 35 deletions(-) diff --git a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc index cc65f3bf1400..a7bae5aafb0b 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc @@ -1,6 +1,6 @@ # LPC LPC55XXX Series -# Copyright (c) 2019, NXP +# Copyright 2019, 2023 NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -120,6 +120,14 @@ config SOC_PART_NUMBER_LPC55XXX config INIT_PLL0 bool "Initialize PLL0" +config INIT_PLL1 + bool "Initialize PLL1" + default "y" + depends on !SOC_LPC55S06 + 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. + config SECOND_CORE_MCUX bool "LPC55xxx's second core" depends on HAS_MCUX diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 45c51d18424a..c297553669c5 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -35,6 +35,13 @@ #include #endif +/* System clock frequency */ +extern uint32_t SystemCoreClock; + +/*Should be in the range of 12MHz to 32MHz */ +static uint32_t ExternalClockFrequency; + + #define CTIMER_CLOCK_SOURCE(node_id) \ TO_CTIMER_CLOCK_SOURCE(DT_CLOCKS_CELL(node_id, name), DT_PROP(node_id, clk_source)) #define TO_CTIMER_CLOCK_SOURCE(inst, val) TO_CLOCK_ATTACH_ID(inst, val) @@ -44,13 +51,25 @@ #ifdef CONFIG_INIT_PLL0 const pll_setup_t pll0Setup = { .pllctrl = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_SELI(2U) | - SYSCON_PLL0CTRL_SELP(31U), + SYSCON_PLL0CTRL_SELP(31U), .pllndec = SYSCON_PLL0NDEC_NDIV(125U), .pllpdec = SYSCON_PLL0PDEC_PDIV(8U), .pllsscg = {0x0U, (SYSCON_PLL0SSCG1_MDIV_EXT(3072U) | SYSCON_PLL0SSCG1_SEL_EXT_MASK)}, .pllRate = 24576000U, - .flags = PLL_SETUPFLAG_WAITLOCK} -; + .flags = PLL_SETUPFLAG_WAITLOCK +}; +#endif + +#ifdef CONFIG_INIT_PLL1 +const pll_setup_t pll1Setup = { + .pllctrl = SYSCON_PLL1CTRL_CLKEN_MASK | SYSCON_PLL1CTRL_SELI(53U) | + SYSCON_PLL1CTRL_SELP(31U), + .pllndec = SYSCON_PLL1NDEC_NDIV(8U), + .pllpdec = SYSCON_PLL1PDEC_PDIV(1U), + .pllmdec = SYSCON_PLL1MDEC_MDIV(150U), + .pllRate = 150000000U, + .flags = PLL_SETUPFLAG_WAITLOCK +}; #endif /** @@ -61,6 +80,7 @@ const pll_setup_t pll0Setup = { static ALWAYS_INLINE void clock_init(void) { + ExternalClockFrequency = 0; #if defined(CONFIG_SOC_LPC55S36) /* Power Management Controller initialization */ @@ -70,50 +90,91 @@ static ALWAYS_INLINE void clock_init(void) #if defined(CONFIG_SOC_LPC55S06) || defined(CONFIG_SOC_LPC55S16) || \ defined(CONFIG_SOC_LPC55S28) || defined(CONFIG_SOC_LPC55S36) || \ defined(CONFIG_SOC_LPC55S69_CPU0) - /*!< Set up the clock sources */ - /*!< Configure FRO192M */ - /*!< Ensure FRO is on */ + /* Set up the clock sources */ + /* Configure FRO192M */ + /* Ensure FRO is on */ POWER_DisablePD(kPDRUNCFG_PD_FRO192M); - /*!< Set up FRO to the 12 MHz, just for sure */ + /* Set up FRO to the 12 MHz, to ensure we can change the clock freq */ CLOCK_SetupFROClocking(12000000U); - /*!< Switch to FRO 12MHz first to ensure we can change the clock */ + /* Switch to FRO 12MHz first to ensure we can change the clock */ CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); - /* Enable FRO HF(96MHz) output */ - CLOCK_SetupFROClocking(96000000U); - -#ifdef CONFIG_INIT_PLL0 - /*!< Ensure XTAL16M is on */ - PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_XTAL32M_MASK; - PMC->PDRUNCFGCLR0 |= PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK; - - /*!< Ensure CLK_IN is on */ + /* Ensure CLK_IN is on */ SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK; - /*!< Switch PLL0 clock source selector to XTAL16M */ + /* Setting the Core Clock to either 96MHz or in the case of using PLL, 150MHz */ +#if defined(CONFIG_SOC_LPC55S06) || !defined(CONFIG_INIT_PLL1) + SystemCoreClock = 96000000U; +#else + SystemCoreClock = 150000000U; +#endif + + + /* These functions must be called before increasing to a higher frequency + * Additionally, CONFIG_TRUSTED_EXECUTION_NONSECURE is being used + * since the non-secure SOCs should not have access to the flash + * as this will cause a secure fault to occur + */ +#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) + /* Set Voltage for one of the fastest clock outputs: System clock output */ + POWER_SetVoltageForFreq(SystemCoreClock); + /*!< Set FLASH wait states for core */ + CLOCK_SetFLASHAccessCyclesForFreq(SystemCoreClock); +#endif /* !CONFIG_TRUSTED_EXECUTION_NONSECURE */ + + +#if defined(CONFIG_INIT_PLL0) || defined(CONFIG_INIT_PLL1) + /* Configure XTAL32M */ + ExternalClockFrequency = 16000000U; + CLOCK_SetupExtClocking(ExternalClockFrequency); +#endif + +#if defined(CONFIG_SOC_LPC55S06) || !defined(CONFIG_INIT_PLL1) + /* Enable FRO HF(SystemCoreClock) output (Default expected value 96MHz) */ + CLOCK_SetupFROClocking(SystemCoreClock); + + /* Switch MAIN_CLK to FRO_HF */ + CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); + +#else + /* Switch PLL1 clock source selector to XTAL32M */ + CLOCK_AttachClk(kEXT_CLK_to_PLL1); + + /* Ensure PLL1 is on */ + POWER_DisablePD(kPDRUNCFG_PD_PLL1); + + /* Configure PLL to the desired values */ + CLOCK_SetPLL1Freq(&pll1Setup); + + /* Switch MAIN_CLK to FRO_HF */ + CLOCK_AttachClk(kPLL1_to_MAIN_CLK); + +#endif /* CONFIG_SOC_LPC55S06 || !CONFIG_INIT_PLL1 */ + + +#ifdef CONFIG_INIT_PLL0 + /* Switch PLL0 clock source selector to XTAL32M */ CLOCK_AttachClk(kEXT_CLK_to_PLL0); - /*!< Configure PLL to the desired values */ + /* Configure PLL to the desired values */ CLOCK_SetPLL0Freq(&pll0Setup); +#if defined(CONFIG_SOC_LPC55S36) + CLOCK_SetClkDiv(kCLOCK_DivPllClk, 0U, true); + CLOCK_SetClkDiv(kCLOCK_DivPllClk, 1U, false); +#else CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 0U, true); CLOCK_SetClkDiv(kCLOCK_DivPll0Clk, 1U, false); -#endif +#endif /* CONFIG_SOC_LPC55S36 */ +#endif /* CONFIG_INIT_PLL0 */ -#if !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) - /*!< Set FLASH wait states for core */ - CLOCK_SetFLASHAccessCyclesForFreq(96000000U); -#endif - /*!< Set up dividers */ + /* Set up dividers */ CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false); - /*!< Set up clock selectors - Attach clocks to the peripheries */ - CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); - /* Enables the clock for the I/O controller.: Enable Clock. */ - CLOCK_EnableClock(kCLOCK_Iocon); + CLOCK_EnableClock(kCLOCK_Iocon); #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm2), nxp_lpc_usart, okay) #if defined(CONFIG_SOC_LPC55S36) @@ -250,11 +311,11 @@ DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) #if defined(CONFIG_SOC_LPC55S36) && defined(CONFIG_PWM) /* Set the Submodule Clocks for FlexPWM */ SYSCON->PWM0SUBCTL |= - (SYSCON_PWM0SUBCTL_CLK0_EN_MASK | SYSCON_PWM0SUBCTL_CLK1_EN_MASK | - SYSCON_PWM0SUBCTL_CLK2_EN_MASK); + (SYSCON_PWM0SUBCTL_CLK0_EN_MASK | SYSCON_PWM0SUBCTL_CLK1_EN_MASK | + SYSCON_PWM0SUBCTL_CLK2_EN_MASK); SYSCON->PWM1SUBCTL |= - (SYSCON_PWM1SUBCTL_CLK0_EN_MASK | SYSCON_PWM1SUBCTL_CLK1_EN_MASK | - SYSCON_PWM1SUBCTL_CLK2_EN_MASK); + (SYSCON_PWM1SUBCTL_CLK0_EN_MASK | SYSCON_PWM1SUBCTL_CLK1_EN_MASK | + SYSCON_PWM1SUBCTL_CLK2_EN_MASK); #endif #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(adc0), nxp_lpc_lpadc, okay) @@ -322,7 +383,7 @@ void z_arm_platform_init(void) * SystemInit unconditionally enables the trace clock. * Disable the trace clock unless SWO is used */ - SYSCON->TRACECLKDIV = 0x4000000; + SYSCON->TRACECLKDIV = 0x4000000; #endif } From 191ad081541883552856d434a73807f1a908644b Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 12 Jul 2023 13:06:14 -0500 Subject: [PATCH 1349/2042] drivers: dma_mcux_lpc: Add Kconfig to reduce data Add a Kconfig to have the ability to fine tune the amount of RAM that the driver uses based on the number of channels expected to be used. Most of the code is already there but just need this Kconfig to get the benefit of it by reducing the size of the statically created arrays. Also change the number of channels field in the configuration to a byte instead of a 32 bit integer because that should be sufficient to describe the number of DMA channels. Rename LPC DMA Driver Kconfigs with namespace to MCUX_LPC Signed-off-by: Declan Snyder --- drivers/dma/Kconfig.mcux_lpc | 15 ++++++++++++++- drivers/dma/dma_mcux_lpc.c | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/dma/Kconfig.mcux_lpc b/drivers/dma/Kconfig.mcux_lpc index e039dde22bfb..1f18bfb185c0 100644 --- a/drivers/dma/Kconfig.mcux_lpc +++ b/drivers/dma/Kconfig.mcux_lpc @@ -10,7 +10,7 @@ config DMA_MCUX_LPC if DMA_MCUX_LPC -config DMA_NUMBER_OF_DESCRIPTORS +config DMA_MCUX_LPC_NUMBER_OF_DESCRIPTORS int "Number of DMA descriptors to use" default 16 help @@ -18,4 +18,17 @@ config DMA_NUMBER_OF_DESCRIPTORS Increase or decrease this value depending on the max number of data transferred by the application. +config DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED + int "Number of DMA channels to allocate memory for in driver" + default 0 + help + The MCUX LPC DMA driver can save memory by not allocating static data + depending on this value. So, the application can save some data memory + space by setting this value to suit its needs. The meaning of the value + is "total number of unique DMA channels ever expected to be used, maximum + out of all DMA controllers". A value of 0 (default) means to allocate + as many channel data structures as the maximum number of DMA channels + in any DMA controller hardware. About 1 KB per 3-4 channels unused can + be saved by fine tuning this Kconfig. + endif # DMA_MCUX_LPC diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index c5de9bdc8991..dde037243ab6 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #define DT_DRV_COMPAT nxp_lpc_dma @@ -23,15 +25,15 @@ LOG_MODULE_REGISTER(dma_mcux_lpc, CONFIG_DMA_LOG_LEVEL); struct dma_mcux_lpc_config { DMA_Type *base; - uint32_t num_of_channels; uint32_t otrig_base_address; uint32_t itrig_base_address; + uint8_t num_of_channels; uint8_t num_of_otrigs; void (*irq_config_func)(const struct device *dev); }; struct channel_data { - SDK_ALIGN(dma_descriptor_t dma_descriptor_table[CONFIG_DMA_NUMBER_OF_DESCRIPTORS], + SDK_ALIGN(dma_descriptor_t dma_descriptor_table[CONFIG_DMA_MCUX_LPC_NUMBER_OF_DESCRIPTORS], FSL_FEATURE_DMA_LINK_DESCRIPTOR_ALIGN_SIZE); dma_handle_t dma_handle; const struct device *dev; @@ -131,7 +133,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, /* Increase the number of descriptors queued */ data->num_of_descriptors++; - if (data->num_of_descriptors >= CONFIG_DMA_NUMBER_OF_DESCRIPTORS) { + if (data->num_of_descriptors >= CONFIG_DMA_MCUX_LPC_NUMBER_OF_DESCRIPTORS) { return -ENOMEM; } /* Do we need to queue additional DMA descriptors for this block */ @@ -715,6 +717,12 @@ static const struct dma_driver_api dma_mcux_lpc_api = { DMA_MCUX_LPC_DECLARE_CFG(n, \ DMA_MCUX_LPC_IRQ_CFG_FUNC_INIT(n)) +#define DMA_MCUX_LPC_NUM_USED_CHANNELS(n) \ + COND_CODE_0(CONFIG_DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED, \ + (DT_INST_PROP(n, dma_channels)), \ + (MIN(CONFIG_DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED, \ + DT_INST_PROP(n, dma_channels)))) + #define DMA_MCUX_LPC_DECLARE_CFG(n, IRQ_FUNC_INIT) \ static const struct dma_mcux_lpc_config dma_##n##_config = { \ .base = (DMA_Type *)DT_INST_REG_ADDR(n), \ @@ -730,7 +738,7 @@ static const struct dma_mcux_lpc_config dma_##n##_config = { \ static const struct dma_mcux_lpc_config dma_##n##_config; \ \ static struct channel_data dma_##n##_channel_data_arr \ - [DT_INST_PROP(n, dma_channels)] = {0}; \ + [DMA_MCUX_LPC_NUM_USED_CHANNELS(n)] = {0}; \ \ static struct dma_otrig dma_##n##_otrig_arr \ [DT_INST_PROP_OR(n, nxp_dma_num_of_otrigs, 0)]; \ From 9e855347be4d4507e51b65374284088851674fe0 Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Wed, 12 Jul 2023 13:09:04 -0500 Subject: [PATCH 1350/2042] tests: dma loop_transfer: Ex of LPC DMA Kconfig Show an example of the LPC DMA Kconfig to reduce RAM based on the number of DMA channels expected to be used. In this test, only one DMA channel is needed, so we can show an example of how to reduce RAM usage of the driver by configuring this value appropriately. Signed-off-by: Declan Snyder --- tests/drivers/dma/loop_transfer/boards/mimxrt595_evk_cm33.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/drivers/dma/loop_transfer/boards/mimxrt595_evk_cm33.conf diff --git a/tests/drivers/dma/loop_transfer/boards/mimxrt595_evk_cm33.conf b/tests/drivers/dma/loop_transfer/boards/mimxrt595_evk_cm33.conf new file mode 100644 index 000000000000..65066145dbba --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/mimxrt595_evk_cm33.conf @@ -0,0 +1 @@ +CONFIG_DMA_MCUX_LPC_NUMBER_OF_CHANNELS_ALLOCATED=1 From 0683060dc026a52a13ae46fb1ad269daf24e8eea Mon Sep 17 00:00:00 2001 From: Randy Palamar Date: Fri, 14 Jul 2023 14:40:27 -0600 Subject: [PATCH 1351/2042] boards: arm: seeeduino_xiao: support onboard DAC this allows you to use the onboard DAC on the Seeed Xiao Signed-off-by: Randy Palamar --- boards/arm/seeeduino_xiao/doc/index.rst | 8 ++++++++ boards/arm/seeeduino_xiao/seeed_xiao_connector.dtsi | 1 + boards/arm/seeeduino_xiao/seeeduino_xiao-pinctrl.dtsi | 6 ++++++ boards/arm/seeeduino_xiao/seeeduino_xiao.dts | 7 +++++++ boards/arm/seeeduino_xiao/seeeduino_xiao.yaml | 1 + tests/drivers/dac/dac_api/src/test_dac.c | 1 + 6 files changed, 24 insertions(+) diff --git a/boards/arm/seeeduino_xiao/doc/index.rst b/boards/arm/seeeduino_xiao/doc/index.rst index d94473e3f65e..fb4ff4420a08 100644 --- a/boards/arm/seeeduino_xiao/doc/index.rst +++ b/boards/arm/seeeduino_xiao/doc/index.rst @@ -33,6 +33,8 @@ features: +===========+============+==========================================+ | DMA | on-chip | Direct memory access | +-----------+------------+------------------------------------------+ +| DAC | on-chip | Digital to analogue converter | ++-----------+------------+------------------------------------------+ | Flash | on-chip | Can be used with LittleFS to store files | +-----------+------------+------------------------------------------+ | GPIO | on-chip | I/O ports | @@ -100,6 +102,12 @@ with a host PC. See the :ref:`usb-samples` sample applications for more, such as the :ref:`usb_cdc-acm` sample which sets up a virtual serial port that echos characters back to the host PC. +DAC +=== + +The SAMD21 MCU has a single channel DAC with 10 bits of resolution. On +the XIAO, the DAC is available on pin 0. + Programming and Debugging ************************* diff --git a/boards/arm/seeeduino_xiao/seeed_xiao_connector.dtsi b/boards/arm/seeeduino_xiao/seeed_xiao_connector.dtsi index e4fb55c52178..e4709327113f 100644 --- a/boards/arm/seeeduino_xiao/seeed_xiao_connector.dtsi +++ b/boards/arm/seeeduino_xiao/seeed_xiao_connector.dtsi @@ -29,3 +29,4 @@ xiao_spi: &sercom0 {}; xiao_i2c: &sercom2 {}; xiao_serial: &sercom4 {}; +xiao_dac: &dac0 {}; diff --git a/boards/arm/seeeduino_xiao/seeeduino_xiao-pinctrl.dtsi b/boards/arm/seeeduino_xiao/seeeduino_xiao-pinctrl.dtsi index 0c4ff14789a8..28e2e7c6004d 100644 --- a/boards/arm/seeeduino_xiao/seeeduino_xiao-pinctrl.dtsi +++ b/boards/arm/seeeduino_xiao/seeeduino_xiao-pinctrl.dtsi @@ -6,6 +6,12 @@ #include &pinctrl { + dac_default: dac_default { + group1 { + pinmux = ; + }; + }; + sercom2_i2c_default: sercom2_i2c_default { group1 { pinmux = , diff --git a/boards/arm/seeeduino_xiao/seeeduino_xiao.dts b/boards/arm/seeeduino_xiao/seeeduino_xiao.dts index 79b468ae6328..a0bc69a48140 100644 --- a/boards/arm/seeeduino_xiao/seeeduino_xiao.dts +++ b/boards/arm/seeeduino_xiao/seeeduino_xiao.dts @@ -90,6 +90,13 @@ zephyr_udc0: &usb0 { pinctrl-names = "default"; }; +&dac0 { + status = "okay"; + + pinctrl-0 = <&dac_default>; + pinctrl-names = "default"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/boards/arm/seeeduino_xiao/seeeduino_xiao.yaml b/boards/arm/seeeduino_xiao/seeeduino_xiao.yaml index 4166bd150c04..657136f693a3 100644 --- a/boards/arm/seeeduino_xiao/seeeduino_xiao.yaml +++ b/boards/arm/seeeduino_xiao/seeeduino_xiao.yaml @@ -10,6 +10,7 @@ toolchain: - xtools supported: - dma + - dac - gpio - hwinfo - spi diff --git a/tests/drivers/dac/dac_api/src/test_dac.c b/tests/drivers/dac/dac_api/src/test_dac.c index ae03ee582645..6e4883d9a9c5 100644 --- a/tests/drivers/dac/dac_api/src/test_dac.c +++ b/tests/drivers/dac/dac_api/src/test_dac.c @@ -43,6 +43,7 @@ #elif defined(CONFIG_BOARD_TWR_KE18F) || \ defined(CONFIG_BOARD_FRDM_K64F) || \ defined(CONFIG_BOARD_FRDM_K22F) || \ + defined(CONFIG_BOARD_SEEEDUINO_XIAO) || \ defined(CONFIG_BOARD_ARDUINO_MKRZERO) || \ defined(CONFIG_BOARD_ARDUINO_ZERO) From c544926b37d4a5e8ed2881002b7b2a4d83a32ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 17:13:24 +0200 Subject: [PATCH 1352/2042] gpio: doc: fix Doxygen doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A couple of trivial Doxygen fixes. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/gpio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/drivers/gpio.h b/include/zephyr/drivers/gpio.h index 9ea274128f14..3d77108b8537 100644 --- a/include/zephyr/drivers/gpio.h +++ b/include/zephyr/drivers/gpio.h @@ -686,7 +686,7 @@ struct gpio_dt_spec { * in the device structure. */ struct gpio_driver_config { - /* Mask identifying pins supported by the controller. + /** Mask identifying pins supported by the controller. * * Initialization of this mask is the responsibility of device * instance generation in the driver. @@ -699,7 +699,7 @@ struct gpio_driver_config { * element in the driver's struct driver_data declaration. */ struct gpio_driver_data { - /* Mask identifying pins that are configured as active low. + /** Mask identifying pins that are configured as active low. * * Management of this mask is the responsibility of the * wrapper functions in this header. @@ -1024,7 +1024,7 @@ static inline int gpio_pin_configure_dt(const struct gpio_dt_spec *spec, spec->dt_flags | extra_flags); } -/* +/** * @brief Get direction of select pins in a port. * * Retrieve direction of each pin specified in @p map. From f41dffd735aee4b10e5fd67e87a0f7eb7ee3a1d4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 17 Jul 2023 11:53:15 +0300 Subject: [PATCH 1353/2042] tests: smbus: Use depends_on instead of platform_allow Using depends_on instead of platform_allow helps to add new boards and makes test description more clean. Signed-off-by: Andrei Emeltchenko --- tests/drivers/smbus/smbus_api/testcase.yaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/drivers/smbus/smbus_api/testcase.yaml b/tests/drivers/smbus/smbus_api/testcase.yaml index aad8a48f3ddb..9287dfc8a181 100644 --- a/tests/drivers/smbus/smbus_api/testcase.yaml +++ b/tests/drivers/smbus/smbus_api/testcase.yaml @@ -1,7 +1,6 @@ common: - platform_allow: - - ehl_crb - - rpl_crb + depends_on: + - smbus tags: smbus tests: drivers.smbus.api: @@ -11,22 +10,17 @@ tests: extra_configs: - CONFIG_SMBUS_INTEL_PCH_ACCESS_MMIO=y drivers.smbus.api_user: - platform_allow: qemu_x86_64 extra_configs: - CONFIG_USERSPACE=y drivers.smbus.api_stats: - platform_allow: qemu_x86_64 extra_configs: - CONFIG_STATS=y drivers.smbus.api.no_smbalert: - platform_allow: qemu_x86_64 extra_configs: - CONFIG_SMBUS_INTEL_PCH_SMBALERT=n drivers.smbus.api.no_host_notify: - platform_allow: qemu_x86_64 extra_configs: - CONFIG_SMBUS_INTEL_PCH_HOST_NOTIFY=n drivers.smbus.api.debug: - platform_allow: qemu_x86_64 extra_configs: - CONFIG_SMBUS_LOG_LEVEL_DBG=y From 20a7552868195346a2ead2b134959f1debe5e79d Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 17 Jul 2023 11:55:05 +0300 Subject: [PATCH 1354/2042] boards: qemu_x86_64: Add smbus to supported list Add smbus to supported list to run tests on qemu_x86_64 Q35 which supports ICH SMBus controller. Signed-off-by: Andrei Emeltchenko --- boards/x86/qemu_x86/qemu_x86_64.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/x86/qemu_x86/qemu_x86_64.yaml b/boards/x86/qemu_x86/qemu_x86_64.yaml index c76a2b060b4e..c62479ad3306 100644 --- a/boards/x86/qemu_x86/qemu_x86_64.yaml +++ b/boards/x86/qemu_x86/qemu_x86_64.yaml @@ -9,6 +9,7 @@ simulation: qemu supported: - can - smp + - smbus testing: default: true ignore_tags: From 39928ae4a719af1d34e42545153cc1a738521126 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 17 Jul 2023 11:57:30 +0300 Subject: [PATCH 1355/2042] tests: smbus: Rename smbus api test Rename test to drivers.smbus.api.access.io to indicate access type. Signed-off-by: Andrei Emeltchenko --- tests/drivers/smbus/smbus_api/testcase.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/drivers/smbus/smbus_api/testcase.yaml b/tests/drivers/smbus/smbus_api/testcase.yaml index 9287dfc8a181..d349b063462d 100644 --- a/tests/drivers/smbus/smbus_api/testcase.yaml +++ b/tests/drivers/smbus/smbus_api/testcase.yaml @@ -3,8 +3,9 @@ common: - smbus tags: smbus tests: - drivers.smbus.api: - platform_allow: qemu_x86_64 + drivers.smbus.api.access.io: + extra_configs: + - CONFIG_SMBUS_INTEL_PCH_ACCESS_IO=y drivers.smbus.api.access.mmio: platform_exclude: qemu_x86_64 extra_configs: From 7afeefd7dde43a29fc76529eeba825cb2d0bbeeb Mon Sep 17 00:00:00 2001 From: Dmitrii Golovanov Date: Wed, 5 Jul 2023 20:32:09 +0200 Subject: [PATCH 1356/2042] twister: Fix flashing timeout command line options check Fix `--device-flash-with-test` command line options check logic to be effective with `--device-testing`. Remove `--device-flash-timeout` check for `--device-testing` presence as marginal. Signed-off-by: Dmitrii Golovanov --- scripts/pylib/twister/twisterlib/environment.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 0c53a18b993e..53ef2db14e03 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -729,12 +729,8 @@ def parse_arguments(parser, args, options = None): only one platform is allowed""") sys.exit(1) - if options.device_flash_timeout and options.device_testing is None: - logger.error("--device-flash-timeout requires --device-testing") - sys.exit(1) - - if options.device_flash_with_test and options.device_testing is None: - logger.error("--device-flash-with-test requires --device-testing") + if options.device_flash_with_test and not options.device_testing: + logger.error("--device-flash-with-test requires --device_testing") sys.exit(1) if options.shuffle_tests and options.subset is None: From 57c27cd736dfade42810cf2872a8210f7dc44845 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Thu, 15 Jun 2023 19:13:20 +0200 Subject: [PATCH 1357/2042] twister: pytest: Added fixture for mcumgr with unittests Added mcumgr fixture to pytest-twister-harness. Added unittests for new fixture. Signed-off-by: Grzegorz Chwierut --- doc/develop/test/pytest.rst | 35 ++++- .../src/twister_harness/__init__.py | 3 +- .../src/twister_harness/fixtures/mcumgr.py | 121 ++++++++++++++++++ .../src/twister_harness/plugin.py | 3 +- .../tests/fixtures/mcumgr_fixture_test.py | 86 +++++++++++++ 5 files changed, 244 insertions(+), 4 deletions(-) create mode 100755 scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures/mcumgr.py create mode 100644 scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index 48eb2cf8eda8..97737ce0ae2a 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -63,17 +63,48 @@ Following import is required to include in .py sources: from twister_harness import Device -It is important for type checking and enabling IDE hints for ``dut``s (objects representing +It is important for type checking and enabling IDE hints for ``dut`` s (objects representing Devices Under Test). The ``dut`` fixture is the core of pytest harness plugin. When used as an argument of a test function it gives access to a DeviceAbstract type object. The fixture yields a device prepared according to the requested type (native posix, qemu, hardware, etc.). All types of devices share the same API. This allows for writing tests which are device-type-agnostic. +Helpers & fixtures +================== + +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`. + +.. 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`` + +.. code-block:: python + + from twister_harness import Device, McuMgr + + def test_upgrade(dut: Device, mcumgr: McuMgr): + # wait for dut is up + time.sleep(2) + # upload the signed image + mcumgr.image_upload('path/to/zephyr.signed.bin') + # obtain the hash of uploaded image from the device + second_hash = mcumgr.get_hash_to_test() + # test a new upgrade image + mcumgr.image_test(second_hash) + # reset the device remotely + mcumgr.reset_device() + # continue test scenario, check version etc. Limitations *********** -* The whole pytest call is reported as one test in the final twister report (xml or json). * Device adapters in pytest plugin provide `iter_stdout` method to read from devices. In some cases, it is not the most convenient way, and it will be considered how to improve this (for example replace it with a simple read function with a given byte size and timeout arguments). diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py index 67e2fd26b2af..2c8e528c5248 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/__init__.py @@ -5,7 +5,8 @@ # flake8: noqa from twister_harness.device.device_abstract import DeviceAbstract as Device +from twister_harness.fixtures.mcumgr import MCUmgr -__all__= ['Device'] +__all__= ['Device', 'MCUmgr'] __version__ = '0.0.1' diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures/mcumgr.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures/mcumgr.py new file mode 100755 index 000000000000..9034c0c93183 --- /dev/null +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures/mcumgr.py @@ -0,0 +1,121 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +from __future__ import annotations + +import pytest +import logging +import re +import shlex + +from typing import Generator +from subprocess import check_output, getstatusoutput +from pathlib import Path +from dataclasses import dataclass + +from twister_harness.device.device_abstract import DeviceAbstract + + +logger = logging.getLogger(__name__) + + +class MCUmgrException(Exception): + """General MCUmgr exception.""" + + +@dataclass +class MCUmgrImage: + image: int + slot: int + version: str = '' + flags: str = '' + hash: str = '' + + +class MCUmgr: + """Sample wrapper for mcumgr command-line tool""" + mcumgr_exec = 'mcumgr' + + def __init__(self, connection_options: str): + self.conn_opts = connection_options + + @classmethod + def create_for_serial(cls, serial_port: str) -> MCUmgr: + return cls(connection_options=f'--conntype serial --connstring={serial_port}') + + @classmethod + def is_available(cls) -> bool: + exitcode, output = getstatusoutput(f'{cls.mcumgr_exec} version') + if exitcode != 0: + logger.warning(f'mcumgr tool not available: {output}') + return False + return True + + def run_command(self, cmd: str) -> str: + command = f'{self.mcumgr_exec} {self.conn_opts} {cmd}' + logger.info(f'CMD: {command}') + return check_output(shlex.split(command), text=True) + + 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}') + logger.info('Image successfully uploaded') + + def get_image_list(self) -> list[MCUmgrImage]: + output = self.run_command('image list') + return self._parse_image_list(output) + + @staticmethod + def _parse_image_list(cmd_output: str) -> list[MCUmgrImage]: + image_list = [] + re_image = re.compile(r'image=(\d+)\s+slot=(\d+)') + re_version = re.compile(r'version:\s+(\S+)') + re_flags = re.compile(r'flags:\s+(.+)') + re_hash = re.compile(r'hash:\s+(\w+)') + for line in cmd_output.splitlines(): + if m := re_image.search(line): + image_list.append( + MCUmgrImage( + image=int(m.group(1)), + slot=int(m.group(2)) + ) + ) + elif image_list: + if m := re_version.search(line): + image_list[-1].version = m.group(1) + elif m := re_flags.search(line): + image_list[-1].flags = m.group(1) + elif m := re_hash.search(line): + image_list[-1].hash = m.group(1) + return image_list + + 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 + + def image_test(self, hash: str | None = None): + if not hash: + hash = self.get_hash_to_test() + self.run_command(f'image test {hash}') + + def image_confirm(self, hash: str | None = None): + if not hash: + image_list = self.get_image_list() + hash = image_list[0].hash + self.run_command(f'image confirm {hash}') + + +@pytest.fixture(scope='session') +def is_mcumgr_available() -> None: + if not MCUmgr.is_available(): + pytest.skip('mcumgr not available') + + +@pytest.fixture() +def mcumgr(is_mcumgr_available: None, dut: DeviceAbstract) -> Generator[MCUmgr, None, None]: + yield MCUmgr.create_for_serial(dut.device_config.serial) diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py index a5106486e768..f3576c2ff170 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py @@ -16,7 +16,8 @@ logger = logging.getLogger(__name__) pytest_plugins = ( - 'twister_harness.fixtures.dut' + 'twister_harness.fixtures.dut', + 'twister_harness.fixtures.mcumgr' ) 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 new file mode 100644 index 000000000000..f294adba30a5 --- /dev/null +++ b/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py @@ -0,0 +1,86 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import pytest +import textwrap + +from unittest import mock +from twister_harness.fixtures.mcumgr import MCUmgr, MCUmgrException + + +@pytest.fixture(name='mcumgr') +def fixture_mcumgr() -> MCUmgr: + return MCUmgr.create_for_serial('SERIAL_PORT') + + +@mock.patch('twister_harness.fixtures.mcumgr.MCUmgr.run_command', return_value='') +def test_if_mcumgr_fixture_generate_proper_command( + patched_run_command: mock.Mock, mcumgr: MCUmgr +) -> None: + mcumgr.reset_device() + patched_run_command.assert_called_with('reset') + + mcumgr.get_image_list() + patched_run_command.assert_called_with('image list') + + mcumgr.image_upload('/path/to/image', timeout=100) + patched_run_command.assert_called_with('-t 100 image upload /path/to/image') + + mcumgr.image_test(hash='ABCD') + patched_run_command.assert_called_with('image test ABCD') + + mcumgr.image_confirm(hash='ABCD') + patched_run_command.assert_called_with('image confirm ABCD') + + +def test_if_mcumgr_fixture_raises_exception_when_no_hash_to_test(mcumgr: MCUmgr) -> None: + cmd_output = textwrap.dedent(""" + Images: + image=0 slot=0 + version: 0.0.0 + bootable: true + flags: active confirmed + hash: 1234 + Split status: N/A (0) + """) + mcumgr.run_command = mock.Mock(return_value=cmd_output) + with pytest.raises(MCUmgrException): + mcumgr.image_test() + + +def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: + cmd_output = textwrap.dedent(""" + Images: + image=0 slot=0 + version: 0.0.0 + bootable: true + flags: + hash: 0000 + image=0 slot=1 + version: 1.1.1 + bootable: true + flags: pending + hash: 1111 + Split status: N/A (0) + """) + mcumgr.run_command = mock.Mock(return_value=cmd_output) + image_list = mcumgr.get_image_list() + 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].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].hash == '1111' + + # take second hash to test + mcumgr.image_test() + mcumgr.run_command.assert_called_with('image test 1111') + + # take first hash to confirm + mcumgr.image_confirm() + mcumgr.run_command.assert_called_with('image confirm 0000') From e55fb88bcbe70d59c639f137221ed10e07172ccd Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 21 Jun 2023 14:48:08 -0700 Subject: [PATCH 1358/2042] soc: intel_adsp/ace: update clock rate The clock rates for ACE series of Intel Audio DSP have changed. The values come from the SOF project in their board configs. CONFIG_XTENSA_CCOUNT_HZ is also set so the arch timing test can pass. Signed-off-by: Daniel Leung --- soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series index 6124b426cfca..198f0b35f708 100644 --- a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series +++ b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series @@ -46,11 +46,14 @@ config XTENSA_TIMER_ID default 0 config SYS_CLOCK_HW_CYCLES_PER_SEC - default 400000000 if XTENSA_TIMER - default 19200000 if INTEL_ADSP_TIMER + default 393216000 if XTENSA_TIMER + default 38400000 if INTEL_ADSP_TIMER config SYS_CLOCK_TICKS_PER_SEC - default 50000 + default 12000 + +config XTENSA_CCOUNT_HZ + default 393216000 config DYNAMIC_INTERRUPTS default y From 397ed142adfb2b45070b72a7bb335dc5cd3d2b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nerijus=20Bend=C5=BEi=C5=ABnas?= Date: Sat, 15 Jul 2023 09:23:54 +0300 Subject: [PATCH 1359/2042] doc: fix :zephyr-app: paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During testing I've found one bad path and looked if there is more. I've used this oneliner to find more: ``` rg :zephyr-app: | awk '{ print $3 }' | while read dir do test -d $dir || echo $dir done | grep '^samples' | grep -v '<' | sort | uniq ``` Signed-off-by: Nerijus Bendžiūnas --- boards/arm/adafruit_feather_nrf52840/doc/index.rst | 4 ++-- boards/arm/ebyte_e73_tbb_nrf52832/doc/index.rst | 2 +- boards/arm/pinetime_devkit0/doc/index.rst | 4 ++-- boards/shields/arceli_eth_w5500/doc/index.rst | 2 +- boards/shields/boostxl_ulpsense/doc/index.rst | 2 +- boards/shields/lmp90100_evb/doc/index.rst | 2 +- boards/shields/mikroe_eth_click/doc/index.rst | 2 +- boards/shields/semtech_sx1272mb2das/doc/index.rst | 2 +- boards/shields/semtech_sx1276mb1mas/doc/index.rst | 2 +- boards/shields/st7735r/doc/index.rst | 2 +- samples/arch/mpu/mpu_test/README.rst | 4 ++-- samples/boards/nrf/system_off/README.rst | 2 +- samples/boards/stm32/backup_sram/README.rst | 2 +- samples/boards/stm32/power_mgmt/standby_shutdown/README.rst | 2 +- samples/boards/ti/cc13x2_cc26x2/system_off/README.rst | 2 +- samples/cpp/cpp_synchronization/README.rst | 2 +- samples/drivers/misc/grove_display/README.rst | 2 +- samples/sensor/adc_cmp_npcx/README.rst | 2 +- samples/sensor/dps310/README.rst | 2 +- samples/sensor/mcux_acmp/README.rst | 4 ++-- samples/subsys/usb_c/sink/README.rst | 2 +- samples/subsys/usb_c/source/README.rst | 2 +- samples/subsys/video/capture/README.rst | 2 +- samples/subsys/video/tcpserversink/README.rst | 2 +- 24 files changed, 28 insertions(+), 28 deletions(-) diff --git a/boards/arm/adafruit_feather_nrf52840/doc/index.rst b/boards/arm/adafruit_feather_nrf52840/doc/index.rst index 6110da15dca7..d198ec9e3375 100644 --- a/boards/arm/adafruit_feather_nrf52840/doc/index.rst +++ b/boards/arm/adafruit_feather_nrf52840/doc/index.rst @@ -116,7 +116,7 @@ an external programmer. The programmer is attached to the SWD header. Build the Zephyr kernel and the :ref:`blinky-sample` sample application. .. zephyr-app-commands:: - :zephyr-app: samples/blinky + :zephyr-app: samples/basic/blinky :board: adafruit_feather_nrf52840 :goals: build :compact: @@ -124,7 +124,7 @@ Build the Zephyr kernel and the :ref:`blinky-sample` sample application. Flash the image. .. zephyr-app-commands:: - :zephyr-app: samples/blinky + :zephyr-app: samples/basic/blinky :board: adafruit_feather_nrf52840 :goals: flash :compact: diff --git a/boards/arm/ebyte_e73_tbb_nrf52832/doc/index.rst b/boards/arm/ebyte_e73_tbb_nrf52832/doc/index.rst index d679b5f30c4e..8fd7dde6967b 100644 --- a/boards/arm/ebyte_e73_tbb_nrf52832/doc/index.rst +++ b/boards/arm/ebyte_e73_tbb_nrf52832/doc/index.rst @@ -187,7 +187,7 @@ To flash the board connect pins: SWDIO, SWDCLK, RST, GND from E73-TBB to corresponding pins on your J-Link device, then build and flash the application in the usual way. .. zephyr-app-commands:: - :zephyr-app: samples/blinky + :zephyr-app: samples/basic/blinky :board: ebyte_e73_tbb_nrf52832 :goals: build flash diff --git a/boards/arm/pinetime_devkit0/doc/index.rst b/boards/arm/pinetime_devkit0/doc/index.rst index 0a50bf07f60a..16a04cd329cc 100644 --- a/boards/arm/pinetime_devkit0/doc/index.rst +++ b/boards/arm/pinetime_devkit0/doc/index.rst @@ -116,10 +116,10 @@ Building ******** In order to get started with Zephyr on the PineTime, you can use the -board-specific sample: +basic button sample: .. zephyr-app-commands:: - :zephyr-app: samples/boards/pine64_pinetime + :zephyr-app: samples/basic/button :board: pinetime_devkit0 :goals: build diff --git a/boards/shields/arceli_eth_w5500/doc/index.rst b/boards/shields/arceli_eth_w5500/doc/index.rst index d87c767a8b90..359a91e482ae 100644 --- a/boards/shields/arceli_eth_w5500/doc/index.rst +++ b/boards/shields/arceli_eth_w5500/doc/index.rst @@ -42,7 +42,7 @@ Programming Set ``-DSHIELD=arceli_eth_w5500`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/net/dhcp_client + :zephyr-app: samples/net/dhcpv4_client :board: nrf52840dk_nrf52840 :shield: arceli_eth_w5500 :goals: build diff --git a/boards/shields/boostxl_ulpsense/doc/index.rst b/boards/shields/boostxl_ulpsense/doc/index.rst index d206f77af535..d90717814e4a 100644 --- a/boards/shields/boostxl_ulpsense/doc/index.rst +++ b/boards/shields/boostxl_ulpsense/doc/index.rst @@ -26,7 +26,7 @@ Programming Set ``-DSHIELD=boostxl_ulpsense`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/sensor/adxl362 + :zephyr-app: samples/sensor/accel_polling/ :board: cc1352r1_launchxl :shield: boostxl_ulpsense :goals: build diff --git a/boards/shields/lmp90100_evb/doc/index.rst b/boards/shields/lmp90100_evb/doc/index.rst index 3e06d70abddd..f3a1ff36ed3e 100644 --- a/boards/shields/lmp90100_evb/doc/index.rst +++ b/boards/shields/lmp90100_evb/doc/index.rst @@ -44,7 +44,7 @@ Programming Set ``-DSHIELD=lmp90100_evb`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/shields/lmp90100_evb/thermocouple + :zephyr-app: samples/shields/lmp90100_evb/rtd :board: frdm_k64f :shield: lmp90100_evb :goals: build diff --git a/boards/shields/mikroe_eth_click/doc/index.rst b/boards/shields/mikroe_eth_click/doc/index.rst index 334e57fa714b..3344765fa6d1 100644 --- a/boards/shields/mikroe_eth_click/doc/index.rst +++ b/boards/shields/mikroe_eth_click/doc/index.rst @@ -44,7 +44,7 @@ Programming Set ``-DSHIELD=mikroe_eth_click`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/net/dhcp_client + :zephyr-app: samples/net/dhcpv4_client :board: lpcxpresso55s69 :shield: mikroe_eth_click :goals: build diff --git a/boards/shields/semtech_sx1272mb2das/doc/index.rst b/boards/shields/semtech_sx1272mb2das/doc/index.rst index fe56e6118cf4..8dcea32f3a5c 100644 --- a/boards/shields/semtech_sx1272mb2das/doc/index.rst +++ b/boards/shields/semtech_sx1272mb2das/doc/index.rst @@ -54,7 +54,7 @@ Set ``-DSHIELD=semtech_sx1272mb2das`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/lorawan/class_a + :zephyr-app: samples/subsys/lorawan/class_a :board: nucleo_f429zi :shield: semtech_sx1272mb2das :goals: build diff --git a/boards/shields/semtech_sx1276mb1mas/doc/index.rst b/boards/shields/semtech_sx1276mb1mas/doc/index.rst index bfdb9e41e674..bdf85d4d3c15 100644 --- a/boards/shields/semtech_sx1276mb1mas/doc/index.rst +++ b/boards/shields/semtech_sx1276mb1mas/doc/index.rst @@ -62,7 +62,7 @@ Set ``-DSHIELD=semtech_sx1271mb1mas`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/lorawan/class_a + :zephyr-app: samples/subsys/lorawan/class_a :board: nucleo_l073rz :shield: semtech_sx1276mb1mas :goals: build diff --git a/boards/shields/st7735r/doc/index.rst b/boards/shields/st7735r/doc/index.rst index 3a8fb5414cd8..015396b9690e 100644 --- a/boards/shields/st7735r/doc/index.rst +++ b/boards/shields/st7735r/doc/index.rst @@ -53,7 +53,7 @@ Programming Set ``-DSHIELD=st7735r_ada_160x128`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: samples/gui/lvgl + :zephyr-app: samples/subsys/display/lvgl :board: nrf52840dk_nrf52840 :shield: st7735r_ada_160x128 :goals: build diff --git a/samples/arch/mpu/mpu_test/README.rst b/samples/arch/mpu/mpu_test/README.rst index e4b4cc89359a..750bdda41bcc 100644 --- a/samples/arch/mpu/mpu_test/README.rst +++ b/samples/arch/mpu/mpu_test/README.rst @@ -21,7 +21,7 @@ Building and Running This project can be built and executed as follows: .. zephyr-app-commands:: - :zephyr-app: samples/mpu/mpu_test + :zephyr-app: samples/arch/mpu/mpu_test :board: v2m_beetle :goals: build flash :compact: @@ -30,7 +30,7 @@ To build the single thread version, use the supplied configuration file for single thread: :file:`prj_single.conf`: .. zephyr-app-commands:: - :zephyr-app: samples/mpu/mpu_test + :zephyr-app: samples/arch/mpu/mpu_test :board: v2m_beetle :conf: prj_single.conf :goals: run diff --git a/samples/boards/nrf/system_off/README.rst b/samples/boards/nrf/system_off/README.rst index 000227088506..77eb93766dcc 100644 --- a/samples/boards/nrf/system_off/README.rst +++ b/samples/boards/nrf/system_off/README.rst @@ -40,7 +40,7 @@ Building, Flashing and Running ****************************** .. zephyr-app-commands:: - :zephyr-app: samples/boards/nrf52/system_off + :zephyr-app: samples/boards/nrf/system_off :board: nrf52dk_nrf52832 :goals: build flash :compact: diff --git a/samples/boards/stm32/backup_sram/README.rst b/samples/boards/stm32/backup_sram/README.rst index 2762eb2df34a..620f64faec90 100644 --- a/samples/boards/stm32/backup_sram/README.rst +++ b/samples/boards/stm32/backup_sram/README.rst @@ -26,7 +26,7 @@ In order to run this sample, make sure to enable ``backup_sram`` node in your board DT file. .. zephyr-app-commands:: - :zephyr-app: samples/memc/stm32_backup_sram + :zephyr-app: samples/boards/stm32/backup_sram :board: nucleo_h743zi :goals: build :compact: diff --git a/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst b/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst index 3efd2b08a93c..5b027c69ee24 100644 --- a/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst +++ b/samples/boards/stm32/power_mgmt/standby_shutdown/README.rst @@ -30,7 +30,7 @@ Building and Running Build and flash standby_shutdown as follows, changing ``nucleo_L476RG`` for your board: .. zephyr-app-commands:: - :zephyr-app: samples/samples/boards/stm32/power_mgmt/standby_shutdown + :zephyr-app: samples/boards/stm32/power_mgmt/standby_shutdown :board: nucleo_L476RG :goals: build flash :compact: diff --git a/samples/boards/ti/cc13x2_cc26x2/system_off/README.rst b/samples/boards/ti/cc13x2_cc26x2/system_off/README.rst index 381bb1ef1d8c..b9173549242e 100644 --- a/samples/boards/ti/cc13x2_cc26x2/system_off/README.rst +++ b/samples/boards/ti/cc13x2_cc26x2/system_off/README.rst @@ -28,7 +28,7 @@ Building, Flashing and Running ****************************** .. zephyr-app-commands:: - :zephyr-app: samples/boards/cc13x2_cc26x2/system_off + :zephyr-app: samples/boards/ti/cc13x2_cc26x2/system_off :board: cc1352r1_launchxl :goals: build flash :compact: diff --git a/samples/cpp/cpp_synchronization/README.rst b/samples/cpp/cpp_synchronization/README.rst index 629622e3b3c1..d50e3df8e780 100644 --- a/samples/cpp/cpp_synchronization/README.rst +++ b/samples/cpp/cpp_synchronization/README.rst @@ -22,7 +22,7 @@ This kernel project outputs to the console. It can be built and executed on QEMU as follows: .. zephyr-app-commands:: - :zephyr-app: samples/cpp_synchronization + :zephyr-app: samples/cpp/cpp_synchronization :host-os: unix :board: qemu_x86 :goals: run diff --git a/samples/drivers/misc/grove_display/README.rst b/samples/drivers/misc/grove_display/README.rst index af3920255c5a..a1838d0ec5c5 100644 --- a/samples/drivers/misc/grove_display/README.rst +++ b/samples/drivers/misc/grove_display/README.rst @@ -41,7 +41,7 @@ shield interface. For example, it can be run on the FRDM K64F board as described below: .. zephyr-app-commands:: - :zephyr-app: samples/subsys/display/grove_display + :zephyr-app: samples/drivers/misc/grove_display :board: frdm_k64f :goals: flash :compact: diff --git a/samples/sensor/adc_cmp_npcx/README.rst b/samples/sensor/adc_cmp_npcx/README.rst index 5efd18d7126c..2054ee72c00f 100644 --- a/samples/sensor/adc_cmp_npcx/README.rst +++ b/samples/sensor/adc_cmp_npcx/README.rst @@ -21,7 +21,7 @@ to ADC channel 8, when voltages cross upper/lower limits, detection messages will be printed. .. zephyr-app-commands:: - :zephyr-app: samples/sensor/adc_cmp + :zephyr-app: samples/sensor/adc_cmp_npcx :board: npcx9m6f_evb :goals: flash :compact: diff --git a/samples/sensor/dps310/README.rst b/samples/sensor/dps310/README.rst index fae1ef99e709..57ad36d29820 100644 --- a/samples/sensor/dps310/README.rst +++ b/samples/sensor/dps310/README.rst @@ -22,7 +22,7 @@ Build and flash this sample (for example, for the nrf52840dk_nrf52840 board) using these commands: .. zephyr-app-commands:: - :zephyr-app: samples/sensors/dps310 + :zephyr-app: samples/sensor/dps310 :board: nrf52840dk_nrf52840 :goals: flash :compact: diff --git a/samples/sensor/mcux_acmp/README.rst b/samples/sensor/mcux_acmp/README.rst index adbfa7eb6965..832a3098db54 100644 --- a/samples/sensor/mcux_acmp/README.rst +++ b/samples/sensor/mcux_acmp/README.rst @@ -27,7 +27,7 @@ Build the application for the :ref:`twr_ke18f` board, and adjust the ACMP input voltage by turning the on-board potentiometer. .. zephyr-app-commands:: - :zephyr-app: samples/drivers/mcux_acmp + :zephyr-app: samples/sensor/mcux_acmp :board: twr_ke18f :goals: flash :compact: @@ -38,7 +38,7 @@ Build the application for the MIMXRT1170-EVK board, and adjust the ACMP input voltage by changing the voltage input to J25-13. .. zephyr-app-commands:: - :zephyr-app: samples/drivers/mcux_acmp + :zephyr-app: samples/sensor/mcux_acmp :board: mimxrt1170_evk_cm7 :goals: flash :compact: diff --git a/samples/subsys/usb_c/sink/README.rst b/samples/subsys/usb_c/sink/README.rst index 00de60ec1ed4..8b8a4657c818 100644 --- a/samples/subsys/usb_c/sink/README.rst +++ b/samples/subsys/usb_c/sink/README.rst @@ -30,7 +30,7 @@ Building and Running Build and flash as follows, changing ``b_g474e_dpow1`` for your board: .. zephyr-app-commands:: - :zephyr-app: samples/subsys/usb-c/sink + :zephyr-app: samples/subsys/usb_c/sink :board: b_g474e_dpow1 :goals: build flash :compact: diff --git a/samples/subsys/usb_c/source/README.rst b/samples/subsys/usb_c/source/README.rst index 82096b5b13bf..06cb38eab37b 100644 --- a/samples/subsys/usb_c/source/README.rst +++ b/samples/subsys/usb_c/source/README.rst @@ -29,7 +29,7 @@ Building and Running Build and flash as follows, changing ``stm32g081b_eval`` for your board: .. zephyr-app-commands:: - :zephyr-app: samples/subsys/usb-c/source + :zephyr-app: samples/subsys/usb_c/source :board: stm32g081b_eval :goals: build flash :compact: diff --git a/samples/subsys/video/capture/README.rst b/samples/subsys/video/capture/README.rst index bf6790df1610..4609da6a7dee 100644 --- a/samples/subsys/video/capture/README.rst +++ b/samples/subsys/video/capture/README.rst @@ -32,7 +32,7 @@ Building and Running For :ref:`mimxrt1064_evk`, build this sample application with the following commands: .. zephyr-app-commands:: - :zephyr-app: samples/video/mt9m114 + :zephyr-app: samples/subsys/video/capture :board: mimxrt1064_evk :goals: build :compact: diff --git a/samples/subsys/video/tcpserversink/README.rst b/samples/subsys/video/tcpserversink/README.rst index 5258fde26ea7..df8560110917 100644 --- a/samples/subsys/video/tcpserversink/README.rst +++ b/samples/subsys/video/tcpserversink/README.rst @@ -31,7 +31,7 @@ Building and Running For :ref:`mimxrt1064_evk`, build this sample application with the following commands: .. zephyr-app-commands:: - :zephyr-app: samples/video/mt9m114 + :zephyr-app: samples/subsys/video/tcpserversink :board: mimxrt1064_evk :goals: build :compact: From d58c9a1ca467698f898231c3f7677e4d0d09154f Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 14 Jul 2023 11:36:39 -0700 Subject: [PATCH 1360/2042] tests: kernel: threads: stack: Enable USERSPACE Test that automatic thread stack allocation works for both user and kernel threads. Signed-off-by: Flavio Ceolin --- .../dynamic_thread_stack/testcase.yaml | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/tests/kernel/threads/dynamic_thread_stack/testcase.yaml b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml index 3bf7d892b579..7dc7b6f47bd0 100644 --- a/tests/kernel/threads/dynamic_thread_stack/testcase.yaml +++ b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml @@ -21,56 +21,49 @@ tests: - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - CONFIG_DYNAMIC_THREAD_ALLOC=n - CONFIG_USERSPACE=n - - # kernel.threads.dynamic_thread.stack.no_pool.no_alloc.user: - # tags: userspace - # extra_configs: - # # 001 - # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - # - CONFIG_DYNAMIC_THREAD_ALLOC=n - # - CONFIG_USERSPACE=y - + kernel.threads.dynamic_thread.stack.no_pool.no_alloc.user: + tags: userspace + extra_configs: + # 001 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + - CONFIG_DYNAMIC_THREAD_ALLOC=n + - CONFIG_USERSPACE=y kernel.threads.dynamic_thread.stack.no_pool.alloc.no_user: extra_configs: # 010 - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - CONFIG_DYNAMIC_THREAD_ALLOC=y - CONFIG_USERSPACE=n - - # kernel.threads.dynamic_thread.stack.no_pool.alloc.user: - # tags: userspace - # extra_configs: - # # 011 - # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - # - CONFIG_DYNAMIC_THREAD_ALLOC=y - # - CONFIG_USERSPACE=y - + kernel.threads.dynamic_thread.stack.no_pool.alloc.user: + tags: userspace + extra_configs: + # 011 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 + - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_USERSPACE=y kernel.threads.dynamic_thread.stack.pool.no_alloc.no_user: extra_configs: # 100 - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 - CONFIG_DYNAMIC_THREAD_ALLOC=n - CONFIG_USERSPACE=n - - # kernel.threads.dynamic_thread.stack.pool.no_alloc.user: - # tags: userspace - # extra_configs: - # # 101 - # - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 - # - CONFIG_DYNAMIC_THREAD_ALLOC=n - # - CONFIG_USERSPACE=y - + kernel.threads.dynamic_thread.stack.pool.no_alloc.user: + tags: userspace + extra_configs: + # 101 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 + - CONFIG_DYNAMIC_THREAD_ALLOC=n + - CONFIG_USERSPACE=y kernel.threads.dynamic_thread.stack.pool.alloc.no_user: extra_configs: # 110 - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 - CONFIG_DYNAMIC_THREAD_ALLOC=y - CONFIG_USERSPACE=n - -# kernel.threads.dynamic_thread.stack.pool.alloc.user: -# tags: userspace -# extra_configs: -# # 111 -# - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 -# - CONFIG_DYNAMIC_THREAD_ALLOC=y -# - CONFIG_USERSPACE=y + kernel.threads.dynamic_thread.stack.pool.alloc.user: + tags: userspace + extra_configs: + # 111 + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 + - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_USERSPACE=y From 67e66e48077e5f364f4c6335d68a59b17605696e Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 22 Jun 2023 06:27:28 +0000 Subject: [PATCH 1361/2042] kernel: userspace: Add k_object_alloc_size Add a new API to dynamically allocate kernel objects that allow passing an arbitrary size. This new API allows to allocate dynamic thread stack. Signed-off-by: Flavio Ceolin --- include/zephyr/sys/kobject.h | 30 +++++++++++++++++++++++++++++- kernel/userspace.c | 17 ++++++++++++++--- kernel/userspace_handler.c | 6 ++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/zephyr/sys/kobject.h b/include/zephyr/sys/kobject.h index fa6303754282..64db4d781c92 100644 --- a/include/zephyr/sys/kobject.h +++ b/include/zephyr/sys/kobject.h @@ -248,7 +248,8 @@ static inline void k_object_access_all_grant(const void *object) * 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. * - * Currently, allocation of thread stacks is not supported. + * @note Thread stack object has to use k_object_alloc_size() since stacks may + * have different sizes. * * @param otype Requested kernel object type * @return A pointer to the allocated kernel object, or NULL if memory wasn't @@ -256,6 +257,24 @@ static inline void k_object_access_all_grant(const void *object) */ __syscall void *k_object_alloc(enum k_objects otype); +/** + * Allocate a kernel object of a designated type and a given size + * + * This will instantiate at runtime a kernel object of the specified type, + * returning a pointer to it. The object will be returned in an uninitialized + * 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. + * + * This function is specially helpful for thread stack objects because + * their sizes can vary. Other objects should probably look k_object_alloc(). + * + * @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 + * available + */ +__syscall void *k_object_alloc_size(enum k_objects otype, size_t size); + /** * Allocate memory and install as a generic kernel object * @@ -322,6 +341,15 @@ static inline void *z_impl_k_object_alloc(enum k_objects otype) return NULL; } +static inline void *z_impl_k_object_alloc_size(enum k_objects otype, + size_t size) +{ + ARG_UNUSED(otype); + ARG_UNUSED(size); + + return NULL; +} + static inline struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) { diff --git a/kernel/userspace.c b/kernel/userspace.c index 9d8611a3873a..24a59b940124 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -328,7 +328,7 @@ struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) return &dyn->kobj; } -void *z_impl_k_object_alloc(enum k_objects otype) +static void *z_object_alloc(enum k_objects otype, size_t object_size) { struct z_object *zo; uintptr_t tidx = 0; @@ -348,7 +348,8 @@ void *z_impl_k_object_alloc(enum k_objects otype) /* The following are currently not allowed at all */ case K_OBJ_FUTEX: /* Lives in user memory */ case K_OBJ_SYS_MUTEX: /* Lives in user memory */ - case K_OBJ_THREAD_STACK_ELEMENT: /* No aligned allocator */ + case K_OBJ_THREAD_STACK_ELEMENT: + break; case K_OBJ_NET_SOCKET: /* Indeterminate size */ LOG_ERR("forbidden object type '%s' requested", otype_to_str(otype)); @@ -359,7 +360,7 @@ void *z_impl_k_object_alloc(enum k_objects otype) } zo = z_dynamic_object_aligned_create(obj_align_get(otype), - obj_size_get(otype)); + object_size); if (zo == NULL) { if (otype == K_OBJ_THREAD) { thread_idx_free(tidx); @@ -385,6 +386,16 @@ void *z_impl_k_object_alloc(enum k_objects otype) return zo->name; } +void *z_impl_k_object_alloc(enum k_objects otype) +{ + return z_object_alloc(otype, obj_size_get(otype)); +} + +void *z_impl_k_object_alloc_size(enum k_objects otype, size_t size) +{ + return z_object_alloc(otype, size); +} + void k_object_free(void *obj) { struct dyn_obj *dyn; diff --git a/kernel/userspace_handler.c b/kernel/userspace_handler.c index 6531e83791ce..80f9325b7de2 100644 --- a/kernel/userspace_handler.c +++ b/kernel/userspace_handler.c @@ -65,3 +65,9 @@ static inline void *z_vrfy_k_object_alloc(enum k_objects otype) return z_impl_k_object_alloc(otype); } #include + +static inline void *z_vrfy_k_object_alloc_size(enum k_objects otype, size_t size) +{ + return z_impl_k_object_alloc_size(otype, size); +} +#include From fc6d9eeb3e70512331751c41ffaa6ffe07e91447 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 22 Jun 2023 06:31:45 +0000 Subject: [PATCH 1362/2042] kernel: dynamic: Support usermode thread stack Allocate kernel object for userspace thread stack. Signed-off-by: Flavio Ceolin --- kernel/dynamic.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/kernel/dynamic.c b/kernel/dynamic.c index 6f9c1f6adcfe..3f628ee3be76 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -39,6 +41,8 @@ static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size) size_t offset; k_thread_stack_t *stack; + size = Z_KERNEL_STACK_SIZE_ADJUST(size); + if (size > CONFIG_DYNAMIC_THREAD_STACK_SIZE) { LOG_DBG("stack size %zu is > pool stack size %d", size, CONFIG_DYNAMIC_THREAD_STACK_SIZE); @@ -58,25 +62,29 @@ static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size) return stack; } -k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) +static k_thread_stack_t *stack_alloc_dyn(size_t size, int flags) { - size_t align = 0; - size_t obj_size = 0; - k_thread_stack_t *stack = NULL; - -#ifdef CONFIG_USERSPACE - if ((flags & K_USER) != 0) { - align = Z_THREAD_STACK_OBJ_ALIGN(size); - obj_size = Z_THREAD_STACK_SIZE_ADJUST(size); - } else + if ((flags & K_USER) == K_USER) { +#ifdef CONFIG_DYNAMIC_OBJECTS + return k_object_alloc_size(K_OBJ_THREAD_STACK_ELEMENT, size); +#else + /* Dynamic user stack needs a kobject, so if this option is not + * enabled we can't proceed. + */ + return NULL; #endif - { - align = Z_KERNEL_STACK_OBJ_ALIGN; - obj_size = Z_KERNEL_STACK_SIZE_ADJUST(size); } + return z_thread_stack_alloc_dyn(Z_KERNEL_STACK_OBJ_ALIGN, + Z_KERNEL_STACK_SIZE_ADJUST(size)); +} + +k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) +{ + k_thread_stack_t *stack = NULL; + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_ALLOC)) { - stack = z_thread_stack_alloc_dyn(align, obj_size); + stack = stack_alloc_dyn(size, flags); if (stack == NULL && CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { stack = z_thread_stack_alloc_pool(size); } @@ -84,7 +92,7 @@ k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { stack = z_thread_stack_alloc_pool(size); if (stack == NULL && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { - stack = z_thread_stack_alloc_dyn(align, obj_size); + stack = stack_alloc_dyn(size, flags); } } else { return NULL; @@ -144,7 +152,15 @@ int z_impl_k_thread_stack_free(k_thread_stack_t *stack) } if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { +#ifdef CONFIG_USERSPACE + if (z_object_find(stack)) { + k_object_free(stack); + } else { + k_free(stack); + } +#else k_free(stack); +#endif } else { LOG_ERR("Invalid stack %p", stack); return -EINVAL; From 3b7e0b672ea20f5751785fcc709e89fbe7e94f79 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 23 Jun 2023 09:34:14 -0700 Subject: [PATCH 1363/2042] kernel: userspace: Dynamic thread stack object Add support for dynamic thread stack objects. A new container for this kernel object was added to avoid its alignment constraint to all dynamic objects. Signed-off-by: Flavio Ceolin --- kernel/userspace.c | 179 +++++++++++++----- .../threads/dynamic_thread_stack/prj.conf | 2 +- .../threads/dynamic_thread_stack/src/main.c | 19 +- .../dynamic_thread_stack/testcase.yaml | 4 + 4 files changed, 150 insertions(+), 54 deletions(-) diff --git a/kernel/userspace.c b/kernel/userspace.c index 24a59b940124..17680d042c9b 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -49,6 +49,25 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #ifdef CONFIG_DYNAMIC_OBJECTS static struct k_spinlock lists_lock; /* kobj rbtree/dlist */ static struct k_spinlock objfree_lock; /* k_object_free */ + +#ifdef CONFIG_GEN_PRIV_STACKS +/* On ARM MPU we may have two different alignment requirement + * when dynamically allocating thread stacks, one for the privileged + * stack and other for the user stack, so we need to account the + * worst alignment scenario and reserve space for that. + */ +#ifdef CONFIG_ARM_MPU +#define STACK_ELEMENT_DATA_SIZE(size) \ + (sizeof(struct z_stack_data) + CONFIG_PRIVILEGED_STACK_SIZE + \ + Z_THREAD_STACK_OBJ_ALIGN(size) + Z_THREAD_STACK_SIZE_ADJUST(size)) +#else +#define STACK_ELEMENT_DATA_SIZE(size) (sizeof(struct z_stack_data) + \ + Z_THREAD_STACK_SIZE_ADJUST(size)) +#endif /* CONFIG_ARM_MPU */ +#else +#define STACK_ELEMENT_DATA_SIZE(size) Z_THREAD_STACK_SIZE_ADJUST(size) +#endif /* CONFIG_GEN_PRIV_STACKS */ + #endif static struct k_spinlock obj_lock; /* kobj struct data */ @@ -130,18 +149,45 @@ uint8_t *z_priv_stack_find(k_thread_stack_t *stack) #define DYN_OBJ_DATA_ALIGN_K_THREAD (sizeof(void *)) #endif +#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE +#ifndef CONFIG_MPU_STACK_GUARD +#define DYN_OBJ_DATA_ALIGN_K_THREAD_STACK \ + Z_THREAD_STACK_OBJ_ALIGN(CONFIG_PRIVILEGED_STACK_SIZE) +#else +#define DYN_OBJ_DATA_ALIGN_K_THREAD_STACK \ + Z_THREAD_STACK_OBJ_ALIGN(CONFIG_DYNAMIC_THREAD_STACK_SIZE) +#endif /* !CONFIG_MPU_STACK_GUARD */ +#else +#define DYN_OBJ_DATA_ALIGN_K_THREAD_STACK \ + Z_THREAD_STACK_OBJ_ALIGN(ARCH_STACK_PTR_ALIGN) +#endif /* CONFIG_DYNAMIC_THREAD_STACK_SIZE */ + #define DYN_OBJ_DATA_ALIGN \ MAX(DYN_OBJ_DATA_ALIGN_K_THREAD, (sizeof(void *))) -struct dyn_obj { +struct dyn_obj_base { struct z_object kobj; sys_dnode_t dobj_list; struct rbnode node; /* must be immediately before data member */ +}; + +struct dyn_obj { + struct dyn_obj_base base; /* The object itself */ uint8_t data[] __aligned(DYN_OBJ_DATA_ALIGN_K_THREAD); }; +/* Thread stacks impose a very restrict alignment. Use this alignment + * (generally page size) for all objects will cause a lot waste memory. + */ +struct dyn_obj_stack { + struct dyn_obj_base base; + + /* The object itself */ + void *data; +}; + extern struct z_object *z_object_gperf_find(const void *obj); extern void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context); @@ -193,6 +239,9 @@ static size_t obj_align_get(enum k_objects otype) ret = __alignof(struct dyn_obj); #endif break; + case K_OBJ_THREAD_STACK_ELEMENT: + ret = __alignof(struct dyn_obj_stack); + break; default: ret = __alignof(struct dyn_obj); break; @@ -206,36 +255,30 @@ static bool node_lessthan(struct rbnode *a, struct rbnode *b) return a < b; } -static inline struct dyn_obj *node_to_dyn_obj(struct rbnode *node) -{ - return CONTAINER_OF(node, struct dyn_obj, node); -} - -static inline struct rbnode *dyn_obj_to_node(void *obj) -{ - struct dyn_obj *dobj = CONTAINER_OF(obj, struct dyn_obj, data); - - return &dobj->node; -} - -static struct dyn_obj *dyn_object_find(void *obj) +static struct dyn_obj_base *dyn_object_find(void *obj) { struct rbnode *node; - struct dyn_obj *ret; + struct dyn_obj_base *ret; + k_spinlock_key_t key; /* For any dynamically allocated kernel object, the object * pointer is just a member of the containing struct dyn_obj, * so just a little arithmetic is necessary to locate the * corresponding struct rbnode */ - node = dyn_obj_to_node(obj); + key = k_spin_lock(&lists_lock); - k_spinlock_key_t key = k_spin_lock(&lists_lock); - if (rb_contains(&obj_rb_tree, node)) { - ret = node_to_dyn_obj(node); - } else { - ret = NULL; + RB_FOR_EACH(&obj_rb_tree, node) { + ret = CONTAINER_OF(node, struct dyn_obj_base, node); + if (ret->kobj.name == obj) { + goto end; + } } + + /* No object found */ + ret = NULL; + + end: k_spin_unlock(&lists_lock, key); return ret; @@ -304,18 +347,61 @@ static void thread_idx_free(uintptr_t tidx) sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx); } -struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) +static struct z_object *dynamic_object_create(enum k_objects otype, size_t align, + size_t size) { - struct dyn_obj *dyn; + struct dyn_obj_base *dyn; - dyn = z_thread_aligned_alloc(align, sizeof(*dyn) + size); - if (dyn == NULL) { - LOG_ERR("could not allocate kernel object, out of memory"); - return NULL; + if (otype == K_OBJ_THREAD_STACK_ELEMENT) { + struct dyn_obj_stack *stack; + size_t adjusted_size; + + if (size == 0) { + return NULL; + } + + adjusted_size = STACK_ELEMENT_DATA_SIZE(size); + stack = z_thread_aligned_alloc(align, sizeof(struct dyn_obj_stack)); + if (stack == NULL) { + return NULL; + } + dyn = &stack->base; + + stack->data = z_thread_aligned_alloc(DYN_OBJ_DATA_ALIGN_K_THREAD_STACK, + adjusted_size); + if (stack->data == NULL) { + k_free(stack); + return NULL; + } + +#ifdef CONFIG_GEN_PRIV_STACKS + struct z_stack_data *stack_data = (struct z_stack_data *) + ((uint8_t *)stack->data + adjusted_size - sizeof(*stack_data)); + stack_data->priv = (uint8_t *)stack->data; + dyn->kobj.data.stack_data = stack_data; +#ifdef CONFIG_ARM_MPU + dyn->kobj.name = (void *)ROUND_UP( + ((uint8_t *)stack->data + CONFIG_PRIVILEGED_STACK_SIZE), + Z_THREAD_STACK_OBJ_ALIGN(size)); +#else + dyn->kobj.name = stack->data; +#endif +#else + dyn->kobj.name = stack->data; +#endif + } else { + struct dyn_obj *obj; + + obj = z_thread_aligned_alloc(align, + sizeof(struct dyn_obj) + obj_size_get(otype) + size); + if (obj == NULL) { + return NULL; + } + dyn = &obj->base; + dyn->kobj.name = &obj->data; } - dyn->kobj.name = &dyn->data; - dyn->kobj.type = K_OBJ_ANY; + dyn->kobj.type = otype; dyn->kobj.flags = 0; (void)memset(dyn->kobj.perms, 0, CONFIG_MAX_THREAD_BYTES); @@ -328,7 +414,18 @@ struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) return &dyn->kobj; } -static void *z_object_alloc(enum k_objects otype, size_t object_size) +struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size) +{ + struct z_object *obj = dynamic_object_create(K_OBJ_ANY, align, size); + + if (obj == NULL) { + LOG_ERR("could not allocate kernel object, out of memory"); + } + + return obj; +} + +static void *z_object_alloc(enum k_objects otype, size_t size) { struct z_object *zo; uintptr_t tidx = 0; @@ -348,8 +445,6 @@ static void *z_object_alloc(enum k_objects otype, size_t object_size) /* The following are currently not allowed at all */ case K_OBJ_FUTEX: /* Lives in user memory */ case K_OBJ_SYS_MUTEX: /* Lives in user memory */ - case K_OBJ_THREAD_STACK_ELEMENT: - break; case K_OBJ_NET_SOCKET: /* Indeterminate size */ LOG_ERR("forbidden object type '%s' requested", otype_to_str(otype)); @@ -359,15 +454,13 @@ static void *z_object_alloc(enum k_objects otype, size_t object_size) break; } - zo = z_dynamic_object_aligned_create(obj_align_get(otype), - object_size); + zo = dynamic_object_create(otype, obj_align_get(otype), size); if (zo == NULL) { if (otype == K_OBJ_THREAD) { thread_idx_free(tidx); } return NULL; } - zo->type = otype; if (otype == K_OBJ_THREAD) { zo->data.thread_id = tidx; @@ -388,7 +481,7 @@ static void *z_object_alloc(enum k_objects otype, size_t object_size) void *z_impl_k_object_alloc(enum k_objects otype) { - return z_object_alloc(otype, obj_size_get(otype)); + return z_object_alloc(otype, 0); } void *z_impl_k_object_alloc_size(enum k_objects otype, size_t size) @@ -398,7 +491,7 @@ void *z_impl_k_object_alloc_size(enum k_objects otype, size_t size) void k_object_free(void *obj) { - struct dyn_obj *dyn; + struct dyn_obj_base *dyn; /* This function is intentionally not exposed to user mode. * There's currently no robust way to track that an object isn't @@ -430,15 +523,15 @@ struct z_object *z_object_find(const void *obj) ret = z_object_gperf_find(obj); if (ret == NULL) { - struct dyn_obj *dynamic_obj; + struct dyn_obj_base *dyn; /* The cast to pointer-to-non-const violates MISRA * 11.8 but is justified since we know dynamic objects * were not declared with a const qualifier. */ - dynamic_obj = dyn_object_find((void *)obj); - if (dynamic_obj != NULL) { - ret = &dynamic_obj->kobj; + dyn = dyn_object_find((void *)obj); + if (dyn != NULL) { + ret = &dyn->kobj; } } @@ -447,7 +540,7 @@ struct z_object *z_object_find(const void *obj) void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) { - struct dyn_obj *obj, *next; + struct dyn_obj_base *obj, *next; z_object_gperf_wordlist_foreach(func, context); @@ -487,7 +580,7 @@ static void unref_check(struct z_object *ko, uintptr_t index) void *vko = ko; - struct dyn_obj *dyn = CONTAINER_OF(vko, struct dyn_obj, kobj); + struct dyn_obj_base *dyn = CONTAINER_OF(vko, struct dyn_obj_base, kobj); __ASSERT(IS_PTR_ALIGNED(dyn, struct dyn_obj), "unaligned z_object"); diff --git a/tests/kernel/threads/dynamic_thread_stack/prj.conf b/tests/kernel/threads/dynamic_thread_stack/prj.conf index 4377c2ec60b4..07c01bd661f4 100644 --- a/tests/kernel/threads/dynamic_thread_stack/prj.conf +++ b/tests/kernel/threads/dynamic_thread_stack/prj.conf @@ -6,7 +6,7 @@ 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=16384 +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 86848e4249ee..e72f4d2f51b4 100644 --- a/tests/kernel/threads/dynamic_thread_stack/src/main.c +++ b/tests/kernel/threads/dynamic_thread_stack/src/main.c @@ -17,7 +17,7 @@ #define MAX_HEAP_STACKS (CONFIG_HEAP_MEM_POOL_SIZE / STACK_OBJ_SIZE) -ZTEST_DMEM bool flag[CONFIG_DYNAMIC_THREAD_POOL_SIZE]; +ZTEST_DMEM bool flag[MAX(CONFIG_DYNAMIC_THREAD_POOL_SIZE, MAX_HEAP_STACKS)]; static void func(void *arg1, void *arg2, void *arg3) { @@ -63,6 +63,7 @@ ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_pool) /* spawn our threads */ for (size_t i = 0; i < CONFIG_DYNAMIC_THREAD_POOL_SIZE; ++i) { + flag[i] = false; tid[i] = k_thread_create(&th[i], stack[i], CONFIG_DYNAMIC_THREAD_STACK_SIZE, func, &flag[i], NULL, NULL, 0, @@ -86,7 +87,6 @@ ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc) { size_t N; static k_tid_t tid[MAX_HEAP_STACKS]; - static bool flag[MAX_HEAP_STACKS]; static struct k_thread th[MAX_HEAP_STACKS]; static k_thread_stack_t *stack[MAX_HEAP_STACKS]; @@ -102,18 +102,17 @@ ZTEST(dynamic_thread_stack, test_dynamic_thread_stack_alloc) for (N = 0; N < MAX_HEAP_STACKS; ++N) { stack[N] = k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0); - zassert_not_null(stack[N]); - } - - if (CONFIG_DYNAMIC_THREAD_POOL_SIZE == 0) { - /* ensure that no more thread stacks can be allocated from the heap */ - zassert_is_null(k_thread_stack_alloc(CONFIG_DYNAMIC_THREAD_STACK_SIZE, - IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0)); + if (stack[N] == NULL) { + break; + } } /* spwan our threads */ for (size_t i = 0; i < N; ++i) { - tid[i] = k_thread_create(&th[i], stack[i], 0, func, &flag[i], NULL, NULL, 0, + flag[i] = false; + tid[i] = k_thread_create(&th[i], stack[i], + CONFIG_DYNAMIC_THREAD_STACK_SIZE, func, + &flag[i], NULL, NULL, 0, K_USER | K_INHERIT_PERMS, K_NO_WAIT); } diff --git a/tests/kernel/threads/dynamic_thread_stack/testcase.yaml b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml index 7dc7b6f47bd0..69f5651406f9 100644 --- a/tests/kernel/threads/dynamic_thread_stack/testcase.yaml +++ b/tests/kernel/threads/dynamic_thread_stack/testcase.yaml @@ -33,6 +33,7 @@ tests: # 010 - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y - CONFIG_USERSPACE=n kernel.threads.dynamic_thread.stack.no_pool.alloc.user: tags: userspace @@ -40,6 +41,7 @@ tests: # 011 - CONFIG_DYNAMIC_THREAD_POOL_SIZE=0 - CONFIG_DYNAMIC_THREAD_ALLOC=y + - CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y - CONFIG_USERSPACE=y kernel.threads.dynamic_thread.stack.pool.no_alloc.no_user: extra_configs: @@ -57,6 +59,7 @@ tests: kernel.threads.dynamic_thread.stack.pool.alloc.no_user: extra_configs: # 110 + - CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 - CONFIG_DYNAMIC_THREAD_ALLOC=y - CONFIG_USERSPACE=n @@ -64,6 +67,7 @@ tests: tags: userspace extra_configs: # 111 + - CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y - CONFIG_DYNAMIC_THREAD_POOL_SIZE=2 - CONFIG_DYNAMIC_THREAD_ALLOC=y - CONFIG_USERSPACE=y From 4feb182f12313ab7c29b5b0e2a6433c4dc86f725 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 29 Jun 2023 15:54:20 -0700 Subject: [PATCH 1364/2042] kernel: dynamic: Fix stack allocation logic Fix the preference allocation logic. If pool is preferred but POOL_SIZE is 0 or pool allocation fails, it fallbacks to heap allocation if it is enabled. Signed-off-by: Flavio Ceolin --- kernel/dynamic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/dynamic.c b/kernel/dynamic.c index 3f628ee3be76..3c7a624f644e 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -88,14 +88,14 @@ k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) if (stack == NULL && CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { stack = z_thread_stack_alloc_pool(size); } - } else if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL) && - CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { - stack = z_thread_stack_alloc_pool(size); - if (stack == NULL && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { + } else if (IS_ENABLED(CONFIG_DYNAMIC_THREAD_PREFER_POOL)) { + if (CONFIG_DYNAMIC_THREAD_POOL_SIZE > 0) { + stack = z_thread_stack_alloc_pool(size); + } + + if ((stack == NULL) && IS_ENABLED(CONFIG_DYNAMIC_THREAD_ALLOC)) { stack = stack_alloc_dyn(size, flags); } - } else { - return NULL; } return stack; From 2b1106a407cc592cbce7d7bda146d9b99d482df3 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Fri, 14 Jul 2023 12:24:33 -0700 Subject: [PATCH 1365/2042] kernel: userspace: Use only list for dynamic objs Since the rbtree is using as list because we no longer can assume that the object pointer is the address of the data field in the dynamic object struct, lets just use the already existent dlist for tracking dynamic kernel objects. Signed-off-by: Flavio Ceolin --- kernel/userspace.c | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/kernel/userspace.c b/kernel/userspace.c index 17680d042c9b..f9a5be98a27e 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -47,7 +47,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); * not. */ #ifdef CONFIG_DYNAMIC_OBJECTS -static struct k_spinlock lists_lock; /* kobj rbtree/dlist */ +static struct k_spinlock lists_lock; /* kobj dlist */ static struct k_spinlock objfree_lock; /* k_object_free */ #ifdef CONFIG_GEN_PRIV_STACKS @@ -167,8 +167,7 @@ uint8_t *z_priv_stack_find(k_thread_stack_t *stack) struct dyn_obj_base { struct z_object kobj; - sys_dnode_t dobj_list; - struct rbnode node; /* must be immediately before data member */ + sys_dnode_t dobj_list; /* must be immediately before data member */ }; struct dyn_obj { @@ -192,16 +191,6 @@ extern struct z_object *z_object_gperf_find(const void *obj); extern void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context); -static bool node_lessthan(struct rbnode *a, struct rbnode *b); - -/* - * Red/black tree of allocated kernel objects, for reasonably fast lookups - * based on object pointer values. - */ -static struct rbtree obj_rb_tree = { - .lessthan_fn = node_lessthan -}; - /* * Linked list of allocated kernel objects, for iteration over all allocated * objects (and potentially deleting them during iteration). @@ -209,8 +198,7 @@ static struct rbtree obj_rb_tree = { static sys_dlist_t obj_list = SYS_DLIST_STATIC_INIT(&obj_list); /* - * TODO: Write some hash table code that will replace both obj_rb_tree - * and obj_list. + * TODO: Write some hash table code that will replace obj_list. */ static size_t obj_size_get(enum k_objects otype) @@ -250,15 +238,9 @@ static size_t obj_align_get(enum k_objects otype) return ret; } -static bool node_lessthan(struct rbnode *a, struct rbnode *b) -{ - return a < b; -} - static struct dyn_obj_base *dyn_object_find(void *obj) { - struct rbnode *node; - struct dyn_obj_base *ret; + struct dyn_obj_base *node; k_spinlock_key_t key; /* For any dynamically allocated kernel object, the object @@ -268,20 +250,19 @@ static struct dyn_obj_base *dyn_object_find(void *obj) */ key = k_spin_lock(&lists_lock); - RB_FOR_EACH(&obj_rb_tree, node) { - ret = CONTAINER_OF(node, struct dyn_obj_base, node); - if (ret->kobj.name == obj) { + SYS_DLIST_FOR_EACH_CONTAINER(&obj_list, node, dobj_list) { + if (node->kobj.name == obj) { goto end; } } /* No object found */ - ret = NULL; + node = NULL; end: k_spin_unlock(&lists_lock, key); - return ret; + return node; } /** @@ -407,7 +388,6 @@ static struct z_object *dynamic_object_create(enum k_objects otype, size_t align k_spinlock_key_t key = k_spin_lock(&lists_lock); - rb_insert(&obj_rb_tree, &dyn->node); sys_dlist_append(&obj_list, &dyn->dobj_list); k_spin_unlock(&lists_lock, key); @@ -502,7 +482,6 @@ void k_object_free(void *obj) dyn = dyn_object_find(obj); if (dyn != NULL) { - rb_remove(&obj_rb_tree, &dyn->node); sys_dlist_remove(&dyn->dobj_list); if (dyn->kobj.type == K_OBJ_THREAD) { @@ -612,7 +591,6 @@ static void unref_check(struct z_object *ko, uintptr_t index) break; } - rb_remove(&obj_rb_tree, &dyn->node); sys_dlist_remove(&dyn->dobj_list); k_free(dyn); out: From 1f1f550ad69e46afa1719d6b63e8273bb4b8771c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Jul 2023 14:53:56 +0200 Subject: [PATCH 1366/2042] samples: net: echo_client/server: Fix mbed TLS dependency All application level TLS operations should be guarded with "#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)" and not mbed TLS configs only. Otherwise, in case mbed TLS is enabled, but the sample is not configured to use TLS (hence TLS credential library is not available for example), the build may fail or produce spurious warnings. Signed-off-by: Robert Lubos --- samples/net/sockets/echo_client/CMakeLists.txt | 5 +++-- samples/net/sockets/echo_client/src/echo-client.c | 5 +++-- samples/net/sockets/echo_server/CMakeLists.txt | 5 +++-- samples/net/sockets/echo_server/src/echo-server.c | 13 +++++-------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/samples/net/sockets/echo_client/CMakeLists.txt b/samples/net/sockets/echo_client/CMakeLists.txt index 3222441653b3..0fe1ad126cc1 100644 --- a/samples/net/sockets/echo_client/CMakeLists.txt +++ b/samples/net/sockets/echo_client/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sockets_echo_client) -if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND - (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) +if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) add_custom_target(development_psk COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" diff --git a/samples/net/sockets/echo_client/src/echo-client.c b/samples/net/sockets/echo_client/src/echo-client.c index c211de8f3c93..a8388604ba2e 100644 --- a/samples/net/sockets/echo_client/src/echo-client.c +++ b/samples/net/sockets/echo_client/src/echo-client.c @@ -247,7 +247,6 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register public certificate: %d", err); } -#endif #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) err = tls_credential_add(PSK_TAG, @@ -264,7 +263,9 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register PSK ID: %d", err); } -#endif +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */ + if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { net_mgmt_init_event_callback(&mgmt_cb, diff --git a/samples/net/sockets/echo_server/CMakeLists.txt b/samples/net/sockets/echo_server/CMakeLists.txt index 5203e1d16408..8e01b63e70c5 100644 --- a/samples/net/sockets/echo_server/CMakeLists.txt +++ b/samples/net/sockets/echo_server/CMakeLists.txt @@ -5,8 +5,9 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sockets_echo_server) -if(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND - (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) +if(CONFIG_NET_SOCKETS_SOCKOPT_TLS AND + CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED AND + (CONFIG_NET_SAMPLE_PSK_HEADER_FILE STREQUAL "dummy_psk.h")) add_custom_target(development_psk COMMAND ${CMAKE_COMMAND} -E echo "----------------------------------------------------------" COMMAND ${CMAKE_COMMAND} -E echo "--- WARNING: Using dummy PSK! Only suitable for ---" diff --git a/samples/net/sockets/echo_server/src/echo-server.c b/samples/net/sockets/echo_server/src/echo-server.c index fbf189f898ad..7343b1e82174 100644 --- a/samples/net/sockets/echo_server/src/echo-server.c +++ b/samples/net/sockets/echo_server/src/echo-server.c @@ -135,16 +135,13 @@ static void init_app(void) ARG_UNUSED(ret); #endif -#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) || \ - defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) - int err; -#endif - k_sem_init(&quit_lock, 0, K_SEM_MAX_LIMIT); LOG_INF(APP_BANNER); #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) + int err; + #if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) err = tls_credential_add(SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE, @@ -153,7 +150,7 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register CA certificate: %d", err); } -#endif +#endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */ err = tls_credential_add(SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_SERVER_CERTIFICATE, @@ -170,7 +167,6 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register private key: %d", err); } -#endif #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) err = tls_credential_add(PSK_TAG, @@ -187,7 +183,8 @@ static void init_app(void) if (err < 0) { LOG_ERR("Failed to register PSK ID: %d", err); } -#endif +#endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */ +#endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */ if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) { net_mgmt_init_event_callback(&mgmt_cb, From 87ee12ae7238e685324a89e18c85d1af099264e2 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Jul 2023 15:24:34 +0200 Subject: [PATCH 1367/2042] samples: net: echo_client: Fix build with UDP disabled In case UDP is disabled, init_udp() is not compiled and the build fails. Fix this, by providing dummy implementations for UDP functions, in case UDP is disabled. Signed-off-by: Robert Lubos --- samples/net/sockets/echo_client/src/common.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/samples/net/sockets/echo_client/src/common.h b/samples/net/sockets/echo_client/src/common.h index debfa3fbb652..e0b06b7ee141 100644 --- a/samples/net/sockets/echo_client/src/common.h +++ b/samples/net/sockets/echo_client/src/common.h @@ -73,6 +73,7 @@ extern const char lorem_ipsum[]; extern const int ipsum_len; extern struct configs conf; +#if defined(CONFIG_NET_UDP) /* init_udp initializes kernel objects, hence it has to be called from * supervisor thread. */ @@ -80,6 +81,12 @@ void init_udp(void); int start_udp(void); int process_udp(void); void stop_udp(void); +#else +static inline void init_udp(void) { } +static inline int start_udp(void) { return 0; } +static inline int process_udp(void) { return 0; } +static inline void stop_udp(void) { } +#endif /* defined(CONFIG_NET_UDP) */ int start_tcp(void); int process_tcp(void); From c607179cc46dc260f71e7ba9e6097e0bc3004e92 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Thu, 13 Jul 2023 14:44:32 +0200 Subject: [PATCH 1368/2042] Bluetooth: Controller: Add missing nRF53x Tx Power Kconfig This commit adds missing tx power config options for nRF53x SoCs, as well as the missing Radio defines for nRF53x SoCs. Signed-off-by: Kyra Lengfeld --- subsys/bluetooth/controller/Kconfig | 37 ++++++++++++++++++- .../nordic/hal/nrf5/radio/radio_nrf5_txp.h | 14 +++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index f79332d8b41f..56314ed47326 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -324,14 +324,42 @@ config BT_CTLR_TX_PWR_PLUS_3 config BT_CTLR_TX_PWR_PLUS_2 bool "+2 dBm" - depends on HAS_HW_NRF_RADIO_TX_PWR_HIGH + depends on HAS_HW_NRF_RADIO_TX_PWR_HIGH || SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_PLUS_1 + bool "+1 dBm" + depends on SOC_SERIES_NRF53X config BT_CTLR_TX_PWR_0 bool "0 dBm" +config BT_CTLR_TX_PWR_MINUS_1 + bool "-1 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_2 + bool "-2 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_3 + bool "-3 dBm" + depends on SOC_SERIES_NRF53X + config BT_CTLR_TX_PWR_MINUS_4 bool "-4 dBm" +config BT_CTLR_TX_PWR_MINUS_5 + bool "-5 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_6 + bool "-6 dBm" + depends on SOC_SERIES_NRF53X + +config BT_CTLR_TX_PWR_MINUS_7 + bool "-7 dBm" + depends on SOC_SERIES_NRF53X + config BT_CTLR_TX_PWR_MINUS_8 bool "-8 dBm" @@ -363,8 +391,15 @@ config BT_CTLR_TX_PWR_DBM default 4 if BT_CTLR_TX_PWR_PLUS_4 default 3 if BT_CTLR_TX_PWR_PLUS_3 default 2 if BT_CTLR_TX_PWR_PLUS_2 + default 1 if BT_CTLR_TX_PWR_PLUS_1 default 0 if BT_CTLR_TX_PWR_0 + default -1 if BT_CTLR_TX_PWR_MINUS_1 + default -2 if BT_CTLR_TX_PWR_MINUS_2 + default -3 if BT_CTLR_TX_PWR_MINUS_3 default -4 if BT_CTLR_TX_PWR_MINUS_4 + default -5 if BT_CTLR_TX_PWR_MINUS_5 + default -6 if BT_CTLR_TX_PWR_MINUS_6 + default -7 if BT_CTLR_TX_PWR_MINUS_7 default -8 if BT_CTLR_TX_PWR_MINUS_8 default -12 if BT_CTLR_TX_PWR_MINUS_12 default -16 if BT_CTLR_TX_PWR_MINUS_16 diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h index a49089282f43..2eb772f20cca 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_txp.h @@ -18,10 +18,24 @@ #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos3dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_PLUS_2) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos2dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_PLUS_1) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Pos1dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_0) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_0dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_1) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg1dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_2) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg2dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_3) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg3dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_4) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg4dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_5) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg5dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_6) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg6dBm +#elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_7) +#define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg7dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_8) #define RADIO_TXP_DEFAULT RADIO_TXPOWER_TXPOWER_Neg8dBm #elif defined(CONFIG_BT_CTLR_TX_PWR_MINUS_12) From e7acd7199e26f04b6884e56a02b728a24100390d Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 17 Jul 2023 23:13:57 +0000 Subject: [PATCH 1369/2042] MAINTAINERS: fix path for native_simulator Fix syntax of path for native_simulator. Signed-off-by: Anas Nashif --- MAINTAINERS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index f5d282c09791..4c2567ec5fc2 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1794,7 +1794,7 @@ Native POSIX/Sim and POSIX arch: - drivers/*/*/*native* - dts/posix/ - include/zephyr/arch/posix/ - - scripts/native_simulator/* + - scripts/native_simulator/ - scripts/valgrind.supp - soc/posix/ - tests/boards/native_posix/ From 6f74f53efc4d4b90f2850bc0f08d5fec4aab7048 Mon Sep 17 00:00:00 2001 From: Raoul Rubien Date: Mon, 15 May 2023 08:48:17 +0200 Subject: [PATCH 1370/2042] drivers: sensors: ilps22qs: added item in kconfig The ILPS22QS sensor cannot be enabled unless USE_STDC_ILPS22QS is defined. This PR fixes #57825 add adds the missing item in Kconfig.st file. Signed-off-by: Raoul Rubien --- modules/Kconfig.st | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/Kconfig.st b/modules/Kconfig.st index 489ef12b9361..2db03e18f77c 100644 --- a/modules/Kconfig.st +++ b/modules/Kconfig.st @@ -55,6 +55,9 @@ config USE_STDC_IIS3DHHC config USE_STDC_IIS3DWB bool +config USE_STDC_ILPS22QS + bool + config USE_STDC_ISM303DAC bool From a29261c5f476832cfc350b9d68f4fd6980afb238 Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Fri, 23 Jun 2023 09:45:38 +0200 Subject: [PATCH 1371/2042] drivers/sensor: check xyz_mem_bank_set() ret value Check xyz_mem_bank_set() API return value to catch and report as soon as possible the error condition. Impacted stmemsc API: - lsm6dso_mem_bank_set() - lsm6dso16is_mem_bank_set() - lsm6dsv16x_mem_bank_set() Fix: Coverity-CID: 316212 (issue #58579) Coverity-CID: 316224 (issue #58580) Coverity-CID: 316307 (issue #58586) Signed-off-by: Armando Visconti --- drivers/sensor/lsm6dso/lsm6dso_shub.c | 11 ++++++----- drivers/sensor/lsm6dso16is/lsm6dso16is_shub.c | 11 ++++++----- drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c | 11 ++++++----- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/sensor/lsm6dso/lsm6dso_shub.c b/drivers/sensor/lsm6dso/lsm6dso_shub.c index 61903017bcfe..7c8505449b45 100644 --- a/drivers/sensor/lsm6dso/lsm6dso_shub.c +++ b/drivers/sensor/lsm6dso/lsm6dso_shub.c @@ -629,7 +629,10 @@ int lsm6dso_shub_fetch_external_devs(const struct device *dev) struct lsm6dso_shub_slist *sp; /* read data from external target */ - lsm6dso_mem_bank_set(ctx, LSM6DSO_SENSOR_HUB_BANK); + if (lsm6dso_mem_bank_set(ctx, LSM6DSO_SENSOR_HUB_BANK) < 0) { + LOG_DBG("failed to enter SENSOR_HUB bank"); + return -EIO; + } for (n = 0; n < data->num_ext_dev; n++) { sp = &lsm6dso_shub_slist[data->shub_ext[n]]; @@ -637,14 +640,12 @@ int lsm6dso_shub_fetch_external_devs(const struct device *dev) if (lsm6dso_read_reg(ctx, sp->sh_out_reg, data->ext_data[n], sp->out_data_len) < 0) { LOG_DBG("shub: failed to read sample"); - lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK); + (void) lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK); return -EIO; } } - lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK); - - return 0; + return lsm6dso_mem_bank_set(ctx, LSM6DSO_USER_BANK); } int lsm6dso_shub_config(const struct device *dev, enum sensor_channel chan, diff --git a/drivers/sensor/lsm6dso16is/lsm6dso16is_shub.c b/drivers/sensor/lsm6dso16is/lsm6dso16is_shub.c index db2b6b0fc6fd..3df5b3746926 100644 --- a/drivers/sensor/lsm6dso16is/lsm6dso16is_shub.c +++ b/drivers/sensor/lsm6dso16is/lsm6dso16is_shub.c @@ -725,7 +725,10 @@ int lsm6dso16is_shub_fetch_external_devs(const struct device *dev) struct lsm6dso16is_shub_slist *sp; /* read data from external target */ - lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_SENSOR_HUB_MEM_BANK); + if (lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_SENSOR_HUB_MEM_BANK) < 0) { + LOG_DBG("failed to enter SENSOR_HUB bank"); + return -EIO; + } for (n = 0; n < data->num_ext_dev; n++) { sp = &lsm6dso16is_shub_slist[data->shub_ext[n]]; @@ -733,14 +736,12 @@ int lsm6dso16is_shub_fetch_external_devs(const struct device *dev) if (lsm6dso16is_read_reg(ctx, sp->sh_out_reg, data->ext_data[n], sp->out_data_len) < 0) { LOG_DBG("shub: failed to read sample"); - lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_MAIN_MEM_BANK); + (void) lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_MAIN_MEM_BANK); return -EIO; } } - lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_MAIN_MEM_BANK); - - return 0; + return lsm6dso16is_mem_bank_set(ctx, LSM6DSO16IS_MAIN_MEM_BANK); } int lsm6dso16is_shub_config(const struct device *dev, enum sensor_channel chan, diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c index 5114d270a030..cb452f4f0619 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_shub.c @@ -725,7 +725,10 @@ int lsm6dsv16x_shub_fetch_external_devs(const struct device *dev) struct lsm6dsv16x_shub_slist *sp; /* read data from external target */ - lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_SENSOR_HUB_MEM_BANK); + if (lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_SENSOR_HUB_MEM_BANK) < 0) { + LOG_DBG("failed to enter SENSOR_HUB bank"); + return -EIO; + } for (n = 0; n < data->num_ext_dev; n++) { sp = &lsm6dsv16x_shub_slist[data->shub_ext[n]]; @@ -733,14 +736,12 @@ int lsm6dsv16x_shub_fetch_external_devs(const struct device *dev) if (lsm6dsv16x_read_reg(ctx, sp->sh_out_reg, data->ext_data[n], sp->out_data_len) < 0) { LOG_DBG("shub: failed to read sample"); - lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); + (void) lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); return -EIO; } } - lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); - - return 0; + return lsm6dsv16x_mem_bank_set(ctx, LSM6DSV16X_MAIN_MEM_BANK); } int lsm6dsv16x_shub_config(const struct device *dev, enum sensor_channel chan, From 97ed2b9c88900c04dab5786e9525b5ada59608cd Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 11 Jul 2023 16:46:57 +0200 Subject: [PATCH 1372/2042] west.yml: hal stm32: Update STM32Cube packages Update STM32Cube packages: update stm32c0 to cube version V1.1.0 update stm32f2 to cube version V1.9.4 update stm32h5 to cube version V1.1.0 update stm32l1 to cube version V1.10.4 update stm32u5 to cube version V1.3.0 update stm32wb to cube version V1.17.0 update stm32wba to cube version V1.1.0 Signed-off-by: Erwan Gouriou --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 018f32ce4351..5e0e49553182 100644 --- a/west.yml +++ b/west.yml @@ -219,7 +219,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 65b641345a5bfccd93de1fc21103d69c4a9ff1d6 + revision: 1bc72c299d0365c0ee2575a97918b22df0899e10 path: modules/hal/stm32 groups: - hal From 64ec7e18c88ede40283c4f714f068032d57a656b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 10:35:26 +0200 Subject: [PATCH 1373/2042] fs: nvs: doc: fix Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly document nvs_fs struct Signed-off-by: Benjamin Cabé --- include/zephyr/fs/nvs.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/include/zephyr/fs/nvs.h b/include/zephyr/fs/nvs.h index 78c18606ce14..c5a8763697b6 100644 --- a/include/zephyr/fs/nvs.h +++ b/include/zephyr/fs/nvs.h @@ -33,27 +33,29 @@ extern "C" { /** * @brief Non-volatile Storage File system structure - * - * @param offset File system offset in flash - * @param ate_wra Allocation table entry write address. Addresses are stored as uint32_t: - * high 2 bytes correspond to the sector, low 2 bytes are the offset in the sector - * @param data_wra Data write address - * @param sector_size File system is split into sectors, each sector must be multiple of pagesize - * @param sector_count Number of sectors in the file systems - * @param ready Flag indicating if the filesystem is initialized - * @param nvs_lock Mutex - * @param flash_device Flash Device runtime structure - * @param flash_parameters Flash memory parameters structure */ struct nvs_fs { + /** File system offset in flash **/ off_t offset; + /** Allocation table entry write address. + * Addresses are stored as uint32_t: + * - high 2 bytes correspond to the sector + * - low 2 bytes are the offset in the sector + */ uint32_t ate_wra; + /** Data write address */ uint32_t data_wra; + /** File system is split into sectors, each sector must be multiple of erase-block-size */ uint16_t sector_size; + /** Number of sectors in the file system */ uint16_t sector_count; + /** Flag indicating if the file system is initialized */ bool ready; + /** Mutex */ struct k_mutex nvs_lock; + /** Flash device runtime structure */ const struct device *flash_device; + /** Flash memory parameters structure */ const struct flash_parameters *flash_parameters; #if CONFIG_NVS_LOOKUP_CACHE uint32_t lookup_cache[CONFIG_NVS_LOOKUP_CACHE_SIZE]; From a4645908ee10ab40395d3866e19e86ddd1f94039 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Sun, 16 Jul 2023 12:43:52 +0200 Subject: [PATCH 1374/2042] drivers: led_pwm: fix overflow in set_brightness The set_brightness function of the led_pwm driver uses a default PWM period (defined in the pwms DT property) to compute a pulse passed to the pwm_set_pulse_dt function. If this default period is greater than 2^32/100 nanoseconds (about 43 milliseconds) then the calculation may overflow. This patch prevents this overflow by running the pulse computation under a cast with a larger type (uint64_t). Reported-by: Scott Worley Signed-off-by: Simon Guinot --- drivers/led/led_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/led/led_pwm.c b/drivers/led/led_pwm.c index 90db66bf32d9..72cb616a6e55 100644 --- a/drivers/led/led_pwm.c +++ b/drivers/led/led_pwm.c @@ -65,7 +65,7 @@ static int led_pwm_set_brightness(const struct device *dev, dt_led = &config->led[led]; return pwm_set_pulse_dt(&config->led[led], - dt_led->period * value / 100); + (uint32_t) ((uint64_t) dt_led->period * value / 100)); } static int led_pwm_on(const struct device *dev, uint32_t led) From 8b5ebc010bd9e3c76f397a424a565da2d14e2f93 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Sun, 16 Jul 2023 17:28:22 +0200 Subject: [PATCH 1375/2042] dts: bindings: pwm-leds: add description for pwms property This patch adds a description section for the pwms property of the PWM LED child node. This intends to explain how the period field is used by the led_pwm driver and to help with its configuration. Reported-by: Scott Worley Signed-off-by: Simon Guinot --- dts/bindings/led/pwm-leds.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dts/bindings/led/pwm-leds.yaml b/dts/bindings/led/pwm-leds.yaml index f8942d204573..e9e9d131ee62 100644 --- a/dts/bindings/led/pwm-leds.yaml +++ b/dts/bindings/led/pwm-leds.yaml @@ -11,6 +11,14 @@ child-binding: pwms: required: true type: phandle-array + description: | + Reference to a PWM instance. + + The period field is used by the set_brightness function of the LED API. + Its value should at least be greater that 100 nanoseconds (for a full + brigtness granularity) and lesser than 50 milliseconds (average visual + persistence time of the human eye). Typical values for the PWM period + are 10 or 20 milliseconds. label: type: string From 15a2cb5a2f191e130fd21bdbe0b2503c60331523 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Wed, 12 Jul 2023 12:33:51 +0000 Subject: [PATCH 1376/2042] drivers: intel: ssp: delay initialization after dma The SSP driver depends on DMA as there are references in the devicetree, but it currently initialize before the DMA driver itself. This is exposed by the build time priority checking (CONFIG_CHECK_INIT_PRIORITIES=y) and shows up as: ERROR: /soc/ssp@77a00 POST_KERNEL 32 < /soc/dma@7c000 POST_KERNEL 40 ERROR: /soc/ssp@77800 POST_KERNEL 32 < /soc/dma@7c000 POST_KERNEL 40 ERROR: /soc/ssp@77600 POST_KERNEL 32 < /soc/dma@7c000 POST_KERNEL 40 ... Bumping up the SSP priority so the initialization is in sync with the devicetree node hirearchy. Signed-off-by: Fabio Baltieri --- drivers/dai/intel/ssp/ssp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index f34e8aab5c72..809cc9833eb0 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -2280,7 +2280,7 @@ static const char irq_name_level5_z[] = "level5"; ssp_init, PM_DEVICE_DT_INST_GET(n), \ &dai_intel_ssp_data_##n, \ &dai_intel_ssp_config_##n, \ - POST_KERNEL, 32, \ + POST_KERNEL, 42, \ &dai_intel_ssp_api_funcs); DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_SSP_DEVICE_INIT) From c0d7218ef2d7c04a40a036d579e9da3f356924e4 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Tue, 19 Jul 2022 10:22:02 +0200 Subject: [PATCH 1377/2042] json: Skip unknown fields on parsing Skip child objects and arrays that are not specified in the given object descriptor when parsing a JSON input string. This patch adds support for extra child arrays which previously were not supported by the parser as opposed to additional child objects. Fixes #47988 Signed-off-by: Markus Fuchs --- lib/os/json.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/os/json.c b/lib/os/json.c index 801e2e11406c..2041db757e97 100644 --- a/lib/os/json.c +++ b/lib/os/json.c @@ -390,6 +390,33 @@ static int arr_next(struct json_obj *json, struct json_token *value) return element_token(value->type); } +static int skip_field(struct json_obj *obj, struct json_obj_key_value *kv) +{ + int field_count = 1; + + if (kv->value.type == JSON_TOK_OBJECT_START || + kv->value.type == JSON_TOK_ARRAY_START) { + while (field_count > 0 && lexer_next(&obj->lex, &kv->value)) { + switch (kv->value.type) { + case JSON_TOK_OBJECT_START: + case JSON_TOK_ARRAY_START: + field_count++; + break; + case JSON_TOK_OBJECT_END: + case JSON_TOK_ARRAY_END: + field_count--; + break; + case JSON_TOK_ERROR: + return -EINVAL; + default: + break; + } + } + } + + return 0; +} + static int decode_num(const struct json_token *token, int32_t *num) { /* FIXME: strtod() is not available in newlib/minimal libc, @@ -675,6 +702,14 @@ static int64_t obj_parse(struct json_obj *obj, const struct json_obj_descr *desc decoded_fields |= (int64_t)1<= descr_len) { + ret = skip_field(obj, &kv); + if (ret < 0) { + return ret; + } + } } return -EINVAL; From 84df63538437ecd32507a31c1e35f9d7e3340353 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Tue, 19 Jul 2022 10:34:02 +0200 Subject: [PATCH 1378/2042] tests: lib: json: Add tests for parsing inputs with extra fields Add tests for both extra objects and extra arrays nested in JSON objects. Fields in extra nested objects should be ignored and also not manipulate subsequent fields with the same name. Signed-off-by: Markus Fuchs --- tests/lib/json/src/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index 4bab23d92908..f0ebce6f03ca 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -198,8 +198,11 @@ ZTEST(lib_json_test, test_json_decoding) "\"some_nested_struct\":{ " "\"nested_int\":-1234,\n\n" "\"nested_bool\":false,\t" - "\"nested_string\":\"this should be escaped: \\t\"}," - "\"some_array\":[11,22, 33,\t45,\n299]" + "\"nested_string\":\"this should be escaped: \\t\"," + "\"extra_nested_array\":[0,-1]}," + "\"extra_struct\":{\"nested_bool\":false}," + "\"extra_bool\":true," + "\"some_array\":[11,22, 33,\t45,\n299]," "\"another_b!@l\":true," "\"if\":false," "\"another-array\":[2,3,5,7]," From b140b70a170f28793afbe9bc20bdb7bad20e797d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 8 Jun 2023 15:36:51 +0200 Subject: [PATCH 1379/2042] tests: CAP: Add testing of all audio configs Add test cases to test all audio configurations with all presets. Signed-off-by: Emil Gydesen --- subsys/bluetooth/host/iso.c | 2 + tests/bsim/bluetooth/audio/prj.conf | 27 +- .../bluetooth/audio/src/cap_acceptor_test.c | 15 +- .../audio/src/cap_initiator_unicast_test.c | 1062 ++++++++++++++++- tests/bsim/bluetooth/audio/src/common.c | 4 +- .../bsim/bluetooth/audio/test_scripts/_cap.sh | 21 +- .../audio/test_scripts/cap_unicast_ac_1.sh | 50 + .../audio/test_scripts/cap_unicast_ac_10.sh | 50 + .../audio/test_scripts/cap_unicast_ac_11_i.sh | 50 + .../test_scripts/cap_unicast_ac_11_ii.sh | 54 + .../audio/test_scripts/cap_unicast_ac_2.sh | 51 + .../audio/test_scripts/cap_unicast_ac_3.sh | 51 + .../audio/test_scripts/cap_unicast_ac_4.sh | 48 + .../audio/test_scripts/cap_unicast_ac_5.sh | 49 + .../audio/test_scripts/cap_unicast_ac_6_i.sh | 48 + .../audio/test_scripts/cap_unicast_ac_6_ii.sh | 54 + .../audio/test_scripts/cap_unicast_ac_7_i.sh | 50 + .../audio/test_scripts/cap_unicast_ac_7_ii.sh | 54 + .../audio/test_scripts/cap_unicast_ac_8_i.sh | 50 + .../audio/test_scripts/cap_unicast_ac_8_ii.sh | 54 + .../audio/test_scripts/cap_unicast_ac_9_i.sh | 50 + .../audio/test_scripts/cap_unicast_ac_9_ii.sh | 54 + 22 files changed, 1908 insertions(+), 40 deletions(-) create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_ii.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_i.sh create mode 100755 tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_ii.sh diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 1df70878c50b..0dd182fd2bd5 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -329,6 +329,7 @@ static int bt_iso_setup_data_path(struct bt_iso_chan *chan) dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR; err = hci_le_setup_iso_data_path(iso, dir, in_path); if (err) { + LOG_DBG("Failed to setup host-to-ctrl path: %d", err); return err; } } @@ -338,6 +339,7 @@ static int bt_iso_setup_data_path(struct bt_iso_chan *chan) dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST; err = hci_le_setup_iso_data_path(iso, dir, out_path); if (err) { + LOG_DBG("Failed to setup ctlr-to-host path: %d", err); return err; } } diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index c70248cd5128..a014159a2a68 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -13,11 +13,14 @@ CONFIG_BT_MAX_CONN=5 CONFIG_BT_MAX_PAIRED=5 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_AUDIO=y CONFIG_BT_BAP_UNICAST_SERVER=y CONFIG_BT_BAP_UNICAST_CLIENT=y -CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=2 +CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT=4 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT=2 CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT=2 CONFIG_BT_ASCS_ASE_SNK_COUNT=2 @@ -30,7 +33,11 @@ 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_ISO_TX_BUF_COUNT=4 -CONFIG_BT_ISO_MAX_CHAN=2 +CONFIG_BT_ISO_MAX_CHAN=4 +CONFIG_BT_ISO_TX_MTU=310 +CONFIG_BT_ISO_RX_MTU=310 + +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n # Needed for Periodic Advertising Sync Transfer CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y @@ -164,8 +171,7 @@ CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_BT_CTLR_ADV_ISO=y CONFIG_BT_CTLR_SYNC_ISO=y CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=255 -# Supports the highest SDU size required by any BAP LC3 presets (155) -CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=251 CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=1 CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=1 @@ -173,5 +179,18 @@ CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=1 # Controller Connected ISO configs CONFIG_BT_CTLR_CENTRAL_ISO=y CONFIG_BT_CTLR_PERIPHERAL_ISO=y +CONFIG_BT_CTLR_ISOAL_SOURCES=2 +CONFIG_BT_CTLR_ISOAL_SINKS=2 +CONFIG_BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY=y CONFIG_BT_CTLR_ISO_TX_BUFFERS=3 + +# Controller advanced options +CONFIG_BT_CTLR_ADVANCED_FEATURES=y +CONFIG_BT_CTLR_ADV_RESERVE_MAX=n +CONFIG_BT_CTLR_CENTRAL_RESERVE_MAX=n +CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE=n +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 diff --git a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c index 4b15da29299a..71f554d92297 100644 --- a/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_acceptor_test.c @@ -15,10 +15,10 @@ extern enum bst_result_t bst_result; -#define SINK_CONTEXT BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ - BT_AUDIO_CONTEXT_TYPE_MEDIA | \ - BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL -#define SOURCE_CONTEXT BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS +#define SINK_CONTEXT \ + (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL) +#define SOURCE_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS) CREATE_FLAG(flag_broadcaster_found); CREATE_FLAG(flag_base_received); @@ -531,6 +531,13 @@ static void init(void) return; } + err = bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &unicast_cap); + if (err != 0) { + FAIL("Broadcast 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", 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 4d3698bd7128..923e54a9e28e 100644 --- a/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c +++ b/tests/bsim/bluetooth/audio/src/cap_initiator_unicast_test.c @@ -11,16 +11,59 @@ #include #include #include +#include #include "common.h" #include "bap_unicast_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 CAP_AC_MAX_CONN 2U +#define CAP_AC_MAX_SNK (2U * CAP_AC_MAX_CONN) +#define CAP_AC_MAX_SRC (2U * CAP_AC_MAX_CONN) +#define CAP_AC_MAX_PAIR MAX(CAP_AC_MAX_SNK, CAP_AC_MAX_SRC) +#define CAP_AC_MAX_STREAM (CAP_AC_MAX_SNK + CAP_AC_MAX_SRC) + +#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; + size_t snk_cnt[CAP_AC_MAX_CONN]; + size_t src_cnt[CAP_AC_MAX_CONN]; + size_t snk_chan_cnt; + size_t src_chan_cnt; + const struct named_lc3_preset *snk_named_preset; + const struct named_lc3_preset *src_named_preset; +}; + extern enum bst_result_t bst_result; static struct bt_bap_lc3_preset unicast_preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1( BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED); static struct bt_cap_stream unicast_client_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; -static struct bt_bap_ep *unicast_sink_eps[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct bt_bap_ep + *unicast_sink_eps[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +static struct bt_bap_ep + *unicast_source_eps[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; +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; CREATE_FLAG(flag_discovered); CREATE_FLAG(flag_codec_found); @@ -31,6 +74,43 @@ CREATE_FLAG(flag_updated); CREATE_FLAG(flag_stopped); CREATE_FLAG(flag_mtu_exchanged); CREATE_FLAG(flag_sink_discovered); +CREATE_FLAG(flag_source_discovered); + +static const struct named_lc3_preset lc3_unicast_presets[] = { + {"8_1_1", BT_BAP_LC3_UNICAST_PRESET_8_1_1(LOCATION, CONTEXT)}, + {"8_2_1", BT_BAP_LC3_UNICAST_PRESET_8_2_1(LOCATION, CONTEXT)}, + {"16_1_1", BT_BAP_LC3_UNICAST_PRESET_16_1_1(LOCATION, CONTEXT)}, + {"16_2_1", BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)}, + {"24_1_1", BT_BAP_LC3_UNICAST_PRESET_24_1_1(LOCATION, CONTEXT)}, + {"24_2_1", BT_BAP_LC3_UNICAST_PRESET_24_2_1(LOCATION, CONTEXT)}, + {"32_1_1", BT_BAP_LC3_UNICAST_PRESET_32_1_1(LOCATION, CONTEXT)}, + {"32_2_1", BT_BAP_LC3_UNICAST_PRESET_32_2_1(LOCATION, CONTEXT)}, + {"441_1_1", BT_BAP_LC3_UNICAST_PRESET_441_1_1(LOCATION, CONTEXT)}, + {"441_2_1", BT_BAP_LC3_UNICAST_PRESET_441_2_1(LOCATION, CONTEXT)}, + {"48_1_1", BT_BAP_LC3_UNICAST_PRESET_48_1_1(LOCATION, CONTEXT)}, + {"48_2_1", BT_BAP_LC3_UNICAST_PRESET_48_2_1(LOCATION, CONTEXT)}, + {"48_3_1", BT_BAP_LC3_UNICAST_PRESET_48_3_1(LOCATION, CONTEXT)}, + {"48_4_1", BT_BAP_LC3_UNICAST_PRESET_48_4_1(LOCATION, CONTEXT)}, + {"48_5_1", BT_BAP_LC3_UNICAST_PRESET_48_5_1(LOCATION, CONTEXT)}, + {"48_6_1", BT_BAP_LC3_UNICAST_PRESET_48_6_1(LOCATION, CONTEXT)}, + /* High-reliability presets */ + {"8_1_2", BT_BAP_LC3_UNICAST_PRESET_8_1_2(LOCATION, CONTEXT)}, + {"8_2_2", BT_BAP_LC3_UNICAST_PRESET_8_2_2(LOCATION, CONTEXT)}, + {"16_1_2", BT_BAP_LC3_UNICAST_PRESET_16_1_2(LOCATION, CONTEXT)}, + {"16_2_2", BT_BAP_LC3_UNICAST_PRESET_16_2_2(LOCATION, CONTEXT)}, + {"24_1_2", BT_BAP_LC3_UNICAST_PRESET_24_1_2(LOCATION, CONTEXT)}, + {"24_2_2", BT_BAP_LC3_UNICAST_PRESET_24_2_2(LOCATION, CONTEXT)}, + {"32_1_2", BT_BAP_LC3_UNICAST_PRESET_32_1_2(LOCATION, CONTEXT)}, + {"32_2_2", BT_BAP_LC3_UNICAST_PRESET_32_2_2(LOCATION, CONTEXT)}, + {"441_1_2", BT_BAP_LC3_UNICAST_PRESET_441_1_2(LOCATION, CONTEXT)}, + {"441_2_2", BT_BAP_LC3_UNICAST_PRESET_441_2_2(LOCATION, CONTEXT)}, + {"48_1_2", BT_BAP_LC3_UNICAST_PRESET_48_1_2(LOCATION, CONTEXT)}, + {"48_2_2", BT_BAP_LC3_UNICAST_PRESET_48_2_2(LOCATION, CONTEXT)}, + {"48_3_2", BT_BAP_LC3_UNICAST_PRESET_48_3_2(LOCATION, CONTEXT)}, + {"48_4_2", BT_BAP_LC3_UNICAST_PRESET_48_4_2(LOCATION, CONTEXT)}, + {"48_5_2", BT_BAP_LC3_UNICAST_PRESET_48_5_2(LOCATION, CONTEXT)}, + {"48_6_2", BT_BAP_LC3_UNICAST_PRESET_48_6_2(LOCATION, CONTEXT)}, +}; static void unicast_stream_configured(struct bt_bap_stream *stream, const struct bt_audio_codec_qos_pref *pref) @@ -154,12 +234,29 @@ static struct bt_cap_initiator_cb cap_cb = { .unicast_stop_complete = unicast_stop_complete_cb, }; -static void add_remote_sink(struct bt_bap_ep *ep) +static void add_remote_sink(const struct bt_conn *conn, struct bt_bap_ep *ep) { - for (size_t i = 0U; i < ARRAY_SIZE(unicast_sink_eps); i++) { - if (unicast_sink_eps[i] == NULL) { - printk("Sink #%zu: ep %p\n", i, ep); - unicast_sink_eps[i] = ep; + const uint8_t conn_index = bt_conn_index(conn); + + for (size_t i = 0U; i < ARRAY_SIZE(unicast_sink_eps[conn_index]); i++) { + if (unicast_sink_eps[conn_index][i] == NULL) { + printk("Conn[%u] %p: Sink #%zu: ep %p\n", conn_index, conn, i, ep); + unicast_sink_eps[conn_index][i] = ep; + return; + } + } + + FAIL("Could not add sink ep\n"); +} + +static void add_remote_source(const struct bt_conn *conn, struct bt_bap_ep *ep) +{ + const uint8_t conn_index = bt_conn_index(conn); + + for (size_t i = 0U; i < ARRAY_SIZE(unicast_source_eps[conn_index]); i++) { + if (unicast_source_eps[conn_index][i] == NULL) { + printk("Conn[%u] %p: Source #%zu: ep %p\n", conn_index, conn, i, ep); + unicast_source_eps[conn_index][i] = ep; return; } } @@ -181,22 +278,33 @@ static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir, SET_FLAG(flag_codec_found); } -static void discover_sink_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) +static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) { if (err != 0) { FAIL("Discovery failed: %d\n", err); return; } - printk("Sink discover complete\n"); + 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_sink_discovered); + SET_FLAG(flag_source_discovered); + } else { + FAIL("Invalid dir: %u\n", dir); + } } static void 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); + add_remote_sink(conn, ep); + SET_FLAG(flag_endpoint_found); + } else if (dir == BT_AUDIO_DIR_SOURCE) { + add_remote_source(conn, ep); SET_FLAG(flag_endpoint_found); } else { FAIL("Invalid param dir: %u\n", dir); @@ -204,7 +312,7 @@ static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_b } static const struct bt_bap_unicast_client_cb unicast_client_cbs = { - .discover = discover_sink_cb, + .discover = discover_cb, .pac_record = pac_record_cb, .endpoint = endpoint_cb, }; @@ -248,11 +356,56 @@ static void init(void) } } +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; - err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + 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; @@ -260,30 +413,54 @@ static void scan_and_connect(void) printk("Scanning successfully started\n"); WAIT_FOR_FLAG(flag_connected); + connected_conn_cnt++; } -static void discover_sink(void) +static void discover_sink(struct bt_conn *conn) { + const uint8_t conn_index = bt_conn_index(conn); int err; UNSET_FLAG(flag_sink_discovered); UNSET_FLAG(flag_codec_found); UNSET_FLAG(flag_endpoint_found); - err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK); + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK); if (err != 0) { printk("Failed to discover sink: %d\n", err); return; } - memset(unicast_sink_eps, 0, sizeof(unicast_sink_eps)); + memset(unicast_sink_eps[conn_index], 0, sizeof(unicast_sink_eps[conn_index])); WAIT_FOR_FLAG(flag_sink_discovered); WAIT_FOR_FLAG(flag_endpoint_found); WAIT_FOR_FLAG(flag_codec_found); } -static void discover_cas_inval(void) +static void discover_source(struct bt_conn *conn) +{ + const uint8_t conn_index = bt_conn_index(conn); + int err; + + UNSET_FLAG(flag_source_discovered); + UNSET_FLAG(flag_codec_found); + UNSET_FLAG(flag_endpoint_found); + + err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE); + if (err != 0) { + printk("Failed to discover sink: %d\n", err); + return; + } + + memset(unicast_source_eps[conn_index], 0, sizeof(unicast_source_eps[conn_index])); + + WAIT_FOR_FLAG(flag_source_discovered); + WAIT_FOR_FLAG(flag_endpoint_found); + WAIT_FOR_FLAG(flag_codec_found); +} + +static void discover_cas_inval(struct bt_conn *conn) { int err; @@ -296,13 +473,13 @@ static void discover_cas_inval(void) /* Test if it handles concurrent request for same connection */ UNSET_FLAG(flag_discovered); - err = bt_cap_initiator_unicast_discover(default_conn); + err = bt_cap_initiator_unicast_discover(conn); if (err != 0) { printk("Failed to discover CAS: %d\n", err); return; } - err = bt_cap_initiator_unicast_discover(default_conn); + err = bt_cap_initiator_unicast_discover(conn); if (err == 0) { FAIL("bt_cap_initiator_unicast_discover while previous discovery has not completed " "did not fail\n"); @@ -312,13 +489,13 @@ static void discover_cas_inval(void) WAIT_FOR_FLAG(flag_discovered); } -static void discover_cas(void) +static void discover_cas(struct bt_conn *conn) { int err; UNSET_FLAG(flag_discovered); - err = bt_cap_initiator_unicast_discover(default_conn); + err = bt_cap_initiator_unicast_discover(conn); if (err != 0) { printk("Failed to discover CAS: %d\n", err); return; @@ -366,7 +543,7 @@ static void unicast_audio_start_inval(struct bt_bap_unicast_group *unicast_group valid_stream_param.member.member = default_conn; valid_stream_param.stream = &unicast_client_streams[0]; - valid_stream_param.ep = unicast_sink_eps[0]; + valid_stream_param.ep = unicast_sink_eps[bt_conn_index(default_conn)][0]; valid_stream_param.codec_cfg = &unicast_preset_16_2_1.codec_cfg; valid_stream_param.qos = &unicast_preset_16_2_1.qos; @@ -482,7 +659,7 @@ static void unicast_audio_start(struct bt_bap_unicast_group *unicast_group, bool param.stream_params = stream_param; stream_param[0].member.member = default_conn; stream_param[0].stream = &unicast_client_streams[0]; - stream_param[0].ep = unicast_sink_eps[0]; + stream_param[0].ep = unicast_sink_eps[bt_conn_index(default_conn)][0]; stream_param[0].codec_cfg = &unicast_preset_16_2_1.codec_cfg; stream_param[0].qos = &unicast_preset_16_2_1.qos; @@ -640,9 +817,9 @@ static void test_main_cap_initiator_unicast(void) WAIT_FOR_FLAG(flag_mtu_exchanged); - discover_cas(); + discover_cas(default_conn); - discover_sink(); + discover_sink(default_conn); for (size_t i = 0U; i < iterations; i++) { unicast_group_create(&unicast_group); @@ -672,10 +849,10 @@ static void test_main_cap_initiator_unicast_inval(void) WAIT_FOR_FLAG(flag_mtu_exchanged); - discover_cas_inval(); - discover_cas(); + discover_cas_inval(default_conn); + discover_cas(default_conn); - discover_sink(); + discover_sink(default_conn); unicast_group_create(&unicast_group); @@ -707,9 +884,9 @@ static void test_cap_initiator_unicast_timeout(void) WAIT_FOR_FLAG(flag_mtu_exchanged); - discover_cas(); + discover_cas(default_conn); - discover_sink(); + discover_sink(default_conn); unicast_group_create(&unicast_group); @@ -734,6 +911,721 @@ 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) +{ + for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) { + if (strcmp(preset_arg, lc3_unicast_presets[i].name) == 0) { + return &lc3_unicast_presets[i]; + } + } + + 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)); + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + /* Need to update the `bt_data.data` pointer to the new value after copying the codec */ + for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.data); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.data[i]; + struct bt_audio_codec_data *data = &stream->codec_cfg.data[i]; + const uint8_t data_len = preset_data->data.data_len; + + data->data.data = data->value; + data->data.data_len = data_len; + memcpy(data->value, preset_data->data.data, data_len); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 \ + */ + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + for (size_t i = 0U; i < ARRAY_SIZE(stream->codec_cfg.meta); i++) { + const struct bt_audio_codec_data *preset_data = + &named_preset->preset.codec_cfg.meta[i]; + struct bt_audio_codec_data *data = &stream->codec_cfg.meta[i]; + const uint8_t data_len = preset_data->data.data_len; + + data->data.data = data->value; + data->data.data_len = data_len; + memcpy(data->value, preset_data->data.data, data_len); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > \ + * 0 \ + */ +} + +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, + 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[CAP_AC_MAX_SNK] = {0}; + struct bt_bap_unicast_group_stream_param src_group_stream_params[CAP_AC_MAX_SRC] = {0}; + struct bt_bap_unicast_group_stream_pair_param pair_params[CAP_AC_MAX_PAIR] = {0}; + struct bt_bap_unicast_group_param group_param = {0}; + struct bt_audio_codec_qos *snk_qos[CAP_AC_MAX_SNK]; + struct bt_audio_codec_qos *src_qos[CAP_AC_MAX_SRC]; + size_t snk_stream_cnt = 0U; + size_t src_stream_cnt = 0U; + size_t pair_cnt = 0U; + + for (size_t i = 0U; i < snk_cnt; i++) { + snk_qos[i] = &snk_uni_streams[i]->qos; + } + + for (size_t i = 0U; i < src_cnt; i++) { + src_qos[i] = &src_uni_streams[i]->qos; + } + + /* 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_qos[i]; + 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_qos[i]; + 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 set_chan_alloc(enum bt_audio_location loc, struct bt_audio_codec_cfg *codec_cfg) +{ + for (size_t i = 0U; i < codec_cfg->data_count; i++) { + struct bt_audio_codec_data *data = &codec_cfg->data[i]; + + /* Overwrite the location value */ + if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { + const uint32_t loc_32 = loc; + + sys_put_le32(loc_32, data->value); + + break; + } + } + + return 0; +} + +static int cap_initiator_ac_cap_unicast_start(const struct cap_initiator_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[CAP_AC_MAX_STREAM] = {0}; + struct bt_audio_codec_cfg *snk_codec_cfgs[CAP_AC_MAX_SNK] = {0}; + struct bt_audio_codec_cfg *src_codec_cfgs[CAP_AC_MAX_SRC] = {0}; + struct bt_cap_stream *snk_cap_streams[CAP_AC_MAX_SNK] = {0}; + struct bt_cap_stream *src_cap_streams[CAP_AC_MAX_SRC] = {0}; + struct bt_cap_unicast_audio_start_param start_param = {0}; + struct bt_audio_codec_qos *snk_qos[CAP_AC_MAX_SNK] = {0}; + struct bt_audio_codec_qos *src_qos[CAP_AC_MAX_SRC] = {0}; + struct bt_bap_ep *snk_eps[CAP_AC_MAX_SNK] = {0}; + struct bt_bap_ep *src_eps[CAP_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++) { + const uint8_t conn_index = bt_conn_index(connected_conns[i]); +#if UNICAST_SINK_SUPPORTED + for (size_t j = 0U; j < param->snk_cnt[i]; j++) { + snk_eps[snk_ep_cnt] = unicast_sink_eps[conn_index][j]; + if (snk_eps[snk_ep_cnt] == NULL) { + FAIL("No sink[%u][%zu] endpoint available\n", conn_index, 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] = unicast_source_eps[conn_index][j]; + if (src_eps[src_ep_cnt] == NULL) { + FAIL("No source[%u][%zu] endpoint available\n", conn_index, 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_qos[i] = &snk_uni_streams[i]->qos; + 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_qos[i] = &src_uni_streams[i]->qos; + 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->qos = snk_qos[snk_stream_cnt]; + stream_param->stream = snk_cap_streams[snk_stream_cnt]; + + snk_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + set_chan_alloc(BIT(i), stream_param->codec_cfg); + } + } + + 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->qos = src_qos[src_stream_cnt]; + stream_param->stream = src_cap_streams[src_stream_cnt]; + + src_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + set_chan_alloc(BIT(i), stream_param->codec_cfg); + } + } + } + + 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 cap_initiator_ac_unicast(const struct cap_initiator_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[CAP_AC_MAX_SNK]; + struct unicast_stream *src_uni_streams[CAP_AC_MAX_SRC]; + size_t snk_cnt = 0; + size_t src_cnt = 0; + int err; + + if (param->conn_cnt > CAP_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] > CAP_AC_MAX_SNK) { + FAIL("Invalid param->snk_cnt[%zu]: %zu\n", i, param->snk_cnt[i]); + + return -EINVAL; + } + + if (param->src_cnt[i] > CAP_AC_MAX_SRC) { + FAIL("Invalid param->src_cnt[%zu]: %zu\n", i, param->src_cnt[i]); + + return -EINVAL; + } + } + + /* Set all endpoints from multiple connections in a single array, and verify that the known + * endpoints matches the audio configuration + */ + 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]; + + if (param->snk_named_preset == NULL) { + FAIL("No sink preset available\n"); + return -EINVAL; + } + + 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]; + + if (param->src_named_preset == NULL) { + FAIL("No sink preset available\n"); + return -EINVAL; + } + + copy_unicast_stream_preset(src_uni_streams[i], param->src_named_preset); + + /* Some audio configuration requires multiple source channels, + * so multiply the SDU based on the channel count + */ + src_uni_streams[i]->qos.sdu *= param->src_chan_cnt; + } + + err = cap_initiator_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 = cap_initiator_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 test_cap_initiator_ac(const struct cap_initiator_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 > CAP_AC_MAX_CONN) { + FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt); + return; + } + + if (param->snk_named_preset == NULL && param->src_named_preset == NULL) { + FAIL("No presets available\n"); + 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]); + } + } + + cap_initiator_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("CAP initiator 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_cap_initiator_ac_1(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_1", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_2(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_2", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {1U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + .snk_named_preset = NULL, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_3(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_3", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_4(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_4", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {0U}, + .snk_chan_cnt = 2U, + .src_chan_cnt = 0U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_5(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_5", + .conn_cnt = 1U, + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 2U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_6_i(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_6_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_6_ii(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_6_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 1U}, + .src_cnt = {0U, 0U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 0U, + .snk_named_preset = snk_named_preset, + .src_named_preset = NULL, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_7_i(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_7_i", + .conn_cnt = 1U, + /* TODO: These should be in different CIS but will be in the same currently */ + .snk_cnt = {1U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_7_ii(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_7_ii", + .conn_cnt = 2U, + .snk_cnt = {1U, 0U}, + .src_cnt = {0U, 1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_8_i(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_8_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_8_ii(void) +{ + const struct cap_initiator_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, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_9_i(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_9_i", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {2U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + .snk_named_preset = NULL, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_9_ii(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_9_ii", + .conn_cnt = 2U, + .snk_cnt = {0U, 0U}, + .src_cnt = {1U, 1U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + .snk_named_preset = NULL, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} +static void test_cap_initiator_ac_10(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_10", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {1U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 2U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_11_i(void) +{ + const struct cap_initiator_ac_param param = { + .name = "ac_11_i", + .conn_cnt = 1U, + .snk_cnt = {2U}, + .src_cnt = {2U}, + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶m); +} + +static void test_cap_initiator_ac_11_ii(void) +{ + const struct cap_initiator_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, + .snk_named_preset = snk_named_preset, + .src_named_preset = src_named_preset, + }; + + test_cap_initiator_ac(¶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) { + const char *preset_arg = argv[++argn]; + + snk_named_preset = cap_get_named_preset(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 = cap_get_named_preset(preset_arg); + if (src_named_preset == NULL) { + FAIL("Failed to get source preset from %s\n", preset_arg); + } + } else { + FAIL("Invalid arg: %s\n", arg); + } + } +} + static const struct bst_test_instance test_cap_initiator_unicast[] = { { .test_id = "cap_initiator_unicast", @@ -753,6 +1645,118 @@ static const struct bst_test_instance test_cap_initiator_unicast[] = { .test_tick_f = test_tick, .test_main_f = test_main_cap_initiator_unicast_inval, }, + { + .test_id = "cap_initiator_ac_1", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_1, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_2", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_2, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_3", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_3, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_4", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_4, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_5", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_5, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_6_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_6_i, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_6_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_6_ii, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_7_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_7_i, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_7_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_7_ii, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_8_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_8_i, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_8_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_8_ii, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_9_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_9_i, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_9_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_9_ii, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_10", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_10, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_11_i", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_11_i, + .test_args_f = test_args, + }, + { + .test_id = "cap_initiator_ac_11_ii", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_cap_initiator_ac_11_ii, + .test_args_f = test_args, + }, BSTEST_END_MARKER, }; diff --git a/tests/bsim/bluetooth/audio/src/common.c b/tests/bsim/bluetooth/audio/src/common.c index 3bac03064caa..30758e01732d 100644 --- a/tests/bsim/bluetooth/audio/src/common.c +++ b/tests/bsim/bluetooth/audio/src/common.c @@ -67,7 +67,7 @@ static void connected(struct bt_conn *conn, uint8_t err) bt_conn_unref(default_conn); default_conn = NULL; - FAIL("Failed to connect to %s (%u)\n", addr, err); + FAIL("Failed to connect to %s (0x%02x)\n", addr, err); return; } @@ -85,7 +85,7 @@ void disconnected(struct bt_conn *conn, uint8_t reason) bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - printk("Disconnected: %s (reason %u)\n", addr, reason); + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); bt_conn_unref(default_conn); default_conn = NULL; diff --git a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh index 622a32d0373f..2afa116b8891 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/_cap.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/_cap.sh @@ -1,13 +1,32 @@ #!/usr/bin/env bash # -# Copyright (c) 2022 Nordic Semiconductor ASA +# Copyright (c) 2022-2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 dir_path=$(dirname "$0") +set -e # Exit on error + $dir_path/cap_unicast_inval.sh $dir_path/cap_unicast.sh $dir_path/cap_broadcast.sh + +$dir_path/cap_unicast_ac_1.sh +$dir_path/cap_unicast_ac_2.sh +$dir_path/cap_unicast_ac_3.sh +$dir_path/cap_unicast_ac_4.sh +$dir_path/cap_unicast_ac_5.sh +$dir_path/cap_unicast_ac_6_i.sh +$dir_path/cap_unicast_ac_6_ii.sh +$dir_path/cap_unicast_ac_7_i.sh +$dir_path/cap_unicast_ac_7_ii.sh +$dir_path/cap_unicast_ac_8_i.sh +$dir_path/cap_unicast_ac_8_ii.sh +$dir_path/cap_unicast_ac_9_i.sh +$dir_path/cap_unicast_ac_9_ii.sh +$dir_path/cap_unicast_ac_10.sh +$dir_path/cap_unicast_ac_11_i.sh +$dir_path/cap_unicast_ac_11_ii.sh diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh new file mode 100755 index 000000000000..b7b52002c7da --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_1.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP 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=cap_initiator_ac_1 \ + -RealEncryption=1 -rs=23 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 8_1_1 +Execute_AC_1 8_2_1 +Execute_AC_1 16_1_1 +Execute_AC_1 16_2_1 +Execute_AC_1 24_1_1 +Execute_AC_1 24_2_1 +Execute_AC_1 32_1_1 +Execute_AC_1 32_2_1 +# Execute_AC_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_1 48_1_1 +Execute_AC_1 48_2_1 +Execute_AC_1 48_3_1 +Execute_AC_1 48_4_1 +Execute_AC_1 48_5_1 +Execute_AC_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh new file mode 100755 index 000000000000..c1a3a90b51fd --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_10.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_10" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_10() { + printf "\n\n======== Running CAP AC_10 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_10 \ + -RealEncryption=1 -rs=23 -argstest source_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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_10 8_1_1 +Execute_AC_10 8_2_1 +Execute_AC_10 16_1_1 +Execute_AC_10 16_2_1 +Execute_AC_10 24_1_1 +Execute_AC_10 24_2_1 +Execute_AC_10 32_1_1 +Execute_AC_10 32_2_1 +# Execute_AC_10 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_10 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_10 48_1_1 +Execute_AC_10 48_2_1 +Execute_AC_10 48_3_1 +Execute_AC_10 48_4_1 +Execute_AC_10 48_5_1 +Execute_AC_10 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh new file mode 100755 index 000000000000..e2cb567d185b --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_i.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_11_I 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_11_i \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 8_1_1 8_1_1 +Execute_AC_11_I 8_2_1 8_2_1 +Execute_AC_11_I 16_1_1 16_1_1 +Execute_AC_11_I 16_2_1 16_2_1 +Execute_AC_11_I 24_1_1 24_1_1 +Execute_AC_11_I 24_2_1 24_2_1 +Execute_AC_11_I 32_1_1 32_1_1 +Execute_AC_11_I 32_2_1 32_2_1 +# Execute_AC_11_I 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_11_I 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_11_I 48_1_1 48_1_1 +Execute_AC_11_I 48_2_1 48_2_1 +Execute_AC_11_I 48_3_1 48_3_1 +Execute_AC_11_I 48_4_1 48_4_1 +# Execute_AC_11_I 48_5_1 48_5_1 # ASSERTION FAIL [c_latency <= cig->c_latency] +Execute_AC_11_I 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh new file mode 100755 index 000000000000..a1f194d92b40 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_11_ii.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_11_II 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_11_ii \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=69 + + # 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 8_1_1 8_1_1 +Execute_AC_11_II 8_2_1 8_2_1 +Execute_AC_11_II 16_1_1 16_1_1 +Execute_AC_11_II 16_2_1 16_2_1 +Execute_AC_11_II 24_1_1 24_1_1 +Execute_AC_11_II 24_2_1 24_2_1 +Execute_AC_11_II 32_1_1 32_1_1 +Execute_AC_11_II 32_2_1 32_2_1 +# Execute_AC_11_II 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_11_II 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_11_II 48_1_1 48_1_1 +Execute_AC_11_II 48_2_1 48_2_1 +Execute_AC_11_II 48_3_1 48_3_1 +Execute_AC_11_II 48_4_1 48_4_1 +# Execute_AC_11_II 48_5_1 48_5_1 # Controller assert: ASSERTION FAIL [c_latency <= cig->c_latency] +Execute_AC_11_II 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh new file mode 100755 index 000000000000..cb6b9e8d4277 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_2.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP 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=cap_initiator_ac_2 \ + -RealEncryption=1 -rs=23 -argstest source_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 8_1_1 +Execute_AC_2 8_2_1 +Execute_AC_2 16_1_1 +Execute_AC_2 16_2_1 +Execute_AC_2 24_1_1 +Execute_AC_2 24_2_1 +Execute_AC_2 32_1_1 +Execute_AC_2 32_2_1 +# Execute_AC_2 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_2 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_2 48_1_1 +Execute_AC_2 48_2_1 +Execute_AC_2 48_3_1 +Execute_AC_2 48_4_1 +Execute_AC_2 48_5_1 +Execute_AC_2 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh new file mode 100755 index 000000000000..9c303b768e60 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_3.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_3 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_3 \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 8_1_1 8_1_1 +Execute_AC_3 8_2_1 8_2_1 +Execute_AC_3 16_1_1 16_1_1 +Execute_AC_3 16_2_1 16_2_1 +Execute_AC_3 24_1_1 24_1_1 +Execute_AC_3 24_2_1 24_2_1 +Execute_AC_3 32_1_1 32_1_1 +Execute_AC_3 32_2_1 32_2_1 +# Execute_AC_3 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_3 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_3 48_1_1 48_1_1 +Execute_AC_3 48_2_1 48_2_1 +Execute_AC_3 48_3_1 48_3_1 +Execute_AC_3 48_4_1 48_4_1 +Execute_AC_3 48_5_1 48_5_1 +Execute_AC_3 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh new file mode 100755 index 000000000000..85ab40eaae07 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_4.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP 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=cap_initiator_ac_4 \ + -RealEncryption=1 -rs=23 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 +} + +Execute_AC_4 8_1_1 +Execute_AC_4 8_2_1 +Execute_AC_4 16_1_1 +Execute_AC_4 16_2_1 +Execute_AC_4 24_1_1 +Execute_AC_4 24_2_1 +Execute_AC_4 32_1_1 +Execute_AC_4 32_2_1 +# Execute_AC_4 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_4 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_4 48_1_1 +Execute_AC_4 48_2_1 +Execute_AC_4 48_3_1 +Execute_AC_4 48_4_1 +Execute_AC_4 48_5_1 +Execute_AC_4 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh new file mode 100755 index 000000000000..bc3cfbffa7f1 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_5.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_5 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_5 \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 +} + +Execute_AC_5 8_1_1 8_1_1 +Execute_AC_5 8_2_1 8_2_1 +Execute_AC_5 16_1_1 16_1_1 +Execute_AC_5 16_2_1 16_2_1 +Execute_AC_5 24_1_1 24_1_1 +Execute_AC_5 24_2_1 24_2_1 +Execute_AC_5 32_1_1 32_1_1 +Execute_AC_5 32_2_1 32_2_1 +# Execute_AC_5 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_5 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_5 48_1_1 48_1_1 +Execute_AC_5 48_2_1 48_2_1 +Execute_AC_5 48_3_1 48_3_1 +Execute_AC_5 48_4_1 48_4_1 +Execute_AC_5 48_5_1 48_5_1 +# Execute_AC_5 48_6_1 48_6_1 # ASSERTION FAIL [c_latency <= cig->c_latency] diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_i.sh new file mode 100755 index 000000000000..3e34f75be165 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_i.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP 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=cap_initiator_ac_6_i \ + -RealEncryption=1 -rs=23 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 +} + +Execute_AC_6_I 8_1_1 +Execute_AC_6_I 8_2_1 +Execute_AC_6_I 16_1_1 +Execute_AC_6_I 16_2_1 +Execute_AC_6_I 24_1_1 +Execute_AC_6_I 24_2_1 +Execute_AC_6_I 32_1_1 +Execute_AC_6_I 32_2_1 +# Execute_AC_6_I 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_6_I 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_6_I 48_1_1 +Execute_AC_6_I 48_2_1 +Execute_AC_6_I 48_3_1 +Execute_AC_6_I 48_4_1 +Execute_AC_6_I 48_5_1 +Execute_AC_6_I 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_ii.sh new file mode 100755 index 000000000000..e354dd452879 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_6_ii.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP 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=cap_initiator_ac_6_ii \ + -RealEncryption=1 -rs=23 -argstest sink_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=69 + + # 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 8_1_1 +Execute_AC_6_II 8_2_1 +Execute_AC_6_II 16_1_1 +Execute_AC_6_II 16_2_1 +Execute_AC_6_II 24_1_1 +Execute_AC_6_II 24_2_1 +Execute_AC_6_II 32_1_1 +Execute_AC_6_II 32_2_1 +# Execute_AC_6_II 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_6_II 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_6_II 48_1_1 +Execute_AC_6_II 48_2_1 +Execute_AC_6_II 48_3_1 +Execute_AC_6_II 48_4_1 +Execute_AC_6_II 48_5_1 +Execute_AC_6_II 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh new file mode 100755 index 000000000000..bf5a9174aa07 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_i.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_7_i" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_7_I() { + printf "\n\n======== Running CAP AC_7_I 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_7_i \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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_7_I 8_1_1 8_1_1 +Execute_AC_7_I 8_2_1 8_2_1 +Execute_AC_7_I 16_1_1 16_1_1 +Execute_AC_7_I 16_2_1 16_2_1 +Execute_AC_7_I 24_1_1 24_1_1 +Execute_AC_7_I 24_2_1 24_2_1 +Execute_AC_7_I 32_1_1 32_1_1 +Execute_AC_7_I 32_2_1 32_2_1 +# Execute_AC_7_I 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_7_I 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_7_I 48_1_1 48_1_1 +Execute_AC_7_I 48_2_1 48_2_1 +Execute_AC_7_I 48_3_1 48_3_1 +Execute_AC_7_I 48_4_1 48_4_1 +Execute_AC_7_I 48_5_1 48_5_1 +Execute_AC_7_I 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_ii.sh new file mode 100755 index 000000000000..1dd957f86dc0 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_7_ii.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_7_II 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_7_ii \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=69 + + # 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 8_1_1 8_1_1 +Execute_AC_7_II 8_2_1 8_2_1 +Execute_AC_7_II 16_1_1 16_1_1 +Execute_AC_7_II 16_2_1 16_2_1 +Execute_AC_7_II 24_1_1 24_1_1 +Execute_AC_7_II 24_2_1 24_2_1 +Execute_AC_7_II 32_1_1 32_1_1 +Execute_AC_7_II 32_2_1 32_2_1 +# Execute_AC_7_II 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_7_II 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_7_II 48_1_1 48_1_1 +Execute_AC_7_II 48_2_1 48_2_1 +Execute_AC_7_II 48_3_1 48_3_1 +Execute_AC_7_II 48_4_1 48_4_1 +Execute_AC_7_II 48_5_1 48_5_1 +Execute_AC_7_II 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_i.sh new file mode 100755 index 000000000000..00955fd8063a --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_i.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_8_I 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_8_i \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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 8_1_1 8_1_1 +Execute_AC_8_I 8_2_1 8_2_1 +Execute_AC_8_I 16_1_1 16_1_1 +Execute_AC_8_I 16_2_1 16_2_1 +Execute_AC_8_I 24_1_1 24_1_1 +Execute_AC_8_I 24_2_1 24_2_1 +Execute_AC_8_I 32_1_1 32_1_1 +Execute_AC_8_I 32_2_1 32_2_1 +# Execute_AC_8_I 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_8_I 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_8_I 48_1_1 48_1_1 +Execute_AC_8_I 48_2_1 48_2_1 +Execute_AC_8_I 48_3_1 48_3_1 +Execute_AC_8_I 48_4_1 48_4_1 +Execute_AC_8_I 48_5_1 48_5_1 +Execute_AC_8_I 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_ii.sh new file mode 100755 index 000000000000..1539bd0ceac5 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_8_ii.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_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 CAP AC_8_II 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_8_ii \ + -RealEncryption=1 -rs=23 -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=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=69 + + # 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 8_1_1 8_1_1 +Execute_AC_8_II 8_2_1 8_2_1 +Execute_AC_8_II 16_1_1 16_1_1 +Execute_AC_8_II 16_2_1 16_2_1 +Execute_AC_8_II 24_1_1 24_1_1 +Execute_AC_8_II 24_2_1 24_2_1 +Execute_AC_8_II 32_1_1 32_1_1 +Execute_AC_8_II 32_2_1 32_2_1 +# Execute_AC_8_II 441_1_1 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_8_II 441_2_1 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_8_II 48_1_1 48_1_1 +Execute_AC_8_II 48_2_1 48_2_1 +Execute_AC_8_II 48_3_1 48_3_1 +Execute_AC_8_II 48_4_1 48_4_1 +Execute_AC_8_II 48_5_1 48_5_1 +Execute_AC_8_II 48_6_1 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_i.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_i.sh new file mode 100755 index 000000000000..b6097a88b589 --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_i.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_9_i" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_9_I() { + printf "\n\n======== Running CAP AC_9_I 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_9_i \ + -RealEncryption=1 -rs=23 -argstest source_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + # 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_9_I 8_1_1 +Execute_AC_9_I 8_2_1 +Execute_AC_9_I 16_1_1 +Execute_AC_9_I 16_2_1 +Execute_AC_9_I 24_1_1 +Execute_AC_9_I 24_2_1 +Execute_AC_9_I 32_1_1 +Execute_AC_9_I 32_2_1 +# Execute_AC_9_I 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_9_I 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_9_I 48_1_1 +Execute_AC_9_I 48_2_1 +Execute_AC_9_I 48_3_1 +Execute_AC_9_I 48_4_1 +Execute_AC_9_I 48_5_1 +Execute_AC_9_I 48_6_1 diff --git a/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_ii.sh b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_ii.sh new file mode 100755 index 000000000000..5f17668a626f --- /dev/null +++ b/tests/bsim/bluetooth/audio/test_scripts/cap_unicast_ac_9_ii.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +SIMULATION_ID="cap_unicast_ac_9_ii" +VERBOSITY_LEVEL=2 +EXECUTE_TIMEOUT=60 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +cd ${BSIM_OUT_PATH}/bin + +function Execute_AC_9_II() { + printf "\n\n======== Running CAP AC_9_II 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_9_ii \ + -RealEncryption=1 -rs=23 -argstest source_preset $1 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=1 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=46 + + Execute ./bs_${BOARD}_tests_bsim_bluetooth_audio_prj_conf \ + -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=cap_acceptor_unicast \ + -RealEncryption=1 -rs=69 + + # 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_9_II 8_1_1 +Execute_AC_9_II 8_2_1 +Execute_AC_9_II 16_1_1 +Execute_AC_9_II 16_2_1 +Execute_AC_9_II 24_1_1 +Execute_AC_9_II 24_2_1 +Execute_AC_9_II 32_1_1 +Execute_AC_9_II 32_2_1 +# Execute_AC_9_II 441_1_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +# Execute_AC_9_II 441_2_1 # ASSERTION FAIL [iso_interval_us >= cig->c_sdu_interval] +Execute_AC_9_II 48_1_1 +Execute_AC_9_II 48_2_1 +Execute_AC_9_II 48_3_1 +Execute_AC_9_II 48_4_1 +Execute_AC_9_II 48_5_1 +Execute_AC_9_II 48_6_1 From bdd83e723915b2a3a45511054288888770e65e94 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 6 Jun 2023 19:10:19 +0200 Subject: [PATCH 1380/2042] Bluetooth: CAP: Shell: Add support for specific audio configs Add CAP shell commands for starting specific audio configurations based on the BAP specification. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/audio.h | 67 ++ subsys/bluetooth/audio/shell/bap.c | 73 +- subsys/bluetooth/audio/shell/cap_initiator.c | 740 ++++++++++++++++++- 3 files changed, 867 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index e1e39d892a5c..e4e7b61941b2 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -17,6 +17,7 @@ #include #include +#include #include #include "shell/bt.h" @@ -43,6 +44,8 @@ struct named_lc3_preset { struct bt_bap_lc3_preset preset; }; +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg); + #if defined(CONFIG_BT_BAP_UNICAST) #define UNICAST_SERVER_STREAM_COUNT \ @@ -54,6 +57,12 @@ struct named_lc3_preset { CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), \ (0)) +#define BAP_UNICAST_AC_MAX_CONN 2U +#define BAP_UNICAST_AC_MAX_SNK (2U * BAP_UNICAST_AC_MAX_CONN) +#define BAP_UNICAST_AC_MAX_SRC (2U * BAP_UNICAST_AC_MAX_CONN) +#define BAP_UNICAST_AC_MAX_PAIR MAX(BAP_UNICAST_AC_MAX_SNK, BAP_UNICAST_AC_MAX_SRC) +#define BAP_UNICAST_AC_MAX_STREAM (BAP_UNICAST_AC_MAX_SNK + BAP_UNICAST_AC_MAX_SRC) + struct shell_stream { struct bt_cap_stream stream; struct bt_audio_codec_cfg codec_cfg; @@ -92,11 +101,27 @@ extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_ #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) +struct bap_unicast_ac_param { + char *name; + size_t conn_cnt; + size_t snk_cnt[BAP_UNICAST_AC_MAX_CONN]; + size_t src_cnt[BAP_UNICAST_AC_MAX_CONN]; + size_t snk_chan_cnt; + size_t src_chan_cnt; +}; + extern struct bt_bap_unicast_group *default_unicast_group; extern struct bt_bap_ep *snks[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT]; extern struct bt_bap_ep *srcs[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT]; extern const struct named_lc3_preset *default_sink_preset; extern const struct named_lc3_preset *default_source_preset; + +int bap_ac_create_unicast_group(const struct bap_unicast_ac_param *param, + struct shell_stream *snk_uni_streams[], size_t snk_cnt, + struct shell_stream *src_uni_streams[], size_t src_cnt); + +int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, + const struct bap_unicast_ac_param *param); #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ #endif /* CONFIG_BT_BAP_UNICAST */ @@ -172,6 +197,12 @@ static inline void print_codec_cfg(const struct shell *sh, } #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) +struct bap_broadcast_ac_param { + char *name; + size_t stream_cnt; + size_t chan_cnt; +}; + 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 */ @@ -308,6 +339,42 @@ static inline void copy_broadcast_source_preset(struct broadcast_source *source, */ } +static inline void codec_data_set_chan_alloc(struct bt_audio_codec_data *data, + enum bt_audio_location loc) +{ + const uint32_t loc_32 = loc; + + data->data.type = BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC; + data->data.data_len = sizeof(loc_32); + sys_put_le32(loc_32, data->value); +} + +static inline int codec_set_chan_alloc(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_location loc) +{ + for (size_t i = 0U; i < codec_cfg->data_count; i++) { + struct bt_audio_codec_data *data = &codec_cfg->data[i]; + + /* Overwrite the location value */ + if (data->data.type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { + codec_data_set_chan_alloc(data, loc); + + return 0; + } + } + + /* Not found, add new if possible */ + if (codec_cfg->data_count < CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT) { + struct bt_audio_codec_data *data = &codec_cfg->data[codec_cfg->data_count++]; + + codec_data_set_chan_alloc(data, loc); + + return 0; + } + + return -ENOMEM; +} + #endif /* CONFIG_BT_AUDIO */ #endif /* __AUDIO_H */ diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index 7f30567035c6..d38055fd889d 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -384,7 +384,7 @@ void sdu_sent_cb(struct bt_bap_stream *bap_stream) } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ -static const struct named_lc3_preset *get_named_preset(bool is_unicast, const char *preset_arg) +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg) { if (is_unicast) { for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) { @@ -682,6 +682,71 @@ static int set_metadata(struct bt_audio_codec_cfg *codec_cfg, const char *meta_s } #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) +int bap_ac_create_unicast_group(const struct bap_unicast_ac_param *param, + struct shell_stream *snk_uni_streams[], size_t snk_cnt, + struct shell_stream *src_uni_streams[], size_t src_cnt) +{ + struct bt_bap_unicast_group_stream_param snk_group_stream_params[BAP_UNICAST_AC_MAX_SNK] = { + 0}; + struct bt_bap_unicast_group_stream_param src_group_stream_params[BAP_UNICAST_AC_MAX_SRC] = { + 0}; + struct bt_bap_unicast_group_stream_pair_param pair_params[BAP_UNICAST_AC_MAX_PAIR] = {0}; + struct bt_bap_unicast_group_param group_param = {0}; + struct bt_audio_codec_qos *snk_qos[BAP_UNICAST_AC_MAX_SNK]; + struct bt_audio_codec_qos *src_qos[BAP_UNICAST_AC_MAX_SRC]; + size_t snk_stream_cnt = 0U; + size_t src_stream_cnt = 0U; + size_t pair_cnt = 0U; + + for (size_t i = 0U; i < snk_cnt; i++) { + snk_qos[i] = &snk_uni_streams[i]->qos; + } + + for (size_t i = 0U; i < src_cnt; i++) { + src_qos[i] = &src_uni_streams[i]->qos; + } + + /* 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_qos[i]; + 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_qos[i]; + 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, &default_unicast_group); +} + static uint8_t stream_dir(const struct bt_bap_stream *stream) { if (stream->conn) { @@ -1041,7 +1106,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) if (argc > i) { arg = argv[++i]; - named_preset = get_named_preset(true, arg); + named_preset = bap_get_named_preset(true, arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); return -ENOEXEC; @@ -1377,7 +1442,7 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) } if (argc > 2) { - named_preset = get_named_preset(unicast, argv[2]); + named_preset = bap_get_named_preset(unicast, argv[2]); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", argv[2]); return -ENOEXEC; @@ -1933,7 +1998,7 @@ static int cmd_create_broadcast(const struct shell *sh, size_t argc, i++; arg = argv[i]; - named_preset = get_named_preset(false, arg); + named_preset = bap_get_named_preset(false, arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); diff --git a/subsys/bluetooth/audio/shell/cap_initiator.c b/subsys/bluetooth/audio/shell/cap_initiator.c index 3e93c455c2db..f71e6dcab247 100644 --- a/subsys/bluetooth/audio/shell/cap_initiator.c +++ b/subsys/bluetooth/audio/shell/cap_initiator.c @@ -19,6 +19,9 @@ #include "audio.h" #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) +#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 CAP_UNICAST_CLIENT_STREAM_COUNT ARRAY_SIZE(unicast_streams) static void cap_discover_cb(struct bt_conn *conn, int err, @@ -481,14 +484,676 @@ static int cmd_cap_initiator_unicast_cancel(const struct shell *sh, size_t argc, err = bt_cap_initiator_unicast_audio_cancel(); if (err != 0) { shell_print(sh, "Failed to cancel unicast audio procedure: %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param, + struct bt_conn *connected_conns[], + struct shell_stream *snk_uni_streams[], size_t snk_cnt, + struct shell_stream *src_uni_streams[], size_t src_cnt) +{ + struct bt_cap_unicast_audio_start_stream_param stream_params[BAP_UNICAST_AC_MAX_STREAM] = { + 0}; + struct bt_audio_codec_cfg *snk_codec_cfgs[BAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_audio_codec_cfg *src_codec_cfgs[BAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_cap_stream *snk_cap_streams[BAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_cap_stream *src_cap_streams[BAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_audio_codec_qos *snk_qos[BAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_audio_codec_qos *src_qos[BAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_cap_unicast_audio_start_param start_param = {0}; + struct bt_bap_ep *snk_eps[BAP_UNICAST_AC_MAX_SNK] = {0}; + struct bt_bap_ep *src_eps[BAP_UNICAST_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] = snks[bt_conn_index(connected_conns[i])][j]; + if (snk_eps[snk_ep_cnt] == NULL) { + shell_error(ctx_shell, "No sink[%zu][%zu] endpoint available", i, + j); + + return -ENOEXEC; + } + 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] = srcs[bt_conn_index(connected_conns[i])][j]; + if (src_eps[src_ep_cnt] == NULL) { + shell_error(ctx_shell, "No source[%zu][%zu] endpoint available", i, + j); + + return -ENOEXEC; + } + src_ep_cnt++; + } +#endif /* UNICAST_SRC_SUPPORTED */ + } + + if (snk_ep_cnt != snk_cnt) { + shell_error(ctx_shell, "Sink endpoint and stream count mismatch: %zu != %zu", + snk_ep_cnt, snk_cnt); + + return -ENOEXEC; + } + + if (src_ep_cnt != src_cnt) { + shell_error(ctx_shell, "Source endpoint and stream count mismatch: %zu != %zu", + src_ep_cnt, src_cnt); + + return -ENOEXEC; + } + + /* 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_qos[i] = &snk_uni_streams[i]->qos; + 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_qos[i] = &src_uni_streams[i]->qos; + 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->qos = snk_qos[snk_stream_cnt]; + stream_param->stream = snk_cap_streams[snk_stream_cnt]; + + snk_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + const int err = + codec_set_chan_alloc(stream_param->codec_cfg, BIT(i)); + + if (err != 0) { + shell_error(ctx_shell, + "Failed to set channel allocation for " + "snk[%zu][%zu]: %d", + i, j, err); + + return err; + } + } + } + + 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->qos = src_qos[src_stream_cnt]; + stream_param->stream = src_cap_streams[src_stream_cnt]; + + src_stream_cnt++; + stream_cnt++; + + if (param->conn_cnt > 1) { + const int err = + codec_set_chan_alloc(stream_param->codec_cfg, BIT(i)); + + if (err != 0) { + shell_error(ctx_shell, + "Failed to set channel allocation for " + "src[%zu][%zu]: %d", + i, j, err); + + return err; + } + } + } + } + + 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, default_unicast_group); +} + +int cap_ac_unicast(const struct shell *sh, size_t argc, char **argv, + const struct bap_unicast_ac_param *param) +{ + /* Allocate params large enough for any params, but only use what is required */ + struct bt_conn *connected_conns[BAP_UNICAST_AC_MAX_CONN] = {0}; + struct shell_stream *snk_uni_streams[BAP_UNICAST_AC_MAX_SNK]; + struct shell_stream *src_uni_streams[BAP_UNICAST_AC_MAX_SRC]; + const struct named_lc3_preset *snk_named_preset = NULL; + const struct named_lc3_preset *src_named_preset = NULL; + size_t conn_avail_cnt; + size_t snk_cnt = 0; + size_t src_cnt = 0; + int err; + + if (default_unicast_group != NULL) { + shell_error(sh, "Unicast Group already exist, please delete first"); + return -ENOEXEC; + } + + if (param->conn_cnt > BAP_UNICAST_AC_MAX_CONN) { + shell_error(sh, "Invalid conn_cnt: %zu", param->conn_cnt); + return -ENOEXEC; + } + + for (size_t i = 0; i < param->conn_cnt; i++) { + /* Verify conn values */ + if (param->snk_cnt[i] > BAP_UNICAST_AC_MAX_SNK) { + shell_error(sh, "Invalid conn_snk_cnt[%zu]: %zu", i, param->snk_cnt[i]); + return -ENOEXEC; + } + + if (param->src_cnt[i] > BAP_UNICAST_AC_MAX_SRC) { + shell_error(sh, "Invalid conn_src_cnt[%zu]: %zu", i, param->src_cnt[i]); + return -ENOEXEC; + } + } + + /* Populate the array of connected connections */ + bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns, (void *)connected_conns); + for (conn_avail_cnt = 0; conn_avail_cnt < ARRAY_SIZE(connected_conns); conn_avail_cnt++) { + if (connected_conns[conn_avail_cnt] == NULL) { + break; + } + } + + if (conn_avail_cnt < param->conn_cnt) { + shell_error(sh, + "Only %zu/%u connected devices, please connect additional devices for " + "this audio configuration", + conn_avail_cnt, param->conn_cnt); + return -ENOEXEC; + } + + /* Set all endpoints from multiple connections in a single array, and verify that the known + * endpoints matches the audio configuration + */ + 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++; + } + } + + if (snk_cnt > 0U) { + snk_named_preset = bap_get_named_preset(true, argv[1]); + if (snk_named_preset == NULL) { + shell_error(sh, "Unable to parse snk_named_preset %s", argv[1]); + return -ENOEXEC; + } + } + + if (src_cnt > 0U) { + const char *preset_arg = argc > 2 ? argv[2] : argv[1]; + + src_named_preset = bap_get_named_preset(true, preset_arg); + if (src_named_preset == NULL) { + shell_error(sh, "Unable to parse src_named_preset %s", argv[1]); + return -ENOEXEC; + } + } + + if (!ctx_shell) { + ctx_shell = sh; + } + + /* 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++) { + struct shell_stream *snk_uni_stream = snk_uni_streams[i] = &unicast_streams[i]; + + if (snk_uni_stream->stream.bap_stream.conn != NULL) { + shell_error(sh, "unicast_streams[%zu] already in use", i); + return -ENOEXEC; + } + + copy_unicast_stream_preset(snk_uni_stream, snk_named_preset); + + /* Some audio configuration requires multiple sink channels, + * so multiply the SDU based on the channel count + */ + snk_uni_stream->qos.sdu *= param->snk_chan_cnt; + } + + for (size_t i = 0U; i < src_cnt; i++) { + struct shell_stream *src_uni_stream = src_uni_streams[i] = + &unicast_streams[i + snk_cnt]; + + if (src_uni_stream->stream.bap_stream.conn != NULL) { + shell_error(sh, "unicast_streams[%zu] already in use", i + snk_cnt); + return -ENOEXEC; + } + + copy_unicast_stream_preset(src_uni_stream, src_named_preset); + } + + err = bap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams, + src_cnt); + if (err != 0) { + shell_error(sh, "Failed to create group: %d", err); + + return -ENOEXEC; + } + + shell_print(sh, "Starting %zu streams for %s", snk_cnt + src_cnt, param->name); + err = cap_ac_unicast_start(param, connected_conns, snk_uni_streams, snk_cnt, + src_uni_streams, src_cnt); + if (err != 0) { + shell_error(sh, "Failed to start unicast audio: %d", err); + + err = bt_bap_unicast_group_delete(default_unicast_group); + if (err != 0) { + shell_error(sh, "Failed to delete group: %d", err); + } else { + default_unicast_group = NULL; + } return -ENOEXEC; } return 0; } + +#if UNICAST_SINK_SUPPORTED +static int cmd_cap_ac_1(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_1", + .conn_cnt = 1U, + .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_cap_ac_2(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_2", + .conn_cnt = 1U, + .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_cap_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_cap_ac_4(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_4", + .conn_cnt = 1, + .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_cap_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_cap_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_cap_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 = 2U, + .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 +static int cmd_cap_ac_7_i(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_7_I", + .conn_cnt = 1U, + .snk_cnt = {1U}, /* TODO: These should be separate CIS */ + .src_cnt = {1U}, /* TODO: These should be separate CIS */ + .snk_chan_cnt = 1U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} + +#if CONFIG_BT_MAX_CONN >= 2 +static int cmd_cap_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 = 2U, + .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_cap_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_cap_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_SRC_COUNT > 1 +static int cmd_cap_ac_9_i(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_9_I", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {2U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ + +#if CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 +static int cmd_cap_ac_9_ii(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_9_II", + .conn_cnt = 2U, + .snk_cnt = {0U, 0U}, + .src_cnt = {1U, 1U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 1U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 +static int cmd_cap_ac_10(const struct shell *sh, size_t argc, char **argv) +{ + const struct bap_unicast_ac_param param = { + .name = "AC_10", + .conn_cnt = 1U, + .snk_cnt = {0U}, + .src_cnt = {1U}, + .snk_chan_cnt = 0U, + .src_chan_cnt = 2U, + }; + + return cap_ac_unicast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ + +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 +static int cmd_cap_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_cap_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_BAP_UNICAST_CLIENT */ +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) +static 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 */ + struct bt_bap_broadcast_source_stream_param stream_params[BAP_UNICAST_AC_MAX_SRC] = {0}; + struct bt_audio_codec_data stereo_data = + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, + BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT); + struct bt_audio_codec_data right_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, BT_AUDIO_LOCATION_FRONT_RIGHT); + struct bt_audio_codec_data left_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC, BT_AUDIO_LOCATION_FRONT_LEFT); + struct bt_bap_broadcast_source_subgroup_param subgroup_param = {0}; + struct bt_bap_broadcast_source_create_param create_param = {0}; + const struct named_lc3_preset *named_preset; + struct bt_le_ext_adv *adv; + int err; + + if (default_source.bap_source != NULL) { + shell_error(sh, "Broadcast Source already created, please delete first"); + return -ENOEXEC; + } + + adv = adv_sets[selected_adv]; + if (adv == NULL) { + shell_error(sh, "Extended advertising set is NULL"); + return -ENOEXEC; + } + + named_preset = bap_get_named_preset(false, argv[1]); + if (named_preset == NULL) { + shell_error(sh, "Unable to parse named_preset %s", argv[1]); + return -ENOEXEC; + } + + copy_broadcast_source_preset(&default_source, named_preset); + default_source.qos.sdu *= param->chan_cnt; + + for (size_t i = 0U; i < param->stream_cnt; i++) { + stream_params[i].stream = &broadcast_source_streams[i].stream.bap_stream; + stream_params[i].data_count = 1U; + + if (param->stream_cnt == 1U) { + stream_params[i].data = &stereo_data; + } else if (i == 0U) { + stream_params[i].data = &left_data; + } else if (i == 1U) { + stream_params[i].data = &right_data; + } + } + + subgroup_param.params_count = param->stream_cnt; + subgroup_param.params = stream_params; + subgroup_param.codec_cfg = &default_source.codec_cfg; + create_param.params_count = 1U; + create_param.params = &subgroup_param; + create_param.qos = &default_source.qos; + + err = bt_bap_broadcast_source_create(&create_param, &default_source.bap_source); + if (err != 0) { + shell_error(sh, "Failed to create broadcast source: %d", err); + return -ENOEXEC; + } + + /* We don't start the broadcast source here, because in order to populate the BASE in the + * periodic advertising data, the broadcast source needs to be created but not started. + */ + shell_print(sh, + "Broadcast source for %s created. Start via `bap start_broadcast`, and " + "update/set the base via `bt per-adv data`", + param->name); + + return 0; +} + +static int cmd_cap_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_cap_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_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, + }; + + return cap_ac_broadcast(sh, argc, argv, ¶m); +} +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + static int cmd_cap_initiator(const struct shell *sh, size_t argc, char **argv) { if (argc > 1) { @@ -501,27 +1166,84 @@ static int cmd_cap_initiator(const struct shell *sh, size_t argc, char **argv) return -ENOEXEC; } -SHELL_STATIC_SUBCMD_SET_CREATE(cap_initiator_cmds, +SHELL_STATIC_SUBCMD_SET_CREATE( + cap_initiator_cmds, #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) - SHELL_CMD_ARG(discover, NULL, - "Discover CAS", cmd_cap_initiator_discover, 1, 0), + SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_initiator_discover, 1, 0), SHELL_CMD_ARG(unicast-start, NULL, "Unicast Start [csip] [sinks (default 1)] " "[sources (default 1)] " "[conns ( | all) (default 1)]", cmd_cap_initiator_unicast_start, 1, 7), - SHELL_CMD_ARG(unicast-list, NULL, "Unicast list streams", - cmd_cap_initiator_unicast_list, 1, 0), + SHELL_CMD_ARG(unicast-list, NULL, "Unicast list streams", cmd_cap_initiator_unicast_list, + 1, 0), SHELL_CMD_ARG(unicast-update, NULL, "Unicast Update ", - cmd_cap_initiator_unicast_update, 2, - CAP_UNICAST_CLIENT_STREAM_COUNT), + cmd_cap_initiator_unicast_update, 2, CAP_UNICAST_CLIENT_STREAM_COUNT), SHELL_CMD_ARG(unicast-stop, NULL, "Unicast stop all streams", cmd_cap_initiator_unicast_stop, 1, 0), SHELL_CMD_ARG(unicast-cancel, NULL, "Unicast cancel current procedure", cmd_cap_initiator_unicast_cancel, 1, 0), +#if UNICAST_SINK_SUPPORTED + SHELL_CMD_ARG(ac_1, NULL, "", cmd_cap_ac_1, 2, 0), +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_2, NULL, "", cmd_cap_ac_2, 2, 0), +#endif /* UNICAST_SRC_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_3, NULL, " ", cmd_cap_ac_3, 3, 0), +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED + SHELL_CMD_ARG(ac_4, NULL, "", cmd_cap_ac_4, 2, 0), +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_5, NULL, " ", cmd_cap_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_cap_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_cap_ac_6_ii, 2, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED */ +#if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED + SHELL_CMD_ARG(ac_7_i, NULL, " ", cmd_cap_ac_7_i, 3, 0), +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_7_ii, NULL, " ", cmd_cap_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_cap_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_cap_ac_8_ii, 3, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#if UNICAST_SRC_SUPPORTED +#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 + SHELL_CMD_ARG(ac_9_i, NULL, "", cmd_cap_ac_9_i, 2, 0), +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */ +#if CONFIG_BT_MAX_CONN >= 2 + SHELL_CMD_ARG(ac_9_ii, NULL, "", cmd_cap_ac_9_ii, 2, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ + SHELL_CMD_ARG(ac_10, NULL, "", cmd_cap_ac_10, 2, 0), +#endif /* UNICAST_SRC_SUPPORTED */ +#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_cap_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_cap_ac_11_ii, 3, 0), +#endif /* CONFIG_BT_MAX_CONN >= 2 */ +#endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */ #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ - SHELL_SUBCMD_SET_END -); +#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) + SHELL_CMD_ARG(ac_12, NULL, "", cmd_cap_ac_12, 2, 0), +#if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 + SHELL_CMD_ARG(ac_13, NULL, "", cmd_cap_ac_13, 2, 0), +#endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */ + SHELL_CMD_ARG(ac_14, NULL, "", cmd_cap_ac_14, 2, 0), +#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ + SHELL_SUBCMD_SET_END); SHELL_CMD_ARG_REGISTER(cap_initiator, &cap_initiator_cmds, "Bluetooth CAP initiator shell commands", From 9752cbe045bda058aa3855b5104bc5edaea89583 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Tue, 20 Jun 2023 15:47:21 +0200 Subject: [PATCH 1381/2042] ipc_service: open-amp: Align VRINGs This patchset is doing three things: 1. It is fixing the bogus algorithm to find the optimal number of descriptors for a given memory size. 2. It is changing values for VDEV_STATUS_SIZE and IPC_SERVICE_STATIC_VRINGS_ALIGNMENT to better align to a usual cache line size. 3. RX/TX VRINGs are now correctly aligned to MEM_ALIGNMENT (and cache line alignment). Signed-off-by: Carlo Caione --- .../ipc/zephyr,ipc-openamp-static-vrings.yaml | 3 +- include/zephyr/ipc/ipc_static_vrings.h | 9 ++++-- .../backends/ipc_rpmsg_static_vrings.c | 30 ++++++++++++++++--- .../backends/ipc_rpmsg_static_vrings.h | 24 ++++++++------- subsys/ipc/ipc_service/lib/Kconfig | 5 ++-- .../ipc/ipc_service/lib/ipc_static_vrings.c | 4 +-- 6 files changed, 54 insertions(+), 21 deletions(-) diff --git a/dts/bindings/ipc/zephyr,ipc-openamp-static-vrings.yaml b/dts/bindings/ipc/zephyr,ipc-openamp-static-vrings.yaml index d57278fd35b5..024dc1e4a351 100644 --- a/dts/bindings/ipc/zephyr,ipc-openamp-static-vrings.yaml +++ b/dts/bindings/ipc/zephyr,ipc-openamp-static-vrings.yaml @@ -48,4 +48,5 @@ properties: type: int description: | The size of the buffer used to send data between host and remote. Default - value is RPMSG_BUFFER_SIZE. This property must be the same for host and remote. + value is RPMSG_BUFFER_SIZE. This property must be the same for host and + remote and preferably a multiple of the cache line size. diff --git a/include/zephyr/ipc/ipc_static_vrings.h b/include/zephyr/ipc/ipc_static_vrings.h index ee4fc9fab7c5..d82144f4522b 100644 --- a/include/zephyr/ipc/ipc_static_vrings.h +++ b/include/zephyr/ipc/ipc_static_vrings.h @@ -25,8 +25,13 @@ extern "C" { /** Number of used VRING buffers. */ #define VRING_COUNT (2) -/** VRING alignment. */ -#define VRING_ALIGNMENT CONFIG_IPC_SERVICE_STATIC_VRINGS_ALIGNMENT +/** + * Memory alignment. + * + * This should take into account the cache line if the cache is enabled, otherwise + * it should be naturally aligned to the machine word size. + */ +#define MEM_ALIGNMENT CONFIG_IPC_SERVICE_STATIC_VRINGS_MEM_ALIGNMENT /** * @typedef ipc_notify_cb 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 684d73944386..deb799a75b9d 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c @@ -250,12 +250,34 @@ static int vr_shm_configure(struct ipc_static_vrings *vr, const struct backend_c return -ENOMEM; } - vr->shm_addr = conf->shm_addr + VDEV_STATUS_SIZE; - vr->shm_size = shm_size(num_desc, conf->buffer_size) - VDEV_STATUS_SIZE; + /* + * conf->shm_addr +--------------+ vr->status_reg_addr + * | STATUS | + * +--------------+ vr->shm_addr + * | | + * | | + * | RX BUFS | + * | | + * | | + * +--------------+ + * | | + * | | + * | TX BUFS | + * | | + * | | + * +--------------+ vr->rx_addr (aligned) + * | RX VRING | + * +--------------+ vr->tx_addr (aligned) + * | TX VRING | + * +--------------+ + */ + + vr->shm_addr = ROUND_UP(conf->shm_addr + VDEV_STATUS_SIZE, MEM_ALIGNMENT); + vr->shm_size = shm_size(num_desc, conf->buffer_size); vr->rx_addr = vr->shm_addr + VRING_COUNT * vq_ring_size(num_desc, conf->buffer_size); - vr->tx_addr = ROUND_UP(vr->rx_addr + vring_size(num_desc, VRING_ALIGNMENT), - VRING_ALIGNMENT); + vr->tx_addr = ROUND_UP(vr->rx_addr + vring_size(num_desc, MEM_ALIGNMENT), + MEM_ALIGNMENT); vr->status_reg_addr = conf->shm_addr; diff --git a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.h b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.h index 0ef0c9ca9500..343426daec5c 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.h +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.h @@ -130,7 +130,10 @@ * */ -#define VDEV_STATUS_SIZE (4) /* Size of status region */ +/* + * Size of the status region (possibly a multiple of the cache line size). + */ +#define VDEV_STATUS_SIZE CONFIG_IPC_SERVICE_STATIC_VRINGS_MEM_ALIGNMENT #define VIRTQUEUE_ID_HOST (0) #define VIRTQUEUE_ID_REMOTE (1) @@ -140,24 +143,25 @@ static inline size_t vq_ring_size(unsigned int num, unsigned int buf_size) { - return (buf_size * num); + return ROUND_UP((buf_size * num), MEM_ALIGNMENT); } static inline size_t shm_size(unsigned int num, unsigned int buf_size) { - return (VDEV_STATUS_SIZE + (VRING_COUNT * vq_ring_size(num, buf_size)) + - (VRING_COUNT * vring_size(num, VRING_ALIGNMENT))); + return (VRING_COUNT * (vq_ring_size(num, buf_size) + + ROUND_UP(vring_size(num, MEM_ALIGNMENT), MEM_ALIGNMENT))); } -static inline unsigned int optimal_num_desc(size_t shm_size, unsigned int buf_size) +static inline unsigned int optimal_num_desc(size_t mem_size, unsigned int buf_size) { - size_t available, single_alloc; - unsigned int num_desc; + size_t available; + unsigned int num_desc = 1; - available = shm_size - VDEV_STATUS_SIZE; - single_alloc = VRING_COUNT * (vq_ring_size(1, buf_size) + vring_size(1, VRING_ALIGNMENT)); + available = mem_size - VDEV_STATUS_SIZE; - num_desc = (unsigned int) (available / single_alloc); + while (available > shm_size(num_desc, buf_size)) { + num_desc++; + } return (1 << (find_msb_set(num_desc) - 1)); } diff --git a/subsys/ipc/ipc_service/lib/Kconfig b/subsys/ipc/ipc_service/lib/Kconfig index a98c010471bd..f2b4d8ae210a 100644 --- a/subsys/ipc/ipc_service/lib/Kconfig +++ b/subsys/ipc/ipc_service/lib/Kconfig @@ -11,12 +11,13 @@ config IPC_SERVICE_STATIC_VRINGS help "Static VRINGs library" -config IPC_SERVICE_STATIC_VRINGS_ALIGNMENT +config IPC_SERVICE_STATIC_VRINGS_MEM_ALIGNMENT int "VRINGs alignment" depends on IPC_SERVICE_STATIC_VRINGS default 4 help - Static VRINGs alignment + Static VRINGs alignment. This should take into account the cache line + alignment if the cache is enabled. menuconfig IPC_SERVICE_ICMSG bool "icmsg IPC library" diff --git a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c index 6d253b6d071c..be6c365a0237 100644 --- a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c +++ b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c @@ -127,13 +127,13 @@ static int vq_setup(struct ipc_static_vrings *vr, unsigned int role) vr->rvrings[RPMSG_VQ_0].io = vr->shm_io; vr->rvrings[RPMSG_VQ_0].info.vaddr = (void *) vr->tx_addr; vr->rvrings[RPMSG_VQ_0].info.num_descs = vr->vring_size; - vr->rvrings[RPMSG_VQ_0].info.align = VRING_ALIGNMENT; + vr->rvrings[RPMSG_VQ_0].info.align = MEM_ALIGNMENT; vr->rvrings[RPMSG_VQ_0].vq = vr->vq[RPMSG_VQ_0]; vr->rvrings[RPMSG_VQ_1].io = vr->shm_io; vr->rvrings[RPMSG_VQ_1].info.vaddr = (void *) vr->rx_addr; vr->rvrings[RPMSG_VQ_1].info.num_descs = vr->vring_size; - vr->rvrings[RPMSG_VQ_1].info.align = VRING_ALIGNMENT; + vr->rvrings[RPMSG_VQ_1].info.align = MEM_ALIGNMENT; vr->rvrings[RPMSG_VQ_1].vq = vr->vq[RPMSG_VQ_1]; vr->vdev.role = role; From 1fcb929108f37015e2646cdd6c0a0698d994a64e Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 22 Jun 2023 11:37:29 +0200 Subject: [PATCH 1382/2042] ipc_service: open-amp: Add __ASSERTs on cache alignment Add some asserts to warn the user about unaligned VDEV status area, VRINGs and buffers. Signed-off-by: Carlo Caione --- .../ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c | 9 +++++++++ 1 file changed, 9 insertions(+) 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 deb799a75b9d..65eb5f940582 100644 --- a/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c +++ b/subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings.c @@ -758,6 +758,15 @@ static int backend_init(const struct device *instance) data->role = conf->role; +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_DCACHE) + __ASSERT((VDEV_STATUS_SIZE % sys_cache_data_line_size_get()) == 0U, + "VDEV status area must be aligned to the cache line"); + __ASSERT((VRING_ALIGNMENT % sys_cache_data_line_size_get()) == 0U, + "Static VRINGs must be aligned to the cache line"); + __ASSERT((conf->buffer_size % sys_cache_data_line_size_get()) == 0U, + "Buffers must be aligned to the cache line "); +#endif + k_mutex_init(&data->rpmsg_inst.mtx); atomic_set(&data->state, STATE_READY); From 03d296d5462cedc7b4c28b259cdcd7bc623ff8fd Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 18 Jul 2023 09:16:42 +0200 Subject: [PATCH 1383/2042] Bluetooth: audio: ascs: Remove unused variable The `ops` variable is unused, thus can be removed. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index cf703b7d3593..72a4c468a909 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -795,7 +795,6 @@ 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 *ops; struct bt_bap_stream *stream; stream = ep->stream; @@ -804,8 +803,6 @@ static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); if (ep->status.state == BT_BAP_EP_STATE_ENABLING && From 9fa45439941b347f3dd23f0619596e7eb31568b2 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 4 Jul 2023 09:15:27 +0200 Subject: [PATCH 1384/2042] Bluetooth: audio: ascs: Defer ASE state transition This adds handling of ASE control point operations in separate thread so that the notifications of ASE state changes are sent from non-BT thread. This ensures bt_gatt_notify_cb to be blocking waiting for available buffers to send the notifications. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 463 +++++++++++--------- subsys/bluetooth/audio/ascs_internal.h | 2 +- subsys/bluetooth/audio/bap_unicast_server.c | 14 +- tests/bluetooth/audio/mocks/src/kernel.c | 17 + 4 files changed, 286 insertions(+), 210 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 72a4c468a909..c831d51821cc 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -61,6 +61,8 @@ static struct bt_ascs_ase { struct bt_bap_ep ep; const struct bt_gatt_attr *attr; struct k_work_delayable disconnect_work; + struct k_work state_transition_work; + enum bt_bap_ep_state state_pending; } ase_pool[CONFIG_BT_ASCS_MAX_ACTIVE_ASES]; #define MAX_CODEC_CONFIG \ @@ -124,12 +126,14 @@ static void ase_free(struct bt_ascs_ase *ase) ase->conn = NULL; } -static void ase_status_changed(struct bt_bap_ep *ep, uint8_t old_state, uint8_t state) +static void ase_status_changed(struct bt_ascs_ase *ase, uint8_t state) { - struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); struct bt_conn *conn = ase->conn; - LOG_DBG("ase %p, ep %p", ase, ep); + LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, + bt_bap_ep_state_str(ascs_ep_get_state(&ase->ep)), bt_bap_ep_state_str(state)); + + ase->ep.status.state = state; if (conn != NULL) { struct bt_conn_info conn_info; @@ -155,7 +159,7 @@ static void ase_status_changed(struct bt_bap_ep *ep, uint8_t old_state, uint8_t return; } - ascs_ep_get_status(ep, &ase_buf); + ascs_ep_get_status(&ase->ep, &ase_buf); ntf_size = MIN(max_ntf_size, ase_buf.len); if (ntf_size < ase_buf.len) { @@ -163,7 +167,8 @@ static void ase_status_changed(struct bt_bap_ep *ep, uint8_t old_state, uint8_t ntf_size, ase_buf.len); } - bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); + err = bt_gatt_notify(conn, ase->attr, ase_buf.data, ntf_size); + __ASSERT_NO_MSG(err == 0); k_sem_give(&ase_buf_sem); } @@ -237,37 +242,157 @@ static int ascs_disconnect_stream(struct bt_bap_stream *stream) K_MSEC(CONFIG_BT_ASCS_ISO_DISCONNECT_DELAY)); } -void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) +static void ase_set_state_idle(struct bt_ascs_ase *ase) { - struct bt_bap_stream *stream; - bool state_changed; - uint8_t old_state; + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; - if (!ep) { - return; + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; + + ase_status_changed(ase, BT_BAP_EP_STATE_IDLE); + + bt_bap_stream_reset(stream); + + ops = stream->ops; + if (ops != NULL && ops->released != NULL) { + ops->released(stream); } - /* TODO: Verify state changes */ + ase_free(ase); +} + +static void ase_set_state_codec_configured(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; - old_state = ep->status.state; - ep->status.state = state; - state_changed = old_state != state; + __ASSERT_NO_MSG(stream != NULL); - LOG_DBG("ep %p id 0x%02x %s -> %s", ep, ep->status.id, bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(state)); + ase->ep.receiver_ready = false; - /* Notify clients*/ - ase_status_changed(ep, old_state, state); + ase_status_changed(ase, BT_BAP_EP_STATE_CODEC_CONFIGURED); - if (ep->stream == NULL) { - return; + ops = stream->ops; + if (ops != NULL && ops->configured != NULL) { + ops->configured(stream, &ase->ep.qos_pref); } +} - stream = ep->stream; +static void ase_set_state_qos_configured(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; - if (state_changed && old_state == BT_BAP_EP_STATE_STREAMING) { - /* We left the streaming state, let the upper layers know that the stream is stopped - */ + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; + + ase_status_changed(ase, BT_BAP_EP_STATE_QOS_CONFIGURED); + + ops = stream->ops; + if (ops != NULL && ops->qos_set != NULL) { + ops->qos_set(stream); + } +} + +static void ase_set_state_enabling(struct bt_ascs_ase *ase) +{ + const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_ENABLING; + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ase_status_changed(ase, BT_BAP_EP_STATE_ENABLING); + + ops = stream->ops; + if (state_changed && ops != NULL && ops->enabled != NULL) { + ops->enabled(stream); + } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { + ops->metadata_updated(stream); + } + + /* SINK ASEs can autonomously go into the streaming state if the CIS is connected */ + if (ase->ep.dir == BT_AUDIO_DIR_SINK && ase->ep.receiver_ready && ase->ep.iso != NULL && + ase->ep.iso->chan.state == BT_ISO_STATE_CONNECTED) { + ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_STREAMING); + } +} + +static void ase_set_state_streaming(struct bt_ascs_ase *ase) +{ + const bool state_changed = ascs_ep_get_state(&ase->ep) != BT_BAP_EP_STATE_STREAMING; + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ase_status_changed(ase, BT_BAP_EP_STATE_STREAMING); + + ops = stream->ops; + if (state_changed && ops != NULL && ops->started != NULL) { + ops->started(stream); + } else if (!state_changed && ops != NULL && ops->metadata_updated != NULL) { + ops->metadata_updated(stream); + } +} + +static void ase_set_state_disabling(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; + + ase_status_changed(ase, BT_BAP_EP_STATE_DISABLING); + + ops = stream->ops; + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(stream); + } +} + +static void ase_set_state_releasing(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + + __ASSERT_NO_MSG(stream != NULL); + + ase->ep.receiver_ready = false; + + ase_status_changed(ase, BT_BAP_EP_STATE_RELEASING); + + /* Either the client or the server may disconnect the CISes when entering the releasing + * state. + */ + if (bt_bap_stream_can_disconnect(stream)) { + int err; + + err = ascs_disconnect_stream(stream); + if (err < 0) { + LOG_ERR("Failed to disconnect stream %p: %d", stream, err); + } + } else { + ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_IDLE); + } +} + +static void state_transition_work_handler(struct k_work *work) +{ + struct bt_ascs_ase *ase = CONTAINER_OF(work, struct bt_ascs_ase, state_transition_work); + const enum bt_bap_ep_state old_state = ascs_ep_get_state(&ase->ep); + const enum bt_bap_ep_state new_state = ase->state_pending; + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_ep *ep = &ase->ep; + + __ASSERT_NO_MSG(stream != NULL); + + /* We left the streaming state, let the upper layers know that the stream is stopped */ + if (old_state != new_state && old_state == BT_BAP_EP_STATE_STREAMING) { struct bt_bap_stream_ops *ops = stream->ops; uint8_t reason = ep->reason; @@ -286,198 +411,130 @@ void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) } } - if (stream->ops != NULL) { - const struct bt_bap_stream_ops *ops = stream->ops; - - switch (state) { - case BT_BAP_EP_STATE_IDLE: - ep->receiver_ready = false; - bt_bap_stream_reset(stream); - - if (ops->released != NULL) { - ops->released(stream); - } - struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + switch (new_state) { + case BT_BAP_EP_STATE_IDLE: + ase_set_state_idle(ase); + break; + case BT_BAP_EP_STATE_CODEC_CONFIGURED: + ase_set_state_codec_configured(ase); + break; + case BT_BAP_EP_STATE_QOS_CONFIGURED: + ase_set_state_qos_configured(ase); + break; + case BT_BAP_EP_STATE_ENABLING: + ase_set_state_enabling(ase); + break; + case BT_BAP_EP_STATE_STREAMING: + ase_set_state_streaming(ase); + break; + case BT_BAP_EP_STATE_DISABLING: + ase_set_state_disabling(ase); + break; + case BT_BAP_EP_STATE_RELEASING: + ase_set_state_releasing(ase); + break; + default: + __ASSERT_PRINT("Invalid state %d", new_state); + } +} - ase_free(ase); +int ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state) +{ + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const enum bt_bap_ep_state old_state = ascs_ep_get_state(&ase->ep); + bool valid_state_transition = false; + int err; + switch (state) { + case BT_BAP_EP_STATE_IDLE: + valid_state_transition = true; + break; + case BT_BAP_EP_STATE_CODEC_CONFIGURED: + switch (old_state) { + case BT_BAP_EP_STATE_IDLE: + case BT_BAP_EP_STATE_CODEC_CONFIGURED: + case BT_BAP_EP_STATE_QOS_CONFIGURED: + case BT_BAP_EP_STATE_RELEASING: + valid_state_transition = true; + break; + default: break; + } break; + case BT_BAP_EP_STATE_QOS_CONFIGURED: + switch (old_state) { case BT_BAP_EP_STATE_CODEC_CONFIGURED: - switch (old_state) { - case BT_BAP_EP_STATE_IDLE: - case BT_BAP_EP_STATE_CODEC_CONFIGURED: - case BT_BAP_EP_STATE_QOS_CONFIGURED: - case BT_BAP_EP_STATE_RELEASING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - - ep->receiver_ready = false; - - if (ops->configured != NULL) { - ops->configured(stream, &ep->qos_pref); - } - + case BT_BAP_EP_STATE_QOS_CONFIGURED: + valid_state_transition = true; + break; + case BT_BAP_EP_STATE_DISABLING: + valid_state_transition = ase->ep.dir == BT_AUDIO_DIR_SOURCE; + break; + case BT_BAP_EP_STATE_ENABLING: + case BT_BAP_EP_STATE_STREAMING: + valid_state_transition = ase->ep.dir == BT_AUDIO_DIR_SINK; + break; + default: break; + } break; + case BT_BAP_EP_STATE_ENABLING: + switch (old_state) { case BT_BAP_EP_STATE_QOS_CONFIGURED: - /* QoS configured have different allowed states - * depending on the endpoint type - */ - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - switch (old_state) { - case BT_BAP_EP_STATE_CODEC_CONFIGURED: - case BT_BAP_EP_STATE_QOS_CONFIGURED: - case BT_BAP_EP_STATE_DISABLING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - } else { - switch (old_state) { - case BT_BAP_EP_STATE_CODEC_CONFIGURED: - case BT_BAP_EP_STATE_QOS_CONFIGURED: - case BT_BAP_EP_STATE_ENABLING: - case BT_BAP_EP_STATE_STREAMING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - } - - ep->receiver_ready = false; - - if (ops->qos_set != NULL) { - ops->qos_set(stream); - } - + case BT_BAP_EP_STATE_ENABLING: + valid_state_transition = true; break; + default: + break; + } break; + case BT_BAP_EP_STATE_STREAMING: + switch (old_state) { case BT_BAP_EP_STATE_ENABLING: - switch (old_state) { - case BT_BAP_EP_STATE_QOS_CONFIGURED: - case BT_BAP_EP_STATE_ENABLING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - - if (state_changed && ops->enabled != NULL) { - ops->enabled(stream); - } else if (!state_changed && ops->metadata_updated) { - ops->metadata_updated(stream); - } - - /* SINK ASEs can autonomously go into the streaming state if - * the CIS is connected - */ - if (ep->dir == BT_AUDIO_DIR_SINK && - ep->receiver_ready && - ep->iso != NULL && - ep->iso->chan.state == BT_ISO_STATE_CONNECTED) { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING); - } - + case BT_BAP_EP_STATE_STREAMING: + valid_state_transition = true; break; + default: + break; + } break; + case BT_BAP_EP_STATE_DISABLING: + switch (old_state) { + case BT_BAP_EP_STATE_ENABLING: case BT_BAP_EP_STATE_STREAMING: - switch (old_state) { - case BT_BAP_EP_STATE_ENABLING: - case BT_BAP_EP_STATE_STREAMING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - - if (state_changed && ops->started != NULL) { - ops->started(stream); - } else if (!state_changed && ops->metadata_updated) { - ops->metadata_updated(stream); - } - + valid_state_transition = ase->ep.dir == BT_AUDIO_DIR_SOURCE; + break; + default: + break; + } break; + case BT_BAP_EP_STATE_RELEASING: + switch (old_state) { + case BT_BAP_EP_STATE_CODEC_CONFIGURED: + case BT_BAP_EP_STATE_QOS_CONFIGURED: + case BT_BAP_EP_STATE_ENABLING: + case BT_BAP_EP_STATE_STREAMING: + valid_state_transition = true; break; case BT_BAP_EP_STATE_DISABLING: - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - switch (old_state) { - case BT_BAP_EP_STATE_ENABLING: - case BT_BAP_EP_STATE_STREAMING: - break; - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - } else { - /* Sinks cannot go into the disabling state */ - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } - - ep->receiver_ready = false; - - if (ops->disabled != NULL) { - ops->disabled(stream); - } - + valid_state_transition = ase->ep.dir == BT_AUDIO_DIR_SOURCE; break; - case BT_BAP_EP_STATE_RELEASING: - switch (old_state) { - case BT_BAP_EP_STATE_CODEC_CONFIGURED: - case BT_BAP_EP_STATE_QOS_CONFIGURED: - case BT_BAP_EP_STATE_ENABLING: - case BT_BAP_EP_STATE_STREAMING: - break; - case BT_BAP_EP_STATE_DISABLING: - if (ep->dir == BT_AUDIO_DIR_SOURCE) { - break; - } /* else fall through for sink */ - - /* fall through */ - default: - BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", - bt_bap_ep_state_str(old_state), - bt_bap_ep_state_str(ep->status.state)); - return; - } + default: + break; + } break; + } - ep->receiver_ready = false; + if (!valid_state_transition) { + BT_ASSERT_MSG(false, "Invalid state transition: %s -> %s", + bt_bap_ep_state_str(old_state), bt_bap_ep_state_str(state)); - if (bt_bap_stream_can_disconnect(stream)) { - /* Either the client or the server may disconnect the - * CISes when entering the releasing state. - */ - const int err = ascs_disconnect_stream(stream); + return -EBADMSG; + } - if (err < 0) { - LOG_ERR("Failed to disconnect stream %p: %d", - stream, err); - } - } else { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_IDLE); - } + ase->state_pending = state; - break; - default: - LOG_ERR("Invalid state: %u", state); - break; - } + err = k_work_submit(&ase->state_transition_work); + if (err < 0) { + LOG_ERR("Failed to submit state transition work err %d", err); + return err; } + + return 0; } static void ascs_codec_data_add(struct net_buf_simple *buf, const char *prefix, uint8_t num, @@ -1135,6 +1192,7 @@ static void ase_init(struct bt_ascs_ase *ase, struct bt_conn *conn, uint8_t id) k_work_init_delayable(&ase->disconnect_work, ascs_disconnect_stream_work_handler); + k_work_init(&ase->state_transition_work, state_transition_work_handler); } static struct bt_ascs_ase *ase_new(struct bt_conn *conn, uint8_t id) @@ -1508,7 +1566,12 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, bt_bap_stream_attach(conn, stream, ep, &ep->codec_cfg); - ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); + err = ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); + if (err != 0) { + bt_bap_stream_detach(stream); + ase_free(ase); + return err; + } return 0; } diff --git a/subsys/bluetooth/audio/ascs_internal.h b/subsys/bluetooth/audio/ascs_internal.h index bad0b2bb527e..fc76964a0183 100644 --- a/subsys/bluetooth/audio/ascs_internal.h +++ b/subsys/bluetooth/audio/ascs_internal.h @@ -340,7 +340,7 @@ static inline const char *bt_ascs_reason_str(uint8_t reason) int bt_ascs_init(const struct bt_bap_unicast_server_cb *cb); void bt_ascs_cleanup(void); -void ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state); +int ascs_ep_set_state(struct bt_bap_ep *ep, uint8_t state); int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg, diff --git a/subsys/bluetooth/audio/bap_unicast_server.c b/subsys/bluetooth/audio/bap_unicast_server.c index 48e5beb79a56..9646d0377a91 100644 --- a/subsys/bluetooth/audio/bap_unicast_server.c +++ b/subsys/bluetooth/audio/bap_unicast_server.c @@ -86,9 +86,7 @@ int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, (void)memcpy(&ep->codec_cfg, codec_cfg, sizeof(*codec_cfg)); - ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); - - return 0; + return ascs_ep_set_state(ep, BT_BAP_EP_STATE_CODEC_CONFIGURED); } int bt_bap_unicast_server_start(struct bt_bap_stream *stream) @@ -106,11 +104,11 @@ int bt_bap_unicast_server_start(struct bt_bap_stream *stream) * else wait for ISO to be connected */ if (ep->iso->chan.state == BT_ISO_STATE_CONNECTED) { - ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING); - } else { - ep->receiver_ready = true; + return ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING); } + ep->receiver_ready = true; + return 0; } @@ -140,9 +138,7 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_audio } /* Set the state to the same state to trigger the notifications */ - ascs_ep_set_state(ep, ep->status.state); - - return 0; + return ascs_ep_set_state(ep, ep->status.state); } int bt_bap_unicast_server_disable(struct bt_bap_stream *stream) diff --git a/tests/bluetooth/audio/mocks/src/kernel.c b/tests/bluetooth/audio/mocks/src/kernel.c index 554497e5916a..ce9dcab5d3a1 100644 --- a/tests/bluetooth/audio/mocks/src/kernel.c +++ b/tests/bluetooth/audio/mocks/src/kernel.c @@ -56,6 +56,23 @@ int k_work_cancel_delayable(struct k_work_delayable *dwork) return 0; } +void k_work_init(struct k_work *work, k_work_handler_t handler) +{ + work->handler = handler; +} + +int k_work_submit(struct k_work *work) +{ + work->handler(work); + + return 0; +} + +int k_work_busy_get(const struct k_work *work) +{ + return 0; +} + int32_t k_sleep(k_timeout_t timeout) { struct k_work *work; From 6775b263f339cc784a068ab2d72fa79f1ecac19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20B=C3=B8ndergaard?= Date: Tue, 13 Jun 2023 15:12:01 +0200 Subject: [PATCH 1385/2042] drivers: counter: stm32_rtc: Make dependent of !RTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New RTC API seems to conflict with old RTC implementations based on COUNTER This scheme follows Zephyrproject-rtos issue 56599 while keeping backward compatibility. Signed-off-by: Kim Bøndergaard --- drivers/counter/Kconfig.stm32_rtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/Kconfig.stm32_rtc b/drivers/counter/Kconfig.stm32_rtc index 52de35bd57a7..03e72babc601 100644 --- a/drivers/counter/Kconfig.stm32_rtc +++ b/drivers/counter/Kconfig.stm32_rtc @@ -5,7 +5,7 @@ menuconfig COUNTER_RTC_STM32 bool "STM32 Counter RTC driver" - default y + default y if !RTC depends on DT_HAS_ST_STM32_RTC_ENABLED select USE_STM32_LL_RTC select USE_STM32_LL_PWR From b3c46083fb07b579ecfb46decc32fd2c5ecd6a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20B=C3=B8ndergaard?= Date: Tue, 13 Jun 2023 15:13:56 +0200 Subject: [PATCH 1386/2042] drivers: rtc: stm32: New stm32 RTC driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STM32 RTC driver for the new RTC API. Can't coexist with old COUNTER based RTC Though supported by HW, RTC_ALARM still to be supported by driver Signed-off-by: Kim Bøndergaard --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.stm32 | 12 ++ drivers/rtc/rtc_ll_stm32.c | 170 ++++++++++++++++++ .../rtc/rtc_api/boards/nucleo_h563zi.overlay | 11 ++ 5 files changed, 195 insertions(+) create mode 100644 drivers/rtc/Kconfig.stm32 create mode 100644 drivers/rtc/rtc_ll_stm32.c create mode 100644 tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.overlay diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 267347fc664c..3f07a859da1f 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_RTC_EMUL rtc_emul.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8563 rtc_pcf8563.c) zephyr_library_sources_ifdef(CONFIG_RTC_MOTOROLA_MC146818 rtc_mc146818.c) +zephyr_library_sources_ifdef(CONFIG_RTC_STM32 rtc_ll_stm32.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 25e135438bcc..e2f0a43bf529 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -39,5 +39,6 @@ source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.pcf8523" source "drivers/rtc/Kconfig.pcf8563" source "drivers/rtc/Kconfig.mc146818" +source "drivers/rtc/Kconfig.stm32" endif # RTC diff --git a/drivers/rtc/Kconfig.stm32 b/drivers/rtc/Kconfig.stm32 new file mode 100644 index 000000000000..510d259a2065 --- /dev/null +++ b/drivers/rtc/Kconfig.stm32 @@ -0,0 +1,12 @@ +# Copyright 2023 Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +config RTC_STM32 + bool "STM32 RTC driver" + default y if !COUNTER + depends on DT_HAS_ST_STM32_RTC_ENABLED + select USE_STM32_LL_RTC + select USE_STM32_LL_PWR + select USE_STM32_LL_RCC + help + Build RTC driver for STM32 SoCs. diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c new file mode 100644 index 000000000000..7380fb102fa1 --- /dev/null +++ b/drivers/rtc/rtc_ll_stm32.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023 Prevas A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#define DT_DRV_COMPAT st_stm32_rtc + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(rtc_stm32, CONFIG_RTC_LOG_LEVEL); + +/* Convert calendar start time */ +/* RTC start time: 1st, Jan, 2000 */ +/* struct tm start: 1st, Jan, 1900 */ +#define TM_TO_RTC_OFFSET 100 + +struct rtc_stm32_config { + LL_RTC_InitTypeDef ll_rtc_config; + const struct stm32_pclken *pclken; +}; + +struct rtc_stm32_data { + /* Currently empty */ +}; + +static int rtc_stm32_init(const struct device *dev) +{ + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + if (!device_is_ready(clk)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + /* 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; + } + + /* 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 */ + + /* Enable RTC clock source */ + if (clock_control_configure(clk, (clock_control_subsys_t)&cfg->pclken[1], NULL) != 0) { + LOG_ERR("clock configure failed\n"); + return -EIO; + } + + LL_RCC_EnableRTC(); + + z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); + + if (LL_RTC_Init(RTC, ((LL_RTC_InitTypeDef *)&cfg->ll_rtc_config)) != SUCCESS) { + return -EIO; + } + +#ifdef RTC_CR_BYPSHAD + LL_RTC_DisableWriteProtection(RTC); + LL_RTC_EnableShadowRegBypass(RTC); + LL_RTC_EnableWriteProtection(RTC); +#endif /* RTC_CR_BYPSHAD */ + + return 0; +} + +static const struct stm32_pclken rtc_clk[] = STM32_DT_INST_CLOCKS(0); + +static const struct rtc_stm32_config rtc_config = { + .ll_rtc_config = { + .HourFormat = LL_RTC_HOURFORMAT_24HOUR, +#if DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSI + /* prescaler values for LSI @ 32 KHz */ + .AsynchPrescaler = 0x7F, + .SynchPrescaler = 0x00F9, +#else /* DT_INST_CLOCKS_CELL(1, bus) == STM32_SRC_LSE */ + /* prescaler values for LSE @ 32768 Hz */ + .AsynchPrescaler = 0x7F, + .SynchPrescaler = 0x00FF, +#endif + }, + .pclken = rtc_clk, +}; + +static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + LOG_INF("Setting clock"); + LL_RTC_DisableWriteProtection(RTC); + + LL_RTC_EnableInitMode(RTC); + + while (!LL_RTC_IsActiveFlag_INIT(RTC)) { + }; + + LL_RTC_DATE_SetYear(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_year - TM_TO_RTC_OFFSET)); + LL_RTC_DATE_SetMonth(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_mon + 1)); + LL_RTC_DATE_SetDay(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_mday)); + + LL_RTC_DATE_SetWeekDay(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_wday) + 1); + + LL_RTC_TIME_SetHour(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_hour)); + LL_RTC_TIME_SetMinute(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_min)); + LL_RTC_TIME_SetSecond(RTC, __LL_RTC_CONVERT_BIN2BCD(timeptr->tm_sec)); + + LL_RTC_DisableInitMode(RTC); + + LL_RTC_EnableWriteProtection(RTC); + + return 0; +} + +static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + ARG_UNUSED(dev); + + uint32_t rtc_date, rtc_time; + + /* Read time and date registers */ + rtc_time = LL_RTC_TIME_Get(RTC); + rtc_date = LL_RTC_DATE_Get(RTC); + + timeptr->tm_year = TM_TO_RTC_OFFSET + __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_YEAR(rtc_date)); + /* tm_mon allowed values are 0-11 */ + timeptr->tm_mon = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MONTH(rtc_date)) - 1; + timeptr->tm_mday = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_DAY(rtc_date)); + timeptr->tm_wday = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_WEEKDAY(rtc_date)) - 1; + + timeptr->tm_hour = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_HOUR(rtc_time)); + timeptr->tm_min = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MINUTE(rtc_time)); + timeptr->tm_sec = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_SECOND(rtc_time)); + + timeptr->tm_nsec = LL_RTC_TIME_GetSubSecond(RTC); + + return 0; +} + +struct rtc_driver_api rtc_stm32_driver_api = { + .set_time = rtc_stm32_set_time, + .get_time = rtc_stm32_get_time, + /* RTC_ALARM not supported */ + /* RTC_UPDATE not supported */ +}; + +#define RTC_STM32_DEV_CFG(n) \ + static struct rtc_stm32_data rtc_data_##n = {}; \ + \ + DEVICE_DT_INST_DEFINE(n, &rtc_stm32_init, NULL, &rtc_data_##n, &rtc_config, POST_KERNEL, \ + CONFIG_RTC_INIT_PRIORITY, &rtc_stm32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(RTC_STM32_DEV_CFG); diff --git a/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.overlay b/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.overlay new file mode 100644 index 000000000000..6b78b2a9a577 --- /dev/null +++ b/tests/drivers/rtc/rtc_api/boards/nucleo_h563zi.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Prevas A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + rtc = &rtc; + }; +}; From c811a4f43052f644df476e4b4fef704cd53d77c2 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Fri, 23 Jun 2023 17:28:38 +0200 Subject: [PATCH 1387/2042] drivers: adc: add ADC driver for EFM32 This adds a driver for ADCs available on EFM32 Signed-off-by: Wojciech Sipak --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig.gecko | 9 + drivers/adc/adc_gecko.c | 315 ++++++++++++++++++ dts/bindings/adc/silabs,gecko-adc.yaml | 25 ++ soc/arm/silabs_exx32/Kconfig | 5 + .../silabs_exx32/efm32pg12b/Kconfig.series | 1 + 6 files changed, 356 insertions(+) create mode 100644 drivers/adc/adc_gecko.c create mode 100644 dts/bindings/adc/silabs,gecko-adc.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index eded385c80c1..daf2dff347e6 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_ADC_ADS114S0X adc_ads114s0x.c) zephyr_library_sources_ifdef(CONFIG_ADC_RPI_PICO adc_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_ADC_XMC4XXX adc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_ADC_ESP32 adc_esp32.c) +zephyr_library_sources_ifdef(CONFIG_ADC_GECKO_ADC adc_gecko.c) zephyr_library_sources_ifdef(CONFIG_ADC_GECKO_IADC iadc_gecko.c) zephyr_library_sources_ifdef(CONFIG_ADC_INFINEON_CAT1 adc_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_GPADC adc_smartbond_gpadc.c) diff --git a/drivers/adc/Kconfig.gecko b/drivers/adc/Kconfig.gecko index 72de957c9aa8..693803b26c9d 100644 --- a/drivers/adc/Kconfig.gecko +++ b/drivers/adc/Kconfig.gecko @@ -11,3 +11,12 @@ config ADC_GECKO_IADC select ADC_CONFIGURABLE_INPUTS help Enable the driver implementation for the Silabs GeckoEXX32 Incremental ADC + +config ADC_GECKO_ADC + bool "Gecko ADC driver" + default y + depends on DT_HAS_SILABS_GECKO_ADC_ENABLED + select SOC_GECKO_ADC + select ADC_CONFIGURABLE_INPUTS + help + Enable the driver implementation for the Silabs GeckoEFM32 ADC diff --git a/drivers/adc/adc_gecko.c b/drivers/adc/adc_gecko.c new file mode 100644 index 000000000000..d8544cebd612 --- /dev/null +++ b/drivers/adc/adc_gecko.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT silabs_gecko_adc + +#include + +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#include +LOG_MODULE_REGISTER(adc_gecko, CONFIG_ADC_LOG_LEVEL); + +/* Number of channels available. */ +#define GECKO_CHANNEL_COUNT 16 + +struct adc_gecko_channel_config { + bool initialized; + ADC_Ref_TypeDef reference; + ADC_PosSel_TypeDef input_select; +}; + +struct adc_gecko_data { + const struct device *dev; + struct adc_context ctx; + uint16_t *buffer; + uint16_t *repeat_buffer; + uint32_t channels; + uint8_t channel_id; + ADC_Res_TypeDef resolution; + struct adc_gecko_channel_config channel_config[GECKO_CHANNEL_COUNT]; +}; + +struct adc_gecko_config { + ADC_TypeDef *base; + void (*irq_cfg_func)(void); + uint32_t frequency; +}; + +static void adc_gecko_set_config(const struct device *dev) +{ + struct adc_gecko_data *data = dev->data; + struct adc_gecko_channel_config *channel_config = NULL; + const struct adc_gecko_config *config = dev->config; + ADC_TypeDef *adc_base = (ADC_TypeDef *)config->base; + + ADC_Init_TypeDef init = ADC_INIT_DEFAULT; + ADC_InitSingle_TypeDef initSingle = ADC_INITSINGLE_DEFAULT; + + channel_config = &data->channel_config[data->channel_id]; + + init.prescale = ADC_PrescaleCalc(config->frequency, 0); + init.timebase = ADC_TimebaseCalc(0); + + initSingle.diff = false; + initSingle.reference = channel_config->reference; + initSingle.resolution = data->resolution; + initSingle.acqTime = adcAcqTime4; + + initSingle.posSel = channel_config->input_select; + + ADC_Init(adc_base, &init); + ADC_InitSingle(adc_base, &initSingle); +} + +static int adc_gecko_check_buffer_size(const struct adc_sequence *sequence, + uint8_t active_channels) +{ + size_t needed_buffer_size; + + needed_buffer_size = active_channels * sizeof(uint16_t); + + if (sequence->options) { + needed_buffer_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_buffer_size) { + LOG_DBG("Provided buffer is too small (%u/%u)", + sequence->buffer_size, needed_buffer_size); + return -ENOMEM; + } + + return 0; +} + +static int start_read(const struct device *dev, const struct adc_sequence *sequence) +{ + + struct adc_gecko_data *data = dev->data; + uint32_t channels; + uint8_t channel_count; + uint8_t index; + int res; + + /* Check if at least 1 channel is requested */ + if (sequence->channels == 0) { + LOG_DBG("No channel requested"); + return -EINVAL; + } + + if (sequence->oversampling) { + LOG_ERR("Oversampling is not supported"); + return -ENOTSUP; + } + + /* Verify all requested channels are initialized and store resolution */ + channels = sequence->channels; + channel_count = 0; + while (channels) { + /* Iterate through all channels and check if they are initialized */ + index = find_lsb_set(channels) - 1; + if (index >= GECKO_CHANNEL_COUNT) { + LOG_DBG("Requested channel index not available: %d", index); + return -EINVAL; + } + + if (!data->channel_config[index].initialized) { + LOG_DBG("Channel not initialized"); + return -EINVAL; + } + channel_count++; + channels &= ~BIT(index); + } + + res = adc_gecko_check_buffer_size(sequence, channel_count); + if (res < 0) { + return res; + } + + data->buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + + res = adc_context_wait_for_completion(&data->ctx); + + return res; +} + +static void adc_gecko_start_channel(const struct device *dev) +{ + const struct adc_gecko_config *config = dev->config; + struct adc_gecko_data *data = dev->data; + ADC_TypeDef *adc_base = (ADC_TypeDef *)config->base; + + data->channel_id = find_lsb_set(data->channels) - 1; + adc_gecko_set_config(data->dev); + + ADC_IntEnable(adc_base, ADC_IEN_SINGLE); + ADC_Start(adc_base, adcStartSingle); +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_gecko_data *data = CONTAINER_OF(ctx, struct adc_gecko_data, ctx); + + data->channels = ctx->sequence.channels; + adc_gecko_start_channel(data->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repeat_sampling) +{ + struct adc_gecko_data *data = CONTAINER_OF(ctx, struct adc_gecko_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void adc_gecko_isr(void *arg) +{ + const struct device *dev = (const struct device *)arg; + const struct adc_gecko_config *config = dev->config; + struct adc_gecko_data *data = dev->data; + ADC_TypeDef *adc_base = config->base; + + uint32_t sample = 0; + uint32_t flags, err; + + flags = ADC_IntGet(adc_base); + + __ASSERT(flags & ADC_IF_SINGLE, "unexpected ADC IRQ (flags=0x%08x)!", flags); + + err = flags & (ADC_IF_EM23ERR | ADC_IF_PROGERR | ADC_IF_VREFOV | ADC_IF_SINGLEOF); + + if (!err) { + sample = ADC_DataSingleGet(adc_base); + *data->buffer++ = (uint16_t)sample; + data->channels &= ~BIT(data->channel_id); + + if (data->channels) { + adc_gecko_start_channel(dev); + } else { + adc_context_on_sampling_done(&data->ctx, dev); + } + } else { + LOG_ERR("ADC conversion error, flags=%08x", err); + adc_context_complete(&data->ctx, -EIO); + } + ADC_IntClear(adc_base, ADC_IF_SINGLE | err); +} + +static int adc_gecko_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_gecko_data *data = dev->data; + int error; + + adc_context_lock(&data->ctx, false, NULL); + error = start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +static int adc_gecko_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + struct adc_gecko_data *data = dev->data; + struct adc_gecko_channel_config *channel_config = NULL; + + if (channel_cfg->channel_id < GECKO_CHANNEL_COUNT) { + channel_config = &data->channel_config[channel_cfg->channel_id]; + } else { + LOG_DBG("Requested channel index not available: %d", channel_cfg->channel_id); + return -EINVAL; + } + + channel_config->initialized = false; + + channel_config->input_select = channel_cfg->input_positive; + + switch (channel_cfg->gain) { + case ADC_GAIN_1: + break; + default: + LOG_ERR("unsupported channel gain '%d'", channel_cfg->gain); + return -ENOTSUP; + } + + switch (channel_cfg->reference) { + case ADC_REF_VDD_1: + channel_config->reference = adcRef5V; + break; + case ADC_REF_VDD_1_2: + channel_config->reference = adcRef2V5; + break; + case ADC_REF_VDD_1_4: + channel_config->reference = adcRef1V25; + break; + default: + LOG_ERR("unsupported channel reference type '%d'", channel_cfg->reference); + return -ENOTSUP; + } + + channel_config->initialized = true; + return 0; +} + +static int adc_gecko_init(const struct device *dev) +{ + const struct adc_gecko_config *config = dev->config; + struct adc_gecko_data *data = dev->data; + + CMU_ClockEnable(cmuClock_HFPER, true); + CMU_ClockEnable(cmuClock_ADC0, true); + + data->dev = dev; + data->resolution = adcRes12Bit; + + config->irq_cfg_func(); + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api api_gecko_adc_driver_api = { + .channel_setup = adc_gecko_channel_setup, + .read = adc_gecko_read, +}; + +#define GECKO_ADC_INIT(n) \ + \ + static void adc_gecko_config_func_##n(void); \ + \ + const static struct adc_gecko_config adc_gecko_config_##n = { \ + .base = (ADC_TypeDef *)DT_INST_REG_ADDR(n), \ + .irq_cfg_func = adc_gecko_config_func_##n, \ + .frequency = DT_INST_PROP(n, frequency), \ + }; \ + static struct adc_gecko_data adc_gecko_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(adc_gecko_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_gecko_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_gecko_data_##n, ctx), \ + }; \ + static void adc_gecko_config_func_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + adc_gecko_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &adc_gecko_init, NULL, \ + &adc_gecko_data_##n, &adc_gecko_config_##n,\ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &api_gecko_adc_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(GECKO_ADC_INIT) diff --git a/dts/bindings/adc/silabs,gecko-adc.yaml b/dts/bindings/adc/silabs,gecko-adc.yaml new file mode 100644 index 000000000000..33327498e6ca --- /dev/null +++ b/dts/bindings/adc/silabs,gecko-adc.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Silicon Labs Gecko Series 1 ADC + +compatible: "silabs,gecko-adc" + +include: adc-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + frequency: + type: int + required: true + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/soc/arm/silabs_exx32/Kconfig b/soc/arm/silabs_exx32/Kconfig index 95b2be39f1b0..af050de81090 100644 --- a/soc/arm/silabs_exx32/Kconfig +++ b/soc/arm/silabs_exx32/Kconfig @@ -39,6 +39,11 @@ config SOC_GECKO_CORE help Set if the Core interrupt handling (CORE) HAL module is used. +config SOC_GECKO_ADC + bool + help + Set if the Analog to Digital Converter (ADC) HAL module is used. + config SOC_GECKO_IADC bool help diff --git a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series index 7f99d6d64b8b..3f3a3ca39f64 100644 --- a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFM32PG12B select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select SOC_GECKO_ADC help Enable support for EFM32 PearlGecko MCU series From 6fe016984c9258bb2b5f5e13965747408c2548c2 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Tue, 4 Jul 2023 13:23:46 +0200 Subject: [PATCH 1388/2042] boards: efm32pg_stk3402a: use gecko-adc This adds a proper ADC node that uses the gecko-adc driver. Signed-off-by: Wojciech Sipak --- .../efm32pg_stk3402a_common.dtsi | 6 ++++- dts/arm/silabs/efm32_jg_pg_12b.dtsi | 10 ++++++++ .../adc/boards/efm32pg_stk3402a.overlay | 25 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/adc/boards/efm32pg_stk3402a.overlay diff --git a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi index d862a0da5b77..8d45639bcb71 100644 --- a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi +++ b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi @@ -153,5 +153,9 @@ }; &trng0 { - status = "okay"; + status = "okay"; +}; + +&adc0 { + status = "okay"; }; diff --git a/dts/arm/silabs/efm32_jg_pg_12b.dtsi b/dts/arm/silabs/efm32_jg_pg_12b.dtsi index 7280d1050d49..59680df2c559 100644 --- a/dts/arm/silabs/efm32_jg_pg_12b.dtsi +++ b/dts/arm/silabs/efm32_jg_pg_12b.dtsi @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -243,6 +244,15 @@ #pwm-cells = <3>; }; }; + + adc0: adc@40002000 { + compatible = "silabs,gecko-adc"; + reg = <0x40002000 0x400>; + interrupts = <15 0>; + frequency = <16000000>; + status = "disabled"; + #io-channel-cells = <1>; + }; }; }; diff --git a/samples/drivers/adc/boards/efm32pg_stk3402a.overlay b/samples/drivers/adc/boards/efm32pg_stk3402a.overlay new file mode 100644 index 000000000000..efce5c908cc5 --- /dev/null +++ b/samples/drivers/adc/boards/efm32pg_stk3402a.overlay @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Antmicro + */ + +/ { + zephyr,user { + io-channels = <&adc0 3>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_VDD_1"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + zephyr,input-positive = <0>; + }; +}; From e11cc216b1025bdb6c3b30d0d21e46d00b8736b8 Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Wed, 5 Jul 2023 15:40:03 +0200 Subject: [PATCH 1389/2042] tests: lib: json: add extra nested array 2dim tests Add tests with extra JSON fields with 2dim array. Signed-off-by: Bartosz Bilas --- tests/lib/json/src/main.c | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index f0ebce6f03ca..6dd209528d03 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -121,6 +121,20 @@ static const struct json_obj_descr array_2dim_descr[] = { ARRAY_SIZE(obj_array_descr)), }; +struct obj_array_2dim_extra { + const char *name; + int val; + struct obj_array_2dim obj_array_2dim; +}; + +static const struct json_obj_descr array_2dim_extra_descr[] = { + JSON_OBJ_DESCR_PRIM(struct obj_array_2dim_extra, name, JSON_TOK_STRING), + JSON_OBJ_DESCR_PRIM(struct obj_array_2dim_extra, val, JSON_TOK_NUMBER), + JSON_OBJ_DESCR_ARRAY_ARRAY(struct obj_array_2dim_extra, obj_array_2dim, 3, + obj_array_2dim.objects_array_array_len, obj_array_descr, + ARRAY_SIZE(obj_array_descr)), +}; + ZTEST(lib_json_test, test_json_encoding) { struct test_struct ts = { @@ -601,6 +615,89 @@ ZTEST(lib_json_test, test_json_2dim_arr_obj_encoding) "Encoded two-dimensional array is not consistent"); } +ZTEST(lib_json_test, test_json_2dim_arr_extra_obj_encoding) +{ + struct obj_array_2dim_extra obj_array_2dim_extra_ts = { + .name = "Paavo Nurmi", + .val = 123, + .obj_array_2dim.objects_array_array = { + [0] = { + .elements = { + [0] = { + .name = "Sim\303\263n Bol\303\255var", + .height = 168 + }, + [1] = { + .name = "Pel\303\251", + .height = 173 + }, + [2] = { + .name = "Usain Bolt", + .height = 195 + }, + }, + .num_elements = 3 + }, + [1] = { + .elements = { + [0] = { + .name = "Muggsy Bogues", + .height = 160 + }, + [1] = { + .name = "Hakeem Olajuwon", + .height = 213 + }, + }, + .num_elements = 2 + }, + [2] = { + .elements = { + [0] = { + .name = "Alex Honnold", + .height = 180 + }, + [1] = { + .name = "Hazel Findlay", + .height = 157 + }, + [2] = { + .name = "Daila Ojeda", + .height = 158 + }, + [3] = { + .name = "Albert Einstein", + .height = 172 + }, + }, + .num_elements = 4 + }, + }, + .obj_array_2dim.objects_array_array_len = 3, + }; + + char encoded[] = "{\"name\":\"Paavo Nurmi\",\"val\":123," + "\"obj_array_2dim\":[" + "[{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," + "{\"name\":\"Pel\303\251\",\"height\":173}," + "{\"name\":\"Usain Bolt\",\"height\":195}]," + "[{\"name\":\"Muggsy Bogues\",\"height\":160}," + "{\"name\":\"Hakeem Olajuwon\",\"height\":213}]," + "[{\"name\":\"Alex Honnold\",\"height\":180}," + "{\"name\":\"Hazel Findlay\",\"height\":157}," + "{\"name\":\"Daila Ojeda\",\"height\":158}," + "{\"name\":\"Albert Einstein\",\"height\":172}]" + "]}"; + char buffer[sizeof(encoded)]; + int ret; + + ret = json_obj_encode_buf(array_2dim_extra_descr, ARRAY_SIZE(array_2dim_extra_descr), + &obj_array_2dim_extra_ts, buffer, sizeof(buffer)); + zassert_equal(ret, 0, "Encoding two-dimensional extra array returned error"); + zassert_true(!strcmp(buffer, encoded), + "Encoded two-dimensional extra array is not consistent"); +} + ZTEST(lib_json_test, test_json_2dim_obj_arr_decoding) { struct obj_array_2dim oaa; From 650a0d8331573224917949f7e53c54910ced7930 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 7 Jul 2023 11:52:20 +0200 Subject: [PATCH 1390/2042] Bluetooth: audio: tbs_client: Separate GTBS from TBS instances This improves the code readability and reduces flash usage a bit by spliting up GTBS from other TBS instances in bt_tbs_server_inst structure, so that some of the code could be conditionally compiled out. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs_client.c | 243 ++++++++++++++++++---------- 1 file changed, 160 insertions(+), 83 deletions(-) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 3f4c61acfa6d..1fb10ff64b7b 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -45,29 +45,46 @@ BUILD_ASSERT(CONFIG_BT_L2CAP_TX_BUF_COUNT >= TBS_CLIENT_BUF_COUNT, "Too few L2CA #include "common/bt_str.h" +struct bt_tbs_server_inst { +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 + struct bt_tbs_instance tbs_insts[CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES]; + uint8_t inst_cnt; +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ #if defined(CONFIG_BT_TBS_CLIENT_GTBS) -#define BT_TBS_INSTANCE_MAX_CNT (CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES + 1) -#else -#define BT_TBS_INSTANCE_MAX_CNT CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES + struct bt_tbs_instance gtbs_inst; #endif /* IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) */ - -struct bt_tbs_server_inst { - struct bt_tbs_instance tbs_insts[BT_TBS_INSTANCE_MAX_CNT]; struct bt_gatt_discover_params discover_params; struct bt_tbs_instance *current_inst; - struct bt_tbs_instance *gtbs; - uint8_t inst_cnt; bool subscribe_all; }; static const struct bt_tbs_client_cb *tbs_client_cbs; static struct bt_tbs_server_inst srv_insts[CONFIG_BT_MAX_CONN]; -static const struct bt_uuid *tbs_uuid = BT_UUID_TBS; -static const struct bt_uuid *gtbs_uuid = BT_UUID_GTBS; static void discover_next_instance(struct bt_conn *conn, uint8_t index); +typedef bool (*tbs_instance_find_func_t)(struct bt_tbs_instance *inst, void *user_data); + +static struct bt_tbs_instance *tbs_instance_find(struct bt_tbs_server_inst *server, + tbs_instance_find_func_t func, void *user_data) +{ +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) + if (func(&server->gtbs_inst, user_data)) { + return &server->gtbs_inst; + } +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 + for (size_t i = 0; i < server->inst_cnt; i++) { + if (func(&server->tbs_insts[i], user_data)) { + return &server->tbs_insts[i]; + } + } +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ + + return NULL; +} + static struct bt_tbs_instance *tbs_inst_by_index(struct bt_conn *conn, uint8_t index) { struct bt_tbs_server_inst *server; @@ -76,20 +93,16 @@ static struct bt_tbs_instance *tbs_inst_by_index(struct bt_conn *conn, uint8_t i server = &srv_insts[bt_conn_index(conn)]; - if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS)) { - /* GTBS can be accessed by BT_TBS_GTBS_INDEX only */ - if (index == ARRAY_SIZE(server->tbs_insts) - 1) { - return NULL; - } - - if (index == BT_TBS_GTBS_INDEX) { - return server->gtbs; - } +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) + if (index == BT_TBS_GTBS_INDEX) { + return &server->gtbs_inst; } - +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 if (index < server->inst_cnt) { return &server->tbs_insts[index]; } +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ return NULL; } @@ -104,12 +117,19 @@ static uint8_t tbs_index(struct bt_conn *conn, const struct bt_tbs_instance *ins server = &srv_insts[bt_conn_index(conn)]; - if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) && inst == server->gtbs) { +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) + if (inst == &server->gtbs_inst) { return BT_TBS_GTBS_INDEX; } - +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 index = inst - server->tbs_insts; - __ASSERT_NO_MSG(index >= 0 && index < ARRAY_SIZE(server->tbs_insts)); + __ASSERT(index >= 0 && index < ARRAY_SIZE(server->tbs_insts), + "Invalid bt_tbs_instance pointer"); + +#else + __ASSERT_PRINT("Invalid bt_tbs_instance pointer"); +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ return (uint8_t)index; } @@ -127,23 +147,30 @@ static bool free_call_spot(struct bt_tbs_instance *inst) } #endif /* defined(CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL) */ +static bool is_instance_handle(struct bt_tbs_instance *inst, void *user_data) +{ + uint16_t handle = POINTER_TO_UINT(user_data); + + return inst->start_handle <= handle && inst->end_handle >= handle; +} + static struct bt_tbs_instance *lookup_inst_by_handle(struct bt_conn *conn, uint16_t handle) { uint8_t conn_index; struct bt_tbs_server_inst *srv_inst; + struct bt_tbs_instance *inst; __ASSERT(conn, "NULL conn"); conn_index = bt_conn_index(conn); srv_inst = &srv_insts[conn_index]; - for (size_t i = 0; i < ARRAY_SIZE(srv_inst->tbs_insts); i++) { - if (srv_inst->tbs_insts[i].start_handle <= handle && - srv_inst->tbs_insts[i].end_handle >= handle) { - return &srv_inst->tbs_insts[i]; - } + inst = tbs_instance_find(srv_inst, is_instance_handle, UINT_TO_POINTER(handle)); + if (inst != NULL) { + return inst; } + LOG_DBG("Could not find instance with handle 0x%04x", handle); return NULL; @@ -655,6 +682,24 @@ static int tbs_client_gatt_read(struct bt_conn *conn, struct bt_tbs_instance *in return 0; } +static bool gtbs_found(struct bt_tbs_server_inst *srv_inst) +{ +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) + return srv_inst->gtbs_inst.start_handle != 0; +#else + return false; +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ +} + +static uint8_t inst_cnt(struct bt_tbs_server_inst *srv_inst) +{ +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 + return srv_inst->inst_cnt; +#else + return 0; +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +} + static void tbs_client_discover_complete(struct bt_conn *conn, int err) { struct bt_tbs_server_inst *srv_inst = &srv_insts[bt_conn_index(conn)]; @@ -665,7 +710,7 @@ static void tbs_client_discover_complete(struct bt_conn *conn, int err) srv_inst->current_inst = NULL; if (tbs_client_cbs != NULL && tbs_client_cbs->discover != NULL) { - tbs_client_cbs->discover(conn, err, srv_inst->inst_cnt, srv_inst->gtbs != NULL); + tbs_client_cbs->discover(conn, err, inst_cnt(srv_inst), gtbs_found(srv_inst)); } } @@ -1325,17 +1370,17 @@ static uint8_t disc_read_ccid_cb(struct bt_conn *conn, uint8_t err, if (cb_err != 0) { tbs_client_discover_complete(conn, cb_err); } else { - if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) && inst == srv_inst->gtbs) { + if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) && inst_index == BT_TBS_GTBS_INDEX) { LOG_DBG("Setup complete GTBS"); inst_index = 0; } else { inst_index++; - LOG_DBG("Setup complete for %u / %u TBS", inst_index, srv_inst->inst_cnt); + LOG_DBG("Setup complete for %u / %u TBS", inst_index, inst_cnt(srv_inst)); } - if (inst_index < srv_inst->inst_cnt) { + if (inst_index < inst_cnt(srv_inst)) { discover_next_instance(conn, inst_index); } else { tbs_client_discover_complete(conn, 0); @@ -1552,15 +1597,15 @@ static void discover_next_instance(struct bt_conn *conn, uint8_t index) static void primary_discover_complete(struct bt_tbs_server_inst *server, struct bt_conn *conn) { if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS)) { - LOG_DBG("Discover complete, found %u instances (GTBS%s found)", server->inst_cnt, - server->gtbs != NULL ? "" : " not"); + LOG_DBG("Discover complete, found %u instances (GTBS%s found)", + inst_cnt(server), gtbs_found(server) ? "" : " not"); } else { - LOG_DBG("Discover complete, found %u instances", server->inst_cnt); + LOG_DBG("Discover complete, found %u instances", inst_cnt(server)); } - if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) && server->gtbs != NULL) { + if (gtbs_found(server)) { discover_next_instance(conn, BT_TBS_GTBS_INDEX); - } else if (server->inst_cnt > 0) { + } else if (inst_cnt(server) > 0) { discover_next_instance(conn, 0); } else { tbs_client_discover_complete(conn, 0); @@ -1572,12 +1617,17 @@ static void primary_discover_complete(struct bt_tbs_server_inst *server, struct * handles of the writeable characteristics and subscribing to all notify and * indicate characteristics. */ -static uint8_t primary_discover_tbs(struct bt_conn *conn, const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +static const struct bt_uuid *tbs_uuid = BT_UUID_TBS; + +static uint8_t primary_discover_tbs_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { const uint8_t conn_index = bt_conn_index(conn); struct bt_tbs_server_inst *srv_inst = &srv_insts[conn_index]; + LOG_DBG("conn %p attr %p", (void *)conn, attr); + if (attr != NULL) { const struct bt_gatt_service_val *prim_service; @@ -1589,8 +1639,7 @@ static uint8_t primary_discover_tbs(struct bt_conn *conn, const struct bt_gatt_a srv_inst->current_inst->start_handle = attr->handle + 1; srv_inst->current_inst->end_handle = prim_service->end_handle; - if (CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 1 && - srv_inst->inst_cnt < CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES) { + if (srv_inst->inst_cnt < CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES) { return BT_GATT_ITER_CONTINUE; } } @@ -1600,12 +1649,35 @@ static uint8_t primary_discover_tbs(struct bt_conn *conn, const struct bt_gatt_a return BT_GATT_ITER_STOP; } -static uint8_t primary_discover_gtbs(struct bt_conn *conn, const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) +static int primary_discover_tbs(struct bt_conn *conn) +{ + struct bt_tbs_server_inst *srv_inst = &srv_insts[bt_conn_index(conn)]; + struct bt_gatt_discover_params *params = &srv_inst->discover_params; + + LOG_DBG("conn %p", (void *)conn); + + (void)memset(params, 0, sizeof(*params)); + params->uuid = tbs_uuid; + params->func = primary_discover_tbs_cb; + params->type = BT_GATT_DISCOVER_PRIMARY; + params->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + params->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + return bt_gatt_discover(conn, params); +} +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ + +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) +static const struct bt_uuid *gtbs_uuid = BT_UUID_GTBS; + +static uint8_t primary_discover_gtbs_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { const uint8_t conn_index = bt_conn_index(conn); struct bt_tbs_server_inst *srv_inst = &srv_insts[conn_index]; + LOG_DBG("conn %p attr %p", (void *)conn, attr); + if (attr != NULL) { const struct bt_gatt_service_val *prim_service; @@ -1613,34 +1685,45 @@ static uint8_t primary_discover_gtbs(struct bt_conn *conn, const struct bt_gatt_ prim_service = (struct bt_gatt_service_val *)attr->user_data; - /* GTBS is placed as the "last" instance */ - srv_inst->gtbs = &srv_inst->tbs_insts[ARRAY_SIZE(srv_inst->tbs_insts) - 1]; - srv_inst->gtbs->start_handle = attr->handle + 1; - srv_inst->gtbs->end_handle = prim_service->end_handle; - - srv_inst->current_inst = srv_inst->gtbs; + srv_inst->current_inst = &srv_inst->gtbs_inst; + srv_inst->current_inst->start_handle = attr->handle + 1; + srv_inst->current_inst->end_handle = prim_service->end_handle; } - if (CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0) { - int err; - - params->uuid = tbs_uuid; - params->func = primary_discover_tbs; - params->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; - - err = bt_gatt_discover(conn, params); - if (err == 0) { - return BT_GATT_ITER_STOP; - } +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 + int err; - LOG_DBG("Discover failed (err %d)", err); + err = primary_discover_tbs(conn); + if (err == 0) { + return BT_GATT_ITER_STOP; } + LOG_DBG("Discover failed (err %d)", err); +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ + primary_discover_complete(srv_inst, conn); return BT_GATT_ITER_STOP; } +static int primary_discover_gtbs(struct bt_conn *conn) +{ + struct bt_tbs_server_inst *srv_inst = &srv_insts[bt_conn_index(conn)]; + struct bt_gatt_discover_params *params = &srv_inst->discover_params; + + LOG_DBG("conn %p", (void *)conn); + + (void)memset(params, 0, sizeof(*params)); + params->uuid = gtbs_uuid; + params->func = primary_discover_gtbs_cb; + params->type = BT_GATT_DISCOVER_PRIMARY; + params->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + params->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + return bt_gatt_discover(conn, params); +} +#endif /* IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) */ + /****************************** PUBLIC API ******************************/ #if defined(CONFIG_BT_TBS_CLIENT_HOLD_CALL) @@ -2151,25 +2234,18 @@ int bt_tbs_client_discover(struct bt_conn *conn, bool subscribe) return -EBUSY; } +#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 (void)memset(srv_inst->tbs_insts, 0, sizeof(srv_inst->tbs_insts)); /* reset data */ srv_inst->inst_cnt = 0; - srv_inst->gtbs = NULL; +#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ /* Discover TBS on peer, setup handles and notify/indicate */ srv_inst->subscribe_all = subscribe; - (void)memset(&srv_inst->discover_params, 0, sizeof(srv_inst->discover_params)); - if (IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS)) { - LOG_DBG("Discovering GTBS"); - srv_inst->discover_params.uuid = gtbs_uuid; - srv_inst->discover_params.func = primary_discover_gtbs; - } else { - srv_inst->discover_params.uuid = tbs_uuid; - srv_inst->discover_params.func = primary_discover_tbs; - } - srv_inst->discover_params.type = BT_GATT_DISCOVER_PRIMARY; - srv_inst->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; - srv_inst->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - - return bt_gatt_discover(conn, &srv_inst->discover_params); +#if defined(CONFIG_BT_TBS_CLIENT_GTBS) + (void)memset(&srv_inst->gtbs_inst, 0, sizeof(srv_inst->gtbs_inst)); /* reset data */ + return primary_discover_gtbs(conn); +#else + return primary_discover_tbs(conn); +#endif /* CONFIG_BT_TBS_CLIENT_GTBS */ } void bt_tbs_client_register_cb(const struct bt_tbs_client_cb *cbs) @@ -2178,6 +2254,13 @@ void bt_tbs_client_register_cb(const struct bt_tbs_client_cb *cbs) } #if defined(CONFIG_BT_TBS_CLIENT_CCID) +static bool tbs_instance_ccid_is_eq(struct bt_tbs_instance *inst, void *user_data) +{ + uint8_t ccid = POINTER_TO_UINT(user_data); + + return inst->ccid == ccid; +} + struct bt_tbs_instance *bt_tbs_client_get_by_ccid(const struct bt_conn *conn, uint8_t ccid) { @@ -2190,12 +2273,6 @@ struct bt_tbs_instance *bt_tbs_client_get_by_ccid(const struct bt_conn *conn, server = &srv_insts[bt_conn_index(conn)]; - for (size_t i = 0; i < ARRAY_SIZE(server->tbs_insts); i++) { - if (server->tbs_insts[i].ccid == ccid) { - return &server->tbs_insts[i]; - } - } - - return NULL; + return tbs_instance_find(server, tbs_instance_ccid_is_eq, UINT_TO_POINTER(ccid)); } #endif /* defined(CONFIG_BT_TBS_CLIENT_CCID) */ From c09c4181cf6d55a6817d2bda90660ca49e806fc5 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 7 Jul 2023 14:09:19 +0200 Subject: [PATCH 1391/2042] Bluetooth: audio: tbs_client: Minor Kconfig refactor This intoduces dedicated Kconfig option to enable TBS client, that makes the configuration more intuitive. While configuring GTBS only, the user does not have to explicitly set the BT_TBS_CLIENT_MAX_TBS_INSTANCES to 0 to disable the TBS client functionality. This adds also `tbs_only_client` test case to test the TBS only build option. Signed-off-by: Mariusz Skamra --- samples/bluetooth/hap_ha/prj.conf | 2 -- samples/bluetooth/tmap_peripheral/prj.conf | 2 -- subsys/bluetooth/audio/Kconfig.tbs | 23 ++++++++------- subsys/bluetooth/audio/tbs_client.c | 34 +++++++++++----------- tests/bluetooth/shell/audio.conf | 3 +- tests/bluetooth/shell/testcase.yaml | 12 ++++++-- tests/bsim/bluetooth/audio/prj.conf | 3 +- 7 files changed, 43 insertions(+), 36 deletions(-) diff --git a/samples/bluetooth/hap_ha/prj.conf b/samples/bluetooth/hap_ha/prj.conf index 53240f86c614..179b5a5f4d72 100644 --- a/samples/bluetooth/hap_ha/prj.conf +++ b/samples/bluetooth/hap_ha/prj.conf @@ -54,10 +54,8 @@ CONFIG_BT_VCP_VOL_REND_VOCS_INSTANCE_COUNT=1 CONFIG_BT_BAS=y CONFIG_BT_IAS=y -CONFIG_BT_TBS_CLIENT=y CONFIG_BT_TBS_CLIENT_MINIMAL=y CONFIG_BT_TBS_CLIENT_GTBS=y -CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=0 CONFIG_BT_TBS_CLIENT_CCID=y CONFIG_BT_TBS_CLIENT_STATUS_FLAGS=y diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index d742e1f2c442..756f86db3ab6 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -43,9 +43,7 @@ CONFIG_BT_PAC_SNK_LOC=y CONFIG_BT_PAC_SRC_LOC=y # CCP Client Support -CONFIG_BT_TBS_CLIENT=y CONFIG_BT_TBS_CLIENT_GTBS=y -CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES=0 CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL=y CONFIG_BT_TBS_CLIENT_TERMINATE_CALL=y CONFIG_BT_TBS_CLIENT_BEARER_URI_SCHEMES_SUPPORTED_LIST=y diff --git a/subsys/bluetooth/audio/Kconfig.tbs b/subsys/bluetooth/audio/Kconfig.tbs index 4fbf4a2098ac..2ca4492d2d04 100644 --- a/subsys/bluetooth/audio/Kconfig.tbs +++ b/subsys/bluetooth/audio/Kconfig.tbs @@ -132,22 +132,23 @@ endif # BT_TBS ##################### Call Control Client ##################### +config BT_TBS_CLIENT_GTBS + bool "Generic Telephone Bearer Service client support" + help + This option enables support for the GTBS-oriented Call Control client. + +config BT_TBS_CLIENT_TBS + bool "Telephone Bearer Service client support" + help + This option enables support for the TBS-oriented Call Control client. + config BT_TBS_CLIENT - bool "Telephone Bearer Service client" + def_bool BT_TBS_CLIENT_GTBS || BT_TBS_CLIENT_TBS select BT_GATT_CLIENT select BT_GATT_AUTO_DISCOVER_CCC - help - This option enables support for Telephone Bearer Service client. if BT_TBS_CLIENT -config BT_TBS_CLIENT_GTBS - bool "Telephone Bearer Service client GTBS support" - default y - help - This option enables support for the generic TBS for the - Call Control client. - config BT_TBS_CLIENT_MAX_CALLS int "Maximum Number Of Calls Supported" default 1 @@ -156,8 +157,8 @@ config BT_TBS_CLIENT_MAX_CALLS config BT_TBS_CLIENT_MAX_TBS_INSTANCES int "Maximum number of TBS instances to setup" + depends on BT_TBS_CLIENT_TBS default 1 - range 0 3 if BT_TBS_CLIENT_GTBS range 1 3 help Sets the maximum number of Telephone Bearer Service (TBS) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 1fb10ff64b7b..80d48c2e29f3 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -46,10 +46,10 @@ BUILD_ASSERT(CONFIG_BT_L2CAP_TX_BUF_COUNT >= TBS_CLIENT_BUF_COUNT, "Too few L2CA #include "common/bt_str.h" struct bt_tbs_server_inst { -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) struct bt_tbs_instance tbs_insts[CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES]; uint8_t inst_cnt; -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ #if defined(CONFIG_BT_TBS_CLIENT_GTBS) struct bt_tbs_instance gtbs_inst; #endif /* IS_ENABLED(CONFIG_BT_TBS_CLIENT_GTBS) */ @@ -74,13 +74,13 @@ static struct bt_tbs_instance *tbs_instance_find(struct bt_tbs_server_inst *serv return &server->gtbs_inst; } #endif /* CONFIG_BT_TBS_CLIENT_GTBS */ -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) for (size_t i = 0; i < server->inst_cnt; i++) { if (func(&server->tbs_insts[i], user_data)) { return &server->tbs_insts[i]; } } -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ return NULL; } @@ -98,11 +98,11 @@ static struct bt_tbs_instance *tbs_inst_by_index(struct bt_conn *conn, uint8_t i return &server->gtbs_inst; } #endif /* CONFIG_BT_TBS_CLIENT_GTBS */ -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) if (index < server->inst_cnt) { return &server->tbs_insts[index]; } -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ return NULL; } @@ -122,14 +122,14 @@ static uint8_t tbs_index(struct bt_conn *conn, const struct bt_tbs_instance *ins return BT_TBS_GTBS_INDEX; } #endif /* CONFIG_BT_TBS_CLIENT_GTBS */ -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) index = inst - server->tbs_insts; __ASSERT(index >= 0 && index < ARRAY_SIZE(server->tbs_insts), "Invalid bt_tbs_instance pointer"); #else __ASSERT_PRINT("Invalid bt_tbs_instance pointer"); -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ return (uint8_t)index; } @@ -693,11 +693,11 @@ static bool gtbs_found(struct bt_tbs_server_inst *srv_inst) static uint8_t inst_cnt(struct bt_tbs_server_inst *srv_inst) { -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) return srv_inst->inst_cnt; #else return 0; -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ } static void tbs_client_discover_complete(struct bt_conn *conn, int err) @@ -1617,7 +1617,7 @@ static void primary_discover_complete(struct bt_tbs_server_inst *server, struct * handles of the writeable characteristics and subscribing to all notify and * indicate characteristics. */ -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) static const struct bt_uuid *tbs_uuid = BT_UUID_TBS; static uint8_t primary_discover_tbs_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, @@ -1639,7 +1639,7 @@ static uint8_t primary_discover_tbs_cb(struct bt_conn *conn, const struct bt_gat srv_inst->current_inst->start_handle = attr->handle + 1; srv_inst->current_inst->end_handle = prim_service->end_handle; - if (srv_inst->inst_cnt < CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES) { + if (srv_inst->inst_cnt < ARRAY_SIZE(srv_inst->tbs_insts)) { return BT_GATT_ITER_CONTINUE; } } @@ -1665,7 +1665,7 @@ static int primary_discover_tbs(struct bt_conn *conn) return bt_gatt_discover(conn, params); } -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ #if defined(CONFIG_BT_TBS_CLIENT_GTBS) static const struct bt_uuid *gtbs_uuid = BT_UUID_GTBS; @@ -1690,7 +1690,7 @@ static uint8_t primary_discover_gtbs_cb(struct bt_conn *conn, const struct bt_ga srv_inst->current_inst->end_handle = prim_service->end_handle; } -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) int err; err = primary_discover_tbs(conn); @@ -1699,7 +1699,7 @@ static uint8_t primary_discover_gtbs_cb(struct bt_conn *conn, const struct bt_ga } LOG_DBG("Discover failed (err %d)", err); -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ primary_discover_complete(srv_inst, conn); @@ -2234,10 +2234,10 @@ int bt_tbs_client_discover(struct bt_conn *conn, bool subscribe) return -EBUSY; } -#if CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 +#if defined(CONFIG_BT_TBS_CLIENT_TBS) (void)memset(srv_inst->tbs_insts, 0, sizeof(srv_inst->tbs_insts)); /* reset data */ srv_inst->inst_cnt = 0; -#endif /* CONFIG_BT_TBS_CLIENT_MAX_TBS_INSTANCES > 0 */ +#endif /* CONFIG_BT_TBS_CLIENT_TBS */ /* Discover TBS on peer, setup handles and notify/indicate */ srv_inst->subscribe_all = subscribe; #if defined(CONFIG_BT_TBS_CLIENT_GTBS) diff --git a/tests/bluetooth/shell/audio.conf b/tests/bluetooth/shell/audio.conf index 04f3503edd33..96d94829d2e2 100644 --- a/tests/bluetooth/shell/audio.conf +++ b/tests/bluetooth/shell/audio.conf @@ -119,7 +119,8 @@ CONFIG_BT_MPL_TRACK_MAX_SIZE=50 # Telephone bearer service CONFIG_BT_TBS=y CONFIG_BT_TBS_SUPPORTED_FEATURES=3 -CONFIG_BT_TBS_CLIENT=y +CONFIG_BT_TBS_CLIENT_TBS=y +CONFIG_BT_TBS_CLIENT_GTBS=y CONFIG_BT_MCS=y CONFIG_BT_MCC=y diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index d25b712c79f7..4b46c8d6781f 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -289,14 +289,22 @@ tests: build_only: true platform_allow: native_posix extra_configs: - - CONFIG_BT_TBS_CLIENT=n + - CONFIG_BT_TBS_CLIENT_TBS=n + - CONFIG_BT_TBS_CLIENT_GTBS=n + tags: bluetooth + 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_MAX_TBS_INSTANCES=0 + - CONFIG_BT_TBS_CLIENT_TBS=n tags: bluetooth bluetooth.audio_shell.no_cap_acceptor: extra_args: CONF_FILE="audio.conf" diff --git a/tests/bsim/bluetooth/audio/prj.conf b/tests/bsim/bluetooth/audio/prj.conf index a014159a2a68..c516eeb1bdd0 100644 --- a/tests/bsim/bluetooth/audio/prj.conf +++ b/tests/bsim/bluetooth/audio/prj.conf @@ -72,7 +72,8 @@ CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA=y # Telephone bearer service CONFIG_BT_TBS=y -CONFIG_BT_TBS_CLIENT=y +CONFIG_BT_TBS_CLIENT_TBS=y +CONFIG_BT_TBS_CLIENT_GTBS=y CONFIG_BT_TBS_CLIENT_MAX_CALLS=4 CONFIG_BT_TBS_MAX_CALLS=4 CONFIG_BT_TBS_SUPPORTED_FEATURES=3 From a5f8c775d7ac24a07876cc1d5f4150ec786e69f8 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 10 Jul 2023 12:06:23 +0200 Subject: [PATCH 1392/2042] debug: add missing include to thread_analyzer Including thread_analyzer.h implicitly requires a previous include of thread.h. This adds this include directly to thread_analyzer to remove this implicit dependency. Signed-off-by: Benedikt Schmidt --- include/zephyr/debug/thread_analyzer.h | 2 ++ include/zephyr/kernel/thread.h | 1 + 2 files changed, 3 insertions(+) diff --git a/include/zephyr/debug/thread_analyzer.h b/include/zephyr/debug/thread_analyzer.h index d29ec0383960..d9c0f855e6c2 100644 --- a/include/zephyr/debug/thread_analyzer.h +++ b/include/zephyr/debug/thread_analyzer.h @@ -6,7 +6,9 @@ #ifndef __STACK_SIZE_ANALYZER_H #define __STACK_SIZE_ANALYZER_H + #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index 6f24413e13d0..eaed5b5d21dd 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -12,6 +12,7 @@ #endif #include +#include /** * @typedef k_thread_entry_t From 631312334ef312740ec8baa7a5e5ef04ddb6ae7a Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Wed, 12 Jul 2023 01:48:17 +0530 Subject: [PATCH 1393/2042] samples: lwm2m: Fix default ID length check for DTLS If the default which is set to CONFIG_BOARD is used, then the lwm2m client fails to set the client identity as the default maximum length allowed is only 16 and for some boards this exceeds. So, increase the default length to accomodate almost all boards. Also add a build assert for the length validation. Signed-off-by: Chaitanya Tata --- samples/net/lwm2m_client/overlay-dtls.conf | 5 +++++ samples/net/lwm2m_client/src/lwm2m-client.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/samples/net/lwm2m_client/overlay-dtls.conf b/samples/net/lwm2m_client/overlay-dtls.conf index 3a144fdd5b43..d9cf838ddc51 100644 --- a/samples/net/lwm2m_client/overlay-dtls.conf +++ b/samples/net/lwm2m_client/overlay-dtls.conf @@ -23,3 +23,8 @@ CONFIG_NET_SOCKETS_ENABLE_DTLS=y # MbedTLS needs a larger stack CONFIG_MAIN_STACK_SIZE=2048 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +# This has to be match length of LWM2M_APP_ID and if LWM2M_APP_ID is empty, +# then this has to be match length of CONFIG_BOARD. Default 16 is not enough +# for some boards, so, increase it to 32. +CONFIG_LWM2M_SECURITY_KEY_SIZE=32 diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index facba6109458..6a7de16ade6d 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -45,6 +45,11 @@ static struct lwm2m_ctx client; static const char *endpoint = (sizeof(CONFIG_LWM2M_APP_ID) > 1 ? CONFIG_LWM2M_APP_ID : CONFIG_BOARD); +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +BUILD_ASSERT(sizeof(endpoint) <= CONFIG_LWM2M_SECURITY_KEY_SIZE, + "Client ID length is too long"); +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + static struct k_sem quit_lock; static int device_reboot_cb(uint16_t obj_inst_id, From ce3d0af18308efbf99266cfcc2fd162c02b34c20 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Tue, 11 Jul 2023 16:33:20 -0600 Subject: [PATCH 1394/2042] emul: Don't panic if matching emul can't be found When initializing emulators for devices registered on an emulated bus, Zephyr will assert if a matching emulator for the device cannot be found. This feels overly restrictive --there may be cases where we still want to build a driver for testing even without an emulator and drivers should be able to handle situations where there is no device emulator present (the I2C/SPI transactions will simply fail and the driver never becomes ready). This commit removes the assert and replaces it with an warning message if no matching emulator is found. Signed-off-by: Tristan Honscheid --- subsys/emul/emul.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/subsys/emul/emul.c b/subsys/emul/emul.c index 15299381a385..96adb888dd29 100644 --- a/subsys/emul/emul.c +++ b/subsys/emul/emul.c @@ -40,7 +40,10 @@ int emul_init_for_bus(const struct device *dev) for (elp = cfg->children; elp < end; elp++) { const struct emul *emul = emul_get_binding(elp->dev->name); - __ASSERT(emul, "Cannot find emulator for '%s'", elp->dev->name); + if (!emul) { + LOG_WRN("Cannot find emulator for '%s'", elp->dev->name); + continue; + } switch (emul->bus_type) { case EMUL_BUS_TYPE_I2C: From 4ac8000bf2fdef543da4638a0ae17497e61947a6 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Wed, 12 Jul 2023 15:43:51 -0600 Subject: [PATCH 1395/2042] drivers: fdc2x1x: Loosen newlib dependency The FDC2X1X driver depends on newlib in Kconfig. This prevents the driver from being built in a native_posix testing environment, which uses an external libc from the host. Allow the driver to be built with an external libc as well. Signed-off-by: Tristan Honscheid --- drivers/sensor/fdc2x1x/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/fdc2x1x/Kconfig b/drivers/sensor/fdc2x1x/Kconfig index 33894acb17fc..bf6f7b148d7b 100644 --- a/drivers/sensor/fdc2x1x/Kconfig +++ b/drivers/sensor/fdc2x1x/Kconfig @@ -7,7 +7,7 @@ menuconfig FDC2X1X bool "FDC2X1X Capacitance-to-Digital Converter" default y depends on DT_HAS_TI_FDC2X1X_ENABLED - depends on NEWLIB_LIBC + depends on NEWLIB_LIBC || EXTERNAL_LIBC select I2C help Enable driver for FDC2X1X Capacitance-to-Digital Converter. From f119d5341a6148ea50a1dcc035a5d7598a3e01a5 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Wed, 12 Jul 2023 16:50:30 -0600 Subject: [PATCH 1396/2042] drivers: fdc2x1x: Fix compilation error When CONFIG_PM_DEVICE is enabled, the FDC2x1x driver includes code that doesn't access the name of the shutdown pin's GPIO port correctly. Correct this so the code derefences the right struct members. Signed-off-by: Tristan Honscheid --- drivers/sensor/fdc2x1x/fdc2x1x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/fdc2x1x/fdc2x1x.c b/drivers/sensor/fdc2x1x/fdc2x1x.c index 78d3cc091215..aa5854186e53 100644 --- a/drivers/sensor/fdc2x1x/fdc2x1x.c +++ b/drivers/sensor/fdc2x1x/fdc2x1x.c @@ -516,7 +516,7 @@ static int fdc2x1x_device_pm_action(const struct device *dev, break; case PM_DEVICE_ACTION_TURN_OFF: - if (cfg->sd_gpio->port.name) { + if (cfg->sd_gpio.port->name) { ret = fdc2x1x_set_shutdown(dev, true); } else { LOG_ERR("SD pin not defined"); From 613c32b03fb3462be85d35ba15285119699bccf6 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Wed, 12 Jul 2023 15:49:58 -0600 Subject: [PATCH 1397/2042] tests: Clean up sensor driver build_all test This PR performs a few cleanup actions for the build-all sensor driver test: 1. Remove many non-sensors from the test's device tree, including wireless radios, LED strips, flash memory, and displays. These devices don't belong in this test and in most cases were not being compiled anyways due to missing config flags and not being status-okay. 2. For the remaining devices, enable them in the device tree so the sensors build and get instantiated. A handful of device nodes that caused linker errors due to the driver not instantiating are left disabled. 3. Convert the test I2C and SPI buses into emulated buses to support upcoming live testing over these sensor devices. Signed-off-by: Tristan Honscheid --- tests/drivers/build_all/sensor/app.overlay | 34 +- tests/drivers/build_all/sensor/i2c.dtsi | 534 ++++++++++++--------- tests/drivers/build_all/sensor/spi.dtsi | 310 ++++-------- 3 files changed, 413 insertions(+), 465 deletions(-) diff --git a/tests/drivers/build_all/sensor/app.overlay b/tests/drivers/build_all/sensor/app.overlay index 7c6737a64a88..36bb97915d76 100644 --- a/tests/drivers/build_all/sensor/app.overlay +++ b/tests/drivers/build_all/sensor/app.overlay @@ -48,7 +48,7 @@ test_i2c: i2c@11112222 { #address-cells = <1>; #size-cells = <0>; - compatible = "vnd,i2c"; + compatible = "zephyr,i2c-emul-controller"; reg = <0x11112222 0x1000>; status = "okay"; clock-frequency = <100000>; @@ -59,7 +59,7 @@ test_spi: spi@33334444 { #address-cells = <1>; #size-cells = <0>; - compatible = "vnd,spi"; + compatible = "zephyr,spi-emul-controller"; reg = <0x33334444 0x1000>; status = "okay"; clock-frequency = <2000000>; @@ -101,35 +101,7 @@ <&test_gpio 0 0>, <&test_gpio 0 0>, <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, /* 0x30 */ - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>, - <&test_gpio 0 0>; /* 0x40 */ + <&test_gpio 0 0>; /* 0x24 */ #include "spi.dtsi" }; diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index b81009e154d0..ec47ec174003 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -14,17 +14,20 @@ test_i2c_adt7420: adt7420@0 { compatible = "adi,adt7420"; reg = <0x0>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_adxl345: adxl345@1 { compatible = "adi,adxl345"; reg = <0x1>; + status = "okay"; }; test_i2c_adxl372: adxl372@2 { compatible = "adi,adxl372"; reg = <0x2>; int1-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_ccs811: ccs811@3 { @@ -33,27 +36,32 @@ test_i2c_ccs811: ccs811@3 { wake-gpios = <&test_gpio 0 0>; reset-gpios = <&test_gpio 0 0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_ens210: ens210@4 { compatible = "ams,ens210"; reg = <0x4>; + status = "okay"; }; test_i2c_iaqcore: iaqcore@5 { compatible = "ams,iaqcore"; reg = <0x5>; + status = "okay"; }; test_i2c_bme280: bme280@6 { compatible = "bosch,bme280"; reg = <0x6>; + status = "okay"; }; test_i2c_apds9960: apds9960@7 { compatible = "avago,apds9960"; reg = <0x7>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_bma280: bma280@8 { @@ -61,461 +69,503 @@ test_i2c_bma280: bma280@8 { reg = <0x8>; int1-gpios = <&test_gpio 0 0>; /* is-bmc150; */ + status = "okay"; }; test_i2c_bmc150_magn: bmc150_magn@9 { compatible = "bosch,bmc150_magn"; reg = <0x9>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_ak8975: ak8975@a { compatible = "asahi-kasei,ak8975"; reg = <0xa>; + status = "okay"; }; test_i2c_bme680: bme680@b { compatible = "bosch,bme680"; reg = <0xb>; + status = "okay"; }; test_i2c_bmg160: bmg160@c { compatible = "bosch,bmg160"; reg = <0xc>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_i2c_bmm150: bmm150@d { compatible = "bosch,bmm150"; reg = <0xd>; + status = "okay"; }; -test_i2c_ht16k33: ht16k33@f { - compatible = "holtek,ht16k33"; - reg = <0xf>; - #address-cells = <1>; - #size-cells = <0>; - irq-gpios = <&test_gpio 0 0>; -}; - -test_i2c_hmc5883l: hmc5883l@10 { +test_i2c_hmc5883l: hmc5883l@e { compatible = "honeywell,hmc5883l"; - reg = <0x10>; + reg = <0xe>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_hp206c: hp206c@11 { +test_i2c_hp206c: hp206c@f { compatible = "hoperf,hp206c"; - reg = <0x11>; + reg = <0xf>; + status = "okay"; }; -test_i2c_th02: th02@12 { +test_i2c_th02: th02@10 { compatible = "hoperf,th02"; - reg = <0x12>; + reg = <0x10>; + status = "okay"; }; -test_i2c_mpu6050: mpu6050@13 { +test_i2c_mpu6050: mpu6050@11 { compatible = "invensense,mpu6050"; - reg = <0x13>; + reg = <0x11>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_mpu9250: mpu9250@14 { +test_i2c_mpu9250: mpu9250@12 { compatible = "invensense,mpu9250"; - reg = <0x14>; + reg = <0x12>; irq-gpios = <&test_gpio 0 0>; gyro-sr-div = <10>; gyro-dlpf = <5>; gyro-fs = <250>; accel-fs = <2>; accel-dlpf="5.05"; + status = "okay"; }; -test_i2c_ina219: ina219@15 { +test_i2c_ina219: ina219@13 { compatible = "ti,ina219"; - reg = <0x15>; + reg = <0x13>; brng = <0>; pg = <0>; sadc = <13>; badc = <13>; shunt-milliohm = <100>; lsb-microamp = <10>; + status = "okay"; }; -test_i2c_isl29035: isl29035@16 { +test_i2c_isl29035: isl29035@14 { compatible = "isil,isl29035"; - reg = <0x16>; + reg = <0x14>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_max30101: max30101@17 { +test_i2c_max30101: max30101@15 { compatible = "maxim,max30101"; - reg = <0x17>; + reg = <0x15>; + status = "okay"; }; -test_i2c_max44009: max44009@18 { +test_i2c_max44009: max44009@16 { compatible = "maxim,max44009"; - reg = <0x18>; + reg = <0x16>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_ms5607: ms5607@19 { +test_i2c_ms5607: ms5607@17 { compatible = "meas,ms5607"; - reg = <0x19>; + reg = <0x17>; + status = "okay"; }; -test_i2c_ms5837: ms5837@1a { +test_i2c_ms5837: ms5837@18 { compatible = "meas,ms5837"; - reg = <0x1a>; + reg = <0x18>; + status = "okay"; }; -test_i2c_mcp9808: mcp9808@1b { +test_i2c_mcp9808: mcp9808@19 { compatible = "microchip,mcp9808"; - reg = <0x1b>; + reg = <0x19>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_fxas21002: fxas21002@1c { +test_i2c_fxas21002: fxas21002@1a { compatible = "nxp,fxas21002"; - reg = <0x1c>; + reg = <0x1a>; int1-gpios = <&test_gpio 0 0>; int2-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_fxos8700: fxos8700@1d { +test_i2c_fxos8700: fxos8700@1b { compatible = "nxp,fxos8700"; - reg = <0x1d>; + reg = <0x1b>; reset-gpios = <&test_gpio 0 0>; int1-gpios = <&test_gpio 0 0>; int2-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_pca9633: pca9633@1e { - compatible = "nxp,pca9633"; - reg = <0x1e>; -}; - -test_i2c_amg88xx: amg88xx@1f { +test_i2c_amg88xx: amg88xx@1c { compatible = "panasonic,amg88xx"; - reg = <0x1f>; + reg = <0x1c>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_sx9500: sx9500@20 { +test_i2c_sx9500: sx9500@1d { compatible = "semtech,sx9500"; - reg = <0x20>; + reg = <0x1d>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_sgp40: sgp40@21 { +test_i2c_sgp40: sgp40@1e { compatible = "sensirion,sgp40"; - reg = <0x21>; + reg = <0x1e>; enable-selftest; + status = "okay"; }; -test_i2c_sht3xd: sht3xd@22 { +test_i2c_sht3xd: sht3xd@1f { compatible = "sensirion,sht3xd"; - reg = <0x22>; + reg = <0x1f>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_sht4xd: sht4x@23 { +test_i2c_sht4xd: sht4x@20 { compatible = "sensirion,sht4x"; - reg = <0x23>; + reg = <0x20>; repeatability = <2>; + status = "okay"; }; -test_i2c_shtc3: SHTC3@24 { +test_i2c_shtc3: SHTC3@21 { compatible = "sensirion,shtcx"; - reg = <0x24>; + reg = <0x21>; chip = "shtc3"; measure-mode = "normal"; clock-stretching; + status = "okay"; }; -test_i2c_si7006: si7006@25 { +test_i2c_si7006: si7006@22 { compatible = "silabs,si7006"; - reg = <0x25>; + reg = <0x22>; + status = "okay"; }; -test_i2c_si7055: si7055@26 { +test_i2c_si7055: si7055@23 { compatible = "silabs,si7055"; - reg = <0x26>; + reg = <0x23>; + status = "okay"; }; -test_i2c_si7060: si7060@27 { +test_i2c_si7060: si7060@24 { compatible = "silabs,si7060"; - reg = <0x27>; + reg = <0x24>; + status = "okay"; }; -test_i2c_si7210: si7010@28 { +test_i2c_si7210: si7010@25 { compatible = "silabs,si7210"; - reg = <0x28>; + reg = <0x25>; + status = "okay"; }; -test_i2c_hts221: hts221@29 { +test_i2c_hts221: hts221@26 { compatible = "st,hts221"; - reg = <0x29>; + reg = <0x26>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_iis2dlpc: iis2dlpc@2a { +test_i2c_iis2dlpc: iis2dlpc@27 { compatible = "st,iis2dlpc"; - reg = <0x2a>; + reg = <0x27>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_iis2mdc: iis2mdc@2b { +test_i2c_iis2mdc: iis2mdc@28 { compatible = "st,iis2mdc"; - reg = <0x2b>; + reg = <0x28>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_ism330dhcx: ism330dhcx@2c { +test_i2c_ism330dhcx: ism330dhcx@29 { compatible = "st,ism330dhcx"; - reg = <0x2c>; + reg = <0x29>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lis2dh: lis2dh@2d { +test_i2c_lis2dh: lis2dh@2a { compatible = "st,lis2dh"; - reg = <0x2d>; + reg = <0x2a>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + status = "okay"; }; -test_i2c_lis2dh12: lis2dh12@2e { +test_i2c_lis2dh12: lis2dh12@2b { compatible = "st,lis2dh12"; - reg = <0x2e>; + reg = <0x2b>; irq-gpios = <&test_gpio 0 0>; + status = "disabled"; }; -test_i2c_lis2ds12: lis2ds12@2f { +test_i2c_lis2ds12: lis2ds12@2c { compatible = "st,lis2ds12"; - reg = <0x2f>; + reg = <0x2c>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lis2dw12: lis2dw12@30 { +test_i2c_lis2dw12: lis2dw12@2d { compatible = "st,lis2dw12"; - reg = <0x30>; + reg = <0x2d>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lis2mdl: lis2mdl@31 { +test_i2c_lis2mdl: lis2mdl@2e { compatible = "st,lis2mdl"; - reg = <0x31>; + reg = <0x2e>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lis3dh: lis3dh@32 { +test_i2c_lis3dh: lis3dh@2f { compatible = "st,lis3dh"; - reg = <0x32>; + reg = <0x2f>; irq-gpios = <&test_gpio 0 0>; + status = "disabled"; }; -test_i2c_lis3mdl_magn: lis3mdl-magn@33 { +test_i2c_lis3mdl_magn: lis3mdl-magn@30 { compatible = "st,lis3mdl-magn"; - reg = <0x33>; + reg = <0x30>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lps22hb_press: lps22hb-press@34 { +test_i2c_lps22hb_press: lps22hb-press@31 { compatible = "st,lps22hb-press"; - reg = <0x34>; + reg = <0x31>; + status = "okay"; }; -test_i2c_lps22hh: lps22hh@35 { +test_i2c_lps22hh: lps22hh@32 { compatible = "st,lps22hh"; - reg = <0x35>; + reg = <0x32>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lps25hb_press: lps25hb-press@36 { +test_i2c_lps25hb_press: lps25hb-press@33 { compatible = "st,lps25hb-press"; - reg = <0x36>; + reg = <0x33>; + status = "okay"; }; -test_i2c_lsm303agr_accel: lsm303agr-accel@37 { +test_i2c_lsm303agr_accel: lsm303agr-accel@34 { compatible = "st,lsm303agr-accel"; - reg = <0x37>; + reg = <0x34>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + status = "disabled"; }; -test_i2c_lsm303dlhc_accel: lsm303dlhc-accel@38 { +test_i2c_lsm303dlhc_accel: lsm303dlhc-accel@35 { compatible = "st,lsm303dlhc-accel"; - reg = <0x38>; + reg = <0x35>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + status = "disabled"; }; -test_i2c_lsm303dlhc_magn: lsm303dlhc-magn@39 { +test_i2c_lsm303dlhc_magn: lsm303dlhc-magn@36 { compatible = "st,lsm303dlhc-magn"; - reg = <0x39>; + reg = <0x36>; + status = "okay"; }; -test_i2c_lsm6ds0: lsm6ds0@3a { +test_i2c_lsm6ds0: lsm6ds0@37 { compatible = "st,lsm6ds0"; - reg = <0x3a>; + reg = <0x37>; + status = "okay"; }; -test_i2c_lsm6dsl: lsm6dsl@3b { +test_i2c_lsm6dsl: lsm6dsl@38 { compatible = "st,lsm6dsl"; - reg = <0x3b>; + reg = <0x38>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lsm6dso: lsm6dso@3c { +test_i2c_lsm6dso: lsm6dso@39 { compatible = "st,lsm6dso"; - reg = <0x3c>; + reg = <0x39>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lsm9ds0_gyro: lsm9ds0-gyro@3d { +test_i2c_lsm9ds0_gyro: lsm9ds0-gyro@3a { compatible = "st,lsm9ds0-gyro"; - reg = <0x3d>; + reg = <0x3a>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lsm9ds0_mfd: lsm9ds0-mfd@3e { +test_i2c_lsm9ds0_mfd: lsm9ds0-mfd@3b { compatible = "st,lsm9ds0-mfd"; - reg = <0x3e>; + reg = <0x3b>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_stts751: stts751@3f { +test_i2c_stts751: stts751@3c { compatible = "st,stts751"; - reg = <0x3f>; + reg = <0x3c>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_vl53l0x: vl53l0x@40 { +test_i2c_vl53l0x: vl53l0x@3d { compatible = "st,vl53l0x"; - reg = <0x40>; + reg = <0x3d>; xshut-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_hdc: hdc@41 { +test_i2c_hdc: hdc@3e { compatible = "ti,hdc"; - reg = <0x41>; + reg = <0x3e>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_hdc2010: hdc2010@42 { +test_i2c_hdc2010: hdc2010@3f { compatible = "ti,hdc2010"; - reg = <0x42>; + reg = <0x3f>; + status = "okay"; }; -test_i2c_hdc2021: hdc2021@43 { +test_i2c_hdc2021: hdc2021@40 { compatible = "ti,hdc2021"; - reg = <0x43>; + reg = <0x40>; + status = "okay"; }; -test_i2c_hdc2022: hdc2022@44 { +test_i2c_hdc2022: hdc2022@41 { compatible = "ti,hdc2022"; - reg = <0x44>; + reg = <0x41>; + status = "okay"; }; -test_i2c_hdc2080: hdc2080@45 { +test_i2c_hdc2080: hdc2080@42 { compatible = "ti,hdc2080"; - reg = <0x45>; -}; - -test_i2c_lp3943: lp3943@46 { - compatible = "ti,lp3943"; - reg = <0x46>; -}; - -test_i2c_lp5562: lp5562@47 { - compatible = "ti,lp5562"; - reg = <0x47>; + reg = <0x42>; + status = "okay"; }; -test_i2c_opt3001: opt3001@48 { +test_i2c_opt3001: opt3001@43 { compatible = "ti,opt3001"; - reg = <0x48>; -}; - -test_i2c_tlv320dac: tlv320dac@49 { - compatible = "ti,tlv320dac"; - reg = <0x49>; - reset-gpios = <&test_gpio 0 0>; + reg = <0x43>; + status = "okay"; }; -test_i2c_tmp007: tmp007@4a { +test_i2c_tmp007: tmp007@44 { compatible = "ti,tmp007"; - reg = <0x4a>; + reg = <0x44>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_tmp108: tmp108@4b { +test_i2c_tmp108: tmp108@45 { compatible = "ti,tmp108"; - reg = <0x4b>; + reg = <0x45>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_tmp112: tmp112@4c { +test_i2c_tmp112: tmp112@46 { compatible = "ti,tmp112"; - reg = <0x4c>; + reg = <0x46>; + status = "okay"; }; -test_i2c_tmp116: tmp116@4d { +test_i2c_tmp116: tmp116@47 { compatible = "ti,tmp116"; - reg = <0x4d>; + reg = <0x47>; + status = "okay"; }; -test_i2c_bq274xx: bq27xx@4e { +test_i2c_bq274xx: bq27xx@48 { compatible = "ti,bq274xx"; - reg = <0x4e>; + reg = <0x48>; design-voltage = <3700>; design-capacity = <1800>; taper-current = <45>; terminate-voltage = <3000>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_mpr: mpr@4f { +test_i2c_mpr: mpr@49 { compatible = "honeywell,mpr"; - reg = <0x4f>; + reg = <0x49>; + status = "okay"; }; -test_i2c_dps310: dps310@50 { - compatible = "infineon,dps310"; - reg = <0x50>; +test_i2c_dps310: dps310@4a { + compatible = "infineon,dps310"; + reg = <0x4a>; + status = "okay"; }; -test_i2c_iis2dh: iis2dh@51 { +test_i2c_iis2dh: iis2dh@4b { compatible = "st,iis2dh"; - reg = <0x51>; + reg = <0x4b>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_iis2iclx: iis2iclx@52 { +test_i2c_iis2iclx: iis2iclx@4c { compatible = "st,iis2iclx"; - reg = <0x52>; + reg = <0x4c>; drdy-gpios = <&test_gpio 0 0>; int-pin = <1>; + status = "okay"; }; -test_i2c_wsen_hids: wsen_hids@53 { +test_i2c_wsen_hids: wsen_hids@4d { compatible = "we,wsen-hids"; - reg = <0x53>; + reg = <0x4d>; drdy-gpios = <&test_gpio 0 0>; odr = "1"; + status = "okay"; }; -test_i2c_itds: itds@54 { +test_i2c_itds: itds@4e { compatible = "we,wsen-itds"; - reg = <0x54>; + reg = <0x4e>; int-gpios = <&test_gpio 0 0>; odr = "800"; op-mode = "high-perf"; + status = "okay"; }; -test_i2c_max17055: max17055@55 { +test_i2c_max17055: max17055@4f { compatible = "maxim,max17055"; - reg = <0x55>; + reg = <0x4f>; design-capacity = <1500>; design-voltage = <3860>; desired-charging-current = <2000>; @@ -523,11 +573,12 @@ test_i2c_max17055: max17055@55 { i-chg-term = <100>; rsense-mohms = <5>; v-empty = <3300>; + status = "okay"; }; -test_i2c_max17262: max17262@56 { +test_i2c_max17262: max17262@50 { compatible = "maxim,max17262"; - reg = <0x56>; + reg = <0x50>; design-voltage = <3600>; desired-voltage = <3600>; desired-charging-current = <2000>; @@ -535,29 +586,34 @@ test_i2c_max17262: max17262@56 { empty-voltage = <3300>; recovery-voltage = <3880>; charge-voltage = <3600>; + status = "okay"; }; -test_i2c_vcnl4040: vcnl4040@57 { +test_i2c_vcnl4040: vcnl4040@51 { compatible = "vishay,vcnl4040"; - reg = <0x57>; + reg = <0x51>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_bmi160: bmi160@58 { +test_i2c_bmi160: bmi160@52 { compatible = "bosch,bmi160"; - reg = <0x58>; + reg = <0x52>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_bmi270: bmi270@59 { +test_i2c_bmi270: bmi270@53 { compatible = "bosch,bmi270"; - reg = <0x59>; + reg = <0x53>; + status = "okay"; }; -test_i2c_fdc2x1x: fdc2x1x@5a { +test_i2c_fdc2x1x: fdc2x1x@54 { compatible = "ti,fdc2x1x"; - reg = <0x5a>; + reg = <0x54>; intb-gpios = <&test_gpio 0 0>; + sd-gpios = <&test_gpio 0 0>; deglitch = <5>; fref = <43360>; channel_0 { @@ -568,109 +624,118 @@ test_i2c_fdc2x1x: fdc2x1x@5a { fin-sel = <2>; inductance = <18>; }; + status = "okay"; }; -test_i2c_bmp388: bmp388@5b { +test_i2c_bmp388: bmp388@55 { compatible = "bosch,bmp388"; - reg = <0x5b>; + reg = <0x55>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_sbc_gauge: sbsgauge@5c { - compatible = "sbs,sbs-gauge"; - reg = <0x5c>; -}; - -test_i2c_lm75: lm75@5d { +test_i2c_lm75: lm75@56 { compatible = "lm75"; - reg = <0x5d>; + reg = <0x56>; + status = "okay"; }; -test_i2c_ina230: ina230@5e { +test_i2c_ina230: ina230@57 { compatible = "ti,ina230"; - reg = <0x5e>; + reg = <0x57>; config = <0>; current-lsb-microamps = <1000>; rshunt-micro-ohms = <1000>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lm77: lm77@5f { +test_i2c_lm77: lm77@58 { compatible = "lm77"; - reg = <0x5f>; + reg = <0x58>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_ina231: ina231@60 { +test_i2c_ina231: ina231@59 { compatible = "ti,ina230"; - reg = <0x60>; + reg = <0x59>; config = <0>; current-lsb-microamps = <1000>; rshunt-micro-ohms = <1000>; mask = <0>; alert-limit = <0>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_ina237: ina237@61 { +test_i2c_ina237: ina237@5a { compatible = "ti,ina237"; - reg = <0x61>; + reg = <0x5a>; config = <0>; current-lsb-microamps = <1000>; adc-config = <0>; rshunt-micro-ohms = <1000>; alert-config = <0>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_max31875: max31875@62 { +test_i2c_max31875: max31875@5b { compatible = "maxim,max31875"; - reg = <0x62>; + reg = <0x5b>; + status = "okay"; }; -test_i2c_icp10125: icp10125@63 { +test_i2c_icp10125: icp10125@5c { compatible = "invensense,icp10125"; - reg = <0x63>; + reg = <0x5c>; temperature-measurement-mode = "normal"; pressure-measurement-mode = "normal"; + status = "okay"; }; -test_i2c_as5600: as5600@64 { +test_i2c_as5600: as5600@5d { compatible = "ams,as5600"; - reg = <0x64>; + reg = <0x5d>; + status = "okay"; }; -test_i2c_bh1750: bh1750@65 { +test_i2c_bh1750: bh1750@5e { compatible = "rohm,bh1750"; - reg = <0x65>; + reg = <0x5e>; + status = "okay"; }; -test_i2c_akm09918c: akm09918c@66 { +test_i2c_akm09918c: akm09918c@5f { compatible = "asahi-kasei,akm09918c"; - reg = <0x66>; + reg = <0x5f>; + status = "okay"; }; -test_i2c_wsen_tids: wsen_tids@67 { +test_i2c_wsen_tids: wsen_tids@60 { compatible = "we,wsen-tids"; - reg = <0x67>; + reg = <0x60>; int-gpios = <&test_gpio 0 0>; odr = <25>; temp-high-threshold = <0>; temp-low-threshold = <0>; + status = "okay"; }; -test_i2c_vl53l1x: vl53l1x@68 { +test_i2c_vl53l1x: vl53l1x@61 { compatible = "st,vl53l1x"; - reg = <0x68>; + reg = <0x61>; int-gpios = <&test_gpio 0 0>; xshut-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_tmd2620: tmd2620@69 { +test_i2c_tmd2620: tmd2620@62 { compatible = "ams,tmd2620"; - reg = <0x69>; + reg = <0x62>; int-gpios = <&test_gpio 0 0>; proximity-gain = <4>; proximity-pulse-length = <16>; @@ -680,75 +745,86 @@ test_i2c_tmd2620: tmd2620@69 { proximity-led-drive-strength = <4>; proximity-interrupt-filter = <0>; wait-time-factor = <0>; + status = "okay"; }; -test_i2c_wsen_pads: wsen_pads@6A { +test_i2c_wsen_pads: wsen_pads@63 { compatible = "we,wsen-pads"; - reg = <0x6A>; + reg = <0x63>; drdy-gpios = <&test_gpio 0 0>; odr = <1>; + status = "okay"; }; -test_i2c_s11059: s11059@6b { +test_i2c_s11059: s11059@64 { compatible = "hamamatsu,s11059"; - reg = <0x6b>; + reg = <0x64>; integration-time = <546000>; + status = "okay"; }; -test_i2c_wsen_pdus: wsen_pdus@6C { +test_i2c_wsen_pdus: wsen_pdus@65 { compatible = "we,wsen-pdus"; - reg = <0x6C>; + reg = <0x65>; sensor-type = <3>; + status = "okay"; }; -test_i2c_veml7700: veml7700@6d { +test_i2c_veml7700: veml7700@66 { compatible = "vishay,veml7700"; - reg = <0x6d>; + reg = <0x66>; psm-mode = <0x03>; + status = "okay"; }; -test_i2c_ina3221: ina3221@6e { +test_i2c_ina3221: ina3221@67 { compatible = "ti,ina3221"; - reg = <0x6e>; + reg = <0x67>; shunt-resistors = <1000 1000 1000>; enable-channel = <1 0 0>; conv-time-bus = <7>; conv-time-shunt = <7>; avg-mode = <2>; + status = "okay"; }; -test_i2c_lsm6dso16is: lsm6dso16is@6f { +test_i2c_lsm6dso16is: lsm6dso16is@68 { compatible = "st,lsm6dso16is"; - reg = <0x6f>; + reg = <0x68>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_lsm6dsv16x: lsm6dsv16x@70 { +test_i2c_lsm6dsv16x: lsm6dsv16x@69 { compatible = "st,lsm6dsv16x"; - reg = <0x70>; + reg = <0x69>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_mcp9600: mcp9600@71 { +test_i2c_mcp9600: mcp9600@6a { compatible = "microchip,mcp9600"; - reg = <0x71>; + reg = <0x6a>; + status = "okay"; }; -test_i2c_tcs3400: tcs3400@72 { +test_i2c_tcs3400: tcs3400@6b { compatible = "ams,tcs3400"; - reg = <0x72>; + reg = <0x6b>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_tcn75a: tcn75a@73 { +test_tcn75a: tcn75a@6c { compatible = "microchip,tcn75a"; - reg = <0x73>; + reg = <0x6c>; alert-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_i2c_bmi08x_accel: bmi08x@74 { +test_i2c_bmi08x_accel: bmi08x@6d { compatible = "bosch,bmi08x-accel"; - reg = <0x74>; + reg = <0x6d>; int-gpios = <&test_gpio 0 0>; int1-map-io = <0x01>; int2-map-io = <0x00>; @@ -758,9 +834,9 @@ test_i2c_bmi08x_accel: bmi08x@74 { accel-fs = <4>; }; -test_i2c_bmi08x_gyro: bmi08x@75 { +test_i2c_bmi08x_gyro: bmi08x@6e { compatible = "bosch,bmi08x-gyro"; - reg = <0x75>; + reg = <0x6e>; int-gpios = <&test_gpio 0 0>; int3-4-map-io = <0x01>; int3-4-conf-io = <0x01>; diff --git a/tests/drivers/build_all/sensor/spi.dtsi b/tests/drivers/build_all/sensor/spi.dtsi index 6afc3958474d..2b882c27b746 100644 --- a/tests/drivers/build_all/sensor/spi.dtsi +++ b/tests/drivers/build_all/sensor/spi.dtsi @@ -15,6 +15,7 @@ test_spi_adxl362: adxl362@0 { reg = <0x0>; spi-max-frequency = <0>; int1-gpios = <&test_gpio 0 0>; + status = "okay"; }; test_spi_adxl372: adxl372@1 { @@ -22,383 +23,282 @@ test_spi_adxl372: adxl372@1 { reg = <0x1>; spi-max-frequency = <0>; int1-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_apa102: apa102@2 { - compatible = "apa,apa102"; - reg = <0x2>; - spi-max-frequency = <0>; -}; - -test_spi_rf2xx: rf2xx@3 { - compatible = "atmel,rf2xx"; - reg = <0x3>; - spi-max-frequency = <0>; - irq-gpios = <&test_gpio 0 0>; - reset-gpios = <&test_gpio 0 0>; - slptr-gpios = <&test_gpio 0 0>; - dig2-gpios = <&test_gpio 0 0>; - clkm-gpios = <&test_gpio 0 0>; -}; - -test_spi_winc1500: winc1500@4 { - compatible = "atmel,winc1500"; - reg = <0x4>; - spi-max-frequency = <0>; - irq-gpios = <&test_gpio 0 0>; - reset-gpios = <&test_gpio 0 0>; - enable-gpios = <&test_gpio 0 0>; -}; - -test_spi_bme280: bme280@5 { +test_spi_bme280: bme280@2 { compatible = "bosch,bme280"; - reg = <0x5>; + reg = <0x2>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_bmi160: bmi160@6 { +test_spi_bmi160: bmi160@3 { compatible = "bosch,bmi160"; - reg = <0x6>; + reg = <0x3>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lpd8803: lpd8803@7 { - compatible = "greeled,lpd8803"; - reg = <0x7>; - spi-max-frequency = <0>; -}; - -test_spi_lpd8806: lpd8806@8 { - compatible = "greeled,lpd8806"; - reg = <0x8>; - spi-max-frequency = <0>; -}; - -test_spi_uc8176: uc8176@9 { - compatible = "ultrachip,uc8176"; - reg = <0x9>; - spi-max-frequency = <0>; - height = <0>; - width = <0>; - reset-gpios = <&test_gpio 0 0>; - dc-gpios = <&test_gpio 0 0>; - busy-gpios = <&test_gpio 0 0>; -}; - -test_spi_uc8179: uc8179@a { - compatible = "ultrachip,uc8179"; - reg = <0xa>; - spi-max-frequency = <0>; - height = <0>; - width = <0>; - reset-gpios = <&test_gpio 0 0>; - dc-gpios = <&test_gpio 0 0>; - busy-gpios = <&test_gpio 0 0>; - softstart = []; - full { - pwr = []; - cdi = <0>; - tcon = <0>; - }; - partial { - pwr = []; - cdi = <0>; - tcon = <0>; - }; -}; - -test_spi_eswifi: eswifi@b { - compatible = "inventek,eswifi"; - reg = <0xb>; - spi-max-frequency = <0>; - resetn-gpios = <&test_gpio 0 0>; - data-gpios = <&test_gpio 0 0>; - wakeup-gpios = <&test_gpio 0 0>; - boot0-gpios = <&test_gpio 0 0>; -}; - -test_spi_spi_nor: spi-nor@c { - compatible = "jedec,spi-nor"; - reg = <0xc>; - spi-max-frequency = <0>; - wp-gpios = <&test_gpio 0 0>; - hold-gpios = <&test_gpio 0 0>; - reset-gpios = <&test_gpio 0 0>; - jedec-id = []; - /* requires-ulbpr; */ - /* has-dpd; */ - size = <0>; -}; - -test_spi_ms5607: ms5607@d { +test_spi_ms5607: ms5607@4 { compatible = "meas,ms5607"; - reg = <0xd>; - spi-max-frequency = <0>; -}; - -test_spi_mcr20a: mcr20a@e { - compatible = "nxp,mcr20a"; - reg = <0xe>; - spi-max-frequency = <0>; - irqb-gpios = <&test_gpio 0 0>; - reset-gpios = <&test_gpio 0 0>; -}; - -test_spi_sx1276: sx1276@f { - compatible = "semtech,sx1276"; - reg = <0xf>; + reg = <0x4>; spi-max-frequency = <0>; - reset-gpios = <&test_gpio 0 0>; - dio-gpios = <&test_gpio 0 0>; - power-amplifier-output = "rfo"; + status = "okay"; }; -test_spi_iis2dlpc: iis2dlpc@10 { +test_spi_iis2dlpc: iis2dlpc@5 { compatible = "st,iis2dlpc"; - reg = <0x10>; + reg = <0x5>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_iis2mdc: iis2mdc@11 { +test_spi_iis2mdc: iis2mdc@6 { compatible = "st,iis2mdc"; - reg = <0x11>; + reg = <0x6>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_iis3dhhc: iis3dhhc@12 { +test_spi_iis3dhhc: iis3dhhc@7 { compatible = "st,iis3dhhc"; - reg = <0x12>; + reg = <0x7>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_ism330dhcx: ism330dhcx@13 { +test_spi_ism330dhcx: ism330dhcx@8 { compatible = "st,ism330dhcx"; - reg = <0x13>; + reg = <0x8>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lis2dh: lis2dh@14 { +test_spi_lis2dh: lis2dh@9 { compatible = "st,lis2dh"; - reg = <0x14>; + reg = <0x9>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + status = "okay"; }; -test_spi_lis2ds12: lis2ds12@15 { +test_spi_lis2ds12: lis2ds12@a { compatible = "st,lis2ds12"; - reg = <0x15>; + reg = <0xa>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lis2dw12: lis2dw12@16 { +test_spi_lis2dw12: lis2dw12@b { compatible = "st,lis2dw12"; - reg = <0x16>; + reg = <0xb>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lis2mdl: lis2mdl@17 { +test_spi_lis2mdl: lis2mdl@c { compatible = "st,lis2mdl"; - reg = <0x17>; + reg = <0xc>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lps22hh: lps22hh@18 { +test_spi_lps22hh: lps22hh@d { compatible = "st,lps22hh"; - reg = <0x18>; + reg = <0xd>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lsm303agr_accel: lsm303agr-accel@19 { +test_spi_lsm303agr_accel: lsm303agr-accel@e { compatible = "st,lsm303agr-accel"; - reg = <0x19>; + reg = <0xe>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; /* disconnect-sdo-sa0-pull-up; */ + status = "disabled"; }; -test_spi_lsm6dsl: lsm6dsl@1a { +test_spi_lsm6dsl: lsm6dsl@f { compatible = "st,lsm6dsl"; - reg = <0x1a>; + reg = <0xf>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lsm6dso: lsm6dso@1b { +test_spi_lsm6dso: lsm6dso@10 { compatible = "st,lsm6dso"; - reg = <0x1b>; - spi-max-frequency = <0>; - irq-gpios = <&test_gpio 0 0>; -}; - -test_spi_ws2812_spi: ws2812-spi@1c { - compatible = "worldsemi,ws2812-spi"; - reg = <0x1c>; - spi-max-frequency = <0>; - spi-one-frame = <0>; - spi-zero-frame = <0>; - chain-length = <0>; - color-mapping = <0 0 0>; -}; - -test_spi_bt_hci_spi: bt-hci-spi@1d { - compatible = "zephyr,bt-hci-spi"; - reg = <0x1d>; + reg = <0x10>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; - reset-gpios = <&test_gpio 0 0>; -}; - -test_spi_mmc_spi_slot: mmc-spi-slot@1e { - compatible = "zephyr,mmc-spi-slot"; - reg = <0x1e>; - spi-max-frequency = <0>; + status = "okay"; }; -test_spi_iis2dh: iis2dh@1f { +test_spi_iis2dh: iis2dh@11 { compatible = "st,iis2dh"; - reg = <0x1f>; + reg = <0x11>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_iis2iclx: iis2iclx@20 { +test_spi_iis2iclx: iis2iclx@12 { compatible = "st,iis2iclx"; - reg = <0x20>; + reg = <0x12>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; int-pin = <1>; + status = "okay"; }; -test_spi_icm42605: icm42605@21 { +test_spi_icm42605: icm42605@13 { compatible = "invensense,icm42605"; - reg = <0x21>; + reg = <0x13>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_max6675: max6675@22 { +test_spi_max6675: max6675@14 { compatible = "maxim,max6675"; - reg = <0x22>; + reg = <0x14>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_bmi270: bmi270@23 { +test_spi_bmi270: bmi270@15 { compatible = "bosch,bmi270"; - reg = <0x23>; + reg = <0x15>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_bmp388: bmp388@24 { +test_spi_bmp388: bmp388@16 { compatible = "bosch,bmp388"; - reg = <0x24>; + reg = <0x16>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_i3g4250d: i3g4250d@25 { +test_spi_i3g4250d: i3g4250d@17 { compatible = "st,i3g4250d"; - reg = <0x25>; + reg = <0x17>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_icm42670: icm42670@26 { +test_spi_icm42670: icm42670@18 { compatible = "invensense,icm42670"; - reg = <0x26>; + reg = <0x18>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; accel-hz = <800>; accel-fs = <16>; gyro-hz = <800>; gyro-fs = <2000>; + status = "okay"; }; -test_spi_bme680: bme680@27 { +test_spi_bme680: bme680@19 { compatible = "bosch,bme680"; - reg = <0x27>; + reg = <0x19>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_icm426888: icm42688@28 { +test_spi_icm426888: icm42688@1a { compatible = "invensense,icm42688"; - reg = <0x28>; + reg = <0x1a>; spi-max-frequency = <24000000>; accel-hz = <32000>; accel-fs = <16>; gyro-hz = <32000>; gyro-fs = <2000>; + status = "okay"; }; -test_spi_max31855: max31855@29 { +test_spi_max31855: max31855@1b { compatible = "maxim,max31855"; - reg = <0x29>; + reg = <0x1b>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_max31865: max31865@2a { +test_spi_max31865: max31865@1c { compatible = "maxim,max31865"; - reg = <0x2a>; + reg = <0x1c>; spi-max-frequency = <125000>; resistance-at-zero = <100>; resistance-reference = <430>; low-threshold = <6579>; high-threshold = <32767>; filter-50hz; + status = "okay"; }; -test_spi_bmm150: bmm150@2b { +test_spi_bmm150: bmm150@1d { compatible = "bosch,bmm150"; - reg = <0x2b>; + reg = <0x1d>; spi-max-frequency = <0>; + status = "okay"; }; -test_spi_hts221: hts221@2c { +test_spi_hts221: hts221@1e { compatible = "st,hts221"; - reg = <0x2c>; + reg = <0x1e>; spi-max-frequency = <0>; drdy-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_adt7310: adt7310@2d { +test_spi_adt7310: adt7310@1f { compatible = "adi,adt7310"; - reg = <0x2d>; + reg = <0x1f>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_bmi323: bmi323@2e { +test_spi_bmi323: bmi323@20 { compatible = "bosch,bmi323"; - reg = <0x2e>; + reg = <0x20>; spi-max-frequency = <8000000>; int-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lsm6dso16is: lsm6dso16is@2f { +test_spi_lsm6dso16is: lsm6dso16is@21 { compatible = "st,lsm6dso16is"; - reg = <0x2f>; + reg = <0x21>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_lsm6dsv16x: lsm6dsv16x@30 { +test_spi_lsm6dsv16x: lsm6dsv16x@22 { compatible = "st,lsm6dsv16x"; - reg = <0x30>; + reg = <0x22>; spi-max-frequency = <0>; irq-gpios = <&test_gpio 0 0>; + status = "okay"; }; -test_spi_bmi08x_accel: bmi08x@31 { +test_spi_bmi08x_accel: bmi08x@23 { compatible = "bosch,bmi08x-accel"; - reg = <0x31>; + reg = <0x23>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; int1-map-io = <0x01>; @@ -409,9 +309,9 @@ test_spi_bmi08x_accel: bmi08x@31 { accel-fs = <4>; }; -test_spi_bmi08x_gyro: bmi08x@32 { +test_spi_bmi08x_gyro: bmi08x@24 { compatible = "bosch,bmi08x-gyro"; - reg = <0x32>; + reg = <0x24>; spi-max-frequency = <0>; int-gpios = <&test_gpio 0 0>; int3-4-map-io = <0x01>; From f3aaf334226ab201b318c5ee0d0a6f7a9e658397 Mon Sep 17 00:00:00 2001 From: Silviu Petria Date: Wed, 12 Jul 2023 10:50:43 +0300 Subject: [PATCH 1398/2042] Bluetooth: Audio: Add TMAP broadcast samples Add two TMAP broadcast sample applications. tmap_bms implements the Broadcast Media Sender role. It uses CAP Initiator broadcast APIs to broadcast an audio stream. tmap_bmr implements the Broadcast Media Receiver role. It scans and syncs to the PA having filtered the EA by the presence of TMAP role information. It also instantiates the VCP. Signed-off-by: Silviu Petria --- samples/bluetooth/tmap_bmr/CMakeLists.txt | 13 + samples/bluetooth/tmap_bmr/Kconfig | 12 + samples/bluetooth/tmap_bmr/README.rst | 21 + .../tmap_bmr/boards/native_posix.conf | 10 + .../tmap_bmr/boards/nrf52840dk_nrf52840.conf | 4 + .../nrf5340_audio_dk_nrf5340_cpuapp.conf | 8 + .../boards/nrf5340dk_nrf5340_cpuapp.conf | 8 + samples/bluetooth/tmap_bmr/prj.conf | 37 ++ samples/bluetooth/tmap_bmr/sample.yaml | 10 + .../tmap_bmr/src/bap_broadcast_sink.c | 413 ++++++++++++++++++ samples/bluetooth/tmap_bmr/src/main.c | 54 +++ samples/bluetooth/tmap_bmr/src/tmap_bmr.h | 28 ++ .../bluetooth/tmap_bmr/src/vcp_vol_renderer.c | 68 +++ samples/bluetooth/tmap_bms/CMakeLists.txt | 12 + samples/bluetooth/tmap_bms/README.rst | 22 + .../tmap_bms/boards/native_posix.conf | 10 + .../tmap_bms/boards/nrf52840dk_nrf52840.conf | 4 + .../nrf5340_audio_dk_nrf5340_cpuapp.conf | 8 + .../boards/nrf5340dk_nrf5340_cpuapp.conf | 8 + samples/bluetooth/tmap_bms/prj.conf | 26 ++ samples/bluetooth/tmap_bms/sample.yaml | 10 + .../bluetooth/tmap_bms/src/cap_initiator.c | 346 +++++++++++++++ samples/bluetooth/tmap_bms/src/main.c | 63 +++ samples/bluetooth/tmap_bms/src/tmap_bms.h | 20 + 24 files changed, 1215 insertions(+) create mode 100644 samples/bluetooth/tmap_bmr/CMakeLists.txt create mode 100644 samples/bluetooth/tmap_bmr/Kconfig create mode 100644 samples/bluetooth/tmap_bmr/README.rst create mode 100644 samples/bluetooth/tmap_bmr/boards/native_posix.conf create mode 100644 samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf create mode 100644 samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf create mode 100644 samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 samples/bluetooth/tmap_bmr/prj.conf create mode 100644 samples/bluetooth/tmap_bmr/sample.yaml create mode 100644 samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c create mode 100644 samples/bluetooth/tmap_bmr/src/main.c create mode 100644 samples/bluetooth/tmap_bmr/src/tmap_bmr.h create mode 100644 samples/bluetooth/tmap_bmr/src/vcp_vol_renderer.c create mode 100644 samples/bluetooth/tmap_bms/CMakeLists.txt create mode 100644 samples/bluetooth/tmap_bms/README.rst create mode 100644 samples/bluetooth/tmap_bms/boards/native_posix.conf create mode 100644 samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf create mode 100644 samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf create mode 100644 samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 samples/bluetooth/tmap_bms/prj.conf create mode 100644 samples/bluetooth/tmap_bms/sample.yaml create mode 100644 samples/bluetooth/tmap_bms/src/cap_initiator.c create mode 100644 samples/bluetooth/tmap_bms/src/main.c create mode 100644 samples/bluetooth/tmap_bms/src/tmap_bms.h diff --git a/samples/bluetooth/tmap_bmr/CMakeLists.txt b/samples/bluetooth/tmap_bmr/CMakeLists.txt new file mode 100644 index 000000000000..6aacc402d203 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(tmap_bmr) + +target_sources(app PRIVATE + src/main.c + src/vcp_vol_renderer.c + src/bap_broadcast_sink.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/tmap_bmr/Kconfig b/samples/bluetooth/tmap_bmr/Kconfig new file mode 100644 index 000000000000..cb6662f72044 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/Kconfig @@ -0,0 +1,12 @@ +# +# Copyright (c) 2022 Codecoup +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "Bluetooth: Earbuds" + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu diff --git a/samples/bluetooth/tmap_bmr/README.rst b/samples/bluetooth/tmap_bmr/README.rst new file mode 100644 index 000000000000..0c904803062c --- /dev/null +++ b/samples/bluetooth/tmap_bmr/README.rst @@ -0,0 +1,21 @@ +.. _bluetooth_tmap_bmr: + +Bluetooth: TMAP BMR +################### + +Overview +******** + +Application demonstrating the LE Audio TMAP Broadcast Media Receiver functionality. +Implements the BMR role. + +Requirements +************ + +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** +This sample can be found under :zephyr_file:`samples/bluetooth/tmap_bmr` in the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/tmap_bmr/boards/native_posix.conf b/samples/bluetooth/tmap_bmr/boards/native_posix.conf new file mode 100644 index 000000000000..3d06b9f321f3 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/native_posix.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 000000000000..3c7c698c48b8 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,4 @@ +CONFIG_BT_CTLR_PERIPHERAL_ISO=y + +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..f7c6bbfd3db0 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -0,0 +1,8 @@ +# 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 +# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. +CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..f7c6bbfd3db0 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,8 @@ +# 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 +# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. +CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bmr/prj.conf b/samples/bluetooth/tmap_bmr/prj.conf new file mode 100644 index 000000000000..3a0fd96f598e --- /dev/null +++ b/samples/bluetooth/tmap_bmr/prj.conf @@ -0,0 +1,37 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_PAC_SNK=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_PRIVACY=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 + +# TMAP support +CONFIG_BT_TMAP=y + +# 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 + +# VCP support +CONFIG_BT_VCP_VOL_REND=y + +# 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_GATT_DYNAMIC_DB=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="TMAP BMR" diff --git a/samples/bluetooth/tmap_bmr/sample.yaml b/samples/bluetooth/tmap_bmr/sample.yaml new file mode 100644 index 000000000000..2427ef9ca823 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/sample.yaml @@ -0,0 +1,10 @@ +sample: + description: Bluetooth Low Energy Audio TMAP BMR sample + name: Bluetooth Low Energy Audio TMAP BMR sample +tests: + sample.bluetooth.tmap_bmr: + harness: bluetooth + platform_allow: qemu_cortex_m3 qemu_x86 + tags: bluetooth + integration_platforms: + - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c new file mode 100644 index 000000000000..394c06a6c1a1 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include +#include +#include + +#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 tmap_bms_found; + +static K_SEM_DEFINE(sem_pa_synced, 0U, 1U); +static K_SEM_DEFINE(sem_base_received, 0U, 1U); +static K_SEM_DEFINE(sem_sink_created, 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 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, +}; + +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 struct bt_audio_codec_cap codec = BT_AUDIO_CODEC_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; + + 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_TMAS)) { + struct net_buf_simple tmas_svc_data; + uint16_t uuid_val; + uint16_t peer_tmap_role = 0; + + net_buf_simple_init_with_data(&tmas_svc_data, + (void *)data->data, + data->data_len); + uuid_val = net_buf_simple_pull_le16(&tmas_svc_data); + if (tmas_svc_data.len < sizeof(peer_tmap_role)) { + return false; + } + + peer_tmap_role = net_buf_simple_pull_le16(&tmas_svc_data); + if ((peer_tmap_role & BT_TMAP_ROLE_BMS)) { + printk("Found TMAP BMS\n"); + tmap_bms_found = true; + } + + return true; + } + + return true; +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + uint32_t broadcast_id; + + tmap_bms_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) && tmap_bms_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) +{ + uint32_t base_bis_index_bitfield = 0U; + struct bt_bap_base base = { 0 }; + + if (data->type != BT_DATA_SVC_DATA16) { + return true; + } + + if (data->data_len < BT_BAP_BASE_MIN_SIZE) { + return true; + } + + if (bt_bap_decode_base(data, &base) != 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); + + 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 pa_synced_cb(struct bt_bap_broadcast_sink *sink, + struct bt_le_per_adv_sync *sync, + uint32_t broadcast_id) +{ + if (broadcast_sink != NULL) { + printk("Unexpected PA sync\n"); + return; + } + + printk("PA synced for broadcast sink %p with broadcast ID 0x%06X\n", + sink, broadcast_id); + + broadcast_sink = sink; + + k_sem_give(&sem_sink_created); +} + +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) +{ + k_sem_give(&sem_base_received); +} + +static void pa_sync_lost_cb(struct bt_bap_broadcast_sink *sink) +{ + if (broadcast_sink == NULL) { + printk("Unexpected PA sync lost\n"); + return; + } + + printk("Sink %p disconnected\n", sink); + broadcast_sink = NULL; + k_sem_give(&sem_pa_sync_lost); +} + +static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { + .pa_synced = pa_synced_cb, + .syncable = syncable_cb, + .base_recv = base_recv_cb, + .pa_sync_lost = pa_sync_lost_cb +}; + +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_sink_created); + 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; + } + + bt_le_scan_cb_register(&broadcast_scan_cb); + /* Start scanning */ + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL); + if (err) { + printk("Scan start failed (err %d)\n", err); + return err; + } + + /* Wait for PA sync */ + err = k_sem_take(&sem_pa_synced, SEM_TIMEOUT); + if (err != 0) { + printk("sem_pa_synced timed out\n"); + return err; + } + 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); + err = k_sem_take(&sem_sink_created, SEM_TIMEOUT); + if (err != 0) { + printk("sem_sink_created timed out\n"); + 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; +} diff --git a/samples/bluetooth/tmap_bmr/src/main.c b/samples/bluetooth/tmap_bmr/src/main.c new file mode 100644 index 000000000000..af18476f5b26 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/src/main.c @@ -0,0 +1,54 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#include "tmap_bmr.h" + +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 TMAP and setting role\n"); + err = bt_tmap_register(BT_TMAP_ROLE_BMR); + if (err != 0) { + return err; + } + + err = vcp_vol_renderer_init(); + if (err != 0) { + return err; + } + printk("VCP initialized\n"); + + printk("Initializing BAP Broadcast Sink\n"); + err = bap_broadcast_sink_init(); + if (err != 0) { + return err; + } + + printk("Starting BAP Broadcast Sink\n"); + err = bap_broadcast_sink_run(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/samples/bluetooth/tmap_bmr/src/tmap_bmr.h b/samples/bluetooth/tmap_bmr/src/tmap_bmr.h new file mode 100644 index 000000000000..62b7a8c9483b --- /dev/null +++ b/samples/bluetooth/tmap_bmr/src/tmap_bmr.h @@ -0,0 +1,28 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/** + * @brief Initialize the VCP Volume Renderer role + * + * @return 0 if success, errno on failure. + */ +int vcp_vol_renderer_init(void); + +/** + * @brief Initialize BAP Broadcast Sink + * + * @return 0 if success, errno on failure. + */ +int bap_broadcast_sink_init(void); + +/** + * @brief Run BAP Broadcast Sink + * + * @return 0 if success, errno on failure. + */ +int bap_broadcast_sink_run(void); diff --git a/samples/bluetooth/tmap_bmr/src/vcp_vol_renderer.c b/samples/bluetooth/tmap_bmr/src/vcp_vol_renderer.c new file mode 100644 index 000000000000..a87bd374b727 --- /dev/null +++ b/samples/bluetooth/tmap_bmr/src/vcp_vol_renderer.c @@ -0,0 +1,68 @@ +/** @file + * @brief Bluetooth Volume Control Profile (VCP) Volume Renderer role. + * + * Copyright (c) 2020 Bose Corporation + * Copyright (c) 2020-2022 Nordic Semiconductor ASA + * Copyright (c) 2022 Codecoup + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +static struct bt_vcp_included vcp_included; + +static void vcs_state_cb(int err, uint8_t volume, uint8_t mute) +{ + if (err) { + printk("VCS state get failed (%d)\n", err); + } else { + printk("VCS volume %u, mute %u\n", volume, mute); + } +} + +static void vcs_flags_cb(int err, uint8_t flags) +{ + if (err) { + printk("VCS flags get failed (%d)\n", err); + } else { + printk("VCS flags 0x%02X\n", flags); + } +} + +static struct bt_vcp_vol_rend_cb vcp_cbs = { + .state = vcs_state_cb, + .flags = vcs_flags_cb, +}; + +int vcp_vol_renderer_init(void) +{ + int err; + struct bt_vcp_vol_rend_register_param vcp_register_param; + + memset(&vcp_register_param, 0, sizeof(vcp_register_param)); + + vcp_register_param.step = 1; + vcp_register_param.mute = BT_VCP_STATE_UNMUTED; + vcp_register_param.volume = 100; + vcp_register_param.cb = &vcp_cbs; + + err = bt_vcp_vol_rend_register(&vcp_register_param); + if (err) { + return err; + } + + err = bt_vcp_vol_rend_included_get(&vcp_included); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/samples/bluetooth/tmap_bms/CMakeLists.txt b/samples/bluetooth/tmap_bms/CMakeLists.txt new file mode 100644 index 000000000000..953a75ea9e00 --- /dev/null +++ b/samples/bluetooth/tmap_bms/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(tmap_bms) + +target_sources(app PRIVATE + src/main.c + src/cap_initiator.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/tmap_bms/README.rst b/samples/bluetooth/tmap_bms/README.rst new file mode 100644 index 000000000000..92c36a48e543 --- /dev/null +++ b/samples/bluetooth/tmap_bms/README.rst @@ -0,0 +1,22 @@ +.. _bluetooth_tmap_bms: + +Bluetooth: TMAP BMS +################### + +Overview +******** + +Application demonstrating the LE Audio TMAP Broadcast Media Sender functionality. +Implements the BMS role. + + +Requirements +************ + +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** +This sample can be found under :zephyr_file:`samples/bluetooth/tmap_bms` in the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. diff --git a/samples/bluetooth/tmap_bms/boards/native_posix.conf b/samples/bluetooth/tmap_bms/boards/native_posix.conf new file mode 100644 index 000000000000..3d06b9f321f3 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/native_posix.conf @@ -0,0 +1,10 @@ +CONFIG_LOG_MODE_IMMEDIATE=y +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_LIBLC3=y +CONFIG_FPU=y + +# For LE-audio at 10ms intervals we need the tick counter to occur more frequently +# than every 10 ms as each PDU for some reason takes 2 ticks to process. +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y diff --git a/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 000000000000..57d674179ff9 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,4 @@ +CONFIG_BT_CTLR_CENTRAL_ISO=y + +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=155 diff --git a/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..f7c6bbfd3db0 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -0,0 +1,8 @@ +# 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 +# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. +CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..f7c6bbfd3db0 --- /dev/null +++ b/samples/bluetooth/tmap_bms/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,8 @@ +# 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 +# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that. +CONFIG_NEWLIB_LIBC=y diff --git a/samples/bluetooth/tmap_bms/prj.conf b/samples/bluetooth/tmap_bms/prj.conf new file mode 100644 index 000000000000..ab3641a7a0fc --- /dev/null +++ b/samples/bluetooth/tmap_bms/prj.conf @@ -0,0 +1,26 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_AUDIO=y + +CONFIG_BT_SMP=y +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_L2CAP_TX_BUF_COUNT=20 + +# TMAP support +CONFIG_BT_TMAP=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_ISO_TX_BUF_COUNT=2 +CONFIG_BT_ISO_MAX_CHAN=2 +CONFIG_BT_GATT_DYNAMIC_DB=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="TMAP BMS" diff --git a/samples/bluetooth/tmap_bms/sample.yaml b/samples/bluetooth/tmap_bms/sample.yaml new file mode 100644 index 000000000000..83bdc86a9a2d --- /dev/null +++ b/samples/bluetooth/tmap_bms/sample.yaml @@ -0,0 +1,10 @@ +sample: + description: Bluetooth Low Energy Audio TMAP BMS sample + name: Bluetooth Low Energy Audio TMAP BMS sample +tests: + sample.bluetooth.tmap_bms: + harness: bluetooth + platform_allow: qemu_cortex_m3 qemu_x86 + tags: bluetooth + integration_platforms: + - qemu_cortex_m3 diff --git a/samples/bluetooth/tmap_bms/src/cap_initiator.c b/samples/bluetooth/tmap_bms/src/cap_initiator.c new file mode 100644 index 000000000000..7e48147c00a7 --- /dev/null +++ b/samples/bluetooth/tmap_bms/src/cap_initiator.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BROADCAST_ENQUEUE_COUNT 2U +#define MOCK_CCID 0x1234 +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; + +struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ); + +const struct bt_audio_codec_data new_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, + (BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU), + ((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)), + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, + (MOCK_CCID & 0xFFU), + ((MOCK_CCID >> 8) & 0xFFU)) +}; + +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 *adv; + +static uint8_t tmap_addata[] = { + BT_UUID_16_ENCODE(BT_UUID_TMAS_VAL), /* TMAS UUID */ + BT_BYTES_LIST_LE16(BT_TMAP_ROLE_BMS), /* TMAP Role */ +}; + +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) +{ + 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); + 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; + } + + /* Setup extended advertising data */ + ext_ad[0].type = BT_DATA_SVC_DATA16; + ext_ad[0].data_len = ARRAY_SIZE(tmap_addata); + ext_ad[0].data = tmap_addata; + 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); + 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) +{ + 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_count = 1U; + 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; + } + printk("Creating broadcast source\n"); + + err = setup_extended_adv(&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, adv); + if (err != 0) { + printk("Unable to start broadcast source: %d\n", err); + return; + } + + err = setup_extended_adv_data(broadcast_source, adv); + if (err != 0) { + printk("Unable to setup extended advertising data: %d\n", err); + return; + } + + err = start_extended_adv(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); + } + + /* Run for a little while */ + k_sleep(K_SECONDS(10)); + + err = bt_cap_initiator_broadcast_audio_update(broadcast_source, + new_metadata, + ARRAY_SIZE(new_metadata)); + if (err != 0) { + printk("Failed to update broadcast source metadata: %d\n", err); + return; + } + + /* Run for a little while */ + k_sleep(K_SECONDS(10)); + + 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(adv); + if (err != 0) { + printk("Failed to stop and delete extended advertising: %d\n", err); + return; + } + } +} diff --git a/samples/bluetooth/tmap_bms/src/main.c b/samples/bluetooth/tmap_bms/src/main.c new file mode 100644 index 000000000000..ff260901b361 --- /dev/null +++ b/samples/bluetooth/tmap_bms/src/main.c @@ -0,0 +1,63 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "tmap_bms.h" + +static int init(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + printk("Bluetooth enable failed (err %d)\n", err); + return err; + } + + printk("Bluetooth initialized\n"); + + return 0; +} + +int main(void) +{ + int err; + + err = init(); + if (err != 0) { + return err; + } + + printk("Initializing TMAP and setting role\n"); + /* Initialize TMAP */ + err = bt_tmap_register(BT_TMAP_ROLE_BMS); + if (err != 0) { + return err; + } + + /* Initialize CAP Initiator */ + err = cap_initiator_init(); + if (err != 0) { + return err; + } + printk("CAP initialized\n"); + + /* Configure and start broadcast stream */ + err = cap_initiator_setup(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/samples/bluetooth/tmap_bms/src/tmap_bms.h b/samples/bluetooth/tmap_bms/src/tmap_bms.h new file mode 100644 index 000000000000..5110b2f04cd7 --- /dev/null +++ b/samples/bluetooth/tmap_bms/src/tmap_bms.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +/** + * @brief Initialize the CAP Initiator role + * + * @return 0 if success, errno on failure. + */ +int cap_initiator_init(void); + +/** + * @brief Setup streams for CAP Initiator + * + * @return 0 if success, errno on failure. + */ +int cap_initiator_setup(void); From a2ceded56fd1d91419f0ac3a851584bff15537ab Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Wed, 12 Jul 2023 11:33:22 +0200 Subject: [PATCH 1399/2042] Bluetooth: ASCS: Update ISO QOS based on BAP QOS When a CIS is established for the peripheral, then not all QOS values are completely valid as they are simply missing from the CIS established event. This commit updates the missing fields based on the QOS settings provided by the BAP Unicast Client during QoS Configuration of the endpoint. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/ascs.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index c831d51821cc..60bc04e4ae27 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -804,6 +804,23 @@ static void ascs_iso_sent(struct bt_iso_chan *chan) } #endif /* CONFIG_BT_AUDIO_TX */ +static void ascs_update_sdu_size(struct bt_bap_ep *ep) +{ + struct bt_iso_chan_io_qos *io_qos; + struct bt_audio_codec_qos *codec_qos = &ep->qos; + + if (ep->dir == BT_AUDIO_DIR_SINK) { + io_qos = ep->iso->chan.qos->rx; + } else if (ep->dir == BT_AUDIO_DIR_SOURCE) { + io_qos = ep->iso->chan.qos->tx; + } else { + return; + } + + io_qos->sdu = codec_qos->sdu; + io_qos->rtn = codec_qos->rtn; +} + static void ascs_ep_iso_connected(struct bt_bap_ep *ep) { struct bt_bap_stream *stream; @@ -820,6 +837,12 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep) return; } + /* Some values are not provided by the HCI events when the CIS is established for the + * peripheral, so we update them here based on the parameters provided by the BAP Unicast + * Client + */ + ascs_update_sdu_size(ep); + 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 From c9461ca783915612865ebe0be63342a62a0b2533 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 23 Jun 2023 15:17:09 +0200 Subject: [PATCH 1400/2042] drivers: clock_control: add support for stm32 hsi14 clock Add support of the dedicated STM32F0 14 MHz HSI clock for ADC. Also remove ADC clock source selection as it is obsolete. Signed-off-by: Guillaume Gautier --- drivers/clock_control/clock_stm32_ll_common.c | 16 ++++++++++++++++ include/zephyr/dt-bindings/clock/stm32f0_clock.h | 10 +++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index 6d4425a3f99f..52ca69c24264 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -138,6 +138,13 @@ static int enabled_clock(uint32_t src_clk) } break; #endif /* STM32_SRC_LSI */ +#if defined(STM32_SRC_HSI14) + case STM32_SRC_HSI14: + if (!IS_ENABLED(STM32_HSI14_ENABLED)) { + r = -ENOTSUP; + } + break; +#endif /* STM32_SRC_HSI14 */ #if defined(STM32_SRC_HSI48) case STM32_SRC_HSI48: if (!IS_ENABLED(STM32_HSI48_ENABLED)) { @@ -688,6 +695,15 @@ static void set_up_fixed_clock_sources(void) z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); } +#if defined(STM32_HSI14_ENABLED) + /* For all series with HSI 14 clock support */ + if (IS_ENABLED(STM32_HSI14_ENABLED)) { + LL_RCC_HSI14_Enable(); + while (LL_RCC_HSI14_IsReady() != 1) { + } + } +#endif /* STM32_HSI48_ENABLED */ + #if defined(STM32_HSI48_ENABLED) /* For all series with HSI 48 clock support */ if (IS_ENABLED(STM32_HSI48_ENABLED)) { diff --git a/include/zephyr/dt-bindings/clock/stm32f0_clock.h b/include/zephyr/dt-bindings/clock/stm32f0_clock.h index af8582ab5611..309c31877e3f 100644 --- a/include/zephyr/dt-bindings/clock/stm32f0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f0_clock.h @@ -20,13 +20,14 @@ #define STM32_SRC_HSI 0x001 #define STM32_SRC_LSE 0x002 #define STM32_SRC_LSI 0x003 -#define STM32_SRC_HSI48 0x004 +#define STM32_SRC_HSI14 0x004 +#define STM32_SRC_HSI48 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +#define STM32_SRC_SYSCLK 0x006 /** Bus clock */ -#define STM32_SRC_PCLK 0x006 +#define STM32_SRC_PCLK 0x007 /** PLL clock */ -#define STM32_SRC_PLLCLK 0x007 +#define STM32_SRC_PLLCLK 0x008 #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -68,7 +69,6 @@ #define I2C1_SEL(val) STM32_CLOCK(val, 1, 4, CFGR3_REG) #define CEC_SEL(val) STM32_CLOCK(val, 1, 6, CFGR3_REG) #define USB_SEL(val) STM32_CLOCK(val, 1, 7, CFGR3_REG) -#define ADC_SEL(val) STM32_CLOCK(val, 1, 8, CFGR3_REG) #define USART2_SEL(val) STM32_CLOCK(val, 3, 16, CFGR3_REG) #define USART3_SEL(val) STM32_CLOCK(val, 3, 18, CFGR3_REG) /** BDCR devices */ From a254ea0cd1258277f20178b5ca741a90ef3f06a0 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 23 Jun 2023 15:17:52 +0200 Subject: [PATCH 1401/2042] dts: arm: st: f0: add hsi14 clock Add HIS14 clock in STM32F0 dtsi. Signed-off-by: Guillaume Gautier --- dts/arm/st/f0/stm32f0.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index ff7ee5ee347a..447062008833 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -51,6 +51,13 @@ status = "disabled"; }; + clk_hsi14: clk-hsi14 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = ; + status = "disabled"; + }; + clk_lse: clk-lse { #clock-cells = <0>; compatible = "st,stm32-lse-clock"; From bbbc28a0bafe89e8016709bf6b3fdf8fcffac2e6 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 13 Jul 2023 14:40:22 +0200 Subject: [PATCH 1402/2042] Bluetooth: CAP: Always register BAP callbacks with CAP callbacks Modified bt_cap_stream_ops_register to always register BAP callbacks to ensure that the callbacks are always forwarded (unless later overwritten by the application...) The CAP Initiator Unicast will still register the callbacks itself, to ensure that the unicast procedures still work even if bt_cap_stream_ops_register was never called. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/cap_stream.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/subsys/bluetooth/audio/cap_stream.c b/subsys/bluetooth/audio/cap_stream.c index c9c91de1f4ad..e542bc2b288b 100644 --- a/subsys/bluetooth/audio/cap_stream.c +++ b/subsys/bluetooth/audio/cap_stream.c @@ -210,11 +210,13 @@ void bt_cap_stream_ops_register(struct bt_cap_stream *stream, { stream->ops = ops; - /* For the broadcast sink role, this is the only way we can ensure that - * the BAP callbacks are registered, as there are no CAP broadcast sink - * procedures that we can use to register the callbacks in other ways. + /* CAP basically just forwards the BAP callbacks after doing what it (CAP) needs to do, + * so we can just always register the BAP callbacks here + * + * It is, however, only the CAP Initiator Unicast that depend on the callbacks being set in + * order to work, so for the CAP Initiator Unicast we need an additional register to ensure + * correctness. */ - if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK)) { - bt_cap_stream_ops_register_bap(stream); - } + + bt_cap_stream_ops_register_bap(stream); } From 9f02eeadf890c80047fea2bb50905ac5ea43183d Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 18 Aug 2022 11:19:46 -0700 Subject: [PATCH 1403/2042] serial: allow callback setting to be exclusive Both the IRQ API and Asynchronous API support callback. However, since they are both interrupt driven, having callbacks on both API would interfere with each other in almost all cases. So this adds a kconfig to signal that the callbacks should be exclusive to each other. In other words, if one is set, the other should not be active. Drivers implementing both APIs have been updated to remove the callbacks from the other API. Though, this still leaves the option to disable the kconfig and allows both APIs to have callbacks if one desires. Fixes #48606 Signed-off-by: Daniel Leung --- doc/hardware/peripherals/uart.rst | 9 +++++++++ drivers/serial/Kconfig | 15 +++++++++++++++ drivers/serial/uart_esp32.c | 10 ++++++++++ drivers/serial/uart_mcux_flexcomm.c | 11 +++++++++++ drivers/serial/uart_mcux_lpuart.c | 10 ++++++++++ drivers/serial/uart_nrfx_uart.c | 10 ++++++++++ drivers/serial/uart_nrfx_uarte.c | 10 ++++++++++ drivers/serial/uart_sam0.c | 10 ++++++++++ drivers/serial/uart_stm32.c | 10 ++++++++++ drivers/serial/uart_xmc4xxx.c | 11 +++++++++++ 10 files changed, 106 insertions(+) diff --git a/doc/hardware/peripherals/uart.rst b/doc/hardware/peripherals/uart.rst index b190dcbeea03..42906bca6fab 100644 --- a/doc/hardware/peripherals/uart.rst +++ b/doc/hardware/peripherals/uart.rst @@ -28,6 +28,15 @@ The Asynchronous API allows to read and write data in the background using DMA without interrupting the MCU at all. However, the setup is more complex 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. + Configuration Options ********************* diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 405fda7d0744..a803c152919c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -76,6 +76,21 @@ config UART_INTERRUPT_DRIVEN This option enables interrupt support for UART allowing console input and other UART based drivers. +config UART_EXCLUSIVE_API_CALLBACKS + bool "Use exclusive callbacks for multiple APIs" + depends on UART_ASYNC_API && UART_INTERRUPT_DRIVEN + default y + help + When multiple set of APIs support callbacks, enabling this + option will result in only the callbacks of one set of API + being active at a time. Setting a new callback to one set of + API will remove callbacks to other set of APIs. For example, + calling uart_callback_set() would disable the callback + previously set via uart_irq_callback_set(). + + Says yes unless you are absolutely sure you know what you are + doing and promise not to file bug when things do not work out. + config UART_LINE_CTRL bool "Serial Line Control API" help diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 380226dcfe6e..a1054ba7d853 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -435,6 +435,11 @@ static void uart_esp32_irq_callback_set(const struct device *dev, uart_irq_callb data->irq_cb = cb; data->irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async.cb = NULL; + data->async.user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -662,6 +667,11 @@ static int uart_esp32_async_callback_set(const struct device *dev, uart_callback data->async.cb = callback; data->async.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->irq_cb = NULL; + data->irq_cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_mcux_flexcomm.c b/drivers/serial/uart_mcux_flexcomm.c index 041f690317d3..4332b20cb910 100644 --- a/drivers/serial/uart_mcux_flexcomm.c +++ b/drivers/serial/uart_mcux_flexcomm.c @@ -279,6 +279,11 @@ static void mcux_flexcomm_irq_callback_set(const struct device *dev, data->irq_callback = cb; data->irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_callback = NULL; + data->async_cb_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -400,6 +405,12 @@ static int mcux_flexcomm_uart_callback_set(const struct device *dev, data->async_callback = callback; data->async_cb_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->irq_callback = NULL; + data->irq_cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index cdafa42d585d..e1fe23ea3228 100644 --- a/drivers/serial/uart_mcux_lpuart.c +++ b/drivers/serial/uart_mcux_lpuart.c @@ -370,6 +370,11 @@ static void mcux_lpuart_irq_callback_set(const struct device *dev, data->callback = cb; data->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async.user_callback = NULL; + data->async.user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -661,6 +666,11 @@ static int mcux_lpuart_callback_set(const struct device *dev, uart_callback_t ca data->async.user_callback = callback; data->async.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->callback = NULL; + data->cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_nrfx_uart.c b/drivers/serial/uart_nrfx_uart.c index 77efdd0050ae..96cb190a4878 100644 --- a/drivers/serial/uart_nrfx_uart.c +++ b/drivers/serial/uart_nrfx_uart.c @@ -405,6 +405,11 @@ static int uart_nrfx_callback_set(const struct device *dev, uart0_cb.callback = callback; uart0_cb.user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + irq_callback = NULL; + irq_cb_data = NULL; +#endif + return 0; } @@ -923,6 +928,11 @@ static void uart_nrfx_irq_callback_set(const struct device *dev, (void)dev; irq_callback = cb; irq_cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + uart0_cb.callback = NULL; + uart0_cb.user_data = NULL; +#endif } /** diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 047405b84c00..16877328e5f2 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -937,6 +937,11 @@ static int uarte_nrfx_callback_set(const struct device *dev, data->async->user_callback = callback; data->async->user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->int_driven->cb = NULL; + data->int_driven->cb_data = NULL; +#endif + return 0; } @@ -1675,6 +1680,11 @@ static void uarte_nrfx_irq_callback_set(const struct device *dev, data->int_driven->cb = cb; data->int_driven->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async->user_callback = NULL; + data->async->user_data = NULL; +#endif } #endif /* UARTE_INTERRUPT_DRIVEN */ diff --git a/drivers/serial/uart_sam0.c b/drivers/serial/uart_sam0.c index 82676b4f85bd..4f4407bdca94 100644 --- a/drivers/serial/uart_sam0.c +++ b/drivers/serial/uart_sam0.c @@ -935,6 +935,11 @@ static void uart_sam0_irq_callback_set(const struct device *dev, dev_data->cb = cb; dev_data->cb_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + dev_data->async_cb = NULL; + dev_data->async_cb_data = NULL; +#endif } #endif @@ -949,6 +954,11 @@ static int uart_sam0_callback_set(const struct device *dev, dev_data->async_cb = callback; dev_data->async_cb_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + dev_data->cb = NULL; + dev_data->cb_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index 45a16e9e8931..23be4a9138cd 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -904,6 +904,11 @@ static void uart_stm32_irq_callback_set(const struct device *dev, data->user_cb = cb; data->user_data = cb_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_cb = NULL; + data->async_user_data = NULL; +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -1125,6 +1130,11 @@ static int uart_stm32_async_callback_set(const struct device *dev, data->async_cb = callback; data->async_user_data = user_data; +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->user_cb = NULL; + data->user_data = NULL; +#endif + return 0; } diff --git a/drivers/serial/uart_xmc4xxx.c b/drivers/serial/uart_xmc4xxx.c index 278e7bcfb101..40e33b9fa452 100644 --- a/drivers/serial/uart_xmc4xxx.c +++ b/drivers/serial/uart_xmc4xxx.c @@ -360,6 +360,11 @@ static void uart_xmc4xxx_irq_callback_set(const struct device *dev, data->user_cb = cb; data->user_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->async_cb = NULL; + data->async_user_data = NULL; +#endif } #define NVIC_ISPR_BASE 0xe000e200u @@ -599,6 +604,12 @@ static int uart_xmc4xxx_async_callback_set(const struct device *dev, uart_callba data->async_cb = callback; data->async_user_data = user_data; + +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) + data->user_cb = NULL; + data->user_data = NULL; +#endif + return 0; } From 0c4900d5abb1e71b23d782e00349b106124b91f4 Mon Sep 17 00:00:00 2001 From: Mykola Kvach Date: Mon, 17 Jul 2023 12:44:40 +0300 Subject: [PATCH 1404/2042] soc: arm64: renesas: gen3: Move GIC version to DT Move the GIC version to the device tree for Renesas R-Car Gen3 to improve readability Signed-off-by: Mykola Kvach --- dts/arm64/renesas/rcar_gen3_ca57.dtsi | 2 +- soc/arm64/renesas_rcar/gen3/Kconfig.series | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dts/arm64/renesas/rcar_gen3_ca57.dtsi b/dts/arm64/renesas/rcar_gen3_ca57.dtsi index d9bba53f2a35..5c87c8accd3b 100644 --- a/dts/arm64/renesas/rcar_gen3_ca57.dtsi +++ b/dts/arm64/renesas/rcar_gen3_ca57.dtsi @@ -29,7 +29,7 @@ }; gic: interrupt-controller@f1010000 { - compatible = "arm,gic-400", "arm,gic" ; + compatible = "arm,gic-400", "arm,gic-v2", "arm,gic" ; #interrupt-cells = <4>; #address-cells = <0>; interrupt-controller; diff --git a/soc/arm64/renesas_rcar/gen3/Kconfig.series b/soc/arm64/renesas_rcar/gen3/Kconfig.series index 49465fa741e5..395b95175286 100644 --- a/soc/arm64/renesas_rcar/gen3/Kconfig.series +++ b/soc/arm64/renesas_rcar/gen3/Kconfig.series @@ -5,7 +5,6 @@ config SOC_SERIES_RCAR_GEN3 bool "Renesas RCAR Gen3 Cortex A" select ARM64 select CPU_CORTEX_A57 - select GIC_V2 select SOC_FAMILY_RCAR select ARM_ARCH_TIMER select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL From e1f4a6f3ef16cfbdaf9a4a5530f3dff69f4df06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 14:58:40 +0200 Subject: [PATCH 1405/2042] bluetooth: mesh: doc: Add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Misc. improvements in the Doxygen comments Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/mesh/access.h | 170 ++++++++++++++++++++++--- include/zephyr/bluetooth/mesh/main.h | 59 ++++----- 2 files changed, 183 insertions(+), 46 deletions(-) diff --git a/include/zephyr/bluetooth/mesh/access.h b/include/zephyr/bluetooth/mesh/access.h index d033d9e88499..f3b6c3731289 100644 --- a/include/zephyr/bluetooth/mesh/access.h +++ b/include/zephyr/bluetooth/mesh/access.h @@ -41,28 +41,60 @@ extern "C" { #endif -#define BT_MESH_ADDR_UNASSIGNED 0x0000 -#define BT_MESH_ADDR_ALL_NODES 0xffff -#define BT_MESH_ADDR_RELAYS 0xfffe -#define BT_MESH_ADDR_FRIENDS 0xfffd -#define BT_MESH_ADDR_PROXIES 0xfffc -#define BT_MESH_ADDR_DFW_NODES 0xfffb -#define BT_MESH_ADDR_IP_NODES 0xfffa -#define BT_MESH_ADDR_IP_BR_ROUTERS 0xfff9 - -#define BT_MESH_KEY_UNUSED 0xffff -#define BT_MESH_KEY_ANY 0xffff -#define BT_MESH_KEY_DEV 0xfffe -#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV -#define BT_MESH_KEY_DEV_REMOTE 0xfffd -#define BT_MESH_KEY_DEV_ANY 0xfffc +/** + * @name Group addresses + * @{ + */ +#define BT_MESH_ADDR_UNASSIGNED 0x0000 /**< unassigned */ +#define BT_MESH_ADDR_ALL_NODES 0xffff /**< all-nodes */ +#define BT_MESH_ADDR_RELAYS 0xfffe /**< all-relays */ +#define BT_MESH_ADDR_FRIENDS 0xfffd /**< all-friends */ +#define BT_MESH_ADDR_PROXIES 0xfffc /**< all-proxies */ +#define BT_MESH_ADDR_DFW_NODES 0xfffb /**< all-directed-forwarding-nodes */ +#define BT_MESH_ADDR_IP_NODES 0xfffa /**< all-ipt-nodes */ +#define BT_MESH_ADDR_IP_BR_ROUTERS 0xfff9 /**< all-ipt-border-routers */ +/** + * @} + */ + +/** + * @name Predefined key indexes + * @{ + */ +#define BT_MESH_KEY_UNUSED 0xffff /**< Key unused */ +#define BT_MESH_KEY_ANY 0xffff /**< Any key index */ +#define BT_MESH_KEY_DEV 0xfffe /**< Device key */ +#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV /**< Local device key */ +#define BT_MESH_KEY_DEV_REMOTE 0xfffd /**< Remote device key */ +#define BT_MESH_KEY_DEV_ANY 0xfffc /**< Any device key */ +/** + * @} + */ +/** + * Check if a Bluetooth Mesh address is a unicast address. + */ #define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000) +/** + * Check if a Bluetooth Mesh address is a group address. + */ #define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) < 0xff00) +/** + * Check if a Bluetooth Mesh address is a fixed group address. + */ #define BT_MESH_ADDR_IS_FIXED_GROUP(addr) ((addr) >= 0xff00 && (addr) < 0xffff) +/** + * Check if a Bluetooth Mesh address is a virtual address. + */ #define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000) +/** + * Check if a Bluetooth Mesh address is an RFU address. + */ #define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfff8) +/** + * Check if a Bluetooth Mesh key is a device key. + */ #define BT_MESH_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \ key == BT_MESH_KEY_DEV_REMOTE) @@ -132,85 +164,189 @@ struct bt_mesh_elem { struct bt_mesh_model * const vnd_models; }; -/* Foundation Models */ +/** + * @name Foundation Models + * @{ + */ +/** Configuration Server */ #define BT_MESH_MODEL_ID_CFG_SRV 0x0000 +/** Configuration Client */ #define BT_MESH_MODEL_ID_CFG_CLI 0x0001 +/** Health Server */ #define BT_MESH_MODEL_ID_HEALTH_SRV 0x0002 +/** Health Client */ #define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003 +/** Remote Provisioning Server */ #define BT_MESH_MODEL_ID_REMOTE_PROV_SRV 0x0004 +/** Remote Provisioning Client */ #define BT_MESH_MODEL_ID_REMOTE_PROV_CLI 0x0005 +/** Private Beacon Server */ #define BT_MESH_MODEL_ID_PRIV_BEACON_SRV 0x000a +/** Private Beacon Client */ #define BT_MESH_MODEL_ID_PRIV_BEACON_CLI 0x000b +/** SAR Configuration Server */ #define BT_MESH_MODEL_ID_SAR_CFG_SRV 0x000e +/** SAR Configuration Client */ #define BT_MESH_MODEL_ID_SAR_CFG_CLI 0x000f +/** Opcodes Aggregator Server */ #define BT_MESH_MODEL_ID_OP_AGG_SRV 0x0010 +/** Opcodes Aggregator Client */ #define BT_MESH_MODEL_ID_OP_AGG_CLI 0x0011 +/** Large Composition Data Server */ #define BT_MESH_MODEL_ID_LARGE_COMP_DATA_SRV 0x0012 +/** Large Composition Data Client */ #define BT_MESH_MODEL_ID_LARGE_COMP_DATA_CLI 0x0013 +/** Solicitation PDU RPL Configuration Client */ #define BT_MESH_MODEL_ID_SOL_PDU_RPL_SRV 0x0014 +/** Solicitation PDU RPL Configuration Server */ #define BT_MESH_MODEL_ID_SOL_PDU_RPL_CLI 0x0015 +/** Private Proxy Server */ #define BT_MESH_MODEL_ID_ON_DEMAND_PROXY_SRV 0x000c +/** Private Proxy Client */ #define BT_MESH_MODEL_ID_ON_DEMAND_PROXY_CLI 0x000d +/** + * @} + */ -/* Models from the Mesh Model Specification */ +/** + * @name Models from the Mesh Model Specification + * @{ + */ +/** Generic OnOff Server */ #define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000 +/** Generic OnOff Client */ #define BT_MESH_MODEL_ID_GEN_ONOFF_CLI 0x1001 +/** Generic Level Server */ #define BT_MESH_MODEL_ID_GEN_LEVEL_SRV 0x1002 +/** Generic Level Client */ #define BT_MESH_MODEL_ID_GEN_LEVEL_CLI 0x1003 +/** Generic Default Transition Time Server */ #define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV 0x1004 +/** Generic Default Transition Time Client */ #define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI 0x1005 +/** Generic Power OnOff Server */ #define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV 0x1006 +/** Generic Power OnOff Setup Server */ #define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV 0x1007 +/** Generic Power OnOff Client */ #define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI 0x1008 +/** Generic Power Level Server */ #define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV 0x1009 +/** Generic Power Level Setup Server */ #define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV 0x100a +/** Generic Power Level Client */ #define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI 0x100b +/** Generic Battery Server */ #define BT_MESH_MODEL_ID_GEN_BATTERY_SRV 0x100c +/** Generic Battery Client */ #define BT_MESH_MODEL_ID_GEN_BATTERY_CLI 0x100d +/** Generic Location Server */ #define BT_MESH_MODEL_ID_GEN_LOCATION_SRV 0x100e +/** Generic Location Setup Server */ #define BT_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV 0x100f +/** Generic Location Client */ #define BT_MESH_MODEL_ID_GEN_LOCATION_CLI 0x1010 +/** Generic Admin Property Server */ #define BT_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV 0x1011 +/** Generic Manufacturer Property Server */ #define BT_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV 0x1012 +/** Generic User Property Server */ #define BT_MESH_MODEL_ID_GEN_USER_PROP_SRV 0x1013 +/** Generic Client Property Server */ #define BT_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV 0x1014 +/** Generic Property Client */ #define BT_MESH_MODEL_ID_GEN_PROP_CLI 0x1015 +/** Sensor Server */ #define BT_MESH_MODEL_ID_SENSOR_SRV 0x1100 +/** Sensor Setup Server */ #define BT_MESH_MODEL_ID_SENSOR_SETUP_SRV 0x1101 +/** Sensor Client */ #define BT_MESH_MODEL_ID_SENSOR_CLI 0x1102 +/** Time Server */ #define BT_MESH_MODEL_ID_TIME_SRV 0x1200 +/** Time Setup Server */ #define BT_MESH_MODEL_ID_TIME_SETUP_SRV 0x1201 +/** Time Client */ #define BT_MESH_MODEL_ID_TIME_CLI 0x1202 +/** Scene Server */ #define BT_MESH_MODEL_ID_SCENE_SRV 0x1203 +/** Scene Setup Server */ #define BT_MESH_MODEL_ID_SCENE_SETUP_SRV 0x1204 +/** Scene Client */ #define BT_MESH_MODEL_ID_SCENE_CLI 0x1205 +/** Scheduler Server */ #define BT_MESH_MODEL_ID_SCHEDULER_SRV 0x1206 +/** Scheduler Setup Server */ #define BT_MESH_MODEL_ID_SCHEDULER_SETUP_SRV 0x1207 +/** Scheduler Client */ #define BT_MESH_MODEL_ID_SCHEDULER_CLI 0x1208 +/** Light Lightness Server */ #define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV 0x1300 +/** Light Lightness Setup Server */ #define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV 0x1301 +/** Light Lightness Client */ #define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI 0x1302 +/** Light CTL Server */ #define BT_MESH_MODEL_ID_LIGHT_CTL_SRV 0x1303 +/** Light CTL Setup Server */ #define BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV 0x1304 +/** Light CTL Client */ #define BT_MESH_MODEL_ID_LIGHT_CTL_CLI 0x1305 +/** Light CTL Temperature Server */ #define BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV 0x1306 +/** Light HSL Server */ #define BT_MESH_MODEL_ID_LIGHT_HSL_SRV 0x1307 +/** Light HSL Setup Server */ #define BT_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV 0x1308 +/** Light HSL Client */ #define BT_MESH_MODEL_ID_LIGHT_HSL_CLI 0x1309 +/** Light HSL Hue Server */ #define BT_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV 0x130a +/** Light HSL Saturation Server */ #define BT_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV 0x130b +/** Light xyL Server */ #define BT_MESH_MODEL_ID_LIGHT_XYL_SRV 0x130c +/** Light xyL Setup Server */ #define BT_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV 0x130d +/** Light xyL Client */ #define BT_MESH_MODEL_ID_LIGHT_XYL_CLI 0x130e +/** Light LC Server */ #define BT_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f +/** Light LC Setup Server */ #define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 +/** Light LC Client */ #define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 +/** + * @} + */ + +/** + * @name Models from the Mesh Binary Large Object Transfer Model Specification + * @{ + */ +/** BLOB Transfer Server */ #define BT_MESH_MODEL_ID_BLOB_SRV 0x1400 +/** BLOB Transfer Client */ #define BT_MESH_MODEL_ID_BLOB_CLI 0x1401 +/** + * @} + */ + +/** + * @name Models from the Mesh Device Firmware Update Model Specification + * @{ + */ +/** Firmware Update Server */ #define BT_MESH_MODEL_ID_DFU_SRV 0x1402 +/** Firmware Update Client */ #define BT_MESH_MODEL_ID_DFU_CLI 0x1403 +/** Firmware Distribution Server */ #define BT_MESH_MODEL_ID_DFD_SRV 0x1404 +/** Firmware Distribution Client */ #define BT_MESH_MODEL_ID_DFD_CLI 0x1405 +/** + * @} + */ /** Model opcode handler. */ struct bt_mesh_model_op { diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index 5d37b581f4d3..ab274729cf8b 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -35,53 +35,53 @@ enum { /** OOB Type field values. */ enum { - BT_MESH_STATIC_OOB_AVAILABLE = BIT(0), /* Static OOB information available */ - BT_MESH_OOB_AUTH_REQUIRED = BIT(1) /* OOB authentication required */ + BT_MESH_STATIC_OOB_AVAILABLE = BIT(0), /**< Static OOB information available */ + BT_MESH_OOB_AUTH_REQUIRED = BIT(1) /**< OOB authentication required */ }; /** Available Provisioning output authentication actions. */ typedef enum { BT_MESH_NO_OUTPUT = 0, - BT_MESH_BLINK = BIT(0), - BT_MESH_BEEP = BIT(1), - BT_MESH_VIBRATE = BIT(2), - BT_MESH_DISPLAY_NUMBER = BIT(3), - BT_MESH_DISPLAY_STRING = BIT(4), + BT_MESH_BLINK = BIT(0), /**< Blink */ + BT_MESH_BEEP = BIT(1), /**< Beep */ + BT_MESH_VIBRATE = BIT(2), /**< Vibrate */ + BT_MESH_DISPLAY_NUMBER = BIT(3), /**< Output numeric */ + BT_MESH_DISPLAY_STRING = BIT(4), /**< Output alphanumeric */ } bt_mesh_output_action_t; /** Available Provisioning input authentication actions. */ typedef enum { BT_MESH_NO_INPUT = 0, - BT_MESH_PUSH = BIT(0), - BT_MESH_TWIST = BIT(1), - BT_MESH_ENTER_NUMBER = BIT(2), - BT_MESH_ENTER_STRING = BIT(3), + BT_MESH_PUSH = BIT(0), /**< Push */ + BT_MESH_TWIST = BIT(1), /**< Twist */ + BT_MESH_ENTER_NUMBER = BIT(2), /**< Input number */ + BT_MESH_ENTER_STRING = BIT(3), /**< Input alphanumeric */ } bt_mesh_input_action_t; /** Available Provisioning bearers. */ typedef enum { - BT_MESH_PROV_ADV = BIT(0), - BT_MESH_PROV_GATT = BIT(1), - BT_MESH_PROV_REMOTE = BIT(2), + BT_MESH_PROV_ADV = BIT(0), /**< PB-ADV bearer */ + BT_MESH_PROV_GATT = BIT(1), /**< PB-GATT bearer */ + BT_MESH_PROV_REMOTE = BIT(2), /**< PB-Remote bearer */ } bt_mesh_prov_bearer_t; /** Out of Band information location. */ typedef enum { - BT_MESH_PROV_OOB_OTHER = BIT(0), - BT_MESH_PROV_OOB_URI = BIT(1), - BT_MESH_PROV_OOB_2D_CODE = BIT(2), - BT_MESH_PROV_OOB_BAR_CODE = BIT(3), - BT_MESH_PROV_OOB_NFC = BIT(4), - BT_MESH_PROV_OOB_NUMBER = BIT(5), - BT_MESH_PROV_OOB_STRING = BIT(6), - BT_MESH_PROV_OOB_CERTIFICATE = BIT(7), - BT_MESH_PROV_OOB_RECORDS = BIT(8), + BT_MESH_PROV_OOB_OTHER = BIT(0), /**< Other */ + BT_MESH_PROV_OOB_URI = BIT(1), /**< Electronic / URI */ + BT_MESH_PROV_OOB_2D_CODE = BIT(2), /**< 2D machine-readable code */ + BT_MESH_PROV_OOB_BAR_CODE = BIT(3), /**< Bar Code */ + BT_MESH_PROV_OOB_NFC = BIT(4), /**< Near Field Communication (NFC) */ + BT_MESH_PROV_OOB_NUMBER = BIT(5), /**< Number */ + BT_MESH_PROV_OOB_STRING = BIT(6), /**< String */ + BT_MESH_PROV_OOB_CERTIFICATE = BIT(7), /**< Support for certificate-based provisioning */ + BT_MESH_PROV_OOB_RECORDS = BIT(8), /**< Support for provisioning records */ /* 9 - 10 are reserved */ - BT_MESH_PROV_OOB_ON_BOX = BIT(11), - BT_MESH_PROV_OOB_IN_BOX = BIT(12), - BT_MESH_PROV_OOB_ON_PAPER = BIT(13), - BT_MESH_PROV_OOB_IN_MANUAL = BIT(14), - BT_MESH_PROV_OOB_ON_DEV = BIT(15), + BT_MESH_PROV_OOB_ON_BOX = BIT(11), /**< On box */ + BT_MESH_PROV_OOB_IN_BOX = BIT(12), /**< Inside box */ + BT_MESH_PROV_OOB_ON_PAPER = BIT(13), /**< On piece of paper */ + BT_MESH_PROV_OOB_IN_MANUAL = BIT(14), /**< Inside manual */ + BT_MESH_PROV_OOB_ON_DEV = BIT(15), /**< On device */ } bt_mesh_prov_oob_info_t; /** Device Capabilities. */ @@ -556,7 +556,7 @@ bool bt_mesh_is_provisioned(void); * @{ */ -/* Primary Network Key index */ +/** Primary Network Key index */ #define BT_MESH_NET_PRIMARY 0x000 /** Relay feature */ @@ -567,6 +567,7 @@ bool bt_mesh_is_provisioned(void); #define BT_MESH_FEAT_FRIEND BIT(2) /** Low Power Node feature */ #define BT_MESH_FEAT_LOW_POWER BIT(3) +/** Supported heartbeat publication features */ #define BT_MESH_FEAT_SUPPORTED (BT_MESH_FEAT_RELAY | \ BT_MESH_FEAT_PROXY | \ BT_MESH_FEAT_FRIEND | \ From 95bedcd20f7553afbd5c2b920aae9da60d19bef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 17:31:16 +0200 Subject: [PATCH 1406/2042] doc: lora: Cleanup doxygen documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed missing Javadoc style comments and briefs for some enums. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/lora.h | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/include/zephyr/drivers/lora.h b/include/zephyr/drivers/lora.h index b42143814c68..47ad4dbb4835 100644 --- a/include/zephyr/drivers/lora.h +++ b/include/zephyr/drivers/lora.h @@ -4,6 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Public LoRa driver APIs + */ #ifndef ZEPHYR_INCLUDE_DRIVERS_LORA_H_ #define ZEPHYR_INCLUDE_DRIVERS_LORA_H_ @@ -23,12 +27,18 @@ extern "C" { #endif +/** + * @brief LoRa signal bandwidth + */ enum lora_signal_bandwidth { BW_125_KHZ = 0, BW_250_KHZ, BW_500_KHZ, }; +/** + * @brief LoRa data-rate + */ enum lora_datarate { SF_6 = 6, SF_7, @@ -39,6 +49,9 @@ enum lora_datarate { SF_12, }; +/** + * @brief LoRa coding rate + */ enum lora_coding_rate { CR_4_5 = 1, CR_4_6 = 2, @@ -46,26 +59,30 @@ enum lora_coding_rate { CR_4_8 = 4, }; +/** + * @struct lora_modem_config + * Structure containing the configuration of a LoRa modem + */ struct lora_modem_config { - /* Frequency in Hz to use for transceiving */ + /** Frequency in Hz to use for transceiving */ uint32_t frequency; - /* The bandwidth to use for transceiving */ + /** The bandwidth to use for transceiving */ enum lora_signal_bandwidth bandwidth; - /* The data-rate to use for transceiving */ + /** The data-rate to use for transceiving */ enum lora_datarate datarate; - /* The coding rate to use for transceiving */ + /** The coding rate to use for transceiving */ enum lora_coding_rate coding_rate; - /* Length of the preamble */ + /** Length of the preamble */ uint16_t preamble_len; - /* TX-power in dBm to use for transmission */ + /** TX-power in dBm to use for transmission */ int8_t tx_power; - /* Set to true for transmission, false for receiving */ + /** Set to true for transmission, false for receiving */ bool tx; /** From e1f7f944804c6ca20a42f9be63cbb1f6117e87e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 17:34:05 +0200 Subject: [PATCH 1407/2042] doc: lorawan: Cleanup doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some missing Doxygen comments / fixed existing ones. Signed-off-by: Benjamin Cabé --- include/zephyr/lorawan/lorawan.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 6e8b4b055c3b..924ed6ec2768 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -110,6 +110,9 @@ struct lorawan_join_otaa { uint32_t dev_nonce; }; +/** + * @brief LoRaWAN join parameters for activation by personalization (ABP) + */ struct lorawan_join_abp { /** Device address on the network */ uint32_t dev_addr; @@ -121,6 +124,9 @@ struct lorawan_join_abp { uint8_t *app_eui; }; +/** + * @brief LoRaWAN join parameters + */ struct lorawan_join_config { union { struct lorawan_join_otaa otaa; @@ -130,16 +136,22 @@ struct lorawan_join_config { /** Device EUI. Optional if a secure element is present. */ uint8_t *dev_eui; + /** Activation mode */ enum lorawan_act_type mode; }; #define LW_RECV_PORT_ANY UINT16_MAX +/** + * @brief LoRaWAN downlink callback parameters + */ struct lorawan_downlink_cb { - /* Port to handle messages for: - * Port 0: TX packet acknowledgements - * Ports 1-255: Standard downlink port - * LW_RECV_PORT_ANY: All downlinks + /** + * @brief Port to handle messages for. + * + * - Port 0: TX packet acknowledgements + * - Ports 1-255: Standard downlink port + * - LW_RECV_PORT_ANY: All downlinks */ uint16_t port; /** From b8f7c81dd3930ae1dde60dcf1daba32d03176816 Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Tue, 18 Jul 2023 10:34:13 +0200 Subject: [PATCH 1408/2042] tests: Bluetooth: Mesh: fix omitted names PR fixes using of the parameter with omitted names. Signed-off-by: Aleksandr Khromykh --- tests/bsim/bluetooth/mesh/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bsim/bluetooth/mesh/src/main.c b/tests/bsim/bluetooth/mesh/src/main.c index d83ca64eeb79..3c314e24a586 100644 --- a/tests/bsim/bluetooth/mesh/src/main.c +++ b/tests/bsim/bluetooth/mesh/src/main.c @@ -77,7 +77,7 @@ bst_test_install_t test_installers[] = { static struct k_thread bsim_mesh_thread; static K_KERNEL_STACK_DEFINE(bsim_mesh_thread_stack, 4096); -static void bsim_mesh_entry_point(void *, void *, void *) +static void bsim_mesh_entry_point(void *unused1, void *unused2, void *unused3) { bst_main(); } From db00177e2e7778bd4a93e16cddf5219361302fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nerijus=20Bend=C5=BEi=C5=ABnas?= Date: Sun, 16 Jul 2023 10:35:52 +0300 Subject: [PATCH 1409/2042] boards: arm: move nucleo_g474re storage_partition to end of flash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Board/MCU has 512 KiB of flash (see stm32g474Xe.dtsi). Signed-off-by: Nerijus Bendžiūnas --- boards/arm/nucleo_g474re/nucleo_g474re.dts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/arm/nucleo_g474re/nucleo_g474re.dts b/boards/arm/nucleo_g474re/nucleo_g474re.dts index 9ec245219304..36761654136c 100644 --- a/boards/arm/nucleo_g474re/nucleo_g474re.dts +++ b/boards/arm/nucleo_g474re/nucleo_g474re.dts @@ -174,10 +174,10 @@ #address-cells = <1>; #size-cells = <1>; - /* Set 4Kb of storage at the end of the 128Kb of flash */ - storage_partition: partition@1f000 { + /* Set 4Kb of storage at the end of the 512Kb of flash */ + storage_partition: partition@7f000 { label = "storage"; - reg = <0x0001f000 DT_SIZE_K(4)>; + reg = <0x0007f000 DT_SIZE_K(4)>; }; }; }; From 723421b23104d42a787438bfb6c1eb8553360298 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Tue, 18 Jul 2023 08:39:10 +0200 Subject: [PATCH 1410/2042] input: convert cst816s from kscan Convert the cst816s capacitive touch screen driver to the input subsystem. Signed-off-by: Fabian Blatz --- boards/arm/pinetime_devkit0/Kconfig.defconfig | 3 + .../arm/pinetime_devkit0/pinetime_devkit0.dts | 8 +- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/{kscan => input}/Kconfig.cst816s | 12 +- .../kscan_cst816s.c => input/input_cst816s.c} | 166 ++++++------------ drivers/kscan/CMakeLists.txt | 1 - drivers/kscan/Kconfig | 1 - tests/drivers/build_all/input/app.overlay | 7 + 9 files changed, 82 insertions(+), 118 deletions(-) rename drivers/{kscan => input}/Kconfig.cst816s (74%) rename drivers/{kscan/kscan_cst816s.c => input/input_cst816s.c} (62%) diff --git a/boards/arm/pinetime_devkit0/Kconfig.defconfig b/boards/arm/pinetime_devkit0/Kconfig.defconfig index 10855a789394..0edb704b90c4 100644 --- a/boards/arm/pinetime_devkit0/Kconfig.defconfig +++ b/boards/arm/pinetime_devkit0/Kconfig.defconfig @@ -11,6 +11,9 @@ config BOARD config BT_CTLR default BT +config INPUT + default y if KSCAN + if FLASH config SPI_NOR_FLASH_LAYOUT_PAGE_SIZE diff --git a/boards/arm/pinetime_devkit0/pinetime_devkit0.dts b/boards/arm/pinetime_devkit0/pinetime_devkit0.dts index 55b16ecc79ee..e2817fbf0c64 100644 --- a/boards/arm/pinetime_devkit0/pinetime_devkit0.dts +++ b/boards/arm/pinetime_devkit0/pinetime_devkit0.dts @@ -25,7 +25,7 @@ zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; zephyr,display = &st7789v; - zephyr,keyboard-scan = &cst816s; + zephyr,keyboard-scan = &kscan_input; }; aliases { @@ -34,7 +34,7 @@ led2 = &blled2; /* backlight high */ led3 = &statusled; /* status led, may be not populated */ sw0 = &key_in; /* key in */ - kscan0 = &cst816s; + kscan0 = &kscan_input; watchdog0 = &wdt0; }; @@ -128,6 +128,10 @@ reg = <0x15>; irq-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; rst-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + + kscan_input: kscan-input { + compatible = "zephyr,kscan-input"; + }; }; }; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 3872f182b3cd..0f47dd493391 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) +zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 226c9c9d6c5a..2be3cfcf6390 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -5,6 +5,7 @@ if INPUT menu "Input drivers" +source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_keys" source "drivers/input/Kconfig.gpio_qdec" diff --git a/drivers/kscan/Kconfig.cst816s b/drivers/input/Kconfig.cst816s similarity index 74% rename from drivers/kscan/Kconfig.cst816s rename to drivers/input/Kconfig.cst816s index 2524a0841c99..c7cbc59e2450 100644 --- a/drivers/kscan/Kconfig.cst816s +++ b/drivers/input/Kconfig.cst816s @@ -1,7 +1,7 @@ # Copyright (c) 2020 Qingsong Gou # SPDX-License-Identifier: Apache-2.0 -menuconfig KSCAN_CST816S +menuconfig INPUT_CST816S bool "CST816S capacitive touch panel driver" default y depends on DT_HAS_HYNITRON_CST816S_ENABLED @@ -9,20 +9,20 @@ menuconfig KSCAN_CST816S help Enable driver for hynitron cst816s touch panel. -if KSCAN_CST816S +if INPUT_CST816S -config KSCAN_CST816S_PERIOD +config INPUT_CST816S_PERIOD int "Sample period" - depends on !KSCAN_CST816S_INTERRUPT + depends on !INPUT_CST816S_INTERRUPT default 20 help Sample period in milliseconds when in polling mode. -config KSCAN_CST816S_INTERRUPT +config INPUT_CST816S_INTERRUPT bool "Interrupt support" default y depends on GPIO help Enable interrupt support (requires GPIO). -endif # KSCAN_CST816S +endif # INPUT_CST816S diff --git a/drivers/kscan/kscan_cst816s.c b/drivers/input/input_cst816s.c similarity index 62% rename from drivers/kscan/kscan_cst816s.c rename to drivers/input/input_cst816s.c index ee370f881d95..5d22af3c51da 100644 --- a/drivers/kscan/kscan_cst816s.c +++ b/drivers/input/input_cst816s.c @@ -7,14 +7,14 @@ #define DT_DRV_COMPAT hynitron_cst816s #include -#include +#include #include #include #include -LOG_MODULE_REGISTER(cst816s, CONFIG_KSCAN_LOG_LEVEL); +LOG_MODULE_REGISTER(cst816s, CONFIG_INPUT_LOG_LEVEL); -#define CST816S_CHIP_ID 0xB4 +#define CST816S_CHIP_ID 0xB4 #define CST816S_REG_DATA 0x00 #define CST816S_REG_GESTURE_ID 0x01 @@ -51,39 +51,38 @@ LOG_MODULE_REGISTER(cst816s, CONFIG_KSCAN_LOG_LEVEL); #define CST816S_REG_IOCTL 0xFD #define CST816S_REG_DIS_AUTO_SLEEP 0xFE -#define CST816S_MOTION_EN_CON_LR BIT(2) -#define CST816S_MOTION_EN_CON_UR BIT(1) -#define CST816S_MOTION_EN_DCLICK BIT(0) +#define CST816S_MOTION_EN_CON_LR BIT(2) +#define CST816S_MOTION_EN_CON_UR BIT(1) +#define CST816S_MOTION_EN_DCLICK BIT(0) -#define CST816S_IRQ_EN_TEST BIT(7) -#define CST816S_IRQ_EN_TOUCH BIT(6) -#define CST816S_IRQ_EN_CHANGE BIT(5) -#define CST816S_IRQ_EN_MOTION BIT(4) -#define CST816S_IRQ_ONCE_WLP BIT(0) +#define CST816S_IRQ_EN_TEST BIT(7) +#define CST816S_IRQ_EN_TOUCH BIT(6) +#define CST816S_IRQ_EN_CHANGE BIT(5) +#define CST816S_IRQ_EN_MOTION BIT(4) +#define CST816S_IRQ_ONCE_WLP BIT(0) -#define CST816S_IOCTL_SOFT_RTS BIT(2) -#define CST816S_IOCTL_IIC_OD BIT(1) -#define CST816S_IOCTL_EN_1V8 BIT(0) +#define CST816S_IOCTL_SOFT_RTS BIT(2) +#define CST816S_IOCTL_IIC_OD BIT(1) +#define CST816S_IOCTL_EN_1V8 BIT(0) -#define CST816S_POWER_MODE_SLEEP (0x03) -#define CST816S_POWER_MODE_EXPERIMENTAL (0x05) +#define CST816S_POWER_MODE_SLEEP (0x03) +#define CST816S_POWER_MODE_EXPERIMENTAL (0x05) -#define CST816S_EVENT_BITS_POS (0x06) +#define CST816S_EVENT_BITS_POS (0x06) -#define CST816S_RESET_DELAY (5) /* in ms */ -#define CST816S_WAIT_DELAY (50) /* in ms */ - -#define EVENT_PRESS_DOWN 0x00U -#define EVENT_LIFT_UP 0x01U -#define EVENT_CONTACT 0x02U -#define EVENT_NONE 0x03U +#define CST816S_RESET_DELAY (5) /* in ms */ +#define CST816S_WAIT_DELAY (50) /* in ms */ +#define EVENT_PRESS_DOWN 0x00U +#define EVENT_LIFT_UP 0x01U +#define EVENT_CONTACT 0x02U +#define EVENT_NONE 0x03U /** cst816s configuration (DT). */ struct cst816s_config { struct i2c_dt_spec i2c; const struct gpio_dt_spec rst_gpio; -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT +#ifdef CONFIG_INPUT_CST816S_INTERRUPT const struct gpio_dt_spec int_gpio; #endif }; @@ -92,12 +91,10 @@ struct cst816s_config { struct cst816s_data { /** Device pointer. */ const struct device *dev; - /** KSCAN Callback. */ - kscan_callback_t callback; /** Work queue (for deferred read). */ struct k_work work; -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT +#ifdef CONFIG_INPUT_CST816S_INTERRUPT /** Interrupt GPIO callback. */ struct gpio_callback int_gpio_cb; #else @@ -109,7 +106,6 @@ struct cst816s_data { static int cst816s_process(const struct device *dev) { const struct cst816s_config *cfg = dev->config; - struct cst816s_data *data = dev->data; int r; uint8_t event; @@ -137,9 +133,14 @@ static int cst816s_process(const struct device *dev) LOG_DBG("event: %d, row: %d, col: %d", event, row, col); - if (data->callback) { - data->callback(dev, row, col, pressed); + if (pressed) { + 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, 1, true, K_FOREVER); + } else { + input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); } + return r; } @@ -150,9 +151,8 @@ static void cst816s_work_handler(struct k_work *work) cst816s_process(data->dev); } -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT -static void cst816s_isr_handler(const struct device *dev, - struct gpio_callback *cb, uint32_t pins) +#ifdef CONFIG_INPUT_CST816S_INTERRUPT +static void cst816s_isr_handler(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { struct cst816s_data *data = CONTAINER_OF(cb, struct cst816s_data, int_gpio_cb); @@ -167,60 +167,13 @@ static void cst816s_timer_handler(struct k_timer *timer) } #endif -static int cst816s_configure(const struct device *dev, - kscan_callback_t callback) -{ - struct cst816s_data *data = dev->data; - - if (!callback) { - LOG_ERR("Invalid callback (NULL)"); - return -EINVAL; - } - - data->callback = callback; - - return 0; -} - -static int cst816s_enable_callback(const struct device *dev) -{ - struct cst816s_data *data = dev->data; - -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT - const struct cst816s_config *config = dev->config; - - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); -#else - k_timer_start(&data->timer, K_MSEC(CONFIG_KSCAN_CST816S_PERIOD), - K_MSEC(CONFIG_KSCAN_CST816S_PERIOD)); -#endif - - return 0; -} - -static int cst816s_disable_callback(const struct device *dev) -{ - struct cst816s_data *data = dev->data; - -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT - const struct cst816s_config *config = dev->config; - - gpio_remove_callback(config->int_gpio.port, &data->int_gpio_cb); -#else - k_timer_stop(&data->timer); -#endif - - return 0; -} - static void cst816s_chip_reset(const struct device *dev) { const struct cst816s_config *config = dev->config; int ret; if (device_is_ready(config->rst_gpio.port)) { - ret = gpio_pin_configure_dt(&config->rst_gpio, - GPIO_OUTPUT_INACTIVE); + ret = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_INACTIVE); if (ret < 0) { LOG_ERR("Could not configure reset GPIO pin"); return; @@ -255,8 +208,7 @@ static int cst816s_chip_init(const struct device *dev) return -ENODEV; } - ret = i2c_reg_update_byte_dt(&cfg->i2c, - CST816S_REG_IRQ_CTL, + ret = i2c_reg_update_byte_dt(&cfg->i2c, CST816S_REG_IRQ_CTL, CST816S_IRQ_EN_TOUCH | CST816S_IRQ_EN_CHANGE, CST816S_IRQ_EN_TOUCH | CST816S_IRQ_EN_CHANGE); if (ret < 0) { @@ -273,7 +225,7 @@ static int cst816s_init(const struct device *dev) data->dev = dev; k_work_init(&data->work, cst816s_work_handler); -#ifdef CONFIG_KSCAN_CST816S_INTERRUPT +#ifdef CONFIG_INPUT_CST816S_INTERRUPT const struct cst816s_config *config = dev->config; int ret; @@ -288,40 +240,38 @@ static int cst816s_init(const struct device *dev) return ret; } - ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, - GPIO_INT_EDGE_TO_ACTIVE); + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); if (ret < 0) { LOG_ERR("Could not configure interrupt GPIO interrupt."); return ret; } - gpio_init_callback(&data->int_gpio_cb, cst816s_isr_handler, - BIT(config->int_gpio.pin)); + gpio_init_callback(&data->int_gpio_cb, cst816s_isr_handler, BIT(config->int_gpio.pin)); + + ret = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } #else k_timer_init(&data->timer, cst816s_timer_handler, NULL); + k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_CST816S_PERIOD), + K_MSEC(CONFIG_INPUT_CST816S_PERIOD)); #endif return cst816s_chip_init(dev); } -static const struct kscan_driver_api cst816s_driver_api = { - .config = cst816s_configure, - .enable_callback = cst816s_enable_callback, - .disable_callback = cst816s_disable_callback, -}; - -#define CST816S_DEFINE(index) \ - static const struct cst816s_config cst816s_config_##index = { \ - .i2c = I2C_DT_SPEC_INST_GET(index), \ - COND_CODE_1(CONFIG_KSCAN_CST816S_INTERRUPT, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET(index, irq_gpios),),\ - ()) \ - .rst_gpio = GPIO_DT_SPEC_INST_GET_OR(index, rst_gpios, {}), \ - }; \ - static struct cst816s_data cst816s_data_##index; \ - DEVICE_DT_INST_DEFINE(index, cst816s_init, NULL, \ - &cst816s_data_##index, &cst816s_config_##index, \ - POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ - &cst816s_driver_api); +#define CST816S_DEFINE(index) \ + static const struct cst816s_config cst816s_config_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + COND_CODE_1(CONFIG_INPUT_CST816S_INTERRUPT, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(index, irq_gpios),), ()) \ + .rst_gpio = GPIO_DT_SPEC_INST_GET_OR(index, rst_gpios, {}), \ + }; \ + static struct cst816s_data cst816s_data_##index; \ + DEVICE_DT_INST_DEFINE(index, cst816s_init, NULL, &cst816s_data_##index, \ + &cst816s_config_##index, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); DT_INST_FOREACH_STATUS_OKAY(CST816S_DEFINE) diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index 2f27d65ff232..abec7d712ca6 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -7,7 +7,6 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) -zephyr_library_sources_ifdef(CONFIG_KSCAN_CST816S kscan_cst816s.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_CAP1203 kscan_cap1203.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index 4c08a2d88878..d82067901c42 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -13,7 +13,6 @@ if KSCAN source "drivers/kscan/Kconfig.it8xxx2" source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" -source "drivers/kscan/Kconfig.cst816s" source "drivers/kscan/Kconfig.cap1203" source "drivers/kscan/Kconfig.input" diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index 686da3a4180e..b5be8830bde5 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -64,6 +64,13 @@ irq-gpios = <&gpio0 0 0>; reset-gpios = <&gpio0 0 0>; }; + + cst816s: cst816s@2 { + compatible = "hynitron,cst816s"; + reg = <0x2>; + irq-gpios = <&gpio0 0 0>; + rst-gpios = <&gpio0 0 0>; + }; }; spi@2 { From d72ad22c499f89d4dd8e6425c6c44618b18faf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 11:26:21 +0200 Subject: [PATCH 1411/2042] smbus: doc: Fix smbus_dt_spec documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Doxygen doc for smbus_dt_spec. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/smbus.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index f7111a6cb5e9..b624462f4259 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -288,12 +288,11 @@ struct smbus_callback { /** * @brief Complete SMBus DT information - * - * @param bus SMBus bus - * @param addr Address of the SMBus peripheral device. */ struct smbus_dt_spec { + /** SMBus bus */ const struct device *bus; + /** Address of the SMBus peripheral device */ uint16_t addr; }; From bbe6bb231af4f082080101a07ebd6799aee40b7b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 14 Apr 2023 16:49:47 +0200 Subject: [PATCH 1412/2042] tests: Bluetooth: Add testing of invalid input for BAP broadcast source Add tests to verify that the stack does not allow any invalid data. Signed-off-by: Emil Gydesen --- .../audio/src/bap_broadcast_source_test.c | 932 +++++++++++++++++- 1 file changed, 879 insertions(+), 53 deletions(-) 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 4d5edf1a05b7..9143b4742693 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_source_test.c @@ -97,6 +97,449 @@ static struct bt_bap_stream_ops stream_ops = { .sent = sent_cb }; +static struct bt_audio_codec_data valid_bis_codec_data = + BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ); + +static void broadcast_source_create_inval_reset_param( + struct bt_bap_broadcast_source_create_param *param, + struct bt_bap_broadcast_source_subgroup_param *subgroup_param, + struct bt_bap_broadcast_source_stream_param *stream_param) +{ + struct bt_bap_broadcast_source_stream_param valid_stream_param; + struct bt_bap_broadcast_source_subgroup_param valid_subgroup_param; + struct bt_bap_broadcast_source_create_param create_param; + + valid_stream_param.stream = &broadcast_source_streams[0]; + valid_stream_param.data_count = 1U; + valid_stream_param.data = &valid_bis_codec_data; + + valid_subgroup_param.params_count = 1U; + valid_subgroup_param.params = &valid_stream_param; + valid_subgroup_param.codec_cfg = &preset_16_2_1.codec_cfg; + + create_param.params_count = 1U; + create_param.params = &valid_subgroup_param; + create_param.qos = &preset_16_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + memcpy(param, &create_param, sizeof(create_param)); + memcpy(subgroup_param, &valid_subgroup_param, sizeof(valid_subgroup_param)); + memcpy(stream_param, &valid_stream_param, sizeof(valid_stream_param)); + param->params = subgroup_param; + subgroup_param->params = stream_param; +} + +static void broadcast_source_create_inval_stream_param(void) +{ + struct bt_bap_broadcast_source_subgroup_param subgroup_param; + struct bt_bap_broadcast_source_create_param create_param; + struct bt_bap_broadcast_source_stream_param stream_param; + struct bt_bap_broadcast_source *broadcast_source; + int err; + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Set data NULL while count is 1 */ + stream_param.data = NULL; + + printk("Test bt_bap_broadcast_source_create with NULL stream_param\n"); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL stream_param data did not " + "fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Initialize codec configuration data that is too large */ + stream_param.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1; + + printk("Test bt_bap_broadcast_source_create with stream_param.data_count %zu\n", + stream_param.data_count); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with stream_param data count %u " + "did not fail\n", + stream_param.data_count); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Set stream to NULL */ + stream_param.stream = NULL; + + printk("Test bt_bap_broadcast_source_create with NULL stream_param.stream\n"); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL stream_param stream " + "did not fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) { + struct bt_audio_codec_data bis_codec_data; + + memcpy(&bis_codec_data, &valid_bis_codec_data, sizeof(valid_bis_codec_data)); + + /* Set LTV data to invalid size */ + bis_codec_data.data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1; + stream_param.data = &bis_codec_data; + + printk("Test bt_bap_broadcast_source_create with CC LTV size %u\n", + bis_codec_data.data.data_len); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with CC LTV size %u in stream_param " + "did not fail\n", + bis_codec_data.data.data_len); + return; + } + } +} + +static void broadcast_source_create_inval_subgroup_codec_param(void) +{ + struct bt_bap_broadcast_source_subgroup_param subgroup_param; + struct bt_bap_broadcast_source_create_param create_param; + struct bt_bap_broadcast_source_stream_param stream_param; + struct bt_bap_broadcast_source *broadcast_source; + struct bt_audio_codec_cfg codec_cfg; + int err; + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + subgroup_param.codec_cfg = + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + + codec_cfg.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1; + + printk("Test bt_bap_broadcast_source_create with codec.data_count %u\n", + codec_cfg.data_count); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with codec data count %zu did not fail\n", + codec_cfg.data_count); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + subgroup_param.codec_cfg = + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + + codec_cfg.meta_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT + 1; + + printk("Test bt_bap_broadcast_source_create with codec.meta_count %u\n", + codec_cfg.meta_count); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with codec meta count %zu did not fail\n", + codec_cfg.meta_count); + return; + } + + if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) { + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, + &stream_param); + subgroup_param.codec_cfg = memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, + sizeof(preset_16_2_1.codec_cfg)); + + /* Set LTV data to invalid size */ + codec_cfg.data[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1; + + printk("Test bt_bap_broadcast_source_create with CC LTV size %u\n", + codec_cfg.data[0].data.data_len); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with CC LTV size %zu in " + "subgroup_param did not fail\n", + codec_cfg.data[0].data.data_len); + return; + } + } + + if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) { + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, + &stream_param); + subgroup_param.codec_cfg = memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, + sizeof(preset_16_2_1.codec_cfg)); + + /* Set LTV data to invalid size */ + codec_cfg.meta[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1; + + printk("Test bt_bap_broadcast_source_create with Meta LTV size %u\n", + codec_cfg.meta[0].data.data_len); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with meta LTV size %zu in " + "subgroup_param did not fail\n", + codec_cfg.meta[0].data.data_len); + return; + } + } +} + +static void broadcast_source_create_inval_subgroup_param(void) +{ + struct bt_bap_broadcast_source_subgroup_param subgroup_param; + struct bt_bap_broadcast_source_create_param create_param; + struct bt_bap_broadcast_source_stream_param stream_param; + struct bt_bap_broadcast_source *broadcast_source; + int err; + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Set count to 0 */ + subgroup_param.params_count = 0; + + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with 0 stream_param count did not fail\n"); + return; + } + + /* Set count higher than max */ + subgroup_param.params_count = CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT + 1; + + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with too high stream_param count did not " + "fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Set params to NULL */ + subgroup_param.params = NULL; + + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL stream_param did not fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + /* Set codec to NULL */ + subgroup_param.codec_cfg = NULL; + + err = bt_bap_broadcast_source_create(&create_param, &broadcast_source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL codec did not fail\n"); + return; + } + + /* Invalid codec values */ + broadcast_source_create_inval_subgroup_codec_param(); +} + +static void broadcast_source_create_inval(void) +{ + struct bt_bap_broadcast_source_stream_param stream_param; + struct bt_bap_broadcast_source_subgroup_param subgroup_param; + struct bt_bap_broadcast_source_create_param create_param; + struct bt_bap_broadcast_source *broadcast_sources[CONFIG_BT_BAP_BROADCAST_SRC_COUNT + 1U]; + struct bt_audio_codec_qos qos; + int err; + + /* Test NULL parameters */ + printk("Test bt_bap_broadcast_source_create with NULL param\n"); + err = bt_bap_broadcast_source_create(NULL, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL param did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_create with NULL broadcast source\n"); + err = bt_bap_broadcast_source_create(&create_param, NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL broadcast source did not " + "fail\n"); + return; + } + + /* Test stream_param values */ + broadcast_source_create_inval_stream_param(); + + /* Test invalid subgroup_param values*/ + broadcast_source_create_inval_subgroup_param(); + + /* Invalid create_param values */ + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + create_param.params_count = 0; + + printk("Test bt_bap_broadcast_source_create with 0 params_count\n"); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with 0 params_count did not fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + create_param.params = NULL; + + printk("Test bt_bap_broadcast_source_create with NULL params\n"); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL params did not fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + create_param.packing = 0x35; + + printk("Test bt_bap_broadcast_source_create with packing 0x%02X\n", create_param.packing); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with invalid packing did not fail\n"); + return; + } + + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + create_param.qos = NULL; + + printk("Test bt_bap_broadcast_source_create with NULL qos\n"); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with NULL qos did not fail\n"); + return; + } + + /* Invalid QoS values */ + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + create_param.qos = memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + qos.phy = BT_AUDIO_CODEC_QOS_CODED + 1; + + printk("Test bt_bap_broadcast_source_create with qos.phy 0x%02X\n", qos.phy); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with invalid PHY did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.framing = BT_AUDIO_CODEC_QOS_FRAMED + 1; + + printk("Test bt_bap_broadcast_source_create with qos.framing 0x%02X\n", qos.framing); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with invalid framing did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.rtn = BT_ISO_BROADCAST_RTN_MAX + 1; + + printk("Test bt_bap_broadcast_source_create with qos.rtn 0x%02X\n", qos.rtn); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with invalid RTN did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.sdu = BT_ISO_MAX_SDU + 1; + + printk("Test bt_bap_broadcast_source_create with qos.sdu 0x%02X\n", qos.sdu); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with invalid SDU size did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.latency = BT_ISO_LATENCY_MIN - 1; + + printk("Test bt_bap_broadcast_source_create with qos.latency 0x%02X\n", qos.latency); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with too low latency did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.latency = BT_ISO_LATENCY_MAX + 1; + + printk("Test bt_bap_broadcast_source_create with qos.latency 0x%02X\n", qos.latency); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with too high latency did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.interval = BT_ISO_SDU_INTERVAL_MIN - 1; + + printk("Test bt_bap_broadcast_source_create with qos.interval 0x%02X\n", qos.interval); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with too low interval did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.interval = BT_ISO_SDU_INTERVAL_MAX + 1; + + printk("Test bt_bap_broadcast_source_create with qos.interval 0x%02X\n", qos.interval); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with too high interval did not fail\n"); + return; + } + + /* Exceeding memory limits */ + broadcast_source_create_inval_reset_param(&create_param, &subgroup_param, &stream_param); + + printk("Test bt_bap_broadcast_source_create with %zu broadcast sources\n", + ARRAY_SIZE(broadcast_sources)); + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources); i++) { + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[i]); + + if (i < CONFIG_BT_BAP_BROADCAST_SRC_COUNT) { + if (err != 0) { + FAIL("bt_bap_broadcast_source_create[%zu] failed: %d\n", i, err); + return; + } + } else { + if (err == 0) { + FAIL("bt_bap_broadcast_source_create[%zu] did not fail\n", i); + return; + } + } + } + + for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sources) - 1; i++) { + err = bt_bap_broadcast_source_delete(broadcast_sources[i]); + if (err != 0) { + FAIL("bt_bap_broadcast_source_delete[%zu] failed: %d\n", i, err); + return; + } + broadcast_sources[i] = NULL; + } + + create_param.params_count = CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT + 1; + + printk("Test bt_bap_broadcast_source_create with %zu subgroups\n", + create_param.params_count); + err = bt_bap_broadcast_source_create(&create_param, &broadcast_sources[0]); + if (err == 0) { + FAIL("bt_bap_broadcast_source_create with %zu subgroups did not fail\n", + create_param.params_count); + return; + } +} + static int setup_broadcast_source(struct bt_bap_broadcast_source **source) { struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA( @@ -142,6 +585,87 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source) return 0; } +static void test_broadcast_source_get_id_inval(struct bt_bap_broadcast_source *source, + uint32_t *broadcast_id_out) +{ + int err; + + printk("Test bt_bap_broadcast_source_get_id with NULL source\n"); + err = bt_bap_broadcast_source_get_id(NULL, broadcast_id_out); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_id with NULL source did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_get_id with NULL broadcast_id\n"); + err = bt_bap_broadcast_source_get_id(source, NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_id with NULL ID did not fail\n"); + return; + } +} + +static void test_broadcast_source_get_id(struct bt_bap_broadcast_source *source, + uint32_t *broadcast_id_out) +{ + int err; + + err = bt_bap_broadcast_source_get_id(source, broadcast_id_out); + if (err != 0) { + FAIL("Unable to get broadcast ID: %d\n", err); + return; + } +} + +static void test_broadcast_source_get_base_inval(struct bt_bap_broadcast_source *source, + struct net_buf_simple *base_buf) +{ + /* Large enough for minimum, but not large enough for any CC or Meta data */ + NET_BUF_SIMPLE_DEFINE(small_base_buf, BT_BAP_BASE_MIN_SIZE + 2); + NET_BUF_SIMPLE_DEFINE(very_small_base_buf, 4); + int err; + + printk("Test bt_bap_broadcast_source_get_base with NULL source\n"); + err = bt_bap_broadcast_source_get_base(NULL, base_buf); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_base with NULL source did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_get_base with NULL buf\n"); + err = bt_bap_broadcast_source_get_base(source, NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_base with NULL buf did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_get_base with very small buf\n"); + err = bt_bap_broadcast_source_get_base(source, &very_small_base_buf); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_base with very small buf did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_get_base with small buf\n"); + err = bt_bap_broadcast_source_get_base(source, &small_base_buf); + if (err == 0) { + FAIL("bt_bap_broadcast_source_get_base with small buf did not fail\n"); + return; + } +} + +static void test_broadcast_source_get_base(struct bt_bap_broadcast_source *source, + struct net_buf_simple *base_buf) +{ + int err; + + err = bt_bap_broadcast_source_get_base(source, base_buf); + if (err != 0) { + FAIL("Failed to get encoded BASE: %d\n", err); + return; + } +} + static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_le_ext_adv **adv) { /* Broadcast Audio Streaming Endpoint advertising data */ @@ -168,11 +692,8 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ return err; } - err = bt_bap_broadcast_source_get_id(source, &broadcast_id); - if (err != 0) { - printk("Unable to get broadcast ID: %d\n", err); - return err; - } + test_broadcast_source_get_id_inval(source, &broadcast_id); + test_broadcast_source_get_id(source, &broadcast_id); /* Setup extended advertising data */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); @@ -187,11 +708,8 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ } /* Setup periodic advertising data */ - err = bt_bap_broadcast_source_get_base(source, &base_buf); - if (err != 0) { - printk("Failed to get encoded BASE: %d\n", err); - return err; - } + test_broadcast_source_get_base_inval(source, &base_buf); + test_broadcast_source_get_base(source, &base_buf); per_ad.type = BT_DATA_SVC_DATA16; per_ad.data_len = base_buf.len; @@ -219,6 +737,343 @@ static int setup_extended_adv(struct bt_bap_broadcast_source *source, struct bt_ return 0; } +static void test_broadcast_source_reconfig_inval_state(struct bt_bap_broadcast_source *source) +{ + int err; + + printk("Test bt_bap_broadcast_source_reconfig in stopped state\n"); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, + &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig in stopped state did not fail\n"); + return; + } +} + +static void test_broadcast_source_reconfig_inval(struct bt_bap_broadcast_source *source) +{ + struct bt_audio_codec_qos qos; + struct bt_audio_codec_cfg codec_cfg; + int err; + + /* Test NULL values */ + printk("Test bt_bap_broadcast_source_reconfig with NULL source\n"); + err = bt_bap_broadcast_source_reconfig(NULL, &preset_16_2_1.codec_cfg, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with NULL broadcast source did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_reconfig with NULL codec\n"); + err = bt_bap_broadcast_source_reconfig(source, NULL, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with NULL codec did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_reconfig with NULL QoS\n"); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with NULL QoS did not fail\n"); + return; + } + + /* Test invalid codec values */ + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + + codec_cfg.data_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT + 1; + + printk("Test bt_bap_broadcast_source_reconfig with codec.data_count %u\n", + codec_cfg.data_count); + err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too high codec data count did not " + "fail\n"); + return; + } + + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + + codec_cfg.meta_count = CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT + 1; + + printk("Test bt_bap_broadcast_source_reconfig with codec.meta_count %u\n", + codec_cfg.meta_count); + err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too high codec meta count did not " + "fail\n"); + return; + } + + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + + if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) { + /* Set LTV data to invalid size */ + codec_cfg.data[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1; + + printk("Test bt_bap_broadcast_source_reconfig with CC LTV size %u\n", + codec_cfg.data[0].data.data_len); + err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too large CC LTV did not " + "fail\n"); + return; + } + + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + } + + if (CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN < 255) { + /* Set LTV data to invalid size */ + codec_cfg.meta[0].data.data_len = CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN + 1; + + printk("Test bt_bap_broadcast_source_reconfig with meta LTV size %u\n", + codec_cfg.meta[0].data.data_len); + err = bt_bap_broadcast_source_reconfig(source, &codec_cfg, &preset_16_2_1.qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too large meta LTV did not " + "fail\n"); + return; + } + + memcpy(&codec_cfg, &preset_16_2_1.codec_cfg, sizeof(preset_16_2_1.codec_cfg)); + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + qos.phy = BT_AUDIO_CODEC_QOS_CODED + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.phy %u\n", qos.phy); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with invalid PHY did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.framing = BT_AUDIO_CODEC_QOS_FRAMED + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.framing %u\n", qos.framing); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with invalid framing did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.rtn = BT_ISO_BROADCAST_RTN_MAX + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.rtn %u\n", qos.rtn); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with invalid RTN did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.sdu = BT_ISO_MAX_SDU + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.sdu %u\n", qos.sdu); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with invalid SDU size did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.latency = BT_ISO_LATENCY_MIN - 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.latency %u\n", qos.latency); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too low latency did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.latency = BT_ISO_LATENCY_MAX + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.latency %u\n", qos.latency); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too high latency did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.interval = BT_ISO_SDU_INTERVAL_MIN - 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.interval %u\n", qos.interval); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too low interval did not fail\n"); + return; + } + + memcpy(&qos, &preset_16_2_1.qos, sizeof(preset_16_2_1.qos)); + + qos.interval = BT_ISO_SDU_INTERVAL_MAX + 1; + + printk("Test bt_bap_broadcast_source_reconfig with qos.interval %u\n", qos.interval); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, &qos); + if (err == 0) { + FAIL("bt_bap_broadcast_source_reconfig with too high interval did not fail\n"); + return; + } +} + +static void test_broadcast_source_reconfig(struct bt_bap_broadcast_source *source) +{ + int err; + + printk("Reconfiguring broadcast source\n"); + err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, + &preset_16_2_1.qos); + if (err != 0) { + FAIL("Unable to reconfigure broadcast source: %d\n", err); + return; + } +} + +static void test_broadcast_source_start_inval_state(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + int err; + + printk("Test bt_bap_broadcast_source_start in streaming state\n"); + err = bt_bap_broadcast_source_start(source, adv); + if (err == 0) { + FAIL("bt_bap_broadcast_source_start in streaming state did not fail\n"); + return; + } +} + +static void test_broadcast_source_start_inval(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + int err; + + printk("Test bt_bap_broadcast_source_start with NULL source\n"); + err = bt_bap_broadcast_source_start(NULL, adv); + if (err == 0) { + FAIL("bt_bap_broadcast_source_start with NULL source did not fail\n"); + return; + } + + printk("Test bt_bap_broadcast_source_start with NULL adv\n"); + err = bt_bap_broadcast_source_start(source, NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_start with NULL adv did not fail\n"); + return; + } +} + +static void test_broadcast_source_start(struct bt_bap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + int err; + + printk("Starting broadcast source\n"); + err = bt_bap_broadcast_source_start(source, adv); + if (err != 0) { + FAIL("Unable to start broadcast source: %d\n", err); + return; + } + + /* Wait for all to be started */ + printk("Waiting for streams to be started\n"); + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + k_sem_take(&sem_started, K_FOREVER); + } +} + +static void test_broadcast_source_stop_inval_state(struct bt_bap_broadcast_source *source) +{ + int err; + + printk("Test bt_bap_broadcast_source_stop in stopped state\n"); + err = bt_bap_broadcast_source_stop(source); + if (err == 0) { + FAIL("bt_bap_broadcast_source_stop in stopped state did not fail\n"); + return; + } +} + +static void test_broadcast_source_stop_inval(void) +{ + int err; + + printk("Test bt_bap_broadcast_source_stop with NULL source\n"); + err = bt_bap_broadcast_source_stop(NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_stop with NULL source did not fail\n"); + return; + } +} + +static void test_broadcast_source_stop(struct bt_bap_broadcast_source *source) +{ + int err; + + SET_FLAG(flag_stopping); + printk("Stopping broadcast source\n"); + + err = bt_bap_broadcast_source_stop(source); + if (err != 0) { + FAIL("Unable to stop broadcast source: %d\n", err); + return; + } + + /* Wait for all to be stopped */ + printk("Waiting for streams to be stopped\n"); + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + k_sem_take(&sem_stopped, K_FOREVER); + } +} + +static void test_broadcast_source_delete_inval_state(struct bt_bap_broadcast_source *source) +{ + int err; + + printk("Test bt_bap_broadcast_source_delete in streaming state\n"); + err = bt_bap_broadcast_source_delete(NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_delete in streaming state not fail\n"); + return; + } +} + +static void test_broadcast_source_delete_inval(void) +{ + int err; + + printk("Test bt_bap_broadcast_source_delete with NULL source\n"); + err = bt_bap_broadcast_source_delete(NULL); + if (err == 0) { + FAIL("bt_bap_broadcast_source_delete with NULL source did not fail\n"); + return; + } +} + +static void test_broadcast_source_delete(struct bt_bap_broadcast_source *source) +{ + int err; + + SET_FLAG(flag_stopping); + printk("Deleting broadcast source\n"); + + err = bt_bap_broadcast_source_delete(source); + if (err != 0) { + FAIL("Unable to stop broadcast source: %d\n", err); + return; + } +} + static int stop_extended_adv(struct bt_le_ext_adv *adv) { int err; @@ -260,6 +1115,7 @@ static void test_main(void) printk("Bluetooth initialized\n"); + broadcast_source_create_inval(); err = setup_broadcast_source(&source); if (err != 0) { FAIL("Unable to setup broadcast source: %d\n", err); @@ -272,26 +1128,13 @@ static void test_main(void) return; } - printk("Reconfiguring broadcast source\n"); - err = bt_bap_broadcast_source_reconfig(source, &preset_16_2_1.codec_cfg, - &preset_16_2_1.qos); - if (err != 0) { - FAIL("Unable to reconfigure broadcast source: %d\n", err); - return; - } + test_broadcast_source_reconfig_inval(source); + test_broadcast_source_reconfig(source); - printk("Starting broadcast source\n"); - err = bt_bap_broadcast_source_start(source, adv); - if (err != 0) { - FAIL("Unable to start broadcast source: %d\n", err); - return; - } - - /* Wait for all to be started */ - printk("Waiting for streams to be started\n"); - for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - k_sem_take(&sem_started, K_FOREVER); - } + test_broadcast_source_start_inval(source, adv); + test_broadcast_source_start(source, adv); + test_broadcast_source_reconfig_inval_state(source); + test_broadcast_source_start_inval_state(source, adv); /* Initialize sending */ for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { @@ -315,29 +1158,16 @@ static void test_main(void) /* Keeping running for a little while */ k_sleep(K_SECONDS(5)); - printk("Stopping broadcast source\n"); - SET_FLAG(flag_stopping); - err = bt_bap_broadcast_source_stop(source); - if (err != 0) { - FAIL("Unable to stop broadcast source: %d\n", err); - return; - } + test_broadcast_source_delete_inval_state(source); - /* Wait for all to be stopped */ - printk("Waiting for streams to be stopped\n"); - for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { - k_sem_take(&sem_stopped, K_FOREVER); - } + test_broadcast_source_stop_inval(); + test_broadcast_source_stop(source); + test_broadcast_source_stop_inval_state(source); - printk("Deleting broadcast source\n"); - err = bt_bap_broadcast_source_delete(source); - if (err != 0) { - FAIL("Unable to delete broadcast source: %d\n", err); - return; - } + test_broadcast_source_delete_inval(); + test_broadcast_source_delete(source); source = NULL; - err = stop_extended_adv(adv); if (err != 0) { FAIL("Unable to stop extended advertising: %d\n", err); @@ -354,11 +1184,7 @@ static void test_main(void) } printk("Deleting broadcast source\n"); - err = bt_bap_broadcast_source_delete(source); - if (err != 0) { - FAIL("Unable to delete broadcast source: %d\n", err); - return; - } + test_broadcast_source_delete(source); source = NULL; PASS("Broadcast source passed\n"); From 353148280098cc3fb96cf395337136f7438996dd Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 9 Jun 2023 12:25:23 -0500 Subject: [PATCH 1413/2042] dts: arm: nxp: nxp_rt5xx_common: Added required inputmux bindings Added required inputmux bindings to support DMA Channel Chaining for the mimxrt595_evk Signed-off-by: Emilio Benavente --- dts/arm/nxp/nxp_rt5xx_common.dtsi | 7 +++++++ .../zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index a180a80117a7..3b4bf2ec380c 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -11,6 +11,7 @@ #include #include #include +#include / { chosen { @@ -327,6 +328,9 @@ reg = <0x104000 0x1000>; interrupts = <1 0>; dma-channels = <37>; + nxp,dma-num-of-otrigs = <4>; + nxp,dma-otrig-base-address = ; + nxp,dma-itrig-base-address = ; status = "disabled"; #dma-cells = <1>; }; @@ -336,6 +340,9 @@ reg = <0x105000 0x1000>; interrupts = <54 0>; dma-channels = <37>; + nxp,dma-num-of-otrigs = <4>; + nxp,dma-otrig-base-address = ; + nxp,dma-itrig-base-address = ; status = "disabled"; #dma-cells = <1>; }; diff --git a/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h b/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h index b7e249db9dfe..b419baeaa04f 100644 --- a/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h +++ b/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h @@ -11,4 +11,9 @@ #define LPC55S69_DMA1_OTRIG_BASE 0x24000002 #define LPC55S69_DMA1_ITRIG_BASE 0x20000008 +#define RT595_DMA0_OTRIG_BASE 0x30000000 +#define RT595_DMA0_ITRIG_BASE 0x2000000E +#define RT595_DMA1_OTRIG_BASE 0x50000000 +#define RT595_DMA1_ITRIG_BASE 0x4000000E + #endif From 0d2127317b5b03b7f575b7ff18258e239d3819c4 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 9 Jun 2023 12:29:02 -0500 Subject: [PATCH 1414/2042] tests: drivers: dma: Added the 595 to chan link testcase.yml Added the mimxrt595_evk into the testcase.yml for the channel chaining test. Signed-off-by: Emilio Benavente --- tests/drivers/dma/chan_link_transfer/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/dma/chan_link_transfer/testcase.yaml b/tests/drivers/dma/chan_link_transfer/testcase.yaml index 45027d880979..468efbf6eb6b 100644 --- a/tests/drivers/dma/chan_link_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_link_transfer/testcase.yaml @@ -7,6 +7,7 @@ tests: - dma platform_allow: - frdm_k64f + - mimxrt595_evk_cm33 - mimxrt1050_evk - mimxrt1060_evk - mimxrt1064_evk From fa94dcd277f6e8a4179756cdac78bf88629732f9 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 13 Jun 2023 23:39:52 +0000 Subject: [PATCH 1415/2042] drivers: mipi_dsi: implement clock selection algorithm With the phy-clock being specified in devicetree (and thus under user control), there is no need to artificially enlarge the DPHY clock to insure it is fast enough. Instead, we can calculate the DPHY clock directly, selecting the closest realizable value that is at least as fast as the value requested by the user. Fixes #59215 Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux.c | 154 +++++++++++++++++++++++++++++++----- 1 file changed, 136 insertions(+), 18 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux.c b/drivers/mipi_dsi/dsi_mcux.c index 98fcb0be5642..c865a9f914aa 100644 --- a/drivers/mipi_dsi/dsi_mcux.c +++ b/drivers/mipi_dsi/dsi_mcux.c @@ -17,16 +17,27 @@ LOG_MODULE_REGISTER(dsi_mcux, CONFIG_MIPI_DSI_LOG_LEVEL); #define MIPI_DPHY_REF_CLK DT_INST_PROP(0, dphy_ref_frequency) -/* - * The DPHY bit clock must be fast enough to send out the pixels, it should be - * larger than: - * - * (Pixel clock * bit per output pixel) / number of MIPI data lane - * - * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure - * it is fast enough. - */ -#define MIPI_DPHY_BIT_CLK_ENLARGE(origin) (((origin) / 8) * 9) +/* Max output frequency of DPHY bit clock */ +#define MIPI_DPHY_MAX_FREQ MHZ(800) + +/* PLL CN should be in the range of 1 to 32. */ +#define DSI_DPHY_PLL_CN_MIN 1U +#define DSI_DPHY_PLL_CN_MAX 32U + +/* PLL refClk / CN should be in the range of 24M to 30M. */ +#define DSI_DPHY_PLL_REFCLK_CN_MIN MHZ(24) +#define DSI_DPHY_PLL_REFCLK_CN_MAX MHZ(30) + +/* PLL CM should be in the range of 16 to 255. */ +#define DSI_DPHY_PLL_CM_MIN 16U +#define DSI_DPHY_PLL_CM_MAX 255U + +/* PLL VCO output frequency max value is 1.5GHz, VCO output is (ref_clk / CN ) * CM. */ +#define DSI_DPHY_PLL_VCO_MAX MHZ(1500) +#define DSI_DPHY_PLL_VCO_MIN (DSI_DPHY_PLL_REFCLK_CN_MIN * DSI_DPHY_PLL_CM_MIN) + +#define DSI_DPHY_PLL_CO_MIN 0 +#define DSI_DPHY_PLL_CO_MAX 3 struct display_mcux_mipi_dsi_config { MIPI_DSI_Type base; @@ -39,6 +50,111 @@ struct display_mcux_mipi_dsi_data { const struct device *dev; }; +static uint32_t dsi_mcux_best_clock(uint32_t ref_clk, uint32_t target_freq) +{ + /* + * This function is intended to find the closest realizable DPHY + * bit clock for a given target frequency, such that the DPHY clock + * is faster than the target frequency. MCUX SDK implements a similar + * function with DSI_DphyGetPllDivider, but this function will + * configure the DPHY to output the closest realizable clock frequency + * to the requested value. This can cause dropped pixels if + * the output frequency is less than the requested one. + */ + uint32_t co_shift, cn, cm; + uint32_t cand_freq, vco_freq, refclk_cn_freq; + uint32_t best_pll_freq = 0U; + uint32_t best_diff = UINT32_MAX; + + /* + * The formula for the DPHY output frequency is: + * ref_clk * (CM / (CN * (1 << CO))) + */ + + /* Test all available CO shifts (1x, 2x, 4x, 8x) */ + for (co_shift = DSI_DPHY_PLL_CO_MIN; co_shift <= DSI_DPHY_PLL_CO_MAX; co_shift++) { + /* Determine VCO output frequency before CO divider */ + vco_freq = target_freq << co_shift; + + /* If desired VCO output frequency is too low, try next CO shift */ + if (vco_freq < DSI_DPHY_PLL_VCO_MIN) { + continue; + } + + /* If desired VCO output frequency is too high, no point in + * searching further + */ + if (vco_freq > DSI_DPHY_PLL_VCO_MAX) { + break; + } + + /* Search the best CN and CM values for desired VCO frequency */ + for (cn = DSI_DPHY_PLL_CN_MIN; cn <= DSI_DPHY_PLL_CN_MAX; cn++) { + refclk_cn_freq = ref_clk / cn; + + /* If the frequency after input divider is too high, + * try next CN value + */ + if (refclk_cn_freq > DSI_DPHY_PLL_REFCLK_CN_MAX) { + continue; + } + + /* If the frequency after input divider is too low, + * no point in trying higher dividers. + */ + if (refclk_cn_freq < DSI_DPHY_PLL_REFCLK_CN_MIN) { + break; + } + + /* Get the closest CM value for this vco frequency + * and input divider. Round up, to bias towards higher + * frequencies + * NOTE: we differ from the SDK algorithm here, which + * would round cm to the closest integer + */ + cm = (vco_freq + (refclk_cn_freq - 1)) / refclk_cn_freq; + + /* If CM was rounded up to one over valid range, + * round down + */ + if (cm == (DSI_DPHY_PLL_CM_MAX + 1)) { + cm = DSI_DPHY_PLL_CM_MAX; + } + + /* If CM value is still out of range, CN/CO setting won't work */ + if ((cm < DSI_DPHY_PLL_CM_MIN) || (cm > DSI_DPHY_PLL_CM_MAX)) { + continue; + } + + /* Calculate candidate frequency */ + cand_freq = (refclk_cn_freq * cm) >> co_shift; + + if (cand_freq < target_freq) { + /* SKIP frequencies less than target frequency. + * this is where the algorithm differs from the + * SDK. + */ + continue; + } else { + if ((cand_freq - target_freq) < best_diff) { + /* New best CN, CM, and CO found */ + best_diff = (cand_freq - target_freq); + best_pll_freq = cand_freq; + } + } + + if (best_diff == 0U) { + /* We have found exact match for CN, CM, CO. + * return now. + */ + return best_pll_freq; + } + } + } + return best_pll_freq; +} + + static int dsi_mcux_attach(const struct device *dev, uint8_t channel, const struct mipi_dsi_device *mdev) @@ -63,16 +179,17 @@ static int dsi_mcux_attach(const struct device *dev, * larger than: * * (Pixel clock * bit per output pixel) / number of MIPI data lane - * - * Here the desired DPHY bit clock multiplied by ( 9 / 8 = 1.125) to ensure - * it is fast enough. - * - * Note that the DSI output pixel is 24bit per pixel. */ uint32_t mipi_dsi_dpi_clk_hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Lcdif); - uint32_t mipi_dsi_dphy_bit_clk_hz = config->phy_clock; - - mipi_dsi_dphy_bit_clk_hz = MIPI_DPHY_BIT_CLK_ENLARGE(mipi_dsi_dphy_bit_clk_hz); + /* Find the best realizable clock value for the MIPI DSI */ + uint32_t mipi_dsi_dphy_bit_clk_hz = + dsi_mcux_best_clock(mipi_dsi_dphy_ref_clk_hz, config->phy_clock); + if (mipi_dsi_dphy_bit_clk_hz == 0) { + LOG_ERR("DPHY cannot support requested PHY clock"); + return -ENOTSUP; + } + /* Cap clock value to max frequency */ + mipi_dsi_dphy_bit_clk_hz = MIN(mipi_dsi_dphy_bit_clk_hz, MIPI_DPHY_MAX_FREQ); mipi_dsi_esc_clk_hz = CLOCK_GetRootClockFreq(kCLOCK_Root_Mipi_Esc); mipi_dsi_tx_esc_clk_hz = mipi_dsi_esc_clk_hz / 3; @@ -81,6 +198,7 @@ static int dsi_mcux_attach(const struct device *dev, mipi_dsi_dphy_bit_clk_hz = DSI_InitDphy((MIPI_DSI_Type *)&config->base, &dphy_config, mipi_dsi_dphy_ref_clk_hz); + LOG_DBG("DPHY clock set to %u", mipi_dsi_dphy_bit_clk_hz); /* Init DPI interface. */ DSI_SetDpiConfig((MIPI_DSI_Type *)&config->base, &config->dpi_config, mdev->data_lanes, mipi_dsi_dpi_clk_hz, mipi_dsi_dphy_bit_clk_hz); From 7c270c848867580dd522677e4500f724e8e0f657 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Wed, 5 Jul 2023 12:48:06 +0200 Subject: [PATCH 1416/2042] scripts: tests: Expand environment.py tests As we aim to enhance our test coverage, environment module is a target-rich environment. Some errors in the original module were discovered and tests regarding these cases were commented out until they are fixed. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/conftest.py | 4 + scripts/tests/twister/test_environment.py | 428 ++++++++++++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 scripts/tests/twister/test_environment.py diff --git a/scripts/tests/twister/conftest.py b/scripts/tests/twister/conftest.py index 232c9c374584..bc391ad5e3d5 100644 --- a/scripts/tests/twister/conftest.py +++ b/scripts/tests/twister/conftest.py @@ -29,6 +29,10 @@ def _test_data(): data = ZEPHYR_BASE + "/scripts/tests/twister/test_data/" return data +@pytest.fixture(name='zephyr_base') +def zephyr_base_directory(): + return ZEPHYR_BASE + @pytest.fixture(name='testsuites_dir') def testsuites_directory(): """ Pytest fixture to load the test data directory""" diff --git a/scripts/tests/twister/test_environment.py b/scripts/tests/twister/test_environment.py new file mode 100644 index 000000000000..6ca39a613100 --- /dev/null +++ b/scripts/tests/twister/test_environment.py @@ -0,0 +1,428 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for environment.py classes' methods +""" + +import mock +import os +import pytest +import shutil + +from contextlib import nullcontext + +import twisterlib.environment + + +TESTDATA_1 = [ + ( + None, + None, + None, + ['--short-build-path', '-k'], + '--short-build-path requires Ninja to be enabled' + ), + ( + 'nt', + None, + None, + ['--device-serial-pty', 'dummy'], + '--device-serial-pty is not supported on Windows OS' + ), + ( + None, + None, + None, + ['--west-runner=dummy'], + 'west-runner requires west-flash to be enabled' + ), + ( + None, + None, + None, + ['--west-flash=\"--board-id=dummy\"'], + 'west-flash requires device-testing to be enabled' + ), + ( + None, + { + 'exist': [], + 'missing': ['valgrind'] + }, + None, + ['--enable-valgrind'], + 'valgrind enabled but valgrind executable not found' + ), + ( + None, + None, + None, + ['--device-testing', '--device-serial', 'dummy', '--platform', 'dummy_platform1', '--platform', 'dummy_platform2'], + 'When --device-testing is used with --device-serial or --device-serial-pty, only one platform is allowed' + ), +# environment.py compares a store_false/true argument to None. +# This case will never raise an error, until that is fixed. +# ( +# None, +# None, +# None, +# ['--device-flash-timeout', '60'], +# '--device-flash-timeout requires --device-testing' +# ), +# environment.py compares a store_false/true argument to None. +# This case will never raise an error, until that is fixed. +# ( +# None, +# None, +# None, +# ['--device-flash-with-test'], +# '--device-flash-with-test requires --device-testing' +# ), + ( + None, + None, + None, + ['--shuffle-tests'], + '--shuffle-tests requires --subset' + ), + ( + None, + None, + None, + ['--shuffle-tests-seed', '0'], + '--shuffle-tests-seed requires --shuffle-tests' + ), + ( + None, + None, + None, + ['--coverage-formats', 'html', '--coverage-tool', 'lcov'], + '--coverage-formats can only be used when coverage tool is set to gcovr' + ), + ( + None, + None, + None, + ['/dummy/unrecognised/arg'], + 'Unrecognized arguments found: \'/dummy/unrecognised/arg\'. Use -- to delineate extra arguments for test binary or pass -h for help.' + ), + ( + None, + None, + True, + [], + 'By default Twister should work without pytest-twister-harness plugin being installed, so please, uninstall it by `pip uninstall pytest-twister-harness` and `git clean -dxf scripts/pylib/pytest-twister-harness`.' + ), +] + + +@pytest.mark.parametrize("os_name, which_dict, pytest_installed_var, args, expected_error", TESTDATA_1) +def test_parse_arguments_errors(caplog, os_name, which_dict, pytest_installed_var, args, expected_error): + def mock_which(name): + if name in which_dict['missing']: + return False + elif name in which_dict['exist']: + return which_dict['path'][which_dict['exist']] if which_dict['path'][which_dict['exist']] else f'dummy/path/{name}' + else: + return f'dummy/path/{name}' + + with mock.patch("sys.argv", ['twister'] + args): + parser = twisterlib.environment.add_parse_arguments() + + if which_dict: + which_dict['path'] = {name: shutil.which(name) for name in which_dict['exist']} + which_mock = mock.Mock(side_effect=mock_which) + + with mock.patch("os.name", os_name) if os_name is not None else nullcontext(), \ + mock.patch("shutil.which", which_mock) if which_dict else nullcontext(), \ + mock.patch("twisterlib.environment.PYTEST_PLUGIN_INSTALLED", pytest_installed_var) if pytest_installed_var is not None else nullcontext(): + with pytest.raises(SystemExit) as exit_info: + twisterlib.environment.parse_arguments(parser, args) + + assert exit_info.value.code == 1 + assert expected_error in ' '.join(caplog.text.split()) + + +def test_parse_arguments_errors_size(): + """`options.size` is not an error, rather a different functionality.""" + + args = ['--size', 'dummy.elf'] + + with mock.patch("sys.argv", ['twister'] + args): + parser = twisterlib.environment.add_parse_arguments() + + mock_calc_parent = mock.Mock() + mock_calc_parent.child = mock.Mock(return_value=mock.Mock()) + + def mock_calc(*args, **kwargs): + return mock_calc_parent.child(args, kwargs) + + with mock.patch("twisterlib.size_calc.SizeCalculator", mock_calc): + with pytest.raises(SystemExit) as exit_info: + twisterlib.environment.parse_arguments(parser, args) + + assert exit_info.value.code == 1 + + mock_calc_parent.child.assert_has_calls([mock.call(('dummy.elf', []), {})]) + mock_calc_parent.child().size_report.assert_has_calls([mock.call()]) + + +def test_parse_arguments_warnings(caplog): + args = ['--allow-installed-plugin'] + + with mock.patch("sys.argv", ['twister'] + args): + parser = twisterlib.environment.add_parse_arguments() + + with mock.patch("twisterlib.environment.PYTEST_PLUGIN_INSTALLED", True): + twisterlib.environment.parse_arguments(parser, args) + + assert "You work with installed version of pytest-twister-harness plugin." in ' '.join(caplog.text.split()) + + +TESTDATA_2 = [ + (['--show-footprint']), + (['--compare-report', 'dummy']), +] + + +@pytest.mark.parametrize("additional_args", TESTDATA_2) +def test_parse_arguments(zephyr_base, additional_args): + args = ['--coverage', '--platform', 'dummy_platform'] + additional_args + ['--', 'dummy_extra_1', 'dummy_extra_2'] + + with mock.patch("sys.argv", ['twister'] + args): + parser = twisterlib.environment.add_parse_arguments() + + options = twisterlib.environment.parse_arguments(parser, args) + + assert os.path.join(zephyr_base, "tests") in options.testsuite_root + assert os.path.join(zephyr_base, "samples") in options.testsuite_root + + assert options.enable_size_report + + assert options.enable_coverage + + assert options.coverage_platform == ['dummy_platform'] + + assert options.extra_test_args == ['dummy_extra_1', 'dummy_extra_2'] + + +TESTDATA_3 = [ +# Causes an error because some option member accesses +# do not check if it is not None +# ( +# None, +# mock.Mock( +# generator_cmd='make', +# generator='Unix Makefiles', +# test_roots=None, +# board_roots=None, +# outdir=None, +# ) +# ), + ( + mock.Mock( + ninja=True, + board_root=['dummy1', 'dummy2'], + testsuite_root=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")] + ), + mock.Mock( + generator_cmd='ninja', + generator='Ninja', + test_roots=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")], + board_roots=['dummy1', 'dummy2'], + outdir='dummy_abspath', + ) + ), + ( + mock.Mock( + ninja=False, + board_root='dummy0', + testsuite_root=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")] + ), + mock.Mock( + generator_cmd='make', + generator='Unix Makefiles', + test_roots=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")], + board_roots=['dummy0'], + outdir='dummy_abspath', + ) + ), +] + + +@pytest.mark.parametrize("options, expected_env", TESTDATA_3) +def test_twisterenv_init(options, expected_env): + with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + twister_env = twisterlib.environment.TwisterEnv(options=options) + + assert twister_env.generator_cmd == expected_env.generator_cmd + assert twister_env.generator == expected_env.generator + + assert twister_env.test_roots == expected_env.test_roots + + assert twister_env.board_roots == expected_env.board_roots + assert twister_env.outdir == expected_env.outdir + + +def test_twisterenv_discover(): + options = mock.Mock( + ninja=True + ) + + with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + twister_env = twisterlib.environment.TwisterEnv(options=options) + + mock_datetime = mock.Mock( + now=mock.Mock( + return_value=mock.Mock( + isoformat=mock.Mock(return_value='dummy_time') + ) + ) + ) + + with mock.patch.object(twisterlib.environment.TwisterEnv, "check_zephyr_version", mock.Mock()) as mock_czv, \ + mock.patch.object(twisterlib.environment.TwisterEnv, "get_toolchain", mock.Mock()) as mock_gt, \ + mock.patch("twisterlib.environment.datetime", mock_datetime): + twister_env.discover() + + mock_czv.assert_called_once() + mock_gt.assert_called_once() + assert twister_env.run_date == 'dummy_time' + + +TESTDATA_3 = [ + (mock.Mock(returncode=0, stdout='dummy stdout version'), mock.Mock(returncode=0, stdout='dummy stdout date'), ['Zephyr version: dummy stdout version'], 'dummy stdout version', 'dummy stdout date'), +# Note the 'Coult' typo instead of 'Could' + (mock.Mock(returncode=0, stdout=''), mock.Mock(returncode=0, stdout='dummy stdout date'), ['Coult not determine version'], 'Unknown', 'dummy stdout date'), + (OSError, mock.Mock(returncode=1), ['Cannot read zephyr version.'], None, 'Unknown'), +] + + +@pytest.mark.parametrize("git_describe_return, git_show_return, expected_logs, expected_version, expected_commit_date", TESTDATA_3) +def test_twisterenv_check_zephyr_version(caplog, git_describe_return, git_show_return, expected_logs, expected_version, expected_commit_date): + def mock_run(command, *args, **kwargs): + if all([keyword in command for keyword in ['git', 'describe']]): + if isinstance(git_describe_return, type) and issubclass(git_describe_return, Exception): + raise git_describe_return() + return git_describe_return + if all([keyword in command for keyword in ['git', 'show']]): + if isinstance(git_show_return, type) and issubclass(git_show_return, Exception): + raise git_show_return() + return git_show_return + + options = mock.Mock( + ninja=True + ) + + with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + twister_env = twisterlib.environment.TwisterEnv(options=options) + + with mock.patch("subprocess.run", mock.Mock(side_effect=mock_run)): + twister_env.check_zephyr_version() + print(expected_logs) + print(caplog.text) + assert twister_env.version == expected_version + assert twister_env.commit_date == expected_commit_date + assert all([expected_log in caplog.text for expected_log in expected_logs]) + + +TESTDATA_4 = [ + ( + False, + None, + None, + 'Unable to find `cmake` in path', + None + ), +# Note the double-space + ( + True, + 0, + b'somedummy\x1B[123-@d1770', + 'Finished running dummy/script/path', + { + 'returncode': 0, + 'msg': 'Finished running dummy/script/path', + 'stdout': 'somedummyd1770', + } + ), + ( + True, + 1, + b'another\x1B_dummy', + 'Cmake script failure: dummy/script/path', + { + 'returncode': 1, + 'returnmsg': 'anotherdummy' + } + ), +] + + +@pytest.mark.parametrize("find_cmake, return_code, out, expected_log, expected_result", TESTDATA_4) +def test_twisterenv_run_cmake_script(caplog, find_cmake, return_code, out, expected_log, expected_result): + def mock_which(name, *args, **kwargs): + return 'dummy/cmake/path' if find_cmake else None + + def mock_popen(command, *args, **kwargs): + return mock.Mock( + pid=0, + returncode=return_code, + communicate=mock.Mock( + return_value=(out, '') + ) + ) + + args = ['dummy/script/path', 'var1=val1'] + + with mock.patch("shutil.which", mock_which), \ + mock.patch("subprocess.Popen", mock.Mock(side_effect=mock_popen)), \ + pytest.raises(Exception) if not find_cmake else nullcontext() as exception: + results = twisterlib.environment.TwisterEnv.run_cmake_script(args) + + assert 'Running cmake script dummy/script/path' in caplog.text + + assert expected_log in caplog.text + + if exception is not None: + return + + assert expected_result.items() <= results.items() + + +TESTDATA_5 = [ + ( + { + 'returncode': 0, + 'stdout': '{"ZEPHYR_TOOLCHAIN_VARIANT": "dummy toolchain"}' + }, + None, + 'Using \'dummy toolchain\' toolchain.' + ), + ( + {'returncode': 1}, + 2, + None + ), +] + + +@pytest.mark.parametrize("script_result, exit_value, expected_log", TESTDATA_5) +def test_get_toolchain(caplog, script_result, exit_value, expected_log): + options = mock.Mock( + ninja=True + ) + + with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + twister_env = twisterlib.environment.TwisterEnv(options=options) + + with mock.patch.object(twisterlib.environment.TwisterEnv, "run_cmake_script", mock.Mock(return_value=script_result)), \ + pytest.raises(SystemExit) if exit_value is not None else nullcontext() as exit_info: + twister_env.get_toolchain() + + if exit_info is not None: + assert exit_info.value.code == exit_value + else: + assert expected_log in caplog.text From d42b2e0a9bddc4f5ae81e50bee762aabc7693e86 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Mon, 17 Jul 2023 18:31:23 +0200 Subject: [PATCH 1417/2042] scripts: tests: Environment tests update Implented suggestions proposed by gchwier. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_environment.py | 261 +++++++++++++++++----- 1 file changed, 206 insertions(+), 55 deletions(-) diff --git a/scripts/tests/twister/test_environment.py b/scripts/tests/twister/test_environment.py index 6ca39a613100..ed8f7e4e65d8 100644 --- a/scripts/tests/twister/test_environment.py +++ b/scripts/tests/twister/test_environment.py @@ -59,8 +59,17 @@ None, None, None, - ['--device-testing', '--device-serial', 'dummy', '--platform', 'dummy_platform1', '--platform', 'dummy_platform2'], - 'When --device-testing is used with --device-serial or --device-serial-pty, only one platform is allowed' + [ + '--device-testing', + '--device-serial', + 'dummy', + '--platform', + 'dummy_platform1', + '--platform', + 'dummy_platform2' + ], + 'When --device-testing is used with --device-serial' \ + ' or --device-serial-pty, only one platform is allowed' ), # environment.py compares a store_false/true argument to None. # This case will never raise an error, until that is fixed. @@ -99,45 +108,84 @@ None, None, ['--coverage-formats', 'html', '--coverage-tool', 'lcov'], - '--coverage-formats can only be used when coverage tool is set to gcovr' + '--coverage-formats can only be used when' \ + ' coverage tool is set to gcovr' ), ( None, None, None, ['/dummy/unrecognised/arg'], - 'Unrecognized arguments found: \'/dummy/unrecognised/arg\'. Use -- to delineate extra arguments for test binary or pass -h for help.' + 'Unrecognized arguments found: \'/dummy/unrecognised/arg\'.' \ + ' Use -- to delineate extra arguments for test binary' \ + ' or pass -h for help.' ), ( None, None, True, [], - 'By default Twister should work without pytest-twister-harness plugin being installed, so please, uninstall it by `pip uninstall pytest-twister-harness` and `git clean -dxf scripts/pylib/pytest-twister-harness`.' + 'By default Twister should work without pytest-twister-harness' \ + ' plugin being installed, so please, uninstall it by' \ + ' `pip uninstall pytest-twister-harness` and' \ + ' `git clean -dxf scripts/pylib/pytest-twister-harness`.' ), ] -@pytest.mark.parametrize("os_name, which_dict, pytest_installed_var, args, expected_error", TESTDATA_1) -def test_parse_arguments_errors(caplog, os_name, which_dict, pytest_installed_var, args, expected_error): +@pytest.mark.parametrize( + 'os_name, which_dict, pytest_installed_var, args, expected_error', + TESTDATA_1, + ids=[ + 'short build path without ninja', + 'device-serial-pty on Windows', + 'west runner without west flash', + 'west-flash without device-testing', + 'valgrind without executable', + 'device serial with multiple platforms', +# 'device flash timeout without device testing', +# 'device flash with test without device testing', + 'shuffle-tests without subset', + 'shuffle-tests-seed without shuffle-tests', + 'coverage-formats without gcovr', + 'unrecognised argument', + 'pytest-twister-harness installed' + ] +) +def test_parse_arguments_errors( + caplog, + os_name, + which_dict, + pytest_installed_var, + args, + expected_error +): def mock_which(name): if name in which_dict['missing']: return False elif name in which_dict['exist']: - return which_dict['path'][which_dict['exist']] if which_dict['path'][which_dict['exist']] else f'dummy/path/{name}' + return which_dict['path'][which_dict['exist']] \ + if which_dict['path'][which_dict['exist']] \ + else f'dummy/path/{name}' else: return f'dummy/path/{name}' - with mock.patch("sys.argv", ['twister'] + args): + with mock.patch('sys.argv', ['twister'] + args): parser = twisterlib.environment.add_parse_arguments() if which_dict: - which_dict['path'] = {name: shutil.which(name) for name in which_dict['exist']} + which_dict['path'] = {name: shutil.which(name) \ + for name in which_dict['exist']} which_mock = mock.Mock(side_effect=mock_which) - with mock.patch("os.name", os_name) if os_name is not None else nullcontext(), \ - mock.patch("shutil.which", which_mock) if which_dict else nullcontext(), \ - mock.patch("twisterlib.environment.PYTEST_PLUGIN_INSTALLED", pytest_installed_var) if pytest_installed_var is not None else nullcontext(): + with mock.patch('os.name', os_name) \ + if os_name is not None else nullcontext(), \ + mock.patch('shutil.which', which_mock) \ + if which_dict else nullcontext(), \ + mock.patch( + 'twisterlib.environment.PYTEST_PLUGIN_INSTALLED', + pytest_installed_var + ) if pytest_installed_var is not None else nullcontext(): with pytest.raises(SystemExit) as exit_info: twisterlib.environment.parse_arguments(parser, args) @@ -150,7 +198,7 @@ def test_parse_arguments_errors_size(): args = ['--size', 'dummy.elf'] - with mock.patch("sys.argv", ['twister'] + args): + with mock.patch('sys.argv', ['twister'] + args): parser = twisterlib.environment.add_parse_arguments() mock_calc_parent = mock.Mock() @@ -159,7 +207,7 @@ def test_parse_arguments_errors_size(): def mock_calc(*args, **kwargs): return mock_calc_parent.child(args, kwargs) - with mock.patch("twisterlib.size_calc.SizeCalculator", mock_calc): + with mock.patch('twisterlib.size_calc.SizeCalculator', mock_calc): with pytest.raises(SystemExit) as exit_info: twisterlib.environment.parse_arguments(parser, args) @@ -172,13 +220,14 @@ def mock_calc(*args, **kwargs): def test_parse_arguments_warnings(caplog): args = ['--allow-installed-plugin'] - with mock.patch("sys.argv", ['twister'] + args): + with mock.patch('sys.argv', ['twister'] + args): parser = twisterlib.environment.add_parse_arguments() - with mock.patch("twisterlib.environment.PYTEST_PLUGIN_INSTALLED", True): + with mock.patch('twisterlib.environment.PYTEST_PLUGIN_INSTALLED', True): twisterlib.environment.parse_arguments(parser, args) - assert "You work with installed version of pytest-twister-harness plugin." in ' '.join(caplog.text.split()) + assert 'You work with installed version of' \ + ' pytest-twister-harness plugin.' in ' '.join(caplog.text.split()) TESTDATA_2 = [ @@ -187,17 +236,22 @@ def test_parse_arguments_warnings(caplog): ] -@pytest.mark.parametrize("additional_args", TESTDATA_2) +@pytest.mark.parametrize( + 'additional_args', + TESTDATA_2, + ids=['show footprint', 'compare report'] +) def test_parse_arguments(zephyr_base, additional_args): - args = ['--coverage', '--platform', 'dummy_platform'] + additional_args + ['--', 'dummy_extra_1', 'dummy_extra_2'] + args = ['--coverage', '--platform', 'dummy_platform'] + \ + additional_args + ['--', 'dummy_extra_1', 'dummy_extra_2'] - with mock.patch("sys.argv", ['twister'] + args): + with mock.patch('sys.argv', ['twister'] + args): parser = twisterlib.environment.add_parse_arguments() options = twisterlib.environment.parse_arguments(parser, args) - assert os.path.join(zephyr_base, "tests") in options.testsuite_root - assert os.path.join(zephyr_base, "samples") in options.testsuite_root + assert os.path.join(zephyr_base, 'tests') in options.testsuite_root + assert os.path.join(zephyr_base, 'samples') in options.testsuite_root assert options.enable_size_report @@ -225,12 +279,18 @@ def test_parse_arguments(zephyr_base, additional_args): mock.Mock( ninja=True, board_root=['dummy1', 'dummy2'], - testsuite_root=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")] + testsuite_root=[ + os.path.join('dummy', 'path', "tests"), + os.path.join('dummy', 'path', "samples") + ] ), mock.Mock( generator_cmd='ninja', generator='Ninja', - test_roots=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")], + test_roots=[ + os.path.join('dummy', 'path', "tests"), + os.path.join('dummy', 'path', "samples") + ], board_roots=['dummy1', 'dummy2'], outdir='dummy_abspath', ) @@ -239,12 +299,18 @@ def test_parse_arguments(zephyr_base, additional_args): mock.Mock( ninja=False, board_root='dummy0', - testsuite_root=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")] + testsuite_root=[ + os.path.join('dummy', 'path', "tests"), + os.path.join('dummy', 'path', "samples") + ] ), mock.Mock( generator_cmd='make', generator='Unix Makefiles', - test_roots=[os.path.join('dummy', 'path', "tests"), os.path.join('dummy', 'path', "samples")], + test_roots=[ + os.path.join('dummy', 'path', "tests"), + os.path.join('dummy', 'path', "samples") + ], board_roots=['dummy0'], outdir='dummy_abspath', ) @@ -252,9 +318,20 @@ def test_parse_arguments(zephyr_base, additional_args): ] -@pytest.mark.parametrize("options, expected_env", TESTDATA_3) +@pytest.mark.parametrize( + 'options, expected_env', + TESTDATA_3, + ids=[ +# 'no options', + 'ninja', + 'make' + ] +) def test_twisterenv_init(options, expected_env): - with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + with mock.patch( + 'os.path.abspath', + mock.Mock(return_value='dummy_abspath') + ): twister_env = twisterlib.environment.TwisterEnv(options=options) assert twister_env.generator_cmd == expected_env.generator_cmd @@ -271,7 +348,10 @@ def test_twisterenv_discover(): ninja=True ) - with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + with mock.patch( + 'os.path.abspath', + mock.Mock(return_value='dummy_abspath') + ): twister_env = twisterlib.environment.TwisterEnv(options=options) mock_datetime = mock.Mock( @@ -282,9 +362,17 @@ def test_twisterenv_discover(): ) ) - with mock.patch.object(twisterlib.environment.TwisterEnv, "check_zephyr_version", mock.Mock()) as mock_czv, \ - mock.patch.object(twisterlib.environment.TwisterEnv, "get_toolchain", mock.Mock()) as mock_gt, \ - mock.patch("twisterlib.environment.datetime", mock_datetime): + with mock.patch.object( + twisterlib.environment.TwisterEnv, + 'check_zephyr_version', + mock.Mock() + ) as mock_czv, \ + mock.patch.object( + twisterlib.environment.TwisterEnv, + 'get_toolchain', + mock.Mock() + ) as mock_gt, \ + mock.patch('twisterlib.environment.datetime', mock_datetime): twister_env.discover() mock_czv.assert_called_once() @@ -292,23 +380,55 @@ def test_twisterenv_discover(): assert twister_env.run_date == 'dummy_time' -TESTDATA_3 = [ - (mock.Mock(returncode=0, stdout='dummy stdout version'), mock.Mock(returncode=0, stdout='dummy stdout date'), ['Zephyr version: dummy stdout version'], 'dummy stdout version', 'dummy stdout date'), +TESTDATA_4 = [ + ( + mock.Mock(returncode=0, stdout='dummy stdout version'), + mock.Mock(returncode=0, stdout='dummy stdout date'), + ['Zephyr version: dummy stdout version'], + 'dummy stdout version', + 'dummy stdout date' + ), # Note the 'Coult' typo instead of 'Could' - (mock.Mock(returncode=0, stdout=''), mock.Mock(returncode=0, stdout='dummy stdout date'), ['Coult not determine version'], 'Unknown', 'dummy stdout date'), - (OSError, mock.Mock(returncode=1), ['Cannot read zephyr version.'], None, 'Unknown'), + ( + mock.Mock(returncode=0, stdout=''), + mock.Mock(returncode=0, stdout='dummy stdout date'), + ['Coult not determine version'], + 'Unknown', + 'dummy stdout date' + ), + ( + OSError, + mock.Mock(returncode=1), + ['Cannot read zephyr version.'], + None, + 'Unknown' + ), ] -@pytest.mark.parametrize("git_describe_return, git_show_return, expected_logs, expected_version, expected_commit_date", TESTDATA_3) -def test_twisterenv_check_zephyr_version(caplog, git_describe_return, git_show_return, expected_logs, expected_version, expected_commit_date): +@pytest.mark.parametrize( + 'git_describe_return, git_show_return, expected_logs,' \ + ' expected_version, expected_commit_date', + TESTDATA_4, + ids=['valid', 'no zephyr version on describe', 'error on git describe'] +) +def test_twisterenv_check_zephyr_version( + caplog, + git_describe_return, + git_show_return, + expected_logs, + expected_version, + expected_commit_date +): def mock_run(command, *args, **kwargs): if all([keyword in command for keyword in ['git', 'describe']]): - if isinstance(git_describe_return, type) and issubclass(git_describe_return, Exception): + if isinstance(git_describe_return, type) and \ + issubclass(git_describe_return, Exception): raise git_describe_return() return git_describe_return if all([keyword in command for keyword in ['git', 'show']]): - if isinstance(git_show_return, type) and issubclass(git_show_return, Exception): + if isinstance(git_show_return, type) and \ + issubclass(git_show_return, Exception): raise git_show_return() return git_show_return @@ -316,10 +436,13 @@ def mock_run(command, *args, **kwargs): ninja=True ) - with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + with mock.patch( + 'os.path.abspath', + mock.Mock(return_value='dummy_abspath') + ): twister_env = twisterlib.environment.TwisterEnv(options=options) - with mock.patch("subprocess.run", mock.Mock(side_effect=mock_run)): + with mock.patch('subprocess.run', mock.Mock(side_effect=mock_run)): twister_env.check_zephyr_version() print(expected_logs) print(caplog.text) @@ -328,7 +451,7 @@ def mock_run(command, *args, **kwargs): assert all([expected_log in caplog.text for expected_log in expected_logs]) -TESTDATA_4 = [ +TESTDATA_5 = [ ( False, None, @@ -361,8 +484,23 @@ def mock_run(command, *args, **kwargs): ] -@pytest.mark.parametrize("find_cmake, return_code, out, expected_log, expected_result", TESTDATA_4) -def test_twisterenv_run_cmake_script(caplog, find_cmake, return_code, out, expected_log, expected_result): +@pytest.mark.parametrize( + 'find_cmake, return_code, out, expected_log, expected_result', + TESTDATA_5, + ids=[ + 'cmake not found', + 'regex sanitation 1', + 'regex sanitation 2' + ] +) +def test_twisterenv_run_cmake_script( + caplog, + find_cmake, + return_code, + out, + expected_log, + expected_result +): def mock_which(name, *args, **kwargs): return 'dummy/cmake/path' if find_cmake else None @@ -377,9 +515,10 @@ def mock_popen(command, *args, **kwargs): args = ['dummy/script/path', 'var1=val1'] - with mock.patch("shutil.which", mock_which), \ - mock.patch("subprocess.Popen", mock.Mock(side_effect=mock_popen)), \ - pytest.raises(Exception) if not find_cmake else nullcontext() as exception: + with mock.patch('shutil.which', mock_which), \ + mock.patch('subprocess.Popen', mock.Mock(side_effect=mock_popen)), \ + pytest.raises(Exception) if \ + not find_cmake else nullcontext() as exception: results = twisterlib.environment.TwisterEnv.run_cmake_script(args) assert 'Running cmake script dummy/script/path' in caplog.text @@ -392,11 +531,11 @@ def mock_popen(command, *args, **kwargs): assert expected_result.items() <= results.items() -TESTDATA_5 = [ +TESTDATA_6 = [ ( { 'returncode': 0, - 'stdout': '{"ZEPHYR_TOOLCHAIN_VARIANT": "dummy toolchain"}' + 'stdout': '{\"ZEPHYR_TOOLCHAIN_VARIANT\": \"dummy toolchain\"}' }, None, 'Using \'dummy toolchain\' toolchain.' @@ -409,17 +548,29 @@ def mock_popen(command, *args, **kwargs): ] -@pytest.mark.parametrize("script_result, exit_value, expected_log", TESTDATA_5) +@pytest.mark.parametrize( + 'script_result, exit_value, expected_log', + TESTDATA_6, + ids=['valid', 'error'] +) def test_get_toolchain(caplog, script_result, exit_value, expected_log): options = mock.Mock( ninja=True ) - with mock.patch("os.path.abspath", mock.Mock(return_value='dummy_abspath')): + with mock.patch( + 'os.path.abspath', + mock.Mock(return_value='dummy_abspath') + ): twister_env = twisterlib.environment.TwisterEnv(options=options) - with mock.patch.object(twisterlib.environment.TwisterEnv, "run_cmake_script", mock.Mock(return_value=script_result)), \ - pytest.raises(SystemExit) if exit_value is not None else nullcontext() as exit_info: + with mock.patch.object( + twisterlib.environment.TwisterEnv, + 'run_cmake_script', + mock.Mock(return_value=script_result) + ), \ + pytest.raises(SystemExit) if \ + exit_value is not None else nullcontext() as exit_info: twister_env.get_toolchain() if exit_info is not None: From 48fc80fa792f9972f1ae83ee6485dd6c1cbbd976 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Fri, 7 Jul 2023 12:50:32 +0200 Subject: [PATCH 1418/2042] drivers: adc: iadc_gecko: select proper bits from sample Only 12-bit resolution is currently available in the driver, and each of the 16-bit samples store the actual data aligned to the left. A sample should be shifted 4 bits to the right to allow proper interpretation. Signed-off-by: Wojciech Sipak --- drivers/adc/iadc_gecko.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/adc/iadc_gecko.c b/drivers/adc/iadc_gecko.c index 0b9fcb07c8c0..1317a4e47295 100644 --- a/drivers/adc/iadc_gecko.c +++ b/drivers/adc/iadc_gecko.c @@ -20,6 +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); struct adc_gecko_channel_config { IADC_CfgAnalogGain_t gain; @@ -231,7 +232,7 @@ static void adc_gecko_isr(void *arg) if (!err) { sample = IADC_readSingleResult(iadc); - *data->buffer++ = (uint16_t)sample.data; + *data->buffer++ = GECKO_DATA_RES12BIT((uint16_t)sample.data); data->channels &= ~BIT(data->channel_id); if (data->channels) { From 022b2343560297c05f432892b6360761163bc7f0 Mon Sep 17 00:00:00 2001 From: Dipak Shetty Date: Fri, 7 Jul 2023 20:17:58 +0200 Subject: [PATCH 1419/2042] drivers: spi: eliminate dead code in spi_mcux_lpspi The `spi_mcux_transceive` had 2 return calls when the `CONFIG_SPI_MCUX_LPSPI_DMA` flag was active. The first return would be called and the later was unreachable. With the fix, now the return calls are mutually exclusive. Also, the `transceive` call is not compiled with the `CONFIG_SPI_MCUX_LPSPI_DMA` flag is active. Fixes #59533 Signed-off-by: Dipak Shetty --- drivers/spi/spi_mcux_lpspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 7976c5d00875..7cca7947cb91 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -469,7 +469,7 @@ static int transceive_dma(const struct device *dev, return ret; } -#endif +#else static int transceive(const struct device *dev, const struct spi_config *spi_cfg, @@ -502,6 +502,8 @@ static int transceive(const struct device *dev, return ret; } +#endif /*CONFIG_SPI_MCUX_LPSPI_DMA */ + static int spi_mcux_transceive(const struct device *dev, const struct spi_config *spi_cfg, const struct spi_buf_set *tx_bufs, @@ -509,8 +511,9 @@ static int spi_mcux_transceive(const struct device *dev, { #ifdef CONFIG_SPI_MCUX_LPSPI_DMA return transceive_dma(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); -#endif /* CONFIG_SPI_MCUX_LPSPI_DMA */ +#else return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +#endif /* CONFIG_SPI_MCUX_LPSPI_DMA */ } #ifdef CONFIG_SPI_ASYNC From f2735b6109057e49725f86dc5a05a3926d9c6471 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 14 Jul 2023 11:42:31 +0100 Subject: [PATCH 1420/2042] drivers: mfd: npm1300: Added reset and hibernate New reset function which performs a full power reset New hibernate function which powers down and wakes after specified timeout Signed-off-by: Andy Sinclair --- drivers/mfd/mfd_npm1300.c | 22 ++++++++++++++++++++++ include/zephyr/drivers/mfd/npm1300.h | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/drivers/mfd/mfd_npm1300.c b/drivers/mfd/mfd_npm1300.c index 7cacfc30e390..c971d6d5a80e 100644 --- a/drivers/mfd/mfd_npm1300.c +++ b/drivers/mfd/mfd_npm1300.c @@ -13,10 +13,16 @@ #include #define TIME_BASE 0x07U +#define MAIN_BASE 0x00U +#define SHIP_BASE 0x0BU #define TIME_OFFSET_LOAD 0x03U #define TIME_OFFSET_TIMER 0x08U +#define MAIN_OFFSET_RESET 0x01U + +#define SHIP_OFFSET_HIBERNATE 0x00U + #define TIMER_PRESCALER_MS 16U #define TIMER_MAX 0xFFFFFFU @@ -115,6 +121,22 @@ int mfd_npm1300_set_timer(const struct device *dev, uint32_t time_ms) return mfd_npm1300_reg_write(dev, TIME_BASE, TIME_OFFSET_LOAD, 1U); } +int mfd_npm1300_reset(const struct device *dev) +{ + return mfd_npm1300_reg_write(dev, MAIN_BASE, MAIN_OFFSET_RESET, 1U); +} + +int mfd_npm1300_hibernate(const struct device *dev, uint32_t time_ms) +{ + int ret = mfd_npm1300_set_timer(dev, time_ms); + + if (ret != 0) { + return ret; + } + + return mfd_npm1300_reg_write(dev, SHIP_BASE, SHIP_OFFSET_HIBERNATE, 1U); +} + #define MFD_NPM1300_DEFINE(inst) \ static struct mfd_npm1300_data data_##inst; \ \ diff --git a/include/zephyr/drivers/mfd/npm1300.h b/include/zephyr/drivers/mfd/npm1300.h index 4463bafa3a17..5bfe4477c3a9 100644 --- a/include/zephyr/drivers/mfd/npm1300.h +++ b/include/zephyr/drivers/mfd/npm1300.h @@ -98,6 +98,28 @@ int mfd_npm1300_reg_update(const struct device *dev, uint8_t base, uint8_t offse */ int mfd_npm1300_set_timer(const struct device *dev, uint32_t time_ms); +/** + * @brief npm1300 full power reset + * + * @param dev npm1300 mfd device + * @retval 0 If successful + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_reset(const struct device *dev); + +/** + * @brief npm1300 hibernate + * + * Enters low power state, and wakes after specified time + * + * @param dev npm1300 mfd device + * @param time_ms timer value in ms + * @retval 0 If successful + * @retval -EINVAL if time value is too large + * @retval -errno In case of any bus error (see i2c_write_dt()) + */ +int mfd_npm1300_hibernate(const struct device *dev, uint32_t time_ms); + /** @} */ #ifdef __cplusplus From b76aa7cfaf75c18f271d9632cc7955680de090a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 08:38:55 +0200 Subject: [PATCH 1421/2042] net: mqtt-sn: doc: Fix Doxygen documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing Doxygen comments. - Fix typo in Doxygen group name. Signed-off-by: Benjamin Cabé --- include/zephyr/net/mqtt_sn.h | 106 ++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/include/zephyr/net/mqtt_sn.h b/include/zephyr/net/mqtt_sn.h index c84ec56ec460..7700558f1fef 100644 --- a/include/zephyr/net/mqtt_sn.h +++ b/include/zephyr/net/mqtt_sn.h @@ -6,7 +6,7 @@ /** @file mqtt_sn.h * - * @defgroup mqtt_sn_socket MQTT Client library + * @defgroup mqtt_sn_socket MQTT-SN Client library * @ingroup networking * @{ * @brief MQTT-SN Client Implementation @@ -50,11 +50,28 @@ enum mqtt_sn_qos { * MQTT-SN topic types. */ enum mqtt_sn_topic_type { + /** + * Normal topic. + * It allows usage of any valid UTF-8 string as a topic name. + */ MQTT_SN_TOPIC_TYPE_NORMAL, + /** + * Pre-defined topic. + * It allows usage of a two-byte identifier representing a topic name for + * which the corresponding topic name is known in advance by both the client + * and the gateway/server. + */ MQTT_SN_TOPIC_TYPE_PREDEF, + /** + * Short topic. + * It allows usage of a two-byte string as a topic name. + */ MQTT_SN_TOPIC_TYPE_SHORT }; +/** + * MQTT-SN return codes. + */ enum mqtt_sn_return_code { MQTT_SN_CODE_ACCEPTED = 0x00, /**< Accepted */ MQTT_SN_CODE_REJECTED_CONGESTION = 0x01, /**< Rejected: congestion */ @@ -105,9 +122,13 @@ enum mqtt_sn_evt_type { * Event metadata. */ union mqtt_sn_evt_param { + /** Structure holding publish event details */ struct { + /** The payload data associated with the event */ struct mqtt_sn_data data; + /** The type of topic for the event */ enum mqtt_sn_topic_type topic_type; + /** The identifier for the topic of the event */ uint16_t topic_id; } publish; }; @@ -116,7 +137,9 @@ union mqtt_sn_evt_param { * MQTT-SN event structure to be handled by the event callback. */ struct mqtt_sn_evt { + /** Event type */ enum mqtt_sn_evt_type type; + /** Event parameters */ union mqtt_sn_evt_param param; }; @@ -212,49 +235,93 @@ int mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp *udp, struct sockadd * Structure describing an MQTT-SN client. */ struct mqtt_sn_client { - struct mqtt_sn_data client_id; /**< 1-23 character unique client ID */ + /** 1-23 character unique client ID */ + struct mqtt_sn_data client_id; - struct mqtt_sn_data will_topic; /**< Must be initialized before connecting with will=true */ - struct mqtt_sn_data will_msg; /**< Must be initialized before connecting with will=true */ + /** Topic for Will message. + * Must be initialized before connecting with will=true + */ + struct mqtt_sn_data will_topic; + + /** Will message. + * Must be initialized before connecting with will=true + */ + struct mqtt_sn_data will_msg; + + /** Quality of Service for the Will message */ enum mqtt_sn_qos will_qos; + + /** Flag indicating if the will message should be retained by the broker */ bool will_retain; + /** Underlying transport to be used by the client */ struct mqtt_sn_transport *transport; + /** Buffer for outgoing data */ struct net_buf_simple tx; + /** Buffer for incoming data */ struct net_buf_simple rx; + /** Event callback */ mqtt_sn_evt_cb_t evt_cb; + /** Message ID for the next message to be sent */ uint16_t next_msg_id; + + /** List of pending publish messages */ sys_slist_t publish; + + /** List of registered topics */ sys_slist_t topic; + /** Current state of the MQTT-SN client */ int state; + + /** Timestamp of the last ping request */ int64_t last_ping; + + /** Number of retries for failed ping attempts */ uint8_t ping_retries; + /** Delayable work structure for processing MQTT-SN events */ struct k_work_delayable process_work; }; /** * @brief Initialize a client. + * + * @param client The MQTT-SN client to initialize. + * @param client_id The ID to be used by the client. + * @param transport The transport to be used by the client. + * @param evt_cb The event callback function for the client. + * @param tx Pointer to the transmit buffer. + * @param txsz Size of the transmit buffer. + * @param rx Pointer to the receive buffer. + * @param rxsz Size of the receive buffer. + * + * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_client_init(struct mqtt_sn_client *client, const struct mqtt_sn_data *client_id, struct mqtt_sn_transport *transport, mqtt_sn_evt_cb_t evt_cb, void *tx, size_t txsz, void *rx, size_t rxsz); /** - * @brief Deinitialize the client + * @brief Deinitialize the client. * - * This removes all topics and publishes, and also deinits the transport. + * This removes all topics and publishes, and also de-inits the transport. + * + * @param client The MQTT-SN client to deinitialize. */ void mqtt_sn_client_deinit(struct mqtt_sn_client *client); /** * @brief Connect the client. * + * @param client The MQTT-SN client to connect. + * @param will Flag indicating if a Will message should be sent. + * @param clean_session Flag indicating if a clean session should be started. + * * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_connect(struct mqtt_sn_client *client, bool will, bool clean_session); @@ -262,20 +329,29 @@ int mqtt_sn_connect(struct mqtt_sn_client *client, bool will, bool clean_session /** * @brief Disconnect the client. * + * @param client The MQTT-SN client to disconnect. + * * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_disconnect(struct mqtt_sn_client *client); /** - * @brief Set the client into sleep state for the given duration (seconds). + * @brief Set the client into sleep state. * - * @return 0 or a negative error code (errno.h) indicating reason of failure. + * @param client The MQTT-SN client to be put to sleep. + * @param duration Sleep duration (in seconds). + * + * @return 0 on success, negative errno code on failure. */ int mqtt_sn_sleep(struct mqtt_sn_client *client, uint16_t duration); /** * @brief Subscribe to a given topic. * + * @param client The MQTT-SN client that should subscribe. + * @param qos The desired quality of service for the subscription. + * @param topic_name The name of the topic to subscribe to. + * * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_subscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, @@ -283,6 +359,12 @@ int mqtt_sn_subscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, /** * @brief Unsubscribe from a topic. + * + * @param client The MQTT-SN client that should unsubscribe. + * @param qos The quality of service used when subscribing. + * @param topic_name The name of the topic to unsubscribe from. + * + * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_unsubscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, struct mqtt_sn_data *topic_name); @@ -292,6 +374,12 @@ int mqtt_sn_unsubscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, * * If the topic is not yet registered with the gateway, the library takes care of it. * + * @param client The MQTT-SN client that should publish. + * @param qos The desired quality of service for the publish. + * @param topic_name The name of the topic to publish to. + * @param retain Flag indicating if the message should be retained by the broker. + * @param data The data to be published. + * * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, @@ -303,6 +391,8 @@ int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, * Call this function periodically, or if you have good reason to believe there is any data. * If the client's transport struct contains a poll-function, this function is non-blocking. * + * @param client The MQTT-SN client to check for incoming data. + * * @return 0 or a negative error code (errno.h) indicating reason of failure. */ int mqtt_sn_input(struct mqtt_sn_client *client); From 27a695dda06bf137f9989c8c2e03ba3387557c6c Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 18 Jul 2023 11:07:36 +0300 Subject: [PATCH 1422/2042] tests: coap_client: Zero-initialize address structures Even though tests don't use the address, it causes warnings on static analyzers. Signed-off-by: Seppo Takalo --- tests/net/lib/coap_client/src/main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/net/lib/coap_client/src/main.c b/tests/net/lib/coap_client/src/main.c index 9e66015dbee0..a3862852c212 100644 --- a/tests/net/lib/coap_client/src/main.c +++ b/tests/net/lib/coap_client/src/main.c @@ -188,7 +188,7 @@ ZTEST_SUITE(coap_client, NULL, suite_setup, test_setup, NULL, NULL); ZTEST(coap_client, test_get_request) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -217,7 +217,7 @@ ZTEST(coap_client, test_get_request) ZTEST(coap_client, test_get_no_path) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -242,7 +242,7 @@ ZTEST(coap_client, test_get_no_path) ZTEST(coap_client, test_send_large_data) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -271,7 +271,7 @@ ZTEST(coap_client, test_send_large_data) ZTEST(coap_client, test_no_response) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -298,7 +298,7 @@ ZTEST(coap_client, test_no_response) ZTEST(coap_client, test_separate_response) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -332,7 +332,7 @@ ZTEST(coap_client, test_separate_response) ZTEST(coap_client, test_multiple_requests) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, @@ -368,7 +368,7 @@ ZTEST(coap_client, test_multiple_requests) ZTEST(coap_client, test_unmatching_tokens) { int ret = 0; - struct sockaddr address; + struct sockaddr address = {0}; struct coap_client_request client_request = { .method = COAP_METHOD_GET, .confirmable = true, From 6719caf05e0fc43166a959fdefa5375789dc4320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 10:24:34 +0200 Subject: [PATCH 1423/2042] drivers: hwinfo: doc: Reset causes documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing Doxygen for reset cause flags. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/hwinfo.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/include/zephyr/drivers/hwinfo.h b/include/zephyr/drivers/hwinfo.h index 18132336994d..7e9b7201e38d 100644 --- a/include/zephyr/drivers/hwinfo.h +++ b/include/zephyr/drivers/hwinfo.h @@ -30,21 +30,44 @@ extern "C" { #endif +/** + * @name Reset cause flags + * @anchor reset_cause + * @{ + */ +/** External pin */ #define RESET_PIN BIT(0) +/** Software reset */ #define RESET_SOFTWARE BIT(1) +/** Brownout (drop in voltage) */ #define RESET_BROWNOUT BIT(2) +/** Power-on reset (POR) */ #define RESET_POR BIT(3) +/** Watchdog timer expiration */ #define RESET_WATCHDOG BIT(4) +/** Debug event */ #define RESET_DEBUG BIT(5) +/** Security violation */ #define RESET_SECURITY BIT(6) +/** Waking up from low power mode */ #define RESET_LOW_POWER_WAKE BIT(7) +/** CPU lock-up detected */ #define RESET_CPU_LOCKUP BIT(8) +/** Parity error */ #define RESET_PARITY BIT(9) +/** PLL error */ #define RESET_PLL BIT(10) +/** Clock error */ #define RESET_CLOCK BIT(11) +/** Hardware reset */ #define RESET_HARDWARE BIT(12) +/** User reset */ #define RESET_USER BIT(13) +/** Temperature reset */ #define RESET_TEMPERATURE BIT(14) +/** + * @} + */ /** * @brief Copy the device id to a buffer @@ -73,7 +96,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length); /** * @brief Retrieve cause of device reset. * - * @param cause OR'd `reset_cause` flags + * @param cause OR'd @ref reset_cause "reset cause" flags * * This routine retrieves the flags that indicate why the device was reset. * @@ -110,7 +133,7 @@ int z_impl_hwinfo_clear_reset_cause(void); /** * @brief Get supported reset cause flags * - * @param supported OR'd `reset_cause` flags that are supported + * @param supported OR'd @ref reset_cause "reset cause" flags that are supported * * Retrieves all `reset_cause` flags that are supported by this device. * From 2e09dc4eb086f9da0bab124656c217b47d3a0455 Mon Sep 17 00:00:00 2001 From: Ali Hozhabri Date: Tue, 18 Jul 2023 14:31:59 +0200 Subject: [PATCH 1424/2042] boards: arm: nucleo_l476rg: add storage partition Add fixed-partition to be used as storage partition with the size of 32KB. Signed-off-by: Ali Hozhabri --- boards/arm/nucleo_l476rg/nucleo_l476rg.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts index f2ae533fa73d..7d9ac593d77f 100644 --- a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts +++ b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts @@ -179,3 +179,17 @@ &vbat { status = "okay"; }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 32KB of storage at the end of 1024KB flash */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 DT_SIZE_K(32)>; + }; + }; +}; From 5862b38e999188386002357a3a646b9da75ef281 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 13 Jul 2023 10:00:25 -0500 Subject: [PATCH 1425/2042] drivers: input: gt911: enable fallback to alternate address GT911 IC uses the INT pin to select the correct I2C address during reset. However, some boards may not route this pin (or may only support receiving inputs on it). This results in the I2C address selected by the GT911 IC being arbitrary based on the state of the (floating) INT pin. To resolve this, introduce an `alt-addr` property for this device. When set, the INT pin will not be pulled low. Instead, the I2C address will be probed at runtime, starting with the devicetree address and falling back to `alt-addr`. Signed-off-by: Daniel DeGrasse --- .../boards/mimxrt595_evk_cm33.overlay | 3 +- drivers/input/input_gt911.c | 124 ++++++++++++++---- dts/bindings/input/goodix,gt911.yaml | 6 + 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay index 40a3b02036fa..e8658bdc42b6 100644 --- a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay +++ b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.overlay @@ -12,7 +12,8 @@ rx-buffer-config = <1 7 11 1024>; }; -/* GT911 IRQ GPIO is active low on this board */ +/* GT911 IRQ GPIO is active low on this board, and needs probing mode */ &touch_controller { irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; + alt-addr = <0x14>; }; diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index e2fd67188ecd..a13586caf85f 100644 --- a/drivers/input/input_gt911.c +++ b/drivers/input/input_gt911.c @@ -31,6 +31,7 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); #define GT911_CONFIG_REG __bswap_16(0x8047U) #define REG_CONFIG_VERSION GT911_CONFIG_REG #define REG_CONFIG_SIZE (186U) +#define GT911_PRODUCT_ID (0x00313139U) /** GT911 configuration (DT). */ struct gt911_config { @@ -39,6 +40,8 @@ struct gt911_config { struct gpio_dt_spec rst_gpio; /** Interrupt GPIO information. */ struct gpio_dt_spec int_gpio; + /* Alternate fallback I2C address */ + uint8_t alt_addr; }; /** GT911 data. */ @@ -47,6 +50,8 @@ struct gt911_data { const struct device *dev; /** Work queue (for deferred read). */ struct k_work work; + /** Actual device I2C address */ + uint8_t actual_address; #ifdef CONFIG_INPUT_GT911_INTERRUPT /** Interrupt GPIO callback. */ struct gpio_callback int_gpio_cb; @@ -68,10 +73,33 @@ struct gt911_point_reg_t { uint8_t reserved; /*!< Reserved. */ }; -static int gt911_process(const struct device *dev) +/* + * Device-specific wrappers around i2c_write_dt and i2c_write_read_dt. + * These wrappers handle the case where the GT911 did not accept the requested + * I2C address, and the alternate I2C address is used. + */ +static int gt911_i2c_write(const struct device *dev, + const uint8_t *buf, uint32_t num_bytes) +{ + const struct gt911_config *config = dev->config; + struct gt911_data *data = dev->data; + + return i2c_write(config->bus.bus, buf, num_bytes, data->actual_address); +} + +static int gt911_i2c_write_read(const struct device *dev, + const void *write_buf, size_t num_write, + void *read_buf, size_t num_read) { const struct gt911_config *config = dev->config; + struct gt911_data *data = dev->data; + return i2c_write_read(config->bus.bus, data->actual_address, write_buf, + num_write, read_buf, num_read); +} + +static int gt911_process(const struct device *dev) +{ int r; uint16_t reg_addr; uint8_t status; @@ -82,8 +110,8 @@ static int gt911_process(const struct device *dev) /* obtain number of touch points (NOTE: multi-touch ignored) */ reg_addr = REG_STATUS; - r = i2c_write_read_dt(&config->bus, ®_addr, sizeof(reg_addr), - &status, sizeof(status)); + r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), + &status, sizeof(status)); if (r < 0) { return r; } @@ -100,7 +128,7 @@ static int gt911_process(const struct device *dev) /* need to clear the status */ uint8_t clear_buffer[3] = {(uint8_t)REG_STATUS, (uint8_t)(REG_STATUS >> 8), 0}; - r = i2c_write_dt(&config->bus, clear_buffer, sizeof(clear_buffer)); + r = gt911_i2c_write(dev, clear_buffer, sizeof(clear_buffer)); if (r < 0) { return r; } @@ -109,8 +137,8 @@ static int gt911_process(const struct device *dev) * REG_P1_XH, REG_P1_XL, REG_P1_YH, REG_P1_YL. */ reg_addr = REG_FIRST_POINT; - r = i2c_write_read_dt(&config->bus, ®_addr, sizeof(reg_addr), - &pointRegs, sizeof(pointRegs)); + r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), + &pointRegs, sizeof(pointRegs)); if (r < 0) { return r; } @@ -180,28 +208,47 @@ static int gt911_init(const struct device *dev) const struct gt911_config *config = dev->config; struct gt911_data *data = dev->data; - if (!device_is_ready(config->bus.bus)) { + if (!i2c_is_ready_dt(&config->bus)) { LOG_ERR("I2C controller device not ready"); return -ENODEV; } data->dev = dev; + data->actual_address = config->bus.addr; k_work_init(&data->work, gt911_work_handler); int r; + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("Interrupt GPIO controller device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&config->rst_gpio)) { + LOG_ERR("Reset GPIO controller device not ready"); + return -ENODEV; + } + r = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_INACTIVE); if (r < 0) { LOG_ERR("Could not configure reset GPIO pin"); return r; } - /* we need to configure the int-pin to 0, in order toenter the AddressModel0 */ - r = gpio_pin_configure_dt(&config->int_gpio, GPIO_OUTPUT_INACTIVE); - if (r < 0) { - LOG_ERR("Could not configure int GPIO pin"); - return r; + if (config->alt_addr == 0x0) { + /* + * We need to configure the int-pin to 0, in order to enter the + * AddressMode0. Keeping the INT pin low during the reset sequence + * should result in the device selecting an I2C address of 0x5D. + * Note we skip this step if an alternate I2C address is set, + * and fall through to probing for the actual address. + */ + r = gpio_pin_configure_dt(&config->int_gpio, GPIO_OUTPUT_INACTIVE); + if (r < 0) { + LOG_ERR("Could not configure int GPIO pin"); + return r; + } } /* Delay at least 10 ms after power on before we configure gt911 */ k_sleep(K_MSEC(20)); @@ -210,15 +257,10 @@ static int gt911_init(const struct device *dev) /* hold down at least 1us, 1ms here */ k_sleep(K_MSEC(1)); gpio_pin_set_dt(&config->rst_gpio, 1); - /* hold down at least 5ms, before set the int pin low */ + /* hold down at least 5ms. This is the point the INT pin must be low. */ k_sleep(K_MSEC(5)); - gpio_pin_set_dt(&config->int_gpio, 0); /* hold down 50ms to make sure the address available */ k_sleep(K_MSEC(50)); - if (!device_is_ready(config->int_gpio.port)) { - LOG_ERR("Interrupt GPIO controller device not ready"); - return -ENODEV; - } r = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); if (r < 0) { @@ -244,13 +286,36 @@ static int gt911_init(const struct device *dev) uint32_t reg_id = 0; uint16_t reg_addr = DEVICE_ID; - r = i2c_write_read_dt(&config->bus, ®_addr, sizeof(reg_addr), - ®_id, sizeof(reg_id)); + if (config->alt_addr != 0x0) { + /* + * The level of the INT pin during reset is used by the GT911 + * to select the I2C address mode. If an alternate I2C address + * is set, we should probe the GT911 to determine which address + * it actually selected. This is useful for boards that do not + * route the INT pin, or can only read it as an input (IE when + * using a level shifter). + */ + r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), + ®_id, sizeof(reg_id)); + if (r < 0) { + /* Try alternate address */ + data->actual_address = config->alt_addr; + r = gt911_i2c_write_read(dev, ®_addr, + sizeof(reg_addr), + ®_id, sizeof(reg_id)); + LOG_INF("Device did not accept I2C address, " + "updated to 0x%02X", data->actual_address); + } + } else { + r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), + ®_id, sizeof(reg_id)); + } if (r < 0) { + LOG_ERR("Device did not respond to I2C request"); return r; } - if (reg_id != 0x00313139U) { - LOG_ERR("The Devide ID is not correct"); + if (reg_id != GT911_PRODUCT_ID) { + LOG_ERR("The Device ID is not correct"); return -ENODEV; } @@ -260,8 +325,8 @@ static int gt911_init(const struct device *dev) }; reg_addr = GT911_CONFIG_REG; - r = i2c_write_read_dt(&config->bus, ®_addr, sizeof(reg_addr), - gt911Config + 2, REG_CONFIG_SIZE); + r = gt911_i2c_write_read(dev, ®_addr, sizeof(reg_addr), + gt911Config + 2, REG_CONFIG_SIZE); if (r < 0) { return r; } @@ -272,7 +337,7 @@ static int gt911_init(const struct device *dev) gt911Config[REG_CONFIG_SIZE] = gt911_get_firmware_checksum(gt911Config + 2); gt911Config[REG_CONFIG_SIZE + 1] = 1; - r = i2c_write_dt(&config->bus, gt911Config, sizeof(gt911Config)); + r = gt911_i2c_write(dev, gt911Config, sizeof(gt911Config)); if (r < 0) { return r; } @@ -287,15 +352,16 @@ static int gt911_init(const struct device *dev) return 0; } -#define GT911_INIT(index) \ +#define GT911_INIT(index) \ static const struct gt911_config gt911_config_##index = { \ .bus = I2C_DT_SPEC_INST_GET(index), \ - .rst_gpio = GPIO_DT_SPEC_INST_GET(index, reset_gpios), \ - .int_gpio = GPIO_DT_SPEC_INST_GET(index, irq_gpios) \ + .rst_gpio = GPIO_DT_SPEC_INST_GET(index, reset_gpios), \ + .int_gpio = GPIO_DT_SPEC_INST_GET(index, irq_gpios), \ + .alt_addr = DT_INST_PROP_OR(index, alt_addr, 0), \ }; \ static struct gt911_data gt911_data_##index; \ DEVICE_DT_INST_DEFINE(index, gt911_init, NULL, \ - >911_data_##index, >911_config_##index, \ + >911_data_##index, >911_config_##index, \ POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ NULL); diff --git a/dts/bindings/input/goodix,gt911.yaml b/dts/bindings/input/goodix,gt911.yaml index 1222032f7255..112d2e425d8f 100644 --- a/dts/bindings/input/goodix,gt911.yaml +++ b/dts/bindings/input/goodix,gt911.yaml @@ -12,3 +12,9 @@ properties: type: phandle-array reset-gpios: type: phandle-array + alt-addr: + type: int + description: + Alternate I2C address for this device. When provided, the driver will + use probing mode to determine the I2C address rather than setting the + INT pin low to force a specific address From 4648917be4876adb23c31bf02452f2194e7815d4 Mon Sep 17 00:00:00 2001 From: Valentin Korenblit Date: Thu, 11 May 2023 13:44:31 +0200 Subject: [PATCH 1426/2042] drivers: gicv3: GICR_TYPER_LAST mask width is 1 bit Fix compiler warning: bitwise comparison always evaluates to false Signed-off-by: Valentin Korenblit --- drivers/interrupt_controller/intc_gicv3_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/interrupt_controller/intc_gicv3_priv.h b/drivers/interrupt_controller/intc_gicv3_priv.h index e0347ed35768..6003235dcab5 100644 --- a/drivers/interrupt_controller/intc_gicv3_priv.h +++ b/drivers/interrupt_controller/intc_gicv3_priv.h @@ -67,7 +67,7 @@ #define GICR_TYPER_AFFINITY_VALUE_MASK 0xFFFFFFFFUL #define GICR_TYPER_AFFINITY_VALUE_GET(_val) MASK_GET(_val, GICR_TYPER_AFFINITY_VALUE) #define GICR_TYPER_LAST_SHIFT 4 -#define GICR_TYPER_LAST_MASK 0x10UL +#define GICR_TYPER_LAST_MASK 0x1UL #define GICR_TYPER_LAST_GET(_val) MASK_GET(_val, GICR_TYPER_LAST) #define GICR_TYPER_PROCESSOR_NUMBER_SHIFT 8 #define GICR_TYPER_PROCESSOR_NUMBER_MASK 0xFFFFUL From 80d46c5f7ebfc379adf5be2edab0c1f8ef813ddf Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Fri, 7 Jul 2023 20:53:03 +0530 Subject: [PATCH 1427/2042] drivers: eeprom: mchp: Bug fix Updated the DT macro to read EEPROM size property. Signed-off-by: Manimaran A --- drivers/eeprom/eeprom_mchp_xec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/eeprom/eeprom_mchp_xec.c b/drivers/eeprom/eeprom_mchp_xec.c index 226f0aabd1e9..11f0712a8633 100644 --- a/drivers/eeprom/eeprom_mchp_xec.c +++ b/drivers/eeprom/eeprom_mchp_xec.c @@ -325,7 +325,7 @@ PINCTRL_DT_INST_DEFINE(0); static const struct eeprom_xec_config eeprom_config = { .regs = (struct eeprom_xec_regs * const)DT_INST_REG_ADDR(0), - .size = DT_INST_REG_SIZE(0), + .size = DT_INST_PROP(0, size), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; From 6168f47ac3b59e0daa80c673bf97f2611691b976 Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Sun, 9 Jul 2023 06:50:13 +0200 Subject: [PATCH 1428/2042] arch/posix: put fuzzing kconfigs into submenu Without fuzzing enabled they don't do anything and should not be selectable. Signed-off-by: Michael Zimmermann --- arch/posix/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/posix/Kconfig b/arch/posix/Kconfig index 6db2a25d90d9..c3841e9795a8 100644 --- a/arch/posix/Kconfig +++ b/arch/posix/Kconfig @@ -22,7 +22,7 @@ config ARCH_POSIX_RECOMMENDED_STACK_SIZE thread stack, the real stack is the native underlying pthread stack. Therefore the allocated stack can be limited to this size) -config ARCH_POSIX_LIBFUZZER +menuconfig ARCH_POSIX_LIBFUZZER bool "Build fuzz test target" help Build the posix app as a LLVM libfuzzer target. Requires @@ -35,6 +35,8 @@ config ARCH_POSIX_LIBFUZZER sample and https://llvm.org/docs/LibFuzzer.html for more information. +if ARCH_POSIX_LIBFUZZER + config ARCH_POSIX_FUZZ_IRQ int "OS interrupt via which to deliver fuzz cases" default 3 @@ -53,4 +55,6 @@ config ARCH_POSIX_FUZZ_TICKS following a unit-test style case, so the default is short to prevent interaction with regular timer workloads. +endif # CONFIG_ARCH_POSIX_LIBFUZZER + endmenu From 8de34fef190513cc7e649dc83d2f6a1ff9a73a1a Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Tue, 11 Jul 2023 14:10:06 +0200 Subject: [PATCH 1429/2042] arch/posix: use size_t for posix_fuzz_sz That's the type of the original argument and we should use it internally as well to prevent truncating the value. Signed-off-by: Michael Zimmermann --- boards/posix/native_posix/main.c | 3 ++- samples/subsys/debug/fuzz/src/main.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/boards/posix/native_posix/main.c b/boards/posix/native_posix/main.c index d1b4934c5456..86c7937b56c5 100644 --- a/boards/posix/native_posix/main.c +++ b/boards/posix/native_posix/main.c @@ -127,7 +127,8 @@ int main(int argc, char *argv[]) * "long enough" to handle the event and reach a quiescent state * again) */ -uint8_t *posix_fuzz_buf, posix_fuzz_sz; +uint8_t *posix_fuzz_buf; +size_t posix_fuzz_sz; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { diff --git a/samples/subsys/debug/fuzz/src/main.c b/samples/subsys/debug/fuzz/src/main.c index cf7600ec99a9..3937e874e863 100644 --- a/samples/subsys/debug/fuzz/src/main.c +++ b/samples/subsys/debug/fuzz/src/main.c @@ -49,7 +49,8 @@ GEN_CHECK(5, 6) GEN_CHECK(6, 0) /* Fuzz input received from LLVM via "interrupt" */ -extern uint8_t *posix_fuzz_buf, posix_fuzz_sz; +extern uint8_t *posix_fuzz_buf; +extern size_t posix_fuzz_sz; K_SEM_DEFINE(fuzz_sem, 0, K_SEM_MAX_LIMIT); From 0da94225b0879f63f432a55780345f2946fc042a Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Tue, 11 Jul 2023 14:12:18 +0200 Subject: [PATCH 1430/2042] arch/posix: make posix_fuzz_buf const The original buffer is const as well and we're not allowed to modify it. Signed-off-by: Michael Zimmermann --- boards/posix/native_posix/main.c | 4 ++-- samples/subsys/debug/fuzz/src/main.c | 32 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/boards/posix/native_posix/main.c b/boards/posix/native_posix/main.c index 86c7937b56c5..c90530533b37 100644 --- a/boards/posix/native_posix/main.c +++ b/boards/posix/native_posix/main.c @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) * "long enough" to handle the event and reach a quiescent state * again) */ -uint8_t *posix_fuzz_buf; +const uint8_t *posix_fuzz_buf; size_t posix_fuzz_sz; int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) @@ -142,7 +142,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) /* Provide the fuzz data to Zephyr as an interrupt, with * "DMA-like" data placed into posix_fuzz_buf/sz */ - posix_fuzz_buf = (void *)data; + posix_fuzz_buf = data; posix_fuzz_sz = sz; hw_irq_ctrl_set_irq(CONFIG_ARCH_POSIX_FUZZ_IRQ); diff --git a/samples/subsys/debug/fuzz/src/main.c b/samples/subsys/debug/fuzz/src/main.c index 3937e874e863..ae486e938947 100644 --- a/samples/subsys/debug/fuzz/src/main.c +++ b/samples/subsys/debug/fuzz/src/main.c @@ -23,21 +23,21 @@ bool found[ARRAY_SIZE(key)]; #define LASTKEY (ARRAY_SIZE(key) - 1) -#define GEN_CHECK(cur, nxt) \ - void check##nxt(uint8_t *data, size_t sz); \ - void __attribute__((noinline)) check##cur(uint8_t *data, size_t sz) \ - { \ - if (cur < sz && data[cur] == key[cur]) { \ - if (!found[cur]) { \ - printk("#\n# Found key %d\n#\n", cur); \ - found[cur] = true; \ - } \ - if (cur == LASTKEY) { \ - *global_null_ptr = 0; /* boom! */ \ - } else { \ - check##nxt(data, sz); \ - } \ - } \ +#define GEN_CHECK(cur, nxt) \ + void check##nxt(const uint8_t *data, size_t sz); \ + void __attribute__((noinline)) check##cur(const uint8_t *data, size_t sz) \ + { \ + if (cur < sz && data[cur] == key[cur]) { \ + if (!found[cur]) { \ + printk("#\n# Found key %d\n#\n", cur); \ + found[cur] = true; \ + } \ + if (cur == LASTKEY) { \ + *global_null_ptr = 0; /* boom! */ \ + } else { \ + check##nxt(data, sz); \ + } \ + } \ } GEN_CHECK(0, 1) @@ -49,7 +49,7 @@ GEN_CHECK(5, 6) GEN_CHECK(6, 0) /* Fuzz input received from LLVM via "interrupt" */ -extern uint8_t *posix_fuzz_buf; +extern const uint8_t *posix_fuzz_buf; extern size_t posix_fuzz_sz; K_SEM_DEFINE(fuzz_sem, 0, K_SEM_MAX_LIMIT); From f937c031d82b9ed2b76a2477d62444a767323ac9 Mon Sep 17 00:00:00 2001 From: Michael Zimmermann Date: Tue, 11 Jul 2023 14:50:15 +0200 Subject: [PATCH 1431/2042] arch/posix: move fuzz entry doc to the right place It should document the entry point function, not the DMA-like variable. Signed-off-by: Michael Zimmermann --- boards/posix/native_posix/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boards/posix/native_posix/main.c b/boards/posix/native_posix/main.c index c90530533b37..5e603ac6efdf 100644 --- a/boards/posix/native_posix/main.c +++ b/boards/posix/native_posix/main.c @@ -120,6 +120,9 @@ int main(int argc, char *argv[]) #else /* CONFIG_ARCH_POSIX_LIBFUZZER */ +const uint8_t *posix_fuzz_buf; +size_t posix_fuzz_sz; + /** * Entry point for fuzzing (when enabled). Works by placing the data * into two known symbols, triggering an app-visible interrupt, and @@ -127,9 +130,6 @@ int main(int argc, char *argv[]) * "long enough" to handle the event and reach a quiescent state * again) */ -const uint8_t *posix_fuzz_buf; -size_t posix_fuzz_sz; - int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) { static bool posix_initialized; From b021dece987d691342636dad836d6c9611d510e1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 17 Jul 2023 14:45:26 -0700 Subject: [PATCH 1432/2042] scripts/checkpatch: Check for patches adding #defines for libc APIs All code in the Zephyr core must use only the Zephyr C library API according to rules A.4 and A.5. Such code is not permitted to request API extensions from the C library via any of the API request mechanisms. This addition to checkpatch.pl verifies that patches don't #define any of these: __STRICT_ANSI__ _POSIX_SOURCE _POSIX_C_SOURCE _XOPEN_SOURCE _ISOC99_SOURCE _ISOC11_SOURCE _ATFILE_SOURCE _GNU_SOURCE _BSD_SOURCE _SVID_SOURCE _DEFAULT_SOURCE Reference: #49922 Signed-off-by: Keith Packard --- scripts/checkpatch.pl | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 6e55520a2afe..57ca4a17749b 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -592,6 +592,20 @@ sub hash_show_words { ["__ATTR", 2], ); +our $api_defines = qr{(?x: + _ATFILE_SOURCE| + _BSD_SOURCE| + _DEFAULT_SOURCE + _GNU_SOURCE| + _ISOC11_SOURCE| + _ISOC99_SOURCE| + _POSIX_C_SOURCE| + _POSIX_SOURCE| + _SVID_SOURCE| + _XOPEN_SOURCE| + _XOPEN_SOURCE_EXTENDED| +)}; + my $word_pattern = '\b[A-Z]?[a-z]{2,}\b'; #Create a search pattern for all these functions to speed up a loop below @@ -6527,6 +6541,13 @@ sub process { } } +# check for feature test macros that request C library API extensions, violating rules A.4 and A.5 + + if ($line =~ /#\s*define\s+$api_defines/) { + ERROR("API_DEFINE", + "do not specify a non-Zephyr API for libc\n" . "$here$rawline\n"); + } + # check for IS_ENABLED() without CONFIG_ ($rawline for comments too) if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^CONFIG_/) { WARN("IS_ENABLED_CONFIG", From 2037362e1665ce901b5ff085d3fa6bcaf2ac426c Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 7 Jul 2023 10:18:23 +0800 Subject: [PATCH 1433/2042] checkpatch: exclude POSIX headers from typedef rule The `NEW_TYPEDEFS` rule consistently generates false positives when implementing POSIX standard APIs. It makes sense to disable this check for the POSIX haders rather than requiring merge superpowers constantly. That way, we can merge as per usual after sufficient approvals rather than waiting for someone with merge superpowers to override / manually merge. Signed-off-by: Yong Cong Sin --- scripts/checkpatch.pl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 57ca4a17749b..b34c2ad31d22 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -4164,13 +4164,15 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. - if ($line =~ /\btypedef\s/ && - $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && - $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && - $line !~ /\b$typeTypedefs\b/ && - $line !~ /\b__bitwise\b/) { - WARN("NEW_TYPEDEFS", - "do not add new typedefs\n" . $herecurr); + if ($realfile =~ /\/include\/zephyr\/posix\/*.h/) { + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise\b/) { + WARN("NEW_TYPEDEFS", + "do not add new typedefs\n" . $herecurr); + } } # * goes on variable not on type From e3c49b9573519ee0752941593546fc29b8297893 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:09:25 +0800 Subject: [PATCH 1434/2042] posix: signal: add initial header Initial header for the signal APIs. APIs to be implemented in later commit. Signed-off-by: Yong Cong Sin --- include/zephyr/posix/signal.h | 44 +++++++++++++++++++++++ lib/posix/Kconfig | 1 + lib/posix/Kconfig.signal | 19 ++++++++++ tests/posix/headers/src/signal_h.c | 58 +++++++++++++++--------------- 4 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 lib/posix/Kconfig.signal diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 88b137e7547a..eac4d1d64176 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -12,6 +12,50 @@ extern "C" { #endif +#ifdef CONFIG_POSIX_SIGNAL +#define SIGHUP 1 /**< Hangup */ +#define SIGINT 2 /**< Interrupt */ +#define SIGQUIT 3 /**< Quit */ +#define SIGILL 4 /**< Illegal instruction */ +#define SIGTRAP 5 /**< Trace/breakpoint trap */ +#define SIGABRT 6 /**< Aborted */ +#define SIGBUS 7 /**< Bus error */ +#define SIGFPE 8 /**< Arithmetic exception */ +#define SIGKILL 9 /**< Killed */ +#define SIGUSR1 10 /**< User-defined signal 1 */ +#define SIGSEGV 11 /**< Invalid memory reference */ +#define SIGUSR2 12 /**< User-defined signal 2 */ +#define SIGPIPE 13 /**< Broken pipe */ +#define SIGALRM 14 /**< Alarm clock */ +#define SIGTERM 15 /**< Terminated */ +/* 16 not used */ +#define SIGCHLD 17 /**< Child status changed */ +#define SIGCONT 18 /**< Continued */ +#define SIGSTOP 19 /**< Stop executing */ +#define SIGTSTP 20 /**< Stopped */ +#define SIGTTIN 21 /**< Stopped (read) */ +#define SIGTTOU 22 /**< Stopped (write) */ +#define SIGURG 23 /**< Urgent I/O condition */ +#define SIGXCPU 24 /**< CPU time limit exceeded */ +#define SIGXFSZ 25 /**< File size limit exceeded */ +#define SIGVTALRM 26 /**< Virtual timer expired */ +#define SIGPROF 27 /**< Profiling timer expired */ +/* 28 not used */ +#define SIGPOLL 29 /**< Pollable event occurred */ +/* 30 not used */ +#define SIGSYS 31 /**< Bad system call */ + +#define SIGRTMIN 32 +#define SIGRTMAX (SIGRTMIN + CONFIG_POSIX_RTSIG_MAX) +#define _NSIG (SIGRTMAX + 1) + +BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= 0); + +typedef struct { + unsigned long sig[DIV_ROUND_UP(_NSIG, BITS_PER_LONG)]; +} sigset_t; +#endif /* CONFIG_POSIX_SIGNAL */ + #ifndef SIGEV_NONE #define SIGEV_NONE 1 #endif diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 15f019d4a30e..59414797328c 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -48,6 +48,7 @@ source "lib/posix/Kconfig.mqueue" source "lib/posix/Kconfig.mutex" source "lib/posix/Kconfig.pthread" 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" diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal new file mode 100644 index 000000000000..3ff5b75e8e89 --- /dev/null +++ b/lib/posix/Kconfig.signal @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_SIGNAL + bool "Support for POSIX signal APIs" + default y if POSIX_API + help + 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)] + +endif diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 9b8711e530e0..791735d966e5 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -25,7 +25,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_equal(-1, SIG_IGN); */ /* not implemented */ /* zassert_not_equal((sig_atomic_t)-1, (sig_atomic_t)0); */ /* not implemented */ - /* zassert_not_equal((sigset_t)-1, (sigset_t)0); */ /* not implemented */ /* zassert_not_equal((pid_t)-1, (pid_t)0); */ /* not implemented */ zassert_not_equal(-1, offsetof(struct sigevent, sigev_notify)); @@ -42,35 +41,8 @@ ZTEST(posix_headers, test_signal_h) zassert_not_equal(-1, offsetof(union sigval, sival_ptr)); /* zassert_not_equal(-1, RTSIG_MAX); */ /* not implemented */ - /* zassert_true(SIGRTMIN >= 0); */ /* not implemented */ - /* zassert_true(SIGRTMAX >= SIGRTMIN); */ /* not implemented */ /* zassert_true(SIGRTMAX - SIGRTMIN >= RTSIG_MAX); */ /* not implemented */ - /* zassert_not_equal(-1, SIGABRT); */ /* not implemented */ - /* zassert_not_equal(-1, SIGALRM); */ /* not implemented */ - /* zassert_not_equal(-1, SIGBUS); */ /* not implemented */ - /* zassert_not_equal(-1, SIGCHLD); */ /* not implemented */ - /* zassert_not_equal(-1, SIGCONT); */ /* not implemented */ - /* zassert_not_equal(-1, SIGFPE); */ /* not implemented */ - /* zassert_not_equal(-1, SIGHUP); */ /* not implemented */ - /* zassert_not_equal(-1, SIGILL); */ /* not implemented */ - /* zassert_not_equal(-1, SIGINT); */ /* not implemented */ - /* zassert_not_equal(-1, SIGKILL); */ /* not implemented */ - /* zassert_not_equal(-1, SIGPIPE); */ /* not implemented */ - /* zassert_not_equal(-1, SIGQUIT); */ /* not implemented */ - /* zassert_not_equal(-1, SIGSEGV); */ /* not implemented */ - /* zassert_not_equal(-1, SIGSTOP); */ /* not implemented */ - /* zassert_not_equal(-1, SIGTERM); */ /* not implemented */ - /* zassert_not_equal(-1, SIGTSTP); */ /* not implemented */ - /* zassert_not_equal(-1, SIGTTIN); */ /* not implemented */ - /* zassert_not_equal(-1, SIGTTOU); */ /* not implemented */ - /* zassert_not_equal(-1, SIGUSR1); */ /* not implemented */ - /* zassert_not_equal(-1, SIGUSR2); */ /* not implemented */ - /* zassert_not_equal(-1, SIGTRAP); */ /* not implemented */ - /* zassert_not_equal(-1, SIGURG); */ /* not implemented */ - /* zassert_not_equal(-1, SIGXCPU); */ /* not implemented */ - /* zassert_not_equal(-1, SIGXFSZ); */ /* not implemented */ - /* zassert_not_equal(-1, SIG_BLOCK); */ /* not implemented */ /* zassert_not_equal(-1, SIG_UNBLOCK); */ /* not implemented */ /* zassert_not_equal(-1, SIG_SETMASK); */ /* not implemented */ @@ -158,6 +130,36 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_equal(-1, SI_ASYNCIO); */ /* not implemented */ /* zassert_not_equal(-1, SI_MESGQ); */ /* not implemented */ +#ifdef CONFIG_POSIX_SIGNAL + zassert_true(SIGRTMIN >= 0); + zassert_true(SIGRTMAX >= SIGRTMIN); + zassert_not_equal(-1, SIGABRT); + zassert_not_equal(-1, SIGALRM); + zassert_not_equal(-1, SIGBUS); + zassert_not_equal(-1, SIGCHLD); + zassert_not_equal(-1, SIGCONT); + zassert_not_equal(-1, SIGFPE); + zassert_not_equal(-1, SIGHUP); + zassert_not_equal(-1, SIGILL); + zassert_not_equal(-1, SIGINT); + zassert_not_equal(-1, SIGKILL); + zassert_not_equal(-1, SIGPIPE); + zassert_not_equal(-1, SIGQUIT); + zassert_not_equal(-1, SIGSEGV); + zassert_not_equal(-1, SIGSTOP); + zassert_not_equal(-1, SIGTERM); + zassert_not_equal(-1, SIGTSTP); + zassert_not_equal(-1, SIGTTIN); + zassert_not_equal(-1, SIGTTOU); + zassert_not_equal(-1, SIGUSR1); + zassert_not_equal(-1, SIGUSR2); + zassert_not_equal(-1, SIGTRAP); + zassert_not_equal(-1, SIGURG); + zassert_not_equal(-1, SIGXCPU); + zassert_not_equal(-1, SIGXFSZ); + zassert_not_equal(((sigset_t){.sig[0] = 0}).sig[0], ((sigset_t){.sig[0] = -1}).sig[0]); +#endif /* CONFIG_POSIX_SIGNAL */ + if (IS_ENABLED(CONFIG_POSIX_API)) { /* zassert_not_null(kill); */ /* not implemented */ /* zassert_not_null(killpg); */ /* not implemented */ From 6910eb4a9b7fb801e69b72409ffb15c9096b27f3 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:28:34 +0800 Subject: [PATCH 1435/2042] posix: signal: implement sigemptyset Implementation and ztest for sigemptyset. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/signal.h | 2 ++ lib/posix/CMakeLists.txt | 1 + lib/posix/signal.c | 12 ++++++++++++ tests/posix/common/CMakeLists.txt | 2 ++ tests/posix/common/src/signal.c | 25 +++++++++++++++++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 7 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 lib/posix/signal.c create mode 100644 tests/posix/common/src/signal.c diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 6028ab508d71..fbcdc4f4779e 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -378,7 +378,7 @@ required for error and event handling. sigaction(), igaddset(), sigdelset(), - sigemptyset(), + sigemptyset(),yes sigfillset(), igismember(), signal(), diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index eac4d1d64176..6c63ca9da078 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -54,6 +54,8 @@ BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= 0); typedef struct { unsigned long sig[DIV_ROUND_UP(_NSIG, BITS_PER_LONG)]; } sigset_t; + +int sigemptyset(sigset_t *set); #endif /* CONFIG_POSIX_SIGNAL */ #ifndef SIGEV_NONE diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index d0c1c88910f5..ce5e809d04ed 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -29,6 +29,7 @@ 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) zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC barrier.c) diff --git a/lib/posix/signal.c b/lib/posix/signal.c new file mode 100644 index 000000000000..ca0277d36f28 --- /dev/null +++ b/lib/posix/signal.c @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +int sigemptyset(sigset_t *set) +{ + *set = (sigset_t){0}; + return 0; +} diff --git a/tests/posix/common/CMakeLists.txt b/tests/posix/common/CMakeLists.txt index e3ba5d8eaa6a..1a4aefa91631 100644 --- a/tests/posix/common/CMakeLists.txt +++ b/tests/posix/common/CMakeLists.txt @@ -5,4 +5,6 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(posix_common) FILE(GLOB app_sources src/*.c) +zephyr_include_directories(${ZEPHYR_BASE}/lib/posix) + target_sources(app PRIVATE ${app_sources}) diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c new file mode 100644 index 000000000000..23ab9bc01ba6 --- /dev/null +++ b/tests/posix/common/src/signal.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +ZTEST(posix_apis, test_signal_emptyset) +{ + sigset_t set; + + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + set.sig[i] = -1; + } + + zassert_ok(sigemptyset(&set)); + + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], 0u, "set.sig[%d] is not empty: 0x%lx", i, set.sig[i]); + } +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 791735d966e5..9822fe1b227a 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -158,6 +158,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_equal(-1, SIGXCPU); zassert_not_equal(-1, SIGXFSZ); zassert_not_equal(((sigset_t){.sig[0] = 0}).sig[0], ((sigset_t){.sig[0] = -1}).sig[0]); + zassert_not_null(sigemptyset); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -172,7 +173,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(sigaddset); */ /* not implemented */ /* zassert_not_null(sigaltstack); */ /* not implemented */ /* zassert_not_null(sigdelset); */ /* not implemented */ - /* zassert_not_null(sigemptyset); */ /* not implemented */ /* zassert_not_null(sigfillset); */ /* not implemented */ /* zassert_not_null(sighold); */ /* not implemented */ /* zassert_not_null(sigignore); */ /* not implemented */ From b9720e27c0ee58427867cef8f1802e59a3477683 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:33:31 +0800 Subject: [PATCH 1436/2042] posix: signal: implement sigfillset Implementation and ztest for sigfillset. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/signal.h | 1 + lib/posix/signal.c | 9 +++++++++ tests/posix/common/src/signal.c | 11 +++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index fbcdc4f4779e..ee5295bd55b2 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -379,7 +379,7 @@ required for error and event handling. igaddset(), sigdelset(), sigemptyset(),yes - sigfillset(), + sigfillset(),yes igismember(), signal(), sigpending(), diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 6c63ca9da078..b7d17a73b53a 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -56,6 +56,7 @@ typedef struct { } sigset_t; int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); #endif /* CONFIG_POSIX_SIGNAL */ #ifndef SIGEV_NONE diff --git a/lib/posix/signal.c b/lib/posix/signal.c index ca0277d36f28..da0c29266552 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -10,3 +10,12 @@ int sigemptyset(sigset_t *set) *set = (sigset_t){0}; return 0; } + +int sigfillset(sigset_t *set) +{ + for (int i = 0; i < ARRAY_SIZE(set->sig); i++) { + set->sig[i] = -1; + } + + return 0; +} diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 23ab9bc01ba6..572ef53cbdaa 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -23,3 +23,14 @@ ZTEST(posix_apis, test_signal_emptyset) zassert_equal(set.sig[i], 0u, "set.sig[%d] is not empty: 0x%lx", i, set.sig[i]); } } + +ZTEST(posix_apis, test_signal_fillset) +{ + sigset_t set = (sigset_t){0}; + + zassert_ok(sigfillset(&set)); + + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], -1, "set.sig[%d] is not filled: 0x%lx", i, set.sig[i]); + } +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 9822fe1b227a..24f451dc59f1 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -159,6 +159,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_equal(-1, SIGXFSZ); zassert_not_equal(((sigset_t){.sig[0] = 0}).sig[0], ((sigset_t){.sig[0] = -1}).sig[0]); zassert_not_null(sigemptyset); + zassert_not_null(sigfillset); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -173,7 +174,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(sigaddset); */ /* not implemented */ /* zassert_not_null(sigaltstack); */ /* not implemented */ /* zassert_not_null(sigdelset); */ /* not implemented */ - /* zassert_not_null(sigfillset); */ /* not implemented */ /* zassert_not_null(sighold); */ /* not implemented */ /* zassert_not_null(sigignore); */ /* not implemented */ /* zassert_not_null(siginterrupt); */ /* not implemented */ From 8011449542674d7fb10a5d7c09df390bbcb581c4 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:45:27 +0800 Subject: [PATCH 1437/2042] posix: signal: implement sigaddset Implementation and ztest for sigaddset. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/signal.h | 1 + lib/posix/signal.c | 27 +++++++++++++ tests/posix/common/src/signal.c | 62 ++++++++++++++++++++++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index ee5295bd55b2..b2a3c8cfc929 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -376,7 +376,7 @@ required for error and event handling. pause(), raise(), sigaction(), - igaddset(), + sigaddset(),yes sigdelset(), sigemptyset(),yes sigfillset(),yes diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index b7d17a73b53a..1ffacbd617b1 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -57,6 +57,7 @@ typedef struct { int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); +int sigaddset(sigset_t *set, int signo); #endif /* CONFIG_POSIX_SIGNAL */ #ifndef SIGEV_NONE diff --git a/lib/posix/signal.c b/lib/posix/signal.c index da0c29266552..d1b4a543d18f 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -3,8 +3,23 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include + #include +#define SIGNO_WORD_IDX(_signo) (signo / BITS_PER_LONG) +#define SIGNO_WORD_BIT(_signo) (signo & BIT_MASK(LOG2(BITS_PER_LONG))) + +static inline bool signo_valid(int signo) +{ + return ((signo > 0) && (signo < _NSIG)); +} + +static inline bool signo_is_rt(int signo) +{ + return ((signo >= SIGRTMIN) && (signo <= SIGRTMAX)); +} + int sigemptyset(sigset_t *set) { *set = (sigset_t){0}; @@ -19,3 +34,15 @@ int sigfillset(sigset_t *set) return 0; } + +int sigaddset(sigset_t *set, int signo) +{ + if (!signo_valid(signo)) { + errno = EINVAL; + return -1; + } + + WRITE_BIT(set->sig[SIGNO_WORD_IDX(signo)], SIGNO_WORD_BIT(signo), 1); + + return 0; +} diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 572ef53cbdaa..982987a19b3e 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -34,3 +35,64 @@ ZTEST(posix_apis, test_signal_fillset) zassert_equal(set.sig[i], -1, "set.sig[%d] is not filled: 0x%lx", i, set.sig[i]); } } + +ZTEST(posix_apis, test_signal_addset_oor) +{ + sigset_t set = (sigset_t){0}; + + zassert_equal(sigaddset(&set, -1), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigaddset(&set, 0), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigaddset(&set, _NSIG), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); +} + +ZTEST(posix_apis, test_signal_addset) +{ + int signo; + sigset_t set = (sigset_t){0}; + sigset_t target = (sigset_t){0}; + + signo = SIGHUP; + zassert_ok(sigaddset(&set, signo)); + WRITE_BIT(target.sig[0], signo, 1); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGSYS; + zassert_ok(sigaddset(&set, signo)); + WRITE_BIT(target.sig[0], signo, 1); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */ + zassert_ok(sigaddset(&set, signo)); +#ifdef CONFIG_64BIT + WRITE_BIT(target.sig[0], signo, 1); +#else /* 32BIT */ + WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 1); +#endif + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGRTMAX; + zassert_ok(sigaddset(&set, signo)); + WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 1); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 24f451dc59f1..2a5e35833efc 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -160,6 +160,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_equal(((sigset_t){.sig[0] = 0}).sig[0], ((sigset_t){.sig[0] = -1}).sig[0]); zassert_not_null(sigemptyset); zassert_not_null(sigfillset); + zassert_not_null(sigaddset); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -171,7 +172,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(pthread_sigmask); */ /* not implemented */ /* zassert_not_null(raise); */ /* not implemented */ /* zassert_not_null(sigaction); */ /* not implemented */ - /* zassert_not_null(sigaddset); */ /* not implemented */ /* zassert_not_null(sigaltstack); */ /* not implemented */ /* zassert_not_null(sigdelset); */ /* not implemented */ /* zassert_not_null(sighold); */ /* not implemented */ From 88cd4944308f3d568874f73beb130241b46299d9 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:47:20 +0800 Subject: [PATCH 1438/2042] posix: signal: implement sigdelset Implementation and ztest for sigdelset. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/signal.h | 1 + lib/posix/signal.c | 12 ++++++ tests/posix/common/src/signal.c | 61 ++++++++++++++++++++++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index b2a3c8cfc929..0b6e0f54da9b 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -377,7 +377,7 @@ required for error and event handling. raise(), sigaction(), sigaddset(),yes - sigdelset(), + sigdelset(),yes sigemptyset(),yes sigfillset(),yes igismember(), diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 1ffacbd617b1..462bff8ce4d7 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -58,6 +58,7 @@ typedef struct { int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); +int sigdelset(sigset_t *set, int signo); #endif /* CONFIG_POSIX_SIGNAL */ #ifndef SIGEV_NONE diff --git a/lib/posix/signal.c b/lib/posix/signal.c index d1b4a543d18f..d20557b3fc1c 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -46,3 +46,15 @@ int sigaddset(sigset_t *set, int signo) return 0; } + +int sigdelset(sigset_t *set, int signo) +{ + if (!signo_valid(signo)) { + errno = EINVAL; + return -1; + } + + WRITE_BIT(set->sig[SIGNO_WORD_IDX(signo)], SIGNO_WORD_BIT(signo), 0); + + return 0; +} diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 982987a19b3e..afc0fb9e60b4 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -96,3 +96,64 @@ ZTEST(posix_apis, test_signal_addset) ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } } + +ZTEST(posix_apis, test_signal_delset_oor) +{ + sigset_t set = (sigset_t){0}; + + zassert_equal(sigdelset(&set, -1), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigdelset(&set, 0), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigdelset(&set, _NSIG), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); +} + +ZTEST(posix_apis, test_signal_delset) +{ + int signo; + sigset_t set = (sigset_t){0}; + sigset_t target = (sigset_t){0}; + + signo = SIGHUP; + zassert_ok(sigdelset(&set, signo)); + WRITE_BIT(target.sig[0], signo, 0); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGSYS; + zassert_ok(sigdelset(&set, signo)); + WRITE_BIT(target.sig[0], signo, 0); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */ + zassert_ok(sigdelset(&set, signo)); +#ifdef CONFIG_64BIT + WRITE_BIT(target.sig[0], signo, 0); +#else /* 32BIT */ + WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 0); +#endif + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } + + signo = SIGRTMAX; + zassert_ok(sigdelset(&set, signo)); + WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 0); + for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { + zassert_equal(set.sig[i], target.sig[i], + "set.sig[%d of %d] has content: %lx, expected %lx", i, + ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); + } +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 2a5e35833efc..34703c0b2c07 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -161,6 +161,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigemptyset); zassert_not_null(sigfillset); zassert_not_null(sigaddset); + zassert_not_null(sigdelset); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -173,7 +174,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(raise); */ /* not implemented */ /* zassert_not_null(sigaction); */ /* not implemented */ /* zassert_not_null(sigaltstack); */ /* not implemented */ - /* zassert_not_null(sigdelset); */ /* not implemented */ /* zassert_not_null(sighold); */ /* not implemented */ /* zassert_not_null(sigignore); */ /* not implemented */ /* zassert_not_null(siginterrupt); */ /* not implemented */ From ff4b81e5e5a48979f03ccfa9a17f0da0da80efe8 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Sat, 8 Jul 2023 22:48:31 +0800 Subject: [PATCH 1439/2042] posix: signal: implement sigismember Implementation and ztest for sigismember. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 2 +- include/zephyr/posix/signal.h | 1 + lib/posix/signal.c | 10 +++++++++ tests/posix/common/src/signal.c | 35 ++++++++++++++++++++++++++++++ tests/posix/headers/src/signal_h.c | 2 +- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 0b6e0f54da9b..fb06cba1c750 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -380,7 +380,7 @@ required for error and event handling. sigdelset(),yes sigemptyset(),yes sigfillset(),yes - igismember(), + sigismember(),yes signal(), sigpending(), sigprocmask(), diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 462bff8ce4d7..8c509954edd6 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -59,6 +59,7 @@ 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 diff --git a/lib/posix/signal.c b/lib/posix/signal.c index d20557b3fc1c..165d9aa9dbcd 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -58,3 +58,13 @@ int sigdelset(sigset_t *set, int signo) return 0; } + +int sigismember(const sigset_t *set, int signo) +{ + if (!signo_valid(signo)) { + errno = EINVAL; + return -1; + } + + return 1 & (set->sig[SIGNO_WORD_IDX(signo)] >> SIGNO_WORD_BIT(signo)); +} diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index afc0fb9e60b4..90fb001bc5bb 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -157,3 +157,38 @@ ZTEST(posix_apis, test_signal_delset) ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } } + +ZTEST(posix_apis, test_signal_ismember_oor) +{ + sigset_t set = {0}; + + zassert_equal(sigismember(&set, -1), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigismember(&set, 0), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); + + zassert_equal(sigismember(&set, _NSIG), -1, "rc should be -1"); + zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); +} + +ZTEST(posix_apis, test_signal_ismember) +{ + sigset_t set = (sigset_t){0}; + +#ifdef CONFIG_64BIT + set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS) | BIT(SIGRTMIN); +#else /* 32BIT */ + set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS); + set.sig[1] = BIT((SIGRTMIN)-BITS_PER_LONG); +#endif + WRITE_BIT(set.sig[SIGRTMAX / BITS_PER_LONG], SIGRTMAX % BITS_PER_LONG, 1); + + zassert_equal(sigismember(&set, SIGHUP), 1, "%s expected to be member", "SIGHUP"); + zassert_equal(sigismember(&set, SIGSYS), 1, "%s expected to be member", "SIGSYS"); + zassert_equal(sigismember(&set, SIGRTMIN), 1, "%s expected to be member", "SIGRTMIN"); + zassert_equal(sigismember(&set, SIGRTMAX), 1, "%s expected to be member", "SIGRTMAX"); + + zassert_equal(sigismember(&set, SIGKILL), 0, "%s not expected to be member", "SIGKILL"); + zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM"); +} diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 34703c0b2c07..5a78c0ec0a75 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -162,6 +162,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigfillset); zassert_not_null(sigaddset); zassert_not_null(sigdelset); + zassert_not_null(sigismember); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { @@ -177,7 +178,6 @@ ZTEST(posix_headers, test_signal_h) /* zassert_not_null(sighold); */ /* not implemented */ /* zassert_not_null(sigignore); */ /* not implemented */ /* zassert_not_null(siginterrupt); */ /* not implemented */ - /* zassert_not_null(sigismember); */ /* not implemented */ /* zassert_not_null(signal); */ /* not implemented */ /* zassert_not_null(sigpause); */ /* not implemented */ /* zassert_not_null(sigpending); */ /* not implemented */ From 335acf817d950fb4029a5a23f4b37b0ba5c74380 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 11 Jul 2023 01:14:25 +0800 Subject: [PATCH 1440/2042] posix: signal: implement strsignal Implementation and ztest for strsignal. Signed-off-by: Yong Cong Sin --- doc/services/portability/posix.rst | 3 +- include/zephyr/posix/signal.h | 1 + lib/posix/CMakeLists.txt | 18 +++++- lib/posix/Kconfig.signal | 7 +++ lib/posix/signal.c | 28 +++++++++ scripts/build/gen_strsignal_table.py | 92 ++++++++++++++++++++++++++++ tests/posix/common/src/signal.c | 24 ++++++++ tests/posix/common/testcase.yaml | 3 + tests/posix/headers/src/signal_h.c | 1 + 9 files changed, 175 insertions(+), 2 deletions(-) create mode 100755 scripts/build/gen_strsignal_table.py diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index fb06cba1c750..83d8c78cbcec 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -385,7 +385,8 @@ required for error and event handling. sigpending(), sigprocmask(), igsuspend(), - sigwait() + sigwait(), + strsignal(),yes .. csv-table:: POSIX_SPIN_LOCKS :header: API, Supported diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index 8c509954edd6..0cfa5649b387 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -55,6 +55,7 @@ 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); diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index ce5e809d04ed..48bb598ef2d5 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) + zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/posix/time.h ) @@ -10,6 +12,20 @@ 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 @@ -29,7 +45,7 @@ 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) +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_IPC barrier.c) diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal index 3ff5b75e8e89..c51e68f1f36a 100644 --- a/lib/posix/Kconfig.signal +++ b/lib/posix/Kconfig.signal @@ -16,4 +16,11 @@ config POSIX_RTSIG_MAX 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" + default y + help + Use full description for the strsignal API. + Will use 256 bytes of ROM. + endif diff --git a/lib/posix/signal.c b/lib/posix/signal.c index 165d9aa9dbcd..e1d7feab299d 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -3,7 +3,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "posix/strsignal_table.h" + #include +#include #include @@ -68,3 +71,28 @@ int sigismember(const sigset_t *set, int signo) return 1 & (set->sig[SIGNO_WORD_IDX(signo)] >> SIGNO_WORD_BIT(signo)); } + +char *strsignal(int signum) +{ + static char buf[sizeof("RT signal " STRINGIFY(SIGRTMAX))]; + + if (!signo_valid(signum)) { + errno = EINVAL; + return "Invalid signal"; + } + + if (signo_is_rt(signum)) { + snprintf(buf, sizeof(buf), "RT signal %d", signum - SIGRTMIN); + return buf; + } + + if (IS_ENABLED(CONFIG_POSIX_SIGNAL_STRING_DESC)) { + if (strsignal_list[signum] != NULL) { + return (char *)strsignal_list[signum]; + } + } + + snprintf(buf, sizeof(buf), "Signal %d", signum); + + return buf; +} diff --git a/scripts/build/gen_strsignal_table.py b/scripts/build/gen_strsignal_table.py new file mode 100755 index 000000000000..b60b23237dc6 --- /dev/null +++ b/scripts/build/gen_strsignal_table.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import os +import re + + +def front_matter(): + return f''' +/* + * This file is generated by {__file__} + */ + +#include +''' + + +def gen_strsignal_table(input, output): + with open(input, 'r') as inf: + + highest_signo = 0 + symbols = [] + msgs = {} + + for line in inf.readlines(): + # Select items of the form below (note: SIGNO is numeric) + # #define SYMBOL SIGNO /**< MSG */ + pat = r'^#define[\s]+(SIG[A-Z_]*)[\s]+([1-9][0-9]*)[\s]+/\*\*<[\s]+(.*)[\s]+\*/[\s]*$' + match = re.match(pat, line) + + if not match: + continue + + symbol = match[1] + signo = int(match[2]) + msg = match[3] + + symbols.append(symbol) + msgs[symbol] = msg + + highest_signo = max(int(signo), highest_signo) + + try: + os.makedirs(os.path.dirname(output)) + except BaseException: + # directory already present + pass + + with open(output, 'w') as outf: + + print(front_matter(), file=outf) + + # Generate string table + print( + f'static const char *const strsignal_list[{highest_signo + 1}] = {{', file=outf) + for symbol in symbols: + print(f'\t[{symbol}] = "{msgs[symbol]}",', file=outf) + + print('};', file=outf) + + +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument( + '-i', + '--input', + dest='input', + required=True, + help='input file (e.g. include/zephyr/posix/signal.h)') + parser.add_argument( + '-o', + '--output', + dest='output', + required=True, + help='output file (e.g. build/zephyr/misc/generated/lib/posix/strsignal_table.h)') + + args = parser.parse_args() + + return args + + +def main(): + args = parse_args() + gen_strsignal_table(args.input, args.output) + + +if __name__ == '__main__': + main() diff --git a/tests/posix/common/src/signal.c b/tests/posix/common/src/signal.c index 90fb001bc5bb..79b78e5444e4 100644 --- a/tests/posix/common/src/signal.c +++ b/tests/posix/common/src/signal.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -192,3 +193,26 @@ ZTEST(posix_apis, test_signal_ismember) zassert_equal(sigismember(&set, SIGKILL), 0, "%s not expected to be member", "SIGKILL"); zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM"); } + +ZTEST(posix_apis, test_signal_strsignal) +{ + char buf[sizeof("RT signal " STRINGIFY(SIGRTMAX))] = {0}; + + zassert_mem_equal(strsignal(-1), "Invalid signal", sizeof("Invalid signal")); + zassert_mem_equal(strsignal(0), "Invalid signal", sizeof("Invalid signal")); + zassert_mem_equal(strsignal(_NSIG), "Invalid signal", sizeof("Invalid signal")); + + zassert_mem_equal(strsignal(30), "Signal 30", sizeof("Signal 30")); + snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMIN - SIGRTMIN); + zassert_mem_equal(strsignal(SIGRTMIN), buf, strlen(buf)); + snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMAX - SIGRTMIN); + zassert_mem_equal(strsignal(SIGRTMAX), buf, strlen(buf)); + +#ifdef CONFIG_POSIX_SIGNAL_STRING_DESC + zassert_mem_equal(strsignal(SIGHUP), "Hangup", sizeof("Hangup")); + zassert_mem_equal(strsignal(SIGSYS), "Bad system call", sizeof("Bad system call")); +#else + zassert_mem_equal(strsignal(SIGHUP), "Signal 1", sizeof("Signal 1")); + zassert_mem_equal(strsignal(SIGSYS), "Signal 31", sizeof("Signal 31")); +#endif +} diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index 899bb8910bce..e4b30e45ea69 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -80,3 +80,6 @@ tests: - CONFIG_SPIN_VALIDATE=n integration_platforms: - mps2_an385 + portability.posix.common.signal.strsignal_no_desc: + extra_configs: + - CONFIG_POSIX_SIGNAL_STRING_DESC=n diff --git a/tests/posix/headers/src/signal_h.c b/tests/posix/headers/src/signal_h.c index 5a78c0ec0a75..852cddf3df0f 100644 --- a/tests/posix/headers/src/signal_h.c +++ b/tests/posix/headers/src/signal_h.c @@ -163,6 +163,7 @@ ZTEST(posix_headers, test_signal_h) zassert_not_null(sigaddset); zassert_not_null(sigdelset); zassert_not_null(sigismember); + zassert_not_null(strsignal); #endif /* CONFIG_POSIX_SIGNAL */ if (IS_ENABLED(CONFIG_POSIX_API)) { From 597054399961de2922dea60b725fe4e3f1bce981 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Fri, 14 Jul 2023 13:23:37 +0800 Subject: [PATCH 1441/2042] test: posix: signal: add test for big nsig number Add an extra test config to test large number of signals. Signed-off-by: Yong Cong Sin --- tests/posix/common/testcase.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index e4b30e45ea69..a3086233b6c3 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -83,3 +83,6 @@ tests: portability.posix.common.signal.strsignal_no_desc: extra_configs: - CONFIG_POSIX_SIGNAL_STRING_DESC=n + portability.posix.common.signal.big_nsig: + extra_configs: + - CONFIG_POSIX_RTSIG_MAX=1024 From 43c549305bdb0770a3fbebe7347b3da8b2d9ceec Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 18 Jul 2023 13:00:59 +0800 Subject: [PATCH 1442/2042] posix: signal: check RTSIG limit Use build assert to make sure that the realtime signal constants are configured properly in the Kconfig. Signed-off-by: Yong Cong Sin --- lib/posix/Kconfig | 1 + lib/posix/Kconfig.limits | 13 +++++++++++++ lib/posix/signal.c | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 lib/posix/Kconfig.limits diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 59414797328c..199ed956af25 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -44,6 +44,7 @@ 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" diff --git a/lib/posix/Kconfig.limits b/lib/posix/Kconfig.limits new file mode 100644 index 000000000000..cc651203961c --- /dev/null +++ b/lib/posix/Kconfig.limits @@ -0,0 +1,13 @@ +# 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/signal.c b/lib/posix/signal.c index e1d7feab299d..809ba84dc3a6 100644 --- a/lib/posix/signal.c +++ b/lib/posix/signal.c @@ -13,6 +13,9 @@ #define SIGNO_WORD_IDX(_signo) (signo / BITS_PER_LONG) #define SIGNO_WORD_BIT(_signo) (signo & BIT_MASK(LOG2(BITS_PER_LONG))) +BUILD_ASSERT(CONFIG_POSIX_LIMITS_RTSIG_MAX >= 0); +BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= CONFIG_POSIX_LIMITS_RTSIG_MAX); + static inline bool signo_valid(int signo) { return ((signo > 0) && (signo < _NSIG)); From 141299fb80fbdd3aab6fa90e8a555f8da0c380ce Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 12 Jun 2023 15:30:40 -0400 Subject: [PATCH 1443/2042] tests: timer_behavior: better cope with timer wrap-arounds Commit a1d21ca69bf4 ("tests: timer_behavior: don't fail the test with timer wrap-arounds") simply ignored the total time validation whenever any rollover was detected. Let's adjust the end timestamp according to the number of rollovers instead. Documentation for sys_clock_cycle_get_32() says it should count up monotonically through the full 32 bit space, wrapping at 0xffffffff. Therefore we just need to add 2^32 times the number of rollovers to the end timestamp. Signed-off-by: Nicolas Pitre --- .../timer/timer_behavior/src/jitter_drift.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/kernel/timer/timer_behavior/src/jitter_drift.c b/tests/kernel/timer/timer_behavior/src/jitter_drift.c index b1b6f818361e..cd6afaea00de 100644 --- a/tests/kernel/timer/timer_behavior/src/jitter_drift.c +++ b/tests/kernel/timer/timer_behavior/src/jitter_drift.c @@ -145,6 +145,15 @@ static void do_test_using(void (*sample_collection_fn)(void)) } } +#ifndef CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER + /* + * Account for rollovers if any, and only when k_cycle_get_32() + * is used. This should not happen with k_cycle_get_64() and will + * be trapped later otherwise. + */ + periodic_end += (1ULL << 32) * periodic_rollovers; +#endif + double min_us = cycles_to_us(min_cyc); double max_us = cycles_to_us(max_cyc); @@ -249,14 +258,9 @@ static void do_test_using(void (*sample_collection_fn)(void)) zassert_true(stddev_us < (double)CONFIG_TIMER_TEST_MAX_STDDEV, "Standard deviation (in microseconds) outside expected bound"); - if (periodic_rollovers != 0) { - TC_PRINT("WARNING: the total time is bogus due to timer " - "rollovers and canot be validated\n"); - } else { - /* Validate the timer drift (accuracy over time) is within a configurable bound */ - zassert_true(abs(time_diff_us) < CONFIG_TIMER_TEST_MAX_DRIFT, - "Drift (in microseconds) outside expected bound"); - } + /* Validate the timer drift (accuracy over time) is within a configurable bound */ + zassert_true(abs(time_diff_us) < CONFIG_TIMER_TEST_MAX_DRIFT, + "Drift (in microseconds) outside expected bound"); } ZTEST(timer_jitter_drift, test_jitter_drift_timer_period) From d8147ce648d8b102fa0777755ac5bef452b95d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 14:41:43 +0200 Subject: [PATCH 1444/2042] input: doc: document event definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing documentation to event types, key codes, etc. Signed-off-by: Benjamin Cabé --- .../dt-bindings/input/input-event-codes.h | 157 +++++++++--------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/include/zephyr/dt-bindings/input/input-event-codes.h b/include/zephyr/dt-bindings/input/input-event-codes.h index c4b8e0883e1b..e07f8d2d7ace 100644 --- a/include/zephyr/dt-bindings/input/input-event-codes.h +++ b/include/zephyr/dt-bindings/input/input-event-codes.h @@ -22,12 +22,12 @@ * @anchor INPUT_EV_CODES * @{ */ -#define INPUT_EV_KEY 0x01 -#define INPUT_EV_REL 0x02 -#define INPUT_EV_ABS 0x03 -#define INPUT_EV_MSC 0x04 -#define INPUT_EV_VENDOR_START 0xf0 -#define INPUT_EV_VENDOR_STOP 0xff +#define INPUT_EV_KEY 0x01 /**< Key event */ +#define INPUT_EV_REL 0x02 /**< Relative coordinate event */ +#define INPUT_EV_ABS 0x03 /**< Absolute coordinate event */ +#define INPUT_EV_MSC 0x04 /**< Miscellaneous event */ +#define INPUT_EV_VENDOR_START 0xf0 /**< Vendor specific event start */ +#define INPUT_EV_VENDOR_STOP 0xff /**< Vendor specific event stop */ /** @} */ /** @@ -35,72 +35,73 @@ * @anchor INPUT_KEY_CODES * @{ */ -#define INPUT_KEY_0 11 -#define INPUT_KEY_1 2 -#define INPUT_KEY_2 3 -#define INPUT_KEY_3 4 -#define INPUT_KEY_4 5 -#define INPUT_KEY_5 6 -#define INPUT_KEY_6 7 -#define INPUT_KEY_7 8 -#define INPUT_KEY_8 9 -#define INPUT_KEY_9 10 -#define INPUT_KEY_A 30 -#define INPUT_KEY_B 48 -#define INPUT_KEY_C 46 -#define INPUT_KEY_D 32 -#define INPUT_KEY_E 18 -#define INPUT_KEY_F 33 -#define INPUT_KEY_G 34 -#define INPUT_KEY_H 35 -#define INPUT_KEY_I 23 -#define INPUT_KEY_J 36 -#define INPUT_KEY_K 37 -#define INPUT_KEY_L 38 -#define INPUT_KEY_M 50 -#define INPUT_KEY_N 49 -#define INPUT_KEY_O 24 -#define INPUT_KEY_P 25 -#define INPUT_KEY_Q 16 -#define INPUT_KEY_R 19 -#define INPUT_KEY_S 31 -#define INPUT_KEY_T 20 -#define INPUT_KEY_U 22 -#define INPUT_KEY_V 47 -#define INPUT_KEY_VOLUMEDOWN 114 -#define INPUT_KEY_VOLUMEUP 115 -#define INPUT_KEY_W 17 -#define INPUT_KEY_X 45 -#define INPUT_KEY_Y 21 -#define INPUT_KEY_Z 44 +#define INPUT_KEY_0 11 /**< 0 Key */ +#define INPUT_KEY_1 2 /**< 1 Key */ +#define INPUT_KEY_2 3 /**< 2 Key */ +#define INPUT_KEY_3 4 /**< 3 Key */ +#define INPUT_KEY_4 5 /**< 4 Key */ +#define INPUT_KEY_5 6 /**< 5 Key */ +#define INPUT_KEY_6 7 /**< 6 Key */ +#define INPUT_KEY_7 8 /**< 7 Key */ +#define INPUT_KEY_8 9 /**< 8 Key */ +#define INPUT_KEY_9 10 /**< 9 Key */ +#define INPUT_KEY_A 30 /**< A Key */ +#define INPUT_KEY_B 48 /**< B Key */ +#define INPUT_KEY_C 46 /**< C Key */ +#define INPUT_KEY_D 32 /**< D Key */ +#define INPUT_KEY_E 18 /**< E Key */ +#define INPUT_KEY_F 33 /**< F Key */ +#define INPUT_KEY_G 34 /**< G Key */ +#define INPUT_KEY_H 35 /**< H Key */ +#define INPUT_KEY_I 23 /**< I Key */ +#define INPUT_KEY_J 36 /**< J Key */ +#define INPUT_KEY_K 37 /**< K Key */ +#define INPUT_KEY_L 38 /**< L Key */ +#define INPUT_KEY_M 50 /**< M Key */ +#define INPUT_KEY_N 49 /**< N Key */ +#define INPUT_KEY_O 24 /**< O Key */ +#define INPUT_KEY_P 25 /**< P Key */ +#define INPUT_KEY_Q 16 /**< Q Key */ +#define INPUT_KEY_R 19 /**< R Key */ +#define INPUT_KEY_S 31 /**< S Key */ +#define INPUT_KEY_T 20 /**< T Key */ +#define INPUT_KEY_U 22 /**< U Key */ +#define INPUT_KEY_V 47 /**< V Key */ +#define INPUT_KEY_VOLUMEDOWN 114 /**< Volume Down Key */ +#define INPUT_KEY_VOLUMEUP 115 /**< Volume Up Key */ +#define INPUT_KEY_W 17 /**< W Key */ +#define INPUT_KEY_X 45 /**< X Key */ +#define INPUT_KEY_Y 21 /**< Y Key */ +#define INPUT_KEY_Z 44 /**< Z Key */ /** @} */ + /** * @name Input event BTN codes. * @anchor INPUT_BTN_CODES * @{ */ -#define INPUT_BTN_DPAD_DOWN 0x221 -#define INPUT_BTN_DPAD_LEFT 0x222 -#define INPUT_BTN_DPAD_RIGHT 0x223 -#define INPUT_BTN_DPAD_UP 0x220 -#define INPUT_BTN_EAST 0x131 -#define INPUT_BTN_LEFT 0x110 -#define INPUT_BTN_MIDDLE 0x112 -#define INPUT_BTN_MODE 0x13c -#define INPUT_BTN_NORTH 0x133 -#define INPUT_BTN_RIGHT 0x111 -#define INPUT_BTN_SELECT 0x13a -#define INPUT_BTN_SOUTH 0x130 -#define INPUT_BTN_START 0x13b -#define INPUT_BTN_THUMBL 0x13d -#define INPUT_BTN_THUMBR 0x13e -#define INPUT_BTN_TL 0x136 -#define INPUT_BTN_TL2 0x138 -#define INPUT_BTN_TOUCH 0x14a -#define INPUT_BTN_TR 0x137 -#define INPUT_BTN_TR2 0x139 -#define INPUT_BTN_WEST 0x134 +#define INPUT_BTN_DPAD_DOWN 0x221 /**< Directional pad Down */ +#define INPUT_BTN_DPAD_LEFT 0x222 /**< Directional pad Left */ +#define INPUT_BTN_DPAD_RIGHT 0x223 /**< Directional pad Right */ +#define INPUT_BTN_DPAD_UP 0x220 /**< Directional pad Up */ +#define INPUT_BTN_EAST 0x131 /**< East button */ +#define INPUT_BTN_LEFT 0x110 /**< Left button */ +#define INPUT_BTN_MIDDLE 0x112 /**< Middle button */ +#define INPUT_BTN_MODE 0x13c /**< Mode button */ +#define INPUT_BTN_NORTH 0x133 /**< North button */ +#define INPUT_BTN_RIGHT 0x111 /**< Right button */ +#define INPUT_BTN_SELECT 0x13a /**< Select button */ +#define INPUT_BTN_SOUTH 0x130 /**< South button */ +#define INPUT_BTN_START 0x13b /**< Start button */ +#define INPUT_BTN_THUMBL 0x13d /**< Left thumbstick button */ +#define INPUT_BTN_THUMBR 0x13e /**< Right thumbstick button */ +#define INPUT_BTN_TL 0x136 /**< Left trigger (L1) */ +#define INPUT_BTN_TL2 0x138 /**< Left trigger 2 (L2) */ +#define INPUT_BTN_TOUCH 0x14a /**< Touchscreen touch */ +#define INPUT_BTN_TR 0x137 /**< Right trigger (R1) */ +#define INPUT_BTN_TR2 0x139 /**< Right trigger 2 (R2) */ +#define INPUT_BTN_WEST 0x134 /**< West button */ /** @} */ /** @@ -108,12 +109,12 @@ * @anchor INPUT_ABS_CODES * @{ */ -#define INPUT_ABS_RX 0x03 -#define INPUT_ABS_RY 0x04 -#define INPUT_ABS_RZ 0x05 -#define INPUT_ABS_X 0x00 -#define INPUT_ABS_Y 0x01 -#define INPUT_ABS_Z 0x02 +#define INPUT_ABS_RX 0x03 /**< Absolute rotation around X axis */ +#define INPUT_ABS_RY 0x04 /**< Absolute rotation around Y axis */ +#define INPUT_ABS_RZ 0x05 /**< Absolute rotation around Z axis */ +#define INPUT_ABS_X 0x00 /**< Absolute X coordinate */ +#define INPUT_ABS_Y 0x01 /**< Absolute Y coordinate */ +#define INPUT_ABS_Z 0x02 /**< Absolute Z coordinate */ /** @} */ /** @@ -121,12 +122,12 @@ * @anchor INPUT_REL_CODES * @{ */ -#define INPUT_REL_RX 0x03 -#define INPUT_REL_RY 0x04 -#define INPUT_REL_RZ 0x05 -#define INPUT_REL_X 0x00 -#define INPUT_REL_Y 0x01 -#define INPUT_REL_Z 0x02 +#define INPUT_REL_RX 0x03 /**< Relative rotation around X axis */ +#define INPUT_REL_RY 0x04 /**< Relative rotation around Y axis */ +#define INPUT_REL_RZ 0x05 /**< Relative rotation around Z axis */ +#define INPUT_REL_X 0x00 /**< Relative X coordinate */ +#define INPUT_REL_Y 0x01 /**< Relative Y coordinate */ +#define INPUT_REL_Z 0x02 /**< Relative Z coordinate */ /** @} */ /** @@ -134,7 +135,7 @@ * @anchor INPUT_MSC_CODES * @{ */ -#define INPUT_MSC_SCAN 0x04 +#define INPUT_MSC_SCAN 0x04 /**< Scan code */ /** @} */ /** @} */ From 61c38379ba959016459eab6dc19f2c8efcd2533b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 18:44:26 +0200 Subject: [PATCH 1445/2042] app_memdomain: doc: Properly mount doc page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly mount App memory domain APIs into Doxygen doc hierarchy. Signed-off-by: Benjamin Cabé --- include/zephyr/app_memory/app_memdomain.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/zephyr/app_memory/app_memdomain.h b/include/zephyr/app_memory/app_memdomain.h index dcb37fab5f85..08e28982ad63 100644 --- a/include/zephyr/app_memory/app_memdomain.h +++ b/include/zephyr/app_memory/app_memdomain.h @@ -10,6 +10,13 @@ #include #include +/** + * @brief Application memory domain APIs + * @defgroup mem_domain_apis_app Application memory domain APIs + * @ingroup mem_domain_apis + * @{ + */ + #ifdef CONFIG_USERSPACE /** @@ -142,4 +149,9 @@ struct z_app_region { #define K_APPMEM_PARTITION_DEFINE(name) #endif /* CONFIG_USERSPACE */ + +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_APP_MEMORY_APP_MEMDOMAIN_H_ */ From 93031ad5a00780d3d189fe0f45c3bbaef93bfb97 Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Mon, 17 Jul 2023 12:16:59 +0200 Subject: [PATCH 1446/2042] west_commands: Fix parsing of extra args for test-item An arg --test-item makes west loading twister's test configurations form sample/testcase.yaml. It has to mirror twister's behavior. It was not the case with "extra_args" section. Quotation marks were not removed in west as they were in twister. The quotation marks have to be removed from the extra_args section but left in extra_configs. The commit adds differentiation for those. fixes: #60297 Signed-off-by: Maciej Perkowski --- scripts/west_commands/build.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index 379f5e702947..a9a156125ce0 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -285,7 +285,10 @@ def _parse_test_item(self, test_item): arg_list = extra.split(" ") else: arg_list = extra - args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] + if data == 'extra_configs': + args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] + elif data == 'extra_args': + args = ["-D{}".format(arg.replace('"', '')) for arg in arg_list] if self.args.cmake_opts: self.args.cmake_opts.extend(args) else: From e47fc45c4d4ed3c04d6a147e10d2a52630b7f0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 18 Jul 2023 11:26:54 +0200 Subject: [PATCH 1447/2042] usb: audio: correctly report internal delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every USB device must buffer isochronous data for at least 1 frame in order to remove packet jitter within a frame. USB Specification Revision 2.0 describes necessary buffering in 5.12.5 Data Prebuffering. USB Audio 1.0 specification mentions buffering in 3.4 Inter Channel Synchronization. Set bDelay to 1 instead of 0, because bDelay 1 is both the minimum allowed value and matches the actual device behavior. Signed-off-by: Tomasz Moń --- subsys/usb/device/class/audio/usb_audio_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/usb/device/class/audio/usb_audio_internal.h b/subsys/usb/device/class/audio/usb_audio_internal.h index fb2a8971de1b..1cf8a10702d8 100644 --- a/subsys/usb/device/class/audio/usb_audio_internal.h +++ b/subsys/usb/device/class/audio/usb_audio_internal.h @@ -473,7 +473,7 @@ struct dev##_descriptor_##i { \ .bDescriptorType = USB_DESC_CS_INTERFACE, \ .bDescriptorSubtype = USB_AUDIO_AS_GENERAL, \ .bTerminalLink = link, \ - .bDelay = 0, \ + .bDelay = 1, \ .wFormatTag = sys_cpu_to_le16(0x0001), \ } From 3d94c830a3d466e1e387d6e1efa9f9c7ccbcc10f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 18 Jul 2023 14:55:41 -0700 Subject: [PATCH 1448/2042] scripts/checkpatch: Fix check for libc API defines Re-ordering the API names moved a trailing '|' causing the pattern to match *every* #define in the input. Signed-off-by: Keith Packard --- scripts/checkpatch.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index b34c2ad31d22..c72f54e9c147 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -595,7 +595,7 @@ sub hash_show_words { our $api_defines = qr{(?x: _ATFILE_SOURCE| _BSD_SOURCE| - _DEFAULT_SOURCE + _DEFAULT_SOURCE| _GNU_SOURCE| _ISOC11_SOURCE| _ISOC99_SOURCE| @@ -603,7 +603,7 @@ sub hash_show_words { _POSIX_SOURCE| _SVID_SOURCE| _XOPEN_SOURCE| - _XOPEN_SOURCE_EXTENDED| + _XOPEN_SOURCE_EXTENDED )}; my $word_pattern = '\b[A-Z]?[a-z]{2,}\b'; From d95c12848d20942772460f8c310c76a5f86f4e6d Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 18 Jul 2023 11:28:40 +0000 Subject: [PATCH 1449/2042] drivers: input: add few missing gpio_add_callback return check Add few missing check on gpio_add_callback and gpio_add_callback_dt calls, fixes a coverity warning. Signed-off-by: Fabio Baltieri --- drivers/input/input_gpio_qdec.c | 6 +++++- drivers/input/input_gt911.c | 6 +++++- drivers/input/input_xpt2046.c | 8 +++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index 85716fdcc1b7..88d403cdc556 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -204,7 +204,11 @@ static int gpio_qdec_init(const struct device *dev) return ret; } - gpio_add_callback_dt(gpio, &data->gpio_cb); + ret = gpio_add_callback_dt(gpio, &data->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } } data->prev_step = gpio_qdec_get_step(dev); diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index a13586caf85f..99468b4ed37f 100644 --- a/drivers/input/input_gt911.c +++ b/drivers/input/input_gt911.c @@ -343,7 +343,11 @@ static int gt911_init(const struct device *dev) } #ifdef CONFIG_INPUT_GT911_INTERRUPT - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + r = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (r < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } #else k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_GT911_PERIOD_MS), K_MSEC(CONFIG_INPUT_GT911_PERIOD_MS)); diff --git a/drivers/input/input_xpt2046.c b/drivers/input/input_xpt2046.c index 4c4f4c514b52..6e56fcb5874e 100644 --- a/drivers/input/input_xpt2046.c +++ b/drivers/input/input_xpt2046.c @@ -125,6 +125,7 @@ static void xpt2046_work_handler(struct k_work *kw) { struct xpt2046_data *data = CONTAINER_OF(kw, struct xpt2046_data, work); struct xpt2046_config *config = (struct xpt2046_config *)data->dev->config; + int ret; const struct spi_buf txb = {.buf = tbuf, .len = sizeof(tbuf)}; const struct spi_buf rxb = {.buf = data->rbuf, .len = sizeof(data->rbuf)}; @@ -180,7 +181,12 @@ static void xpt2046_work_handler(struct k_work *kw) /* Ensure that we send released event */ k_work_reschedule(&data->dwork, K_MSEC(100)); } - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + + ret = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return; + } } static int xpt2046_init(const struct device *dev) From f6aa1c4321b9e501a9cee1bc68ed1a3a006bb35b Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 14 Jul 2023 13:46:23 +0100 Subject: [PATCH 1450/2042] drivers: regulator: Added ship mode to API Added ship mode entry function to common regulator driver Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_fake.c | 4 +++ include/zephyr/drivers/regulator.h | 29 ++++++++++++++++++++ include/zephyr/drivers/regulator/fake.h | 2 ++ tests/drivers/regulator/api/src/main.c | 36 +++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/drivers/regulator/regulator_fake.c b/drivers/regulator/regulator_fake.c index e204714a66bc..05b74bc56e10 100644 --- a/drivers/regulator/regulator_fake.c +++ b/drivers/regulator/regulator_fake.c @@ -68,8 +68,12 @@ static int regulator_fake_init(const struct device *dev) DEFINE_FAKE_VALUE_FUNC(int, regulator_parent_fake_dvs_state_set, const struct device *, regulator_dvs_state_t); +DEFINE_FAKE_VALUE_FUNC(int, regulator_parent_fake_ship_mode, + const struct device *); + static struct regulator_parent_driver_api parent_api = { .dvs_state_set = regulator_parent_fake_dvs_state_set, + .ship_mode = regulator_parent_fake_ship_mode, }; #define FAKE_DATA_NAME(node_id) _CONCAT(data_, DT_DEP_ORD(node_id)) diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index 19c5d9957982..ae37b04635e6 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -58,9 +58,12 @@ typedef uint8_t regulator_error_flags_t; typedef int (*regulator_dvs_state_set_t)(const struct device *dev, regulator_dvs_state_t state); +typedef int (*regulator_ship_mode_t)(const struct device *dev); + /** @brief Driver-specific API functions to support parent regulator control. */ __subsystem struct regulator_parent_driver_api { regulator_dvs_state_set_t dvs_state_set; + regulator_ship_mode_t ship_mode; }; typedef int (*regulator_enable_t)(const struct device *dev); @@ -279,6 +282,32 @@ static inline int regulator_parent_dvs_state_set(const struct device *dev, return api->dvs_state_set(dev, state); } +/** + * @brief Enter ship mode. + * + * Some PMICs feature a ship mode, which allows the system to save power. + * Exit from low power is normally by pin transition. + * + * This API can be used when ship mode needs to be entered. + * + * @param dev Parent regulator device instance. + * + * @retval 0 If successful. + * @retval -ENOSYS If function is not implemented. + * @retval -errno In case of any other error. + */ +static inline int regulator_parent_ship_mode(const struct device *dev) +{ + const struct regulator_parent_driver_api *api = + (const struct regulator_parent_driver_api *)dev->api; + + if (api->ship_mode == NULL) { + return -ENOSYS; + } + + return api->ship_mode(dev); +} + /** @} */ /** diff --git a/include/zephyr/drivers/regulator/fake.h b/include/zephyr/drivers/regulator/fake.h index 4f97ab70e3c5..1bfffe6381b3 100644 --- a/include/zephyr/drivers/regulator/fake.h +++ b/include/zephyr/drivers/regulator/fake.h @@ -36,6 +36,8 @@ DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags, DECLARE_FAKE_VALUE_FUNC(int, regulator_parent_fake_dvs_state_set, const struct device *, regulator_dvs_state_t); +DECLARE_FAKE_VALUE_FUNC(int, regulator_parent_fake_ship_mode, + const struct device *); #ifdef __cplusplus } diff --git a/tests/drivers/regulator/api/src/main.c b/tests/drivers/regulator/api/src/main.c index 47310e2889b7..cf598067301e 100644 --- a/tests/drivers/regulator/api/src/main.c +++ b/tests/drivers/regulator/api/src/main.c @@ -60,6 +60,42 @@ ZTEST(regulator_api, test_parent_dvs_state_set_fail) zassert_equal(regulator_parent_fake_dvs_state_set_fake.call_count, 1U); } +ZTEST(regulator_api, test_parent_ship_mode_not_implemented) +{ + int ret; + struct regulator_parent_driver_api *api = + (struct regulator_parent_driver_api *)parent->api; + regulator_ship_mode_t ship_mode = api->ship_mode; + + api->ship_mode = NULL; + ret = regulator_parent_ship_mode(parent); + api->ship_mode = ship_mode; + + zassert_equal(ret, -ENOSYS); +} + +ZTEST(regulator_api, test_parent_ship_mode_ok) +{ + RESET_FAKE(regulator_parent_fake_ship_mode); + + regulator_parent_fake_ship_mode_fake.return_val = 0; + + zassert_equal(regulator_parent_ship_mode(parent), 0); + zassert_equal(regulator_parent_fake_ship_mode_fake.arg0_val, parent); + zassert_equal(regulator_parent_fake_ship_mode_fake.call_count, 1U); +} + +ZTEST(regulator_api, test_parent_ship_mode_fail) +{ + RESET_FAKE(regulator_parent_fake_ship_mode); + + regulator_parent_fake_ship_mode_fake.return_val = -ENOTSUP; + + zassert_equal(regulator_parent_ship_mode(parent), -ENOTSUP); + zassert_equal(regulator_parent_fake_ship_mode_fake.arg0_val, parent); + zassert_equal(regulator_parent_fake_ship_mode_fake.call_count, 1U); +} + ZTEST(regulator_api, test_common_config) { const struct regulator_common_config *config; From 024196be9dc01db3ef105e65eaf90106970a7295 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Fri, 14 Jul 2023 13:47:22 +0100 Subject: [PATCH 1451/2042] drivers: regulator: npm1300: Added ship mode npm1300 ship mode entry added Signed-off-by: Andy Sinclair --- drivers/regulator/regulator_npm1300.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/regulator/regulator_npm1300.c b/drivers/regulator/regulator_npm1300.c index 7f05e12b5b3e..ad52374466d8 100644 --- a/drivers/regulator/regulator_npm1300.c +++ b/drivers/regulator/regulator_npm1300.c @@ -33,6 +33,7 @@ enum npm1300_gpio_type { /* nPM1300 regulator base addresses */ #define BUCK_BASE 0x04U #define LDSW_BASE 0x08U +#define SHIP_BASE 0x0BU /* nPM1300 regulator register offsets */ #define BUCK_OFFSET_EN_SET 0x00U @@ -57,7 +58,11 @@ enum npm1300_gpio_type { #define LDSW_OFFSET_LDOSEL 0x08U #define LDSW_OFFSET_VOUTSEL 0x0CU +/* nPM1300 ship register offsets */ +#define SHIP_OFFSET_SHIP 0x02U + struct regulator_npm1300_pconfig { + const struct device *mfd; struct gpio_dt_spec dvs_state_pins[5]; }; @@ -440,8 +445,16 @@ int regulator_npm1300_dvs_state_set(const struct device *dev, regulator_dvs_stat return 0; } +int regulator_npm1300_ship_mode(const struct device *dev) +{ + const struct regulator_npm1300_pconfig *pconfig = dev->config; + + return mfd_npm1300_reg_write(pconfig->mfd, SHIP_BASE, SHIP_OFFSET_SHIP, 1U); +} + static const struct regulator_parent_driver_api parent_api = { .dvs_state_set = regulator_npm1300_dvs_state_set, + .ship_mode = regulator_npm1300_ship_mode, }; int regulator_npm1300_common_init(const struct device *dev) @@ -540,6 +553,7 @@ static const struct regulator_driver_api api = {.enable = regulator_npm1300_enab #define REGULATOR_NPM1300_DEFINE_ALL(inst) \ static const struct regulator_npm1300_pconfig config_##inst = { \ + .mfd = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ .dvs_state_pins = {GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 0, {0}), \ GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 1, {0}), \ GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 2, {0}), \ From 6d824667df23e785fd4c8847eda28dcfcfbbd0a2 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Tue, 18 Jul 2023 16:09:13 +0200 Subject: [PATCH 1452/2042] modules: align Kconfig.stm32 conforms the Kconfig.stm32 file with the CmakeLists.txt files for STM32H5x/C0x/U5x/WBx series Signed-off-by: Marc Desvaux --- modules/Kconfig.stm32 | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/modules/Kconfig.stm32 b/modules/Kconfig.stm32 index bb2ec3391757..ad598f630068 100644 --- a/modules/Kconfig.stm32 +++ b/modules/Kconfig.stm32 @@ -40,6 +40,12 @@ config USE_STM32_HAL_COMP Enable STM32Cube Ultra Low Power Comparator channels (COMP) HAL module driver +config USE_STM32_HAL_CORDIC + bool + help + Enable STM32Cube CORDIC co-processor (CORDIC) functions HAL module + driver + config USE_STM32_HAL_CORTEX bool help @@ -79,6 +85,11 @@ config USE_STM32_HAL_DAC_EX Enable STM32Cube Extended Digital-to-analog converter (DAC) HAL module driver +config USE_STM32_HAL_DCACHE + bool + help + Enable STM32Cube data cache (DCACHE) HAL module driver + config USE_STM32_HAL_DCMI bool help @@ -125,6 +136,11 @@ config USE_STM32_HAL_DSI help Enable STM32Cube Display Serial Interface Host (DSI) HAL module driver +config USE_STM32_HAL_DTS + bool + help + Enable STM32Cube Digital temperature sensor (DTS) HAL module driver + config USE_STM32_HAL_ETH bool help @@ -202,6 +218,18 @@ config USE_STM32_HAL_GPIO_EX Enable STM32Cube Extended General-purpose I/Os (GPIO) HAL module driver +config USE_STM32_HAL_GPU2D + bool + help + Enable STM32Cube Neo-Chrom graphic processor (GPU2D) HAL module + driver + +config USE_STM32_HAL_GTZC + bool + help + Enable STM32Cube Global TrustZone controller (GTZC) HAL module + driver + config USE_STM32_HAL_HASH bool help @@ -249,6 +277,17 @@ config USE_STM32_HAL_I2S_EX help Enable STM32Cube Extended Inter-IC sound (I2S) HAL module driver +config USE_STM32_HAL_I3C + bool + help + Enable STM32Cube Improved inter-integrated circuit (I3C) HAL module + driver + +config USE_STM32_HAL_ICACHE + bool + help + Enable STM32Cube Instruction cache (ICACHE) HAL module driver + config USE_STM32_HAL_IPCC bool help @@ -290,6 +329,11 @@ config USE_STM32_HAL_LTDC_EX help Enable STM32Cube Extended LCD-TFT controller (LTDC) HAL module driver +config USE_STM32_HAL_MDF + bool + help + Enable STM32Cube Multi-function digital filter (MDF) HAL module driver + config USE_STM32_HAL_MDIOS bool help @@ -313,6 +357,11 @@ config USE_STM32_HAL_MMC_EX Enable STM32Cube Extended MultiMediaCard interface (SDMMC) HAL module driver +config USE_STM32_HAL_MSP + bool + help + Enable STM32Cube MCU Support Package (MSP) HAL module driver + config USE_STM32_HAL_NAND bool help @@ -339,6 +388,12 @@ config USE_STM32_HAL_OSPI help Enable STM32Cube Octo-SPI interface (OSPI) HAL module driver +config USE_STM32_HAL_OTFDEC + bool + help + Enable STM32Cube On-the-fly decryption engine (OTFDEC) HAL module + driver + config USE_STM32_HAL_PCCARD bool help @@ -355,6 +410,11 @@ config USE_STM32_HAL_PCD_EX Enable STM32Cube Extended USB Peripheral Controller (PCD) HAL module driver +config USE_STM32_HAL_PKA + bool + help + Enable STM32Cube Public key accelerator (PKA) HAL module driver + config USE_STM32_HAL_PSSI bool help @@ -376,6 +436,12 @@ config USE_STM32_HAL_QSPI help Enable STM32Cube Quad-SPI interface (QSPI) HAL module driver +config USE_STM32_HAL_RAMCFG + bool + help + Enable STM32Cube RAMs configuration controller (RAMCFG) HAL module + driver + config USE_STM32_HAL_RAMECC bool help @@ -538,6 +604,12 @@ config USE_STM32_LL_COMP Enable STM32Cube Ultra Low Power Comparator channels (COMP) LL module driver +config USE_STM32_LL_CORDIC + bool + help + Enable STM32Cube CORDIC co-processor (CORDIC) functions LL module + driver + config USE_STM32_LL_CRC bool help @@ -614,12 +686,29 @@ config USE_STM32_LL_I2C Enable STM32Cube Inter-integrated circuit (I2C) interface LL module driver +config USE_STM32_LL_I3C + bool + help + Enable STM32Cube Improved inter-integrated circuit (I3C) LL module + driver + +config USE_STM32_LL_ICACHE + bool + help + Enable STM32Cube Instruction cache (ICACHE) LL module driver + config USE_STM32_LL_IPCC bool help Enable STM32Cube Inter-Processor communication controller (IPCC) LL module driver +config USE_STM32_LL_LPGPIO + bool + help + Enable STM32Cube Low-power general-purpose I/Os (LPGPIO) LL + module driver + config USE_STM32_LL_LPTIM bool help @@ -642,6 +731,11 @@ config USE_STM32_LL_OPAMP help Enable STM32Cube Operational amplifiers (OPAMP) LL module driver +config USE_STM32_LL_PKA + bool + help + Enable STM32Cube Public key accelerator (PKA) LL module driver + config USE_STM32_LL_PWR bool help From 820bc9267e678e2339026430c9812db805f82666 Mon Sep 17 00:00:00 2001 From: Marcin Zapolski Date: Tue, 18 Jul 2023 10:09:15 +0200 Subject: [PATCH 1453/2042] drivers: flash: stm32l4: Fix STM32L4Q5 support in flash driver Add STM32L4Q5xx to the list of MCUs that have 4kB flash pages, instead of 2kB. Signed-off-by: Marcin Zapolski --- drivers/flash/flash_stm32l4x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index c841c64ef7ee..56fe85e1fad6 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -20,7 +20,9 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #include "flash_stm32.h" -#if !defined (STM32L4R5xx) && !defined (STM32L4R7xx) && !defined (STM32L4R9xx) && !defined (STM32L4S5xx) && !defined (STM32L4S7xx) && !defined (STM32L4S9xx) +#if !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && \ + !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx) && \ + !defined(STM32L4Q5xx) #define STM32L4X_PAGE_SHIFT 11 #else #define STM32L4X_PAGE_SHIFT 12 From 09da4cf89df5b4be1caf6505c78aa543b0bed8ee Mon Sep 17 00:00:00 2001 From: Martin Kiepfer Date: Thu, 1 Jun 2023 23:57:45 +0200 Subject: [PATCH 1454/2042] driver: regulator: Add support for AXP192 power management IC AXP192 is a small and simple power management IC featuring different LDOs, DCDCs, AINs and also GPIOs. It also offers functionaltiy for battery management. This change includes the basic regulator driver functionaltiy for LDO2-3 and DCDC1-3 as well as the mfd driver layer. Further drivers for GPIO and ADC will follow. Drivers have been developed and tested on M5StackCore2, an ESP32-based board. Support for M5StackCore2 is still in progress. Signed-off-by: Martin Kiepfer --- drivers/mfd/CMakeLists.txt | 1 + drivers/mfd/Kconfig | 1 + drivers/mfd/Kconfig.axp192 | 10 + drivers/mfd/mfd_axp192.c | 61 +++ drivers/regulator/CMakeLists.txt | 1 + drivers/regulator/Kconfig | 1 + drivers/regulator/Kconfig.axp192 | 23 ++ drivers/regulator/regulator_axp192.c | 360 ++++++++++++++++++ dts/bindings/mfd/x-powers,axp192.yaml | 12 + .../regulator/x-powers,axp192-regulator.yaml | 64 ++++ include/zephyr/dt-bindings/regulator/axp192.h | 28 ++ tests/drivers/build_all/regulator/i2c.dtsi | 16 + 12 files changed, 578 insertions(+) create mode 100644 drivers/mfd/Kconfig.axp192 create mode 100644 drivers/mfd/mfd_axp192.c create mode 100644 drivers/regulator/Kconfig.axp192 create mode 100644 drivers/regulator/regulator_axp192.c create mode 100644 dts/bindings/mfd/x-powers,axp192.yaml create mode 100644 dts/bindings/regulator/x-powers,axp192-regulator.yaml create mode 100644 include/zephyr/dt-bindings/regulator/axp192.h diff --git a/drivers/mfd/CMakeLists.txt b/drivers/mfd/CMakeLists.txt index d7071a6af95b..0d27ef2c034f 100644 --- a/drivers/mfd/CMakeLists.txt +++ b/drivers/mfd/CMakeLists.txt @@ -5,3 +5,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_MFD_NPM1300 mfd_npm1300.c) zephyr_library_sources_ifdef(CONFIG_MFD_NPM6001 mfd_npm6001.c) +zephyr_library_sources_ifdef(CONFIG_MFD_AXP192 mfd_axp192.c) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 64a166c7cc78..114b78ad5874 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -18,6 +18,7 @@ config MFD_INIT_PRIORITY help Multi-function devices initialization priority. +source "drivers/mfd/Kconfig.axp192" source "drivers/mfd/Kconfig.npm1300" source "drivers/mfd/Kconfig.npm6001" diff --git a/drivers/mfd/Kconfig.axp192 b/drivers/mfd/Kconfig.axp192 new file mode 100644 index 000000000000..fed776d36564 --- /dev/null +++ b/drivers/mfd/Kconfig.axp192 @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX -License-Identifier: Apache-2.0 + +config MFD_AXP192 + bool "AXP192 PMIC multi-function device driver" + default y + depends on DT_HAS_X_POWERS_AXP192_ENABLED + select I2C + help + Enable the X-Powers AXP192 PMIC multi-function device driver diff --git a/drivers/mfd/mfd_axp192.c b/drivers/mfd/mfd_axp192.c new file mode 100644 index 000000000000..ee144721db40 --- /dev/null +++ b/drivers/mfd/mfd_axp192.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT x_powers_axp192 + +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(mfd_axp192, CONFIG_MFD_LOG_LEVEL); + +/* Chip ID value */ +#define AXP192_CHIP_ID 0x03U + +/* Registers definitions */ +#define AXP192_REG_CHIP_ID 0x03U + +struct mfd_axp192_config { + struct i2c_dt_spec i2c; +}; + +static int mfd_axp192_init(const struct device *dev) +{ + const struct mfd_axp192_config *config = dev->config; + uint8_t chip_id; + int ret; + + LOG_DBG("Initializing instance"); + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + /* Check if axp192 chip is available */ + ret = i2c_reg_read_byte_dt(&config->i2c, AXP192_REG_CHIP_ID, &chip_id); + if (ret < 0) { + return ret; + } + + if (chip_id != AXP192_CHIP_ID) { + LOG_ERR("Invalid Chip detected (%d)", chip_id); + return -EINVAL; + } + + return 0; +} + +#define MFD_AXP192_DEFINE(inst) \ + static const struct mfd_axp192_config config##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, mfd_axp192_init, NULL, NULL, &config##inst, POST_KERNEL, \ + CONFIG_MFD_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(MFD_AXP192_DEFINE) diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 1f5f9f8b3454..c5c616f0d2ab 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -4,6 +4,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_FAKE regulator_fake.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FIXED regulator_fixed.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c51d55b4de43..dc745407ec6f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -27,6 +27,7 @@ module = REGULATOR module-str = regulator source "subsys/logging/Kconfig.template.log_config" +source "drivers/regulator/Kconfig.axp192" source "drivers/regulator/Kconfig.adp5360" source "drivers/regulator/Kconfig.fake" source "drivers/regulator/Kconfig.fixed" diff --git a/drivers/regulator/Kconfig.axp192 b/drivers/regulator/Kconfig.axp192 new file mode 100644 index 000000000000..c2ec403359ef --- /dev/null +++ b/drivers/regulator/Kconfig.axp192 @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX -License-Identifier: Apache-2.0 + +config REGULATOR_AXP192 + bool "X-Power AXP192 PMIC regulator driver" + default y + depends on DT_HAS_X_POWERS_AXP192_REGULATOR_ENABLED + depends on DT_HAS_X_POWERS_AXP192_ENABLED + select I2C + select MFD + help + Enable the AXP PMIC regulator driver + +if REGULATOR_AXP192 + +config REGULATOR_AXP192_INIT_PRIORITY + int "AXP192 regulator driver init priority" + default 76 + help + Init priority for the axp192 regulator driver. It must be + greater than MFD_INIT_PRIORITY. + +endif diff --git a/drivers/regulator/regulator_axp192.c b/drivers/regulator/regulator_axp192.c new file mode 100644 index 000000000000..a2513d6e5aef --- /dev/null +++ b/drivers/regulator/regulator_axp192.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2021 NXP + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT x_powers_axp192_regulator + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(regulator_axp192, CONFIG_REGULATOR_LOG_LEVEL); + +/* Output control registers */ +#define AXP192_REG_EXTEN_DCDC2_CONTROL 0x10U +#define AXP192_REG_DCDC123_LDO23_CONTROL 0x12U +#define AXP192_REG_DCDC2_VOLTAGE 0x23U +#define AXP192_REG_DCDC2_SLOPE 0x25U +#define AXP192_REG_DCDC1_VOLTAGE 0x26U +#define AXP192_REG_DCDC3_VOLTAGE 0x27U +#define AXP192_REG_LDO23_VOLTAGE 0x28U +#define AXP192_REG_DCDC123_WORKMODE 0x80U + +struct regulator_axp192_desc { + const uint8_t enable_reg; + const uint8_t enable_mask; + const uint8_t enable_val; + const uint8_t vsel_reg; + const uint8_t vsel_mask; + const uint8_t vsel_bitpos; + const int32_t max_ua; + const uint8_t workmode_reg; + const uint8_t workmode_mask; + const uint8_t workmode_pwm_val; + const uint8_t num_ranges; + const struct linear_range *ranges; +}; + +struct regulator_axp192_data { + struct regulator_common_data data; +}; + +struct regulator_axp192_config { + struct regulator_common_config common; + const struct regulator_axp192_desc *desc; + const struct device *mfd; + const struct i2c_dt_spec i2c; + + LOG_INSTANCE_PTR_DECLARE(log); +}; + +static const struct linear_range dcdc1_ranges[] = { + LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x7FU), +}; + +static const struct regulator_axp192_desc dcdc1_desc = { + .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL, + .enable_mask = 0x01U, + .enable_val = 0x01U, + .vsel_reg = AXP192_REG_DCDC1_VOLTAGE, + .vsel_mask = 0x7FU, + .vsel_bitpos = 0U, + .max_ua = 1200000U, + .workmode_reg = AXP192_REG_DCDC123_WORKMODE, + .workmode_mask = 0x08U, + .workmode_pwm_val = 0x08U, + .ranges = dcdc1_ranges, + .num_ranges = ARRAY_SIZE(dcdc1_ranges), +}; + +static const struct linear_range dcdc2_ranges[] = { + LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x3FU), +}; + +static const struct regulator_axp192_desc dcdc2_desc = { + .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL, + .enable_mask = 0x10U, + .enable_val = 0x10U, + .vsel_reg = AXP192_REG_DCDC2_VOLTAGE, + .vsel_mask = 0x3FU, + .vsel_bitpos = 0U, + .max_ua = 1600000U, + .workmode_reg = AXP192_REG_DCDC123_WORKMODE, + .workmode_mask = 0x04U, + .workmode_pwm_val = 0x04U, + .ranges = dcdc2_ranges, + .num_ranges = ARRAY_SIZE(dcdc2_ranges), +}; + +static const struct linear_range dcdc3_ranges[] = { + LINEAR_RANGE_INIT(700000U, 25000U, 0x00U, 0x7FU), +}; + +static const struct regulator_axp192_desc dcdc3_desc = { + .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL, + .enable_mask = 0x02U, + .enable_val = 0x02U, + .vsel_reg = AXP192_REG_DCDC3_VOLTAGE, + .vsel_mask = 0x7FU, + .vsel_bitpos = 0U, + .max_ua = 700000U, + .workmode_reg = AXP192_REG_DCDC123_WORKMODE, + .workmode_mask = 0x02U, + .workmode_pwm_val = 0x02U, + .ranges = dcdc3_ranges, + .num_ranges = ARRAY_SIZE(dcdc3_ranges), +}; + +static const struct linear_range ldo2_ranges[] = { + LINEAR_RANGE_INIT(1800000U, 100000U, 0x00U, 0x0FU), +}; + +static const struct regulator_axp192_desc ldo2_desc = { + .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL, + .enable_mask = 0x04U, + .enable_val = 0x04U, + .vsel_reg = AXP192_REG_LDO23_VOLTAGE, + .vsel_mask = 0xF0U, + .vsel_bitpos = 4U, + .max_ua = 200000U, + .workmode_reg = 0U, + .workmode_mask = 0U, + .ranges = ldo2_ranges, + .num_ranges = ARRAY_SIZE(ldo2_ranges), +}; + +static const struct linear_range ldo3_ranges[] = { + LINEAR_RANGE_INIT(1800000U, 100000U, 0x00U, 0x0FU), +}; + +static const struct regulator_axp192_desc ldo3_desc = { + .enable_reg = AXP192_REG_DCDC123_LDO23_CONTROL, + .enable_mask = 0x08U, + .enable_val = 0x08U, + .vsel_reg = AXP192_REG_LDO23_VOLTAGE, + .vsel_mask = 0x0FU, + .vsel_bitpos = 0U, + .max_ua = 200000U, + .workmode_reg = 0U, + .workmode_mask = 0U, + .ranges = ldo3_ranges, + .num_ranges = ARRAY_SIZE(ldo3_ranges), +}; + +static int axp192_enable(const struct device *dev) +{ + const struct regulator_axp192_config *config = dev->config; + int ret; + + LOG_INST_DBG(config->log, "Enabling regulator"); + LOG_INST_DBG(config->log, "[0x%02x]=0x%02x mask=0x%02x", config->desc->enable_reg, + config->desc->enable_val, config->desc->enable_mask); + + ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->enable_reg, + config->desc->enable_mask, config->desc->enable_val); + if (ret != 0) { + LOG_INST_ERR(config->log, "Failed to enable regulator"); + } + + return ret; +} + +static int axp192_disable(const struct device *dev) +{ + const struct regulator_axp192_config *config = dev->config; + int ret; + + LOG_INST_DBG(config->log, "Disabling regulator"); + LOG_INST_DBG(config->log, "[0x%02x]=0 mask=0x%x", config->desc->enable_reg, + config->desc->enable_mask); + + ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->enable_reg, + config->desc->enable_mask, 0u); + if (ret != 0) { + LOG_INST_ERR(config->log, "Failed to disable regulator"); + } + + return ret; +} + +static unsigned int axp192_count_voltages(const struct device *dev) +{ + const struct regulator_axp192_config *config = dev->config; + + return linear_range_group_values_count(config->desc->ranges, config->desc->num_ranges); +} + +static int axp192_list_voltage(const struct device *dev, unsigned int idx, int32_t *volt_uv) +{ + const struct regulator_axp192_config *config = dev->config; + + return linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, idx, + volt_uv); +} + +static int axp192_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) +{ + const struct regulator_axp192_config *config = dev->config; + uint16_t idx; + int ret; + + LOG_INST_DBG(config->log, "voltage = [min=%d, max=%d]", min_uv, max_uv); + + /* set voltage */ + ret = linear_range_group_get_win_index(config->desc->ranges, config->desc->num_ranges, + min_uv, max_uv, &idx); + if (ret != 0) { + LOG_INST_ERR(config->log, "No voltage range window could be detected"); + return ret; + } + + idx <<= config->desc->vsel_bitpos; + + LOG_INST_DBG(config->log, "[0x%x]=0x%x mask=0x%x", config->desc->vsel_reg, idx, + config->desc->vsel_mask); + ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->vsel_reg, config->desc->vsel_mask, + (uint8_t)idx); + if (ret != 0) { + LOG_INST_ERR(config->log, "Failed to set regulator voltage"); + } + + return ret; +} + +static int axp192_get_voltage(const struct device *dev, int32_t *volt_uv) +{ + const struct regulator_axp192_config *config = dev->config; + int ret; + uint8_t raw_reg; + + /* read voltage */ + ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->vsel_reg, &raw_reg); + if (ret != 0) { + return ret; + } + + raw_reg = (raw_reg & config->desc->vsel_mask) >> config->desc->vsel_bitpos; + + ret = linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, raw_reg, + volt_uv); + + return ret; +} + +static int axp192_set_mode(const struct device *dev, regulator_mode_t mode) +{ + const struct regulator_axp192_config *config = dev->config; + int ret; + + /* setting workmode is only possible for DCDC1-3 */ + if ((mode == AXP192_DCDC_MODE_PWM) && (config->desc->workmode_reg != 0)) { + + /* configure PWM mode */ + LOG_INST_DBG(config->log, "PWM mode enabled"); + ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->workmode_reg, + config->desc->workmode_mask, + config->desc->workmode_pwm_val); + if (ret != 0) { + return ret; + } + } else if (mode == AXP192_DCDC_MODE_AUTO) { + + /* configure AUTO mode (default) */ + if (config->desc->workmode_reg != 0) { + ret = i2c_reg_update_byte_dt(&config->i2c, config->desc->workmode_reg, + config->desc->workmode_mask, 0u); + if (ret != 0) { + return ret; + } + } else { + + /* AUTO is default mode for LDOs that cannot be configured */ + return 0; + } + } else { + LOG_INST_ERR(config->log, "Setting DCDC workmode failed"); + return -ENOTSUP; + } + + return 0; +} + +static int axp192_get_current_limit(const struct device *dev, int32_t *curr_ua) +{ + const struct regulator_axp192_config *config = dev->config; + + *curr_ua = config->desc->max_ua; + + return 0; +} + +static struct regulator_driver_api api = { + .enable = axp192_enable, + .disable = axp192_disable, + .count_voltages = axp192_count_voltages, + .list_voltage = axp192_list_voltage, + .set_voltage = axp192_set_voltage, + .get_voltage = axp192_get_voltage, + .set_mode = axp192_set_mode, + .get_current_limit = axp192_get_current_limit, +}; + +static int regulator_axp192_init(const struct device *dev) +{ + const struct regulator_axp192_config *config = dev->config; + uint8_t enabled_val; + bool is_enabled; + int ret = 0; + + regulator_common_data_init(dev); + + if (!device_is_ready(config->mfd)) { + LOG_INST_ERR(config->log, "Parent instance not ready!"); + return -ENODEV; + } + + /* read regulator state */ + ret = i2c_reg_read_byte_dt(&config->i2c, config->desc->enable_reg, &enabled_val); + if (ret != 0) { + LOG_INST_ERR(config->log, "Reading enable status failed!"); + return ret; + } + is_enabled = ((enabled_val & config->desc->enable_mask) == config->desc->enable_val); + LOG_INST_DBG(config->log, "is_enabled: %d", is_enabled); + + return regulator_common_init(dev, is_enabled); +} + +#define REGULATOR_AXP192_DEFINE(node_id, id, name) \ + static struct regulator_axp192_data data_##id; \ + LOG_INSTANCE_REGISTER(name, node_id, CONFIG_REGULATOR_LOG_LEVEL); \ + static const struct regulator_axp192_config config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \ + .desc = &name##_desc, \ + .mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \ + .i2c = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \ + LOG_INSTANCE_PTR_INIT(log, name, node_id)}; \ + DEVICE_DT_DEFINE(node_id, regulator_axp192_init, NULL, &data_##id, &config_##id, \ + POST_KERNEL, CONFIG_REGULATOR_AXP192_INIT_PRIORITY, &api); + +#define REGULATOR_AXP192_DEFINE_COND(inst, child) \ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_AXP192_DEFINE(DT_INST_CHILD(inst, child), child##inst, child)), ()) + +#define REGULATOR_AXP192_DEFINE_ALL(inst) \ + REGULATOR_AXP192_DEFINE_COND(inst, dcdc1) \ + REGULATOR_AXP192_DEFINE_COND(inst, dcdc2) \ + REGULATOR_AXP192_DEFINE_COND(inst, dcdc3) \ + REGULATOR_AXP192_DEFINE_COND(inst, ldo2) \ + REGULATOR_AXP192_DEFINE_COND(inst, ldo3) + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_AXP192_DEFINE_ALL) diff --git a/dts/bindings/mfd/x-powers,axp192.yaml b/dts/bindings/mfd/x-powers,axp192.yaml new file mode 100644 index 000000000000..ae181715e880 --- /dev/null +++ b/dts/bindings/mfd/x-powers,axp192.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023, Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: X-Powers AXP192 + +compatible: "x-powers,axp192" + +include: i2c-device.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/regulator/x-powers,axp192-regulator.yaml b/dts/bindings/regulator/x-powers,axp192-regulator.yaml new file mode 100644 index 000000000000..6f8d8718357a --- /dev/null +++ b/dts/bindings/regulator/x-powers,axp192-regulator.yaml @@ -0,0 +1,64 @@ +# Copyright (c), 2021 NXP +# Copyright (c), 2023 Martin Kiepfer +# SPDX -License-Identifier: Apache-2.0 + +description: | + AXP192 PMIC + + The PMIC has three DCDC converters and two LDOs (LDO1 cannot be disabled). + All need to be defined as children nodes. + For example: + + i2c { + pmic@34 { + reg = <0x34>; + ... + regulators { + compatible = "x-powers,axp192-regulator"; + + DCDC1 { + /* all properties for DCDC1 */ + }; + DCDC2 { + /* all properties for DCDC2 */ + }; + DCDC3 { + /* all properties for DCDC3 */ + }; + LDO2 { + /* all properties for LDO2 */ + }; + LDO3 { + /* all properties for LDO3 */ + }; + }; + }; + }; + +compatible: "x-powers,axp192-regulator" + +include: base.yaml + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-init-microvolt + - regulator-min-microvolt + - regulator-max-microvolt + - regulator-always-on + - regulator-boot-on + - regulator-initial-mode + - regulator-allowed-modes + + properties: + regulator-initial-mode: + type: int + default: 0 + enum: + - 0 + - 1 + description: | + Initial operating mode. AXP192 supports 2 different power modes: + AXP192_DCDC_MODE_AUTO: Auto (0, default) + AXP192_DCDC_MODE_PWM: PWM diff --git a/include/zephyr/dt-bindings/regulator/axp192.h b/include/zephyr/dt-bindings/regulator/axp192.h new file mode 100644 index 000000000000..0ea2eedd3aae --- /dev/null +++ b/include/zephyr/dt-bindings/regulator/axp192.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_AXP192_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_AXP192_H_ + +/** + * @defgroup regulator_axp192 AXP192 Devicetree helpers. + * @ingroup regulator_interface + * @{ + */ + +/** + * @name AXP192 Regulator modes + * @{ + */ +/* DCDCs */ +#define AXP192_DCDC_MODE_AUTO 0x00U +#define AXP192_DCDC_MODE_PWM 0x01U + +/** @} */ + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_AXP192_H_ */ diff --git a/tests/drivers/build_all/regulator/i2c.dtsi b/tests/drivers/build_all/regulator/i2c.dtsi index 36818b03e8fd..250c359f9c89 100644 --- a/tests/drivers/build_all/regulator/i2c.dtsi +++ b/tests/drivers/build_all/regulator/i2c.dtsi @@ -58,3 +58,19 @@ apd356x@3 { BUCKBOOST {}; }; }; + +axp192@4 { + compatible = "x-powers,axp192"; + reg = <0x4>; + + regulators { + compatible = "x-powers,axp192-regulator"; + + DCDC1 {}; + DCDC2 {}; + DCDC3 {}; + LDO1 {}; + LDO2 {}; + LDO3 {}; + }; +}; From 6e2cad555a24583cd342c2dd20df0f17187372db Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 7 Jul 2023 15:42:50 +0200 Subject: [PATCH 1455/2042] board: arm: stm32h573i_dk: add Ethernet add Ethernet for stm32h573i_dk Signed-off-by: Marc Desvaux --- boards/arm/stm32h573i_dk/Kconfig.defconfig | 7 +++++++ boards/arm/stm32h573i_dk/stm32h573i_dk.dts | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/boards/arm/stm32h573i_dk/Kconfig.defconfig b/boards/arm/stm32h573i_dk/Kconfig.defconfig index 166ce9e13dd9..d9bf4c722894 100644 --- a/boards/arm/stm32h573i_dk/Kconfig.defconfig +++ b/boards/arm/stm32h573i_dk/Kconfig.defconfig @@ -10,4 +10,11 @@ if BOARD_STM32H573I_DK config BOARD default "stm32h573i_dk" +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + endif # BOARD_STM32H573I_DK diff --git a/boards/arm/stm32h573i_dk/stm32h573i_dk.dts b/boards/arm/stm32h573i_dk/stm32h573i_dk.dts index 2b0041f3f680..04198a033328 100644 --- a/boards/arm/stm32h573i_dk/stm32h573i_dk.dts +++ b/boards/arm/stm32h573i_dk/stm32h573i_dk.dts @@ -16,7 +16,7 @@ chosen { zephyr,console = &usart1; zephyr,shell-uart = &usart1; - zephyr,sram = &sram0; + zephyr,sram = &sram1; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; zephyr,canbus = &can1; @@ -131,6 +131,20 @@ status = "okay"; }; +&mac { + status = "okay"; + pinctrl-0 = <ð_mdc_pc1 + ð_rxd0_pc4 + ð_rxd1_pc5 + ð_ref_clk_pa1 + ð_mdio_pa2 + ð_crs_dv_pa7 + ð_tx_en_pg11 + ð_txd0_pg13 + ð_txd1_pg12>; + pinctrl-names = "default"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; From 45f4f271d270c3e9dd9f3446dc2105cb66b5ca12 Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 7 Jul 2023 15:45:00 +0200 Subject: [PATCH 1456/2042] dts: arm: st: h5: add Ethernet add Ethernet for stmh573i_dk Signed-off-by: Marc Desvaux --- dts/arm/st/h5/stm32h573Xi.dtsi | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dts/arm/st/h5/stm32h573Xi.dtsi b/dts/arm/st/h5/stm32h573Xi.dtsi index 152d9cbd6bf4..3e4a8b0efcf0 100644 --- a/dts/arm/st/h5/stm32h573Xi.dtsi +++ b/dts/arm/st/h5/stm32h573Xi.dtsi @@ -7,8 +7,22 @@ #include / { - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(640)>; + sram1: memory@20000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; + zephyr,memory-region = "SRAM1"; + }; + + sram2: memory@20040000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(64)>; + zephyr,memory-region = "SRAM2"; + }; + + sram3: memory@20050000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20050000 DT_SIZE_K(320)>; + zephyr,memory-region = "SRAM3"; }; soc { From 5a55a185dd6faa0c551260658c220a40bd03ed02 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 23 Jun 2023 14:28:19 +0200 Subject: [PATCH 1457/2042] dts: bindings: clock: add specific rcc bindings for stm32f1x and f3x Add two new bindings for STM32F1x and F3x RCC to add the ADC prescaler specific to these series. Signed-off-by: Guillaume Gautier --- dts/bindings/clock/st,stm32f1-rcc.yaml | 23 +++++++++++ dts/bindings/clock/st,stm32f3-rcc.yaml | 55 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 dts/bindings/clock/st,stm32f1-rcc.yaml create mode 100644 dts/bindings/clock/st,stm32f3-rcc.yaml diff --git a/dts/bindings/clock/st,stm32f1-rcc.yaml b/dts/bindings/clock/st,stm32f1-rcc.yaml new file mode 100644 index 000000000000..00f54374335c --- /dev/null +++ b/dts/bindings/clock/st,stm32f1-rcc.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32F1 and STM32F37x Reset and Clock controller node. + Adds the ADC prescaler to the standard generic STM32 RCC. + For more description confere st,stm32-rcc.yaml + +compatible: "st,stm32f1-rcc" + +include: st,stm32-rcc.yaml + +properties: + adc-prescaler: + type: int + enum: + - 2 + - 4 + - 6 + - 8 + description: | + ADC prescaler. Defines ADC core clock frequency + based on APB2 frequency input. diff --git a/dts/bindings/clock/st,stm32f3-rcc.yaml b/dts/bindings/clock/st,stm32f3-rcc.yaml new file mode 100644 index 000000000000..5e9825129f72 --- /dev/null +++ b/dts/bindings/clock/st,stm32f3-rcc.yaml @@ -0,0 +1,55 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STM32F3 Reset and Clock controller node. + Adds the STM32F3 ADC prescaler to the standard generic STM32 RCC. + For more description confere st,stm32-rcc.yaml + +compatible: "st,stm32f3-rcc" + +include: st,stm32-rcc.yaml + +properties: + adc12-prescaler: + type: int + enum: + - 0 # Synchronous mode + - 1 # not divided + - 2 + - 4 + - 6 + - 8 + - 10 + - 12 + - 16 + - 32 + - 64 + - 128 + - 256 + description: | + ADC 1 and 2 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 + + adc34-prescaler: + type: int + enum: + - 0 # Synchronous mode + - 1 # not divided + - 2 + - 4 + - 6 + - 8 + - 10 + - 12 + - 16 + - 32 + - 64 + - 128 + - 256 + description: | + 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. From 208d962eb86a1cde25f4fd7362c77978ae2b6046 Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 23 Jun 2023 14:33:55 +0200 Subject: [PATCH 1458/2042] drivers: clock_control: stm32 set adc prescaler in rcc For STM32F1 and F3, set the ADC prescaler in RCC if defined in dts. Signed-off-by: Guillaume Gautier --- drivers/clock_control/clock_stm32_ll_common.c | 9 ++++++++ drivers/clock_control/clock_stm32f0_f3.c | 22 +++++++++++++++++++ drivers/clock_control/clock_stm32f1.c | 3 +++ .../clock_control/stm32_clock_control.h | 4 ++++ 4 files changed, 38 insertions(+) diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index 52ca69c24264..96368dd6b82e 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -842,6 +842,15 @@ int stm32_clock_control_init(const struct device *dev) #if DT_NODE_HAS_PROP(DT_NODELABEL(rcc), ahb4_prescaler) LL_RCC_SetAHB4Prescaler(ahb_prescaler(STM32_AHB4_PRESCALER)); #endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(rcc), adc_prescaler) + LL_RCC_SetADCClockSource(adc_prescaler(STM32_ADC_PRESCALER)); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(rcc), adc12_prescaler) + LL_RCC_SetADCClockSource(adc_prescaler(STM32_ADC12_PRESCALER)); +#endif +#if DT_NODE_HAS_PROP(DT_NODELABEL(rcc), adc34_prescaler) + LL_RCC_SetADCClockSource(adc_prescaler(STM32_ADC34_PRESCALER)); +#endif /* configure MCO1/MCO2 based on Kconfig */ stm32_clock_control_mco_init(); diff --git a/drivers/clock_control/clock_stm32f0_f3.c b/drivers/clock_control/clock_stm32f0_f3.c index 2557355a6f41..a4843782dfdc 100644 --- a/drivers/clock_control/clock_stm32f0_f3.c +++ b/drivers/clock_control/clock_stm32f0_f3.c @@ -15,6 +15,28 @@ #include #include "clock_stm32_ll_common.h" +#if defined(RCC_CFGR_ADCPRE) +#define z_adc_prescaler(v) LL_RCC_ADC_CLKSRC_PCLK2_DIV_ ## v +#define adc_prescaler(v) z_adc_prescaler(v) +#elif defined(RCC_CFGR2_ADC1PRES) +#define z_adc12_prescaler(v) \ + COND_CODE_1(IS_EQ(v, 0), \ + LL_RCC_ADC1_CLKSRC_HCLK, \ + LL_RCC_ADC1_CLKSRC_PLL_DIV_ ## v) +#define adc12_prescaler(v) z_adc12_prescaler(v) +#else +#define z_adc12_prescaler(v) \ + COND_CODE_1(IS_EQ(v, 0), \ + LL_RCC_ADC12_CLKSRC_HCLK, \ + LL_RCC_ADC12_CLKSRC_PLL_DIV_ ## v) +#define adc12_prescaler(v) z_adc12_prescaler(v) +#define z_adc34_prescaler(v) \ + COND_CODE_1(IS_EQ(v, 0), \ + LL_RCC_ADC34_CLKSRC_HCLK, \ + LL_RCC_ADC34_CLKSRC_PLL_DIV_ ## v) +#define adc34_prescaler(v) z_adc34_prescaler(v) +#endif + #if defined(STM32_PLL_ENABLED) /** diff --git a/drivers/clock_control/clock_stm32f1.c b/drivers/clock_control/clock_stm32f1.c index 760e417eaab0..c882fcc40df7 100644 --- a/drivers/clock_control/clock_stm32f1.c +++ b/drivers/clock_control/clock_stm32f1.c @@ -21,6 +21,9 @@ #define STM32_USB_PRE_ENABLED RCC_CFGR_OTGFSPRE #endif +#define z_adc_prescaler(v) LL_RCC_ADC_CLKSRC_PCLK2_DIV_ ## v +#define adc_prescaler(v) z_adc_prescaler(v) + #if defined(STM32_PLL_ENABLED) /* diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index 41be8d14996b..c69718f10487 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -82,6 +82,10 @@ #define STM32_FLASH_PRESCALER STM32_CORE_PRESCALER #endif +#define STM32_ADC_PRESCALER DT_PROP(DT_NODELABEL(rcc), adc_prescaler) +#define STM32_ADC12_PRESCALER DT_PROP(DT_NODELABEL(rcc), adc12_prescaler) +#define STM32_ADC34_PRESCALER DT_PROP(DT_NODELABEL(rcc), adc34_prescaler) + /** STM2H7 specifics RCC dividers */ #define STM32_D1CPRE DT_PROP(DT_NODELABEL(rcc), d1cpre) #define STM32_HPRE DT_PROP(DT_NODELABEL(rcc), hpre) From 3fba82490b5189de33f93bf6f8676805fbdab96b Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 23 Jun 2023 14:40:10 +0200 Subject: [PATCH 1459/2042] dts: arm: st: update stm32f1 and f3 dtsi with new rcc bindings Add the new RCC bindings to the dtsi files. STM32F373 uses the RCC F1 bindings because the ADC prescaler is the same on the two series. Signed-off-by: Guillaume Gautier --- dts/arm/st/f1/stm32f1.dtsi | 2 +- dts/arm/st/f3/stm32f3.dtsi | 2 +- dts/arm/st/f3/stm32f373.dtsi | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index fc8bcb31266e..5b0d9f002c44 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -93,7 +93,7 @@ }; rcc: rcc@40021000 { - compatible = "st,stm32-rcc"; + compatible = "st,stm32f1-rcc"; #clock-cells = <2>; reg = <0x40021000 0x400>; diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index b86627a03a33..4f208b2d5b54 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -94,7 +94,7 @@ }; rcc: rcc@40021000 { - compatible = "st,stm32-rcc"; + compatible = "st,stm32f3-rcc"; #clock-cells = <2>; reg = <0x40021000 0x400>; diff --git a/dts/arm/st/f3/stm32f373.dtsi b/dts/arm/st/f3/stm32f373.dtsi index 0c42d87d0955..36225c63146b 100644 --- a/dts/arm/st/f3/stm32f373.dtsi +++ b/dts/arm/st/f3/stm32f373.dtsi @@ -11,6 +11,14 @@ soc { compatible = "st,stm32f373", "st,stm32f3", "simple-bus"; + rcc: rcc@40021000 { + /* + * Use the STM32F1 compatible that define the same ADC + * prescaler in the RCC register + */ + compatible = "st,stm32f1-rcc"; + }; + pinctrl: pin-controller@48000000 { gpioe: gpio@48001000 { compatible = "st,stm32-gpio"; From ef0d358048c9824a931fd426703073cffc9e5e15 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Mar 2023 11:28:55 +0100 Subject: [PATCH 1460/2042] dts: stm32wba: Add RNG node Add RNG node, configured to use 48MHz clock from PLL_Q. Configured with NIST parameters. Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 0f8c5ba2cbd4..28f3a3a7327e 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -18,6 +18,7 @@ / { chosen { + zephyr,entropy = &rng; zephyr,flash-controller = &flash; }; @@ -384,6 +385,17 @@ interrupt-names = "wakeup"; status = "disabled"; }; + + rng: rng@520c0800 { + compatible = "st,stm32-rng"; + reg = <0x520c0800 0x400>; + interrupts = <59 0>; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00040000>, + <&rcc STM32_SRC_PLL1_Q RNG_SEL(3)>; + nist-config = <0xf00d>; + health-test-config = <0xaac7>; + status = "disabled"; + }; }; }; From e13c193acf57c2283240f690cbae4fd48607ebf9 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 7 Mar 2023 08:44:17 +0100 Subject: [PATCH 1461/2042] boards: nucleo_wba52cg: Update core freq to provide 48MHz on PLLQ PLL Q is used as 48MHz clock source, which is required for RNG Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index f59b38eaeed5..5fda629625ff 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -70,16 +70,16 @@ &pll1 { div-m = <8>; - mul-n = <100>; + mul-n = <48>; div-q = <2>; - div-r = <4>; + div-r = <2>; clocks = <&clk_hse>; status = "okay"; }; &rcc { clocks = <&pll1>; - clock-frequency = ; + clock-frequency = ; ahb-prescaler = <1>; ahb5-prescaler = <4>; apb1-prescaler = <1>; @@ -123,3 +123,7 @@ <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; }; + +&rng { + status = "okay"; +}; From 62545273430ade73332ca8542dc18fd2e8e1c91e Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 18 Jul 2023 08:58:54 +0200 Subject: [PATCH 1462/2042] drivers: timer: stm32 lptim driver check clock_control_on return code This PR is Calling "clock_control_on" and checking return value (as is done elsewhere 10 out of 11 times) CID 322066: Error handling issues (CHECKED_RETURN) Signed-off-by: Francois Ramu --- drivers/timer/stm32_lptim_timer.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index e8938399db77..839e16b52a86 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -179,6 +179,7 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) { /* new LPTIM AutoReload value to set (aligned on Kernel ticks) */ uint32_t next_arr = 0; + int err; ARG_UNUSED(idle); @@ -192,8 +193,11 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) } /* if LPTIM clock was previously stopped, it must now be restored */ - clock_control_on(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]); + err = clock_control_on(clk_ctrl, (clock_control_subsys_t) &lptim_clk[0]); + if (err < 0) { + return; + } /* passing ticks==1 means "announce the next tick", * ticks value of zero (or even negative) is legal and * treated identically: it simply indicates the kernel would like the @@ -328,7 +332,6 @@ static int sys_clock_driver_init(void) uint32_t count_per_tick; int err; - if (!device_is_ready(clk_ctrl)) { return -ENODEV; } From 1c0c2a095b483985ac5a4a1cd3075bd03c11211c Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 16 Jun 2023 13:15:14 +0200 Subject: [PATCH 1463/2042] drivers: intel_adsp_gpdma: Fix release ownership Fixes a bug in intel_adsp_gpdma_release_ownership(). Before fix, this function actually did nothing for ACE platform and the ownership was not released. Now ownership is released to host CPU + DSP. Signed-off-by: Serhiy Katsyuba --- drivers/dma/dma_intel_adsp_gpdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma_intel_adsp_gpdma.c b/drivers/dma/dma_intel_adsp_gpdma.c index 219cec7fad30..3564b15be0ac 100644 --- a/drivers/dma/dma_intel_adsp_gpdma.c +++ b/drivers/dma/dma_intel_adsp_gpdma.c @@ -292,7 +292,7 @@ static void intel_adsp_gpdma_release_ownership(const struct device *dev) #ifdef CONFIG_SOC_SERIES_INTEL_ACE const struct intel_adsp_gpdma_cfg *const dev_cfg = dev->config; uint32_t reg = dev_cfg->shim + GPDMA_CTL_OFFSET; - uint32_t val = sys_read32(reg) & ~GPDMA_OSEL(0x0); + uint32_t val = sys_read32(reg) & ~GPDMA_OSEL(0x3); sys_write32(val, reg); /* CHECKME: Do CAVS platforms set ownership over DMA, From 53b93829a3a80489bddba110f9a13d059f4a3096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 17:11:44 +0200 Subject: [PATCH 1464/2042] bluetooth: ead: Add include guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a missing include guard Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/ead.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/zephyr/bluetooth/ead.h b/include/zephyr/bluetooth/ead.h index 1128044839cf..3df5df293caf 100644 --- a/include/zephyr/bluetooth/ead.h +++ b/include/zephyr/bluetooth/ead.h @@ -5,6 +5,9 @@ #include #include +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_EAD_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_EAD_H_ + #include #include @@ -89,3 +92,5 @@ int bt_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[ int bt_ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[BT_EAD_IV_SIZE], const uint8_t *encrypted_payload, size_t encrypted_payload_size, uint8_t *payload); + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_EAD_H_ */ \ No newline at end of file From f6f3eed7a0da7079d41f86ae7783c13273cee436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 17:19:00 +0200 Subject: [PATCH 1465/2042] bluetooth: ead: doc: Add missing Doxygen header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File was missing Doxygen @brief and @infroup causing it to not be mounted in the documentation. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/ead.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/ead.h b/include/zephyr/bluetooth/ead.h index 3df5df293caf..ba4de42ce404 100644 --- a/include/zephyr/bluetooth/ead.h +++ b/include/zephyr/bluetooth/ead.h @@ -11,6 +11,13 @@ #include #include +/** + * @brief Encrypted Advertising Data (EAD) + * @defgroup bt_ead Encrypted Advertising Data (EAD) + * @ingroup bluetooth + * @{ + */ + /** Randomizer size in bytes */ #define BT_EAD_RANDOMIZER_SIZE 5 /** Key size in bytes */ @@ -93,4 +100,8 @@ int bt_ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[ const uint8_t *encrypted_payload, size_t encrypted_payload_size, uint8_t *payload); -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_EAD_H_ */ \ No newline at end of file +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_EAD_H_ */ From b7ec7ec638451362d2cd2a58edc57a4ff5235fc5 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Mon, 17 Jul 2023 20:04:02 +0000 Subject: [PATCH 1466/2042] debug: thread_analyzer: use printk by default When enabling thread analyzer, use printk by default. Otherwise logging subsystem is enabled which might not be desired. Fixes #59919 Signed-off-by: Anas Nashif --- subsys/debug/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index a94b96d44ce5..47b03f253257 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -26,6 +26,7 @@ source "subsys/logging/Kconfig.template.log_config" choice prompt "Thread analysis print mode" + default THREAD_ANALYZER_USE_PRINTK config THREAD_ANALYZER_USE_LOG bool "Use logger output" From bc0eb32a5e5734e408d93c6260ba838f28e4d881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 16:52:14 +0200 Subject: [PATCH 1467/2042] pcie: doc: Fix doxygen doc for PCIe capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use proper doxygen comments for the PCIe Capabilities. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/pcie/cap.h | 145 ++++++++++++++++-------------- 1 file changed, 77 insertions(+), 68 deletions(-) diff --git a/include/zephyr/drivers/pcie/cap.h b/include/zephyr/drivers/pcie/cap.h index 7a0aeb954ce6..e72d674c1bb0 100644 --- a/include/zephyr/drivers/pcie/cap.h +++ b/include/zephyr/drivers/pcie/cap.h @@ -7,84 +7,93 @@ #define ZEPHYR_INCLUDE_DRIVERS_PCIE_CAP_H_ /** + * @file * @brief PCIe Capabilities * @defgroup pcie_capabilities PCIe Capabilities * @ingroup pcie_host_interface * @{ */ -/* - * PCI & PCI Express Capabilities - * from PCI Code and ID Assignment Specification Revision 1.11 +/** + * @name PCI & PCI Express Capabilities + * + * From PCI Code and ID Assignment Specification Revision 1.11 + * @{ + */ +#define PCI_CAP_ID_NULL 0x00U /**< Null Capability */ +#define PCI_CAP_ID_PM 0x01U /**< Power Management */ +#define PCI_CAP_ID_AGP 0x02U /**< Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03U /**< Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04U /**< Slot Identification */ +#define PCI_CAP_ID_MSI 0x05U /**< Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06U /**< CompactPCI HotSwap */ +#define PCI_CAP_ID_PCIX 0x07U /**< PCI-X */ +#define PCI_CAP_ID_HT 0x08U /**< HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09U /**< Vendor-Specific */ +#define PCI_CAP_ID_DBG 0x0AU /**< Debug port */ +#define PCI_CAP_ID_CCRC 0x0BU /**< CompactPCI Central Resource Control */ +#define PCI_CAP_ID_SHPC 0x0CU /**< PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_SSVID 0x0DU /**< Bridge subsystem vendor/device ID */ +#define PCI_CAP_ID_AGP3 0x0EU /**< AGP 8x */ +#define PCI_CAP_ID_SECDEV 0x0FU /**< Secure Device */ +#define PCI_CAP_ID_EXP 0x10U /**< PCI Express */ +#define PCI_CAP_ID_MSIX 0x11U /**< MSI-X */ +#define PCI_CAP_ID_SATA 0x12U /**< Serial ATA Data/Index Configuration */ +#define PCI_CAP_ID_AF 0x13U /**< PCI Advanced Features */ +#define PCI_CAP_ID_EA 0x14U /**< PCI Enhanced Allocation */ +#define PCI_CAP_ID_FPB 0x14U /**< Flattening Portal Bridge */ +/** + * @} */ -#define PCI_CAP_ID_NULL 0x00U /* Null Capability */ -#define PCI_CAP_ID_PM 0x01U /* Power Management */ -#define PCI_CAP_ID_AGP 0x02U /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03U /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04U /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05U /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06U /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07U /* PCI-X */ -#define PCI_CAP_ID_HT 0x08U /* HyperTransport */ -#define PCI_CAP_ID_VNDR 0x09U /* Vendor-Specific */ -#define PCI_CAP_ID_DBG 0x0AU /* Debug port */ -#define PCI_CAP_ID_CCRC 0x0BU /* CompactPCI Central Resource Control */ -#define PCI_CAP_ID_SHPC 0x0CU /* PCI Standard Hot-Plug Controller */ -#define PCI_CAP_ID_SSVID 0x0DU /* Bridge subsystem vendor/device ID */ -#define PCI_CAP_ID_AGP3 0x0EU /* AGP 8x */ -#define PCI_CAP_ID_SECDEV 0x0FU /* Secure Device */ -#define PCI_CAP_ID_EXP 0x10U /* PCI Express */ -#define PCI_CAP_ID_MSIX 0x11U /* MSI-X */ -#define PCI_CAP_ID_SATA 0x12U /* Serial ATA Data/Index Configuration */ -#define PCI_CAP_ID_AF 0x13U /* PCI Advanced Features */ -#define PCI_CAP_ID_EA 0x14U /* PCI Enhanced Allocation */ -#define PCI_CAP_ID_FPB 0x14U /* Flattening Portal Bridge */ - -/* - * PCI Express Extended Capabilities +/** + * @name PCI Express Extended Capabilities + * @{ */ -#define PCIE_EXT_CAP_ID_NULL 0x0000U /* Null Capability */ -#define PCIE_EXT_CAP_ID_ERR 0x0001U /* Advanced Error Reporting */ -#define PCIE_EXT_CAP_ID_VC 0x0002U /* Virtual Channel when no MFVC */ -#define PCIE_EXT_CAP_ID_DSN 0x0003U /* Device Serial Number */ -#define PCIE_EXT_CAP_ID_PWR 0x0004U /* Power Budgeting */ -#define PCIE_EXT_CAP_ID_RCLD 0x0005U /* Root Complex Link Declaration */ -#define PCIE_EXT_CAP_ID_RCILC 0x0006U /* Root Complex Internal Link Control */ -#define PCIE_EXT_CAP_ID_RCEC 0x0007U /* Root Complex Event Collector Endpoint Association */ -#define PCIE_EXT_CAP_ID_MFVC 0x0008U /* Multi-Function VC Capability */ -#define PCIE_EXT_CAP_ID_MFVC_VC 0x0009U /* Virtual Channel used with MFVC */ -#define PCIE_EXT_CAP_ID_RCRB 0x000AU /* Root Complex Register Block */ -#define PCIE_EXT_CAP_ID_VNDR 0x000BU /* Vendor-Specific Extended Capability */ -#define PCIE_EXT_CAP_ID_CAC 0x000CU /* Config Access Correlation - obsolete */ -#define PCIE_EXT_CAP_ID_ACS 0x000DU /* Access Control Services */ -#define PCIE_EXT_CAP_ID_ARI 0x000EU /* Alternate Routing-ID Interpretation */ -#define PCIE_EXT_CAP_ID_ATS 0x000FU /* Address Translation Services */ -#define PCIE_EXT_CAP_ID_SRIOV 0x0010U /* Single Root I/O Virtualization */ -#define PCIE_EXT_CAP_ID_MRIOV 0x0011U /* Multi Root I/O Virtualization */ -#define PCIE_EXT_CAP_ID_MCAST 0x0012U /* Multicast */ -#define PCIE_EXT_CAP_ID_PRI 0x0013U /* Page Request Interface */ -#define PCIE_EXT_CAP_ID_AMD_XXX 0x0014U /* Reserved for AMD */ -#define PCIE_EXT_CAP_ID_REBAR 0x0015U /* Resizable BAR */ -#define PCIE_EXT_CAP_ID_DPA 0x0016U /* Dynamic Power Allocation */ -#define PCIE_EXT_CAP_ID_TPH 0x0017U /* TPH Requester */ -#define PCIE_EXT_CAP_ID_LTR 0x0018U /* Latency Tolerance Reporting */ -#define PCIE_EXT_CAP_ID_SECPCI 0x0019U /* Secondary PCIe Capability */ -#define PCIE_EXT_CAP_ID_PMUX 0x001AU /* Protocol Multiplexing */ -#define PCIE_EXT_CAP_ID_PASID 0x001BU /* Process Address Space ID */ -#define PCIE_EXT_CAP_ID_DPC 0x001DU /* DPC: Downstream Port Containment */ -#define PCIE_EXT_CAP_ID_L1SS 0x001EU /* L1 PM Substates */ -#define PCIE_EXT_CAP_ID_PTM 0x001FU /* Precision Time Measurement */ -#define PCIE_EXT_CAP_ID_DVSEC 0x0023U /* Designated Vendor-Specific Extended Capability */ -#define PCIE_EXT_CAP_ID_DLF 0x0025U /* Data Link Feature */ -#define PCIE_EXT_CAP_ID_PL_16GT 0x0026U /* Physical Layer 16.0 GT/s */ -#define PCIE_EXT_CAP_ID_LMR 0x0027U /* Lane Margining at the Receiver */ -#define PCIE_EXT_CAP_ID_HID 0x0028U /* Hierarchy ID */ -#define PCIE_EXT_CAP_ID_NPEM 0x0029U /* Native PCIe Enclosure Management */ -#define PCIE_EXT_CAP_ID_PL_32GT 0x002AU /* Physical Layer 32.0 GT/s */ -#define PCIE_EXT_CAP_ID_AP 0x002BU /* Alternate Protocol */ -#define PCIE_EXT_CAP_ID_SFI 0x002CU /* System Firmware Intermediary */ +#define PCIE_EXT_CAP_ID_NULL 0x0000U /**< Null Capability */ +#define PCIE_EXT_CAP_ID_ERR 0x0001U /**< Advanced Error Reporting */ +#define PCIE_EXT_CAP_ID_VC 0x0002U /**< Virtual Channel when no MFVC */ +#define PCIE_EXT_CAP_ID_DSN 0x0003U /**< Device Serial Number */ +#define PCIE_EXT_CAP_ID_PWR 0x0004U /**< Power Budgeting */ +#define PCIE_EXT_CAP_ID_RCLD 0x0005U /**< Root Complex Link Declaration */ +#define PCIE_EXT_CAP_ID_RCILC 0x0006U /**< Root Complex Internal Link Control */ +#define PCIE_EXT_CAP_ID_RCEC 0x0007U /**< Root Complex Event Collector Endpoint Association */ +#define PCIE_EXT_CAP_ID_MFVC 0x0008U /**< Multi-Function VC Capability */ +#define PCIE_EXT_CAP_ID_MFVC_VC 0x0009U /**< Virtual Channel used with MFVC */ +#define PCIE_EXT_CAP_ID_RCRB 0x000AU /**< Root Complex Register Block */ +#define PCIE_EXT_CAP_ID_VNDR 0x000BU /**< Vendor-Specific Extended Capability */ +#define PCIE_EXT_CAP_ID_CAC 0x000CU /**< Config Access Correlation - obsolete */ +#define PCIE_EXT_CAP_ID_ACS 0x000DU /**< Access Control Services */ +#define PCIE_EXT_CAP_ID_ARI 0x000EU /**< Alternate Routing-ID Interpretation */ +#define PCIE_EXT_CAP_ID_ATS 0x000FU /**< Address Translation Services */ +#define PCIE_EXT_CAP_ID_SRIOV 0x0010U /**< Single Root I/O Virtualization */ +#define PCIE_EXT_CAP_ID_MRIOV 0x0011U /**< Multi Root I/O Virtualization */ +#define PCIE_EXT_CAP_ID_MCAST 0x0012U /**< Multicast */ +#define PCIE_EXT_CAP_ID_PRI 0x0013U /**< Page Request Interface */ +#define PCIE_EXT_CAP_ID_AMD_XXX 0x0014U /**< Reserved for AMD */ +#define PCIE_EXT_CAP_ID_REBAR 0x0015U /**< Resizable BAR */ +#define PCIE_EXT_CAP_ID_DPA 0x0016U /**< Dynamic Power Allocation */ +#define PCIE_EXT_CAP_ID_TPH 0x0017U /**< TPH Requester */ +#define PCIE_EXT_CAP_ID_LTR 0x0018U /**< Latency Tolerance Reporting */ +#define PCIE_EXT_CAP_ID_SECPCI 0x0019U /**< Secondary PCIe Capability */ +#define PCIE_EXT_CAP_ID_PMUX 0x001AU /**< Protocol Multiplexing */ +#define PCIE_EXT_CAP_ID_PASID 0x001BU /**< Process Address Space ID */ +#define PCIE_EXT_CAP_ID_DPC 0x001DU /**< DPC: Downstream Port Containment */ +#define PCIE_EXT_CAP_ID_L1SS 0x001EU /**< L1 PM Substates */ +#define PCIE_EXT_CAP_ID_PTM 0x001FU /**< Precision Time Measurement */ +#define PCIE_EXT_CAP_ID_DVSEC 0x0023U /**< Designated Vendor-Specific Extended Capability */ +#define PCIE_EXT_CAP_ID_DLF 0x0025U /**< Data Link Feature */ +#define PCIE_EXT_CAP_ID_PL_16GT 0x0026U /**< Physical Layer 16.0 GT/s */ +#define PCIE_EXT_CAP_ID_LMR 0x0027U /**< Lane Margining at the Receiver */ +#define PCIE_EXT_CAP_ID_HID 0x0028U /**< Hierarchy ID */ +#define PCIE_EXT_CAP_ID_NPEM 0x0029U /**< Native PCIe Enclosure Management */ +#define PCIE_EXT_CAP_ID_PL_32GT 0x002AU /**< Physical Layer 32.0 GT/s */ +#define PCIE_EXT_CAP_ID_AP 0x002BU /**< Alternate Protocol */ +#define PCIE_EXT_CAP_ID_SFI 0x002CU /**< System Firmware Intermediary */ +/** + * @} + */ /** * @} From e5fcca6e99a52334c0c726dfc1b0c432f8d944bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stine=20=C3=85kredalen?= Date: Wed, 19 Jul 2023 00:36:51 -0700 Subject: [PATCH 1468/2042] Bluetooth: mesh: Update default values for transport SAR configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated SAR default values to align with the latest mesh 1.1 drafts, and relevant Bsim tests. Signed-off-by: Stine Åkredalen --- subsys/bluetooth/mesh/Kconfig | 10 +++++----- tests/bsim/bluetooth/mesh/src/test_friendship.c | 6 ++---- tests/bsim/bluetooth/mesh/src/test_transport.c | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index d91f2495aae5..945b45c12cc7 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -1462,7 +1462,7 @@ menu "Transport SAR configuration" config BT_MESH_SAR_TX_SEG_INT_STEP hex "Interval between sending two consecutive segments" range 0x00 0x0F - default 0x01 + default 0x05 help This value controls the interval between sending two consecutive segments in a segmented message. The interval is measured in @@ -1520,7 +1520,7 @@ config BT_MESH_SAR_TX_MULTICAST_RETRANS_COUNT config BT_MESH_SAR_TX_MULTICAST_RETRANS_INT hex "Interval between retransmissions to multicast address" range 0x00 0x0F - default 0x03 + default 0x09 help This value controls the interval between retransmissions of all segments in a segmented message to a multicast address. The @@ -1542,7 +1542,7 @@ config BT_MESH_SAR_RX_SEG_THRESHOLD config BT_MESH_SAR_RX_ACK_DELAY_INC hex "Acknowledgment delay increment" range 0x00 0x07 - default 0x02 + default 0x01 help This value controls the delay increment of an interval used for delaying the transmission of an acknowledgment message after @@ -1553,7 +1553,7 @@ config BT_MESH_SAR_RX_ACK_DELAY_INC config BT_MESH_SAR_RX_SEG_INT_STEP hex "Segments reception interval step" range 0x00 0x0F - default 0x01 + default 0x05 help This value defines the segments reception interval step used for delaying the transmission of an acknowledgment message after @@ -1572,7 +1572,7 @@ config BT_MESH_SAR_RX_DISCARD_TIMEOUT config BT_MESH_SAR_RX_ACK_RETRANS_COUNT hex "Total number of acknowledgment message retransmission" range 0x00 0x03 - default 0x01 + default 0x00 help This value defines the total number of retranmissions of an acknowledgment message that the stack will additionally send when the diff --git a/tests/bsim/bluetooth/mesh/src/test_friendship.c b/tests/bsim/bluetooth/mesh/src/test_friendship.c index 64942e7f3409..afa569f2c060 100644 --- a/tests/bsim/bluetooth/mesh/src/test_friendship.c +++ b/tests/bsim/bluetooth/mesh/src/test_friendship.c @@ -204,12 +204,10 @@ static void test_friend_msg(void) * after sending the segments. */ ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_SECONDS(10))); - /* 4 polls (2 if legacy transport layer is used): - * - The first one triggered manually by transport when sending segmented message; - * - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages); + /* - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages); * - The last one with MD == 0; */ - friend_wait_for_polls(IS_ENABLED(CONFIG_BT_MESH_V1d1) ? 4 : 2); + friend_wait_for_polls(2); PASS(); } diff --git a/tests/bsim/bluetooth/mesh/src/test_transport.c b/tests/bsim/bluetooth/mesh/src/test_transport.c index cb1e33fc8489..e8560d9f6813 100644 --- a/tests/bsim/bluetooth/mesh/src/test_transport.c +++ b/tests/bsim/bluetooth/mesh/src/test_transport.c @@ -235,7 +235,7 @@ static void test_tx_loopback(void) err = bt_mesh_test_send(cfg->addr, NULL, test_vector[i].len, test_vector[i].flags, K_NO_WAIT); ASSERT_OK_MSG(err, "Failed sending vector %d", i); - bt_mesh_test_recv(test_vector[i].len, cfg->addr, NULL, K_SECONDS(1)); + bt_mesh_test_recv(test_vector[i].len, cfg->addr, NULL, K_SECONDS(2)); if (test_stats.received != i + 1) { FAIL("Didn't receive message %d", i); From 797a9afd892372b17f7a7f73d0daa29ff3369cb3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 18 Jul 2023 15:17:31 -0400 Subject: [PATCH 1469/2042] MAINTAINERS: remove cfriedt as GPIO collaborator Unfortunately, I need to reclaim a bit more bandwidth. Signed-off-by: Christopher Friedt --- MAINTAINERS.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 4c2567ec5fc2..56798bba60dc 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -938,7 +938,6 @@ Release Notes: status: odd fixes collaborators: - henrikbrixandersen - - cfriedt - mnkp files: - doc/hardware/peripherals/gpio.rst From b5f8c7154d1b7075711cc79f42bea64e888ddc74 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 19 Jul 2023 08:05:22 -0400 Subject: [PATCH 1470/2042] tests: posix: barrier: use consistent test names Test names were changed recently to change "test_posix_pthread_..." to "test_..." for brevity. Make the same change to "test_posix_pthread_barrier". Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 717b96d8ddcc..f333fb1594b2 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -744,7 +744,7 @@ ZTEST(posix_apis, test_sched_policy) } } -ZTEST(posix_apis, test_posix_pthread_barrier) +ZTEST(posix_apis, test_barrier) { int ret, pshared; pthread_barrierattr_t attr; From d53bbffb713b5f73b2d68f9b34617513a53c2f3a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 18 Jul 2023 15:14:49 -0400 Subject: [PATCH 1471/2042] MAINTAINERS: add cfriedt as kernel collaborator I sometimes do kernel-y things too. Signed-off-by: Christopher Friedt --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 56798bba60dc..e54521306201 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1609,6 +1609,7 @@ Kernel: - ceolin - dcpleung - peter-mitsis + - cfriedt files: - doc/kernel/ - include/zephyr/kernel*.h From feef931fbb17f11540ae9a611214e836b59583cb Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 19 Jul 2023 15:59:23 +0200 Subject: [PATCH 1472/2042] drivers: counter: stm32: Use const TIM_TypeDef on stm32f2 series A recent factorisation moved F2 to non const TIM_TypeDef. This is an error, move it back to const TIM_TypeDef. Signed-off-by: Erwan Gouriou --- drivers/counter/counter_ll_stm32_timer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index c3bffe3f7c2b..a64fe1dedffb 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -44,7 +44,6 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, /** Channel to compare get function mapping. */ #if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F2X) && \ !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32L1X) && \ @@ -76,7 +75,6 @@ static void(*const disable_it[TIMER_MAX_CH])(TIM_TypeDef *) = { /** Channel to interrupt enable check function mapping. */ #if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F2X) && \ !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32L1X) && \ From 0d33ecd56aec5456017933bb22c88a7eabbbb27b Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 4 May 2023 17:20:37 +0200 Subject: [PATCH 1473/2042] drivers: adc: configurable wait for completion timeout Depending on the ADC implementation it might happen that the driver is waiting on an external interrupt. If this interrupt gets lost, for instance due to a race condition with an external port expander, the system will get stuck. Making this configurable allows the user to recover from such an error. Signed-off-by: Benedikt Schmidt --- drivers/adc/Kconfig.ads114s0x | 7 +++++++ drivers/adc/adc_ads114s0x.c | 4 +++- drivers/adc/adc_context.h | 11 ++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/adc/Kconfig.ads114s0x b/drivers/adc/Kconfig.ads114s0x index 31f193906b10..4507ad302175 100644 --- a/drivers/adc/Kconfig.ads114s0x +++ b/drivers/adc/Kconfig.ads114s0x @@ -34,3 +34,10 @@ config ADC_ADS114S0X_GPIO The GPIO functionality is handled by the ADS114S0x GPIO driver. + +config ADC_ADS114S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS + int "Timeout for wait for completion of a read in ms" + default 1000 + depends on ADC_ADS114S0X + help + This is the wait time in ms until a read is completed. diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index eeafd0d3aef3..5c7edd909654 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -16,6 +16,8 @@ #include #define ADC_CONTEXT_USES_KERNEL_TIMER 1 +#define ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT \ + K_MSEC(CONFIG_ADC_ADS114S0X_WAIT_FOR_COMPLETION_TIMEOUT_MS) #include "adc_context.h" LOG_MODULE_REGISTER(ads114s0x, CONFIG_ADC_LOG_LEVEL); @@ -922,7 +924,7 @@ static int ads114s0x_wait_data_ready(const struct device *dev) { struct ads114s0x_data *data = dev->data; - return k_sem_take(&data->data_ready_signal, K_FOREVER); + return k_sem_take(&data->data_ready_signal, ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT); } static int ads114s0x_read_sample(const struct device *dev, uint16_t *buffer) diff --git a/drivers/adc/adc_context.h b/drivers/adc/adc_context.h index f5dd2549edb6..859b1f97f44f 100644 --- a/drivers/adc/adc_context.h +++ b/drivers/adc/adc_context.h @@ -48,6 +48,10 @@ static void adc_context_disable_timer(struct adc_context *ctx); static void adc_context_on_complete(struct adc_context *ctx, int status); #endif /* ADC_CONTEXT_ENABLE_ON_COMPLETE */ +#ifndef ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT +#define ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT K_FOREVER +#endif + struct adc_context { atomic_t sampling_requested; #ifdef ADC_CONTEXT_USES_KERNEL_TIMER @@ -168,7 +172,12 @@ static inline int adc_context_wait_for_completion(struct adc_context *ctx) } #endif /* CONFIG_ADC_ASYNC */ - k_sem_take(&ctx->sync, K_FOREVER); + int status = k_sem_take(&ctx->sync, ADC_CONTEXT_WAIT_FOR_COMPLETION_TIMEOUT); + + if (status != 0) { + ctx->status = status; + } + return ctx->status; } From f882d31ea71ad5f4ea3262446ea1d55228f69d5c Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Tue, 27 Jun 2023 18:34:35 -0700 Subject: [PATCH 1474/2042] drivers: i2s: mcux_flexcomm: fix multiple bugs Fix for bugs described in: https://github.com/zephyrproject-rtos/zephyr/issues/59803 1. the size argument passed to i2s_write() was being ignored. change the code so that the size is queued with the tx mem_block and the dma transfer is configured with this size. 2. change how CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT and CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT are used so that the queue buffers are allocated correctly when the two config values are not the same 3. set source_data_size and dest_data_size to be the same since the DMA controller can only set one size per DMA transfer. the driver was already computing a dest_data_size but always passing 1 for the source_data_size. For I2S RX case, I think source_data_size should be set to the expected FIFO read size instead of dest_data_size. Also some smaller improvements like: * don't allocate two dma_blocks for tx in the static dev_mem when it only needs one * memset both rx_dma_blocks together instead of separtely * set dma_cfg block_count for tx and rx statically instead of at runtime Signed-off-by: Mike J. Chen --- drivers/i2s/i2s_mcux_flexcomm.c | 125 ++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 47 deletions(-) diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index 7550dd7237ff..c48d6565f9d9 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -19,7 +19,7 @@ LOG_MODULE_REGISTER(i2s_mcux_flexcomm); -#define NUM_DMA_BLOCKS 2 +#define NUM_RX_DMA_BLOCKS 2 /* Device constant configuration parameters */ struct i2s_mcux_config { @@ -36,17 +36,32 @@ struct stream { uint32_t channel; /* stores the channel for dma */ struct i2s_config cfg; struct dma_config dma_cfg; - struct dma_block_config dma_block[NUM_DMA_BLOCKS]; bool last_block; struct k_msgq in_queue; - void *in_msgs[CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT]; struct k_msgq out_queue; - void *out_msgs[CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT]; +}; + +struct i2s_txq_entry { + void *mem_block; + size_t size; }; struct i2s_mcux_data { struct stream rx; + void *rx_in_msgs[CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT]; + void *rx_out_msgs[CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT]; + struct dma_block_config rx_dma_blocks[NUM_RX_DMA_BLOCKS]; + struct stream tx; + /* For tx, the in queue is for requests generated by + * the i2s_write() API call, and size must be tracked + * separate from the buffer size. + * The out_queue is for tracking buffers that should + * be freed once the DMA is done transferring it. + */ + struct i2s_txq_entry tx_in_msgs[CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT]; + void *tx_out_msgs[CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT]; + struct dma_block_config tx_dma_block; }; static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, @@ -266,6 +281,7 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, } stream->dma_cfg.dest_data_size = bytes_per_word; + stream->dma_cfg.source_data_size = bytes_per_word; /* Save configuration for get_config */ memcpy(&stream->cfg, i2s_cfg, sizeof(struct i2s_config)); @@ -275,12 +291,21 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, } static inline void i2s_purge_stream_buffers(struct stream *stream, - struct k_mem_slab *mem_slab) + struct k_mem_slab *mem_slab, + bool tx) { void *buffer; - while (k_msgq_get(&stream->in_queue, &buffer, K_NO_WAIT) == 0) { - k_mem_slab_free(mem_slab, &buffer); + if (tx) { + struct i2s_txq_entry queue_entry; + + while (k_msgq_get(&stream->in_queue, &queue_entry, K_NO_WAIT) == 0) { + k_mem_slab_free(mem_slab, &queue_entry.mem_block); + } + } else { + while (k_msgq_get(&stream->in_queue, &buffer, K_NO_WAIT) == 0) { + k_mem_slab_free(mem_slab, &buffer); + } } while (k_msgq_get(&stream->out_queue, &buffer, K_NO_WAIT) == 0) { k_mem_slab_free(mem_slab, &buffer); @@ -324,7 +349,7 @@ static void i2s_mcux_tx_stream_disable(const struct device *dev, bool drop) /* purge buffers queued in the stream */ if (drop) { - i2s_purge_stream_buffers(stream, stream->cfg.mem_slab); + i2s_purge_stream_buffers(stream, stream->cfg.mem_slab, true); } } @@ -351,12 +376,13 @@ static void i2s_mcux_rx_stream_disable(const struct device *dev, bool drop) /* purge buffers queued in the stream */ if (drop) { - i2s_purge_stream_buffers(stream, stream->cfg.mem_slab); + i2s_purge_stream_buffers(stream, stream->cfg.mem_slab, false); } } static void i2s_mcux_config_dma_blocks(const struct device *dev, - enum i2s_dir dir, uint32_t *buffer) + enum i2s_dir dir, uint32_t *buffer, + size_t block_size) { const struct i2s_mcux_config *cfg = dev->config; struct i2s_mcux_data *dev_data = dev->data; @@ -366,36 +392,34 @@ static void i2s_mcux_config_dma_blocks(const struct device *dev, if (dir == I2S_DIR_RX) { stream = &dev_data->rx; + blk_cfg = &dev_data->rx_dma_blocks[0]; + memset(blk_cfg, 0, sizeof(dev_data->rx_dma_blocks)); } else { stream = &dev_data->tx; + blk_cfg = &dev_data->tx_dma_block; + memset(blk_cfg, 0, sizeof(dev_data->tx_dma_block)); } - blk_cfg = &stream->dma_block[0]; - memset(blk_cfg, 0, sizeof(struct dma_block_config)); + stream->dma_cfg.head_block = blk_cfg; if (dir == I2S_DIR_RX) { + blk_cfg->source_address = (uint32_t)&base->FIFORD; blk_cfg->dest_address = (uint32_t)buffer[0]; - blk_cfg->block_size = stream->cfg.block_size; - blk_cfg->next_block = &stream->dma_block[1]; + blk_cfg->block_size = block_size; + blk_cfg->next_block = &dev_data->rx_dma_blocks[1]; blk_cfg->dest_reload_en = 1; - blk_cfg = &stream->dma_block[1]; - memset(blk_cfg, 0, sizeof(struct dma_block_config)); - + blk_cfg = &dev_data->rx_dma_blocks[1]; blk_cfg->source_address = (uint32_t)&base->FIFORD; blk_cfg->dest_address = (uint32_t)buffer[1]; - blk_cfg->block_size = stream->cfg.block_size; - - stream->dma_cfg.block_count = NUM_DMA_BLOCKS; + blk_cfg->block_size = block_size; } else { blk_cfg->dest_address = (uint32_t)&base->FIFOWR; blk_cfg->source_address = (uint32_t)buffer; - blk_cfg->block_size = stream->cfg.block_size; - stream->dma_cfg.block_count = 1; + blk_cfg->block_size = block_size; } - stream->dma_cfg.head_block = &stream->dma_block[0]; stream->dma_cfg.user_data = (void *)dev; dma_config(stream->dev_dma, stream->channel, &stream->dma_cfg); @@ -425,14 +449,15 @@ static void i2s_mcux_dma_tx_callback(const struct device *dma_dev, void *arg, const struct device *dev = (const struct device *)arg; struct i2s_mcux_data *dev_data = dev->data; struct stream *stream = &dev_data->tx; - void *buffer; + struct i2s_txq_entry queue_entry; int ret; LOG_DBG("tx cb: %d", stream->state); - ret = k_msgq_get(&stream->out_queue, &buffer, K_NO_WAIT); + + ret = k_msgq_get(&stream->out_queue, &queue_entry.mem_block, K_NO_WAIT); if (ret == 0) { /* transmission complete. free the buffer */ - k_mem_slab_free(stream->cfg.mem_slab, &buffer); + k_mem_slab_free(stream->cfg.mem_slab, &queue_entry.mem_block); } else { LOG_ERR("no buffer in output queue for channel %u", channel); } @@ -449,11 +474,13 @@ static void i2s_mcux_dma_tx_callback(const struct device *dma_dev, void *arg, case I2S_STATE_RUNNING: case I2S_STATE_STOPPING: /* get the next buffer from queue */ - ret = k_msgq_get(&stream->in_queue, &buffer, K_NO_WAIT); + ret = k_msgq_get(&stream->in_queue, &queue_entry, K_NO_WAIT); if (ret == 0) { /* config the DMA */ - i2s_mcux_config_dma_blocks(dev, I2S_DIR_TX, (uint32_t *)buffer); - k_msgq_put(&stream->out_queue, &buffer, K_NO_WAIT); + i2s_mcux_config_dma_blocks(dev, I2S_DIR_TX, + (uint32_t *)queue_entry.mem_block, + queue_entry.size); + k_msgq_put(&stream->out_queue, &queue_entry.mem_block, K_NO_WAIT); dma_start(stream->dev_dma, stream->channel); } @@ -549,23 +576,25 @@ static void i2s_mcux_dma_rx_callback(const struct device *dma_dev, void *arg, static int i2s_mcux_tx_stream_start(const struct device *dev) { int ret = 0; - void *buffer; const struct i2s_mcux_config *cfg = dev->config; struct i2s_mcux_data *dev_data = dev->data; struct stream *stream = &dev_data->tx; I2S_Type *base = cfg->base; + struct i2s_txq_entry queue_entry; /* retrieve buffer from input queue */ - ret = k_msgq_get(&stream->in_queue, &buffer, K_NO_WAIT); + ret = k_msgq_get(&stream->in_queue, &queue_entry, K_NO_WAIT); if (ret != 0) { LOG_ERR("No buffer in input queue to start transmission"); return ret; } - i2s_mcux_config_dma_blocks(dev, I2S_DIR_TX, (uint32_t *)buffer); + i2s_mcux_config_dma_blocks(dev, I2S_DIR_TX, + (uint32_t *)queue_entry.mem_block, + queue_entry.size); /* put buffer in output queue */ - ret = k_msgq_put(&stream->out_queue, &buffer, K_NO_WAIT); + ret = k_msgq_put(&stream->out_queue, &queue_entry.mem_block, K_NO_WAIT); if (ret != 0) { LOG_ERR("failed to put buffer in output queue"); return ret; @@ -589,7 +618,7 @@ static int i2s_mcux_tx_stream_start(const struct device *dev) static int i2s_mcux_rx_stream_start(const struct device *dev) { int ret = 0; - void *buffer[NUM_DMA_BLOCKS]; + void *buffer[NUM_RX_DMA_BLOCKS]; const struct i2s_mcux_config *cfg = dev->config; struct i2s_mcux_data *dev_data = dev->data; struct stream *stream = &dev_data->rx; @@ -606,7 +635,7 @@ static int i2s_mcux_rx_stream_start(const struct device *dev) return -EINVAL; } - for (int i = 0; i < NUM_DMA_BLOCKS; i++) { + for (int i = 0; i < NUM_RX_DMA_BLOCKS; i++) { ret = k_mem_slab_alloc(stream->cfg.mem_slab, &buffer[i], K_NO_WAIT); if (ret != 0) { @@ -615,10 +644,11 @@ static int i2s_mcux_rx_stream_start(const struct device *dev) } } - i2s_mcux_config_dma_blocks(dev, I2S_DIR_RX, (uint32_t *)buffer); + i2s_mcux_config_dma_blocks(dev, I2S_DIR_RX, (uint32_t *)buffer, + stream->cfg.block_size); /* put buffers in input queue */ - for (int i = 0; i < NUM_DMA_BLOCKS; i++) { + for (int i = 0; i < NUM_RX_DMA_BLOCKS; i++) { ret = k_msgq_put(&stream->in_queue, &buffer[i], K_NO_WAIT); if (ret != 0) { LOG_ERR("failed to put buffer in input queue"); @@ -778,7 +808,10 @@ static int i2s_mcux_write(const struct device *dev, void *mem_block, struct i2s_mcux_data *dev_data = dev->data; struct stream *stream = &dev_data->tx; int ret; - + struct i2s_txq_entry queue_entry = { + .mem_block = mem_block, + .size = size, + }; if (stream->state != I2S_STATE_RUNNING && stream->state != I2S_STATE_READY) { @@ -786,7 +819,7 @@ static int i2s_mcux_write(const struct device *dev, void *mem_block, return -EIO; } - ret = k_msgq_put(&stream->in_queue, &mem_block, + ret = k_msgq_put(&stream->in_queue, &queue_entry, SYS_TIMEOUT_MS(stream->cfg.timeout)); if (ret) { @@ -842,13 +875,13 @@ static int i2s_mcux_init(const struct device *dev) cfg->irq_config(dev); /* Initialize the buffer queues */ - k_msgq_init(&data->tx.in_queue, (char *)data->tx.in_msgs, - sizeof(void *), CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT); - k_msgq_init(&data->rx.in_queue, (char *)data->rx.in_msgs, + k_msgq_init(&data->tx.in_queue, (char *)data->tx_in_msgs, + sizeof(struct i2s_txq_entry), CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT); + k_msgq_init(&data->rx.in_queue, (char *)data->rx_in_msgs, sizeof(void *), CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT); - k_msgq_init(&data->tx.out_queue, (char *)data->tx.out_msgs, + k_msgq_init(&data->tx.out_queue, (char *)data->tx_out_msgs, sizeof(void *), CONFIG_I2S_MCUX_FLEXCOMM_TX_BLOCK_COUNT); - k_msgq_init(&data->rx.out_queue, (char *)data->rx.out_msgs, + k_msgq_init(&data->rx.out_queue, (char *)data->rx_out_msgs, sizeof(void *), CONFIG_I2S_MCUX_FLEXCOMM_RX_BLOCK_COUNT); if (data->tx.dev_dma != NULL) { @@ -884,7 +917,6 @@ static int i2s_mcux_init(const struct device *dev) .dma_cfg = { \ .channel_direction = MEMORY_TO_PERIPHERAL, \ .dma_callback = i2s_mcux_dma_tx_callback, \ - .source_data_size = 1, \ .block_count = 1, \ } \ }, \ @@ -898,8 +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, \ - .source_data_size = 1, \ - .block_count = 1, \ + .block_count = NUM_RX_DMA_BLOCKS, \ } \ } From 04f488accf5cd1e5d7084b6e9f4be5454ab1bc15 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Mon, 17 Jul 2023 10:38:56 -0700 Subject: [PATCH 1475/2042] drivers: spi: mcux_flexcomm: fix DMA bug for 2-byte transfers The MCUX DMA controller only supports a single data_size for a DMA transfer, not separate ones for source and dest. An older version of the DMA driver used dest_data_size as the DMA transfer size, but the current one uses MIN(dest/source) as the trasnfer size, which breaks case when SPI wants to do 2-byte transfers. Signed-off-by: Mike J. Chen --- drivers/spi/spi_mcux_flexcomm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 3667849c8c35..32b5638d49d6 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -590,6 +590,7 @@ static int transceive_dma(const struct device *dev, SPI_Type *base = config->base; int ret; uint32_t word_size; + uint16_t data_size; spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg); @@ -604,9 +605,11 @@ static int transceive_dma(const struct device *dev, word_size = SPI_WORD_SIZE_GET(spi_cfg->operation); - data->dma_rx.dma_cfg.dest_data_size = (word_size > 8) ? - (sizeof(uint16_t)) : (sizeof(uint8_t)); - data->dma_tx.dma_cfg.dest_data_size = data->dma_rx.dma_cfg.dest_data_size; + data_size = (word_size > 8) ? (sizeof(uint16_t)) : (sizeof(uint8_t)); + data->dma_rx.dma_cfg.source_data_size = data_size; + data->dma_rx.dma_cfg.dest_data_size = data_size; + data->dma_tx.dma_cfg.source_data_size = data_size; + data->dma_tx.dma_cfg.dest_data_size = data_size; while (data->ctx.rx_len > 0 || data->ctx.tx_len > 0) { size_t dma_len; @@ -830,7 +833,6 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ .dma_cfg = { \ .channel_direction = MEMORY_TO_PERIPHERAL, \ .dma_callback = spi_mcux_dma_callback, \ - .source_data_size = 1, \ .block_count = 2, \ } \ }, \ @@ -841,7 +843,6 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ .dma_cfg = { \ .channel_direction = PERIPHERAL_TO_MEMORY, \ .dma_callback = spi_mcux_dma_callback, \ - .source_data_size = 1, \ .block_count = 1, \ } \ } From 7839eb524ca718f173fed248b6ba282356c5e413 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Tue, 27 Jun 2023 18:48:14 -0700 Subject: [PATCH 1476/2042] drivers: dma: dma_lpc: fix bug with transfer size/width Fix for bug: https://github.com/zephyrproject-rtos/zephyr/issues/59802 The DMA controller only supports one transfer size, but the Zephyr DMA driver api allows specifying a source_data_size and dest_data_size which might be different. An old version was always using dest_data_size for the transfer size (variable is called "width"), but a recent change made the driver use the MIN for the source and dest data sizes. The MIN choice breaks the I2S driver because it always set source_data_size to 1, but dest_data_size was typically 4 for like two-channel 16-bit PCM data. So the old driver worked using dest_data_size, but the new driver broke I2S using MIN since source_data_size was 1. To prevent confusion, change the DMA driver to assert that source_data_size and dest_data_size are the same. Also assert that the source_address and dest_address for each block_config are properly aligned for the transfer size, since that is a documentated requirement for the DMA controller. Also rename max_xfer to max_xfer-bytes to be more clear what the units are, and use this value in many places that are comparing block_size in bytes rather than converting block_size to words by dividing by width and then comparing to NXP_LPC_DMA_MAX_XFER. Signed-off-by: Mike J. Chen --- drivers/dma/dma_mcux_lpc.c | 56 ++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index dde037243ab6..66032a9df3d7 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -117,7 +117,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, uint32_t xfer_config = 0U; dma_descriptor_t *next_descriptor = NULL; uint32_t width = data->width; - uint32_t max_xfer = NXP_LPC_DMA_MAX_XFER * width; + uint32_t max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; bool setup_extra_descriptor = false; uint8_t enable_interrupt; uint8_t reload; @@ -137,7 +137,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, return -ENOMEM; } /* Do we need to queue additional DMA descriptors for this block */ - if ((local_block.block_size / width > NXP_LPC_DMA_MAX_XFER) || + if ((local_block.block_size > max_xfer_bytes) || (local_block.next_block != NULL)) { /* Allocate DMA descriptors */ next_descriptor = @@ -185,7 +185,7 @@ 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 / width > NXP_LPC_DMA_MAX_XFER) { + if (local_block.block_size > max_xfer_bytes) { enable_interrupt = 0; } else { enable_interrupt = 1; @@ -203,7 +203,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, width, src_inc, dest_inc, - MIN(local_block.block_size, max_xfer)); + MIN(local_block.block_size, max_xfer_bytes)); DMA_SetupDescriptor(data->curr_descriptor, xfer_config, @@ -213,13 +213,13 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, data->curr_descriptor = next_descriptor; - if (local_block.block_size / width > NXP_LPC_DMA_MAX_XFER) { - local_block.block_size -= max_xfer; + if (local_block.block_size > max_xfer_bytes) { + local_block.block_size -= max_xfer_bytes; if (src_inc) { - local_block.source_address += max_xfer; + local_block.source_address += max_xfer_bytes; } if (dest_inc) { - local_block.dest_address += max_xfer; + local_block.dest_address += max_xfer_bytes; } } else { local_block.block_size = 0; @@ -243,7 +243,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, width, src_inc, dest_inc, - MIN(local_block.block_size, max_xfer)); + MIN(local_block.block_size, max_xfer_bytes)); /* Mark this as invalid */ xfer_config &= ~DMA_CHANNEL_XFERCFG_CFGVALID_MASK; DMA_SetupDescriptor(data->curr_descriptor, @@ -272,7 +272,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, uint8_t src_inc, dst_inc; bool is_periph = true; uint8_t width; - uint32_t max_xfer; + uint32_t max_xfer_bytes; uint8_t reload = 0; if (NULL == dev || NULL == config) { @@ -282,8 +282,14 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dev_config = dev->config; dma_data = dev->data; block_config = config->head_block; - width = MIN(config->source_data_size, config->dest_data_size); - max_xfer = NXP_LPC_DMA_MAX_XFER * width; + /* The DMA controller deals with just one transfer + * size, though the API provides separate sizes + * for source and dest. So assert that the source + * and dest sizes are the same. + */ + assert(config->dest_data_size == config->source_data_size); + width = config->dest_data_size; + max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; /* * Check if circular mode is requested. @@ -456,12 +462,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, k_spin_unlock(&configuring_otrigs, otrigs_key); /* Check if we need to queue DMA descriptors */ - if ((block_config->block_size / width > NXP_LPC_DMA_MAX_XFER) || + if ((block_config->block_size > max_xfer_bytes) || (block_config->next_block != NULL)) { /* Allocate a DMA descriptor */ data->curr_descriptor = data->dma_descriptor_table; - if (block_config->block_size / width > NXP_LPC_DMA_MAX_XFER) { + if (block_config->block_size > max_xfer_bytes) { /* Disable interrupt as this is not the entire data. * Reload for the descriptor */ @@ -469,7 +475,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, width, src_inc, dst_inc, - MIN(block_config->block_size, max_xfer)); + max_xfer_bytes); } else { /* Enable interrupt and reload for the descriptor */ @@ -477,7 +483,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, width, src_inc, dst_inc, - MIN(block_config->block_size, max_xfer)); + block_config->block_size); } } else { /* Enable interrupt for the descriptor */ @@ -487,6 +493,9 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dst_inc, block_config->block_size); } + /* DMA controller requires that the address be aligned to transfer size */ + assert(block_config->source_address == ROUND_UP(block_config->source_address, width)); + assert(block_config->dest_address == ROUND_UP(block_config->dest_address, width)); DMA_SubmitChannelTransferParameter(p_handle, xfer_config, @@ -496,7 +505,7 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, /* Start queuing DMA descriptors */ if (data->curr_descriptor) { - if ((block_config->block_size / width > NXP_LPC_DMA_MAX_XFER)) { + if (block_config->block_size > max_xfer_bytes) { /* Queue additional DMA descriptors because the amount of data to * be transferred is greater that the DMA descriptors max XFERCOUNT. */ @@ -504,16 +513,17 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, if (src_inc) { local_block.source_address = block_config->source_address - + max_xfer; + + max_xfer_bytes; } else { local_block.source_address = block_config->source_address; } if (dst_inc) { - local_block.dest_address = block_config->dest_address + max_xfer; + local_block.dest_address = block_config->dest_address + + max_xfer_bytes; } else { local_block.dest_address = block_config->dest_address; } - local_block.block_size = block_config->block_size - max_xfer; + local_block.block_size = block_config->block_size - max_xfer_bytes; local_block.next_block = block_config->next_block; local_block.source_reload_en = reload; @@ -527,6 +537,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, while (block_config != NULL) { block_config->source_reload_en = reload; + /* DMA controller requires that the address be aligned to transfer size */ + assert(block_config->source_address == + ROUND_UP(block_config->source_address, width)); + 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)) { return -ENOMEM; } From 20e7c6db6cc29984b653c7bb103ed1cee8cc24b7 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 7 Jul 2023 20:00:17 +0000 Subject: [PATCH 1477/2042] video: mcux_csi: set a dedicated init priority for video_mcux_csi Set a dedicated priority for the video_mcux_csi instead of using the default kernel device init priority. This allows initializing the device in a sequence that matches the devicetree hirearchy compared to mt9m114. Fixes the error: ERROR: /soc/csi@402bc000 POST_KERNEL 50 < /soc/i2c@403f0000/mt9m114@48 POST_KERNEL 60 found using: $ west build -p -b mimxrt1064_evk samples/subsys/video/capture \ -DCONFIG_CHECK_INIT_PRIORITIES=y Signed-off-by: Fabio Baltieri --- drivers/video/Kconfig.mcux_csi | 7 +++++++ drivers/video/video_mcux_csi.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/video/Kconfig.mcux_csi b/drivers/video/Kconfig.mcux_csi index 006587380f5e..18adaab4c50e 100644 --- a/drivers/video/Kconfig.mcux_csi +++ b/drivers/video/Kconfig.mcux_csi @@ -8,3 +8,10 @@ config VIDEO_MCUX_CSI default y depends on HAS_MCUX_CSI depends on DT_HAS_NXP_IMX_CSI_ENABLED + +config VIDEO_MCUX_CSI_INIT_PRIORITY + int "NXP MCUX CSI init priority" + default 61 + depends on VIDEO_MCUX_CSI + help + Initialization priority for the CSI interface on an NXP MCUX device. diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index ed444501ec43..1e7117c4393e 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -452,6 +452,6 @@ static int video_mcux_csi_init_0(const struct device *dev) DEVICE_DT_INST_DEFINE(0, &video_mcux_csi_init_0, NULL, &video_mcux_csi_data_0, &video_mcux_csi_config_0, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + POST_KERNEL, CONFIG_VIDEO_MCUX_CSI_INIT_PRIORITY, &video_mcux_csi_driver_api); #endif From ebb1fa585f31b9cbe0db7c18e6a8dc28e35bb30d Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 13 Jul 2023 10:46:46 +0000 Subject: [PATCH 1478/2042] dma: iproc_pax_v2: delay initialization after pcie The Broadcom pcie setup has a devicetree dependency like: /pcie/paxdma -> /pcie/pcie -> /soc/pl330 Add a separate init symbol for iproc_pax_v2 so that these gets initialized in order, fixes this error: $ west build -p -b bcm958402m2_m7 tests/kernel/common \ -DCONFIG_CHECK_INIT_PRIORITIES=y ... ERROR: /pcie/paxdma@4e100800 POST_KERNEL 40 < \ /pcie/pcie@4e100000 POST_KERNEL 50 Signed-off-by: Fabio Baltieri --- drivers/dma/Kconfig.iproc_pax | 7 +++++++ drivers/dma/dma_iproc_pax_v2.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/dma/Kconfig.iproc_pax b/drivers/dma/Kconfig.iproc_pax index 64a42a7b8b29..f35b694d5ace 100644 --- a/drivers/dma/Kconfig.iproc_pax +++ b/drivers/dma/Kconfig.iproc_pax @@ -15,6 +15,13 @@ config DMA_IPROC_PAX_V2 depends on DT_HAS_BRCM_IPROC_PAX_DMA_V2_ENABLED depends on PCIE_EP_IPROC_V2 +config DMA_IPROC_PAX_V2_INIT_PRIORITY + int "Broadcom PAX v2 initialization priority" + default 51 + depends on DMA_IPROC_PAX_V2 + help + Broadcom PAX v2 initialization priority. + if DMA_IPROC_PAX || DMA_IPROC_PAX_V2 config DMA_IPROC_PAX_DEBUG diff --git a/drivers/dma/dma_iproc_pax_v2.c b/drivers/dma/dma_iproc_pax_v2.c index 3e9159e02449..4b7e7fafcd21 100644 --- a/drivers/dma/dma_iproc_pax_v2.c +++ b/drivers/dma/dma_iproc_pax_v2.c @@ -1102,5 +1102,5 @@ DEVICE_DT_INST_DEFINE(0, &pax_dma_data, &pax_dma_cfg, POST_KERNEL, - CONFIG_DMA_INIT_PRIORITY, + CONFIG_DMA_IPROC_PAX_V2_INIT_PRIORITY, &pax_dma_driver_api); From 5c93b92a77ddc9366480891ec47af0a2bc7c414e Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 7 Jun 2023 17:06:55 -0400 Subject: [PATCH 1479/2042] test: benchmark latency macro parameter names Changes the names of parameters to the PRINT_STATS() and PRINT_STATS_AVG() macros to be something more meaningful. Signed-off-by: Peter Mitsis --- tests/benchmarks/latency_measure/src/utils.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index e68ee3b7b81d..5c77994452d7 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -37,11 +37,11 @@ extern int error_count; printk("%s", sline); \ } -#define PRINT_STATS(x, y) \ - PRINT_F(x, y, (uint32_t)timing_cycles_to_ns(y)) +#define PRINT_STATS(summary, value) \ + PRINT_F(summary, value, (uint32_t)timing_cycles_to_ns(value)) -#define PRINT_STATS_AVG(x, y, counter) \ - PRINT_F(x, y / counter, (uint32_t)timing_cycles_to_ns_avg(y, counter)); +#define PRINT_STATS_AVG(summary, value, counter) \ + PRINT_F(summary, value / counter, (uint32_t)timing_cycles_to_ns_avg(value, counter)); #endif From fe922d30f9a99c1cc3572846423c75685a185b55 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 7 Jun 2023 17:33:56 -0400 Subject: [PATCH 1480/2042] test: refactor benchmark latency PRINT_F() macro Reduces the stack usage. Also separates the formatting of both the cycle and nsec printing by pre-printing them to string. Signed-off-by: Peter Mitsis --- .../latency_measure/src/int_to_thread_evt.c | 2 +- tests/benchmarks/latency_measure/src/utils.h | 28 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/int_to_thread_evt.c b/tests/benchmarks/latency_measure/src/int_to_thread_evt.c index acafd0e1fc78..9148add45d4b 100644 --- a/tests/benchmarks/latency_measure/src/int_to_thread_evt.c +++ b/tests/benchmarks/latency_measure/src/int_to_thread_evt.c @@ -90,7 +90,7 @@ int int_to_thread_evt(void) diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS("Time from ISR to executing a different thread", diff) + PRINT_STATS("Time from ISR to executing a different thread", diff); return 0; } diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index 5c77994452d7..47fe480f75e1 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -25,17 +25,29 @@ extern int error_count; printk(" Error: tick occurred\n") #ifdef CSV_FORMAT_OUTPUT -#define FORMAT "%-60s,%8u,%8u\n" +#define FORMAT_STR "%-60s,%s,%s\n" +#define CYCLE_FORMAT "%8u" +#define NSEC_FORMAT "%8u" #else -#define FORMAT "%-60s:%8u cycles , %8u ns\n" +#define FORMAT_STR "%-60s:%s , %s\n" +#define CYCLE_FORMAT "%8u cycles" +#define NSEC_FORMAT "%8u ns" #endif -#define PRINT_F(...) \ - { \ - char sline[256]; \ - snprintk(sline, 254, FORMAT, ##__VA_ARGS__); \ - printk("%s", sline); \ - } +#define PRINT_F(summary, cycles, nsec, error, notes) \ + do { \ + char cycle_str[32]; \ + char nsec_str[32]; \ + \ + if (!error) { \ + snprintk(cycle_str, 30, CYCLE_FORMAT, cycles); \ + snprintk(nsec_str, 30, NSEC_FORMAT, nsec); \ + } else { \ + snprintk(cycle_str, 30, "%15s", "FAILED"); \ + snprintk(nsec_str, 30, "%15s", "FAILED"); \ + } \ + printk(FORMAT_STR, summary, cycle_str, nsec_str, notes); \ + } while (0) #define PRINT_STATS(summary, value) \ PRINT_F(summary, value, (uint32_t)timing_cycles_to_ns(value)) From aa4f24694edf37d0ccecb13c8aea5a3ca422168d Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Wed, 7 Jun 2023 18:12:09 -0400 Subject: [PATCH 1481/2042] test: Enhance benchmark latency reporting Enhances the reporting of the benchmark latency failures in the following ways: 1. The failing test is now clearly identified 2. Failures follow the general reporting pattern Signed-off-by: Peter Mitsis --- .../latency_measure/src/coop_ctx_switch.c | 27 +++++++++----- .../latency_measure/src/heap_malloc_free.c | 30 ++++++++++------ .../latency_measure/src/int_to_thread.c | 19 +++++----- .../latency_measure/src/int_to_thread_evt.c | 3 +- .../latency_measure/src/mutex_lock_unlock.c | 24 +++++++++++-- .../src/sema_test_signal_release.c | 31 +++++++++------- tests/benchmarks/latency_measure/src/thread.c | 10 +++--- .../latency_measure/src/thread_switch_yield.c | 35 ++++++++++++------- tests/benchmarks/latency_measure/src/utils.h | 31 +++++++++++----- 9 files changed, 142 insertions(+), 68 deletions(-) diff --git a/tests/benchmarks/latency_measure/src/coop_ctx_switch.c b/tests/benchmarks/latency_measure/src/coop_ctx_switch.c index c3b244e3c9fb..1cecda1358c6 100644 --- a/tests/benchmarks/latency_measure/src/coop_ctx_switch.c +++ b/tests/benchmarks/latency_measure/src/coop_ctx_switch.c @@ -95,6 +95,10 @@ int coop_ctx_switch(void) { ctx_switch_counter = 0U; ctx_switch_balancer = 0; + char error_string[80]; + const char *notes = ""; + bool failed = false; + int end; timing_start(); bench_test_start(); @@ -106,18 +110,25 @@ int coop_ctx_switch(void) (k_thread_entry_t)thread_two, NULL, NULL, NULL, K_PRIO_COOP(6), 0, K_NO_WAIT); + end = bench_test_end(); + if (ctx_switch_balancer > 3 || ctx_switch_balancer < -3) { - printk(" Balance is %d. FAILED", ctx_switch_balancer); - } else if (bench_test_end() != 0) { error_count++; - PRINT_OVERFLOW_ERROR(); - } else { - uint32_t diff; - - diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average context switch time between threads (coop)", diff, ctx_switch_counter); + snprintk(error_string, 78, " Balance is %d", + ctx_switch_balancer); + notes = error_string; + failed = true; + } else if (end != 0) { + error_count++; + notes = TICK_OCCURRENCE_ERROR; } + uint32_t diff; + + diff = timing_cycles_get(×tamp_start, ×tamp_end); + PRINT_STATS_AVG("Average context switch time between threads (coop)", + diff, ctx_switch_counter, failed, notes); + timing_stop(); return 0; diff --git a/tests/benchmarks/latency_measure/src/heap_malloc_free.c b/tests/benchmarks/latency_measure/src/heap_malloc_free.c index fe35e3d3b43d..cdb81e0f5b7c 100644 --- a/tests/benchmarks/latency_measure/src/heap_malloc_free.c +++ b/tests/benchmarks/latency_measure/src/heap_malloc_free.c @@ -23,6 +23,10 @@ void heap_malloc_free(void) uint32_t sum_malloc = 0U; uint32_t sum_free = 0U; + bool failed = false; + char error_string[80]; + const char *notes = ""; + timing_start(); while (count != TEST_COUNT) { @@ -31,8 +35,10 @@ void heap_malloc_free(void) heap_malloc_end_time = timing_counter_get(); if (allocated_mem == NULL) { - printk("Failed to alloc memory from heap " - "at count %d\n", count); + error_count++; + snprintk(error_string, 78, + "alloc memory @ iteration %d", count); + notes = error_string; break; } @@ -47,18 +53,20 @@ void heap_malloc_free(void) count++; } - /* if count is 0, it means that there is not enough memory heap - * to do k_malloc at least once, then it's meaningless to - * calculate average time of memory allocation and free. + /* + * If count is 0, it means that there is not enough memory heap + * to do k_malloc at least once. Override the error string. */ + if (count == 0) { - printk("Error: there isn't enough memory heap to do " - "k_malloc at least once, please " - "increase heap size\n"); - } else { - PRINT_STATS_AVG("Average time for heap malloc", sum_malloc, count); - PRINT_STATS_AVG("Average time for heap free", sum_free, count); + failed = true; + notes = "Memory heap too small--increase it."; } + PRINT_STATS_AVG("Average time for heap malloc", sum_malloc, count, + failed, notes); + PRINT_STATS_AVG("Average time for heap free", 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 072568c6acd9..50c4c56555bf 100644 --- a/tests/benchmarks/latency_measure/src/int_to_thread.c +++ b/tests/benchmarks/latency_measure/src/int_to_thread.c @@ -51,11 +51,7 @@ static void make_int(void) { flag_var = 0; irq_offload(latency_test_isr, NULL); - if (flag_var != 1) { - printk(" Flag variable has not changed. FAILED\n"); - } else { - timestamp_end = timing_counter_get(); - } + timestamp_end = timing_counter_get(); } /** @@ -67,14 +63,21 @@ static void make_int(void) int int_to_thread(void) { uint32_t diff; + bool failed = false; + const char *notes = ""; timing_start(); TICK_SYNCH(); make_int(); - if (flag_var == 1) { - diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS("Switch from ISR back to interrupted thread", diff); + if (flag_var != 1) { + error_count++; + notes = "Flag variable did not change"; + failed = true; } + + diff = timing_cycles_get(×tamp_start, ×tamp_end); + PRINT_STATS("Switch from ISR back to interrupted thread", + diff, failed, notes); timing_stop(); return 0; } diff --git a/tests/benchmarks/latency_measure/src/int_to_thread_evt.c b/tests/benchmarks/latency_measure/src/int_to_thread_evt.c index 9148add45d4b..35ba280df3b3 100644 --- a/tests/benchmarks/latency_measure/src/int_to_thread_evt.c +++ b/tests/benchmarks/latency_measure/src/int_to_thread_evt.c @@ -90,7 +90,8 @@ int int_to_thread_evt(void) diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS("Time from ISR to executing a different thread", diff); + PRINT_STATS("Time from ISR to executing a different thread", + diff, false, ""); return 0; } diff --git a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c index d236f75a37f8..cfc8ae2118b4 100644 --- a/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c +++ b/tests/benchmarks/latency_measure/src/mutex_lock_unlock.c @@ -30,8 +30,11 @@ int mutex_lock_unlock(void) uint32_t diff; timing_t timestamp_start; timing_t timestamp_end; + const char *notes = ""; + int end; timing_start(); + bench_test_start(); timestamp_start = timing_counter_get(); @@ -40,10 +43,19 @@ int mutex_lock_unlock(void) } timestamp_end = timing_counter_get(); + end = bench_test_end(); diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average time to lock a mutex", diff, N_TEST_MUTEX); + if (end != 0) { + notes = TICK_OCCURRENCE_ERROR; + error_count++; + } + + PRINT_STATS_AVG("Average time to lock a mutex", diff, N_TEST_MUTEX, + false, notes); + + bench_test_start(); timestamp_start = timing_counter_get(); for (i = 0; i < N_TEST_MUTEX; i++) { @@ -51,9 +63,17 @@ int mutex_lock_unlock(void) } timestamp_end = timing_counter_get(); + end = bench_test_end(); diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average time to unlock a mutex", diff, N_TEST_MUTEX); + if (end != 0) { + notes = TICK_OCCURRENCE_ERROR; + error_count++; + } + + PRINT_STATS_AVG("Average time to unlock a mutex", diff, N_TEST_MUTEX, + false, notes); + timing_stop(); return 0; } 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 13fad1ff8e2d..f5d2d4a83324 100644 --- a/tests/benchmarks/latency_measure/src/sema_test_signal_release.c +++ b/tests/benchmarks/latency_measure/src/sema_test_signal_release.c @@ -45,7 +45,6 @@ int sema_context_switch(void) { uint32_t diff; - bench_test_start(); timing_start(); k_thread_create(&thread_one_data, thread_one_stack, @@ -57,13 +56,13 @@ int sema_context_switch(void) timestamp_end_sema_t_c = timing_counter_get(); diff = timing_cycles_get(×tamp_start_sema_t_c, ×tamp_end_sema_t_c); - PRINT_STATS("Semaphore take time (context switch)", diff); + PRINT_STATS("Semaphore take time (context switch)", diff, false, ""); timestamp_start_sema_g_c = timing_counter_get(); k_sem_give(&sem_bench); diff = timing_cycles_get(×tamp_start_sema_g_c, ×tamp_end_sema_g_c); - PRINT_STATS("Semaphore give time (context switch)", diff); + PRINT_STATS("Semaphore give time (context switch)", diff, false, ""); timing_stop(); @@ -85,6 +84,8 @@ int sema_test_signal(void) uint32_t diff; timing_t timestamp_start; timing_t timestamp_end; + const char *notes = ""; + int end; bench_test_start(); timing_start(); @@ -96,16 +97,18 @@ int sema_test_signal(void) } timestamp_end = timing_counter_get(); + end = bench_test_end(); timing_stop(); - if (bench_test_end() == 0) { - diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average semaphore signal time", diff, N_TEST_SEMA); - } else { + if (end != 0) { error_count++; - PRINT_OVERFLOW_ERROR(); + notes = TICK_OCCURRENCE_ERROR; } + diff = timing_cycles_get(×tamp_start, ×tamp_end); + PRINT_STATS_AVG("Average semaphore signal time", diff, N_TEST_SEMA, + false, notes); + bench_test_start(); timing_start(); @@ -116,15 +119,17 @@ int sema_test_signal(void) } timestamp_end = timing_counter_get(); + end = bench_test_end(); timing_stop(); - if (bench_test_end() == 0) { - diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average semaphore test time", diff, N_TEST_SEMA); - } else { + if (end != 0) { error_count++; - PRINT_OVERFLOW_ERROR(); + notes = TICK_OCCURRENCE_ERROR; } + diff = timing_cycles_get(×tamp_start, ×tamp_end); + PRINT_STATS_AVG("Average semaphore test time", diff, N_TEST_SEMA, + false, notes); + return 0; } diff --git a/tests/benchmarks/latency_measure/src/thread.c b/tests/benchmarks/latency_measure/src/thread.c index 5d140d9458e6..5178eef784ce 100644 --- a/tests/benchmarks/latency_measure/src/thread.c +++ b/tests/benchmarks/latency_measure/src/thread.c @@ -60,19 +60,19 @@ int suspend_resume(void) diff = timing_cycles_get(×tamp_start_create_c, ×tamp_end_create_c); - PRINT_STATS("Time to create a thread (without start)", diff); + PRINT_STATS("Time to create a thread (without start)", diff, false, ""); diff = timing_cycles_get(×tamp_start_start_c, ×tamp_start_suspend_c); - PRINT_STATS("Time to start a thread", diff); + PRINT_STATS("Time to start a thread", diff, false, ""); diff = timing_cycles_get(×tamp_start_suspend_c, ×tamp_end_suspend_c); - PRINT_STATS("Time to suspend a thread", diff); + PRINT_STATS("Time to suspend a thread", diff, false, ""); diff = timing_cycles_get(×tamp_start_resume_c, ×tamp_end_resume_c); - PRINT_STATS("Time to resume a thread", diff); + PRINT_STATS("Time to resume a thread", diff, false, ""); timestamp_start_abort_1 = timing_counter_get(); k_thread_abort(t1_tid); @@ -80,7 +80,7 @@ int suspend_resume(void) diff = timing_cycles_get(×tamp_start_abort_1, ×tamp_end_abort_1); - PRINT_STATS("Time to abort a thread (not running)", diff); + PRINT_STATS("Time to abort a thread (not running)", diff, false, ""); timing_stop(); return 0; diff --git a/tests/benchmarks/latency_measure/src/thread_switch_yield.c b/tests/benchmarks/latency_measure/src/thread_switch_yield.c index 1ddfa2b1dcfd..4df75a168845 100644 --- a/tests/benchmarks/latency_measure/src/thread_switch_yield.c +++ b/tests/benchmarks/latency_measure/src/thread_switch_yield.c @@ -49,6 +49,10 @@ void thread_switch_yield(void) timing_t timestamp_start; timing_t timestamp_end; uint32_t ts_diff; + const char *notes = ""; + char error_string[80]; + bool failed = false; + int end; timing_start(); bench_test_start(); @@ -71,6 +75,7 @@ void thread_switch_yield(void) /* get the number of cycles it took to do the test */ timestamp_end = timing_counter_get(); + end = bench_test_end(); /* Ensure both helper and this routine were context switching back & * forth. @@ -80,23 +85,29 @@ void thread_switch_yield(void) * back and forth. */ delta = iterations - helper_thread_iterations; - if (bench_test_end() < 0) { - error_count++; - PRINT_OVERFLOW_ERROR(); - } else if (abs(delta) > 1) { + if (abs(delta) > 1) { /* expecting even alternating context switch, seems one routine * called yield without the other having chance to execute */ error_count++; - printk(" Error, iteration:%u, helper iteration:%u", - iterations, helper_thread_iterations); - } else { - /* thread_yield is called (iterations + helper_thread_iterations) - * times in total. - */ - ts_diff = timing_cycles_get(×tamp_start, ×tamp_end); - PRINT_STATS_AVG("Average thread context switch using yield", ts_diff, (iterations + helper_thread_iterations)); + snprintk(error_string, 78, + "Error: iteration:%u : helper iteration:%u", + iterations, helper_thread_iterations); + notes = error_string; + failed = true; + } else if (end != 0) { + error_count++; + notes = TICK_OCCURRENCE_ERROR; } + /* + * thread_yield is called (iterations + helper_thread_iterations) + * times in total. + */ + + ts_diff = timing_cycles_get(×tamp_start, ×tamp_end); + PRINT_STATS_AVG("Average thread context switch using yield", ts_diff, + (iterations + helper_thread_iterations), failed, notes); + timing_stop(); } diff --git a/tests/benchmarks/latency_measure/src/utils.h b/tests/benchmarks/latency_measure/src/utils.h index 47fe480f75e1..56027b1c8509 100644 --- a/tests/benchmarks/latency_measure/src/utils.h +++ b/tests/benchmarks/latency_measure/src/utils.h @@ -21,19 +21,30 @@ extern int error_count; -#define PRINT_OVERFLOW_ERROR() \ - printk(" Error: tick occurred\n") +#define TICK_OCCURRENCE_ERROR "Error: Tick Occurred" #ifdef CSV_FORMAT_OUTPUT -#define FORMAT_STR "%-60s,%s,%s\n" +#define FORMAT_STR "%-52s,%s,%s,%s\n" #define CYCLE_FORMAT "%8u" #define NSEC_FORMAT "%8u" #else -#define FORMAT_STR "%-60s:%s , %s\n" +#define FORMAT_STR "%-52s:%s , %s : %s\n" #define CYCLE_FORMAT "%8u cycles" #define NSEC_FORMAT "%8u ns" #endif +/** + * @brief Display a line of statistics + * + * This macro displays the following: + * 1. Test description summary + * 2. Number of cycles - See Note + * 3. Number of nanoseconds - See Note + * 4. Additional notes describing the nature of any errors + * + * Note - If the @a error parameter is not false, then the test has no + * numerical information to print and it will instead print "FAILED". + */ #define PRINT_F(summary, cycles, nsec, error, notes) \ do { \ char cycle_str[32]; \ @@ -49,11 +60,15 @@ extern int error_count; printk(FORMAT_STR, summary, cycle_str, nsec_str, notes); \ } while (0) -#define PRINT_STATS(summary, value) \ - PRINT_F(summary, value, (uint32_t)timing_cycles_to_ns(value)) +#define PRINT_STATS(summary, value, error, notes) \ + PRINT_F(summary, value, \ + (uint32_t)timing_cycles_to_ns(value), \ + error, notes) -#define PRINT_STATS_AVG(summary, value, counter) \ - PRINT_F(summary, value / counter, (uint32_t)timing_cycles_to_ns_avg(value, counter)); +#define PRINT_STATS_AVG(summary, value, counter, error, notes) \ + PRINT_F(summary, value / counter, \ + (uint32_t)timing_cycles_to_ns_avg(value, counter), \ + error, notes); #endif From 3a24476fb70b813cf5ba01853c10f5c7973dbfbc Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 18 Jul 2023 14:45:51 +0000 Subject: [PATCH 1482/2042] tests: kernel: fix some test identifiers Fixed few test identifiers and tags. Signed-off-by: Anas Nashif --- tests/arch/arm/arm_no_multithreading/testcase.yaml | 2 +- tests/kernel/context/testcase.yaml | 2 +- tests/kernel/mem_heap/mheap_api_concept/testcase.yaml | 2 +- tests/kernel/mem_slab/mslab_api/testcase.yaml | 2 +- tests/kernel/mem_slab/mslab_stats/testcase.yaml | 6 ++++-- tests/kernel/msgq/msgq_usage/testcase.yaml | 6 ++++-- tests/kernel/mutex/mutex_error_case/testcase.yaml | 3 ++- tests/kernel/mutex/sys_mutex/testcase.yaml | 9 ++++++--- tests/kernel/workq/user_work/testcase.yaml | 3 ++- tests/kernel/workq/work/testcase.yaml | 2 +- 10 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/arch/arm/arm_no_multithreading/testcase.yaml b/tests/arch/arm/arm_no_multithreading/testcase.yaml index 5c52fa70f90b..43ab80279f03 100644 --- a/tests/arch/arm/arm_no_multithreading/testcase.yaml +++ b/tests/arch/arm/arm_no_multithreading/testcase.yaml @@ -3,7 +3,7 @@ common: tags: arm arch_allow: arm tests: - arch.arm.no_multithreading: + arch.arm.no-mt: filter: not CONFIG_TRUSTED_EXECUTION_NONSECURE platform_allow: - qemu_cortex_m0 diff --git a/tests/kernel/context/testcase.yaml b/tests/kernel/context/testcase.yaml index 4baa4e7102b7..859287597e21 100644 --- a/tests/kernel/context/testcase.yaml +++ b/tests/kernel/context/testcase.yaml @@ -4,7 +4,7 @@ tests: extra_configs: - CONFIG_TEST_EXTRA_STACK_SIZE=1024 min_ram: 16 - kernel.context.linker_generator: + linker.linker_generator: platform_allow: qemu_cortex_m3 tags: - kernel diff --git a/tests/kernel/mem_heap/mheap_api_concept/testcase.yaml b/tests/kernel/mem_heap/mheap_api_concept/testcase.yaml index 8426487a9db2..897aca938e9c 100644 --- a/tests/kernel/mem_heap/mheap_api_concept/testcase.yaml +++ b/tests/kernel/mem_heap/mheap_api_concept/testcase.yaml @@ -5,7 +5,7 @@ tests: - memory_heap extra_configs: - CONFIG_IRQ_OFFLOAD=y - kernel.memory_heap_no_multithreading: + kernel.memory_heap.no_mt: tags: - kernel - memory_heap diff --git a/tests/kernel/mem_slab/mslab_api/testcase.yaml b/tests/kernel/mem_slab/mslab_api/testcase.yaml index 6cfc5eeb8ecc..fbfdffda5faf 100644 --- a/tests/kernel/mem_slab/mslab_api/testcase.yaml +++ b/tests/kernel/mem_slab/mslab_api/testcase.yaml @@ -3,7 +3,7 @@ tests: tags: - kernel - memory_slabs - kernel.memory_slabs.api_no_multithreading: + kernel.memory_slabs.api.no-mt: tags: - kernel - memory_slabs diff --git a/tests/kernel/mem_slab/mslab_stats/testcase.yaml b/tests/kernel/mem_slab/mslab_stats/testcase.yaml index ca3919d2135a..bcc22f887932 100644 --- a/tests/kernel/mem_slab/mslab_stats/testcase.yaml +++ b/tests/kernel/mem_slab/mslab_stats/testcase.yaml @@ -1,3 +1,5 @@ tests: - kernel.memory_slab.stats: - tags: kernel + kernel.memory_slabs.stats: + tags: + - kernel + - memory slabs diff --git a/tests/kernel/msgq/msgq_usage/testcase.yaml b/tests/kernel/msgq/msgq_usage/testcase.yaml index a991899a6f15..0793df32dced 100644 --- a/tests/kernel/msgq/msgq_usage/testcase.yaml +++ b/tests/kernel/msgq/msgq_usage/testcase.yaml @@ -1,3 +1,5 @@ tests: - kernel.message_queue_usage: - tags: kernel + kernel.message_queue.usage: + tags: + - kernel + - message queue diff --git a/tests/kernel/mutex/mutex_error_case/testcase.yaml b/tests/kernel/mutex/mutex_error_case/testcase.yaml index 206b1f5dced9..ac89d216fbe5 100644 --- a/tests/kernel/mutex/mutex_error_case/testcase.yaml +++ b/tests/kernel/mutex/mutex_error_case/testcase.yaml @@ -1,7 +1,8 @@ tests: - kernel.mutex_error_case: + kernel.mutex.error: filter: CONFIG_ARCH_HAS_USERSPACE tags: - kernel - userspace + - mutex ignore_faults: true diff --git a/tests/kernel/mutex/sys_mutex/testcase.yaml b/tests/kernel/mutex/sys_mutex/testcase.yaml index 20c498e2486c..c3669a6cfef3 100644 --- a/tests/kernel/mutex/sys_mutex/testcase.yaml +++ b/tests/kernel/mutex/sys_mutex/testcase.yaml @@ -1,11 +1,14 @@ tests: - system.mutex: + kernel.mutex.system: filter: CONFIG_ARCH_HAS_USERSPACE tags: - kernel - userspace + - mutex - system.mutex.nouser: - tags: kernel + kernel.mutex.system.nouser: + tags: + - kernel + - mutex extra_configs: - CONFIG_TEST_USERSPACE=n diff --git a/tests/kernel/workq/user_work/testcase.yaml b/tests/kernel/workq/user_work/testcase.yaml index 21ab07b56add..e57d1221461d 100644 --- a/tests/kernel/workq/user_work/testcase.yaml +++ b/tests/kernel/workq/user_work/testcase.yaml @@ -1,7 +1,8 @@ tests: - kernel.work.user: + kernel.workqueue.user: min_flash: 34 filter: CONFIG_ARCH_HAS_USERSPACE tags: - kernel - userspace + - workqueue diff --git a/tests/kernel/workq/work/testcase.yaml b/tests/kernel/workq/work/testcase.yaml index acbc85d24468..b2468b323113 100644 --- a/tests/kernel/workq/work/testcase.yaml +++ b/tests/kernel/workq/work/testcase.yaml @@ -1,5 +1,5 @@ tests: - kernel.work.api: + kernel.workqueue.api: min_flash: 34 tags: kernel # this platform fails to run due to #40376, all From 30d73df1d528496b852ed523139f8acc81f4f907 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 19 Jul 2023 13:49:57 +0200 Subject: [PATCH 1483/2042] MAINTAINERS: Add Kconfig.zephyr to Kconfig subsystem Top file Kconfig.zephyr didn't belong to any maintained area. Add it to Kconfig Signed-off-by: Erwan Gouriou --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index e54521306201..b7efb0bae35f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1594,6 +1594,7 @@ Kconfig: files: - scripts/kconfig/ - doc/build/kconfig/ + - Kconfig.zephyr labels: - "area: Kconfig" description: >- From 7388a07701b61feee2ce9653c51263a646d64f38 Mon Sep 17 00:00:00 2001 From: Filip Kokosinski Date: Wed, 19 Jul 2023 15:40:55 +0200 Subject: [PATCH 1484/2042] kconfig: expand the CLEANUP_INTERMEDIATE_FILES symbol description Y-selecting CLEANUP_INTERMEDIATE_FILES negatively impacts tools/commands that depend on the build artifacts being present. One such case is the `west spdx` command used for Software Bill of Material generation. If CLEANUP_INTERMEDIATE_FILES is y-selected, build files are removed from the `cfgTarget.target.artifacts` list. This in turn causes the `addBuildFile` function to nod add them to `pkg`, so `pkg.targetBuildFile` is `None` in `scripts/west_commands/zspdx/walker.py`. This commit expands the help message for the CLEANUP_INTERMEDIATE_FILES symbol to inform the user of the possible negative impact of selecting this symbol. Signed-off-by: Filip Kokosinski --- Kconfig.zephyr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 809565ee507c..6243a03fe7db 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -537,7 +537,8 @@ config CLEANUP_INTERMEDIATE_FILES bool "Remove all intermediate files" help Delete intermediate files to save space and cleanup clutter resulting - from the build process. + from the build process. Note this breaks incremental builds, west spdx + (Software Bill of Material generation), and maybe others. config BUILD_NO_GAP_FILL bool "Don't fill gaps in generated hex/bin/s19 files." From 385ad46a39ca70708927789ea588082ae1a4dd76 Mon Sep 17 00:00:00 2001 From: Kamil Galik Date: Thu, 22 Jun 2023 16:48:48 +0200 Subject: [PATCH 1485/2042] boards/xtensa: Skip cleaning intermediate binaries up This commit removes `CONFIG_CLEANUP_INTERMEDIATE_FILES` y-selection from some Xtensa board configs. Y-selecting this option causes `west spdx` to fail, due to reasons described in `CONFIG_CLEANUP_INTERMEDIATE_FILES` help string. If CLEANUP_INTERMEDIATE_FILES is y-selected, build files are removed from the `cfgTarget.target.artifacts` list. This in turn causes the `addBuildFile` function to nod add them to `pkg`, so `pkg.targetBuildFile` is `None` in `scripts/west_commands/zspdx/walker.py`. This causes the `west spdx` command to fail. Signed-off-by: Kamil Galik Signed-off-by: Filip Kokosinski --- boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_defconfig | 1 - boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_tgph_defconfig | 1 - boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig | 1 - boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig | 1 - boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig | 1 - 5 files changed, 5 deletions(-) diff --git a/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_defconfig b/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_defconfig index dc7a86d5acbe..18a587061767 100644 --- a/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_defconfig +++ b/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_defconfig @@ -17,7 +17,6 @@ CONFIG_MULTI_LEVEL_INTERRUPTS=y CONFIG_2ND_LEVEL_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_MP_MAX_NUM_CPUS=4 diff --git a/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_tgph_defconfig b/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_tgph_defconfig index 716932e9a24d..2787e3649f9d 100644 --- a/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_tgph_defconfig +++ b/boards/xtensa/intel_adsp_cavs25/intel_adsp_cavs25_tgph_defconfig @@ -18,7 +18,6 @@ CONFIG_MULTI_LEVEL_INTERRUPTS=y CONFIG_2ND_LEVEL_INTERRUPTS=y CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_DAI_SSP_HAS_POWER_CONTROL=y diff --git a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig index 1916547e5563..3d0c02d5017c 100644 --- a/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig +++ b/boards/xtensa/nxp_adsp_imx8/nxp_adsp_imx8_defconfig @@ -18,6 +18,5 @@ CONFIG_MULTI_LEVEL_INTERRUPTS=n CONFIG_2ND_LEVEL_INTERRUPTS=n CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_DCACHE_LINE_SIZE=128 diff --git a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig index 2aa634b97afe..f3b4ca76cbe9 100644 --- a/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig +++ b/boards/xtensa/nxp_adsp_imx8m/nxp_adsp_imx8m_defconfig @@ -19,7 +19,6 @@ CONFIG_MULTI_LEVEL_INTERRUPTS=n CONFIG_2ND_LEVEL_INTERRUPTS=n CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_DCACHE_LINE_SIZE=128 diff --git a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig index 77316f9dbf22..92a66362cd03 100644 --- a/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig +++ b/boards/xtensa/nxp_adsp_imx8x/nxp_adsp_imx8x_defconfig @@ -18,6 +18,5 @@ CONFIG_MULTI_LEVEL_INTERRUPTS=n CONFIG_2ND_LEVEL_INTERRUPTS=n CONFIG_BUILD_OUTPUT_BIN=n -CONFIG_CLEANUP_INTERMEDIATE_FILES=y CONFIG_DCACHE_LINE_SIZE=128 From 48fef88038b7f97a347e311866e5ee743d63e2ae Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Tue, 18 Jul 2023 14:56:22 +0200 Subject: [PATCH 1486/2042] scripts: pylib: twister: twisterlib: environment: TwisterEnv fixes Fixes Issue #60522 by guarding member access against None parameters. Shortens the init by using the if...else assignment. Fixes two typos. Signed-off-by: Lukasz Mrugala --- scripts/pylib/twister/twisterlib/environment.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 53ef2db14e03..9de0ebc370ce 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -797,6 +797,7 @@ def __init__(self, options=None) -> None: self.commit_date = None self.run_date = None self.options = options + if options and options.ninja: self.generator_cmd = "ninja" self.generator = "Ninja" @@ -805,10 +806,8 @@ def __init__(self, options=None) -> None: self.generator = "Unix Makefiles" logger.info(f"Using {self.generator}..") - if options: - self.test_roots = options.testsuite_root - else: - self.test_roots = None + self.test_roots = options.testsuite_root if options else None + if options: if not isinstance(options.board_root, list): self.board_roots = [self.options.board_root] @@ -821,9 +820,9 @@ def __init__(self, options=None) -> None: self.hwm = None - self.test_config = options.test_config + self.test_config = options.test_config if options else None - self.alt_config_root = options.alt_config_root + self.alt_config_root = options.alt_config_root if options else None def discover(self): self.check_zephyr_version() @@ -843,7 +842,7 @@ def check_zephyr_version(self): logger.info(f"Zephyr version: {self.version}") else: self.version = "Unknown" - logger.error("Coult not determine version") + logger.error("Could not determine version") except OSError: logger.info("Cannot read zephyr version.") @@ -889,7 +888,7 @@ def run_cmake_script(args=[]): out = ansi_escape.sub('', out.decode()) if p.returncode == 0: - msg = "Finished running %s" % (args[0]) + msg = "Finished running %s" % (args[0]) logger.debug(msg) results = {"returncode": p.returncode, "msg": msg, "stdout": out} From d72c4344eddac8cf5832fd12d7c6a37e6e6997f6 Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Fri, 9 Jun 2023 12:12:27 -0600 Subject: [PATCH 1487/2042] twister: Support --coverage-formats on lcov also When using twister to generate coverage with the coverage tool lcov, allow using --coverage-formats to pick if you want lcov or html, defaulting to both. Picking html will also use lcov, since that is required for geninfo. This will allow callers to avoid the potentially slow and disk intensive html reports if they only wanted the lcov info file. Signed-off-by: Jeremy Bettis --- scripts/pylib/twister/twisterlib/coverage.py | 11 ++++++++--- scripts/pylib/twister/twisterlib/environment.py | 8 +------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index 92d9f6690d2f..067dcfbcca7c 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -102,6 +102,7 @@ def generate(self, outdir): if ret == 0: report_log = { "html": "HTML report generated: {}".format(os.path.join(outdir, "coverage", "index.html")), + "lcov": "LCOV report generated: {}".format(os.path.join(outdir, "coverage.info")), "xml": "XML report generated: {}".format(os.path.join(outdir, "coverage", "coverage.xml")), "csv": "CSV report generated: {}".format(os.path.join(outdir, "coverage", "coverage.csv")), "txt": "TXT report generated: {}".format(os.path.join(outdir, "coverage", "coverage.txt")), @@ -117,6 +118,7 @@ class Lcov(CoverageTool): def __init__(self): super().__init__() self.ignores = [] + self.output_formats = "lcov,html" def add_ignore_file(self, pattern): self.ignores.append('*' + pattern + '*') @@ -159,6 +161,9 @@ def _generate(self, outdir, coveragelog): coveragefile, "--rc", "lcov_branch_coverage=1"], stdout=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", @@ -173,6 +178,7 @@ class Gcovr(CoverageTool): def __init__(self): super().__init__() self.ignores = [] + self.output_formats = "html" def add_ignore_file(self, pattern): self.ignores.append('.*' + pattern + '.*') @@ -269,9 +275,8 @@ def run_coverage(testplan, options): coverage_tool.gcov_tool = options.gcov_tool coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) # Apply output format default - if options.coverage_formats is None: - options.coverage_formats = "html" - coverage_tool.output_formats = options.coverage_formats + if options.coverage_formats is not None: + coverage_tool.output_formats = options.coverage_formats coverage_tool.add_ignore_file('generated') coverage_tool.add_ignore_directory('tests') coverage_tool.add_ignore_directory('samples') diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 9de0ebc370ce..939ffece4aef 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -299,9 +299,8 @@ def add_parse_arguments(parser = None): 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. " - "Only used in conjunction with gcovr. " "Default to html. " - "Valid options are html, xml, csv, txt, coveralls, sonarqube.") + "Valid options are html, xml, csv, txt, coveralls, sonarqube, lcov.") 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.") @@ -741,11 +740,6 @@ def parse_arguments(parser, args, options = None): logger.error("--shuffle-tests-seed requires --shuffle-tests") sys.exit(1) - if options.coverage_formats and (options.coverage_tool != "gcovr"): - logger.error("""--coverage-formats can only be used when coverage - tool is set to gcovr""") - sys.exit(1) - if options.size: from twisterlib.size_calc import SizeCalculator for fn in options.size: From d3db8899c85de78490f80864c92b7f04d38ab9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 16:59:36 +0200 Subject: [PATCH 1488/2042] lib: bitarray: doc: Add to Data Structures in docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promote Bit Array API to Modules > Utilities > Data Structures. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/bitarray.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/zephyr/sys/bitarray.h b/include/zephyr/sys/bitarray.h index 8f68f58fa9d2..90d1f59345bb 100644 --- a/include/zephyr/sys/bitarray.h +++ b/include/zephyr/sys/bitarray.h @@ -17,6 +17,18 @@ extern "C" { #include #include +/** + * @file + * + * @defgroup bitarray_apis Bit array + * @ingroup datastructure_apis + * + * @brief Store and manipulate bits in a bit array. + * + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ struct sys_bitarray { /* Number of bits */ uint32_t num_bits; @@ -30,7 +42,9 @@ struct sys_bitarray { /* Spinlock guarding access to this bit array */ struct k_spinlock lock; }; +/** @endcond */ +/** Bitarray structure */ typedef struct sys_bitarray sys_bitarray_t; /** @@ -263,6 +277,10 @@ int sys_bitarray_test_and_set_region(sys_bitarray_t *bitarray, size_t num_bits, int sys_bitarray_clear_region(sys_bitarray_t *bitarray, size_t num_bits, size_t offset); +/** + * @} + */ + #ifdef __cplusplus } #endif From 897cd59cfe0e1926071d194d974f7fb2dab35d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 16:41:06 +0200 Subject: [PATCH 1489/2042] lib: base64: doc: Promote to Utilities doc section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have base64 helpers show up in the Modules>Utilities section of the doc. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/base64.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/zephyr/sys/base64.h b/include/zephyr/sys/base64.h index 51d96c583342..a7e1f88c19a0 100644 --- a/include/zephyr/sys/base64.h +++ b/include/zephyr/sys/base64.h @@ -31,6 +31,15 @@ extern "C" { #endif +/** + * @file + * + * @defgroup base64 Base64 + * @brief Base64 encoding/decoding functions + * @ingroup utilities + * @{ + */ + /** * @brief Encode a buffer into base64 format * @@ -72,6 +81,10 @@ int base64_encode(uint8_t *dst, size_t dlen, size_t *olen, const uint8_t *src, int base64_decode(uint8_t *dst, size_t dlen, size_t *olen, const uint8_t *src, size_t slen); +/** + * @} + */ + #ifdef __cplusplus } #endif From 0d81be3d70832f6d14bb49e49236984a562ba058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 10:25:12 +0200 Subject: [PATCH 1490/2042] doc: kernel: Fix Doxygen comments for stats.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup doxygen documentation by adding missing comments + enabling docs for fields guarded by CONFIG_SCHED_THREAD_USAGE_ANALYSIS. Signed-off-by: Benjamin Cabé --- include/zephyr/kernel/stats.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/include/zephyr/kernel/stats.h b/include/zephyr/kernel/stats.h index 68f58b580183..812c963751fe 100644 --- a/include/zephyr/kernel/stats.h +++ b/include/zephyr/kernel/stats.h @@ -10,19 +10,24 @@ #include #include -/* - * [k_cycle_stats] is used to track internal statistics about both thread +/** + * Structure used to track internal statistics about both thread * and CPU usage. */ struct k_cycle_stats { - uint64_t total; /* total usage in cycles */ -#ifdef CONFIG_SCHED_THREAD_USAGE_ANALYSIS - uint64_t current; /* # of cycles in current usage window */ - uint64_t longest; /* # of cycles in longest usage window */ - uint32_t num_windows; /* # of usage windows */ + uint64_t total; /**< total usage in cycles */ +#if defined(CONFIG_SCHED_THREAD_USAGE_ANALYSIS) || defined(__DOXYGEN__) + /** + * @name Fields available when CONFIG_SCHED_THREAD_USAGE_ANALYSIS is selected. + * @{ + */ + uint64_t current; /**< \# of cycles in current usage window */ + uint64_t longest; /**< \# of cycles in longest usage window */ + uint32_t num_windows; /**< \# of usage windows */ + /** @} */ #endif - bool track_usage; /* true if gathering usage stats */ + bool track_usage; /**< true if gathering usage stats */ }; #endif From 545943310bdc09c2d77af205554b8b02057895a5 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Wed, 19 Jul 2023 15:48:20 +0200 Subject: [PATCH 1491/2042] drivers: pinctrl: remove unneeded TODO from Kconfig This TODO seems to be no longer needed here. Signed-off-by: Wojciech Sipak --- drivers/pinctrl/Kconfig.gecko | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig.gecko b/drivers/pinctrl/Kconfig.gecko index 9bc09b9d8c00..f2d7e67a56f8 100644 --- a/drivers/pinctrl/Kconfig.gecko +++ b/drivers/pinctrl/Kconfig.gecko @@ -1,6 +1,5 @@ # Copyright (c) 2022 Silicon Labs # SPDX-License-Identifier: Apache-2.0 -# TODO: copyright changes? config PINCTRL_GECKO bool "Gecko pin controller driver" From 5f9e698da43cda434c37675d2a7bd202f8652c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 12:01:00 +0200 Subject: [PATCH 1492/2042] canbus: isotp: doc: Document isotp_tx_callback_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added missing Doxygen doc for isotp_tx_callback_t Signed-off-by: Benjamin Cabé --- include/zephyr/canbus/isotp.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/zephyr/canbus/isotp.h b/include/zephyr/canbus/isotp.h index 0119c0531961..59880dfc12c3 100644 --- a/include/zephyr/canbus/isotp.h +++ b/include/zephyr/canbus/isotp.h @@ -121,7 +121,7 @@ /** Mask for priority in fixed addressing mode */ #define ISOTP_FIXED_ADDR_PRIO_MASK (CONFIG_ISOTP_FIXED_ADDR_PRIO_MASK) -/* CAN filter RX mask to match any priority and source address (SA) */ +/** CAN filter RX mask to match any priority and source address (SA) */ #define ISOTP_FIXED_ADDR_RX_MASK (CONFIG_ISOTP_FIXED_ADDR_RX_MASK) #ifdef __cplusplus @@ -172,6 +172,14 @@ struct isotp_fc_opts { uint8_t stmin; /**< Minimum separation time. Min time between frames */ }; +/** + * @brief Transmission callback + * + * This callback is called when a transmission is completed. + * + * @param error_nr ISOTP_N_OK on success, ISOTP_N_* on error + * @param arg Callback argument passed to the send function + */ typedef void (*isotp_tx_callback_t)(int error_nr, void *arg); struct isotp_send_ctx; From 90b322761a823f4c956f2a5cdd10c3b5196f17fb Mon Sep 17 00:00:00 2001 From: Chen Caidy Date: Wed, 19 Jul 2023 03:47:03 +0000 Subject: [PATCH 1493/2042] drivers: ethernet: mcux: improve receive timestamp accuracy When ENET_ENHANCEDBUFFERDESCRIPTOR_MODE enabled, MAC will automatic capture receive nanosecond from 1588TMR and return back to ENET_ReadFrame. It is a highest accuracy recv timestamp_ns, we do not need manually read from 1588TMR. By this change, receive timestamp accuracy increase from 20us to 200ns above. Signed-off-by: Chen Caidy --- drivers/ethernet/eth_mcux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index 637e4c72260c..30d4fa0fbadd 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -860,7 +860,7 @@ static int eth_rx(struct eth_context *context) ptpTimeData.second--; } - pkt->timestamp.nanosecond = ptpTimeData.nanosecond; + pkt->timestamp.nanosecond = ts; pkt->timestamp.second = ptpTimeData.second; } else { /* Invalid value. */ From 762df873b4bc10a2a77e02dd2a58f292e78a191b Mon Sep 17 00:00:00 2001 From: Chen Caidy Date: Wed, 19 Jul 2023 11:51:42 +0000 Subject: [PATCH 1494/2042] net: gptp: fix follow_up message timestamp According to IEEE802.1AS 11.4.4.2.1, we need fill preciseOriginTimestamp as syncEventEgressTimestamp. In this follow_up message, prec_orig_ts need to filled from net_pkt_timestamp(sync) for best accuracy. state machine is software trigger with insufficient precision. After this change, a grand master endpoint sync accuracy increase from 3.5ms to 580ns with mimxrt1050_evk board. Signed-off-by: Chen Caidy --- subsys/net/l2/ethernet/gptp/gptp_md.c | 7 ------- subsys/net/l2/ethernet/gptp/gptp_messages.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_md.c b/subsys/net/l2/ethernet/gptp/gptp_md.c index 750998ca4074..5c53df4fb3e4 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_md.c +++ b/subsys/net/l2/ethernet/gptp/gptp_md.c @@ -61,13 +61,6 @@ static void gptp_md_follow_up_prepare(struct net_pkt *pkt, hdr->log_msg_interval = sync_send->log_msg_interval; - fup->prec_orig_ts_secs_high = - htons(sync_send->precise_orig_ts._sec.high); - fup->prec_orig_ts_secs_low = - htonl(sync_send->precise_orig_ts._sec.low); - fup->prec_orig_ts_nsecs = - htonl(sync_send->precise_orig_ts.nanosecond); - fup->tlv_hdr.type = htons(GPTP_TLV_ORGANIZATION_EXT); fup->tlv_hdr.len = htons(sizeof(struct gptp_follow_up_tlv)); fup->tlv.org_id[0] = GPTP_FUP_TLV_ORG_ID_BYTE_0; diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index 615df286ea85..1aa6b64a38b4 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -238,8 +238,10 @@ struct net_pkt *gptp_prepare_sync(int port) struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) { struct gptp_hdr *hdr, *sync_hdr; + struct gptp_follow_up *fup; struct net_if *iface; struct net_pkt *pkt; + struct net_ptp_time *sync_ts; NET_ASSERT(sync); NET_ASSERT((port >= GPTP_PORT_START) && (port <= GPTP_PORT_END)); @@ -255,7 +257,9 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) net_pkt_set_priority(pkt, NET_PRIORITY_IC); hdr = GPTP_HDR(pkt); + fup = GPTP_FOLLOW_UP(pkt); sync_hdr = GPTP_HDR(sync); + sync_ts = net_pkt_timestamp(sync); /* * Header configuration. @@ -280,6 +284,14 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) hdr->reserved1 = 0U; hdr->reserved2 = 0U; + /* + * Get preciseOriginTimestamp from previous sync message + * according to IEEE802.1AS 11.4.4.2.1 syncEventEgressTimestamp + */ + fup->prec_orig_ts_secs_high = htons(sync_ts->_sec.high); + fup->prec_orig_ts_secs_low = htonl(sync_ts->_sec.low); + fup->prec_orig_ts_nsecs = htonl(sync_ts->nanosecond); + /* PTP configuration will be set by the MDSyncSend state machine. */ return pkt; From 413eceeddbe47bc71e3283b59e99aaf481f9b7ea Mon Sep 17 00:00:00 2001 From: Chen Caidy Date: Wed, 19 Jul 2023 12:09:15 +0000 Subject: [PATCH 1495/2042] net: gptp: fix follow_up message correction_field According to IEEE802.1AS Table 11-6 and 10.6.2.2.9, 802.1AS using peer-to-peer delay mechanism, two-step clock, Grand master clock should keep this correction_field as zero. Signed-off-by: Chen Caidy --- subsys/net/l2/ethernet/gptp/gptp_md.c | 16 ---------------- subsys/net/l2/ethernet/gptp/gptp_messages.c | 7 +++++-- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_md.c b/subsys/net/l2/ethernet/gptp/gptp_md.c index 5c53df4fb3e4..fd0c62182a48 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_md.c +++ b/subsys/net/l2/ethernet/gptp/gptp_md.c @@ -38,22 +38,6 @@ static void gptp_md_follow_up_prepare(struct net_pkt *pkt, hdr = GPTP_HDR(pkt); fup = GPTP_FOLLOW_UP(pkt); - /* - * Compute correction field according to IEEE802.1AS 11.2.14.2.3. - * - * The correction_field already contains the timestamp of the sync - * message. - * - * TODO: if the value to be stored in correction_field is too big to - * be represented, the field should be set to all 1's except the most - * significant bit. - */ - hdr->correction_field -= sync_send->upstream_tx_time; - hdr->correction_field *= sync_send->rate_ratio; - hdr->correction_field += sync_send->follow_up_correction_field; - hdr->correction_field <<= 16; - hdr->correction_field = htonll(hdr->correction_field); - memcpy(&hdr->port_id.clk_id, &sync_send->src_port_id.clk_id, GPTP_CLOCK_ID_LEN); diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index 1aa6b64a38b4..cb6fcf5bf389 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -271,8 +271,11 @@ struct net_pkt *gptp_prepare_follow_up(int port, struct net_pkt *sync) hdr->ptp_version = GPTP_VERSION; hdr->sequence_id = sync_hdr->sequence_id; hdr->domain_number = 0U; - /* Store timestamp value in correction field. */ - hdr->correction_field = gptp_timestamp_to_nsec(&sync->timestamp); + /* + * Grand master clock should keep correction_field at zero, + * according to IEEE802.1AS Table 11-6 and 10.6.2.2.9 + */ + hdr->correction_field = 0LL; hdr->flags.octets[0] = 0U; hdr->flags.octets[1] = GPTP_FLAG_PTP_TIMESCALE; hdr->message_length = htons(sizeof(struct gptp_hdr) + From 0635e2690e71cb423bb55b66c30e0a6a6a98b836 Mon Sep 17 00:00:00 2001 From: Chen Caidy Date: Wed, 19 Jul 2023 12:14:53 +0000 Subject: [PATCH 1496/2042] net: gptp: fix announce message byte order Linuxptp report UTC offset is 9472 seconds, is a byte order issue, The right value is 37. Also fixed offset_scaled_log_var byte order. Signed-off-by: Chen Caidy --- subsys/net/l2/ethernet/gptp/gptp_messages.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/ethernet/gptp/gptp_messages.c b/subsys/net/l2/ethernet/gptp/gptp_messages.c index cb6fcf5bf389..8fc1ffe2eaf9 100644 --- a/subsys/net/l2/ethernet/gptp/gptp_messages.c +++ b/subsys/net/l2/ethernet/gptp/gptp_messages.c @@ -535,7 +535,7 @@ struct net_pkt *gptp_prepare_announce(int port) hdr->reserved1 = 0U; hdr->reserved2 = 0U; - ann->cur_utc_offset = global_ds->current_utc_offset; + ann->cur_utc_offset = htons(global_ds->current_utc_offset); ann->time_source = global_ds->time_source; switch (GPTP_PORT_BMCA_DATA(port)->info_is) { @@ -543,9 +543,11 @@ struct net_pkt *gptp_prepare_announce(int port) ann->root_system_id.grand_master_prio1 = default_ds->priority1; ann->root_system_id.grand_master_prio2 = default_ds->priority2; - memcpy(&ann->root_system_id.clk_quality, - &default_ds->clk_quality, - sizeof(struct gptp_clock_quality)); + 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, From b1570314681f99d41ac1cd325436744f0d920a74 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 30 Jun 2023 22:22:35 -0400 Subject: [PATCH 1497/2042] kernel: split k_busy_wait() out of timeout.c This will allow for builds with CONFIG_SYS_CLOCK_EXISTS=n. For now this is only the code move. Signed-off-by: Nicolas Pitre --- kernel/CMakeLists.txt | 1 + kernel/busy_wait.c | 51 +++++++++++++++++++++++++++++++++++++++++++ kernel/timeout.c | 40 --------------------------------- 3 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 kernel/busy_wait.c diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 82427e83ba88..2dfcaee9af4c 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -41,6 +41,7 @@ else() list(APPEND kernel_files main_weak.c banner.c + busy_wait.c device.c errno.c fatal.c diff --git a/kernel/busy_wait.c b/kernel/busy_wait.c new file mode 100644 index 000000000000..c19020754503 --- /dev/null +++ b/kernel/busy_wait.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +void z_impl_k_busy_wait(uint32_t usec_to_wait) +{ + SYS_PORT_TRACING_FUNC_ENTER(k_thread, busy_wait, usec_to_wait); + if (usec_to_wait == 0U) { + SYS_PORT_TRACING_FUNC_EXIT(k_thread, busy_wait, usec_to_wait); + return; + } + +#if defined(CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT) + arch_busy_wait(usec_to_wait); +#else + 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 + ); + + for (;;) { + uint32_t current_cycles = k_cycle_get_32(); + + /* this handles the rollover on an unsigned 32-bit value */ + if ((current_cycles - start_cycles) >= cycles_to_wait) { + break; + } + } +#endif + + SYS_PORT_TRACING_FUNC_EXIT(k_thread, busy_wait, usec_to_wait); +} + +#ifdef CONFIG_USERSPACE +static inline void z_vrfy_k_busy_wait(uint32_t usec_to_wait) +{ + z_impl_k_busy_wait(usec_to_wait); +} +#include +#endif /* CONFIG_USERSPACE */ diff --git a/kernel/timeout.c b/kernel/timeout.c index 67c128429bd0..df8c2aaede37 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -289,46 +289,6 @@ static inline int64_t z_vrfy_k_uptime_ticks(void) #include #endif -void z_impl_k_busy_wait(uint32_t usec_to_wait) -{ - SYS_PORT_TRACING_FUNC_ENTER(k_thread, busy_wait, usec_to_wait); - if (usec_to_wait == 0U) { - SYS_PORT_TRACING_FUNC_EXIT(k_thread, busy_wait, usec_to_wait); - return; - } - -#if !defined(CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT) - 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 - ); - - for (;;) { - uint32_t current_cycles = k_cycle_get_32(); - - /* this handles the rollover on an unsigned 32-bit value */ - if ((current_cycles - start_cycles) >= cycles_to_wait) { - break; - } - } -#else - arch_busy_wait(usec_to_wait); -#endif /* CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT */ - SYS_PORT_TRACING_FUNC_EXIT(k_thread, busy_wait, usec_to_wait); -} - -#ifdef CONFIG_USERSPACE -static inline void z_vrfy_k_busy_wait(uint32_t usec_to_wait) -{ - z_impl_k_busy_wait(usec_to_wait); -} -#include -#endif /* CONFIG_USERSPACE */ - /* Returns the uptime expiration (relative to an unlocked "now"!) of a * timeout object. When used correctly, this should be called once, * synchronously with the user passing a new timeout value. It should From 13a6c454529e64cdb9f69cab0f0a9fb8c539b192 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 19 Jul 2023 14:45:19 -0400 Subject: [PATCH 1498/2042] kernel: crude k_busy_wait() implementation This allows for builds with CONFIG_SYS_CLOCK_EXISTS=n in which case busy waits are achieved with a crude CPU loop. If ever accuracy is needed even with such a configuration then implementing arch_busy_wait() should be considered. Signed-off-by: Nicolas Pitre --- kernel/Kconfig | 12 ++++++++++++ kernel/busy_wait.c | 13 ++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/kernel/Kconfig b/kernel/Kconfig index 12cd7b8f836b..695b3b10710f 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -755,6 +755,18 @@ config SYS_CLOCK_MAX_TIMEOUT_DAYS algorithm is selected for conversion if maximum timeout represented in source frequency domain multiplied by target frequency fits in 64 bits. +config BUSYWAIT_CPU_LOOPS_PER_USEC + int "Number of CPU loops per microsecond for crude busy looping" + depends on !SYS_CLOCK_EXISTS && !ARCH_HAS_CUSTOM_BUSY_WAIT + default 500 + help + Calibration for crude CPU based busy loop duration. The default + is assuming 1 GHz CPU and 2 cycles per loop. Reality is certainly + much worse but all we want here is a ball-park figure that ought + to be good enough for the purpose of being able to configure out + system timer support. If accuracy is very important then + implementing arch_busy_wait() should be considered. + config XIP bool "Execute in place" help diff --git a/kernel/busy_wait.c b/kernel/busy_wait.c index c19020754503..4bb94ca04d59 100644 --- a/kernel/busy_wait.c +++ b/kernel/busy_wait.c @@ -19,7 +19,7 @@ void z_impl_k_busy_wait(uint32_t usec_to_wait) #if defined(CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT) arch_busy_wait(usec_to_wait); -#else +#elif defined(CONFIG_SYS_CLOCK_EXISTS) uint32_t start_cycles = k_cycle_get_32(); /* use 64-bit math to prevent overflow when multiplying */ @@ -37,6 +37,17 @@ void z_impl_k_busy_wait(uint32_t usec_to_wait) break; } } +#else + /* + * Crude busy loop for the purpose of being able to configure out + * system timer support. + */ + unsigned int loops_per_usec = CONFIG_BUSYWAIT_CPU_LOOPS_PER_USEC; + unsigned int loops = loops_per_usec * usec_to_wait; + + while (loops-- > 0) { + arch_nop(); + } #endif SYS_PORT_TRACING_FUNC_EXIT(k_thread, busy_wait, usec_to_wait); From 256b0c5bfbb6c5860bfc49685e899113c6349dd6 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Tue, 18 Jul 2023 15:36:53 +0200 Subject: [PATCH 1499/2042] tests: lib: c_lib testcase running with 32KB min ram Limit the testcase to targets with more than 32KB RAM Because of the CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE 8192, the RAM used by the testcase on a too small target might fail at runtime. For example on a nucleo_l073rz target: RAM: 15292 B 20 KB 74.67% Signed-off-by: Francois Ramu --- tests/lib/c_lib/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/testcase.yaml index 9d083c82b7a7..7bc5833a96a8 100644 --- a/tests/lib/c_lib/testcase.yaml +++ b/tests/lib/c_lib/testcase.yaml @@ -16,6 +16,7 @@ tests: - CONFIG_PICOLIBC=y libraries.libc.newlib: filter: CONFIG_NEWLIB_LIBC_SUPPORTED + min_ram: 32 tags: newlib ignore_faults: true extra_configs: From 32efdf9239ea2dfa51d7a6bafb278a549928c49a Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 20 Jul 2023 08:45:10 +0200 Subject: [PATCH 1500/2042] drivers: counter: stm32: Review use const TIM_TypeDef on few series A recent Cube update moved C0/L1/WBA to use const TIM_TypeDef Align counter driver implementation. Signed-off-by: Erwan Gouriou --- drivers/counter/counter_ll_stm32_timer.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index a64fe1dedffb..55af65c7e0a0 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -42,13 +42,10 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to compare get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32C0X) && \ - !defined(CONFIG_SOC_SERIES_STM32F1X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32L1X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) && \ - !defined(CONFIG_SOC_SERIES_STM32WBAX) + !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_OC_GetCompareCH1, LL_TIM_OC_GetCompareCH2, LL_TIM_OC_GetCompareCH3, LL_TIM_OC_GetCompareCH4, @@ -73,13 +70,10 @@ 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_STM32C0X) && \ - !defined(CONFIG_SOC_SERIES_STM32F1X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ - !defined(CONFIG_SOC_SERIES_STM32L1X) && \ - !defined(CONFIG_SOC_SERIES_STM32MP1X) && \ - !defined(CONFIG_SOC_SERIES_STM32WBAX) + !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const check_it_enabled[TIMER_MAX_CH])(const TIM_TypeDef *) = { LL_TIM_IsEnabledIT_CC1, LL_TIM_IsEnabledIT_CC2, LL_TIM_IsEnabledIT_CC3, LL_TIM_IsEnabledIT_CC4, From 69c365950752bfc73dde5ca3720643777fd8ce2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 06:15:06 +0200 Subject: [PATCH 1501/2042] fs: nvs: doc: Provide useful brief descs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide useful descriptions for NVS API. Signed-off-by: Benjamin Cabé --- include/zephyr/fs/nvs.h | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/include/zephyr/fs/nvs.h b/include/zephyr/fs/nvs.h index c5a8763697b6..30315d77b20c 100644 --- a/include/zephyr/fs/nvs.h +++ b/include/zephyr/fs/nvs.h @@ -17,8 +17,8 @@ extern "C" { #endif /** - * @brief Non-volatile Storage - * @defgroup nvs Non-volatile Storage + * @brief Non-volatile Storage (NVS) + * @defgroup nvs Non-volatile Storage (NVS) * @ingroup file_system_storage * @{ * @} @@ -74,9 +74,7 @@ struct nvs_fs { */ /** - * @brief nvs_mount - * - * Mount a NVS file system onto the flash device specified in @p fs. + * @brief Mount an NVS file system onto the flash device specified in @p fs. * * @param fs Pointer to file system * @retval 0 Success @@ -85,9 +83,8 @@ struct nvs_fs { int nvs_mount(struct nvs_fs *fs); /** - * @brief nvs_clear + * @brief Clear the NVS file system from flash. * - * Clears the NVS file system from flash. * @param fs Pointer to file system * @retval 0 Success * @retval -ERRNO errno code if error @@ -95,9 +92,7 @@ int nvs_mount(struct nvs_fs *fs); int nvs_clear(struct nvs_fs *fs); /** - * @brief nvs_write - * - * Write an entry to the file system. + * @brief Write an entry to the file system. * * @param fs Pointer to file system * @param id Id of the entry to be written @@ -111,9 +106,7 @@ int nvs_clear(struct nvs_fs *fs); ssize_t nvs_write(struct nvs_fs *fs, uint16_t id, const void *data, size_t len); /** - * @brief nvs_delete - * - * Delete an entry from the file system + * @brief Delete an entry from the file system * * @param fs Pointer to file system * @param id Id of the entry to be deleted @@ -123,9 +116,7 @@ ssize_t nvs_write(struct nvs_fs *fs, uint16_t id, const void *data, size_t len); int nvs_delete(struct nvs_fs *fs, uint16_t id); /** - * @brief nvs_read - * - * Read an entry from the file system. + * @brief Read an entry from the file system. * * @param fs Pointer to file system * @param id Id of the entry to be read @@ -140,9 +131,7 @@ int nvs_delete(struct nvs_fs *fs, uint16_t id); ssize_t nvs_read(struct nvs_fs *fs, uint16_t id, void *data, size_t len); /** - * @brief nvs_read_hist - * - * Read a history entry from the file system. + * @brief Read a history entry from the file system. * * @param fs Pointer to file system * @param id Id of the entry to be read @@ -158,9 +147,7 @@ ssize_t nvs_read(struct nvs_fs *fs, uint16_t id, void *data, size_t len); ssize_t nvs_read_hist(struct nvs_fs *fs, uint16_t id, void *data, size_t len, uint16_t cnt); /** - * @brief nvs_calc_free_space - * - * Calculate the available free space in the file system. + * @brief Calculate the available free space in the file system. * * @param fs Pointer to file system * From 5b78a386e9b9defa5f660c6f4f2a70c0070d9922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 06:21:30 +0200 Subject: [PATCH 1502/2042] fs: doc: Fix fs_file_system_t documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly document the fs_file_system_t structure Signed-off-by: Benjamin Cabé --- include/zephyr/fs/fs_sys.h | 104 +++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 26 deletions(-) diff --git a/include/zephyr/fs/fs_sys.h b/include/zephyr/fs/fs_sys.h index 806162bdc915..f3ee8b286d63 100644 --- a/include/zephyr/fs/fs_sys.h +++ b/include/zephyr/fs/fs_sys.h @@ -18,59 +18,111 @@ extern "C" { /** * @brief File System interface structure - * - * @param open Opens or creates a file, depending on flags given - * @param read Reads nbytes number of bytes - * @param write Writes nbytes number of bytes - * @param lseek Moves the file position to a new location in the file - * @param tell Retrieves the current position in the file - * @param truncate Truncates/expands the file to the new length - * @param sync Flushes the cache of an open file - * @param close Flushes the associated stream and closes the file - * @param opendir Opens an existing directory specified by the path - * @param readdir Reads directory entries of an open directory - * @param closedir Closes an open directory - * @param mount Mounts a file system - * @param unmount Unmounts a file system - * @param unlink Deletes the specified file or directory - * @param rename Renames a file or directory - * @param mkdir Creates a new directory using specified path - * @param stat Checks the status of a file or directory specified by the path - * @param statvfs Returns the total and available space on the file system - * volume - * @param mkfs Formats a device to specified file system type. Note that this - * operation destroys existing data on a target device. */ struct fs_file_system_t { - /* File operations */ + /** + * @name File operations + * @{ + */ + /** + * Opens or creates a file, depending on flags given. + */ int (*open)(struct fs_file_t *filp, const char *fs_path, fs_mode_t flags); + /** + * Reads nbytes number of bytes. + */ ssize_t (*read)(struct fs_file_t *filp, void *dest, size_t nbytes); + /** + * Writes nbytes number of bytes. + */ ssize_t (*write)(struct fs_file_t *filp, const void *src, size_t nbytes); + /** + * Moves the file position to a new location in the file. + */ int (*lseek)(struct fs_file_t *filp, off_t off, int whence); + /** + * Retrieves the current position in the file. + */ off_t (*tell)(struct fs_file_t *filp); + /** + * Truncates/expands the file to the new length. + */ int (*truncate)(struct fs_file_t *filp, off_t length); + /** + * Flushes the cache of an open file. + */ int (*sync)(struct fs_file_t *filp); + /** + * Flushes the associated stream and closes the file. + */ int (*close)(struct fs_file_t *filp); - /* Directory operations */ + /** @} */ + + /** + * @name Directory operations + * @{ + */ + /** + * Opens an existing directory specified by the path. + */ int (*opendir)(struct fs_dir_t *dirp, const char *fs_path); + /** + * Reads directory entries of an open directory. + */ int (*readdir)(struct fs_dir_t *dirp, struct fs_dirent *entry); + /** + * Closes an open directory. + */ int (*closedir)(struct fs_dir_t *dirp); - /* File system level operations */ + /** @} */ + + /** + * @name File system level operations + * @{ + */ + /** + * Mounts a file system. + */ int (*mount)(struct fs_mount_t *mountp); + /** + * Unmounts a file system. + */ int (*unmount)(struct fs_mount_t *mountp); + /** + * Deletes the specified file or directory. + */ int (*unlink)(struct fs_mount_t *mountp, const char *name); + /** + * Renames a file or directory. + */ int (*rename)(struct fs_mount_t *mountp, const char *from, const char *to); + /** + * Creates a new directory using specified path. + */ int (*mkdir)(struct fs_mount_t *mountp, const char *name); + /** + * Checks the status of a file or directory specified by the path. + */ int (*stat)(struct fs_mount_t *mountp, const char *path, struct fs_dirent *entry); + /** + * Returns the total and available space on the file system volume. + */ int (*statvfs)(struct fs_mount_t *mountp, const char *path, struct fs_statvfs *stat); -#if defined(CONFIG_FILE_SYSTEM_MKFS) +#if defined(CONFIG_FILE_SYSTEM_MKFS) || defined(__DOXYGEN__) + /** + * Formats a device to specified file system type. + * Available only if @kconfig{CONFIG_FILE_SYSTEM_MKFS} is enabled. + * + * @note This operation destroys existing data on the target device. + */ int (*mkfs)(uintptr_t dev_id, void *cfg, int flags); #endif + /** @} */ }; /** From ae7efcade244035d67f4cf9570eb88995dc108a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 06:45:15 +0200 Subject: [PATCH 1503/2042] fs: doc: Document fs_file_system_t methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fully document all the methods in the File System interface structure Signed-off-by: Benjamin Cabé --- include/zephyr/fs/fs_sys.h | 78 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/include/zephyr/fs/fs_sys.h b/include/zephyr/fs/fs_sys.h index f3ee8b286d63..decb07332c15 100644 --- a/include/zephyr/fs/fs_sys.h +++ b/include/zephyr/fs/fs_sys.h @@ -26,36 +26,69 @@ struct fs_file_system_t { */ /** * Opens or creates a file, depending on flags given. + * + * @param filp File to open/create. + * @param fs_path Path to the file. + * @param flags Flags for opening/creating the file. + * @return 0 on success, negative errno code on fail. */ int (*open)(struct fs_file_t *filp, const char *fs_path, fs_mode_t flags); /** * Reads nbytes number of bytes. + * + * @param filp File to read from. + * @param dest Destination buffer. + * @param nbytes Number of bytes to read. + * @return Number of bytes read on success, negative errno code on fail. */ ssize_t (*read)(struct fs_file_t *filp, void *dest, size_t nbytes); /** * Writes nbytes number of bytes. + * + * @param filp File to write to. + * @param src Source buffer. + * @param nbytes Number of bytes to write. + * @return Number of bytes written on success, negative errno code on fail. */ ssize_t (*write)(struct fs_file_t *filp, const void *src, size_t nbytes); /** * Moves the file position to a new location in the file. + * + * @param filp File to move. + * @param off Relative offset from the position specified by whence. + * @param whence Position in the file. Possible values: SEEK_CUR, SEEK_SET, SEEK_END. + * @return New position in the file or negative errno code on fail. */ int (*lseek)(struct fs_file_t *filp, off_t off, int whence); /** * Retrieves the current position in the file. + * + * @param filp File to get the current position from. + * @return Current position in the file or negative errno code on fail. */ off_t (*tell)(struct fs_file_t *filp); /** * Truncates/expands the file to the new length. + * + * @param filp File to truncate/expand. + * @param length New length of the file. + * @return 0 on success, negative errno code on fail. */ int (*truncate)(struct fs_file_t *filp, off_t length); /** * Flushes the cache of an open file. + * + * @param filp File to flush. + * @return 0 on success, negative errno code on fail. */ int (*sync)(struct fs_file_t *filp); /** * Flushes the associated stream and closes the file. + * + * @param filp File to close. + * @return 0 on success, negative errno code on fail. */ int (*close)(struct fs_file_t *filp); /** @} */ @@ -66,14 +99,25 @@ struct fs_file_system_t { */ /** * Opens an existing directory specified by the path. + * + * @param dirp Directory to open. + * @param fs_path Path to the directory. + * @return 0 on success, negative errno code on fail. */ int (*opendir)(struct fs_dir_t *dirp, const char *fs_path); /** * Reads directory entries of an open directory. + * + * @param dirp Directory to read from. + * @param entry Next directory entry in the dirp directory. + * @return 0 on success, negative errno code on fail. */ int (*readdir)(struct fs_dir_t *dirp, struct fs_dirent *entry); /** * Closes an open directory. + * + * @param dirp Directory to close. + * @return 0 on success, negative errno code on fail. */ int (*closedir)(struct fs_dir_t *dirp); /** @} */ @@ -84,32 +128,61 @@ struct fs_file_system_t { */ /** * Mounts a file system. + * + * @param mountp Mount point. + * @return 0 on success, negative errno code on fail. */ int (*mount)(struct fs_mount_t *mountp); /** * Unmounts a file system. + * + * @param mountp Mount point. + * @return 0 on success, negative errno code on fail. */ int (*unmount)(struct fs_mount_t *mountp); /** * Deletes the specified file or directory. + * + * @param mountp Mount point. + * @param name Path to the file or directory to delete. + * @return 0 on success, negative errno code on fail. */ int (*unlink)(struct fs_mount_t *mountp, const char *name); /** * Renames a file or directory. + * + * @param mountp Mount point. + * @param from Path to the file or directory to rename. + * @param to New name of the file or directory. + * @return 0 on success, negative errno code on fail. */ int (*rename)(struct fs_mount_t *mountp, const char *from, const char *to); /** * Creates a new directory using specified path. + * + * @param mountp Mount point. + * @param name Path to the directory to create. + * @return 0 on success, negative errno code on fail. */ int (*mkdir)(struct fs_mount_t *mountp, const char *name); /** * Checks the status of a file or directory specified by the path. + * + * @param mountp Mount point. + * @param path Path to the file or directory. + * @param entry Directory entry. + * @return 0 on success, negative errno code on fail. */ int (*stat)(struct fs_mount_t *mountp, const char *path, struct fs_dirent *entry); /** * Returns the total and available space on the file system volume. + * + * @param mountp Mount point. + * @param path Path to the file or directory. + * @param stat File system statistics. + * @return 0 on success, negative errno code on fail. */ int (*statvfs)(struct fs_mount_t *mountp, const char *path, struct fs_statvfs *stat); @@ -118,6 +191,11 @@ struct fs_file_system_t { * Formats a device to specified file system type. * Available only if @kconfig{CONFIG_FILE_SYSTEM_MKFS} is enabled. * + * @param dev_id Device identifier. + * @param cfg File system configuration. + * @param flags Formatting flags. + * @return 0 on success, negative errno code on fail. + * * @note This operation destroys existing data on the target device. */ int (*mkfs)(uintptr_t dev_id, void *cfg, int flags); From 485ebbbebd994a8c1f4f5dddf0794aecf5275b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 07:13:38 +0200 Subject: [PATCH 1504/2042] fs: doc: Document fs.h structs and macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Doxygen docs for structs and added missing docs for a few macros and enums. Signed-off-by: Benjamin Cabé --- include/zephyr/fs/fs.h | 50 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/include/zephyr/fs/fs.h b/include/zephyr/fs/fs.h index 300da9272c7f..699b5e9ec6b3 100644 --- a/include/zephyr/fs/fs.h +++ b/include/zephyr/fs/fs.h @@ -25,6 +25,9 @@ extern "C" { */ struct fs_file_system_t; +/** + * @brief Enumeration for directory entry types + */ enum fs_dir_entry_type { /** Identifier for file entry */ FS_DIR_ENTRY_FILE = 0, @@ -79,43 +82,41 @@ enum { /** * @brief File system mount info structure - * - * @param node Entry for the fs_mount_list list - * @param type File system type - * @param mnt_point Mount point directory name (ex: "/fatfs") - * @param fs_data Pointer to file system specific data - * @param storage_dev Pointer to backend storage device - * @param mountp_len Length of Mount point string - * @param fs Pointer to File system interface of the mount point - * @param flags Mount flags */ struct fs_mount_t { + /** Entry for the fs_mount_list list */ sys_dnode_t node; + /** File system type */ int type; + /** Mount point directory name (ex: "/fatfs") */ const char *mnt_point; + /** Pointer to file system specific data */ void *fs_data; + /** Pointer to backend storage device */ void *storage_dev; - /* fields filled by file system core */ + /* The following fields are filled by file system core */ + /** Length of Mount point string */ size_t mountp_len; + /** Pointer to File system interface of the mount point */ const struct fs_file_system_t *fs; + /** Mount flags */ uint8_t flags; }; /** * @brief Structure to receive file or directory information * - * Used in functions that reads the directory entries to get + * Used in functions that read the directory entries to get * file or directory information. - * - * @param dir_entry_type Whether file or directory - * - FS_DIR_ENTRY_FILE - * - FS_DIR_ENTRY_DIR - * @param name Name of directory or file - * @param size Size of file. 0 if directory */ struct fs_dirent { + /** + * File/directory type (FS_DIR_ENTRY_FILE or FS_DIR_ENTRY_DIR) + */ enum fs_dir_entry_type type; + /** Name of file or directory */ char name[MAX_FILE_NAME + 1]; + /** Size of file (0 if directory). */ size_t size; }; @@ -124,16 +125,15 @@ struct fs_dirent { * * Used to retrieve information about total and available space * in the volume. - * - * @param f_bsize Optimal transfer block size - * @param f_frsize Allocation unit size - * @param f_blocks Size of FS in f_frsize units - * @param f_bfree Number of free blocks */ struct fs_statvfs { + /** Optimal transfer block size */ unsigned long f_bsize; + /** Allocation unit size */ unsigned long f_frsize; + /** Size of FS in f_frsize units */ unsigned long f_blocks; + /** Number of free blocks */ unsigned long f_bfree; }; @@ -184,7 +184,7 @@ struct fs_statvfs { * @} */ -/* +/** * @brief Get the common mount flags for an fstab entry. * @param node_id the node identifier for a child entry in a @@ -201,6 +201,8 @@ struct fs_statvfs { /** * @brief The name under which a zephyr,fstab entry mount structure is * defined. + * + * @param node_id the node identifier for a child entry in a zephyr,fstab node. */ #define FS_FSTAB_ENTRY(node_id) _CONCAT(z_fsmp_, node_id) @@ -209,6 +211,8 @@ struct fs_statvfs { * entry. * * This will evaluate to the name of a struct fs_mount_t object. + * + * @param node_id the node identifier for a child entry in a zephyr,fstab node. */ #define FS_FSTAB_DECLARE_ENTRY(node_id) \ extern struct fs_mount_t FS_FSTAB_ENTRY(node_id) From d48c3396cb7b309628bcbbc2e13da83743ec238c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 07:14:09 +0200 Subject: [PATCH 1505/2042] fs: doc: fs_interface doxygen fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed Doxygen docs for structs Signed-off-by: Benjamin Cabé --- include/zephyr/fs/fs_interface.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/zephyr/fs/fs_interface.h b/include/zephyr/fs/fs_interface.h index 1ca1be081409..d1d78f8cb4fc 100644 --- a/include/zephyr/fs/fs_interface.h +++ b/include/zephyr/fs/fs_interface.h @@ -45,27 +45,26 @@ struct fs_mount_t; /** * @brief File object representing an open file * - * The object needs to be initialized with function fs_file_t_init(). - * - * @param Pointer to FATFS file object structure - * @param mp Pointer to mount point structure + * The object needs to be initialized with fs_file_t_init(). */ struct fs_file_t { + /** Pointer to file object structure */ void *filep; + /** Pointer to mount point structure */ const struct fs_mount_t *mp; + /** Open/create flags */ fs_mode_t flags; }; /** * @brief Directory object representing an open directory * - * The object needs to be initialized with function fs_dir_t_init(). - * - * @param dirp Pointer to directory object structure - * @param mp Pointer to mount point structure + * The object needs to be initialized with fs_dir_t_init(). */ struct fs_dir_t { + /** Pointer to directory object structure */ void *dirp; + /** Pointer to mount point structure */ const struct fs_mount_t *mp; }; From 660c5f5c98a23b70f9e96428c607d136b51919a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Thu, 20 Jul 2023 10:53:04 +0200 Subject: [PATCH 1506/2042] doc: mqtt: Add missing Doxygen comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completed the documentation of the mqtt.h header file. Signed-off-by: Benjamin Cabé --- include/zephyr/net/mqtt.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/zephyr/net/mqtt.h b/include/zephyr/net/mqtt.h index aaba49a60e56..1980b95bbeaf 100644 --- a/include/zephyr/net/mqtt.h +++ b/include/zephyr/net/mqtt.h @@ -11,9 +11,6 @@ * @{ * @brief MQTT Client Implementation * - * @details - * MQTT Client's Application interface is defined in this header. - * * @note The implementation assumes TCP module is enabled. * * @note By default the implementation uses MQTT version 3.1.1. @@ -207,36 +204,45 @@ struct mqtt_connack_param { /** @brief Parameters for MQTT publish acknowledgment (PUBACK). */ struct mqtt_puback_param { + /** Message id of the PUBLISH message being acknowledged */ uint16_t message_id; }; /** @brief Parameters for MQTT publish receive (PUBREC). */ struct mqtt_pubrec_param { + /** Message id of the PUBLISH message being acknowledged */ uint16_t message_id; }; /** @brief Parameters for MQTT publish release (PUBREL). */ struct mqtt_pubrel_param { + /** Message id of the PUBREC message being acknowledged */ uint16_t message_id; }; /** @brief Parameters for MQTT publish complete (PUBCOMP). */ struct mqtt_pubcomp_param { + /** Message id of the PUBREL message being acknowledged */ uint16_t message_id; }; /** @brief Parameters for MQTT subscription acknowledgment (SUBACK). */ struct mqtt_suback_param { + /** Message id of the SUBSCRIBE message being acknowledged */ uint16_t message_id; + /** Return codes indicating maximum QoS level granted for each topic + * in the subscription list. + */ struct mqtt_binstr return_codes; }; /** @brief Parameters for MQTT unsubscribe acknowledgment (UNSUBACK). */ struct mqtt_unsuback_param { + /** Message id of the UNSUBSCRIBE message being acknowledged */ uint16_t message_id; }; -/** @brief Parameters for a publish message. */ +/** @brief Parameters for a publish message (PUBLISH). */ struct mqtt_publish_param { /** Messages including topic, QoS and its payload (if any) * to be published. From 26bf349ab12933d52384d41b647e552559738710 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 18 Jul 2023 10:23:18 +0200 Subject: [PATCH 1507/2042] pm: drop HAS_NO_PM Remove HAS_NO_PM option, in preparation for a new HAS_PM option (inverted logic). Signed-off-by: Gerard Marull-Paretas --- soc/arm/nordic_nrf/Kconfig.defconfig | 2 +- soc/arm/nordic_nrf/nrf53/Kconfig.soc | 1 - subsys/pm/Kconfig | 10 +--------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 183ec475fde9..bf4264c734bc 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -29,7 +29,7 @@ config ARCH_HAS_CUSTOM_BUSY_WAIT default y if !QEMU_TARGET config PM - default y if SYS_CLOCK_EXISTS && !HAS_NO_PM && MULTITHREADING + default y if SYS_CLOCK_EXISTS && MULTITHREADING config BUILD_OUTPUT_HEX default y diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 67cb8a08a6f7..521964b5ac62 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -12,7 +12,6 @@ config SOC_NRF5340_CPUAPP config SOC_NRF5340_CPUNET bool - select HAS_NO_PM select ARM_ON_EXIT_CPU_IDLE imply SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 240924f17bac..3a66d736c411 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -6,7 +6,7 @@ menu "Power Management" menuconfig PM bool "System Power Management" - depends on SYS_CLOCK_EXISTS && !HAS_NO_PM + depends on SYS_CLOCK_EXISTS help This option enables the board to implement extra power management policies whenever the kernel becomes idle. The kernel informs the @@ -54,14 +54,6 @@ endchoice endif # PM -config HAS_NO_PM - bool - help - This option blocks selection of PM. It can be selected in SOC - targets where system power management is not supported, for example - on support core of a multi-core device where SoC power management is - the responsibility of a different core. - config PM_DEVICE bool "Device Power Management" help From 3d2194f11e465adb2b99dfe85f88fef41ace7500 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 18 Jul 2023 10:40:27 +0200 Subject: [PATCH 1508/2042] pm: introduce HAS_PM Add a new Kconfig option that has to be selected by SoCs providing PM hooks. This option will be now required to enable CONFIG_PM. Before this change, CONFIG_PM could always be enabled, regardless of SoC providing any kind of low-power support. Signed-off-by: Gerard Marull-Paretas --- soc/arm/microchip_mec/mec1501/Kconfig.series | 1 + soc/arm/microchip_mec/mec172x/Kconfig.series | 1 + soc/arm/nordic_nrf/Kconfig.defconfig | 2 +- soc/arm/nordic_nrf/nrf51/Kconfig.series | 1 + soc/arm/nordic_nrf/nrf52/Kconfig.series | 1 + soc/arm/nordic_nrf/nrf53/Kconfig.soc | 1 + soc/arm/nordic_nrf/nrf91/Kconfig.series | 1 + soc/arm/nuvoton_npcx/npcx7/Kconfig.series | 1 + soc/arm/nuvoton_npcx/npcx9/Kconfig.series | 1 + soc/arm/nxp_imx/rt/Kconfig.series | 1 + soc/arm/nxp_imx/rt5xx/Kconfig.series | 1 + soc/arm/nxp_imx/rt6xx/Kconfig.series | 1 + soc/arm/nxp_kinetis/ke1xf/Kconfig.series | 1 + soc/arm/silabs_exx32/efm32hg/Kconfig.series | 1 + soc/arm/silabs_exx32/efm32jg12b/Kconfig.series | 1 + soc/arm/silabs_exx32/efm32pg12b/Kconfig.series | 1 + soc/arm/silabs_exx32/efm32pg1b/Kconfig.series | 1 + soc/arm/silabs_exx32/efm32wg/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32bg13p/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32bg22/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32bg27/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32fg13p/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32fg1p/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32mg12p/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32mg21/Kconfig.series | 1 + soc/arm/silabs_exx32/efr32mg24/Kconfig.series | 1 + soc/arm/st_stm32/stm32g0/Kconfig.series | 1 + soc/arm/st_stm32/stm32g4/Kconfig.series | 1 + soc/arm/st_stm32/stm32l0/Kconfig.series | 1 + soc/arm/st_stm32/stm32l4/Kconfig.series | 1 + soc/arm/st_stm32/stm32l5/Kconfig.series | 1 + soc/arm/st_stm32/stm32u5/Kconfig.series | 1 + soc/arm/st_stm32/stm32wb/Kconfig.series | 1 + soc/arm/st_stm32/stm32wba/Kconfig.series | 1 + soc/arm/st_stm32/stm32wl/Kconfig.series | 1 + soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series | 1 + soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series | 1 + soc/riscv/esp32c3/Kconfig.soc | 1 + soc/riscv/riscv-ite/it8xxx2/Kconfig.series | 1 + soc/xtensa/esp32/Kconfig.soc | 1 + soc/xtensa/esp32s2/Kconfig.soc | 1 + soc/xtensa/intel_adsp/ace/Kconfig.series | 1 + soc/xtensa/intel_adsp/cavs/Kconfig.series | 1 + subsys/pm/Kconfig | 10 ++++++++-- 44 files changed, 51 insertions(+), 3 deletions(-) diff --git a/soc/arm/microchip_mec/mec1501/Kconfig.series b/soc/arm/microchip_mec/mec1501/Kconfig.series index 83683877bf6a..d3b679bb557d 100644 --- a/soc/arm/microchip_mec/mec1501/Kconfig.series +++ b/soc/arm/microchip_mec/mec1501/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_MEC1501X select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select SOC_FAMILY_MEC + select HAS_PM help Enable support for Microchip MEC Cortex-M4 MCU series diff --git a/soc/arm/microchip_mec/mec172x/Kconfig.series b/soc/arm/microchip_mec/mec172x/Kconfig.series index 77f7d4023c10..cb62a2bbfa91 100644 --- a/soc/arm/microchip_mec/mec172x/Kconfig.series +++ b/soc/arm/microchip_mec/mec172x/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_MEC172X select CPU_HAS_ARM_MPU select SOC_FAMILY_MEC select HAS_SWO + select HAS_PM help Enable support for Microchip MEC Cortex-M4F MCU series diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index bf4264c734bc..18ffeafe020d 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -29,7 +29,7 @@ config ARCH_HAS_CUSTOM_BUSY_WAIT default y if !QEMU_TARGET config PM - default y if SYS_CLOCK_EXISTS && MULTITHREADING + default y if SYS_CLOCK_EXISTS && MULTITHREADING && HAS_PM config BUILD_OUTPUT_HEX default y diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.series index 33f62dc43273..632ec5792fca 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_NRF51X select XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM help Enable support for NRF51 MCU series diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.series index 6ff33c5da4c2..fc02e76a41b3 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_NRF52X select HAS_NORDIC_DRIVERS select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select HAS_SWO + select HAS_PM help Enable support for NRF52 MCU series diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index 521964b5ac62..b72528e3aa31 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -9,6 +9,7 @@ config SOC_NRF5340_CPUAPP select CPU_HAS_NRF_IDAU select CPU_HAS_FPU select ARMV8_M_DSP + select HAS_PM config SOC_NRF5340_CPUNET bool diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.series index 54884ec13d2f..971855ef932e 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.series @@ -16,5 +16,6 @@ config SOC_SERIES_NRF91X select XIP select HAS_NRFX select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM help Enable support for NRF91 MCU series diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.series index 3fb6921fc094..8f8898388cf2 100644 --- a/soc/arm/nuvoton_npcx/npcx7/Kconfig.series +++ b/soc/arm/nuvoton_npcx/npcx7/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_NPCX7 select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + select HAS_PM help Enable support for Nuvoton NPCX7 series diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.series b/soc/arm/nuvoton_npcx/npcx9/Kconfig.series index 61f258171fbb..82423b370598 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.series +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_NPCX9 select CPU_HAS_FPU select CPU_HAS_ARM_MPU select SOC_FAMILY_NPCX + select HAS_PM help Enable support for Nuvoton NPCX9 series diff --git a/soc/arm/nxp_imx/rt/Kconfig.series b/soc/arm/nxp_imx/rt/Kconfig.series index d1adff602513..0a94b3963b1d 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_IMX_RT select ARM select SOC_FAMILY_IMX select CLOCK_CONTROL + select HAS_PM help Enable support for i.MX RT MCU series diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.series b/soc/arm/nxp_imx/rt5xx/Kconfig.series index 057e03115be8..0acc80909516 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.series +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.series @@ -10,5 +10,6 @@ config SOC_SERIES_IMX_RT5XX select CPU_CORTEX_M_HAS_DWT select SOC_FAMILY_IMX select CLOCK_CONTROL + select HAS_PM help Enable support for i.MX RT5XX Series MCU series diff --git a/soc/arm/nxp_imx/rt6xx/Kconfig.series b/soc/arm/nxp_imx/rt6xx/Kconfig.series index b028afbfa343..bcbf86ff6bfb 100644 --- a/soc/arm/nxp_imx/rt6xx/Kconfig.series +++ b/soc/arm/nxp_imx/rt6xx/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_IMX_RT6XX select CLOCK_CONTROL select CODE_DATA_RELOCATION_SRAM if FLASH_MCUX_FLEXSPI_XIP select PLATFORM_SPECIFIC_INIT + select HAS_PM help Enable support for i.MX RT6XX Series MCU series diff --git a/soc/arm/nxp_kinetis/ke1xf/Kconfig.series b/soc/arm/nxp_kinetis/ke1xf/Kconfig.series index 259e95e8a6d4..640bc4ec8fdf 100644 --- a/soc/arm/nxp_kinetis/ke1xf/Kconfig.series +++ b/soc/arm/nxp_kinetis/ke1xf/Kconfig.series @@ -32,5 +32,6 @@ config SOC_SERIES_KINETIS_KE1XF select HAS_MCUX_PWT select HAS_MCUX_RCM select PLATFORM_SPECIFIC_INIT + select HAS_PM help Enable support for Kinetis KE1xF MCU series diff --git a/soc/arm/silabs_exx32/efm32hg/Kconfig.series b/soc/arm/silabs_exx32/efm32hg/Kconfig.series index 13c74edb2e6c..4acdfa793ccd 100644 --- a/soc/arm/silabs_exx32/efm32hg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32hg/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_EFM32HG select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 Happy Gecko MCU series diff --git a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series index f454316dad44..2d9675430bef 100644 --- a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_EFM32JG12B select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select HAS_PM help Enable support for EFM32 JadeGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series index 3f3a3ca39f64..6df3aa9b6997 100644 --- a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series @@ -20,5 +20,6 @@ config SOC_SERIES_EFM32PG12B select SOC_GECKO_GPIO select SOC_GECKO_TRNG select SOC_GECKO_ADC + select HAS_PM help Enable support for EFM32 PearlGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series index 9bbf4def7629..caeae082a3bf 100644 --- a/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg1b/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFM32PG1B select SOC_GECKO_CMU select SOC_GECKO_EMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 PearlGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32wg/Kconfig.series b/soc/arm/silabs_exx32/efm32wg/Kconfig.series index 5d6e4f21e444..f339c755e050 100644 --- a/soc/arm/silabs_exx32/efm32wg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32wg/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_EFM32WG select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFM32 WonderGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series b/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series index 3fea9b454df3..e7f524a026f7 100644 --- a/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg13p/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_EFR32BG13P select SOC_GECKO_CMU select SOC_GECKO_EMU select SOC_GECKO_GPIO + select HAS_PM help Enable support for EFR32BG13P Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg22/Kconfig.series b/soc/arm/silabs_exx32/efr32bg22/Kconfig.series index 776175de925e..266d63917257 100644 --- a/soc/arm/silabs_exx32/efr32bg22/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg22/Kconfig.series @@ -20,5 +20,6 @@ config SOC_SERIES_EFR32BG22 select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32BG22 Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32bg27/Kconfig.series b/soc/arm/silabs_exx32/efr32bg27/Kconfig.series index 6118e1886294..572e6107f4e2 100644 --- a/soc/arm/silabs_exx32/efr32bg27/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32bg27/Kconfig.series @@ -20,5 +20,6 @@ config SOC_SERIES_EFR32BG27 select SOC_GECKO_CORE select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32BG27 Blue Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series index 1913377b3e70..6f5573775795 100644 --- a/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32fg13p/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFR32FG13P select SOC_GECKO_CMU select SOC_GECKO_GPIO select SOC_GECKO_HAS_ERRATA_RTCC_E201 + select HAS_PM help Enable support for EFR32 FlexGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series b/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series index b2d1ff287447..f8e509faa6db 100644 --- a/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32fg1p/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_EFR32FG1P select SOC_GECKO_CMU select SOC_GECKO_GPIO select SOC_GECKO_HAS_ERRATA_RTCC_E201 + select HAS_PM help Enable support for EFR32 FlexGecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series index 510889568f03..7c636daec862 100644 --- a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFR32MG12P select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_TRNG + select HAS_PM help Enable support for EFR32 Mighty Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series index ab64bea46d1f..c22cb8376ee2 100644 --- a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_EFR32MG21 select SOC_GECKO_EMU select SOC_GECKO_GPIO select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32MG21 Mighty Gecko MCU series diff --git a/soc/arm/silabs_exx32/efr32mg24/Kconfig.series b/soc/arm/silabs_exx32/efr32mg24/Kconfig.series index 7c6d49d2eaed..064db296cd8e 100644 --- a/soc/arm/silabs_exx32/efr32mg24/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg24/Kconfig.series @@ -22,5 +22,6 @@ config SOC_SERIES_EFR32MG24 select SOC_GECKO_GPIO select SOC_GECKO_DEV_INIT select SOC_GECKO_SE + select HAS_PM help Enable support for EFR32MG24 Mighty Gecko MCU series diff --git a/soc/arm/st_stm32/stm32g0/Kconfig.series b/soc/arm/st_stm32/stm32g0/Kconfig.series index 43353332745f..acdb926ef61d 100644 --- a/soc/arm/st_stm32/stm32g0/Kconfig.series +++ b/soc/arm/st_stm32/stm32g0/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32G0X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_CORTEX_M_HAS_SYSTICK + select HAS_PM help Enable support for STM32G0 MCU series diff --git a/soc/arm/st_stm32/stm32g4/Kconfig.series b/soc/arm/st_stm32/stm32g4/Kconfig.series index 93fda8ba9a05..6d81e3f1fc14 100644 --- a/soc/arm/st_stm32/stm32g4/Kconfig.series +++ b/soc/arm/st_stm32/stm32g4/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32G4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL + select HAS_PM help Enable support for STM32G4 MCU series diff --git a/soc/arm/st_stm32/stm32l0/Kconfig.series b/soc/arm/st_stm32/stm32l0/Kconfig.series index c465a922848a..950c72d4aa78 100644 --- a/soc/arm/st_stm32/stm32l0/Kconfig.series +++ b/soc/arm/st_stm32/stm32l0/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_STM32L0X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_CORTEX_M_HAS_SYSTICK + select HAS_PM help Enable support for STM32L0 MCU series diff --git a/soc/arm/st_stm32/stm32l4/Kconfig.series b/soc/arm/st_stm32/stm32l4/Kconfig.series index 084082188b2f..33758aadefd7 100644 --- a/soc/arm/st_stm32/stm32l4/Kconfig.series +++ b/soc/arm/st_stm32/stm32l4/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_STM32L4X select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32L4 MCU series diff --git a/soc/arm/st_stm32/stm32l5/Kconfig.series b/soc/arm/st_stm32/stm32l5/Kconfig.series index f9447205a539..ffee96473c32 100644 --- a/soc/arm/st_stm32/stm32l5/Kconfig.series +++ b/soc/arm/st_stm32/stm32l5/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_STM32L5X select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM help Enable support for STM32L5 MCU series diff --git a/soc/arm/st_stm32/stm32u5/Kconfig.series b/soc/arm/st_stm32/stm32u5/Kconfig.series index 69082b70e1cf..99835997a6a2 100644 --- a/soc/arm/st_stm32/stm32u5/Kconfig.series +++ b/soc/arm/st_stm32/stm32u5/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_STM32U5X select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM help Enable support for STM32U5 MCU series diff --git a/soc/arm/st_stm32/stm32wb/Kconfig.series b/soc/arm/st_stm32/stm32wb/Kconfig.series index 8ba570edfe6e..03c9bf957235 100644 --- a/soc/arm/st_stm32/stm32wb/Kconfig.series +++ b/soc/arm/st_stm32/stm32wb/Kconfig.series @@ -13,5 +13,6 @@ config SOC_SERIES_STM32WBX select HAS_STM32CUBE select CPU_HAS_ARM_MPU select HAS_SWO + select HAS_PM help Enable support for STM32WB MCU series diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.series index 7bb4cc44f184..28edaf07790e 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_STM32WBAX select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select HAS_PM help Enable support for STM32WBA MCU series diff --git a/soc/arm/st_stm32/stm32wl/Kconfig.series b/soc/arm/st_stm32/stm32wl/Kconfig.series index 3b2645dd6cdd..58dcae421bad 100644 --- a/soc/arm/st_stm32/stm32wl/Kconfig.series +++ b/soc/arm/st_stm32/stm32wl/Kconfig.series @@ -12,5 +12,6 @@ config SOC_SERIES_STM32WLX select HAS_STM32CUBE select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL + select HAS_PM help Enable support for STM32WL MCU series diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series index 831ea9734b42..9332a4c06720 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_CC13X2_CC26X2 select HAS_CC13X2_CC26X2_SDK select HAS_TI_CCFG select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM help Enable support for TI SimpleLink CC13x2 / CC26x2 SoCs diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series index aadeed980c4d..773b3b85253b 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/Kconfig.series @@ -15,5 +15,6 @@ config SOC_SERIES_CC13X2X7_CC26X2X7 select HAS_CC13X2X7_CC26X2X7_SDK select HAS_TI_CCFG if !BOOTLOADER_MCUBOOT select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM help Enable support for TI SimpleLink CC13x2x7 / CC26x2x7 SoCs diff --git a/soc/riscv/esp32c3/Kconfig.soc b/soc/riscv/esp32c3/Kconfig.soc index 63321375841f..56d2a64a63ce 100644 --- a/soc/riscv/esp32c3/Kconfig.soc +++ b/soc/riscv/esp32c3/Kconfig.soc @@ -14,6 +14,7 @@ config SOC_ESP32C3 select RISCV_ISA_EXT_M select RISCV_ISA_EXT_C select RISCV_ISA_EXT_ZICSR + select HAS_PM if SOC_ESP32C3 diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series b/soc/riscv/riscv-ite/it8xxx2/Kconfig.series index a30d1e554385..ebed0fcd120e 100644 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series +++ b/soc/riscv/riscv-ite/it8xxx2/Kconfig.series @@ -8,5 +8,6 @@ config SOC_SERIES_RISCV32_IT8XXX2 # 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 HAS_PM help Enable support for ITE IT8XXX2 diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/esp32/Kconfig.soc index e6f5a3de42eb..9e4e0e6892f5 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/esp32/Kconfig.soc @@ -12,6 +12,7 @@ config SOC_ESP32 select XIP if !MCUBOOT select HAS_ESPRESSIF_HAL select CPU_HAS_FPU + select HAS_PM if SOC_ESP32 diff --git a/soc/xtensa/esp32s2/Kconfig.soc b/soc/xtensa/esp32s2/Kconfig.soc index 4792cda7a4da..eef1a489ea2f 100644 --- a/soc/xtensa/esp32s2/Kconfig.soc +++ b/soc/xtensa/esp32s2/Kconfig.soc @@ -11,6 +11,7 @@ config SOC_ESP32S2 select XIP if !MCUBOOT select HAS_ESPRESSIF_HAL select ARCH_SUPPORTS_COREDUMP + select HAS_PM if SOC_ESP32S2 diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.series index 8b4f8e61436f..963c33bdf615 100644 --- a/soc/xtensa/intel_adsp/ace/Kconfig.series +++ b/soc/xtensa/intel_adsp/ace/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_INTEL_ACE select SCHED_IPI_SUPPORTED select DW_ICTL_ACE select SOC_HAS_RUNTIME_NUM_CPUS + select HAS_PM help Intel ADSP ACE diff --git a/soc/xtensa/intel_adsp/cavs/Kconfig.series b/soc/xtensa/intel_adsp/cavs/Kconfig.series index 1f398025eb4b..adbc1f39e1d4 100644 --- a/soc/xtensa/intel_adsp/cavs/Kconfig.series +++ b/soc/xtensa/intel_adsp/cavs/Kconfig.series @@ -10,5 +10,6 @@ config SOC_SERIES_INTEL_ADSP_CAVS select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" select ARCH_HAS_COHERENCE + select HAS_PM help Intel ADSP CAVS diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 3a66d736c411..36535e383a10 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -4,9 +4,15 @@ menu "Power Management" -menuconfig PM +config HAS_PM + bool + help + This option must be selected by SoCs that provide PM hooks, that is, + calls to configure low-power states. + +config PM bool "System Power Management" - depends on SYS_CLOCK_EXISTS + depends on SYS_CLOCK_EXISTS && HAS_PM help This option enables the board to implement extra power management policies whenever the kernel becomes idle. The kernel informs the From bddf2d9dc0721d15e828b7acd7de6dd25a3a736a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 18 Jul 2023 11:21:35 +0200 Subject: [PATCH 1509/2042] tests: pm: select HAS_PM Some tests provide their own PM hooks, adapted for testing purposes. Add a new option to select HAS_PM, so that CONFIG_PM can be enabled. Signed-off-by: Gerard Marull-Paretas --- samples/subsys/pm/latency/Kconfig | 6 ++++++ tests/subsys/pm/device_wakeup_api/Kconfig | 11 +++++++++++ tests/subsys/pm/policy_api/Kconfig | 11 +++++++++++ tests/subsys/pm/policy_api/src/main.c | 14 ++++++++++++++ tests/subsys/pm/power_mgmt/Kconfig | 11 +++++++++++ tests/subsys/pm/power_mgmt_multicore/Kconfig | 11 +++++++++++ 6 files changed, 64 insertions(+) create mode 100644 tests/subsys/pm/device_wakeup_api/Kconfig create mode 100644 tests/subsys/pm/policy_api/Kconfig create mode 100644 tests/subsys/pm/power_mgmt/Kconfig create mode 100644 tests/subsys/pm/power_mgmt_multicore/Kconfig diff --git a/samples/subsys/pm/latency/Kconfig b/samples/subsys/pm/latency/Kconfig index 0e08794c13a8..e3578670ddfb 100644 --- a/samples/subsys/pm/latency/Kconfig +++ b/samples/subsys/pm/latency/Kconfig @@ -8,3 +8,9 @@ endmenu module = APP module-str = Application source "subsys/logging/Kconfig.template.log_config" + + +config APP_PROVIDE_PM_HOOKS + bool "Application provides PM hooks" + default y + select HAS_PM diff --git a/tests/subsys/pm/device_wakeup_api/Kconfig b/tests/subsys/pm/device_wakeup_api/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/device_wakeup_api/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/policy_api/Kconfig b/tests/subsys/pm/policy_api/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/policy_api/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/policy_api/src/main.c b/tests/subsys/pm/policy_api/src/main.c index c29c7eb86d0c..8ea72d7e3f03 100644 --- a/tests/subsys/pm/policy_api/src/main.c +++ b/tests/subsys/pm/policy_api/src/main.c @@ -9,6 +9,20 @@ #include #include +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + ARG_UNUSED(state); +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + irq_unlock(0); +} + #ifdef CONFIG_PM_POLICY_DEFAULT /** * @brief Test the behavior of pm_policy_next_state() when diff --git a/tests/subsys/pm/power_mgmt/Kconfig b/tests/subsys/pm/power_mgmt/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/power_mgmt/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM diff --git a/tests/subsys/pm/power_mgmt_multicore/Kconfig b/tests/subsys/pm/power_mgmt_multicore/Kconfig new file mode 100644 index 000000000000..6a021dcd9449 --- /dev/null +++ b/tests/subsys/pm/power_mgmt_multicore/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "Zephyr" +source "Kconfig.zephyr" +endmenu + +config TEST_PROVIDE_PM_HOOKS + bool "Provide PM hooks for test purposes" + default y + select HAS_PM From b3fa2eec45178e26bcf7bce4ad13463af8dadcea Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 17 Jul 2023 16:49:31 +0200 Subject: [PATCH 1510/2042] pm: remove dummy pm_state_set/pm_state_exit_post_ops Dummy inline functions are useful to avoid ifdeffery in code when a certain option is not available. pm_state_set/pm_state_exit_post_ops, are only called from the PM subsystem, so never called if CONFIG_PM=n, that is, never surrounded with ifdeffery. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/pm/pm.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/include/zephyr/pm/pm.h b/include/zephyr/pm/pm.h index 9d6b69ad21a3..03062eefd12e 100644 --- a/include/zephyr/pm/pm.h +++ b/include/zephyr/pm/pm.h @@ -167,19 +167,6 @@ static inline int pm_notifier_unregister(struct pm_notifier *notifier) return -ENOSYS; } -static inline void pm_state_set(enum pm_state state, uint8_t substate_id) -{ - ARG_UNUSED(state); - ARG_UNUSED(substate_id); -} - -static inline void pm_state_exit_post_ops(enum pm_state state, - uint8_t substate_id) -{ - ARG_UNUSED(state); - ARG_UNUSED(substate_id); -} - static inline const struct pm_state_info *pm_state_next_get(uint8_t cpu) { ARG_UNUSED(cpu); From e1eedd1a9f714e7c40d8f4591fd4c2360a355d64 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 17 Jul 2023 16:59:26 +0200 Subject: [PATCH 1511/2042] pm: require pm_state_set/pm_exit_post_ops Any system supporting PM must now implement pm_state_set/pm_exit_post_ops. Before this change any platform could enable CONFIG_PM=y, even though it did nothing, ie, no power savings at all. Signed-off-by: Gerard Marull-Paretas --- subsys/pm/pm.c | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/subsys/pm/pm.c b/subsys/pm/pm.c index c9eb15e0d351..ae6e8505d891 100644 --- a/subsys/pm/pm.c +++ b/subsys/pm/pm.c @@ -107,35 +107,6 @@ static void pm_resume_devices(void) #endif /* !CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE */ #endif /* CONFIG_PM_DEVICE */ -static inline void pm_exit_pos_ops(struct pm_state_info *info) -{ - extern __weak void - pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id); - - if (pm_state_exit_post_ops != NULL) { - pm_state_exit_post_ops(info->state, info->substate_id); - } else { - /* - * This function is supposed to be overridden to do SoC or - * architecture specific post ops after sleep state exits. - * - * The kernel expects that irqs are unlocked after this. - */ - - irq_unlock(0); - } -} - -static inline void state_set(struct pm_state_info *info) -{ - extern __weak void - pm_state_set(enum pm_state state, uint8_t substate_id); - - if (pm_state_set != NULL) { - pm_state_set(info->state, info->substate_id); - } -} - /* * Function called to notify when the system is entering / exiting a * power state @@ -178,7 +149,7 @@ void pm_system_resume(void) * and it may schedule another thread. */ if (atomic_test_and_clear_bit(z_post_ops_required, id)) { - pm_exit_pos_ops(&z_cpus_pm_state[id]); + pm_state_exit_post_ops(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); pm_state_notify(false); z_cpus_pm_state[id] = (struct pm_state_info){PM_STATE_ACTIVE, 0, 0}; @@ -266,7 +237,7 @@ bool pm_system_suspend(int32_t ticks) /* Enter power state */ pm_state_notify(true); atomic_set_bit(z_post_ops_required, id); - state_set(&z_cpus_pm_state[id]); + pm_state_set(z_cpus_pm_state[id].state, z_cpus_pm_state[id].substate_id); pm_stats_stop(); /* Wake up sequence starts here */ From 55f5a75c58e8e693ca95bd6d6f14510061bb5055 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Mon, 17 Jul 2023 17:03:00 +0200 Subject: [PATCH 1512/2042] pm: remove unnecessary __weak from pm_state_set/pm_exit_post_ops Remove unnecessary __weak attribute from power management functions. These functions are now defined once, globally, and mandatory for systems that support CONFIG_PM. Signed-off-by: Gerard Marull-Paretas --- soc/arm/microchip_mec/mec1501/power.c | 4 ++-- soc/arm/microchip_mec/mec172x/power.c | 4 ++-- soc/arm/nordic_nrf/nrf51/power.c | 4 ++-- soc/arm/nordic_nrf/nrf52/power.c | 4 ++-- soc/arm/nordic_nrf/nrf53/power.c | 4 ++-- soc/arm/nordic_nrf/nrf91/power.c | 4 ++-- soc/arm/nuvoton_npcx/common/power.c | 4 ++-- soc/arm/nxp_imx/rt/power_rt10xx.c | 4 ++-- soc/arm/nxp_imx/rt/power_rt11xx.c | 4 ++-- soc/arm/nxp_imx/rt5xx/power.c | 4 ++-- soc/arm/nxp_imx/rt6xx/power.c | 4 ++-- soc/arm/nxp_kinetis/ke1xf/power.c | 4 ++-- soc/arm/silabs_exx32/common/soc_power.c | 4 ++-- soc/arm/silabs_exx32/common/soc_power_pmgr.c | 2 +- soc/arm/st_stm32/stm32g0/power.c | 4 ++-- soc/arm/st_stm32/stm32g4/power.c | 4 ++-- soc/arm/st_stm32/stm32l0/power.c | 4 ++-- soc/arm/st_stm32/stm32l4/power.c | 4 ++-- soc/arm/st_stm32/stm32l5/power.c | 4 ++-- soc/arm/st_stm32/stm32u5/power.c | 4 ++-- soc/arm/st_stm32/stm32wb/power.c | 4 ++-- soc/arm/st_stm32/stm32wba/power.c | 4 ++-- soc/arm/st_stm32/stm32wl/power.c | 4 ++-- soc/arm/ti_simplelink/cc13x2_cc26x2/power.c | 4 ++-- soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c | 4 ++-- soc/riscv/esp32c3/power.c | 4 ++-- soc/riscv/riscv-ite/common/power.c | 4 ++-- soc/xtensa/esp32/power.c | 4 ++-- soc/xtensa/esp32s2/power.c | 4 ++-- soc/xtensa/intel_adsp/ace/power.c | 4 ++-- soc/xtensa/intel_adsp/cavs/power.c | 4 ++-- 31 files changed, 61 insertions(+), 61 deletions(-) diff --git a/soc/arm/microchip_mec/mec1501/power.c b/soc/arm/microchip_mec/mec1501/power.c index 53cc7bc9717d..de6e2fd6fbfb 100644 --- a/soc/arm/microchip_mec/mec1501/power.c +++ b/soc/arm/microchip_mec/mec1501/power.c @@ -102,7 +102,7 @@ static void z_power_soc_sleep(void) * For deep sleep pm_system_suspend has executed all the driver * power management call backs. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -126,7 +126,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) * an ISR on wake except for faults. We re-enable interrupts by setting PRIMASK * to 0. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/microchip_mec/mec172x/power.c b/soc/arm/microchip_mec/mec172x/power.c index ec0034589ef3..0f31cca31288 100644 --- a/soc/arm/microchip_mec/mec172x/power.c +++ b/soc/arm/microchip_mec/mec172x/power.c @@ -144,7 +144,7 @@ static void z_power_soc_sleep(void) * For deep sleep pm_system_suspend has executed all the driver * power management call backs. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -168,7 +168,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) * ISR on wake except for faults. We re-enable interrupts by undoing global disable * and alling irq_unlock with the same value, 0 zephyr core uses. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { __enable_irq(); irq_unlock(0); diff --git a/soc/arm/nordic_nrf/nrf51/power.c b/soc/arm/nordic_nrf/nrf51/power.c index 8291d10700d2..1f86bca17b8c 100644 --- a/soc/arm/nordic_nrf/nrf51/power.c +++ b/soc/arm/nordic_nrf/nrf51/power.c @@ -11,7 +11,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -26,7 +26,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nordic_nrf/nrf52/power.c b/soc/arm/nordic_nrf/nrf52/power.c index 8291d10700d2..1f86bca17b8c 100644 --- a/soc/arm/nordic_nrf/nrf52/power.c +++ b/soc/arm/nordic_nrf/nrf52/power.c @@ -11,7 +11,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -26,7 +26,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nordic_nrf/nrf53/power.c b/soc/arm/nordic_nrf/nrf53/power.c index ccd658be6ebc..5e4f6080dd41 100644 --- a/soc/arm/nordic_nrf/nrf53/power.c +++ b/soc/arm/nordic_nrf/nrf53/power.c @@ -13,7 +13,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -28,7 +28,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nordic_nrf/nrf91/power.c b/soc/arm/nordic_nrf/nrf91/power.c index 20834906069d..44bcefbf1593 100644 --- a/soc/arm/nordic_nrf/nrf91/power.c +++ b/soc/arm/nordic_nrf/nrf91/power.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -27,7 +27,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nuvoton_npcx/common/power.c b/soc/arm/nuvoton_npcx/common/power.c index 379784231d2c..e7fe036f7669 100644 --- a/soc/arm/nuvoton_npcx/common/power.c +++ b/soc/arm/nuvoton_npcx/common/power.c @@ -199,7 +199,7 @@ static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode) } /* Invoke when enter "Suspend/Low Power" mode. */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -228,7 +228,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle soc specific activity after exiting "Suspend/Low Power" mode. */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); diff --git a/soc/arm/nxp_imx/rt/power_rt10xx.c b/soc/arm/nxp_imx/rt/power_rt10xx.c index dea33f3ce8f6..ca10fdecf4dc 100644 --- a/soc/arm/nxp_imx/rt/power_rt10xx.c +++ b/soc/arm/nxp_imx/rt/power_rt10xx.c @@ -183,7 +183,7 @@ static void lpm_raise_voltage(void) /* Sets device into low power mode */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -213,7 +213,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt/power_rt11xx.c b/soc/arm/nxp_imx/rt/power_rt11xx.c index 559e61ce5bcc..871a7d809a3c 100644 --- a/soc/arm/nxp_imx/rt/power_rt11xx.c +++ b/soc/arm/nxp_imx/rt/power_rt11xx.c @@ -283,7 +283,7 @@ void cpu_mode_transition(gpc_cpu_mode_t mode, bool enable_standby) * SOC specific low power mode implementation * Drop to lowest power state possible given system's request */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); @@ -306,7 +306,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } } -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt5xx/power.c b/soc/arm/nxp_imx/rt5xx/power.c index 9c95fc3a424f..b4137827c605 100644 --- a/soc/arm/nxp_imx/rt5xx/power.c +++ b/soc/arm/nxp_imx/rt5xx/power.c @@ -45,7 +45,7 @@ __ramfunc void restore_deepsleep_pin_config(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -82,7 +82,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_imx/rt6xx/power.c b/soc/arm/nxp_imx/rt6xx/power.c index 6709f7b2c9dc..04494737af60 100644 --- a/soc/arm/nxp_imx/rt6xx/power.c +++ b/soc/arm/nxp_imx/rt6xx/power.c @@ -22,7 +22,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); APP_DEEPSLEEP_RAM_APD, APP_DEEPSLEEP_RAM_PPD})) /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -52,7 +52,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/nxp_kinetis/ke1xf/power.c b/soc/arm/nxp_kinetis/ke1xf/power.c index 8d2cdfbe4383..6340df6ff5b9 100644 --- a/soc/arm/nxp_kinetis/ke1xf/power.c +++ b/soc/arm/nxp_kinetis/ke1xf/power.c @@ -25,7 +25,7 @@ __ramfunc static void wait_for_flash_prefetch_and_idle(void) } #endif /* CONFIG_XIP */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_RUNTIME_IDLE: @@ -51,7 +51,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } } -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/silabs_exx32/common/soc_power.c b/soc/arm/silabs_exx32/common/soc_power.c index e1702a100833..cdb279c848fe 100644 --- a/soc/arm/silabs_exx32/common/soc_power.c +++ b/soc/arm/silabs_exx32/common/soc_power.c @@ -20,7 +20,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -63,7 +63,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/silabs_exx32/common/soc_power_pmgr.c b/soc/arm/silabs_exx32/common/soc_power_pmgr.c index aa303874ddec..0286e99e77f5 100644 --- a/soc/arm/silabs_exx32/common/soc_power_pmgr.c +++ b/soc/arm/silabs_exx32/common/soc_power_pmgr.c @@ -21,7 +21,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); sl_power_manager_em_t energy_mode = SL_POWER_MANAGER_EM0; diff --git a/soc/arm/st_stm32/stm32g0/power.c b/soc/arm/st_stm32/stm32g0/power.c index bc9ca8f2a312..d13ec265679e 100644 --- a/soc/arm/st_stm32/stm32g0/power.c +++ b/soc/arm/st_stm32/stm32g0/power.c @@ -20,7 +20,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -50,7 +50,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate %u", state); diff --git a/soc/arm/st_stm32/stm32g4/power.c b/soc/arm/st_stm32/stm32g4/power.c index 7d55a3c42094..dadb07114681 100644 --- a/soc/arm/st_stm32/stm32g4/power.c +++ b/soc/arm/st_stm32/stm32g4/power.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -49,7 +49,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate %u", state); diff --git a/soc/arm/st_stm32/stm32l0/power.c b/soc/arm/st_stm32/stm32l0/power.c index 585aaf69293f..a2a11f824aad 100644 --- a/soc/arm/st_stm32/stm32l0/power.c +++ b/soc/arm/st_stm32/stm32l0/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -54,7 +54,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/st_stm32/stm32l4/power.c b/soc/arm/st_stm32/stm32l4/power.c index b8445a7165cd..8b1a68fc767e 100644 --- a/soc/arm/st_stm32/stm32l4/power.c +++ b/soc/arm/st_stm32/stm32l4/power.c @@ -82,7 +82,7 @@ void set_mode_shutdown(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -106,7 +106,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: diff --git a/soc/arm/st_stm32/stm32l5/power.c b/soc/arm/st_stm32/stm32l5/power.c index e799b88c86ef..1d5316c69635 100644 --- a/soc/arm/st_stm32/stm32l5/power.c +++ b/soc/arm/st_stm32/stm32l5/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power state %u", state); @@ -66,7 +66,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_IDLE) { LOG_DBG("Unsupported power substate-id %u", state); diff --git a/soc/arm/st_stm32/stm32u5/power.c b/soc/arm/st_stm32/stm32u5/power.c index 32e8e7334e29..4cd5834cf8be 100644 --- a/soc/arm/st_stm32/stm32u5/power.c +++ b/soc/arm/st_stm32/stm32u5/power.c @@ -62,7 +62,7 @@ void set_mode_shutdown(uint8_t substate_id) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -88,7 +88,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: diff --git a/soc/arm/st_stm32/stm32wb/power.c b/soc/arm/st_stm32/stm32wb/power.c index fba9c06aad2d..cf368503c364 100644 --- a/soc/arm/st_stm32/stm32wb/power.c +++ b/soc/arm/st_stm32/stm32wb/power.c @@ -56,7 +56,7 @@ static void lpm_hsem_lock(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state == PM_STATE_SOFT_OFF) { lpm_hsem_lock(); @@ -108,7 +108,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { /* Implementation of STM32 AN5289 algorithm to enter/exit lowpower */ /* Release ENTRY_STOP_MODE semaphore */ diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 51bc737858a1..83073b7b293c 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -42,7 +42,7 @@ void set_mode_standby(uint8_t substate_id) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -65,7 +65,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: diff --git a/soc/arm/st_stm32/stm32wl/power.c b/soc/arm/st_stm32/stm32wl/power.c index e85f55ea39a3..5517ec1ff470 100644 --- a/soc/arm/st_stm32/stm32wl/power.c +++ b/soc/arm/st_stm32/stm32wl/power.c @@ -28,7 +28,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #endif /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { switch (state) { case PM_STATE_SUSPEND_TO_IDLE: @@ -74,7 +74,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c index a22ecee538f3..88a519336654 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/power.c @@ -58,7 +58,7 @@ extern PowerCC26X2_ModuleState PowerCC26X2_module; */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -122,7 +122,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c index 07057129e258..f0e1407ef45a 100644 --- a/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c +++ b/soc/arm/ti_simplelink/cc13x2x7_cc26x2x7/power.c @@ -58,7 +58,7 @@ extern PowerCC26X2_ModuleState PowerCC26X2_module; */ /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -122,7 +122,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/riscv/esp32c3/power.c b/soc/riscv/esp32c3/power.c index f7dd0e8ec508..aa63c6925f0a 100644 --- a/soc/riscv/esp32c3/power.c +++ b/soc/riscv/esp32c3/power.c @@ -12,7 +12,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -32,7 +32,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/riscv/riscv-ite/common/power.c b/soc/riscv/riscv-ite/common/power.c index 882101b94346..120c80c68524 100644 --- a/soc/riscv/riscv-ite/common/power.c +++ b/soc/riscv/riscv-ite/common/power.c @@ -16,7 +16,7 @@ static void ite_power_soc_deep_doze(void) } /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -31,7 +31,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(state); ARG_UNUSED(substate_id); diff --git a/soc/xtensa/esp32/power.c b/soc/xtensa/esp32/power.c index 440d232d4b3c..ddbf77c42fcc 100644 --- a/soc/xtensa/esp32/power.c +++ b/soc/xtensa/esp32/power.c @@ -16,7 +16,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); static uint32_t intenable; /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -43,7 +43,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/xtensa/esp32s2/power.c b/soc/xtensa/esp32s2/power.c index 907784d5cd4c..42e7121438ea 100644 --- a/soc/xtensa/esp32s2/power.c +++ b/soc/xtensa/esp32s2/power.c @@ -14,7 +14,7 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); static uint32_t intenable; /* Invoke Low Power/System Off specific Tasks */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); @@ -35,7 +35,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 518e0808d3c3..cb9159882981 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -223,7 +223,7 @@ __imr void pm_state_imr_restore(void) } #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); @@ -308,7 +308,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index e05df97c6e72..34ddb726afdb 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -76,7 +76,7 @@ static inline void __sparse_cache *uncache_to_cache(void *address) return (void __sparse_cache *)((uintptr_t)(address) | SRAM_ALIAS_OFFSET); } -__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); @@ -112,7 +112,7 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id) } /* Handle SOC specific activity after Low Power Mode Exit */ -__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); From f60306193844208f4f9ac373f8cae1fd3a207d12 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 09:40:09 +0200 Subject: [PATCH 1513/2042] soc: xtensa: intel_adsp: cavs: fix PM hooks guards The PM hooks were guarded with CONFIG_PM_POLICY_CUSTOM, however, they need to be guarded (if file is always compiled) with CONFIG_PM. In fact, CONFIG_PM_POLICY_CUSTOM requires to implement a custom policy hook, something this module did not provide. Signed-off-by: Gerard Marull-Paretas --- soc/xtensa/intel_adsp/cavs/power.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index 34ddb726afdb..42598e9b56fd 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(soc); # define SHIM_GPDMA_CLKCTL(x) (SHIM_GPDMA_BASE(x) + 0x4) # define SHIM_CLKCTL_LPGPDMAFDCGB BIT(0) -#ifdef CONFIG_PM_POLICY_CUSTOM +#ifdef CONFIG_PM #define SRAM_ALIAS_BASE 0x9E000000 #define SRAM_ALIAS_MASK 0xFF000000 #define SRAM_ALIAS_OFFSET 0x20000000 @@ -125,7 +125,7 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) __ASSERT(false, "invalid argument - unsupported power state"); } } -#endif /* CONFIG_PM_POLICY_CUSTOM */ +#endif /* CONFIG_PM */ __imr void power_init(void) { From ecfbabd2133f71f36ec5c48af080e2c651a7db8e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 21 Jun 2023 12:12:38 +0100 Subject: [PATCH 1514/2042] mgmt: mcumgr: Make SMP version 2 to legacy error lookup extensible Replaces the manual lookup function with a lookup function which is provided when registering MCUmgr handlers which can be used to find the function to translate error codes, allowing out of tree MCUmgr handlers to provide error translation handlers. Signed-off-by: Jamie McCrae --- .../zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h | 11 --- .../mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 11 --- .../zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h | 12 +-- .../mgmt/mcumgr/grp/shell_mgmt/shell_mgmt.h | 11 --- .../mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h | 11 --- .../mgmt/mcumgr/grp/zephyr/zephyr_basic.h | 11 --- include/zephyr/mgmt/mcumgr/mgmt/mgmt.h | 24 +++++- include/zephyr/mgmt/mcumgr/smp/smp.h | 14 +++- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 76 ++++++++++-------- .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 80 +++++++++++-------- subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 48 ++++++----- .../mcumgr/grp/shell_mgmt/src/shell_mgmt.c | 46 ++++++----- .../mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c | 48 ++++++----- .../mcumgr/grp/zephyr_basic/src/basic_mgmt.c | 48 ++++++----- subsys/mgmt/mcumgr/mgmt/src/mgmt.c | 26 +++++- subsys/mgmt/mcumgr/smp/src/smp.c | 66 ++++----------- 16 files changed, 279 insertions(+), 264 deletions(-) diff --git a/include/zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h index 23c4a33fb1d8..af7f612a7fa3 100644 --- a/include/zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h @@ -75,17 +75,6 @@ enum fs_mgmt_ret_code_t { FS_MGMT_RET_RC_CHECKSUM_HASH_NOT_FOUND, }; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate FS mgmt group error code into MCUmgr error code - * - * @param ret #fs_mgmt_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int fs_mgmt_translate_error_code(uint16_t ret); -#endif - #ifdef __cplusplus } #endif 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 36220c1d128f..ef5f840c261e 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -341,17 +341,6 @@ int img_mgmt_vercmp(const struct image_version *a, const struct image_version *b void img_mgmt_reset_upload(void); #endif -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate IMG mgmt group error code into MCUmgr error code - * - * @param ret #img_mgmt_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int img_mgmt_translate_error_code(uint16_t ret); -#endif - #ifdef CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR #define IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, rsn) ((action)->rc_rsn = (rsn)) #define IMG_MGMT_UPLOAD_ACTION_RC_RSN(action) ((action)->rc_rsn) diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h index 3fdfc01678cf..c995528872c2 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2021 mcumgr authors * Copyright (c) 2022 Laird Connectivity + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -97,17 +98,6 @@ struct os_mgmt_info_append { bool *prior_output; }; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate OS mgmt group error code into MCUmgr error code - * - * @param ret #os_mgmt_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int os_mgmt_translate_error_code(uint16_t ret); -#endif - #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/grp/shell_mgmt/shell_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/shell_mgmt/shell_mgmt.h index 25d9a25df422..c4f36dbd6db0 100644 --- a/include/zephyr/mgmt/mcumgr/grp/shell_mgmt/shell_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/shell_mgmt/shell_mgmt.h @@ -34,17 +34,6 @@ enum shell_mgmt_ret_code_t { SHELL_MGMT_RET_RC_EMPTY_COMMAND, }; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate shell mgmt group error code into MCUmgr error code - * - * @param ret #shell_mgmt_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int shell_mgmt_translate_error_code(uint16_t ret); -#endif - #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h index 36c7016c12ca..b9d424652951 100644 --- a/include/zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/stat_mgmt/stat_mgmt.h @@ -49,17 +49,6 @@ struct stat_mgmt_entry { uint64_t value; }; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate stat mgmt group error code into MCUmgr error code - * - * @param ret #stat_mgmt_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int stat_mgmt_translate_error_code(uint16_t ret); -#endif - #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h b/include/zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h index b69c57ed08c0..089243ac7e34 100644 --- a/include/zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h +++ b/include/zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h @@ -35,17 +35,6 @@ enum zephyr_basic_group_ret_code_t { ZEPHYR_MGMT_GRP_CMD_RC_FLASH_ERASE_FAILED, }; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -/* - * @brief Translate zephyr basic group error code into MCUmgr error code - * - * @param ret #zephyr_basic_group_ret_code_t error code - * - * @return #mcumgr_err_t error code - */ -int zephyr_basic_group_translate_error_code(uint16_t ret); -#endif - #ifdef __cplusplus } #endif diff --git a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h index f6d23a193b2d..af7c844169cf 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2021 mcumgr authors - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -195,8 +195,15 @@ struct mgmt_group { const struct mgmt_handler *mg_handlers; uint16_t mg_handlers_count; - /* The numeric ID of this group. */ + /** The numeric ID of this group. */ uint16_t mg_group_id; + +#if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) + /** A function handler for translating version 2 SMP error codes to version 1 SMP error + * codes (optional) + */ + smp_translate_error_fn mg_translate_error; +#endif }; /** @@ -224,6 +231,19 @@ void mgmt_unregister_group(struct mgmt_group *group); */ const struct mgmt_handler *mgmt_find_handler(uint16_t group_id, uint16_t command_id); +#if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) +/** + * @brief Finds a registered error translation function for converting from SMP + * version 2 error codes to legacy SMP version 1 error codes. + * + * @param group_id The group of the translation function to find. + * + * @return Requested lookup function on success. + * @return NULL on failure. + */ +smp_translate_error_fn mgmt_find_error_translation_function(uint16_t group_id); +#endif + /** * @} */ diff --git a/include/zephyr/mgmt/mcumgr/smp/smp.h b/include/zephyr/mgmt/mcumgr/smp/smp.h index cb5305b40c10..fd964ae2c45d 100644 --- a/include/zephyr/mgmt/mcumgr/smp/smp.h +++ b/include/zephyr/mgmt/mcumgr/smp/smp.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021 mcumgr authors + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,7 +56,7 @@ struct cbor_nb_writer { struct net_buf *nb; zcbor_state_t zs[2]; -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL +#if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) uint16_t error_group; uint16_t error_ret; #endif @@ -120,6 +121,17 @@ int smp_process_request_packet(struct smp_streamer *streamer, void *req); */ bool smp_add_cmd_ret(zcbor_state_t *zse, uint16_t group, uint16_t ret); +#if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) +/** @typedef smp_translate_error_fn + * @brief Translates a SMP version 2 error response to a legacy SMP version 1 error code. + * + * @param ret The SMP version 2 error ret/rc value. + * + * @return #enum mcumgr_err_t Legacy SMP version 1 error code to return to client. + */ +typedef int (*smp_translate_error_fn)(uint16_t ret); +#endif + #ifdef __cplusplus } #endif 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 0e5e934ed03f..4cbd6b893b3f 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -896,6 +896,46 @@ static int fs_mgmt_close_opened_file(struct smp_streamer *ctxt) return MGMT_ERR_EOK; } +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL +/* + * @brief Translate FS mgmt group error code into MCUmgr error code + * + * @param ret #fs_mgmt_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int fs_mgmt_translate_error_code(uint16_t ret) +{ + int rc; + + switch (ret) { + case FS_MGMT_RET_RC_FILE_INVALID_NAME: + case FS_MGMT_RET_RC_CHECKSUM_HASH_NOT_FOUND: + rc = MGMT_ERR_EINVAL; + break; + + case FS_MGMT_RET_RC_FILE_NOT_FOUND: + case FS_MGMT_RET_RC_FILE_IS_DIRECTORY: + rc = MGMT_ERR_ENOENT; + break; + + case FS_MGMT_RET_RC_UNKNOWN: + case FS_MGMT_RET_RC_FILE_OPEN_FAILED: + case FS_MGMT_RET_RC_FILE_SEEK_FAILED: + case FS_MGMT_RET_RC_FILE_READ_FAILED: + case FS_MGMT_RET_RC_FILE_TRUNCATE_FAILED: + case FS_MGMT_RET_RC_FILE_DELETE_FAILED: + case FS_MGMT_RET_RC_FILE_WRITE_FAILED: + case FS_MGMT_RET_RC_FILE_OFFSET_NOT_VALID: + case FS_MGMT_RET_RC_FILE_OFFSET_LARGER_THAN_FILE: + default: + rc = MGMT_ERR_EUNKNOWN; + } + + return rc; +} +#endif + static const struct mgmt_handler fs_mgmt_handlers[] = { [FS_MGMT_ID_FILE] = { .mh_read = fs_mgmt_file_download, @@ -931,6 +971,9 @@ static struct mgmt_group fs_mgmt_group = { .mg_handlers = fs_mgmt_handlers, .mg_handlers_count = FS_MGMT_HANDLER_CNT, .mg_group_id = MGMT_GROUP_ID_FS, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = fs_mgmt_translate_error_code, +#endif }; static void fs_mgmt_register_group(void) @@ -954,37 +997,4 @@ static void fs_mgmt_register_group(void) #endif } -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int fs_mgmt_translate_error_code(uint16_t ret) -{ - int rc; - - switch (ret) { - case FS_MGMT_RET_RC_FILE_INVALID_NAME: - case FS_MGMT_RET_RC_CHECKSUM_HASH_NOT_FOUND: - rc = MGMT_ERR_EINVAL; - break; - - case FS_MGMT_RET_RC_FILE_NOT_FOUND: - case FS_MGMT_RET_RC_FILE_IS_DIRECTORY: - rc = MGMT_ERR_ENOENT; - break; - - case FS_MGMT_RET_RC_UNKNOWN: - case FS_MGMT_RET_RC_FILE_OPEN_FAILED: - case FS_MGMT_RET_RC_FILE_SEEK_FAILED: - case FS_MGMT_RET_RC_FILE_READ_FAILED: - case FS_MGMT_RET_RC_FILE_TRUNCATE_FAILED: - case FS_MGMT_RET_RC_FILE_DELETE_FAILED: - case FS_MGMT_RET_RC_FILE_WRITE_FAILED: - case FS_MGMT_RET_RC_FILE_OFFSET_NOT_VALID: - case FS_MGMT_RET_RC_FILE_OFFSET_LARGER_THAN_FILE: - default: - rc = MGMT_ERR_EUNKNOWN; - } - - return rc; -} -#endif - MCUMGR_HANDLER_DEFINE(fs_mgmt, fs_mgmt_register_group); diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 502ed779f76b..85d62acfb6a8 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -752,42 +752,15 @@ int img_mgmt_my_version(struct image_version *ver) ver, NULL, NULL); } -static const struct mgmt_handler img_mgmt_handlers[] = { - [IMG_MGMT_ID_STATE] = { - .mh_read = img_mgmt_state_read, -#ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP - .mh_write = NULL -#else - .mh_write = img_mgmt_state_write, -#endif - }, - [IMG_MGMT_ID_UPLOAD] = { - .mh_read = NULL, - .mh_write = img_mgmt_upload - }, - [IMG_MGMT_ID_ERASE] = { - .mh_read = NULL, - .mh_write = img_mgmt_erase - }, -}; - -static const struct mgmt_handler img_mgmt_handlers[]; - -#define IMG_MGMT_HANDLER_CNT ARRAY_SIZE(img_mgmt_handlers) - -static struct mgmt_group img_mgmt_group = { - .mg_handlers = (struct mgmt_handler *)img_mgmt_handlers, - .mg_handlers_count = IMG_MGMT_HANDLER_CNT, - .mg_group_id = MGMT_GROUP_ID_IMAGE, -}; - -static void img_mgmt_register_group(void) -{ - mgmt_register_group(&img_mgmt_group); -} - #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int img_mgmt_translate_error_code(uint16_t ret) +/* + * @brief Translate IMG mgmt group error code into MCUmgr error code + * + * @param ret #img_mgmt_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int img_mgmt_translate_error_code(uint16_t ret) { int rc; @@ -841,4 +814,41 @@ int img_mgmt_translate_error_code(uint16_t ret) } #endif +static const struct mgmt_handler img_mgmt_handlers[] = { + [IMG_MGMT_ID_STATE] = { + .mh_read = img_mgmt_state_read, +#ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP + .mh_write = NULL +#else + .mh_write = img_mgmt_state_write, +#endif + }, + [IMG_MGMT_ID_UPLOAD] = { + .mh_read = NULL, + .mh_write = img_mgmt_upload + }, + [IMG_MGMT_ID_ERASE] = { + .mh_read = NULL, + .mh_write = img_mgmt_erase + }, +}; + +static const struct mgmt_handler img_mgmt_handlers[]; + +#define IMG_MGMT_HANDLER_CNT ARRAY_SIZE(img_mgmt_handlers) + +static struct mgmt_group img_mgmt_group = { + .mg_handlers = (struct mgmt_handler *)img_mgmt_handlers, + .mg_handlers_count = IMG_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_IMAGE, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = img_mgmt_translate_error_code, +#endif +}; + +static void img_mgmt_register_group(void) +{ + mgmt_register_group(&img_mgmt_group); +} + MCUMGR_HANDLER_DEFINE(img_mgmt, img_mgmt_register_group); 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 d98dc4e2b852..8b0c3dd02468 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -674,6 +674,32 @@ static int os_mgmt_info(struct smp_streamer *ctxt) } #endif +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL +/* + * @brief Translate OS mgmt group error code into MCUmgr error code + * + * @param ret #os_mgmt_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int os_mgmt_translate_error_code(uint16_t ret) +{ + int rc; + + switch (ret) { + case OS_MGMT_RET_RC_INVALID_FORMAT: + rc = MGMT_ERR_EINVAL; + break; + + case OS_MGMT_RET_RC_UNKNOWN: + default: + rc = MGMT_ERR_EUNKNOWN; + } + + return rc; +} +#endif + static const struct mgmt_handler os_mgmt_group_handlers[] = { #ifdef CONFIG_MCUMGR_GRP_OS_ECHO [OS_MGMT_ID_ECHO] = { @@ -708,6 +734,9 @@ static struct mgmt_group os_mgmt_group = { .mg_handlers = os_mgmt_group_handlers, .mg_handlers_count = OS_MGMT_GROUP_SZ, .mg_group_id = MGMT_GROUP_ID_OS, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = os_mgmt_translate_error_code, +#endif }; static void os_mgmt_register_group(void) @@ -715,23 +744,4 @@ static void os_mgmt_register_group(void) mgmt_register_group(&os_mgmt_group); } -#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int os_mgmt_translate_error_code(uint16_t ret) -{ - int rc; - - switch (ret) { - case OS_MGMT_RET_RC_INVALID_FORMAT: - rc = MGMT_ERR_EINVAL; - break; - - case OS_MGMT_RET_RC_UNKNOWN: - default: - rc = MGMT_ERR_EUNKNOWN; - } - - return rc; -} -#endif - MCUMGR_HANDLER_DEFINE(os_mgmt, os_mgmt_register_group); diff --git a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c index f6cb3f014ba6..d0f2a3949731 100644 --- a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c @@ -128,25 +128,15 @@ shell_mgmt_exec(struct smp_streamer *ctxt) return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; } -static struct mgmt_handler shell_mgmt_handlers[] = { - [SHELL_MGMT_ID_EXEC] = { NULL, shell_mgmt_exec }, -}; - -#define SHELL_MGMT_HANDLER_CNT ARRAY_SIZE(shell_mgmt_handlers) - -static struct mgmt_group shell_mgmt_group = { - .mg_handlers = shell_mgmt_handlers, - .mg_handlers_count = SHELL_MGMT_HANDLER_CNT, - .mg_group_id = MGMT_GROUP_ID_SHELL, -}; - -static void shell_mgmt_register_group(void) -{ - mgmt_register_group(&shell_mgmt_group); -} - #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int shell_mgmt_translate_error_code(uint16_t ret) +/* + * @brief Translate shell mgmt group error code into MCUmgr error code + * + * @param ret #shell_mgmt_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int shell_mgmt_translate_error_code(uint16_t ret) { int rc; @@ -164,4 +154,24 @@ int shell_mgmt_translate_error_code(uint16_t ret) } #endif +static struct mgmt_handler shell_mgmt_handlers[] = { + [SHELL_MGMT_ID_EXEC] = { NULL, shell_mgmt_exec }, +}; + +#define SHELL_MGMT_HANDLER_CNT ARRAY_SIZE(shell_mgmt_handlers) + +static struct mgmt_group shell_mgmt_group = { + .mg_handlers = shell_mgmt_handlers, + .mg_handlers_count = SHELL_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_SHELL, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = shell_mgmt_translate_error_code, +#endif +}; + +static void shell_mgmt_register_group(void) +{ + mgmt_register_group(&shell_mgmt_group); +} + MCUMGR_HANDLER_DEFINE(shell_mgmt, shell_mgmt_register_group); 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 78f6e8d14581..9f9b93011680 100644 --- a/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c @@ -239,26 +239,15 @@ stat_mgmt_list(struct smp_streamer *ctxt) return 0; } -static struct mgmt_handler stat_mgmt_handlers[] = { - [STAT_MGMT_ID_SHOW] = { stat_mgmt_show, NULL }, - [STAT_MGMT_ID_LIST] = { stat_mgmt_list, NULL }, -}; - -#define STAT_MGMT_HANDLER_CNT ARRAY_SIZE(stat_mgmt_handlers) - -static struct mgmt_group stat_mgmt_group = { - .mg_handlers = stat_mgmt_handlers, - .mg_handlers_count = STAT_MGMT_HANDLER_CNT, - .mg_group_id = MGMT_GROUP_ID_STAT, -}; - -static void stat_mgmt_register_group(void) -{ - mgmt_register_group(&stat_mgmt_group); -} - #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int stat_mgmt_translate_error_code(uint16_t ret) +/* + * @brief Translate stat mgmt group error code into MCUmgr error code + * + * @param ret #stat_mgmt_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int stat_mgmt_translate_error_code(uint16_t ret) { int rc; @@ -281,4 +270,25 @@ int stat_mgmt_translate_error_code(uint16_t ret) } #endif +static struct mgmt_handler stat_mgmt_handlers[] = { + [STAT_MGMT_ID_SHOW] = { stat_mgmt_show, NULL }, + [STAT_MGMT_ID_LIST] = { stat_mgmt_list, NULL }, +}; + +#define STAT_MGMT_HANDLER_CNT ARRAY_SIZE(stat_mgmt_handlers) + +static struct mgmt_group stat_mgmt_group = { + .mg_handlers = stat_mgmt_handlers, + .mg_handlers_count = STAT_MGMT_HANDLER_CNT, + .mg_group_id = MGMT_GROUP_ID_STAT, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = stat_mgmt_translate_error_code, +#endif +}; + +static void stat_mgmt_register_group(void) +{ + mgmt_register_group(&stat_mgmt_group); +} + MCUMGR_HANDLER_DEFINE(stat_mgmt, stat_mgmt_register_group); diff --git a/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c b/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c index 025b9c557eff..4ccf95b2e71f 100644 --- a/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c @@ -64,26 +64,15 @@ static int storage_erase_handler(struct smp_streamer *ctxt) return MGMT_ERR_EOK; } -static const struct mgmt_handler zephyr_mgmt_basic_handlers[] = { - [ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE] = { - .mh_read = NULL, - .mh_write = storage_erase_handler, - }, -}; - -static struct mgmt_group zephyr_basic_mgmt_group = { - .mg_handlers = (struct mgmt_handler *)zephyr_mgmt_basic_handlers, - .mg_handlers_count = ARRAY_SIZE(zephyr_mgmt_basic_handlers), - .mg_group_id = (ZEPHYR_MGMT_GRP_BASIC), -}; - -static void zephyr_basic_mgmt_init(void) -{ - mgmt_register_group(&zephyr_basic_mgmt_group); -} - #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL -int zephyr_basic_group_translate_error_code(uint16_t ret) +/* + * @brief Translate zephyr basic group error code into MCUmgr error code + * + * @param ret #zephyr_basic_group_ret_code_t error code + * + * @return #mcumgr_err_t error code + */ +static int zephyr_basic_group_translate_error_code(uint16_t ret) { int rc; @@ -105,4 +94,25 @@ int zephyr_basic_group_translate_error_code(uint16_t ret) } #endif +static const struct mgmt_handler zephyr_mgmt_basic_handlers[] = { + [ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE] = { + .mh_read = NULL, + .mh_write = storage_erase_handler, + }, +}; + +static struct mgmt_group zephyr_basic_mgmt_group = { + .mg_handlers = (struct mgmt_handler *)zephyr_mgmt_basic_handlers, + .mg_handlers_count = ARRAY_SIZE(zephyr_mgmt_basic_handlers), + .mg_group_id = (ZEPHYR_MGMT_GRP_BASIC), +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = zephyr_basic_group_translate_error_code, +#endif +}; + +static void zephyr_basic_mgmt_init(void) +{ + mgmt_register_group(&zephyr_basic_mgmt_group); +} + MCUMGR_HANDLER_DEFINE(zephyr_basic_mgmt, zephyr_basic_mgmt_init); diff --git a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c index e83d948dca9a..b2faf5ea81be 100644 --- a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c +++ b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2021 mcumgr authors - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -68,6 +68,30 @@ mgmt_find_handler(uint16_t group_id, uint16_t command_id) return &group->mg_handlers[command_id]; } +#if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) +smp_translate_error_fn mgmt_find_error_translation_function(uint16_t group_id) +{ + struct mgmt_group *group = NULL; + sys_snode_t *snp, *sns; + + /* Find the group with the specified group ID. */ + 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; + } + } + + if (group == NULL) { + return NULL; + } + + return group->mg_translate_error; +} +#endif + void mgmt_register_group(struct mgmt_group *group) { diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 6107ef9ca1e1..42bf633f09d5 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2021 mcumgr authors - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,62 +25,26 @@ #include #endif -#ifdef CONFIG_MCUMGR_GRP_FS -#include -#endif -#ifdef CONFIG_MCUMGR_GRP_IMG -#include -#endif -#ifdef CONFIG_MCUMGR_GRP_OS -#include -#endif -#ifdef CONFIG_MCUMGR_GRP_SHELL -#include -#endif -#ifdef CONFIG_MCUMGR_GRP_STAT -#include -#endif -#ifdef CONFIG_MCUMGR_GRP_ZBASIC -#include -#endif - #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL +/* + * @brief Translate SMP version 2 error code to legacy SMP version 1 MCUmgr error code. + * + * @param group #mcumgr_group_t group ID + * @param ret Group-specific error code + * + * @return #mcumgr_err_t error code + */ static int smp_translate_error_code(uint16_t group, uint16_t ret) { - switch (group) { -#ifdef CONFIG_MCUMGR_GRP_OS - case MGMT_GROUP_ID_OS: - return os_mgmt_translate_error_code(ret); -#endif + smp_translate_error_fn translate_error_function = NULL; -#ifdef CONFIG_MCUMGR_GRP_IMG - case MGMT_GROUP_ID_IMAGE: - return img_mgmt_translate_error_code(ret); -#endif - -#ifdef CONFIG_MCUMGR_GRP_STAT - case MGMT_GROUP_ID_STAT: - return stat_mgmt_translate_error_code(ret); -#endif + translate_error_function = mgmt_find_error_translation_function(group); -#ifdef CONFIG_MCUMGR_GRP_FS - case MGMT_GROUP_ID_FS: - return fs_mgmt_translate_error_code(ret); -#endif - -#ifdef CONFIG_MCUMGR_GRP_SHELL - case MGMT_GROUP_ID_SHELL: - return shell_mgmt_translate_error_code(ret); -#endif - -#ifdef CONFIG_MCUMGR_GRP_ZBASIC - case ZEPHYR_MGMT_GRP_BASIC: - return zephyr_basic_group_translate_error_code(ret); -#endif - - default: - return MGMT_ERR_EUNKNOWN; + if (translate_error_function == NULL) { + return MGMT_ERR_EUNKNOWN; } + + return translate_error_function(ret); } #endif From 35f380510c19e00e9d025701317d08026aec85b8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 21 Jun 2023 14:56:32 +0100 Subject: [PATCH 1515/2042] doc: release: 3.5: Add note on MCUmgr SMP version 2 error conversion Adds a note on the new MCUmgr SMP version 2 to legacy MCUmgr error type conversion feature. Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.5.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 807511b95d9d..1259abb43679 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -249,6 +249,11 @@ Libraries / Subsystems * Added response checking to MCUmgr's :c:enumerator:`MGMT_EVT_OP_CMD_RECV` notification callback to allow applications to reject MCUmgr commands. + * MCUmgr SMP version 2 error translation (to legacy MCUmgr error code) is now + supported in function handlers by setting ``mg_translate_error`` of + :c:struct:`mgmt_group` when registering a transport. See + :c:type:`smp_translate_error_fn` for function details. + HALs **** From 63fa033d11017bd9f234ab7c5d3d9c5e4fc9e1c6 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 19 Jul 2023 14:48:28 +0200 Subject: [PATCH 1516/2042] drivers: pwm: pwm_stm32: add macro for using DT_INST_PARENT() Make device init more readable by adding a macro Suggested-by: Francois Ramu Signed-off-by: Sean Nyekjaer --- drivers/pwm/pwm_stm32.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index 6b27545ebcc0..3c5103c69c4a 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -722,27 +722,29 @@ static int pwm_stm32_init(const struct device *dev) return 0; } +#define PWM(index) DT_INST_PARENT(index) + #ifdef CONFIG_PWM_CAPTURE #define IRQ_CONNECT_AND_ENABLE_BY_NAME(index, name) \ { \ - IRQ_CONNECT(DT_IRQ_BY_NAME(DT_INST_PARENT(index), name, irq), \ - DT_IRQ_BY_NAME(DT_INST_PARENT(index), name, priority), \ + IRQ_CONNECT(DT_IRQ_BY_NAME(PWM(index), name, irq), \ + DT_IRQ_BY_NAME(PWM(index), name, priority), \ pwm_stm32_isr, DEVICE_DT_INST_GET(index), 0); \ - irq_enable(DT_IRQ_BY_NAME(DT_INST_PARENT(index), name, irq)); \ + irq_enable(DT_IRQ_BY_NAME(PWM(index), name, irq)); \ } #define IRQ_CONNECT_AND_ENABLE_DEFAULT(index) \ { \ - IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(index)), \ - DT_IRQ(DT_INST_PARENT(index), priority), \ + IRQ_CONNECT(DT_IRQN(PWM(index)), \ + DT_IRQ(PWM(index), priority), \ pwm_stm32_isr, DEVICE_DT_INST_GET(index), 0); \ - irq_enable(DT_IRQN(DT_INST_PARENT(index))); \ + irq_enable(DT_IRQN(PWM(index))); \ } #define IRQ_CONFIG_FUNC(index) \ static void pwm_stm32_irq_config_func_##index(const struct device *dev) \ { \ - COND_CODE_1(DT_IRQ_HAS_NAME(DT_INST_PARENT(index), cc), \ + COND_CODE_1(DT_IRQ_HAS_NAME(PWM(index), cc), \ (IRQ_CONNECT_AND_ENABLE_BY_NAME(index, cc)), \ (IRQ_CONNECT_AND_ENABLE_DEFAULT(index)) \ ); \ @@ -756,10 +758,11 @@ static void pwm_stm32_irq_config_func_##index(const struct device *dev) \ #define DT_INST_CLK(index, inst) \ { \ - .bus = DT_CLOCKS_CELL(DT_INST_PARENT(index), bus), \ - .enr = DT_CLOCKS_CELL(DT_INST_PARENT(index), bits) \ + .bus = DT_CLOCKS_CELL(PWM(index), bus), \ + .enr = DT_CLOCKS_CELL(PWM(index), bits) \ } + #define PWM_DEVICE_INIT(index) \ static struct pwm_stm32_data pwm_stm32_data_##index; \ IRQ_CONFIG_FUNC(index) \ @@ -767,9 +770,9 @@ static void pwm_stm32_irq_config_func_##index(const struct device *dev) \ PINCTRL_DT_INST_DEFINE(index); \ \ static const struct pwm_stm32_config pwm_stm32_config_##index = { \ - .timer = (TIM_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(index)), \ - .prescaler = DT_PROP(DT_INST_PARENT(index), st_prescaler), \ - .countermode = DT_PROP(DT_INST_PARENT(index), st_countermode), \ + .timer = (TIM_TypeDef *)DT_REG_ADDR(PWM(index)), \ + .prescaler = DT_PROP(PWM(index), st_prescaler), \ + .countermode = DT_PROP(PWM(index), st_countermode), \ .pclken = DT_INST_CLK(index, timer), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ CAPTURE_INIT(index) \ From 25d496949ff80c0c758f1d071b1d6126161eb317 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Fri, 23 Jun 2023 08:24:07 +0200 Subject: [PATCH 1517/2042] drivers: pwm: pwm_stm32: reset timer using RCC before initialization If a timer is left running on an stm32mp1, (most likely) on the next run the timer is stuck. A simple timer reset before initialization fixes the issue. Signed-off-by: Sean Nyekjaer --- drivers/pwm/Kconfig.stm32 | 1 + drivers/pwm/pwm_stm32.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/Kconfig.stm32 b/drivers/pwm/Kconfig.stm32 index 8fc52f6cf5a5..7f914af4ff37 100644 --- a/drivers/pwm/Kconfig.stm32 +++ b/drivers/pwm/Kconfig.stm32 @@ -9,6 +9,7 @@ config PWM_STM32 depends on DT_HAS_ST_STM32_PWM_ENABLED select USE_STM32_LL_TIM select USE_STM32_LL_RCC if SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X + select RESET help This option enables the PWM driver for STM32 family of processors. Say y if you wish to use PWM port on STM32 diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index 3c5103c69c4a..44f021a874d7 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,8 @@ struct pwm_stm32_capture_data { struct pwm_stm32_data { /** Timer clock (Hz). */ uint32_t tim_clk; + /* Reset controller device configuration */ + const struct reset_dt_spec reset; #ifdef CONFIG_PWM_CAPTURE struct pwm_stm32_capture_data capture; #endif /* CONFIG_PWM_CAPTURE */ @@ -686,6 +689,9 @@ static int pwm_stm32_init(const struct device *dev) return r; } + /* Reset timer to default state using RCC */ + (void)reset_line_toggle_dt(&data->reset); + /* configure pinmux */ r = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (r < 0) { @@ -764,7 +770,10 @@ static void pwm_stm32_irq_config_func_##index(const struct device *dev) \ #define PWM_DEVICE_INIT(index) \ - static struct pwm_stm32_data pwm_stm32_data_##index; \ + static struct pwm_stm32_data pwm_stm32_data_##index = { \ + .reset = RESET_DT_SPEC_GET(PWM(index)), \ + }; \ + \ IRQ_CONFIG_FUNC(index) \ \ PINCTRL_DT_INST_DEFINE(index); \ From 85a70c9847dc9581c292c1189139484d6cde50af Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Wed, 19 Jul 2023 00:24:05 +0530 Subject: [PATCH 1518/2042] drivers: pwm: mchp: Low power mode enabled Updated the driver with low power feature Signed-off-by: Manimaran A --- drivers/pwm/pwm_mchp_xec.c | 57 ++++++++++++++- .../microchip/mec152x/mec152xhsz-pinctrl.dtsi | 64 +++++++++++++++++ .../microchip/mec172x/mec172xnsz-pinctrl.dtsi | 70 +++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm_mchp_xec.c b/drivers/pwm/pwm_mchp_xec.c index 5595c7e6f1c8..305944cf99b1 100644 --- a/drivers/pwm/pwm_mchp_xec.c +++ b/drivers/pwm/pwm_mchp_xec.c @@ -19,6 +19,7 @@ #endif #include #include +#include #include @@ -62,6 +63,10 @@ struct xec_params { uint8_t div; }; +struct pwm_xec_data { + uint32_t config; +}; + #define NUM_DIV_ELEMS 16 static const uint32_t max_freq_high_on_div[NUM_DIV_ELEMS] = { @@ -368,6 +373,50 @@ static int pwm_xec_get_cycles_per_sec(const struct device *dev, return 0; } +#ifdef CONFIG_PM_DEVICE +static int pwm_xec_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct pwm_xec_config *const devcfg = dev->config; + struct pwm_regs * const regs = devcfg->regs; + struct pwm_xec_data * const data = dev->data; + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("XEC PWM pinctrl setup failed (%d)", ret); + } + + /* Turn on PWM only if it is ON before sleep */ + if ((data->config & MCHP_PWM_CFG_ENABLE) == MCHP_PWM_CFG_ENABLE) { + + regs->CONFIG |= MCHP_PWM_CFG_ENABLE; + + data->config &= (~MCHP_PWM_CFG_ENABLE); + } + break; + case PM_DEVICE_ACTION_SUSPEND: + if ((regs->CONFIG & MCHP_PWM_CFG_ENABLE) == MCHP_PWM_CFG_ENABLE) { + /* Do copy first, then clear mode. */ + data->config = regs->CONFIG; + + regs->CONFIG &= ~(MCHP_PWM_CFG_ENABLE); + } + + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP); + /* pinctrl-1 does not exist. */ + if (ret == -ENOENT) { + ret = 0; + } + break; + default: + ret = -ENOTSUP; + } + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct pwm_driver_api pwm_xec_driver_api = { .set_cycles = pwm_xec_set_cycles, .get_cycles_per_sec = pwm_xec_get_cycles_per_sec, @@ -396,13 +445,17 @@ static int pwm_xec_init(const struct device *dev) #define XEC_PWM_DEVICE_INIT(index) \ \ + static struct pwm_xec_data pwm_xec_data_##index; \ + \ PINCTRL_DT_INST_DEFINE(index); \ \ XEC_PWM_CONFIG(index); \ \ + PM_DEVICE_DT_INST_DEFINE(index, pwm_xec_pm_action); \ + \ DEVICE_DT_INST_DEFINE(index, &pwm_xec_init, \ - NULL, \ - NULL, \ + PM_DEVICE_DT_INST_GET(index), \ + &pwm_xec_data_##index, \ &pwm_xec_config_##index, POST_KERNEL, \ CONFIG_PWM_INIT_PRIORITY, \ &pwm_xec_driver_api); diff --git a/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi b/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi index 3625736add3f..c408de42b8b7 100644 --- a/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi +++ b/dts/arm/microchip/mec152x/mec152xhsz-pinctrl.dtsi @@ -1088,4 +1088,68 @@ pinmux = < MCHP_XEC_PINMUX(0155, MCHP_AF2) >; low-power-enable; }; + + /* PWM */ + pwm0_gpio053_sleep: pwm0_gpio053_sleep { + pinmux = < MCHP_XEC_PINMUX(053, MCHP_AF1) >; + }; + + pwm0_alt_gpio241_sleep: pwm0_alt_gpio241_sleep { + pinmux = < MCHP_XEC_PINMUX(0241, MCHP_AF1) >; + }; + + pwm1_gpio054_sleep: pwm1_gpio054_sleep { + pinmux = < MCHP_XEC_PINMUX(054, MCHP_AF1) >; + }; + + pwm1_alt_gpio254_sleep: pwm1_alt_gpio254_sleep { + pinmux = < MCHP_XEC_PINMUX(0254, MCHP_AF1) >; + }; + + pwm2_gpio055_sleep: pwm2_gpio055_sleep { + pinmux = < MCHP_XEC_PINMUX(055, MCHP_AF1) >; + }; + + pwm2_alt_gpio045_sleep: pwm2_alt_gpio045_sleep { + pinmux = < MCHP_XEC_PINMUX(045, MCHP_AF2) >; + }; + pwm3_gpio056_sleep: pwm3_gpio056_sleep { + pinmux = < MCHP_XEC_PINMUX(056, MCHP_AF1) >; + }; + + pwm3_alt_gpio047_sleep: pwm3_alt_gpio047_sleep { + pinmux = < MCHP_XEC_PINMUX(047, MCHP_AF2) >; + }; + + pwm4_gpio011_sleep: pwm4_gpio011_sleep { + pinmux = < MCHP_XEC_PINMUX(011, MCHP_AF2) >; + }; + + pwm5_gpio002_sleep: pwm5_gpio002_sleep { + pinmux = < MCHP_XEC_PINMUX(02, MCHP_AF1) >; + }; + + pwm6_gpio014_sleep: pwm6_gpio014_sleep { + pinmux = < MCHP_XEC_PINMUX(014, MCHP_AF1) >; + }; + + pwm6_alt_gpio063_sleep: pwm6_alt_gpio063_sleep { + pinmux = < MCHP_XEC_PINMUX(063, MCHP_AF2) >; + }; + + pwm7_gpio015_sleep: pwm7_gpio015_sleep { + pinmux = < MCHP_XEC_PINMUX(015, MCHP_AF1) >; + }; + + pwm7_alt_gpio061_sleep: pwm7_alt_gpio061_sleep { + pinmux = < MCHP_XEC_PINMUX(061, MCHP_AF2) >; + }; + + pwm8_gpio035_sleep: pwm8_gpio035_sleep { + pinmux = < MCHP_XEC_PINMUX(035, MCHP_AF1) >; + }; + + pwm8_alt_gpio175_sleep: pwm8_alt_gpio175_sleep { + pinmux = < MCHP_XEC_PINMUX(0175, MCHP_AF3) >; + }; }; diff --git a/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi b/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi index b218d28c6d2b..51aa064152f6 100644 --- a/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi +++ b/dts/arm/microchip/mec172x/mec172xnsz-pinctrl.dtsi @@ -1113,4 +1113,74 @@ low-power-enable; }; + /* PWM */ + pwm0_gpio053_sleep: pwm0_gpio053_sleep { + pinmux = < MCHP_XEC_PINMUX(053, MCHP_AF1) >; + low-power-enable; + }; + + pwm0_alt_gpio241_sleep: pwm0_alt_gpio241_sleep { + pinmux = < MCHP_XEC_PINMUX(0241, MCHP_AF4) >; + low-power-enable; + }; + + pwm1_gpio054_sleep: pwm1_gpio054_sleep { + pinmux = < MCHP_XEC_PINMUX(054, MCHP_AF1) >; + low-power-enable; + }; + + pwm2_gpio055_sleep: pwm2_gpio055_sleep { + pinmux = < MCHP_XEC_PINMUX(055, MCHP_AF1) >; + low-power-enable; + }; + + pwm2_alt_gpio045_sleep: pwm2_alt_gpio045_sleep { + pinmux = < MCHP_XEC_PINMUX(045, MCHP_AF2) >; + low-power-enable; + }; + + pwm3_gpio056_sleep: pwm3_gpio056_sleep { + pinmux = < MCHP_XEC_PINMUX(056, MCHP_AF1) >; + low-power-enable; + }; + + pwm3_alt_gpio047_sleep: pwm3_alt_gpio047_sleep { + pinmux = < MCHP_XEC_PINMUX(047, MCHP_AF2) >; + low-power-enable; + }; + pwm4_gpio011_sleep: pwm4_gpio011_sleep { + pinmux = < MCHP_XEC_PINMUX(011, MCHP_AF2) >; + low-power-enable; + }; + + pwm5_gpio002_sleep: pwm5_gpio002_sleep { + pinmux = < MCHP_XEC_PINMUX(02, MCHP_AF1) >; + low-power-enable; + }; + + pwm6_gpio014_sleep: pwm6_gpio014_sleep { + pinmux = < MCHP_XEC_PINMUX(014, MCHP_AF1) >; + low-power-enable; + }; + + pwm6_alt_gpio063_sleep: pwm6_alt_gpio063_sleep { + pinmux = < MCHP_XEC_PINMUX(063, MCHP_AF2) >; + low-power-enable; + }; + + pwm7_gpio015_sleep: pwm7_gpio015_sleep { + pinmux = < MCHP_XEC_PINMUX(015, MCHP_AF1) >; + low-power-enable; + }; + + pwm8_gpio035_sleep: pwm8_gpio035_sleep { + pinmux = < MCHP_XEC_PINMUX(035, MCHP_AF1) >; + low-power-enable; + }; + + pwm8_alt_gpio175_sleep: pwm8_alt_gpio175_sleep { + pinmux = < MCHP_XEC_PINMUX(0175, MCHP_AF3) >; + low-power-enable; + }; + }; From bb8b515ffa317d60ac2915c59a00132b17e4751b Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Fri, 30 Jun 2023 11:06:33 +0200 Subject: [PATCH 1519/2042] native_posix: Add support for `west debug` This change adds the convenience of `west debug` to native builds. Signed-off-by: Aleksander Wasaznik --- boards/posix/native_posix/board.cmake | 3 ++ scripts/west_commands/runners/__init__.py | 1 + scripts/west_commands/runners/native_gdb.py | 46 +++++++++++++++++++++ scripts/west_commands/tests/test_imports.py | 1 + 4 files changed, 51 insertions(+) create mode 100644 scripts/west_commands/runners/native_gdb.py diff --git a/boards/posix/native_posix/board.cmake b/boards/posix/native_posix/board.cmake index 0ec9fc6a83a7..d9d444c1be94 100644 --- a/boards/posix/native_posix/board.cmake +++ b/boards/posix/native_posix/board.cmake @@ -1,3 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 set(SUPPORTED_EMU_PLATFORMS native) + +board_set_debugger_ifnset(native_gdb) +board_finalize_runner_args(native_gdb) diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index 5ee0ebf841c2..e4b4cf0d402b 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -39,6 +39,7 @@ def _import_runner_module(runner_name): 'jlink', 'mdb', 'misc', + 'native_gdb', 'nios2', 'nrfjprog', 'nrfutil', diff --git a/scripts/west_commands/runners/native_gdb.py b/scripts/west_commands/runners/native_gdb.py new file mode 100644 index 000000000000..777290cd3e89 --- /dev/null +++ b/scripts/west_commands/runners/native_gdb.py @@ -0,0 +1,46 @@ +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +"""This file provides a ZephyrBinaryRunner that launches GDB.""" + +import argparse +from runners.core import ZephyrBinaryRunner, RunnerCaps, RunnerConfig + +class NativeGDBBinaryRunner(ZephyrBinaryRunner): + """Runs the ELF binary under GDB.""" + + @classmethod + def name(cls): + return 'native_gdb' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'debug'}) + + @classmethod + def do_add_parser(cls, parser: argparse.ArgumentParser): + pass + + @classmethod + def do_create(cls, cfg: RunnerConfig, args: argparse.Namespace) -> ZephyrBinaryRunner: + return NativeGDBBinaryRunner(cfg) + + def do_run(self, command: str, **kwargs): + assert command == 'debug' + + # Clues to debug missing RunnerConfig values (in context of `west debug`): + # build/zephyr/runners.yaml is missing `gdb` or `elf_file`. + # board.cmake should have `board_finalize_runner_args(native_gdb)`. + # build/CMakeCache.txt should have `CMAKE_GDB`. + + if self.cfg.gdb is None: + raise ValueError("The provided RunnerConfig is missing the required field 'gdb'.") + + if self.cfg.elf_file is None: + raise ValueError("The provided RunnerConfig is missing the required field 'elf_file'.") + + self.call([ + self.cfg.gdb, + '--quiet', + self.cfg.elf_file, + ]) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 1a685caa73ae..49559567ec0d 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -30,6 +30,7 @@ def test_runner_imports(): 'mdb-nsim', 'mdb-hw', 'misc-flasher', + 'native_gdb', 'nios2', 'nrfjprog', 'nrfutil', From 7ca59d7bfe7331d3233b6077ffa3ac9b8f763c4b Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Mon, 17 Jul 2023 09:44:44 -0300 Subject: [PATCH 1520/2042] drivers: ipm: added IPM over IVSHMEM driver This driver is built on top of the IVSHMEM doorbell notification mechanism providing an unified way to generate inter VM interrupts. Signed-off-by: Felipe Neves --- CODEOWNERS | 1 + drivers/ipm/CMakeLists.txt | 1 + drivers/ipm/Kconfig | 11 ++ drivers/ipm/Kconfig.ivshmem | 18 +++ drivers/ipm/ipm_ivshmem.c | 135 +++++++++++++++++++++++ dts/bindings/ipm/linaro,ivshmem-ipm.yaml | 15 +++ 6 files changed, 181 insertions(+) create mode 100644 drivers/ipm/Kconfig.ivshmem create mode 100644 drivers/ipm/ipm_ivshmem.c create mode 100644 dts/bindings/ipm/linaro,ivshmem-ipm.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 69c4c894d214..05d7ad42ca0f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -346,6 +346,7 @@ /drivers/ipm/ipm_stm32_ipcc.c @arnopo /drivers/ipm/ipm_stm32_hsem.c @cameled /drivers/ipm/ipm_esp32.c @uLipe +/drivers/ipm/ipm_ivshmem.c @uLipe /drivers/kscan/ @VenkatKotakonda @franciscomunoz @sjvasanth1 /drivers/kscan/*xec* @franciscomunoz @sjvasanth1 /drivers/kscan/*ft5336* @MaureenHelm diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index 63148148e87e..1da9b759b289 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_library_sources_ifdef(CONFIG_IPM_STM32_HSEM ipm_stm32_hsem.c) zephyr_library_sources_ifdef(CONFIG_IPM_CAVS_HOST ipm_cavs_host.c) zephyr_library_sources_ifdef(CONFIG_ESP32_SOFT_IPM ipm_esp32.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE ipm_handlers.c) +zephyr_library_sources_ifdef(CONFIG_IPM_IVSHMEM ipm_ivshmem.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index c69321349645..d8aef8e0d3c3 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -38,10 +38,21 @@ config ESP32_SOFT_IPM help Interprocessor driver for ESP32 when using AMP. +config IPM_IVSHMEM + bool "IPM driver based on IVSHMEM-Doorbell" + default y + depends on DT_HAS_LINARO_IVSHMEM_IPM_ENABLED + depends on IVSHMEM + depends on IVSHMEM_DOORBELL + help + Interprocessor driver using IVSHMEM Doorbell mechanism. + source "drivers/ipm/Kconfig.nrfx" source "drivers/ipm/Kconfig.imx" source "drivers/ipm/Kconfig.stm32" source "drivers/ipm/Kconfig.intel_adsp" +source "drivers/ipm/Kconfig.ivshmem" + module = IPM module-str = ipm diff --git a/drivers/ipm/Kconfig.ivshmem b/drivers/ipm/Kconfig.ivshmem new file mode 100644 index 000000000000..7e693f044cab --- /dev/null +++ b/drivers/ipm/Kconfig.ivshmem @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023, Linaro + +if IPM_IVSHMEM + +config IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE + int "Stack size in bytes of IVSHMEM IPM Event loop task" + default 8192 + help + Adjust the stack size, in bytes of the ivshmem event loop task. + +config IPM_IVSHMEM_EVENT_LOOP_PRIO + int "Priority of IVSHMEM IPM Event loop task" + default 2 + help + Adjust the priority of the ivshmem event loop task. + +endif diff --git a/drivers/ipm/ipm_ivshmem.c b/drivers/ipm/ipm_ivshmem.c new file mode 100644 index 000000000000..deda3f519506 --- /dev/null +++ b/drivers/ipm/ipm_ivshmem.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023 Linaro. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT linaro_ivshmem_ipm + +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(ipm_ivshmem, CONFIG_IPM_LOG_LEVEL); + +K_THREAD_STACK_DEFINE(ivshmem_ev_loop_stack, CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE); +static struct k_thread ivshmem_ev_loop_thread; + +struct ivshmem_ipm_data { + ipm_callback_t cb; + void *user_data; +}; + +struct ivshmem_ipm_config { + const struct device *ivshmem_dev; +}; + +static void ivshmem_ipm_event_loop_thread(void *arg, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + unsigned int poll_signaled; + int ivshmem_vector_rx; + struct k_poll_signal sig; + struct k_poll_event events[] = { + K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, + &sig), + }; + + const struct device *dev = (const struct device *)arg; + struct ivshmem_ipm_data *dev_data = (struct ivshmem_ipm_data *)dev->data; + struct ivshmem_ipm_config *dev_cfg = (struct ivshmem_ipm_config *)dev->config; + + k_poll_signal_init(&sig); + int ret = ivshmem_register_handler(dev_cfg->ivshmem_dev, &sig, 0); + + if (ret < 0) { + LOG_ERR("registering handlers must be supported: %d\n", ret); + k_panic(); + } + + while (1) { + LOG_DBG("%s: waiting interrupt from client...\n", __func__); + ret = k_poll(events, ARRAY_SIZE(events), K_FOREVER); + + k_poll_signal_check(&sig, &poll_signaled, &ivshmem_vector_rx); + /* get ready for next signal */ + k_poll_signal_reset(&sig); + + if (dev_data->cb) + dev_data->cb(dev, dev_data->user_data, 0, NULL); + } +} + +static int ivshmem_ipm_send(const struct device *dev, int wait, uint32_t id, + const void *data, int size) +{ + ARG_UNUSED(wait); + ARG_UNUSED(data); + ARG_UNUSED(size); + + struct ivshmem_ipm_config *dev_cfg = (struct ivshmem_ipm_config *)dev->config; + + LOG_DBG("sending notification to the peer id 0x%x\n", id); + return ivshmem_int_peer(dev_cfg->ivshmem_dev, id, 0); +} + +static void ivshmem_ipm_register_callback(const struct device *dev, + ipm_callback_t cb, + void *user_data) +{ + struct ivshmem_ipm_data *dev_data = (struct ivshmem_ipm_data *)dev->data; + + dev_data->cb = cb; + dev_data->user_data = user_data; +} + +static int ivshmem_ipm_set_enabled(const struct device *dev, int enable) +{ + /* some subsystems needs this minimal function just return success here*/ + ARG_UNUSED(dev); + ARG_UNUSED(enable); + + return 0; +} + +static int ivshmem_ipm_init(const struct device *dev) +{ + k_thread_create(&ivshmem_ev_loop_thread, + ivshmem_ev_loop_stack, + CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE, + (k_thread_entry_t)ivshmem_ipm_event_loop_thread, + (void *)dev, NULL, NULL, + CONFIG_IPM_IVSHMEM_EVENT_LOOP_PRIO, + 0, K_NO_WAIT); + + return 0; +} + +static const struct ipm_driver_api ivshmem_ipm_driver_api = { + .send = ivshmem_ipm_send, + .register_callback = ivshmem_ipm_register_callback, + .set_enabled = ivshmem_ipm_set_enabled +}; + +#define IPM_IVSHMEM_INIT(inst) \ + static const struct ivshmem_ipm_config ivshmem_ipm_cfg_##inst = { \ + .ivshmem_dev = \ + DEVICE_DT_GET(DT_INST_PHANDLE(inst, ivshmem))\ + }; \ + static struct ivshmem_ipm_data ivshmem_ipm_data_##inst = { \ + .cb = NULL, \ + .user_data = NULL, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + ivshmem_ipm_init, \ + NULL, \ + &ivshmem_ipm_data_##inst, &ivshmem_ipm_cfg_##inst, \ + POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, \ + &ivshmem_ipm_driver_api); \ + +DT_INST_FOREACH_STATUS_OKAY(IPM_IVSHMEM_INIT); diff --git a/dts/bindings/ipm/linaro,ivshmem-ipm.yaml b/dts/bindings/ipm/linaro,ivshmem-ipm.yaml new file mode 100644 index 000000000000..7d2b660ff424 --- /dev/null +++ b/dts/bindings/ipm/linaro,ivshmem-ipm.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Linaro +# SPDX-License-Identifier: Apache-2.0 + +description: Inter processor message based on IVSHMEM + +compatible: "linaro,ivshmem-ipm" + +include: base.yaml + +properties: + + ivshmem: + type: phandle + required: true + description: ivshmem device node From da3ae1af61b42770a2a566eda64749639c73e2ee Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Mon, 17 Jul 2023 09:55:43 -0300 Subject: [PATCH 1521/2042] samples: drivers: ipm: added IPM over IVSHMEM sample To demonstrate how to configure Zephyr to use the IPM driver over the IVSHMEM subsystem. Since this driver is intended to generate inter QEMU VM notifications it was better to create a sample app using the shell for quick demonstration for the users. Signed-off-by: Felipe Neves --- drivers/virtualization/virt_ivshmem_shell.c | 2 +- .../drivers/ipm/ipm_ivshmem/CMakeLists.txt | 8 ++ samples/drivers/ipm/ipm_ivshmem/README.rst | 129 ++++++++++++++++++ .../ipm/ipm_ivshmem/boards/pcie_ivshmem.dtsi | 18 +++ .../ipm_ivshmem/boards/qemu_cortex_a53.conf | 16 +++ .../boards/qemu_cortex_a53.overlay | 14 ++ samples/drivers/ipm/ipm_ivshmem/prj.conf | 14 ++ samples/drivers/ipm/ipm_ivshmem/sample.yaml | 9 ++ samples/drivers/ipm/ipm_ivshmem/src/main.c | 50 +++++++ 9 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/ipm/ipm_ivshmem/CMakeLists.txt create mode 100644 samples/drivers/ipm/ipm_ivshmem/README.rst create mode 100644 samples/drivers/ipm/ipm_ivshmem/boards/pcie_ivshmem.dtsi create mode 100644 samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.conf create mode 100644 samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.overlay create mode 100644 samples/drivers/ipm/ipm_ivshmem/prj.conf create mode 100644 samples/drivers/ipm/ipm_ivshmem/sample.yaml create mode 100644 samples/drivers/ipm/ipm_ivshmem/src/main.c diff --git a/drivers/virtualization/virt_ivshmem_shell.c b/drivers/virtualization/virt_ivshmem_shell.c index 56d9b248e201..b073cbf8f416 100644 --- a/drivers/virtualization/virt_ivshmem_shell.c +++ b/drivers/virtualization/virt_ivshmem_shell.c @@ -76,7 +76,7 @@ static int cmd_ivshmem_shmem(const struct shell *sh, shell_fprintf(sh, SHELL_NORMAL, "IVshmem up and running: \n" - "\tShared memory: 0x%x of size %u bytes\n" + "\tShared memory: 0x%lx of size %lu bytes\n" "\tPeer id: %u\n" "\tNotification vectors: %u\n", mem, size, id, vectors); diff --git a/samples/drivers/ipm/ipm_ivshmem/CMakeLists.txt b/samples/drivers/ipm/ipm_ivshmem/CMakeLists.txt new file mode 100644 index 000000000000..cbcc43cc4f17 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Linaro +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ivshmem_ipm_sample) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/ipm/ipm_ivshmem/README.rst b/samples/drivers/ipm/ipm_ivshmem/README.rst new file mode 100644 index 000000000000..174fce788e75 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/README.rst @@ -0,0 +1,129 @@ +IPM over IVSHMEM Driver sample +################################ + +Prerequisites +************* + +* QEMU needs to available. + +ivshmem-server needs to be available and running. The server is available in +Zephyr SDK or pre-built in some distributions. Otherwise, it is available in +QEMU source tree. + +ivshmem-client needs to be available as it is employed in this sample as an +external application. The same conditions of ivshmem-server apply to the +ivshmem-server, as it is also available via QEMU. + +Preparing IVSHMEM server +************************ +#. The ivshmem-server utility for QEMU can be found into the Zephyr SDK + directory, in: + ``/path/to/your/zephyr-sdk/zephyr-/sysroots/x86_64-pokysdk-linux/usr/xilinx/bin/`` + +#. You may also find ivshmem-client utility, it can be useful to check if everything works + as expected. + +#. Run ivshmem-server. For the ivshmem-server, both number of vectors and + shared memory size are decided at run-time (when the server is executed). + For Zephyr, the number of vectors and shared memory size of ivshmem are + decided at compile-time and run-time, respectively. For Arm64 we use + vectors == 2 for the project configuration in this sample. Here is an example: + + .. code-block:: console + + # n = number of vectors + $ sudo ivshmem-server -n 2 + $ *** Example code, do not use in production *** + +#. Appropriately set ownership of ``/dev/shm/ivshmem`` and + ``/tmp/ivshmem_socket`` for your deployment scenario. For instance: + + .. code-block:: console + + $ sudo chgrp $USER /dev/shm/ivshmem + $ sudo chmod 060 /dev/shm/ivshmem + $ sudo chgrp $USER /tmp/ivshmem_socket + $ sudo chmod 060 /tmp/ivshmem_socket + +Building and Running +******************** + +After getting QEMU ready to go, first create two output folders, so open two terminals +and create them, these folders will receive the output of Zephyr west commands: + + .. code-block:: console + + $ mkdir -p path/to/instance_1 + +On another terminal window do: + + .. code-block:: console + + $ mkdir -p path/to/instance_2 + +Then build the sample as follows, don't forget, two builds are necessary +to test this sample, so append the option ``-d path/to/instance_1`` and +on the other terminal window do the same, that is it ``-d path/to/instance_2`` + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/ipm/ipm_ivshmem + :board: qemu_cortex_a53 + :goals: build + :compact: + +To run both QEMU sides, repeat the west build command followed +by ``-d path/to/instance_x`` where x is 1 or 2 depending on the +terminal window, using the run target: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/ipm/ipm_ivshmem + :board: qemu_cortex_a53 + :goals: run + :compact: + +Expected output +*************** + +On the console just use the ``ivshmem_ipm_send`` command +followed by the destination peer-id, to get the peer-id destination +go to the other terminal window and check with ``ivshmem`` command: + + .. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.4.0-974-g7fba7d395750 *** + + + uart:~$ ivshmem + IVshmem up and running: + Shared memory: 0xafa00000 of size 4194304 bytes + Peer id: 12 + Notification vectors: 2 + uart:~$ + +For example one of the instances has the peer-id 12, so go the other +instance and use the command to send the IPM notification followed +by this peer-id: + + .. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.4.0-974-g7fba7d395750 *** + + + uart:~$ ivshmem + IVshmem up and running: + Shared memory: 0xafa00000 of size 4194304 bytes + Peer id: 11 + Notification vectors: 2 + uart:~$ ivshmem_ipm_send 12 + +Then go back to the other terminal window where user may see the reception +of the notification on the terminal: + + .. code-block:: console + + uart:~$ ivshmem + IVshmem up and running: + Shared memory: 0xafa00000 of size 4194304 bytes + Peer id: 12 + Notification vectors: 2 + uart:~$ Received IPM notification over IVSHMEM diff --git a/samples/drivers/ipm/ipm_ivshmem/boards/pcie_ivshmem.dtsi b/samples/drivers/ipm/ipm_ivshmem/boards/pcie_ivshmem.dtsi new file mode 100644 index 000000000000..e0237864189a --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/boards/pcie_ivshmem.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright 2023 Linaro. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + ivhsmem { + ivshmem0: ivshmem { + compatible = "qemu,ivshmem"; + + vendor-id = <0x1af4>; + device-id = <0x1110>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.conf b/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.conf new file mode 100644 index 000000000000..996843465101 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.conf @@ -0,0 +1,16 @@ +CONFIG_PCIE_CONTROLLER=y +CONFIG_PCIE_ECAM=y + +# Hungry PCI requires at least 256M of virtual space +CONFIG_KERNEL_VM_SIZE=0x80000000 + +# Hungry PCI requires phys addresses with more than 32 bits +CONFIG_ARM64_VA_BITS_40=y +CONFIG_ARM64_PA_BITS_40=y + +# MSI support requires ITS +CONFIG_GIC_V3_ITS=y + +# ITS, in turn, requires dynamic memory (9x64 + alignment constrains) +# Additionally, our test also uses malloc +CONFIG_HEAP_MEM_POOL_SIZE=1048576 diff --git a/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.overlay b/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.overlay new file mode 100644 index 000000000000..5672d5255479 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/boards/qemu_cortex_a53.overlay @@ -0,0 +1,14 @@ +/* + * Copyright 2023 Linaro. + * + * SPDX-License-Identifier: Apache-2.0 + */ + #include "pcie_ivshmem.dtsi" + + / { + ipm_ivshmem0: ipm_ivshmem { + compatible = "linaro,ivshmem-ipm"; + ivshmem = <&ivshmem0>; + status = "okay"; + }; + }; diff --git a/samples/drivers/ipm/ipm_ivshmem/prj.conf b/samples/drivers/ipm/ipm_ivshmem/prj.conf new file mode 100644 index 000000000000..443b595e0cb0 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/prj.conf @@ -0,0 +1,14 @@ +CONFIG_PCIE=y +# required by doorbell +CONFIG_PCIE_MSI=y +CONFIG_PCIE_MSI_X=y +CONFIG_PCIE_MSI_MULTI_VECTOR=y +CONFIG_POLL=y + +CONFIG_VIRTUALIZATION=y +CONFIG_IVSHMEM=y +CONFIG_IVSHMEM_DOORBELL=y + +CONFIG_SHELL=y +CONFIG_IVSHMEM_SHELL=y +CONFIG_IPM=y diff --git a/samples/drivers/ipm/ipm_ivshmem/sample.yaml b/samples/drivers/ipm/ipm_ivshmem/sample.yaml new file mode 100644 index 000000000000..b808e8382099 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/sample.yaml @@ -0,0 +1,9 @@ +sample: + name: IVSHMEM IPM Sample +tests: + sample.ipm.ipm_ivshmem: + build_only: true + platform_allow: qemu_cortex_a53 + tags: + - samples + - ipm diff --git a/samples/drivers/ipm/ipm_ivshmem/src/main.c b/samples/drivers/ipm/ipm_ivshmem/src/main.c new file mode 100644 index 000000000000..6b77efc227f7 --- /dev/null +++ b/samples/drivers/ipm/ipm_ivshmem/src/main.c @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Linaro. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static void ipm_receive_callback(const struct device *ipmdev, void *user_data, + uint32_t id, volatile void *data) +{ + ARG_UNUSED(ipmdev); + ARG_UNUSED(user_data); + + printf("Received IPM notification over IVSHMEM\n"); +} + +int main(void) +{ + const struct device *ipm_dev = DEVICE_DT_GET(DT_NODELABEL(ipm_ivshmem0)); + + ipm_register_callback(ipm_dev, ipm_receive_callback, NULL); + return 0; +} + +static int cmd_ipm_send(const struct shell *sh, + size_t argc, char **argv) +{ + + const struct device *ipm_dev = DEVICE_DT_GET(DT_NODELABEL(ipm_ivshmem0)); + + int peer_id = strtol(argv[1], NULL, 10); + + return ipm_send(ipm_dev, 0, peer_id, NULL, 0); +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_ivshmem_ipm, + SHELL_CMD_ARG(ivshmem_ipm_send, NULL, + "Send notification to other side using IPM", + cmd_ipm_send, 2, 0), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_ARG_REGISTER(ivshmem_ipm_send, + &sub_ivshmem_ipm, + "Send notification to other side using IPM", + cmd_ipm_send, 2, 0); From ddcceed7e80b1db3bee60f696903fddf1e5b3f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 11:31:05 +0200 Subject: [PATCH 1522/2042] doc: bluetooth: Spell out GAP acronym MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with other groups, spell out GAP Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/bluetooth.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index e5aa503de25d..78291949c5be 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -32,8 +32,8 @@ extern "C" { #endif /** - * @brief Generic Access Profile - * @defgroup bt_gap Generic Access Profile + * @brief Generic Access Profile (GAP) + * @defgroup bt_gap Generic Access Profile (GAP) * @ingroup bluetooth * @{ */ From abac1bcc1ff1046b5c9ff0f08e9ada7ba234d7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 11:31:54 +0200 Subject: [PATCH 1523/2042] bluetooth: doc: Move GAP defines to bt_gap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved Doxygen documentation under bt_gap group. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/gap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/bluetooth/gap.h b/include/zephyr/bluetooth/gap.h index c643da671299..1df1cfcde12e 100644 --- a/include/zephyr/bluetooth/gap.h +++ b/include/zephyr/bluetooth/gap.h @@ -21,7 +21,7 @@ extern "C" { /** * @brief Bluetooth Generic Access Profile defines and Assigned Numbers. * @defgroup bt_gap_defines Defines and Assigned Numbers - * @ingroup bluetooth + * @ingroup bt_gap * @{ */ From 9fab241991c38da5bda57ed5af7b6d4cc46d364a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 11:50:17 +0200 Subject: [PATCH 1524/2042] bluetooth: doc: Reformat BT_APPEARANCE_* defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the BT_APPEARANCE_* doc on two lines as several lines were dangerously close to 100-character line limit + some constants were misaligned. This makes follow-up commit possible without breaking code formatting rules. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/gap.h | 907 ++++++++++++++++++++++----------- 1 file changed, 604 insertions(+), 303 deletions(-) diff --git a/include/zephyr/bluetooth/gap.h b/include/zephyr/bluetooth/gap.h index 1df1cfcde12e..90b17e958da0 100644 --- a/include/zephyr/bluetooth/gap.h +++ b/include/zephyr/bluetooth/gap.h @@ -81,309 +81,610 @@ extern "C" { #define BT_LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */ /* Appearance Values Last Modified on 2023-01-05 */ -#define BT_APPEARANCE_UNKNOWN 0x0000 /* Generic Unknown */ -#define BT_APPEARANCE_GENERIC_PHONE 0x0040 /* Generic Phone */ -#define BT_APPEARANCE_GENERIC_COMPUTER 0x0080 /* Generic Computer */ -#define BT_APPEARANCE_COMPUTER_DESKTOP_WORKSTATION 0x0081 /* Desktop Workstation */ -#define BT_APPEARANCE_COMPUTER_SERVER_CLASS 0x0082 /* Server-class Computer */ -#define BT_APPEARANCE_COMPUTER_LAPTOP 0x0083 /* Laptop */ -#define BT_APPEARANCE_COMPUTER_HANDHELD_PCPDA 0x0084 /* Handheld PC/PDA (clamshell) */ -#define BT_APPEARANCE_COMPUTER_PALMSIZE_PCPDA 0x0085 /* Palm­size PC/PDA */ -#define BT_APPEARANCE_COMPUTER_WEARABLE_COMPUTER 0x0086 /* Wearable computer (watch size) */ -#define BT_APPEARANCE_COMPUTER_TABLET 0x0087 /* Tablet */ -#define BT_APPEARANCE_COMPUTER_DOCKING_STATION 0x0088 /* Docking Station */ -#define BT_APPEARANCE_COMPUTER_ALL_IN_ONE 0x0089 /* All in One */ -#define BT_APPEARANCE_COMPUTER_BLADE_SERVER 0x008A /* Blade Server */ -#define BT_APPEARANCE_COMPUTER_CONVERTIBLE 0x008B /* Convertible */ -#define BT_APPEARANCE_COMPUTER_DETACHABLE 0x008C /* Detachable */ -#define BT_APPEARANCE_COMPUTER_IOT_GATEWAY 0x008D /* IoT Gateway */ -#define BT_APPEARANCE_COMPUTER_MINI_PC 0x008E /* Mini PC */ -#define BT_APPEARANCE_COMPUTER_STICK_PC 0x008F /* Stick PC */ -#define BT_APPEARANCE_GENERIC_WATCH 0x00C0 /* Generic Watch */ -#define BT_APPEARANCE_SPORTS_WATCH 0x00C1 /* Sports Watch */ -#define BT_APPEARANCE_SMARTWATCH 0x00C2 /* Smartwatch */ -#define BT_APPEARANCE_GENERIC_CLOCK 0x0100 /* Generic Clock */ -#define BT_APPEARANCE_GENERIC_DISPLAY 0x0140 /* Generic Display */ -#define BT_APPEARANCE_GENERIC_REMOTE 0x0180 /* Generic Remote Control */ -#define BT_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 /* Generic Eye-glasses */ -#define BT_APPEARANCE_GENERIC_TAG 0x0200 /* Generic Tag */ -#define BT_APPEARANCE_GENERIC_KEYRING 0x0240 /* Generic Keyring */ -#define BT_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 /* Generic Media Player */ -#define BT_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 /* Generic Barcode Scanner */ -#define BT_APPEARANCE_GENERIC_THERMOMETER 0x0300 /* Generic Thermometer */ -#define BT_APPEARANCE_THERMOMETER_EAR 0x0301 /* Ear Thermometer */ -#define BT_APPEARANCE_GENERIC_HEART_RATE 0x0340 /* Generic Heart Rate Sensor */ -#define BT_APPEARANCE_HEART_RATE_BELT 0x0341 /* Heart Rate Belt */ -#define BT_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 /* Generic Blood Pressure */ -#define BT_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 /* Arm Blood Pressure */ -#define BT_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 /* Wrist Blood Pressure */ -#define BT_APPEARANCE_GENERIC_HID 0x03C0 /* Generic Human Interface Device */ -#define BT_APPEARANCE_HID_KEYBOARD 0x03C1 /* Keyboard */ -#define BT_APPEARANCE_HID_MOUSE 0x03C2 /* Mouse */ -#define BT_APPEARANCE_HID_JOYSTICK 0x03C3 /* Joystick */ -#define BT_APPEARANCE_HID_GAMEPAD 0x03C4 /* Gamepad */ -#define BT_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 /* Digitizer Tablet */ -#define BT_APPEARANCE_HID_CARD_READER 0x03C6 /* Card Reader */ -#define BT_APPEARANCE_HID_DIGITAL_PEN 0x03C7 /* Digital Pen */ -#define BT_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 /* Barcode Scanner */ -#define BT_APPEARANCE_HID_TOUCHPAD 0x03C9 /* Touchpad */ -#define BT_APPEARANCE_HID_PRESENTATION_REMOTE 0x03CA /* Presentation Remote */ -#define BT_APPEARANCE_GENERIC_GLUCOSE 0x0400 /* Generic Glucose Meter */ -#define BT_APPEARANCE_GENERIC_WALKING 0x0440 /* Generic Running Walking Sensor */ -#define BT_APPEARANCE_WALKING_IN_SHOE 0x0441 /* In-Shoe Running Walking Sensor */ -#define BT_APPEARANCE_WALKING_ON_SHOE 0x0442 /* On-Shoe Running Walking Sensor */ -#define BT_APPEARANCE_WALKING_ON_HIP 0x0443 /* On-Hip Running Walking Sensor */ -#define BT_APPEARANCE_GENERIC_CYCLING 0x0480 /* Generic Cycling */ -#define BT_APPEARANCE_CYCLING_COMPUTER 0x0481 /* Cycling Computer */ -#define BT_APPEARANCE_CYCLING_SPEED 0x0482 /* Speed Sensor */ -#define BT_APPEARANCE_CYCLING_CADENCE 0x0483 /* Cadence Sensor */ -#define BT_APPEARANCE_CYCLING_POWER 0x0484 /* Power Sensor */ -#define BT_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 /* Speed and Cadence Sensor */ -#define BT_APPEARANCE_GENERIC_CONTROL_DEVICE 0x04C0 /* Generic Control Device */ -#define BT_APPEARANCE_CONTROL_SWITCH 0x04C1 /* Switch */ -#define BT_APPEARANCE_CONTROL_MULTI_SWITCH 0x04C2 /* Multi-switch */ -#define BT_APPEARANCE_CONTROL_BUTTON 0x04C3 /* Button */ -#define BT_APPEARANCE_CONTROL_SLIDER 0x04C4 /* Slider */ -#define BT_APPEARANCE_CONTROL_ROTARY_SWITCH 0x04C5 /* Rotary Switch */ -#define BT_APPEARANCE_CONTROL_TOUCH_PANEL 0x04C6 /* Touch Panel */ -#define BT_APPEARANCE_CONTROL_SINGLE_SWITCH 0x04C7 /* Single Switch */ -#define BT_APPEARANCE_CONTROL_DOUBLE_SWITCH 0x04C8 /* Double Switch */ -#define BT_APPEARANCE_CONTROL_TRIPLE_SWITCH 0x04C9 /* Triple Switch */ -#define BT_APPEARANCE_CONTROL_BATTERY_SWITCH 0x04CA /* Battery Switch */ -#define BT_APPEARANCE_CONTROL_ENERGY_HARVESTING_SWITCH 0x04CB /* Energy Harvesting Switch */ -#define BT_APPEARANCE_CONTROL_PUSH_BUTTON 0x04CC /* Push Button */ -#define BT_APPEARANCE_GENERIC_NETWORK_DEVICE 0x0500 /* Generic Network Device */ -#define BT_APPEARANCE_NETWORK_ACCESS_POINT 0x0501 /* Access Point */ -#define BT_APPEARANCE_NETWORK_MESH_DEVICE 0x0502 /* Mesh Device */ -#define BT_APPEARANCE_NETWORK_MESH_PROXY 0x0503 /* Mesh Network Proxy */ -#define BT_APPEARANCE_GENERIC_SENSOR 0x0540 /* Generic Sensor */ -#define BT_APPEARANCE_SENSOR_MOTION 0x0541 /* Motion Sensor */ -#define BT_APPEARANCE_SENSOR_AIR_QUALITY 0x0542 /* Air quality Sensor */ -#define BT_APPEARANCE_SENSOR_TEMPERATURE 0x0543 /* Temperature Sensor */ -#define BT_APPEARANCE_SENSOR_HUMIDITY 0x0544 /* Humidity Sensor */ -#define BT_APPEARANCE_SENSOR_LEAK 0x0545 /* Leak Sensor */ -#define BT_APPEARANCE_SENSOR_SMOKE 0x0546 /* Smoke Sensor */ -#define BT_APPEARANCE_SENSOR_OCCUPANCY 0x0547 /* Occupancy Sensor */ -#define BT_APPEARANCE_SENSOR_CONTACT 0x0548 /* Contact Sensor */ -#define BT_APPEARANCE_SENSOR_CARBON_MONOXIDE 0x0549 /* Carbon Monoxide Sensor */ -#define BT_APPEARANCE_SENSOR_CARBON_DIOXIDE 0x054A /* Carbon Dioxide Sensor */ -#define BT_APPEARANCE_SENSOR_AMBIENT_LIGHT 0x054B /* Ambient Light Sensor */ -#define BT_APPEARANCE_SENSOR_ENERGY 0x054C /* Energy Sensor */ -#define BT_APPEARANCE_SENSOR_COLOR_LIGHT 0x054D /* Color Light Sensor */ -#define BT_APPEARANCE_SENSOR_RAIN 0x054E /* Rain Sensor */ -#define BT_APPEARANCE_SENSOR_FIRE 0x054F /* Fire Sensor */ -#define BT_APPEARANCE_SENSOR_WIND 0x0550 /* Wind Sensor */ -#define BT_APPEARANCE_SENSOR_PROXIMITY 0x0551 /* Proximity Sensor */ -#define BT_APPEARANCE_SENSOR_MULTI 0x0552 /* Multi-Sensor */ -#define BT_APPEARANCE_SENSOR_FLUSH_MOUNTED 0x0553 /* Flush Mounted Sensor */ -#define BT_APPEARANCE_SENSOR_CEILING_MOUNTED 0x0554 /* Ceiling Mounted Sensor */ -#define BT_APPEARANCE_SENSOR_WALL_MOUNTED 0x0555 /* Wall Mounted Sensor */ -#define BT_APPEARANCE_MULTISENSOR 0x0556 /* Multisensor */ -#define BT_APPEARANCE_SENSOR_ENERGY_METER 0x0557 /* Energy Meter */ -#define BT_APPEARANCE_SENSOR_FLAME_DETECTOR 0x0558 /* Flame Detector */ -#define BT_APPEARANCE_SENSOR_VEHICLE_TIRE_PRESSURE 0x0559 /* Vehicle Tire Pressure Sensor */ -#define BT_APPEARANCE_GENERIC_LIGHT_FIXTURES 0x0580 /* Generic Light Fixtures */ -#define BT_APPEARANCE_LIGHT_FIXTURES_WALL 0x0581 /* Wall Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_CEILING 0x0582 /* Ceiling Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOR 0x0583 /* Floor Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_CABINET 0x0584 /* Cabinet Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_DESK 0x0585 /* Desk Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_TROFFER 0x0586 /* Troffer Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_PENDANT 0x0587 /* Pendant Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_IN_GROUND 0x0588 /* In-ground Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOD 0x0589 /* Flood Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_UNDERWATER 0x058A /* Underwater Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_BOLLARD_WITH 0x058B /* Bollard with Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_PATHWAY 0x058C /* Pathway Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_GARDEN 0x058D /* Garden Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_POLE_TOP 0x058E /* Pole-top Light */ -#define BT_APPEARANCE_SPOT_LIGHT 0x058F /* Spotlight */ -#define BT_APPEARANCE_LIGHT_FIXTURES_LINEAR 0x0590 /* Linear Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_STREET 0x0591 /* Street Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_SHELVES 0x0592 /* Shelves Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_BAY 0x0593 /* Bay Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_EMERGENCY_EXIT 0x0594 /* Emergency Exit Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_CONTROLLER 0x0595 /* Light Controller */ -#define BT_APPEARANCE_LIGHT_FIXTURES_DRIVER 0x0596 /* Light Driver */ -#define BT_APPEARANCE_LIGHT_FIXTURES_BULB 0x0597 /* Bulb */ -#define BT_APPEARANCE_LIGHT_FIXTURES_LOW_BAY 0x0598 /* Low-bay Light */ -#define BT_APPEARANCE_LIGHT_FIXTURES_HIGH_BAY 0x0599 /* High-bay Light */ -#define BT_APPEARANCE_GENERIC_FAN 0x05C0 /* Generic Fan */ -#define BT_APPEARANCE_FAN_CEILING 0x05C1 /* Ceiling Fan */ -#define BT_APPEARANCE_FAN_AXIAL 0x05C2 /* Axial Fan */ -#define BT_APPEARANCE_FAN_EXHAUST 0x05C3 /* Exhaust Fan */ -#define BT_APPEARANCE_FAN_PEDESTAL 0x05C4 /* Pedestal Fan */ -#define BT_APPEARANCE_FAN_DESK 0x05C5 /* Desk Fan */ -#define BT_APPEARANCE_FAN_WALL 0x05C6 /* Wall Fan */ -#define BT_APPEARANCE_GENERIC_HVAC 0x0600 /* Generic HVAC */ -#define BT_APPEARANCE_HVAC_THERMOSTAT 0x0601 /* Thermostat */ -#define BT_APPEARANCE_HVAC_HUMIDIFIER 0x0602 /* Humidifier */ -#define BT_APPEARANCE_HVAC_DEHUMIDIFIER 0x0603 /* De-humidifier */ -#define BT_APPEARANCE_HVAC_HEATER 0x0604 /* Heater */ -#define BT_APPEARANCE_HVAC_RADIATOR 0x0605 /* Radiator */ -#define BT_APPEARANCE_HVAC_BOILER 0x0606 /* Boiler */ -#define BT_APPEARANCE_HVAC_HEAT_PUMP 0x0607 /* Heat Pump */ -#define BT_APPEARANCE_HVAC_INFRARED_HEATER 0x0608 /* Infrared Heater */ -#define BT_APPEARANCE_HVAC_RADIANT_PANEL_HEATER 0x0609 /* Radiant Panel Heater */ -#define BT_APPEARANCE_HVAC_FAN_HEATER 0x060A /* Fan Heater */ -#define BT_APPEARANCE_HVAC_AIR_CURTAIN 0x060B /* Air Curtain */ -#define BT_APPEARANCE_GENERIC_AIR_CONDITIONING 0x0640 /* Generic Air Conditioning */ -#define BT_APPEARANCE_GENERIC_HUMIDIFIER 0x0680 /* Generic Humidifier */ -#define BT_APPEARANCE_GENERIC_HEATING 0x06C0 /* Generic Heating */ -#define BT_APPEARANCE_HEATING_RADIATOR 0x06C1 /* Radiator */ -#define BT_APPEARANCE_HEATING_BOILER 0x06C2 /* Boiler */ -#define BT_APPEARANCE_HEATING_HEAT_PUMP 0x06C3 /* Heat Pump */ -#define BT_APPEARANCE_HEATING_INFRARED_HEATER 0x06C4 /* Infrared Heater */ -#define BT_APPEARANCE_HEATING_RADIANT_PANEL_HEATER 0x06C5 /* Radiant Panel Heater */ -#define BT_APPEARANCE_HEATING_FAN_HEATER 0x06C6 /* Fan Heater */ -#define BT_APPEARANCE_HEATING_AIR_CURTAIN 0x06C7 /* Air Curtain */ -#define BT_APPEARANCE_GENERIC_ACCESS_CONTROL 0x0700 /* Generic Access Control */ -#define BT_APPEARANCE_CONTROL_ACCESS_DOOR 0x0701 /* Access Door */ -#define BT_APPEARANCE_CONTROL_GARAGE_DOOR 0x0702 /* Garage Door */ -#define BT_APPEARANCE_CONTROL_EMERGENCY_EXIT_DOOR 0x0703 /* Emergency Exit Door */ -#define BT_APPEARANCE_CONTROL_ACCESS_LOCK 0x0704 /* Access Lock */ -#define BT_APPEARANCE_CONTROL_ELEVATOR 0x0705 /* Elevator */ -#define BT_APPEARANCE_CONTROL_WINDOW 0x0706 /* Window */ -#define BT_APPEARANCE_CONTROL_ENTRANCE_GATE 0x0707 /* Entrance Gate */ -#define BT_APPEARANCE_CONTROL_DOOR_LOCK 0x0708 /* Door Lock */ -#define BT_APPEARANCE_CONTROL_LOCKER 0x0709 /* Locker */ -#define BT_APPEARANCE_GENERIC_MOTORIZED_DEVICE 0x0740 /* Generic Motorized Device */ -#define BT_APPEARANCE_MOTORIZED_GATE 0x0741 /* Motorized Gate */ -#define BT_APPEARANCE_MOTORIZED_AWNING 0x0742 /* Awning */ -#define BT_APPEARANCE_MOTORIZED_BLINDS_OR_SHADES 0x0743 /* Blinds or Shades */ -#define BT_APPEARANCE_MOTORIZED_CURTAINS 0x0744 /* Curtains */ -#define BT_APPEARANCE_MOTORIZED_SCREEN 0x0745 /* Screen */ -#define BT_APPEARANCE_GENERIC_POWER_DEVICE 0x0780 /* Generic Power Device */ -#define BT_APPEARANCE_POWER_OUTLET 0x0781 /* Power Outlet */ -#define BT_APPEARANCE_POWER_STRIP 0x0782 /* Power Strip */ -#define BT_APPEARANCE_POWER_PLUG 0x0783 /* Plug */ -#define BT_APPEARANCE_POWER_SUPPLY 0x0784 /* Power Supply */ -#define BT_APPEARANCE_POWER_LED_DRIVER 0x0785 /* LED Driver */ -#define BT_APPEARANCE_POWER_FLUORESCENT_LAMP_GEAR 0x0786 /* Fluorescent Lamp Gear */ -#define BT_APPEARANCE_POWER_HID_LAMP_GEAR 0x0787 /* HID Lamp Gear */ -#define BT_APPEARANCE_POWER_CHARGE_CASE 0x0788 /* Charge Case */ -#define BT_APPEARANCE_POWER_POWER_BANK 0x0789 /* Power Bank */ -#define BT_APPEARANCE_GENERIC_LIGHT_SOURCE 0x07C0 /* Generic Light Source */ -#define BT_APPEARANCE_LIGHT_SOURCE_INCANDESCENT_BULB 0x07C1 /* Incandescent Light Bulb */ -#define BT_APPEARANCE_LIGHT_SOURCE_LED_LAMP 0x07C2 /* LED Lamp */ -#define BT_APPEARANCE_LIGHT_SOURCE_HID_LAMP 0x07C3 /* HID Lamp */ -#define BT_APPEARANCE_LIGHT_SOURCE_FLUORESCENT_LAMP 0x07C4 /* Fluorescent Lamp */ -#define BT_APPEARANCE_LIGHT_SOURCE_LED_ARRAY 0x07C5 /* LED Array */ -#define BT_APPEARANCE_LIGHT_SOURCE_MULTICOLOR_LED_ARRAY 0x07C6 /* Multi-Color LED Array */ -#define BT_APPEARANCE_LIGHT_SOURCE_LOW_VOLTAGE_HALOGEN 0x07C7 /* Low voltage halogen */ -#define BT_APPEARANCE_LIGHT_SOURCE_OLED 0x07C8 /* Organic light emitting diode */ -#define BT_APPEARANCE_GENERIC_WINDOW_COVERING 0x0800 /* Generic Window Covering */ -#define BT_APPEARANCE_WINDOW_SHADES 0x0801 /* Window Shades */ -#define BT_APPEARANCE_WINDOW_BLINDS 0x0802 /* Window Blinds */ -#define BT_APPEARANCE_WINDOW_AWNING 0x0803 /* Window Awning */ -#define BT_APPEARANCE_WINDOW_CURTAIN 0x0804 /* Window Curtain */ -#define BT_APPEARANCE_WINDOW_EXTERIOR_SHUTTER 0x0805 /* Exterior Shutter */ -#define BT_APPEARANCE_WINDOW_EXTERIOR_SCREEN 0x0806 /* Exterior Screen */ -#define BT_APPEARANCE_GENERIC_AUDIO_SINK 0x0840 /* Generic Audio Sink */ -#define BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER 0x0841 /* Standalone Speaker */ -#define BT_APPEARANCE_AUDIO_SINK_SOUNDBAR 0x0842 /* Soundbar */ -#define BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER 0x0843 /* Bookshelf Speaker */ -#define BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER 0x0844 /* Standmounted Speaker */ -#define BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE 0x0845 /* Speakerphone */ -#define BT_APPEARANCE_GENERIC_AUDIO_SOURCE 0x0880 /* Generic Audio Source */ -#define BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE 0x0881 /* Microphone */ -#define BT_APPEARANCE_AUDIO_SOURCE_ALARM 0x0882 /* Alarm */ -#define BT_APPEARANCE_AUDIO_SOURCE_BELL 0x0883 /* Bell */ -#define BT_APPEARANCE_AUDIO_SOURCE_HORN 0x0884 /* Horn */ -#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE 0x0885 /* Broadcasting Device */ -#define BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK 0x0886 /* Service Desk */ -#define BT_APPEARANCE_AUDIO_SOURCE_KIOSK 0x0887 /* Kiosk */ -#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM 0x0888 /* Broadcasting Room */ -#define BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM 0x0889 /* Auditorium */ -#define BT_APPEARANCE_GENERIC_MOTORIZED_VEHICLE 0x08C0 /* Generic Motorized Vehicle */ -#define BT_APPEARANCE_VEHICLE_CAR 0x08C1 /* Car */ -#define BT_APPEARANCE_VEHICLE_LARGE_GOODS 0x08C2 /* Large Goods Vehicle */ -#define BT_APPEARANCE_VEHICLE_TWO_WHEELED 0x08C3 /* 2-Wheeled Vehicle */ -#define BT_APPEARANCE_VEHICLE_MOTORBIKE 0x08C4 /* Motorbike */ -#define BT_APPEARANCE_VEHICLE_SCOOTER 0x08C5 /* Scooter */ -#define BT_APPEARANCE_VEHICLE_MOPED 0x08C6 /* Moped */ -#define BT_APPEARANCE_VEHICLE_THREE_WHEELED 0x08C7 /* 3-Wheeled Vehicle */ -#define BT_APPEARANCE_VEHICLE_LIGHT 0x08C8 /* Light Vehicle */ -#define BT_APPEARANCE_VEHICLE_QUAD_BIKE 0x08C9 /* Quad Bike */ -#define BT_APPEARANCE_VEHICLE_MINIBUS 0x08CA /* Minibus */ -#define BT_APPEARANCE_VEHICLE_BUS 0x08CB /* Bus */ -#define BT_APPEARANCE_VEHICLE_TROLLEY 0x08CC /* Trolley */ -#define BT_APPEARANCE_VEHICLE_AGRICULTURAL 0x08CD /* Agricultural Vehicle */ -#define BT_APPEARANCE_VEHICLE_CAMPER_OR_CARAVAN 0x08CE /* Camper/Caravan */ -#define BT_APPEARANCE_VEHICLE_RECREATIONAL 0x08CF /* Recreational Vehicle/Motor Home */ -#define BT_APPEARANCE_GENERIC_DOMESTIC_APPLIANCE 0x0900 /* Generic Domestic Appliance */ -#define BT_APPEARANCE_APPLIANCE_REFRIGERATOR 0x0901 /* Refrigerator */ -#define BT_APPEARANCE_APPLIANCE_FREEZER 0x0902 /* Freezer */ -#define BT_APPEARANCE_APPLIANCE_OVEN 0x0903 /* Oven */ -#define BT_APPEARANCE_APPLIANCE_MICROWAVE 0x0904 /* Microwave */ -#define BT_APPEARANCE_APPLIANCE_TOASTER 0x0905 /* Toaster */ -#define BT_APPEARANCE_APPLIANCE_WASHING_MACHINE 0x0906 /* Washing Machine */ -#define BT_APPEARANCE_APPLIANCE_DRYER 0x0907 /* Dryer */ -#define BT_APPEARANCE_APPLIANCE_COFFEE_MAKER 0x0908 /* Coffee maker */ -#define BT_APPEARANCE_APPLIANCE_CLOTHES_IRON 0x0909 /* Clothes iron */ -#define BT_APPEARANCE_APPLIANCE_CURLING_IRON 0x090A /* Curling iron */ -#define BT_APPEARANCE_APPLIANCE_HAIR_DRYER 0x090B /* Hair dryer */ -#define BT_APPEARANCE_APPLIANCE_VACUUM_CLEANER 0x090C /* Vacuum cleaner */ -#define BT_APPEARANCE_APPLIANCE_ROBOTIC_VACUUM_CLEANER 0x090D /* Robotic vacuum cleaner */ -#define BT_APPEARANCE_APPLIANCE_RICE_COOKER 0x090E /* Rice cooker */ -#define BT_APPEARANCE_APPLIANCE_CLOTHES_STEAMER 0x090F /* Clothes steamer */ -#define BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940 /* Generic Wearable Audio Device */ -#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941 /* Earbud */ -#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942 /* Headset */ -#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943 /* Headphones */ -#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944 /* Neck Band */ -#define BT_APPEARANCE_GENERIC_AIRCRAFT 0x0980 /* Generic Aircraft */ -#define BT_APPEARANCE_AIRCRAFT_LIGHT 0x0981 /* Light Aircraft */ -#define BT_APPEARANCE_AIRCRAFT_MICROLIGHT 0x0982 /* Microlight */ -#define BT_APPEARANCE_AIRCRAFT_PARAGLIDER 0x0983 /* Paraglider */ -#define BT_APPEARANCE_AIRCRAFT_LARGE_PASSENGER 0x0984 /* Large Passenger Aircraft */ -#define BT_APPEARANCE_GENERIC_AV_EQUIPMENT 0x09C0 /* Generic AV Equipment */ -#define BT_APPEARANCE_AV_EQUIPMENT_AMPLIFIER 0x09C1 /* Amplifier */ -#define BT_APPEARANCE_AV_EQUIPMENT_RECEIVER 0x09C2 /* Receiver */ -#define BT_APPEARANCE_AV_EQUIPMENT_RADIO 0x09C3 /* Radio */ -#define BT_APPEARANCE_AV_EQUIPMENT_TUNER 0x09C4 /* Tuner */ -#define BT_APPEARANCE_AV_EQUIPMENT_TURNTABLE 0x09C5 /* Turntable */ -#define BT_APPEARANCE_AV_EQUIPMENT_CD_PLAYER 0x09C6 /* CD Player */ -#define BT_APPEARANCE_AV_EQUIPMENT_DVD_PLAYER 0x09C7 /* DVD Player */ -#define BT_APPEARANCE_AV_EQUIPMENT_BLURAY_PLAYER 0x09C8 /* Bluray Player */ -#define BT_APPEARANCE_AV_EQUIPMENT_OPTICAL_DISC_PLAYER 0x09C9 /* Optical Disc Player */ -#define BT_APPEARANCE_AV_EQUIPMENT_SET_TOP_BOX 0x09CA /* Set-Top Box */ -#define BT_APPEARANCE_GENERIC_DISPLAY_EQUIPMENT 0x0A00 /* Generic Display Equipment */ -#define BT_APPEARANCE_DISPLAY_EQUIPMENT_TELEVISION 0x0A01 /* Television */ -#define BT_APPEARANCE_DISPLAY_EQUIPMENT_MONITOR 0x0A02 /* Monitor */ -#define BT_APPEARANCE_DISPLAY_EQUIPMENT_PROJECTOR 0x0A03 /* Projector */ -#define BT_APPEARANCE_GENERIC_HEARING_AID 0x0A40 /* Generic Hearing aid */ -#define BT_APPEARANCE_HEARING_AID_IN_EAR 0x0A41 /* In-ear hearing aid */ -#define BT_APPEARANCE_HEARING_AID_BEHIND_EAR 0x0A42 /* Behind-ear hearing aid */ -#define BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT 0x0A43 /* Cochlear Implant */ -#define BT_APPEARANCE_GENERIC_GAMING 0x0A80 /* Generic Gaming */ -#define BT_APPEARANCE_HOME_VIDEO_GAME_CONSOLE 0x0A81 /* Home Video Game Console */ -#define BT_APPEARANCE_PORTABLE_HANDHELD_CONSOLE 0x0A82 /* Portable handheld console */ -#define BT_APPEARANCE_GENERIC_SIGNAGE 0x0AC0 /* Generic Signage */ -#define BT_APPEARANCE_SIGNAGE_DIGITAL 0x0AC1 /* Digital Signage */ -#define BT_APPEARANCE_SIGNAGE_ELECTRONIC_LABEL 0x0AC2 /* Electronic Label */ -#define BT_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 /* Generic Pulse Oximeter */ -#define BT_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 /* Fingertip Pulse Oximeter */ -#define BT_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 /* Wrist Worn Pulse Oximeter */ -#define BT_APPEARANCE_GENERIC_WEIGHT_SCALE 0x0C80 /* Generic Weight Scale */ -#define BT_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0 /* Generic Personal Mobility Device */ -#define BT_APPEARANCE_MOBILITY_POWERED_WHEELCHAIR 0x0CC1 /* Powered Wheelchair */ -#define BT_APPEARANCE_MOBILITY_SCOOTER 0x0CC2 /* Mobility Scooter */ -#define BT_APPEARANCE_CONTINUOUS_GLUCOSE_MONITOR 0x0D00 /* Continuous Glucose Monitor */ -#define BT_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40 /* Generic Insulin Pump */ -#define BT_APPEARANCE_INSULIN_PUMP_DURABLE 0x0D41 /* Insulin Pump, durable pump */ -#define BT_APPEARANCE_INSULIN_PUMP_PATCH 0x0D44 /* Insulin Pump, patch pump */ -#define BT_APPEARANCE_INSULIN_PEN 0x0D48 /* Insulin Pen */ -#define BT_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80 /* Generic Medication Delivery */ -#define BT_APPEARANCE_GENERIC_SPIROMETER 0x0DC0 /* Generic Spirometer */ -#define BT_APPEARANCE_SPIROMETER_HANDHELD 0x0DC1 /* Handheld Spirometer */ -#define BT_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 /* Generic Outdoor Sports Activity */ -#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 /* Location Display */ -#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 /* Location and Navigation Display */ -#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 /* Location Pod */ -#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 /* Location and Navigation Pod */ - -/* Defined GAP timers */ +/* Generic Unknown */ +#define BT_APPEARANCE_UNKNOWN 0x0000 +/* Generic Phone */ +#define BT_APPEARANCE_GENERIC_PHONE 0x0040 +/* Generic Computer */ +#define BT_APPEARANCE_GENERIC_COMPUTER 0x0080 +/* Desktop Workstation */ +#define BT_APPEARANCE_COMPUTER_DESKTOP_WORKSTATION 0x0081 +/* Server-class Computer */ +#define BT_APPEARANCE_COMPUTER_SERVER_CLASS 0x0082 +/* Laptop */ +#define BT_APPEARANCE_COMPUTER_LAPTOP 0x0083 +/* Handheld PC/PDA (clamshell) */ +#define BT_APPEARANCE_COMPUTER_HANDHELD_PCPDA 0x0084 +/* Palm­size PC/PDA */ +#define BT_APPEARANCE_COMPUTER_PALMSIZE_PCPDA 0x0085 +/* Wearable computer (watch size) */ +#define BT_APPEARANCE_COMPUTER_WEARABLE_COMPUTER 0x0086 +/* Tablet */ +#define BT_APPEARANCE_COMPUTER_TABLET 0x0087 +/* Docking Station */ +#define BT_APPEARANCE_COMPUTER_DOCKING_STATION 0x0088 +/* All in One */ +#define BT_APPEARANCE_COMPUTER_ALL_IN_ONE 0x0089 +/* Blade Server */ +#define BT_APPEARANCE_COMPUTER_BLADE_SERVER 0x008A +/* Convertible */ +#define BT_APPEARANCE_COMPUTER_CONVERTIBLE 0x008B +/* Detachable */ +#define BT_APPEARANCE_COMPUTER_DETACHABLE 0x008C +/* IoT Gateway */ +#define BT_APPEARANCE_COMPUTER_IOT_GATEWAY 0x008D +/* Mini PC */ +#define BT_APPEARANCE_COMPUTER_MINI_PC 0x008E +/* Stick PC */ +#define BT_APPEARANCE_COMPUTER_STICK_PC 0x008F +/* Generic Watch */ +#define BT_APPEARANCE_GENERIC_WATCH 0x00C0 +/* Sports Watch */ +#define BT_APPEARANCE_SPORTS_WATCH 0x00C1 +/* Smartwatch */ +#define BT_APPEARANCE_SMARTWATCH 0x00C2 +/* Generic Clock */ +#define BT_APPEARANCE_GENERIC_CLOCK 0x0100 +/* Generic Display */ +#define BT_APPEARANCE_GENERIC_DISPLAY 0x0140 +/* Generic Remote Control */ +#define BT_APPEARANCE_GENERIC_REMOTE 0x0180 +/* Generic Eye-glasses */ +#define BT_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 +/* Generic Tag */ +#define BT_APPEARANCE_GENERIC_TAG 0x0200 +/* Generic Keyring */ +#define BT_APPEARANCE_GENERIC_KEYRING 0x0240 +/* Generic Media Player */ +#define BT_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 +/* Generic Barcode Scanner */ +#define BT_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 +/* Generic Thermometer */ +#define BT_APPEARANCE_GENERIC_THERMOMETER 0x0300 +/* Ear Thermometer */ +#define BT_APPEARANCE_THERMOMETER_EAR 0x0301 +/* Generic Heart Rate Sensor */ +#define BT_APPEARANCE_GENERIC_HEART_RATE 0x0340 +/* Heart Rate Belt */ +#define BT_APPEARANCE_HEART_RATE_BELT 0x0341 +/* Generic Blood Pressure */ +#define BT_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 +/* Arm Blood Pressure */ +#define BT_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 +/* Wrist Blood Pressure */ +#define BT_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 +/* Generic Human Interface Device */ +#define BT_APPEARANCE_GENERIC_HID 0x03C0 +/* Keyboard */ +#define BT_APPEARANCE_HID_KEYBOARD 0x03C1 +/* Mouse */ +#define BT_APPEARANCE_HID_MOUSE 0x03C2 +/* Joystick */ +#define BT_APPEARANCE_HID_JOYSTICK 0x03C3 +/* Gamepad */ +#define BT_APPEARANCE_HID_GAMEPAD 0x03C4 +/* Digitizer Tablet */ +#define BT_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 +/* Card Reader */ +#define BT_APPEARANCE_HID_CARD_READER 0x03C6 +/* Digital Pen */ +#define BT_APPEARANCE_HID_DIGITAL_PEN 0x03C7 +/* Barcode Scanner */ +#define BT_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 +/* Touchpad */ +#define BT_APPEARANCE_HID_TOUCHPAD 0x03C9 +/* Presentation Remote */ +#define BT_APPEARANCE_HID_PRESENTATION_REMOTE 0x03CA +/* Generic Glucose Meter */ +#define BT_APPEARANCE_GENERIC_GLUCOSE 0x0400 +/* Generic Running Walking Sensor */ +#define BT_APPEARANCE_GENERIC_WALKING 0x0440 +/* In-Shoe Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_IN_SHOE 0x0441 +/* On-Shoe Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_ON_SHOE 0x0442 +/* On-Hip Running Walking Sensor */ +#define BT_APPEARANCE_WALKING_ON_HIP 0x0443 +/* Generic Cycling */ +#define BT_APPEARANCE_GENERIC_CYCLING 0x0480 +/* Cycling Computer */ +#define BT_APPEARANCE_CYCLING_COMPUTER 0x0481 +/* Speed Sensor */ +#define BT_APPEARANCE_CYCLING_SPEED 0x0482 +/* Cadence Sensor */ +#define BT_APPEARANCE_CYCLING_CADENCE 0x0483 +/* Power Sensor */ +#define BT_APPEARANCE_CYCLING_POWER 0x0484 +/* Speed and Cadence Sensor */ +#define BT_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 +/* Generic Control Device */ +#define BT_APPEARANCE_GENERIC_CONTROL_DEVICE 0x04C0 +/* Switch */ +#define BT_APPEARANCE_CONTROL_SWITCH 0x04C1 +/* Multi-switch */ +#define BT_APPEARANCE_CONTROL_MULTI_SWITCH 0x04C2 +/* Button */ +#define BT_APPEARANCE_CONTROL_BUTTON 0x04C3 +/* Slider */ +#define BT_APPEARANCE_CONTROL_SLIDER 0x04C4 +/* Rotary Switch */ +#define BT_APPEARANCE_CONTROL_ROTARY_SWITCH 0x04C5 +/* Touch Panel */ +#define BT_APPEARANCE_CONTROL_TOUCH_PANEL 0x04C6 +/* Single Switch */ +#define BT_APPEARANCE_CONTROL_SINGLE_SWITCH 0x04C7 +/* Double Switch */ +#define BT_APPEARANCE_CONTROL_DOUBLE_SWITCH 0x04C8 +/* Triple Switch */ +#define BT_APPEARANCE_CONTROL_TRIPLE_SWITCH 0x04C9 +/* Battery Switch */ +#define BT_APPEARANCE_CONTROL_BATTERY_SWITCH 0x04CA +/* Energy Harvesting Switch */ +#define BT_APPEARANCE_CONTROL_ENERGY_HARVESTING_SWITCH 0x04CB +/* Push Button */ +#define BT_APPEARANCE_CONTROL_PUSH_BUTTON 0x04CC +/* Generic Network Device */ +#define BT_APPEARANCE_GENERIC_NETWORK_DEVICE 0x0500 +/* Access Point */ +#define BT_APPEARANCE_NETWORK_ACCESS_POINT 0x0501 +/* Mesh Device */ +#define BT_APPEARANCE_NETWORK_MESH_DEVICE 0x0502 +/* Mesh Network Proxy */ +#define BT_APPEARANCE_NETWORK_MESH_PROXY 0x0503 +/* Generic Sensor */ +#define BT_APPEARANCE_GENERIC_SENSOR 0x0540 +/* Motion Sensor */ +#define BT_APPEARANCE_SENSOR_MOTION 0x0541 +/* Air quality Sensor */ +#define BT_APPEARANCE_SENSOR_AIR_QUALITY 0x0542 +/* Temperature Sensor */ +#define BT_APPEARANCE_SENSOR_TEMPERATURE 0x0543 +/* Humidity Sensor */ +#define BT_APPEARANCE_SENSOR_HUMIDITY 0x0544 +/* Leak Sensor */ +#define BT_APPEARANCE_SENSOR_LEAK 0x0545 +/* Smoke Sensor */ +#define BT_APPEARANCE_SENSOR_SMOKE 0x0546 +/* Occupancy Sensor */ +#define BT_APPEARANCE_SENSOR_OCCUPANCY 0x0547 +/* Contact Sensor */ +#define BT_APPEARANCE_SENSOR_CONTACT 0x0548 +/* Carbon Monoxide Sensor */ +#define BT_APPEARANCE_SENSOR_CARBON_MONOXIDE 0x0549 +/* Carbon Dioxide Sensor */ +#define BT_APPEARANCE_SENSOR_CARBON_DIOXIDE 0x054A +/* Ambient Light Sensor */ +#define BT_APPEARANCE_SENSOR_AMBIENT_LIGHT 0x054B +/* Energy Sensor */ +#define BT_APPEARANCE_SENSOR_ENERGY 0x054C +/* Color Light Sensor */ +#define BT_APPEARANCE_SENSOR_COLOR_LIGHT 0x054D +/* Rain Sensor */ +#define BT_APPEARANCE_SENSOR_RAIN 0x054E +/* Fire Sensor */ +#define BT_APPEARANCE_SENSOR_FIRE 0x054F +/* Wind Sensor */ +#define BT_APPEARANCE_SENSOR_WIND 0x0550 +/* Proximity Sensor */ +#define BT_APPEARANCE_SENSOR_PROXIMITY 0x0551 +/* Multi-Sensor */ +#define BT_APPEARANCE_SENSOR_MULTI 0x0552 +/* Flush Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_FLUSH_MOUNTED 0x0553 +/* Ceiling Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_CEILING_MOUNTED 0x0554 +/* Wall Mounted Sensor */ +#define BT_APPEARANCE_SENSOR_WALL_MOUNTED 0x0555 +/* Multisensor */ +#define BT_APPEARANCE_MULTISENSOR 0x0556 +/* Energy Meter */ +#define BT_APPEARANCE_SENSOR_ENERGY_METER 0x0557 +/* Flame Detector */ +#define BT_APPEARANCE_SENSOR_FLAME_DETECTOR 0x0558 +/* Vehicle Tire Pressure Sensor */ +#define BT_APPEARANCE_SENSOR_VEHICLE_TIRE_PRESSURE 0x0559 +/* Generic Light Fixtures */ +#define BT_APPEARANCE_GENERIC_LIGHT_FIXTURES 0x0580 +/* Wall Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_WALL 0x0581 +/* Ceiling Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CEILING 0x0582 +/* Floor Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOR 0x0583 +/* Cabinet Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CABINET 0x0584 +/* Desk Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_DESK 0x0585 +/* Troffer Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_TROFFER 0x0586 +/* Pendant Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_PENDANT 0x0587 +/* In-ground Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_IN_GROUND 0x0588 +/* Flood Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_FLOOD 0x0589 +/* Underwater Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_UNDERWATER 0x058A +/* Bollard with Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BOLLARD_WITH 0x058B +/* Pathway Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_PATHWAY 0x058C +/* Garden Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_GARDEN 0x058D +/* Pole-top Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_POLE_TOP 0x058E +/* Spotlight */ +#define BT_APPEARANCE_SPOT_LIGHT 0x058F +/* Linear Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_LINEAR 0x0590 +/* Street Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_STREET 0x0591 +/* Shelves Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_SHELVES 0x0592 +/* Bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BAY 0x0593 +/* Emergency Exit Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_EMERGENCY_EXIT 0x0594 +/* Light Controller */ +#define BT_APPEARANCE_LIGHT_FIXTURES_CONTROLLER 0x0595 +/* Light Driver */ +#define BT_APPEARANCE_LIGHT_FIXTURES_DRIVER 0x0596 +/* Bulb */ +#define BT_APPEARANCE_LIGHT_FIXTURES_BULB 0x0597 +/* Low-bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_LOW_BAY 0x0598 +/* High-bay Light */ +#define BT_APPEARANCE_LIGHT_FIXTURES_HIGH_BAY 0x0599 +/* Generic Fan */ +#define BT_APPEARANCE_GENERIC_FAN 0x05C0 +/* Ceiling Fan */ +#define BT_APPEARANCE_FAN_CEILING 0x05C1 +/* Axial Fan */ +#define BT_APPEARANCE_FAN_AXIAL 0x05C2 +/* Exhaust Fan */ +#define BT_APPEARANCE_FAN_EXHAUST 0x05C3 +/* Pedestal Fan */ +#define BT_APPEARANCE_FAN_PEDESTAL 0x05C4 +/* Desk Fan */ +#define BT_APPEARANCE_FAN_DESK 0x05C5 +/* Wall Fan */ +#define BT_APPEARANCE_FAN_WALL 0x05C6 +/* Generic HVAC */ +#define BT_APPEARANCE_GENERIC_HVAC 0x0600 +/* Thermostat */ +#define BT_APPEARANCE_HVAC_THERMOSTAT 0x0601 +/* Humidifier */ +#define BT_APPEARANCE_HVAC_HUMIDIFIER 0x0602 +/* De-humidifier */ +#define BT_APPEARANCE_HVAC_DEHUMIDIFIER 0x0603 +/* Heater */ +#define BT_APPEARANCE_HVAC_HEATER 0x0604 +/* Radiator */ +#define BT_APPEARANCE_HVAC_RADIATOR 0x0605 +/* Boiler */ +#define BT_APPEARANCE_HVAC_BOILER 0x0606 +/* Heat Pump */ +#define BT_APPEARANCE_HVAC_HEAT_PUMP 0x0607 +/* Infrared Heater */ +#define BT_APPEARANCE_HVAC_INFRARED_HEATER 0x0608 +/* Radiant Panel Heater */ +#define BT_APPEARANCE_HVAC_RADIANT_PANEL_HEATER 0x0609 +/* Fan Heater */ +#define BT_APPEARANCE_HVAC_FAN_HEATER 0x060A +/* Air Curtain */ +#define BT_APPEARANCE_HVAC_AIR_CURTAIN 0x060B +/* Generic Air Conditioning */ +#define BT_APPEARANCE_GENERIC_AIR_CONDITIONING 0x0640 +/* Generic Humidifier */ +#define BT_APPEARANCE_GENERIC_HUMIDIFIER 0x0680 +/* Generic Heating */ +#define BT_APPEARANCE_GENERIC_HEATING 0x06C0 +/* Radiator */ +#define BT_APPEARANCE_HEATING_RADIATOR 0x06C1 +/* Boiler */ +#define BT_APPEARANCE_HEATING_BOILER 0x06C2 +/* Heat Pump */ +#define BT_APPEARANCE_HEATING_HEAT_PUMP 0x06C3 +/* Infrared Heater */ +#define BT_APPEARANCE_HEATING_INFRARED_HEATER 0x06C4 +/* Radiant Panel Heater */ +#define BT_APPEARANCE_HEATING_RADIANT_PANEL_HEATER 0x06C5 +/* Fan Heater */ +#define BT_APPEARANCE_HEATING_FAN_HEATER 0x06C6 +/* Air Curtain */ +#define BT_APPEARANCE_HEATING_AIR_CURTAIN 0x06C7 +/* Generic Access Control */ +#define BT_APPEARANCE_GENERIC_ACCESS_CONTROL 0x0700 +/* Access Door */ +#define BT_APPEARANCE_CONTROL_ACCESS_DOOR 0x0701 +/* Garage Door */ +#define BT_APPEARANCE_CONTROL_GARAGE_DOOR 0x0702 +/* Emergency Exit Door */ +#define BT_APPEARANCE_CONTROL_EMERGENCY_EXIT_DOOR 0x0703 +/* Access Lock */ +#define BT_APPEARANCE_CONTROL_ACCESS_LOCK 0x0704 +/* Elevator */ +#define BT_APPEARANCE_CONTROL_ELEVATOR 0x0705 +/* Window */ +#define BT_APPEARANCE_CONTROL_WINDOW 0x0706 +/* Entrance Gate */ +#define BT_APPEARANCE_CONTROL_ENTRANCE_GATE 0x0707 +/* Door Lock */ +#define BT_APPEARANCE_CONTROL_DOOR_LOCK 0x0708 +/* Locker */ +#define BT_APPEARANCE_CONTROL_LOCKER 0x0709 +/* Generic Motorized Device */ +#define BT_APPEARANCE_GENERIC_MOTORIZED_DEVICE 0x0740 +/* Motorized Gate */ +#define BT_APPEARANCE_MOTORIZED_GATE 0x0741 +/* Awning */ +#define BT_APPEARANCE_MOTORIZED_AWNING 0x0742 +/* Blinds or Shades */ +#define BT_APPEARANCE_MOTORIZED_BLINDS_OR_SHADES 0x0743 +/* Curtains */ +#define BT_APPEARANCE_MOTORIZED_CURTAINS 0x0744 +/* Screen */ +#define BT_APPEARANCE_MOTORIZED_SCREEN 0x0745 +/* Generic Power Device */ +#define BT_APPEARANCE_GENERIC_POWER_DEVICE 0x0780 +/* Power Outlet */ +#define BT_APPEARANCE_POWER_OUTLET 0x0781 +/* Power Strip */ +#define BT_APPEARANCE_POWER_STRIP 0x0782 +/* Plug */ +#define BT_APPEARANCE_POWER_PLUG 0x0783 +/* Power Supply */ +#define BT_APPEARANCE_POWER_SUPPLY 0x0784 +/* LED Driver */ +#define BT_APPEARANCE_POWER_LED_DRIVER 0x0785 +/* Fluorescent Lamp Gear */ +#define BT_APPEARANCE_POWER_FLUORESCENT_LAMP_GEAR 0x0786 +/* HID Lamp Gear */ +#define BT_APPEARANCE_POWER_HID_LAMP_GEAR 0x0787 +/* Charge Case */ +#define BT_APPEARANCE_POWER_CHARGE_CASE 0x0788 +/* Power Bank */ +#define BT_APPEARANCE_POWER_POWER_BANK 0x0789 +/* Generic Light Source */ +#define BT_APPEARANCE_GENERIC_LIGHT_SOURCE 0x07C0 +/* Incandescent Light Bulb */ +#define BT_APPEARANCE_LIGHT_SOURCE_INCANDESCENT_BULB 0x07C1 +/* LED Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_LED_LAMP 0x07C2 +/* HID Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_HID_LAMP 0x07C3 +/* Fluorescent Lamp */ +#define BT_APPEARANCE_LIGHT_SOURCE_FLUORESCENT_LAMP 0x07C4 +/* LED Array */ +#define BT_APPEARANCE_LIGHT_SOURCE_LED_ARRAY 0x07C5 +/* Multi-Color LED Array */ +#define BT_APPEARANCE_LIGHT_SOURCE_MULTICOLOR_LED_ARRAY 0x07C6 +/* Low voltage halogen */ +#define BT_APPEARANCE_LIGHT_SOURCE_LOW_VOLTAGE_HALOGEN 0x07C7 +/* Organic light emitting diode */ +#define BT_APPEARANCE_LIGHT_SOURCE_OLED 0x07C8 +/* Generic Window Covering */ +#define BT_APPEARANCE_GENERIC_WINDOW_COVERING 0x0800 +/* Window Shades */ +#define BT_APPEARANCE_WINDOW_SHADES 0x0801 +/* Window Blinds */ +#define BT_APPEARANCE_WINDOW_BLINDS 0x0802 +/* Window Awning */ +#define BT_APPEARANCE_WINDOW_AWNING 0x0803 +/* Window Curtain */ +#define BT_APPEARANCE_WINDOW_CURTAIN 0x0804 +/* Exterior Shutter */ +#define BT_APPEARANCE_WINDOW_EXTERIOR_SHUTTER 0x0805 +/* Exterior Screen */ +#define BT_APPEARANCE_WINDOW_EXTERIOR_SCREEN 0x0806 +/* Generic Audio Sink */ +#define BT_APPEARANCE_GENERIC_AUDIO_SINK 0x0840 +/* Standalone Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER 0x0841 +/* Soundbar */ +#define BT_APPEARANCE_AUDIO_SINK_SOUNDBAR 0x0842 +/* Bookshelf Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER 0x0843 +/* Standmounted Speaker */ +#define BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER 0x0844 +/* Speakerphone */ +#define BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE 0x0845 +/* Generic Audio Source */ +#define BT_APPEARANCE_GENERIC_AUDIO_SOURCE 0x0880 +/* Microphone */ +#define BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE 0x0881 +/* Alarm */ +#define BT_APPEARANCE_AUDIO_SOURCE_ALARM 0x0882 +/* Bell */ +#define BT_APPEARANCE_AUDIO_SOURCE_BELL 0x0883 +/* Horn */ +#define BT_APPEARANCE_AUDIO_SOURCE_HORN 0x0884 +/* Broadcasting Device */ +#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE 0x0885 +/* Service Desk */ +#define BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK 0x0886 +/* Kiosk */ +#define BT_APPEARANCE_AUDIO_SOURCE_KIOSK 0x0887 +/* Broadcasting Room */ +#define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM 0x0888 +/* Auditorium */ +#define BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM 0x0889 +/* Generic Motorized Vehicle */ +#define BT_APPEARANCE_GENERIC_MOTORIZED_VEHICLE 0x08C0 +/* Car */ +#define BT_APPEARANCE_VEHICLE_CAR 0x08C1 +/* Large Goods Vehicle */ +#define BT_APPEARANCE_VEHICLE_LARGE_GOODS 0x08C2 +/* 2-Wheeled Vehicle */ +#define BT_APPEARANCE_VEHICLE_TWO_WHEELED 0x08C3 +/* Motorbike */ +#define BT_APPEARANCE_VEHICLE_MOTORBIKE 0x08C4 +/* Scooter */ +#define BT_APPEARANCE_VEHICLE_SCOOTER 0x08C5 +/* Moped */ +#define BT_APPEARANCE_VEHICLE_MOPED 0x08C6 +/* 3-Wheeled Vehicle */ +#define BT_APPEARANCE_VEHICLE_THREE_WHEELED 0x08C7 +/* Light Vehicle */ +#define BT_APPEARANCE_VEHICLE_LIGHT 0x08C8 +/* Quad Bike */ +#define BT_APPEARANCE_VEHICLE_QUAD_BIKE 0x08C9 +/* Minibus */ +#define BT_APPEARANCE_VEHICLE_MINIBUS 0x08CA +/* Bus */ +#define BT_APPEARANCE_VEHICLE_BUS 0x08CB +/* Trolley */ +#define BT_APPEARANCE_VEHICLE_TROLLEY 0x08CC +/* Agricultural Vehicle */ +#define BT_APPEARANCE_VEHICLE_AGRICULTURAL 0x08CD +/* Camper/Caravan */ +#define BT_APPEARANCE_VEHICLE_CAMPER_OR_CARAVAN 0x08CE +/* Recreational Vehicle/Motor Home */ +#define BT_APPEARANCE_VEHICLE_RECREATIONAL 0x08CF +/* Generic Domestic Appliance */ +#define BT_APPEARANCE_GENERIC_DOMESTIC_APPLIANCE 0x0900 +/* Refrigerator */ +#define BT_APPEARANCE_APPLIANCE_REFRIGERATOR 0x0901 +/* Freezer */ +#define BT_APPEARANCE_APPLIANCE_FREEZER 0x0902 +/* Oven */ +#define BT_APPEARANCE_APPLIANCE_OVEN 0x0903 +/* Microwave */ +#define BT_APPEARANCE_APPLIANCE_MICROWAVE 0x0904 +/* Toaster */ +#define BT_APPEARANCE_APPLIANCE_TOASTER 0x0905 +/* Washing Machine */ +#define BT_APPEARANCE_APPLIANCE_WASHING_MACHINE 0x0906 +/* Dryer */ +#define BT_APPEARANCE_APPLIANCE_DRYER 0x0907 +/* Coffee maker */ +#define BT_APPEARANCE_APPLIANCE_COFFEE_MAKER 0x0908 +/* Clothes iron */ +#define BT_APPEARANCE_APPLIANCE_CLOTHES_IRON 0x0909 +/* Curling iron */ +#define BT_APPEARANCE_APPLIANCE_CURLING_IRON 0x090A +/* Hair dryer */ +#define BT_APPEARANCE_APPLIANCE_HAIR_DRYER 0x090B +/* Vacuum cleaner */ +#define BT_APPEARANCE_APPLIANCE_VACUUM_CLEANER 0x090C +/* Robotic vacuum cleaner */ +#define BT_APPEARANCE_APPLIANCE_ROBOTIC_VACUUM_CLEANER 0x090D +/* Rice cooker */ +#define BT_APPEARANCE_APPLIANCE_RICE_COOKER 0x090E +/* Clothes steamer */ +#define BT_APPEARANCE_APPLIANCE_CLOTHES_STEAMER 0x090F +/* Generic Wearable Audio Device */ +#define BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940 +/* Earbud */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941 +/* Headset */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942 +/* Headphones */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943 +/* Neck Band */ +#define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944 +/* Generic Aircraft */ +#define BT_APPEARANCE_GENERIC_AIRCRAFT 0x0980 +/* Light Aircraft */ +#define BT_APPEARANCE_AIRCRAFT_LIGHT 0x0981 +/* Microlight */ +#define BT_APPEARANCE_AIRCRAFT_MICROLIGHT 0x0982 +/* Paraglider */ +#define BT_APPEARANCE_AIRCRAFT_PARAGLIDER 0x0983 +/* Large Passenger Aircraft */ +#define BT_APPEARANCE_AIRCRAFT_LARGE_PASSENGER 0x0984 +/* Generic AV Equipment */ +#define BT_APPEARANCE_GENERIC_AV_EQUIPMENT 0x09C0 +/* Amplifier */ +#define BT_APPEARANCE_AV_EQUIPMENT_AMPLIFIER 0x09C1 +/* Receiver */ +#define BT_APPEARANCE_AV_EQUIPMENT_RECEIVER 0x09C2 +/* Radio */ +#define BT_APPEARANCE_AV_EQUIPMENT_RADIO 0x09C3 +/* Tuner */ +#define BT_APPEARANCE_AV_EQUIPMENT_TUNER 0x09C4 +/* Turntable */ +#define BT_APPEARANCE_AV_EQUIPMENT_TURNTABLE 0x09C5 +/* CD Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_CD_PLAYER 0x09C6 +/* DVD Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_DVD_PLAYER 0x09C7 +/* Bluray Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_BLURAY_PLAYER 0x09C8 +/* Optical Disc Player */ +#define BT_APPEARANCE_AV_EQUIPMENT_OPTICAL_DISC_PLAYER 0x09C9 +/* Set-Top Box */ +#define BT_APPEARANCE_AV_EQUIPMENT_SET_TOP_BOX 0x09CA +/* Generic Display Equipment */ +#define BT_APPEARANCE_GENERIC_DISPLAY_EQUIPMENT 0x0A00 +/* Television */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_TELEVISION 0x0A01 +/* Monitor */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_MONITOR 0x0A02 +/* Projector */ +#define BT_APPEARANCE_DISPLAY_EQUIPMENT_PROJECTOR 0x0A03 +/* Generic Hearing aid */ +#define BT_APPEARANCE_GENERIC_HEARING_AID 0x0A40 +/* In-ear hearing aid */ +#define BT_APPEARANCE_HEARING_AID_IN_EAR 0x0A41 +/* Behind-ear hearing aid */ +#define BT_APPEARANCE_HEARING_AID_BEHIND_EAR 0x0A42 +/* Cochlear Implant */ +#define BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT 0x0A43 +/* Generic Gaming */ +#define BT_APPEARANCE_GENERIC_GAMING 0x0A80 +/* Home Video Game Console */ +#define BT_APPEARANCE_HOME_VIDEO_GAME_CONSOLE 0x0A81 +/* Portable handheld console */ +#define BT_APPEARANCE_PORTABLE_HANDHELD_CONSOLE 0x0A82 +/* Generic Signage */ +#define BT_APPEARANCE_GENERIC_SIGNAGE 0x0AC0 +/* Digital Signage */ +#define BT_APPEARANCE_SIGNAGE_DIGITAL 0x0AC1 +/* Electronic Label */ +#define BT_APPEARANCE_SIGNAGE_ELECTRONIC_LABEL 0x0AC2 +/* Generic Pulse Oximeter */ +#define BT_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 +/* Fingertip Pulse Oximeter */ +#define BT_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 +/* Wrist Worn Pulse Oximeter */ +#define BT_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 +/* Generic Weight Scale */ +#define BT_APPEARANCE_GENERIC_WEIGHT_SCALE 0x0C80 +/* Generic Personal Mobility Device */ +#define BT_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0 +/* Powered Wheelchair */ +#define BT_APPEARANCE_MOBILITY_POWERED_WHEELCHAIR 0x0CC1 +/* Mobility Scooter */ +#define BT_APPEARANCE_MOBILITY_SCOOTER 0x0CC2 +/* Continuous Glucose Monitor */ +#define BT_APPEARANCE_CONTINUOUS_GLUCOSE_MONITOR 0x0D00 +/* Generic Insulin Pump */ +#define BT_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40 +/* Insulin Pump, durable pump */ +#define BT_APPEARANCE_INSULIN_PUMP_DURABLE 0x0D41 +/* Insulin Pump, patch pump */ +#define BT_APPEARANCE_INSULIN_PUMP_PATCH 0x0D44 +/* Insulin Pen */ +#define BT_APPEARANCE_INSULIN_PEN 0x0D48 +/* Generic Medication Delivery */ +#define BT_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80 +/* Generic Spirometer */ +#define BT_APPEARANCE_GENERIC_SPIROMETER 0x0DC0 +/* Handheld Spirometer */ +#define BT_APPEARANCE_SPIROMETER_HANDHELD 0x0DC1 +/* Generic Outdoor Sports Activity */ +#define BT_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 +/* Location Display */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 +/* Location and Navigation Display */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 +/* Location Pod */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 +/* Location and Navigation Pod */ +#define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 + +/** #define BT_GAP_SCAN_FAST_INTERVAL 0x0060 /* 60 ms */ #define BT_GAP_SCAN_FAST_WINDOW 0x0030 /* 30 ms */ #define BT_GAP_SCAN_SLOW_INTERVAL_1 0x0800 /* 1.28 s */ From c3d515755d6e4e5ab73038dd3e4866978ba3dae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 11:53:07 +0200 Subject: [PATCH 1525/2042] bluetooth: doc: Fix gap.h Doxygen documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make #defines properly Doxygen-documented, add some named groups, and add a few missing comments to some #defines. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/gap.h | 776 +++++++++++++++++---------------- 1 file changed, 406 insertions(+), 370 deletions(-) diff --git a/include/zephyr/bluetooth/gap.h b/include/zephyr/bluetooth/gap.h index 90b17e958da0..02fa8878c6b1 100644 --- a/include/zephyr/bluetooth/gap.h +++ b/include/zephyr/bluetooth/gap.h @@ -25,666 +25,689 @@ extern "C" { * @{ */ -/** Company Identifiers (see Bluetooth Assigned Numbers) */ -#define BT_COMP_ID_LF 0x05f1 /* The Linux Foundation */ - -/** EIR/AD data type definitions */ -#define BT_DATA_FLAGS 0x01 /* AD flags */ -#define BT_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */ -#define BT_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ -#define BT_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */ -#define BT_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ -#define BT_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */ -#define BT_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ -#define BT_DATA_NAME_SHORTENED 0x08 /* Shortened name */ -#define BT_DATA_NAME_COMPLETE 0x09 /* Complete name */ -#define BT_DATA_TX_POWER 0x0a /* Tx Power */ -#define BT_DATA_SM_TK_VALUE 0x10 /* Security Manager TK Value */ -#define BT_DATA_SM_OOB_FLAGS 0x11 /* Security Manager OOB Flags */ -#define BT_DATA_PERIPHERAL_INT_RANGE 0x12 /* Peripheral Connection Interval Range */ -#define BT_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */ -#define BT_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */ -#define BT_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */ -#define BT_DATA_PUB_TARGET_ADDR 0x17 /* Public Target Address */ -#define BT_DATA_RAND_TARGET_ADDR 0x18 /* Random Target Address */ -#define BT_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */ -#define BT_DATA_ADV_INT 0x1a /* Advertising Interval */ -#define BT_DATA_LE_BT_DEVICE_ADDRESS 0x1b /* LE Bluetooth Device Address */ -#define BT_DATA_LE_ROLE 0x1c /* LE Role */ -#define BT_DATA_SIMPLE_PAIRING_HASH 0x1d /* Simple Pairing Hash C256 */ -#define BT_DATA_SIMPLE_PAIRING_RAND 0x1e /* Simple Pairing Randomizer R256 */ -#define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ -#define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ -#define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ -#define BT_DATA_LE_SC_CONFIRM_VALUE 0x22 /* LE SC Confirmation Value */ -#define BT_DATA_LE_SC_RANDOM_VALUE 0x23 /* LE SC Random Value */ -#define BT_DATA_URI 0x24 /* URI */ -#define BT_DATA_INDOOR_POS 0x25 /* Indoor Positioning */ -#define BT_DATA_TRANS_DISCOVER_DATA 0x26 /* Transport Discovery Data */ -#define BT_DATA_LE_SUPPORTED_FEATURES 0x27 /* LE Supported Features */ -#define BT_DATA_CHANNEL_MAP_UPDATE_IND 0x28 /* Channel Map Update Indication */ -#define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */ -#define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */ -#define BT_DATA_MESH_BEACON 0x2b /* Mesh Beacon */ -#define BT_DATA_BIG_INFO 0x2c /* BIGInfo */ -#define BT_DATA_BROADCAST_CODE 0x2d /* Broadcast Code */ -#define BT_DATA_CSIS_RSI 0x2e /* CSIS Random Set ID type */ -#define BT_DATA_ADV_INT_LONG 0x2f /* Advertising Interval long */ -#define BT_DATA_BROADCAST_NAME 0x30 /* Broadcast Name */ -#define BT_DATA_ENCRYPTED_AD_DATA 0x31 /* Encrypted Advertising Data */ -#define BT_DATA_3D_INFO 0x3D /* 3D Information Data */ - -#define BT_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */ - -#define BT_LE_AD_LIMITED 0x01 /* Limited Discoverable */ -#define BT_LE_AD_GENERAL 0x02 /* General Discoverable */ -#define BT_LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */ - -/* Appearance Values Last Modified on 2023-01-05 */ -/* Generic Unknown */ +/** + * @name Company Identifiers (see Bluetooth Assigned Numbers) + * @{ + */ +#define BT_COMP_ID_LF 0x05f1 /**< The Linux Foundation */ +/** + * @} + */ + +/** + * @name EIR/AD data type definitions + * @{ + */ +#define BT_DATA_FLAGS 0x01 /**< AD flags */ +#define BT_DATA_UUID16_SOME 0x02 /**< 16-bit UUID, more available */ +#define BT_DATA_UUID16_ALL 0x03 /**< 16-bit UUID, all listed */ +#define BT_DATA_UUID32_SOME 0x04 /**< 32-bit UUID, more available */ +#define BT_DATA_UUID32_ALL 0x05 /**< 32-bit UUID, all listed */ +#define BT_DATA_UUID128_SOME 0x06 /**< 128-bit UUID, more available */ +#define BT_DATA_UUID128_ALL 0x07 /**< 128-bit UUID, all listed */ +#define BT_DATA_NAME_SHORTENED 0x08 /**< Shortened name */ +#define BT_DATA_NAME_COMPLETE 0x09 /**< Complete name */ +#define BT_DATA_TX_POWER 0x0a /**< Tx Power */ +#define BT_DATA_SM_TK_VALUE 0x10 /**< Security Manager TK Value */ +#define BT_DATA_SM_OOB_FLAGS 0x11 /**< Security Manager OOB Flags */ +#define BT_DATA_PERIPHERAL_INT_RANGE 0x12 /**< Peripheral Connection Interval Range */ +#define BT_DATA_SOLICIT16 0x14 /**< Solicit UUIDs, 16-bit */ +#define BT_DATA_SOLICIT128 0x15 /**< Solicit UUIDs, 128-bit */ +#define BT_DATA_SVC_DATA16 0x16 /**< Service data, 16-bit UUID */ +#define BT_DATA_PUB_TARGET_ADDR 0x17 /**< Public Target Address */ +#define BT_DATA_RAND_TARGET_ADDR 0x18 /**< Random Target Address */ +#define BT_DATA_GAP_APPEARANCE 0x19 /**< GAP appearance */ +#define BT_DATA_ADV_INT 0x1a /**< Advertising Interval */ +#define BT_DATA_LE_BT_DEVICE_ADDRESS 0x1b /**< LE Bluetooth Device Address */ +#define BT_DATA_LE_ROLE 0x1c /**< LE Role */ +#define BT_DATA_SIMPLE_PAIRING_HASH 0x1d /**< Simple Pairing Hash C256 */ +#define BT_DATA_SIMPLE_PAIRING_RAND 0x1e /**< Simple Pairing Randomizer R256 */ +#define BT_DATA_SOLICIT32 0x1f /**< Solicit UUIDs, 32-bit */ +#define BT_DATA_SVC_DATA32 0x20 /**< Service data, 32-bit UUID */ +#define BT_DATA_SVC_DATA128 0x21 /**< Service data, 128-bit UUID */ +#define BT_DATA_LE_SC_CONFIRM_VALUE 0x22 /**< LE SC Confirmation Value */ +#define BT_DATA_LE_SC_RANDOM_VALUE 0x23 /**< LE SC Random Value */ +#define BT_DATA_URI 0x24 /**< URI */ +#define BT_DATA_INDOOR_POS 0x25 /**< Indoor Positioning */ +#define BT_DATA_TRANS_DISCOVER_DATA 0x26 /**< Transport Discovery Data */ +#define BT_DATA_LE_SUPPORTED_FEATURES 0x27 /**< LE Supported Features */ +#define BT_DATA_CHANNEL_MAP_UPDATE_IND 0x28 /**< Channel Map Update Indication */ +#define BT_DATA_MESH_PROV 0x29 /**< Mesh Provisioning PDU */ +#define BT_DATA_MESH_MESSAGE 0x2a /**< Mesh Networking PDU */ +#define BT_DATA_MESH_BEACON 0x2b /**< Mesh Beacon */ +#define BT_DATA_BIG_INFO 0x2c /**< BIGInfo */ +#define BT_DATA_BROADCAST_CODE 0x2d /**< Broadcast Code */ +#define BT_DATA_CSIS_RSI 0x2e /**< CSIS Random Set ID type */ +#define BT_DATA_ADV_INT_LONG 0x2f /**< Advertising Interval long */ +#define BT_DATA_BROADCAST_NAME 0x30 /**< Broadcast Name */ +#define BT_DATA_ENCRYPTED_AD_DATA 0x31 /**< Encrypted Advertising Data */ +#define BT_DATA_3D_INFO 0x3D /**< 3D Information Data */ + +#define BT_DATA_MANUFACTURER_DATA 0xff /**< Manufacturer Specific Data */ + +#define BT_LE_AD_LIMITED 0x01 /**< Limited Discoverable */ +#define BT_LE_AD_GENERAL 0x02 /**< General Discoverable */ +#define BT_LE_AD_NO_BREDR 0x04 /**< BR/EDR not supported */ +/** + * @} + */ + +/** + * @name Appearance Values + * + * Last Modified on 2023-01-05 + * @{ + */ +/** Generic Unknown */ #define BT_APPEARANCE_UNKNOWN 0x0000 -/* Generic Phone */ +/** Generic Phone */ #define BT_APPEARANCE_GENERIC_PHONE 0x0040 -/* Generic Computer */ +/** Generic Computer */ #define BT_APPEARANCE_GENERIC_COMPUTER 0x0080 -/* Desktop Workstation */ +/** Desktop Workstation */ #define BT_APPEARANCE_COMPUTER_DESKTOP_WORKSTATION 0x0081 -/* Server-class Computer */ +/** Server-class Computer */ #define BT_APPEARANCE_COMPUTER_SERVER_CLASS 0x0082 -/* Laptop */ +/** Laptop */ #define BT_APPEARANCE_COMPUTER_LAPTOP 0x0083 -/* Handheld PC/PDA (clamshell) */ +/** Handheld PC/PDA (clamshell) */ #define BT_APPEARANCE_COMPUTER_HANDHELD_PCPDA 0x0084 -/* Palm­size PC/PDA */ +/** Palm­size PC/PDA */ #define BT_APPEARANCE_COMPUTER_PALMSIZE_PCPDA 0x0085 -/* Wearable computer (watch size) */ +/** Wearable computer (watch size) */ #define BT_APPEARANCE_COMPUTER_WEARABLE_COMPUTER 0x0086 -/* Tablet */ +/** Tablet */ #define BT_APPEARANCE_COMPUTER_TABLET 0x0087 -/* Docking Station */ +/** Docking Station */ #define BT_APPEARANCE_COMPUTER_DOCKING_STATION 0x0088 -/* All in One */ +/** All in One */ #define BT_APPEARANCE_COMPUTER_ALL_IN_ONE 0x0089 -/* Blade Server */ +/** Blade Server */ #define BT_APPEARANCE_COMPUTER_BLADE_SERVER 0x008A -/* Convertible */ +/** Convertible */ #define BT_APPEARANCE_COMPUTER_CONVERTIBLE 0x008B -/* Detachable */ +/** Detachable */ #define BT_APPEARANCE_COMPUTER_DETACHABLE 0x008C -/* IoT Gateway */ +/** IoT Gateway */ #define BT_APPEARANCE_COMPUTER_IOT_GATEWAY 0x008D -/* Mini PC */ +/** Mini PC */ #define BT_APPEARANCE_COMPUTER_MINI_PC 0x008E -/* Stick PC */ +/** Stick PC */ #define BT_APPEARANCE_COMPUTER_STICK_PC 0x008F -/* Generic Watch */ +/** Generic Watch */ #define BT_APPEARANCE_GENERIC_WATCH 0x00C0 -/* Sports Watch */ +/** Sports Watch */ #define BT_APPEARANCE_SPORTS_WATCH 0x00C1 -/* Smartwatch */ +/** Smartwatch */ #define BT_APPEARANCE_SMARTWATCH 0x00C2 -/* Generic Clock */ +/** Generic Clock */ #define BT_APPEARANCE_GENERIC_CLOCK 0x0100 -/* Generic Display */ +/** Generic Display */ #define BT_APPEARANCE_GENERIC_DISPLAY 0x0140 -/* Generic Remote Control */ +/** Generic Remote Control */ #define BT_APPEARANCE_GENERIC_REMOTE 0x0180 -/* Generic Eye-glasses */ +/** Generic Eye-glasses */ #define BT_APPEARANCE_GENERIC_EYEGLASSES 0x01C0 -/* Generic Tag */ +/** Generic Tag */ #define BT_APPEARANCE_GENERIC_TAG 0x0200 -/* Generic Keyring */ +/** Generic Keyring */ #define BT_APPEARANCE_GENERIC_KEYRING 0x0240 -/* Generic Media Player */ +/** Generic Media Player */ #define BT_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280 -/* Generic Barcode Scanner */ +/** Generic Barcode Scanner */ #define BT_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0 -/* Generic Thermometer */ +/** Generic Thermometer */ #define BT_APPEARANCE_GENERIC_THERMOMETER 0x0300 -/* Ear Thermometer */ +/** Ear Thermometer */ #define BT_APPEARANCE_THERMOMETER_EAR 0x0301 -/* Generic Heart Rate Sensor */ +/** Generic Heart Rate Sensor */ #define BT_APPEARANCE_GENERIC_HEART_RATE 0x0340 -/* Heart Rate Belt */ +/** Heart Rate Belt */ #define BT_APPEARANCE_HEART_RATE_BELT 0x0341 -/* Generic Blood Pressure */ +/** Generic Blood Pressure */ #define BT_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380 -/* Arm Blood Pressure */ +/** Arm Blood Pressure */ #define BT_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381 -/* Wrist Blood Pressure */ +/** Wrist Blood Pressure */ #define BT_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382 -/* Generic Human Interface Device */ +/** Generic Human Interface Device */ #define BT_APPEARANCE_GENERIC_HID 0x03C0 -/* Keyboard */ +/** Keyboard */ #define BT_APPEARANCE_HID_KEYBOARD 0x03C1 -/* Mouse */ +/** Mouse */ #define BT_APPEARANCE_HID_MOUSE 0x03C2 -/* Joystick */ +/** Joystick */ #define BT_APPEARANCE_HID_JOYSTICK 0x03C3 -/* Gamepad */ +/** Gamepad */ #define BT_APPEARANCE_HID_GAMEPAD 0x03C4 -/* Digitizer Tablet */ +/** Digitizer Tablet */ #define BT_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5 -/* Card Reader */ +/** Card Reader */ #define BT_APPEARANCE_HID_CARD_READER 0x03C6 -/* Digital Pen */ +/** Digital Pen */ #define BT_APPEARANCE_HID_DIGITAL_PEN 0x03C7 -/* Barcode Scanner */ +/** Barcode Scanner */ #define BT_APPEARANCE_HID_BARCODE_SCANNER 0x03C8 -/* Touchpad */ +/** Touchpad */ #define BT_APPEARANCE_HID_TOUCHPAD 0x03C9 -/* Presentation Remote */ +/** Presentation Remote */ #define BT_APPEARANCE_HID_PRESENTATION_REMOTE 0x03CA -/* Generic Glucose Meter */ +/** Generic Glucose Meter */ #define BT_APPEARANCE_GENERIC_GLUCOSE 0x0400 -/* Generic Running Walking Sensor */ +/** Generic Running Walking Sensor */ #define BT_APPEARANCE_GENERIC_WALKING 0x0440 -/* In-Shoe Running Walking Sensor */ +/** In-Shoe Running Walking Sensor */ #define BT_APPEARANCE_WALKING_IN_SHOE 0x0441 -/* On-Shoe Running Walking Sensor */ +/** On-Shoe Running Walking Sensor */ #define BT_APPEARANCE_WALKING_ON_SHOE 0x0442 -/* On-Hip Running Walking Sensor */ +/** On-Hip Running Walking Sensor */ #define BT_APPEARANCE_WALKING_ON_HIP 0x0443 -/* Generic Cycling */ +/** Generic Cycling */ #define BT_APPEARANCE_GENERIC_CYCLING 0x0480 -/* Cycling Computer */ +/** Cycling Computer */ #define BT_APPEARANCE_CYCLING_COMPUTER 0x0481 -/* Speed Sensor */ +/** Speed Sensor */ #define BT_APPEARANCE_CYCLING_SPEED 0x0482 -/* Cadence Sensor */ +/** Cadence Sensor */ #define BT_APPEARANCE_CYCLING_CADENCE 0x0483 -/* Power Sensor */ +/** Power Sensor */ #define BT_APPEARANCE_CYCLING_POWER 0x0484 -/* Speed and Cadence Sensor */ +/** Speed and Cadence Sensor */ #define BT_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485 -/* Generic Control Device */ +/** Generic Control Device */ #define BT_APPEARANCE_GENERIC_CONTROL_DEVICE 0x04C0 -/* Switch */ +/** Switch */ #define BT_APPEARANCE_CONTROL_SWITCH 0x04C1 -/* Multi-switch */ +/** Multi-switch */ #define BT_APPEARANCE_CONTROL_MULTI_SWITCH 0x04C2 -/* Button */ +/** Button */ #define BT_APPEARANCE_CONTROL_BUTTON 0x04C3 -/* Slider */ +/** Slider */ #define BT_APPEARANCE_CONTROL_SLIDER 0x04C4 -/* Rotary Switch */ +/** Rotary Switch */ #define BT_APPEARANCE_CONTROL_ROTARY_SWITCH 0x04C5 -/* Touch Panel */ +/** Touch Panel */ #define BT_APPEARANCE_CONTROL_TOUCH_PANEL 0x04C6 -/* Single Switch */ +/** Single Switch */ #define BT_APPEARANCE_CONTROL_SINGLE_SWITCH 0x04C7 -/* Double Switch */ +/** Double Switch */ #define BT_APPEARANCE_CONTROL_DOUBLE_SWITCH 0x04C8 -/* Triple Switch */ +/** Triple Switch */ #define BT_APPEARANCE_CONTROL_TRIPLE_SWITCH 0x04C9 -/* Battery Switch */ +/** Battery Switch */ #define BT_APPEARANCE_CONTROL_BATTERY_SWITCH 0x04CA -/* Energy Harvesting Switch */ +/** Energy Harvesting Switch */ #define BT_APPEARANCE_CONTROL_ENERGY_HARVESTING_SWITCH 0x04CB -/* Push Button */ +/** Push Button */ #define BT_APPEARANCE_CONTROL_PUSH_BUTTON 0x04CC -/* Generic Network Device */ +/** Generic Network Device */ #define BT_APPEARANCE_GENERIC_NETWORK_DEVICE 0x0500 -/* Access Point */ +/** Access Point */ #define BT_APPEARANCE_NETWORK_ACCESS_POINT 0x0501 -/* Mesh Device */ +/** Mesh Device */ #define BT_APPEARANCE_NETWORK_MESH_DEVICE 0x0502 -/* Mesh Network Proxy */ +/** Mesh Network Proxy */ #define BT_APPEARANCE_NETWORK_MESH_PROXY 0x0503 -/* Generic Sensor */ +/** Generic Sensor */ #define BT_APPEARANCE_GENERIC_SENSOR 0x0540 -/* Motion Sensor */ +/** Motion Sensor */ #define BT_APPEARANCE_SENSOR_MOTION 0x0541 -/* Air quality Sensor */ +/** Air quality Sensor */ #define BT_APPEARANCE_SENSOR_AIR_QUALITY 0x0542 -/* Temperature Sensor */ +/** Temperature Sensor */ #define BT_APPEARANCE_SENSOR_TEMPERATURE 0x0543 -/* Humidity Sensor */ +/** Humidity Sensor */ #define BT_APPEARANCE_SENSOR_HUMIDITY 0x0544 -/* Leak Sensor */ +/** Leak Sensor */ #define BT_APPEARANCE_SENSOR_LEAK 0x0545 -/* Smoke Sensor */ +/** Smoke Sensor */ #define BT_APPEARANCE_SENSOR_SMOKE 0x0546 -/* Occupancy Sensor */ +/** Occupancy Sensor */ #define BT_APPEARANCE_SENSOR_OCCUPANCY 0x0547 -/* Contact Sensor */ +/** Contact Sensor */ #define BT_APPEARANCE_SENSOR_CONTACT 0x0548 -/* Carbon Monoxide Sensor */ +/** Carbon Monoxide Sensor */ #define BT_APPEARANCE_SENSOR_CARBON_MONOXIDE 0x0549 -/* Carbon Dioxide Sensor */ +/** Carbon Dioxide Sensor */ #define BT_APPEARANCE_SENSOR_CARBON_DIOXIDE 0x054A -/* Ambient Light Sensor */ +/** Ambient Light Sensor */ #define BT_APPEARANCE_SENSOR_AMBIENT_LIGHT 0x054B -/* Energy Sensor */ +/** Energy Sensor */ #define BT_APPEARANCE_SENSOR_ENERGY 0x054C -/* Color Light Sensor */ +/** Color Light Sensor */ #define BT_APPEARANCE_SENSOR_COLOR_LIGHT 0x054D -/* Rain Sensor */ +/** Rain Sensor */ #define BT_APPEARANCE_SENSOR_RAIN 0x054E -/* Fire Sensor */ +/** Fire Sensor */ #define BT_APPEARANCE_SENSOR_FIRE 0x054F -/* Wind Sensor */ +/** Wind Sensor */ #define BT_APPEARANCE_SENSOR_WIND 0x0550 -/* Proximity Sensor */ +/** Proximity Sensor */ #define BT_APPEARANCE_SENSOR_PROXIMITY 0x0551 -/* Multi-Sensor */ +/** Multi-Sensor */ #define BT_APPEARANCE_SENSOR_MULTI 0x0552 -/* Flush Mounted Sensor */ +/** Flush Mounted Sensor */ #define BT_APPEARANCE_SENSOR_FLUSH_MOUNTED 0x0553 -/* Ceiling Mounted Sensor */ +/** Ceiling Mounted Sensor */ #define BT_APPEARANCE_SENSOR_CEILING_MOUNTED 0x0554 -/* Wall Mounted Sensor */ +/** Wall Mounted Sensor */ #define BT_APPEARANCE_SENSOR_WALL_MOUNTED 0x0555 -/* Multisensor */ +/** Multisensor */ #define BT_APPEARANCE_MULTISENSOR 0x0556 -/* Energy Meter */ +/** Energy Meter */ #define BT_APPEARANCE_SENSOR_ENERGY_METER 0x0557 -/* Flame Detector */ +/** Flame Detector */ #define BT_APPEARANCE_SENSOR_FLAME_DETECTOR 0x0558 -/* Vehicle Tire Pressure Sensor */ +/** Vehicle Tire Pressure Sensor */ #define BT_APPEARANCE_SENSOR_VEHICLE_TIRE_PRESSURE 0x0559 -/* Generic Light Fixtures */ +/** Generic Light Fixtures */ #define BT_APPEARANCE_GENERIC_LIGHT_FIXTURES 0x0580 -/* Wall Light */ +/** Wall Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_WALL 0x0581 -/* Ceiling Light */ +/** Ceiling Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_CEILING 0x0582 -/* Floor Light */ +/** Floor Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_FLOOR 0x0583 -/* Cabinet Light */ +/** Cabinet Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_CABINET 0x0584 -/* Desk Light */ +/** Desk Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_DESK 0x0585 -/* Troffer Light */ +/** Troffer Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_TROFFER 0x0586 -/* Pendant Light */ +/** Pendant Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_PENDANT 0x0587 -/* In-ground Light */ +/** In-ground Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_IN_GROUND 0x0588 -/* Flood Light */ +/** Flood Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_FLOOD 0x0589 -/* Underwater Light */ +/** Underwater Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_UNDERWATER 0x058A -/* Bollard with Light */ +/** Bollard with Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_BOLLARD_WITH 0x058B -/* Pathway Light */ +/** Pathway Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_PATHWAY 0x058C -/* Garden Light */ +/** Garden Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_GARDEN 0x058D -/* Pole-top Light */ +/** Pole-top Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_POLE_TOP 0x058E -/* Spotlight */ +/** Spotlight */ #define BT_APPEARANCE_SPOT_LIGHT 0x058F -/* Linear Light */ +/** Linear Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_LINEAR 0x0590 -/* Street Light */ +/** Street Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_STREET 0x0591 -/* Shelves Light */ +/** Shelves Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_SHELVES 0x0592 -/* Bay Light */ +/** Bay Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_BAY 0x0593 -/* Emergency Exit Light */ +/** Emergency Exit Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_EMERGENCY_EXIT 0x0594 -/* Light Controller */ +/** Light Controller */ #define BT_APPEARANCE_LIGHT_FIXTURES_CONTROLLER 0x0595 -/* Light Driver */ +/** Light Driver */ #define BT_APPEARANCE_LIGHT_FIXTURES_DRIVER 0x0596 -/* Bulb */ +/** Bulb */ #define BT_APPEARANCE_LIGHT_FIXTURES_BULB 0x0597 -/* Low-bay Light */ +/** Low-bay Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_LOW_BAY 0x0598 -/* High-bay Light */ +/** High-bay Light */ #define BT_APPEARANCE_LIGHT_FIXTURES_HIGH_BAY 0x0599 -/* Generic Fan */ +/** Generic Fan */ #define BT_APPEARANCE_GENERIC_FAN 0x05C0 -/* Ceiling Fan */ +/** Ceiling Fan */ #define BT_APPEARANCE_FAN_CEILING 0x05C1 -/* Axial Fan */ +/** Axial Fan */ #define BT_APPEARANCE_FAN_AXIAL 0x05C2 -/* Exhaust Fan */ +/** Exhaust Fan */ #define BT_APPEARANCE_FAN_EXHAUST 0x05C3 -/* Pedestal Fan */ +/** Pedestal Fan */ #define BT_APPEARANCE_FAN_PEDESTAL 0x05C4 -/* Desk Fan */ +/** Desk Fan */ #define BT_APPEARANCE_FAN_DESK 0x05C5 -/* Wall Fan */ +/** Wall Fan */ #define BT_APPEARANCE_FAN_WALL 0x05C6 -/* Generic HVAC */ +/** Generic HVAC */ #define BT_APPEARANCE_GENERIC_HVAC 0x0600 -/* Thermostat */ +/** Thermostat */ #define BT_APPEARANCE_HVAC_THERMOSTAT 0x0601 -/* Humidifier */ +/** Humidifier */ #define BT_APPEARANCE_HVAC_HUMIDIFIER 0x0602 -/* De-humidifier */ +/** De-humidifier */ #define BT_APPEARANCE_HVAC_DEHUMIDIFIER 0x0603 -/* Heater */ +/** Heater */ #define BT_APPEARANCE_HVAC_HEATER 0x0604 -/* Radiator */ +/** Radiator */ #define BT_APPEARANCE_HVAC_RADIATOR 0x0605 -/* Boiler */ +/** Boiler */ #define BT_APPEARANCE_HVAC_BOILER 0x0606 -/* Heat Pump */ +/** Heat Pump */ #define BT_APPEARANCE_HVAC_HEAT_PUMP 0x0607 -/* Infrared Heater */ +/** Infrared Heater */ #define BT_APPEARANCE_HVAC_INFRARED_HEATER 0x0608 -/* Radiant Panel Heater */ +/** Radiant Panel Heater */ #define BT_APPEARANCE_HVAC_RADIANT_PANEL_HEATER 0x0609 -/* Fan Heater */ +/** Fan Heater */ #define BT_APPEARANCE_HVAC_FAN_HEATER 0x060A -/* Air Curtain */ +/** Air Curtain */ #define BT_APPEARANCE_HVAC_AIR_CURTAIN 0x060B -/* Generic Air Conditioning */ +/** Generic Air Conditioning */ #define BT_APPEARANCE_GENERIC_AIR_CONDITIONING 0x0640 -/* Generic Humidifier */ +/** Generic Humidifier */ #define BT_APPEARANCE_GENERIC_HUMIDIFIER 0x0680 -/* Generic Heating */ +/** Generic Heating */ #define BT_APPEARANCE_GENERIC_HEATING 0x06C0 -/* Radiator */ +/** Radiator */ #define BT_APPEARANCE_HEATING_RADIATOR 0x06C1 -/* Boiler */ +/** Boiler */ #define BT_APPEARANCE_HEATING_BOILER 0x06C2 -/* Heat Pump */ +/** Heat Pump */ #define BT_APPEARANCE_HEATING_HEAT_PUMP 0x06C3 -/* Infrared Heater */ +/** Infrared Heater */ #define BT_APPEARANCE_HEATING_INFRARED_HEATER 0x06C4 -/* Radiant Panel Heater */ +/** Radiant Panel Heater */ #define BT_APPEARANCE_HEATING_RADIANT_PANEL_HEATER 0x06C5 -/* Fan Heater */ +/** Fan Heater */ #define BT_APPEARANCE_HEATING_FAN_HEATER 0x06C6 -/* Air Curtain */ +/** Air Curtain */ #define BT_APPEARANCE_HEATING_AIR_CURTAIN 0x06C7 -/* Generic Access Control */ +/** Generic Access Control */ #define BT_APPEARANCE_GENERIC_ACCESS_CONTROL 0x0700 -/* Access Door */ +/** Access Door */ #define BT_APPEARANCE_CONTROL_ACCESS_DOOR 0x0701 -/* Garage Door */ +/** Garage Door */ #define BT_APPEARANCE_CONTROL_GARAGE_DOOR 0x0702 -/* Emergency Exit Door */ +/** Emergency Exit Door */ #define BT_APPEARANCE_CONTROL_EMERGENCY_EXIT_DOOR 0x0703 -/* Access Lock */ +/** Access Lock */ #define BT_APPEARANCE_CONTROL_ACCESS_LOCK 0x0704 -/* Elevator */ +/** Elevator */ #define BT_APPEARANCE_CONTROL_ELEVATOR 0x0705 -/* Window */ +/** Window */ #define BT_APPEARANCE_CONTROL_WINDOW 0x0706 -/* Entrance Gate */ +/** Entrance Gate */ #define BT_APPEARANCE_CONTROL_ENTRANCE_GATE 0x0707 -/* Door Lock */ +/** Door Lock */ #define BT_APPEARANCE_CONTROL_DOOR_LOCK 0x0708 -/* Locker */ +/** Locker */ #define BT_APPEARANCE_CONTROL_LOCKER 0x0709 -/* Generic Motorized Device */ +/** Generic Motorized Device */ #define BT_APPEARANCE_GENERIC_MOTORIZED_DEVICE 0x0740 -/* Motorized Gate */ +/** Motorized Gate */ #define BT_APPEARANCE_MOTORIZED_GATE 0x0741 -/* Awning */ +/** Awning */ #define BT_APPEARANCE_MOTORIZED_AWNING 0x0742 -/* Blinds or Shades */ +/** Blinds or Shades */ #define BT_APPEARANCE_MOTORIZED_BLINDS_OR_SHADES 0x0743 -/* Curtains */ +/** Curtains */ #define BT_APPEARANCE_MOTORIZED_CURTAINS 0x0744 -/* Screen */ +/** Screen */ #define BT_APPEARANCE_MOTORIZED_SCREEN 0x0745 -/* Generic Power Device */ +/** Generic Power Device */ #define BT_APPEARANCE_GENERIC_POWER_DEVICE 0x0780 -/* Power Outlet */ +/** Power Outlet */ #define BT_APPEARANCE_POWER_OUTLET 0x0781 -/* Power Strip */ +/** Power Strip */ #define BT_APPEARANCE_POWER_STRIP 0x0782 -/* Plug */ +/** Plug */ #define BT_APPEARANCE_POWER_PLUG 0x0783 -/* Power Supply */ +/** Power Supply */ #define BT_APPEARANCE_POWER_SUPPLY 0x0784 -/* LED Driver */ +/** LED Driver */ #define BT_APPEARANCE_POWER_LED_DRIVER 0x0785 -/* Fluorescent Lamp Gear */ +/** Fluorescent Lamp Gear */ #define BT_APPEARANCE_POWER_FLUORESCENT_LAMP_GEAR 0x0786 -/* HID Lamp Gear */ +/** HID Lamp Gear */ #define BT_APPEARANCE_POWER_HID_LAMP_GEAR 0x0787 -/* Charge Case */ +/** Charge Case */ #define BT_APPEARANCE_POWER_CHARGE_CASE 0x0788 -/* Power Bank */ +/** Power Bank */ #define BT_APPEARANCE_POWER_POWER_BANK 0x0789 -/* Generic Light Source */ +/** Generic Light Source */ #define BT_APPEARANCE_GENERIC_LIGHT_SOURCE 0x07C0 -/* Incandescent Light Bulb */ +/** Incandescent Light Bulb */ #define BT_APPEARANCE_LIGHT_SOURCE_INCANDESCENT_BULB 0x07C1 -/* LED Lamp */ +/** LED Lamp */ #define BT_APPEARANCE_LIGHT_SOURCE_LED_LAMP 0x07C2 -/* HID Lamp */ +/** HID Lamp */ #define BT_APPEARANCE_LIGHT_SOURCE_HID_LAMP 0x07C3 -/* Fluorescent Lamp */ +/** Fluorescent Lamp */ #define BT_APPEARANCE_LIGHT_SOURCE_FLUORESCENT_LAMP 0x07C4 -/* LED Array */ +/** LED Array */ #define BT_APPEARANCE_LIGHT_SOURCE_LED_ARRAY 0x07C5 -/* Multi-Color LED Array */ +/** Multi-Color LED Array */ #define BT_APPEARANCE_LIGHT_SOURCE_MULTICOLOR_LED_ARRAY 0x07C6 -/* Low voltage halogen */ +/** Low voltage halogen */ #define BT_APPEARANCE_LIGHT_SOURCE_LOW_VOLTAGE_HALOGEN 0x07C7 -/* Organic light emitting diode */ +/** Organic light emitting diode */ #define BT_APPEARANCE_LIGHT_SOURCE_OLED 0x07C8 -/* Generic Window Covering */ +/** Generic Window Covering */ #define BT_APPEARANCE_GENERIC_WINDOW_COVERING 0x0800 -/* Window Shades */ +/** Window Shades */ #define BT_APPEARANCE_WINDOW_SHADES 0x0801 -/* Window Blinds */ +/** Window Blinds */ #define BT_APPEARANCE_WINDOW_BLINDS 0x0802 -/* Window Awning */ +/** Window Awning */ #define BT_APPEARANCE_WINDOW_AWNING 0x0803 -/* Window Curtain */ +/** Window Curtain */ #define BT_APPEARANCE_WINDOW_CURTAIN 0x0804 -/* Exterior Shutter */ +/** Exterior Shutter */ #define BT_APPEARANCE_WINDOW_EXTERIOR_SHUTTER 0x0805 -/* Exterior Screen */ +/** Exterior Screen */ #define BT_APPEARANCE_WINDOW_EXTERIOR_SCREEN 0x0806 -/* Generic Audio Sink */ +/** Generic Audio Sink */ #define BT_APPEARANCE_GENERIC_AUDIO_SINK 0x0840 -/* Standalone Speaker */ +/** Standalone Speaker */ #define BT_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER 0x0841 -/* Soundbar */ +/** Soundbar */ #define BT_APPEARANCE_AUDIO_SINK_SOUNDBAR 0x0842 -/* Bookshelf Speaker */ +/** Bookshelf Speaker */ #define BT_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER 0x0843 -/* Standmounted Speaker */ +/** Standmounted Speaker */ #define BT_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER 0x0844 -/* Speakerphone */ +/** Speakerphone */ #define BT_APPEARANCE_AUDIO_SINK_SPEAKERPHONE 0x0845 -/* Generic Audio Source */ +/** Generic Audio Source */ #define BT_APPEARANCE_GENERIC_AUDIO_SOURCE 0x0880 -/* Microphone */ +/** Microphone */ #define BT_APPEARANCE_AUDIO_SOURCE_MICROPHONE 0x0881 -/* Alarm */ +/** Alarm */ #define BT_APPEARANCE_AUDIO_SOURCE_ALARM 0x0882 -/* Bell */ +/** Bell */ #define BT_APPEARANCE_AUDIO_SOURCE_BELL 0x0883 -/* Horn */ +/** Horn */ #define BT_APPEARANCE_AUDIO_SOURCE_HORN 0x0884 -/* Broadcasting Device */ +/** Broadcasting Device */ #define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE 0x0885 -/* Service Desk */ +/** Service Desk */ #define BT_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK 0x0886 -/* Kiosk */ +/** Kiosk */ #define BT_APPEARANCE_AUDIO_SOURCE_KIOSK 0x0887 -/* Broadcasting Room */ +/** Broadcasting Room */ #define BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM 0x0888 -/* Auditorium */ +/** Auditorium */ #define BT_APPEARANCE_AUDIO_SOURCE_AUDITORIUM 0x0889 -/* Generic Motorized Vehicle */ +/** Generic Motorized Vehicle */ #define BT_APPEARANCE_GENERIC_MOTORIZED_VEHICLE 0x08C0 -/* Car */ +/** Car */ #define BT_APPEARANCE_VEHICLE_CAR 0x08C1 -/* Large Goods Vehicle */ +/** Large Goods Vehicle */ #define BT_APPEARANCE_VEHICLE_LARGE_GOODS 0x08C2 -/* 2-Wheeled Vehicle */ +/** 2-Wheeled Vehicle */ #define BT_APPEARANCE_VEHICLE_TWO_WHEELED 0x08C3 -/* Motorbike */ +/** Motorbike */ #define BT_APPEARANCE_VEHICLE_MOTORBIKE 0x08C4 -/* Scooter */ +/** Scooter */ #define BT_APPEARANCE_VEHICLE_SCOOTER 0x08C5 -/* Moped */ +/** Moped */ #define BT_APPEARANCE_VEHICLE_MOPED 0x08C6 -/* 3-Wheeled Vehicle */ +/** 3-Wheeled Vehicle */ #define BT_APPEARANCE_VEHICLE_THREE_WHEELED 0x08C7 -/* Light Vehicle */ +/** Light Vehicle */ #define BT_APPEARANCE_VEHICLE_LIGHT 0x08C8 -/* Quad Bike */ +/** Quad Bike */ #define BT_APPEARANCE_VEHICLE_QUAD_BIKE 0x08C9 -/* Minibus */ +/** Minibus */ #define BT_APPEARANCE_VEHICLE_MINIBUS 0x08CA -/* Bus */ +/** Bus */ #define BT_APPEARANCE_VEHICLE_BUS 0x08CB -/* Trolley */ +/** Trolley */ #define BT_APPEARANCE_VEHICLE_TROLLEY 0x08CC -/* Agricultural Vehicle */ +/** Agricultural Vehicle */ #define BT_APPEARANCE_VEHICLE_AGRICULTURAL 0x08CD -/* Camper/Caravan */ +/** Camper/Caravan */ #define BT_APPEARANCE_VEHICLE_CAMPER_OR_CARAVAN 0x08CE -/* Recreational Vehicle/Motor Home */ +/** Recreational Vehicle/Motor Home */ #define BT_APPEARANCE_VEHICLE_RECREATIONAL 0x08CF -/* Generic Domestic Appliance */ +/** Generic Domestic Appliance */ #define BT_APPEARANCE_GENERIC_DOMESTIC_APPLIANCE 0x0900 -/* Refrigerator */ +/** Refrigerator */ #define BT_APPEARANCE_APPLIANCE_REFRIGERATOR 0x0901 -/* Freezer */ +/** Freezer */ #define BT_APPEARANCE_APPLIANCE_FREEZER 0x0902 -/* Oven */ +/** Oven */ #define BT_APPEARANCE_APPLIANCE_OVEN 0x0903 -/* Microwave */ +/** Microwave */ #define BT_APPEARANCE_APPLIANCE_MICROWAVE 0x0904 -/* Toaster */ +/** Toaster */ #define BT_APPEARANCE_APPLIANCE_TOASTER 0x0905 -/* Washing Machine */ +/** Washing Machine */ #define BT_APPEARANCE_APPLIANCE_WASHING_MACHINE 0x0906 -/* Dryer */ +/** Dryer */ #define BT_APPEARANCE_APPLIANCE_DRYER 0x0907 -/* Coffee maker */ +/** Coffee maker */ #define BT_APPEARANCE_APPLIANCE_COFFEE_MAKER 0x0908 -/* Clothes iron */ +/** Clothes iron */ #define BT_APPEARANCE_APPLIANCE_CLOTHES_IRON 0x0909 -/* Curling iron */ +/** Curling iron */ #define BT_APPEARANCE_APPLIANCE_CURLING_IRON 0x090A -/* Hair dryer */ +/** Hair dryer */ #define BT_APPEARANCE_APPLIANCE_HAIR_DRYER 0x090B -/* Vacuum cleaner */ +/** Vacuum cleaner */ #define BT_APPEARANCE_APPLIANCE_VACUUM_CLEANER 0x090C -/* Robotic vacuum cleaner */ +/** Robotic vacuum cleaner */ #define BT_APPEARANCE_APPLIANCE_ROBOTIC_VACUUM_CLEANER 0x090D -/* Rice cooker */ +/** Rice cooker */ #define BT_APPEARANCE_APPLIANCE_RICE_COOKER 0x090E -/* Clothes steamer */ +/** Clothes steamer */ #define BT_APPEARANCE_APPLIANCE_CLOTHES_STEAMER 0x090F -/* Generic Wearable Audio Device */ +/** Generic Wearable Audio Device */ #define BT_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940 -/* Earbud */ +/** Earbud */ #define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941 -/* Headset */ +/** Headset */ #define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942 -/* Headphones */ +/** Headphones */ #define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943 -/* Neck Band */ +/** Neck Band */ #define BT_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944 -/* Generic Aircraft */ +/** Generic Aircraft */ #define BT_APPEARANCE_GENERIC_AIRCRAFT 0x0980 -/* Light Aircraft */ +/** Light Aircraft */ #define BT_APPEARANCE_AIRCRAFT_LIGHT 0x0981 -/* Microlight */ +/** Microlight */ #define BT_APPEARANCE_AIRCRAFT_MICROLIGHT 0x0982 -/* Paraglider */ +/** Paraglider */ #define BT_APPEARANCE_AIRCRAFT_PARAGLIDER 0x0983 -/* Large Passenger Aircraft */ +/** Large Passenger Aircraft */ #define BT_APPEARANCE_AIRCRAFT_LARGE_PASSENGER 0x0984 -/* Generic AV Equipment */ +/** Generic AV Equipment */ #define BT_APPEARANCE_GENERIC_AV_EQUIPMENT 0x09C0 -/* Amplifier */ +/** Amplifier */ #define BT_APPEARANCE_AV_EQUIPMENT_AMPLIFIER 0x09C1 -/* Receiver */ +/** Receiver */ #define BT_APPEARANCE_AV_EQUIPMENT_RECEIVER 0x09C2 -/* Radio */ +/** Radio */ #define BT_APPEARANCE_AV_EQUIPMENT_RADIO 0x09C3 -/* Tuner */ +/** Tuner */ #define BT_APPEARANCE_AV_EQUIPMENT_TUNER 0x09C4 -/* Turntable */ +/** Turntable */ #define BT_APPEARANCE_AV_EQUIPMENT_TURNTABLE 0x09C5 -/* CD Player */ +/** CD Player */ #define BT_APPEARANCE_AV_EQUIPMENT_CD_PLAYER 0x09C6 -/* DVD Player */ +/** DVD Player */ #define BT_APPEARANCE_AV_EQUIPMENT_DVD_PLAYER 0x09C7 -/* Bluray Player */ +/** Bluray Player */ #define BT_APPEARANCE_AV_EQUIPMENT_BLURAY_PLAYER 0x09C8 -/* Optical Disc Player */ +/** Optical Disc Player */ #define BT_APPEARANCE_AV_EQUIPMENT_OPTICAL_DISC_PLAYER 0x09C9 -/* Set-Top Box */ +/** Set-Top Box */ #define BT_APPEARANCE_AV_EQUIPMENT_SET_TOP_BOX 0x09CA -/* Generic Display Equipment */ +/** Generic Display Equipment */ #define BT_APPEARANCE_GENERIC_DISPLAY_EQUIPMENT 0x0A00 -/* Television */ +/** Television */ #define BT_APPEARANCE_DISPLAY_EQUIPMENT_TELEVISION 0x0A01 -/* Monitor */ +/** Monitor */ #define BT_APPEARANCE_DISPLAY_EQUIPMENT_MONITOR 0x0A02 -/* Projector */ +/** Projector */ #define BT_APPEARANCE_DISPLAY_EQUIPMENT_PROJECTOR 0x0A03 -/* Generic Hearing aid */ +/** Generic Hearing aid */ #define BT_APPEARANCE_GENERIC_HEARING_AID 0x0A40 -/* In-ear hearing aid */ +/** In-ear hearing aid */ #define BT_APPEARANCE_HEARING_AID_IN_EAR 0x0A41 -/* Behind-ear hearing aid */ +/** Behind-ear hearing aid */ #define BT_APPEARANCE_HEARING_AID_BEHIND_EAR 0x0A42 -/* Cochlear Implant */ +/** Cochlear Implant */ #define BT_APPEARANCE_HEARING_AID_COCHLEAR_IMPLANT 0x0A43 -/* Generic Gaming */ +/** Generic Gaming */ #define BT_APPEARANCE_GENERIC_GAMING 0x0A80 -/* Home Video Game Console */ +/** Home Video Game Console */ #define BT_APPEARANCE_HOME_VIDEO_GAME_CONSOLE 0x0A81 -/* Portable handheld console */ +/** Portable handheld console */ #define BT_APPEARANCE_PORTABLE_HANDHELD_CONSOLE 0x0A82 -/* Generic Signage */ +/** Generic Signage */ #define BT_APPEARANCE_GENERIC_SIGNAGE 0x0AC0 -/* Digital Signage */ +/** Digital Signage */ #define BT_APPEARANCE_SIGNAGE_DIGITAL 0x0AC1 -/* Electronic Label */ +/** Electronic Label */ #define BT_APPEARANCE_SIGNAGE_ELECTRONIC_LABEL 0x0AC2 -/* Generic Pulse Oximeter */ +/** Generic Pulse Oximeter */ #define BT_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40 -/* Fingertip Pulse Oximeter */ +/** Fingertip Pulse Oximeter */ #define BT_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41 -/* Wrist Worn Pulse Oximeter */ +/** Wrist Worn Pulse Oximeter */ #define BT_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42 -/* Generic Weight Scale */ +/** Generic Weight Scale */ #define BT_APPEARANCE_GENERIC_WEIGHT_SCALE 0x0C80 -/* Generic Personal Mobility Device */ +/** Generic Personal Mobility Device */ #define BT_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0 -/* Powered Wheelchair */ +/** Powered Wheelchair */ #define BT_APPEARANCE_MOBILITY_POWERED_WHEELCHAIR 0x0CC1 -/* Mobility Scooter */ +/** Mobility Scooter */ #define BT_APPEARANCE_MOBILITY_SCOOTER 0x0CC2 -/* Continuous Glucose Monitor */ +/** Continuous Glucose Monitor */ #define BT_APPEARANCE_CONTINUOUS_GLUCOSE_MONITOR 0x0D00 -/* Generic Insulin Pump */ +/** Generic Insulin Pump */ #define BT_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40 -/* Insulin Pump, durable pump */ +/** Insulin Pump, durable pump */ #define BT_APPEARANCE_INSULIN_PUMP_DURABLE 0x0D41 -/* Insulin Pump, patch pump */ +/** Insulin Pump, patch pump */ #define BT_APPEARANCE_INSULIN_PUMP_PATCH 0x0D44 -/* Insulin Pen */ +/** Insulin Pen */ #define BT_APPEARANCE_INSULIN_PEN 0x0D48 -/* Generic Medication Delivery */ +/** Generic Medication Delivery */ #define BT_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80 -/* Generic Spirometer */ +/** Generic Spirometer */ #define BT_APPEARANCE_GENERIC_SPIROMETER 0x0DC0 -/* Handheld Spirometer */ +/** Handheld Spirometer */ #define BT_APPEARANCE_SPIROMETER_HANDHELD 0x0DC1 -/* Generic Outdoor Sports Activity */ +/** Generic Outdoor Sports Activity */ #define BT_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440 -/* Location Display */ +/** Location Display */ #define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441 -/* Location and Navigation Display */ +/** Location and Navigation Display */ #define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442 -/* Location Pod */ +/** Location Pod */ #define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443 -/* Location and Navigation Pod */ +/** Location and Navigation Pod */ #define BT_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444 +/** + * @} + */ /** + * @name Defined GAP timers + * @{ + */ #define BT_GAP_SCAN_FAST_INTERVAL 0x0060 /* 60 ms */ #define BT_GAP_SCAN_FAST_WINDOW 0x0030 /* 30 ms */ #define BT_GAP_SCAN_SLOW_INTERVAL_1 0x0800 /* 1.28 s */ @@ -705,6 +728,9 @@ extern "C" { #define BT_GAP_PER_ADV_SLOW_INT_MAX 0x03C0 /* 1.2 s */ #define BT_GAP_INIT_CONN_INT_MIN 0x0018 /* 30 ms */ #define BT_GAP_INIT_CONN_INT_MAX 0x0028 /* 50 ms */ +/** + * @} + */ /** LE PHY types */ enum { @@ -767,20 +793,30 @@ enum { */ #define BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT 128 +/** Default data length */ #define BT_GAP_DATA_LEN_DEFAULT 0x001b /* 27 bytes */ +/** Maximum data length */ #define BT_GAP_DATA_LEN_MAX 0x00fb /* 251 bytes */ +/** Default data time */ #define BT_GAP_DATA_TIME_DEFAULT 0x0148 /* 328 us */ +/** Maximum data time */ #define BT_GAP_DATA_TIME_MAX 0x4290 /* 17040 us */ +/** Maximum advertising set number */ #define BT_GAP_SID_MAX 0x0F +/** Maximum number of consecutive periodic advertisement events that can be + * skipped after a successful receive. + */ #define BT_GAP_PER_ADV_MAX_SKIP 0x01F3 -#define BT_GAP_PER_ADV_MIN_TIMEOUT 0x000A -#define BT_GAP_PER_ADV_MAX_TIMEOUT 0x4000 +/** Minimum Periodic Advertising Timeout (N * 10 ms) */ +#define BT_GAP_PER_ADV_MIN_TIMEOUT 0x000A /* 100 ms */ +/** Maximum Periodic Advertising Timeout (N * 10 ms) */ +#define BT_GAP_PER_ADV_MAX_TIMEOUT 0x4000 /* 163.84 s */ /** Minimum Periodic Advertising Interval (N * 1.25 ms) */ -#define BT_GAP_PER_ADV_MIN_INTERVAL 0x0006 +#define BT_GAP_PER_ADV_MIN_INTERVAL 0x0006 /* 7.5 ms */ /** Maximum Periodic Advertising Interval (N * 1.25 ms) */ -#define BT_GAP_PER_ADV_MAX_INTERVAL 0xFFFF +#define BT_GAP_PER_ADV_MAX_INTERVAL 0xFFFF /* 81.91875 s */ /** * @brief Convert periodic advertising interval (N * 1.25 ms) to milliseconds @@ -803,15 +839,15 @@ enum { /** @brief Peripheral sleep clock accuracy (SCA) in ppm (parts per million) */ enum { - BT_GAP_SCA_UNKNOWN = 0, - BT_GAP_SCA_251_500 = 0, - BT_GAP_SCA_151_250 = 1, - BT_GAP_SCA_101_150 = 2, - BT_GAP_SCA_76_100 = 3, - BT_GAP_SCA_51_75 = 4, - BT_GAP_SCA_31_50 = 5, - BT_GAP_SCA_21_30 = 6, - BT_GAP_SCA_0_20 = 7, + BT_GAP_SCA_UNKNOWN = 0, /**< Unknown */ + BT_GAP_SCA_251_500 = 0, /**< 251 ppm to 500 ppm */ + BT_GAP_SCA_151_250 = 1, /**< 151 ppm to 250 ppm */ + BT_GAP_SCA_101_150 = 2, /**< 101 ppm to 150 ppm */ + BT_GAP_SCA_76_100 = 3, /**< 76 ppm to 100 ppm */ + BT_GAP_SCA_51_75 = 4, /**< 51 ppm to 75 ppm */ + BT_GAP_SCA_31_50 = 5, /**< 31 ppm to 50 ppm */ + BT_GAP_SCA_21_30 = 6, /**< 21 ppm to 30 ppm */ + BT_GAP_SCA_0_20 = 7, /**< 0 ppm to 20 ppm */ }; /** From 691b357b59fa1204def67f7a76c75155a67a2642 Mon Sep 17 00:00:00 2001 From: Johan Lafon Date: Mon, 17 Jul 2023 16:00:09 +0200 Subject: [PATCH 1526/2042] drivers: clock-control: st: add MCO support for H7 family Create clock_stm32_ll_mco.h file to bring stm32_clock_control_mco_init, mco1_prescaler, mco2_prescaler, MCO1_SOURCE and MCO2_SOURCE definitions which were previously in clock_stm32_ll_common.{c,h}. This is done so that stm32_clock_control_mco_init can be called from clock_stm32_ll_h7.c. Also update Kconfig.stm32 and add new MCO sources to allow H7 support. Signed-off-by: Johan Lafon --- drivers/clock_control/Kconfig.stm32 | 66 ++++++++++-- drivers/clock_control/clock_stm32_ll_common.c | 28 +---- drivers/clock_control/clock_stm32_ll_common.h | 42 -------- drivers/clock_control/clock_stm32_ll_h7.c | 4 + drivers/clock_control/clock_stm32_ll_mco.h | 101 ++++++++++++++++++ 5 files changed, 162 insertions(+), 79 deletions(-) create mode 100644 drivers/clock_control/clock_stm32_ll_mco.h diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index 5a96e9151481..03a53a1cdbcb 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -65,7 +65,8 @@ config CLOCK_STM32_MCO1_SRC_LSE bool "LSE" depends on SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32L4X + SOC_SERIES_STM32L4X || \ + SOC_SERIES_STM32H7X help Use LSE as source of MCO1 @@ -74,7 +75,8 @@ config CLOCK_STM32_MCO1_SRC_HSE depends on SOC_SERIES_STM32F1X || \ SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32L4X + SOC_SERIES_STM32L4X || \ + SOC_SERIES_STM32H7X help Use HSE as source of MCO1 @@ -92,7 +94,10 @@ config CLOCK_STM32_MCO1_SRC_MSI config CLOCK_STM32_MCO1_SRC_HSI bool "HSI" - depends on SOC_SERIES_STM32F1X || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + depends on SOC_SERIES_STM32F1X || \ + SOC_SERIES_STM32F4X || \ + SOC_SERIES_STM32F7X || \ + SOC_SERIES_STM32H7X help Use HSI as source of MCO1 @@ -104,7 +109,8 @@ config CLOCK_STM32_MCO1_SRC_HSI16 config CLOCK_STM32_MCO1_SRC_HSI48 bool "HSI48" - depends on SOC_SERIES_STM32L4X + depends on SOC_SERIES_STM32L4X || \ + SOC_SERIES_STM32H7X help Use HSI48 as source of MCO1 @@ -114,6 +120,12 @@ config CLOCK_STM32_MCO1_SRC_PLLCLK help Use PLLCLK as source of MCO1 +config CLOCK_STM32_MCO1_SRC_PLLQCLK + bool "PLLQ" + depends on SOC_SERIES_STM32H7X + help + Use PLLQ as source of MCO1 + config CLOCK_STM32_MCO1_SRC_PLLCLK_DIV2 bool "PLLCLK_DIV2" depends on SOC_SERIES_STM32F1X @@ -150,10 +162,12 @@ config CLOCK_STM32_MCO1_DIV depends on !CLOCK_STM32_MCO1_SRC_NOCLOCK && (\ SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32L4X \ + SOC_SERIES_STM32L4X || \ + SOC_SERIES_STM32H7X \ ) default 1 range 1 5 if SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + range 1 15 if SOC_SERIES_STM32H7X range 1 16 if SOC_SERIES_STM32L4X help Prescaler for MCO1 output clock @@ -169,7 +183,9 @@ config CLOCK_STM32_MCO2_SRC_NOCLOCK config CLOCK_STM32_MCO2_SRC_SYSCLK bool "SYSCLK" - depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + depends on SOC_SERIES_STM32F4X || \ + SOC_SERIES_STM32F7X || \ + SOC_SERIES_STM32H7X help Use SYSCLK as source of MCO2 @@ -181,24 +197,54 @@ config CLOCK_STM32_MCO2_SRC_PLLI2S config CLOCK_STM32_MCO2_SRC_HSE bool "HSE" - depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + depends on SOC_SERIES_STM32F4X || \ + SOC_SERIES_STM32F7X || \ + SOC_SERIES_STM32H7X help Use HSE as source of MCO2 +config CLOCK_STM32_MCO2_SRC_LSI + bool "LSI" + depends on SOC_SERIES_STM32H7X + help + Use LSI as source of MCO2 + +config CLOCK_STM32_MCO2_SRC_CSI + bool "CSI" + depends on SOC_SERIES_STM32H7X + help + Use CSI as source of MCO2 + config CLOCK_STM32_MCO2_SRC_PLLCLK bool "PLLCLK" depends on SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X help Use PLLCLK as source of MCO2 +config CLOCK_STM32_MCO2_SRC_PLLPCLK + bool "PLLPCLK" + depends on SOC_SERIES_STM32H7X + help + Use PLLPCLK as source of MC02 + +config CLOCK_STM32_MCO2_SRC_PLL2PCLK + bool "PLL2PCLK" + depends on SOC_SERIES_STM32H7X + help + Use PLL2PCLK as source of MC02 endchoice config CLOCK_STM32_MCO2_DIV int "MCO2 prescaler" - depends on !CLOCK_STM32_MCO2_SRC_NOCLOCK + depends on !CLOCK_STM32_MCO2_SRC_NOCLOCK && (\ + SOC_SERIES_STM32F4X || \ + SOC_SERIES_STM32F7X || \ + SOC_SERIES_STM32H7X \ + ) default 1 - range 1 5 + range 1 5 if SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X + range 1 15 if SOC_SERIES_STM32H7X help - allowed values: 1, 2, 3, 4, 5 + Prescaler for MCO2 output clock endif # CLOCK_CONTROL_STM32_CUBE diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index 96368dd6b82e..b596ac08da97 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -17,6 +17,7 @@ #include #include #include "clock_stm32_ll_common.h" +#include "clock_stm32_ll_mco.h" #include "stm32_hsem.h" /* Macros to fill up prescaler values */ @@ -34,12 +35,6 @@ #define apb2_prescaler(v) fn_apb2_prescaler(v) #endif -#define fn_mco1_prescaler(v) LL_RCC_MCO1_DIV_ ## v -#define mco1_prescaler(v) fn_mco1_prescaler(v) - -#define fn_mco2_prescaler(v) LL_RCC_MCO2_DIV_ ## v -#define mco2_prescaler(v) fn_mco2_prescaler(v) - #if DT_NODE_HAS_PROP(DT_NODELABEL(rcc), ahb4_prescaler) #define RCC_CALC_FLASH_FREQ __LL_RCC_CALC_HCLK4_FREQ #define GET_CURRENT_FLASH_PRESCALER LL_RCC_GetAHB4Prescaler @@ -479,27 +474,6 @@ static void stm32_clock_switch_to_hsi(void) } } -/* - * MCO configure doesn't active requested clock source, - * so please make sure the clock source was enabled. - */ -static inline void stm32_clock_control_mco_init(void) -{ -#ifndef CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK -#ifdef CONFIG_SOC_SERIES_STM32F1X - LL_RCC_ConfigMCO(MCO1_SOURCE); -#else - LL_RCC_ConfigMCO(MCO1_SOURCE, - mco1_prescaler(CONFIG_CLOCK_STM32_MCO1_DIV)); -#endif -#endif /* CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK */ - -#ifndef CONFIG_CLOCK_STM32_MCO2_SRC_NOCLOCK - LL_RCC_ConfigMCO(MCO2_SOURCE, - mco2_prescaler(CONFIG_CLOCK_STM32_MCO2_DIV)); -#endif /* CONFIG_CLOCK_STM32_MCO2_SRC_NOCLOCK */ -} - __unused static void set_up_plls(void) { diff --git a/drivers/clock_control/clock_stm32_ll_common.h b/drivers/clock_control/clock_stm32_ll_common.h index a8f926621f05..5bab50d2e0df 100644 --- a/drivers/clock_control/clock_stm32_ll_common.h +++ b/drivers/clock_control/clock_stm32_ll_common.h @@ -14,48 +14,6 @@ #include -#if CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_NOCLOCK -#elif CONFIG_CLOCK_STM32_MCO1_SRC_EXT_HSE - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_EXT_HSE -#elif CONFIG_CLOCK_STM32_MCO1_SRC_LSE - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_LSE -#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSE - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSE -#elif CONFIG_CLOCK_STM32_MCO1_SRC_LSI - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_LSI -#elif CONFIG_CLOCK_STM32_MCO1_SRC_MSI - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_MSI -#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI -#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI16 - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI -#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI48 - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI48 -#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK -#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK_DIV2 - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK_DIV_2 -#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLL2CLK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLL2CLK -#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLI2SCLK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLI2SCLK -#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLI2SCLK_DIV2 - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLI2SCLK_DIV2 -#elif CONFIG_CLOCK_STM32_MCO1_SRC_SYSCLK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_SYSCLK -#endif - -#if CONFIG_CLOCK_STM32_MCO2_SRC_SYSCLK - #define MCO2_SOURCE LL_RCC_MCO2SOURCE_SYSCLK -#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLLI2S - #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLLI2S -#elif CONFIG_CLOCK_STM32_MCO2_SRC_HSE - #define MCO2_SOURCE LL_RCC_MCO2SOURCE_HSE -#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLLCLK - #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLLCLK -#endif - /* Macros to fill up multiplication and division factors values */ #define z_pllm(v) LL_RCC_PLLM_DIV_ ## v #define pllm(v) z_pllm(v) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index 8ef3b48c4970..c95d8ab1294f 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -16,6 +16,7 @@ #include #include #include +#include "clock_stm32_ll_mco.h" #include "stm32_hsem.h" @@ -836,6 +837,9 @@ int stm32_clock_control_init(const struct device *dev) z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + /* Configure MCO1/MCO2 based on Kconfig */ + stm32_clock_control_mco_init(); + /* Set up indiviual enabled clocks */ set_up_fixed_clock_sources(); diff --git a/drivers/clock_control/clock_stm32_ll_mco.h b/drivers/clock_control/clock_stm32_ll_mco.h new file mode 100644 index 000000000000..73a02ff5911c --- /dev/null +++ b/drivers/clock_control/clock_stm32_ll_mco.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2022 Linaro Limited. + * Copyright (c) 2017 RnDity Sp. z o.o. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_CLOCK_CONTROL_CLOCK_STM32_LL_MCO_H_ +#define ZEPHYR_DRIVERS_CLOCK_CONTROL_CLOCK_STM32_LL_MCO_H_ + +#include + +#if CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_NOCLOCK +#elif CONFIG_CLOCK_STM32_MCO1_SRC_EXT_HSE + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_EXT_HSE +#elif CONFIG_CLOCK_STM32_MCO1_SRC_LSE + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_LSE +#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSE + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSE +#elif CONFIG_CLOCK_STM32_MCO1_SRC_LSI + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_LSI +#elif CONFIG_CLOCK_STM32_MCO1_SRC_MSI + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_MSI +#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI +#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI16 + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI +#elif CONFIG_CLOCK_STM32_MCO1_SRC_HSI48 + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_HSI48 +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLQCLK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLL1QCLK +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK_DIV2 + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK_DIV_2 +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLL2CLK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLL2CLK +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLI2SCLK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLI2SCLK +#elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLI2SCLK_DIV2 + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLI2SCLK_DIV2 +#elif CONFIG_CLOCK_STM32_MCO1_SRC_SYSCLK + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_SYSCLK +#endif + +#if CONFIG_CLOCK_STM32_MCO2_SRC_SYSCLK + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_SYSCLK +#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLLI2S + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLLI2S +#elif CONFIG_CLOCK_STM32_MCO2_SRC_HSE + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_HSE +#elif CONFIG_CLOCK_STM32_MCO2_SRC_LSI + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_LSI +#elif CONFIG_CLOCK_STM32_MCO2_SRC_CSI + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_CSI +#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLLCLK + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLLCLK +#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLLPCLK + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLL1PCLK +#elif CONFIG_CLOCK_STM32_MCO2_SRC_PLL2PCLK + #define MCO2_SOURCE LL_RCC_MCO2SOURCE_PLL2PCLK +#endif + +#define fn_mco1_prescaler(v) LL_RCC_MCO1_DIV_ ## v +#define mco1_prescaler(v) fn_mco1_prescaler(v) + +#define fn_mco2_prescaler(v) LL_RCC_MCO2_DIV_ ## v +#define mco2_prescaler(v) fn_mco2_prescaler(v) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * MCO configure doesn't active requested clock source, + * so please make sure the clock source was enabled. + */ +__unused +static inline void stm32_clock_control_mco_init(void) +{ +#ifndef CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK +#ifdef CONFIG_SOC_SERIES_STM32F1X + LL_RCC_ConfigMCO(MCO1_SOURCE); +#else + LL_RCC_ConfigMCO(MCO1_SOURCE, + mco1_prescaler(CONFIG_CLOCK_STM32_MCO1_DIV)); +#endif +#endif /* CONFIG_CLOCK_STM32_MCO1_SRC_NOCLOCK */ + +#ifndef CONFIG_CLOCK_STM32_MCO2_SRC_NOCLOCK + LL_RCC_ConfigMCO(MCO2_SOURCE, + mco2_prescaler(CONFIG_CLOCK_STM32_MCO2_DIV)); +#endif /* CONFIG_CLOCK_STM32_MCO2_SRC_NOCLOCK */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_CLOCK_CONTROL_CLOCK_STM32_LL_MCO_H_ */ From 6135ae0fa09c98e21313fcea2bb7c2daab4bd8f3 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 18 Jul 2023 13:02:08 +0200 Subject: [PATCH 1527/2042] bluetooth: audio: ascs: Fix Codec Config initiated by server The Codec Specific Configuration Parameters provided by server was not copied at bt_ascs_config_ase. Detected by PTS in BAP/USR/SCC PTS test cases, because no LTV values appeared in ASE Codec Configured notification. Signed-off-by: Magdalena Kasenberg --- subsys/bluetooth/audio/ascs.c | 60 +++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 60bc04e4ae27..c3ab06ff887f 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -1541,6 +1541,37 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) return 0; } +void copy_codec_cfg_pointers(struct bt_audio_codec_cfg *dst, + struct bt_audio_codec_cfg *src) +{ +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + /* Need to update the `bt_data.data` pointer to the new value after copying the codec */ + for (size_t i = 0U; i < ARRAY_SIZE(dst->data); i++) { + const struct bt_audio_codec_data *codec_data = &src->data[i]; + struct bt_audio_codec_data *data = &dst->data[i]; + const uint8_t data_len = codec_data->data.data_len; + + data->data.data = data->value; + data->data.data_len = data_len; + memcpy(data->value, codec_data->data.data, data_len); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 */ + +#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + for (size_t i = 0U; i < ARRAY_SIZE(dst->meta); i++) { + const struct bt_audio_codec_data *meta_data = &src->meta[i]; + struct bt_audio_codec_data *data = &dst->meta[i]; + const uint8_t data_len = meta_data->data.data_len; + + data->data.data = data->value; + data->data.data_len = data_len; + memcpy(data->value, meta_data->data.data, data_len); + } +#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_COUNT > 0 && + * CONFIG_BT_AUDIO_CODEC_MAX_DATA_LEN > 0 + */ +} + int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_audio_codec_cfg *codec_cfg, const struct bt_audio_codec_qos_pref *qos_pref) @@ -1548,16 +1579,13 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, int err; struct bt_ascs_ase *ase = NULL; struct bt_bap_ep *ep; - struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, - BT_BAP_ASCS_REASON_NONE); + struct codec_cap_lookup_id_data lookup_data; CHECKIF(conn == NULL || stream == NULL || codec_cfg == NULL || qos_pref == NULL) { LOG_DBG("NULL value(s) supplied)"); return -EINVAL; } - ep = stream->ep; - if (stream->ep != NULL) { LOG_DBG("Stream already configured for conn %p", (void *)stream->conn); return -EALREADY; @@ -1578,13 +1606,27 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, ep = &ase->ep; - err = ascs_ep_set_codec(ep, codec_cfg->id, sys_le16_to_cpu(codec_cfg->cid), - sys_le16_to_cpu(codec_cfg->vid), NULL, 0, &rsp); - if (err) { - ase_free(ase); - return err; + if (ep == NULL) { + return -EINVAL; } + lookup_data.id = codec_cfg->id; + lookup_data.cid = codec_cfg->cid; + lookup_data.vid = codec_cfg->vid; + + bt_pacs_cap_foreach(ep->dir, codec_lookup_id, &lookup_data); + + if (lookup_data.codec_cap == NULL) { + LOG_DBG("Codec with id %u for dir %s is not supported by our capabilities", + codec_cfg->id, bt_audio_dir_str(ep->dir)); + return -ENOENT; + } + + (void)memcpy(&ep->codec_cfg, codec_cfg, sizeof(ep->codec_cfg)); + + /* TODO: Remove this after refactoring bt_audio_codec_cfg to use flat arrays */ + copy_codec_cfg_pointers(&ep->codec_cfg, codec_cfg); + ep->qos_pref = *qos_pref; bt_bap_stream_attach(conn, stream, ep, &ep->codec_cfg); From 51726f3648dc6fa257e9267e7e48848fcf45b622 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 19 Jul 2023 13:17:12 +0200 Subject: [PATCH 1528/2042] net: l2: ieee802154: shell: Validate address on input Associate command handler did not validate the provided address length. In result, if provided address string was longer than the expected extended address size, strncpy() would not NULL terminate the buffer, which could lead to unexpected behavior in parse_extended_address(), as it expects NULL terminated string. Fix this by validating the length of the provided address string before parsing. Additionally, make parse_extended_address() return the parsing result, so that it can be detected when provided extended address has incorrect format. Signed-off-by: Robert Lubos --- subsys/net/l2/ieee802154/ieee802154_shell.c | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_shell.c b/subsys/net/l2/ieee802154/ieee802154_shell.c index 56dcf096f97f..ad73185f4f8e 100644 --- a/subsys/net/l2/ieee802154/ieee802154_shell.c +++ b/subsys/net/l2/ieee802154/ieee802154_shell.c @@ -67,10 +67,12 @@ static int cmd_ieee802154_ack(const struct shell *sh, * * @param addr Extended address as a string. * @param ext_addr Extended address in big endian byte ordering. + * + * @return 0 on success, negative error code otherwise */ -static inline void parse_extended_address(char *addr, uint8_t *ext_addr) +static inline int parse_extended_address(char *addr, uint8_t *ext_addr) { - net_bytes_from_str(ext_addr, IEEE802154_EXT_ADDR_LENGTH, addr); + return net_bytes_from_str(ext_addr, IEEE802154_EXT_ADDR_LENGTH, addr); } static int cmd_ieee802154_associate(const struct shell *sh, @@ -90,12 +92,21 @@ static int cmd_ieee802154_associate(const struct shell *sh, return -ENOEXEC; } + if (strlen(argv[2]) > EXT_ADDR_STR_LEN) { + shell_fprintf(sh, SHELL_INFO, "Address too long\n"); + return -ENOEXEC; + } + params = (struct ieee802154_req_params){0}; params.pan_id = atoi(argv[1]); strncpy(ext_addr, argv[2], sizeof(ext_addr)); if (strlen(ext_addr) == EXT_ADDR_STR_LEN) { - parse_extended_address(ext_addr, params.addr); + if (parse_extended_address(ext_addr, params.addr) < 0) { + shell_fprintf(sh, SHELL_INFO, + "Failed to parse extended address\n"); + return -ENOEXEC; + } params.len = IEEE802154_EXT_ADDR_LENGTH; } else { params.short_addr = (uint16_t) atoi(ext_addr); @@ -435,7 +446,11 @@ static int cmd_ieee802154_set_ext_addr(const struct shell *sh, return -ENOEXEC; } - parse_extended_address(argv[1], addr); + if (parse_extended_address(argv[1], addr) < 0) { + shell_fprintf(sh, SHELL_INFO, + "Failed to parse extended address\n"); + return -ENOEXEC; + } if (net_mgmt(NET_REQUEST_IEEE802154_SET_EXT_ADDR, iface, addr, IEEE802154_EXT_ADDR_LENGTH)) { From a458d0443a91d818bd9de3df886d96fa1afbebc5 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 18 Jul 2023 17:44:58 -0700 Subject: [PATCH 1529/2042] xtensa: allow arch-specific arch_spin_relax() with more NOPs This adds a Kconfig to introduce the Xtensa specific arch_spin_relax() which can do more NOPs. Some Xtensa SoCs may need more NOPs after failure to lock a spinlock, especially under SMP. This gives the bus extra time to propagate the RCW transactions among CPUs. Signed-off-by: Daniel Leung --- arch/xtensa/Kconfig | 16 ++++++++++++++++ arch/xtensa/core/xtensa-asm2.c | 13 +++++++++++++ 2 files changed, 29 insertions(+) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 242683b6ffd8..93216a5aa247 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -103,6 +103,22 @@ config XTENSA_CCOUNT_HZ Rate in HZ of the Xtensa core as measured by the value of the CCOUNT register. +config XTENSA_MORE_SPIN_RELAX_NOPS + bool "Use Xtensa specific arch_spin_relax() with more NOPs" + help + Some Xtensa SoCs, especially under SMP, may need extra + NOPs after failure to lock a spinlock. This gives + the bus extra time to synchronize the RCW transaction + among CPUs. + +config XTENSA_NUM_SPIN_RELAX_NOPS + int "Number of NOPs to be used in arch_spin_relax()" + default 1 + depends on XTENSA_MORE_SPIN_RELAX_NOPS + help + Specify the number of NOPs in Xtensa specific + arch_spin_relax(). + if CPU_HAS_MMU config XTENSA_MMU diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c index f81040d74b2b..2c35c7efac82 100644 --- a/arch/xtensa/core/xtensa-asm2.c +++ b/arch/xtensa/core/xtensa-asm2.c @@ -455,3 +455,16 @@ 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 */ From f21526c5c9486097e47cac867c796a09378e84d3 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 19 Jul 2023 15:00:20 +0200 Subject: [PATCH 1530/2042] drivers: counter: stm32: void return value from reset_line_toggle_dt Suggested-by: Francois Ramu Signed-off-by: Sean Nyekjaer --- drivers/counter/counter_ll_stm32_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index 55af65c7e0a0..3c7d561db0f3 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -495,7 +495,7 @@ static int counter_stm32_init_timer(const struct device *dev) } /* Reset timer to default state using RCC */ - reset_line_toggle_dt(&data->reset); + (void)reset_line_toggle_dt(&data->reset); /* config/enable IRQ */ cfg->irq_config_func(dev); From 09f4b6f3bdf2328fe0c93065f59af43ee41f358d Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 19 Jul 2023 15:05:05 +0200 Subject: [PATCH 1531/2042] drivers: mipi_dsi: dsi_stm32: void return value from reset_line_toggle_dt Suggested-by: Francois Ramu Signed-off-by: Sean Nyekjaer --- drivers/mipi_dsi/dsi_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mipi_dsi/dsi_stm32.c b/drivers/mipi_dsi/dsi_stm32.c index be22c82de14a..cb8a0177003c 100644 --- a/drivers/mipi_dsi/dsi_stm32.c +++ b/drivers/mipi_dsi/dsi_stm32.c @@ -413,7 +413,7 @@ static int mipi_dsi_stm32_init(const struct device *dev) return ret; } - reset_line_toggle_dt(&config->reset); + (void)reset_line_toggle_dt(&config->reset); ret = mipi_dsi_stm32_host_init(dev); if (ret) { From d0651a8d96778730eddfa8212d2ba45c7e2b2f9a Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 19 Jul 2023 15:05:37 +0200 Subject: [PATCH 1532/2042] drivers: serial: stm32: void return value from reset_line_toggle_dt Suggested-by: Francois Ramu Signed-off-by: Sean Nyekjaer --- 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 23be4a9138cd..4b19fb25c3e1 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -1701,7 +1701,7 @@ static int uart_stm32_init(const struct device *dev) } /* Reset UART to default state using RCC */ - reset_line_toggle_dt(&data->reset); + (void)reset_line_toggle_dt(&data->reset); /* TX/RX direction */ LL_USART_SetTransferDirection(config->usart, From fbd56fd9201724cecb08dd6f6196f854eb0d87b9 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 17 Jul 2023 11:06:06 -0700 Subject: [PATCH 1533/2042] bt: host: Fix possible buffer overflow Check in bt_conn_le_start_encryption if the given ltk fits in bt_conn.ltk before copying it. Signed-off-by: Flavio Ceolin --- subsys/bluetooth/host/conn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 66b8a662f3ec..af678496295b 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2170,6 +2170,10 @@ int bt_conn_le_start_encryption(struct bt_conn *conn, uint8_t rand[8], struct bt_hci_cp_le_start_encryption *cp; struct net_buf *buf; + if (len > sizeof(cp->ltk)) { + return -EINVAL; + } + buf = bt_hci_cmd_create(BT_HCI_OP_LE_START_ENCRYPTION, sizeof(*cp)); if (!buf) { return -ENOBUFS; From 02e70f509f60b2eed425216407bcdfb9f39fc86d Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 17 Jul 2023 11:19:28 -0700 Subject: [PATCH 1534/2042] bt: audio: shell: Fix possible buffer overflow Check the size of the search argument in cmd_mcc_send_search_raw before copying it. Signed-off-by: Flavio Ceolin --- subsys/bluetooth/audio/shell/mcc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/shell/mcc.c b/subsys/bluetooth/audio/shell/mcc.c index 71bc44c8ff3e..ba4c10de9be9 100644 --- a/subsys/bluetooth/audio/shell/mcc.c +++ b/subsys/bluetooth/audio/shell/mcc.c @@ -1448,9 +1448,16 @@ static int cmd_mcc_send_search_raw(const struct shell *sh, size_t argc, char *argv[]) { int result; + size_t len; struct mpl_search search; - search.len = strlen(argv[1]); + len = strlen(argv[1]); + if (len > sizeof(search.search)) { + shell_print(sh, "Fail: Invalid argument"); + return -EINVAL; + } + + search.len = len; memcpy(search.search, argv[1], search.len); LOG_DBG("Search string: %s", argv[1]); From e55af04e65967158fe9e5294c9dccec63a1f3b84 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 17 Jul 2023 11:23:57 -0700 Subject: [PATCH 1535/2042] bt: audio: shell: Fix possible buffer overflow Check the size of the search argument in cmd_media_set_search before copying it. Signed-off-by: Flavio Ceolin --- subsys/bluetooth/audio/shell/media_controller.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/audio/shell/media_controller.c b/subsys/bluetooth/audio/shell/media_controller.c index fb239df02dc2..25acc028a9ef 100644 --- a/subsys/bluetooth/audio/shell/media_controller.c +++ b/subsys/bluetooth/audio/shell/media_controller.c @@ -1230,9 +1230,16 @@ static int cmd_media_set_search(const struct shell *sh, size_t argc, char *argv[ */ struct mpl_search search; + size_t len; int err; - search.len = strlen(argv[1]); + len = strlen(argv[1]); + if (len > sizeof(search.search)) { + shell_print(sh, "Fail: Invalid argument"); + return -EINVAL; + } + + search.len = len; memcpy(search.search, argv[1], search.len); LOG_DBG("Search string: %s", argv[1]); From ddd2bc94e2f4b51a3ac6f1f0e63e5665266c0f3f Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Mon, 17 Jul 2023 11:38:03 -0700 Subject: [PATCH 1536/2042] bt: mesh: shell: Fix possible buffer overflow Fix possible overflow in rpr_scan_report. Signed-off-by: Flavio Ceolin --- subsys/bluetooth/mesh/shell/rpr.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/mesh/shell/rpr.c b/subsys/bluetooth/mesh/shell/rpr.c index df8979682ca5..c8f058171048 100644 --- a/subsys/bluetooth/mesh/shell/rpr.c +++ b/subsys/bluetooth/mesh/shell/rpr.c @@ -38,9 +38,26 @@ static void rpr_scan_report(struct bt_mesh_rpr_cli *cli, uint8_t len, type; uint8_t data[31]; - len = net_buf_simple_pull_u8(adv_data) - 1; + len = net_buf_simple_pull_u8(adv_data); + if (len == 0) { + /* No data in this AD Structure. */ + continue; + } + + if (len > adv_data->len) { + /* Malformed AD Structure. */ + break; + } + type = net_buf_simple_pull_u8(adv_data); - memcpy(data, net_buf_simple_pull_mem(adv_data, len), len); + if ((--len) > 0) { + uint8_t dlen; + + /* Pull all length, but print only what fits into `data` array. */ + dlen = MIN(len, sizeof(data) - 1); + memcpy(data, net_buf_simple_pull_mem(adv_data, len), dlen); + len = dlen; + } data[len] = '\0'; if (type == BT_DATA_URI) { From f99d497281d2ad42d45dff9dd12481f4509d3a2c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 20 Jul 2023 13:07:42 +0100 Subject: [PATCH 1537/2042] tests: mgmt: mcumgr: Add handler_demo test Adds a test that tests a build-only configuration of an application which uses custom handlers is able to build, and can be referenced in documentation. Signed-off-by: Jamie McCrae --- .../mgmt/mcumgr/handler_demo/CMakeLists.txt | 18 ++ tests/subsys/mgmt/mcumgr/handler_demo/Kconfig | 38 ++++ .../example_as_module/CMakeLists.txt | 9 + .../handler_demo/example_as_module/Kconfig | 36 ++++ .../example_as_module/include/example_mgmt.h | 45 ++++ .../include/example_mgmt_callbacks.h | 37 ++++ .../example_as_module/src/example_mgmt.c | 194 ++++++++++++++++++ .../example_as_module/zephyr/module.yml | 5 + .../mgmt/mcumgr/handler_demo/module.conf | 4 + .../subsys/mgmt/mcumgr/handler_demo/prj.conf | 19 ++ .../mgmt/mcumgr/handler_demo/src/main.c | 62 ++++++ .../mgmt/mcumgr/handler_demo/testcase.yaml | 26 +++ 12 files changed, 493 insertions(+) create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/Kconfig create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/Kconfig create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt.h create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt_callbacks.h create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/src/example_mgmt.c create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/zephyr/module.yml create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/module.conf create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/prj.conf create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/src/main.c create mode 100644 tests/subsys/mgmt/mcumgr/handler_demo/testcase.yaml diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/handler_demo/CMakeLists.txt new file mode 100644 index 000000000000..515889d54b47 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +# This adds the example module to the list of extra zephyr modules +list(APPEND ZEPHYR_EXTRA_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/example_as_module") + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(handler_demo) + +target_sources(app PRIVATE src/main.c) + +# Include handler files +if(CONFIG_MCUMGR_GRP_EXAMPLE_APP) + target_sources(app PRIVATE example_as_module/src/example_mgmt.c) + zephyr_include_directories(example_as_module/include) +endif() diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/Kconfig b/tests/subsys/mgmt/mcumgr/handler_demo/Kconfig new file mode 100644 index 000000000000..5be58cae2b38 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/Kconfig @@ -0,0 +1,38 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# The Kconfig file is dedicated to example management group of +# of MCUmgr subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_EXAMPLE_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. +if MCUMGR + +menuconfig MCUMGR_GRP_EXAMPLE_APP + bool "MCUmgr handlers for example management (app)" + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 + default y + help + Enables MCUmgr handlers for example management. This demonstrates the + file at application-level. + +if MCUMGR_GRP_EXAMPLE_APP +config MCUMGR_GRP_EXAMPLE_OTHER_HOOK + bool "Other hook" + depends on MCUMGR_MGMT_NOTIFICATION_HOOKS + help + Allows applications to receive callback when the "other" example + management function is called + +module = MCUMGR_GRP_EXAMPLE +module-str = mcumgr_grp_example +source "subsys/logging/Kconfig.template.log_config" + +endif + +endif + +source "Kconfig.zephyr" diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/CMakeLists.txt new file mode 100644 index 000000000000..852bf4745cd5 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_MCUMGR_GRP_EXAMPLE_MODULE) + zephyr_library(mgmt_mcumgr_grp_example) + # The below should be updated with the real name of the file + zephyr_library_sources(src/example_mgmt.c) + zephyr_include_directories(include) +endif() diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/Kconfig b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/Kconfig new file mode 100644 index 000000000000..66018d68f995 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/Kconfig @@ -0,0 +1,36 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# The Kconfig file is dedicated to example management group of +# of MCUmgr subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_EXAMPLE_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. +if MCUMGR + +menuconfig MCUMGR_GRP_EXAMPLE_MODULE + bool "MCUmgr handlers for example management (module)" + depends on !MCUMGR_GRP_EXAMPLE_APP + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 + help + Enables MCUmgr handlers for example management. This demonstrates the + file at a zephyr module level. + +if MCUMGR_GRP_EXAMPLE_MODULE + +config MCUMGR_GRP_EXAMPLE_OTHER_HOOK + bool "Other hook" + depends on MCUMGR_MGMT_NOTIFICATION_HOOKS + help + Allows applications to receive callback when the "other" example + management function is called + +module = MCUMGR_GRP_EXAMPLE +module-str = mcumgr_grp_example +source "subsys/logging/Kconfig.template.log_config" + +endif +endif diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt.h b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt.h new file mode 100644 index 000000000000..43f0b0d3a2eb --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_EXAMPLE_MGMT_ +#define H_EXAMPLE_MGMT_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Group ID for example management group. + */ +#define MGMT_GROUP_ID_EXAMPLE MGMT_GROUP_ID_PERUSER + +/** + * Command IDs for example management group. + */ +#define EXAMPLE_MGMT_ID_TEST 0 +#define EXAMPLE_MGMT_ID_OTHER 1 + +/** + * Command result codes for example management group. + */ +enum example_mgmt_ret_code_t { + /** No error, this is implied if there is no ret value in the response */ + EXAMPLE_MGMT_RET_RC_OK = 0, + + /** Unknown error occurred. */ + EXAMPLE_MGMT_RET_RC_UNKNOWN, + + /** The provided value is not wanted at this time. */ + EXAMPLE_MGMT_RET_RC_NOT_WANTED, + + /** The provided value was rejected by a hook. */ + EXAMPLE_MGMT_RET_RC_REJECTED_BY_HOOK, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt_callbacks.h b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt_callbacks.h new file mode 100644 index 000000000000..f74a8db097a0 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt_callbacks.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_MCUMGR_EXAMPLE_MGMT_CALLBACKS_ +#define H_MCUMGR_EXAMPLE_MGMT_CALLBACKS_ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is the event ID for the example group */ +#define MGMT_EVT_GRP_EXAMPLE MGMT_EVT_GRP_USER_CUSTOM_START + +/* MGMT event opcodes for example management group */ +enum example_mgmt_group_events { + /* Callback when the other command is received, data is example_mgmt_other_data */ + MGMT_EVT_OP_EXAMPLE_OTHER = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_EXAMPLE, 0), + + /* Used to enable all smp_group events */ + MGMT_EVT_OP_EXAMPLE_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_EXAMPLE), +}; + +/* Structure provided in the #MGMT_EVT_OP_EXAMPLE_OTHER notification callback */ +struct example_mgmt_other_data { + /* Contains the user supplied value */ + uint32_t user_value; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/src/example_mgmt.c b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/src/example_mgmt.c new file mode 100644 index 000000000000..f5bb6eccaf12 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/src/example_mgmt.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +/* The below should be updated with the real name of the file */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS) +#include +#if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK) +/* The below should be updated with the real name of the file */ +#include +#endif +#endif + +LOG_MODULE_REGISTER(mcumgr_example_grp, CONFIG_MCUMGR_GRP_EXAMPLE_LOG_LEVEL); +/* Example function with "read" command support, requires both parameters are supplied */ +static int example_mgmt_test(struct smp_streamer *ctxt) +{ + uint32_t uint_value = 0; + zcbor_state_t *zse = ctxt->writer->zs; + zcbor_state_t *zsd = ctxt->reader->zs; + bool ok; + struct zcbor_string string_value = { 0 }; + size_t decoded; + struct zcbor_map_decode_key_val example_test_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("uint_key", zcbor_uint32_decode, &uint_value), + ZCBOR_MAP_DECODE_KEY_DECODER("string_key", zcbor_tstr_decode, &string_value), + }; + + LOG_DBG("Example test function called"); + + ok = zcbor_map_decode_bulk(zsd, example_test_decode, ARRAY_SIZE(example_test_decode), + &decoded) == 0; + /* Check that both parameters were supplied and that the value of "string_key" is not + * empty + */ + if (!ok || string_value.len == 0 || !zcbor_map_decode_bulk_key_found( + example_test_decode, ARRAY_SIZE(example_test_decode), "uint_key")) { + return MGMT_ERR_EINVAL; + } + + /* If the value of "uint_key" is over 50, return an error of "not wanted" */ + if (uint_value > 50) { + ok = smp_add_cmd_ret(zse, MGMT_GROUP_ID_EXAMPLE, EXAMPLE_MGMT_RET_RC_NOT_WANTED); + goto end; + } + + /* Otherwise, return an integer value of 4691 */ + ok = zcbor_tstr_put_lit(zse, "return_int") && + zcbor_int32_put(zse, 4691); + +end: + /* If "ok" is false, then there was an error processing the output cbor message, which + * likely indicates a lack of available memory + */ + return (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); +} + +/* Example function with "write" command support */ +static int example_mgmt_other(struct smp_streamer *ctxt) +{ + uint32_t user_value = 0; + zcbor_state_t *zse = ctxt->writer->zs; + zcbor_state_t *zsd = ctxt->reader->zs; + bool ok; + size_t decoded; + struct zcbor_map_decode_key_val example_other_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("user_value", zcbor_uint32_decode, &user_value), + }; + +#if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK) + struct example_mgmt_other_data other_data; + enum mgmt_cb_return status; + int32_t ret_rc; + uint16_t ret_group; +#endif + + LOG_DBG("Example other function called"); + + ok = zcbor_map_decode_bulk(zsd, example_other_decode, ARRAY_SIZE(example_other_decode), + &decoded) == 0; + + /* The supplied value is optional, therefore do not return an error if it was not + * provided + */ + if (!ok) { + return MGMT_ERR_EINVAL; + } + +#if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK) + /* Send request to application to check what to do */ + other_data.user_value = user_value; + status = mgmt_callback_notify(MGMT_EVT_OP_EXAMPLE_OTHER, &other_data, sizeof(other_data), + &ret_rc, &ret_group); + if (status != MGMT_CB_OK) { + /* If a callback returned an RC error, exit out, if it returned a group error + * code, add the error code to the response and return to the calling function to + * have it sent back to the client + */ + if (status == MGMT_CB_ERROR_RC) { + return ret_rc; + } + + ok = smp_add_cmd_ret(zse, ret_group, (uint16_t)ret_rc); + goto end; + } +#endif + /* Return some dummy data to the client */ + ok = zcbor_tstr_put_lit(zse, "return_string") && + zcbor_tstr_put_lit(zse, "some dummy data!"); + +#if defined(CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK) +end: +#endif + /* If "ok" is false, then there was an error processing the output cbor message, which + * likely indicates a lack of available memory + */ + return (ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE); +} + +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL +/* This is a lookup function that converts from SMP version 2 group error codes to legacy + * MCUmgr error codes, it is only included if support for the original protocol is enabled. + * Note that in SMP version 2, MCUmgr error codes can still be returned, but are to be used + * only for general SMP/MCUmgr errors. The success/OK error code is not used in translation + * functions as it is automatically handled by the base SMP code. + */ +static int example_mgmt_translate_error_code(uint16_t ret) +{ + int rc; + + switch (ret) { + case EXAMPLE_MGMT_RET_RC_NOT_WANTED: + rc = MGMT_ERR_ENOENT; + break; + + case EXAMPLE_MGMT_RET_RC_REJECTED_BY_HOOK: + rc = MGMT_ERR_EBADSTATE; + break; + + case EXAMPLE_MGMT_RET_RC_UNKNOWN: + default: + rc = MGMT_ERR_EUNKNOWN; + } + + return rc; +} +#endif + +static const struct mgmt_handler example_mgmt_handlers[] = { + [EXAMPLE_MGMT_ID_TEST] = { + .mh_read = example_mgmt_test, + .mh_write = NULL, + }, + [EXAMPLE_MGMT_ID_OTHER] = { + .mh_read = NULL, + .mh_write = example_mgmt_other, + }, +}; + +static struct mgmt_group example_mgmt_group = { + .mg_handlers = example_mgmt_handlers, + .mg_handlers_count = ARRAY_SIZE(example_mgmt_handlers), + .mg_group_id = MGMT_GROUP_ID_EXAMPLE, +#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + .mg_translate_error = example_mgmt_translate_error_code, +#endif +}; + +static void example_mgmt_register_group(void) +{ + /* This function is called during system init before main() is invoked, if the + * handler needs to set anything up before it can be used, it should do it here. + * This register the group so that clients can call the function handlers. + */ + mgmt_register_group(&example_mgmt_group); +} + +MCUMGR_HANDLER_DEFINE(example_mgmt, example_mgmt_register_group); diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/zephyr/module.yml b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/zephyr/module.yml new file mode 100644 index 000000000000..2c2ce96a3860 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/zephyr/module.yml @@ -0,0 +1,5 @@ +name: example_as_module + +build: + cmake: ./ + kconfig: ./Kconfig diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/module.conf b/tests/subsys/mgmt/mcumgr/handler_demo/module.conf new file mode 100644 index 000000000000..a104cfecf496 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/module.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +CONFIG_MCUMGR_GRP_EXAMPLE_APP=n +CONFIG_MCUMGR_GRP_EXAMPLE_MODULE=y diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/prj.conf b/tests/subsys/mgmt/mcumgr/handler_demo/prj.conf new file mode 100644 index 000000000000..9bbed9bb004c --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/prj.conf @@ -0,0 +1,19 @@ +CONFIG_NET_BUF=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_MCUMGR=y + +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_LOG=y +CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y +CONFIG_LOG_MAX_LEVEL=3 + +CONFIG_BASE64=y +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_MCUMGR_TRANSPORT_SHELL=y + +CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y +CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK=y diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/src/main.c b/tests/subsys/mgmt/mcumgr/handler_demo/src/main.c new file mode 100644 index 000000000000..f4f2ffa70a1a --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/src/main.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define LOG_LEVEL LOG_LEVEL_DBG +#include +LOG_MODULE_REGISTER(handler_demo); + +#if !defined(CONFIG_MCUMGR_GRP_EXAMPLE_APP) && !defined(CONFIG_MCUMGR_GRP_EXAMPLE_MODULE) +#error Building this application with neither CONFIG_MCUMGR_GRP_EXAMPLE_APP or \ + CONFIG_MCUMGR_GRP_EXAMPLE_MODULE enabled is not valid +#endif + +#ifdef CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK +#include +#include +#include +#include + +static struct mgmt_callback test_callback; +static bool last_run; + +enum mgmt_cb_return test_function(uint32_t event, enum mgmt_cb_return prev_status, int32_t *rc, + uint16_t *group, bool *abort_more, void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_EXAMPLE_OTHER) { + last_run = !last_run; + + if (last_run) { + /* Return a dummy error for a demo */ + *group = MGMT_GROUP_ID_EXAMPLE; + *rc = EXAMPLE_MGMT_RET_RC_REJECTED_BY_HOOK; + + LOG_INF("Received hook, rejecting!"); + return MGMT_CB_ERROR_RET; + } + + LOG_INF("Received hook, allowing"); + } else { + LOG_ERR("Received unknown event: %d", event); + } + + /* Return OK status code to continue with acceptance to underlying handler */ + return MGMT_CB_OK; +} +#endif + +int main(void) +{ +#ifdef CONFIG_MCUMGR_GRP_EXAMPLE_OTHER_HOOK + /* Register for the example hook */ + test_callback.callback = test_function; + test_callback.event_id = MGMT_EVT_OP_EXAMPLE_OTHER; + mgmt_callback_register(&test_callback); +#endif + + return 0; +} diff --git a/tests/subsys/mgmt/mcumgr/handler_demo/testcase.yaml b/tests/subsys/mgmt/mcumgr/handler_demo/testcase.yaml new file mode 100644 index 000000000000..88e6eae4b5e2 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/handler_demo/testcase.yaml @@ -0,0 +1,26 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +common: + tags: + - handler_demo + - mcumgr + - mgmt +tests: + mgmt.mcumgr.handler.demo: + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 + build_only: true + mgmt.mcumgr.handler.demo.module: + extra_args: + - OVERLAY_CONFIG="module.conf" + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 + build_only: true From d52b6346108234594e63a1b03d6d69fddf40019b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Jun 2023 10:04:09 +0100 Subject: [PATCH 1538/2042] doc: mgmt: mcumgr: Add details on making handlers Adds a guide on how to make out-of-tree MCUmgr function handlers and groups, with an example showing a test implementation. Signed-off-by: Jamie McCrae --- doc/services/device_mgmt/index.rst | 1 + doc/services/device_mgmt/mcumgr_handlers.rst | 203 +++++++++++++++++++ scripts/ci/check_compliance.py | 3 + 3 files changed, 207 insertions(+) create mode 100644 doc/services/device_mgmt/mcumgr_handlers.rst diff --git a/doc/services/device_mgmt/index.rst b/doc/services/device_mgmt/index.rst index e50acf724816..22ab494defbb 100644 --- a/doc/services/device_mgmt/index.rst +++ b/doc/services/device_mgmt/index.rst @@ -7,6 +7,7 @@ Device Management :maxdepth: 1 mcumgr.rst + mcumgr_handlers.rst mcumgr_callbacks.rst mcumgr_backporting.rst smp_protocol.rst diff --git a/doc/services/device_mgmt/mcumgr_handlers.rst b/doc/services/device_mgmt/mcumgr_handlers.rst new file mode 100644 index 000000000000..e189ea887d47 --- /dev/null +++ b/doc/services/device_mgmt/mcumgr_handlers.rst @@ -0,0 +1,203 @@ +.. _mcumgr_handlers: + +MCUmgr handlers +############### + +Overview +******** + +MCUmgr functions by having group handlers which identify a group of functions relating to a +specific management area, which is addressed with a 16-bit identification value, +:c:enum:`mcumgr_group_t` contains the management groups available in Zephyr with their +corresponding group ID values. The group ID is included in SMP headers to identify which +group a command belongs to, there is also an 8-bit command ID which identifies the function of +that group to execute - see :ref:`mcumgr_smp_protocol_specification` for details on the SMP +protocol and header. There can only be one registered group per unique ID. + +Implementation +************** + +MCUmgr handlers can be added externally by application code or by module code, they do not have +to reside in the upstream Zephyr tree to be usable. The first step to creating a handler is to +create the folder structure for it, the typical Zephyr MCUmgr group layout is as follows: + +.. code-block:: none + +

/grp/_mgmt/ + ├── CMakeLists.txt + ├── Kconfig + ├── include + ├──── _mgmt.h + ├──── _mgmt_callbacks.h + ├── src + └──── _mgmt.c + +Note that the header files in upstream Zephyr MCUmgr handlers reside in the +``zephyr/include/zephyr/mgmt/mcumgr/grp/_mgmt`` directory to allow the files to be +globally included by applications. + +Initial header _mgmt.h +================================ + +The purpose of the header file is to provide defines which can be used by the MCUmgr handler +itself and application code, e.g. to reference the command IDs for executing functions. An example +file would look similar to: + +.. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt.h + :language: c + :linenos: + +This provides the defines for 2 command ``test`` and ``other`` and sets up the SMP version 2 error +responses (which have unique error codes per group as opposed to the legacy SMP version 1 error +responses that return a :c:enum:`mcumgr_err_t` - there should always be an OK error code with the +value 0 and an unknown error code with the value 1. The above example then adds an error code of +``not wanted`` with value 2. In addition, the group ID is set to be +:c:enum:`MGMT_GROUP_ID_PERUSER`, which is the start group ID for user-defined groups, note that +group IDs need to be unique so other custom groups should use different values, a central index +header file (as upstream Zephyr has) can be used to distribute group IDs more easily. + +Initial header _mgmt_callbacks.h +========================================== + +The purpose of the header file is to provide defines which can be used by the MCUmgr handler +itself and application code, e.g. to reference the command IDs for executing functions. An example +file would look similar to: + +.. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/include/example_mgmt_callbacks.h + :language: c + :linenos: + +This sets up a single event which application (or module) code can register for to receive a +callback when the function handler is executed, which allows the flow of the handler to be +changed (i.e. to return an error instead of continuing). The event group ID is set to +:c:enum:`MGMT_EVT_GRP_USER_CUSTOM_START`, which is the start event ID for user-defined groups, +note that event IDs need to be unique so other custom groups should use different values, a +central index header file (as upstream Zephyr has) can be used to distribute event IDs more +easily. + +Initial source _mgmt.c +================================ + +The purpose of this source file is to handle the incoming MCUmgr commands, provide responses, and +register the transport with MCUmgr so that commands will be sent to it. An example file would +look similar to: + +.. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/src/example_mgmt.c + :language: c + :linenos: + +The above code creates 2 function handlers, ``test`` which supports read requests and takes 2 +required parameters, and ``other`` which supports write requests and takes 1 optional parameter, +this function handler has an optional notification callback feature that allows other parts of +the code to listen for the event and take any required actions that are necessary or prevent +further execution of the function by returning an error, further details on MCUmgr callback +functionality can be found on :ref:`mcumgr_callbacks`. + +Note that other code referencing callbacks for custom MCUmgr handlers needs to include both the +base Zephyr callback include file and the custom handler callback file, only in-tree Zephyr +handler headers are included when including the upstream Zephyr callback header file. + +Initial Kconfig +=============== + +The purpose of the Kconfig file is to provide options which users can enable or change relating +to the functionality of the handler being implemented. An example file would look similar to: + +.. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/Kconfig + :language: kconfig + +Initial CMakeLists.txt +====================== + +The CMakeLists.txt file is used by the build system to setup files to compile, include +directories to add and specify options that can be changed. A basic file only need to include the +source files if the Kconfig options are enabled. An example file would look similar to: + +.. tabs:: + + .. group-tab:: Zephyr module + + .. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/example_as_module/CMakeLists.txt + :language: cmake + + .. group-tab:: Application + + .. literalinclude:: ../../../tests/subsys/mgmt/mcumgr/handler_demo/CMakeLists.txt + :language: cmake + :start-after: Include handler files + +Including from application +************************** + +Application-specific MCUmgr handlers can be added by creating/editing application build files. +Example modifications are shown below. + +Example CMakeLists.txt +====================== + +The application ``CMakeLists.txt`` file can load the CMake file for the example MCUmgr handler by +adding the following: + +.. code-block:: cmake + + add_subdirectory(mcumgr/grp/) + +Example Kconfig +=============== + +The application Kconfig file can include the Kconfig file for the example MCUmgr handler by adding +the following to the ``Kconfig`` file in the application directory (or creating it if it does not +exist): + +.. code-block:: kconfig + + rsource "mcumgr/grp//Kconfig" + + # Include Zephyr's Kconfig + source "Kconfig.zephyr" + +Including from Zephyr Module +**************************** + +Zephyr :ref:`modules` can be used to add custom MCUmgr handlers to multiple different applications +without needing to duplicate the code in each application's source tree, see :ref:`module-yml` for +details on how to set up the module files. Example files are shown below. + +Example zephyr/module.yml +========================= + +This is an example file which can be used to load the Kconfig and CMake files from the root of the +module directory, and would be placed at ``zephyr/module.yml``: + +.. code-block:: yaml + + build: + kconfig: Kconfig + cmake: . + +Example CMakeLists.txt +====================== + +This is an example CMakeLists.txt file which loads the CMake file for the example MCUmgr handler, +and would be placed at ``CMakeLists.txt``: + +.. code-block:: cmake + + add_subdirectory(mcumgr/grp/) + +Example Kconfig +=============== + +This is an example Kconfig file which loads the Kconfig file for the example MCUmgr handler, and +would be placed at ``Kconfig``: + +.. code-block:: kconfig + + rsource "mcumgr/grp//Kconfig" + +Demonstration handler +********************* + +There is a demonstration project which includes configuration for both application and zephyr +module-MCUmgr handlers which can be used as a basis for created your own in +:zephyr_file:`tests/subsys/mgmt/mcumgr/handler_demo/`. diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index f5e3002fd5ea..bf96755ecf38 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -660,6 +660,9 @@ def check_no_undef_outside_kconfig(self, kconf): "MCUBOOT_CLEANUP_ARM_CORE", # Used in (sysbuild-based) test "MCUBOOT_SERIAL", # Used in (sysbuild-based) test/ # documentation + "MCUMGR_GRP_EXAMPLE", # Used in documentation + "MCUMGR_GRP_EXAMPLE_LOG_LEVEL", # Used in documentation + "MCUMGR_GRP_EXAMPLE_OTHER_HOOK", # Used in documentation "MISSING", "MODULES", "MYFEATURE", From 7411fbcb5b19a1eba440614d1375bfb06c4dd938 Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Wed, 24 May 2023 02:46:50 -0700 Subject: [PATCH 1539/2042] pinctrl: npcx: add DEV_CTLx configuration support Add a new pinctrl type to control peripheral modules' specific IO characteristics such as tri-state, the power supply type selection (3.3V or 1.8V), and so on. In NPCX series, the corresponding registers/fields are irregular. This CL wraps these definitions to dt nodes and put them in pinctrl property if needed. Signed-off-by: Mulin Chao --- drivers/pinctrl/pinctrl_npcx.c | 13 +++++++ dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi | 28 ++++++++++++++ dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi | 37 +++++++++++++++++++ .../pinctrl/nuvoton,npcx-pinctrl.yaml | 3 ++ soc/arm/nuvoton_npcx/common/pinctrl_soc.h | 37 +++++++++++++++++++ soc/arm/nuvoton_npcx/common/reg/reg_def.h | 1 + 6 files changed, 119 insertions(+) diff --git a/drivers/pinctrl/pinctrl_npcx.c b/drivers/pinctrl/pinctrl_npcx.c index 22848b937d17..5759122018f4 100644 --- a/drivers/pinctrl/pinctrl_npcx.c +++ b/drivers/pinctrl/pinctrl_npcx.c @@ -153,6 +153,16 @@ static void npcx_psl_input_detection_configure(const pinctrl_soc_pin_t *pin) } } +static void npcx_device_control_configure(const pinctrl_soc_pin_t *pin) +{ + const struct npcx_dev_ctl *ctrl = (const struct npcx_dev_ctl *)&pin->cfg.dev_ctl; + const uintptr_t scfg_base = npcx_pinctrl_cfg.base_scfg; + + SET_FIELD(NPCX_DEV_CTL(scfg_base, ctrl->offest), + FIELD(ctrl->field_offset, ctrl->field_size), + ctrl->field_value); +} + /* Pinctrl API implementation */ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) @@ -164,6 +174,9 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, if (pins[i].flags.type == NPCX_PINCTRL_TYPE_PERIPH) { /* Configure peripheral device's pinmux functionality */ npcx_periph_configure(&pins[i], reg); + } else if (pins[i].flags.type == NPCX_PINCTRL_TYPE_DEVICE_CTRL) { + /* Configure device's io characteristics */ + npcx_device_control_configure(&pins[i]); } else if (pins[i].flags.type == NPCX_PINCTRL_TYPE_PSL_IN) { /* Configure SPL input's detection mode */ npcx_psl_input_detection_configure(&pins[i]); diff --git a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi index 26baa312a145..e9acb4a09782 100644 --- a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi @@ -5,7 +5,35 @@ */ &pinctrl { + /* Prebuild nodes for peripheral device's characteristics (Optional) */ + /omit-if-no-ref/ vhif_lpc_sl: devctl-vhif-3p3v-lpc { + dev-ctl = <0x0 2 2 0x01>; + }; + + /omit-if-no-ref/ vhif_espi_shi_sl: devctl-vhif-1p8v-espi-shi { + dev-ctl = <0x0 2 2 0x02>; + }; + + /omit-if-no-ref/ ext_flash_tris_off: devctl-fiu-ext-tris-off { + dev-ctl = <0x0 6 1 0x00>; + }; + + /omit-if-no-ref/ ext_flash_tris_on: devctl-fiu-ext-tris-on { + dev-ctl = <0x0 6 1 0x01>; + }; + /* Prebuild nodes for peripheral device's pin-muxing and pad properties */ + /* Flash Interface Unit (FIU) */ + /omit-if-no-ref/ fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0: periph-fiu-ext { + dev-ctl = <0x6 1 1 0x00>; /* Select to external flash */ + pinmux = <&alt0_gpio_no_fpip>; + }; + + /omit-if-no-ref/ int_flash_sl: periph-fiu-int { + dev-ctl = <0x6 1 1 0x01>; /* Select to internal flash */ + /* No need for pin-muxing */ + }; + /* Host peripheral interfaces */ /omit-if-no-ref/ espi_lpc_gp46_47_51_52_53_54_55_57: periph-lpc-espi { pinmux = <&alt1_no_lpc_espi>; diff --git a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi index 51275147558d..2fe2b1f75c9b 100644 --- a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi @@ -5,7 +5,44 @@ */ &pinctrl { + + /* Prebuild nodes for peripheral device's characteristics (Optional) */ + /omit-if-no-ref/ vhif_lpc_sl: devctl-vhif-3p3v-lpc { + dev-ctl = <0x0 2 2 0x01>; + }; + + /omit-if-no-ref/ vhif_espi_shi_sl: devctl-vhif-1p8v-espi-shi { + dev-ctl = <0x0 2 2 0x02>; + }; + + /omit-if-no-ref/ ext_flash_tris_off: devctl-fiu-ext-tris-off { + dev-ctl = <0x0 6 1 0x00>; + }; + + /omit-if-no-ref/ ext_flash_tris_on: devctl-fiu-ext-tris-on { + dev-ctl = <0x0 6 1 0x01>; + }; + /* Prebuild nodes for peripheral device's pin-muxing and pad properties */ + /* Flash Interface Unit (FIU) */ + /omit-if-no-ref/ fiu_ext_io0_io1_clk_cs_gpa4_96_a2_a0: periph-fiu-ext { + dev-ctl = <0x6 1 1 0x00>; /* Select to external flash */ + pinmux = <&alt0_gpio_no_fpip>; + }; + + /omit-if-no-ref/ ext_flash_cs1_gpa6: periph-ext-spi-flash-cs1 { + pinmux = <&alt0_f_spi_cs1>; + }; + + /omit-if-no-ref/ int_flash_sl: periph-fiu-int { + dev-ctl = <0x6 1 1 0x01>; /* Select to internal flash */ + /* No need for pin-muxing */ + }; + + /omit-if-no-ref/ fiu_ext_quad_io2_io3_gp93_a7: periph-fiu-ext-quad { + pinmux = <&alt0_f_spi_quad>; + }; + /* Host peripheral interfaces */ /omit-if-no-ref/ espi_lpc_gp46_47_51_52_53_54_55_57: periph-lpc-espi { pinmux = <&alt1_no_lpc_espi>; diff --git a/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml b/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml index 962ecad5fa87..f1ecdc8d8912 100644 --- a/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml +++ b/dts/bindings/pinctrl/nuvoton,npcx-pinctrl.yaml @@ -57,6 +57,9 @@ child-binding: pinmux: type: phandle description: Configurations of pinmux selection + dev-ctl: + type: array + description: Configurations of device control such as tri-state, io type and so on. periph-pupd: type: array description: | diff --git a/soc/arm/nuvoton_npcx/common/pinctrl_soc.h b/soc/arm/nuvoton_npcx/common/pinctrl_soc.h index cd8af7584ba0..8f03faa82b71 100644 --- a/soc/arm/nuvoton_npcx/common/pinctrl_soc.h +++ b/soc/arm/nuvoton_npcx/common/pinctrl_soc.h @@ -16,6 +16,7 @@ */ enum npcx_pinctrl_type { NPCX_PINCTRL_TYPE_PERIPH, + NPCX_PINCTRL_TYPE_DEVICE_CTRL, NPCX_PINCTRL_TYPE_PSL_IN, NPCX_PINCTRL_TYPE_RESERVED, }; @@ -81,6 +82,23 @@ struct npcx_periph { uint16_t reserved: 2; } __packed; +/** + * @brief NPCX device control structure + * + * Used to indicate the device's corresponding register/field for its io + * characteristics such as tri-state, power supply type selection, and so on. + */ +struct npcx_dev_ctl { + /** Related register offset for device configuration. */ + uint16_t offest: 5; + /** Related register field offset for device control. */ + uint16_t field_offset: 3; + /** Related register field size for device control. */ + uint16_t field_size: 3; + /** field value */ + uint16_t field_value: 5; +} __packed; + /** * @brief NPCX Power Switch Logic (PSL) input pad configuration structure * @@ -103,6 +121,7 @@ struct npcx_psl_input { struct npcx_pinctrl { union { struct npcx_periph periph; + struct npcx_dev_ctl dev_ctl; struct npcx_psl_input psl_in; uint16_t cfg_word; } cfg; @@ -163,6 +182,21 @@ typedef struct npcx_pinctrl pinctrl_soc_pin_t; .cfg.periph.inverted = DT_PHA(DT_PROP(node_id, prop), alts, inv), \ }, +/** + * @brief Utility macro to initialize a periphral pinmux configuration. + * + * @param node_id Node identifier. + * @param prop Property name for pinmux configuration. (i.e. 'pinmux') + */ +#define Z_PINCTRL_NPCX_DEVICE_CONTROL_INIT(node_id, prop) \ + { \ + .flags.type = NPCX_PINCTRL_TYPE_DEVICE_CTRL, \ + .cfg.dev_ctl.offest = DT_PROP_BY_IDX(node_id, prop, 0), \ + .cfg.dev_ctl.field_offset = DT_PROP_BY_IDX(node_id, prop, 1), \ + .cfg.dev_ctl.field_size = DT_PROP_BY_IDX(node_id, prop, 2), \ + .cfg.dev_ctl.field_value = DT_PROP_BY_IDX(node_id, prop, 3), \ + }, + /** * @brief Utility macro to initialize a periphral pull-up/down configuration. * @@ -227,6 +261,9 @@ typedef struct npcx_pinctrl pinctrl_soc_pin_t; COND_CODE_1(Z_PINCTRL_NPCX_HAS_PSL_IN_PROP(DT_PROP_BY_IDX(node_id, prop, idx)), \ (Z_PINCTRL_NPCX_PSL_IN_DETECT_CONF_INIT( \ DT_PROP_BY_IDX(node_id, prop, idx), psl_polarity)), ()) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_PROP_BY_IDX(node_id, prop, idx), dev_ctl), \ + (Z_PINCTRL_NPCX_DEVICE_CONTROL_INIT( \ + DT_PROP_BY_IDX(node_id, prop, idx), dev_ctl)), ()) \ COND_CODE_1(DT_NODE_HAS_PROP(DT_PROP_BY_IDX(node_id, prop, idx), pinmux), \ (Z_PINCTRL_NPCX_PERIPH_PINMUX_INIT( \ DT_PROP_BY_IDX(node_id, prop, idx), pinmux)), ()) diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 31517a0189c4..4bed431a457f 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -254,6 +254,7 @@ static inline uint32_t npcx_lv_gpio_ctl_offset(uint32_t ctl_no) } /* Macro functions for SCFG multi-registers */ +#define NPCX_DEV_CTL(base, n) (*(volatile uint8_t *)(base + n)) #define NPCX_DEVALT(base, n) (*(volatile uint8_t *)(base + \ npcx_devalt_offset(n))) #define NPCX_DEVALT_LK(base, n) (*(volatile uint8_t *)(base + \ From f34fff91bc7215cfe0b0186fec479acd9486936c Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Mon, 19 Jun 2023 18:44:57 -0700 Subject: [PATCH 1540/2042] driver: flash: npcx: introduce npcx flash driver This CL attempts to implement npcx's flash driver instead of the original one (npcx spi driver plus spi_nor flash driver). Signed-off-by: Mulin Chao --- drivers/flash/CMakeLists.txt | 2 + drivers/flash/Kconfig | 2 + drivers/flash/Kconfig.npcx_fiu | 34 + drivers/flash/flash_npcx_fiu_nor.c | 625 ++++++++++++++++++ drivers/flash/flash_npcx_fiu_qspi.c | 271 ++++++++ drivers/flash/flash_npcx_fiu_qspi.h | 82 +++ drivers/spi/CMakeLists.txt | 1 - drivers/spi/Kconfig | 2 - drivers/spi/Kconfig.npcx_fiu | 12 - drivers/spi/spi_npcx_fiu.c | 183 ----- dts/arm/nuvoton/npcx/npcx.dtsi | 7 +- dts/arm/nuvoton/npcx7m6fb.dtsi | 17 +- dts/arm/nuvoton/npcx7m6fc.dtsi | 17 +- dts/arm/nuvoton/npcx7m7fc.dtsi | 17 +- dts/arm/nuvoton/npcx9m3f.dtsi | 17 +- dts/arm/nuvoton/npcx9m6f.dtsi | 17 +- dts/arm/nuvoton/npcx9m7f.dtsi | 15 +- .../nuvoton,npcx-fiu-nor.yaml | 56 ++ .../nuvoton,npcx-fiu-qspi.yaml | 40 ++ dts/bindings/spi/nuvoton,npcx-spi-fiu.yaml | 14 - .../zephyr/drivers/flash/npcx_flash_api_ex.h | 75 +++ .../flash_controller/npcx_fiu_qspi.h | 25 + soc/arm/nuvoton_npcx/common/reg/reg_def.h | 18 + soc/arm/nuvoton_npcx/common/registers.c | 4 + 24 files changed, 1302 insertions(+), 251 deletions(-) create mode 100644 drivers/flash/Kconfig.npcx_fiu create mode 100644 drivers/flash/flash_npcx_fiu_nor.c create mode 100644 drivers/flash/flash_npcx_fiu_qspi.c create mode 100644 drivers/flash/flash_npcx_fiu_qspi.h delete mode 100644 drivers/spi/Kconfig.npcx_fiu delete mode 100644 drivers/spi/spi_npcx_fiu.c create mode 100644 dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml create mode 100644 dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml delete mode 100644 dts/bindings/spi/nuvoton,npcx-spi-fiu.yaml create mode 100644 include/zephyr/drivers/flash/npcx_flash_api_ex.h create mode 100644 include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index c34a62804ea1..b78ce14e78cc 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -38,6 +38,8 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_flexspi_mx25um51345g.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 84ee3d9769fb..2229d5207050 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -118,6 +118,8 @@ source "drivers/flash/Kconfig.mcux" source "drivers/flash/Kconfig.nios2_qspi" +source "drivers/flash/Kconfig.npcx_fiu" + source "drivers/flash/Kconfig.gecko" source "drivers/flash/Kconfig.nor" diff --git a/drivers/flash/Kconfig.npcx_fiu b/drivers/flash/Kconfig.npcx_fiu new file mode 100644 index 000000000000..d46d7f2e0dcc --- /dev/null +++ b/drivers/flash/Kconfig.npcx_fiu @@ -0,0 +1,34 @@ +# NPCX Flash driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_NPCX_FIU_QSPI + bool "Nuvoton NPCX QSPI Bus Flash driver" + default y + depends on DT_HAS_NUVOTON_NPCX_FIU_QSPI_ENABLED + help + This option enables the QSPI Bus Flash driver for NPCX family of + processors. + +config FLASH_NPCX_FIU_NOR + bool "Nuvoton NPCX embedded controller (EC) QSPI NOR Flash driver" + default y + depends on DT_HAS_NUVOTON_NPCX_FIU_NOR_ENABLED + depends on FLASH_NPCX_FIU_QSPI + select FLASH_HAS_DRIVER_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_JESD216 + select FLASH_HAS_EX_OP + help + This option enables the QSPI NOR Flash driver for NPCX family of + processors. + +config FLASH_NPCX_FIU_NOR_INIT + bool "QSPI NOR flash feature during driver initialization" + default y + depends on FLASH_NPCX_FIU_NOR + help + This option enables the QSPI NOR Flash features such as Quad-Enable, + 4-byte address support and so on during driver initialization. Disable + it if QSPI NOR devices are not ready during driver initialization. diff --git a/drivers/flash/flash_npcx_fiu_nor.c b/drivers/flash/flash_npcx_fiu_nor.c new file mode 100644 index 000000000000..85bde757ce5d --- /dev/null +++ b/drivers/flash/flash_npcx_fiu_nor.c @@ -0,0 +1,625 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_fiu_nor + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_USERSPACE +#include +#include +#endif + +#include "flash_npcx_fiu_qspi.h" +#include "spi_nor.h" + +#include +LOG_MODULE_REGISTER(flash_npcx_fiu_nor, CONFIG_FLASH_LOG_LEVEL); + +/* Device config */ +struct flash_npcx_nor_config { + /* QSPI bus device for mutex control and bus configuration */ + const struct device *qspi_bus; + /* Mapped address for flash read via direct access */ + uintptr_t mapped_addr; + /* Size of nor device in bytes, from size property */ + uint32_t flash_size; + /* Minimum size for flash erase */ + uint32_t min_erase_size; + /* Maximum chip erase time-out in ms */ + uint32_t max_timeout; + /* SPI Nor device configuration on QSPI bus */ + struct npcx_qspi_cfg qspi_cfg; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif +}; + +/* Device data */ +struct flash_npcx_nor_data { + /* Specific control operation for Quad-SPI Nor Flash */ + uint32_t operation; +}; + +static const struct flash_parameters flash_npcx_parameters = { + .write_block_size = 1, + .erase_value = 0xff, +}; + +#define DT_INST_QUAD_EN_PROP_OR(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, quad_enable_requirements), \ + (_CONCAT(JESD216_DW15_QER_VAL_, \ + DT_INST_STRING_TOKEN(inst, quad_enable_requirements))), \ + ((JESD216_DW15_QER_VAL_NONE))) + +static inline bool is_within_region(off_t addr, size_t size, off_t region_start, + size_t region_size) +{ + return (addr >= region_start && + (addr < (region_start + region_size)) && + ((addr + size) <= (region_start + region_size))); +} + +static int flash_npcx_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg, + uint32_t flags) +{ + const struct flash_npcx_nor_config *config = dev->config; + struct flash_npcx_nor_data *data = dev->data; + int ret; + + /* Lock SPI bus and configure it if needed */ + qspi_npcx_fiu_mutex_lock_configure(config->qspi_bus, &config->qspi_cfg, + data->operation); + + /* Execute UMA transaction */ + ret = qspi_npcx_fiu_uma_transceive(config->qspi_bus, cfg, flags); + + /* Unlock SPI bus */ + qspi_npcx_fiu_mutex_unlock(config->qspi_bus); + + return ret; +} + +/* NPCX UMA functions for SPI NOR flash */ +static int flash_npcx_uma_cmd_only(const struct device *dev, uint8_t opcode) +{ + struct npcx_uma_cfg cfg = { .opcode = opcode}; + + return flash_npcx_uma_transceive(dev, &cfg, 0); /* opcode only */ +} + +static int flash_npcx_uma_cmd_by_addr(const struct device *dev, uint8_t opcode, + uint32_t addr) +{ + struct npcx_uma_cfg cfg = { .opcode = opcode}; + + cfg.addr.u32 = sys_cpu_to_be32(addr); + return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_ADDR); +} + +static int flash_npcx_uma_read(const struct device *dev, uint8_t opcode, + uint8_t *dst, const size_t size) +{ + struct npcx_uma_cfg cfg = { .opcode = opcode, + .rx_buf = dst, + .rx_count = size}; + + return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_READ); +} + +static int flash_npcx_uma_write(const struct device *dev, uint8_t opcode, + uint8_t *src, const size_t size) +{ + struct npcx_uma_cfg cfg = { .opcode = opcode, + .tx_buf = src, + .tx_count = size}; + + return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE); +} + +static int flash_npcx_uma_write_by_addr(const struct device *dev, uint8_t opcode, + uint8_t *src, const size_t size, uint32_t addr) +{ + struct npcx_uma_cfg cfg = { .opcode = opcode, + .tx_buf = src, + .tx_count = size}; + + cfg.addr.u32 = sys_cpu_to_be32(addr); + return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE | + NPCX_UMA_ACCESS_ADDR); +} + +/* Local SPI NOR flash functions */ +static int flash_npcx_nor_wait_until_ready(const struct device *dev) +{ + int ret; + uint8_t reg; + const struct flash_npcx_nor_config *config = dev->config; + int64_t st = k_uptime_get(); + + do { + ret = flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg)); + if (ret != 0) { + return ret; + } else if ((reg & SPI_NOR_WIP_BIT) == 0) { + return 0; + } + + } while ((k_uptime_get() - st) < config->max_timeout); + + return -EBUSY; +} + +static int flash_npcx_nor_read_status_regs(const struct device *dev, uint8_t *sts_reg) +{ + int ret = flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR, sts_reg, 1); + + if (ret != 0) { + return ret; + } + return flash_npcx_uma_read(dev, SPI_NOR_CMD_RDSR2, sts_reg + 1, 1); +} + +static int flash_npcx_nor_write_status_regs(const struct device *dev, uint8_t *sts_reg) +{ + int ret; + + ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN); + if (ret != 0) { + return ret; + } + + ret = flash_npcx_uma_write(dev, SPI_NOR_CMD_WRSR, sts_reg, 2); + if (ret != 0) { + return ret; + } + + return flash_npcx_nor_wait_until_ready(dev); +} + +/* Flash API functions */ +#if defined(CONFIG_FLASH_JESD216_API) +static int flash_npcx_nor_read_jedec_id(const struct device *dev, uint8_t *id) +{ + if (id == NULL) { + return -EINVAL; + } + + return flash_npcx_uma_read(dev, SPI_NOR_CMD_RDID, id, SPI_NOR_MAX_ID_LEN); +} + +static int flash_npcx_nor_read_sfdp(const struct device *dev, off_t addr, + void *data, size_t size) +{ + uint8_t sfdp_addr[4]; + struct npcx_uma_cfg cfg = { .opcode = JESD216_CMD_READ_SFDP, + .tx_buf = sfdp_addr, + .tx_count = 4, + .rx_buf = data, + .rx_count = size}; + + if (data == NULL) { + return -EINVAL; + } + + /* CMD_READ_SFDP needs a 24-bit address followed by a dummy byte */ + sfdp_addr[0] = (addr >> 16) & 0xff; + sfdp_addr[1] = (addr >> 8) & 0xff; + sfdp_addr[2] = addr & 0xff; + return flash_npcx_uma_transceive(dev, &cfg, NPCX_UMA_ACCESS_WRITE | + NPCX_UMA_ACCESS_READ); +} +#endif /* CONFIG_FLASH_JESD216_API */ + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_npcx_nor_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + const struct flash_npcx_nor_config *config = dev->config; + + *layout = &config->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static int flash_npcx_nor_read(const struct device *dev, off_t addr, + void *data, size_t size) +{ + const struct flash_npcx_nor_config *config = dev->config; + struct flash_npcx_nor_data *dev_data = dev->data; + + /* Out of the region of nor flash device? */ + if (!is_within_region(addr, size, 0, config->flash_size)) { + return -EINVAL; + } + + /* Lock/Unlock SPI bus also for DRA mode */ + qspi_npcx_fiu_mutex_lock_configure(config->qspi_bus, &config->qspi_cfg, + dev_data->operation); + + /* Trigger Direct Read Access (DRA) via reading memory mapped-address */ + memcpy(data, (void *)(config->mapped_addr + addr), size); + + qspi_npcx_fiu_mutex_unlock(config->qspi_bus); + + return 0; +} + +static int flash_npcx_nor_erase(const struct device *dev, off_t addr, + size_t size) +{ + const struct flash_npcx_nor_config *config = dev->config; + int ret = 0; + uint8_t opcode; + + /* Out of the region of nor flash device? */ + if (!is_within_region(addr, size, 0, config->flash_size)) { + LOG_ERR("Addr %ld, size %d are out of range", addr, size); + return -EINVAL; + } + + /* address must be sector-aligned */ + if (!SPI_NOR_IS_SECTOR_ALIGNED(addr)) { + LOG_ERR("Addr %ld is not sector-aligned", addr); + return -EINVAL; + } + + /* size must be a multiple of sectors */ + if ((size % config->min_erase_size) != 0) { + LOG_ERR("Size %d is not a multiple of sectors", size); + return -EINVAL; + } + + /* Select erase opcode by size */ + if (size == config->flash_size) { + flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN); + /* Send chip erase command */ + flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_CE); + return flash_npcx_nor_wait_until_ready(dev); + } else if (config->min_erase_size == KB(4)) { + opcode = SPI_NOR_CMD_SE; + } else if (config->min_erase_size == KB(64)) { + opcode = SPI_NOR_CMD_BE; + } else { + return -EINVAL; + } + + while (size > 0) { + flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN); + /* Send page/block erase command with addr */ + flash_npcx_uma_cmd_by_addr(dev, opcode, addr); + addr += config->min_erase_size; + size -= config->min_erase_size; + ret = flash_npcx_nor_wait_until_ready(dev); + if (ret != 0) { + break; + } + } + + return ret; +} + +static int flash_npcx_nor_write(const struct device *dev, off_t addr, + const void *data, size_t size) +{ + const struct flash_npcx_nor_config *config = dev->config; + uint8_t *tx_buf = (uint8_t *)data; + int ret = 0; + size_t sz_write; + + /* Out of the region of nor flash device? */ + if (!is_within_region(addr, size, 0, config->flash_size)) { + return -EINVAL; + } + + /* Don't write more than a page. */ + if (size > SPI_NOR_PAGE_SIZE) { + sz_write = SPI_NOR_PAGE_SIZE; + } else { + sz_write = size; + } + + /* + * Correct the size of first write to not go through page boundary and + * make the address of next write to align to page boundary. + */ + if (((addr + sz_write - 1U) / SPI_NOR_PAGE_SIZE) != (addr / SPI_NOR_PAGE_SIZE)) { + sz_write -= (addr + sz_write) & (SPI_NOR_PAGE_SIZE - 1); + } + + while (size > 0) { + /* Start to write */ + flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN); + ret = flash_npcx_uma_write_by_addr(dev, SPI_NOR_CMD_PP, tx_buf, + sz_write, addr); + if (ret != 0) { + break; + } + + /* Wait for writing completed */ + ret = flash_npcx_nor_wait_until_ready(dev); + if (ret != 0) { + break; + } + + size -= sz_write; + tx_buf += sz_write; + addr += sz_write; + + if (size > SPI_NOR_PAGE_SIZE) { + sz_write = SPI_NOR_PAGE_SIZE; + } else { + sz_write = size; + } + } + + return ret; +} + +static const struct flash_parameters * +flash_npcx_nor_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_npcx_parameters; +}; + +#ifdef CONFIG_FLASH_EX_OP_ENABLED +static int flash_npcx_nor_ex_exec_uma(const struct device *dev, + const struct npcx_ex_ops_uma_in *op_in, + const struct npcx_ex_ops_uma_out *op_out) +{ + int flag = 0; + struct npcx_uma_cfg cfg; + + if (op_in == NULL) { + return -EINVAL; + } + + /* Organize a UMA transaction */ + cfg.opcode = op_in->opcode; + if (op_in->tx_count != 0) { + cfg.tx_buf = op_in->tx_buf; + cfg.tx_count = op_in->tx_count; + flag |= NPCX_UMA_ACCESS_WRITE; + } + + if (op_in->addr_count != 0) { + cfg.addr.u32 = sys_cpu_to_be32(op_in->addr); + flag |= NPCX_UMA_ACCESS_ADDR; + } + + if (op_out != NULL && op_in->rx_count != 0) { + cfg.rx_buf = op_out->rx_buf; + cfg.rx_count = op_in->rx_count; + flag |= NPCX_UMA_ACCESS_READ; + } + + return flash_npcx_uma_transceive(dev, &cfg, flag); +} + +static int flash_npcx_nor_ex_set_spi_spec(const struct device *dev, + const struct npcx_ex_ops_qspi_oper_in *op_in) +{ + struct flash_npcx_nor_data *data = dev->data; + + /* Cannot disable write protection of internal flash */ + if ((data->operation & NPCX_EX_OP_INT_FLASH_WP) != 0) { + if ((op_in->mask & NPCX_EX_OP_INT_FLASH_WP) != 0 && !op_in->enable) { + return -EINVAL; + } + } + + if (op_in->enable) { + data->operation |= op_in->mask; + } else { + data->operation &= ~op_in->mask; + } + + return 0; +} + +static int flash_npcx_nor_ex_get_spi_spec(const struct device *dev, + struct npcx_ex_ops_qspi_oper_out *op_out) +{ + struct flash_npcx_nor_data *data = dev->data; + + op_out->oper = data->operation; + return 0; +} + +static int flash_npcx_nor_ex_op(const struct device *dev, uint16_t code, + const uintptr_t in, void *out) +{ +#ifdef CONFIG_USERSPACE + bool syscall_trap = z_syscall_trap(); +#endif + int ret; + + switch (code) { + case FLASH_NPCX_EX_OP_EXEC_UMA: + { + struct npcx_ex_ops_uma_in *op_in = (struct npcx_ex_ops_uma_in *)in; + struct npcx_ex_ops_uma_out *op_out = (struct npcx_ex_ops_uma_out *)out; +#ifdef CONFIG_USERSPACE + struct npcx_ex_ops_uma_in in_copy; + struct npcx_ex_ops_uma_out out_copy; + + if (syscall_trap) { + Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy))); + op_in = &in_copy; + op_out = &out_copy; + } +#endif + + ret = flash_npcx_nor_ex_exec_uma(dev, op_in, op_out); +#ifdef CONFIG_USERSPACE + if (ret == 0 && syscall_trap) { + Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy))); + } +#endif + break; + } + case FLASH_NPCX_EX_OP_SET_QSPI_OPER: + { + struct npcx_ex_ops_qspi_oper_in *op_in = (struct npcx_ex_ops_qspi_oper_in *)in; +#ifdef CONFIG_USERSPACE + struct npcx_ex_ops_qspi_oper_in in_copy; + + if (syscall_trap) { + Z_OOPS(z_user_from_copy(&in_copy, op_in, sizeof(in_copy))); + op_in = &in_copy; + } +#endif + ret = flash_npcx_nor_ex_set_spi_spec(dev, op_in); + break; + } + case FLASH_NPCX_EX_OP_GET_QSPI_OPER: + { + struct npcx_ex_ops_qspi_oper_out *op_out = + (struct npcx_ex_ops_qspi_oper_out *)out; +#ifdef CONFIG_USERSPACE + struct npcx_ex_ops_qspi_oper_out out_copy; + + if (syscall_trap) { + op_out = &out_copy; + } +#endif + ret = flash_npcx_nor_ex_get_spi_spec(dev, op_out); +#ifdef CONFIG_USERSPACE + if (ret == 0 && syscall_trap) { + Z_OOPS(z_user_to_copy(out, op_out, sizeof(out_copy))); + } +#endif + break; + } + default: + ret = -ENOTSUP; + break; + } + + return ret; +} +#endif + +static const struct flash_driver_api flash_npcx_nor_driver_api = { + .read = flash_npcx_nor_read, + .write = flash_npcx_nor_write, + .erase = flash_npcx_nor_erase, + .get_parameters = flash_npcx_nor_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_npcx_nor_pages_layout, +#endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = flash_npcx_nor_read_sfdp, + .read_jedec_id = flash_npcx_nor_read_jedec_id, +#endif +#ifdef CONFIG_FLASH_EX_OP_ENABLED + .ex_op = flash_npcx_nor_ex_op, +#endif +}; + +static int flash_npcx_nor_init(const struct device *dev) +{ + const struct flash_npcx_nor_config *config = dev->config; + int ret; + + if (!IS_ENABLED(CONFIG_FLASH_NPCX_FIU_NOR_INIT)) { + return 0; + } + + /* Enable quad access of spi NOR flash */ + if (config->qspi_cfg.qer_type != JESD216_DW15_QER_NONE) { + uint8_t qe_idx, qe_bit, sts_reg[2]; + /* Read status registers first */ + ret = flash_npcx_nor_read_status_regs(dev, sts_reg); + if (ret != 0) { + LOG_ERR("Enable quad access: read reg failed %d!", ret); + return ret; + } + switch (config->qspi_cfg.qer_type) { + case JESD216_DW15_QER_S1B6: + qe_idx = 1; + qe_bit = 6; + break; + case JESD216_DW15_QER_S2B1v1: + __fallthrough; + case JESD216_DW15_QER_S2B1v4: + __fallthrough; + case JESD216_DW15_QER_S2B1v5: + qe_idx = 2; + qe_bit = 1; + break; + default: + return -ENOTSUP; + } + /* Set QE bit in status register */ + sts_reg[qe_idx - 1] |= BIT(qe_bit); + ret = flash_npcx_nor_write_status_regs(dev, sts_reg); + if (ret != 0) { + LOG_ERR("Enable quad access: write reg failed %d!", ret); + return ret; + } + } + + /* Enable 4-byte address of spi NOR flash */ + if (config->qspi_cfg.enter_4ba != 0) { + bool wr_en = (config->qspi_cfg.enter_4ba & 0x02) != 0; + + if (wr_en) { + ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_WREN); + if (ret != 0) { + LOG_ERR("Enable 4byte addr: WREN failed %d!", ret); + return ret; + } + } + ret = flash_npcx_uma_cmd_only(dev, SPI_NOR_CMD_4BA); + if (ret != 0) { + LOG_ERR("Enable 4byte addr: 4BA failed %d!", ret); + return ret; + } + } + + return 0; +} + +#define NPCX_FLASH_NOR_INIT(n) \ +BUILD_ASSERT(DT_INST_QUAD_EN_PROP_OR(n) == JESD216_DW15_QER_NONE || \ + DT_INST_STRING_TOKEN(n, rd_mode) == NPCX_RD_MODE_FAST_DUAL, \ + "Fast Dual IO read must be selected in Quad mode"); \ +PINCTRL_DT_INST_DEFINE(n); \ +static const struct flash_npcx_nor_config flash_npcx_nor_config_##n = { \ + .qspi_bus = DEVICE_DT_GET(DT_PARENT(DT_DRV_INST(n))), \ + .mapped_addr = DT_INST_PROP(n, mapped_addr), \ + .flash_size = DT_INST_PROP(n, size) / 8, \ + .min_erase_size = DT_INST_PROP(n, min_erase_size), \ + .max_timeout = DT_INST_PROP(n, max_timeout), \ + .qspi_cfg = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .flags = DT_INST_PROP(n, qspi_flags), \ + .enter_4ba = DT_INST_PROP_OR(n, enter_4byte_addr, 0), \ + .qer_type = DT_INST_QUAD_EN_PROP_OR(n), \ + .rd_mode = DT_INST_STRING_TOKEN(n, rd_mode), \ + }, \ + IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, ( \ + .layout = { \ + .pages_count = DT_INST_PROP(n, size) / \ + (8 * SPI_NOR_PAGE_SIZE), \ + .pages_size = SPI_NOR_PAGE_SIZE, \ + },)) \ +}; \ +static struct flash_npcx_nor_data flash_npcx_nor_data_##n; \ +DEVICE_DT_INST_DEFINE(n, flash_npcx_nor_init, NULL, \ + &flash_npcx_nor_data_##n, &flash_npcx_nor_config_##n, \ + POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \ + &flash_npcx_nor_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NPCX_FLASH_NOR_INIT) diff --git a/drivers/flash/flash_npcx_fiu_qspi.c b/drivers/flash/flash_npcx_fiu_qspi.c new file mode 100644 index 000000000000..8b53be28c86d --- /dev/null +++ b/drivers/flash/flash_npcx_fiu_qspi.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_fiu_qspi + +#include +#include +#include +#include +#include +#include + +#include "flash_npcx_fiu_qspi.h" + +#include +LOG_MODULE_REGISTER(npcx_fiu_qspi, LOG_LEVEL_ERR); + +/* Driver convenience defines */ +#define HAL_INSTANCE(dev) \ + ((struct fiu_reg *)((const struct npcx_qspi_fiu_config *)(dev)->config)->base) + +/* Device config */ +struct npcx_qspi_fiu_config { + /* Flash interface unit base address */ + uintptr_t base; + /* Clock configuration */ + struct npcx_clk_cfg clk_cfg; + /* Enable 2 external SPI devices for direct read on QSPI bus */ + bool en_direct_access_2dev; +}; + +/* Device data */ +struct npcx_qspi_fiu_data { + /* mutex of qspi bus controller */ + struct k_sem lock_sem; + /* Current device configuration on QSPI bus */ + const struct npcx_qspi_cfg *cur_cfg; + /* Current Software controlled Chip-Select number */ + int sw_cs; + /* Current QSPI bus operation */ + uint32_t operation; +}; + +/* NPCX SPI User Mode Access (UMA) functions */ +static inline void qspi_npcx_uma_cs_level(const struct device *dev, uint8_t sw_cs, bool level) +{ + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + /* Set chip select to high/low level */ + if (level) { + inst->UMA_ECTS |= BIT(sw_cs); + } else { + inst->UMA_ECTS &= ~BIT(sw_cs); + } +} + +static inline void qspi_npcx_uma_write_byte(const struct device *dev, uint8_t data) +{ + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + /* Set data to UMA_CODE and trigger UMA */ + inst->UMA_CODE = data; + inst->UMA_CTS = UMA_CODE_CMD_WR_ONLY; + /* EXEC_DONE will be zero automatically if a UMA transaction is completed. */ + while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) { + continue; + } +} + +static inline void qspi_npcx_uma_read_byte(const struct device *dev, uint8_t *data) +{ + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + /* Trigger UMA and Get data from DB0 later */ + inst->UMA_CTS = UMA_CODE_RD_BYTE(1); + while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) { + continue; + } + + *data = inst->UMA_DB0; +} + +/* NPCX SPI Direct Read Access (DRA)/User Mode Access (UMA) configuration functions */ +static inline void qspi_npcx_config_uma_mode(const struct device *dev, + const struct npcx_qspi_cfg *qspi_cfg) +{ + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + if ((qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0) { + inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_SEC_CS); + } else { + inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_SEC_CS); + } +} + +static inline void qspi_npcx_config_dra_mode(const struct device *dev, + const struct npcx_qspi_cfg *qspi_cfg) +{ + struct fiu_reg *const inst = HAL_INSTANCE(dev); + + /* Enable quad mode of Direct Read Mode if needed */ + if (qspi_cfg->qer_type != JESD216_DW15_QER_NONE) { + inst->RESP_CFG |= BIT(NPCX_RESP_CFG_QUAD_EN); + } else { + inst->RESP_CFG &= ~BIT(NPCX_RESP_CFG_QUAD_EN); + } + + /* Selects the SPI read access type of Direct Read Access mode */ + SET_FIELD(inst->SPI_FL_CFG, NPCX_SPI_FL_CFG_RD_MODE, qspi_cfg->rd_mode); + + /* Enable/Disable 4 byte address mode for Direct Read Access (DRA) */ +#if !defined(CONFIG_SOC_SERIES_NPCX7) /* NPCX7 doesn't support this feature */ + if (qspi_cfg->enter_4ba != 0) { + if ((qspi_cfg->flags & NPCX_QSPI_SEC_FLASH_SL) != 0) { + inst->SPI1_DEV |= BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11); + } else { + inst->SPI1_DEV |= BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS10); + } + } else { + inst->SPI1_DEV &= ~(BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS11) | + BIT(NPCX_SPI1_DEV_FOUR_BADDR_CS10)); + } +#endif /* CONFIG_SOC_SERIES_NPCX7 */ +} + +static inline void qspi_npcx_fiu_set_operation(const struct device *dev, uint32_t operation) +{ + if ((operation & NPCX_EX_OP_INT_FLASH_WP) != 0) { + npcx_pinctrl_flash_write_protect_set(); + } +} + +/* NPCX specific QSPI-FIU controller functions */ +int qspi_npcx_fiu_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg, + uint32_t flags) +{ + struct npcx_qspi_fiu_data *const data = dev->data; + + /* UMA transaction is permitted? */ + if ((data->operation & NPCX_EX_OP_LOCK_UMA) != 0) { + return -EPERM; + } + + /* Assert chip select */ + qspi_npcx_uma_cs_level(dev, data->sw_cs, false); + + /* Transmit op-code first */ + qspi_npcx_uma_write_byte(dev, cfg->opcode); + + if ((flags & NPCX_UMA_ACCESS_ADDR) != 0) { + /* 3-byte or 4-byte address? */ + const int addr_start = (data->cur_cfg->enter_4ba != 0) ? 0 : 1; + + for (size_t i = addr_start; i < 4; i++) { + LOG_DBG("addr %d, %02x", i, cfg->addr.u8[i]); + qspi_npcx_uma_write_byte(dev, cfg->addr.u8[i]); + } + } + + if ((flags & NPCX_UMA_ACCESS_WRITE) != 0) { + if (cfg->tx_buf == NULL) { + return -EINVAL; + } + for (size_t i = 0; i < cfg->tx_count; i++) { + qspi_npcx_uma_write_byte(dev, cfg->tx_buf[i]); + } + } + + if ((flags & NPCX_UMA_ACCESS_READ) != 0) { + if (cfg->rx_buf == NULL) { + return -EINVAL; + } + for (size_t i = 0; i < cfg->rx_count; i++) { + qspi_npcx_uma_read_byte(dev, cfg->rx_buf + i); + } + } + + /* De-assert chip select */ + qspi_npcx_uma_cs_level(dev, data->sw_cs, true); + + return 0; +} + +void qspi_npcx_fiu_mutex_lock_configure(const struct device *dev, + const struct npcx_qspi_cfg *cfg, + const uint32_t operation) +{ + struct npcx_qspi_fiu_data *const data = dev->data; + + k_sem_take(&data->lock_sem, K_FOREVER); + + /* If the current device is different from previous one, configure it */ + if (data->cur_cfg != cfg) { + data->cur_cfg = cfg; + + /* Apply pin-muxing and tri-state */ + pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + + /* Configure User Mode Access (UMA) settings */ + qspi_npcx_config_uma_mode(dev, cfg); + + /* Configure for Direct Read Access (DRA) settings */ + qspi_npcx_config_dra_mode(dev, cfg); + + /* Save SW CS bit used in UMA mode */ + data->sw_cs = find_lsb_set(cfg->flags & NPCX_QSPI_SW_CS_MASK) - 1; + } + + /* Set QSPI bus operation */ + if (data->operation != operation) { + qspi_npcx_fiu_set_operation(dev, operation); + data->operation = operation; + } +} + +void qspi_npcx_fiu_mutex_unlock(const struct device *dev) +{ + struct npcx_qspi_fiu_data *const data = dev->data; + + k_sem_give(&data->lock_sem); +} + +static int qspi_npcx_fiu_init(const struct device *dev) +{ + const struct npcx_qspi_fiu_config *const config = dev->config; + struct fiu_reg *const inst = HAL_INSTANCE(dev); + struct npcx_qspi_fiu_data *const data = dev->data; + const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); + int ret; + + if (!device_is_ready(clk_dev)) { + LOG_ERR("%s device not ready", clk_dev->name); + return -ENODEV; + } + + /* Turn on device clock first and get source clock freq. */ + ret = clock_control_on(clk_dev, + (clock_control_subsys_t)&config->clk_cfg); + if (ret < 0) { + LOG_ERR("Turn on FIU clock fail %d", ret); + return ret; + } + + /* initialize mutex for qspi controller */ + k_sem_init(&data->lock_sem, 1, 1); + + /* Enable direct access for 2 external SPI devices */ + if (config->en_direct_access_2dev) { + if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX9)) { + inst->FIU_EXT_CFG |= BIT(NPCX_FIU_EXT_CFG_SPI1_2DEV); + } + } + + return 0; +} + +#define NPCX_SPI_FIU_INIT(n) \ +static const struct npcx_qspi_fiu_config npcx_qspi_fiu_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .clk_cfg = NPCX_DT_CLK_CFG_ITEM(n), \ + .en_direct_access_2dev = DT_INST_PROP(n, en_direct_access_2dev), \ +}; \ +static struct npcx_qspi_fiu_data npcx_qspi_fiu_data_##n; \ +DEVICE_DT_INST_DEFINE(n, qspi_npcx_fiu_init, NULL, \ + &npcx_qspi_fiu_data_##n, &npcx_qspi_fiu_config_##n, \ + PRE_KERNEL_1, CONFIG_FLASH_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(NPCX_SPI_FIU_INIT) diff --git a/drivers/flash/flash_npcx_fiu_qspi.h b/drivers/flash/flash_npcx_fiu_qspi.h new file mode 100644 index 000000000000..092c4371e652 --- /dev/null +++ b/drivers/flash/flash_npcx_fiu_qspi.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_ +#define ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_ + +#include +#include "jesd216.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* UMA operation flags */ +#define NPCX_UMA_ACCESS_WRITE BIT(0) +#define NPCX_UMA_ACCESS_READ BIT(1) +#define NPCX_UMA_ACCESS_ADDR BIT(2) + +/* UMA operation configuration for a SPI device */ +struct npcx_uma_cfg { + uint8_t opcode; + uint8_t *tx_buf; + size_t tx_count; + uint8_t *rx_buf; + size_t rx_count; + union { + uint32_t u32; + uint8_t u8[4]; + } addr; +}; + +/* QSPI bus configuration for a SPI device */ +struct npcx_qspi_cfg { + /* Type of Quad Enable bit in status register */ + enum jesd216_dw15_qer_type qer_type; + /* Pinctrl for QSPI bus */ + const struct pinctrl_dev_config *pcfg; + /* Enter four bytes address mode value */ + uint8_t enter_4ba; + /* SPI read access type of Direct Read Access mode */ + uint8_t rd_mode; + /* Configurations for the Quad-SPI peripherals */ + int flags; +}; + +/** + * @brief Execute UMA transactions on qspi bus + * + * @param dev Pointer to the device structure for qspi bus controller instance. + * @param cfg Pointer to the configuration of UMA transactions. + * @param flags Flags to be used during transactions. + * @retval 0 on success, -EPERM if an UMA transaction is not permitted. + */ +int qspi_npcx_fiu_uma_transceive(const struct device *dev, struct npcx_uma_cfg *cfg, + uint32_t flags); + +/** + * @brief Lock the mutex of npcx qspi bus controller and apply its configuration + * + * @param dev Pointer to the device structure for qspi bus controller instance. + * @param cfg Pointer to the configuration for the device on qspi bus. + * @param operation Qspi bus operation for the device. + */ +void qspi_npcx_fiu_mutex_lock_configure(const struct device *dev, + const struct npcx_qspi_cfg *cfg, + const uint32_t operation); + +/** + * @brief Unlock the mutex of npcx qspi bus controller. + * + * @param dev Pointer to the device structure for qspi bus controller instance. + */ +void qspi_npcx_fiu_mutex_unlock(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_FLASH_NPCX_FIU_QSPI_H_ */ diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index a544b4e7b684..91d70e8cbeff 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -27,7 +27,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_XLNX_AXI_QUADSPI spi_xlnx_axi_quadspi.c) zephyr_library_sources_ifdef(CONFIG_ESP32_SPIM spi_esp32_spim.c) zephyr_library_sources_ifdef(CONFIG_SPI_TEST spi_test.c) zephyr_library_sources_ifdef(CONFIG_SPI_PSOC6 spi_psoc6.c) -zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_FIU spi_npcx_fiu.c) zephyr_library_sources_ifdef(CONFIG_SPI_BITBANG spi_bitbang.c) zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_LDMA spi_xec_qmspi_ldma.c) zephyr_library_sources_ifdef(CONFIG_SPI_GD32 spi_gd32.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0dea58b241ab..03d9afba1fe5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -107,8 +107,6 @@ source "drivers/spi/Kconfig.test" source "drivers/spi/Kconfig.psoc6" -source "drivers/spi/Kconfig.npcx_fiu" - source "drivers/spi/Kconfig.bitbang" source "drivers/spi/Kconfig.gd32" diff --git a/drivers/spi/Kconfig.npcx_fiu b/drivers/spi/Kconfig.npcx_fiu deleted file mode 100644 index a37b8841e183..000000000000 --- a/drivers/spi/Kconfig.npcx_fiu +++ /dev/null @@ -1,12 +0,0 @@ -# NPCX SPI Driver configuration options - -# Copyright (c) 2021 Nuvoton Technology Corporation. -# SPDX-License-Identifier: Apache-2.0 - -config SPI_NPCX_FIU - bool "Nuvoton NPCX embedded controller (EC) SPI driver for NOR flash" - default y - depends on DT_HAS_NUVOTON_NPCX_SPI_FIU_ENABLED - help - Enable the SPI driver for NPCX family of processors. This driver is - for the dedicated SPI controller (FIU) to access the NOR flash. diff --git a/drivers/spi/spi_npcx_fiu.c b/drivers/spi/spi_npcx_fiu.c deleted file mode 100644 index 08938cc4561d..000000000000 --- a/drivers/spi/spi_npcx_fiu.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2021 Nuvoton Technology Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT nuvoton_npcx_spi_fiu - -#include -#include -#include -#include - -LOG_MODULE_REGISTER(spi_npcx_fiu, LOG_LEVEL_ERR); - -#include "spi_context.h" - -/* Device config */ -struct npcx_spi_fiu_config { - /* flash interface unit base address */ - uintptr_t base; - /* clock configuration */ - struct npcx_clk_cfg clk_cfg; -}; - -/* Device data */ -struct npcx_spi_fiu_data { - struct spi_context ctx; -}; - -/* Driver convenience defines */ -#define HAL_INSTANCE(dev) \ - ((struct fiu_reg *)((const struct npcx_spi_fiu_config *)(dev)->config)->base) - -static inline void spi_npcx_fiu_cs_level(const struct device *dev, int level) -{ - struct fiu_reg *const inst = HAL_INSTANCE(dev); - - /* Set chip select to high/low level */ - if (level == 0) - inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_SW_CS1); - else - inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_SW_CS1); -} - -static inline void spi_npcx_fiu_exec_cmd(const struct device *dev, uint8_t code, - uint8_t cts) -{ - struct fiu_reg *const inst = HAL_INSTANCE(dev); - -#ifdef CONFIG_ASSERT - struct npcx_spi_fiu_data *data = dev->data; - struct spi_context *ctx = &data->ctx; - - /* Flash mutex must be held while executing UMA commands */ - __ASSERT((k_sem_count_get(&ctx->lock) == 0), "UMA is not locked"); -#endif - - /* set UMA_CODE */ - inst->UMA_CODE = code; - /* execute UMA flash transaction */ - inst->UMA_CTS = cts; - while (IS_BIT_SET(inst->UMA_CTS, NPCX_UMA_CTS_EXEC_DONE)) - continue; -} - -static int spi_npcx_fiu_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) -{ - struct npcx_spi_fiu_data *data = dev->data; - struct fiu_reg *const inst = HAL_INSTANCE(dev); - struct spi_context *ctx = &data->ctx; - size_t cur_xfer_len; - int error = 0; - - spi_context_lock(ctx, false, NULL, NULL, spi_cfg); - ctx->config = spi_cfg; - - /* - * Configure UMA lock/unlock only if tx buffer set and rx buffer set - * are both empty. - */ - if (tx_bufs == NULL && rx_bufs == NULL) { - if (spi_cfg->operation & SPI_LOCK_ON) - inst->UMA_ECTS |= BIT(NPCX_UMA_ECTS_UMA_LOCK); - else - inst->UMA_ECTS &= ~BIT(NPCX_UMA_ECTS_UMA_LOCK); - spi_context_unlock_unconditionally(ctx); - return 0; - } - - /* Assert chip assert */ - spi_npcx_fiu_cs_level(dev, 0); - spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); - if (rx_bufs == NULL) { - while (spi_context_tx_buf_on(ctx)) { - spi_npcx_fiu_exec_cmd(dev, *ctx->tx_buf, - UMA_CODE_CMD_WR_ONLY); - spi_context_update_tx(ctx, 1, 1); - } - } else { - cur_xfer_len = spi_context_longest_current_buf(ctx); - for (size_t i = 0; i < cur_xfer_len; i++) { - spi_npcx_fiu_exec_cmd(dev, *ctx->tx_buf, - UMA_CODE_CMD_WR_ONLY); - spi_context_update_tx(ctx, 1, 1); - spi_context_update_rx(ctx, 1, 1); - } - while (spi_context_rx_buf_on(ctx)) { - inst->UMA_CTS = UMA_CODE_RD_BYTE(1); - while (IS_BIT_SET(inst->UMA_CTS, - NPCX_UMA_CTS_EXEC_DONE)) - continue; - /* Get read transaction results */ - *ctx->rx_buf = inst->UMA_DB0; - spi_context_update_tx(ctx, 1, 1); - spi_context_update_rx(ctx, 1, 1); - } - } - spi_npcx_fiu_cs_level(dev, 1); - spi_context_release(ctx, error); - - return error; -} - -int spi_npcx_fiu_release(const struct device *dev, - const struct spi_config *config) -{ - struct npcx_spi_fiu_data *data = dev->data; - struct spi_context *ctx = &data->ctx; - - if (!spi_context_configured(ctx, config)) { - return -EINVAL; - } - - spi_context_unlock_unconditionally(ctx); - return 0; -} - -static int spi_npcx_fiu_init(const struct device *dev) -{ - const struct npcx_spi_fiu_config *const config = dev->config; - const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); - int ret; - - if (!device_is_ready(clk_dev)) { - LOG_ERR("%s device not ready", clk_dev->name); - return -ENODEV; - } - - /* Turn on device clock first and get source clock freq. */ - ret = clock_control_on(clk_dev, - (clock_control_subsys_t)&config->clk_cfg); - if (ret < 0) { - LOG_ERR("Turn on FIU clock fail %d", ret); - return ret; - } - - /* Make sure the context is unlocked */ - spi_context_unlock_unconditionally(&((struct npcx_spi_fiu_data *)dev->data)->ctx); - - return 0; -} - -static struct spi_driver_api spi_npcx_fiu_api = { - .transceive = spi_npcx_fiu_transceive, - .release = spi_npcx_fiu_release, -}; - -static const struct npcx_spi_fiu_config npcx_spi_fiu_config = { - .base = DT_INST_REG_ADDR(0), - .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0), -}; - -static struct npcx_spi_fiu_data npcx_spi_fiu_data = { - SPI_CONTEXT_INIT_LOCK(npcx_spi_fiu_data, ctx), -}; - -DEVICE_DT_INST_DEFINE(0, &spi_npcx_fiu_init, NULL, &npcx_spi_fiu_data, - &npcx_spi_fiu_config, POST_KERNEL, - CONFIG_SPI_INIT_PRIORITY, &spi_npcx_fiu_api); diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index 78f0b84ba5ba..3994920af39a 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -9,6 +9,7 @@ /* Macros for device tree declarations of npcx soc family */ #include #include +#include #include #include #include @@ -510,9 +511,9 @@ }; }; - /* Dedicated SPI interface to access SPI flashes */ - spi_fiu0: spi@40020000 { - compatible = "nuvoton,npcx-spi-fiu"; + /* Dedicated Quad-SPI interface to access SPI flashes */ + qspi_fiu0: quadspi@40020000 { + compatible = "nuvoton,npcx-fiu-qspi"; #address-cells = <1>; #size-cells = <0>; reg = <0x40020000 0x2000>; diff --git a/dts/arm/nuvoton/npcx7m6fb.dtsi b/dts/arm/nuvoton/npcx7m6fb.dtsi index c4bd84bf5319..171da95e374c 100644 --- a/dts/arm/nuvoton/npcx7m6fb.dtsi +++ b/dts/arm/nuvoton/npcx7m6fb.dtsi @@ -32,14 +32,19 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { + status = "okay"; + int_flash: w25q80@0 { - compatible ="jedec,spi-nor"; - /* 8388608 bits = 1 Mbytes */ - size = <0x800000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 14]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/arm/nuvoton/npcx7m6fc.dtsi b/dts/arm/nuvoton/npcx7m6fc.dtsi index 531b6da6329b..b5b6dfa7c3e0 100644 --- a/dts/arm/nuvoton/npcx7m6fc.dtsi +++ b/dts/arm/nuvoton/npcx7m6fc.dtsi @@ -32,14 +32,19 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { + status = "okay"; + int_flash: w25q40@0 { - compatible ="jedec,spi-nor"; - /* 4194304 bits = 512K Bytes */ - size = <0x400000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 13]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/arm/nuvoton/npcx7m7fc.dtsi b/dts/arm/nuvoton/npcx7m7fc.dtsi index 31670039d699..240fe7ae7281 100644 --- a/dts/arm/nuvoton/npcx7m7fc.dtsi +++ b/dts/arm/nuvoton/npcx7m7fc.dtsi @@ -36,14 +36,19 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { + status = "okay"; + int_flash: w25q40@0 { - compatible ="jedec,spi-nor"; - /* 4194304 bits = 512K Bytes */ - size = <0x400000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 13]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/arm/nuvoton/npcx9m3f.dtsi b/dts/arm/nuvoton/npcx9m3f.dtsi index 4f32f2f06322..4feb0568fa08 100644 --- a/dts/arm/nuvoton/npcx9m3f.dtsi +++ b/dts/arm/nuvoton/npcx9m3f.dtsi @@ -26,14 +26,19 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { + status = "okay"; + int_flash: w25q40@0 { - compatible ="jedec,spi-nor"; - /* 4194304 bits = 512K Bytes */ - size = <0x400000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 13]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/arm/nuvoton/npcx9m6f.dtsi b/dts/arm/nuvoton/npcx9m6f.dtsi index a918784f46a1..76cf19c2ca55 100644 --- a/dts/arm/nuvoton/npcx9m6f.dtsi +++ b/dts/arm/nuvoton/npcx9m6f.dtsi @@ -26,14 +26,19 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { + status = "okay"; + int_flash: w25q40@0 { - compatible ="jedec,spi-nor"; - /* 4194304 bits = 512K Bytes */ - size = <0x400000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 13]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/arm/nuvoton/npcx9m7f.dtsi b/dts/arm/nuvoton/npcx9m7f.dtsi index 646225431ceb..572daeca9ba0 100644 --- a/dts/arm/nuvoton/npcx9m7f.dtsi +++ b/dts/arm/nuvoton/npcx9m7f.dtsi @@ -26,14 +26,17 @@ }; }; -&spi_fiu0 { +&qspi_fiu0 { int_flash: w25q80@0 { - compatible ="jedec,spi-nor"; - /* 8388608 bits = 1 Mbytes */ - size = <0x800000>; + compatible ="nuvoton,npcx-fiu-nor"; + size = ; reg = <0>; - spi-max-frequency = <50000000>; status = "okay"; - jedec-id = [ef 40 14]; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; }; }; diff --git a/dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml b/dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml new file mode 100644 index 000000000000..10955f8709cb --- /dev/null +++ b/dts/bindings/flash_controller/nuvoton,npcx-fiu-nor.yaml @@ -0,0 +1,56 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The SPI NOR flash devices accessed by Nuvoton Flash Interface Unit (FIU). + + Representation of a SPI NOR flash on a qspi bus looks like: + + int_flash: w25q40@0 { + compatible ="nuvoton,npcx-fiu-nor"; + size = ; + reg = <0>; + + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; + }; + +compatible: "nuvoton,npcx-fiu-nor" + +include: [flash-controller.yaml, pinctrl-device.yaml, "jedec,spi-nor-common.yaml"] + +on-bus: qspi + +properties: + mapped-addr: + type: int + required: true + description: Mapped memory address of direct read access for spi nor flash. + min-erase-size: + type: int + default: 0x10000 + description: Minimum erase size of spi nor flash. + enum: + - 0x1000 # 4KB (Sector Erase) + - 0x10000 # 64KB (Block Erase) + max-timeout: + type: int + default: 10000 + description: Typically, it equals to max timeout of chip erase in ms. + qspi-flags: + type: int + required: true + description: The definitions for configuring the Quad-SPI peripherals. + rd-mode: + type: string + default: "NPCX_RD_MODE_FAST_DUAL" + description: | + Selects the SPI read access type of Direct Read Access. Usually, we choose + Fast Read Dual I/O mode for better performance. If the nor spi flash does + not support this mode, please set this property explicitly. + enum: + - "NPCX_RD_MODE_NORMAL" # Direct read access by command code 03h + - "NPCX_RD_MODE_FAST" # Direct read access by command code 0bh + - "NPCX_RD_MODE_FAST_DUAL" # Direct read access by command code bbh diff --git a/dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml b/dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml new file mode 100644 index 000000000000..3e8627faf237 --- /dev/null +++ b/dts/bindings/flash_controller/nuvoton,npcx-fiu-qspi.yaml @@ -0,0 +1,40 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Properties defining the NPCX Quad-SPI peripheral of Flash Interface Unit (FIU). + A npcx quad-spi dt node would typically looks like: + + &qspi_fiu0 { + status = "okay"; + + int_flash: w25q400@0 { + status = "okay"; + reg = <0>; + ... + }; + + ext_flash: w25q256@1 { + status = "okay"; + reg = <1>; + ... + }; + }; + + `int_flash` and `ext_flash` are the devices accessed by this peripheral. + +compatible: "nuvoton,npcx-fiu-qspi" + +include: [base.yaml, pinctrl-device.yaml] + +bus: qspi + +properties: + reg: + required: true + clocks: + required: true + en-direct-access-2dev: + type: boolean + description: | + Two external SPI devices are supported for Direct Read Access (DRA) on QSPI bus. diff --git a/dts/bindings/spi/nuvoton,npcx-spi-fiu.yaml b/dts/bindings/spi/nuvoton,npcx-spi-fiu.yaml deleted file mode 100644 index 6f3b900e435a..000000000000 --- a/dts/bindings/spi/nuvoton,npcx-spi-fiu.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2021 Nuvoton Technology Corporation. -# SPDX-License-Identifier: Apache-2.0 - -description: Nuvoton, NPCX-SPI-FIU controller node - -compatible: "nuvoton,npcx-spi-fiu" - -include: [spi-controller.yaml] - -properties: - reg: - required: true - clocks: - required: true diff --git a/include/zephyr/drivers/flash/npcx_flash_api_ex.h b/include/zephyr/drivers/flash/npcx_flash_api_ex.h new file mode 100644 index 000000000000..c640a28648bc --- /dev/null +++ b/include/zephyr/drivers/flash/npcx_flash_api_ex.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__ +#define __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum flash_npcx_ex_ops { + /* + * NPCX User Mode Access (UMA) mode execution. + * + * Execute a SPI transaction via User Mode Access (UMA) mode. Users can + * perform a customized SPI transaction to gread or write the device's + * configuration such as status registers of nor flash, power on/off, + * and so on. + */ + FLASH_NPCX_EX_OP_EXEC_UMA = FLASH_EX_OP_VENDOR_BASE, + /* + * NPCX Configure specific operation for Quad-SPI nor flash. + * + * It configures specific operation for Quad-SPI nor flash such as lock + * or unlock UMA mode, set write protection pin of internal flash, and + * so on. + */ + FLASH_NPCX_EX_OP_SET_QSPI_OPER, + /* + * NPCX Get specific operation for Quad-SPI nor flash. + * + * It returns current specific operation for Quad-SPI nor flash. + */ + FLASH_NPCX_EX_OP_GET_QSPI_OPER, +}; + +/* Structures used by FLASH_NPCX_EX_OP_EXEC_UMA */ +struct npcx_ex_ops_uma_in { + uint8_t opcode; + uint8_t *tx_buf; + size_t tx_count; + uint32_t addr; + size_t addr_count; + size_t rx_count; +}; + +struct npcx_ex_ops_uma_out { + uint8_t *rx_buf; +}; + +/* Structures used by FLASH_NPCX_EX_OP_SET_QSPI_OPER */ +struct npcx_ex_ops_qspi_oper_in { + bool enable; + uint32_t mask; +}; + +/* Structures used by FLASH_NPCX_EX_OP_GET_QSPI_OPER */ +struct npcx_ex_ops_qspi_oper_out { + uint32_t oper; +}; + +/* Specific NPCX QSPI devices control bits */ +#define NPCX_EX_OP_LOCK_UMA BIT(0) /* Lock/Unlock UMA mode */ +#define NPCX_EX_OP_INT_FLASH_WP BIT(1) /* Issue write protection of internal flash */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ZEPHYR_INCLUDE_DRIVERS_NPCX_FLASH_API_EX_H__ */ diff --git a/include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h b/include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h new file mode 100644 index 000000000000..c214218f523e --- /dev/null +++ b/include/zephyr/dt-bindings/flash_controller/npcx_fiu_qspi.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_ + +#include + +/* Software controlled Chip-Select number for UMA transactions */ +#define NPCX_QSPI_SW_CS0 BIT(0) +#define NPCX_QSPI_SW_CS1 BIT(1) +#define NPCX_QSPI_SW_CS2 BIT(2) +#define NPCX_QSPI_SW_CS_MASK (NPCX_QSPI_SW_CS0 | NPCX_QSPI_SW_CS1 | NPCX_QSPI_SW_CS2) + +/* Supported flash interfaces for UMA transactions */ +#define NPCX_QSPI_SEC_FLASH_SL BIT(4) + +/* Supported read mode for Direct Read Access */ +#define NPCX_RD_MODE_NORMAL 0 +#define NPCX_RD_MODE_FAST 1 +#define NPCX_RD_MODE_FAST_DUAL 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NPCK_FIU_QSPI_H_ */ diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 4bed431a457f..283f9bd200a1 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -1516,11 +1516,23 @@ struct fiu_reg { volatile uint8_t FIU_DMM_CYC; /* 0x033: FIU Extended Configuration */ volatile uint8_t FIU_EXT_CFG; +#if defined(CONFIG_SOC_SERIES_NPCX9) + /* 0x034: UMA address byte 0-3 */ + volatile uint32_t UMA_AB0_3; + /* 0x038-0x3C */ + volatile uint8_t reserved8[5]; + /* 0x03D: SPI Device */ + volatile uint8_t SPI1_DEV; + /* 0x03E-0x3F */ + volatile uint8_t reserved9[2]; +#endif }; /* FIU register fields */ #define NPCX_RESP_CFG_IAD_EN 0 #define NPCX_RESP_CFG_DEV_SIZE_EX 2 +#define NPCX_RESP_CFG_QUAD_EN 3 +#define NPCX_SPI_FL_CFG_RD_MODE FIELD(6, 2) #define NPCX_UMA_CTS_A_SIZE 3 #define NPCX_UMA_CTS_C_SIZE 4 #define NPCX_UMA_CTS_RD_WR 5 @@ -1530,6 +1542,12 @@ struct fiu_reg { #define NPCX_UMA_ECTS_SW_CS1 1 #define NPCX_UMA_ECTS_SEC_CS 2 #define NPCX_UMA_ECTS_UMA_LOCK 3 +#define NPCX_SPI1_DEV_FOUR_BADDR_CS10 6 +#define NPCX_SPI1_DEV_FOUR_BADDR_CS11 7 +#define NPCX_SPI1_DEV_SPI1_LO_DEV_SIZE FIELD(0, 4) +#define NPCX_FIU_EXT_CFG_SPI1_2DEV 7 +#define NPCX_FIU_EXT_CFG_SET_DMM_EN 2 +#define NPCX_FIU_EXT_CFG_SET_CMD_EN 1 /* UMA fields selections */ #define UMA_FLD_ADDR BIT(NPCX_UMA_CTS_A_SIZE) /* 3-bytes ADR field */ diff --git a/soc/arm/nuvoton_npcx/common/registers.c b/soc/arm/nuvoton_npcx/common/registers.c index f1e112190ae2..453fffbe24aa 100644 --- a/soc/arm/nuvoton_npcx/common/registers.c +++ b/soc/arm/nuvoton_npcx/common/registers.c @@ -162,7 +162,11 @@ NPCX_REG_OFFSET_CHECK(ps2_reg, PSISIG, 0x008); NPCX_REG_OFFSET_CHECK(ps2_reg, PSIEN, 0x00a); /* FIU register structure check */ +#if defined(CONFIG_SOC_SERIES_NPCX9) +NPCX_REG_SIZE_CHECK(fiu_reg, 0x040); +#else NPCX_REG_SIZE_CHECK(fiu_reg, 0x034); +#endif NPCX_REG_OFFSET_CHECK(fiu_reg, BURST_CFG, 0x001); NPCX_REG_OFFSET_CHECK(fiu_reg, SPI_FL_CFG, 0x014); NPCX_REG_OFFSET_CHECK(fiu_reg, UMA_CTS, 0x01e); From 927168fb5aba67a5012b4e36930972ef511a7aa0 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 4 Jul 2023 13:51:00 +0200 Subject: [PATCH 1541/2042] bluetooth: tester: bap: Add support for AC 7(i) tests Allow to assing end points to CISes before creating a CIG. Previously the end points were assinged top-down, so the configuration 7(i) and other similar were not covered. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/src/btp/btp_ascs.h | 17 ++ tests/bluetooth/tester/src/btp_bap.c | 223 ++++++++++++++++++---- 2 files changed, 207 insertions(+), 33 deletions(-) diff --git a/tests/bluetooth/tester/src/btp/btp_ascs.h b/tests/bluetooth/tester/src/btp/btp_ascs.h index 1cd279914e44..a5968a919af6 100644 --- a/tests/bluetooth/tester/src/btp/btp_ascs.h +++ b/tests/bluetooth/tester/src/btp/btp_ascs.h @@ -73,6 +73,14 @@ struct btp_ascs_update_metadata_cmd { uint8_t ase_id; } __packed; +#define BTP_ASCS_ADD_ASE_TO_CIS 0x0a +struct btp_ascs_add_ase_to_cis { + bt_addr_le_t address; + uint8_t ase_id; + uint8_t cig_id; + uint8_t cis_id; +} __packed; + /* ASCS events */ #define BTP_ASCS_EV_OPERATION_COMPLETED 0x80 struct btp_ascs_operation_completed_ev { @@ -85,5 +93,14 @@ struct btp_ascs_operation_completed_ev { uint8_t flags; } __packed; +#define BTP_ASCS_EV_CHARACTERISTIC_SUBSCRIBED 0x81 + +#define BTP_ASCS_EV_ASE_STATE_CHANGED 0x82 +struct btp_ascs_ase_state_changed_ev { + bt_addr_le_t address; + uint8_t ase_id; + uint8_t state; +} __packed; + #define BTP_ASCS_STATUS_SUCCESS 0x00 #define BTP_ASCS_STATUS_FAILED 0x01 diff --git a/tests/bluetooth/tester/src/btp_bap.c b/tests/bluetooth/tester/src/btp_bap.c index 8591c43de042..27b3c9eb70e2 100644 --- a/tests/bluetooth/tester/src/btp_bap.c +++ b/tests/bluetooth/tester/src/btp_bap.c @@ -56,6 +56,10 @@ struct audio_stream { size_t len_to_send; struct k_work_delayable audio_clock_work; struct k_work_delayable audio_send_work; + uint8_t cig_id; + uint8_t cis_id; + struct bt_bap_unicast_group **cig; + bool already_sent; }; #define MAX_STREAMS_COUNT MAX(CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, \ @@ -69,11 +73,12 @@ struct audio_connection { size_t configured_source_stream_count; struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; - struct bt_bap_unicast_group *unicast_group; struct bt_bap_ep *end_points[MAX_END_POINTS_COUNT]; size_t end_points_count; } connections[CONFIG_BT_MAX_CONN]; +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); @@ -84,8 +89,6 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool, MAX(CONFIG_BT_ASCS_ASE_SRC_COUNT, static struct net_buf_simple *rx_ev_buf = NET_BUF_SIMPLE(CONFIG_BT_ISO_RX_MTU + sizeof(struct btp_bap_stream_received_ev)); -static bool already_sent; - 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); @@ -222,6 +225,19 @@ static void btp_send_ascs_operation_completed_ev(struct bt_conn *conn, uint8_t a 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; + struct bt_conn_info info; + + (void)bt_conn_get_info(conn, &info); + bt_addr_le_copy(&ev.address, info.le.dst); + 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 freq_hz; @@ -528,6 +544,13 @@ 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); + + if (stream->ep->dir == BT_AUDIO_DIR_SINK) { + /* 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); } @@ -541,10 +564,17 @@ static void stream_released(struct bt_bap_stream *stream) audio_conn = &connections[a_stream->conn_id]; - if (audio_conn->unicast_group != NULL) { + if (stream->ep->dir == BT_AUDIO_DIR_SINK) { + /* 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(audio_conn->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); @@ -552,7 +582,7 @@ static void stream_released(struct bt_bap_stream *stream) return; } - audio_conn->unicast_group = NULL; + cigs[stream->ep->cig_id] = NULL; } a_stream->ase_id = 0; @@ -564,6 +594,8 @@ static void stream_started(struct bt_bap_stream *stream) struct bt_bap_ep_info info; int err; + /* Callback called on transition to Streaming state */ + LOG_DBG("Started stream %p", stream); err = bt_bap_ep_get_info(stream->ep, &info); @@ -587,8 +619,8 @@ static void stream_started(struct bt_bap_stream *stream) K_USEC(a_stream->stream.qos->interval)); } - btp_send_ascs_operation_completed_ev(stream->conn, a_stream->ase_id, - BT_ASCS_START_OP, BTP_STATUS_SUCCESS); + 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) @@ -597,7 +629,7 @@ static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason) LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason); - if (stream->dir == BT_AUDIO_DIR_SINK) { + if (stream->ep->dir == BT_AUDIO_DIR_SINK) { /* Stop send timer */ k_work_cancel_delayable(&a_stream->audio_clock_work); k_work_cancel_delayable(&a_stream->audio_send_work); @@ -611,12 +643,14 @@ static void stream_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) { - if (already_sent == false) { + 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); - already_sent = true; + a_stream->already_sent = true; btp_send_stream_received_ev(stream->conn, stream->ep, buf->len, buf->data); } } @@ -749,8 +783,15 @@ static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rs 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); - already_sent = false; + 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, @@ -972,7 +1013,7 @@ static void audio_send_timeout(struct k_work *work) BT_ISO_TIMESTAMP_NONE); if (err != 0) { LOG_ERR("Failed to send audio data to stream: ase_id %d dir seq %d %d err %d", - stream->ase_id, stream->stream.dir, stream->last_req_seq_num, err); + stream->ase_id, stream->stream.ep->dir, stream->last_req_seq_num, err); net_buf_unref(buf); } @@ -1009,7 +1050,7 @@ static uint8_t bap_send(const void *cmd, uint16_t cmd_len, (void)bt_conn_get_info(conn, &conn_info); stream = stream_find(audio_conn, cp->ase_id); - if (stream == NULL || stream->stream.dir != BT_AUDIO_DIR_SINK) { + if (stream == NULL || stream->stream.ep->dir != BT_AUDIO_DIR_SINK) { return BTP_STATUS_FAILED; } @@ -1103,7 +1144,31 @@ static int server_stream_config(struct bt_conn *conn, struct bt_bap_stream *stre return 0; } -static int client_create_unicast_group(struct audio_connection *audio_conn, uint8_t ase_id) +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]; @@ -1112,13 +1177,31 @@ static int client_create_unicast_group(struct audio_connection *audio_conn, uint 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[cig_id] == NULL) { + return -EINVAL; + } + } + + /* Assign end points to CISes */ for (size_t i = 0; i < MAX_STREAMS_COUNT; i++) { - struct bt_bap_stream *stream = &audio_conn->streams[i].stream; + struct audio_stream *a_stream = &audio_conn->streams[i]; + struct bt_bap_stream *stream = &a_stream->stream; - if (stream == NULL || stream->ep == NULL) { + if (stream == NULL || stream->ep == NULL || a_stream->cig == NULL || + a_stream->cig_id != cig_id) { continue; } @@ -1126,26 +1209,45 @@ static int client_create_unicast_group(struct audio_connection *audio_conn, uint stream_params[stream_cnt].qos = &audio_conn->qos; if (stream->ep->dir == BT_AUDIO_DIR_SOURCE) { - pair_params[src_cnt].rx_param = &stream_params[stream_cnt]; + 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 { - pair_params[sink_cnt].tx_param = &stream_params[stream_cnt]; + 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++; } - if (stream_cnt == 0) { + /* 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 = MAX(sink_cnt, src_cnt); + param.params_count = cis_cnt; param.packing = BT_ISO_PACKING_SEQUENTIAL; LOG_DBG("Creating unicast group"); - err = bt_bap_unicast_group_create(¶m, &audio_conn->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; @@ -1305,15 +1407,20 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, audio_conn = &connections[bt_conn_index(conn)]; - if (audio_conn->unicast_group != NULL) { - err = bt_bap_unicast_group_delete(audio_conn->unicast_group); + 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; } - audio_conn->unicast_group = NULL; + 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; @@ -1325,7 +1432,7 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, 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); + 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); @@ -1334,7 +1441,7 @@ static uint8_t ascs_configure_qos(const void *cmd, uint16_t cmd_len, } LOG_DBG("QoS configuring streams"); - err = bt_bap_stream_qos(conn, audio_conn->unicast_group); + err = bt_bap_stream_qos(conn, cigs[cp->cig_id]); bt_conn_unref(conn); if (err != 0) { @@ -1438,11 +1545,22 @@ static uint8_t ascs_receiver_start_ready(const void *cmd, uint16_t cmd_len, LOG_DBG("Starting stream %p, ep %u, dir %u", &stream->stream, cp->ase_id, stream->stream.ep->dir); - err = bt_bap_stream_start(&stream->stream); - if (err != 0) { - LOG_DBG("Could not start stream: %d", err); - return BTP_STATUS_FAILED; - } + 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; } @@ -1473,7 +1591,7 @@ static uint8_t ascs_receiver_stop_ready(const void *cmd, uint16_t cmd_len, LOG_DBG("Stopping stream"); err = bt_bap_stream_stop(&stream->stream); if (err != 0) { - LOG_DBG("Could not start stream: %d", err); + LOG_DBG("Could not stop stream: %d", err); return BTP_STATUS_FAILED; } @@ -1552,6 +1670,40 @@ static uint8_t ascs_update_metadata(const void *cmd, uint16_t cmd_len, void *rsp 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, @@ -1599,6 +1751,11 @@ static const struct btp_handler ascs_handlers[] = { .expect_len = sizeof(struct btp_ascs_update_metadata_cmd), .func = 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, + }, }; static int set_location(void) From f0551108025fe6ec21dd5d6e2f9c04fe075bd7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Fri, 14 Jul 2023 11:42:08 +0200 Subject: [PATCH 1542/2042] doc: Add hint for automatic power domain swiching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a hint that when a device is on a power domain and the device and power domain have runtime PM, the power domain will automatically resumed/susepended. Signed-off-by: Marcel Krüger --- doc/services/pm/device_runtime.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/services/pm/device_runtime.rst b/doc/services/pm/device_runtime.rst index 8ef1ecaf9213..5d9df2d8706e 100644 --- a/doc/services/pm/device_runtime.rst +++ b/doc/services/pm/device_runtime.rst @@ -26,6 +26,15 @@ asynchronously, it will be put into the :c:enumerator:`PM_DEVICE_STATE_SUSPENDING` state first and then into the :c:enumerator:`PM_DEVICE_STATE_SUSPENDED` state when the action is run. +For devices on a power domain (via the devicetree 'power-domain' property), device runtime +power management automatically attempts to request and release the dependent domain +in response to :c:func:`pm_device_runtime_get` and :c:func:`pm_device_runtime_put` +calls on the child device. + +For the previous to automatically control the power domain state, device runtime PM must be enabled +on the power domain device (either through the `zephyr,pm-device-runtime-auto` devicetree property +or :c:func:`pm_device_runtime_enable`). + .. graphviz:: :caption: Device states and transitions From 82f5db37d228743fa4ca458f98aec5ae9f701a38 Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Sun, 16 Jul 2023 14:37:22 +0530 Subject: [PATCH 1543/2042] posix: Changes pthread_equal to regular type function Patch changes pthread_equal function from static inline to regular function type Fix for issue#59942 Signed-off-by: Jai Arora --- include/zephyr/posix/pthread.h | 5 +---- lib/posix/pthread.c | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index b11c61a9f6ed..8258ac441605 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -396,10 +396,7 @@ pthread_t pthread_self(void); * * See IEEE 1003.1 */ -static inline int pthread_equal(pthread_t pt1, pthread_t pt2) -{ - return (pt1 == pt2); -} +int pthread_equal(pthread_t pt1, pthread_t pt2); /** * @brief Destroy the read-write lock attributes object. diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 652e539e48a3..519d68091248 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -848,4 +848,9 @@ 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 81ef6b5afb59d31a1cc418c8c8189773b4d0a979 Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Thu, 20 Jul 2023 15:52:26 +0530 Subject: [PATCH 1544/2042] posix: Adds test case for pthread_equal functions Adds test case for pthread_equal Adds test coverage for same and different thread id Signed-off-by: Jai Arora --- tests/posix/common/src/pthread.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index f333fb1594b2..3cd284f62dc4 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -771,3 +771,9 @@ ZTEST(posix_apis, test_barrier) 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())); + zassert_false(pthread_equal(pthread_self(), (pthread_t)4242)); +} From 7daaad454a9e25fd47fd35bca4d74fef20812e3d Mon Sep 17 00:00:00 2001 From: Jai Arora Date: Thu, 20 Jul 2023 15:57:21 +0530 Subject: [PATCH 1545/2042] docs: update posix docs with pthread_equal add pthread_equal to supported api list Signed-off-by: Jai Arora --- doc/services/portability/posix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst index 83d8c78cbcec..38be76f9118e 100644 --- a/doc/services/portability/posix.rst +++ b/doc/services/portability/posix.rst @@ -157,7 +157,7 @@ multiple processes. pthread_condattr_init(),yes pthread_create(),yes pthread_detach(),yes - pthread_equal(), + pthread_equal(),yes pthread_exit(),yes pthread_getspecific(),yes pthread_join(),yes From cf58d11f8fc08a2fcbec2e656d1786b3c1c96140 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 18 Jul 2023 15:52:11 +0200 Subject: [PATCH 1546/2042] drivers: ieee802154_nrf5: Add payload length check on TX In case upper layer does not follow the convention, and the net_pkt provided to the nRF 15.4 driver had a payload larger than the maximum payload size of an individual 15.4 frame, the driver would end up with buffer overflow. Fix this by adding an extra payload_len check before attempting to copy the payload to the internal buffer. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 3c69d5fb4392..bc64a4b3e4bf 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -582,6 +582,11 @@ static int nrf5_tx(const struct device *dev, uint8_t *payload = frag->data; bool ret = true; + if (payload_len > NRF5_PSDU_LENGTH) { + LOG_ERR("Payload too large: %d", payload_len); + return -EMSGSIZE; + } + LOG_DBG("%p (%u)", payload, payload_len); nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH; From 5c5be08ba9bd0ed9002187394283574a5269fdc8 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 19 Jul 2023 09:15:08 +0200 Subject: [PATCH 1547/2042] drivers: ieee802154_nrf5: Use generic symbols for packet size Use generic symbols defined in ieee802154.h for packet/FCS size instead of redefining them in the driver header. Signed-off-by: Robert Lubos --- drivers/ieee802154/ieee802154_nrf5.c | 8 ++++---- drivers/ieee802154/ieee802154_nrf5.h | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index bc64a4b3e4bf..d77b96147094 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -150,7 +150,7 @@ static void nrf5_rx_thread(void *arg1, void *arg2, void *arg3) if (IS_ENABLED(CONFIG_IEEE802154_NRF5_FCS_IN_LENGTH)) { pkt_len = rx_frame->psdu[0]; } else { - pkt_len = rx_frame->psdu[0] - NRF5_FCS_LENGTH; + pkt_len = rx_frame->psdu[0] - IEEE802154_FCS_LENGTH; } #if defined(CONFIG_NET_BUF_DATA_SIZE) @@ -378,7 +378,7 @@ static int handle_ack(struct nrf5_802154_data *nrf5_radio) if (IS_ENABLED(CONFIG_IEEE802154_NRF5_FCS_IN_LENGTH)) { ack_len = nrf5_radio->ack_frame.psdu[0]; } else { - ack_len = nrf5_radio->ack_frame.psdu[0] - NRF5_FCS_LENGTH; + ack_len = nrf5_radio->ack_frame.psdu[0] - IEEE802154_FCS_LENGTH; } ack_pkt = net_pkt_rx_alloc_with_buffer(nrf5_radio->iface, ack_len, @@ -582,14 +582,14 @@ static int nrf5_tx(const struct device *dev, uint8_t *payload = frag->data; bool ret = true; - if (payload_len > NRF5_PSDU_LENGTH) { + if (payload_len > IEEE802154_MTU) { LOG_ERR("Payload too large: %d", payload_len); return -EMSGSIZE; } LOG_DBG("%p (%u)", payload, payload_len); - nrf5_radio->tx_psdu[0] = payload_len + NRF5_FCS_LENGTH; + nrf5_radio->tx_psdu[0] = payload_len + IEEE802154_FCS_LENGTH; memcpy(nrf5_radio->tx_psdu + 1, payload, payload_len); /* Reset semaphore in case ACK was received after timeout */ diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 482e4a2e82af..81c71721dda4 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -10,8 +10,6 @@ #include -#define NRF5_FCS_LENGTH (2) -#define NRF5_PSDU_LENGTH (125) #define NRF5_PHR_LENGTH (1) struct nrf5_802154_rx_frame { @@ -61,7 +59,7 @@ struct nrf5_802154_data { /* TX buffer. First byte is PHR (length), remaining bytes are * MPDU data. */ - uint8_t tx_psdu[NRF5_PHR_LENGTH + NRF5_PSDU_LENGTH + NRF5_FCS_LENGTH]; + uint8_t tx_psdu[NRF5_PHR_LENGTH + IEEE802154_MAX_PHY_PACKET_SIZE]; /* TX result, updated in radio transmit callbacks. */ uint8_t tx_result; From 0b6b970f0a967dec690bba58afcc488fb068eb40 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Tue, 18 Jul 2023 18:20:45 -0500 Subject: [PATCH 1548/2042] sensors: icm42688: Do not force rc oscillator Forcing the usage of the RC oscillator and keeping it on turns out to have detrimental effects to the readings by default. The default clock mode settings are perfectly fine. Signed-off-by: Tom Burdick --- drivers/sensor/icm42688/icm42688_common.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/sensor/icm42688/icm42688_common.c b/drivers/sensor/icm42688/icm42688_common.c index 6e82f22678bd..3ccd107cfbb3 100644 --- a/drivers/sensor/icm42688/icm42688_common.c +++ b/drivers/sensor/icm42688/icm42688_common.c @@ -58,15 +58,7 @@ int icm42688_reset(const struct device *dev) return -EINVAL; } - /* Always use internal RC oscillator */ - res = icm42688_spi_single_write(&dev_cfg->spi, REG_INTF_CONFIG1, - FIELD_PREP(MASK_CLKSEL, BIT_CLKSEL_INT_RC)); - if (res) { - return res; - } - - /* Switch on MCLK by setting the IDLE bit */ - return icm42688_spi_single_write(&dev_cfg->spi, REG_PWR_MGMT0, BIT_IDLE); + return 0; } int icm42688_configure(const struct device *dev, struct icm42688_cfg *cfg) From 30061ecd7f10485f35a3d13a075463ebc8a057f7 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 22 Jun 2022 17:32:46 +0200 Subject: [PATCH 1549/2042] tests/drivers/clock_control: Add tests for stm32wba_core Add tests to validate implementation of stm32wba clock_control driver. Signed-off-by: Erwan Gouriou --- .../stm32wba_core/CMakeLists.txt | 9 +++ .../stm32wba_core/boards/clear_clocks.overlay | 43 ++++++++++++ .../stm32wba_core/boards/hse_16.overlay | 24 +++++++ .../stm32wba_core/boards/hse_32.overlay | 24 +++++++ .../stm32wba_core/boards/hsi_16.overlay | 23 ++++++ .../boards/hsi_16_ahb5_div.overlay | 24 +++++++ .../stm32wba_core/boards/pll_hse_100.overlay | 34 +++++++++ .../boards/pll_hse_100_ahb_50.overlay | 34 +++++++++ .../stm32wba_core/prj.conf | 2 + .../src/test_stm32_clock_configuration.c | 70 +++++++++++++++++++ .../stm32wba_core/testcase.yaml | 16 +++++ 11 files changed, 303 insertions(+) create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/CMakeLists.txt create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/clear_clocks.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_16.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_32.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16_ahb5_div.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100_ahb_50.overlay create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/prj.conf create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/src/test_stm32_clock_configuration.c create mode 100644 tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/testcase.yaml diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/CMakeLists.txt b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/CMakeLists.txt new file mode 100644 index 000000000000..da56bddf634e --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/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(stm32_clock_configuration_wba) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/clear_clocks.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/clear_clocks.overlay new file mode 100644 index 000000000000..cadef95055ce --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/clear_clocks.overlay @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay clears clocks back to a state equivalent to what could + * be found in stm32wba.dtsi + */ + +&clk_hse { + status = "disabled"; + /delete-property/ hse-div; +}; + +&clk_hsi { + status = "disabled"; +}; + +&clk_lse { + status = "disabled"; +}; + +&pll1 { + /delete-property/ div-m; + /delete-property/ mul-n; + /delete-property/ div-q; + /delete-property/ div-r; + /delete-property/ clocks; + status = "disabled"; +}; + +&rcc { + /delete-property/ clocks; + /delete-property/ clock-frequency; + /delete-property/ ahb-prescaler; + /delete-property/ ahb5-prescaler; + /delete-property/ ahb-div; + /delete-property/ apb1-prescaler; + /delete-property/ apb2-prescaler; + /delete-property/ apb7-prescaler; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_16.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_16.overlay new file mode 100644 index 000000000000..203e29863ad5 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_16.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hse { + status = "okay"; + hse-div2; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_32.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_32.overlay new file mode 100644 index 000000000000..038ded144b46 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hse_32.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hse { + status = "okay"; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + ahb-prescaler = <1>; + ahb5-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16.overlay new file mode 100644 index 000000000000..4e7f11c29e67 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hsi { + status = "okay"; +}; + +&rcc { + clocks = <&clk_hsi>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16_ahb5_div.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16_ahb5_div.overlay new file mode 100644 index 000000000000..ff481955060b --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/hsi_16_ahb5_div.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hsi { + status = "okay"; +}; + +&rcc { + clocks = <&clk_hsi>; + clock-frequency = ; + ahb-prescaler = <1>; + ahb5-div; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100.overlay new file mode 100644 index 000000000000..f5f2cff0d8e5 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&pll1 { + div-m = <8>; + mul-n = <100>; + div-q = <2>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + ahb5-prescaler = <4>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100_ahb_50.overlay b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100_ahb_50.overlay new file mode 100644 index 000000000000..9c0d128b78aa --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/boards/pll_hse_100_ahb_50.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Warning: This overlay performs configuration from clean sheet. + * It is assumed that it is applied after clear_clocks.overlay file. + */ + +&clk_hse { + status = "okay"; + clock-frequency = ; +}; + +&pll1 { + div-m = <8>; + mul-n = <100>; + div-q = <2>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + ahb-prescaler = <2>; + clock-frequency = ; + ahb5-prescaler = <4>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; + apb7-prescaler = <1>; +}; diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/prj.conf b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/prj.conf new file mode 100644 index 000000000000..9228251051ec --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/src/test_stm32_clock_configuration.c b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/src/test_stm32_clock_configuration.c new file mode 100644 index 000000000000..06bde001757f --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/src/test_stm32_clock_configuration.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +ZTEST(stm32_syclck_config, test_hclk_freq) +{ + uint32_t soc_hclk_freq; + + soc_hclk_freq = HAL_RCC_GetHCLKFreq(); + + zassert_equal(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, soc_hclk_freq, + "Expected hclk_freq: %d. Actual hclk_freq: %d", + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, soc_hclk_freq); +} + +ZTEST(stm32_syclck_config, test_sysclk_src) +{ + int sys_clk_src = __HAL_RCC_GET_SYSCLK_SOURCE(); + +#if STM32_SYSCLK_SRC_PLL + zassert_equal(RCC_SYSCLKSOURCE_STATUS_PLLCLK, sys_clk_src, + "Expected sysclk src: PLL1. Actual sysclk src: %d", + sys_clk_src); +#elif STM32_SYSCLK_SRC_HSE + zassert_equal(RCC_SYSCLKSOURCE_STATUS_HSE, sys_clk_src, + "Expected sysclk src: HSE. Actual sysclk src: %d", + sys_clk_src); +#elif STM32_SYSCLK_SRC_HSI + zassert_equal(RCC_SYSCLKSOURCE_STATUS_HSI, sys_clk_src, + "Expected sysclk src: HSI. Actual sysclk src: %d", + sys_clk_src); +#else + /* Case not expected */ + zassert_true((STM32_SYSCLK_SRC_PLL || + STM32_SYSCLK_SRC_HSE || + STM32_SYSCLK_SRC_HSI), + "Not expected. sys_clk_src: %d\n", sys_clk_src); +#endif + +} + +ZTEST(stm32_syclck_config, test_pll_src) +{ + uint32_t pll_src = __HAL_RCC_GET_PLL1_OSCSOURCE(); + +#if STM32_PLL_SRC_HSE + zassert_equal(RCC_PLLSOURCE_HSE, pll_src, + "Expected PLL src: HSE. Actual PLL src: %d", + pll_src); +#elif STM32_PLL_SRC_HSI + zassert_equal(RCC_PLLSOURCE_HSI, pll_src, + "Expected PLL src: HSI. Actual PLL src: %d", + pll_src); +#else + zassert_equal(RCC_PLLSOURCE_NONE, pll_src, + "Expected PLL src: None. Actual PLL src: %d", + pll_src); +#endif + +} +ZTEST_SUITE(stm32_syclck_config, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/testcase.yaml b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/testcase.yaml new file mode 100644 index 000000000000..e540315bcea7 --- /dev/null +++ b/tests/drivers/clock_control/stm32_clock_configuration/stm32wba_core/testcase.yaml @@ -0,0 +1,16 @@ +common: + timeout: 5 + platform_allow: nucleo_wba52cg +tests: + drivers.stm32_clock_configuration.wba.sysclksrc_hsi_32: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hsi_16.overlay" + drivers.stm32_clock_configuration.wba.sysclksrc_hsi_32_ahb5_div: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hsi_16_ahb5_div.overlay" + drivers.stm32_clock_configuration.wba.sysclksrc_hse_16: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_16.overlay" + drivers.stm32_clock_configuration.wba.sysclksrc_hse_32: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/hse_32.overlay" + drivers.stm32_clock_configuration.wba.sysclksrc_pll_hse_100: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_hse_100.overlay" + drivers.stm32_clock_configuration.wba.sysclksrc_pll_hse_50: + extra_args: DTC_OVERLAY_FILE="boards/clear_clocks.overlay;boards/pll_hse_100_ahb_50.overlay" From bd0a0e40e25565dba41d381bf3eecf2518b8e8fc Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Tue, 21 Jun 2022 16:44:06 +0200 Subject: [PATCH 1550/2042] tests: drivers: pwm: pwm_loopback: board: Add NUCLEO_WBA52CG Add NUCLEO_WBA52CG board to the PWM loopback test Signed-off-by: Guillaume Gautier --- .../boards/nucleo_wba52cg.overlay | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/drivers/pwm/pwm_loopback/boards/nucleo_wba52cg.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/nucleo_wba52cg.overlay b/tests/drivers/pwm/pwm_loopback/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000..043ecaa76a80 --- /dev/null +++ b/tests/drivers/pwm/pwm_loopback/boards/nucleo_wba52cg.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/ { + pwm_loopback_0 { + compatible = "test-pwm-loopback"; + /* first index must be a 32-Bit timer */ + pwms = <&pwm2 1 0 PWM_POLARITY_NORMAL>, + <&pwm3 1 0 PWM_POLARITY_NORMAL>; + }; +}; + +/* 32-Bit timers */ +&timers2 { + status = "okay"; + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch1_pb6>; /* PB6 D3 */ + pinctrl-names = "default"; + }; +}; + +&timers3 { + status = "okay"; + pwm3: pwm { + status = "okay"; + pinctrl-0 = <&tim3_ch1_pb5>; /* PB5 D1 */ + pinctrl-names = "default"; + }; +}; From 276b5577cb4bc73f57c8b2e09a7d9f9d84a11b9b Mon Sep 17 00:00:00 2001 From: Guillaume Gautier Date: Fri, 24 Jun 2022 14:47:43 +0200 Subject: [PATCH 1551/2042] samples: drivers: adc: boards: Add overlay for NUCLEO_WBA52CG Add overlay for NUCLEO_WBA52CG Signed-off-by: Guillaume Gautier --- samples/drivers/adc/boards/nucleo_wba52cg.overlay | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 samples/drivers/adc/boards/nucleo_wba52cg.overlay diff --git a/samples/drivers/adc/boards/nucleo_wba52cg.overlay b/samples/drivers/adc/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000..3cd6cb64bf5a --- /dev/null +++ b/samples/drivers/adc/boards/nucleo_wba52cg.overlay @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; From a59182d73baa30b224c35715048aaa43cbdaea21 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 6 Mar 2023 16:51:43 +0100 Subject: [PATCH 1552/2042] dts: stm32wba: Add counter node on timer1 Counter node was missing for this timer Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 28f3a3a7327e..ed3dc80911ca 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -253,6 +253,11 @@ st,prescaler = <0>; status = "disabled"; + counter { + compatible = "st,stm32-counter"; + status = "disabled"; + }; + pwm { compatible = "st,stm32-pwm"; status = "disabled"; From 9e2e3cf090f2d5a20bdd00be56dbeb7cab6222e6 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 6 Mar 2023 17:07:22 +0100 Subject: [PATCH 1553/2042] tests: driver: counter: Add stm32wba target Add stm32wba target to verify driver implementation Signed-off-by: Erwan Gouriou --- .../counter_basic_api/boards/nucleo_wba52cg.overlay | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/drivers/counter/counter_basic_api/boards/nucleo_wba52cg.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/nucleo_wba52cg.overlay b/tests/drivers/counter/counter_basic_api/boards/nucleo_wba52cg.overlay new file mode 100644 index 000000000000..a84786ae4d04 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/nucleo_wba52cg.overlay @@ -0,0 +1,13 @@ +&timers2 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; + +&timers3 { + st,prescaler = <79>; + counter { + status = "okay"; + }; +}; From c6e03d1ec4dccee151afa28b4a881e8ec7114900 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 19 Jul 2023 12:09:31 +0200 Subject: [PATCH 1554/2042] boards: nucleo_wba: Document entropy support Update documentation and yaml file Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst | 2 ++ boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml | 1 + 2 files changed, 3 insertions(+) diff --git a/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst index 6fa83ae8856f..2693de4f4be1 100644 --- a/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst +++ b/boards/arm/nucleo_wba52cg/doc/nucleo_wba52cg.rst @@ -175,6 +175,8 @@ The Zephyr nucleo_wba52cg board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | ADC | on-chip | adc | +-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml index 08aa1bec15fa..c5524c22fc0c 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.yaml @@ -10,6 +10,7 @@ supported: - i2c - spi - adc + - rng - arduino_gpio - arduino_i2c - arduino_spi From 779636415c182c5c61d7afbc0c9dc850bc7c4fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 16:26:55 +0200 Subject: [PATCH 1555/2042] lib: cbprintf: doc: Doxygen cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a couple typos and added @deprecated tags for deprecated macros. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/cbprintf.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/zephyr/sys/cbprintf.h b/include/zephyr/sys/cbprintf.h index fcf585a34320..43fe4f921e8d 100644 --- a/include/zephyr/sys/cbprintf.h +++ b/include/zephyr/sys/cbprintf.h @@ -145,7 +145,7 @@ extern "C" { BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); -/**@defgroup CBPRINTF_PACKAGE_FLAGS Package flags. +/**@defgroup CBPRINTF_PACKAGE_FLAGS Package flags * @{ */ @@ -155,7 +155,7 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); */ #define CBPRINTF_PACKAGE_CONST_CHAR_RO BIT(0) -/** @brief Append locations (within the package) of read-only string pointers.`*/ +/** @brief Append locations (within the package) of read-only string pointers. */ #define CBPRINTF_PACKAGE_ADD_RO_STR_POS BIT(1) /** @brief Append locations (within the package) of read-write string pointers. @@ -202,7 +202,8 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); /**@} */ -/**@defgroup CBPRINTF_PACKAGE_CONVERT_FLAGS Package flags. +/** + * @defgroup CBPRINTF_PACKAGE_CONVERT_FLAGS Package convert flags * @{ */ @@ -215,6 +216,7 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); * are also checked and if determined to be read-only they are also copied. */ #define CBPRINTF_PACKAGE_CONVERT_RO_STR BIT(0) +/** @deprecated Use @ref CBPRINTF_PACKAGE_CONVERT_RO_STR instead. */ #define CBPRINTF_PACKAGE_COPY_RO_STR CBPRINTF_PACKAGE_CONVERT_RO_STR __DEPRECATED_MACRO /** @brief Append read-write strings from source package to destination package. @@ -228,6 +230,7 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); * package if @ref CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR is set. */ #define CBPRINTF_PACKAGE_CONVERT_RW_STR BIT(1) +/** @deprecated Use @ref CBPRINTF_PACKAGE_CONVERT_RW_STR instead. */ #define CBPRINTF_PACKAGE_COPY_RW_STR CBPRINTF_PACKAGE_CONVERT_RW_STR __DEPRECATED_MACRO /** @brief Keep read-only location indexes in the package. @@ -236,6 +239,7 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); * not set they are discarded. */ #define CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR BIT(2) +/** @deprecated Use @ref CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR instead. */ #define CBPRINTF_PACKAGE_COPY_KEEP_RO_STR CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR __DEPRECATED_MACRO /** @brief Check format string if %p argument was treated as %s in the package. @@ -259,7 +263,8 @@ BUILD_ASSERT(Z_IS_POW2(CBPRINTF_PACKAGE_ALIGNMENT)); /**@} */ -/**@defgroup Z_CBVPRINTF_PROCESS_FLAGS cbvprintf processing flags. +/** + * @defgroup Z_CBVPRINTF_PROCESS_FLAGS cbvprintf processing flags. * @{ */ From a9a6df9b50033ebc3006613677785edfa7e7bd22 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Tue, 18 Jul 2023 16:29:58 +0200 Subject: [PATCH 1556/2042] scripts: tests: Environment tests update Implemented style changes proposed by gchwier previously. Tests updated according to fixes in environment.py in * PR #60526 * commit d72c434 * commit 7afeefd Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_environment.py | 138 +++++++++------------- 1 file changed, 53 insertions(+), 85 deletions(-) diff --git a/scripts/tests/twister/test_environment.py b/scripts/tests/twister/test_environment.py index ed8f7e4e65d8..8f495921d5ca 100644 --- a/scripts/tests/twister/test_environment.py +++ b/scripts/tests/twister/test_environment.py @@ -71,45 +71,27 @@ 'When --device-testing is used with --device-serial' \ ' or --device-serial-pty, only one platform is allowed' ), -# environment.py compares a store_false/true argument to None. -# This case will never raise an error, until that is fixed. -# ( -# None, -# None, -# None, -# ['--device-flash-timeout', '60'], -# '--device-flash-timeout requires --device-testing' -# ), -# environment.py compares a store_false/true argument to None. -# This case will never raise an error, until that is fixed. -# ( -# None, -# None, -# None, -# ['--device-flash-with-test'], -# '--device-flash-with-test requires --device-testing' -# ), +# Note the underscore. ( None, None, None, - ['--shuffle-tests'], - '--shuffle-tests requires --subset' + ['--device-flash-with-test'], + '--device-flash-with-test requires --device_testing' ), ( None, None, None, - ['--shuffle-tests-seed', '0'], - '--shuffle-tests-seed requires --shuffle-tests' + ['--shuffle-tests'], + '--shuffle-tests requires --subset' ), ( None, None, None, - ['--coverage-formats', 'html', '--coverage-tool', 'lcov'], - '--coverage-formats can only be used when' \ - ' coverage tool is set to gcovr' + ['--shuffle-tests-seed', '0'], + '--shuffle-tests-seed requires --shuffle-tests' ), ( None, @@ -134,7 +116,7 @@ @pytest.mark.parametrize( - 'os_name, which_dict, pytest_installed_var, args, expected_error', + 'os_name, which_dict, pytest_plugin, args, expected_error', TESTDATA_1, ids=[ 'short build path without ninja', @@ -143,11 +125,9 @@ 'west-flash without device-testing', 'valgrind without executable', 'device serial with multiple platforms', -# 'device flash timeout without device testing', -# 'device flash with test without device testing', + 'device flash with test without device testing', 'shuffle-tests without subset', 'shuffle-tests-seed without shuffle-tests', - 'coverage-formats without gcovr', 'unrecognised argument', 'pytest-twister-harness installed' ] @@ -156,7 +136,7 @@ def test_parse_arguments_errors( caplog, os_name, which_dict, - pytest_installed_var, + pytest_plugin, args, expected_error ): @@ -179,13 +159,12 @@ def mock_which(name): which_mock = mock.Mock(side_effect=mock_which) with mock.patch('os.name', os_name) \ - if os_name is not None else nullcontext(), \ + if os_name is not None else nullcontext(), \ mock.patch('shutil.which', which_mock) \ - if which_dict else nullcontext(), \ - mock.patch( - 'twisterlib.environment.PYTEST_PLUGIN_INSTALLED', - pytest_installed_var - ) if pytest_installed_var is not None else nullcontext(): + if which_dict else nullcontext(), \ + mock.patch('twisterlib.environment' \ + '.PYTEST_PLUGIN_INSTALLED', pytest_plugin) \ + if pytest_plugin is not None else nullcontext(): with pytest.raises(SystemExit) as exit_info: twisterlib.environment.parse_arguments(parser, args) @@ -263,18 +242,16 @@ def test_parse_arguments(zephyr_base, additional_args): TESTDATA_3 = [ -# Causes an error because some option member accesses -# do not check if it is not None -# ( -# None, -# mock.Mock( -# generator_cmd='make', -# generator='Unix Makefiles', -# test_roots=None, -# board_roots=None, -# outdir=None, -# ) -# ), + ( + None, + mock.Mock( + generator_cmd='make', + generator='Unix Makefiles', + test_roots=None, + board_roots=None, + outdir=None, + ) + ), ( mock.Mock( ninja=True, @@ -322,16 +299,15 @@ def test_parse_arguments(zephyr_base, additional_args): 'options, expected_env', TESTDATA_3, ids=[ -# 'no options', + 'no options', 'ninja', 'make' ] ) def test_twisterenv_init(options, expected_env): with mock.patch( - 'os.path.abspath', - mock.Mock(return_value='dummy_abspath') - ): + 'os.path.abspath', + mock.Mock(return_value='dummy_abspath')): twister_env = twisterlib.environment.TwisterEnv(options=options) assert twister_env.generator_cmd == expected_env.generator_cmd @@ -348,10 +324,9 @@ def test_twisterenv_discover(): ninja=True ) - with mock.patch( - 'os.path.abspath', - mock.Mock(return_value='dummy_abspath') - ): + abspath_mock = mock.Mock(return_value='dummy_abspath') + + with mock.patch('os.path.abspath', abspath_mock): twister_env = twisterlib.environment.TwisterEnv(options=options) mock_datetime = mock.Mock( @@ -363,15 +338,13 @@ def test_twisterenv_discover(): ) with mock.patch.object( - twisterlib.environment.TwisterEnv, - 'check_zephyr_version', - mock.Mock() - ) as mock_czv, \ + twisterlib.environment.TwisterEnv, + 'check_zephyr_version', + mock.Mock()) as mock_czv, \ mock.patch.object( - twisterlib.environment.TwisterEnv, - 'get_toolchain', - mock.Mock() - ) as mock_gt, \ + twisterlib.environment.TwisterEnv, + 'get_toolchain', + mock.Mock()) as mock_gt, \ mock.patch('twisterlib.environment.datetime', mock_datetime): twister_env.discover() @@ -388,11 +361,10 @@ def test_twisterenv_discover(): 'dummy stdout version', 'dummy stdout date' ), -# Note the 'Coult' typo instead of 'Could' ( mock.Mock(returncode=0, stdout=''), mock.Mock(returncode=0, stdout='dummy stdout date'), - ['Coult not determine version'], + ['Could not determine version'], 'Unknown', 'dummy stdout date' ), @@ -436,10 +408,9 @@ def mock_run(command, *args, **kwargs): ninja=True ) - with mock.patch( - 'os.path.abspath', - mock.Mock(return_value='dummy_abspath') - ): + abspath_mock = mock.Mock(return_value='dummy_abspath') + + with mock.patch('os.path.abspath', abspath_mock): twister_env = twisterlib.environment.TwisterEnv(options=options) with mock.patch('subprocess.run', mock.Mock(side_effect=mock_run)): @@ -459,15 +430,14 @@ def mock_run(command, *args, **kwargs): 'Unable to find `cmake` in path', None ), -# Note the double-space ( True, 0, b'somedummy\x1B[123-@d1770', - 'Finished running dummy/script/path', + 'Finished running dummy/script/path', { 'returncode': 0, - 'msg': 'Finished running dummy/script/path', + 'msg': 'Finished running dummy/script/path', 'stdout': 'somedummyd1770', } ), @@ -517,8 +487,8 @@ def mock_popen(command, *args, **kwargs): with mock.patch('shutil.which', mock_which), \ mock.patch('subprocess.Popen', mock.Mock(side_effect=mock_popen)), \ - pytest.raises(Exception) if \ - not find_cmake else nullcontext() as exception: + pytest.raises(Exception) \ + if not find_cmake else nullcontext() as exception: results = twisterlib.environment.TwisterEnv.run_cmake_script(args) assert 'Running cmake script dummy/script/path' in caplog.text @@ -558,19 +528,17 @@ def test_get_toolchain(caplog, script_result, exit_value, expected_log): ninja=True ) - with mock.patch( - 'os.path.abspath', - mock.Mock(return_value='dummy_abspath') - ): + abspath_mock = mock.Mock(return_value='dummy_abspath') + + with mock.patch('os.path.abspath', abspath_mock): twister_env = twisterlib.environment.TwisterEnv(options=options) with mock.patch.object( - twisterlib.environment.TwisterEnv, - 'run_cmake_script', - mock.Mock(return_value=script_result) - ), \ - pytest.raises(SystemExit) if \ - exit_value is not None else nullcontext() as exit_info: + twisterlib.environment.TwisterEnv, + 'run_cmake_script', + mock.Mock(return_value=script_result)), \ + pytest.raises(SystemExit) \ + if exit_value is not None else nullcontext() as exit_info: twister_env.get_toolchain() if exit_info is not None: From 6c541e1af055e249356a02ee6effe188c635e2a6 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 12 Jun 2023 13:05:21 +0100 Subject: [PATCH 1557/2042] mgmt: mcumgr: Add event ID index callback function Adds a function which gets the callback ID index of a given event ID. Signed-off-by: Jamie McCrae --- include/zephyr/mgmt/mcumgr/mgmt/callbacks.h | 9 ++++++++ subsys/mgmt/mcumgr/mgmt/src/mgmt.c | 23 +++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index 443d9c2f073a..ec462ec2454f 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -227,6 +227,15 @@ struct mgmt_evt_op_cmd_arg { }; }; +/** + * @brief Get event ID index from event. + * + * @param event Event to get ID index from. + * + * @return Event index. + */ +uint8_t mgmt_evt_get_index(uint32_t event); + /** * @brief This function is called to notify registered callbacks about mcumgr notifications/events. * diff --git a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c index b2faf5ea81be..ffbe4aec5cb3 100644 --- a/subsys/mgmt/mcumgr/mgmt/src/mgmt.c +++ b/subsys/mgmt/mcumgr/mgmt/src/mgmt.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -167,6 +168,28 @@ enum mgmt_cb_return mgmt_callback_notify(uint32_t event, void *data, size_t data return return_status; } + +uint8_t mgmt_evt_get_index(uint32_t event) +{ + uint8_t index = 0; + + event &= MGMT_EVT_OP_ID_ALL; + __ASSERT((event != 0), "Event cannot be 0."); + + while (index < 16) { + if (event & 0x1) { + break; + } + + ++index; + event = event >> 1; + } + + event = event >> 1; + __ASSERT((event == 0), "Event cannot contain multiple values."); + + return index; +} #endif /* Processes all registered MCUmgr handlers at start up and registers them */ From ee5c9b2629611ccf232148f2d12eb4e3e70e40cb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 12 Jun 2023 13:06:22 +0100 Subject: [PATCH 1558/2042] mgmt: mcumgr: grp: img_mgmt: Add image data written callback Adds an optional callback upon image data being written, can be used for syncing or timeout purposes. Signed-off-by: Jamie McCrae --- include/zephyr/mgmt/mcumgr/mgmt/callbacks.h | 15 +++++++++------ subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 4 ++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index ec462ec2454f..6796059453d7 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -151,22 +151,25 @@ enum fs_mgmt_group_events { */ enum img_mgmt_group_events { /** Callback when a client sends a file upload chunk, data is img_mgmt_upload_check(). */ - MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 0), + MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 0), /** Callback when a DFU operation is stopped. */ - MGMT_EVT_OP_IMG_MGMT_DFU_STOPPED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 1), + MGMT_EVT_OP_IMG_MGMT_DFU_STOPPED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 1), /** Callback when a DFU operation is started. */ - MGMT_EVT_OP_IMG_MGMT_DFU_STARTED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 2), + MGMT_EVT_OP_IMG_MGMT_DFU_STARTED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 2), /** Callback when a DFU operation has finished being transferred. */ - MGMT_EVT_OP_IMG_MGMT_DFU_PENDING = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 3), + MGMT_EVT_OP_IMG_MGMT_DFU_PENDING = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 3), /** Callback when an image has been confirmed. */ - MGMT_EVT_OP_IMG_MGMT_DFU_CONFIRMED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 4), + MGMT_EVT_OP_IMG_MGMT_DFU_CONFIRMED = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 4), + + /** Callback when an image write command has finished writing to flash. */ + MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK_WRITE_COMPLETE = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_IMG, 5), /** Used to enable all img_mgmt_group events. */ - MGMT_EVT_OP_IMG_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_IMG), + MGMT_EVT_OP_IMG_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_IMG), }; /** diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 85d62acfb6a8..42f3bf76c8e2 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -701,6 +701,10 @@ defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS) #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) (void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_PENDING, NULL, 0, &ret_rc, &ret_group); + } else { + /* Notify that the write has completed */ + (void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK_WRITE_COMPLETE, + NULL, 0, &ret_rc, &ret_group); #endif } } From a4d56e4f55664c91596cacae9b4f667c2258b091 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 26 Jun 2023 10:47:23 +0100 Subject: [PATCH 1559/2042] tests: boot: mcuboot_recovery_retention: Fix configuration issue Fixes an issue with the tests whereby the RAM memory configuration files were not being used, and could not be passed to the mcuboot image. Signed-off-by: Jamie McCrae --- .../boot/mcuboot_recovery_retention/sysbuild.cmake | 12 ++++++++++++ .../mcuboot/boards/nrf52840dk_nrf52840_mem.conf | 7 +++++++ .../mcuboot/boards/nrf52840dk_nrf52840_mem.overlay | 14 ++++++++++++++ .../boot/mcuboot_recovery_retention/testcase.yaml | 6 ++++-- 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.conf create mode 100644 tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.overlay diff --git a/tests/boot/mcuboot_recovery_retention/sysbuild.cmake b/tests/boot/mcuboot_recovery_retention/sysbuild.cmake index cc73038d6cef..6000a6416e7e 100644 --- a/tests/boot/mcuboot_recovery_retention/sysbuild.cmake +++ b/tests/boot/mcuboot_recovery_retention/sysbuild.cmake @@ -1 +1,13 @@ set(mcuboot_EXTRA_ZEPHYR_MODULES "${CMAKE_CURRENT_LIST_DIR}/test_module" CACHE INTERNAL "test_module directory") + +if(DEFINED mcuboot_TARGET_OVERLAY_CONFIG) + list(APPEND mcuboot_OVERLAY_CONFIG "${CMAKE_CURRENT_LIST_DIR}/sysbuild/mcuboot/${mcuboot_TARGET_OVERLAY_CONFIG}") + list(REMOVE_DUPLICATES mcuboot_OVERLAY_CONFIG) + set(mcuboot_OVERLAY_CONFIG "${mcuboot_OVERLAY_CONFIG}" CACHE INTERNAL "") +endif() + +if(DEFINED mcuboot_TARGET_DTC_OVERLAY_FILE) + list(APPEND mcuboot_DTC_OVERLAY_FILE "${CMAKE_CURRENT_LIST_DIR}/sysbuild/mcuboot/${mcuboot_TARGET_DTC_OVERLAY_FILE}") + list(REMOVE_DUPLICATES mcuboot_DTC_OVERLAY_FILE) + set(mcuboot_DTC_OVERLAY_FILE "${mcuboot_DTC_OVERLAY_FILE}" CACHE INTERNAL "") +endif() diff --git a/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.conf b/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.conf new file mode 100644 index 000000000000..8f39b13f7eca --- /dev/null +++ b/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.conf @@ -0,0 +1,7 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_RETAINED_MEM_NRF_GPREGRET=n +CONFIG_RETAINED_MEM_ZEPHYR_RAM=y diff --git a/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.overlay b/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.overlay new file mode 100644 index 000000000000..0080560291d0 --- /dev/null +++ b/tests/boot/mcuboot_recovery_retention/sysbuild/mcuboot/boards/nrf52840dk_nrf52840_mem.overlay @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +#include "../../../boards/nrf52840dk_nrf52840_mem.overlay" + +/ { + chosen { + zephyr,code-partition = &boot_partition; + }; +}; + +&zephyr_udc0 { + cdc_acm_uart0 { + compatible = "zephyr,cdc-acm-uart"; + }; +}; diff --git a/tests/boot/mcuboot_recovery_retention/testcase.yaml b/tests/boot/mcuboot_recovery_retention/testcase.yaml index 2d089706c488..a66c361c1d24 100644 --- a/tests/boot/mcuboot_recovery_retention/testcase.yaml +++ b/tests/boot/mcuboot_recovery_retention/testcase.yaml @@ -30,8 +30,10 @@ tests: mcuboot.recovery.retention.mem: platform_allow: nrf52840dk_nrf52840 extra_args: - - "'OVERLAY_CONFIG=\"nrf52840dk_nrf52840_mem.conf\"'" - - "'DTC_OVERLAY_FILE=\"boards/nrf52840dk_nrf52840_mem.overlay\"'" + - OVERLAY_CONFIG="boards/nrf52840dk_nrf52840_mem.conf" + - DTC_OVERLAY_FILE="boards/nrf52840dk_nrf52840_mem.overlay" + - mcuboot_TARGET_OVERLAY_CONFIG="boards/nrf52840dk_nrf52840_mem.conf" + - mcuboot_TARGET_DTC_OVERLAY_FILE="boards/nrf52840dk_nrf52840_mem.overlay" tags: - mcuboot - sysbuild From 7c08a9b6adf93f22b2b52283b7073674eb7857d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nerijus=20Bend=C5=BEi=C5=ABnas?= Date: Wed, 19 Jul 2023 10:52:11 +0300 Subject: [PATCH 1560/2042] doc: fix FIXED_PARITION_ID typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems flash_map.rst is the only place for this typo. Signed-off-by: Nerijus Bendžiūnas --- doc/services/storage/flash_map/flash_map.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/services/storage/flash_map/flash_map.rst b/doc/services/storage/flash_map/flash_map.rst index beb1da68c4fc..f5ef355f4347 100644 --- a/doc/services/storage/flash_map/flash_map.rst +++ b/doc/services/storage/flash_map/flash_map.rst @@ -76,7 +76,7 @@ nonvolatile storage API. Numeric flash area ID is obtained by passing DTS node label to :c:macro:`FIXED_PARTITION_ID()`; for example to obtain ID number -for ``slot0_partition``, user would invoke ``FIXED_PARITION_ID(slot0_partition)``. +for ``slot0_partition``, user would invoke ``FIXED_PARTITION_ID(slot0_partition)``. All :c:macro:`FIXED_PARTITION_` macros take DTS node labels as partition identifiers. @@ -96,7 +96,7 @@ using :c:func:`flash_area_open` and DTS node label: .. code-block:: c const struct flash_area *my_area; - int err = flash_area_open(FIXED_PARITION_ID(slot0_partition), &my_area); + int err = flash_area_open(FIXED_PARTITION_ID(slot0_partition), &my_area); if (err != 0) { handle_the_error(err); From 34a24ec4cdeb525a8076f6118e539fa0202aeb11 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Mon, 17 Apr 2023 13:26:13 -0500 Subject: [PATCH 1561/2042] docs: RTIO documentation updates Updates docs to account for the large number of changes that have occured since the initial documentation was written. Signed-off-by: Tom Burdick --- doc/services/rtio/index.rst | 170 ++++++++++-------------------------- 1 file changed, 45 insertions(+), 125 deletions(-) diff --git a/doc/services/rtio/index.rst b/doc/services/rtio/index.rst index 5e3a36f28481..11f5602b1157 100644 --- a/doc/services/rtio/index.rst +++ b/doc/services/rtio/index.rst @@ -16,14 +16,8 @@ driven I/O. This section covers the RTIO API, queues, executor, iodev, and common usage patterns with peripheral devices. RTIO takes a lot of inspiration from Linux's io_uring in its operations and API -as that API matches up well with hardware DMA transfer queues and descriptions. - -A quick sales pitch on why RTIO works well in many scenarios: - -1. API is DMA and interrupt friendly -2. No buffer copying -3. No callbacks -4. Blocking or non-blocking operation +as that API matches up well with hardware transfer queues and descriptions such as +DMA transfer lists. Problem ******* @@ -60,8 +54,8 @@ sequence of operations in an asynchronous way directly relates to the way hardware typically works with interrupt driven state machines potentially involving multiple peripheral IPs like bus and DMA controllers. -Submission Queue and Chaining -***************************** +Submission Queue +**************** The submission queue (sq), is the description of the operations to perform in concurrent chains. @@ -105,37 +99,43 @@ sqe. A chain of sqe will however ensure ordering and failure cascading. Other potential schemes are possible but a completion queue is a well trod idea with io_uring and other similar operating system APIs. -Executor and IODev -****************** - -Turning submission queue entries (sqe) into completion queue events (cqe) is the -job of objects implementing the executor and iodev APIs. These APIs enable -coordination between themselves to enable things like DMA transfers. +Executor +******** -The end result of these APIs should be a method to resolve the request by -deciding some of the following questions with heuristic/constraint -based decision making. +The RTIO executor is a low overhead concurrent I/O task scheduler. It ensures +certain request flags provide the expected behavior. It takes a list of +submissions working through them in order. Various flags allow for changing the +behavior of how submissions are worked through. Flags to form in order chains of +submissions, transactional sets of submissions, or create multi-shot +(continuously producing) requests are all possible! -* Polling, Interrupt, or DMA transfer? -* If DMA, are the requirements met (peripheral supported by DMAC, etc). +IO Device +********* -The executor is meant to provide policy for when to use each transfer -type, and provide the common code for walking through submission queue -chains by providing calls the iodev may use to signal completion, -error, or a need to suspend and wait. +Turning submission queue entries (sqe) into completion queue events (cqe) is the +job of objects implementing the iodev (IO device) API. This API accepts requests +in the form of the iodev submit API call. It is the io devices job to work +through its internal queue of submissions and convert them into completions. In +effect every io device can be viewed as an independent, event driven actor like +object, that accepts a never ending queue of I/O like requests. How the iodev +does this work is up to the author of the iodev, perhaps the entire queue of +operations can be converted to a set of DMA transfer descriptors, meaning the +hardware does almost all of the real work. Memory pools ************ -In some cases, the consumer may not know how much data will be produced. -Alternatively, a consumer might be handling data from multiple producers where -the frequency of the data is unpredictable. In these cases, read operations may -not want to bind memory at the time of allocation, but leave it to the IODev. -In such cases, there exists a macro :c:macro:`RTIO_DEFINE_WITH_MEMPOOL`. It -allows creating the RTIO context with a dedicated pool of "memory blocks" which -can be consumed by the IODev. Below is a snippet setting up the RTIO context -with a memory pool. The memory pool has 128 blocks, each block has the size of -16 bytes, and the data is 4 byte aligned. +In some cases requests to read may not know how much data will be produced. +Alternatively, a reader might be handling data from multiple io devices where +the frequency of the data is unpredictable. In these cases it may be wasteful +to bind memory to in flight read requests. Instead with memory pools the memory +to read into is left to the iodev to allocate from a memory pool associated with +the RTIO context that the read was associated with. To create such an RTIO +context the :c:macro:`RTIO_DEFINE_WITH_MEMPOOL` can be used. It allows creating +an RTIO context with a dedicated pool of "memory blocks" which can be consumed by +the iodev. Below is a snippet setting up the RTIO context with a memory pool. +The memory pool has 128 blocks, each block has the size of 16 bytes, and the data +is 4 byte aligned. .. code-block:: C @@ -151,12 +151,12 @@ with a memory pool. The memory pool has 128 blocks, each block has the size of RTIO_DEFINE_WITH_MEMPOOL(rtio_context, (struct rtio_executor *)&simple_exec, SQ_SIZE, CQ_SIZE, MEM_BLK_COUNT, MEM_BLK_SIZE, MEM_BLK_ALIGN); -When a read is needed, the consumer simply needs to replace the call +When a read is needed, the caller simply needs to replace the call :c:func:`rtio_sqe_prep_read` (which takes a pointer to a buffer and a length) -with a call to :c:func:`rtio_sqe_prep_read_with_pool`. The IODev requires +with a call to :c:func:`rtio_sqe_prep_read_with_pool`. The iodev requires only a small change which works with both pre-allocated data buffers as well as the mempool. When the read is ready, instead of getting the buffers directly -from the :c:struct:`rtio_iodev_sqe`, the IODev should get the buffer and count +from the :c:struct:`rtio_iodev_sqe`, the iodev should get the buffer and count by calling :c:func:`rtio_sqe_rx_buf` like so: .. code-block:: C @@ -192,90 +192,18 @@ c:func:`rtio_cqe_get_mempool_buffer`. /* Release the mempool buffer */ rtio_release_buffer(&rtio_context, buf); -Outstanding Questions -********************* - -RTIO is not a complete API and solution, and is currently evolving to best -fit the nature of an RTOS. The general ideas behind a pair of queues to -describe requests and completions seems sound and has been proven out in -other contexts. Questions remain though. - -Timeouts and Deadlines -====================== - -Timeouts and deadlines are key to being Real-Time. Real-Time in Zephyr means -being able to do things when an application wants them done. That could mean -different things from a deadline with best effort attempts or a timeout and -failure. - -These features would surely be useful in many cases, but would likely add some -significant complexities. It's something to decide upon, and even if enabled -would likely be a compile time optional feature leading to complex testing. - -Cancellation -============ - -Canceling an already queued operation could be possible with a small -API addition to perhaps take both the RTIO context and a pointer to the -submission queue entry. However, cancellation as an API induces many potential -complexities that might not be appropriate. It's something to be decided upon. - -Userspace Support -================= - -RTIO with userspace is certainly plausible but would require the equivalent of -a memory map call to map the shared ringbuffers and also potentially dma buffers. - -Additionally a DMA buffer interface would likely need to be provided for -coherence and MMU usage. - -IODev and Executor API -====================== - -Lastly the API between an executor and iodev is incomplete. - -There are certain interactions that should be supported. Perhaps things like -expanding a submission queue entry into multiple submission queue entries in -order to split up work that can be done by a device and work that can be done -by a DMA controller. - -In some SoCs only specific DMA channels may be used with specific devices. In -others there are requirements around needing a DMA handshake or specific -triggering setups to tell the DMA when to start its operation. - -None of that, from the outward facing API, is an issue. - -It is however an unresolved task and issue from an internal API between the -executor and iodev. This requires some SoC specifics and enabling those -generically isn't likely possible. That's ok, an iodev and dma executor should -be vendor specific, but an API needs to be there between them that is not! - - -Special Hardware: Intel HDA -=========================== - -In some cases there's a need to always do things in a specific order -with a specific buffer allocation strategy. Consider a DMA that *requires* -the usage of a circular buffer segmented into blocks that may only be -transferred one after another. This is the case of the Intel HDA stream for -audio. - -In this scenario the above API can still work, but would require an additional -buffer allocator to work with fixed sized segments. - When to Use *********** -It's important to understand when DMA like transfers are useful and when they -are not. It's a poor idea to assume that something made for high throughput will -work for you. There is a computational, memory, and latency cost to setup the -description of transfers. +RTIO is useful in cases where concurrent or batch like I/O flows are useful. -Polling at 1Hz an air sensor will almost certainly result in a net negative -result compared to ad-hoc sensor (i2c/spi) requests to get the sample. +From the driver/hardware perspective the API enables batching of I/O requests, potentially in an optimal way. +Many requests to the same SPI peripheral for example might be translated to hardware command queues or DMA transfer +descriptors entirely. Meaning the hardware can potentially do more than ever. -Continuous transfers, driven by timer or interrupt, of data from a peripheral's -on board FIFO over I2C, I3C, SPI, MIPI, I2S, etc... maybe, but not always! +There is a small cost to each RTIO context and iodev. This cost could be weighed +against using a thread for each concurent I/O operation or custom queues and +threads per peripheral. RTIO is much lower cost than that. Examples ******** @@ -488,12 +416,4 @@ video. API Reference ************* -RTIO API -======== - -.. doxygengroup:: rtio_api - -RTIO SPSC API -============= - -.. doxygengroup:: rtio_spsc +.. doxygengroup:: rtio From cbbe6d2ab76b20d772f548251ed7c84ea87bb7dd Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 18 Jul 2023 13:11:07 -0700 Subject: [PATCH 1562/2042] kernel: userspace: Simplify dinamyc objects There is not need to have two types to represent dynamic objects. Signed-off-by: Flavio Ceolin --- kernel/userspace.c | 75 +++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/kernel/userspace.c b/kernel/userspace.c index f9a5be98a27e..9c7d8d33930d 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -165,23 +165,9 @@ uint8_t *z_priv_stack_find(k_thread_stack_t *stack) #define DYN_OBJ_DATA_ALIGN \ MAX(DYN_OBJ_DATA_ALIGN_K_THREAD, (sizeof(void *))) -struct dyn_obj_base { - struct z_object kobj; - sys_dnode_t dobj_list; /* must be immediately before data member */ -}; - struct dyn_obj { - struct dyn_obj_base base; - - /* The object itself */ - uint8_t data[] __aligned(DYN_OBJ_DATA_ALIGN_K_THREAD); -}; - -/* Thread stacks impose a very restrict alignment. Use this alignment - * (generally page size) for all objects will cause a lot waste memory. - */ -struct dyn_obj_stack { - struct dyn_obj_base base; + struct z_object kobj; + sys_dnode_t dobj_list; /* The object itself */ void *data; @@ -227,9 +213,6 @@ static size_t obj_align_get(enum k_objects otype) ret = __alignof(struct dyn_obj); #endif break; - case K_OBJ_THREAD_STACK_ELEMENT: - ret = __alignof(struct dyn_obj_stack); - break; default: ret = __alignof(struct dyn_obj); break; @@ -238,9 +221,9 @@ static size_t obj_align_get(enum k_objects otype) return ret; } -static struct dyn_obj_base *dyn_object_find(void *obj) +static struct dyn_obj *dyn_object_find(void *obj) { - struct dyn_obj_base *node; + struct dyn_obj *node; k_spinlock_key_t key; /* For any dynamically allocated kernel object, the object @@ -331,55 +314,51 @@ static void thread_idx_free(uintptr_t tidx) static struct z_object *dynamic_object_create(enum k_objects otype, size_t align, size_t size) { - struct dyn_obj_base *dyn; + struct dyn_obj *dyn; + + dyn = z_thread_aligned_alloc(align, sizeof(struct dyn_obj)); + if (dyn == NULL) { + return NULL; + } if (otype == K_OBJ_THREAD_STACK_ELEMENT) { - struct dyn_obj_stack *stack; size_t adjusted_size; if (size == 0) { + k_free(dyn); return NULL; } adjusted_size = STACK_ELEMENT_DATA_SIZE(size); - stack = z_thread_aligned_alloc(align, sizeof(struct dyn_obj_stack)); - if (stack == NULL) { - return NULL; - } - dyn = &stack->base; - - stack->data = z_thread_aligned_alloc(DYN_OBJ_DATA_ALIGN_K_THREAD_STACK, + dyn->data = z_thread_aligned_alloc(DYN_OBJ_DATA_ALIGN_K_THREAD_STACK, adjusted_size); - if (stack->data == NULL) { - k_free(stack); + if (dyn->data == NULL) { + k_free(dyn); return NULL; } #ifdef CONFIG_GEN_PRIV_STACKS struct z_stack_data *stack_data = (struct z_stack_data *) - ((uint8_t *)stack->data + adjusted_size - sizeof(*stack_data)); - stack_data->priv = (uint8_t *)stack->data; + ((uint8_t *)dyn->data + adjusted_size - sizeof(*stack_data)); + stack_data->priv = (uint8_t *)dyn->data; dyn->kobj.data.stack_data = stack_data; #ifdef CONFIG_ARM_MPU dyn->kobj.name = (void *)ROUND_UP( - ((uint8_t *)stack->data + CONFIG_PRIVILEGED_STACK_SIZE), + ((uint8_t *)dyn->data + CONFIG_PRIVILEGED_STACK_SIZE), Z_THREAD_STACK_OBJ_ALIGN(size)); #else - dyn->kobj.name = stack->data; + dyn->kobj.name = dyn->data; #endif #else - dyn->kobj.name = stack->data; + dyn->kobj.name = dyn->data; #endif } else { - struct dyn_obj *obj; - - obj = z_thread_aligned_alloc(align, - sizeof(struct dyn_obj) + obj_size_get(otype) + size); - if (obj == NULL) { + dyn->data = z_thread_aligned_alloc(align, obj_size_get(otype) + size); + if (dyn->data == NULL) { + k_free(dyn->data); return NULL; } - dyn = &obj->base; - dyn->kobj.name = &obj->data; + dyn->kobj.name = dyn->data; } dyn->kobj.type = otype; @@ -471,7 +450,7 @@ void *z_impl_k_object_alloc_size(enum k_objects otype, size_t size) void k_object_free(void *obj) { - struct dyn_obj_base *dyn; + struct dyn_obj *dyn; /* This function is intentionally not exposed to user mode. * There's currently no robust way to track that an object isn't @@ -502,7 +481,7 @@ struct z_object *z_object_find(const void *obj) ret = z_object_gperf_find(obj); if (ret == NULL) { - struct dyn_obj_base *dyn; + struct dyn_obj *dyn; /* The cast to pointer-to-non-const violates MISRA * 11.8 but is justified since we know dynamic objects @@ -519,7 +498,7 @@ struct z_object *z_object_find(const void *obj) void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) { - struct dyn_obj_base *obj, *next; + struct dyn_obj *obj, *next; z_object_gperf_wordlist_foreach(func, context); @@ -559,7 +538,7 @@ static void unref_check(struct z_object *ko, uintptr_t index) void *vko = ko; - struct dyn_obj_base *dyn = CONTAINER_OF(vko, struct dyn_obj_base, kobj); + struct dyn_obj *dyn = CONTAINER_OF(vko, struct dyn_obj, kobj); __ASSERT(IS_PTR_ALIGNED(dyn, struct dyn_obj), "unaligned z_object"); From ed8355ad3ff35aae28b8a7a48c66748d9e8ada24 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Tue, 18 Jul 2023 21:00:07 +0000 Subject: [PATCH 1563/2042] kernel: userspace: Fix memory leak Fix memory leak on dynamic object allocation. Signed-off-by: Flavio Ceolin --- kernel/userspace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/userspace.c b/kernel/userspace.c index 9c7d8d33930d..000310c3ab06 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -470,6 +470,7 @@ void k_object_free(void *obj) k_spin_unlock(&objfree_lock, key); if (dyn != NULL) { + k_free(dyn->data); k_free(dyn); } } @@ -571,6 +572,7 @@ static void unref_check(struct z_object *ko, uintptr_t index) } sys_dlist_remove(&dyn->dobj_list); + k_free(dyn->data); k_free(dyn); out: #endif From 4c80949ecf4d90b3e23a18d7e58b623272ba6c10 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 20 Jul 2023 09:04:38 -0700 Subject: [PATCH 1564/2042] libc: remove no longer valid kconfig comment After commit 9a0aebc5fd9c39fb3d4a4a9741fcff7e1695e807, the exclusion of qemu_x86_tiny is no longer and the "depends on" option was removed. However, the comment about that remained. Remove the comment as it is no longer valid. Signed-off-by: Daniel Leung --- lib/libc/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 13e590b23b51..b864f5b34f10 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -37,7 +37,6 @@ config PICOLIBC_SUPPORTED depends on !NATIVE_APPLICATION depends on ("$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr") || (NATIVE_LIBRARY) depends on !(CPP && "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr") - # picolibc text is outside .pinned.text on this board. #54148 default y select FULL_LIBC_SUPPORTED help From 3038a3c4e041858f1f77fcc4fa1463107dbac4f9 Mon Sep 17 00:00:00 2001 From: David Leach Date: Mon, 17 Jul 2023 14:29:06 -0500 Subject: [PATCH 1565/2042] MAINTAINERS: Add manuargue to NXP HAL maintainer list Add manuargue to NXP HAL maintainer list Signed-off-by: David Leach --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index b7efb0bae35f..3e9ccaea4b9f 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2911,10 +2911,12 @@ West: collaborators: - mmahadevan108 - danieldegrasse + - manuargue files: - modules/hal_nxp/ - modules/Kconfig.imx - modules/Kconfig.mcux + - modules/Kconfig.s32 labels: - manifest-hal_nxp From f856e7ba636602a9549c72a4704c3f7268b93ee3 Mon Sep 17 00:00:00 2001 From: Al Semjonovs Date: Thu, 20 Jul 2023 09:17:16 -0600 Subject: [PATCH 1566/2042] icm42688: Fix channels read BIT shift error channel_pos_read bit was being cleared with a sensor channel enum value instead of the encoded bit position. Signed-off-by: Al Semjonovs --- drivers/sensor/icm42688/icm42688_decoder.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 16cb48dbcca0..42a44496ef70 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -223,39 +223,39 @@ static int icm42688_one_shot_decode(const uint8_t *buffer, sensor_frame_iterator q31_t *values, uint8_t max_count) { const struct icm42688_encoded_data *edata = (const struct icm42688_encoded_data *)buffer; - uint8_t channels_read = edata->channels; + uint8_t channel_pos_read = edata->channels; struct icm42688_cfg cfg = { .accel_fs = edata->header.accel_fs, .gyro_fs = edata->header.gyro_fs, }; - int chan; + enum sensor_channel chan; int pos; int count = 0; - int num_samples = __builtin_popcount(channels_read); + int num_samples = __builtin_popcount(channel_pos_read); - channels_read = edata->channels; + channel_pos_read = edata->channels; if (*fit != 0) { return 0; } /* Skip channels already decoded */ - for (int i = 0; i < *cit && channels_read; i++) { - chan = __builtin_ctz(channels_read); - channels_read &= ~BIT(chan); + for (int i = 0; i < *cit && channel_pos_read; i++) { + pos = __builtin_ctz(channel_pos_read); + channel_pos_read &= ~BIT(pos); } /* Decode remaining channels */ - while (channels_read && *cit < num_samples && count < max_count) { - chan = icm42688_get_channel_from_position(__builtin_ctz(channels_read)); + while (channel_pos_read && *cit < num_samples && count < max_count) { + pos = __builtin_ctz(channel_pos_read); + chan = icm42688_get_channel_from_position(pos); channels[count] = chan; - pos = icm42688_get_channel_position(chan); icm42688_convert_raw_to_q31(&cfg, chan, edata->readings[pos], &values[count]); count++; - channels_read &= ~BIT(chan); + channel_pos_read &= ~BIT(pos); *cit += 1; } From 278563ed45e5a0724d469e079348cbdd416bd1ad Mon Sep 17 00:00:00 2001 From: Paul He Date: Thu, 20 Jul 2023 22:49:12 +0800 Subject: [PATCH 1567/2042] drivers: input: gt911: fix error 'ret' undeclared When CONFIG_INPUT_GT911_INTERRUPT is set to 'y', it will get this undeclared error, now fix it. Signed-off-by: Paul He --- drivers/input/input_gt911.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index 99468b4ed37f..1517c25ec655 100644 --- a/drivers/input/input_gt911.c +++ b/drivers/input/input_gt911.c @@ -346,7 +346,7 @@ static int gt911_init(const struct device *dev) r = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); if (r < 0) { LOG_ERR("Could not set gpio callback"); - return ret; + return r; } #else k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_GT911_PERIOD_MS), From b3f0a085123f3573e172f66f7ca252c538414453 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 20 Jul 2023 15:49:59 +0200 Subject: [PATCH 1568/2042] doc: nrf52_bsim: Update list of supported peripherals The GPIO, GPIOTE and FICR are now also modelled to a reasonable degree. Signed-off-by: Alberto Escolar Piedras --- boards/posix/nrf52_bsim/doc/index.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/boards/posix/nrf52_bsim/doc/index.rst b/boards/posix/nrf52_bsim/doc/index.rst index a1de9a4f7ba7..afddf7e9098d 100644 --- a/boards/posix/nrf52_bsim/doc/index.rst +++ b/boards/posix/nrf52_bsim/doc/index.rst @@ -19,16 +19,18 @@ This board models some of the NRF52 SOC peripherals: * Radio * Timers -* Real time counter -* Random number generator +* RTC (Real Time Counter) +* RNG (Random Number Generator) * AES CCM & AES ECB encryption HW -* Accelerated address resolver -* Clock control +* AAR (Accelerated Address Resolver) +* CLOCK (Clock control) * PPI (Programmable Peripheral Interconnect) * EGU (Event Generator Unit) +* GPIO & GPIOTE * TEMP (Temperature sensor) -* UICR (User information configuration registers) -* NVMC (Non-volatile memory controller) +* UICR (User Information Configuration Registers) +* FICR (Factory Information Configuration Registers) +* NVMC (Non-Volatile Memory Controller) The nrf52_bsim board definition uses the POSIX architecture to run applications natively on the development system, this has the benefit of From b69cd3cbc101cae3558a4730fa320e25a43b1543 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 20 Jul 2023 15:58:26 +0200 Subject: [PATCH 1569/2042] manifest: Update nRF HW models to latest Which include a more complete model of the CLOCK peripheral. 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 5e0e49553182..efefa62175f3 100644 --- a/west.yml +++ b/west.yml @@ -287,7 +287,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 33b999d50093da88cf935383da2bdac70ffd9456 + revision: 7a5b67d9ee66d84e4ef5cb1f56c8f0f3252d5aa2 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad From d24880e35894aebf0fd24e02babf5ac1e02254f6 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 21 Jul 2023 11:45:43 +0200 Subject: [PATCH 1570/2042] test: Exclude qemu_cortex_a53_smp from portability.posix.eventfd The test is failing for (so far) unknown reasons, blocking several PRs. Exclude it until a proper investigation finds the root cause. Signed-off-by: Carlo Caione --- tests/posix/eventfd/testcase.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/posix/eventfd/testcase.yaml b/tests/posix/eventfd/testcase.yaml index f44c97fc100f..5111b7ddcbc7 100644 --- a/tests/posix/eventfd/testcase.yaml +++ b/tests/posix/eventfd/testcase.yaml @@ -5,5 +5,8 @@ common: - eventfd integration_platforms: - qemu_x86 + # See issue #60678 + platform_exclude: + - qemu_cortex_a53_smp tests: portability.posix.eventfd: {} From f851d2a61b45f6dd452bb1ecab1d2cbee60dfb5b Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 19 Jul 2023 11:16:25 -0700 Subject: [PATCH 1571/2042] tests: lib: c_lib: fix test_sqrt double promotion warnings Double promotion warnings are generated with the flag -Wdouble-promotion Exponent was defined as a float, but was really be used a double here Change the type of exponent in sqrt from float to double. Signed-off-by: Ryan McClelland --- tests/lib/c_lib/src/test_sqrt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lib/c_lib/src/test_sqrt.c b/tests/lib/c_lib/src/test_sqrt.c index ce7fd4f58594..99af27717af3 100644 --- a/tests/lib/c_lib/src/test_sqrt.c +++ b/tests/lib/c_lib/src/test_sqrt.c @@ -167,8 +167,7 @@ int32_t *p_root_squared = (int32_t *)&root_squared; ZTEST(test_c_lib, test_sqrt) { int i; -float exponent; -double resd, error, square, root_squared; +double resd, error, square, root_squared, exponent; uint64_t max_error; int64_t ierror; int64_t *p_square = (int64_t *)□ From 995444d5a92aab704727a6dd9f9e06a5375e2809 Mon Sep 17 00:00:00 2001 From: Tim Lin Date: Wed, 19 Jul 2023 21:20:50 +0800 Subject: [PATCH 1572/2042] ITE: drivers/i2c: Modify the condition of assert Channel B or C do not necessarily have to use FIFO mode. Signed-off-by: Tim Lin --- drivers/i2c/i2c_ite_it8xxx2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c_ite_it8xxx2.c b/drivers/i2c/i2c_ite_it8xxx2.c index 60f64a5404a8..9e2bf227c6dd 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -1232,11 +1232,9 @@ static const struct i2c_driver_api i2c_it8xxx2_driver_api = { }; #ifdef CONFIG_I2C_IT8XXX2_FIFO_MODE -BUILD_ASSERT(((DT_INST_PROP(SMB_CHANNEL_B, fifo_enable) == true) && - (DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == false)) || - ((DT_INST_PROP(SMB_CHANNEL_B, fifo_enable) == false) && +BUILD_ASSERT(!((DT_INST_PROP(SMB_CHANNEL_B, fifo_enable) == true) && (DT_INST_PROP(SMB_CHANNEL_C, fifo_enable) == true)), - "FIFO2 only supports one channel of B or C."); + "Channel B and C cannot support FIFO mode at the same time."); #endif #define I2C_ITE_IT8XXX2_INIT(inst) \ From 748683fae6fa53511df9170da3e8384a092214f9 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 20 Jul 2023 21:02:30 -0400 Subject: [PATCH 1573/2042] posix: eventfd: remove redundant conditional Since the argument is a 32-bit unsigned int, all possible values satisfy the condition that intval < UINT64_MAX - 1. Remove the redundant conditional. Signed-off-by: Christopher Friedt --- lib/posix/eventfd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/posix/eventfd.c b/lib/posix/eventfd.c index d32ac4c06b42..767cf5a60cc3 100644 --- a/lib/posix/eventfd.c +++ b/lib/posix/eventfd.c @@ -435,9 +435,8 @@ int eventfd(unsigned int initval, int flags) if (initval != 0) { k_poll_signal_raise(&efd->read_sig, 0); } - if (initval < UINT64_MAX - 1) { - k_poll_signal_raise(&efd->write_sig, 0); - } + + k_poll_signal_raise(&efd->write_sig, 0); z_finalize_fd(fd, efd, &eventfd_fd_vtable); From ecbaac60bd41142ae4dc6aa65b52816e5ffe69e2 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Thu, 20 Jul 2023 21:10:29 +0800 Subject: [PATCH 1574/2042] drivers: flash: support for Nuvoton numaker series FMC Add Nuvoton numaker series flash memory controller(FMC) with erase, read & write features of soc-flash. Also update Nuvoton manifest to include zephyrproject-rtos/hal_nuvoton#6. Signed-off-by: cyliang tw --- .../numaker_pfm_m467_defconfig | 4 + drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig | 2 + drivers/flash/Kconfig.numaker | 16 + drivers/flash/soc_flash_numaker.c | 284 ++++++++++++++++++ dts/arm/nuvoton/m46x.dtsi | 25 +- .../flash_controller/nuvoton,numaker-fmc.yaml | 9 + west.yml | 2 +- 8 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 drivers/flash/Kconfig.numaker create mode 100644 drivers/flash/soc_flash_numaker.c create mode 100644 dts/bindings/flash_controller/nuvoton,numaker-fmc.yaml diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig b/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig index 8b9e8d75b12c..abc0d144a949 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467_defconfig @@ -20,3 +20,7 @@ CONFIG_UART_INTERRUPT_DRIVEN=y # console CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y + +# Enable FMC +CONFIG_FLASH=y +CONFIG_SOC_FLASH_NUMAKER=y diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index b78ce14e78cc..fd9aff229e19 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -109,3 +109,4 @@ zephyr_library_include_directories_ifdef( zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c) zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c) zephyr_library_sources_ifdef(CONFIG_FLASH_INFINEON_CAT1 flash_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER soc_flash_numaker.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 2229d5207050..8d50a77e78db 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -152,4 +152,6 @@ source "drivers/flash/Kconfig.xmc4xxx" source "drivers/flash/Kconfig.ifx_cat1" +source "drivers/flash/Kconfig.numaker" + endif # FLASH diff --git a/drivers/flash/Kconfig.numaker b/drivers/flash/Kconfig.numaker new file mode 100644 index 000000000000..98d4790589d3 --- /dev/null +++ b/drivers/flash/Kconfig.numaker @@ -0,0 +1,16 @@ +# NUMAKER GPIO driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FLASH_NUMAKER + bool "Nuvoton NuMaker MCU flash driver" + default y + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select HAS_NUMAKER_FMC + depends on DT_HAS_NUVOTON_NUMAKER_FMC_ENABLED + help + This option enables the FMC driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker FMC. diff --git a/drivers/flash/soc_flash_numaker.c b/drivers/flash/soc_flash_numaker.c new file mode 100644 index 000000000000..81daec426c83 --- /dev/null +++ b/drivers/flash/soc_flash_numaker.c @@ -0,0 +1,284 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Nuvoton Technology Corporation. + */ + +#define DT_DRV_COMPAT nuvoton_numaker_fmc + +#include +#include +#include +#include +#include +#include +#include "flash_priv.h" +#include + +LOG_MODULE_REGISTER(flash_numaker, CONFIG_FLASH_LOG_LEVEL); + +#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +#define SOC_NV_FLASH_WRITE_BLOCK_SIZE DT_PROP_OR(SOC_NV_FLASH_NODE, write_block_size, 0x04) + +struct flash_numaker_data { + FMC_T *fmc; + struct k_sem write_lock; + uint32_t flash_block_base; +}; + +static const struct flash_parameters flash_numaker_parameters = { + .write_block_size = SOC_NV_FLASH_WRITE_BLOCK_SIZE, + .erase_value = 0xff, +}; + +/* Validate offset and length */ +static bool flash_numaker_is_range_valid(off_t offset, size_t len) +{ + uint32_t aprom_size = (FMC_APROM_END - FMC_APROM_BASE); + + /* check for min value */ + if ((offset < 0) || (len == 0)) { + return false; + } + + /* check for max value */ + if (offset >= aprom_size || len > aprom_size || (aprom_size - offset) < len) { + return false; + } + + return true; +} + +/* + * Erase a flash memory area. + * + * param dev Device struct + * param offset The address's offset + * param len The size of the buffer + * return 0 on success + * return -EINVAL erroneous code + */ + +static int flash_numaker_erase(const struct device *dev, off_t offset, size_t len) +{ + struct flash_numaker_data *dev_data = dev->data; + uint32_t rc = 0; + unsigned int key; + int page_nums = (len / FMC_FLASH_PAGE_SIZE); + uint32_t addr = dev_data->flash_block_base + offset; + + /* return SUCCESS for len == 0 (required by tests/drivers/flash) */ + if (!len) { + return 0; + } + + /* Validate range */ + if (!flash_numaker_is_range_valid(offset, len)) { + return -EINVAL; + } + + /* check alignment and erase only by pages */ + if (((addr % FMC_FLASH_PAGE_SIZE) != 0) || ((len % FMC_FLASH_PAGE_SIZE) != 0)) { + return -EINVAL; + } + + /* take semaphore */ + if (k_sem_take(&dev_data->write_lock, K_NO_WAIT)) { + return -EACCES; + } + + SYS_UnlockReg(); + key = irq_lock(); + while (page_nums) { + if (((len >= FMC_BANK_SIZE)) && ((addr % FMC_BANK_SIZE) == 0)) { + if (FMC_Erase_Bank(addr)) { + LOG_ERR("Erase flash bank failed or erase time-out"); + rc = -EIO; + goto done; + } + page_nums -= (FMC_BANK_SIZE / FMC_FLASH_PAGE_SIZE); + addr += FMC_BANK_SIZE; + } else { + /* erase page */ + if (FMC_Erase(addr)) { + LOG_ERR("Erase flash page failed or erase time-out"); + rc = -EIO; + goto done; + } + page_nums--; + addr += FMC_FLASH_PAGE_SIZE; + } + } + +done: + SYS_LockReg(); + irq_unlock(key); + /* release semaphore */ + k_sem_give(&dev_data->write_lock); + + return rc; +} + +/* + * Read a flash memory area. + * + * param dev Device struct + * param offset The address's offset + * param data The buffer to store or read the value + * param length The size of the buffer + * return 0 on success, + * return -EIO erroneous code + */ +static int flash_numaker_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + struct flash_numaker_data *dev_data = dev->data; + uint32_t addr = dev_data->flash_block_base + offset; + + /* return SUCCESS for len == 0 (required by tests/drivers/flash) */ + if (!len) { + return 0; + } + + /* Validate range */ + if (!flash_numaker_is_range_valid(offset, len)) { + return -EINVAL; + } + + /* read flash */ + memcpy(data, (void *)addr, len); + + return 0; +} + +static int32_t flash_numaker_block_write(uint32_t u32_addr, uint8_t *pu8_data, int block_size) +{ + int32_t retval; + uint32_t *pu32_data = (uint32_t *)pu8_data; + + SYS_UnlockReg(); + if (block_size == 4) { + retval = FMC_Write(u32_addr, *pu32_data); + } else if (block_size == 8) { + retval = FMC_Write8Bytes(u32_addr, *pu32_data, *(pu32_data + 1)); + } else { + retval = -1; + } + SYS_LockReg(); + + return retval; +} + +static int flash_numaker_write(const struct device *dev, off_t offset, const void *data, size_t len) +{ + struct flash_numaker_data *dev_data = dev->data; + uint32_t rc = 0; + unsigned int key; + uint32_t addr = dev_data->flash_block_base + offset; + int block_size = flash_numaker_parameters.write_block_size; + int blocks = (len / flash_numaker_parameters.write_block_size); + uint8_t *pu8_data = (uint8_t *)data; + + /* return SUCCESS for len == 0 (required by tests/drivers/flash) */ + if (!len) { + return 0; + } + + /* Validate range */ + if (!flash_numaker_is_range_valid(offset, len)) { + return -EINVAL; + } + + /* Validate address alignment */ + if ((addr % flash_numaker_parameters.write_block_size) != 0) { + return -EINVAL; + } + + /* Validate write size be multiples of the write block size */ + if ((len % block_size) != 0) { + return -EINVAL; + } + + /* Validate offset be multiples of the write block size */ + if ((offset % block_size) != 0) { + return -EINVAL; + } + + if (k_sem_take(&dev_data->write_lock, K_FOREVER)) { + return -EACCES; + } + + key = irq_lock(); + + while (blocks) { + if (flash_numaker_block_write(addr, pu8_data, block_size)) { + rc = -EIO; + goto done; + } + pu8_data += block_size; + addr += block_size; + blocks--; + } + +done: + irq_unlock(key); + + k_sem_give(&dev_data->write_lock); + + return rc; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static const struct flash_pages_layout dev_layout = { + .pages_count = + DT_REG_SIZE(SOC_NV_FLASH_NODE) / DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), + .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), +}; + +static void flash_numaker_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + *layout = &dev_layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static const struct flash_parameters *flash_numaker_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_numaker_parameters; +} + +static struct flash_numaker_data flash_data; + +static const struct flash_driver_api flash_numaker_api = { + .erase = flash_numaker_erase, + .write = flash_numaker_write, + .read = flash_numaker_read, + .get_parameters = flash_numaker_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_numaker_pages_layout, +#endif +}; + +static int flash_numaker_init(const struct device *dev) +{ + struct flash_numaker_data *dev_data = dev->data; + + k_sem_init(&dev_data->write_lock, 1, 1); + + /* Enable FMC ISP function */ + SYS_UnlockReg(); + FMC_Open(); + /* Enable APROM update. */ + FMC_ENABLE_AP_UPDATE(); + SYS_LockReg(); + dev_data->flash_block_base = (uint32_t)FMC_APROM_BASE; + dev_data->fmc = (FMC_T *)DT_REG_ADDR(DT_NODELABEL(fmc)); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, flash_numaker_init, NULL, &flash_data, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &flash_numaker_api); diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index d4bec675f61b..b018032cc82f 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -12,6 +12,10 @@ #include / { + chosen { + zephyr,flash-controller = &fmc; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -28,13 +32,6 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; - flash0: flash@0 { - compatible = "soc-nv-flash"; - reg = <0 DT_SIZE_K(1024)>; - erase-block-size = <4096>; - write-block-size = <4>; - }; - sysclk: system-clock { compatible = "fixed-clock"; clock-frequency = <200000000>; @@ -65,6 +62,20 @@ status = "okay"; }; + fmc: flash-controller@4000c000 { + compatible = "nuvoton,numaker-fmc"; + reg = <0x4000c000 0x110>; + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_K(1024)>; + erase-block-size = <4096>; + write-block-size = <4>; + }; + }; + uart0: serial@40070000 { compatible = "nuvoton,numaker-uart"; reg = <0x40070000 0x1000>; diff --git a/dts/bindings/flash_controller/nuvoton,numaker-fmc.yaml b/dts/bindings/flash_controller/nuvoton,numaker-fmc.yaml new file mode 100644 index 000000000000..8555885214d0 --- /dev/null +++ b/dts/bindings/flash_controller/nuvoton,numaker-fmc.yaml @@ -0,0 +1,9 @@ +description: Nuvoton NuMaker Flash Controller + +compatible: "nuvoton,numaker-fmc" + +include: flash-controller.yaml + +properties: + reg: + required: true diff --git a/west.yml b/west.yml index efefa62175f3..f0a69af00ab4 100644 --- a/west.yml +++ b/west.yml @@ -178,7 +178,7 @@ manifest: groups: - hal - name: hal_nuvoton - revision: 8a2b5de1670b59fcacd20d7495cb1c0f26fbe7bd + revision: 3e0a4c4d3328b2f72b164219add19d5308b53cb5 path: modules/hal/nuvoton groups: - hal From 8fc913374fd4db256d556a47babb164b05c40331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kornel=20Dul=C4=99ba?= Date: Mon, 17 Jul 2023 08:36:52 +0000 Subject: [PATCH 1575/2042] include: util: Add DIV_ROUND_CLOSEST helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's similar to DIV_ROUND_UP, but rounds to the nearest integer. Some basic unit tests were introduced to check that it works as intended. Signed-off-by: Kornel Dulęba --- include/zephyr/sys/util.h | 19 +++++++++++++++++++ tests/unit/util/main.c | 10 ++++++++++ tests/unit/util/test.inc | 13 +++++++++++++ 3 files changed, 42 insertions(+) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index d8a63a25e9da..f352e7b7a80b 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -259,6 +259,25 @@ extern "C" { */ #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +/** + * @brief Divide and round to the nearest integer. + * + * Example: + * @code{.c} + * DIV_ROUND_CLOSEST(5, 2); // 3 + * DIV_ROUND_CLOSEST(5, -2); // -3 + * DIV_ROUND_CLOSEST(5, 3); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded to the nearest integer. + */ +#define DIV_ROUND_CLOSEST(n, d) \ + ((((n) < 0) ^ ((d) < 0)) ? ((n) - ((d) / 2)) / (d) : \ + ((n) + ((d) / 2)) / (d)) + /** * @brief Ceiling function applied to @p numerator / @p divider as a fraction. * @deprecated Use DIV_ROUND_UP() instead. diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 18a33802eb50..bce626f9fe4f 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -151,6 +151,11 @@ ZTEST(util_cxx, test_DIV_ROUND_UP) run_DIV_ROUND_UP(); } +ZTEST(util_cxx, test_DIV_ROUND_CLOSEST) +{ + run_DIV_ROUND_CLOSEST(); +} + ZTEST_SUITE(util_cxx, NULL, NULL, NULL, NULL, NULL); #if __cplusplus @@ -294,4 +299,9 @@ ZTEST(util_cc, test_DIV_ROUND_UP) run_DIV_ROUND_UP(); } +ZTEST(util_cc, test_DIV_ROUND_CLOSEST) +{ + run_DIV_ROUND_CLOSEST(); +} + ZTEST_SUITE(util_cc, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/unit/util/test.inc b/tests/unit/util/test.inc index aef613b95910..c47cc7ab7e25 100644 --- a/tests/unit/util/test.inc +++ b/tests/unit/util/test.inc @@ -615,3 +615,16 @@ void run_DIV_ROUND_UP(void) 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); +} From 85a41ae88a44c39059d9875d184fd8af14baa47f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 23 Dec 2022 22:42:29 -0600 Subject: [PATCH 1576/2042] drivers: led: added support for is31fl3733 led driver Enabled support for is31fl3733 driver. This driver supports the full LED API, and enables the following features of the is31fl3733: - individual LED dimming - individual LED enable/disable - bulk writes of LED enabled and dimming states - global LED current limit - blanking (via custom API) Signed-off-by: Daniel DeGrasse --- drivers/led/CMakeLists.txt | 1 + drivers/led/Kconfig | 1 + drivers/led/Kconfig.is31fl3733 | 12 + drivers/led/is31fl3733.c | 301 ++++++++++++++++++++++++ dts/bindings/led/issi,is31fl3733.yaml | 38 +++ include/zephyr/drivers/led/is31fl3733.h | 36 +++ 6 files changed, 389 insertions(+) create mode 100644 drivers/led/Kconfig.is31fl3733 create mode 100644 drivers/led/is31fl3733.c create mode 100644 dts/bindings/led/issi,is31fl3733.yaml create mode 100644 include/zephyr/drivers/led/is31fl3733.h diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index b38ecbf58410..2560b038c135 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_LP5562 lp5562.c) zephyr_library_sources_ifdef(CONFIG_LP5569 lp5569.c) zephyr_library_sources_ifdef(CONFIG_PCA9633 pca9633.c) zephyr_library_sources_ifdef(CONFIG_TLC59108 tlc59108.c) +zephyr_library_sources_ifdef(CONFIG_IS31FL3733 is31fl3733.c) zephyr_library_sources_ifdef(CONFIG_LED_SHELL led_shell.c) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 91cb28544b98..65d2449ee1a1 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -38,5 +38,6 @@ source "drivers/led/Kconfig.pca9633" source "drivers/led/Kconfig.pwm" source "drivers/led/Kconfig.tlc59108" source "drivers/led/Kconfig.xec" +source "drivers/led/Kconfig.is31fl3733" endif # LED diff --git a/drivers/led/Kconfig.is31fl3733 b/drivers/led/Kconfig.is31fl3733 new file mode 100644 index 000000000000..20eaf3d269c1 --- /dev/null +++ b/drivers/led/Kconfig.is31fl3733 @@ -0,0 +1,12 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +config IS31FL3733 + bool "IS31FL3733 LED driver" + default y + depends on DT_HAS_ISSI_IS31FL3733_ENABLED + select I2C + help + Enable LED driver for IS31FL3733. + IS31FL3733 is a matrix LED driver, capable of a maximum of 3.29 mA + per LED, or 42 mA total across all LEDs in the 12x16 dot matrix. diff --git a/drivers/led/is31fl3733.c b/drivers/led/is31fl3733.c new file mode 100644 index 000000000000..3298bbc9b7c4 --- /dev/null +++ b/drivers/led/is31fl3733.c @@ -0,0 +1,301 @@ +/* + * Copyright 2022-2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT issi_is31fl3733 + +#include +#include +#include +#include + +#include + +#include +LOG_MODULE_REGISTER(is31fl3733, CONFIG_LED_LOG_LEVEL); + +/* IS31FL3733 register definitions */ +#define CMD_SEL_REG 0xFD /* Command/page selection reg */ +#define CMD_SEL_LED 0x0 /* LED configuration page */ +#define CMD_SEL_PWM 0x1 /* PWM configuration page */ +#define CMD_SEL_FUNC 0x3 /* Function configuration page */ + +#define CMD_LOCK_REG 0xFE /* Command selection lock reg */ +#define CMD_LOCK_UNLOCK 0xC5 /* Command sel unlock value */ + +/* IS31FL3733 page specific register definitions */ + +/* Function configuration page */ +#define CONF_REG 0x0 /* configuration register */ +#define CONF_REG_SSD_MASK 0x1 /* Software shutdown mask */ +#define CONF_REG_SSD_SHIFT 0x0 /* Software shutdown shift */ +#define CONF_REG_SYNC_SHIFT 0x6 /* Sync mode shift */ +#define CONF_REG_SYNC_MASK 0xC /* Sync mode mask */ + +#define GLOBAL_CURRENT_CTRL_REG 0x1 /* global current control register */ + +#define RESET_REG 0x11 /* Reset all registers to POR state */ + +/* Matrix Layout definitions */ +#define IS31FL3733_ROW_COUNT 12 +#define IS31FL3733_COL_COUNT 16 +#define IS31FL3733_MAX_LED (IS31FL3733_ROW_COUNT * IS31FL3733_COL_COUNT) + +/* Max brightness */ +#define IS31FL3733_MAX_BRIGHTNESS 100 + +struct is31fl3733_config { + struct i2c_dt_spec bus; + struct gpio_dt_spec sdb; + uint8_t current_limit; + uint8_t sync; +}; + +struct is31fl3733_data { + /* Active configuration page */ + uint32_t selected_page; + /* Scratch buffer, used for bulk controller writes */ + uint8_t scratch_buf[IS31FL3733_MAX_LED + 1]; + /* LED config reg state, IS31FL3733 conf reg is write only */ + uint8_t conf_reg; +}; + +/* Selects target register page for IS31FL3733. After setting the + * target page, all I2C writes will use the selected page until the selected + * page is changed. + */ +static int is31fl3733_select_page(const struct device *dev, uint8_t page) +{ + const struct is31fl3733_config *config = dev->config; + struct is31fl3733_data *data = dev->data; + int ret = 0U; + + if (data->selected_page == page) { + /* No change necessary */ + return 0; + } + + /* Unlock page selection register */ + ret = i2c_reg_write_byte_dt(&config->bus, CMD_LOCK_REG, CMD_LOCK_UNLOCK); + if (ret < 0) { + LOG_ERR("Could not unlock page selection register"); + return ret; + } + + /* Write to function select to select active page */ + ret = i2c_reg_write_byte_dt(&config->bus, CMD_SEL_REG, page); + if (ret < 0) { + LOG_ERR("Could not select active page"); + return ret; + } + data->selected_page = page; + + return ret; +} + +static int is31fl3733_led_set_brightness(const struct device *dev, uint32_t led, uint8_t value) +{ + const struct is31fl3733_config *config = dev->config; + int ret; + uint8_t led_brightness = (uint8_t)(((uint32_t)value * 255) / 100); + + if (led >= IS31FL3733_MAX_LED) { + return -EINVAL; + } + + /* Configure PWM mode */ + ret = is31fl3733_select_page(dev, CMD_SEL_PWM); + if (ret < 0) { + return ret; + } + + return i2c_reg_write_byte_dt(&config->bus, led, led_brightness); +} + +static int is31fl3733_led_on(const struct device *dev, uint32_t led) +{ + return is31fl3733_led_set_brightness(dev, led, IS31FL3733_MAX_BRIGHTNESS); +} + +static int is31fl3733_led_off(const struct device *dev, uint32_t led) +{ + return is31fl3733_led_set_brightness(dev, led, 0); +} + +static int is31fl3733_led_write_channels(const struct device *dev, uint32_t start_channel, + uint32_t num_channels, const uint8_t *buf) +{ + const struct is31fl3733_config *config = dev->config; + struct is31fl3733_data *data = dev->data; + int ret = 0U; + uint8_t *pwm_start; + + if ((start_channel + num_channels) > IS31FL3733_MAX_LED) { + return -EINVAL; + } + pwm_start = data->scratch_buf + start_channel; + /* Set PWM and LED target registers as first byte of each transfer */ + *pwm_start = start_channel; + memcpy((pwm_start + 1), buf, num_channels); + + /* Write LED PWM states */ + ret = is31fl3733_select_page(dev, CMD_SEL_PWM); + if (ret < 0) { + return ret; + } + LOG_HEXDUMP_DBG(pwm_start, (num_channels + 1), "PWM states"); + + return i2c_write_dt(&config->bus, pwm_start, num_channels + 1); +} + +static int is31fl3733_init(const struct device *dev) +{ + const struct is31fl3733_config *config = dev->config; + struct is31fl3733_data *data = dev->data; + int ret = 0U; + uint8_t dummy; + + if (!i2c_is_ready_dt(&config->bus)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + if (config->sdb.port != NULL) { + if (!gpio_is_ready_dt(&config->sdb)) { + LOG_ERR("GPIO SDB pin not ready"); + return -ENODEV; + } + /* Set SDB pin high to exit hardware shutdown */ + ret = gpio_pin_configure_dt(&config->sdb, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + return ret; + } + } + + ret = is31fl3733_select_page(dev, CMD_SEL_FUNC); + if (ret < 0) { + return ret; + } + /* + * read reset reg to reset all registers to POR state, + * in case we are booting from a warm reset. + */ + ret = i2c_reg_read_byte_dt(&config->bus, RESET_REG, &dummy); + if (ret < 0) { + return ret; + } + + /* Select function page after LED controller reset */ + ret = is31fl3733_select_page(dev, CMD_SEL_FUNC); + if (ret < 0) { + return ret; + } + /* Set global current control register based off devicetree value */ + ret = i2c_reg_write_byte_dt(&config->bus, GLOBAL_CURRENT_CTRL_REG, + config->current_limit); + if (ret < 0) { + return ret; + } + /* As a final step, we exit software shutdown, disabling display + * blanking. We also set the LED controller sync mode here. + */ + data->conf_reg = (config->sync << CONF_REG_SYNC_SHIFT) | CONF_REG_SSD_MASK; + ret = i2c_reg_write_byte_dt(&config->bus, CONF_REG, data->conf_reg); + if (ret < 0) { + return ret; + } + + /* Enable all LEDs. We only control LED brightness in this driver. */ + data->scratch_buf[0] = 0x0; + memset(data->scratch_buf + 1, 0xFF, (IS31FL3733_MAX_LED / 8)); + ret = is31fl3733_select_page(dev, CMD_SEL_LED); + if (ret < 0) { + return ret; + } + + return i2c_write_dt(&config->bus, data->scratch_buf, + (IS31FL3733_MAX_LED / 8) + 1); +} + +/* Custom IS31FL3733 specific APIs */ + +/** + * @brief Blanks IS31FL3733 LED display. + * + * When blank_en is set, the LED display will be disabled. This can be used for + * flicker-free display updates, or power saving. + * + * @param dev: LED device structure + * @param blank_en: should blanking be enabled + * @return 0 on success, or negative value on error. + */ +int is31fl3733_blank(const struct device *dev, bool blank_en) +{ + const struct is31fl3733_config *config = dev->config; + struct is31fl3733_data *data = dev->data; + int ret; + + ret = is31fl3733_select_page(dev, CMD_SEL_FUNC); + if (ret < 0) { + return ret; + } + + if (blank_en) { + data->conf_reg &= ~CONF_REG_SSD_MASK; + } else { + data->conf_reg |= CONF_REG_SSD_MASK; + } + + return i2c_reg_write_byte_dt(&config->bus, CONF_REG, data->conf_reg); +} + +/** + * @brief Sets led current limit + * + * Sets the current limit for the LED driver. This is a separate value + * from per-led brightness, and applies to all LEDs. + * This value sets the output current limit according + * to the following formula: (840/R_ISET) * (limit/256) + * See table 14 of the datasheet for additional details. + * @param dev: LED device structure + * @param limit: current limit to apply + * @return 0 on success, or negative value on error. + */ +int is31fl3733_current_limit(const struct device *dev, uint8_t limit) +{ + const struct is31fl3733_config *config = dev->config; + int ret; + + ret = is31fl3733_select_page(dev, CMD_SEL_FUNC); + if (ret < 0) { + return ret; + } + + /* Set global current control register */ + return i2c_reg_write_byte_dt(&config->bus, GLOBAL_CURRENT_CTRL_REG, limit); +} + +static const struct led_driver_api is31fl3733_api = { + .on = is31fl3733_led_on, + .off = is31fl3733_led_off, + .set_brightness = is31fl3733_led_set_brightness, + .write_channels = is31fl3733_led_write_channels, +}; + +#define IS31FL3733_DEVICE(n) \ + static const struct is31fl3733_config is31fl3733_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + .sdb = GPIO_DT_SPEC_INST_GET_OR(n, sdb_gpios, {}), \ + .current_limit = DT_INST_PROP(n, current_limit), \ + .sync = DT_INST_ENUM_IDX(n, sync_mode), \ + }; \ + \ + static struct is31fl3733_data is31fl3733_data_##n = { \ + .selected_page = CMD_SEL_LED, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &is31fl3733_init, NULL, &is31fl3733_data_##n, \ + &is31fl3733_config_##n, POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \ + &is31fl3733_api); + +DT_INST_FOREACH_STATUS_OKAY(IS31FL3733_DEVICE) diff --git a/dts/bindings/led/issi,is31fl3733.yaml b/dts/bindings/led/issi,is31fl3733.yaml new file mode 100644 index 000000000000..365dfece42ed --- /dev/null +++ b/dts/bindings/led/issi,is31fl3733.yaml @@ -0,0 +1,38 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 +description: ISSI IS31FL3733 LED Matrix Driver + +compatible: "issi,is31fl3733" + +include: "i2c-device.yaml" + +properties: + sdb-gpios: + type: phandle-array + description: | + Hardware shutdown pin. If routed on the board, this property must be + present. Set to a logical 1 at boot to exit the device from hardware + shutdown. + + current-limit: + type: int + default: 0xFF + description: | + Global current limit. Sets the global current control register of LED + driver (set table 14). Limits global current based on the following + formula: (840/R_ISET) * (current-limit/256). Defaults to max value + of 0xFF, so led output will still be enabled if property is + not provided. + + sync-mode: + type: string + default: "none" + enum: + - "none" + - "master" + - "slave" + description: | + This property configures the LED controller as a master or slave + clock device. This can be used to synchronize the output of multiple + LED controllers. See SYNC bits in led configuration register for more + information. diff --git a/include/zephyr/drivers/led/is31fl3733.h b/include/zephyr/drivers/led/is31fl3733.h new file mode 100644 index 000000000000..33f18a06d646 --- /dev/null +++ b/include/zephyr/drivers/led/is31fl3733.h @@ -0,0 +1,36 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_IS31FL3733_H_ +#define ZEPHYR_INCLUDE_DRIVERS_LED_IS31FL3733_H_ + +/** + * @brief Blanks IS31FL3733 LED display. + * + * When blank_en is set, the LED display will be disabled. This can be used for + * flicker-free display updates, or power saving. + * + * @param dev: LED device structure + * @param blank_en: should blanking be enabled + * @return 0 on success, or negative value on error. + */ +int is31fl3733_blank(const struct device *dev, bool blank_en); + +/** + * @brief Sets led current limit + * + * Sets the current limit for the LED driver. This is a separate value + * from per-led brightness, and applies to all LEDs. + * This value sets the output current limit according + * to the following formula: (840/R_ISET) * (limit/256) + * See table 14 of the datasheet for additional details. + * @param dev: LED device structure + * @param limit: current limit to apply + * @return 0 on success, or negative value on error. + */ +int is31fl3733_current_limit(const struct device *dev, uint8_t limit); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_IS31FL3733_H_ */ From 351cb4bafe6b8cb54773ae78f5ca465f03d8c76f Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 7 Apr 2023 23:58:35 -0500 Subject: [PATCH 1577/2042] samples: drivers: add led_is31fl3733 sample to demonstrate usage Add sample to demonstrate usage of IS31FL3733 LED using the LED API. This led matrix controller has several custom APIs to expose functionality not available within the standard led API, such as limiting LED current. Signed-off-by: Daniel DeGrasse --- samples/drivers/led_is31fl3733/CMakeLists.txt | 8 + samples/drivers/led_is31fl3733/Kconfig | 20 +++ samples/drivers/led_is31fl3733/README.rst | 35 ++++ .../led_is31fl3733/boards/frdm_k22f.overlay | 13 ++ samples/drivers/led_is31fl3733/prj.conf | 4 + samples/drivers/led_is31fl3733/sample.yaml | 8 + samples/drivers/led_is31fl3733/src/main.c | 156 ++++++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 samples/drivers/led_is31fl3733/CMakeLists.txt create mode 100644 samples/drivers/led_is31fl3733/Kconfig create mode 100644 samples/drivers/led_is31fl3733/README.rst create mode 100644 samples/drivers/led_is31fl3733/boards/frdm_k22f.overlay create mode 100644 samples/drivers/led_is31fl3733/prj.conf create mode 100644 samples/drivers/led_is31fl3733/sample.yaml create mode 100644 samples/drivers/led_is31fl3733/src/main.c diff --git a/samples/drivers/led_is31fl3733/CMakeLists.txt b/samples/drivers/led_is31fl3733/CMakeLists.txt new file mode 100644 index 000000000000..8fb7f287ed7a --- /dev/null +++ b/samples/drivers/led_is31fl3733/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(is31fl3733_matrix) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/led_is31fl3733/Kconfig b/samples/drivers/led_is31fl3733/Kconfig new file mode 100644 index 000000000000..38f3875aa934 --- /dev/null +++ b/samples/drivers/led_is31fl3733/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2023 Daniel DeGrasse + +source "Kconfig.zephyr" + +config LED_ROW_COUNT + int "Number of rows in IS31FL3733 matrix" + default 12 + help + Set this to match the number of SW LED sink connections + wired up to your IS31FL3733 LED driver. The sample will only attempt + to drive LEDs within this range. + +config LED_COLUMN_COUNT + int "Number of columns in IS31FL3733 matrix" + default 16 + help + Set this to match the number of CS LED source connections wired up + to your IS31FL3733 LED driver. The sample will only attempt to drive + LEDs within this range. diff --git a/samples/drivers/led_is31fl3733/README.rst b/samples/drivers/led_is31fl3733/README.rst new file mode 100644 index 000000000000..0894c7ef9e82 --- /dev/null +++ b/samples/drivers/led_is31fl3733/README.rst @@ -0,0 +1,35 @@ +.. _is31fl3733: + +IS31FL3733 LED Matrix Driver Demo Application +############################################# + +Overview +******** + +This sample controls a matrix of up to 192 LEDs. The sample performs the +following test steps in an infinite loop: + +- Set all LEDs to full brightness with `led_write_channels` API +- Disable upper quadrant of LED array with `led_write_channels` API +- Dim each LED in sequence using `led_set_brightness` API +- Toggle each LED in sequency using `led_on` and `led_off` APIs +- Toggle between low or high current limit using `is31fl3733_current_limit` + API, and repeat the above tests + +Sample Configuration +==================== + +The number of LEDs can be limited using the following sample specific Kconfigs: +- `CONFIG_LED_ROW_COUNT` +- `CONFIG_LED_COLUMN_COUNT` + +Building and Running +******************** + +This sample can be run on any board with an IS31FL3733 LED driver connected via +I2C, and a node with the `issi,is31fl3733` compatible present in its devicetree. + +This sample provides a DTS overlay for the :ref:`frdm_k22f` board +(:file:`boards/frdm_k22f.overlay`). It assumes that the IS31FL3733 LED +controller is connected to I2C0, at address 0x50. The SDB GPIO should be +connected to PTC2 (A3 on the arduino header) diff --git a/samples/drivers/led_is31fl3733/boards/frdm_k22f.overlay b/samples/drivers/led_is31fl3733/boards/frdm_k22f.overlay new file mode 100644 index 000000000000..795fcc2b79e4 --- /dev/null +++ b/samples/drivers/led_is31fl3733/boards/frdm_k22f.overlay @@ -0,0 +1,13 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c0 { + led_ctrl1: is31fl3733@50 { + reg = <0x50>; + compatible = "issi,is31fl3733"; + sdb-gpios = <&gpioc 2 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/samples/drivers/led_is31fl3733/prj.conf b/samples/drivers/led_is31fl3733/prj.conf new file mode 100644 index 000000000000..b6e7fb41fcd6 --- /dev/null +++ b/samples/drivers/led_is31fl3733/prj.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2022 Daniel DeGrasse +CONFIG_LED=y +CONFIG_GPIO=y diff --git a/samples/drivers/led_is31fl3733/sample.yaml b/samples/drivers/led_is31fl3733/sample.yaml new file mode 100644 index 000000000000..a16b0c469a07 --- /dev/null +++ b/samples/drivers/led_is31fl3733/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: Demonstration of the IS31FL3733 LED driver + name: IS31FL3733 sample +tests: + sample.drivers.led.is31fl3733: + filter: dt_compat_enabled("issi,is31fl3733") + tags: LED + depends_on: i2c diff --git a/samples/drivers/led_is31fl3733/src/main.c b/samples/drivers/led_is31fl3733/src/main.c new file mode 100644 index 000000000000..c878d998b6c7 --- /dev/null +++ b/samples/drivers/led_is31fl3733/src/main.c @@ -0,0 +1,156 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define HW_ROW_COUNT 12 +#define HW_COL_COUNT 16 + +/* LED matrix is addressed using a row major format */ +#define LED_MATRIX_COORD(x, y) ((x) * HW_COL_COUNT) + (y) + +static uint8_t led_state[HW_COL_COUNT * HW_ROW_COUNT]; + +static int led_channel_write(const struct device *led) +{ + int ret; + uint32_t led_idx; + + /* Set all LEDs to full brightness */ + printk("Set all LEDs to full brightness\n"); + memset(led_state, 0, sizeof(led_state)); + for (uint8_t row = 0; row < CONFIG_LED_ROW_COUNT; row++) { + for (uint8_t col = 0; col < CONFIG_LED_COLUMN_COUNT; col++) { + led_idx = LED_MATRIX_COORD(row, col); + led_state[led_idx] = 0xFF; + } + } + ret = led_write_channels(led, 0, sizeof(led_state), led_state); + if (ret) { + printk("Error: could not write LED channels (%d)\n", ret); + return ret; + } + k_msleep(1000); + /* Disable quadrant of LED display */ + printk("Disable LED quadrant\n"); + for (uint8_t row = 0; row < CONFIG_LED_ROW_COUNT / 2; row++) { + for (uint8_t col = 0; col < CONFIG_LED_COLUMN_COUNT / 2; col++) { + led_idx = LED_MATRIX_COORD(row, col); + led_state[led_idx] = 0x00; + } + } + ret = led_write_channels(led, 0, + ((CONFIG_LED_ROW_COUNT / 2) * HW_COL_COUNT), led_state); + if (ret) { + printk("Error: could not write LED channels (%d)\n", ret); + return ret; + } + k_msleep(1000); + return 0; +} + +static int led_brightness(const struct device *led) +{ + int ret; + uint8_t row, col; + + /* Set LED brightness to low value sequentially */ + printk("Set LEDs to half brightness sequentially\n"); + for (row = 0; row < CONFIG_LED_ROW_COUNT; row++) { + for (col = 0; col < CONFIG_LED_COLUMN_COUNT; col++) { + ret = led_set_brightness(led, LED_MATRIX_COORD(row, col), + 50); + if (ret < 0) { + printk("Error: could not enable led " + "at [%d, %d]: (%d)\n", + row, col, ret); + return ret; + } + k_msleep(100); + } + } + return 0; +} + +static int led_on_off(const struct device *led) +{ + int ret; + uint8_t row, col; + + printk("Toggle each led\n"); + /* Turn on each led for a short duration */ + for (row = 0; row < CONFIG_LED_ROW_COUNT; row++) { + for (col = 0; col < CONFIG_LED_COLUMN_COUNT; col++) { + ret = led_off(led, LED_MATRIX_COORD(row, col)); + if (ret < 0) { + printk("Error: could not disable led " + "at [%d, %d]: (%d)\n", + row, col, ret); + return ret; + } + k_msleep(100); + ret = led_on(led, LED_MATRIX_COORD(row, col)); + if (ret < 0) { + printk("Error: could not enable led " + "at [%d, %d]: (%d)\n", + row, col, ret); + return ret; + } + } + } + k_msleep(500); + return 0; +} + +const struct device *led_dev = DEVICE_DT_GET_ONE(issi_is31fl3733); + +void main(void) +{ + int ret; + int current_limit = 0xFF; + + if (!device_is_ready(led_dev)) { + printk("Error- LED device is not ready\n"); + return; + } + + while (1) { + ret = led_channel_write(led_dev); + if (ret < 0) { + return; + } + ret = led_brightness(led_dev); + if (ret < 0) { + return; + } + ret = led_on_off(led_dev); + if (ret < 0) { + return; + } + if (current_limit == 0xFF) { + /* Select lower current limt */ + printk("Restarting sample with lower current limit\n"); + current_limit = 0x3F; + ret = is31fl3733_current_limit(led_dev, current_limit); + if (ret) { + printk("Could not set LED current limit (%d)\n", ret); + return; + } + } else { + /* Select higher current limt */ + printk("Restarting sample with higher current limit\n"); + current_limit = 0xFF; + ret = is31fl3733_current_limit(led_dev, current_limit); + if (ret) { + printk("Could not set LED current limit (%d)\n", ret); + return; + } + } + } +} From bf153e576bb7c91241b0d9afbdc479fac993a45d Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 20 Jul 2023 14:42:38 +0200 Subject: [PATCH 1578/2042] Bluetooth: CCP: Fix coverity issue for current_inst == NULL In discover_next_instance coverity did not consider the ASSERT and warns about possibly dereferecing current_inst which could be NULL. Modifed the code slightly to make Coverity happy. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/tbs_client.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/subsys/bluetooth/audio/tbs_client.c b/subsys/bluetooth/audio/tbs_client.c index 80d48c2e29f3..ccdfb964a134 100644 --- a/subsys/bluetooth/audio/tbs_client.c +++ b/subsys/bluetooth/audio/tbs_client.c @@ -1578,19 +1578,21 @@ static void discover_next_instance(struct bt_conn *conn, uint8_t index) struct bt_tbs_server_inst *srv_inst = &srv_insts[conn_index]; srv_inst->current_inst = tbs_inst_by_index(conn, index); - __ASSERT(srv_inst->current_inst != NULL, - "srv_inst->current_inst was NULL for conn %p and index %u", conn, index); - - (void)memset(&srv_inst->discover_params, 0, sizeof(srv_inst->discover_params)); - srv_inst->discover_params.uuid = NULL; - srv_inst->discover_params.start_handle = srv_inst->current_inst->start_handle; - srv_inst->discover_params.end_handle = srv_inst->current_inst->end_handle; - srv_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; - srv_inst->discover_params.func = discover_func; - - err = bt_gatt_discover(conn, &srv_inst->discover_params); - if (err != 0) { - tbs_client_discover_complete(conn, err); + if (srv_inst->current_inst != NULL) { + (void)memset(&srv_inst->discover_params, 0, sizeof(srv_inst->discover_params)); + srv_inst->discover_params.uuid = NULL; + srv_inst->discover_params.start_handle = srv_inst->current_inst->start_handle; + srv_inst->discover_params.end_handle = srv_inst->current_inst->end_handle; + srv_inst->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + srv_inst->discover_params.func = discover_func; + + err = bt_gatt_discover(conn, &srv_inst->discover_params); + if (err != 0) { + tbs_client_discover_complete(conn, err); + } + } else { + __ASSERT_PRINT("srv_inst->current_inst was NULL for conn %p and index %u", conn, + index); } } From cab52d23c4ce286ff441b03507e16f53a0d001bb Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 20 Jul 2023 15:43:12 +0200 Subject: [PATCH 1579/2042] footprint: Add BT TMAP broadcast samples Add the BT Telephony and Media Audio Profile broadcast samples. These reflect devices that control telephone and media audio of LE Audio. Signed-off-by: Emil Gydesen --- scripts/footprint/plan.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/footprint/plan.txt b/scripts/footprint/plan.txt index 36ad9d122007..b138bc065b49 100644 --- a/scripts/footprint/plan.txt +++ b/scripts/footprint/plan.txt @@ -23,6 +23,8 @@ bt_unicast_audio_client,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/unica bt_unicast_audio_server,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/unicast_audio_server, bt_tmap_central,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_central, bt_tmap_peripheral,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_peripheral, +bt_tmap_bms,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_bms, +bt_tmap_bmr,default,nrf5340dk_nrf5340_cpuapp,samples/bluetooth/tmap_bmr, bt_hci_rpmsg,default,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg, bt_hci_rpmsg,iso-broadcast,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_broadcast-bt_ll_sw_split.conf bt_hci_rpmsg,iso-receive,nrf5340dk_nrf5340_cpunet,samples/bluetooth/hci_rpmsg,-DCONF_FILE=nrf5340_cpunet_iso_receive-bt_ll_sw_split.conf From a6a129c971ccb50e4ecb58c6796a1b7495b59127 Mon Sep 17 00:00:00 2001 From: David Leach Date: Thu, 20 Jul 2023 11:51:05 -0500 Subject: [PATCH 1580/2042] drivers: gpio: fix coverity memory overwrite error memcpy of a sub-structure in a structure was using the structure size of the parent structure instead of the sub-structure. fixes: #59548 Signed-off-by: David Leach --- drivers/gpio/gpio_imx.c | 2 +- drivers/gpio/gpio_mcux_igpio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio_imx.c b/drivers/gpio/gpio_imx.c index bf534c064bfb..68caf1786da8 100644 --- a/drivers/gpio/gpio_imx.c +++ b/drivers/gpio/gpio_imx.c @@ -82,7 +82,7 @@ static int imx_gpio_configure(const struct device *port, gpio_pin_t pin, /* Init pin configuration struct, and use pinctrl api to apply settings */ __ASSERT_NO_MSG(pin < config->mux_count); - memcpy(&pin_cfg.pinmux, &config->pin_muxes[pin], sizeof(pin_cfg)); + memcpy(&pin_cfg.pinmux, &config->pin_muxes[pin], sizeof(pin_cfg.pinmux)); /* cfg register will be set by pinctrl_configure_pins */ pin_cfg.pin_ctrl_flags = reg; pinctrl_configure_pins(&pin_cfg, 1, PINCTRL_REG_NONE); diff --git a/drivers/gpio/gpio_mcux_igpio.c b/drivers/gpio/gpio_mcux_igpio.c index 26e770cb79f1..fbb8d85b6fba 100644 --- a/drivers/gpio/gpio_mcux_igpio.c +++ b/drivers/gpio/gpio_mcux_igpio.c @@ -186,7 +186,7 @@ static int mcux_igpio_configure(const struct device *dev, } #endif /* CONFIG_SOC_SERIES_IMX_RT10XX */ - memcpy(&pin_cfg.pinmux, &config->pin_muxes[cfg_idx], sizeof(pin_cfg)); + memcpy(&pin_cfg.pinmux, &config->pin_muxes[cfg_idx], sizeof(pin_cfg.pinmux)); /* cfg register will be set by pinctrl_configure_pins */ pin_cfg.pin_ctrl_flags = reg; pinctrl_configure_pins(&pin_cfg, 1, PINCTRL_REG_NONE); From 34584c9e0ccd4a16c3abc760a8bd0567c8c2b773 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 20 Jul 2023 22:02:18 +0100 Subject: [PATCH 1581/2042] tests: build_all: input: add an alternate setting test case Many touchscreen drivers have an option interrupt mode that enables a different code path. Add an extra test for touchscreen drivers to build the non-default case. Signed-off-by: Fabio Baltieri --- tests/drivers/build_all/input/testcase.yaml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/drivers/build_all/input/testcase.yaml b/tests/drivers/build_all/input/testcase.yaml index ea0777be1310..32fe44b883f2 100644 --- a/tests/drivers/build_all/input/testcase.yaml +++ b/tests/drivers/build_all/input/testcase.yaml @@ -1,7 +1,15 @@ +common: + tags: + - drivers + - input + build_only: true + platform_allow: native_posix tests: - drivers.input.build: - tags: - - drivers - - input - build_only: true - platform_allow: native_posix + drivers.input.default: {} + + # Touchscreen drivers, non-default option + drivers.input.touchscreen_interrupt: + extra_configs: + - CONFIG_INPUT_CST816S_INTERRUPT=n + - CONFIG_INPUT_FT5336_INTERRUPT=y + - CONFIG_INPUT_GT911_INTERRUPT=y From 9c69368b1dff828710cd15a9a245be0e14c25fbf Mon Sep 17 00:00:00 2001 From: Johan Lafon Date: Fri, 21 Jul 2023 09:48:33 +0200 Subject: [PATCH 1582/2042] driver: clock-control: st: allow PLL1Q support for G0 and WL LL name for PLL1Q is not the same across STM32G0, STM32WL, STM32H5 and STM32H7 families. This allows to choose the proper definition depending on the family. Signed-off-by: Johan Lafon --- drivers/clock_control/clock_stm32_ll_mco.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/clock_control/clock_stm32_ll_mco.h b/drivers/clock_control/clock_stm32_ll_mco.h index 73a02ff5911c..d98c4a116e8e 100644 --- a/drivers/clock_control/clock_stm32_ll_mco.h +++ b/drivers/clock_control/clock_stm32_ll_mco.h @@ -31,7 +31,13 @@ #elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK #elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLQCLK - #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLL1QCLK + #if (CONFIG_SOC_SERIES_STM32G0X || CONFIG_SOC_SERIES_STM32WLX) + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLQCLK + #elif (CONFIG_SOC_SERIES_STM32H5X || CONFIG_SOC_SERIES_STM32H7X) + #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLL1QCLK + #else + #error "PLLQCLK is not a valid clock source on your SOC" + #endif #elif CONFIG_CLOCK_STM32_MCO1_SRC_PLLCLK_DIV2 #define MCO1_SOURCE LL_RCC_MCO1SOURCE_PLLCLK_DIV_2 #elif CONFIG_CLOCK_STM32_MCO1_SRC_PLL2CLK From 41bbf18c25aad01cd27a0b823afe28a3dba6a4b9 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 11:10:07 +0000 Subject: [PATCH 1583/2042] MAINTAINERS: point release notes to Johan and Fabio Change the release notes area to the release owners for 3.5. Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 3e9ccaea4b9f..231267f24e29 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -620,8 +620,8 @@ Documentation Infrastructure: Release Notes: status: maintained maintainers: - - nashif - - jgl-meta + - jhedberg + - fabiobaltieri files: - doc/releases/release-notes-* labels: From 976474d194546422da0c32dc2a6371c2572e33b2 Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Thu, 20 Jul 2023 18:48:48 -0700 Subject: [PATCH 1584/2042] doc: releases: Add release notes for npcx flash driver Add release notes for npcx flash driver in 3.5 release. Signed-off-by: Mulin Chao --- doc/releases/release-notes-3.5.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 1259abb43679..6837ae0e2c53 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -160,6 +160,10 @@ Drivers and Sensors * Flash + * Introduce npcx flash driver that supports two or more spi nor flashes via a + single Flash Interface Unit (FIU) module and Direct Read Access (DRA) mode + for better performance. + * FPGA * Fuel Gauge @@ -212,6 +216,8 @@ Drivers and Sensors * SPI + * Remove npcx spi driver implemented by Flash Interface Unit (FIU) module. + * Timer * The TI CC13xx/26xx system clock timer compatible was changed from From b5cf5d1f249d42c95519bc42f9016d4017dc388f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 12:58:21 +0200 Subject: [PATCH 1585/2042] lib: os: doc: Show hash functions in documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show hash functions under Hashmap doc entry. Also fixed minor issue with '.' character ending @brief early. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_function.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/zephyr/sys/hash_function.h b/include/zephyr/sys/hash_function.h index d6a93cec84ee..5b5ef921c8ee 100644 --- a/include/zephyr/sys/hash_function.h +++ b/include/zephyr/sys/hash_function.h @@ -17,6 +17,12 @@ extern "C" { #endif +/** + * @ingroup hashmap_apis + * @defgroup hash_functions Hash Functions + * @{ + */ + /** * @brief 32-bit Hash function interface * @@ -70,7 +76,7 @@ static inline uint32_t sys_hash32_identity(const void *str, size_t n) } /** - * @brief Daniel J. Bernstein's hash function + * @brief Daniel J.\ Bernstein's hash function * * Some notes: * - normally, this hash function is used on NUL-terminated strings @@ -129,6 +135,10 @@ static inline uint32_t sys_hash32(const void *str, size_t n) return 0; } +/** + * @} + */ + #ifdef __cplusplus } #endif From 1539c1c094475b190e935740de1817bf1071594f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 12:59:05 +0200 Subject: [PATCH 1586/2042] lib: os: doc: Show hash implementations in documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a Doxygen group for Hash implementations Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_map_api.h | 5 +++++ include/zephyr/sys/hash_map_cxx.h | 1 + include/zephyr/sys/hash_map_oa_lp.h | 1 + include/zephyr/sys/hash_map_sc.h | 1 + 4 files changed, 8 insertions(+) diff --git a/include/zephyr/sys/hash_map_api.h b/include/zephyr/sys/hash_map_api.h index 9e2b88c675c1..e456146928e2 100644 --- a/include/zephyr/sys/hash_map_api.h +++ b/include/zephyr/sys/hash_map_api.h @@ -29,6 +29,11 @@ extern "C" { /** * @defgroup hashmap_apis Hashmap * @ingroup datastructure_apis + * + * @defgroup hashmap_implementations Hashmap Implementations + * @ingroup hashmap_apis + * + * @addtogroup hashmap_apis * @{ */ diff --git a/include/zephyr/sys/hash_map_cxx.h b/include/zephyr/sys/hash_map_cxx.h index cbb6e1e591b0..0ed7681b1f3e 100644 --- a/include/zephyr/sys/hash_map_cxx.h +++ b/include/zephyr/sys/hash_map_cxx.h @@ -6,6 +6,7 @@ /** * @file + * @ingroup hashmap_implementations * @brief C++ Hashmap * * This is a C wrapper around `std::unordered_map`. It is mainly used for diff --git a/include/zephyr/sys/hash_map_oa_lp.h b/include/zephyr/sys/hash_map_oa_lp.h index 0532ead95a70..f3ec3c5dc672 100644 --- a/include/zephyr/sys/hash_map_oa_lp.h +++ b/include/zephyr/sys/hash_map_oa_lp.h @@ -6,6 +6,7 @@ /** * @file + * @ingroup hashmap_implementations * @brief Open-Addressing / Linear Probe Hashmap Implementation * * @note Enable with @kconfig{CONFIG_SYS_HASH_MAP_OA_LP} diff --git a/include/zephyr/sys/hash_map_sc.h b/include/zephyr/sys/hash_map_sc.h index 359fc490a239..d511823c8f59 100644 --- a/include/zephyr/sys/hash_map_sc.h +++ b/include/zephyr/sys/hash_map_sc.h @@ -6,6 +6,7 @@ /** * @file + * @ingroup hashmap_implementations * @brief Separate Chaining Hashmap Implementation * * @note Enable with @kconfig{CONFIG_SYS_HASH_MAP_SC} From ea1e6b59f5309796338037e319eddcd6288ddec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 13:12:22 +0200 Subject: [PATCH 1587/2042] lib: os: doc: Cleanup doxygen groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleaned up doxygen group for hash_map and hash_map_api Adding brief/desc to the main group instead of the file to actually surface them in the documentation Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_map.h | 11 ++--------- include/zephyr/sys/hash_map_api.h | 14 ++++++-------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/include/zephyr/sys/hash_map.h b/include/zephyr/sys/hash_map.h index 9c4f5d08e694..60a3c9725fe6 100644 --- a/include/zephyr/sys/hash_map.h +++ b/include/zephyr/sys/hash_map.h @@ -6,10 +6,8 @@ /** * @file - * @brief Hashmap (Hash Table) API - * - * Hashmaps (a.k.a Hash Tables) sacrifice space for speed. All operations - * on a Hashmap (insert, delete, search) are O(1) complexity (on average). + * @addtogroup hashmap_apis + * @{ */ #ifndef ZEPHYR_INCLUDE_SYS_HASH_MAP_H_ @@ -29,11 +27,6 @@ extern "C" { #endif -/** - * @ingroup hashmap_apis - * @{ - */ - /** * @brief Declare a Hashmap (advanced) * diff --git a/include/zephyr/sys/hash_map_api.h b/include/zephyr/sys/hash_map_api.h index e456146928e2..83af05ba5d07 100644 --- a/include/zephyr/sys/hash_map_api.h +++ b/include/zephyr/sys/hash_map_api.h @@ -4,14 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * @file - * @brief Hashmap (Hash Table) API - * - * Hashmaps (a.k.a Hash Tables) sacrifice space for speed. All operations - * on a Hashmap (insert, delete, search) are O(1) complexity (on average). - */ - #ifndef ZEPHYR_INCLUDE_SYS_HASHMAP_API_H_ #define ZEPHYR_INCLUDE_SYS_HASHMAP_API_H_ @@ -27,9 +19,15 @@ extern "C" { #endif /** + * @file * @defgroup hashmap_apis Hashmap * @ingroup datastructure_apis * + * @brief Hashmap (Hash Table) API + * + * Hashmaps (a.k.a Hash Tables) sacrifice space for speed. All operations + * on a Hashmap (insert, delete, search) are O(1) complexity (on average). + * * @defgroup hashmap_implementations Hashmap Implementations * @ingroup hashmap_apis * From dde023fb8a01fc880bfdd8e41b8668ca9898dc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Wed, 19 Jul 2023 13:24:44 +0200 Subject: [PATCH 1588/2042] lib: os: doc: Hashmap documentation fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing documentation for SYS_HASHMAP_DEFAULT_ALLOCATOR and sys_hashmap struct. Fixed minor type in SYS_HASHMAP_DEFINE_STATIC_ADVANCED doc. Signed-off-by: Benjamin Cabé --- include/zephyr/sys/hash_map.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/zephyr/sys/hash_map.h b/include/zephyr/sys/hash_map.h index 60a3c9725fe6..c8fb600a4327 100644 --- a/include/zephyr/sys/hash_map.h +++ b/include/zephyr/sys/hash_map.h @@ -56,9 +56,9 @@ extern "C" { } /** - * @brief Declare a Hashmap (advanced) + * @brief Declare a Hashmap statically (advanced) * - * Declare a Hashmap with control over advanced parameters. + * Declare a Hashmap statically with control over advanced parameters. * * @note The allocator @p _alloc is used for allocating internal Hashmap * entries and does not interact with any user-provided keys or values. @@ -114,6 +114,7 @@ static inline void *sys_hashmap_default_allocator(void *ptr, size_t size) return realloc(ptr, size); } +/** @brief The default Hashmap allocator */ #define SYS_HASHMAP_DEFAULT_ALLOCATOR sys_hashmap_default_allocator /** @brief The default Hashmap load factor (in hundredths) */ @@ -121,10 +122,15 @@ static inline void *sys_hashmap_default_allocator(void *ptr, size_t size) /** @brief Generic Hashmap */ struct sys_hashmap { + /** Hashmap API */ const struct sys_hashmap_api *api; + /** Hashmap configuration */ const struct sys_hashmap_config *config; + /** Hashmap data */ struct sys_hashmap_data *data; + /** Hash function */ sys_hash_func32_t hash_func; + /** Allocator */ sys_hashmap_allocator_t alloc_func; }; From a50c26d80f89b9f1b2ecce1bef1d0d4f8f0d17d3 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 23 Jun 2023 10:38:31 -0500 Subject: [PATCH 1589/2042] drivers: dma: dma_mcux_lpx: Added parameter in macro for 55S36 Added a parameter inside the Channel Number macro since the LPC55S36 expects an address rather than a static number. Signed-off-by: Emilio Benavente --- drivers/dma/dma_mcux_lpc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index 66032a9df3d7..eb44d4fb5fca 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -777,7 +777,6 @@ static const struct dma_mcux_lpc_config dma_##n##_config = { \ &dma_mcux_lpc_api); \ \ DMA_MCUX_LPC_CONFIG_FUNC(n) \ - \ DMA_MCUX_LPC_INIT_CFG(n); DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) From e12e026c955febe272ef71e640e4388851c04e67 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Wed, 7 Jun 2023 18:05:40 -0500 Subject: [PATCH 1590/2042] dts: arm: nxp: lpc55s3x: Added DMA Nodes in dts files. Added dts nodes for DMA support on LPC55S3X devices. Signed-off-by: Emilio Benavente --- dts/arm/nxp/nxp_lpc55S3x_common.dtsi | 45 +++++++++++++++++++ .../inputmux/inputmux_trigger_ports.h | 5 +++ 2 files changed, 50 insertions(+) diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index 29ac36e81335..51243bcb88e2 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include #include / { @@ -142,6 +143,30 @@ port = <2>; }; + dma0: dma-controller@82000 { + compatible = "nxp,lpc-dma"; + reg = <0x82000 0x1000>; + interrupts = <1 0>; + dma-channels = <52>; + nxp,dma-num-of-otrigs = <4>; + nxp,dma-otrig-base-address = ; + nxp,dma-itrig-base-address = ; + status = "disabled"; + #dma-cells = <1>; + }; + + dma1: dma-controller@a7000 { + compatible = "nxp,lpc-dma"; + reg = <0xa7000 0x1000>; + interrupts = <58 0>; + dma-channels = <16>; + nxp,dma-num-of-otrigs = <4>; + nxp,dma-otrig-base-address = ; + nxp,dma-itrig-base-address = ; + status = "disabled"; + #dma-cells = <1>; + }; + pint: pint@4000 { compatible = "nxp,pint"; reg = <0x4000 0x1000>; @@ -159,6 +184,8 @@ reg = <0x86000 0x1000>; interrupts = <14 0>; clocks = <&syscon MCUX_FLEXCOMM0_CLK>; + dmas = <&dma0 4>, <&dma0 5>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -167,6 +194,8 @@ reg = <0x87000 0x1000>; interrupts = <15 0>; clocks = <&syscon MCUX_FLEXCOMM1_CLK>; + dmas = <&dma0 6>, <&dma0 7>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -175,6 +204,8 @@ reg = <0x88000 0x1000>; interrupts = <16 0>; clocks = <&syscon MCUX_FLEXCOMM2_CLK>; + dmas = <&dma0 10>, <&dma0 11>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -183,6 +214,8 @@ reg = <0x89000 0x1000>; interrupts = <17 0>; clocks = <&syscon MCUX_FLEXCOMM3_CLK>; + dmas = <&dma0 8>, <&dma0 9>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -191,6 +224,8 @@ reg = <0x8a000 0x1000>; interrupts = <18 0>; clocks = <&syscon MCUX_FLEXCOMM4_CLK>; + dmas = <&dma0 12>, <&dma0 13>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -199,6 +234,8 @@ reg = <0x96000 0x1000>; interrupts = <19 0>; clocks = <&syscon MCUX_FLEXCOMM5_CLK>; + dmas = <&dma0 14>, <&dma0 15>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -207,6 +244,8 @@ reg = <0x97000 0x1000>; interrupts = <20 0>; clocks = <&syscon MCUX_FLEXCOMM6_CLK>; + dmas = <&dma0 16>, <&dma0 17>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -215,6 +254,8 @@ reg = <0x98000 0x1000>; interrupts = <21 0>; clocks = <&syscon MCUX_FLEXCOMM7_CLK>; + dmas = <&dma0 18>, <&dma0 19>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -223,6 +264,8 @@ reg = <0x9f000 0x1000>; interrupts = <59 0>; clocks = <&syscon MCUX_HS_SPI_CLK>; + dmas = <&dma0 2>, <&dma0 3>; + dma-names = "rx", "tx"; status = "disabled"; #address-cells = <1>; #size-cells = <0>; @@ -247,6 +290,8 @@ offset-value-a = <10>; offset-value-b = <10>; #io-channel-cells = <1>; + dmas = <&dma0 21>, <&dma0 22>; + dma-names = "adc0-dma0", "adc0-dma1"; }; can0: can@4009d000 { diff --git a/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h b/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h index b419baeaa04f..d348dce7030e 100644 --- a/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h +++ b/include/zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h @@ -16,4 +16,9 @@ #define RT595_DMA1_OTRIG_BASE 0x50000000 #define RT595_DMA1_ITRIG_BASE 0x4000000E +#define LPC55S36_DMA0_OTRIG_BASE 0x16000000 +#define LPC55S36_DMA0_ITRIG_BASE 0x0E000011 +#define LPC55S36_DMA1_OTRIG_BASE 0x24000002 +#define LPC55S36_DMA1_ITRIG_BASE 0x20000008 + #endif From 19b526f467857767a8b4935f61313514a72af279 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 9 May 2023 12:10:45 -0500 Subject: [PATCH 1591/2042] boards: arm: lpcxpresso55s36: Added DMA Support for LPC55S36 Added DMA Support for the LPC55S36 Board as well as a creation for space on the HEAP when DMA Blocks are required. Signed-off-by: Emilio Benavente --- boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts b/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts index 7ac40ff15f3a..8b761f5cab1d 100644 --- a/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts +++ b/boards/arm/lpcxpresso55s36/lpcxpresso55s36.dts @@ -168,3 +168,7 @@ zephyr_udc0: &usbfs { pinctrl-0 = <&pinmux_usbfs>; pinctrl-names = "default"; }; + +&dma0 { + status = "okay"; +}; From 7059b433ae04b11c37ab839833487c5b6dde4394 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Tue, 9 May 2023 12:13:20 -0500 Subject: [PATCH 1592/2042] tests: drivers: dma: chan_blen_transfer: Added Overlay file. Added an overlay file for the LPC55S36 to demonstrate the DMA Support with the chan_blen_transfer test. Signed-off-by: Emilio Benavente --- .../dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay | 1 + tests/drivers/dma/chan_link_transfer/testcase.yaml | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay new file mode 100644 index 000000000000..b1c2b20904c3 --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/lpcxpresso55s36.overlay @@ -0,0 +1 @@ +test_dma0: &dma0 { }; diff --git a/tests/drivers/dma/chan_link_transfer/testcase.yaml b/tests/drivers/dma/chan_link_transfer/testcase.yaml index 468efbf6eb6b..ea35f8c95330 100644 --- a/tests/drivers/dma/chan_link_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_link_transfer/testcase.yaml @@ -15,5 +15,6 @@ tests: - mimxrt1170_evk_cm7 - mimxrt1024_evk - lpcxpresso55s69_cpu0 + - lpcxpresso55s36 integration_platforms: - frdm_k64f From e8495d76682b3c7e67d333dd25716b998f97eac4 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 23 Jun 2023 13:48:27 -0500 Subject: [PATCH 1593/2042] tests: drivers: dma: loop_transfer: Added Overlay file. Added an overlay file for the LPC55S36 to demonstrate the DMA Support with the loop_transfer test. Signed-off-by: Emilio Benavente --- .../dma/loop_transfer/boards/lpcxpresso55s36.overlay | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/drivers/dma/loop_transfer/boards/lpcxpresso55s36.overlay diff --git a/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s36.overlay b/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s36.overlay new file mode 100644 index 000000000000..425598bc9de5 --- /dev/null +++ b/tests/drivers/dma/loop_transfer/boards/lpcxpresso55s36.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 NXP Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &dma0 { }; From 0798b68c64555bc58ba41a194ad27a6020084c36 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 23 Jun 2023 14:09:39 -0500 Subject: [PATCH 1594/2042] tests: drivers: dma: scatter_gather: Added Overlay file. Added an overlay file for the LPC55S36 to demonstrate the DMA Support with the scatter_gather test. Signed-off-by: Emilio Benavente --- .../dma/scatter_gather/boards/lpcxpresso55s36.overlay | 11 +++++++++++ tests/drivers/dma/scatter_gather/testcase.yaml | 1 + 2 files changed, 12 insertions(+) create mode 100644 tests/drivers/dma/scatter_gather/boards/lpcxpresso55s36.overlay diff --git a/tests/drivers/dma/scatter_gather/boards/lpcxpresso55s36.overlay b/tests/drivers/dma/scatter_gather/boards/lpcxpresso55s36.overlay new file mode 100644 index 000000000000..c3c3e91d468e --- /dev/null +++ b/tests/drivers/dma/scatter_gather/boards/lpcxpresso55s36.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2023 NXP Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + dma0 = &dma0; + }; +}; diff --git a/tests/drivers/dma/scatter_gather/testcase.yaml b/tests/drivers/dma/scatter_gather/testcase.yaml index c716bdf4dadf..880f09267b75 100644 --- a/tests/drivers/dma/scatter_gather/testcase.yaml +++ b/tests/drivers/dma/scatter_gather/testcase.yaml @@ -8,6 +8,7 @@ tests: - intel_adsp_cavs25 - frdm_k64f - mimxrt1060_evk + - lpcxpresso55s36 filter: dt_alias_exists("dma0") integration_platforms: - intel_adsp_cavs25 From e68e623963b52570b5c20d68313a802ec4f53ac5 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 21:26:40 +0100 Subject: [PATCH 1595/2042] sensor: bq274xx: re-add function prefixes Add the bq274xx_ back to the static function prefixes for the bq274xx driver. These have been removed recently but every other sensor and most Zephyr driver have static function prefixed, this helps avoiding ambiguity in list files, stack traces, setting debugging breakpoints etc. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 137 ++++++++++++----------- drivers/sensor/bq274xx/bq274xx_trigger.c | 21 ++-- 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 5342fcb245c4..c9d5b7da1bb4 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -29,9 +29,10 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* Time it takes device to initialize before doing any configuration */ #define INIT_TIME 100U -static int gauge_configure(const struct device *dev); +static int bq274xx_gauge_configure(const struct device *dev); -static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) +static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, + int16_t *val) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data[2]; @@ -48,7 +49,7 @@ static int cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val return 0; } -static int ctrl_reg_write(const struct device *dev, uint16_t subcommand) +static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; @@ -77,7 +78,8 @@ static int ctrl_reg_write(const struct device *dev, uint16_t subcommand) return 0; } -static int cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data) +static int bq274xx_cmd_reg_write(const struct device *dev, uint8_t command, + uint8_t data) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; @@ -95,8 +97,8 @@ static int cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data return 0; } -static int read_data_block(const struct device *dev, uint8_t offset, - uint8_t *data, uint8_t bytes) +static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, + uint8_t *data, uint8_t bytes) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data; @@ -115,17 +117,17 @@ static int read_data_block(const struct device *dev, uint8_t offset, return 0; } -static int get_device_type(const struct device *dev, uint16_t *val) +static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) { int ret; - ret = ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_DEVICE_TYPE); if (ret < 0) { LOG_ERR("Unable to write control register"); return -EIO; } - ret = cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); if (ret < 0) { LOG_ERR("Unable to read register"); @@ -140,8 +142,8 @@ static int get_device_type(const struct device *dev, uint16_t *val) * * @return -ENOTSUP for unsupported channels */ -static int channel_get(const struct device *dev, enum sensor_channel chan, - struct sensor_value *val) +static int bq274xx_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { struct bq274xx_data *data = dev->data; float int_temp; @@ -216,13 +218,13 @@ static int channel_get(const struct device *dev, enum sensor_channel chan, return 0; } -static int sample_fetch(const struct device *dev, enum sensor_channel chan) +static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; int ret = 0; if (!data->configured) { - ret = gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); if (ret < 0) { return ret; @@ -231,7 +233,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: - ret = cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, &data->voltage); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, + &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; @@ -239,8 +242,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, - &data->avg_current); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, + &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; @@ -248,8 +251,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_TEMP: - ret = cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, - &data->internal_temperature); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, + &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; @@ -257,8 +260,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_STDBY_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, - &data->stdby_current); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, + &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; @@ -266,8 +269,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: - ret = cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, - &data->max_load_current); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, + &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; @@ -275,7 +278,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOC, &data->state_of_charge); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOC, + &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; @@ -283,7 +287,7 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); @@ -292,7 +296,7 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); @@ -301,7 +305,7 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); @@ -310,7 +314,7 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); @@ -319,7 +323,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_AVG_POWER: - ret = cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, &data->avg_power); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, + &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; @@ -327,7 +332,8 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) break; case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: - ret = cmd_reg_read(dev, BQ274XX_CMD_SOH, &data->state_of_health); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOH, + &data->state_of_health); data->state_of_health = (data->state_of_health) & 0x00FF; @@ -349,7 +355,7 @@ static int sample_fetch(const struct device *dev, enum sensor_channel chan) * * @return 0 for success */ -static int gauge_init(const struct device *dev) +static int bq274xx_gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; int ret = 0; @@ -367,7 +373,7 @@ static int gauge_init(const struct device *dev) } #endif - ret = get_device_type(dev, &id); + ret = bq274xx_get_device_type(dev, &id); if (ret < 0) { LOG_ERR("Unable to get device ID"); return -EIO; @@ -387,13 +393,13 @@ static int gauge_init(const struct device *dev) #endif if (!config->lazy_loading) { - ret = gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); } return ret; } -static int gauge_configure(const struct device *dev) +static int bq274xx_gauge_configure(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; @@ -409,20 +415,20 @@ static int gauge_configure(const struct device *dev) taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); /** Unseal the battery control register **/ - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } /* Send CFG_UPDATE */ - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); if (ret < 0) { LOG_ERR("Unable to set CFGUpdate"); return -EIO; @@ -430,7 +436,7 @@ static int gauge_configure(const struct device *dev) /** Step to place the Gauge into CONFIG UPDATE Mode **/ do { - ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -442,21 +448,21 @@ static int gauge_configure(const struct device *dev) } while (!(flags & 0x0010)); - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { LOG_ERR("Failed to enable block data memory"); return -EIO; } /* Access State subclass */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); if (ret < 0) { LOG_ERR("Failed to update state subclass"); return -EIO; } /* Write the block offset */ - ret = cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); if (ret < 0) { LOG_ERR("Failed to update block offset"); return -EIO; @@ -466,7 +472,7 @@ static int gauge_configure(const struct device *dev) block[i] = 0; } - ret = read_data_block(dev, 0x00, block, 32); + ret = bq274xx_read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; @@ -553,7 +559,7 @@ static int gauge_configure(const struct device *dev) block[i] = 0; } - ret = read_data_block(dev, 0x00, block, 32); + ret = bq274xx_read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; @@ -565,7 +571,7 @@ static int gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - ret = cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); if (ret < 0) { LOG_ERR("Failed to update new checksum"); return -EIO; @@ -578,13 +584,13 @@ static int gauge_configure(const struct device *dev) return -EIO; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); if (ret < 0) { LOG_ERR("Unable to configure BAT Detect"); return -EIO; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); if (ret < 0) { LOG_ERR("Failed to soft reset the gauge"); return -EIO; @@ -593,7 +599,7 @@ static int gauge_configure(const struct device *dev) flags = 0; /* Poll Flags */ do { - ret = cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { LOG_ERR("Unable to read flags"); return -EIO; @@ -605,7 +611,7 @@ static int gauge_configure(const struct device *dev) } while (flags & 0x0010); /* Seal the gauge */ - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return -EIO; @@ -617,35 +623,35 @@ static int gauge_configure(const struct device *dev) } #ifdef CONFIG_BQ274XX_PM -static int enter_shutdown_mode(const struct device *dev) +static int bq274xx_enter_shutdown_mode(const struct device *dev) { int ret; - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN_ENABLE); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN_ENABLE); if (ret < 0) { LOG_ERR("Unable to enable shutdown mode"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SHUTDOWN); if (ret < 0) { LOG_ERR("Unable to enter shutdown mode"); return ret; } - ret = ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); if (ret < 0) { LOG_ERR("Failed to seal the gauge"); return ret; @@ -654,7 +660,7 @@ static int enter_shutdown_mode(const struct device *dev) return 0; } -static int exit_shutdown_mode(const struct device *dev) +static int bq274xx_exit_shutdown_mode(const struct device *dev) { const struct bq274xx_config *const config = dev->config; int ret = 0; @@ -682,7 +688,7 @@ static int exit_shutdown_mode(const struct device *dev) if (!config->lazy_loading) { k_msleep(INIT_TIME); - ret = gauge_configure(dev); + ret = bq274xx_gauge_configure(dev); if (ret < 0) { LOG_ERR("Unable to configure bq274xx gauge"); return ret; @@ -692,16 +698,17 @@ static int exit_shutdown_mode(const struct device *dev) return 0; } -static int pm_action(const struct device *dev, enum pm_device_action action) +static int bq274xx_pm_action(const struct device *dev, + enum pm_device_action action) { int ret; switch (action) { case PM_DEVICE_ACTION_TURN_OFF: - ret = enter_shutdown_mode(dev); + ret = bq274xx_enter_shutdown_mode(dev); break; case PM_DEVICE_ACTION_RESUME: - ret = exit_shutdown_mode(dev); + ret = bq274xx_exit_shutdown_mode(dev); break; default: ret = -ENOTSUP; @@ -713,8 +720,8 @@ static int pm_action(const struct device *dev, enum pm_device_action action) #endif /* CONFIG_BQ274XX_PM */ static const struct sensor_driver_api bq274xx_battery_driver_api = { - .sample_fetch = sample_fetch, - .channel_get = channel_get, + .sample_fetch = bq274xx_sample_fetch, + .channel_get = bq274xx_channel_get, #ifdef CONFIG_BQ274XX_TRIGGER .trigger_set = bq274xx_trigger_set, #endif @@ -723,12 +730,12 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { #if defined(CONFIG_BQ274XX_PM) || defined(CONFIG_BQ274XX_TRIGGER) #define BQ274XX_INT_CFG(index) \ .int_gpios = GPIO_DT_SPEC_INST_GET(index, int_gpios), -#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) \ - PM_DEVICE_DT_INST_DEFINE(index, pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) \ + PM_DEVICE_DT_INST_DEFINE(index, bq274xx_pm_action) #define PM_BQ274XX_DT_INST_GET(index) PM_DEVICE_DT_INST_GET(index) #else #define BQ274XX_INT_CFG(index) -#define PM_BQ274XX_DT_INST_DEFINE(index, pm_action) +#define PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action) #define PM_BQ274XX_DT_INST_GET(index) NULL #endif @@ -745,9 +752,9 @@ static const struct sensor_driver_api bq274xx_battery_driver_api = { .lazy_loading = DT_INST_PROP(index, zephyr_lazy_load), \ }; \ \ - PM_BQ274XX_DT_INST_DEFINE(index, pm_action); \ + PM_BQ274XX_DT_INST_DEFINE(index, bq274xx_pm_action); \ \ - SENSOR_DEVICE_DT_INST_DEFINE(index, &gauge_init, \ + SENSOR_DEVICE_DT_INST_DEFINE(index, &bq274xx_gauge_init, \ PM_BQ274XX_DT_INST_GET(index), \ &bq274xx_driver_##index, \ &bq274xx_config_##index, POST_KERNEL, \ diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 658fef2f72cc..1559a4ee79bc 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(bq274xx, CONFIG_SENSOR_LOG_LEVEL); -static void handle_interrupts(const struct device *dev) +static void bq274xx_handle_interrupts(const struct device *dev) { struct bq274xx_data *data = dev->data; @@ -31,26 +31,27 @@ static void handle_interrupts(const struct device *dev) static K_KERNEL_STACK_DEFINE(bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE); static struct k_thread bq274xx_thread; -static void thread_main(struct bq274xx_data *data) +static void bq274xx_thread_main(struct bq274xx_data *data) { while (1) { k_sem_take(&data->sem, K_FOREVER); - handle_interrupts(data->dev); + bq274xx_handle_interrupts(data->dev); } } #endif #ifdef CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD -static void work_handler(struct k_work *work) +static void bq274xx_work_handler(struct k_work *work) { struct bq274xx_data *data = CONTAINER_OF(work, struct bq274xx_data, work); - handle_interrupts(data->dev); + bq274xx_handle_interrupts(data->dev); } #endif -static void ready_callback_handler(const struct device *port, struct gpio_callback *cb, - gpio_port_pins_t pins) +static void bq274xx_ready_callback_handler(const struct device *port, + struct gpio_callback *cb, + gpio_port_pins_t pins) { struct bq274xx_data *data = CONTAINER_OF(cb, struct bq274xx_data, ready_callback); @@ -78,12 +79,12 @@ int bq274xx_trigger_mode_init(const struct device *dev) k_thread_create(&bq274xx_thread, bq274xx_thread_stack, CONFIG_BQ274XX_THREAD_STACK_SIZE, - (k_thread_entry_t)thread_main, + (k_thread_entry_t)bq274xx_thread_main, data, NULL, NULL, K_PRIO_COOP(CONFIG_BQ274XX_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_BQ274XX_TRIGGER_GLOBAL_THREAD) - k_work_init(&data->work, work_handler); + k_work_init(&data->work, bq274xx_work_handler); #endif ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); @@ -92,7 +93,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) return ret; } gpio_init_callback(&data->ready_callback, - ready_callback_handler, + bq274xx_ready_callback_handler, BIT(config->int_gpios.pin)); return 0; From f6f568b7129a557a080a82bd9d711db8f9faa915 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 21:34:23 +0100 Subject: [PATCH 1596/2042] sensor: bq274xx: drop unnecessary casting Drop unnecessary casting from uint16_t to uint8_t. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index c9d5b7da1bb4..33ff53ef79c8 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -56,7 +56,7 @@ static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) int ret = 0; reg_addr = BQ274XX_CMD_CONTROL_LOW; - i2c_data = (uint8_t)((subcommand)&0x00FF); + i2c_data = subcommand & 0xFF; ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); if (ret < 0) { @@ -67,7 +67,7 @@ static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) k_msleep(BQ274XX_SUBCLASS_DELAY); reg_addr = BQ274XX_CMD_CONTROL_HIGH; - i2c_data = (uint8_t)((subcommand >> 8) & 0x00FF); + i2c_data = (subcommand >> 8) & 0xFF; ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); if (ret < 0) { From 1e2b7de13bdfb438f969e5f16c4a06af967c898e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 21:36:35 +0100 Subject: [PATCH 1597/2042] sensor: bq274xx: remove forward declaration Move bq274xx_gauge_configure up in the code, remove the forward declaration. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 448 +++++++++++++++---------------- 1 file changed, 223 insertions(+), 225 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 33ff53ef79c8..ebd5434a7350 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -29,8 +29,6 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* Time it takes device to initialize before doing any configuration */ #define INIT_TIME 100U -static int bq274xx_gauge_configure(const struct device *dev); - static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { @@ -137,6 +135,229 @@ static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) return 0; } +static int bq274xx_gauge_configure(const struct device *dev) +{ + const struct bq274xx_config *const config = dev->config; + struct bq274xx_data *data = dev->data; + + int ret = 0; + uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; + uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; + uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, + terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; + uint8_t block[32]; + + designenergy_mwh = (uint16_t)3.7 * config->design_capacity; + taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); + + /* Unseal the battery control register */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { + LOG_ERR("Unable to unseal the battery"); + return -EIO; + } + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + if (ret < 0) { + LOG_ERR("Unable to unseal the battery"); + return -EIO; + } + + /* Send CFG_UPDATE */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); + if (ret < 0) { + LOG_ERR("Unable to set CFGUpdate"); + return -EIO; + } + + /* Step to place the Gauge into CONFIG UPDATE Mode */ + do { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + if (ret < 0) { + LOG_ERR("Unable to read flags"); + return -EIO; + } + + if (!(flags & 0x0010)) { + k_msleep(BQ274XX_SUBCLASS_DELAY * 10); + } + + } while (!(flags & 0x0010)); + + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); + if (ret < 0) { + LOG_ERR("Failed to enable block data memory"); + return -EIO; + } + + /* Access State subclass */ + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); + if (ret < 0) { + LOG_ERR("Failed to update state subclass"); + return -EIO; + } + + /* Write the block offset */ + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); + if (ret < 0) { + LOG_ERR("Failed to update block offset"); + return -EIO; + } + + for (uint8_t i = 0; i < 32; i++) { + block[i] = 0; + } + + ret = bq274xx_read_data_block(dev, 0x00, block, 32); + if (ret < 0) { + LOG_ERR("Unable to read block data"); + return -EIO; + } + + tmp_checksum = 0; + for (uint8_t i = 0; i < 32; i++) { + tmp_checksum += block[i]; + } + tmp_checksum = 255 - tmp_checksum; + + /* Read the block checksum */ + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &checksum_old); + if (ret < 0) { + LOG_ERR("Unable to read block checksum"); + return -EIO; + } + + designcap_msb = config->design_capacity >> 8; + designcap_lsb = config->design_capacity & 0x00FF; + designenergy_msb = designenergy_mwh >> 8; + designenergy_lsb = designenergy_mwh & 0x00FF; + terminatevolt_msb = config->terminate_voltage >> 8; + terminatevolt_lsb = config->terminate_voltage & 0x00FF; + taperrate_msb = taperrate >> 8; + taperrate_lsb = taperrate & 0x00FF; + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, + designcap_msb); + if (ret < 0) { + LOG_ERR("Failed to write designCAP MSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, + designcap_lsb); + if (ret < 0) { + LOG_ERR("Failed to write designCAP LSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, + designenergy_msb); + if (ret < 0) { + LOG_ERR("Failed to write designEnergy MSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, + designenergy_lsb); + if (ret < 0) { + LOG_ERR("Failed to write designEnergy LSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, + terminatevolt_msb); + if (ret < 0) { + LOG_ERR("Failed to write terminateVolt MSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, + terminatevolt_lsb); + if (ret < 0) { + LOG_ERR("Failed to write terminateVolt LSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, + taperrate_msb); + if (ret < 0) { + LOG_ERR("Failed to write taperRate MSB"); + return -EIO; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); + if (ret < 0) { + LOG_ERR("Failed to write taperRate LSB"); + return -EIO; + } + + for (uint8_t i = 0; i < 32; i++) { + block[i] = 0; + } + + ret = bq274xx_read_data_block(dev, 0x00, block, 32); + if (ret < 0) { + LOG_ERR("Unable to read block data"); + return -EIO; + } + + checksum_new = 0; + for (uint8_t i = 0; i < 32; i++) { + checksum_new += block[i]; + } + checksum_new = 255 - checksum_new; + + ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); + if (ret < 0) { + LOG_ERR("Failed to update new checksum"); + return -EIO; + } + + tmp_checksum = 0; + ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &tmp_checksum); + if (ret < 0) { + LOG_ERR("Failed to read checksum"); + return -EIO; + } + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); + if (ret < 0) { + LOG_ERR("Unable to configure BAT Detect"); + return -EIO; + } + + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); + if (ret < 0) { + LOG_ERR("Failed to soft reset the gauge"); + return -EIO; + } + + flags = 0; + /* Poll Flags */ + do { + ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); + if (ret < 0) { + LOG_ERR("Unable to read flags"); + return -EIO; + } + + if (flags & 0x0010) { + k_msleep(BQ274XX_SUBCLASS_DELAY * 10); + } + } while (flags & 0x0010); + + /* Seal the gauge */ + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); + if (ret < 0) { + LOG_ERR("Failed to seal the gauge"); + return -EIO; + } + + data->configured = true; + + return 0; +} + /** * @brief sensor value get * @@ -399,229 +620,6 @@ static int bq274xx_gauge_init(const struct device *dev) return ret; } -static int bq274xx_gauge_configure(const struct device *dev) -{ - const struct bq274xx_config *const config = dev->config; - struct bq274xx_data *data = dev->data; - - int ret = 0; - uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; - uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; - uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, - terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; - uint8_t block[32]; - - designenergy_mwh = (uint16_t)3.7 * config->design_capacity; - taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); - - /** Unseal the battery control register **/ - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (ret < 0) { - LOG_ERR("Unable to unseal the battery"); - return -EIO; - } - - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); - if (ret < 0) { - LOG_ERR("Unable to unseal the battery"); - return -EIO; - } - - /* Send CFG_UPDATE */ - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SET_CFGUPDATE); - if (ret < 0) { - LOG_ERR("Unable to set CFGUpdate"); - return -EIO; - } - - /** Step to place the Gauge into CONFIG UPDATE Mode **/ - do { - ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); - if (ret < 0) { - LOG_ERR("Unable to read flags"); - return -EIO; - } - - if (!(flags & 0x0010)) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); - } - - } while (!(flags & 0x0010)); - - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); - if (ret < 0) { - LOG_ERR("Failed to enable block data memory"); - return -EIO; - } - - /* Access State subclass */ - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); - if (ret < 0) { - LOG_ERR("Failed to update state subclass"); - return -EIO; - } - - /* Write the block offset */ - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); - if (ret < 0) { - LOG_ERR("Failed to update block offset"); - return -EIO; - } - - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - - ret = bq274xx_read_data_block(dev, 0x00, block, 32); - if (ret < 0) { - LOG_ERR("Unable to read block data"); - return -EIO; - } - - tmp_checksum = 0; - for (uint8_t i = 0; i < 32; i++) { - tmp_checksum += block[i]; - } - tmp_checksum = 255 - tmp_checksum; - - /* Read the block checksum */ - ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &checksum_old); - if (ret < 0) { - LOG_ERR("Unable to read block checksum"); - return -EIO; - } - - designcap_msb = config->design_capacity >> 8; - designcap_lsb = config->design_capacity & 0x00FF; - designenergy_msb = designenergy_mwh >> 8; - designenergy_lsb = designenergy_mwh & 0x00FF; - terminatevolt_msb = config->terminate_voltage >> 8; - terminatevolt_lsb = config->terminate_voltage & 0x00FF; - taperrate_msb = taperrate >> 8; - taperrate_lsb = taperrate & 0x00FF; - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, - designcap_msb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, - designcap_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, - designenergy_msb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, - designenergy_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, - terminatevolt_msb); - if (ret < 0) { - LOG_ERR("Failed to write terminateVolt MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, - terminatevolt_lsb); - if (ret < 0) { - LOG_ERR("Failed to write terminateVolt LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, - taperrate_msb); - if (ret < 0) { - LOG_ERR("Failed to write taperRate MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); - if (ret < 0) { - LOG_ERR("Failed to write taperRate LSB"); - return -EIO; - } - - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - - ret = bq274xx_read_data_block(dev, 0x00, block, 32); - if (ret < 0) { - LOG_ERR("Unable to read block data"); - return -EIO; - } - - checksum_new = 0; - for (uint8_t i = 0; i < 32; i++) { - checksum_new += block[i]; - } - checksum_new = 255 - checksum_new; - - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); - if (ret < 0) { - LOG_ERR("Failed to update new checksum"); - return -EIO; - } - - tmp_checksum = 0; - ret = i2c_reg_read_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, &tmp_checksum); - if (ret < 0) { - LOG_ERR("Failed to read checksum"); - return -EIO; - } - - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_BAT_INSERT); - if (ret < 0) { - LOG_ERR("Unable to configure BAT Detect"); - return -EIO; - } - - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SOFT_RESET); - if (ret < 0) { - LOG_ERR("Failed to soft reset the gauge"); - return -EIO; - } - - flags = 0; - /* Poll Flags */ - do { - ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); - if (ret < 0) { - LOG_ERR("Unable to read flags"); - return -EIO; - } - - if (flags & 0x0010) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); - } - } while (flags & 0x0010); - - /* Seal the gauge */ - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); - if (ret < 0) { - LOG_ERR("Failed to seal the gauge"); - return -EIO; - } - - data->configured = true; - - return 0; -} - #ifdef CONFIG_BQ274XX_PM static int bq274xx_enter_shutdown_mode(const struct device *dev) { From 2dcaed3252f9b750d7a41079ee43271a92b4656e Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 21:43:44 +0100 Subject: [PATCH 1598/2042] sensor: bq274xx: drop a bunch of redundant initialization Drop various unnecessarily initialized variables from the driver. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 27 ++++++++---------------- drivers/sensor/bq274xx/bq274xx_trigger.c | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index ebd5434a7350..41925e4b0728 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -51,7 +51,7 @@ static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; - int ret = 0; + int ret; reg_addr = BQ274XX_CMD_CONTROL_LOW; i2c_data = subcommand & 0xFF; @@ -81,7 +81,7 @@ static int bq274xx_cmd_reg_write(const struct device *dev, uint8_t command, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data, reg_addr; - int ret = 0; + int ret; reg_addr = command; i2c_data = data; @@ -100,7 +100,7 @@ static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, { const struct bq274xx_config *config = dev->config; uint8_t i2c_data; - int ret = 0; + int ret; i2c_data = BQ274XX_EXT_BLKDAT_START + offset; @@ -140,9 +140,9 @@ static int bq274xx_gauge_configure(const struct device *dev) const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - int ret = 0; - uint8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0; - uint16_t flags = 0, designenergy_mwh = 0, taperrate = 0; + int ret; + uint8_t tmp_checksum, checksum_old, checksum_new; + uint16_t flags, designenergy_mwh, taperrate; uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; uint8_t block[32]; @@ -204,10 +204,6 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); @@ -291,10 +287,6 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - for (uint8_t i = 0; i < 32; i++) { - block[i] = 0; - } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); if (ret < 0) { LOG_ERR("Unable to read block data"); @@ -332,7 +324,6 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - flags = 0; /* Poll Flags */ do { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); @@ -442,7 +433,7 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; - int ret = 0; + int ret; if (!data->configured) { ret = bq274xx_gauge_configure(dev); @@ -579,7 +570,7 @@ static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel ch static int bq274xx_gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int ret = 0; + int ret; uint16_t id; if (!device_is_ready(config->i2c.bus)) { @@ -661,7 +652,7 @@ static int bq274xx_enter_shutdown_mode(const struct device *dev) static int bq274xx_exit_shutdown_mode(const struct device *dev) { const struct bq274xx_config *const config = dev->config; - int ret = 0; + int ret; ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_OUTPUT | GPIO_OPEN_DRAIN); if (ret < 0) { diff --git a/drivers/sensor/bq274xx/bq274xx_trigger.c b/drivers/sensor/bq274xx/bq274xx_trigger.c index 1559a4ee79bc..b13662904683 100644 --- a/drivers/sensor/bq274xx/bq274xx_trigger.c +++ b/drivers/sensor/bq274xx/bq274xx_trigger.c @@ -70,7 +70,7 @@ int bq274xx_trigger_mode_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - int ret = 0; + int ret; data->dev = dev; From 9bc43ac3ced599da8bb7687e3726c3a42bbec933 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 22:25:53 +0100 Subject: [PATCH 1599/2042] sensor: bq274xx: simplify i2c write code Control reg write seems to support two bytes mode (the technical reference shows example of that), so use a single i2c_write_dt there. Also drop a couple alias variables from bq274xx_cmd_reg_write. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 41925e4b0728..d1b9acfb142c 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -50,26 +50,17 @@ static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) { const struct bq274xx_config *config = dev->config; - uint8_t i2c_data, reg_addr; int ret; - reg_addr = BQ274XX_CMD_CONTROL_LOW; - i2c_data = subcommand & 0xFF; + uint8_t tx_buf[3] = { + BQ274XX_CMD_CONTROL_LOW, + subcommand & 0xff, + subcommand >> 8, + }; - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); + ret = i2c_write_dt(&config->i2c, tx_buf, 3); if (ret < 0) { - LOG_ERR("Failed to write into control low register"); - return -EIO; - } - - k_msleep(BQ274XX_SUBCLASS_DELAY); - - reg_addr = BQ274XX_CMD_CONTROL_HIGH; - i2c_data = (subcommand >> 8) & 0xFF; - - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); - if (ret < 0) { - LOG_ERR("Failed to write into control high register"); + LOG_ERR("Failed to write into control register"); return -EIO; } @@ -80,13 +71,9 @@ static int bq274xx_cmd_reg_write(const struct device *dev, uint8_t command, uint8_t data) { const struct bq274xx_config *config = dev->config; - uint8_t i2c_data, reg_addr; int ret; - reg_addr = command; - i2c_data = data; - - ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, i2c_data); + ret = i2c_reg_write_byte_dt(&config->i2c, command, data); if (ret < 0) { LOG_ERR("Failed to write into control register"); return -EIO; From 35bb28abaf2c3933d15501e6182f4c8fa6be3aad Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 22:42:59 +0100 Subject: [PATCH 1600/2042] sensor: bq274xx: add few defines for magic numbers Add a couple of define for the data memory block size and config flag bit. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index d1b9acfb142c..75885850bfdc 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -29,6 +29,12 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* Time it takes device to initialize before doing any configuration */ #define INIT_TIME 100U +/* Data memory size */ +#define BQ27XXX_DM_SZ 32 + +/* Config update mode flag */ +#define BQ27XXX_FLAG_CFGUP BIT(4) + static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { @@ -36,7 +42,7 @@ static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, uint8_t i2c_data[2]; int ret; - ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, 2); + ret = i2c_burst_read_dt(&config->i2c, reg_addr, i2c_data, sizeof(i2c_data)); if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; @@ -58,7 +64,7 @@ static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) subcommand >> 8, }; - ret = i2c_write_dt(&config->i2c, tx_buf, 3); + ret = i2c_write_dt(&config->i2c, tx_buf, sizeof(tx_buf)); if (ret < 0) { LOG_ERR("Failed to write into control register"); return -EIO; @@ -132,7 +138,7 @@ static int bq274xx_gauge_configure(const struct device *dev) uint16_t flags, designenergy_mwh, taperrate; uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; - uint8_t block[32]; + uint8_t block[BQ27XXX_DM_SZ]; designenergy_mwh = (uint16_t)3.7 * config->design_capacity; taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); @@ -165,11 +171,11 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - if (!(flags & 0x0010)) { + if (!(flags & BQ27XXX_FLAG_CFGUP)) { k_msleep(BQ274XX_SUBCLASS_DELAY * 10); } - } while (!(flags & 0x0010)); + } while (!(flags & BQ27XXX_FLAG_CFGUP)); ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { @@ -191,14 +197,14 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); + ret = bq274xx_read_data_block(dev, 0, block, sizeof(block)); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; } tmp_checksum = 0; - for (uint8_t i = 0; i < 32; i++) { + for (uint8_t i = 0; i < ARRAY_SIZE(block); i++) { tmp_checksum += block[i]; } tmp_checksum = 255 - tmp_checksum; @@ -274,14 +280,14 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - ret = bq274xx_read_data_block(dev, 0x00, block, 32); + ret = bq274xx_read_data_block(dev, 0, block, sizeof(block)); if (ret < 0) { LOG_ERR("Unable to read block data"); return -EIO; } checksum_new = 0; - for (uint8_t i = 0; i < 32; i++) { + for (uint8_t i = 0; i < ARRAY_SIZE(block); i++) { checksum_new += block[i]; } checksum_new = 255 - checksum_new; @@ -319,10 +325,10 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - if (flags & 0x0010) { + if (flags & BQ27XXX_FLAG_CFGUP) { k_msleep(BQ274XX_SUBCLASS_DELAY * 10); } - } while (flags & 0x0010); + } while (flags & BQ27XXX_FLAG_CFGUP); /* Seal the gauge */ ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); From 71bd63d0071b0c136fcf23624fc9969447e8bc89 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 22:56:25 +0100 Subject: [PATCH 1601/2042] sensor: bq274xx: fix few parameter calculations Fix the calculation for designenergy_mwh, as right now it's using a float casted straight to an int, which results in the factor rounded from 3.7 to 3. Also rework both that and taperrate so that they don't use floating point. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 75885850bfdc..60a0039ba1a5 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -140,8 +140,8 @@ static int bq274xx_gauge_configure(const struct device *dev) terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; uint8_t block[BQ27XXX_DM_SZ]; - designenergy_mwh = (uint16_t)3.7 * config->design_capacity; - taperrate = (uint16_t)config->design_capacity / (0.1 * config->taper_current); + designenergy_mwh = (uint32_t)config->design_capacity * 37 / 10; /* x3.7 */ + taperrate = config->design_capacity * 10 / config->taper_current; /* Unseal the battery control register */ ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); From 7b6430cc800be5795f1655d7c0ca735716daa197 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 8 Jul 2023 18:40:02 +0100 Subject: [PATCH 1602/2042] sensor: bq274xx: limit config update mode check loops Add a retry count limit to config update mode loops, this way the system can still boot if there's an issue with the device. The normal sleep should be enough for correct operation, adding a conservative limit. Rework the delays to be unambiguous while at it. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 35 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 60a0039ba1a5..6c8f971ba517 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -21,13 +21,16 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* subclass 64 & 82 needs 5ms delay */ -#define BQ274XX_SUBCLASS_DELAY 5 +#define BQ274XX_SUBCLASS_DELAY K_MSEC(5) + +/* Time to wait for CFGUP bit to be set */ +#define BQ274XX_CFGUP_DELAY K_MSEC(50) /* Time to set pin in order to exit shutdown mode */ -#define PIN_DELAY_TIME 1U +#define PIN_DELAY_TIME K_MSEC(1) /* Time it takes device to initialize before doing any configuration */ -#define INIT_TIME 100U +#define INIT_TIME K_MSEC(100) /* Data memory size */ #define BQ27XXX_DM_SZ 32 @@ -103,7 +106,7 @@ static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, return -EIO; } - k_msleep(BQ274XX_SUBCLASS_DELAY); + k_sleep(BQ274XX_SUBCLASS_DELAY); return 0; } @@ -139,6 +142,7 @@ static int bq274xx_gauge_configure(const struct device *dev) uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; uint8_t block[BQ27XXX_DM_SZ]; + uint8_t try; designenergy_mwh = (uint32_t)config->design_capacity * 37 / 10; /* x3.7 */ taperrate = config->design_capacity * 10 / config->taper_current; @@ -164,6 +168,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } /* Step to place the Gauge into CONFIG UPDATE Mode */ + try = 100; do { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { @@ -172,10 +177,14 @@ static int bq274xx_gauge_configure(const struct device *dev) } if (!(flags & BQ27XXX_FLAG_CFGUP)) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); + k_sleep(BQ274XX_CFGUP_DELAY); } + } while (!(flags & BQ27XXX_FLAG_CFGUP) && --try); - } while (!(flags & BQ27XXX_FLAG_CFGUP)); + if (!try) { + LOG_ERR("Config mode change timeout"); + return -EIO; + } ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { @@ -318,6 +327,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } /* Poll Flags */ + try = 100; do { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FLAGS, &flags); if (ret < 0) { @@ -326,9 +336,14 @@ static int bq274xx_gauge_configure(const struct device *dev) } if (flags & BQ27XXX_FLAG_CFGUP) { - k_msleep(BQ274XX_SUBCLASS_DELAY * 10); + k_sleep(BQ274XX_CFGUP_DELAY); } - } while (flags & BQ27XXX_FLAG_CFGUP); + } while ((flags & BQ27XXX_FLAG_CFGUP) & --try); + + if (!try) { + LOG_ERR("Config mode change timeout"); + return -EIO; + } /* Seal the gauge */ ret = bq274xx_ctrl_reg_write(dev, BQ274XX_CTRL_SEALED); @@ -659,7 +674,7 @@ static int bq274xx_exit_shutdown_mode(const struct device *dev) return ret; } - k_msleep(PIN_DELAY_TIME); + k_sleep(PIN_DELAY_TIME); ret = gpio_pin_configure_dt(&config->int_gpios, GPIO_INPUT); if (ret < 0) { @@ -668,7 +683,7 @@ static int bq274xx_exit_shutdown_mode(const struct device *dev) } if (!config->lazy_loading) { - k_msleep(INIT_TIME); + k_sleep(INIT_TIME); ret = bq274xx_gauge_configure(dev); if (ret < 0) { From 76509a73b1869019cb91665e12f5b8fd9526e65b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 8 Jul 2023 18:47:31 +0100 Subject: [PATCH 1603/2042] sensor: bq274xx: clarify the unseal sequence The device technical reference manual says "The Sealed to Unsealed key has two identical words". Use two different defines with the same value in the code so it's somewhat less ambiguous that the double write is intentional. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 8 ++++---- drivers/sensor/bq274xx/bq274xx.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 6c8f971ba517..0e21254f18f4 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -148,13 +148,13 @@ static int bq274xx_gauge_configure(const struct device *dev) taperrate = config->design_capacity * 10 / config->taper_current; /* Unseal the battery control register */ - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_A); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; } - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_B); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return -EIO; @@ -624,13 +624,13 @@ static int bq274xx_enter_shutdown_mode(const struct device *dev) { int ret; - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_A); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; } - ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY); + ret = bq274xx_ctrl_reg_write(dev, BQ274XX_UNSEAL_KEY_B); if (ret < 0) { LOG_ERR("Unable to unseal the battery"); return ret; diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index 96bb9e83edf8..67cda5fe8e2d 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -11,7 +11,8 @@ #include /*** General Constant ***/ -#define BQ274XX_UNSEAL_KEY 0x8000 /* Secret code to unseal the BQ27441-G1A */ +#define BQ274XX_UNSEAL_KEY_A 0x8000 /* Unseal code one on BQ27441-G1A and similar */ +#define BQ274XX_UNSEAL_KEY_B 0x8000 /* Unseal code two on BQ27441-G1A and similar */ #define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ /*** Standard Commands ***/ From 4dc7437d45ea337e5b13d07af5625707c8becac7 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 8 Jul 2023 18:53:50 +0100 Subject: [PATCH 1604/2042] sensor: bq274xx: support fetching all channels Change bq274xx_sample_fetch to support SENSOR_CHAN_ALL. This makes it possible to get the sensor data using the sensor shell, besides being generally convenient. Also drop a redundant comment. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 61 +++++++++++++------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 0e21254f18f4..45b838a18a07 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -357,11 +357,6 @@ static int bq274xx_gauge_configure(const struct device *dev) return 0; } -/** - * @brief sensor value get - * - * @return -ENOTSUP for unsupported channels - */ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { @@ -441,117 +436,115 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bq274xx_data *data = dev->data; - int ret; + int ret = -ENOTSUP; if (!data->configured) { ret = bq274xx_gauge_configure(dev); - if (ret < 0) { return ret; } } - switch (chan) { - case SENSOR_CHAN_GAUGE_VOLTAGE: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_VOLTAGE) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_VOLTAGE, &data->voltage); if (ret < 0) { LOG_ERR("Failed to read voltage"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_AVG_CURRENT: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_AVG_CURRENT) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_CURRENT, &data->avg_current); if (ret < 0) { LOG_ERR("Failed to read average current "); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_TEMP: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_TEMP) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_INT_TEMP, &data->internal_temperature); if (ret < 0) { LOG_ERR("Failed to read internal temperature"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STDBY_CURRENT: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STDBY_CURRENT) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_STDBY_CURRENT, &data->stdby_current); if (ret < 0) { LOG_ERR("Failed to read standby current"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_MAX_CURRENT, &data->max_load_current); if (ret < 0) { LOG_ERR("Failed to read maximum current"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STATE_OF_CHARGE) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOC, &data->state_of_charge); if (ret < 0) { LOG_ERR("Failed to read state of charge"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_FULL_CAPACITY, &data->full_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read full charge capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_REM_CAPACITY, &data->remaining_charge_capacity); if (ret < 0) { LOG_ERR("Failed to read remaining charge capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_NOM_CAPACITY, &data->nom_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read nominal available capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVAIL_CAPACITY, &data->full_avail_capacity); if (ret < 0) { LOG_ERR("Failed to read full available capacity"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_AVG_POWER: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_AVG_POWER) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_AVG_POWER, &data->avg_power); if (ret < 0) { LOG_ERR("Failed to read battery average power"); return -EIO; } - break; + } - case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH: + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_GAUGE_STATE_OF_HEALTH) { ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_SOH, &data->state_of_health); @@ -561,13 +554,9 @@ static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel ch LOG_ERR("Failed to read state of health"); return -EIO; } - break; - - default: - return -ENOTSUP; } - return 0; + return ret; } /** From 6390dd582a02d8b1af54e97c48c0cefc196fd665 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 9 Jul 2023 15:09:14 +0100 Subject: [PATCH 1605/2042] sensor: bq274xx: drop bq274xx_ctrl_reg_write Use i2c_reg_write_byte_dt instead of bq274xx_cmd_reg_write. The wrapper does not add anything anyway. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 45b838a18a07..ebaddec2707a 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -76,21 +76,6 @@ static int bq274xx_ctrl_reg_write(const struct device *dev, uint16_t subcommand) return 0; } -static int bq274xx_cmd_reg_write(const struct device *dev, uint8_t command, - uint8_t data) -{ - const struct bq274xx_config *config = dev->config; - int ret; - - ret = i2c_reg_write_byte_dt(&config->i2c, command, data); - if (ret < 0) { - LOG_ERR("Failed to write into control register"); - return -EIO; - } - - return 0; -} - static int bq274xx_read_data_block(const struct device *dev, uint8_t offset, uint8_t *data, uint8_t bytes) { @@ -186,21 +171,21 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CONTROL, 0x00); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_CONTROL, 0x00); if (ret < 0) { LOG_ERR("Failed to enable block data memory"); return -EIO; } /* Access State subclass */ - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_CLASS, 0x52); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_CLASS, 0x52); if (ret < 0) { LOG_ERR("Failed to update state subclass"); return -EIO; } /* Write the block offset */ - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_DATA_BLOCK, 0x00); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_DATA_BLOCK, 0x00); if (ret < 0) { LOG_ERR("Failed to update block offset"); return -EIO; @@ -301,7 +286,7 @@ static int bq274xx_gauge_configure(const struct device *dev) } checksum_new = 255 - checksum_new; - ret = bq274xx_cmd_reg_write(dev, BQ274XX_EXT_CHECKSUM, checksum_new); + ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_CHECKSUM, checksum_new); if (ret < 0) { LOG_ERR("Failed to update new checksum"); return -EIO; From ec98bf7cbcf446285c6c8d656c456ceb658a9387 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 6 Jul 2023 22:29:31 +0100 Subject: [PATCH 1606/2042] sensor: bq274xx: add support for bq27427 The current ID for BQ274XX_DEVICE_ID is actually the one for the BQ27421. The driver seems to work with the BQ27427 as well, at least the common and extended commands are the same, so add that variant as well, rename the existing one and print the currently read ID when the ID check fails. The configuration registers have a different offset though, so add a register offset table and make the device rcognize the right one un runtime based on the device ID. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 53 ++++++++++++++++++++++++-------- drivers/sensor/bq274xx/bq274xx.h | 22 +++++++------ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index ebaddec2707a..937f0f152a32 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -38,6 +38,20 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); /* Config update mode flag */ #define BQ27XXX_FLAG_CFGUP BIT(4) +static const struct bq274xx_regs bq27421_regs = { + .dm_design_capacity = 10, + .dm_design_energy = 12, + .dm_terminate_voltage = 16, + .dm_taper_rate = 27, +}; + +static const struct bq274xx_regs bq27427_regs = { + .dm_design_capacity = 6, + .dm_design_energy = 8, + .dm_terminate_voltage = 10, + .dm_taper_rate = 21, +}; + static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, int16_t *val) { @@ -107,7 +121,6 @@ static int bq274xx_get_device_type(const struct device *dev, uint16_t *val) } ret = bq274xx_cmd_reg_read(dev, BQ274XX_CMD_CONTROL_LOW, val); - if (ret < 0) { LOG_ERR("Unable to read register"); return -EIO; @@ -120,7 +133,7 @@ static int bq274xx_gauge_configure(const struct device *dev) { const struct bq274xx_config *const config = dev->config; struct bq274xx_data *data = dev->data; - + const struct bq274xx_regs *regs = data->regs; int ret; uint8_t tmp_checksum, checksum_old, checksum_new; uint16_t flags, designenergy_mwh, taperrate; @@ -219,56 +232,65 @@ static int bq274xx_gauge_configure(const struct device *dev) taperrate_msb = taperrate >> 8; taperrate_lsb = taperrate & 0x00FF; - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_HIGH(regs->dm_design_capacity), designcap_msb); if (ret < 0) { LOG_ERR("Failed to write designCAP MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_LOW(regs->dm_design_capacity), designcap_lsb); if (ret < 0) { LOG_ERR("Failed to write designCAP LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_HIGH(regs->dm_design_energy), designenergy_msb); if (ret < 0) { LOG_ERR("Failed to write designEnergy MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_LOW(regs->dm_design_energy), designenergy_lsb); if (ret < 0) { LOG_ERR("Failed to write designEnergy LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_HIGH(regs->dm_terminate_voltage), terminatevolt_msb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_LOW(regs->dm_terminate_voltage), terminatevolt_lsb); if (ret < 0) { LOG_ERR("Failed to write terminateVolt LSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH, + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_HIGH(regs->dm_taper_rate), taperrate_msb); if (ret < 0) { LOG_ERR("Failed to write taperRate MSB"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, BQ274XX_EXT_BLKDAT_TAPERRATE_LOW, taperrate_lsb); + ret = i2c_reg_write_byte_dt(&config->i2c, + BQ274XX_EXT_BLKDAT_LOW(regs->dm_taper_rate), + taperrate_lsb); if (ret < 0) { LOG_ERR("Failed to write taperRate LSB"); return -EIO; @@ -552,6 +574,7 @@ static int bq274xx_sample_fetch(const struct device *dev, enum sensor_channel ch static int bq274xx_gauge_init(const struct device *dev) { const struct bq274xx_config *const config = dev->config; + struct bq274xx_data *data = dev->data; int ret; uint16_t id; @@ -573,9 +596,13 @@ static int bq274xx_gauge_init(const struct device *dev) return -EIO; } - if (id != BQ274XX_DEVICE_ID) { - LOG_ERR("Invalid Device"); - return -EINVAL; + if (id == BQ27421_DEVICE_ID) { + data->regs = &bq27421_regs; + } else if (id == BQ27427_DEVICE_ID) { + data->regs = &bq27427_regs; + } else { + LOG_ERR("Unsupported device ID: 0x%04x", id); + return -ENOTSUP; } #ifdef CONFIG_BQ274XX_TRIGGER diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index 67cda5fe8e2d..54faceb7fcc5 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -13,7 +13,8 @@ /*** General Constant ***/ #define BQ274XX_UNSEAL_KEY_A 0x8000 /* Unseal code one on BQ27441-G1A and similar */ #define BQ274XX_UNSEAL_KEY_B 0x8000 /* Unseal code two on BQ27441-G1A and similar */ -#define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */ +#define BQ27421_DEVICE_ID 0x0421 +#define BQ27427_DEVICE_ID 0x0427 /*** Standard Commands ***/ #define BQ274XX_CMD_CONTROL_LOW 0x00 /* Control() low register */ @@ -68,18 +69,19 @@ #define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ #define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ #define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_HIGH 0x4A /* BlockData */ -#define BQ274XX_EXT_BLKDAT_DESIGN_CAP_LOW 0x4B -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_HIGH 0x4C -#define BQ274XX_EXT_BLKDAT_DESIGN_ENR_LOW 0x4D -#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_HIGH 0x50 -#define BQ274XX_EXT_BLKDAT_TERMINATE_VOLT_LOW 0x51 -#define BQ274XX_EXT_BLKDAT_TAPERRATE_HIGH 0x5B -#define BQ274XX_EXT_BLKDAT_TAPERRATE_LOW 0x5C +#define BQ274XX_EXT_BLKDAT_HIGH(off) (BQ274XX_EXT_BLKDAT_START + off) +#define BQ274XX_EXT_BLKDAT_LOW(off) (BQ274XX_EXT_BLKDAT_START + off + 1) -#define BQ274XX_DELAY 1000 +/* Hold the register offset for a device variant. */ +struct bq274xx_regs { + uint8_t dm_design_capacity; + uint8_t dm_design_energy; + uint8_t dm_terminate_voltage; + uint8_t dm_taper_rate; +}; struct bq274xx_data { + const struct bq274xx_regs *regs; bool configured; uint16_t voltage; int16_t avg_current; From bb0135b64c4566268d5f2d89090bf7da97427bc2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 9 Jul 2023 16:25:11 +0100 Subject: [PATCH 1607/2042] sensor: bq274xx: use two bytes write for settings Use a combination of sys_cpu_to_be16 and i2c_burst_write_dt for setting 16 bits registers. Get rid of a bunch of temporary variables, custom conversions and few bus writes. Signed-off-by: Fabio Baltieri --- drivers/sensor/bq274xx/bq274xx.c | 83 +++++++++----------------------- drivers/sensor/bq274xx/bq274xx.h | 3 +- 2 files changed, 23 insertions(+), 63 deletions(-) diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 937f0f152a32..3a16e22bd586 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -65,7 +65,7 @@ static int bq274xx_cmd_reg_read(const struct device *dev, uint8_t reg_addr, return -EIO; } - *val = (i2c_data[1] << 8) | i2c_data[0]; + *val = sys_get_le16(i2c_data); return 0; } @@ -136,9 +136,7 @@ static int bq274xx_gauge_configure(const struct device *dev) const struct bq274xx_regs *regs = data->regs; int ret; uint8_t tmp_checksum, checksum_old, checksum_new; - uint16_t flags, designenergy_mwh, taperrate; - uint8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb, - terminatevolt_msb, terminatevolt_lsb, taperrate_msb, taperrate_lsb; + uint16_t flags, designenergy_mwh, taperrate, reg_val; uint8_t block[BQ27XXX_DM_SZ]; uint8_t try; @@ -223,76 +221,39 @@ static int bq274xx_gauge_configure(const struct device *dev) return -EIO; } - designcap_msb = config->design_capacity >> 8; - designcap_lsb = config->design_capacity & 0x00FF; - designenergy_msb = designenergy_mwh >> 8; - designenergy_lsb = designenergy_mwh & 0x00FF; - terminatevolt_msb = config->terminate_voltage >> 8; - terminatevolt_lsb = config->terminate_voltage & 0x00FF; - taperrate_msb = taperrate >> 8; - taperrate_lsb = taperrate & 0x00FF; - - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_HIGH(regs->dm_design_capacity), - designcap_msb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_LOW(regs->dm_design_capacity), - designcap_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designCAP LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_HIGH(regs->dm_design_energy), - designenergy_msb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy MSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_LOW(regs->dm_design_energy), - designenergy_lsb); - if (ret < 0) { - LOG_ERR("Failed to write designEnergy LSB"); - return -EIO; - } - - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_HIGH(regs->dm_terminate_voltage), - terminatevolt_msb); + reg_val = sys_cpu_to_be16(config->design_capacity); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_design_capacity), + (uint8_t *)®_val, sizeof(reg_val)); if (ret < 0) { - LOG_ERR("Failed to write terminateVolt MSB"); + LOG_ERR("Failed to write design capacity"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_LOW(regs->dm_terminate_voltage), - terminatevolt_lsb); + reg_val = sys_cpu_to_be16(designenergy_mwh); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_design_energy), + (uint8_t *)®_val, sizeof(reg_val)); if (ret < 0) { - LOG_ERR("Failed to write terminateVolt LSB"); + LOG_ERR("Failed to write design energy"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_HIGH(regs->dm_taper_rate), - taperrate_msb); + reg_val = sys_cpu_to_be16(config->terminate_voltage); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_terminate_voltage), + (uint8_t *)®_val, sizeof(reg_val)); if (ret < 0) { - LOG_ERR("Failed to write taperRate MSB"); + LOG_ERR("Failed to write terminate voltage"); return -EIO; } - ret = i2c_reg_write_byte_dt(&config->i2c, - BQ274XX_EXT_BLKDAT_LOW(regs->dm_taper_rate), - taperrate_lsb); + reg_val = sys_cpu_to_be16(taperrate); + ret = i2c_burst_write_dt(&config->i2c, + BQ274XX_EXT_BLKDAT(regs->dm_taper_rate), + (uint8_t *)®_val, sizeof(reg_val)); if (ret < 0) { - LOG_ERR("Failed to write taperRate LSB"); + LOG_ERR("Failed to write taper rate"); return -EIO; } diff --git a/drivers/sensor/bq274xx/bq274xx.h b/drivers/sensor/bq274xx/bq274xx.h index 54faceb7fcc5..ea81b9f2489e 100644 --- a/drivers/sensor/bq274xx/bq274xx.h +++ b/drivers/sensor/bq274xx/bq274xx.h @@ -69,8 +69,7 @@ #define BQ274XX_EXT_BLKDAT_END 0x5F /* BlockData_end() */ #define BQ274XX_EXT_CHECKSUM 0x60 /* BlockDataCheckSum() */ #define BQ274XX_EXT_DATA_CONTROL 0x61 /* BlockDataControl() */ -#define BQ274XX_EXT_BLKDAT_HIGH(off) (BQ274XX_EXT_BLKDAT_START + off) -#define BQ274XX_EXT_BLKDAT_LOW(off) (BQ274XX_EXT_BLKDAT_START + off + 1) +#define BQ274XX_EXT_BLKDAT(off) (BQ274XX_EXT_BLKDAT_START + off) /* Hold the register offset for a device variant. */ struct bq274xx_regs { From e44314aeee8f0f4f4c4011fe444dec1db6479ad2 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Mon, 17 Jul 2023 10:39:21 -0400 Subject: [PATCH 1608/2042] soc: nxp_imx: rt5xx: fix part numbers in WLCSP Dropped R from part numbers to match MCUXpresso SDK Signed-off-by: Derek Snell --- soc/arm/nxp_imx/rt5xx/Kconfig.soc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.soc b/soc/arm/nxp_imx/rt5xx/Kconfig.soc index aec0191b24e1..f41c63d104bb 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.soc +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.soc @@ -44,20 +44,20 @@ config SOC_PART_NUMBER_MIMXRT555SFFOC config SOC_PART_NUMBER_MIMXRT595SFFOC bool -config SOC_PART_NUMBER_MIMXRT533SFAWCR +config SOC_PART_NUMBER_MIMXRT533SFAWC bool -config SOC_PART_NUMBER_MIMXRT555SFAWCR +config SOC_PART_NUMBER_MIMXRT555SFAWC bool -config SOC_PART_NUMBER_MIMXRT595SFAWCR +config SOC_PART_NUMBER_MIMXRT595SFAWC bool config SOC_PART_NUMBER_IMX_RT5XX string - default "MIMXRT533SFAWCR" if SOC_PART_NUMBER_MIMXRT533SFAWCR - default "MIMXRT555SFAWCR" if SOC_PART_NUMBER_MIMXRT555SFAWCR - default "MIMXRT595SFAWCR" if SOC_PART_NUMBER_MIMXRT595SFAWCR + default "MIMXRT533SFAWC" if SOC_PART_NUMBER_MIMXRT533SFAWC + default "MIMXRT555SFAWC" if SOC_PART_NUMBER_MIMXRT555SFAWC + default "MIMXRT595SFAWC" if SOC_PART_NUMBER_MIMXRT595SFAWC default "MIMXRT533SFFOC" if SOC_PART_NUMBER_MIMXRT533SFFOC default "MIMXRT555SFFOC" if SOC_PART_NUMBER_MIMXRT555SFFOC default "MIMXRT595SFFOC" if SOC_PART_NUMBER_MIMXRT595SFFOC From 502ecaeac59b28c9dff343345130b048a6667b58 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 12:27:01 +0000 Subject: [PATCH 1609/2042] sensors: icm42688: ensure SENSOR_ASYNC_API is selected This fix a build issue where ICM42688_DECODER is enabled but SENSOR_ASYNC_API is not, which results in some structures in an orphan section: warning: orphan section `._sensor_decoder_api.static.invensense_icm42688__decoder_api_' from `libdrivers__sensor__icm42688.a(icm42688_decoder.c.obj)' being placed in section `._sensor_decoder_api.static.invensense_icm42688__decoder_api_' Signed-off-by: Fabio Baltieri --- drivers/sensor/icm42688/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index 19d0602cbd31..2944a9d1183a 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -24,6 +24,7 @@ config EMUL_ICM42688 config ICM42688_DECODER bool "ICM42688 decoder logic" default y if ICM42688 + select SENSOR_ASYNC_API help Compile the ICM42688 decoder API which allows decoding raw data returned from the sensor. From 1fd372737bc1f06f00d6890e656834d14dc8f141 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 12:37:10 +0000 Subject: [PATCH 1610/2042] hwinfo: gecko: fix warning when building for efr32bg27_brd2602a When building the driver for efr32bg27_brd2602a none of the condition matches and the compiler warns for: hwinfo_gecko.c: In function 'z_impl_hwinfo_get_reset_cause': hwinfo_gecko.c:38:18: warning: unused variable 'rmu_flags' 38 | uint32_t rmu_flags = RMU_ResetCauseGet(); This fails the bi-weekly build, add a __maybe_unused to silence the warning. Signed-off-by: Fabio Baltieri --- drivers/hwinfo/hwinfo_gecko.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwinfo/hwinfo_gecko.c b/drivers/hwinfo/hwinfo_gecko.c index 42f0a1071ca2..df00d007013a 100644 --- a/drivers/hwinfo/hwinfo_gecko.c +++ b/drivers/hwinfo/hwinfo_gecko.c @@ -35,7 +35,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) int z_impl_hwinfo_get_reset_cause(uint32_t *cause) { uint32_t flags = 0; - uint32_t rmu_flags = RMU_ResetCauseGet(); + uint32_t __maybe_unused rmu_flags = RMU_ResetCauseGet(); #ifdef RMU_RSTCAUSE_PORST if (rmu_flags & RMU_RSTCAUSE_PORST) { From a30dbd5fe8636b3a543198259799bf47982951fc Mon Sep 17 00:00:00 2001 From: David Brown Date: Mon, 10 Jul 2023 12:12:21 -0600 Subject: [PATCH 1611/2042] manifest: Upgrade to trusted-firmware-m 1.8.0 Update trusted-firmware-m to 1.8.0, mbedtls to 3.4.0, and tf-m-tests to 1.8.0. Includes minor cmake changes due to file renames and such, as well as adjusting the return type of a callback function that has changed since the previous version of trusted-firmware-m. Signed-off-by: David Brown --- modules/mbedtls/CMakeLists.txt | 2 +- modules/trusted-firmware-m/CMakeLists.txt | 2 -- modules/trusted-firmware-m/interface/interface.c | 2 +- west.yml | 6 +++--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index aee2f78bd110..70636b5d5fd2 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -52,7 +52,6 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher_wrap.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cmac.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/code_share.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ctr_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/debug.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/des.c @@ -77,6 +76,7 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_reader.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_trace.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/poly1305.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_util.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ripemd160.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/rsa_alt_helpers.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/rsa.c diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 74020af556d6..0c01858f34d5 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -214,7 +214,6 @@ if (CONFIG_BUILD_WITH_TFM) ${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_psa_ns_connection_api.c # Specific to nordic_nrf platform ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c @@ -409,7 +408,6 @@ 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_ifdef(CONFIG_TFM_CONNECTION_BASED_SERVICE_API ${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_connection_api.c) zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c) if(CONFIG_SOC_FAMILY_NRF) diff --git a/modules/trusted-firmware-m/interface/interface.c b/modules/trusted-firmware-m/interface/interface.c index 66100b9e62ac..9cbcf5636c65 100644 --- a/modules/trusted-firmware-m/interface/interface.c +++ b/modules/trusted-firmware-m/interface/interface.c @@ -74,7 +74,7 @@ int32_t tfm_ns_interface_dispatch(veneer_fn fn, return result; } -enum tfm_status_e tfm_ns_interface_init(void) +uint32_t tfm_ns_interface_init(void) { /* * The static K_MUTEX_DEFINE handles mutex initialization, diff --git a/west.yml b/west.yml index f0a69af00ab4..4aae6651d573 100644 --- a/west.yml +++ b/west.yml @@ -266,7 +266,7 @@ manifest: revision: 8e303c264fc21c2116dc612658003a22e933124d path: modules/lib/lz4 - name: mbedtls - revision: 6e7841e5a08eb5da3c82dbc8b6b6d82ae4b7d2a0 + revision: c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26 path: modules/crypto/mbedtls groups: - crypto @@ -321,7 +321,7 @@ manifest: groups: - debug - name: trusted-firmware-m - revision: 79a6115d3a8d0e04864ae8156c1dc8532b750f5a + revision: bad0696f388d6f713742c5da8dfce426ec17ef20 path: modules/tee/tf-m/trusted-firmware-m groups: - tee @@ -331,7 +331,7 @@ manifest: groups: - tee - name: tf-m-tests - revision: 0f80a65193ddbbe3f0ac38b33b07b26138c11fa7 + revision: a878426da78fbd1486dfc29d6c6b82be4ee79e72 path: modules/tee/tf-m/tf-m-tests groups: - tee From a64f430d6f1338746e8c196a3fefffc26df0414b Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 18 Jul 2023 10:46:20 -0600 Subject: [PATCH 1612/2042] doc: release-notes: Update tf-m and mbed TLS Describe the versions of TF-M and Mbed TLS being used. Signed-off-by: David Brown --- doc/releases/release-notes-3.5.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 6837ae0e2c53..ba78018e6905 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -266,12 +266,19 @@ HALs MCUboot ******* +Mbed TLS +******** + +* Update to Mbed TLS 3.4.0. + Storage ******* Trusted Firmware-M ****************** +* Update to TF-M 1.8.0 + Trusted Firmware-A ****************** From 58e4df64609ee054868aa839a3e780bc04b42b7c Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Wed, 17 May 2023 15:54:55 -0500 Subject: [PATCH 1613/2042] west: runner: add support for NXP's linkserver Linkserver is a utility for launching and managing GDB servers for NXP debug probes, which also provides a command-line target flash programming capabilities. Linkserver can be used with NXP MCUXpresso for Visual Studio Code. For more information about LinkServer, please visit the LinkServer web page (link [1] below). This commit adds a runner to west, supporting debug and flash commands. Documentation is also added. [1] - LinkServer web page: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/linkserver-for-microcontrollers:LINKERSERVER Signed-off-by: Yves Vandervennet --- boards/common/linkserver.board.cmake | 4 + doc/develop/flash_debug/host-tools.rst | 49 +++++ doc/develop/flash_debug/probes.rst | 29 +++ scripts/west_commands/runners/__init__.py | 1 + scripts/west_commands/runners/linkserver.py | 196 ++++++++++++++++++++ scripts/west_commands/tests/test_imports.py | 1 + 6 files changed, 280 insertions(+) create mode 100644 boards/common/linkserver.board.cmake create mode 100644 scripts/west_commands/runners/linkserver.py diff --git a/boards/common/linkserver.board.cmake b/boards/common/linkserver.board.cmake new file mode 100644 index 000000000000..743eef573994 --- /dev/null +++ b/boards/common/linkserver.board.cmake @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_finalize_runner_args(linkserver "--dt-flash=y") diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index 1d0b915f5635..ef59c47e566d 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -199,6 +199,55 @@ Windows PATH. A specific bossac executable can be used by passing the WSL is not currently supported. +.. _linkserver-debug-host-tools: + +LinkServer Debug Host Tools +**************************** + +Linkserver is a utility for launching and managing GDB servers for NXP debug probes, +which also provides a command-line target flash programming capabilities. +Linkserver can be used with NXP MCUXpresso for Visual Studio Code implementation, +with custom debug configurations based on GNU tools or as part of a headless solution +for continuous integration and test. Linkserver can be used with MCU-Link, LPC-Link2, +LPC11U35-based and OpenSDA based standalone or on-board debug probes from NXP. +The Linkserver installer also includes the firmware update utilities for MCU-Link and +the LPCScrypt utility for use with LPC-Link2. Linkserver can also be installed using +the MCUXpresso Installer. + +LinkServer is compatible with the following debug probes: + +- :ref:`lpclink2-cmsis-onboard-debug-probe` + +Supported west commands: + +1. flash +#. debug +#. debugserver +#. attach + +Notes: + + +1. Probes can be listed with LinkServer: + +.. code-block:: console + + LinkServer probes + +2. Use the LinkServer west runner ``--probe`` option to pass the probe index. + +.. code-block:: console + + west flash --runner=linkserver --probe=3 + +3. device specific settings can be overridden with the west runner for LinkServer with + the option '--override'. May be used multiple times. The format is dictated + by LinkServer, e.g.: + +.. code-block:: console + + west flash --runner=linkserver --override /device/memory/5/flash-driver=MIMXRT500_SFDP_MXIC_OSPI_S.cfx + .. _jlink-debug-host-tools: J-Link Debug Host Tools diff --git a/doc/develop/flash_debug/probes.rst b/doc/develop/flash_debug/probes.rst index 3adcb9b0b94b..78a068d6ac41 100644 --- a/doc/develop/flash_debug/probes.rst +++ b/doc/develop/flash_debug/probes.rst @@ -58,6 +58,35 @@ onboard debug probe may have limitations, such as lack of support for advanced debuggers or high-speed tracing. You may need to adjust jumpers to prevent the onboard debug probe from interfering with the external debug probe. +.. _lpclink2-cmsis-onboard-debug-probe: + +LPC-LINK2 CMSIS DAP Onboard Debug Probe +*************************************** + +The CMSIS-DAP debug probes allow debugging from any compatible toolchain, +including IAR EWARM, Keil MDK, as well as NXP’s MCUXpresso IDE and +MCUXpresso extension for VS Code. +As well as providing debug probe functionality, the LPC-Link2 probes also +provide: + +1. SWO trace end point: this virtual device is used by MCUXpresso to retrieve + SWO trace data. See the MCUXpresso IDE documentation for more information. +2. Virtual COM (VCOM) port / UART bridge connected to the target processor +3. LPCSIO bridge that provides communication to I2C and SPI slave devices + +This probe is realized by programming the LPC-Link2 microcontroller with the CMSIS-DAP +LPC-Link2 firmware. Download and install `LPCScrypt`_ to get the firmware and +programming scripts. + +.. note:: Verify the firmware supports your board by visiting `Firmware for LPCXpresso`_ + +1. Put the LPC-Link2 microcontroller into DFU boot mode by attaching the DFU + jumper, then powering up the board. + +#. Run the ``program_CMSIS`` script. + +#. Remove the DFU jumper and power cycle the board. + .. _lpclink2-jlink-onboard-debug-probe: LPC-Link2 J-Link Onboard Debug Probe diff --git a/scripts/west_commands/runners/__init__.py b/scripts/west_commands/runners/__init__.py index e4b4cf0d402b..f4340bc19b0b 100644 --- a/scripts/west_commands/runners/__init__.py +++ b/scripts/west_commands/runners/__init__.py @@ -37,6 +37,7 @@ def _import_runner_module(runner_name): 'intel_adsp', 'intel_cyclonev', 'jlink', + 'linkserver', 'mdb', 'misc', 'native_gdb', diff --git a/scripts/west_commands/runners/linkserver.py b/scripts/west_commands/runners/linkserver.py new file mode 100644 index 000000000000..10833618fa12 --- /dev/null +++ b/scripts/west_commands/runners/linkserver.py @@ -0,0 +1,196 @@ +# Copyright 2023 NXP +# Copyright (c) 2017 Linaro Limited. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Based on jlink.py + +'''Runner for debugging with NXP's LinkServer.''' + +import logging +import os +import shlex +import subprocess +import sys + +from runners.core import ZephyrBinaryRunner, RunnerCaps + + +DEFAULT_LINKSERVER_EXE = 'Linkserver.exe' if sys.platform == 'win32' else 'LinkServer' +DEFAULT_LINKSERVER_GDB_PORT = 3333 +DEFAULT_LINKSERVER_SEMIHOST_PORT = 3334 + +class LinkServerBinaryRunner(ZephyrBinaryRunner): + '''Runner front-end for NXP Linkserver''' + def __init__(self, cfg, device, + linkserver=DEFAULT_LINKSERVER_EXE, + dt_flash=True, erase=True, + probe=1, + gdb_host='', + gdb_port=DEFAULT_LINKSERVER_GDB_PORT, + semihost_port=DEFAULT_LINKSERVER_SEMIHOST_PORT, + override=[], + tui=False, tool_opt=[]): + super().__init__(cfg) + self.file = cfg.file + self.file_type = cfg.file_type + self.hex_name = cfg.hex_file + self.bin_name = cfg.bin_file + self.elf_name = cfg.elf_file + self.gdb_cmd = cfg.gdb if cfg.gdb else None + self.device = device + self.linkserver = linkserver + self.dt_flash = dt_flash + self.erase = erase + self.probe = probe + self.gdb_host = gdb_host + self.gdb_port = gdb_port + self.semihost_port = semihost_port + self.tui_arg = ['-tui'] if tui else [] + self.override = override + self.override_cli = self._build_override_cli() + + self.tool_opt = [] + for opts in [shlex.split(opt) for opt in tool_opt]: + self.tool_opt += opts + + @classmethod + def name(cls): + return 'linkserver' + + @classmethod + def capabilities(cls): + return RunnerCaps(commands={'flash', 'debug', 'debugserver', 'attach'}, + dev_id=True, flash_addr=True, erase=True, + tool_opt=True, file=True) + + @classmethod + def do_add_parser(cls, parser): + parser.add_argument('--device', required=True, help='device name') + + parser.add_argument('--probe', default=1, + help='interface to use (index, no serial number), default is 1') + + parser.add_argument('--tui', default=False, action='store_true', + help='if given, GDB uses -tui') + + parser.add_argument('--gdb-port', default=DEFAULT_LINKSERVER_GDB_PORT, + help='gdb port to open, defaults to {}'.format( + DEFAULT_LINKSERVER_GDB_PORT)) + + parser.add_argument('--semihost-port', default=DEFAULT_LINKSERVER_SEMIHOST_PORT, + help='semihost port to open, defaults to the empty string ' + 'and runs a gdb server') + # keep this, we have to assume that the default 'commander' is on PATH + parser.add_argument('--linkserver', default=DEFAULT_LINKSERVER_EXE, + help=f'''LinkServer executable, default is + {DEFAULT_LINKSERVER_EXE}''') + # user may need to override settings. + parser.add_argument('--override', required=False, action='append', + help=f'''configuration overrides as defined bylinkserver. Example: /device/memory/0/location=0xcafecafe''') + + @classmethod + def do_create(cls, cfg, args): + + return LinkServerBinaryRunner(cfg, args.device, + linkserver=args.linkserver, + dt_flash=args.dt_flash, + erase=args.erase, + probe=args.probe, + semihost_port=args.semihost_port, + gdb_port=args.gdb_port, + override=args.override, + tui=args.tui, tool_opt=args.tool_opt) + + @property + def linkserver_version_str(self): + + if not hasattr(self, '_linkserver_version'): + linkserver_version_cmd=[self.linkserver, "-v"] + ls_output=self.check_output(linkserver_version_cmd) + self.linkserver_version = str(ls_output.split()[1].decode()) + + return self.linkserver_version + + def do_run(self, command, **kwargs): + + self.linkserver = self.require(self.linkserver) + self.logger.info(f'LinkServer: {self.linkserver}, version {self.linkserver_version_str}') + + if command == 'flash': + self.flash(**kwargs) + else: + linkserver_cmd = ([self.linkserver] + + ["gdbserver"] + + ["--probe", "#"+str(self.probe) ] + + ["--gdb-port", str(self.gdb_port )] + + ["--semihost-port", str(self.semihost_port) ] + + self.override_cli + + [self.device]) + + if command in ('debug', 'attach'): + if self.elf_name is None or not os.path.isfile(self.elf_name): + raise ValueError('Cannot debug; elf file required') + + gdb_cmd = ([self.gdb_cmd] + + self.tui_arg + + [self.elf_name] + + ['-ex', 'target remote {}:{}'.format(self.gdb_host, self.gdb_port)]) + + if command == 'debug': + gdb_cmd += [ '-ex', 'load', '-ex', 'monitor reset'] + + if command == 'attach': + linkserver_cmd += ['--attach'] + + self.run_server_and_client(linkserver_cmd, gdb_cmd) + + elif command == 'debugserver': + if self.gdb_host: + raise ValueError('Cannot run debugserver with --gdb-host') + + self.check_call(linkserver_cmd) + + def do_erase(self, **kwargs): + + linkserver_cmd = ([self.linkserver, "flash"] + ["--probe", "#"+str(self.probe)] + + [self.device] + ["erase"]) + self.logger.debug("flash erase command = " + str(linkserver_cmd)) + self.check_call(linkserver_cmd) + + def _build_override_cli(self): + + override_cli = [] + + if self.override is not None: + for ov in self.override: + override_cli = (override_cli + ["-o", str(ov)]) + + return override_cli + + def flash(self, **kwargs): + + linkserver_cmd = ([self.linkserver, "flash"] + ["--probe", "#"+str(self.probe)] + self.override_cli + [self.device]) + + if self.erase: + self.do_erase() + + if self.bin_name is not None and os.path.isfile(self.bin_name): + if self.dt_flash: + load_addr = self.flash_address_from_build_conf(self.build_conf) + else: + self.logger.critical("no load flash address could be found...") + raise RuntimeError("no load flash address could be found...") + + flash_cmd = (["load", "--addr", str(load_addr), self.bin_name]) + else: + err = 'Cannot flash; no bin ({}) file found.' + raise ValueError(err.format(self.bin_name)) + + # Flash the selected elf file + linkserver_cmd = linkserver_cmd + flash_cmd + self.logger.debug("flash command = " + str(linkserver_cmd)) + kwargs = {} + if not self.logger.isEnabledFor(logging.DEBUG): + kwargs['stderr'] = subprocess.DEVNULL + self.check_call(linkserver_cmd, **kwargs) diff --git a/scripts/west_commands/tests/test_imports.py b/scripts/west_commands/tests/test_imports.py index 49559567ec0d..774d4f7d7221 100644 --- a/scripts/west_commands/tests/test_imports.py +++ b/scripts/west_commands/tests/test_imports.py @@ -27,6 +27,7 @@ def test_runner_imports(): 'intel_adsp', 'intel_cyclonev', 'jlink', + 'linkserver', 'mdb-nsim', 'mdb-hw', 'misc-flasher', From 91353053ba3ca9527d701b5cb56af13709547c0b Mon Sep 17 00:00:00 2001 From: Yves Vandervennet Date: Wed, 17 May 2023 16:02:05 -0500 Subject: [PATCH 1614/2042] west: linkserver: adding support to NXP boards Support for the following platforms is provided with this commit: - mimxrt595 - mimxrt1060 - mimxrt1064 - lpc55s69. Support for more boards will be added with future PR's Notes: - the debug firmware of the board must be CMSIS-DAP/LPC-Link (latest revision). If your board is running the jlink firmware, linkserver fails to connect to the board - probes can be listed by running: $ LinkServer probes Signed-off-by: Yves Vandervennet --- boards/arm/lpcxpresso55s69/board.cmake | 6 +++++- boards/arm/lpcxpresso55s69/doc/index.rst | 10 ++++++++++ boards/arm/mimxrt1060_evk/board.cmake | 4 +++- boards/arm/mimxrt1060_evk/doc/index.rst | 9 +++++++++ boards/arm/mimxrt1064_evk/board.cmake | 4 +++- boards/arm/mimxrt1064_evk/doc/index.rst | 9 +++++++++ boards/arm/mimxrt595_evk/board.cmake | 8 +++++++- boards/arm/mimxrt595_evk/doc/index.rst | 9 +++++++++ 8 files changed, 55 insertions(+), 4 deletions(-) diff --git a/boards/arm/lpcxpresso55s69/board.cmake b/boards/arm/lpcxpresso55s69/board.cmake index 02f2982f8d16..21ed8e82672c 100644 --- a/boards/arm/lpcxpresso55s69/board.cmake +++ b/boards/arm/lpcxpresso55s69/board.cmake @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, NXP +# Copyright 2019, 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -10,6 +10,9 @@ if(CONFIG_BOARD_LPCXPRESSO55S69_CPU0 OR CONFIG_SECOND_CORE_MCUX) board_runner_args(jlink "--device=LPC55S69_M33_0") +board_runner_args(linkserver "--device=LPC55S69:LPCXpresso55S69") +board_runner_args(linkserver "--override=/device/memory/0/flash-driver=LPC55xx_S.cfx") +board_runner_args(linkserver "--override=/device/memory/0/location=0x10000000") elseif(CONFIG_BOARD_LPCXPRESSO55S69_CPU1) board_runner_args(jlink "--device=LPC55S69_M33_1") endif() @@ -18,3 +21,4 @@ board_runner_args(pyocd "--target=lpc55s69") include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/lpcxpresso55s69/doc/index.rst b/boards/arm/lpcxpresso55s69/doc/index.rst index 52bcb1499f18..1bd0ccfbae5c 100644 --- a/boards/arm/lpcxpresso55s69/doc/index.rst +++ b/boards/arm/lpcxpresso55s69/doc/index.rst @@ -43,6 +43,7 @@ For more information about the LPC55S69 SoC and LPCXPRESSO55S69 board, see: - `LPCXPRESSO55S69 Website`_ - `LPCXPRESSO55S69 User Guide`_ - `LPCXPRESSO55S69 Schematics`_ +- `LPCXPRESSO55S69 Debug Firmware`_ Supported Features ================== @@ -289,6 +290,12 @@ 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. +:ref:`lpclink2-cmsis-onboard-debug-probe` +----------------------------------------- + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your search path. + 2. To update the debug firmware, please follow the instructions on `LPCXPRESSO55S69 Debug Firmware` + :ref:`opensda-daplink-onboard-debug-probe` ------------------------------------------ @@ -392,6 +399,9 @@ should see the following message in the terminal: .. _LPCXPRESSO55S69 User Guide: https://www.nxp.com/webapp/Download?colCode=UM11158 +.. _LPCXPRESSO55S69 Debug Firmware: + https://www.nxp.com/docs/en/application-note/AN13206.pdf + .. _LPCXPRESSO55S69 Schematics: https://www.nxp.com/webapp/Download?colCode=LPC55S69-SCH diff --git a/boards/arm/mimxrt1060_evk/board.cmake b/boards/arm/mimxrt1060_evk/board.cmake index 2ef8740454a1..d3031f1542e3 100644 --- a/boards/arm/mimxrt1060_evk/board.cmake +++ b/boards/arm/mimxrt1060_evk/board.cmake @@ -1,11 +1,12 @@ # -# Copyright (c) 2018, NXP +# Copyright (c) 2018, 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # board_runner_args(pyocd "--target=mimxrt1060") board_runner_args(jlink "--device=MIMXRT1062xxx6A") +board_runner_args(linkserver "--device=MIMXRT1062xxxxA:EVK-MIMXRT1060") if ((${CONFIG_BOARD_MIMXRT1060_EVK}) OR (${CONFIG_BOARD_MIMXRT1060_EVKB})) board_runner_args(jlink "--loader=BankAddr=0x60000000&Loader=QSPI") @@ -15,3 +16,4 @@ 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) diff --git a/boards/arm/mimxrt1060_evk/doc/index.rst b/boards/arm/mimxrt1060_evk/doc/index.rst index e153d78f06b6..47f6b7132dbc 100644 --- a/boards/arm/mimxrt1060_evk/doc/index.rst +++ b/boards/arm/mimxrt1060_evk/doc/index.rst @@ -79,6 +79,7 @@ these references: - `MIMXRT1060-EVK Website`_ - `MIMXRT1060-EVK User Guide`_ - `MIMXRT1060-EVK Schematics`_ +- `MIMXRT1060-EVK Debug Firmware`_ Supported Features ================== @@ -315,6 +316,11 @@ 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. +.. _Using LinkServer: + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your search path. + 2. To update the debug firmware, please follow the instructions on `MIMXRT1060-EVK Debug Firmware` + .. _Using J-Link RT1060: Using J-Link @@ -429,6 +435,9 @@ connected to the EVK properly. See :ref:`Using J-Link RT1060` for more details. .. _MIMXRT1060-EVK User Guide: https://www.nxp.com/webapp/Download?colCode=MIMXRT10601064EKBHUG +.. _MIMXRT1060-EVK Debug Firmware: + https://www.nxp.com/docs/en/application-note/AN13206.pdf + .. _MIMXRT1060-EVK Schematics: https://www.nxp.com/webapp/Download?colCode=MIMXRT1060-EVK-DESIGNFILE-A3 diff --git a/boards/arm/mimxrt1064_evk/board.cmake b/boards/arm/mimxrt1064_evk/board.cmake index b7da66ef1d48..e637428a1c3b 100644 --- a/boards/arm/mimxrt1064_evk/board.cmake +++ b/boards/arm/mimxrt1064_evk/board.cmake @@ -1,11 +1,13 @@ # -# Copyright (c) 2018, NXP +# Copyright 2018, 2023 NXP # # SPDX-License-Identifier: Apache-2.0 # board_runner_args(pyocd "--target=mimxrt1064") board_runner_args(jlink "--device=MIMXRT1064") +board_runner_args(linkserver "--device=MIMXRT1064xxxxA:EVK-MIMXRT1064") include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/mimxrt1064_evk/doc/index.rst b/boards/arm/mimxrt1064_evk/doc/index.rst index 6b5f0064bd93..1dce1d44e9f5 100644 --- a/boards/arm/mimxrt1064_evk/doc/index.rst +++ b/boards/arm/mimxrt1064_evk/doc/index.rst @@ -80,6 +80,7 @@ these references: - `MIMXRT1064-EVK Quick Reference Guide`_ - `MIMXRT1064-EVK User Guide`_ - `MIMXRT1064-EVK Schematics`_ +- `MIMXRT1064-EVK Debug Firmware`_ Supported Features ================== @@ -318,6 +319,11 @@ 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. +.. _Using LinkServer: + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your search path. + 2. To update the debug firmware, please follow the instructions on `MIMXRT1064-EVK Debug Firmware` + .. _Using J-Link RT1064: Using J-Link @@ -439,6 +445,9 @@ details. .. _MIMXRT1064-EVK User Guide: https://www.nxp.com/docs/en/data-sheet/MIMXRT10601064EKBHUG.pdf +.. _MIMXRT1064-EVK Debug Firmware: + https://www.nxp.com/docs/en/application-note/AN13206.pdf + .. _MIMXRT1064-EVK Schematics: https://www.nxp.com/webapp/Download?colCode=i.MXRT160EVKDS&Parent_nodeId=1537930933174731284155&Parent_pageType=product diff --git a/boards/arm/mimxrt595_evk/board.cmake b/boards/arm/mimxrt595_evk/board.cmake index 83f8ffdfd6e6..5b26eacd3c9f 100644 --- a/boards/arm/mimxrt595_evk/board.cmake +++ b/boards/arm/mimxrt595_evk/board.cmake @@ -1,9 +1,15 @@ # -# Copyright (c) 2022, NXP +# Copyright 2022-2023 NXP # # SPDX-License-Identifier: Apache-2.0 # board_runner_args(jlink "--device=MIMXRT595S_M33" "--reset-after-load") +board_runner_args(linkserver "--device=MIMXRT595S:EVK-MIMXRT595") +board_runner_args(linkserver "--override=/device/memory/5/flash-driver=MIMXRT500_SFDP_MXIC_OSPI_S.cfx") +board_runner_args(linkserver "--override=/device/memory/5/location=0x18000000") + + include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index c5c215b41bd9..a21b97459382 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -52,6 +52,7 @@ these references: - `MIMXRT595-EVK Website`_ - `MIMXRT595-EVK User Guide`_ - `MIMXRT595-EVK Schematics`_ +- `MIMXRT595-EVK Debug Firmware`_ Supported Features ================== @@ -206,6 +207,11 @@ configured by default to use the LPC-Link2. See :ref:`jlink-external-debug-probe` for more information. + .. group-tab:: Linkserver + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your search path. + 2. To update the debug firmware, please follow the instructions on `MIMXRT595-EVK Debug Firmware` + Configuring a Console ===================== @@ -291,6 +297,9 @@ steps: .. _MIMXRT595-EVK User Guide: https://www.nxp.com/webapp/Download?colCode=MIMXRT595EVKHUG +.. _MIMXRT595-EVK Debug Firmware: + https://www.nxp.com/docs/en/application-note/AN13206.pdf + .. _MIMXRT595-EVK Schematics: https://www.nxp.com/downloads/en/schematics/MIMXRT595-EVK-DESIGN-FILES.zip From 343772213a0d0480438a72c43358b06f197fe1df Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 17 Jul 2023 16:47:21 -0700 Subject: [PATCH 1615/2042] serial: CONFIG_UART_USE_RUNTIME_CONFIGURE on API for cfg funcs This adds the CONFIG_UART_USE_RUNTIME_CONFIGURE guard to disable the API function pointers if the kconfig is not enabled. Both .configure and .config_get should only be usable if runtime (re-)configuration of UART is needed. Ifdef guards are added to drivers previously lacking this guard. Signed-off-by: Daniel Leung --- drivers/serial/uart_altera.c | 4 ++-- drivers/serial/uart_b91.c | 4 ++++ drivers/serial/uart_emul.c | 4 ++++ drivers/serial/uart_handlers.c | 2 ++ drivers/serial/uart_native_tty.c | 2 ++ drivers/serial/uart_neorv32.c | 2 ++ include/zephyr/drivers/uart.h | 16 ++++++++++++++++ 7 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_altera.c b/drivers/serial/uart_altera.c index 4d1160fe6cd2..18ef231fb47e 100644 --- a/drivers/serial/uart_altera.c +++ b/drivers/serial/uart_altera.c @@ -350,7 +350,6 @@ static int uart_altera_configure(const struct device *dev, return ret_val; } -#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ /** * @brief Get UART configuration and stores in *cfg_out. @@ -377,6 +376,7 @@ static int uart_altera_config_get(const struct device *dev, *cfg_out = data->uart_cfg; return 0; } +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN /** @@ -907,8 +907,8 @@ static const struct uart_driver_api uart_altera_driver_api = { .err_check = uart_altera_err_check, #ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = uart_altera_configure, -#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ .config_get = uart_altera_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_altera_fifo_fill, diff --git a/drivers/serial/uart_b91.c b/drivers/serial/uart_b91.c index 2573434f34f7..cb2d7ebd1904 100644 --- a/drivers/serial/uart_b91.c +++ b/drivers/serial/uart_b91.c @@ -240,6 +240,7 @@ static void uart_b91_irq_handler(const struct device *dev) #endif } +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE /* API implementation: configure */ static int uart_b91_configure(const struct device *dev, const struct uart_config *cfg) @@ -299,6 +300,7 @@ static int uart_b91_config_get(const struct device *dev, return 0; } +#endif /* API implementation: driver initialization */ static int uart_b91_driver_init(const struct device *dev) @@ -523,8 +525,10 @@ static const struct uart_driver_api uart_b91_driver_api = { .poll_in = uart_b91_poll_in, .poll_out = uart_b91_poll_out, .err_check = uart_b91_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = uart_b91_configure, .config_get = uart_b91_config_get, +#endif #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = uart_b91_fifo_fill, .fifo_read = uart_b91_fifo_read, diff --git a/drivers/serial/uart_emul.c b/drivers/serial/uart_emul.c index 1fd03068ffc0..4cb50731f9c0 100644 --- a/drivers/serial/uart_emul.c +++ b/drivers/serial/uart_emul.c @@ -81,6 +81,7 @@ int uart_emul_err_check(const struct device *dev) return 0; } +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE int uart_emul_configure(const struct device *dev, const struct uart_config *cfg) { struct uart_emul_data *drv_data = dev->data; @@ -96,12 +97,15 @@ int uart_emul_config_get(const struct device *dev, struct uart_config *cfg) memcpy(cfg, &drv_data->cfg, sizeof(struct uart_config)); return 0; } +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ static const struct uart_driver_api uart_emul_api = { .poll_in = uart_emul_poll_in, .poll_out = uart_emul_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .config_get = uart_emul_config_get, .configure = uart_emul_configure, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ .err_check = uart_emul_err_check }; diff --git a/drivers/serial/uart_handlers.c b/drivers/serial/uart_handlers.c index b57fc8e063e9..1dd4dd78f104 100644 --- a/drivers/serial/uart_handlers.c +++ b/drivers/serial/uart_handlers.c @@ -58,6 +58,7 @@ static inline void z_vrfy_uart_poll_out_u16(const struct device *dev, } #include +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE static inline int z_vrfy_uart_config_get(const struct device *dev, struct uart_config *cfg) { @@ -77,6 +78,7 @@ static inline int z_vrfy_uart_configure(const struct device *dev, return z_impl_uart_configure(dev, cfg); } #include +#endif #ifdef CONFIG_UART_ASYNC_API /* callback_set() excluded as we don't allow ISR callback installation from diff --git a/drivers/serial/uart_native_tty.c b/drivers/serial/uart_native_tty.c index 3ca5a879c56b..2027279d440b 100644 --- a/drivers/serial/uart_native_tty.c +++ b/drivers/serial/uart_native_tty.c @@ -379,7 +379,9 @@ static int native_tty_serial_init(const struct device *dev) static struct uart_driver_api native_tty_uart_driver_api = { .poll_out = native_tty_uart_poll_out, .poll_in = native_tty_uart_poll_in, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = native_tty_configure, +#endif }; #define NATIVE_TTY_INSTANCE(inst) \ diff --git a/drivers/serial/uart_neorv32.c b/drivers/serial/uart_neorv32.c index 668f05305ca3..547d1f46efb4 100644 --- a/drivers/serial/uart_neorv32.c +++ b/drivers/serial/uart_neorv32.c @@ -440,8 +440,10 @@ static int neorv32_uart_pm_action(const struct device *dev, static const struct uart_driver_api neorv32_uart_driver_api = { .poll_in = neorv32_uart_poll_in, .poll_out = neorv32_uart_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE .configure = neorv32_uart_configure, .config_get = neorv32_uart_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ #ifdef CONFIG_UART_INTERRUPT_DRIVEN .fifo_fill = neorv32_uart_fifo_fill, .fifo_read = neorv32_uart_fifo_read, diff --git a/include/zephyr/drivers/uart.h b/include/zephyr/drivers/uart.h index 01ee29368b01..8604d3fa543a 100644 --- a/include/zephyr/drivers/uart.h +++ b/include/zephyr/drivers/uart.h @@ -377,10 +377,12 @@ __subsystem struct uart_driver_api { /** Console I/O function */ int (*err_check)(const struct device *dev); +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE /** UART configuration functions */ int (*configure)(const struct device *dev, const struct uart_config *cfg); int (*config_get)(const struct device *dev, struct uart_config *cfg); +#endif #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -630,6 +632,7 @@ static inline void z_impl_uart_poll_out_u16(const struct device *dev, * @retval -errno Negative errno code in case of failure. * @retval -ENOSYS If configuration is not supported by device * or driver does not support setting configuration in runtime. + * @retval -ENOTSUP If API is not enabled. */ __syscall int uart_configure(const struct device *dev, const struct uart_config *cfg); @@ -637,6 +640,7 @@ __syscall int uart_configure(const struct device *dev, static inline int z_impl_uart_configure(const struct device *dev, const struct uart_config *cfg) { +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE const struct uart_driver_api *api = (const struct uart_driver_api *)dev->api; @@ -644,6 +648,11 @@ static inline int z_impl_uart_configure(const struct device *dev, return -ENOSYS; } return api->configure(dev, cfg); +#else + ARG_UNUSED(dev); + ARG_UNUSED(cfg); + return -ENOTSUP; +#endif } /** @@ -658,6 +667,7 @@ static inline int z_impl_uart_configure(const struct device *dev, * @retval 0 If successful. * @retval -errno Negative errno code in case of failure. * @retval -ENOSYS If driver does not support getting current configuration. + * @retval -ENOTSUP If API is not enabled. */ __syscall int uart_config_get(const struct device *dev, struct uart_config *cfg); @@ -665,6 +675,7 @@ __syscall int uart_config_get(const struct device *dev, static inline int z_impl_uart_config_get(const struct device *dev, struct uart_config *cfg) { +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE const struct uart_driver_api *api = (const struct uart_driver_api *)dev->api; @@ -673,6 +684,11 @@ static inline int z_impl_uart_config_get(const struct device *dev, } return api->config_get(dev, cfg); +#else + ARG_UNUSED(dev); + ARG_UNUSED(cfg); + return -ENOTSUP; +#endif } /** From c719b70136736700f206bac35393ca5a4c6cb47b Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 28 Jun 2023 09:56:18 -0700 Subject: [PATCH 1616/2042] tests: kernel/smp: mark torture test as skipped if factor is 0 If CONFIG_SMP_TEST_RUN_FACTOR is zero, the switch torture test is effectively not doing anything as the k_sleep() below is not going to sleep at all, and all created threads are being terminated (almost) immediately after creation. So if run factor is zero, mark the test as skipped. Signed-off-by: Daniel Leung --- tests/kernel/smp/src/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/kernel/smp/src/main.c b/tests/kernel/smp/src/main.c index 0adf7052c986..246c9d13311d 100644 --- a/tests/kernel/smp/src/main.c +++ b/tests/kernel/smp/src/main.c @@ -1118,6 +1118,19 @@ ZTEST(smp, test_smp_switch_torture) { unsigned int num_threads = arch_num_cpus(); + if (CONFIG_SMP_TEST_RUN_FACTOR == 0) { + /* If CONFIG_SMP_TEST_RUN_FACTOR is zero, + * the switch torture test is effectively + * not doing anything as the k_sleep() + * below is not going to sleep at all, + * and all created threads are being + * terminated (almost) immediately after + * creation. So if run factor is zero, + * mark the test as skipped. + */ + ztest_test_skip(); + } + for (uintptr_t i = 0; i < num_threads; i++) { k_poll_signal_init(&tsignal[i]); k_poll_event_init(&tevent[i], K_POLL_TYPE_SIGNAL, From fd3a8ee209fe9a338c2c1a57e0be0eab73bb264e Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 27 Jun 2023 13:46:58 -0700 Subject: [PATCH 1617/2042] tests: kernel/sys_mutex: sleep a bit for private_mutex to lock With SMP, the private_mutex may not be locked fast enough by thread_12 after the thread creation as it might take longer for a thread to start running the entry function, resulting in test failure when the main test thread goes into locking it again. So give it a bit more delay after thread creation so thread_12 has a chance to lock the private_mutex. Signed-off-by: Daniel Leung --- tests/kernel/mutex/sys_mutex/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/kernel/mutex/sys_mutex/src/main.c b/tests/kernel/mutex/sys_mutex/src/main.c index 4c301a4c6080..b335e80f53e5 100644 --- a/tests/kernel/mutex/sys_mutex/src/main.c +++ b/tests/kernel/mutex/sys_mutex/src/main.c @@ -397,7 +397,7 @@ ZTEST_USER_OR_NOT(mutex_complex, test_mutex) k_thread_create(&thread_12_thread_data, thread_12_stack_area, STACKSIZE, (k_thread_entry_t)thread_12, NULL, NULL, NULL, K_PRIO_PREEMPT(12), PARTICIPANT_THREAD_OPTIONS, K_NO_WAIT); - k_sleep(K_MSEC(1)); /* Give thread_12 a chance to block on the mutex */ + k_sleep(K_MSEC(5)); /* Give thread_12 a chance to block on the mutex */ sys_mutex_unlock(&private_mutex); sys_mutex_unlock(&private_mutex); /* thread_12 should now have lock */ From 6c7cc1f6836806b0a6c1c6b19e6f792b072fbd44 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Fri, 16 Jun 2023 12:40:13 -0700 Subject: [PATCH 1618/2042] tests: kernel/mp: extend to more CPUs This extends the multi-processor start tests to more than 2 CPUs. Signed-off-by: Daniel Leung --- tests/kernel/mp/src/main.c | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/tests/kernel/mp/src/main.c b/tests/kernel/mp/src/main.c index 503e637605c6..baec544f20a4 100644 --- a/tests/kernel/mp/src/main.c +++ b/tests/kernel/mp/src/main.c @@ -14,13 +14,13 @@ BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS > 1); -#define CPU1_STACK_SIZE 1024 +#define CPU_STACK_SIZE 1024 -K_THREAD_STACK_DEFINE(cpu1_stack, CPU1_STACK_SIZE); +K_THREAD_STACK_ARRAY_DEFINE(cpu_stacks, CONFIG_MP_MAX_NUM_CPUS, CPU_STACK_SIZE); int cpu_arg; -volatile int cpu_running; +volatile int cpu_running[CONFIG_MP_MAX_NUM_CPUS]; /** * @brief Tests for multi processing @@ -32,11 +32,16 @@ volatile int cpu_running; * @{ * @} */ -FUNC_NORETURN void cpu1_fn(void *arg) +FUNC_NORETURN void cpu_fn(void *arg) { - zassert_true(arg == &cpu_arg && *(int *)arg == 12345, "wrong arg"); + zassert_true(arg == &cpu_arg, "mismatched arg"); - cpu_running = 1; + int cpu_id = (*(int *)arg) / 12345; + int mod = (*(int *)arg) % 12345; + + zassert_true(mod == 0, "wrong arg"); + + cpu_running[cpu_id] = 1; while (1) { } @@ -93,14 +98,28 @@ FUNC_NORETURN void cpu1_fn(void *arg) */ ZTEST(multiprocessing, test_mp_start) { - cpu_arg = 12345; + for (int i = 1; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + int wait_count; - arch_start_cpu(1, cpu1_stack, CPU1_STACK_SIZE, cpu1_fn, &cpu_arg); + TC_PRINT("Starting CPU #%d...\n", i); - while (!cpu_running) { - } + cpu_arg = 12345 * i; + + arch_start_cpu(i, cpu_stacks[i], CPU_STACK_SIZE, cpu_fn, &cpu_arg); - zassert_true(cpu_running, "cpu1 didn't start"); + /* Wait for about 5 (500 * 10ms) seconds for CPU to start. */ + wait_count = 500; + while (!cpu_running[i]) { + k_busy_wait(10 * USEC_PER_MSEC); + + wait_count--; + if (wait_count < 0) { + break; + } + } + + zassert_true(cpu_running[i], "cpu #%d didn't start", i); + } } ZTEST_SUITE(multiprocessing, NULL, NULL, NULL, NULL, NULL); From c094bd688a26153627ed7eac6720a6222baf43bf Mon Sep 17 00:00:00 2001 From: Armin Brauns Date: Fri, 23 Jun 2023 08:10:46 +0000 Subject: [PATCH 1619/2042] drivers: mcp23xxx: fix deadlock in interrupt callbacks Interrupt callbacks may want to configure GPIO pins on the port expander, e.g. to change the polarity of a level interrupt. This would cause a deadlock because the callback handler would still be holding the lock. Signed-off-by: Armin Brauns --- drivers/gpio/gpio_mcp23xxx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio_mcp23xxx.c b/drivers/gpio/gpio_mcp23xxx.c index 38d7ea26da3a..8d20117b0467 100644 --- a/drivers/gpio/gpio_mcp23xxx.c +++ b/drivers/gpio/gpio_mcp23xxx.c @@ -408,7 +408,7 @@ static void mcp23xxx_work_handler(struct k_work *work) ret = read_port_regs(dev, REG_INTF, &intf); if (ret != 0) { LOG_ERR("Failed to read INTF"); - goto done; + goto fail; } if (!intf) { @@ -416,7 +416,7 @@ static void mcp23xxx_work_handler(struct k_work *work) * handler had a chance to run */ LOG_ERR("Spurious interrupt"); - goto done; + goto fail; } uint16_t intcap; @@ -425,7 +425,7 @@ static void mcp23xxx_work_handler(struct k_work *work) ret = read_port_regs(dev, REG_INTCAP, &intcap); if (ret != 0) { LOG_ERR("Failed to read INTCAP"); - goto done; + goto fail; } /* mcp23xxx does not support single-edge interrupts in hardware, filter them out manually */ @@ -434,8 +434,11 @@ static void mcp23xxx_work_handler(struct k_work *work) intf &= level_ints | (intcap & drv_data->rising_edge_ints) | (~intcap & drv_data->falling_edge_ints); + k_sem_give(&drv_data->lock); gpio_fire_callbacks(&drv_data->callbacks, dev, intf); -done: + return; + +fail: k_sem_give(&drv_data->lock); } From d026ce898a6f7f6e50e4536e44a99fb761d6fb67 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 22 Jul 2023 14:04:25 +0100 Subject: [PATCH 1620/2042] Revert "doc: release-notes: Update tf-m and mbed TLS" This reverts commit a64f430d6f1338746e8c196a3fefffc26df0414b. Signed-off-by: Fabio Baltieri --- doc/releases/release-notes-3.5.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index ba78018e6905..6837ae0e2c53 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -266,19 +266,12 @@ HALs MCUboot ******* -Mbed TLS -******** - -* Update to Mbed TLS 3.4.0. - Storage ******* Trusted Firmware-M ****************** -* Update to TF-M 1.8.0 - Trusted Firmware-A ****************** From 0bfe3cc2d051d1c2e1e4a4f65c4ac36284b5c0bf Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 22 Jul 2023 14:04:28 +0100 Subject: [PATCH 1621/2042] Revert "manifest: Upgrade to trusted-firmware-m 1.8.0" This reverts commit a30dbd5fe8636b3a543198259799bf47982951fc. It's causing some breakage in the main CI run. Signed-off-by: Fabio Baltieri --- modules/mbedtls/CMakeLists.txt | 2 +- modules/trusted-firmware-m/CMakeLists.txt | 2 ++ modules/trusted-firmware-m/interface/interface.c | 2 +- west.yml | 6 +++--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index 70636b5d5fd2..aee2f78bd110 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -52,6 +52,7 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher_wrap.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cmac.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/code_share.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ctr_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/debug.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/des.c @@ -76,7 +77,6 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_reader.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_trace.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/poly1305.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_util.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ripemd160.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/rsa_alt_helpers.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/rsa.c diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index 0c01858f34d5..74020af556d6 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -214,6 +214,7 @@ if (CONFIG_BUILD_WITH_TFM) ${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_psa_ns_connection_api.c # Specific to nordic_nrf platform ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c @@ -408,6 +409,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_ifdef(CONFIG_TFM_CONNECTION_BASED_SERVICE_API ${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_connection_api.c) zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c) if(CONFIG_SOC_FAMILY_NRF) diff --git a/modules/trusted-firmware-m/interface/interface.c b/modules/trusted-firmware-m/interface/interface.c index 9cbcf5636c65..66100b9e62ac 100644 --- a/modules/trusted-firmware-m/interface/interface.c +++ b/modules/trusted-firmware-m/interface/interface.c @@ -74,7 +74,7 @@ int32_t tfm_ns_interface_dispatch(veneer_fn fn, return result; } -uint32_t tfm_ns_interface_init(void) +enum tfm_status_e tfm_ns_interface_init(void) { /* * The static K_MUTEX_DEFINE handles mutex initialization, diff --git a/west.yml b/west.yml index 4aae6651d573..f0a69af00ab4 100644 --- a/west.yml +++ b/west.yml @@ -266,7 +266,7 @@ manifest: revision: 8e303c264fc21c2116dc612658003a22e933124d path: modules/lib/lz4 - name: mbedtls - revision: c38dc78d9a8dcbe43b898cc1171ab33ba3e6fc26 + revision: 6e7841e5a08eb5da3c82dbc8b6b6d82ae4b7d2a0 path: modules/crypto/mbedtls groups: - crypto @@ -321,7 +321,7 @@ manifest: groups: - debug - name: trusted-firmware-m - revision: bad0696f388d6f713742c5da8dfce426ec17ef20 + revision: 79a6115d3a8d0e04864ae8156c1dc8532b750f5a path: modules/tee/tf-m/trusted-firmware-m groups: - tee @@ -331,7 +331,7 @@ manifest: groups: - tee - name: tf-m-tests - revision: a878426da78fbd1486dfc29d6c6b82be4ee79e72 + revision: 0f80a65193ddbbe3f0ac38b33b07b26138c11fa7 path: modules/tee/tf-m/tf-m-tests groups: - tee From 177638f11dd2a8282acad16abf40cef4abf917d9 Mon Sep 17 00:00:00 2001 From: cyliang tw Date: Fri, 21 Jul 2023 15:08:38 +0800 Subject: [PATCH 1622/2042] doc: releases: Add release notes for NuMaker M46x Add release notes for NuMaker M46x platform in 3.5 release. Signed-off-by: cyliang tw --- doc/releases/release-notes-3.5.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index 6837ae0e2c53..ea22236df2a4 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -78,6 +78,8 @@ Boards & SoC Support * Added support for these SoC series: + * Nuvoton NuMaker M46x series + * Removed support for these SoC series: * Made these changes in other SoC series: @@ -86,6 +88,8 @@ Boards & SoC Support * Added support for these ARM boards: + * Nuvoton NuMaker Platform M467 + * Added support for these ARM64 boards: * Added support for these RISC-V boards: @@ -136,6 +140,8 @@ Drivers and Sensors * Clock control + * Added support for Nuvoton NuMaker M46x + * Counter * Crypto @@ -163,6 +169,7 @@ Drivers and Sensors * Introduce npcx flash driver that supports two or more spi nor flashes via a single Flash Interface Unit (FIU) module and Direct Read Access (DRA) mode for better performance. + * Added support for Nuvoton NuMaker M46x embedded flash * FPGA @@ -170,6 +177,8 @@ Drivers and Sensors * GPIO + * Added support for Nuvoton NuMaker M46x + * hwinfo * I2C @@ -200,6 +209,8 @@ Drivers and Sensors * Pin control + * Added support for Nuvoton NuMaker M46x + * PWM * Power domain @@ -208,12 +219,16 @@ Drivers and Sensors * Reset + * Added support for Nuvoton NuMaker M46x + * SDHC * Sensor * Serial + * Added support for Nuvoton NuMaker M46x + * SPI * Remove npcx spi driver implemented by Flash Interface Unit (FIU) module. @@ -263,6 +278,10 @@ Libraries / Subsystems HALs **** +* Nuvoton + + * Added Nuvoton NuMaker M46x + MCUboot ******* From 49a97540dc6e8f52113434511fdd44d4647ba5a4 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Fri, 23 Jun 2023 13:23:46 -0500 Subject: [PATCH 1623/2042] rtio: Use an atomic completion counter Rather than looking at the pool of completions for spinning use an atomic counter of total completions ever done. The relative number of completions being waited on by rtio_submit may then always be correctly done. Prior to this a race was possible, and understood, as rtio_cqe_consumable was a likely but not guaranteed count of completions. Sure enough on an SMP system the likely count was ahead of the actual available completions and a race was caught by the simple test case. Signed-off-by: Tom Burdick --- include/zephyr/rtio/rtio.h | 22 ++++++++----------- .../subsys/rtio/rtio_api/src/test_rtio_api.c | 10 ++++++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index 8845fa097faf..c617161df540 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -354,6 +354,9 @@ struct rtio { struct k_sem *consume_sem; #endif + /* Total number of completions */ + atomic_t cq_count; + /* Number of completions that were unable to be submitted with results * due to the cq spsc being full */ @@ -761,6 +764,7 @@ static inline void rtio_block_pool_free(struct rtio_block_pool *pool, void *buf, IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, (.submit_sem = &_submit_sem_##name,)) \ IF_ENABLED(CONFIG_RTIO_SUBMIT_SEM, (.submit_count = 0,)) \ IF_ENABLED(CONFIG_RTIO_CONSUME_SEM, (.consume_sem = &_consume_sem_##name,)) \ + .cq_count = ATOMIC_INIT(0), \ .xcqcnt = ATOMIC_INIT(0), \ .sqe_pool = _sqe_pool, \ .cqe_pool = _cqe_pool, \ @@ -813,18 +817,6 @@ static inline uint32_t rtio_sqe_acquirable(struct rtio *r) return r->sqe_pool->pool_free; } -/** - * @brief Count of likely, but not gauranteed, consumable completion queue events - * - * @param r RTIO context - * - * @return Likely count of consumable completion queue events - */ -static inline uint32_t rtio_cqe_consumable(struct rtio *r) -{ - return (r->cqe_pool->pool_size - r->cqe_pool->pool_free); -} - /** * @brief Get the next sqe in the transaction * @@ -1148,6 +1140,8 @@ static inline void rtio_cqe_submit(struct rtio *r, int result, void *userdata, u cqe->flags = flags; rtio_cqe_produce(r, cqe); } + + atomic_inc(&r->cq_count); #ifdef CONFIG_RTIO_SUBMIT_SEM if (r->submit_count > 0) { r->submit_count--; @@ -1425,6 +1419,8 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count) k_sem_reset(r->submit_sem); r->submit_count = wait_count; } +#else + uintptr_t cq_count = atomic_get(&r->cq_count) + wait_count; #endif /* Submit the queue to the executor which consumes submissions @@ -1444,7 +1440,7 @@ static inline int z_impl_rtio_submit(struct rtio *r, uint32_t wait_count) "semaphore was reset or timed out while waiting on completions!"); } #else - while (rtio_cqe_consumable(r) < wait_count) { + while (atomic_get(&r->cq_count) < cq_count) { Z_SPIN_DELAY(10); k_yield(); } diff --git a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c index 626f5e3abda8..05fcb724db1d 100644 --- a/tests/subsys/rtio/rtio_api/src/test_rtio_api.c +++ b/tests/subsys/rtio/rtio_api/src/test_rtio_api.c @@ -117,6 +117,7 @@ void test_rtio_chain_(struct rtio *r) uint32_t userdata[4] = {0, 1, 2, 3}; struct rtio_sqe *sqe; struct rtio_cqe *cqe; + uintptr_t cq_count = atomic_get(&r->cq_count); for (int i = 0; i < 4; i++) { sqe = rtio_sqe_acquire(r); @@ -131,10 +132,11 @@ void test_rtio_chain_(struct rtio *r) sqe->flags = 0; TC_PRINT("submitting\n"); + res = rtio_submit(r, 4); TC_PRINT("checking cq\n"); zassert_ok(res, "Should return ok from rtio_execute"); - zassert_equal(rtio_cqe_consumable(r), 4, "Should have 4 pending completions"); + zassert_equal(atomic_get(&r->cq_count) - cq_count, 4, "Should have 4 pending completions"); for (int i = 0; i < 4; i++) { cqe = rtio_cqe_consume(r); @@ -527,6 +529,7 @@ void test_rtio_transaction_(struct rtio *r) struct rtio_sqe *sqe; struct rtio_cqe *cqe; bool seen[2] = { 0 }; + uintptr_t cq_count = atomic_get(&r->cq_count); sqe = rtio_sqe_acquire(r); zassert_not_null(sqe, "Expected a valid sqe"); @@ -551,9 +554,10 @@ void test_rtio_transaction_(struct rtio *r) TC_PRINT("submitting userdata 0 %p, userdata 1 %p\n", &userdata[0], &userdata[1]); res = rtio_submit(r, 4); - TC_PRINT("checking cq, completions available %u\n", rtio_cqe_consumable(r)); + TC_PRINT("checking cq, completions available, count at start %lu, current count %lu\n", + cq_count, atomic_get(&r->cq_count)); zassert_ok(res, "Should return ok from rtio_execute"); - zassert_equal(rtio_cqe_consumable(r), 4, "Should have 4 pending completions"); + zassert_equal(atomic_get(&r->cq_count) - cq_count, 4, "Should have 4 pending completions"); for (int i = 0; i < 4; i++) { TC_PRINT("consume %d\n", i); From 63f718f9b83d7ff40dc3a81f8ec348ac4e4630b0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:27:06 +0530 Subject: [PATCH 1624/2042] Bluetooth: Controller: Fix coverity issue 318648 [Coverity CID: 318648] Explicit null dereferenced in subsys/bluetooth/controller/ll_sw/ull_scan_aux.c Fixes #59002. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_scan_aux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index 057d25a3b535..8758a677c8af 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -591,6 +591,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) /* Switching to ULL scheduling to receive auxiliary PDUs */ if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || lll) { + LL_ASSERT(scan); + /* Do not ULL schedule if scan disable requested */ if (unlikely(scan->is_stop)) { goto ull_scan_aux_rx_flush; @@ -724,6 +726,8 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * immediately since we are in sync context. */ if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || aux->rx_last) { + LL_ASSERT(scan); + /* If scan is being disabled, rx could already be * enqueued before coming here to ull_scan_aux_rx_flush. * Check if rx not the last in the list of received PDUs From b8546150a30c6a11863397b56fd6048af2297116 Mon Sep 17 00:00:00 2001 From: Lucas Mathias Balling Date: Thu, 13 Jul 2023 07:54:46 +0200 Subject: [PATCH 1625/2042] Bluetooth: Controller: Added ISO CH feature bit check in le_create_cis Check that the Isochronous Channels (Host Support) feature bit is set before creating a CIS. Signed-off-by: Lucas Mathias Balling --- subsys/bluetooth/controller/hci/hci.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 92f1456bff4b..5e4fee9ae4a1 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -2121,6 +2121,15 @@ static void le_create_cis(struct net_buf *buf, struct net_buf **evt) uint8_t status; uint8_t i; + /* + * Only create a CIS if the Isochronous Channels (Host Support) feature bit + * is set. Refer to BT Spec v5.4 Vol 6 Part B Section 4.6.33.1. + */ + if (!(ll_feat_get() & BIT64(BT_LE_FEAT_BIT_ISO_CHANNELS))) { + *evt = cmd_status(BT_HCI_ERR_CMD_DISALLOWED); + return; + } + /* * Creating new CISes is disallowed until all previous CIS * established events have been generated From 9506c65db1fb8d1f0038b8e78304d5e4bea35a4a Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Fri, 14 Jul 2023 09:56:23 +0200 Subject: [PATCH 1626/2042] manifest: Update west manifest to add LVGL shell support Updates the west manifest to add an LVGL shell with initial memory statistics and monkey testing support. Signed-off-by: Fabian Blatz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f0a69af00ab4..ef4cef239b5b 100644 --- a/west.yml +++ b/west.yml @@ -260,7 +260,7 @@ manifest: revision: ce57712f3e426bbbb13acaec97b45369f716f43a path: modules/lib/loramac-node - name: lvgl - revision: f7cf01d413aa9e76f376e25aa7b5c08dfdbc3c24 + revision: 5da257f782a8f9c6e265bdc60ebc2a93fdee24de path: modules/lib/gui/lvgl - name: lz4 revision: 8e303c264fc21c2116dc612658003a22e933124d From a8b103e4ad13bbfaab1abd9160977fd95a264ec1 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Wed, 19 Jul 2023 15:08:52 +0200 Subject: [PATCH 1627/2042] samples: lvgl: Enable lvgl shell Activate the lvgl shell with memory statistics and monkey testing support for the lvgl sample. Signed-off-by: Fabian Blatz --- samples/subsys/display/lvgl/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samples/subsys/display/lvgl/prj.conf b/samples/subsys/display/lvgl/prj.conf index 8ac5276a02d7..87a03f57cc05 100644 --- a/samples/subsys/display/lvgl/prj.conf +++ b/samples/subsys/display/lvgl/prj.conf @@ -1,10 +1,12 @@ CONFIG_LV_Z_MEM_POOL_NUMBER_BLOCKS=8 +CONFIG_LV_Z_SHELL=y CONFIG_MAIN_STACK_SIZE=2048 CONFIG_DISPLAY=y CONFIG_DISPLAY_LOG_LEVEL_ERR=y CONFIG_LOG=y +CONFIG_SHELL=y CONFIG_LVGL=y CONFIG_LV_MEM_CUSTOM=y @@ -12,4 +14,5 @@ CONFIG_LV_USE_LOG=y CONFIG_LV_USE_LABEL=y CONFIG_LV_USE_BTN=y CONFIG_LV_USE_IMG=y +CONFIG_LV_USE_MONKEY=y CONFIG_LV_FONT_MONTSERRAT_14=y From 20021abf0a1afc4e81b497531cf194a4b1271a59 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 17 Jul 2023 16:35:07 -0700 Subject: [PATCH 1628/2042] serial: ns16550: check return of clock_control_get_rate() This adds a check of the return of clock_control_get_rate(), and returns error in uart_configure() if unsuccessful in getting clock rate. Fixes #60478 Signed-off-by: Daniel Leung --- drivers/serial/uart_ns16550.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index 885c38389280..da5bd79fa530 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -458,8 +458,12 @@ static int uart_ns16550_configure(const struct device *dev, goto out; } - clock_control_get_rate(dev_cfg->clock_dev, dev_cfg->clock_subsys, - &pclk); + if (clock_control_get_rate(dev_cfg->clock_dev, + dev_cfg->clock_subsys, + &pclk) != 0) { + ret = -EINVAL; + goto out; + } } set_baud_rate(dev, cfg->baudrate, pclk); From 80f079a2cd1d1ff61e45cc91de738f05180a4cc0 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 18 Jul 2023 10:06:10 -0700 Subject: [PATCH 1629/2042] pcie: host: guard include of ACPICA header file This puts a ifdef guard around the inclusion of ACPICA header file. The ACPICA module is not active unless CONFIG_ACPI is also enabled so we should not be using that header without CONFIG_ACPI also being enabled. This was discovered by Coverity. Fixes #60484 Signed-off-by: Daniel Leung --- drivers/pcie/host/pcie.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index 89f05ac1238e..9efaf454214d 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -14,7 +14,10 @@ LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); #include #include #include + +#ifdef CONFIG_ACPI #include +#endif #if CONFIG_PCIE_MSI #include @@ -287,11 +290,11 @@ unsigned int pcie_alloc_irq(pcie_bdf_t bdf) irq >= CONFIG_MAX_IRQ_LINES || arch_irq_is_used(irq)) { - if (IS_ENABLED(CONFIG_ACPI)) { - irq = acpi_legacy_irq_get(bdf); - } else { - irq = arch_irq_allocate(); - } +#ifdef CONFIG_ACPI + irq = acpi_legacy_irq_get(bdf); +#else + irq = arch_irq_allocate(); +#endif if (irq == UINT_MAX) { return PCIE_CONF_INTR_IRQ_NONE; From 878d15cf94d3489aa1d3053fa9202c706678e28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Storr=C3=B8?= Date: Wed, 19 Jul 2023 11:14:35 +0200 Subject: [PATCH 1630/2042] Bluetooth: Mesh: Align handling of seg_ack to spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the handling of incoming seg ack messages to comply with the mesh protocol specification, section 3.5.3.3.2 and section 3.5.3.3.3. Previous implementation did not restart the retransmission timer unless the incoming ack contained at least one segment newly marked as acknowledged. According to the spec, the timer should be restated regardless. The implementation depends on the retransmission timer to end the transmission early if there was no more retransmission attempts. Checks have been added to ensure that this now happens immediately. Signed-off-by: Anders Storrø --- subsys/bluetooth/mesh/transport.c | 48 +++++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index 4cacf8d526c8..ece71a635f44 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -255,6 +255,7 @@ static void seg_tx_reset(struct seg_tx *tx) tx->nack_count = 0; tx->seg_send_started = 0; + tx->ack_received = 0; if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IVU_PENDING)) { LOG_DBG("Proceeding with pending IV Update"); @@ -918,27 +919,36 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, /* If transmission is not in progress it means * that Retransmission Timer is running */ - if (new_seg_ack) { - if (tx->seg_o == 0) { - uint32_t delta_ms = (uint32_t)(k_uptime_get() - - tx->adv_start_timestamp); - k_timeout_t timeout = K_NO_WAIT; - - /* According to the Bluetooth Mesh Profile specification, - * section 3.5.3.3, we should reset the retransmit timer and - * retransmit immediately when receiving a valid ack message - * while Retransmisison timer is running. However, transport should - * still keep segment transmission interval time between - * transmission of each segment. - */ - if (delta_ms < BT_MESH_SAR_TX_SEG_INT_MS) { - timeout = K_MSEC(BT_MESH_SAR_TX_SEG_INT_MS - delta_ms); - } + if (tx->seg_o == 0) { + k_timeout_t timeout = K_NO_WAIT; - k_work_reschedule(&tx->retransmit, timeout); - } else { - tx->ack_received = 1U; + /* If there are no retransmission attempts left we + * immediately trigger the retransmit call that will + * end the transmission. + */ + if ((BT_MESH_ADDR_IS_UNICAST(tx->dst) && + !tx->attempts_left_without_progress) || + !tx->attempts_left) { + goto reschedule; } + + uint32_t delta_ms = (uint32_t)(k_uptime_get() - tx->adv_start_timestamp); + + /* According to the Bluetooth Mesh Profile specification, + * section 3.5.3.3, we should reset the retransmit timer and + * retransmit immediately when receiving a valid ack message + * while Retransmisison timer is running. However, transport should + * still keep segment transmission interval time between + * transmission of each segment. + */ + if (delta_ms < BT_MESH_SAR_TX_SEG_INT_MS) { + timeout = K_MSEC(BT_MESH_SAR_TX_SEG_INT_MS - delta_ms); + } + +reschedule: + k_work_reschedule(&tx->retransmit, timeout); + } else { + tx->ack_received = 1U; } } else { LOG_DBG("SDU TX complete"); From aa7ed78827b70fd38fb65e14bc199cc599a2c706 Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Tue, 18 Jul 2023 23:05:37 +0200 Subject: [PATCH 1631/2042] sensors: bmp388: allow mix of instances with and without int gpio makes int_gpios optional so we can mix both bmp388 with and without DRDY triggers Signed-off-by: Peter van der Perk --- drivers/sensor/bmp388/bmp388.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/bmp388/bmp388.c b/drivers/sensor/bmp388/bmp388.c index a3ed2253abbe..e88dc66c02af 100644 --- a/drivers/sensor/bmp388/bmp388.c +++ b/drivers/sensor/bmp388/bmp388.c @@ -546,7 +546,7 @@ static int bmp388_init(const struct device *dev) } #ifdef CONFIG_BMP388_TRIGGER - if (bmp388_trigger_mode_init(dev) < 0) { + if (cfg->gpio_int.port != NULL && bmp388_trigger_mode_init(dev) < 0) { LOG_ERR("Cannot set up trigger mode."); return -EINVAL; } @@ -572,7 +572,7 @@ static int bmp388_init(const struct device *dev) #if defined(CONFIG_BMP388_TRIGGER) #define BMP388_INT_CFG(inst) \ - .gpio_int = GPIO_DT_SPEC_INST_GET(inst, int_gpios), + .gpio_int = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0}), #else #define BMP388_INT_CFG(inst) #endif From 0fa7c01adcebf1c7aaa275ab18a8820a58ae0b31 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 21 Jul 2023 11:14:18 +0200 Subject: [PATCH 1632/2042] Bluetooth: att: Remove unused bt_att_free_tx_meta_data function This function seems to unused thus can be safely removed. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/host/att.c | 5 ----- subsys/bluetooth/host/att_internal.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 2b14f37aa9c9..c70078b42262 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -3948,11 +3948,6 @@ bool bt_att_tx_meta_data_match(const struct net_buf *buf, bt_gatt_complete_func_ (bt_att_tx_meta_data(buf)->chan_opt == chan_opt)); } -void bt_att_free_tx_meta_data(const struct net_buf *buf) -{ - tx_meta_data_free(bt_att_tx_meta_data(buf)); -} - bool bt_att_chan_opt_valid(struct bt_conn *conn, enum bt_att_chan_opt chan_opt) { if ((chan_opt & (BT_ATT_CHAN_OPT_ENHANCED_ONLY | BT_ATT_CHAN_OPT_UNENHANCED_ONLY)) == diff --git a/subsys/bluetooth/host/att_internal.h b/subsys/bluetooth/host/att_internal.h index 7f81b181989b..2910c018e851 100644 --- a/subsys/bluetooth/host/att_internal.h +++ b/subsys/bluetooth/host/att_internal.h @@ -340,8 +340,6 @@ 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); -void bt_att_free_tx_meta_data(const struct net_buf *buf); - #if defined(CONFIG_BT_EATT) #define BT_ATT_CHAN_OPT(_params) (_params)->chan_opt #else From c2402a436800dacec9decb1ff8273236205c746d Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 21 Jul 2023 11:14:02 +0200 Subject: [PATCH 1633/2042] Bluetooth: att: Make bt_att_chan_create_pdu static function This fixes missing `static` function specifier. The bt_att_chan_create_pdu is not called outside of att.c. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/host/att.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index c70078b42262..0f741d23aaf3 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -638,8 +638,7 @@ static bt_conn_tx_cb_t att_cb(const struct net_buf *buf) return att_unknown; } -struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op, - size_t len) +static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op, size_t len) { struct bt_att_hdr *hdr; struct net_buf *buf; From 666769e54b9998c2508edfc4a2a49d3ce14bb64e Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 15:13:38 +1200 Subject: [PATCH 1634/2042] soc: arm64: rename "TI Sitara" to "TI K3" The Keystone 3 (K3) family encompasses a wider variety of SoC's. This aligns the soc/arm64 naming with the soc/arm directory. Signed-off-by: Grant Ramsay --- MAINTAINERS.yml | 6 +++--- soc/arm64/{ti_sitara => ti_k3}/CMakeLists.txt | 0 soc/arm64/ti_k3/Kconfig | 15 +++++++++++++++ soc/arm64/{ti_sitara => ti_k3}/Kconfig.defconfig | 2 +- soc/arm64/{ti_sitara => ti_k3}/Kconfig.soc | 2 +- .../{ti_sitara => ti_k3}/am6x/CMakeLists.txt | 0 .../am6x/Kconfig.defconfig.am6234 | 0 .../am6x/Kconfig.defconfig.series | 2 +- .../{ti_sitara => ti_k3}/am6x/Kconfig.series | 2 +- soc/arm64/{ti_sitara => ti_k3}/am6x/Kconfig.soc | 0 soc/arm64/{ti_sitara => ti_k3}/am6x/linker.ld | 0 soc/arm64/{ti_sitara => ti_k3}/am6x/mmu_regions.c | 0 soc/arm64/{ti_sitara => ti_k3}/pinctrl_soc.h | 10 +++++----- soc/arm64/ti_sitara/Kconfig | 15 --------------- 14 files changed, 27 insertions(+), 27 deletions(-) rename soc/arm64/{ti_sitara => ti_k3}/CMakeLists.txt (100%) create mode 100644 soc/arm64/ti_k3/Kconfig rename soc/arm64/{ti_sitara => ti_k3}/Kconfig.defconfig (57%) rename soc/arm64/{ti_sitara => ti_k3}/Kconfig.soc (61%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/CMakeLists.txt (100%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/Kconfig.defconfig.am6234 (100%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/Kconfig.defconfig.series (92%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/Kconfig.series (90%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/Kconfig.soc (100%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/linker.ld (100%) rename soc/arm64/{ti_sitara => ti_k3}/am6x/mmu_regions.c (100%) rename soc/arm64/{ti_sitara => ti_k3}/pinctrl_soc.h (69%) delete mode 100644 soc/arm64/ti_sitara/Kconfig diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 231267f24e29..f15ad8c3427d 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2516,7 +2516,7 @@ TI SimpleLink Platforms: labels: - "platform: TI SimpleLink" -TI Sitara Platforms: +TI K3 Platforms: status: maintained maintainers: - vaishnavachath @@ -2525,9 +2525,9 @@ TI Sitara Platforms: files: - boards/arm64/phycore*/ - dts/arm64/ti/ - - soc/arm64/ti_sitara/ + - soc/arm64/ti_k3/ labels: - - "platform: TI Sitara" + - "platform: TI K3" Xilinx Platforms: status: odd fixes diff --git a/soc/arm64/ti_sitara/CMakeLists.txt b/soc/arm64/ti_k3/CMakeLists.txt similarity index 100% rename from soc/arm64/ti_sitara/CMakeLists.txt rename to soc/arm64/ti_k3/CMakeLists.txt diff --git a/soc/arm64/ti_k3/Kconfig b/soc/arm64/ti_k3/Kconfig new file mode 100644 index 000000000000..8e2c68db09b7 --- /dev/null +++ b/soc/arm64/ti_k3/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Enphase Energy +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_TI_K3 + bool + +if SOC_FAMILY_TI_K3 + +config SOC_FAMILY + string + default "ti_k3" + +source "soc/arm64/ti_k3/*/Kconfig.soc" + +endif # SOC_FAMILY_TI_K3 diff --git a/soc/arm64/ti_sitara/Kconfig.defconfig b/soc/arm64/ti_k3/Kconfig.defconfig similarity index 57% rename from soc/arm64/ti_sitara/Kconfig.defconfig rename to soc/arm64/ti_k3/Kconfig.defconfig index cff24e1b8555..2cc51083bf78 100644 --- a/soc/arm64/ti_sitara/Kconfig.defconfig +++ b/soc/arm64/ti_k3/Kconfig.defconfig @@ -1,4 +1,4 @@ # Copyright (c) 2023 Enphase Energy # SPDX-License-Identifier: Apache-2.0 -source "soc/arm64/ti_sitara/*/Kconfig.defconfig.series" +source "soc/arm64/ti_k3/*/Kconfig.defconfig.series" diff --git a/soc/arm64/ti_sitara/Kconfig.soc b/soc/arm64/ti_k3/Kconfig.soc similarity index 61% rename from soc/arm64/ti_sitara/Kconfig.soc rename to soc/arm64/ti_k3/Kconfig.soc index 7b070a003459..49781270d8d1 100644 --- a/soc/arm64/ti_sitara/Kconfig.soc +++ b/soc/arm64/ti_k3/Kconfig.soc @@ -1,4 +1,4 @@ # Copyright (c) 2023 Enphase Energy # SPDX-License-Identifier: Apache-2.0 -source "soc/arm64/ti_sitara/*/Kconfig.series" +source "soc/arm64/ti_k3/*/Kconfig.series" diff --git a/soc/arm64/ti_sitara/am6x/CMakeLists.txt b/soc/arm64/ti_k3/am6x/CMakeLists.txt similarity index 100% rename from soc/arm64/ti_sitara/am6x/CMakeLists.txt rename to soc/arm64/ti_k3/am6x/CMakeLists.txt diff --git a/soc/arm64/ti_sitara/am6x/Kconfig.defconfig.am6234 b/soc/arm64/ti_k3/am6x/Kconfig.defconfig.am6234 similarity index 100% rename from soc/arm64/ti_sitara/am6x/Kconfig.defconfig.am6234 rename to soc/arm64/ti_k3/am6x/Kconfig.defconfig.am6234 diff --git a/soc/arm64/ti_sitara/am6x/Kconfig.defconfig.series b/soc/arm64/ti_k3/am6x/Kconfig.defconfig.series similarity index 92% rename from soc/arm64/ti_sitara/am6x/Kconfig.defconfig.series rename to soc/arm64/ti_k3/am6x/Kconfig.defconfig.series index f2f898cca7dc..066acc7d6685 100644 --- a/soc/arm64/ti_sitara/am6x/Kconfig.defconfig.series +++ b/soc/arm64/ti_k3/am6x/Kconfig.defconfig.series @@ -37,6 +37,6 @@ endchoice endif # SERIAL -source "soc/arm64/ti_sitara/am6x/Kconfig.defconfig.am62*" +source "soc/arm64/ti_k3/am6x/Kconfig.defconfig.am62*" endif # SOC_SERIES_AM6X_A53 diff --git a/soc/arm64/ti_sitara/am6x/Kconfig.series b/soc/arm64/ti_k3/am6x/Kconfig.series similarity index 90% rename from soc/arm64/ti_sitara/am6x/Kconfig.series rename to soc/arm64/ti_k3/am6x/Kconfig.series index 54da4e341663..8d3bbc561218 100644 --- a/soc/arm64/ti_sitara/am6x/Kconfig.series +++ b/soc/arm64/ti_k3/am6x/Kconfig.series @@ -3,7 +3,7 @@ config SOC_SERIES_AM6X_A53 bool "TI AM6X A53 Core Series" - select SOC_FAMILY_SITARA + select SOC_FAMILY_TI_K3 select ARM64 select CPU_CORTEX_A53 select ARM_ARCH_TIMER diff --git a/soc/arm64/ti_sitara/am6x/Kconfig.soc b/soc/arm64/ti_k3/am6x/Kconfig.soc similarity index 100% rename from soc/arm64/ti_sitara/am6x/Kconfig.soc rename to soc/arm64/ti_k3/am6x/Kconfig.soc diff --git a/soc/arm64/ti_sitara/am6x/linker.ld b/soc/arm64/ti_k3/am6x/linker.ld similarity index 100% rename from soc/arm64/ti_sitara/am6x/linker.ld rename to soc/arm64/ti_k3/am6x/linker.ld diff --git a/soc/arm64/ti_sitara/am6x/mmu_regions.c b/soc/arm64/ti_k3/am6x/mmu_regions.c similarity index 100% rename from soc/arm64/ti_sitara/am6x/mmu_regions.c rename to soc/arm64/ti_k3/am6x/mmu_regions.c diff --git a/soc/arm64/ti_sitara/pinctrl_soc.h b/soc/arm64/ti_k3/pinctrl_soc.h similarity index 69% rename from soc/arm64/ti_sitara/pinctrl_soc.h rename to soc/arm64/ti_k3/pinctrl_soc.h index 6e9889e68b52..0328f52b390e 100644 --- a/soc/arm64/ti_sitara/pinctrl_soc.h +++ b/soc/arm64/ti_k3/pinctrl_soc.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_SOC_ARM64_TI_SITARA_PINCTRL_SOC_H_ -#define ZEPHYR_SOC_ARM64_TI_SITARA_PINCTRL_SOC_H_ +#ifndef ZEPHYR_SOC_ARM64_TI_K3_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM64_TI_K3_PINCTRL_SOC_H_ #ifdef __cplusplus extern "C" { @@ -18,14 +18,14 @@ struct pinctrl_soc_pin { typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; -#define TI_SITARA_DT_PIN(node_id) \ +#define TI_K3_DT_PIN(node_id) \ { \ .offset = DT_PROP_BY_IDX(node_id, pinmux, 0), \ .value = DT_PROP_BY_IDX(node_id, pinmux, 1) \ }, #define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ - TI_SITARA_DT_PIN(DT_PROP_BY_IDX(node_id, prop, idx)) + TI_K3_DT_PIN(DT_PROP_BY_IDX(node_id, prop, idx)) #define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } @@ -34,4 +34,4 @@ typedef struct pinctrl_soc_pin pinctrl_soc_pin_t; } #endif -#endif /* ZEPHYR_SOC_ARM64_TI_SITARA_PINCTRL_SOC_H_ */ +#endif /* ZEPHYR_SOC_ARM64_TI_K3_PINCTRL_SOC_H_ */ diff --git a/soc/arm64/ti_sitara/Kconfig b/soc/arm64/ti_sitara/Kconfig deleted file mode 100644 index dc181c857698..000000000000 --- a/soc/arm64/ti_sitara/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2023 Enphase Energy -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_SITARA - bool - -if SOC_FAMILY_SITARA - -config SOC_FAMILY - string - default "ti_sitara" - -source "soc/arm64/ti_sitara/*/Kconfig.soc" - -endif # SOC_FAMILY_SITARA From c0d144b3cd5ddd3641ea574572c54f355ee673a7 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 15:33:15 +1200 Subject: [PATCH 1635/2042] soc: arm64: add comments expanding the K3 acronym This may be useful to users who do not know what K3 means Signed-off-by: Grant Ramsay --- soc/arm/ti_k3/Kconfig | 2 +- soc/arm/ti_k3/Kconfig.defconfig | 2 +- soc/arm/ti_k3/Kconfig.soc | 2 +- soc/arm64/ti_k3/Kconfig | 2 ++ soc/arm64/ti_k3/Kconfig.defconfig | 2 ++ soc/arm64/ti_k3/Kconfig.soc | 2 ++ 6 files changed, 9 insertions(+), 3 deletions(-) diff --git a/soc/arm/ti_k3/Kconfig b/soc/arm/ti_k3/Kconfig index 501654fec1ac..89a5b8813a56 100644 --- a/soc/arm/ti_k3/Kconfig +++ b/soc/arm/ti_k3/Kconfig @@ -1,4 +1,4 @@ -# Texas Instruments K3 Family +# Texas Instruments Keystone 3 (K3) Family # # Copyright (c) 2023 Texas Instruments Incorporated # Copyright (c) 2023 L Lakshmanan diff --git a/soc/arm/ti_k3/Kconfig.defconfig b/soc/arm/ti_k3/Kconfig.defconfig index 668e287ccf7c..0b983592ad41 100644 --- a/soc/arm/ti_k3/Kconfig.defconfig +++ b/soc/arm/ti_k3/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Texas Instruments K3 Family +# Texas Instruments Keystone 3 (K3) Family # # Copyright (c) 2023 Texas Instruments Incorporated # Copyright (c) 2023 L Lakshmanan diff --git a/soc/arm/ti_k3/Kconfig.soc b/soc/arm/ti_k3/Kconfig.soc index 65d1506917b6..893794288273 100644 --- a/soc/arm/ti_k3/Kconfig.soc +++ b/soc/arm/ti_k3/Kconfig.soc @@ -1,4 +1,4 @@ -# Texas Instruments K3 Family +# Texas Instruments Keystone 3 (K3) Family # # Copyright (c) 2023 Texas Instruments Incorporated # Copyright (c) 2023 L Lakshmanan diff --git a/soc/arm64/ti_k3/Kconfig b/soc/arm64/ti_k3/Kconfig index 8e2c68db09b7..081632c0b880 100644 --- a/soc/arm64/ti_k3/Kconfig +++ b/soc/arm64/ti_k3/Kconfig @@ -1,3 +1,5 @@ +# Texas Instruments Keystone 3 (K3) Family +# # Copyright (c) 2023 Enphase Energy # SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm64/ti_k3/Kconfig.defconfig b/soc/arm64/ti_k3/Kconfig.defconfig index 2cc51083bf78..18eeadee4e09 100644 --- a/soc/arm64/ti_k3/Kconfig.defconfig +++ b/soc/arm64/ti_k3/Kconfig.defconfig @@ -1,3 +1,5 @@ +# Texas Instruments Keystone 3 (K3) Family +# # Copyright (c) 2023 Enphase Energy # SPDX-License-Identifier: Apache-2.0 diff --git a/soc/arm64/ti_k3/Kconfig.soc b/soc/arm64/ti_k3/Kconfig.soc index 49781270d8d1..7d48f5cee1db 100644 --- a/soc/arm64/ti_k3/Kconfig.soc +++ b/soc/arm64/ti_k3/Kconfig.soc @@ -1,3 +1,5 @@ +# Texas Instruments Keystone 3 (K3) Family +# # Copyright (c) 2023 Enphase Energy # SPDX-License-Identifier: Apache-2.0 From fe15f7736ca5c0e1a47f5d9b5797f4973f6734a9 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 15:40:57 +1200 Subject: [PATCH 1636/2042] MAINTAINERS: update TI K3 to cover all related files/paths Some newer TI K3 files/paths were not part of the paths/globs Signed-off-by: Grant Ramsay --- MAINTAINERS.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index f15ad8c3427d..630e468d0930 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2523,9 +2523,12 @@ TI K3 Platforms: collaborators: - gramsay0 files: - - boards/arm64/phycore*/ - - dts/arm64/ti/ - - soc/arm64/ti_k3/ + - boards/*/*phycore_am6*/ + - boards/*/*ti_am6*/ + - drivers/*/*ti_k3*/ + - dts/*/ti/*ti_am6*/ + - dts/bindings/*/ti,k3* + - soc/*/ti_k3/ labels: - "platform: TI K3" From d2e89eb512f96eb0e0ed1eda3a55a3775b4d0fa8 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Thu, 13 Jul 2023 09:47:08 +0200 Subject: [PATCH 1637/2042] drivers: adc: make all enabled ADCs available in the shell Previously, only a single type of ADCs was always available in the ADC shell. This change enables the usage of the ADC shell for different ADC types at the same time. Signed-off-by: Benedikt Schmidt --- drivers/adc/adc_shell.c | 94 +++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 164e706b9aa2..c942ed1adcdb 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -11,47 +11,6 @@ #include #include -#if DT_HAS_COMPAT_STATUS_OKAY(atmel_sam_afec) -#define DT_DRV_COMPAT atmel_sam_afec -#elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_adc) -#define DT_DRV_COMPAT espressif_esp32_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(atmel_sam_adc) -#define DT_DRV_COMPAT atmel_sam_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(atmel_sam0_adc) -#define DT_DRV_COMPAT atmel_sam0_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(ite_it8xxx2_adc) -#define DT_DRV_COMPAT ite_it8xxx2_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(microchip_xec_adc) -#define DT_DRV_COMPAT microchip_xec_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_adc) -#define DT_DRV_COMPAT nordic_nrf_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_saadc) -#define DT_DRV_COMPAT nordic_nrf_saadc -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_mcux_12b1msps_sar) -#define DT_DRV_COMPAT nxp_mcux_12b1msps_sar -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_adc12) -#define DT_DRV_COMPAT nxp_kinetis_adc12 -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_kinetis_adc16) -#define DT_DRV_COMPAT nxp_kinetis_adc16 -#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_vf610_adc) -#define DT_DRV_COMPAT nxp_vf610_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_adc) -#define DT_DRV_COMPAT st_stm32_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_adc) -#define DT_DRV_COMPAT nuvoton_npcx_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(ti_ads1112) -#define DT_DRV_COMPAT ti_ads1112 -#elif DT_HAS_COMPAT_STATUS_OKAY(ti_ads1119) -#define DT_DRV_COMPAT ti_ads1119 -#elif DT_HAS_COMPAT_STATUS_OKAY(ti_cc32xx_adc) -#define DT_DRV_COMPAT ti_cc32xx_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_adc) -#define DT_DRV_COMPAT raspberrypi_pico_adc -#elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_adc_emul) -#define DT_DRV_COMPAT zephyr_adc_emul -#else -#error No known devicetree compatible match for ADC shell -#endif #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL #include @@ -89,32 +48,48 @@ LOG_MODULE_REGISTER(adc_shell); #define CMD_HELP_GAIN "Configure gain.\n" #define CMD_HELP_PRINT "Print current configuration" -#define DEVICES(n) DEVICE_DT_INST_GET(n), -#define ADC_HDL_LIST_ENTRY(dev_) \ - { \ - .dev = dev_, \ - .channel_config = { \ - .gain = ADC_GAIN_1, \ - .reference = ADC_REF_INTERNAL, \ - .acquisition_time = ADC_ACQ_TIME_DEFAULT, \ - .channel_id = 0, \ - }, \ - .resolution = 0, \ - } - -#define INIT_MACRO() DT_INST_FOREACH_STATUS_OKAY(DEVICES) NULL +#define ADC_HDL_LIST_ENTRY(node_id) \ + { \ + .dev = DEVICE_DT_GET(node_id), \ + .channel_config = \ + { \ + .gain = ADC_GAIN_1, \ + .reference = ADC_REF_INTERNAL, \ + .acquisition_time = ADC_ACQ_TIME_DEFAULT, \ + .channel_id = 0, \ + }, \ + .resolution = 0, \ + }, #define CHOSEN_STR_LEN 20 static char chosen_reference[CHOSEN_STR_LEN + 1] = "INTERNAL"; static char chosen_gain[CHOSEN_STR_LEN + 1] = "1"; -/* This table size is = ADC devices count + 1 (NA). */ static struct adc_hdl { const struct device *dev; struct adc_channel_cfg channel_config; uint8_t resolution; } adc_list[] = { - FOR_EACH(ADC_HDL_LIST_ENTRY, (,), INIT_MACRO()) + 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(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(nxp_kinetis_adc12, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc16, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_vf610_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) }; static struct adc_hdl *get_adc(const char *device_label) @@ -414,12 +389,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_adc_cmds, static void cmd_adc_dev_get(size_t idx, struct shell_static_entry *entry) { - /* -1 because the last element in the list is a "list terminator" */ - if (idx < ARRAY_SIZE(adc_list) - 1) { + if (idx < ARRAY_SIZE(adc_list)) { entry->syntax = adc_list[idx].dev->name; entry->handler = NULL; entry->subcmd = &sub_adc_cmds; - entry->help = "Select subcommand for ADC property label.\n"; + entry->help = "Select subcommand for ADC property label."; } else { entry->syntax = NULL; } From 332850a367ffa68b10b77557e37f693512e7e11b Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 8 May 2023 14:01:43 +0200 Subject: [PATCH 1638/2042] drivers: adc: configurable acquisition time for ADS114s0x Implement a configurable acquisition time for the ADS114s0x. Signed-off-by: Benedikt Schmidt --- drivers/adc/adc_ads114s0x.c | 20 +++++++++++++ .../zephyr/dt-bindings/adc/ads114s0x_adc.h | 29 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 include/zephyr/dt-bindings/adc/ads114s0x_adc.h diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index 5c7edd909654..3b050e4e6139 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -596,6 +597,8 @@ static int ads114s0x_channel_setup(const struct device *dev, int result; enum ads114s0x_register register_addresses[6]; uint8_t values[ARRAY_SIZE(register_addresses)]; + uint16_t acquisition_time_value = ADC_ACQ_TIME_VALUE(channel_cfg->acquisition_time); + uint16_t acquisition_time_unit = ADC_ACQ_TIME_UNIT(channel_cfg->acquisition_time); ADS114S0X_REGISTER_INPMUX_SET_DEFAULTS(gain); ADS114S0X_REGISTER_REF_SET_DEFAULTS(reference_control); @@ -609,6 +612,23 @@ static int ads114s0x_channel_setup(const struct device *dev, return -EINVAL; } + /* The ADS114 uses samples per seconds units with the lowest being 2.5SPS + * and with acquisition_time only having 14b for time, this will not fit + * within here for microsecond units. Use Tick units and allow the user to + * specify the ODR directly. + */ + 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); + return -EINVAL; + } + + if (channel_cfg->acquisition_time == ADC_ACQ_TIME_DEFAULT) { + ADS114S0X_REGISTER_DATARATE_DR_SET(data_rate, ADS114S0X_CONFIG_DR_20); + } else { + ADS114S0X_REGISTER_DATARATE_DR_SET(data_rate, acquisition_time_value); + } + switch (channel_cfg->reference) { case ADC_REF_INTERNAL: /* disable negative reference buffer */ diff --git a/include/zephyr/dt-bindings/adc/ads114s0x_adc.h b/include/zephyr/dt-bindings/adc/ads114s0x_adc.h new file mode 100644 index 000000000000..c54b1c4c07bf --- /dev/null +++ b/include/zephyr/dt-bindings/adc/ads114s0x_adc.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ + +/* + * These are the available data rates described as samples per second. They + * can be used with the time unit ticks for the acquisition time. + */ +#define ADS114S0X_CONFIG_DR_2_5 0 +#define ADS114S0X_CONFIG_DR_5 1 +#define ADS114S0X_CONFIG_DR_10 2 +#define ADS114S0X_CONFIG_DR_16_6 3 +#define ADS114S0X_CONFIG_DR_20 4 +#define ADS114S0X_CONFIG_DR_50 5 +#define ADS114S0X_CONFIG_DR_60 6 +#define ADS114S0X_CONFIG_DR_100 7 +#define ADS114S0X_CONFIG_DR_200 8 +#define ADS114S0X_CONFIG_DR_400 9 +#define ADS114S0X_CONFIG_DR_800 10 +#define ADS114S0X_CONFIG_DR_1000 11 +#define ADS114S0X_CONFIG_DR_2000 12 +#define ADS114S0X_CONFIG_DR_4000 13 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ADC_ADS114S0X_ADC_H_ */ From 7e3f0ef407692c6f14629c6ee123a1477dfb726f Mon Sep 17 00:00:00 2001 From: Hiroki Tada Date: Fri, 30 Jun 2023 14:57:36 +0000 Subject: [PATCH 1639/2042] samples: Add esp32s2_saola overlay - Add overlay for the esp32s2_saola board to die_temp_polling sample. - Add aliases for the die_temp_polling sample to esp32s2 dtsi. Signed-off-by: Hiroki Tada --- dts/xtensa/espressif/esp32s2.dtsi | 4 ++++ .../sensor/die_temp_polling/boards/esp32s2_saola.conf | 1 + .../die_temp_polling/boards/esp32s2_saola.overlay | 11 +++++++++++ 3 files changed, 16 insertions(+) create mode 100644 samples/sensor/die_temp_polling/boards/esp32s2_saola.conf create mode 100644 samples/sensor/die_temp_polling/boards/esp32s2_saola.overlay diff --git a/dts/xtensa/espressif/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2.dtsi index 7dc04ba6cf54..b0a9d0e791ec 100644 --- a/dts/xtensa/espressif/esp32s2.dtsi +++ b/dts/xtensa/espressif/esp32s2.dtsi @@ -16,6 +16,10 @@ #address-cells = <1>; #size-cells = <1>; + aliases { + die-temp0 = &coretemp; + }; + chosen { zephyr,entropy = &trng0; zephyr,flash-controller = &flash; diff --git a/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf b/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf new file mode 100644 index 000000000000..13ed95d4291d --- /dev/null +++ b/samples/sensor/die_temp_polling/boards/esp32s2_saola.conf @@ -0,0 +1 @@ +CONFIG_NEWLIB_LIBC=y diff --git a/samples/sensor/die_temp_polling/boards/esp32s2_saola.overlay b/samples/sensor/die_temp_polling/boards/esp32s2_saola.overlay new file mode 100644 index 000000000000..a775e1b5d644 --- /dev/null +++ b/samples/sensor/die_temp_polling/boards/esp32s2_saola.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for creating temperature sensor device instance + */ + +&coretemp { + status = "okay"; +}; From 33e0bca01440f90db5eff03c11e2b129023fc85c Mon Sep 17 00:00:00 2001 From: Hiroki Tada Date: Fri, 30 Jun 2023 15:00:02 +0000 Subject: [PATCH 1640/2042] samples: Remove esp32_temp_sensor - esp32_temp_sensor is removed as die_temp_polling is used instead of it. Signed-off-by: Hiroki Tada --- .../sensor/esp32_temp_sensor/CMakeLists.txt | 8 ---- samples/sensor/esp32_temp_sensor/README.rst | 31 ------------ .../boards/esp32c3_devkitm.conf | 1 - .../boards/esp32c3_devkitm.overlay | 11 ----- .../boards/esp32s2_saola.conf | 1 - .../boards/esp32s2_saola.overlay | 11 ----- samples/sensor/esp32_temp_sensor/prj.conf | 3 -- samples/sensor/esp32_temp_sensor/sample.yaml | 15 ------ samples/sensor/esp32_temp_sensor/src/main.c | 48 ------------------- 9 files changed, 129 deletions(-) delete mode 100644 samples/sensor/esp32_temp_sensor/CMakeLists.txt delete mode 100644 samples/sensor/esp32_temp_sensor/README.rst delete mode 100644 samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.conf delete mode 100644 samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.overlay delete mode 100644 samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.conf delete mode 100644 samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.overlay delete mode 100644 samples/sensor/esp32_temp_sensor/prj.conf delete mode 100644 samples/sensor/esp32_temp_sensor/sample.yaml delete mode 100644 samples/sensor/esp32_temp_sensor/src/main.c diff --git a/samples/sensor/esp32_temp_sensor/CMakeLists.txt b/samples/sensor/esp32_temp_sensor/CMakeLists.txt deleted file mode 100644 index 565056c91a3f..000000000000 --- a/samples/sensor/esp32_temp_sensor/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(esp32_temp_sensor) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/esp32_temp_sensor/README.rst b/samples/sensor/esp32_temp_sensor/README.rst deleted file mode 100644 index 57f57737aa7d..000000000000 --- a/samples/sensor/esp32_temp_sensor/README.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _esp32_temp_sensor: - -ESP32 Temperature Sensor -######################## - -Overview -******** - -This sample periodically reads temperature from the ESP32-S2 and ESP32-C3 -Internal Temperature Sensor and display the results. - -Building and Running -******************** - -In order to run this sample, make sure to enable ``esp32_temp`` node in your -board DT file. - -.. zephyr-app-commands:: - :zephyr-app: samples/sensor/esp32_temp_sensor - :board: esp32s2_saola - :goals: build - :compact: - -Sample Output -============= - -.. code-block:: console - - Current temperature: 22.6 °C - Current temperature: 22.8 °C - Current temperature: 23.1 °C diff --git a/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.conf b/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.conf deleted file mode 100644 index 13ed95d4291d..000000000000 --- a/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_NEWLIB_LIBC=y diff --git a/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.overlay b/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.overlay deleted file mode 100644 index 52a0900aa480..000000000000 --- a/samples/sensor/esp32_temp_sensor/boards/esp32c3_devkitm.overlay +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Application overlay for creating temperature sensor device instance - */ - -&coretemp { - status = "okay"; -}; diff --git a/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.conf b/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.conf deleted file mode 100644 index 13ed95d4291d..000000000000 --- a/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_NEWLIB_LIBC=y diff --git a/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.overlay b/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.overlay deleted file mode 100644 index 52a0900aa480..000000000000 --- a/samples/sensor/esp32_temp_sensor/boards/esp32s2_saola.overlay +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Application overlay for creating temperature sensor device instance - */ - -&coretemp { - status = "okay"; -}; diff --git a/samples/sensor/esp32_temp_sensor/prj.conf b/samples/sensor/esp32_temp_sensor/prj.conf deleted file mode 100644 index 96b6d9efbfb0..000000000000 --- a/samples/sensor/esp32_temp_sensor/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_SENSOR=y -CONFIG_PRINTK=y -CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/sensor/esp32_temp_sensor/sample.yaml b/samples/sensor/esp32_temp_sensor/sample.yaml deleted file mode 100644 index dfc99746a2a8..000000000000 --- a/samples/sensor/esp32_temp_sensor/sample.yaml +++ /dev/null @@ -1,15 +0,0 @@ -sample: - description: Usage of ESP32 temperature sensor - name: esp32_temp_sensor -tests: - sample.sensor.esp32_temp_sensor: - tags: - - sensors - integration_platforms: - - esp32c3_devkitm - filter: dt_compat_enabled("espressif,esp32-temp") - harness: console - harness_config: - type: one_line - regex: - - "Current temperature: [1-5][0-9].[0-9] °C" diff --git a/samples/sensor/esp32_temp_sensor/src/main.c b/samples/sensor/esp32_temp_sensor/src/main.c deleted file mode 100644 index 57213bab7db9..000000000000 --- a/samples/sensor/esp32_temp_sensor/src/main.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include - -#if CONFIG_SOC_ESP32 -#error "Temperature sensor is not supported on ESP32 soc" -#endif /* CONFIG_SOC_ESP32 */ - -int main(void) -{ - const struct device *const dev = DEVICE_DT_GET_ONE(espressif_esp32_temp); - struct sensor_value val; - int rc; - - if (!device_is_ready(dev)) { - printk("Temperature sensor is not ready\n"); - return 0; - } - - printk("ESP32 Die temperature sensor test\n"); - - while (1) { - k_sleep(K_MSEC(300)); - - /* fetch sensor samples */ - rc = sensor_sample_fetch(dev); - if (rc) { - printk("Failed to fetch sample (%d)\n", rc); - return 0; - } - - rc = sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, &val); - if (rc) { - printk("Failed to get data (%d)\n", rc); - return 0; - } - - printk("Current temperature: %.1f °C\n", sensor_value_to_double(&val)); - } - return 0; -} From 2718c8271573b57f4d98352b0284b728d4fd236e Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 21 Jul 2023 15:27:21 -0300 Subject: [PATCH 1641/2042] dts: xtensa: esp32s2: add twai as canbus Add twai node as zephyr,canbus for testing purposes Signed-off-by: Lucas Tamborrino --- dts/xtensa/espressif/esp32s2.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/dts/xtensa/espressif/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2.dtsi index b0a9d0e791ec..75a2ed2bf048 100644 --- a/dts/xtensa/espressif/esp32s2.dtsi +++ b/dts/xtensa/espressif/esp32s2.dtsi @@ -21,6 +21,7 @@ }; chosen { + zephyr,canbus = &twai; zephyr,entropy = &trng0; zephyr,flash-controller = &flash; }; From b3fbdc158a149faf9f126339d154174b2a4fd032 Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Fri, 21 Jul 2023 15:30:14 -0300 Subject: [PATCH 1642/2042] tests: drivers: can: add esp32 and esp32s2 Add esp32 and esp32s2_saola boards to platform allow list Signed-off-by: Lucas Tamborrino --- tests/drivers/can/api/testcase.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index e5c666fa40a1..5048e5c6edbc 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -11,4 +11,9 @@ tests: - can extra_args: DTC_OVERLAY_FILE=twai-enable.overlay filter: dt_compat_enabled("espressif,esp32-twai") - platform_allow: esp32c3_devkitm esp32s3_devkitm xiao_esp32s3 + platform_allow: + - esp32 + - esp32c3_devkitm + - esp32s2_saola + - esp32s3_devkitm + - xiao_esp32s3 From 05a7ad1087b4a531fddfa95d3836d392a96accfe Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Mon, 24 Jul 2023 14:10:58 +0200 Subject: [PATCH 1643/2042] drivers: crypto: stm32h5 CRYP_DATATYPE_8B define in hal Define only once the CRYP_DATATYPE_8B for the stm32h5 serie This macro is in modules/hal/stm32/stm32cube/stm32h5xx/d rivers/include/stm32h5xx_hal_cryp.h Signed-off-by: Francois Ramu --- drivers/crypto/crypto_stm32.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/crypto/crypto_stm32.c b/drivers/crypto/crypto_stm32.c index 5a01ff5ec76e..1ed3a714338a 100644 --- a/drivers/crypto/crypto_stm32.c +++ b/drivers/crypto/crypto_stm32.c @@ -48,10 +48,6 @@ LOG_MODULE_REGISTER(crypto_stm32); #define STM32_CRYPTO_TYPEDEF AES_TypeDef #endif -#if defined(CONFIG_SOC_SERIES_STM32H5X) -#define CRYP_DATATYPE_8B CRYP_BYTE_SWAP -#endif - struct crypto_stm32_session crypto_stm32_sessions[CRYPTO_MAX_SESSION]; static void copy_reverse_words(uint8_t *dst_buf, int dst_len, From 6971865d01ce3dc29ba1bb84ec18e121199b56ef Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Fri, 21 Jul 2023 23:11:07 -0400 Subject: [PATCH 1644/2042] soc: nxp_imx: rt11xx enable xbar driver Add bindings to nxp,mcux-bar dirver Signed-off-by: Peter van der Perk --- dts/arm/nxp/nxp_rt11xx.dtsi | 19 +++++++++++++++++++ soc/arm/nxp_imx/rt/Kconfig.soc | 1 + 2 files changed, 20 insertions(+) diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index adfdcc1a23f0..ca459b66dce1 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -1062,6 +1062,25 @@ status = "okay"; }; + xbar1: xbar1@4003c000 { + compatible = "nxp,mcux-xbar"; + reg = <0x4003c000 0x4000>; + interrupts = <143 0>, <144 0>; + status = "disabled"; + }; + + xbar2: xbar2@40040000 { + compatible = "nxp,mcux-xbar"; + reg = <0x40040000 0x4000>; + status = "disabled"; + }; + + xbar3: xbar3@40044000 { + compatible = "nxp,mcux-xbar"; + reg = <0x40044000 0x4000>; + status = "disabled"; + }; + }; }; diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 0f3759c6d70e..00be7064dd3e 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -352,6 +352,7 @@ config SOC_MIMXRT1176_CM7 select HAS_MCUX_ACMP select HAS_MCUX_SRC_V2 select HAS_MCUX_IOMUXC + select HAS_MCUX_XBARA select HAS_SWO config SOC_MIMXRT1176_CM4 From d53021fc5469dcdf5f80b425df6c31ab14c81bda Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Fri, 21 Jul 2023 23:12:09 -0400 Subject: [PATCH 1645/2042] dts: nxp: rt1xx: add qdec bindings rt11xx add qdec bindings Signed-off-by: Peter van der Perk --- dts/arm/nxp/nxp_rt11xx.dtsi | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index ca459b66dce1..9893c5ec3c09 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -1062,6 +1062,35 @@ status = "okay"; }; + + qdec1: qdec@40174000 { + compatible = "nxp,mcux-qdec"; + reg = <0x40174000 0x4000>; + interrupts = <165 0>; + status = "disabled"; + }; + + qdec2: qdec@40178000 { + compatible = "nxp,mcux-qdec"; + reg = <0x40178000 0x4000>; + interrupts = <166 0>; + status = "disabled"; + }; + + qdec3: qdec@4017c000 { + compatible = "nxp,mcux-qdec"; + reg = <0x4017c000 0x4000>; + interrupts = <167 0>; + status = "disabled"; + }; + + qdec4: qdec@40180000 { + compatible = "nxp,mcux-qdec"; + reg = <0x40180000 0x4000>; + interrupts = <168 0>; + status = "disabled"; + }; + xbar1: xbar1@4003c000 { compatible = "nxp,mcux-xbar"; reg = <0x4003c000 0x4000>; From 2bf38b46ec25ac89c5ac63de32928a239ecdbb7e Mon Sep 17 00:00:00 2001 From: Peter van der Perk Date: Fri, 21 Jul 2023 23:13:50 -0400 Subject: [PATCH 1646/2042] drivers: sensor: qdec_mcux: fix fixed point conversion Use macro to convert sensor q31 representation Signed-off-by: Peter van der Perk --- drivers/sensor/qdec_mcux/qdec_mcux.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/sensor/qdec_mcux/qdec_mcux.c b/drivers/sensor/qdec_mcux/qdec_mcux.c index 1e9ebf6120c6..467fec4bcb76 100644 --- a/drivers/sensor/qdec_mcux/qdec_mcux.c +++ b/drivers/sensor/qdec_mcux/qdec_mcux.c @@ -111,9 +111,8 @@ static int qdec_mcux_ch_get(const struct device *dev, enum sensor_channel ch, switch (ch) { case SENSOR_CHAN_ROTATION: - val->val1 = ((int64_t)data->position * 360) / - data->counts_per_revolution; - val->val2 = 0; + sensor_value_from_float(val, (data->position * 360.0f) + / data->counts_per_revolution); break; default: return -ENOTSUP; From 078fac77fe188a484691e3d244e2f1c23fc88f57 Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Wed, 19 Jul 2023 10:16:18 +0800 Subject: [PATCH 1647/2042] i2c: bugfix for new added macro in header file Fix compile failure with macro of I2C_DEVICE_DT_DEFINE Signed-off-by: Qipeng Zha --- include/zephyr/drivers/i2c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index ef96c2ee1748..95d0cf1e9c1b 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -642,7 +642,7 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ DEVICE_DT_NAME(node_id), \ &UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \ - pm_device, data, config, level, prio, api, \ + pm, data, config, level, prio, api, \ &(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \ __VA_ARGS__) From 40a8553b0d70dbf88c0c630ca12fd9b2dce141c7 Mon Sep 17 00:00:00 2001 From: Josep Puigdemont Date: Sun, 25 Jun 2023 09:53:24 +0200 Subject: [PATCH 1648/2042] boards: arm: olimex stm32-h103: update DTS, docs Disable peripherals that are not used by default. Updated the documentation to reflect changes on configured pins, also fixed the References section wich had none listed. Signed-off-by: Josep Puigdemont --- boards/arm/olimex_stm32_h103/doc/index.rst | 65 ++++++++----------- .../olimex_stm32_h103/olimex_stm32_h103.dts | 29 ++------- .../olimex_stm32_h103/olimex_stm32_h103.yaml | 4 -- 3 files changed, 34 insertions(+), 64 deletions(-) diff --git a/boards/arm/olimex_stm32_h103/doc/index.rst b/boards/arm/olimex_stm32_h103/doc/index.rst index 702bff46d616..bc0904c55aef 100644 --- a/boards/arm/olimex_stm32_h103/doc/index.rst +++ b/boards/arm/olimex_stm32_h103/doc/index.rst @@ -63,30 +63,15 @@ Other hardware features have not been enabled yet for this board. Connections and IOs =================== -Default Zephyr Peripheral Mapping: ----------------------------------- - -- UART_1 TX/RX: PA9/PA10 -- UART_2 TX/RX: PA2/PA3 -- UART_3 TX/RX: PC10/PC11 (not enabled) -- I2C_1 SCL/SDA : PB6/PB7 -- I2C_2 SCL/SDA : PB10/PB11 -- PWM_1_CH1: PA8 -- SPI_1 NSS_OE/SCK/MISO/MOSI: PA4/PA5/PA6/PA7 -- SPI_2 NSS_OE/SCK/MISO/MOSI: PB12/PB13/PB14/PB15 -- USB_DC DM/DP/DISC/PWR: PA11/PA12/PC11/PC4 (not enabled) -- ADC_1: PA1 - System Clock ------------ The on-board 8 MHz crystal is used to produce a 72 MHz system clock with PLL. -Serial Port ------------ +Zephyr Console +-------------- -The board has 3 U(S)ARTs, UART1 and UART2 are enabled by default, with UART2 -used as Zephyr's console. Default settings are 115200 8N1. +UART2 is used as Zephyr's console. Default settings are 115200 8N1. On-Board LEDs ------------- @@ -104,11 +89,13 @@ The board has one user button connected to PA0. USB --- -USB is not enabled by default, however PC4 is configured by default as an ADC -input to sense the USB voltage (see schematic). It is possible to disconnect -it by desoldering the appropriate pad in the PCB. +USB is not enabled by default. + +PC4 can be configured as a GPIO input to detect power on the USB port. It is +possible to disconnect it by desoldering the appropriate pad in the PCB. -The board uses PC11 to disconnect the pull-up resistor on the USB-DP line. +PC11 can be used to disconnect the pull-up resistor on the USB-DP line by +setting it high. External Connectors ------------------- @@ -118,7 +105,7 @@ JTAG/SWD debug +-------+----------------------+-------+--------------+ | PIN # | Signal Name | PIN # | Signal Name | +=======+======================+=======+==============+ -| 1 | +3.3V | 2 | TVCC 3.3V | +| 1 | TVCC +3.3V | 2 | TVCC 3.3V | +-------+----------------------+-------+--------------+ | 3 | PB4 / TRST | 4 | GND | +-------+----------------------+-------+--------------+ @@ -144,27 +131,27 @@ EXTENSION 1 +-------+-----------------------+-------+-----------------------+ | PIN # | Name / STM32F103 Port | PIN # | Name / STM32F103 Port | +=======+=======================+=======+=======================+ -| 1 | PA11 / USB_DM | 2 | PA8 / **PWM_1_CH1** | +| 1 | PA11 / **USB_DM** | 2 | PA8 | +-------+-----------------------+-------+-----------------------+ -| 3 | PA12 / USB_DP | 4 | PA9 / **UART1_TX** | +| 3 | PA12 / **USB_DP** | 4 | PA9 | +-------+-----------------------+-------+-----------------------+ | 5 | +3.3V | 6 | GND | +-------+-----------------------+-------+-----------------------+ -| 7 | PA10 / **UART1_RX** | 8 | PC10 | +| 7 | PA10 | 8 | PC10 | +-------+-----------------------+-------+-----------------------+ | 9 | PC11 / **USB_DISC** | 10 | PC12 / **LED** | +-------+-----------------------+-------+-----------------------+ -| 11 | PD2 | 12 | PB5/I2C1_SMBA | +| 11 | PD2 | 12 | PB5 | +-------+-----------------------+-------+-----------------------+ -| 13 | PB6 / **I2C1_SCL** | 14 | PA6 / **SPI1_MISO** | +| 13 | PB6 | 14 | PA6 | +-------+-----------------------+-------+-----------------------+ -| 15 | PB7 / **I2C1_SDA** | 16 | PB8 | +| 15 | PB7 | 16 | PB8 | +-------+-----------------------+-------+-----------------------+ -| 17 | PB9 | 18 | PA5 / **SPI1_SCK** | +| 17 | PB9 | 18 | PA5 | +-------+-----------------------+-------+-----------------------+ | 19 | PC0 | 20 | PC1 | +-------+-----------------------+-------+-----------------------+ -| 21 | PB0 | 22 | PA7 / **SPI1_MOSI** | +| 21 | PB0 | 22 | PA7 | +-------+-----------------------+-------+-----------------------+ | 23 | VBAT | 24 | PC13 | +-------+-----------------------+-------+-----------------------+ @@ -182,19 +169,19 @@ EXTENSION 2 +-------+------------------------+-------+-----------------------+ | 5 | +3.3V | 6 | GND | +-------+------------------------+-------+-----------------------+ -| 7 | PA2 / **USART2_TX** | 8 | PA1 / **ADC_1** | +| 7 | PA2 / **USART2_TX** | 8 | PA1 | +-------+------------------------+-------+-----------------------+ | 9 | PC3 | 10 | PA3 / **USART2_RX** | +-------+------------------------+-------+-----------------------+ -| 11 | PA4 / **SPI1_NSS** | 12 | PC4 / **USB-P** | +| 11 | PA4 | 12 | PC4 / **USB_POWER** | +-------+------------------------+-------+-----------------------+ -| 13 | PC5 | 14 | PB10 / **I2C2_SCL** | +| 13 | PC5 | 14 | PB10 | +-------+------------------------+-------+-----------------------+ -| 15 | P11 / **I2C2_SDA** | 16 | PB13 / **SPI2_SCK** | +| 15 | P11 | 16 | PB13 | +-------+------------------------+-------+-----------------------+ -| 17 | PB12 / **SPI2_NSS** | 18 | PB14 / **SPI2_MISO** | +| 17 | PB12 | 18 | PB14 | +-------+------------------------+-------+-----------------------+ -| 19 | PB15 / **SPI2_MOSI** | 20 | PC6 | +| 19 | PB15 | 20 | PC6 | +-------+------------------------+-------+-----------------------+ | 21 | PC7 | 22 | PC8 | +-------+------------------------+-------+-----------------------+ @@ -241,6 +228,10 @@ You can debug an application in the usual way. Here is an example for the References ********** +- `OLIMEX-STM32-H103 website`_ +- `OLIMEX-STM32-H103 user manual`_ +- `OLIMEX-STM32-H103 schematic`_ + .. _OLIMEX-STM32-H103 website: https://www.olimex.com/Products/ARM/ST/STM32-H103/ diff --git a/boards/arm/olimex_stm32_h103/olimex_stm32_h103.dts b/boards/arm/olimex_stm32_h103/olimex_stm32_h103.dts index 59256d954edb..44b8b7c847b4 100644 --- a/boards/arm/olimex_stm32_h103/olimex_stm32_h103.dts +++ b/boards/arm/olimex_stm32_h103/olimex_stm32_h103.dts @@ -65,7 +65,7 @@ pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; pinctrl-names = "default"; current-speed = <115200>; - status = "okay"; + status = "disabled"; }; &usart2 { @@ -79,19 +79,20 @@ pinctrl-0 = <&usart3_tx_remap1_pc10 &usart3_rx_remap1_pc11>; pinctrl-names = "default"; current-speed = <115200>; + status = "disabled"; }; &i2c1 { pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>; pinctrl-names = "default"; - status = "okay"; + status = "disabled"; clock-frequency = ; }; &i2c2 { pinctrl-0 = <&i2c2_scl_pb10 &i2c2_sda_pb11>; pinctrl-names = "default"; - status = "okay"; + status = "disabled"; clock-frequency = ; }; @@ -99,38 +100,20 @@ pinctrl-0 = <&spi1_nss_master_pa4 &spi1_sck_master_pa5 &spi1_miso_master_pa6 &spi1_mosi_master_pa7>; pinctrl-names = "default"; - status = "okay"; + status = "disabled"; }; &spi2 { pinctrl-0 = <&spi2_nss_master_pb12 &spi2_sck_master_pb13 &spi2_miso_master_pb14 &spi2_mosi_master_pb15>; pinctrl-names = "default"; - status = "okay"; -}; - -&timers1 { - st,prescaler = <10000>; - status = "okay"; - - pwm1: pwm { - status = "okay"; - pinctrl-0 = <&tim1_ch1_pwm_out_pa8>; - pinctrl-names = "default"; - }; + status = "disabled"; }; &iwdg { status = "okay"; }; -&adc1 { - /* adc1_in14_pc4 is used to sense the USB voltage */ - pinctrl-0 = <&adc1_in1_pa1 &adc1_in14_pc4>; - pinctrl-names = "default"; - status = "okay"; -}; - zephyr_udc0: &usb { pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; pinctrl-names = "default"; diff --git a/boards/arm/olimex_stm32_h103/olimex_stm32_h103.yaml b/boards/arm/olimex_stm32_h103/olimex_stm32_h103.yaml index 3dd7361b19bc..392d559fc73d 100644 --- a/boards/arm/olimex_stm32_h103/olimex_stm32_h103.yaml +++ b/boards/arm/olimex_stm32_h103/olimex_stm32_h103.yaml @@ -9,11 +9,7 @@ toolchain: ram: 20 flash: 128 supported: - - adc - gpio - - i2c - - pwm - - spi - uart - watchdog testing: From 447e3e6266c5100c7e355b123699ba46a6fb5b03 Mon Sep 17 00:00:00 2001 From: Josep Puigdemont Date: Sun, 25 Jun 2023 11:37:46 +0200 Subject: [PATCH 1649/2042] boards: arm: olimex stm32-h103: support for BMP Add support for flashing and debugging with the Black Magic Probe debugging tool. Signed-off-by: Josep Puigdemont --- boards/arm/olimex_stm32_h103/board.cmake | 2 ++ boards/arm/olimex_stm32_h103/doc/index.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/boards/arm/olimex_stm32_h103/board.cmake b/boards/arm/olimex_stm32_h103/board.cmake index 51a6e9ef3bdc..d85357babb95 100644 --- a/boards/arm/olimex_stm32_h103/board.cmake +++ b/boards/arm/olimex_stm32_h103/board.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +board_runner_args(blackmagicprobe "--connect-rst") board_runner_args(jlink "--device=STM32F103RB" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/olimex_stm32_h103/doc/index.rst b/boards/arm/olimex_stm32_h103/doc/index.rst index bc0904c55aef..8ba6e949f8b9 100644 --- a/boards/arm/olimex_stm32_h103/doc/index.rst +++ b/boards/arm/olimex_stm32_h103/doc/index.rst @@ -203,6 +203,8 @@ SWD transport, but it is also possible to use JTAG with the Olimex ARM-USB-OCD-H probe, for instance. For the latter, you should replace the file ``openocd.cfg`` by ``openocd_olimex_jtag.cfg``, located in the board's support directory. +The ``blackmagicprobe`` can also be used to program the device. + Flashing ======== From 3e2765cc0da9f309b952ee31c9ff7cf6ad0a3b7a Mon Sep 17 00:00:00 2001 From: Mathieu Anquetin Date: Wed, 19 Jul 2023 15:11:37 +0200 Subject: [PATCH 1650/2042] dts: arm: st: Add dts and soc additions for stm32f105xb Added dts additions for stm32f105xb cpu which is the same as existing stm32f105xc with less flash. Signed-off-by: Mathieu Anquetin --- dts/arm/st/f1/stm32f105Xb.dtsi | 22 +++++++++++++++++++ ...32f105xc => Kconfig.defconfig.stm32f105xx} | 4 ++-- soc/arm/st_stm32/stm32f1/Kconfig.soc | 4 ++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 dts/arm/st/f1/stm32f105Xb.dtsi rename soc/arm/st_stm32/stm32f1/{Kconfig.defconfig.stm32f105xc => Kconfig.defconfig.stm32f105xx} (72%) diff --git a/dts/arm/st/f1/stm32f105Xb.dtsi b/dts/arm/st/f1/stm32f105Xb.dtsi new file mode 100644 index 000000000000..7db805c8a5f5 --- /dev/null +++ b/dts/arm/st/f1/stm32f105Xb.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Groupe Cahors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(64)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + }; +}; diff --git a/soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xc b/soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xx similarity index 72% rename from soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xc rename to soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xx index 0a2c9c2232f8..b7963eacb6a2 100644 --- a/soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xc +++ b/soc/arm/st_stm32/stm32f1/Kconfig.defconfig.stm32f105xx @@ -3,7 +3,7 @@ # Copyright (c) 2019 Argentum Systems Ltd. # SPDX-License-Identifier: Apache-2.0 -if SOC_STM32F105XC +if SOC_STM32F105XC || SOC_STM32F105XB config SOC string @@ -13,4 +13,4 @@ config NUM_IRQS int default 68 -endif # SOC_STM32F105XC +endif # SOC_STM32F105XC || STM32F105XB diff --git a/soc/arm/st_stm32/stm32f1/Kconfig.soc b/soc/arm/st_stm32/stm32f1/Kconfig.soc index 46e9ff96c90c..82f9b5100e51 100644 --- a/soc/arm/st_stm32/stm32f1/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f1/Kconfig.soc @@ -26,6 +26,10 @@ config SOC_STM32F103X8 bool "STM32F103X8" select SOC_STM32F10X_DENSITY_DEVICE +config SOC_STM32F105XB + bool "STM32F105XB" + select SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE + config SOC_STM32F105XC bool "STM32F105XC" select SOC_STM32F10X_CONNECTIVITY_LINE_DEVICE From 00a9cb81c00b955dcee8de4cdf236dc823da4772 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 24 Jul 2023 09:23:51 +0200 Subject: [PATCH 1651/2042] drivers: rtc: stm32: Exclude STM32F1 from current RTC driver STM32F1 series RTC is not compatible with other STM32F1 series, and it uses a different LL API. Current implementation of the driver doesn't take this into account, so we need to explicitly exclude STM32F1 series support until some changes are made. Signed-off-by: Erwan Gouriou --- drivers/rtc/Kconfig.stm32 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/Kconfig.stm32 b/drivers/rtc/Kconfig.stm32 index 510d259a2065..1cdbe99ca0ba 100644 --- a/drivers/rtc/Kconfig.stm32 +++ b/drivers/rtc/Kconfig.stm32 @@ -4,9 +4,9 @@ config RTC_STM32 bool "STM32 RTC driver" default y if !COUNTER - depends on DT_HAS_ST_STM32_RTC_ENABLED + depends on DT_HAS_ST_STM32_RTC_ENABLED && !SOC_SERIES_STM32F1X select USE_STM32_LL_RTC select USE_STM32_LL_PWR select USE_STM32_LL_RCC help - Build RTC driver for STM32 SoCs. + Build RTC driver for STM32 SoCs, excluding STM32F1 series. From 9e3b1c1eae646908e3b8f8a72bc2cfc72a9fa596 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 24 Jul 2023 09:31:47 +0200 Subject: [PATCH 1652/2042] tests: drivers: rtc: api_helpers: Should depend on rtc support Without this, test is run on any target, even if no RTC driver is supported, leading to unexpected issues. Signed-off-by: Erwan Gouriou --- tests/drivers/rtc/rtc_api_helpers/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/drivers/rtc/rtc_api_helpers/testcase.yaml b/tests/drivers/rtc/rtc_api_helpers/testcase.yaml index 436886b4e70c..df1a2ee66cf4 100644 --- a/tests/drivers/rtc/rtc_api_helpers/testcase.yaml +++ b/tests/drivers/rtc/rtc_api_helpers/testcase.yaml @@ -8,3 +8,4 @@ tests: - rtc - api - helpers + depends_on: rtc From 48cdb4b2259be30e1b731a5947a1bacc33702243 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 24 Jul 2023 09:36:33 +0200 Subject: [PATCH 1653/2042] boards: Declare rtc support when missing Without this, rtc related tests can't be run. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_h563zi/nucleo_h563zi.yaml | 1 + boards/x86/qemu_x86/qemu_x86.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml b/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml index 1798cf41e595..0d1b1758a225 100644 --- a/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml +++ b/boards/arm/nucleo_h563zi/nucleo_h563zi.yaml @@ -21,3 +21,4 @@ supported: - spi - usb_device - usb + - rtc diff --git a/boards/x86/qemu_x86/qemu_x86.yaml b/boards/x86/qemu_x86/qemu_x86.yaml index a709683a796a..bb662c7c93b2 100644 --- a/boards/x86/qemu_x86/qemu_x86.yaml +++ b/boards/x86/qemu_x86/qemu_x86.yaml @@ -14,5 +14,6 @@ supported: - netif:serial-net - eeprom - can + - rtc testing: default: true From e6d89268572d7e1e7a39d22908fc98d3e3355dd1 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 19 Jul 2023 13:36:27 -0700 Subject: [PATCH 1654/2042] xtensa: set no optimization for arch_cpu_idle() with xt-clang xt-clang likes to remove any consecutive NOPs more than 8. So we need to force the function to have no optimization to avoid this behavior and to retain all those NOPs. Signed-off-by: Daniel Leung --- arch/xtensa/core/cpu_idle.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/xtensa/core/cpu_idle.c b/arch/xtensa/core/cpu_idle.c index 0770125ebcd8..fa9384d8445a 100644 --- a/arch/xtensa/core/cpu_idle.c +++ b/arch/xtensa/core/cpu_idle.c @@ -3,8 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include +/* xt-clang removes any NOPs more than 8. So we need to set + * no optimization to avoid those NOPs from being removed. + * + * This function is simply enough and full of hand written + * assembly that optimization is not really meaningful + * anyway. So we can skip optimization unconditionally. + * Re-evalulate its use and add #ifdef if this assumption + * is no longer valid. + */ +__no_optimization void arch_cpu_idle(void) { sys_trace_idle(); From 90f388e9b2f8456acd0cf7ba32bc90d6d96185f8 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 6 Jun 2023 10:27:18 -0700 Subject: [PATCH 1655/2042] linker: mark priv_stacks_noinit as NOLOAD Currently priv_stacks_noinit is being put onto the flash waiting to be copied into memory at boot. This is a waste of flash space as priviledge stacks are initialized at runtime. So mark the linker section as NOLOAD to save some flash space. Signed-off-by: Daniel Leung --- include/zephyr/linker/kobject-priv-stacks.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/linker/kobject-priv-stacks.ld b/include/zephyr/linker/kobject-priv-stacks.ld index 7c827895c18f..0da28763a2bf 100644 --- a/include/zephyr/linker/kobject-priv-stacks.ld +++ b/include/zephyr/linker/kobject-priv-stacks.ld @@ -6,7 +6,7 @@ #ifdef CONFIG_USERSPACE #ifdef CONFIG_GEN_PRIV_STACKS - SECTION_DATA_PROLOGUE(priv_stacks_noinit,,) + SECTION_DATA_PROLOGUE(priv_stacks_noinit,(NOLOAD),) { z_priv_stacks_ram_start = .; From 6fdfc91a6c111c7210b30840e526f6604fcbc610 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 19 Jul 2023 02:01:52 +0000 Subject: [PATCH 1656/2042] west: build: also parse common section in yaml file Parse common section and append to cmake args if available when using --test-item option of west build. Signed-off-by: Anas Nashif --- scripts/west_commands/build.py | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index a9a156125ce0..4f600bd881e7 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -270,6 +270,7 @@ def _parse_test_item(self, test_item): y = yaml.safe_load(stream) except yaml.YAMLError as exc: log.die(exc) + common = y.get('common') tests = y.get('tests') if not tests: log.die(f"No tests found in {yf}") @@ -277,23 +278,29 @@ def _parse_test_item(self, test_item): if not item: log.die(f"Test item {test_item} not found in {yf}") - for data in ['extra_args', 'extra_configs']: - extra = item.get(data) - if not extra: + sysbuild = False + for section in [common, item]: + if not section: continue - if isinstance(extra, str): - arg_list = extra.split(" ") - else: - arg_list = extra - if data == 'extra_configs': - args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] - elif data == 'extra_args': - args = ["-D{}".format(arg.replace('"', '')) for arg in arg_list] - if self.args.cmake_opts: - self.args.cmake_opts.extend(args) - else: - self.args.cmake_opts = args - self.args.sysbuild = item.get('sysbuild') + sysbuild = section.get('sysbuild', sysbuild) + for data in ['extra_args', 'extra_configs']: + extra = section.get(data) + if not extra: + continue + if isinstance(extra, str): + arg_list = extra.split(" ") + else: + arg_list = extra + if data == 'extra_configs': + args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] + elif data == 'extra_args': + args = ["-D{}".format(arg.replace('"', '')) for arg in arg_list] + if self.args.cmake_opts: + self.args.cmake_opts.extend(args) + else: + self.args.cmake_opts = args + + self.args.sysbuild = sysbuild return found_test_metadata def _sanity_precheck(self): From 47102de474cb055804e8f786e74c72d8248fd7b0 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Fri, 21 Jul 2023 12:03:58 +0000 Subject: [PATCH 1657/2042] west: build: support additional configuration with --test-item Also support extra_conf_files, extra_overlay_confs, extra_dtc_overlay_files Signed-off-by: Anas Nashif --- scripts/west_commands/build.py | 40 +++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/scripts/west_commands/build.py b/scripts/west_commands/build.py index 4f600bd881e7..dc56ae307d7b 100644 --- a/scripts/west_commands/build.py +++ b/scripts/west_commands/build.py @@ -279,11 +279,20 @@ def _parse_test_item(self, test_item): log.die(f"Test item {test_item} not found in {yf}") sysbuild = False + extra_dtc_overlay_files = [] + extra_overlay_confs = [] + extra_conf_files = [] for section in [common, item]: if not section: continue sysbuild = section.get('sysbuild', sysbuild) - for data in ['extra_args', 'extra_configs']: + for data in [ + 'extra_args', + 'extra_configs', + 'extra_conf_files', + 'extra_overlay_confs', + 'extra_dtc_overlay_files' + ]: extra = section.get(data) if not extra: continue @@ -291,16 +300,45 @@ def _parse_test_item(self, test_item): arg_list = extra.split(" ") else: arg_list = extra + if data == 'extra_configs': args = ["-D{}".format(arg.replace('"', '\"')) for arg in arg_list] elif data == 'extra_args': args = ["-D{}".format(arg.replace('"', '')) for arg in arg_list] + elif data == 'extra_conf_files': + extra_conf_files.extend(arg_list) + continue + elif data == 'extra_overlay_confs': + extra_overlay_confs.extend(arg_list) + continue + elif data == 'extra_dtc_overlay_files': + extra_dtc_overlay_files.extend(arg_list) + continue + if self.args.cmake_opts: self.args.cmake_opts.extend(args) else: self.args.cmake_opts = args self.args.sysbuild = sysbuild + + args = [] + if extra_conf_files: + args.append(f"CONF_FILE=\"{';'.join(extra_conf_files)}\"") + + if extra_dtc_overlay_files: + args.append(f"DTC_OVERLAY_FILE=\"{';'.join(extra_dtc_overlay_files)}\"") + + if extra_overlay_confs: + args.append(f"OVERLAY_CONFIG=\"{';'.join(extra_overlay_confs)}\"") + # Build the final argument list + args_expanded = ["-D{}".format(a.replace('"', '')) for a in args] + + if self.args.cmake_opts: + self.args.cmake_opts.extend(args_expanded) + else: + self.args.cmake_opts = args_expanded + return found_test_metadata def _sanity_precheck(self): From dcdebb616a61ae51ddea8a80a85f7e7ed35d1f4d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Mon, 17 Jul 2023 19:24:53 -0400 Subject: [PATCH 1658/2042] kernel: dynamic: remove unnecessary size assignment Previously, the kernel stack size was adjusted for no apparent reason. Signed-off-by: Christopher Friedt --- kernel/dynamic.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/dynamic.c b/kernel/dynamic.c index 3c7a624f644e..23e64e802b5d 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -41,8 +41,6 @@ static k_thread_stack_t *z_thread_stack_alloc_pool(size_t size) size_t offset; k_thread_stack_t *stack; - size = Z_KERNEL_STACK_SIZE_ADJUST(size); - if (size > CONFIG_DYNAMIC_THREAD_STACK_SIZE) { LOG_DBG("stack size %zu is > pool stack size %d", size, CONFIG_DYNAMIC_THREAD_STACK_SIZE); From d7119b889f8582e20f073a2f8369f176a724d8a5 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Tue, 18 Jul 2023 08:33:41 -0400 Subject: [PATCH 1659/2042] kernel: dynamic: declare dynamic stubs when disabled With some of the recent work to disable unnecessary system calls, there is a scenario where `z_impl_k_thread_stack_free()` is not defined and an undefined symbol error occurs. Safety was very concerned that dynamic thread stack code might touch other code that does not malloc, so add a separate file for the stack alloc and free stubs. Signed-off-by: Christopher Friedt --- include/zephyr/kernel.h | 1 + kernel/CMakeLists.txt | 10 +++++----- kernel/dynamic_disabled.c | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 kernel/dynamic_disabled.c diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index 9a88baeb5bdf..07428d18ca8b 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -289,6 +289,7 @@ __syscall k_thread_stack_t *k_thread_stack_alloc(size_t size, int flags); * @retval 0 on success. * @retval -EBUSY if the thread stack is in use. * @retval -EINVAL if @p stack is invalid. + * @retval -ENOSYS if dynamic thread stack allocation is disabled * * @see CONFIG_DYNAMIC_THREAD */ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 2dfcaee9af4c..9e7602bfbd87 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -123,11 +123,11 @@ target_sources_ifdef( userspace.c ) -target_sources_ifdef( - CONFIG_DYNAMIC_THREAD - kernel PRIVATE - dynamic.c - ) +if(${CONFIG_DYNAMIC_THREAD}) + target_sources(kernel PRIVATE dynamic.c) +else() + target_sources(kernel PRIVATE dynamic_disabled.c) +endif() target_include_directories(kernel PRIVATE ${ZEPHYR_BASE}/kernel/include diff --git a/kernel/dynamic_disabled.c b/kernel/dynamic_disabled.c new file mode 100644 index 000000000000..47ce077304f7 --- /dev/null +++ b/kernel/dynamic_disabled.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +k_thread_stack_t *z_impl_k_thread_stack_alloc(size_t size, int flags) +{ + ARG_UNUSED(size); + ARG_UNUSED(flags); + + return NULL; +} + +int z_impl_k_thread_stack_free(k_thread_stack_t *stack) +{ + ARG_UNUSED(stack); + + return -ENOSYS; +} From 115efa2e35ee10e7215f019c0c8cddb45e718bfe Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 22 Oct 2020 22:41:58 -0400 Subject: [PATCH 1660/2042] pthread: facilitate dynamically allocated thread stacks This change allows users to call pthread_create() with the pthread_attr_t argument equal to NULL. If Zephyr is configured with `CONFIG_DYNAMIC_THREAD`, then a suitable thread stack will be allocated via k_thread_stack_alloc(). The allocated thread stack is automatically freed via k_thread_stack_free(). This makes the Zephyr implementation of pthread_create() compliant with the normative spec. Signed-off-by: Christopher Friedt --- lib/posix/Kconfig.pthread | 21 +++++++ lib/posix/posix_internal.h | 3 + lib/posix/pthread.c | 118 ++++++++++++++++++++++++++++--------- 3 files changed, 114 insertions(+), 28 deletions(-) diff --git a/lib/posix/Kconfig.pthread b/lib/posix/Kconfig.pthread index 9b2541c6631b..388a30c5fa40 100644 --- a/lib/posix/Kconfig.pthread +++ b/lib/posix/Kconfig.pthread @@ -7,3 +7,24 @@ TYPE = PTHREAD type = pthread_t type-function = pthread_create source "lib/posix/Kconfig.template.pooled_ipc_type" + +if PTHREAD + +config PTHREAD_RECYCLER_DELAY_MS + int "Delay for reclaiming dynamic pthread stacks (ms)" + default 100 + help + Prior to a POSIX thread terminating via k_thread_abort(), scheduled + work is added to the system workqueue (SWQ) so that any resources + allocated by the thread (e.g. thread stack from a pool or the heap) + can be released back to the system. Because resources are also freed + on calls to pthread_create() there is no need to worry about resource + starvation. + + This option sets the number of milliseconds by which to defer + scheduled work. + + Note: this option should be considered temporary and will likely be + removed once a more synchronous solution is available. + +endif diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h index e3c2b2817125..39c64c53331c 100644 --- a/lib/posix/posix_internal.h +++ b/lib/posix/posix_internal.h @@ -30,6 +30,9 @@ 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; + /* Exit status */ void *retval; diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 519d68091248..a6505d4f9d33 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -16,6 +16,12 @@ #include #include +#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE +#define DYNAMIC_STACK_SIZE CONFIG_DYNAMIC_THREAD_STACK_SIZE +#else +#define DYNAMIC_STACK_SIZE 0 +#endif + #define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE #define PTHREAD_CANCELED ((void *) -1) @@ -34,6 +40,7 @@ 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)); +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); @@ -205,13 +212,13 @@ int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksi static bool pthread_attr_is_valid(const struct pthread_attr *attr) { - /* - * FIXME: Pthread attribute must be non-null and it provides stack - * pointer and stack size. So even though POSIX 1003.1 spec accepts - * attrib as NULL but zephyr needs it initialized with valid stack. - */ - if (attr == NULL || attr->initialized == 0U || attr->stack == NULL || - attr->stacksize == 0) { + /* auto-alloc thread stack */ + if (attr == NULL) { + return true; + } + + /* caller-provided thread stack */ + if (attr->initialized == 0U || attr->stack == NULL || attr->stacksize == 0) { return false; } @@ -234,6 +241,13 @@ static bool pthread_attr_is_valid(const struct pthread_attr *attr) return true; } +static void posix_thread_recycle_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + posix_thread_recycle(); +} +static K_WORK_DELAYABLE_DEFINE(posix_thread_recycle_work, posix_thread_recycle_work_handler); + static void posix_thread_finalize(struct posix_thread *t, void *retval) { sys_snode_t *node_l; @@ -259,6 +273,9 @@ static void posix_thread_finalize(struct posix_thread *t, void *retval) t->retval = retval; k_spin_unlock(&pthread_pool_lock, key); + /* trigger recycle work */ + (void)k_work_schedule(&posix_thread_recycle_work, K_MSEC(CONFIG_PTHREAD_RECYCLER_DELAY_MS)); + /* abort the underlying k_thread */ k_thread_abort(&t->thread); } @@ -283,6 +300,45 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) CODE_UNREACHABLE; } +static void posix_thread_recycle(void) +{ + k_spinlock_key_t key; + struct posix_thread *t; + struct posix_thread *safe_t; + 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) { + if (t->detachstate == PTHREAD_CREATE_JOINABLE) { + /* thread has not been joined yet */ + continue; + } + + sys_dlist_remove(&t->q_node); + sys_dlist_append(&recyclables, &t->q_node); + } + k_spin_unlock(&pthread_pool_lock, key); + + if (sys_dlist_is_empty(&recyclables)) { + return; + } + + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + SYS_DLIST_FOR_EACH_CONTAINER(&recyclables, t, q_node) { + if (t->dynamic_stack != NULL) { + (void)k_thread_stack_free(t->dynamic_stack); + t->dynamic_stack = NULL; + } + } + } + + key = k_spin_lock(&pthread_pool_lock); + while (!sys_dlist_is_empty(&recyclables)) { + sys_dlist_append(&ready_q, sys_dlist_get(&recyclables)); + } + k_spin_unlock(&pthread_pool_lock, key); +} + /** * @brief Create a new thread. * @@ -297,32 +353,33 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou int err; k_spinlock_key_t key; pthread_barrier_t barrier; - struct posix_thread *safe_t; struct posix_thread *t = NULL; - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; + struct pthread_attr attr_storage = init_pthread_attrs; + struct pthread_attr *attr = (struct pthread_attr *)_attr; if (!pthread_attr_is_valid(attr)) { return EINVAL; } + 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); + if (attr->stack == NULL) { + return EAGAIN; + } + } 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)) { - /* spawn thread 't' directly from ready_q */ t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); - } else { - SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&done_q, t, safe_t, q_node) { - if (t->detachstate == PTHREAD_CREATE_JOINABLE) { - /* thread has not been joined yet */ - continue; - } - /* spawn thread 't' from done_q */ - sys_dlist_remove(&t->q_node); - break; - } - } - - if (t != NULL) { /* initialize thread state */ sys_dlist_append(&run_q, &t->q_node); t->qid = POSIX_THREAD_RUN_Q; @@ -332,12 +389,22 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou } t->cancel_pending = false; sys_slist_init(&t->key_list); + t->dynamic_stack = _attr == NULL ? attr->stack : NULL; } k_spin_unlock(&pthread_pool_lock, key); + if (t == NULL) { + /* no threads are ready */ + return EAGAIN; + } + if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { err = pthread_barrier_init(&barrier, NULL, 2); if (err != 0) { + if (t->dynamic_stack != NULL) { + (void)k_thread_stack_free(attr->stack); + } + /* cannot allocate barrier. move thread back to ready_q */ key = k_spin_lock(&pthread_pool_lock); sys_dlist_remove(&t->q_node); @@ -348,11 +415,6 @@ int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadrou } } - if (t == NULL) { - /* no threads are ready */ - return EAGAIN; - } - /* spawn the thread */ k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, (void *)arg, threadroutine, From 5a28297cf3c8a71bf6f2e1e7d3e6381025a8579d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Wed, 10 Feb 2021 09:17:59 -0500 Subject: [PATCH 1661/2042] pthread: test: facilitate dynamically allocated thread stacks Tests for dynamically allocated POSIX thread stacks. Signed-off-by: Christopher Friedt --- tests/posix/common/prj.conf | 2 +- tests/posix/common/src/pthread.c | 47 ++++++++++++++++++++++++++++---- tests/posix/common/testcase.yaml | 9 ++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/tests/posix/common/prj.conf b/tests/posix/common/prj.conf index f72676270156..1eb3e47658d4 100644 --- a/tests/posix/common/prj.conf +++ b/tests/posix/common/prj.conf @@ -1,6 +1,6 @@ CONFIG_PTHREAD_IPC=y CONFIG_POSIX_API=y -CONFIG_MAX_PTHREAD_COUNT=20 +CONFIG_MAX_PTHREAD_COUNT=10 CONFIG_ZTEST=y CONFIG_ZTEST_NEW_API=y CONFIG_SEM_VALUE_MAX=32767 diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 3cd284f62dc4..e88703bae404 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -216,6 +216,9 @@ 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!"); @@ -345,8 +348,13 @@ ZTEST(posix_apis, test_pthread_execution) getschedparam.sched_priority, "scheduling priorities do not match!"); - ret = pthread_create(&newthread[i], &attr[i], thread_top_exec, - INT_TO_POINTER(i)); + 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"); @@ -500,8 +508,13 @@ ZTEST(posix_apis, test_pthread_termination) schedparam.sched_priority = 2; pthread_attr_setschedparam(&attr[i], &schedparam); pthread_attr_setstack(&attr[i], &stack_t[i][0], STACKS); - ret = pthread_create(&newthread[i], &attr[i], thread_top_term, - INT_TO_POINTER(i)); + 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"); } @@ -571,8 +584,10 @@ ZTEST(posix_apis, test_pthread_create_negative) pthread_attr_t attr1; /* create pthread without attr initialized */ - ret = pthread_create(&pthread1, NULL, create_thread1, (void *)1); - zassert_equal(ret, EINVAL, "create thread with NULL successful"); + 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); @@ -777,3 +792,23 @@ ZTEST(posix_apis, test_pthread_equal) zassert_true(pthread_equal(pthread_self(), pthread_self())); zassert_false(pthread_equal(pthread_self(), (pthread_t)4242)); } + +static void *fun(void *arg) +{ + *((uint32_t *)arg) = 0xB105F00D; + return NULL; +} + +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_join(th, NULL)); + zassert_equal(0xB105F00D, x); +} diff --git a/tests/posix/common/testcase.yaml b/tests/posix/common/testcase.yaml index a3086233b6c3..19f858f0b50f 100644 --- a/tests/posix/common/testcase.yaml +++ b/tests/posix/common/testcase.yaml @@ -86,3 +86,12 @@ tests: portability.posix.common.signal.big_nsig: extra_configs: - CONFIG_POSIX_RTSIG_MAX=1024 + portability.posix.common.dynamic_stack: + integration_platforms: + - qemu_x86 + - qemu_riscv64 + extra_configs: + - CONFIG_DYNAMIC_THREAD=y + - CONFIG_THREAD_STACK_INFO=y + - CONFIG_DYNAMIC_THREAD_POOL_SIZE=5 + - CONFIG_HEAP_MEM_POOL_SIZE=16384 From 1b905fd17bb78d3304784dec22d54a9ab5ed6911 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Mon, 24 Jul 2023 08:36:32 +0000 Subject: [PATCH 1662/2042] MAINTAINERS: Remove myself from settings subsystem Unfortunately I have no capacity to take care of the subsystem. Signed-off-by: Dominik Ermel --- MAINTAINERS.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 630e468d0930..a993fe5fa6f8 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2072,8 +2072,6 @@ Twister: Settings: status: odd fixes - collaborators: - - de-nordic files: - include/zephyr/settings/ - subsys/settings/ From ab9028518e1236213fad01ef3fe20b57b1699e0b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 24 Jul 2023 13:55:19 +0000 Subject: [PATCH 1663/2042] drivers: uart_nrfx_uart{,e}: on clear async pointers when enabled Fix a build error introduced in 9f02eeadf8, the async pointers are only available when UARTE_ANY_ASYNC is set. Signed-off-by: Fabio Baltieri --- drivers/serial/uart_nrfx_uart.c | 4 ++-- drivers/serial/uart_nrfx_uarte.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/serial/uart_nrfx_uart.c b/drivers/serial/uart_nrfx_uart.c index 96cb190a4878..4eb4e231474e 100644 --- a/drivers/serial/uart_nrfx_uart.c +++ b/drivers/serial/uart_nrfx_uart.c @@ -405,7 +405,7 @@ static int uart_nrfx_callback_set(const struct device *dev, uart0_cb.callback = callback; uart0_cb.user_data = user_data; -#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) && defined(CONFIG_UART_0_INTERRUPT_DRIVEN) irq_callback = NULL; irq_cb_data = NULL; #endif @@ -929,7 +929,7 @@ static void uart_nrfx_irq_callback_set(const struct device *dev, irq_callback = cb; irq_cb_data = cb_data; -#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) +#if defined(CONFIG_UART_0_ASYNC) && defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) uart0_cb.callback = NULL; uart0_cb.user_data = NULL; #endif diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 16877328e5f2..c2e8ede305de 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -937,7 +937,7 @@ static int uarte_nrfx_callback_set(const struct device *dev, data->async->user_callback = callback; data->async->user_data = user_data; -#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) +#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) && defined(UARTE_INTERRUPT_DRIVEN) data->int_driven->cb = NULL; data->int_driven->cb_data = NULL; #endif @@ -1681,7 +1681,7 @@ static void uarte_nrfx_irq_callback_set(const struct device *dev, data->int_driven->cb = cb; data->int_driven->cb_data = cb_data; -#if defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) +#if defined(UARTE_ANY_ASYNC) && defined(CONFIG_UART_EXCLUSIVE_API_CALLBACKS) data->async->user_callback = NULL; data->async->user_data = NULL; #endif From 8fb198bf015e4b2c850a3b8b0d45c081af8f6880 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Thu, 26 Jan 2023 14:52:38 -0800 Subject: [PATCH 1664/2042] board: Google Twinkie V2 This is a new board for the google Twinkie V2 tool. Signed-off-by: Jason Yuan --- boards/arm/google_twinkie_v2/Kconfig.board | 6 + .../arm/google_twinkie_v2/Kconfig.defconfig | 9 + boards/arm/google_twinkie_v2/board.cmake | 9 + boards/arm/google_twinkie_v2/doc/index.rst | 57 ++++++ .../google_twinkie_v2/google_twinkie_v2.dts | 182 ++++++++++++++++++ .../google_twinkie_v2/google_twinkie_v2.yaml | 14 ++ .../google_twinkie_v2_defconfig | 18 ++ 7 files changed, 295 insertions(+) create mode 100644 boards/arm/google_twinkie_v2/Kconfig.board create mode 100644 boards/arm/google_twinkie_v2/Kconfig.defconfig create mode 100644 boards/arm/google_twinkie_v2/board.cmake create mode 100644 boards/arm/google_twinkie_v2/doc/index.rst create mode 100644 boards/arm/google_twinkie_v2/google_twinkie_v2.dts create mode 100644 boards/arm/google_twinkie_v2/google_twinkie_v2.yaml create mode 100644 boards/arm/google_twinkie_v2/google_twinkie_v2_defconfig diff --git a/boards/arm/google_twinkie_v2/Kconfig.board b/boards/arm/google_twinkie_v2/Kconfig.board new file mode 100644 index 000000000000..45f571ca2b06 --- /dev/null +++ b/boards/arm/google_twinkie_v2/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_GOOGLE_TWINKIE_V2 + bool "Google Twinkie V2 Board" + depends on SOC_STM32G0B1XX diff --git a/boards/arm/google_twinkie_v2/Kconfig.defconfig b/boards/arm/google_twinkie_v2/Kconfig.defconfig new file mode 100644 index 000000000000..16350500a232 --- /dev/null +++ b/boards/arm/google_twinkie_v2/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright 2023 The ChromiumOS Authors +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_GOOGLE_TWINKIE_V2 + +config BOARD + default "google_twinkie_v2" + +endif # BOARD_GOOGLE_TWINKIE_V2 diff --git a/boards/arm/google_twinkie_v2/board.cmake b/boards/arm/google_twinkie_v2/board.cmake new file mode 100644 index 000000000000..21a528b2e8e6 --- /dev/null +++ b/boards/arm/google_twinkie_v2/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset=hw") +board_runner_args(jlink "--device=STM32G0B1RE" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/google_twinkie_v2/doc/index.rst b/boards/arm/google_twinkie_v2/doc/index.rst new file mode 100644 index 000000000000..216e5747b7fc --- /dev/null +++ b/boards/arm/google_twinkie_v2/doc/index.rst @@ -0,0 +1,57 @@ +.. _google_twinkie_v2_board: + +Google Twinkie V2 +################# + +Overview +******** + +Google Twinkie V2 is a reference board for the google power delivery analyzer +(PDA) Twinkie V2. + +Hardware +******** + +- STM32G0B1REI6 + +Supported Features +================== + +The following features are supported: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: +``boards/arm/google_twinkie_v2/google_twinkie_v2_defconfig`` + +Pin Mapping +=========== + +Default Zephyr Peripheral Mapping: +---------------------------------- +- CC1_BUF : PA1 +- CC2_BUF : PA3 +- VBUS_READ_BUF : PB11 +- CSA_VBUS : PC4 +- CSA_CC2 : PC5 + +Programming and Debugging +************************* + +Build application as usual for the ``google_twinkie_v2`` board, and flash +using dfu-util or J-Link. + +Debugging +========= + +Use SWD with a J-Link or ST-Link. diff --git a/boards/arm/google_twinkie_v2/google_twinkie_v2.dts b/boards/arm/google_twinkie_v2/google_twinkie_v2.dts new file mode 100644 index 000000000000..7a35f217f843 --- /dev/null +++ b/boards/arm/google_twinkie_v2/google_twinkie_v2.dts @@ -0,0 +1,182 @@ +/* + * Copyright 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "Google Twinkie V2"; + compatible = "google,twinkie-v2"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + red_led_0: led0 { + gpios = <&gpioc 8 GPIO_ACTIVE_LOW>; + }; + green_led_1: led1 { + gpios = <&gpiob 6 GPIO_ACTIVE_LOW>; + }; + blue_led_2: led2 { + gpios = <&gpiob 7 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + /* does not go to an actual button in current hardware. + * short TP5 to TP6 to activate. + */ + dfu_detect: dfudetect { + gpios = <&gpioa 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + }; + }; + + cc1_buf: cc1buf { + compatible = "voltage-divider"; + io-channels = <&adc1 1>; + output-ohms = <2000000000>; + }; + + cc2_buf: cc2buf { + compatible = "voltage-divider"; + io-channels = <&adc1 3>; + output-ohms = <2000000000>; + }; + + vbus_read_buf: vbusv { + compatible = "voltage-divider"; + io-channels = <&adc1 15>; + output-ohms = <68000>; + full-ohms = <(2000000 + 68000)>; + }; + + csa_vbus: vbusc { + compatible = "current-sense-amplifier"; + io-channels = <&adc1 17>; + sense-resistor-micro-ohms = <3000>; + sense-gain-mult = <100>; + }; + + csa_cc2: vconc { + compatible = "current-sense-amplifier"; + io-channels = <&adc1 18>; + sense-resistor-micro-ohms = <10000>; + sense-gain-mult = <25>; + }; + + aliases { + led0 = &red_led_0; + led1 = &green_led_1; + led2 = &blue_led_2; + bootloader-led0 = &blue_led_2; + vcc1 = &cc1_buf; + vcc2 = &cc2_buf; + vbus = &vbus_read_buf; + cbus = &csa_vbus; + ccon = &csa_cc2; + }; +}; + + +&adc1 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&adc1_in1_pa1 /* CC1_BUF */ + &adc1_in3_pa3 /* CC2_BUF */ + &adc1_in15_pb11 /* VBUS_READ_BUF */ + &adc1_in17_pc4 /* CSA_VBUS */ + &adc1_in18_pc5 /* CSA_CC2 */ + >; + pinctrl-names = "default"; + status = "okay"; + + channel@1 { + reg = <1>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@15 { + reg = <15>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@17 { + reg = <17>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; + + channel@18 { + reg = <18>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,vref-mv = <3300>; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div-m = <1>; + mul-n = <8>; + div-p = <2>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; +}; + +&iwdg { + status = "okay"; +}; + +&ucpd1 { + status = "okay"; + + psc-ucpdclk = <1>; + hbitclkdiv = <27>; + pinctrl-0 = <&ucpd1_cc1_pa8 &ucpd1_cc2_pb15>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/google_twinkie_v2/google_twinkie_v2.yaml b/boards/arm/google_twinkie_v2/google_twinkie_v2.yaml new file mode 100644 index 000000000000..77f018d136d8 --- /dev/null +++ b/boards/arm/google_twinkie_v2/google_twinkie_v2.yaml @@ -0,0 +1,14 @@ +identifier: google_twinkie_v2 +name: Google Twinkie V2 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 144 +flash: 512 +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm/google_twinkie_v2/google_twinkie_v2_defconfig b/boards/arm/google_twinkie_v2/google_twinkie_v2_defconfig new file mode 100644 index 000000000000..040be2d36725 --- /dev/null +++ b/boards/arm/google_twinkie_v2/google_twinkie_v2_defconfig @@ -0,0 +1,18 @@ +# Copyright 2023 The ChromiumOS Authors +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32G0X=y +CONFIG_SOC_STM32G0B1XX=y + +# GPIO Controller +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y + +# Enable MPU +CONFIG_ARM_MPU=y From ad555d08d8547ea00c5ab95593c76f9a3c8732e7 Mon Sep 17 00:00:00 2001 From: Jason Yuan Date: Tue, 7 Mar 2023 14:06:33 -0800 Subject: [PATCH 1665/2042] samples: boards: firmware for Twinkie V2 sample firmware for Twinkie V2 that toggles the LED based on charging status. Signed-off-by: Jason Yuan --- .../google_twinkie_v2_pda/CMakeLists.txt | 9 ++ .../boards/google_twinkie_v2_pda/README.rst | 25 +++++ samples/boards/google_twinkie_v2_pda/prj.conf | 4 + .../boards/google_twinkie_v2_pda/sample.yaml | 6 ++ .../boards/google_twinkie_v2_pda/src/meas.c | 102 ++++++++++++++++++ .../boards/google_twinkie_v2_pda/src/meas.h | 36 +++++++ .../boards/google_twinkie_v2_pda/src/view.c | 64 +++++++++++ 7 files changed, 246 insertions(+) create mode 100644 samples/boards/google_twinkie_v2_pda/CMakeLists.txt create mode 100644 samples/boards/google_twinkie_v2_pda/README.rst create mode 100644 samples/boards/google_twinkie_v2_pda/prj.conf create mode 100644 samples/boards/google_twinkie_v2_pda/sample.yaml create mode 100644 samples/boards/google_twinkie_v2_pda/src/meas.c create mode 100644 samples/boards/google_twinkie_v2_pda/src/meas.h create mode 100644 samples/boards/google_twinkie_v2_pda/src/view.c diff --git a/samples/boards/google_twinkie_v2_pda/CMakeLists.txt b/samples/boards/google_twinkie_v2_pda/CMakeLists.txt new file mode 100644 index 000000000000..188407e289ee --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/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(google_twinkie_v2) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/boards/google_twinkie_v2_pda/README.rst b/samples/boards/google_twinkie_v2_pda/README.rst new file mode 100644 index 000000000000..3d2d1b813c79 --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/README.rst @@ -0,0 +1,25 @@ +.. _google_twinkie_v2_pda: + +Twinkie Power Delivery +###################### + +Overview +******** + +This provides access to :ref:`Twinkie ` so you can try out +the supported features. + +Building and Running +******************** + +Build and flash Twinkie as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/google_pda + :board: google_twinkie_v2 + :goals: build flash + :compact: + +After flashing, the LED will start red. Putting the Twinkie in between any +usbc connection will cause the LED to turn blue. The LED will turn green instead +if the device is currently charging. diff --git a/samples/boards/google_twinkie_v2_pda/prj.conf b/samples/boards/google_twinkie_v2_pda/prj.conf new file mode 100644 index 000000000000..3e500a69630a --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ADC=y +CONFIG_ADC_STM32=y +CONFIG_GPIO=y +CONFIG_LED=y diff --git a/samples/boards/google_twinkie_v2_pda/sample.yaml b/samples/boards/google_twinkie_v2_pda/sample.yaml new file mode 100644 index 000000000000..8a9a47957547 --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/sample.yaml @@ -0,0 +1,6 @@ +sample: + name: Twinkie V2 usb Vbus snooper +tests: + sample.board.google_twinkie_v2: + platform_allow: google_twinkie_v2 + tags: usb diff --git a/samples/boards/google_twinkie_v2_pda/src/meas.c b/samples/boards/google_twinkie_v2_pda/src/meas.c new file mode 100644 index 000000000000..5d2ba9c793cc --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/src/meas.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/* The devicetree node identifier for the adc aliases. */ +#define VBUS_V_MEAS_NODE DT_ALIAS(vbus) +#define VBUS_C_MEAS_NODE DT_ALIAS(cbus) + +static const struct voltage_divider_dt_spec adc_vbus_v = + VOLTAGE_DIVIDER_DT_SPEC_GET(VBUS_V_MEAS_NODE); +static const struct current_sense_amplifier_dt_spec adc_vbus_c = + CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(VBUS_C_MEAS_NODE); + +int meas_vbus_v(int32_t *v) +{ + int ret; + int32_t sample_buffer = 0; + + /* Structure defining an ADC sampling sequence */ + struct adc_sequence sequence = { + .buffer = &sample_buffer, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(sample_buffer), + .calibrate = true, + }; + adc_sequence_init_dt(&adc_vbus_v.port, &sequence); + + ret = adc_read(adc_vbus_v.port.dev, &sequence); + if (ret != 0) { + return ret; + } + + *v = sample_buffer; + ret = adc_raw_to_millivolts_dt(&adc_vbus_v.port, v); + if (ret != 0) { + return ret; + } + + ret = voltage_divider_scale_dt(&adc_vbus_v, v); + if (ret != 0) { + return ret; + } + + return 0; +} + +int meas_vbus_c(int32_t *c) +{ + int ret; + int32_t sample_buffer = 0; + + /* Structure defining an ADC sampling sequence */ + struct adc_sequence sequence = { + .buffer = &sample_buffer, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(sample_buffer), + .calibrate = true, + }; + adc_sequence_init_dt(&adc_vbus_c.port, &sequence); + + ret = adc_read(adc_vbus_c.port.dev, &sequence); + if (ret != 0) { + return ret; + } + + *c = sample_buffer; + ret = adc_raw_to_millivolts_dt(&adc_vbus_c.port, c); + if (ret != 0) { + return ret; + } + + /* prescaling the voltage offset */ + *c -= adc_vbus_c.port.vref_mv / 2; + current_sense_amplifier_scale_dt(&adc_vbus_c, c); + + return 0; +} + +int meas_init(void) +{ + int ret; + + ret = adc_channel_setup_dt(&adc_vbus_v.port); + if (ret != 0) { + return ret; + } + + ret = adc_channel_setup_dt(&adc_vbus_c.port); + if (ret != 0) { + return ret; + } + + return 0; +} diff --git a/samples/boards/google_twinkie_v2_pda/src/meas.h b/samples/boards/google_twinkie_v2_pda/src/meas.h new file mode 100644 index 000000000000..5367510b460e --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/src/meas.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MEAS_H__ +#define __MEAS_H__ + +/** + * @brief Initializes the measurement module, sets up all the adc channels through the device tree + * binding + * + * @return 0 on success + */ +int meas_init(void); + +/** + * @brief Measure the voltage on VBUS + * + * @param v pointer where VBUS voltage, in millivolts, is stored + * + * @return 0 on success + */ +int meas_vbus_v(int32_t *v); + +/** + * @brief Measure the current on VBUS + * + * @param c pointer where VBUS current, in milliamperes, is stored + * + * @return 0 on success + */ +int meas_vbus_c(int32_t *c); + +#endif diff --git a/samples/boards/google_twinkie_v2_pda/src/view.c b/samples/boards/google_twinkie_v2_pda/src/view.c new file mode 100644 index 000000000000..0a5eb18764a4 --- /dev/null +++ b/samples/boards/google_twinkie_v2_pda/src/view.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 The ChromiumOS Authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "meas.h" + +enum led_color_t { + LED_RED, + LED_GREEN, + LED_BLUE, +}; + +static void set_led(const struct device *const led, enum led_color_t led_color) +{ + if (led_color != LED_RED) { + led_off(led, LED_RED); + } + if (led_color != LED_GREEN) { + led_off(led, LED_GREEN); + } + if (led_color != LED_BLUE) { + led_off(led, LED_BLUE); + } + led_on(led, led_color); +} + +#define CHARGING_VOLTAGE 5000 +#define CHARGING_CURRENT 1000 + +void main(void) +{ + meas_init(); + + const struct device *const led = DEVICE_DT_GET_ONE(gpio_leds); + int32_t vbus_v = 0; + int32_t vbus_c = 0; + + if (!device_is_ready(led)) { + return; + } + + while (1) { + meas_vbus_v(&vbus_v); + meas_vbus_c(&vbus_c); + + if (vbus_v > CHARGING_VOLTAGE) { + if (vbus_c > CHARGING_CURRENT) { + set_led(led, LED_GREEN); + } else { + set_led(led, LED_BLUE); + } + } else { + set_led(led, LED_RED); + } + + k_usleep(500); + } +} From 6587813ce03414a3e50dda61e29be92adc070281 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 27 Mar 2023 10:10:19 +0200 Subject: [PATCH 1666/2042] dts: bindings: pwm: add MAX31790 Add binding for the PWM and fan driver MAX37190. Signed-off-by: Benedikt Schmidt --- dts/bindings/pwm/maxim,max31790.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 dts/bindings/pwm/maxim,max31790.yaml diff --git a/dts/bindings/pwm/maxim,max31790.yaml b/dts/bindings/pwm/maxim,max31790.yaml new file mode 100644 index 000000000000..e6d2ec178817 --- /dev/null +++ b/dts/bindings/pwm/maxim,max31790.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Maxim MAX31790 6-channel I2C-bus PWM controller + +compatible: "maxim,max31790" + +include: [pwm-controller.yaml, i2c-device.yaml, base.yaml] + +properties: + reg: + required: true + + "#pwm-cells": + const: 2 + +pwm-cells: + - channel + - period From 44810b190c0ddd3a9d01bdcb24698f5163f23397 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 27 Mar 2023 10:10:54 +0200 Subject: [PATCH 1667/2042] drivers: pwm: implement MAX31790 Implement a driver for the PWM controller MAX31790. This driver also implements the RPM mode of the controller, which can be accessed via setting pwm_flags_t accordingly to macros defined in the driver specific header. Signed-off-by: Benedikt Schmidt --- drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.max31790 | 13 + drivers/pwm/pwm_max31790.c | 460 ++++++++++++++++++++++++++ include/zephyr/drivers/pwm/max31790.h | 71 ++++ 5 files changed, 547 insertions(+) create mode 100644 drivers/pwm/Kconfig.max31790 create mode 100644 drivers/pwm/pwm_max31790.c create mode 100644 include/zephyr/drivers/pwm/max31790.h diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index 981428ff3140..4f2fde5fd4fe 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -29,6 +29,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_GECKO pwm_gecko.c) zephyr_library_sources_ifdef(CONFIG_PWM_GD32 pwm_gd32.c) zephyr_library_sources_ifdef(CONFIG_PWM_RCAR pwm_rcar.c) zephyr_library_sources_ifdef(CONFIG_PWM_PCA9685 pwm_pca9685.c) +zephyr_library_sources_ifdef(CONFIG_PWM_MAX31790 pwm_max31790.c) zephyr_library_sources_ifdef(CONFIG_PWM_TEST pwm_test.c) zephyr_library_sources_ifdef(CONFIG_PWM_RPI_PICO pwm_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index f205dbb525a0..796989048f0b 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -81,6 +81,8 @@ source "drivers/pwm/Kconfig.rcar" source "drivers/pwm/Kconfig.pca9685" +source "drivers/pwm/Kconfig.max31790" + source "drivers/pwm/Kconfig.test" source "drivers/pwm/Kconfig.rpi_pico" diff --git a/drivers/pwm/Kconfig.max31790 b/drivers/pwm/Kconfig.max31790 new file mode 100644 index 000000000000..f513d7892773 --- /dev/null +++ b/drivers/pwm/Kconfig.max31790 @@ -0,0 +1,13 @@ +# +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# + +config PWM_MAX31790 + bool "MAX31790 6-channel I2C-bus PWM controller" + default y + depends on DT_HAS_MAXIM_MAX31790_ENABLED + select I2C + help + Enable driver for MAX31790 6-channel I2C-bus PWM controller. diff --git a/drivers/pwm/pwm_max31790.c b/drivers/pwm/pwm_max31790.c new file mode 100644 index 000000000000..dab9ee58159d --- /dev/null +++ b/drivers/pwm/pwm_max31790.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max31790 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(pwm_max31790, CONFIG_PWM_LOG_LEVEL); + +#define MAX31790_OSCILLATOR_FREQUENCY_IN_HZ 32768 +#define MAX31790_PWMTARGETDUTYCYCLE_MAXIMUM ((1 << 9) - 1) +#define MAX31790_CHANNEL_COUNT 6 + +struct max31790_config { + struct i2c_dt_spec i2c; +}; + +struct max31790_data { + struct k_mutex lock; +}; + +#define MAX37190_REGISTER_GLOBALCONFIGURATION 0x00 +#define MAX37190_REGISTER_PWMFREQUENCY 0x01 +#define MAX37190_REGISTER_FANCONFIGURATION(channel) (0x02 + channel) +#define MAX31790_REGISTER_PWMOUTTARGETDUTYCYCLEMSB(channel) (0x40 + 2 * channel) +#define MAX31790_REGISTER_FANDYNAMICS(channel) (0x08 + channel) +#define MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel) (0x50 + 2 * channel) + +#define MAX37190_GLOBALCONFIGURATION_STANDBY_BIT BIT(7) +#define MAX37190_FANXCONFIGURATION_MONITOR_BIT BIT(4) +#define MAX37190_FANXCONFIGURATION_TACHINPUTENABLED_BIT BIT(3) +#define MAX37190_FANXCONFIGURATION_LOCKEDROTOR_BIT BIT(2) +#define MAX37190_FANXCONFIGURATION_LOCKEDROTORPOLARITY_BIT BIT(1) +#define MAX37190_FANXCONFIGURATION_TACH_BIT BIT(0) +#define MAX37190_FANXCONFIGURATION_MODE_BIT BIT(7) +#define MAX37190_FANXDYNAMICS_ASYMMETRICRATEOFCHANGE_BIT BIT(1) + +#define MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH 3 +#define MAX37190_FANXDYNAMICS_SPEEDRANGE_POS 5 +#define MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH 3 +#define MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_POS 2 +#define MAX37190_PWMFREQUENCY_PWM_LENGTH 4 +#define MAX37190_PWMFREQUENCY_PWM4TO6_POS 4 +#define MAX37190_PWMFREQUENCY_PWM1TO3_LENGTH 4 +#define MAX37190_PWMFREQUENCY_PWM1TO3_POS 0 +#define MAX37190_FANXCONFIGURATION_SPINUP_LENGTH 2 +#define MAX37190_FANXCONFIGURATION_SPINUP_POS 5 + +#define PWM_MAX31790_FLAG_SPEED_RANGE_GET(flags) \ + FIELD_GET(GENMASK(MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH + \ + PWM_MAX31790_FLAG_SPEED_RANGE_POS - 1, \ + PWM_MAX31790_FLAG_SPEED_RANGE_POS), \ + flags) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_GET(flags) \ + FIELD_GET(GENMASK(MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH + \ + PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS - 1, \ + PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS), \ + flags) + +static void max31790_set_fandynamics_speedrange(uint8_t *destination, uint8_t value) +{ + uint8_t length = MAX37190_FANXDYNAMICS_SPEEDRANGE_LENGTH; + uint8_t pos = MAX37190_FANXDYNAMICS_SPEEDRANGE_POS; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static void max31790_set_fandynamics_pwmrateofchange(uint8_t *destination, uint8_t value) +{ + uint8_t length = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_LENGTH; + uint8_t pos = MAX37190_FANXDYNAMICS_PWMRATEOFCHANGE_POS; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static void max31790_set_pwmfrequency(uint8_t *destination, uint8_t channel, uint8_t value) +{ + uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH; + uint8_t pos = (channel / 3) * 4; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static uint8_t max31790_get_pwmfrequency(uint8_t value, uint8_t channel) +{ + uint8_t length = MAX37190_PWMFREQUENCY_PWM_LENGTH; + uint8_t pos = (channel / 3) * 4; + + return FIELD_GET(GENMASK(pos + length - 1, pos), value); +} + +static void max31790_set_fanconfiguration_spinup(uint8_t *destination, uint8_t value) +{ + uint8_t length = MAX37190_FANXCONFIGURATION_SPINUP_LENGTH; + uint8_t pos = MAX37190_FANXCONFIGURATION_SPINUP_POS; + + *destination &= ~GENMASK(pos + length - 1, pos); + *destination |= FIELD_PREP(GENMASK(pos + length - 1, pos), value); +} + +static int max31790_read_register(const struct device *dev, uint8_t address, uint8_t *value) +{ + const struct max31790_config *config = dev->config; + int result; + + result = i2c_reg_read_byte_dt(&config->i2c, address, value); + if (result != 0) { + LOG_ERR("unable to read register 0x%02X, error %i", address, result); + } + + LOG_DBG("read value 0x%02X from register 0x%02X", *value, address); + + return result; +} + +static int max31790_write_register_uint8(const struct device *dev, uint8_t address, uint8_t value) +{ + const struct max31790_config *config = dev->config; + int result; + + LOG_DBG("writing value 0x%02X to register 0x%02X", value, address); + result = i2c_reg_write_byte_dt(&config->i2c, address, value); + if (result != 0) { + LOG_ERR("unable to write register 0x%02X, error %i", address, result); + } + + return result; +} + +static int max31790_write_register_uint16(const struct device *dev, uint8_t address, uint16_t value) +{ + const struct max31790_config *config = dev->config; + int result; + uint8_t buffer[] = { + address, + value >> 8, + value, + }; + + LOG_DBG("writing value 0x%04X to address 0x%02X", value, address); + result = i2c_write_dt(&config->i2c, buffer, sizeof(buffer)); + if (result != 0) { + LOG_ERR("unable to write to address 0x%02X, error %i", address, result); + } + + return result; +} + +static bool max31790_convert_pwm_frequency_into_hz(uint16_t *result, uint8_t pwm_frequency) +{ + switch (pwm_frequency) { + case 0: + *result = 25; + return true; + case 1: + *result = 30; + return true; + case 2: + *result = 35; + return true; + case 3: + *result = 100; + return true; + case 4: + *result = 125; + return true; + case 5: + *result = 150; /* actually 149.7, according to the datasheet */ + return true; + case 6: + *result = 1250; + return true; + case 7: + *result = 1470; + return true; + case 8: + *result = 3570; + return true; + case 9: + *result = 5000; + return true; + case 10: + *result = 12500; + return true; + case 11: + *result = 25000; + return true; + default: + LOG_ERR("invalid value %i for PWM frequency register", pwm_frequency); + return false; + } +} + +static bool max31790_convert_pwm_frequency_into_register(uint8_t *result, uint32_t pwm_frequency) +{ + switch (pwm_frequency) { + case 25: + *result = 0; + return true; + case 30: + *result = 1; + return true; + case 35: + *result = 2; + return true; + case 100: + *result = 3; + return true; + case 125: + *result = 4; + return true; + case 150: /* actually 149.7, according to the datasheet */ + *result = 5; + return true; + case 1250: + *result = 6; + return true; + case 1470: + *result = 7; + return true; + case 3570: + *result = 8; + return true; + case 5000: + *result = 9; + return true; + case 12500: + *result = 10; + return true; + case 25000: + *result = 11; + return true; + default: + LOG_ERR("invalid value %i for PWM frequency in Hz", pwm_frequency); + return false; + } +} + +static int max31790_set_cycles_internal(const struct device *dev, uint32_t channel, + uint32_t period_count, uint32_t pulse_count, + pwm_flags_t flags) +{ + int result; + uint8_t pwm_frequency_channel_value; + uint8_t value_pwm_frequency; + uint8_t value_fan_configuration; + uint8_t value_fan_dynamics; + uint8_t value_speed_range = PWM_MAX31790_FLAG_SPEED_RANGE_GET(flags); + uint8_t value_pwm_rate_of_change = PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_GET(flags); + + if (!max31790_convert_pwm_frequency_into_register(&pwm_frequency_channel_value, + period_count)) { + return -EINVAL; + } + + result = max31790_read_register(dev, MAX37190_REGISTER_PWMFREQUENCY, &value_pwm_frequency); + if (result != 0) { + return result; + } + + max31790_set_pwmfrequency(&value_pwm_frequency, channel, pwm_frequency_channel_value); + + result = max31790_write_register_uint8(dev, MAX37190_REGISTER_PWMFREQUENCY, + value_pwm_frequency); + if (result != 0) { + return result; + } + + value_fan_configuration = 0; + value_fan_dynamics = 0; + + if (flags & PWM_MAX31790_FLAG_SPIN_UP) { + max31790_set_fanconfiguration_spinup(&value_fan_configuration, 2); + } else { + max31790_set_fanconfiguration_spinup(&value_fan_configuration, 0); + } + + value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MONITOR_BIT; + value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTOR_BIT; + value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_LOCKEDROTORPOLARITY_BIT; + value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_TACH_BIT; + value_fan_configuration |= MAX37190_FANXCONFIGURATION_TACHINPUTENABLED_BIT; + + max31790_set_fandynamics_speedrange(&value_fan_dynamics, value_speed_range); + max31790_set_fandynamics_pwmrateofchange(&value_fan_dynamics, value_pwm_rate_of_change); + value_fan_dynamics |= MAX37190_FANXDYNAMICS_ASYMMETRICRATEOFCHANGE_BIT; + + if ((flags & PWM_MAX31790_FLAG_RPM_MODE) == 0) { + LOG_DBG("PWM mode"); + uint16_t pwm_target_duty_cycle = + pulse_count * MAX31790_PWMTARGETDUTYCYCLE_MAXIMUM / period_count; + value_fan_configuration &= ~MAX37190_FANXCONFIGURATION_MODE_BIT; + + result = max31790_write_register_uint16( + dev, MAX31790_REGISTER_PWMOUTTARGETDUTYCYCLEMSB(channel), + pwm_target_duty_cycle); + if (result != 0) { + return result; + } + } else { + LOG_DBG("RPM mode"); + value_fan_configuration |= MAX37190_FANXCONFIGURATION_MODE_BIT; + + result = max31790_write_register_uint16( + dev, MAX31790_REGISTER_TACHTARGETCOUNTMSB(channel), pulse_count); + if (result != 0) { + return result; + } + } + + result = max31790_write_register_uint8(dev, MAX37190_REGISTER_FANCONFIGURATION(channel), + value_fan_configuration); + if (result != 0) { + return result; + } + + result = max31790_write_register_uint8(dev, MAX31790_REGISTER_FANDYNAMICS(channel), + value_fan_dynamics); + if (result != 0) { + return result; + } + + return 0; +} + +static int max31790_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_count, + uint32_t pulse_count, pwm_flags_t flags) +{ + struct max31790_data *data = dev->data; + int result; + + LOG_DBG("set period %i with pulse %i for channel %i and flags 0x%04X", period_count, + pulse_count, channel, flags); + + if (channel > MAX31790_CHANNEL_COUNT) { + LOG_ERR("invalid channel number %i", channel); + return -EINVAL; + } + + if (period_count == 0) { + LOG_ERR("period count must be > 0"); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + result = max31790_set_cycles_internal(dev, channel, period_count, pulse_count, flags); + k_mutex_unlock(&data->lock); + return result; +} + +static int max31790_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles) +{ + struct max31790_data *data = dev->data; + int result; + bool success; + uint8_t pwm_frequency_register; + uint8_t pwm_frequency = 1; + uint16_t pwm_frequency_in_hz; + + if (channel > MAX31790_CHANNEL_COUNT) { + LOG_ERR("invalid channel number %i", channel); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION, + &pwm_frequency_register); + + if (result != 0) { + k_mutex_unlock(&data->lock); + return result; + } + + pwm_frequency = max31790_get_pwmfrequency(pwm_frequency_register, channel); + success = max31790_convert_pwm_frequency_into_hz(&pwm_frequency_in_hz, pwm_frequency); + + if (!success) { + k_mutex_unlock(&data->lock); + return -EINVAL; + } + + *cycles = pwm_frequency_in_hz; + + k_mutex_unlock(&data->lock); + return 0; +} + +static const struct pwm_driver_api max31790_api = { + .set_cycles = max31790_set_cycles, + .get_cycles_per_sec = max31790_get_cycles_per_sec, +}; + +static int max31790_init(const struct device *dev) +{ + const struct max31790_config *config = dev->config; + struct max31790_data *data = dev->data; + int result; + uint8_t reg_value; + + k_mutex_init(&data->lock); + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("I2C device not ready"); + return -ENODEV; + } + + result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION, ®_value); + if (result != 0) { + return result; + } + + if ((reg_value & MAX37190_GLOBALCONFIGURATION_STANDBY_BIT) != 0) { + LOG_DBG("taking PWM controller out of standby"); + + reg_value &= ~MAX37190_GLOBALCONFIGURATION_STANDBY_BIT; + result = max31790_write_register_uint8(dev, MAX37190_REGISTER_GLOBALCONFIGURATION, + reg_value); + if (result != 0) { + return result; + } + + result = max31790_read_register(dev, MAX37190_REGISTER_GLOBALCONFIGURATION, + ®_value); + if (result != 0) { + return result; + } + + if ((reg_value & MAX37190_GLOBALCONFIGURATION_STANDBY_BIT) != 0) { + LOG_ERR("unable to take PWM controller out of standby"); + return -ENODEV; + } + } + + return 0; +} + +#define MAX31790_INIT(inst) \ + static const struct max31790_config max31790_##inst##_config = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + static struct max31790_data max31790_##inst##_data; \ + \ + DEVICE_DT_INST_DEFINE(inst, max31790_init, NULL, &max31790_##inst##_data, \ + &max31790_##inst##_config, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ + &max31790_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX31790_INIT); diff --git a/include/zephyr/drivers/pwm/max31790.h b/include/zephyr/drivers/pwm/max31790.h new file mode 100644 index 000000000000..6117487baafd --- /dev/null +++ b/include/zephyr/drivers/pwm/max31790.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_PWM_MAX31790_H_ +#define ZEPHYR_INCLUDE_DRIVERS_PWM_MAX31790_H_ + +/** + * @name custom PWM flags for MAX31790 + * These flags can be used with the PWM API in the upper 8 bits of pwm_flags_t + * They allow the usage of the RPM mode, which will cause the MAX31790 to + * measure the actual speed of the fan and automatically control it to the + * desired speed. + * @{ + */ +/** @cond INTERNAL_HIDDEN */ +#define PWM_MAX31790_FLAG_RPM_MODE_POS 8 +#define PWM_MAX31790_FLAG_SPEED_RANGE_POS 9 +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS 12 +#define PWM_MAX31790_FLAG_SPIN_UP_POS 15 +/** @endcond */ + +/*! + * @brief RPM mode + * + * Activating the RPM mode will cause the parameter pulse of @ref pwm_set_cycles + * to be interpreted as TACH target count. This basically is the number of internal + * pulses which occur during each TACH period. Hence, a bigger value means a slower + * rotation of the fan. The details about the TACH target count has to be calculated + * can be taken from the datasheet of the MAX31790. + */ +#define PWM_MAX31790_FLAG_RPM_MODE (1 << PWM_MAX31790_FLAG_RPM_MODE_POS) +/*! + * @brief speed range of fan + * + * This represents a multiplicator for the TACH count and should be chosen depending + * on the nominal RPM of the fan. A detailed table on how to choose a proper value + * can be found in the datasheet of the MAX31790. + */ +#define PWM_MAX31790_FLAG_SPEED_RANGE_1 (0 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +#define PWM_MAX31790_FLAG_SPEED_RANGE_2 (1 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +#define PWM_MAX31790_FLAG_SPEED_RANGE_4 (2 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +#define PWM_MAX31790_FLAG_SPEED_RANGE_8 (3 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +#define PWM_MAX31790_FLAG_SPEED_RANGE_16 (4 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +#define PWM_MAX31790_FLAG_SPEED_RANGE_32 (5 << PWM_MAX31790_FLAG_SPEED_RANGE_POS) +/*! + * @brief PWM rate of change + * + * Configures the internal control loop of the fan. Details about these values can be found + * in the datasheet of the MAX31790. + */ +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_0 (0 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_1 (1 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_2 (2 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_3 (3 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_4 (4 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_5 (5 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_6 (6 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +#define PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_7 (7 << PWM_MAX31790_FLAG_PWM_RATE_OF_CHANGE_POS) +/*! + * @brief activate spin up for fan + * + * This activates the spin up of the fan, which means that the controller will force the fan + * to maximum speed for a startup from a completely stopped state. + */ +#define PWM_MAX31790_FLAG_SPIN_UP (1 << PWM_MAX31790_FLAG_SPIN_UP_POS) +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_PWM_MAX31790_H_ */ From 732b54d82552048b0121a8f4357df4d7ac28b9a0 Mon Sep 17 00:00:00 2001 From: Benedikt Schmidt Date: Mon, 27 Mar 2023 11:05:01 +0200 Subject: [PATCH 1668/2042] tests: drivers: pwm: add MAX31790 Add MAX31790 to the build all tests of PWM. Signed-off-by: Benedikt Schmidt --- tests/drivers/build_all/pwm/max31790.overlay | 17 +++++++++++++++++ tests/drivers/build_all/pwm/testcase.yaml | 4 ++++ 2 files changed, 21 insertions(+) create mode 100644 tests/drivers/build_all/pwm/max31790.overlay diff --git a/tests/drivers/build_all/pwm/max31790.overlay b/tests/drivers/build_all/pwm/max31790.overlay new file mode 100644 index 000000000000..b92274a16737 --- /dev/null +++ b/tests/drivers/build_all/pwm/max31790.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + + &arduino_i2c { + status = "okay"; + clock-frequency = ; + + max31790_max31790: max31790@20 { + compatible = "maxim,max31790"; + status = "okay"; + reg = <0x20>; + pwm-controller; + #pwm-cells = <2>; + }; +}; diff --git a/tests/drivers/build_all/pwm/testcase.yaml b/tests/drivers/build_all/pwm/testcase.yaml index 864a5572feb4..be5af6253f40 100644 --- a/tests/drivers/build_all/pwm/testcase.yaml +++ b/tests/drivers/build_all/pwm/testcase.yaml @@ -69,3 +69,7 @@ tests: drivers.pwm.build.test: platform_allow: qemu_cortex_m3 tags: pwm_test + drivers.pwm.max31790.build: + platform_allow: nucleo_f429zi + extra_args: DTC_OVERLAY_FILE=max31790.overlay + tags: pwm_max31790 From 16f56658173c3338d459db87711bbee531431678 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 5 May 2023 03:10:12 +0000 Subject: [PATCH 1669/2042] drivers: display: display_rm68200: add DSI video mode flag Add DSI video mode flag to MIPI configuration, to indicate to MIPI drivers that this display uses video mode and must be refreshed constantly. Signed-off-by: Daniel DeGrasse --- drivers/display/display_rm68200.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/display/display_rm68200.c b/drivers/display/display_rm68200.c index d3108c874766..a89e0d0201a8 100644 --- a/drivers/display/display_rm68200.c +++ b/drivers/display/display_rm68200.c @@ -210,6 +210,8 @@ static int rm68200_init(const struct device *dev) mdev.data_lanes = config->num_of_lanes; mdev.pixfmt = config->pixel_format; + /* RM68200 runs in video mode */ + mdev.mode_flags = MIPI_DSI_MODE_VIDEO; ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); if (ret < 0) { From 867acef0709e6a3419a1dc874c03e93da281c8ee Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 5 May 2023 03:12:40 +0000 Subject: [PATCH 1670/2042] drivers: mipi_dsi: make DPI mode optional for dsi_mcux_2l driver Make DPI mode an optional configuration for the DSI MCUX 2L driver. DPI mode will only be enabled when the MIPI is attached in video mode, since this is when DPI formatted packets are expected. This will enable the DSI driver to also support DBI/command mode, for displays that use this format. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux_2l.c | 72 +++++++++++++--------- dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml | 4 +- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index 866c950ac4b6..9648653aa2b1 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -105,9 +105,17 @@ static int dsi_mcux_attach(const struct device *dev, DSI_InitDphy(config->base, &dphy_config, 0); } - /* Init DPI interface. */ - DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes, - dsi_pixel_clk_freq, dphy_bit_clk_freq); + /* + * If nxp,lcdif node is present, then the MIPI DSI driver will + * accept input on the DPI port from the LCDIF, and convert the output + * to DSI data. This is useful for video mode, where the LCDIF can + * constantly refresh the MIPI panel. + */ + if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO) { + /* Init DPI interface. */ + DSI_SetDpiConfig(config->base, &config->dpi_config, mdev->data_lanes, + dsi_pixel_clk_freq, dphy_bit_clk_freq); + } imxrt_post_init_display_interface(); @@ -200,35 +208,39 @@ static int mcux_mipi_dsi_init(const struct device *dev) return 0; } +#define MCUX_DSI_DPI_CONFIG(id) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(id), nxp_lcdif), \ + (.dpi_config = { \ + .dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \ + .pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet), \ + .videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \ + .bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode), \ + .pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width), \ + .panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height), \ + .polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vsync_active) ? \ + kDSI_DpiVsyncActiveHigh : \ + kDSI_DpiVsyncActiveLow) | \ + (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hsync_active) ? \ + kDSI_DpiHsyncActiveHigh : \ + kDSI_DpiHsyncActiveLow), \ + .hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hfront_porch), \ + .hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hback_porch), \ + .hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hsync_len), \ + .vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vfront_porch), \ + .vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vback_porch), \ + },)) + #define MCUX_MIPI_DSI_DEVICE(id) \ - static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = { \ + static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = { \ + MCUX_DSI_DPI_CONFIG(id) \ .base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \ - .dpi_config = { \ - .dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \ - .pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet), \ - .videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \ - .bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode), \ - .pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width), \ - .panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height), \ - .polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vsync_active) ? \ - kDSI_DpiVsyncActiveHigh : \ - kDSI_DpiVsyncActiveLow) | \ - (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hsync_active) ? \ - kDSI_DpiHsyncActiveHigh : \ - kDSI_DpiHsyncActiveLow), \ - .hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hfront_porch), \ - .hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hback_porch), \ - .hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hsync_len), \ - .vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vfront_porch), \ - .vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vback_porch), \ - }, \ .auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \ .dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0), \ .bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)), \ diff --git a/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml b/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml index b03c9a25e478..fc0a69870c58 100644 --- a/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml +++ b/dts/bindings/mipi-dsi/nxp,mipi-dsi-2l.yaml @@ -15,9 +15,9 @@ properties: nxp,lcdif: type: phandle - required: true description: - Instance of the LCDIF peripheral. + Instance of the LCDIF peripheral. Only required when using the MIPI + in video mode dpi-color-coding: type: string enum: From 21469a30d24a5917981ef9af5e369f95a6c2304d Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 15 Mar 2023 09:27:30 -0500 Subject: [PATCH 1671/2042] drivers: mipi_dsi: dsi_mcux_2l: enable DCS_LONG_WRITE using interrupts Fixup support for DCS_LONG_WRITE command in DSI MCUX 2L driver. Since long DCS commands may benefit from nonblocking I/O, add support for non blocking transfers to the DSI driver. This commit also corrects the interrupt number for the RT595, which uses the DSI_MCUX_2L IP block. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux_2l.c | 71 +++++++++++++++++++++++++++++-- dts/arm/nxp/nxp_rt5xx_common.dtsi | 2 +- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index 9648653aa2b1..044b27bef78f 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -8,6 +8,7 @@ #define DT_DRV_COMPAT nxp_mipi_dsi_2l +#include #include #include #include @@ -29,14 +30,31 @@ struct mcux_mipi_dsi_config { const struct device *pixel_clk_dev; clock_control_subsys_t pixel_clk_subsys; uint32_t dphy_ref_freq; + void (*irq_config_func)(const struct device *dev); }; +struct mcux_mipi_dsi_data { + dsi_handle_t mipi_handle; + struct k_sem transfer_sem; +}; + +/* Callback for DSI transfer completion, called in ISR context */ +static void dsi_transfer_complete(MIPI_DSI_HOST_Type *base, + dsi_handle_t *handle, status_t status, void *userData) +{ + struct mcux_mipi_dsi_data *data = userData; + + k_sem_give(&data->transfer_sem); +} + static int dsi_mcux_attach(const struct device *dev, uint8_t channel, const struct mipi_dsi_device *mdev) { const struct mcux_mipi_dsi_config *config = dev->config; + struct mcux_mipi_dsi_data *data = dev->data; dsi_dphy_config_t dphy_config; + status_t status; dsi_config_t dsi_config; uint32_t dphy_bit_clk_freq; uint32_t dphy_esc_clk_freq; @@ -50,6 +68,14 @@ static int dsi_mcux_attach(const struct device *dev, /* Init the DSI module. */ DSI_Init(config->base, &dsi_config); + /* Create transfer handle */ + status = DSI_TransferCreateHandle(config->base, &data->mipi_handle, + dsi_transfer_complete, data); + + if (status != kStatus_Success) { + return -ENODEV; + } + /* Get the DPHY bit clock frequency */ if (clock_control_get_rate(config->bit_clk_dev, config->bit_clk_subsys, @@ -126,6 +152,7 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, struct mipi_dsi_msg *msg) { const struct mcux_mipi_dsi_config *config = dev->config; + struct mcux_mipi_dsi_data *data = dev->data; dsi_transfer_t dsi_xfer = {0}; status_t status; @@ -145,12 +172,16 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam; break; case MIPI_DSI_DCS_SHORT_WRITE_PARAM: - __fallthrough; - case MIPI_DSI_DCS_LONG_WRITE: dsi_xfer.sendDscCmd = true; dsi_xfer.dscCmd = msg->cmd; dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam; break; + case MIPI_DSI_DCS_LONG_WRITE: + dsi_xfer.sendDscCmd = true; + dsi_xfer.dscCmd = msg->cmd; + dsi_xfer.flags = kDSI_TransferUseHighSpeed; + dsi_xfer.txDataType = kDSI_TxDataDcsLongWr; + break; case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam; break; @@ -172,7 +203,15 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, return -ENOTSUP; } - status = DSI_TransferBlocking(config->base, &dsi_xfer); + if (msg->type == MIPI_DSI_DCS_LONG_WRITE) { + /* Use a non-blocking transfer */ + status = DSI_TransferNonBlocking(config->base, + &data->mipi_handle, &dsi_xfer); + /* Wait for transfer completion */ + k_sem_take(&data->transfer_sem, K_FOREVER); + } else { + status = DSI_TransferBlocking(config->base, &dsi_xfer); + } if (status != kStatus_Success) { LOG_ERR("Transmission failed"); @@ -194,9 +233,24 @@ static struct mipi_dsi_driver_api dsi_mcux_api = { .transfer = dsi_mcux_transfer, }; +static int mipi_dsi_isr(const struct device *dev) +{ + const struct mcux_mipi_dsi_config *config = dev->config; + struct mcux_mipi_dsi_data *data = dev->data; + + DSI_TransferHandleIRQ(config->base, &data->mipi_handle); + return 0; +} + static int mcux_mipi_dsi_init(const struct device *dev) { const struct mcux_mipi_dsi_config *config = dev->config; + struct mcux_mipi_dsi_data *data = dev->data; + + /* Enable IRQ */ + config->irq_config_func(dev); + + k_sem_init(&data->transfer_sem, 0, 1); imxrt_pre_init_display_interface(); @@ -238,9 +292,16 @@ static int mcux_mipi_dsi_init(const struct device *dev) },)) #define MCUX_MIPI_DSI_DEVICE(id) \ + static void mipi_dsi_##n##_irq_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), \ + mipi_dsi_isr, DEVICE_DT_INST_GET(id), 0); \ + irq_enable(DT_INST_IRQN(id)); \ + } \ static const struct mcux_mipi_dsi_config mipi_dsi_config_##id = { \ MCUX_DSI_DPI_CONFIG(id) \ .base = (MIPI_DSI_HOST_Type *)DT_INST_REG_ADDR(id), \ + .irq_config_func = mipi_dsi_##n##_irq_config_func, \ .auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \ .dphy_ref_freq = DT_INST_PROP_OR(id, dphy_ref_frequency, 0), \ .bit_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(id, dphy)), \ @@ -253,10 +314,12 @@ static int mcux_mipi_dsi_init(const struct device *dev) .pixel_clk_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_NAME(id, pixel, name), \ }; \ + \ + static struct mcux_mipi_dsi_data mipi_dsi_data_##id; \ DEVICE_DT_INST_DEFINE(id, \ &mcux_mipi_dsi_init, \ NULL, \ - NULL, \ + &mipi_dsi_data_##id, \ &mipi_dsi_config_##id, \ POST_KERNEL, \ CONFIG_MIPI_DSI_INIT_PRIORITY, \ diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 3b4bf2ec380c..034c45a904d5 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -497,7 +497,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x31000 0x1000>; - interrupts = <87 0>; + interrupts = <71 0>; clocks = <&clkctl1 MCUX_MIPI_DSI_DPHY_CLK>, <&clkctl1 MCUX_MIPI_DSI_ESC_CLK>, <&clkctl1 MCUX_LCDIF_PIXEL_CLK>; From d1ef34440e0e3ef9277cac42e53ac8711889c3e2 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 5 May 2023 04:02:54 +0000 Subject: [PATCH 1672/2042] drivers: mipi_dsi: dsi_mcux: make DPI mode optional Only setup DPI input from LCDIF if MODE_VIDEO is set, as this is the the only case where input from the LCDIF would be required to drive the display. Do not populate the dpi_config structure unless a reference the the NXP LCDIF device is provided, since this is the output device providing DPI data. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux.c | 68 +++++++++++++-------- dts/bindings/mipi-dsi/nxp,imx-mipi-dsi.yaml | 4 +- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux.c b/drivers/mipi_dsi/dsi_mcux.c index c865a9f914aa..5de31424d92b 100644 --- a/drivers/mipi_dsi/dsi_mcux.c +++ b/drivers/mipi_dsi/dsi_mcux.c @@ -198,10 +198,20 @@ static int dsi_mcux_attach(const struct device *dev, mipi_dsi_dphy_bit_clk_hz = DSI_InitDphy((MIPI_DSI_Type *)&config->base, &dphy_config, mipi_dsi_dphy_ref_clk_hz); + LOG_DBG("DPHY clock set to %u", mipi_dsi_dphy_bit_clk_hz); - /* Init DPI interface. */ - DSI_SetDpiConfig((MIPI_DSI_Type *)&config->base, &config->dpi_config, mdev->data_lanes, - mipi_dsi_dpi_clk_hz, mipi_dsi_dphy_bit_clk_hz); + /* + * If nxp,lcdif node is present, then the MIPI DSI driver will + * accept input on the DPI port from the LCDIF, and convert the output + * to DSI data. This is useful for video mode, where the LCDIF can + * constantly refresh the MIPI panel. + */ + if (mdev->mode_flags & MIPI_DSI_MODE_VIDEO) { + /* Init DPI interface. */ + DSI_SetDpiConfig((MIPI_DSI_Type *)&config->base, + &config->dpi_config, mdev->data_lanes, + mipi_dsi_dpi_clk_hz, mipi_dsi_dphy_bit_clk_hz); + } imxrt_post_init_display_interface(); @@ -288,6 +298,33 @@ static int display_mcux_mipi_dsi_init(const struct device *dev) return 0; } +#define MCUX_DSI_DPI_CONFIG(id) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(id), nxp_lcdif), \ + (.dpi_config = { \ + .dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \ + .pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet), \ + .videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \ + .bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode), \ + .pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width), \ + .panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height), \ + .polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hsync_active) ? \ + kDSI_DpiHsyncActiveHigh : kDSI_DpiHsyncActiveLow) | \ + (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vsync_active) ? \ + kDSI_DpiVsyncActiveHigh : kDSI_DpiVsyncActiveLow), \ + .hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hfront_porch), \ + .hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hback_porch), \ + .hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), hsync_len), \ + .vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vfront_porch), \ + .vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ + display_timings), vback_porch), \ + },)) + #define MCUX_MIPI_DSI_DEVICE(id) \ static const struct display_mcux_mipi_dsi_config display_mcux_mipi_dsi_config_##id = { \ .base = { \ @@ -297,30 +334,7 @@ static int display_mcux_mipi_dsi_init(const struct device *dev) .dphy = (DSI_HOST_NXP_FDSOI28_DPHY_INTFC_Type *) \ DT_INST_REG_ADDR_BY_IDX(id, 3), \ }, \ - .dpi_config = { \ - .dpiColorCoding = DT_INST_ENUM_IDX(id, dpi_color_coding), \ - .pixelPacket = DT_INST_ENUM_IDX(id, dpi_pixel_packet), \ - .videoMode = DT_INST_ENUM_IDX(id, dpi_video_mode), \ - .bllpMode = DT_INST_ENUM_IDX(id, dpi_bllp_mode), \ - .pixelPayloadSize = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, width), \ - .panelHeight = DT_INST_PROP_BY_PHANDLE(id, nxp_lcdif, height), \ - .polarityFlags = (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hsync_active) ? \ - kDSI_DpiHsyncActiveHigh : kDSI_DpiHsyncActiveLow) | \ - (DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vsync_active) ? \ - kDSI_DpiVsyncActiveHigh : kDSI_DpiVsyncActiveLow), \ - .hfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hfront_porch), \ - .hbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hback_porch), \ - .hsw = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), hsync_len), \ - .vfp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vfront_porch), \ - .vbp = DT_PROP(DT_CHILD(DT_INST_PHANDLE(id, nxp_lcdif), \ - display_timings), vback_porch), \ - }, \ + MCUX_DSI_DPI_CONFIG(id) \ .auto_insert_eotp = DT_INST_PROP(id, autoinsert_eotp), \ .phy_clock = DT_INST_PROP(id, phy_clock), \ }; \ diff --git a/dts/bindings/mipi-dsi/nxp,imx-mipi-dsi.yaml b/dts/bindings/mipi-dsi/nxp,imx-mipi-dsi.yaml index 216c8bdc1dd9..8a781e185180 100644 --- a/dts/bindings/mipi-dsi/nxp,imx-mipi-dsi.yaml +++ b/dts/bindings/mipi-dsi/nxp,imx-mipi-dsi.yaml @@ -15,9 +15,9 @@ properties: nxp,lcdif: type: phandle - required: true description: - Instance of the LCDIF peripheral. + Instance of the LCDIF peripheral. Only required when using the MIPI + DSI in video mode. dpi-color-coding: type: string From 35a210be48a4ee545887c327aa428513abb600a8 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 5 May 2023 04:04:48 +0000 Subject: [PATCH 1673/2042] drivers: mipi_dsi: dsi_mcux: fix support for DCS_LONG_WRITE command Fix support for DCS long write command in DSI mcux driver, to enable use with displays that require this command for full support. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mipi_dsi/dsi_mcux.c b/drivers/mipi_dsi/dsi_mcux.c index 5de31424d92b..6326ace79121 100644 --- a/drivers/mipi_dsi/dsi_mcux.c +++ b/drivers/mipi_dsi/dsi_mcux.c @@ -242,12 +242,16 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, dsi_xfer.txDataType = kDSI_TxDataDcsShortWrNoParam; break; case MIPI_DSI_DCS_SHORT_WRITE_PARAM: - __fallthrough; - case MIPI_DSI_DCS_LONG_WRITE: dsi_xfer.sendDscCmd = true; dsi_xfer.dscCmd = msg->cmd; dsi_xfer.txDataType = kDSI_TxDataDcsShortWrOneParam; break; + case MIPI_DSI_DCS_LONG_WRITE: + dsi_xfer.sendDscCmd = true; + dsi_xfer.dscCmd = msg->cmd; + dsi_xfer.flags = kDSI_TransferUseHighSpeed; + dsi_xfer.txDataType = kDSI_TxDataDcsLongWr; + break; case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: dsi_xfer.txDataType = kDSI_TxDataGenShortWrNoParam; break; From 3e77ef8860f951be3c17505dfe05c6323763e785 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 12 Jul 2023 10:35:13 -0500 Subject: [PATCH 1674/2042] boards: mimxrt595_evk_cm33: only set LV_Z_VDB_CUSTOM_SECTION for shield Only set LV_Z_VDB_CUSTOM_SECTION for the RK055HDMIPI4M shield, as it is only required when using displays that require a large framebuffer. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt595_evk/Kconfig.defconfig | 4 ---- boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/boards/arm/mimxrt595_evk/Kconfig.defconfig b/boards/arm/mimxrt595_evk/Kconfig.defconfig index fa01c5ac93fc..d7dbcc1ad7a1 100644 --- a/boards/arm/mimxrt595_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt595_evk/Kconfig.defconfig @@ -19,10 +19,6 @@ config FXOS8700_DRDY_INT1 default y depends on FXOS8700_TRIGGER -# Allocate LVGL buffers in custom section -config LV_Z_VBD_CUSTOM_SECTION - default y if LVGL - if DMA_MCUX_LPC # Memory from the heap pool is used to allocate DMA descriptors for diff --git a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf index 68157838ef52..bf60c87c6934 100644 --- a/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf +++ b/boards/shields/rk055hdmipi4m/boards/mimxrt595_evk_cm33.conf @@ -6,6 +6,7 @@ # Use external framebuffer memory CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM=y +CONFIG_LV_Z_VBD_CUSTOM_SECTION=y # Use FlexSPI2 for framebuffer (pSRAM is present on this bus) CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_ADDR=0x38400000 # M33 core and LCDIF both access FlexSPI2 through the same cache, From e692e57c682a3ed01433ad97db01b7672c0d2525 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 15 Mar 2023 09:32:38 -0500 Subject: [PATCH 1675/2042] drivers: display: add support for RM67162 controller Add support for RM67162 MIPI display controller. This controller is configured to run in MIPI command/DBI mode, driving a 400x392 OLED display. Signed-off-by: Daniel DeGrasse --- drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.rm67162 | 10 + drivers/display/display_rm67162.c | 610 ++++++++++++++++++++++ dts/bindings/display/raydium,rm67162.yaml | 31 ++ 5 files changed, 653 insertions(+) create mode 100644 drivers/display/Kconfig.rm67162 create mode 100644 drivers/display/display_rm67162.c create mode 100644 dts/bindings/display/raydium,rm67162.yaml diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index fd655f1894f8..30e31ed2b116 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_ST7789V display_st7789v.c) zephyr_library_sources_ifdef(CONFIG_ST7735R display_st7735r.c) 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_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 35521077d44c..6654f14d87e7 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -33,6 +33,7 @@ source "drivers/display/Kconfig.stm32_ltdc" source "drivers/display/Kconfig.uc81xx" source "drivers/display/Kconfig.dummy" source "drivers/display/Kconfig.ls0xx" +source "drivers/display/Kconfig.rm67162" source "drivers/display/Kconfig.rm68200" source "drivers/display/Kconfig.max7219" source "drivers/display/Kconfig.intel_multibootfb" diff --git a/drivers/display/Kconfig.rm67162 b/drivers/display/Kconfig.rm67162 new file mode 100644 index 000000000000..9f8e01362428 --- /dev/null +++ b/drivers/display/Kconfig.rm67162 @@ -0,0 +1,10 @@ +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +config RM67162 + bool "RM67162 display driver" + default y + select MIPI_DSI + depends on DT_HAS_RAYDIUM_RM67162_ENABLED + help + Enable driver for RM67162 display driver. diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c new file mode 100644 index 000000000000..c23abef6dc0d --- /dev/null +++ b/drivers/display/display_rm67162.c @@ -0,0 +1,610 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raydium_rm67162 + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(rm67162, CONFIG_DISPLAY_LOG_LEVEL); + +/* + * These commands are taken from NXP's MCUXpresso SDK. + * Additional documentation is added where possible, but the + * Manufacture command set pages are not described in the datasheet + */ +static const struct { + uint8_t cmd; + uint8_t param; +} rm67162_init_400x392[] = { + /* CMD Mode switch, select manufacture command set page 0 */ + {.cmd = 0xFE, .param = 0x01}, + {.cmd = 0x06, .param = 0x62}, + {.cmd = 0x0E, .param = 0x80}, + {.cmd = 0x0F, .param = 0x80}, + {.cmd = 0x10, .param = 0x71}, + {.cmd = 0x13, .param = 0x81}, + {.cmd = 0x14, .param = 0x81}, + {.cmd = 0x15, .param = 0x82}, + {.cmd = 0x16, .param = 0x82}, + {.cmd = 0x18, .param = 0x88}, + {.cmd = 0x19, .param = 0x55}, + {.cmd = 0x1A, .param = 0x10}, + {.cmd = 0x1C, .param = 0x99}, + {.cmd = 0x1D, .param = 0x03}, + {.cmd = 0x1E, .param = 0x03}, + {.cmd = 0x1F, .param = 0x03}, + {.cmd = 0x20, .param = 0x03}, + {.cmd = 0x25, .param = 0x03}, + {.cmd = 0x26, .param = 0x8D}, + {.cmd = 0x2A, .param = 0x03}, + {.cmd = 0x2B, .param = 0x8D}, + {.cmd = 0x36, .param = 0x00}, + {.cmd = 0x37, .param = 0x10}, + {.cmd = 0x3A, .param = 0x00}, + {.cmd = 0x3B, .param = 0x00}, + {.cmd = 0x3D, .param = 0x20}, + {.cmd = 0x3F, .param = 0x3A}, + {.cmd = 0x40, .param = 0x30}, + {.cmd = 0x41, .param = 0x30}, + {.cmd = 0x42, .param = 0x33}, + {.cmd = 0x43, .param = 0x22}, + {.cmd = 0x44, .param = 0x11}, + {.cmd = 0x45, .param = 0x66}, + {.cmd = 0x46, .param = 0x55}, + {.cmd = 0x47, .param = 0x44}, + {.cmd = 0x4C, .param = 0x33}, + {.cmd = 0x4D, .param = 0x22}, + {.cmd = 0x4E, .param = 0x11}, + {.cmd = 0x4F, .param = 0x66}, + {.cmd = 0x50, .param = 0x55}, + {.cmd = 0x51, .param = 0x44}, + {.cmd = 0x57, .param = 0xB3}, + {.cmd = 0x6B, .param = 0x19}, + {.cmd = 0x70, .param = 0x55}, + {.cmd = 0x74, .param = 0x0C}, + + /* VGMP/VGSP Voltage Control (select manufacture command set page 1 ) */ + {.cmd = 0xFE, .param = 0x02}, + {.cmd = 0x9B, .param = 0x40}, + {.cmd = 0x9C, .param = 0x67}, + {.cmd = 0x9D, .param = 0x20}, + + /* VGMP/VGSP Voltage Control (select manufacture command set page 2 ) */ + {.cmd = 0xFE, .param = 0x03}, + {.cmd = 0x9B, .param = 0x40}, + {.cmd = 0x9C, .param = 0x67}, + {.cmd = 0x9D, .param = 0x20}, + + /* VSR Command (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x5D, .param = 0x10}, + + /* VSR1 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x00, .param = 0x8D}, + {.cmd = 0x01, .param = 0x00}, + {.cmd = 0x02, .param = 0x01}, + {.cmd = 0x03, .param = 0x01}, + {.cmd = 0x04, .param = 0x10}, + {.cmd = 0x05, .param = 0x01}, + {.cmd = 0x06, .param = 0xA7}, + {.cmd = 0x07, .param = 0x20}, + {.cmd = 0x08, .param = 0x00}, + + /* VSR2 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x09, .param = 0xC2}, + {.cmd = 0x0A, .param = 0x00}, + {.cmd = 0x0B, .param = 0x02}, + {.cmd = 0x0C, .param = 0x01}, + {.cmd = 0x0D, .param = 0x40}, + {.cmd = 0x0E, .param = 0x06}, + {.cmd = 0x0F, .param = 0x01}, + {.cmd = 0x10, .param = 0xA7}, + {.cmd = 0x11, .param = 0x00}, + + /* VSR3 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x12, .param = 0xC2}, + {.cmd = 0x13, .param = 0x00}, + {.cmd = 0x14, .param = 0x02}, + {.cmd = 0x15, .param = 0x01}, + {.cmd = 0x16, .param = 0x40}, + {.cmd = 0x17, .param = 0x07}, + {.cmd = 0x18, .param = 0x01}, + {.cmd = 0x19, .param = 0xA7}, + {.cmd = 0x1A, .param = 0x00}, + + /* VSR4 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x1B, .param = 0x82}, + {.cmd = 0x1C, .param = 0x00}, + {.cmd = 0x1D, .param = 0xFF}, + {.cmd = 0x1E, .param = 0x05}, + {.cmd = 0x1F, .param = 0x60}, + {.cmd = 0x20, .param = 0x02}, + {.cmd = 0x21, .param = 0x01}, + {.cmd = 0x22, .param = 0x7C}, + {.cmd = 0x23, .param = 0x00}, + + /* VSR5 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x24, .param = 0xC2}, + {.cmd = 0x25, .param = 0x00}, + {.cmd = 0x26, .param = 0x04}, + {.cmd = 0x27, .param = 0x02}, + {.cmd = 0x28, .param = 0x70}, + {.cmd = 0x29, .param = 0x05}, + {.cmd = 0x2A, .param = 0x74}, + {.cmd = 0x2B, .param = 0x8D}, + {.cmd = 0x2D, .param = 0x00}, + + /* VSR6 Timing Set (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x2F, .param = 0xC2}, + {.cmd = 0x30, .param = 0x00}, + {.cmd = 0x31, .param = 0x04}, + {.cmd = 0x32, .param = 0x02}, + {.cmd = 0x33, .param = 0x70}, + {.cmd = 0x34, .param = 0x07}, + {.cmd = 0x35, .param = 0x74}, + {.cmd = 0x36, .param = 0x8D}, + {.cmd = 0x37, .param = 0x00}, + + /* VSR Marping command (select manufacture command set page 3 ) */ + {.cmd = 0xFE, .param = 0x04}, + {.cmd = 0x5E, .param = 0x20}, + {.cmd = 0x5F, .param = 0x31}, + {.cmd = 0x60, .param = 0x54}, + {.cmd = 0x61, .param = 0x76}, + {.cmd = 0x62, .param = 0x98}, + + /* Select manufacture command set page 4 */ + /* ELVSS -2.4V(RT4723). 0x15: RT4723. 0x01: RT4723B. 0x17: STAM1332. */ + {.cmd = 0xFE, .param = 0x05}, + {.cmd = 0x05, .param = 0x15}, + {.cmd = 0x2A, .param = 0x04}, + {.cmd = 0x91, .param = 0x00}, + + /* Select user command set */ + {.cmd = 0xFE, .param = 0x00}, + /* Set tearing effect signal to only output at V-blank*/ + {.cmd = 0x35, .param = 0x00}, +}; + +#define DSI_TX_MAX_PAYLOAD_BYTE (64U * 4U) + +struct rm67162_config { + const struct device *mipi_dsi; + uint8_t channel; + uint8_t num_of_lanes; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec bl_gpio; + const struct gpio_dt_spec te_gpio; + uint16_t panel_width; + uint16_t panel_height; +}; + + +struct rm67162_data { + uint8_t pixel_format; + uint8_t bytes_per_pixel; + struct gpio_callback te_gpio_cb; + struct k_sem te_sem; +}; + +static void rm67162_te_isr_handler(const struct device *gpio_dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct rm67162_data *data = CONTAINER_OF(cb, struct rm67162_data, te_gpio_cb); + + k_sem_give(&data->te_sem); +} + +static int rm67162_init(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + struct mipi_dsi_device mdev = {0}; + int ret; + uint32_t i; + uint8_t cmd, param; + + /* Attach to MIPI DSI host */ + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = data->pixel_format; + + ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not attach to MIPI-DSI host"); + return ret; + } + + if (config->reset_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + + /* + * Power to the display has been enabled via the regulator fixed api during + * regulator init. Per datasheet, we must wait at least 10ms before + * starting reset sequence after power on. + */ + k_sleep(K_MSEC(10)); + /* Start reset sequence */ + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + LOG_ERR("Could not pull reset low (%d)", ret); + return ret; + } + /* Per datasheet, reset low pulse width should be at least 10usec */ + k_sleep(K_USEC(30)); + gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + LOG_ERR("Could not pull reset high (%d)", ret); + return ret; + } + /* + * It is necessary to wait at least 120msec after releasing reset, + * before sending additional commands. This delay can be 5msec + * if we are certain the display module is in SLEEP IN state, + * but this is not guaranteed (for example, with a warm reset) + */ + k_sleep(K_MSEC(150)); + } + + /* Now, write initialization settings for display, running at 400x392 */ + for (i = 0; i < ARRAY_SIZE(rm67162_init_400x392); i++) { + cmd = rm67162_init_400x392[i].cmd; + param = rm67162_init_400x392[i].param; + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd, ¶m, 1); + if (ret < 0) { + return ret; + } + } + + /* Set pixel format */ + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + } else { + /* Unsupported pixel format */ + LOG_ERR("Pixel format not supported"); + return -ENOTSUP; + } + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); + if (ret < 0) { + return ret; + } + + /* Delay 50 ms before exiting sleep mode */ + k_sleep(K_MSEC(50)); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + return ret; + } + /* + * We must wait 5 ms after exiting sleep mode before sending additional + * commands. If we intend to enter sleep mode, we must delay + * 120 ms before sending that command. To be safe, delay 150ms + */ + k_sleep(K_MSEC(150)); + + /* Setup backlight */ + if (config->bl_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure bl GPIO (%d)", ret); + return ret; + } + } + + if (config->te_gpio.port != NULL) { + /* Setup TE pin */ + ret = gpio_pin_configure_dt(&config->te_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure TE GPIO (%d)", ret); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->te_gpio, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure TE interrupt (%d)", ret); + return ret; + } + + /* Init and install GPIO callback */ + gpio_init_callback(&data->te_gpio_cb, rm67162_te_isr_handler, + BIT(config->te_gpio.pin)); + gpio_add_callback(config->te_gpio.port, &data->te_gpio_cb); + + /* Setup te pin semaphore */ + k_sem_init(&data->te_sem, 0, 1); + } + + /* Now, enable display */ + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_DISPLAY_ON, NULL, 0); +} + +/* Helper to write data to rm67162 via MIPI interface. */ +static int rm67162_write_buf(const struct device *dev, bool first_write, + const uint8_t *src, uint32_t len) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + int ret = 0; + uint32_t max_write, wlen; + uint8_t cmd; + + /* + * Max write len: one byte is reserved for DSC command, and + * pixels should not be split across transfers + */ + max_write = ((DSI_TX_MAX_PAYLOAD_BYTE - 1) / data->bytes_per_pixel) * + data->bytes_per_pixel; + if (first_write) { + cmd = MIPI_DCS_WRITE_MEMORY_START; + } else { + cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + while (len > 0) { + /* Cap each tx to max DSI APB transfer size */ + wlen = MIN(max_write, len); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + cmd, src, wlen); + if (ret < 0) { + return ret; + } + /* Advance source pointer and decrement remaining */ + src += wlen; + len -= wlen; + /* All future commands should use WRITE_MEMORY_CONTINUE */ + cmd = MIPI_DCS_WRITE_MEMORY_CONTINUE; + } + return ret; +} + +static int rm67162_write(const struct device *dev, const uint16_t x, + const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + int ret; + uint16_t start, end, h_idx; + const uint8_t *src; + bool first_cmd; + uint8_t param[4]; + + LOG_DBG("W=%d, H=%d @%d,%d", desc->width, desc->height, x, y); + + /* + * RM67162 runs in MIPI DBI mode. This means we can use command mode + * to write to the video memory buffer on the RM67162 control IC, + * and the IC will update the display automatically. + */ + + /* Set column address of target area */ + /* First two bytes are starting X coordinate */ + start = x; + end = x + desc->width - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_COLUMN_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + + /* Set page address of target area */ + /* First two bytes are starting Y coordinate */ + start = y; + end = y + desc->height - 1; + sys_put_be16(start, ¶m[0]); + /* Second two bytes are ending X coordinate */ + sys_put_be16(end, ¶m[2]); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PAGE_ADDRESS, param, + sizeof(param)); + if (ret < 0) { + return ret; + } + + /* + * Now, write the framebuffer. If the tearing effect GPIO is present, + * wait until the display controller issues an interrupt (which will + * 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); + } + 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); + } + } + src = buf; + first_cmd = true; + + if (desc->pitch == desc->width) { + /* Buffer is contiguous, we can perform entire transfer */ + rm67162_write_buf(dev, first_cmd, src, + desc->height * desc->width * data->bytes_per_pixel); + } else { + /* Buffer is not contiguous, we must write each line separately */ + for (h_idx = 0; h_idx < desc->height; h_idx++) { + rm67162_write_buf(dev, first_cmd, src, + desc->width * data->bytes_per_pixel); + first_cmd = false; + /* The pitch is not equal to width, account for it here */ + src += data->bytes_per_pixel * (desc->pitch - desc->width); + } + } + + return 0; +} + +static void rm67162_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct rm67162_config *config = dev->config; + const struct rm67162_data *data = dev->data; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->panel_width; + capabilities->y_resolution = config->panel_height; + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_RGB_888; + switch (data->pixel_format) { + case MIPI_DSI_PIXFMT_RGB565: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_565; + break; + case MIPI_DSI_PIXFMT_RGB888: + capabilities->current_pixel_format = PIXEL_FORMAT_RGB_888; + break; + default: + LOG_WRN("Unsupported display format"); + /* Other display formats not implemented */ + break; + } + capabilities->current_orientation = DISPLAY_ORIENTATION_ROTATED_90; +} + +static int rm67162_blanking_off(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 1); + } else { + return -ENOTSUP; + } +} + +static int rm67162_blanking_on(const struct device *dev) +{ + const struct rm67162_config *config = dev->config; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 0); + } else { + return -ENOTSUP; + } +} + +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) +{ + const struct rm67162_config *config = dev->config; + struct rm67162_data *data = dev->data; + uint8_t param; + + switch (pixel_format) { + case PIXEL_FORMAT_RGB_565: + data->pixel_format = MIPI_DSI_PIXFMT_RGB565; + return 0; + case PIXEL_FORMAT_RGB_888: + data->pixel_format = MIPI_DSI_PIXFMT_RGB888; + return 0; + default: + /* Other display formats not implemented */ + return -ENOTSUP; + } + if (data->pixel_format == MIPI_DSI_PIXFMT_RGB888) { + param = MIPI_DCS_PIXEL_FORMAT_24BIT; + data->bytes_per_pixel = 3; + } else if (data->pixel_format == MIPI_DSI_PIXFMT_RGB565) { + param = MIPI_DCS_PIXEL_FORMAT_16BIT; + data->bytes_per_pixel = 2; + } + return mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_PIXEL_FORMAT, ¶m, 1); +} + +static int rm67162_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + return 0; + } + LOG_ERR("Changing display orientation not implemented"); + return -ENOTSUP; +} + +static const struct display_driver_api rm67162_api = { + .blanking_on = rm67162_blanking_on, + .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, +}; + +#define RM67162_PANEL(id) \ + static const struct rm67162_config rm67162_config_##id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(id)), \ + .num_of_lanes = DT_INST_PROP_BY_IDX(id, data_lanes, 0), \ + .channel = DT_INST_REG_ADDR(id), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(id, reset_gpios, {0}), \ + .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(id, bl_gpios, {0}), \ + .te_gpio = GPIO_DT_SPEC_INST_GET_OR(id, te_gpios, {0}), \ + .panel_width = DT_INST_PROP(id, width), \ + .panel_height = DT_INST_PROP(id, height), \ + }; \ + static struct rm67162_data rm67162_data_##id = { \ + .pixel_format = DT_INST_PROP(id, pixel_format), \ + }; \ + DEVICE_DT_INST_DEFINE(id, \ + &rm67162_init, \ + NULL, \ + &rm67162_data_##id, \ + &rm67162_config_##id, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ + &rm67162_api); + +DT_INST_FOREACH_STATUS_OKAY(RM67162_PANEL) diff --git a/dts/bindings/display/raydium,rm67162.yaml b/dts/bindings/display/raydium,rm67162.yaml new file mode 100644 index 000000000000..3614a861d1f5 --- /dev/null +++ b/dts/bindings/display/raydium,rm67162.yaml @@ -0,0 +1,31 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Raydium RM67162 Panel + +compatible: "raydium,rm67162" + +include: [mipi-dsi-device.yaml, display-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + + bl-gpios: + type: phandle-array + description: | + The BLn pin is asserted to control the backlight of the panel. + The sensor receives this as an active-high signal. + + te-gpios: + type: phandle-array + description: | + The tearing effect pin is asserted by the controller at a display + VSYNC interval. This permits the controller to send new display + data during a VSYNC interval, removing tearing. From 066c40bbb054a869b9ef620c20fb65261ff7d555 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 16 Mar 2023 12:06:29 -0500 Subject: [PATCH 1676/2042] drivers: input: ft5336: Add support for reset GPIO and FT3267 IC Add support for resetting controller at boot, and update FT5336 documentation to indicate that the FT3267 IC is also supported by this driver. Signed-off-by: Daniel DeGrasse --- drivers/input/Kconfig.ft5336 | 5 +++-- drivers/input/input_ft5336.c | 26 ++++++++++++++++++++++-- dts/bindings/input/focaltech,ft5336.yaml | 12 +++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/input/Kconfig.ft5336 b/drivers/input/Kconfig.ft5336 index 4b8eea98e148..f817616a1d60 100644 --- a/drivers/input/Kconfig.ft5336 +++ b/drivers/input/Kconfig.ft5336 @@ -3,14 +3,15 @@ # SPDX-License-Identifier: Apache-2.0 menuconfig INPUT_FT5336 - bool "FT5XX6/FT6XX6 capacitive touch panel driver" + bool "FT3267/FT5XX6/FT6XX6 capacitive touch panel driver" default y depends on DT_HAS_FOCALTECH_FT5336_ENABLED select I2C help Enable driver for multiple Focaltech capacitive touch panel controllers. This driver should support FT5x06, FT5606, FT5x16, - FT6x06, Ft6x36, FT5x06i, FT5336, FT3316, FT5436i, FT5336i and FT5x46. + FT6x06, Ft6x36, FT5x06i, FT5336, FT3316, FT5436i, FT3267, + FT5336i and FT5x46. if INPUT_FT5336 diff --git a/drivers/input/input_ft5336.c b/drivers/input/input_ft5336.c index 6b05b9cf1948..33bc7efa2bd2 100644 --- a/drivers/input/input_ft5336.c +++ b/drivers/input/input_ft5336.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 NXP + * Copyright (c) 2020,2023 NXP * Copyright (c) 2020 Mark Olsson * Copyright (c) 2020 Teslabs Engineering S.L. * @@ -39,6 +39,7 @@ LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); struct ft5336_config { /** I2C bus. */ struct i2c_dt_spec bus; + struct gpio_dt_spec reset_gpio; #ifdef CONFIG_INPUT_FT5336_INTERRUPT /** Interrupt GPIO information. */ struct gpio_dt_spec int_gpio; @@ -140,6 +141,7 @@ static int ft5336_init(const struct device *dev) { const struct ft5336_config *config = dev->config; struct ft5336_data *data = dev->data; + int r; if (!device_is_ready(config->bus.bus)) { LOG_ERR("I2C controller device not ready"); @@ -150,8 +152,27 @@ static int ft5336_init(const struct device *dev) k_work_init(&data->work, ft5336_work_handler); + if (config->reset_gpio.port != NULL) { + /* Enable reset GPIO, and pull down */ + r = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (r < 0) { + LOG_ERR("Could not enable reset GPIO"); + return r; + } + /* + * Datasheet requires reset be held low 1 ms, or + * 1 ms + 100us if powering on controller. Hold low for + * 5 ms to be safe. + */ + k_sleep(K_MSEC(5)); + /* Pull reset pin high to complete reset sequence */ + r = gpio_pin_set_dt(&config->reset_gpio, 1); + if (r < 0) { + return r; + } + } + #ifdef CONFIG_INPUT_FT5336_INTERRUPT - int r; if (!device_is_ready(config->int_gpio.port)) { LOG_ERR("Interrupt GPIO controller device not ready"); @@ -189,6 +210,7 @@ static int ft5336_init(const struct device *dev) #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),)) \ }; \ diff --git a/dts/bindings/input/focaltech,ft5336.yaml b/dts/bindings/input/focaltech,ft5336.yaml index 3898d1821523..d58ba18df809 100644 --- a/dts/bindings/input/focaltech,ft5336.yaml +++ b/dts/bindings/input/focaltech,ft5336.yaml @@ -1,7 +1,7 @@ -# Copyright (c) 2020 NXP +# Copyright (c) 2020,2023 NXP # SPDX-License-Identifier: Apache-2.0 -description: FT5XX6/FT6XX6 capacitive touch panels +description: FT3267/FT5XX6/FT6XX6 capacitive touch panels compatible: "focaltech,ft5336" @@ -10,3 +10,11 @@ include: i2c-device.yaml properties: int-gpios: type: phandle-array + description: | + Interrupt GPIO. Used by the controller to signal touch data is + available. Active low. + reset-gpios: + type: phandle-array + description: | + Reset GPIO. Used to reset the controller during initialization, and + to wake it from hibernation mode. Active low. From f907f9592da7e6590fc0833536fb21015dc1867d Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 15 Mar 2023 09:41:44 -0500 Subject: [PATCH 1677/2042] boards: shields: add g1120b0mipi watch display Add g1120b0mipi watch display to shields. This shield is currently supported with the RT595 and RT1170 EVK. The shield contains a 400x392 circular OLED watch display, with an integrated RM67162 display controller Note that the touchscreen IC can be driven by the FT5336 driver, with the following changes: - the FT3267 reports touch data as inverted from the FT5336, so LVGL must be made aware of this via CONFIG_LV_Z_POINTER_KSCAN_INVERT_Y - the FT3267 reports the X and Y coordinates as swapped from the FT5336. To resolve this, the RM67162 driver reports the display as rotated by 90 degrees. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 3 +- boards/arm/mimxrt595_evk/doc/index.rst | 3 +- boards/shields/g1120b0mipi/Kconfig.defconfig | 44 ++++++++++++ boards/shields/g1120b0mipi/Kconfig.shield | 5 ++ .../boards/mimxrt1170_evk_cm7.overlay | 12 ++++ .../boards/mimxrt1170_evkb_cm7.overlay | 12 ++++ boards/shields/g1120b0mipi/doc/index.rst | 68 +++++++++++++++++++ .../shields/g1120b0mipi/g1120b0mipi.overlay | 58 ++++++++++++++++ 8 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 boards/shields/g1120b0mipi/Kconfig.defconfig create mode 100644 boards/shields/g1120b0mipi/Kconfig.shield create mode 100644 boards/shields/g1120b0mipi/boards/mimxrt1170_evk_cm7.overlay create mode 100644 boards/shields/g1120b0mipi/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 boards/shields/g1120b0mipi/doc/index.rst create mode 100644 boards/shields/g1120b0mipi/g1120b0mipi.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 033f2d823bc0..f62bd6c63dac 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -131,7 +131,8 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) | HWINFO | on-chip | Unique device serial number | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ | DISPLAY | on-chip | eLCDIF; MIPI-DSI. Tested with | Supported (M7) | Supported (M7) | -| | | :ref:`rk055hdmipi4m` shield | | | +| | | :ref:`rk055hdmipi4m` and | | | +| | | :ref:`g1120b0mipi` shields | | | +-----------+------------+-------------------------------------+-----------------+-----------------+ | ACMP | on-chip | analog comparator | Supported | No support | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index a21b97459382..a7b53ea763ce 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -109,7 +109,8 @@ already supported, which can also be re-used on this mimxrt595_evk board: | I2S | on-chip | i2s | +-----------+------------+-------------------------------------+ | DISPLAY | on-chip | LCDIF; MIPI-DSI. Tested with | -| | | :ref:`rk055hdmipi4m` shield | +| | | :ref:`rk055hdmipi4m` and | +| | | :ref:`g1120b0mipi` display shields | +-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/shields/g1120b0mipi/Kconfig.defconfig b/boards/shields/g1120b0mipi/Kconfig.defconfig new file mode 100644 index 000000000000..33d235181945 --- /dev/null +++ b/boards/shields/g1120b0mipi/Kconfig.defconfig @@ -0,0 +1,44 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_G1120B0MIPI + +if LVGL +# Enable input subsystem for FT5336 driver +config INPUT + default y + +config INPUT_FT5336_INTERRUPT + default y + +# KSCAN subsystem must be enabled for KSCAN input shim driver +config KSCAN + default y + +# Configure LVGL to use touchscreen with KSCAN API +config LV_Z_POINTER_KSCAN + default y + +# Y coordinates need to be inverted for this controller. Note that +# the RM67162 display driver also reports the display orientation as rotated +# by 90 degrees, so LVGL will read coordinates correctly. +config LV_Z_POINTER_KSCAN_INVERT_Y + default y + +# Swap 16 bit color setting for LVGL, to send high byte first +config LV_COLOR_16_SWAP + default y + +config LV_Z_VDB_SIZE + default 16 + +config LV_DPI_DEF + default 128 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 +endchoice + +endif # LVGL + +endif # SHIELD_G1120B0MIPI diff --git a/boards/shields/g1120b0mipi/Kconfig.shield b/boards/shields/g1120b0mipi/Kconfig.shield new file mode 100644 index 000000000000..4c15ae49f826 --- /dev/null +++ b/boards/shields/g1120b0mipi/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_G1120B0MIPI + def_bool $(shields_list_contains,g1120b0mipi) diff --git a/boards/shields/g1120b0mipi/boards/mimxrt1170_evk_cm7.overlay b/boards/shields/g1120b0mipi/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 000000000000..5669c8440f22 --- /dev/null +++ b/boards/shields/g1120b0mipi/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,12 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&rm67162_g1120b0mipi { + /* R414 is not populated on this board, so LPTE signal is not + * connected. remove the property from the display. + */ + /delete-property/ te-gpios; +}; diff --git a/boards/shields/g1120b0mipi/boards/mimxrt1170_evkb_cm7.overlay b/boards/shields/g1120b0mipi/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 000000000000..5669c8440f22 --- /dev/null +++ b/boards/shields/g1120b0mipi/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,12 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&rm67162_g1120b0mipi { + /* R414 is not populated on this board, so LPTE signal is not + * connected. remove the property from the display. + */ + /delete-property/ te-gpios; +}; diff --git a/boards/shields/g1120b0mipi/doc/index.rst b/boards/shields/g1120b0mipi/doc/index.rst new file mode 100644 index 000000000000..ccfeae058335 --- /dev/null +++ b/boards/shields/g1120b0mipi/doc/index.rst @@ -0,0 +1,68 @@ +.. _g1120b0mipi: + +G1120B0MIPI MIPI Display +########################## + +Overview +******** + +The G1120B0MIPI is a 1.2 inch circular AMOLED display, 390x390 pixels, with a +1-lane MIPI interface. This display connects to the i.MX RT595 Evaluation Kit. + + +More information about the shield can be found +at the `G1120B0MIPI product page`_. + +This display uses a 40 pin FPC interface, which is available on many +NXP EVKs. + +Pins Assignment of the G1120B0MIPI MIPI Display +========================================================== + ++-----------------------+------------------------+ +| FPC Connector Pin | Function | ++=======================+========================+ +| 1 | LED backlight cathode | ++-----------------------+------------------------+ +| 21 | Controller reset | ++-----------------------+------------------------+ +| 22 | Controller LPTE | ++-----------------------+------------------------+ +| 26 | Touch ctrl I2C SDA | ++-----------------------+------------------------+ +| 27 | Touch ctrl I2C SCL | ++-----------------------+------------------------+ +| 28 | Touch ctrl reset | ++-----------------------+------------------------+ +| 29 | Touch ctrl interrupt | ++-----------------------+------------------------+ +| 32 | LCD power enable | ++-----------------------+------------------------+ +| 34 | Backlight power enable | ++-----------------------+------------------------+ + +Requirements +************ + +This shield can only be used with a board which provides a configuration +for the 40 pin FPC interface + +Programming +*********** + +Set ``-DSHIELD=g1120b0mipi`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/display + :board: mimxrt595_evk_cm33 + :shield: g1120b0mipi + :goals: build + +References +********** + +.. target-notes:: + +.. _G1120B0MIPI product page: + https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/1-2-wearable-display-g1120b0mipi:G1120B0MIPI diff --git a/boards/shields/g1120b0mipi/g1120b0mipi.overlay b/boards/shields/g1120b0mipi/g1120b0mipi.overlay new file mode 100644 index 000000000000..a60fac33121c --- /dev/null +++ b/boards/shields/g1120b0mipi/g1120b0mipi.overlay @@ -0,0 +1,58 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/{ + aliases { + kscan0 = &kscan_input_g1120b0mipi; + }; + + chosen { + zephyr,display = &rm67162_g1120b0mipi; + zephyr,keyboard-scan = &kscan_input_g1120b0mipi; + }; + + en_mipi_display_g1120b0mipi: enable-mipi-display { + compatible = "regulator-fixed"; + regulator-name = "en_mipi_display"; + enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; +}; + +&nxp_mipi_i2c { + status = "okay"; + ft3267@38 { + /* + * Note- the actual controller present on this IC is a FT3267, + * but the FT35336 driver in Zephyr supports this IC. + */ + compatible = "focaltech,ft5336"; + reg = <0x38>; + int-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + kscan_input_g1120b0mipi: kscan-input { + compatible = "zephyr,kscan-input"; + }; + }; +}; + +&zephyr_mipi_dsi { + status = "okay"; + autoinsert-eotp; + phy-clock = <316800000>; + rm67162_g1120b0mipi: rm67162@0 { + status = "okay"; + compatible = "raydium,rm67162"; + reg = <0x0>; + reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; + bl-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; + te-gpios = <&nxp_mipi_connector 22 GPIO_ACTIVE_HIGH>; + data-lanes = <1>; + width = <400>; + height = <392>; + pixel-format = ; + }; +}; From b4cd531e2ceaf60d7c00dd01b9b13b0368d39ec4 Mon Sep 17 00:00:00 2001 From: Manimaran A Date: Wed, 31 May 2023 19:42:06 +0530 Subject: [PATCH 1678/2042] drivers: bbled: pwm: mchp: BBLED low power mode updated Updated the driver to support low power mode. Introduced "enable-low-power" flag in device tree to control(on/off) low power mode. If flag added in DTS, during sleep BBLED will switch off the LEDs. Otherwise BBLED will continue the configured blinking pattern on LEDs. Signed-off-by: Manimaran A --- drivers/pwm/pwm_mchp_xec_bbled.c | 77 +++++++++++++++++++- dts/bindings/pwm/microchip,xec-pwmbbled.yaml | 12 +++ 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm_mchp_xec_bbled.c b/drivers/pwm/pwm_mchp_xec_bbled.c index 0b1083e0e312..63b673ca02ee 100644 --- a/drivers/pwm/pwm_mchp_xec_bbled.c +++ b/drivers/pwm/pwm_mchp_xec_bbled.c @@ -18,6 +18,7 @@ #endif #include #include +#include #include @@ -104,6 +105,7 @@ LOG_MODULE_REGISTER(pwmbbled_mchp_xec, CONFIG_PWM_LOG_LEVEL); #define XEC_PWM_BBLED_CLKSEL_1 XEC_PWM_BBLED_CLKSEL_PCR_SLOW #define XEC_PWM_BBLED_CLKSEL_2 XEC_PWM_BBLED_CLKSEL_AHB_48M + struct bbled_regs { volatile uint32_t config; volatile uint32_t limits; @@ -118,12 +120,17 @@ struct bbled_regs { struct pwm_bbled_xec_config { struct bbled_regs * const regs; + const struct pinctrl_dev_config *pcfg; uint8_t girq; uint8_t girq_pos; uint8_t pcr_idx; uint8_t pcr_pos; uint8_t clk_sel; - const struct pinctrl_dev_config *pcfg; + bool enable_low_power_32K; +}; + +struct bbled_xec_data { + uint32_t config; }; /* Compute BBLED PWM delay factor to produce requested frequency. @@ -318,6 +325,63 @@ static int pwm_bbled_xec_get_cycles_per_sec(const struct device *dev, return 0; } + +#ifdef CONFIG_PM_DEVICE +static int pwm_bbled_xec_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct pwm_bbled_xec_config *const devcfg = dev->config; + struct bbled_regs * const regs = devcfg->regs; + struct bbled_xec_data * const data = dev->data; + int ret = 0; + + /* 32K core clock is not gated by PCR in sleep, so BBLED can blink the LED even + * in sleep, if it is configured to use 32K clock. If we want to control it + * we shall use flag "enable_low_power_32K". + * This flag dont have effect on 48M clock. Since it is gated by PCR in sleep, BBLED + * will not get clock during sleep. + */ + if ((!devcfg->enable_low_power_32K) && + (!(regs->config & BIT(XEC_PWM_BBLED_CFG_CLK_SRC_48M_POS)))) { + return ret; + } + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + LOG_ERR("XEC BBLED pinctrl setup failed (%d)", ret); + } + + /* Turn on BBLED only if it is ON before sleep */ + if ((data->config & XEC_PWM_BBLED_CFG_MODE_MSK) != XEC_PWM_BBLED_CFG_MODE_OFF) { + + regs->config |= (data->config & XEC_PWM_BBLED_CFG_MODE_MSK); + regs->config |= BIT(XEC_PWM_BBLED_CFG_EN_UPDATE_POS); + + data->config = XEC_PWM_BBLED_CFG_MODE_OFF; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + if ((regs->config & XEC_PWM_BBLED_CFG_MODE_MSK) != XEC_PWM_BBLED_CFG_MODE_OFF) { + /* Do copy first, then clear mode. */ + data->config = regs->config; + + regs->config &= ~(XEC_PWM_BBLED_CFG_MODE_MSK); + } + + ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_SLEEP); + /* pinctrl-1 does not exist. */ + if (ret == -ENOENT) { + ret = 0; + } + break; + default: + ret = -ENOTSUP; + } + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + static const struct pwm_driver_api pwm_bbled_xec_driver_api = { .set_cycles = pwm_bbled_xec_set_cycles, .get_cycles_per_sec = pwm_bbled_xec_get_cycles_per_sec, @@ -355,19 +419,24 @@ static int pwm_bbled_xec_init(const struct device *dev) .girq_pos = (uint8_t)(DT_INST_PROP_BY_IDX(0, girqs, 1)), \ .pcr_idx = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 0), \ .pcr_pos = (uint8_t)DT_INST_PROP_BY_IDX(inst, pcrs, 1), \ - .clk_sel = UTIL_CAT(XEC_PWM_BBLED_CLKSEL_, XEC_PWM_BBLED_CLKSEL(n)), \ + .clk_sel = UTIL_CAT(XEC_PWM_BBLED_CLKSEL_, XEC_PWM_BBLED_CLKSEL(inst)), \ + .enable_low_power_32K = DT_INST_PROP(inst, enable_low_power_32k),\ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; #define XEC_PWM_BBLED_DEVICE_INIT(index) \ \ + static struct bbled_xec_data bbled_xec_data_##index; \ + \ PINCTRL_DT_INST_DEFINE(index); \ \ XEC_PWM_BBLED_CONFIG(index); \ \ + PM_DEVICE_DT_INST_DEFINE(index, pwm_bbled_xec_pm_action); \ + \ DEVICE_DT_INST_DEFINE(index, &pwm_bbled_xec_init, \ - NULL, \ - NULL, \ + PM_DEVICE_DT_INST_GET(index), \ + &bbled_xec_data_##index, \ &pwm_bbled_xec_config_##index, POST_KERNEL, \ CONFIG_PWM_INIT_PRIORITY, \ &pwm_bbled_xec_driver_api); diff --git a/dts/bindings/pwm/microchip,xec-pwmbbled.yaml b/dts/bindings/pwm/microchip,xec-pwmbbled.yaml index 00d30921d563..6ee66fafcd9a 100644 --- a/dts/bindings/pwm/microchip,xec-pwmbbled.yaml +++ b/dts/bindings/pwm/microchip,xec-pwmbbled.yaml @@ -46,6 +46,18 @@ properties: "#pwm-cells": const: 2 + enable-low-power-32k: + type: boolean + description: | + BBLED has two clock inputs. + - Main system clock (48MHz) + - 32KHz Core clock (32.768KHz) + When BBLED enter into Suspend state, 48MHz clock will be switched off by + PCR(Power, Clock and Reset) block. But 32KHz Core clock will be available to BBLED. + There may be a product requirement, either to blink (or) not blink LED in Suspend state. + Flag "enable-low-power-32k" shall be used along with 32KHz clock to blink (or) not blink + the LED in Suspend state. + pwm-cells: - channel - period From 6d99e38a84a4ca86b5b3ae097469fe3c3aa4d18c Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 15:20:43 +0000 Subject: [PATCH 1679/2042] scripts: check_init_priorities: ignore zephyr,cdc-acm-uart The new stack zephyr,cdc-acm-uart driver has two separate init path, one of which kicks in before the USB stack to start buffering log messages. This generates a false positive in the build time priority checking, adding a check to ignore that compatible entirely. Signed-off-by: Fabio Baltieri --- scripts/build/check_init_priorities.py | 14 +++++++++ scripts/build/check_init_priorities_test.py | 35 +++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/scripts/build/check_init_priorities.py b/scripts/build/check_init_priorities.py index 23616162673c..444bb428f5ef 100755 --- a/scripts/build/check_init_priorities.py +++ b/scripts/build/check_init_priorities.py @@ -54,6 +54,14 @@ # opposite of the device tree inferred dependency. _INVERTED_PRIORITY_COMPATIBLES = frozenset() +# List of compatibles for nodes where we don't check the priority. +_IGNORE_COMPATIBLES = frozenset([ + # There is no direct dependency between the CDC ACM UART and the USB + # device controller, the logical connection is established after USB + # device support is enabled. + "zephyr,cdc-acm-uart", + ]) + class Priority: """Parses and holds a device initialization priority. @@ -230,6 +238,12 @@ def _check_dep(self, dev_ord, dep_ord): dev_node = self._ord2node[dev_ord] dep_node = self._ord2node[dep_ord] + if dev_node._binding: + dev_compat = dev_node._binding.compatible + if dev_compat in _IGNORE_COMPATIBLES: + self.log.info(f"Ignoring priority: {dev_node._binding.compatible}") + return + if dev_node._binding and dep_node._binding: dev_compat = dev_node._binding.compatible dep_compat = dep_node._binding.compatible diff --git a/scripts/build/check_init_priorities_test.py b/scripts/build/check_init_priorities_test.py index 0ee5741b431e..e704b1f35dea 100755 --- a/scripts/build/check_init_priorities_test.py +++ b/scripts/build/check_init_priorities_test.py @@ -266,6 +266,8 @@ def test_check_swapped(self, mock_vinit): validator.warnings = 0 validator.errors = 0 + save_inverted_priorities = check_init_priorities._INVERTED_PRIORITY_COMPATIBLES + check_init_priorities._INVERTED_PRIORITY_COMPATIBLES = set([("compat-3", "compat-1")]) validator._ord2node = {1: mock.Mock(), 3: mock.Mock()} @@ -282,6 +284,39 @@ def test_check_swapped(self, mock_vinit): mock.call("Swapped priority: compat-3, compat-1"), mock.call("/3 20 > /1 10"), ]) + self.assertEqual(validator.warnings, 0) + self.assertEqual(validator.errors, 0) + + check_init_priorities._INVERTED_PRIORITY_COMPATIBLES = save_inverted_priorities + + @mock.patch("check_init_priorities.Validator.__init__", return_value=None) + def test_check_ignored(self, mock_vinit): + validator = check_init_priorities.Validator("", "", None) + validator.log = mock.Mock() + validator.warnings = 0 + validator.errors = 0 + + save_ignore_compatibles = check_init_priorities._IGNORE_COMPATIBLES + + check_init_priorities._IGNORE_COMPATIBLES = set(["compat-3"]) + + validator._ord2node = {1: mock.Mock(), 3: mock.Mock()} + validator._ord2node[1]._binding.compatible = "compat-1" + validator._ord2node[1].path = "/1" + validator._ord2node[3]._binding.compatible = "compat-3" + validator._ord2node[3].path = "/3" + + validator._dev_priorities = {1: 20, 3: 10} + + validator._check_dep(3, 1) + + self.assertListEqual(validator.log.info.call_args_list, [ + mock.call("Ignoring priority: compat-3"), + ]) + self.assertEqual(validator.warnings, 0) + self.assertEqual(validator.errors, 0) + + check_init_priorities._IGNORE_COMPATIBLES = save_ignore_compatibles @mock.patch("check_init_priorities.Validator._check_dep") @mock.patch("check_init_priorities.Validator.__init__", return_value=None) From 7fe5ce641a688e9f78d9c681102887b3fc0cf111 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jul 2023 12:35:53 -0500 Subject: [PATCH 1680/2042] drivers: dma: add DMA driver for NXP PXP engine The NXP Pixel pipeline engine (PXP) is a 2D DMA engine capable of accelerating display rotation, color space conversion, and limited 2D blending operations. This DMA driver only supports rotation of a framebuffer, via a set of custom dma_slot values. Only DMA channel 0 is supported or utilized. Signed-off-by: Daniel DeGrasse --- drivers/dma/CMakeLists.txt | 1 + drivers/dma/Kconfig | 2 + drivers/dma/Kconfig.mcux_pxp | 9 + drivers/dma/dma_mcux_pxp.c | 200 ++++++++++++++++++++++ dts/bindings/display/nxp,imx-elcdif.yaml | 8 +- dts/bindings/dma/nxp,pxp.yaml | 20 +++ include/zephyr/drivers/dma/dma_mcux_pxp.h | 40 +++++ 7 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 drivers/dma/Kconfig.mcux_pxp create mode 100644 drivers/dma/dma_mcux_pxp.c create mode 100644 dts/bindings/dma/nxp,pxp.yaml create mode 100644 include/zephyr/drivers/dma/dma_mcux_pxp.h diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index 4f8fd7550863..3cb622ae9e83 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -31,3 +31,4 @@ zephyr_library_sources_ifdef(CONFIG_DMA_ESP32 dma_esp32_gdma.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCHP_XEC dma_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_DMA_XMC4XXX dma_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_DMA_RPI_PICO dma_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_MCUX_PXP dma_mcux_pxp.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d88d2bbd832a..5023d9af9dd3 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -59,4 +59,6 @@ source "drivers/dma/Kconfig.xmc4xxx" source "drivers/dma/Kconfig.rpi_pico" source "drivers/dma/Kconfig.intel_lpss" + +source "drivers/dma/Kconfig.mcux_pxp" endif # DMA diff --git a/drivers/dma/Kconfig.mcux_pxp b/drivers/dma/Kconfig.mcux_pxp new file mode 100644 index 000000000000..054dde524512 --- /dev/null +++ b/drivers/dma/Kconfig.mcux_pxp @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MCUX_PXP + bool "MCUX PXP DMA driver" + default y + depends on DT_HAS_NXP_PXP_ENABLED + help + PXP DMA driver for NXP SOCs diff --git a/drivers/dma/dma_mcux_pxp.c b/drivers/dma/dma_mcux_pxp.c new file mode 100644 index 000000000000..69ce6a2eeba8 --- /dev/null +++ b/drivers/dma/dma_mcux_pxp.c @@ -0,0 +1,200 @@ +/* + * Copyright 2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#ifdef CONFIG_HAS_MCUX_CACHE +#include +#endif + +#define DT_DRV_COMPAT nxp_pxp + +#include +LOG_MODULE_REGISTER(dma_mcux_pxp, CONFIG_DMA_LOG_LEVEL); + +struct dma_mcux_pxp_config { + PXP_Type *base; + void (*irq_config_func)(const struct device *dev); +}; + +struct dma_mcux_pxp_data { + void *user_data; + dma_callback_t dma_callback; + uint32_t ps_buf_addr; + uint32_t ps_buf_size; + uint32_t out_buf_addr; + uint32_t out_buf_size; +}; + +static void dma_mcux_pxp_irq_handler(const struct device *dev) +{ + const struct dma_mcux_pxp_config *config = dev->config; + struct dma_mcux_pxp_data *data = dev->data; + + PXP_ClearStatusFlags(config->base, kPXP_CompleteFlag); +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_InvalidateByRange((uint32_t) data->out_buf_addr, data->out_buf_size); +#endif + if (data->dma_callback) { + data->dma_callback(dev, data->user_data, 0, 0); + } +} + +/* Configure a channel */ +static int dma_mcux_pxp_configure(const struct device *dev, uint32_t channel, + struct dma_config *config) +{ + const struct dma_mcux_pxp_config *dev_config = dev->config; + struct dma_mcux_pxp_data *dev_data = dev->data; + pxp_ps_buffer_config_t ps_buffer_cfg; + pxp_output_buffer_config_t output_buffer_cfg; + uint8_t bytes_per_pixel; + pxp_rotate_degree_t rotate; + + ARG_UNUSED(channel); + if (config->channel_direction != MEMORY_TO_MEMORY) { + return -ENOTSUP; + } + /* + * Use the DMA slot value to get the pixel format and rotation + * settings + */ + switch ((config->dma_slot & DMA_MCUX_PXP_CMD_MASK) >> DMA_MCUX_PXP_CMD_SHIFT) { + case DMA_MCUX_PXP_CMD_ROTATE_0: + rotate = kPXP_Rotate0; + break; + case DMA_MCUX_PXP_CMD_ROTATE_90: + rotate = kPXP_Rotate90; + break; + case DMA_MCUX_PXP_CMD_ROTATE_180: + rotate = kPXP_Rotate180; + break; + case DMA_MCUX_PXP_CMD_ROTATE_270: + rotate = kPXP_Rotate270; + break; + default: + return -ENOTSUP; + } + switch ((config->dma_slot & DMA_MCUX_PXP_FMT_MASK) >> DMA_MCUX_PXP_FMT_SHIFT) { + case DMA_MCUX_PXP_FMT_RGB565: + ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB565; + output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB565; + bytes_per_pixel = 2; + break; + case DMA_MCUX_PXP_FMT_RGB888: + ps_buffer_cfg.pixelFormat = kPXP_PsPixelFormatRGB888; + output_buffer_cfg.pixelFormat = kPXP_OutputPixelFormatRGB888; + bytes_per_pixel = 3; + break; + default: + return -ENOTSUP; + } + DCACHE_CleanByRange((uint32_t) config->head_block->source_address, + config->head_block->block_size); + + /* + * Some notes on how specific fields of the DMA config are used by + * the PXP: + * head block source address: PS buffer source address + * head block destination address: Output buffer address + * head block block size: size of destination and source buffer + * source data size: width of source buffer in bytes (pitch) + * source burst length: height of source buffer in pixels + * dest data size: width of destination buffer in bytes (pitch) + * dest burst length: height of destination buffer in pixels + */ + ps_buffer_cfg.swapByte = false; + ps_buffer_cfg.bufferAddr = config->head_block->source_address; + ps_buffer_cfg.bufferAddrU = 0U; + ps_buffer_cfg.bufferAddrV = 0U; + ps_buffer_cfg.pitchBytes = config->source_data_size; + PXP_SetProcessSurfaceBufferConfig(dev_config->base, &ps_buffer_cfg); + + output_buffer_cfg.interlacedMode = kPXP_OutputProgressive; + output_buffer_cfg.buffer0Addr = config->head_block->dest_address; + output_buffer_cfg.buffer1Addr = 0U; + output_buffer_cfg.pitchBytes = config->dest_data_size; + output_buffer_cfg.width = (config->dest_data_size / bytes_per_pixel); + output_buffer_cfg.height = config->dest_burst_length; + PXP_SetOutputBufferConfig(dev_config->base, &output_buffer_cfg); + /* We only support a process surface that covers the full buffer */ + PXP_SetProcessSurfacePosition(dev_config->base, 0U, 0U, + output_buffer_cfg.width, output_buffer_cfg.height); + /* Setup rotation */ + PXP_SetRotateConfig(dev_config->base, kPXP_RotateProcessSurface, + rotate, kPXP_FlipDisable); + + dev_data->ps_buf_addr = config->head_block->source_address; + dev_data->ps_buf_size = config->head_block->block_size; + dev_data->out_buf_addr = config->head_block->dest_address; + dev_data->out_buf_size = config->head_block->block_size; + dev_data->dma_callback = config->dma_callback; + dev_data->user_data = config->user_data; + return 0; +} + +static int dma_mcux_pxp_start(const struct device *dev, uint32_t channel) +{ + const struct dma_mcux_pxp_config *config = dev->config; + struct dma_mcux_pxp_data *data = dev->data; +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_CleanByRange((uint32_t) data->ps_buf_addr, data->ps_buf_size); +#endif + + ARG_UNUSED(channel); + PXP_Start(config->base); + return 0; +} + +static const struct dma_driver_api dma_mcux_pxp_api = { + .config = dma_mcux_pxp_configure, + .start = dma_mcux_pxp_start, +}; + +static int dma_mcux_pxp_init(const struct device *dev) +{ + const struct dma_mcux_pxp_config *config = dev->config; + + PXP_Init(config->base); + PXP_SetProcessSurfaceBackGroundColor(config->base, 0U); + /* Disable alpha surface and CSC1 */ + PXP_SetAlphaSurfacePosition(config->base, 0xFFFFU, 0xFFFFU, 0U, 0U); + PXP_EnableCsc1(config->base, false); + PXP_EnableInterrupts(config->base, kPXP_CompleteInterruptEnable); + config->irq_config_func(dev); + return 0; +} + +#define DMA_INIT(n) \ + static void dma_pxp_config_func##n(const struct device *dev) \ + { \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), ( \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + dma_mcux_pxp_irq_handler, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ(n, irq)); \ + )) \ + } \ + \ + static const struct dma_mcux_pxp_config dma_config_##n = { \ + .base = (PXP_Type *)DT_INST_REG_ADDR(n), \ + .irq_config_func = dma_pxp_config_func##n, \ + }; \ + \ + static struct dma_mcux_pxp_data dma_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + &dma_mcux_pxp_init, NULL, \ + &dma_data_##n, &dma_config_##n, \ + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &dma_mcux_pxp_api); + +DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) diff --git a/dts/bindings/display/nxp,imx-elcdif.yaml b/dts/bindings/display/nxp,imx-elcdif.yaml index cc5bbe9caec1..5f9807bfdcfb 100644 --- a/dts/bindings/display/nxp,imx-elcdif.yaml +++ b/dts/bindings/display/nxp,imx-elcdif.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2022, NXP +# Copyright 2022-2023 NXP # SPDX-License-Identifier: Apache-2.0 description: NXP i.MX eLCDIF (Enhanced LCD Interface) controller @@ -30,3 +30,9 @@ properties: required: true description: LCB backlight control gpio. Driver will initialize this GPIO to active high + + nxp,pxp: + type: phandle + description: + NXP PXP device phandle. The LCDIF can utilize the PXP for acclerated + display rotation via the DMA API, when present and enabled. diff --git a/dts/bindings/dma/nxp,pxp.yaml b/dts/bindings/dma/nxp,pxp.yaml new file mode 100644 index 000000000000..92fbc6be795d --- /dev/null +++ b/dts/bindings/dma/nxp,pxp.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP PXP 2D DMA engine + +compatible: "nxp,pxp" + +include: dma-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + "#dma-cells": + type: int + required: true + const: 0 diff --git a/include/zephyr/drivers/dma/dma_mcux_pxp.h b/include/zephyr/drivers/dma/dma_mcux_pxp.h new file mode 100644 index 000000000000..8c8c5feb0497 --- /dev/null +++ b/include/zephyr/drivers/dma/dma_mcux_pxp.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ +#define ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ + +#define DMA_MCUX_PXP_CMD_MASK 0xE0 +#define DMA_MCUX_PXP_CMD_SHIFT 0x5 + +#define DMA_MCUX_PXP_FMT_MASK 0x1F +#define DMA_MCUX_PXP_FMT_SHIFT 0x0 + +/* + * In order to configure the PXP for rotation, the user should + * supply a format and command as the DMA slot parameter, like so: + * dma_slot = (DMA_MCUX_PXP_FTM(DMA_MCUX_PXP_FMT_RGB565) | + * DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_90)) + * head block source address: input buffer address + * head block destination address: output buffer address + * source data size: input buffer size in bytes + * source burst length: height of source buffer in pixels + * dest data size: output buffer size in bytes + * dest burst length: height of destination buffer in pixels + */ + +#define DMA_MCUX_PXP_FMT(x) ((x << DMA_MCUX_PXP_FMT_SHIFT) & DMA_MCUX_PXP_FMT_MASK) +#define DMA_MCUX_PXP_CMD(x) ((x << DMA_MCUX_PXP_CMD_SHIFT) & DMA_MCUX_PXP_CMD_MASK) + +#define DMA_MCUX_PXP_CMD_ROTATE_0 0 +#define DMA_MCUX_PXP_CMD_ROTATE_90 1 +#define DMA_MCUX_PXP_CMD_ROTATE_180 2 +#define DMA_MCUX_PXP_CMD_ROTATE_270 3 + +#define DMA_MCUX_PXP_FMT_RGB565 0 +#define DMA_MCUX_PXP_FMT_RGB888 1 + +#endif /* ZEPHYR_INCLUDE_DRIVERS_DMA_MCUX_PXP_H_ */ From d2372139f3c0f0a8ae03ba83e240b7c7c2813448 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jul 2023 12:44:07 -0500 Subject: [PATCH 1681/2042] drivers: display: display_mcux_elcdif: enable display rotation using PXP Enable display rotation using the NXP pixel pipeline (PXP). The ELCDIF will only utilize the PXP if a framebuffer equivalent in size to the screen is provided to display_write. The rotation angle can be configured via Kconfig at build time. Fixes #59921 Signed-off-by: Daniel DeGrasse --- drivers/display/Kconfig.mcux_elcdif | 46 +++++++++++ drivers/display/display_mcux_elcdif.c | 108 ++++++++++++++++++++++++-- 2 files changed, 149 insertions(+), 5 deletions(-) diff --git a/drivers/display/Kconfig.mcux_elcdif b/drivers/display/Kconfig.mcux_elcdif index 3531b0f419b0..7bf2ba286242 100644 --- a/drivers/display/Kconfig.mcux_elcdif +++ b/drivers/display/Kconfig.mcux_elcdif @@ -32,4 +32,50 @@ config MCUX_ELCDIF_FB_NUM implications of this concern you, leave at least one driver framebuffer enabled. +config MCUX_ELCDIF_PXP + bool "Use PXP for display rotation" + depends on MCUX_PXP + depends on (MCUX_ELCDIF_FB_NUM > 0) + help + Use the PXP for display rotation. This requires the LCDIF node + have a "nxp,pxp" devicetree property pointing to the PXP device node. + The ELCDIF will only utilize the PXP to rotate frames if + display_write is called with a framebuffer equal in size to the + display. + +if MCUX_ELCDIF_PXP + +choice MCUX_ELCDIF_PXP_ROTATE_DIRECTION + default MCUX_ELCDIF_PXP_ROTATE_0 + prompt "Rotation angle of PXP" + help + Set rotation angle of PXP. The ELCDIF cannot detect the correct + rotation angle based on the call to display_write, so the user + should configure it here. + +config MCUX_ELCDIF_PXP_ROTATE_0 + bool "Rotate display by 0 degrees" + help + Rotate display by 0 degrees. Primarily useful for testing, + production applications should simply disable the PXP. + +config MCUX_ELCDIF_PXP_ROTATE_90 + bool "Rotate display by 90 degrees" + help + Rotate display clockwise by 90 degrees + +config MCUX_ELCDIF_PXP_ROTATE_180 + bool "Rotate display by 180 degrees" + help + Rotate display clockwise by 180 degrees + +config MCUX_ELCDIF_PXP_ROTATE_270 + bool "Rotate display by 270 degrees" + help + Rotate display clockwise by 270 degrees + +endchoice + +endif # MCUX_ELCDIF_PXP + endif # DISPLAY_MCUX_ELCDIF diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c index c3d30552464f..830bc3e9a0cf 100644 --- a/drivers/display/display_mcux_elcdif.c +++ b/drivers/display/display_mcux_elcdif.c @@ -17,6 +17,11 @@ #include #endif +#ifdef CONFIG_MCUX_ELCDIF_PXP +#include +#include +#endif + #include #include @@ -32,6 +37,7 @@ struct mcux_elcdif_config { const struct pinctrl_dev_config *pincfg; const struct gpio_dt_spec backlight_gpio; uint8_t *fb_ptr; + const struct device *pxp; }; struct mcux_elcdif_data { @@ -42,8 +48,22 @@ struct mcux_elcdif_data { struct k_sem sem; /* Tracks index of next active driver framebuffer */ uint8_t next_idx; +#ifdef CONFIG_MCUX_ELCDIF_PXP + /* Given to when PXP completes rotation */ + struct k_sem pxp_done; +#endif }; +#ifdef CONFIG_MCUX_ELCDIF_PXP +static void mcux_elcdif_pxp_callback(const struct device *dma_dev, + void *user_data, uint32_t channel, int ret) +{ + struct mcux_elcdif_data *data = user_data; + + k_sem_give(&data->pxp_done); +} +#endif /* CONFIG_MCUX_ELCDIF_PXP */ + static int mcux_elcdif_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, @@ -54,6 +74,8 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, int h_idx; const uint8_t *src; uint8_t *dst; + int ret = 0; + bool full_fb = false; __ASSERT((config->pixel_bytes * desc->pitch * desc->height) <= desc->buf_size, "Input buffer too small"); @@ -69,6 +91,19 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, LOG_DBG("Setting FB from %p->%p", (void *) dev_data->active_fb, (void *) buf); dev_data->active_fb = buf; + full_fb = true; + } else if ((x == 0) && (y == 0) && + (desc->width == config->rgb_mode.panelHeight) && + (desc->height == config->rgb_mode.panelWidth) && + (desc->pitch == desc->width) && + IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP)) { + /* With the PXP, we can rotate this display buffer to align + * with output dimensions + */ + LOG_DBG("Setting FB from %p->%p", + (void *) dev_data->active_fb, (void *) buf); + dev_data->active_fb = buf; + full_fb = true; } else { /* We must use partial framebuffer copy */ if (CONFIG_MCUX_ELCDIF_FB_NUM == 0) { @@ -101,25 +136,79 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, dev_data->active_fb = dev_data->fb[dev_data->next_idx]; } - #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_CleanByRange((uint32_t) dev_data->active_fb, config->fb_bytes); #endif +#ifdef CONFIG_MCUX_ELCDIF_PXP + if (full_fb) { + /* Configure PXP using DMA API, and rotate frame */ + struct dma_config pxp_dma = {0}; + struct dma_block_config pxp_block = {0}; + + /* Source buffer is input to display_write, we will + * place rotated output into a driver framebuffer. + */ + dev_data->active_fb = dev_data->fb[dev_data->next_idx]; + pxp_block.source_address = (uint32_t)buf; + pxp_block.dest_address = (uint32_t)dev_data->active_fb; + pxp_block.block_size = desc->buf_size; + + /* DMA slot sets pixel format and rotation angle */ + if (config->pixel_format == PIXEL_FORMAT_BGR_565) { + pxp_dma.dma_slot = DMA_MCUX_PXP_FMT(DMA_MCUX_PXP_FMT_RGB565); + } else if (config->pixel_format == PIXEL_FORMAT_RGB_888) { + pxp_dma.dma_slot = DMA_MCUX_PXP_FMT(DMA_MCUX_PXP_FMT_RGB888); + } else { + /* Cannot rotate */ + return -ENOTSUP; + } + if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_90)) { + pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_90); + } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_180)) { + pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_180); + } else if (IS_ENABLED(CONFIG_MCUX_ELCDIF_PXP_ROTATE_270)) { + pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_270); + } else { + pxp_dma.dma_slot |= DMA_MCUX_PXP_CMD(DMA_MCUX_PXP_CMD_ROTATE_0); + } + + pxp_dma.channel_direction = MEMORY_TO_MEMORY; + pxp_dma.source_data_size = desc->width * config->pixel_bytes; + pxp_dma.dest_data_size = config->rgb_mode.panelWidth * config->pixel_bytes; + /* Burst lengths are heights of source/dest buffer in pixels */ + pxp_dma.source_burst_length = desc->height; + pxp_dma.dest_burst_length = config->rgb_mode.panelHeight; + pxp_dma.head_block = &pxp_block; + pxp_dma.dma_callback = mcux_elcdif_pxp_callback; + pxp_dma.user_data = dev_data; + + ret = dma_config(config->pxp, 0, &pxp_dma); + if (ret < 0) { + return ret; + } + ret = dma_start(config->pxp, 0); + if (ret < 0) { + return ret; + } + k_sem_take(&dev_data->pxp_done, K_FOREVER); + } +#endif /* CONFIG_MCUX_ELCDIF_PXP */ + /* Queue next framebuffer */ ELCDIF_SetNextBufferAddr(config->base, (uint32_t)dev_data->active_fb); #if CONFIG_MCUX_ELCDIF_FB_NUM != 0 - /* Update index of active framebuffer */ - dev_data->next_idx = - (dev_data->next_idx + 1) % CONFIG_MCUX_ELCDIF_FB_NUM; + /* Update index of active framebuffer */ + dev_data->next_idx = + (dev_data->next_idx + 1) % CONFIG_MCUX_ELCDIF_FB_NUM; #endif /* Enable frame buffer completion interrupt */ ELCDIF_EnableInterrupts(config->base, kELCDIF_CurFrameDoneInterruptEnable); /* Wait for frame send to complete */ k_sem_take(&dev_data->sem, K_FOREVER); - return 0; + return ret; } static int mcux_elcdif_read(const struct device *dev, const uint16_t x, @@ -259,6 +348,13 @@ static int mcux_elcdif_init(const struct device *dev) dev_data->active_fb = config->fb_ptr; k_sem_init(&dev_data->sem, 0, 1); +#ifdef CONFIG_MCUX_ELCDIF_PXP + k_sem_init(&dev_data->pxp_done, 0, 1); + if (!device_is_ready(config->pxp)) { + LOG_ERR("PXP device is not ready"); + return -ENODEV; + } +#endif config->irq_config_func(dev); @@ -335,6 +431,8 @@ static const struct display_driver_api mcux_elcdif_api = { .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ .backlight_gpio = GPIO_DT_SPEC_INST_GET(id, backlight_gpios), \ .fb_ptr = frame_buffer_##id, \ + IF_ENABLED(CONFIG_MCUX_ELCDIF_PXP, \ + (.pxp = DEVICE_DT_GET(DT_INST_PHANDLE(id, nxp_pxp)),)) \ }; \ static struct mcux_elcdif_data mcux_elcdif_data_##id = { \ .next_idx = 0, \ From 0645b619e3f8a35927c3cfafc9fb6c9431e0e2c5 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jul 2023 12:51:55 -0500 Subject: [PATCH 1682/2042] dts: arm: nxp: add PXP to RT1xxx series Add PXP DTS definition to RT1xxx series SOCs Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_rt10xx.dtsi | 9 +++++++++ dts/arm/nxp/nxp_rt11xx.dtsi | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 57c4c3c982cc..a24eb0ce014b 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -417,6 +417,7 @@ reg = <0x402b8000 0x4000>; interrupts = <42 0>; status = "disabled"; + nxp,pxp = <&pxp>; }; lpspi1: spi@40394000 { @@ -907,6 +908,14 @@ #pinmux-cells = <2>; }; + pxp: pxp@402b4000 { + compatible = "nxp,pxp"; + reg = <0x402b4000 0x4000>; + interrupts = <44 0>; + status = "disabled"; + #dma-cells = <0>; + }; + sai1: sai@40384000 { compatible = "nxp,mcux-i2s"; #address-cells = <1>; diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 9893c5ec3c09..6f907fdb6402 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -351,6 +351,7 @@ reg = <0x40804000 0x4000>; interrupts = <54 0>; status = "disabled"; + nxp,pxp = <&pxp>; }; mipi_dsi: mipi-dsi@4080c000 { @@ -966,6 +967,14 @@ <16 0>; }; + pxp: pxp@40814000 { + compatible = "nxp,pxp"; + reg = <0x40814000 0x4000>; + interrupts = <57 0>; + status = "disabled"; + #dma-cells = <0>; + }; + iomuxcgpr: iomuxcgpr@400e4000 { compatible = "nxp,imx-gpr"; reg = <0x400e4000 0x4000>; From d209c837b5b2d36b92e2ddf6c2cbfed8a6982687 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jul 2023 12:52:32 -0500 Subject: [PATCH 1683/2042] boards: arm: mimxrt1170_evk: enable PXP Enable PXP engine with RT1170 EVK. The PXP is set to rotate by 0 degrees in the LVGL sample, for testing purposes. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi | 4 ++++ .../subsys/display/lvgl/boards/mimxrt1170_evk_cm7.conf | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 samples/subsys/display/lvgl/boards/mimxrt1170_evk_cm7.conf diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi index bd6739d5ca77..c54fd4689669 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi @@ -202,3 +202,7 @@ }; }; }; + +&pxp { + status = "okay"; +}; diff --git a/samples/subsys/display/lvgl/boards/mimxrt1170_evk_cm7.conf b/samples/subsys/display/lvgl/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 000000000000..33e1d5275a88 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Enable PXP DMA engine and set rotation angle to 0 degrees. +# This allows us to verify the DMA driver functions without altering +# the output image +CONFIG_DMA=y +CONFIG_MCUX_ELCDIF_PXP=y From 3c23ff051de1bf7ed42e5cfb375f60038b09c007 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Wed, 5 Jul 2023 14:56:01 -0500 Subject: [PATCH 1684/2042] boards: arm: mimxrt1060_evk: enable PXP rotation for LVGL sample Enable PXP rotation for LVGL sample. The PXP is configured to rotate by 0 degrees, so the original image is left untouched. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts | 4 ++++ samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts index d5fc71d7cf59..ad24991d5e3e 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts @@ -323,3 +323,7 @@ arduino_spi: &lpspi1 { pinctrl-0 = <&pinmux_swo>; pinctrl-names = "default"; }; + +&pxp { + status = "okay"; +}; diff --git a/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf b/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf new file mode 100644 index 000000000000..33e1d5275a88 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/mimxrt1060_evk.conf @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Enable PXP DMA engine and set rotation angle to 0 degrees. +# This allows us to verify the DMA driver functions without altering +# the output image +CONFIG_DMA=y +CONFIG_MCUX_ELCDIF_PXP=y From b9b42bb832ff5ed81292cea9727acf5fae7eddf9 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 29 Jun 2023 17:35:32 +0200 Subject: [PATCH 1685/2042] west.yml: update Silabs HAL Silabs HAL introduces support for EFM32GG12B SoC. Signed-off-by: Wojciech Sipak --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index ef4cef239b5b..15c641492952 100644 --- a/west.yml +++ b/west.yml @@ -209,7 +209,7 @@ manifest: groups: - hal - name: hal_silabs - revision: a143f03e846eb1b7b3135f3c8192820ce1b6d9c4 + revision: 5fbe78d3676b5500585f8e4534a8e56e7dae74a8 path: modules/hal/silabs groups: - hal From e9613856cb365f7fd58c21584704a673f7252018 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Wed, 28 Jun 2023 13:12:25 +0200 Subject: [PATCH 1686/2042] boards: arm: add efm32gg_sltb009a board - Add Silabs SLTB009A board - Add Silabs EFM32GG12B SoC Signed-off-by: Wojciech Sipak --- boards/arm/efm32gg_sltb009a/Kconfig.board | 8 + boards/arm/efm32gg_sltb009a/Kconfig.defconfig | 24 ++ boards/arm/efm32gg_sltb009a/board.cmake | 5 + .../arm/efm32gg_sltb009a/efm32gg_sltb009a.dts | 152 +++++++++++ .../efm32gg_sltb009a/efm32gg_sltb009a.yaml | 15 ++ .../efm32gg_sltb009a_defconfig | 12 + dts/arm/silabs/efm32gg12b.dtsi | 248 ++++++++++++++++++ dts/arm/silabs/efm32gg12b810f1024gm64.dtsi | 26 ++ .../efm32gg12b/Kconfig.defconfig.efm32gg12b | 7 + .../efm32gg12b/Kconfig.defconfig.series | 20 ++ .../silabs_exx32/efm32gg12b/Kconfig.series | 21 ++ soc/arm/silabs_exx32/efm32gg12b/Kconfig.soc | 7 + soc/arm/silabs_exx32/efm32gg12b/linker.ld | 14 + soc/arm/silabs_exx32/efm32gg12b/soc.h | 37 +++ soc/arm/silabs_exx32/efm32gg12b/soc_pinmap.h | 41 +++ 15 files changed, 637 insertions(+) create mode 100644 boards/arm/efm32gg_sltb009a/Kconfig.board create mode 100644 boards/arm/efm32gg_sltb009a/Kconfig.defconfig create mode 100644 boards/arm/efm32gg_sltb009a/board.cmake create mode 100644 boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts create mode 100644 boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.yaml create mode 100644 boards/arm/efm32gg_sltb009a/efm32gg_sltb009a_defconfig create mode 100644 dts/arm/silabs/efm32gg12b.dtsi create mode 100644 dts/arm/silabs/efm32gg12b810f1024gm64.dtsi create mode 100644 soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.efm32gg12b create mode 100644 soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.series create mode 100644 soc/arm/silabs_exx32/efm32gg12b/Kconfig.series create mode 100644 soc/arm/silabs_exx32/efm32gg12b/Kconfig.soc create mode 100644 soc/arm/silabs_exx32/efm32gg12b/linker.ld create mode 100644 soc/arm/silabs_exx32/efm32gg12b/soc.h create mode 100644 soc/arm/silabs_exx32/efm32gg12b/soc_pinmap.h diff --git a/boards/arm/efm32gg_sltb009a/Kconfig.board b/boards/arm/efm32gg_sltb009a/Kconfig.board new file mode 100644 index 000000000000..ae0968a19936 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/Kconfig.board @@ -0,0 +1,8 @@ +# EFM32GG SLTB009A board configuration +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_EFM32GG_SLTB009A + bool "SiLabs EFM32GG-SLTB009A (Giant Gecko 12)" + depends on SOC_SERIES_EFM32GG12B + select SOC_PART_NUMBER_EFM32GG12B810F1024GM64 diff --git a/boards/arm/efm32gg_sltb009a/Kconfig.defconfig b/boards/arm/efm32gg_sltb009a/Kconfig.defconfig new file mode 100644 index 000000000000..055b4925e782 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/Kconfig.defconfig @@ -0,0 +1,24 @@ +# EFM32GG SLTB009A default board configuration +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_EFM32GG_SLTB009A + +config BOARD + string + default "efm32gg_sltb009a" + +config CMU_HFXO_FREQ + default 50000000 + +config CMU_HFRCO_FREQ + default 72000000 + +config CMU_LFXO_FREQ + default 32768 + +config LOG_BACKEND_SWO_FREQ_HZ + default 875000 + depends on LOG_BACKEND_SWO + +endif # BOARD_EFM32GG_SLTB009A diff --git a/boards/arm/efm32gg_sltb009a/board.cmake b/boards/arm/efm32gg_sltb009a/board.cmake new file mode 100644 index 000000000000..9bac0914c0e2 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=EFM32GG12B810F1024") +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts new file mode 100644 index 000000000000..082ebb25d3db --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include + +/ { + model = "Silicon Labs EFM32GG SLTB009A board"; + compatible = "silabs,efm32gg_sltb009a"; + + chosen { + zephyr,console = &usart0; + zephyr,shell-uart = &usart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &button0; + sw1 = &button1; + watchdog0 = &wdog0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpioe 12 GPIO_ACTIVE_HIGH>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpioa 13 GPIO_ACTIVE_HIGH>; + label = "LED 1"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpiod 5 GPIO_ACTIVE_HIGH>; + label = "User Push Button 0"; + }; + button1: button_1 { + gpios = <&gpiod 8 GPIO_ACTIVE_HIGH>; + label = "User Push Button 1"; + }; + }; +}; + +&usart0 { + current-speed = <115200>; + location-rx = ; + location-tx = ; + status = "okay"; +}; + +&usart4 { + current-speed = <115200>; + location-rx = ; + location-tx = ; + status = "okay"; +}; + +&leuart0 { + current-speed = <9600>; + location-rx = ; + location-tx = ; + status = "okay"; +}; + +&i2c0 { + location-sda = ; + location-scl = ; + status = "okay"; +}; + +&i2c1 { + location-sda = ; + location-scl = ; + status = "okay"; +}; + +&rtcc0 { + prescaler = <1>; + status = "okay"; +}; + +&gpioa { + status = "okay"; + board-controller-enable { + // VCOM Isolation. Set PA15 to HIGH to enable VCOM_{RX,TX}. + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&gpio { + location-swo = <0>; + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&gpiof { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 12Kb of storage at the end of the 2048Kb of flash */ + storage_partition: partition@1fd000 { + label = "storage"; + reg = <0x001fd000 0x00003000>; + }; + }; +}; + +&wdog0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&cpu0 { + clock-frequency = <72000000>; +}; diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.yaml b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.yaml new file mode 100644 index 000000000000..44370cc391df --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.yaml @@ -0,0 +1,15 @@ +identifier: efm32gg_sltb009a +name: EFM32GG-SLTB009A +type: mcu +arch: arm +ram: 192 +flash: 1024 +toolchain: + - zephyr +supported: + - i2c + - gpio + - nvs +testing: + ignore_tags: + - bluetooth diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a_defconfig b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a_defconfig new file mode 100644 index 000000000000..31f29cf85e5c --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a_defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_EFM32GG12B=y +CONFIG_BOARD_EFM32GG_SLTB009A=y +CONFIG_ARM_MPU=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 +CONFIG_CMU_HFCLK_HFRCO=y diff --git a/dts/arm/silabs/efm32gg12b.dtsi b/dts/arm/silabs/efm32gg12b.dtsi new file mode 100644 index 000000000000..3e7d105e6b32 --- /dev/null +++ b/dts/arm/silabs/efm32gg12b.dtsi @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "gpio_gecko.h" + +/ { + chosen { + zephyr,entropy = &trng0; + zephyr,flash-controller = &msc; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m4f"; + reg = <0>; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + soc { + msc: flash-controller@40000000 { + compatible = "silabs,gecko-flash-controller"; + reg = <0x40000000 0x110>; + interrupts = <33 0>; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + write-block-size = <4>; + erase-block-size = <4096>; + }; + }; + + rtcc0: rtcc@40062000 { /* RTCC0 */ + compatible = "silabs,gecko-rtcc"; + reg = <0x40062000 0x184>; + interrupts = <31 0>; + clock-frequency = <32768>; + prescaler = <1>; + status = "disabled"; + }; + + uart0: uart@40014000 { /* UART0 */ + compatible = "silabs,gecko-uart"; + reg = <0x40014000 0x400>; + interrupts = <21 0 22 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <0>; + status = "disabled"; + }; + + uart1: uart@40014400 { /* UART1 */ + compatible = "silabs,gecko-uart"; + reg = <0x40014400 0x400>; + interrupts = <23 0 24 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <1>; + status = "disabled"; + }; + + usart0: usart@40010000 { /* USART0 */ + compatible = "silabs,gecko-usart"; + reg = <0x40010000 0x400>; + interrupts = <6 0 7 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <0>; + status = "disabled"; + }; + + usart1: usart@40010400 { /* USART1 */ + compatible = "silabs,gecko-usart"; + reg = <0x40010400 0x400>; + interrupts = <17 0 18 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <1>; + status = "disabled"; + }; + + usart2: usart@40010800 { /* USART2 */ + compatible = "silabs,gecko-usart"; + reg = <0x40010800 0x400>; + interrupts = <19 0 20 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <2>; + status = "disabled"; + }; + + usart3: usart@40010c00 { /* USART3 */ + compatible = "silabs,gecko-usart"; + reg = <0x40010c00 0x400>; + interrupts = <37 0 38 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <3>; + status = "disabled"; + }; + + usart4: usart@40011000 { /* USART4 */ + compatible = "silabs,gecko-usart"; + reg = <0x40011000 0x400>; + interrupts = <39 0 40 0>; + interrupt-names = "rx", "tx"; + peripheral-id = <4>; + status = "disabled"; + }; + + leuart0: leuart@4006a000 { /* LEUART0 */ + compatible = "silabs,gecko-leuart"; + reg = <0x4006a000 0x400>; + interrupts = <25 0>; + peripheral-id = <0>; + status = "disabled"; + }; + + leuart1: leuart@4006a400 { /* LEUART1 */ + compatible = "silabs,gecko-leuart"; + reg = <0x4006a400 0x400>; + interrupts = <26 0>; + peripheral-id = <1>; + status = "disabled"; + }; + + i2c0: i2c@40089000 { + compatible = "silabs,gecko-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40089000 0x400>; + interrupts = <11 0>; + status = "disabled"; + }; + + i2c1: i2c@40089400 { + compatible = "silabs,gecko-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40089400 0x400>; + interrupts = <12 0>; + status = "disabled"; + }; + + gpio: gpio@40088400 { + compatible = "silabs,gecko-gpio"; + reg = <0x40088400 0xc00>; + interrupts = <3 2 13 2>; + interrupt-names = "GPIO_EVEN", "GPIO_ODD"; + + ranges; + #address-cells = <1>; + #size-cells = <1>; + + gpioa: gpio@40088000 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x40088000 0x30>; + peripheral-id = <0>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpiob: gpio@40088030 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x40088030 0x30>; + peripheral-id = <1>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpioc: gpio@40088060 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x40088060 0x30>; + peripheral-id = <2>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpiod: gpio@40088090 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x40088090 0x30>; + peripheral-id = <3>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpioe: gpio@400880c0 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x400880c0 0x30>; + peripheral-id = <4>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpiof: gpio@400880f0 { + compatible = "silabs,gecko-gpio-port"; + reg = <0x400880f0 0x30>; + peripheral-id = <5>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + }; + + trng0: trng@4001d000 { + compatible = "silabs,gecko-trng"; + reg = <0x4001d000 0x400>; + interrupts = <57 0>; + status = "disabled"; + }; + + wdog0: wdog@40052000 { + compatible = "silabs,gecko-wdog"; + reg = <0x40052000 0x2C>; + peripheral-id = <0>; + interrupts = <1 0>; + status = "disabled"; + }; + + wdog1: wdog@40052400 { + compatible = "silabs,gecko-wdog"; + reg = <0x40052400 0x2C>; + peripheral-id = <1>; + interrupts = <55 0>; + status = "disabled"; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; diff --git a/dts/arm/silabs/efm32gg12b810f1024gm64.dtsi b/dts/arm/silabs/efm32gg12b810f1024gm64.dtsi new file mode 100644 index 000000000000..0b052a513d5c --- /dev/null +++ b/dts/arm/silabs/efm32gg12b810f1024gm64.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(192)>; + }; + + soc { + compatible = "silabs,efm32gg12b", "silabs,efm32gg12", + "silabs,efm32", "simple-bus"; + + flash-controller@40000000 { + flash0: flash@0 { + reg = <0 DT_SIZE_K(1024)>; + }; + }; + }; + +}; diff --git a/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.efm32gg12b b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.efm32gg12b new file mode 100644 index 000000000000..ce234528a584 --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.efm32gg12b @@ -0,0 +1,7 @@ +# Silicon Labs EFM32GG12B (Giant Gecko) platform configuration options +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_GECKO + default y + depends on GPIO || LOG_BACKEND_SWO diff --git a/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.series b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.series new file mode 100644 index 000000000000..469b30573109 --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.series @@ -0,0 +1,20 @@ +# EFM32GG12B series configuration options +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_EFM32GG12B + +config SOC_SERIES + default "efm32gg12b" + +config SOC_PART_NUMBER + default "EFM32GG12B810F1024GM64" if SOC_PART_NUMBER_EFM32GG12B810F1024GM64 + +config NUM_IRQS + int + # must be >= the highest interrupt number used + default 68 + +source "soc/arm/silabs_exx32/efm32gg12b/Kconfig.defconfig.efm32gg12b" + +endif # SOC_SERIES_EFM32GG12B diff --git a/soc/arm/silabs_exx32/efm32gg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.series new file mode 100644 index 000000000000..0f2c18cfbb4f --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.series @@ -0,0 +1,21 @@ +# EFM32GG12B (Giant Gecko) MCU line +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_EFM32GG12B + bool "EFM32GG12B Series MCU" + select ARM + select HAS_SILABS_GECKO + select HAS_SWO + select CPU_CORTEX_M4 + select CPU_HAS_FPU + select CPU_HAS_ARM_MPU + select SOC_FAMILY_EXX32 + select SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION + select SOC_GECKO_HAS_HFRCO_FREQRANGE + select SOC_GECKO_CMU + select SOC_GECKO_EMU + select SOC_GECKO_GPIO + select SOC_GECKO_TRNG + help + Enable support for EFM32 GiantGecko MCU series diff --git a/soc/arm/silabs_exx32/efm32gg12b/Kconfig.soc b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.soc new file mode 100644 index 000000000000..72cdf1bf226a --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/Kconfig.soc @@ -0,0 +1,7 @@ +# EFM32GG12B (Giant Gecko) MCU line +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_PART_NUMBER_EFM32GG12B810F1024GM64 + bool + depends on SOC_SERIES_EFM32GG12B diff --git a/soc/arm/silabs_exx32/efm32gg12b/linker.ld b/soc/arm/silabs_exx32/efm32gg12b/linker.ld new file mode 100644 index 000000000000..c7955ec596c9 --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/linker.ld @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * This is the linker script for both standard images. + */ + +#include diff --git a/soc/arm/silabs_exx32/efm32gg12b/soc.h b/soc/arm/silabs_exx32/efm32gg12b/soc.h new file mode 100644 index 000000000000..e38c74ecf0d8 --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/soc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Board configuration macros for the EFM32GG12B SoC family. + * + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE + +#include +#include + + +#include "soc_pinmap.h" +#include "../common/soc_gpio.h" + +#endif /* !_ASMLANGUAGE */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SOC__H_ */ diff --git a/soc/arm/silabs_exx32/efm32gg12b/soc_pinmap.h b/soc/arm/silabs_exx32/efm32gg12b/soc_pinmap.h new file mode 100644 index 000000000000..f2365951d282 --- /dev/null +++ b/soc/arm/silabs_exx32/efm32gg12b/soc_pinmap.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Silabs EFM32GG12B MCU pin definitions. + * + * This file contains pin configuration data required by different MCU + * modules to correctly configure GPIO controller. + */ + +#ifndef _SILABS_EFM32GG12B_SOC_PINMAP_H_ +#define _SILABS_EFM32GG12B_SOC_PINMAP_H_ + +#include +#include +#include + +#define GPIO_NODE DT_INST(0, silabs_gecko_gpio) +#if DT_NODE_HAS_PROP(GPIO_NODE, location_swo) +#define SWO_LOCATION DT_PROP(GPIO_NODE, location_swo) +#endif + +#ifdef CONFIG_GPIO_GECKO +/* Serial Wire Output (SWO) */ +#if (SWO_LOCATION == 0) +#define PIN_SWO {gpioPortF, 2, gpioModePushPull, 1} +#elif (SWO_LOCATION == 1) +#define PIN_SWO {gpioPortC, 15, gpioModePushPull, 1} +#elif (SWO_LOCATION == 2) +#define PIN_SWO {gpioPortD, 1, gpioModePushPull, 1} +#elif (SWO_LOCATION == 3) +#define PIN_SWO {gpioPortD, 2, gpioModePushPull, 1} +#elif (SWO_LOCATION >= 4) +#error ("Invalid SWO pin location") +#endif +#endif /* CONFIG_GPIO_GECKO */ + +#endif /* _SILABS_EFM32GG12B_SOC_PINMAP_H_ */ From 14b91d6bc313700803544df0362354db22278943 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 20 Jul 2023 22:57:57 +0200 Subject: [PATCH 1687/2042] boards: arm: add docs for efm32gg_sltb009a This adds the index page and an image of the board. Signed-off-by: Wojciech Sipak --- .../doc/efm32gg12-thunderboard-kit.jpg | Bin 0 -> 11961 bytes boards/arm/efm32gg_sltb009a/doc/index.rst | 167 ++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 boards/arm/efm32gg_sltb009a/doc/efm32gg12-thunderboard-kit.jpg create mode 100644 boards/arm/efm32gg_sltb009a/doc/index.rst diff --git a/boards/arm/efm32gg_sltb009a/doc/efm32gg12-thunderboard-kit.jpg b/boards/arm/efm32gg_sltb009a/doc/efm32gg12-thunderboard-kit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0db55c94c32d008061002c85f69e58256cad3d4 GIT binary patch literal 11961 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 Hf9L)e6i{&j literal 0 HcmV?d00001 diff --git a/boards/arm/efm32gg_sltb009a/doc/index.rst b/boards/arm/efm32gg_sltb009a/doc/index.rst new file mode 100644 index 000000000000..a3f54c650255 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/doc/index.rst @@ -0,0 +1,167 @@ +.. _efm32gg_sltb009a: + +EFM32GG12 Thunderboard Kit +########################## + +Overview +******** + +The EFM32GG12 Thunderboard Kit (SLTB009A) is an evaluation platform for the EFM32GG12 GiantGecko Microcontroller, +featuring an ARM Cortex-M4 with FPU, 1024kB flash, and 192kB RAM. + +.. figure:: efm32gg12-thunderboard-kit.jpg + :align: center + :alt: SLTB009A + + SLTB009A (Credit: Silicon Labs) + +Hardware +******** + +- PDM stereo microphones +- USB connectivity +- On-board Segger J-Link USB debugger +- 2 user buttons and 2 LEDs +- USB C connector + +For more information about the WGM160P and SLTB009A board: + +- `SLTB009A Website`_ +- `SLTB009A User Guide`_ +- `EFM32GG12 Datasheet`_ +- `EFM32GG12 Reference Manual`_ + +Supported Features +================== + +The efm32gg_sltb009a board configuration supports the following hardware +features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| MPU | on-chip | memory protection unit | ++-----------+------------+-------------------------------------+ +| COUNTER | on-chip | rtcc | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c port-polling | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ + +The default configuration can be found in the defconfig file: + + ``boards/arm/efm32gg_sltb009a/efm32gg_sltb009a_defconfig`` + + +Connections and IOs +=================== + +The EFM32GG12 MCU has six GPIO controllers (PORTA to PORTF), all of which are +currently enabled for the SLTB009A board. + +In the following table, the column **Name** contains pin names. For example, PE1 +means pin number 1 on PORTE, as used in the board's datasheets and manuals. + ++-------+-------------+-------------------------------------+ +| Name | Function | Usage | ++=======+=============+=====================================+ +| PE12 | GPIO | LED0 | ++-------+-------------+-------------------------------------+ +| PA13 | GPIO | LED1 | ++-------+-------------+-------------------------------------+ +| PD5 | GPIO | Push Button PB0 | ++-------+-------------+-------------------------------------+ +| PD8 | GPIO | Push Button PB1 | ++-------+-------------+-------------------------------------+ +| PE7 | UART_TX | UART TX Console VCOM_TX US0_TX #1 | ++-------+-------------+-------------------------------------+ +| PE6 | UART_RX | UART RX Console VCOM_RX US0_RX #1 | ++-------+-------------+-------------------------------------+ +| PC0 | I2C_SDA | SENSOR_I2C_SDA I2C0_SDA #1 | ++-------+-------------+-------------------------------------+ +| PC1 | I2C_SCL | SENSOR_I2C_SCL I2C0_SCL #1 | ++-------+-------------+-------------------------------------+ +| PC4 | I2C_SDA | SENSOR_I2C_SDA I2C1_SDA #1 | ++-------+-------------+-------------------------------------+ +| PC5 | I2C_SCL | SENSOR_I2C_SCL I2C1_SCL #1 | ++-------+-------------+-------------------------------------+ + + +System Clock +============ + +The EFM32GG12 MCU is configured to work at 72 MHz. + +Serial Port +=========== + +The EFM32GG12 SoC has five USARTs, two UARTs and two Low Energy UARTs (LEUART). +USART0 is connected to the board controller and is used for the console. + +Programming and Debugging +************************* + +.. note:: + Before using the kit the first time, you should update the J-Link firmware + from `J-Link-Downloads`_ + +Flashing +======== + +The SLTB009A includes an `J-Link`_ serial and debug adaptor built into the +board. The adaptor provides: + +- A USB connection to the host computer +- A physical UART connection which is relayed over interface USB serial port. + +Flashing an application to SLTB009A +-------------------------------------- + +Connect the SLTB009A to your host computer using the USB port. + +Here is an example to build and flash the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: efm32gg_stb009a + :goals: flash + +Open a serial terminal (minicom, putty, etc.) with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and you'll see the following message on the corresponding serial port +terminal session: + +.. code-block:: console + + Hello World! efm32gg_sltb009a + +.. _SLTB009A Website: + https://www.silabs.com/development-tools/thunderboard/thunderboard-gg12-kit + +.. _SLTB009A User Guide: + https://www.silabs.com/documents/public/user-guides/ug371-sltb009a-user-guide.pdf + +.. _EFM32GG12 Datasheet: + https://www.silabs.com/documents/public/data-sheets/efm32gg12-datasheet.pdf + +.. _EFM32GG12 Reference Manual: + https://www.silabs.com/documents/public/reference-manuals/efm32gg12-rm.pdf + +.. _J-Link: + https://www.segger.com/jlink-debug-probes.html + +.. _J-Link-Downloads: + https://www.segger.com/downloads/jlink From 7dfe0811b5285c48c9e5eb12470ddbf604b6eb29 Mon Sep 17 00:00:00 2001 From: Lukasz Mrugala Date: Fri, 7 Jul 2023 16:24:23 +0200 Subject: [PATCH 1688/2042] scripts: tests: twister: CMakeCache test expansion To enhance out test coverage, this change grants us 100% coverage on cmakecache.py. Signed-off-by: Lukasz Mrugala --- scripts/tests/twister/test_cmakecache.py | 272 +++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 scripts/tests/twister/test_cmakecache.py diff --git a/scripts/tests/twister/test_cmakecache.py b/scripts/tests/twister/test_cmakecache.py new file mode 100644 index 000000000000..ebfb440423b2 --- /dev/null +++ b/scripts/tests/twister/test_cmakecache.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Tests for cmakecache.py classes' methods +""" + +import mock +import pytest + +from contextlib import nullcontext + +from twisterlib.cmakecache import CMakeCacheEntry, CMakeCache + + +TESTDATA_1 = [ + ('ON', True), + ('YES', True), + ('TRUE', True), + ('Y', True), + ('OFF', False), + ('NO', False), + ('FALSE', False), + ('N', False), + ('IGNORE', False), + ('NOTFOUND', False), + ('', False), + ('DUMMY-NOTFOUND', False), + ('1', True), + ('0', False), + ('I AM NOT A PROPER VALUE', ValueError), +] + + +@pytest.mark.parametrize( + 'cmake_bool, expected_bool', + TESTDATA_1, + ids=[t[0] for t in TESTDATA_1] +) +def test_cmakecacheentry_to_bool(cmake_bool, expected_bool): + with pytest.raises(expected_bool) if \ + not isinstance(expected_bool, bool) else nullcontext() as exception: + b = CMakeCacheEntry._to_bool(cmake_bool) + + if exception is None: + assert b == expected_bool + else: + assert str(exception.value) == f'invalid bool {cmake_bool}' + + +TESTDATA_2 = [ + ( + '// I am a comment', + None + ), + ( + '# I am a comment too', + None + ), + ( + ' \r\n ', + None + ), + ( + 'DUMMY:WRONG_TYPE=???', + None + ), + ( + 'DUMMY_VALUE_NAME1:STRING=I am a dummy string', + CMakeCacheEntry('DUMMY_VALUE_NAME1', 'I am a dummy string') + ), + ( + 'DUMMY_VALUE_NAME2:STRING=list_el1;list_el2;list_el3', + CMakeCacheEntry( + 'DUMMY_VALUE_NAME2', + ['list_el1', 'list_el2', 'list_el3'] + ) + ), + ( + 'DUMMY_VALUE_NAME3:INTERNAL=I am a dummy internal string', + CMakeCacheEntry('DUMMY_VALUE_NAME3', 'I am a dummy internal string')), + ( + 'DUMMY_VALUE_NAME4:INTERNAL=list_el1;list_el2', + CMakeCacheEntry('DUMMY_VALUE_NAME4', ['list_el1', 'list_el2']) + ), + ( + 'DUMMY_VALUE_NAME5:FILEPATH=/path/to/dir', + CMakeCacheEntry('DUMMY_VALUE_NAME5', '/path/to/dir') + ), + ( + 'DUMMY_VALUE_NAME6:PATH=/path/to/dir/file.txt', + CMakeCacheEntry('DUMMY_VALUE_NAME6', '/path/to/dir/file.txt')), + ( + 'DUMMY_VALUE_NAME7:BOOL=Y', + CMakeCacheEntry('DUMMY_VALUE_NAME7', True) + ), + ( + 'DUMMY_VALUE_NAME8:BOOL=FALSE', + CMakeCacheEntry('DUMMY_VALUE_NAME8', False) + ), + ( + 'DUMMY_VALUE_NAME9:BOOL=NOT_A_BOOL', + ValueError( + ( + 'invalid bool NOT_A_BOOL', + 'on line 7: DUMMY_VALUE_NAME9:BOOL=NOT_A_BOOL' + ) + ) + ), +] + + +@pytest.mark.parametrize( + 'cmake_line, expected', + TESTDATA_2, + ids=[ + '// comment', + '# comment', + 'whitespace', + 'unrecognised type', + 'string', + 'string list', + 'internal string', + 'internal list', + 'filepath', + 'path', + 'true bool', + 'false bool', + 'not a bool' + ] +) +def test_cmakecacheentry_from_line(cmake_line, expected): + cmake_line_number = 7 + + with pytest.raises(type(expected)) if \ + isinstance(expected, Exception) else nullcontext() as exception: + entry = CMakeCacheEntry.from_line(cmake_line, cmake_line_number) + + if exception is not None: + assert repr(exception.value) == repr(expected) + return + + if expected is None: + assert entry is None + return + + assert entry.name == expected.name + assert entry.value == expected.value + + +TESTDATA_3 = [ + ( + CMakeCacheEntry('DUMMY_NAME1', 'dummy value'), + 'CMakeCacheEntry(name=DUMMY_NAME1, value=dummy value)' + ), + ( + CMakeCacheEntry('DUMMY_NAME2', False), + 'CMakeCacheEntry(name=DUMMY_NAME2, value=False)' + ) +] + + +@pytest.mark.parametrize( + 'cmake_cache_entry, expected', + TESTDATA_3, + ids=['string value', 'bool value'] +) +def test_cmakecacheentry_str(cmake_cache_entry, expected): + assert str(cmake_cache_entry) == expected + + +def test_cmakecache_load(): + file_data = ( + 'DUMMY_NAME1:STRING=First line\n' + '//Comment on the second line\n' + 'DUMMY_NAME2:STRING=Third line\n' + 'DUMMY_NAME3:STRING=Fourth line\n' + ) + + with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): + cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') + + assert cache.cache_file == 'dummy/path/CMakeCache.txt' + + expected = [ + ('DUMMY_NAME1', 'First line'), + ('DUMMY_NAME2', 'Third line'), + ('DUMMY_NAME3', 'Fourth line') + ] + + for expect in reversed(expected): + item = cache._entries.popitem() + + assert item[0] == expect[0] + assert item[1].name == expect[0] + assert item[1].value == expect[1] + + +def test_cmakecache_get(): + file_data = 'DUMMY_NAME:STRING=Dummy value' + + with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): + cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') + + good_val = cache.get('DUMMY_NAME') + + assert good_val == 'Dummy value' + + bad_val = cache.get('ANOTHER_NAME') + + assert bad_val is None + + bad_val = cache.get('ANOTHER_NAME', default='No such value') + + assert bad_val == 'No such value' + + +TESTDATA_4 = [ + ('STRING=el1;el2;el3;el4', True, ['el1', 'el2', 'el3', 'el4']), + ('STRING=dummy value', True, ['dummy value']), + ('STRING=', True, []), + ('BOOL=True', True, RuntimeError), + ('STRING=dummy value', False, []), +] + + +@pytest.mark.parametrize( + 'value, correct_get, expected', + TESTDATA_4, + ids=['list', 'single value', 'empty', 'exception', 'get failure'] +) +def test_cmakecache_get_list(value, correct_get, expected): + file_data = f'DUMMY_NAME:{value}' + + with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): + cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') + + with pytest.raises(expected) if \ + isinstance(expected, type) and issubclass(expected, Exception) else \ + nullcontext() as exception: + res = cache.get_list('DUMMY_NAME') if \ + correct_get else cache.get_list('ANOTHER_NAME') + + if exception is None: + assert res == expected + + +def test_cmakecache_dunders(): + file_data = f'DUMMY_NAME:STRING=dummy value' + + with mock.patch('builtins.open', mock.mock_open(read_data=file_data)): + cache = CMakeCache.from_file('dummy/path/CMakeCache.txt') + + assert len(list(cache.__iter__())) == 1 + + cache.__setitem__( + 'ANOTHER_NAME', + CMakeCacheEntry('ANOTHER_NAME', 'another value') + ) + + assert cache.__contains__('ANOTHER_NAME') + assert cache.__getitem__('ANOTHER_NAME') == 'another value' + + cache.__delitem__('ANOTHER_NAME') + + assert not cache.__contains__('ANOTHER_NAME') + + assert len(list(cache.__iter__())) == 1 + + with pytest.raises(TypeError): + cache.__setitem__('WRONG_TYPE', 'Yet Another Dummy Value') From 52e2f831851e8de8aa29e00938a0ef8f6ae8e8c7 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 6 Jul 2023 13:56:01 -0400 Subject: [PATCH 1689/2042] kernel/timeout: introduce the timepoint API This is meant as a substitute for sys_clock_timeout_end_calc() Current sys_clock_timeout_end_calc() usage opens up many bug possibilities due to the actual timeout evaluation's open-coded nature. Issue ##50611 is one example. - Some users store the returned value in a signed variable, others in an unsigned one, making the comparison with UINT64_MAX (corresponding to K_FOREVER) wrong in the signed case. - Some users compute the difference and store that in a signed variable to compare against 0 which still doesn't work with K_FOREVER. And when this difference is used as a timeout argument then the K_FOREVER nature of the timeout is lost. - Some users complexify their code by special-casing K_NO_WAIT and K_FOREVER inline which is bad for both code readability and binary size. Let's introduce a better abstraction to deal with absolute timepoints with an opaque type to be used with a well-defined API. The word "timeout" was avoided in the naming on purpose as the timeout namespace is quite crowded already and it is preferable to make a distinction between relative time periods (timeouts) and absolute time values (timepoints). A few stacks are also adjusted as they were too tight on X86. Signed-off-by: Nicolas Pitre --- doc/kernel/services/timing/clocks.rst | 36 +++++++------ include/zephyr/sys_clock.h | 73 ++++++++++++++++++++++++++- kernel/timeout.c | 39 +++++++++----- scripts/checkpatch/typedefsfile | 1 + subsys/net/ip/Kconfig | 1 + subsys/net/ip/Kconfig.mgmt | 1 + subsys/testsuite/ztest/Kconfig | 1 + 7 files changed, 122 insertions(+), 30 deletions(-) diff --git a/doc/kernel/services/timing/clocks.rst b/doc/kernel/services/timing/clocks.rst index 3a016b3f3516..0517d601f276 100644 --- a/doc/kernel/services/timing/clocks.rst +++ b/doc/kernel/services/timing/clocks.rst @@ -324,39 +324,43 @@ code. For example, consider this design: } This code requires that the timeout value be inspected, which is no -longer possible. For situations like this, the new API provides an -internal :c:func:`sys_clock_timeout_end_calc` routine that converts an -arbitrary timeout to the uptime value in ticks at which it will -expire. So such a loop might look like: +longer possible. For situations like this, the new API provides the +internal :c:func:`sys_timepoint_calc` and :c:func:`sys_timepoint_timeout` routines +that converts an arbitrary timeout to and from a timepoint value based on +an uptime tick at which it will expire. So such a loop might look like: .. code-block:: c - void my_wait_for_event(struct my_subsys *obj, k_timeout_t timeout_in_ms) + void my_wait_for_event(struct my_subsys *obj, k_timeout_t timeout) { /* Compute the end time from the timeout */ - uint64_t end = sys_clock_timeout_end_calc(timeout_in_ms); + k_timepoint_t end = sys_timepoint_calc(timeout); - while (end > k_uptime_ticks()) { + do { if (is_event_complete(obj)) { return; } + /* Update timeout with remaining time */ + timeout = sys_timepoint_timeout(end); + /* Wait for notification of state change */ - k_sem_take(obj->sem, timeout_in_ms); - } + k_sem_take(obj->sem, timeout); + } while (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)); } -Note that :c:func:`sys_clock_timeout_end_calc` returns values in units of -ticks, to prevent conversion aliasing, is always presented at 64 bit -uptime precision to prevent rollover bugs, handles special -:c:macro:`K_FOREVER` naturally (as ``UINT64_MAX``), and works -identically for absolute timeouts as well as conventional ones. +Note that :c:func:`sys_timepoint_calc` accepts special values :c:macro:`K_FOREVER` +and :c:macro:`K_NO_WAIT`, and works identically for absolute timeouts as well +as conventional ones. Conversely, :c:func:`sys_timepoint_timeout` may return +:c:macro:`K_FOREVER` or :c:macro:`K_NO_WAIT` if those were used to create +the timepoint, the later also being returned if the timepoint is now in the +past. For simple cases, :c:func:`sys_timepoint_expired` can be used as well. -But some care is still required for subsystems that use it. Note that +But some care is still required for subsystems that use those. Note that delta timeouts need to be interpreted relative to a "current time", and obviously that time is the time of the call to -:c:func:`sys_clock_timeout_end_calc`. But the user expects that the time is +:c:func:`sys_timepoint_calc`. But the user expects that the time is the time they passed the timeout to you. Care must be taken to call this function just once, as synchronously as possible to the timeout creation in user code. It should not be used on a "stored" timeout diff --git a/include/zephyr/sys_clock.h b/include/zephyr/sys_clock.h index 52c88b170e98..66c767a24e1d 100644 --- a/include/zephyr/sys_clock.h +++ b/include/zephyr/sys_clock.h @@ -190,7 +190,78 @@ int64_t sys_clock_tick_get(void); #define sys_clock_tick_get_32() (0) #endif -uint64_t sys_clock_timeout_end_calc(k_timeout_t timeout); +/** + * @brief Kernel timepoint type + * + * Absolute timepoints are stored in this opaque type. + * It is best not to inspect its content directly. + * + * @see sys_timepoint_calc() + * @see sys_timepoint_timeout() + * @see sys_timepoint_expired() + */ +typedef struct { uint64_t tick; } k_timepoint_t; + +/** + * @brief Calculate a timepoint value + * + * Returns a timepoint corresponding to the expiration (relative to an + * unlocked "now"!) of a timeout object. When used correctly, this should + * be called once, synchronously with the user passing a new timeout value. + * It should not be used iteratively to adjust a timeout (see + * `sys_timepoint_timeout()` for that purpose). + * + * @param timeout Timeout value relative to current time (may also be + * `K_FOREVER` or `K_NO_WAIT`). + * @retval Timepoint value corresponding to given timeout + * + * @see sys_timepoint_timeout() + * @see sys_timepoint_expired() + */ +k_timepoint_t sys_timepoint_calc(k_timeout_t timeout); + +/** + * @brief Remaining time to given timepoint + * + * Returns the timeout interval between current time and provided timepoint. + * If the timepoint is now in the past or if it was created with `K_NO_WAIT` + * then `K_NO_WAIT` is returned. If it was created with `K_FOREVER` then + * `K_FOREVER` is returned. + * + * @param timepoint Timepoint for which a timeout value is wanted. + * @retval Corresponding timeout value. + * + * @see sys_timepoint_calc() + */ +k_timeout_t sys_timepoint_timeout(k_timepoint_t timepoint); + +/** + * @brief Indicates if timepoint is expired + * + * @param timepoint Timepoint to evaluate + * @retval true if the timepoint is in the past, false otherwise + * + * @see sys_timepoint_calc() + */ +static inline bool sys_timepoint_expired(k_timepoint_t timepoint) +{ + return K_TIMEOUT_EQ(sys_timepoint_timeout(timepoint), Z_TIMEOUT_NO_WAIT); +} + +/** + * @brief Provided for backward compatibility. + * + * This is deprecated. Consider `sys_timepoint_calc()` instead. + * + * @see sys_timepoint_calc() + */ +__deprecated +static inline uint64_t sys_clock_timeout_end_calc(k_timeout_t timeout) +{ + k_timepoint_t tp = sys_timepoint_calc(timeout); + + return tp.tick; +} #ifdef __cplusplus } diff --git a/kernel/timeout.c b/kernel/timeout.c index df8c2aaede37..cfd2b48ac8df 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -289,28 +289,41 @@ static inline int64_t z_vrfy_k_uptime_ticks(void) #include #endif -/* Returns the uptime expiration (relative to an unlocked "now"!) of a - * timeout object. When used correctly, this should be called once, - * synchronously with the user passing a new timeout value. It should - * not be used iteratively to adjust a timeout. - */ -uint64_t sys_clock_timeout_end_calc(k_timeout_t timeout) +k_timepoint_t sys_timepoint_calc(k_timeout_t timeout) { - k_ticks_t dt; + k_timepoint_t timepoint; if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { - return UINT64_MAX; + timepoint.tick = UINT64_MAX; } else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { - return sys_clock_tick_get(); + timepoint.tick = 0; } else { - - dt = timeout.ticks; + k_ticks_t dt = timeout.ticks; if (IS_ENABLED(CONFIG_TIMEOUT_64BIT) && Z_TICK_ABS(dt) >= 0) { - return Z_TICK_ABS(dt); + timepoint.tick = Z_TICK_ABS(dt); + } else { + timepoint.tick = sys_clock_tick_get() + MAX(1, dt); } - return sys_clock_tick_get() + MAX(1, dt); } + + return timepoint; +} + +k_timeout_t sys_timepoint_timeout(k_timepoint_t timepoint) +{ + uint64_t now, remaining; + + if (timepoint.tick == UINT64_MAX) { + return K_FOREVER; + } + if (timepoint.tick == 0) { + return K_NO_WAIT; + } + + now = sys_clock_tick_get(); + remaining = (timepoint.tick > now) ? (timepoint.tick - now) : 0; + return K_TICKS(remaining); } #ifdef CONFIG_ZTEST diff --git a/scripts/checkpatch/typedefsfile b/scripts/checkpatch/typedefsfile index ff7ab3cb93ce..22cb81ef7265 100644 --- a/scripts/checkpatch/typedefsfile +++ b/scripts/checkpatch/typedefsfile @@ -1,5 +1,6 @@ _cpu_arch_t k_mem_partition_attr_t +k_timepoint_t mbedtls_pk_context z_arch_esf_t pinctrl_soc_pin_t diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index e5f096e594f5..3b9947eb50b0 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -508,6 +508,7 @@ config NET_TCP_PKT_ALLOC_TIMEOUT config NET_TCP_WORKQ_STACK_SIZE int "TCP work queue thread stack size" + default 1200 if X86 default 1024 depends on NET_TCP help diff --git a/subsys/net/ip/Kconfig.mgmt b/subsys/net/ip/Kconfig.mgmt index bb5c9ccc1865..2ecfc9d028c7 100644 --- a/subsys/net/ip/Kconfig.mgmt +++ b/subsys/net/ip/Kconfig.mgmt @@ -22,6 +22,7 @@ if NET_MGMT_EVENT config NET_MGMT_EVENT_STACK_SIZE int "Stack size for the inner thread handling event callbacks" default 2048 if COVERAGE_GCOV + default 840 if X86 default 800 if THREAD_LOCAL_STORAGE default 768 help diff --git a/subsys/testsuite/ztest/Kconfig b/subsys/testsuite/ztest/Kconfig index 7c5803147a52..d48961cc8448 100644 --- a/subsys/testsuite/ztest/Kconfig +++ b/subsys/testsuite/ztest/Kconfig @@ -19,6 +19,7 @@ config ZTEST_NEW_API config ZTEST_STACK_SIZE int "Test function thread stack size" default 2048 if COVERAGE_GCOV + default 2048 if X86 default 1024 config ZTEST_TEST_DELAY_MS From 3c9249cedcd9483bab3742d53899d082cb276932 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 10 Jul 2023 18:18:50 -0400 Subject: [PATCH 1690/2042] tests: test the timepoint API This tests sys_timepoint_calc(), sys_timepoint_timeout() and sys_timepoint_expired(). Signed-off-by: Nicolas Pitre --- tests/kernel/timer/timepoints/CMakeLists.txt | 8 ++++ tests/kernel/timer/timepoints/prj.conf | 2 + tests/kernel/timer/timepoints/src/main.c | 38 +++++++++++++++++++ tests/kernel/timer/timepoints/testcase.yaml | 5 +++ .../kernel/timer/timer_error_case/src/main.c | 21 ---------- 5 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 tests/kernel/timer/timepoints/CMakeLists.txt create mode 100644 tests/kernel/timer/timepoints/prj.conf create mode 100644 tests/kernel/timer/timepoints/src/main.c create mode 100644 tests/kernel/timer/timepoints/testcase.yaml diff --git a/tests/kernel/timer/timepoints/CMakeLists.txt b/tests/kernel/timer/timepoints/CMakeLists.txt new file mode 100644 index 000000000000..5e88d3b6333b --- /dev/null +++ b/tests/kernel/timer/timepoints/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(timer_timepoints) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/kernel/timer/timepoints/prj.conf b/tests/kernel/timer/timepoints/prj.conf new file mode 100644 index 000000000000..9228251051ec --- /dev/null +++ b/tests/kernel/timer/timepoints/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y diff --git a/tests/kernel/timer/timepoints/src/main.c b/tests/kernel/timer/timepoints/src/main.c new file mode 100644 index 000000000000..59fc6141c846 --- /dev/null +++ b/tests/kernel/timer/timepoints/src/main.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 BayLibre SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +ZTEST(timepoints, test_timepoint_api) +{ + k_timepoint_t timepoint; + k_timeout_t timeout, remaining; + + timeout = K_NO_WAIT; + timepoint = sys_timepoint_calc(timeout); + zassert_true(sys_timepoint_expired(timepoint)); + remaining = sys_timepoint_timeout(timepoint); + zassert_true(K_TIMEOUT_EQ(remaining, K_NO_WAIT)); + + timeout = K_FOREVER; + timepoint = sys_timepoint_calc(timeout); + zassert_false(sys_timepoint_expired(timepoint)); + remaining = sys_timepoint_timeout(timepoint); + zassert_true(K_TIMEOUT_EQ(remaining, K_FOREVER)); + + timeout = K_SECONDS(1); + timepoint = sys_timepoint_calc(timeout); + zassert_false(sys_timepoint_expired(timepoint)); + remaining = sys_timepoint_timeout(timepoint); + zassert_true(remaining.ticks <= timeout.ticks && remaining.ticks != 0); + k_sleep(K_MSEC(1100)); + zassert_true(sys_timepoint_expired(timepoint)); + remaining = sys_timepoint_timeout(timepoint); + zassert_true(K_TIMEOUT_EQ(remaining, K_NO_WAIT)); +} + +ZTEST_SUITE(timepoints, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/kernel/timer/timepoints/testcase.yaml b/tests/kernel/timer/timepoints/testcase.yaml new file mode 100644 index 000000000000..83576c9e39e2 --- /dev/null +++ b/tests/kernel/timer/timepoints/testcase.yaml @@ -0,0 +1,5 @@ +tests: + kernel.timer.timepoints: + tags: + - kernel + - timer diff --git a/tests/kernel/timer/timer_error_case/src/main.c b/tests/kernel/timer/timer_error_case/src/main.c index 048489fdab63..770253677f32 100644 --- a/tests/kernel/timer/timer_error_case/src/main.c +++ b/tests/kernel/timer/timer_error_case/src/main.c @@ -309,27 +309,6 @@ ZTEST_USER(timer_api_error, test_timer_add_timeout) ztest_test_pass(); } -extern uint64_t sys_clock_timeout_end_calc(k_timeout_t timeout); -extern void sys_clock_announce(int32_t ticks); - -ZTEST(timer_api_error, test_timeout_end_calc) -{ - int ret; - k_timeout_t timeout; - - timeout = K_MSEC(DURATION); - ret = sys_clock_timeout_end_calc(timeout); - zassert_true(ret, "---timeout end calc---"); - - timeout.ticks = TEST_TIMEOUT; - ret = sys_clock_timeout_end_calc(timeout); - zassert_true(ret, "timeout end calc error"); - - timeout = K_FOREVER; - ret = sys_clock_timeout_end_calc(timeout); - zassert_true(ret, "timeout end calc forever"); -} - /** * @brief Tests for the Timer kernel object * @defgroup kernel_timer_tests Timer From 77b7eb119946d5ea364a9505d278ca3488b5007f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 6 Jul 2023 14:58:03 -0400 Subject: [PATCH 1691/2042] kernel/kheap: move to timepoint API Remove sys_clock_timeout_end_calc() usage. Signed-off-by: Nicolas Pitre --- kernel/kheap.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/kernel/kheap.c b/kernel/kheap.c index 161621a08849..fc2d3300e783 100644 --- a/kernel/kheap.c +++ b/kernel/kheap.c @@ -64,11 +64,9 @@ SYS_INIT_NAMED(statics_init_post, statics_init, POST_KERNEL, 0); void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, k_timeout_t timeout) { - int64_t now, end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); void *ret = NULL; - end = K_TIMEOUT_EQ(timeout, K_FOREVER) ? INT64_MAX : end; - k_spinlock_key_t key = k_spin_lock(&h->lock); SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap, aligned_alloc, h, timeout); @@ -80,9 +78,8 @@ void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, while (ret == NULL) { ret = sys_heap_aligned_alloc(&h->heap, align, bytes); - now = sys_clock_tick_get(); if (!IS_ENABLED(CONFIG_MULTITHREADING) || - (ret != NULL) || ((end - now) <= 0)) { + (ret != NULL) || K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { break; } @@ -96,8 +93,8 @@ void *k_heap_aligned_alloc(struct k_heap *h, size_t align, size_t bytes, */ } - (void) z_pend_curr(&h->lock, key, &h->wait_q, - K_TICKS(end - now)); + timeout = sys_timepoint_timeout(end); + (void) z_pend_curr(&h->lock, key, &h->wait_q, timeout); key = k_spin_lock(&h->lock); } From 531aa5786dd2704bb1c9dbbcebf1057ab2586bba Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 6 Jul 2023 16:51:56 -0400 Subject: [PATCH 1692/2042] drivers: move to timepoint API Remove sys_clock_timeout_end_calc() usage. Signed-off-by: Nicolas Pitre --- drivers/ethernet/eth_dwmac.c | 6 +++--- drivers/ethernet/eth_w5500.c | 5 ++--- drivers/i2c/i2c_sc18im704.c | 6 +++--- drivers/input/input_npcx_kbd.c | 6 +++--- drivers/w1/w1_zephyr_serial.c | 6 +++--- include/zephyr/rtio/rtio.h | 4 ++-- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/ethernet/eth_dwmac.c b/drivers/ethernet/eth_dwmac.c index 498f6b17ca12..bc2f82e5a536 100644 --- a/drivers/ethernet/eth_dwmac.c +++ b/drivers/ethernet/eth_dwmac.c @@ -566,7 +566,7 @@ int dwmac_probe(const struct device *dev) struct dwmac_priv *p = dev->data; int ret; uint32_t reg_val; - int64_t timeout; + k_timepoint_t timeout; ret = dwmac_bus_init(p); if (ret != 0) { @@ -580,9 +580,9 @@ int dwmac_probe(const struct device *dev) /* resets all of the MAC internal registers and logic */ REG_WRITE(DMA_MODE, DMA_MODE_SWR); - timeout = sys_clock_timeout_end_calc(K_MSEC(100)); + timeout = sys_timepoint_calc(K_MSEC(100)); while (REG_READ(DMA_MODE) & DMA_MODE_SWR) { - if (timeout - sys_clock_tick_get() < 0) { + if (sys_timepoint_expired(timeout)) { LOG_ERR("unable to reset hardware"); return -EIO; } diff --git a/drivers/ethernet/eth_w5500.c b/drivers/ethernet/eth_w5500.c index c2e1cac18845..d20abf9e40e7 100644 --- a/drivers/ethernet/eth_w5500.c +++ b/drivers/ethernet/eth_w5500.c @@ -157,7 +157,7 @@ static int w5500_writebuf(const struct device *dev, uint16_t offset, uint8_t *bu static int w5500_command(const struct device *dev, uint8_t cmd) { uint8_t reg; - uint64_t end = sys_clock_timeout_end_calc(K_MSEC(100)); + k_timepoint_t end = sys_timepoint_calc(K_MSEC(100)); w5500_spi_write(dev, W5500_S0_CR, &cmd, 1); while (1) { @@ -165,8 +165,7 @@ static int w5500_command(const struct device *dev, uint8_t cmd) if (!reg) { break; } - int64_t remaining = end - sys_clock_tick_get(); - if (remaining <= 0) { + if (sys_timepoint_expired(end)) { return -EIO; } k_busy_wait(W5500_PHY_ACCESS_DELAY); diff --git a/drivers/i2c/i2c_sc18im704.c b/drivers/i2c/i2c_sc18im704.c index 331d5e3263ac..5e23aa2753fe 100644 --- a/drivers/i2c/i2c_sc18im704.c +++ b/drivers/i2c/i2c_sc18im704.c @@ -64,15 +64,15 @@ int sc18im704_transfer(const struct device *dev, } if (rx_data != NULL) { - uint64_t end; + k_timepoint_t end; for (uint8_t i = 0; i < rx_len && ret == 0; ++i) { /* Make sure we don't wait forever */ - end = sys_clock_timeout_end_calc(K_SECONDS(1)); + end = sys_timepoint_calc(K_SECONDS(1)); do { ret = uart_poll_in(cfg->bus, &rx_data[i]); - } while (ret == -1 && end > k_uptime_ticks()); + } while (ret == -1 && !sys_timepoint_expired(end)); } /* -1 indicates we timed out */ diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index dbaa2659773f..ff6f08e16761 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -325,7 +325,7 @@ static bool check_key_events(const struct device *dev) static void kbd_matrix_poll(const struct device *dev) { struct input_npcx_kbd_data *const data = dev->data; - uint64_t poll_time_end = sys_clock_timeout_end_calc(K_USEC(data->poll_timeout_us)); + k_timepoint_t poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); uint32_t current_cycles; uint32_t cycles_diff; uint32_t wait_period; @@ -334,8 +334,8 @@ static void kbd_matrix_poll(const struct device *dev) uint32_t start_period_cycles = k_cycle_get_32(); if (check_key_events(dev)) { - poll_time_end = sys_clock_timeout_end_calc(K_USEC(data->poll_timeout_us)); - } else if (start_period_cycles > poll_time_end) { + poll_time_end = sys_timepoint_calc(K_USEC(data->poll_timeout_us)); + } else if (sys_timepoint_expired(poll_time_end)) { break; } diff --git a/drivers/w1/w1_zephyr_serial.c b/drivers/w1/w1_zephyr_serial.c index eb0ef6637e3a..e83ef6fe596c 100644 --- a/drivers/w1/w1_zephyr_serial.c +++ b/drivers/w1/w1_zephyr_serial.c @@ -70,7 +70,7 @@ static int serial_tx_rx(const struct device *dev, const uint8_t *tx_data, uint8_t *rx_data, size_t len, uint32_t timeout) { const struct w1_serial_config *cfg = dev->config; - uint64_t end; + k_timepoint_t end; uint8_t dummy; int ret = 0; @@ -83,11 +83,11 @@ static int serial_tx_rx(const struct device *dev, const uint8_t *tx_data, } uart_poll_out(cfg->uart_dev, tx_data[i]); - end = sys_clock_timeout_end_calc(K_USEC(timeout)); + end = sys_timepoint_calc(K_USEC(timeout)); do { ret = uart_poll_in(cfg->uart_dev, &rx_data[i]); - } while (ret != 0 && end > k_uptime_ticks()); + } while (ret != 0 && !sys_timepoint_expired(end)); } return ret; diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index c617161df540..eaca1cc79641 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -1369,7 +1369,7 @@ static inline int z_impl_rtio_cqe_copy_out(struct rtio *r, { size_t copied = 0; struct rtio_cqe *cqe; - int64_t end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); do { cqe = K_TIMEOUT_EQ(timeout, K_FOREVER) ? rtio_cqe_consume_block(r) @@ -1385,7 +1385,7 @@ static inline int z_impl_rtio_cqe_copy_out(struct rtio *r, } cqes[copied++] = *cqe; rtio_cqe_release(r, cqe); - } while (copied < cqe_count && end > k_uptime_ticks()); + } while (copied < cqe_count && !sys_timepoint_expired(end)); return copied; } From a7b3584745d8e26e70f530ee18ba4e6af7c18ff1 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 7 Jul 2023 22:29:32 -0400 Subject: [PATCH 1693/2042] subsys/zbus: move to timepoint API Remove sys_clock_timeout_end_calc() usage as well as custom _zbus_timeout_remainder(). Signed-off-by: Nicolas Pitre --- include/zephyr/zbus/zbus.h | 1 - subsys/zbus/zbus.c | 25 +++++++++---------------- subsys/zbus/zbus_runtime_observers.c | 4 ++-- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 1f294f5543fb..eba0b13f38d2 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -148,7 +148,6 @@ struct zbus_observer { #define ZBUS_REF(_value) &(_value) -k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks); /** @endcond */ /** diff --git a/subsys/zbus/zbus.c b/subsys/zbus/zbus.c index 5357e3439a00..7c55e50f434a 100644 --- a/subsys/zbus/zbus.c +++ b/subsys/zbus/zbus.c @@ -9,13 +9,6 @@ #include LOG_MODULE_REGISTER(zbus, CONFIG_ZBUS_LOG_LEVEL); -k_timeout_t _zbus_timeout_remainder(uint64_t end_ticks) -{ - int64_t now_ticks = sys_clock_tick_get(); - - return K_TICKS((k_ticks_t)MAX(end_ticks - now_ticks, 0)); -} - #if (CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE > 0) static inline void _zbus_notify_runtime_listeners(const struct zbus_channel *chan) { @@ -34,7 +27,7 @@ static inline void _zbus_notify_runtime_listeners(const struct zbus_channel *cha } static inline int _zbus_notify_runtime_subscribers(const struct zbus_channel *chan, - uint64_t end_ticks) + k_timepoint_t end_time) { __ASSERT(chan != NULL, "chan is required"); @@ -47,7 +40,7 @@ static inline int _zbus_notify_runtime_subscribers(const struct zbus_channel *ch if (obs_nd->obs->enabled && (obs_nd->obs->queue != NULL)) { err = k_msgq_put(obs_nd->obs->queue, &chan, - _zbus_timeout_remainder(end_ticks)); + sys_timepoint_timeout(end_time)); _ZBUS_ASSERT(err == 0, "could not deliver notification to observer %s. Error code %d", @@ -63,7 +56,7 @@ static inline int _zbus_notify_runtime_subscribers(const struct zbus_channel *ch } #endif /* CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE */ -static int _zbus_notify_observers(const struct zbus_channel *chan, uint64_t end_ticks) +static int _zbus_notify_observers(const struct zbus_channel *chan, k_timepoint_t end_time) { int last_error = 0, err; /* Notify static listeners */ @@ -80,7 +73,7 @@ static int _zbus_notify_observers(const struct zbus_channel *chan, uint64_t end_ /* Notify static subscribers */ for (const struct zbus_observer *const *obs = chan->observers; *obs != NULL; ++obs) { if ((*obs)->enabled && ((*obs)->queue != NULL)) { - err = k_msgq_put((*obs)->queue, &chan, _zbus_timeout_remainder(end_ticks)); + err = k_msgq_put((*obs)->queue, &chan, sys_timepoint_timeout(end_time)); _ZBUS_ASSERT(err == 0, "could not deliver notification to observer %s.", _ZBUS_OBS_NAME(*obs)); if (err) { @@ -92,7 +85,7 @@ static int _zbus_notify_observers(const struct zbus_channel *chan, uint64_t end_ } #if CONFIG_ZBUS_RUNTIME_OBSERVERS_POOL_SIZE > 0 - err = _zbus_notify_runtime_subscribers(chan, end_ticks); + err = _zbus_notify_runtime_subscribers(chan, end_time); if (err) { last_error = err; } @@ -103,7 +96,7 @@ static int _zbus_notify_observers(const struct zbus_channel *chan, uint64_t end_ int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t timeout) { int err; - uint64_t end_ticks = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end_time = sys_timepoint_calc(timeout); _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); @@ -120,7 +113,7 @@ int zbus_chan_pub(const struct zbus_channel *chan, const void *msg, k_timeout_t memcpy(chan->message, msg, chan->message_size); - err = _zbus_notify_observers(chan, end_ticks); + err = _zbus_notify_observers(chan, end_time); k_mutex_unlock(chan->mutex); @@ -148,7 +141,7 @@ int zbus_chan_read(const struct zbus_channel *chan, void *msg, k_timeout_t timeo int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout) { int err; - uint64_t end_ticks = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end_time = sys_timepoint_calc(timeout); _ZBUS_ASSERT(!k_is_in_isr(), "zbus cannot be used inside ISRs"); _ZBUS_ASSERT(chan != NULL, "chan is required"); @@ -158,7 +151,7 @@ int zbus_chan_notify(const struct zbus_channel *chan, k_timeout_t timeout) return err; } - err = _zbus_notify_observers(chan, end_ticks); + err = _zbus_notify_observers(chan, end_time); k_mutex_unlock(chan->mutex); diff --git a/subsys/zbus/zbus_runtime_observers.c b/subsys/zbus/zbus_runtime_observers.c index 8e966e194233..ea4649c38555 100644 --- a/subsys/zbus/zbus_runtime_observers.c +++ b/subsys/zbus/zbus_runtime_observers.c @@ -21,7 +21,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe { int err; struct zbus_observer_node *obs_nd, *tmp; - uint64_t end_ticks = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end_time = sys_timepoint_calc(timeout); _ZBUS_ASSERT(!k_is_in_isr(), "ISR blocked"); _ZBUS_ASSERT(chan != NULL, "chan is required"); @@ -50,7 +50,7 @@ int zbus_chan_add_obs(const struct zbus_channel *chan, const struct zbus_observe } err = k_mem_slab_alloc(&_zbus_runtime_obs_pool, (void **)&obs_nd, - _zbus_timeout_remainder(end_ticks)); + sys_timepoint_timeout(end_time)); if (err) { LOG_ERR("Could not allocate memory on runtime observers pool\n"); From 13d68185d566b0e08c00f4a9332785434ebe0548 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 7 Jul 2023 22:38:36 -0400 Subject: [PATCH 1694/2042] subsys/net: move to timepoint API Remove sys_clock_timeout_end_calc() usage. Signed-off-by: Nicolas Pitre --- subsys/net/buf.c | 27 ++++----------------------- subsys/net/ip/net_pkt.c | 39 ++++----------------------------------- 2 files changed, 8 insertions(+), 58 deletions(-) diff --git a/subsys/net/buf.c b/subsys/net/buf.c index dc460ba705dc..da8c75f32f26 100644 --- a/subsys/net/buf.c +++ b/subsys/net/buf.c @@ -241,7 +241,7 @@ struct net_buf *net_buf_alloc_len(struct net_buf_pool *pool, size_t size, k_timeout_t timeout) #endif { - uint64_t end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); struct net_buf *buf; k_spinlock_key_t key; @@ -322,17 +322,7 @@ struct net_buf *net_buf_alloc_len(struct net_buf_pool *pool, size_t size, #if __ASSERT_ON size_t req_size = size; #endif - if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - timeout = K_NO_WAIT; - } else { - timeout = Z_TIMEOUT_TICKS(remaining); - } - } - + timeout = sys_timepoint_timeout(end); buf->__buf = data_alloc(buf, &size, timeout); if (!buf->__buf) { NET_BUF_ERR("%s():%d: Failed to allocate data", @@ -531,7 +521,7 @@ struct net_buf *net_buf_ref(struct net_buf *buf) struct net_buf *net_buf_clone(struct net_buf *buf, k_timeout_t timeout) { - int64_t end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); struct net_buf_pool *pool; struct net_buf *clone; @@ -555,16 +545,7 @@ struct net_buf *net_buf_clone(struct net_buf *buf, k_timeout_t timeout) } else { size_t size = buf->size; - if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - timeout = K_NO_WAIT; - } else { - timeout = Z_TIMEOUT_TICKS(remaining); - } - } + timeout = sys_timepoint_timeout(end); clone->__buf = data_alloc(clone, &size, timeout); if (!clone->__buf || size < buf->size) { diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 7c3459692d80..ddffbe27a9de 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -866,7 +866,7 @@ static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, size_t size, k_timeout_t timeout) #endif { - uint64_t end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); struct net_buf *first = NULL; struct net_buf *current = NULL; @@ -891,16 +891,7 @@ static struct net_buf *pkt_alloc_buffer(struct net_buf_pool *pool, size -= current->size; - if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - break; - } - - timeout = Z_TIMEOUT_TICKS(remaining); - } + timeout = sys_timepoint_timeout(end); #if CONFIG_NET_PKT_LOG_LEVEL >= LOG_LEVEL_DBG NET_FRAG_CHECK_IF_NOT_IN_USE(new, new->ref + 1); @@ -1147,7 +1138,6 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt, k_timeout_t timeout) #endif { - uint64_t end = sys_clock_timeout_end_calc(timeout); struct net_buf_pool *pool = NULL; size_t alloc_len = 0; size_t hdr_len = 0; @@ -1186,17 +1176,6 @@ int net_pkt_alloc_buffer(struct net_pkt *pkt, pool = pkt->slab == &tx_pkts ? &tx_bufs : &rx_bufs; } - if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - timeout = K_NO_WAIT; - } else { - timeout = Z_TIMEOUT_TICKS(remaining); - } - } - #if NET_LOG_LEVEL >= LOG_LEVEL_DBG buf = pkt_alloc_buffer(pool, alloc_len, timeout, caller, line); #else @@ -1417,7 +1396,7 @@ pkt_alloc_with_buffer(struct k_mem_slab *slab, k_timeout_t timeout) #endif { - uint64_t end = sys_clock_timeout_end_calc(timeout); + k_timepoint_t end = sys_timepoint_calc(timeout); struct net_pkt *pkt; int ret; @@ -1435,17 +1414,7 @@ pkt_alloc_with_buffer(struct k_mem_slab *slab, net_pkt_set_family(pkt, family); - if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - timeout = K_NO_WAIT; - } else { - timeout = Z_TIMEOUT_TICKS(remaining); - } - } - + timeout = sys_timepoint_timeout(end); #if NET_LOG_LEVEL >= LOG_LEVEL_DBG ret = net_pkt_alloc_buffer_debug(pkt, size, proto, timeout, caller, line); From 603cdaa0323fb434232d15e521d4e65237cb5b62 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 7 Jul 2023 22:51:21 -0400 Subject: [PATCH 1695/2042] subsys/net/lib/socket: move to timepoint API Remove sys_clock_timeout_end_calc() usage and custom timeout_recalc(). Signed-off-by: Nicolas Pitre --- subsys/net/lib/sockets/sockets.c | 58 ++++++++++------------------ subsys/net/lib/sockets/sockets_tls.c | 38 ++++++------------ subsys/net/lib/websocket/websocket.c | 20 ++-------- 3 files changed, 35 insertions(+), 81 deletions(-) diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c index 648d9380e85a..c90e553075f1 100644 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -692,11 +692,9 @@ static inline int z_vrfy_zsock_accept(int sock, struct sockaddr *addr, #define MAX_WAIT_BUFS K_SECONDS(10) static int send_check_and_wait(struct net_context *ctx, int status, - uint64_t buf_timeout, k_timeout_t timeout, + k_timepoint_t buf_timeout, k_timeout_t timeout, uint32_t *retry_timeout) { - int64_t remaining; - if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { goto out; } @@ -712,8 +710,7 @@ static int send_check_and_wait(struct net_context *ctx, int status, * it means that the sending window is blocked * and we just cannot send anything. */ - remaining = buf_timeout - sys_clock_tick_get(); - if (remaining <= 0) { + if (sys_timepoint_expired(buf_timeout)) { if (status == -ENOBUFS) { status = -ENOMEM; } else { @@ -769,38 +766,23 @@ static int send_check_and_wait(struct net_context *ctx, int status, return -1; } -static void timeout_recalc(uint64_t end, k_timeout_t *timeout) -{ - if (!K_TIMEOUT_EQ(*timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(*timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - *timeout = K_NO_WAIT; - } else { - *timeout = Z_TIMEOUT_TICKS(remaining); - } - } -} - ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { k_timeout_t timeout = K_FOREVER; uint32_t retry_timeout = WAIT_BUFS_INITIAL_MS; - uint64_t buf_timeout = 0; - uint64_t end; + k_timepoint_t buf_timeout, end; int status; if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) { timeout = K_NO_WAIT; + buf_timeout = sys_timepoint_calc(K_NO_WAIT); } else { net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL); - buf_timeout = sys_clock_timeout_end_calc(MAX_WAIT_BUFS); + buf_timeout = sys_timepoint_calc(MAX_WAIT_BUFS); } - - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); /* Register the callback before sending in order to receive the response * from the peer. @@ -830,7 +812,7 @@ ssize_t zsock_sendto_ctx(struct net_context *ctx, const void *buf, size_t len, } /* Update the timeout value in case loop is repeated. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); continue; } @@ -885,18 +867,17 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg, { k_timeout_t timeout = K_FOREVER; uint32_t retry_timeout = WAIT_BUFS_INITIAL_MS; - uint64_t buf_timeout = 0; - uint64_t end; + k_timepoint_t buf_timeout, end; int status; if ((flags & ZSOCK_MSG_DONTWAIT) || sock_is_nonblock(ctx)) { timeout = K_NO_WAIT; + buf_timeout = sys_timepoint_calc(K_NO_WAIT); } else { net_context_get_option(ctx, NET_OPT_SNDTIMEO, &timeout, NULL); - buf_timeout = sys_clock_timeout_end_calc(MAX_WAIT_BUFS); + buf_timeout = sys_timepoint_calc(MAX_WAIT_BUFS); } - - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); while (1) { status = net_context_sendmsg(ctx, msg, flags, NULL, timeout, NULL); @@ -910,7 +891,7 @@ ssize_t zsock_sendmsg_ctx(struct net_context *ctx, const struct msghdr *msg, } /* Update the timeout value in case loop is repeated. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); continue; } @@ -1307,7 +1288,7 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx, size_t recv_len = 0; struct net_pkt_cursor backup; int res; - uint64_t end; + k_timepoint_t end; const bool waitall = flags & ZSOCK_MSG_WAITALL; if (!net_context_is_used(ctx)) { @@ -1326,7 +1307,7 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx, net_context_get_option(ctx, NET_OPT_RCVTIMEO, &timeout, NULL); } - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); do { struct net_pkt *pkt; @@ -1409,7 +1390,7 @@ static inline ssize_t zsock_recv_stream(struct net_context *ctx, } /* Update the timeout value in case loop is repeated. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); } while ((recv_len == 0) || (waitall && (recv_len < max_len))); if (!(flags & ZSOCK_MSG_PEEK)) { @@ -1619,12 +1600,12 @@ int zsock_poll_internal(struct zsock_pollfd *fds, int nfds, k_timeout_t timeout) struct k_poll_event *pev_end = poll_events + ARRAY_SIZE(poll_events); const struct fd_op_vtable *vtable; struct k_mutex *lock; - uint64_t end; + k_timepoint_t end; bool offload = false; const struct fd_op_vtable *offl_vtable = NULL; void *offl_ctx = NULL; - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); pev = poll_events; for (pfd = fds, i = nfds; i--; pfd++) { @@ -1656,6 +1637,7 @@ int zsock_poll_internal(struct zsock_pollfd *fds, int nfds, k_timeout_t timeout) * as many events as possible, but without any wait. */ timeout = K_NO_WAIT; + end = sys_timepoint_calc(timeout); result = 0; } else if (result == -EXDEV) { /* If POLL_PREPARE returned EXDEV, it means @@ -1697,7 +1679,7 @@ int zsock_poll_internal(struct zsock_pollfd *fds, int nfds, k_timeout_t timeout) fds, nfds, poll_timeout); } - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); do { ret = k_poll(poll_events, pev - poll_events, timeout); @@ -1756,7 +1738,7 @@ int zsock_poll_internal(struct zsock_pollfd *fds, int nfds, k_timeout_t timeout) break; } - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { break; diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 863c530a8209..801a321a208c 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -762,20 +762,6 @@ static bool is_blocking(int sock, int flags) return !((flags & ZSOCK_MSG_DONTWAIT) || (sock_flags & O_NONBLOCK)); } -static void timeout_recalc(uint64_t end, k_timeout_t *timeout) -{ - if (!K_TIMEOUT_EQ(*timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(*timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - *timeout = K_NO_WAIT; - } else { - *timeout = Z_TIMEOUT_TICKS(remaining); - } - } -} - static int timeout_to_ms(k_timeout_t *timeout) { if (K_TIMEOUT_EQ(*timeout, K_NO_WAIT)) { @@ -1162,12 +1148,12 @@ static int tls_mbedtls_reset(struct tls_context *context) static int tls_mbedtls_handshake(struct tls_context *context, k_timeout_t timeout) { - uint64_t end; + k_timepoint_t end; int ret; context->handshake_in_progress = true; - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); while ((ret = mbedtls_ssl_handshake(&context->ssl)) != 0) { if (ret == MBEDTLS_ERR_SSL_WANT_READ || @@ -1177,7 +1163,7 @@ static int tls_mbedtls_handshake(struct tls_context *context, int timeout_ms; /* Blocking timeout. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { ret = -EAGAIN; break; @@ -2013,7 +1999,7 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, { const bool is_block = is_blocking(ctx->sock, flags); k_timeout_t timeout; - uint64_t end; + k_timepoint_t end; int ret; if (!is_block) { @@ -2022,7 +2008,7 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, timeout = ctx->options.timeout_tx; } - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); do { ret = mbedtls_ssl_write(&ctx->ssl, buf, len); @@ -2042,7 +2028,7 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf, } /* Blocking timeout. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { errno = EAGAIN; break; @@ -2225,7 +2211,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, const bool waitall = flags & ZSOCK_MSG_WAITALL; const bool is_block = is_blocking(ctx->sock, flags); k_timeout_t timeout; - uint64_t end; + k_timepoint_t end; int ret; if (!is_block) { @@ -2234,7 +2220,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, timeout = ctx->options.timeout_rx; } - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); do { size_t read_len = max_len - recv_len; @@ -2269,7 +2255,7 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf, } /* Blocking timeout. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { ret = -EAGAIN; goto err; @@ -2314,7 +2300,7 @@ static ssize_t recvfrom_dtls_common(struct tls_context *ctx, void *buf, int ret; bool is_block = is_blocking(ctx->sock, flags); k_timeout_t timeout; - uint64_t end; + k_timepoint_t end; if (!is_block) { timeout = K_NO_WAIT; @@ -2322,7 +2308,7 @@ static ssize_t recvfrom_dtls_common(struct tls_context *ctx, void *buf, timeout = ctx->options.timeout_rx; } - end = sys_clock_timeout_end_calc(timeout); + end = sys_timepoint_calc(timeout); do { size_t remaining; @@ -2340,7 +2326,7 @@ static ssize_t recvfrom_dtls_common(struct tls_context *ctx, void *buf, } /* Blocking timeout. */ - timeout_recalc(end, &timeout); + timeout = sys_timepoint_timeout(end); if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) { return ret; } diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index 5e5eee5fb2c4..f5975dea1472 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -890,20 +890,6 @@ static int wait_rx(int sock, int timeout) return 0; } -static void timeout_recalc(uint64_t end, k_timeout_t *timeout) -{ - if (!K_TIMEOUT_EQ(*timeout, K_NO_WAIT) && - !K_TIMEOUT_EQ(*timeout, K_FOREVER)) { - int64_t remaining = end - sys_clock_tick_get(); - - if (remaining <= 0) { - *timeout = K_NO_WAIT; - } else { - *timeout = Z_TIMEOUT_TICKS(remaining); - } - } -} - static int timeout_to_ms(k_timeout_t *timeout) { if (K_TIMEOUT_EQ(*timeout, K_NO_WAIT)) { @@ -922,7 +908,7 @@ int websocket_recv_msg(int ws_sock, uint8_t *buf, size_t buf_len, { struct websocket_context *ctx; int ret; - uint64_t end; + k_timepoint_t end; k_timeout_t tout = K_FOREVER; struct websocket_buffer payload = {.buf = buf, .size = buf_len, .count = 0}; @@ -934,7 +920,7 @@ int websocket_recv_msg(int ws_sock, uint8_t *buf, size_t buf_len, return -EINVAL; } - end = sys_clock_timeout_end_calc(tout); + end = sys_timepoint_calc(tout); #if defined(CONFIG_NET_TEST) struct test_data *test_data = z_get_fd_obj(ws_sock, NULL, 0); @@ -973,7 +959,7 @@ int websocket_recv_msg(int ws_sock, uint8_t *buf, size_t buf_len, ret = -EAGAIN; } #else - timeout_recalc(end, &tout); + tout = sys_timepoint_timeout(end); ret = wait_rx(ctx->real_sock, timeout_to_ms(&tout)); if (ret == 0) { From 7238b481824eb3fd17bf1bbf2574c9fdd62ddb61 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 7 Jul 2023 23:00:44 -0400 Subject: [PATCH 1696/2042] subsys/net: zperf_tcp_uploader: move to timepoint API Remove sys_clock_timeout_end_calc() usage. While at it, remove dead last_print_time variable. Signed-off-by: Nicolas Pitre --- subsys/net/lib/zperf/zperf_tcp_uploader.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_tcp_uploader.c b/subsys/net/lib/zperf/zperf_tcp_uploader.c index fd0ae06be588..97fd4f57f71d 100644 --- a/subsys/net/lib/zperf/zperf_tcp_uploader.c +++ b/subsys/net/lib/zperf/zperf_tcp_uploader.c @@ -25,8 +25,8 @@ static int tcp_upload(int sock, unsigned int packet_size, struct zperf_results *results) { - int64_t duration = sys_clock_timeout_end_calc(K_MSEC(duration_in_ms)); - int64_t start_time, last_print_time, end_time, remaining; + k_timepoint_t end = sys_timepoint_calc(K_MSEC(duration_in_ms)); + int64_t start_time, end_time; uint32_t nb_packets = 0U, nb_errors = 0U; uint32_t alloc_errors = 0U; int ret = 0; @@ -39,7 +39,6 @@ static int tcp_upload(int sock, /* Start the loop */ start_time = k_uptime_ticks(); - last_print_time = start_time; (void)memset(sample_packet, 'z', sizeof(sample_packet)); @@ -80,8 +79,7 @@ static int tcp_upload(int sock, k_yield(); #endif - remaining = duration - k_uptime_ticks(); - } while (remaining > 0); + } while (!sys_timepoint_expired(end)); end_time = k_uptime_ticks(); From bd3ed9723050a589381011d002d4baaa365bf452 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 7 Jul 2023 23:05:08 -0400 Subject: [PATCH 1697/2042] subsys/net: zperf_udp_uploader: Remove sys_clock_timeout_end_calc() usage The initial goal was to remove sys_clock_timeout_end_calc(). However, several related issues have been fixed as well. First this: int64_t print_interval = sys_clock_timeout_end_calc(K_SECONDS(1)); /* Print log every seconds */ int64_t print_info = print_interval - k_uptime_ticks(); if (print_info <= 0) { [...] } The above condition will simply never be true. Then there is lots of back-and-forth time conversions using expensive base-10 divisions for each loop iterations which is likely to impact performance. Let's do the time conversion only once outside the loop and track everything in terms of ticks within the loop. Also the various timeouts are open-coded based on the absolute uptime tick so to sample it only once per round. Using sys_timepoint_calc() and sys_timepoint_timeout() would have introduced additional uptime tick sampling which implies the overhead of a downstream lock each time for no gain. For those reasons, open coding those timeouts bears more benefits in this particular case compared to using the timepoint API. Then this: secs = k_ticks_to_ms_ceil32(loop_time) / 1000U; usecs = k_ticks_to_us_ceil32(loop_time) - secs * USEC_PER_SEC; The above should round down not up to work accurately. And the usecs value will become garbage past 1.2 hour of runtime due to overflows. And no need to clamp the wait period which is on the microsec scale using the total duration argument being on the millisec scale. That's yet more loop overhead that can be omitted. The actual duration is recorded at the end anyway. Signed-off-by: Nicolas Pitre --- subsys/net/lib/zperf/zperf_udp_uploader.c | 49 ++++++++++------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/subsys/net/lib/zperf/zperf_udp_uploader.c b/subsys/net/lib/zperf/zperf_udp_uploader.c index b38ad9052950..1310063437b1 100644 --- a/subsys/net/lib/zperf/zperf_udp_uploader.c +++ b/subsys/net/lib/zperf/zperf_udp_uploader.c @@ -137,13 +137,13 @@ static int udp_upload(int sock, int port, unsigned int rate_in_kbps, struct zperf_results *results) { - uint32_t packet_duration = zperf_packet_duration(packet_size, rate_in_kbps); - uint64_t duration = sys_clock_timeout_end_calc(K_MSEC(duration_in_ms)); - uint64_t delay = packet_duration; + uint32_t packet_duration_us = zperf_packet_duration(packet_size, rate_in_kbps); + uint32_t packet_duration = k_us_to_ticks_ceil32(packet_duration_us); + uint32_t delay = packet_duration; uint32_t nb_packets = 0U; int64_t start_time, end_time; - int64_t last_print_time, last_loop_time; - int64_t remaining; + int64_t print_time, last_loop_time; + uint32_t print_period; int ret; if (packet_size > PACKET_SIZE_MAX) { @@ -158,14 +158,19 @@ static int udp_upload(int sock, int port, /* Start the loop */ start_time = k_uptime_ticks(); - last_print_time = start_time; last_loop_time = start_time; + end_time = start_time + k_ms_to_ticks_ceil64(duration_in_ms); + + /* Print log every seconds */ + print_period = k_ms_to_ticks_ceil32(MSEC_PER_SEC); + print_time = start_time + print_period; (void)memset(sample_packet, 'z', sizeof(sample_packet)); do { struct zperf_udp_datagram *datagram; struct zperf_client_hdr_v1 *hdr; + uint64_t usecs64; uint32_t secs, usecs; int64_t loop_time; int32_t adjust; @@ -175,27 +180,25 @@ static int udp_upload(int sock, int port, /* Algorithm to maintain a given baud rate */ if (last_loop_time != loop_time) { - adjust = (int32_t)(packet_duration - - k_ticks_to_us_ceil32(loop_time - - last_loop_time)); + adjust = packet_duration; + adjust -= (int32_t)(loop_time - last_loop_time); } else { /* It's the first iteration so no need for adjustment */ adjust = 0; } - if (adjust >= 0) { + if ((adjust >= 0) || (-adjust < delay)) { delay += adjust; - } else if ((uint64_t)-adjust < delay) { - delay -= (uint64_t)-adjust; } else { delay = 0U; /* delay should never be negative */ } last_loop_time = loop_time; - secs = k_ticks_to_ms_ceil32(loop_time) / 1000U; - usecs = k_ticks_to_us_ceil32(loop_time) - secs * USEC_PER_SEC; + usecs64 = k_ticks_to_us_floor64(loop_time); + secs = usecs64 / USEC_PER_SEC; + usecs = usecs64 - (uint64_t)secs * USEC_PER_SEC; /* Fill the packet header */ datagram = (struct zperf_udp_datagram *)sample_packet; @@ -224,33 +227,23 @@ static int udp_upload(int sock, int port, } if (IS_ENABLED(CONFIG_NET_ZPERF_LOG_LEVEL_DBG)) { - int64_t print_interval = sys_clock_timeout_end_calc(K_SECONDS(1)); - /* Print log every seconds */ - int64_t print_info = print_interval - k_uptime_ticks(); - - if (print_info <= 0) { + if (print_time >= loop_time) { NET_DBG("nb_packets=%u\tdelay=%u\tadjust=%d", nb_packets, (unsigned int)delay, (int)adjust); - print_interval = sys_clock_timeout_end_calc(K_SECONDS(1)); + print_time += print_period; } } - remaining = duration - k_uptime_ticks(); - /* Wait */ #if defined(CONFIG_ARCH_POSIX) k_busy_wait(USEC_PER_MSEC); #else if (delay != 0) { - if (k_us_to_ticks_floor64(delay) > remaining) { - delay = k_ticks_to_us_ceil64(remaining); - } - - k_sleep(K_USEC(delay)); + k_sleep(K_TICKS(delay)); } #endif - } while (remaining > 0); + } while (last_loop_time < end_time); end_time = k_uptime_ticks(); From d1a50e540bd54314d928caec99f9c3956a2218a1 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 8 Jul 2023 00:03:14 -0400 Subject: [PATCH 1698/2042] subsys/usb: move to timepoint API Remove sys_clock_timeout_end_calc() usage. Signed-off-by: Nicolas Pitre --- subsys/usb/device/class/dfu/usb_dfu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/usb/device/class/dfu/usb_dfu.c b/subsys/usb/device/class/dfu/usb_dfu.c index 8f207bf92eab..db1706de1d68 100644 --- a/subsys/usb/device/class/dfu/usb_dfu.c +++ b/subsys/usb/device/class/dfu/usb_dfu.c @@ -943,12 +943,12 @@ static bool is_dfu_started(void) */ void wait_for_usb_dfu(k_timeout_t delay) { - uint64_t end = sys_clock_timeout_end_calc(delay); + k_timepoint_t end = sys_timepoint_calc(delay); /* Wait for a prescribed duration of time. If DFU hasn't started within * that time, stop waiting and proceed further. */ - while (end > k_uptime_ticks()) { + while (!sys_timepoint_expired(end)) { if (is_dfu_started()) { k_poll_event_init(&dfu_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &dfu_signal); From 9b7768147342aa65233e9adc802b9cb4b3150ee3 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 21:47:02 +1000 Subject: [PATCH 1699/2042] dts: gen_defines: generate `_ORD_STR_SORTABLE` Generate a zero padded variant of `_ORD` that is suitable for use in linker scripts with the `SORT` property, so that `6` is correctly placed before `24`, and so on. Signed-off-by: Jordan Yates --- include/zephyr/devicetree/ordinals.h | 7 +++++++ scripts/dts/gen_defines.py | 1 + 2 files changed, 8 insertions(+) diff --git a/include/zephyr/devicetree/ordinals.h b/include/zephyr/devicetree/ordinals.h index c8b0302d1c3c..5dd9d00e308a 100644 --- a/include/zephyr/devicetree/ordinals.h +++ b/include/zephyr/devicetree/ordinals.h @@ -24,6 +24,13 @@ */ #define DT_DEP_ORD(node_id) DT_CAT(node_id, _ORD) +/** + * @brief Get a node's dependency ordinal in string sortable form + * @param node_id Node identifier + * @return the node's dependency ordinal as a zero-padded integer literal + */ +#define DT_DEP_ORD_STR_SORTABLE(node_id) DT_CAT(node_id, _ORD_STR_SORTABLE) + /** * @brief Get a list of dependency ordinals of a node's direct dependencies * diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index ed47d3ae1512..0c95557cda2d 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -747,6 +747,7 @@ def fmt_dep_list(dep_list): out_comment("Node's dependency ordinal:") out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal) + out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}") out_comment("Ordinals for what this node depends on directly:") out_dt_define(f"{node.z_path_id}_REQUIRES_ORDS", From bb590b5b6e2e50929c2065dd16822d68b702b2ce Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 21:52:17 +1000 Subject: [PATCH 1700/2042] init: add sub-priority to internal ordering Add a sub-priority field to `Z_INIT_ENTRY_SECTION`, which is used to ensure that multiple drivers running at the same init priority still run in an order that respects their devicetree dependencies. This is primarily useful when multiple instances of the same device are instantiated that can depend on each other, for example power domains and i2c muxes. Signed-off-by: Jordan Yates --- include/zephyr/device.h | 22 ++++++++++++++++++---- include/zephyr/init.h | 10 ++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 2ea95a2d563a..ce9b6c1312e7 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -848,6 +848,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev) #endif /* CONFIG_DEVICE_DEPS */ +/** + * @brief Init sub-priority of the device + * + * The sub-priority is defined by the devicetree ordinal, which ensures that + * multiple drivers running at the same priority level run in an order that + * respects the devicetree dependencies. + */ +#define Z_DEVICE_INIT_SUB_PRIO(node_id) \ + COND_CODE_1(DT_NODE_EXISTS(node_id), \ + (DT_DEP_ORD_STR_SORTABLE(node_id)), (0)) + /** * @brief Maximum device name length. * @@ -923,14 +934,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev) /** * @brief Define the init entry for a device. * + * @param node_id Devicetree node id for the device (DT_INVALID_NODE if a + * software device). * @param dev_id Device identifier. * @param init_fn_ Device init function. * @param level Initialization level. * @param prio Initialization priority. */ -#define Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn_, level, prio) \ - static const Z_DECL_ALIGN(struct init_entry) \ - Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \ +#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ + 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), \ @@ -967,7 +981,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ \ - Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn, level, prio) + Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio) #if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) /** diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 77e8fddc0cc6..9b0d2993d620 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -128,10 +128,12 @@ struct init_entry { * @brief Init entry section. * * Each init entry is placed in a section with a name crafted so that it allows - * linker scripts to sort them according to the specified level/priority. + * linker scripts to sort them according to the specified + * level/priority/sub-priority. */ -#define Z_INIT_ENTRY_SECTION(level, prio) \ - __attribute__((__section__(".z_init_" #level STRINGIFY(prio)"_"))) +#define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \ + __attribute__((__section__( \ + ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) /** @endcond */ @@ -186,7 +188,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) __used __noasan \ + Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ Z_INIT_ENTRY_NAME(name) = { \ .init_fn = {.sys = (init_fn_)}, \ .dev = NULL, \ From 01e98fcb5f9b672d26758c8c73d64e3d2f2c41ca Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 10:46:11 +1000 Subject: [PATCH 1701/2042] tests: kernel: device: test sub-priority Add tests for sorting devices at the same init priority based on their devicetree ordinals. Signed-off-by: Jordan Yates --- tests/kernel/device/app.overlay | 17 ++++++++++ .../device/boards/hifive_unmatched.overlay | 17 ++++++++++ .../kernel/device/dts/bindings/fakedomain.yml | 8 +++++ tests/kernel/device/src/main.c | 22 +++++++++++- tests/kernel/device/src/test_driver_init.c | 34 +++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/kernel/device/dts/bindings/fakedomain.yml diff --git a/tests/kernel/device/app.overlay b/tests/kernel/device/app.overlay index aae8873f6b8d..d7426f2b6134 100644 --- a/tests/kernel/device/app.overlay +++ b/tests/kernel/device/app.overlay @@ -51,4 +51,21 @@ "dale"; status = "okay"; }; + + fakedomain_0: fakedomain_0 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_2>; + }; + + fakedomain_1: fakedomain_1 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_0>; + }; + + fakedomain_2: fakedomain_2 { + compatible = "fakedomain"; + status = "okay"; + }; }; diff --git a/tests/kernel/device/boards/hifive_unmatched.overlay b/tests/kernel/device/boards/hifive_unmatched.overlay index 4a7ce8155f5d..40fa5e74adb4 100644 --- a/tests/kernel/device/boards/hifive_unmatched.overlay +++ b/tests/kernel/device/boards/hifive_unmatched.overlay @@ -48,4 +48,21 @@ "dale"; status = "okay"; }; + + fakedomain_0: fakedomain_0 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_2>; + }; + + fakedomain_1: fakedomain_1 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_0>; + }; + + fakedomain_2: fakedomain_2 { + compatible = "fakedomain"; + status = "okay"; + }; }; diff --git a/tests/kernel/device/dts/bindings/fakedomain.yml b/tests/kernel/device/dts/bindings/fakedomain.yml new file mode 100644 index 000000000000..a676419de1fa --- /dev/null +++ b/tests/kernel/device/dts/bindings/fakedomain.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, CSIRO +# SPDX-License-Identifier: Apache-2.0 + +description: Properties for fake power domain + +compatible: "fakedomain" + +include: base.yaml diff --git a/tests/kernel/device/src/main.c b/tests/kernel/device/src/main.c index cfc89da2f076..a3e9430c15a6 100644 --- a/tests/kernel/device/src/main.c +++ b/tests/kernel/device/src/main.c @@ -265,6 +265,7 @@ ZTEST(device, test_sys_init_multiple) /* this is for storing sequence during initialization */ extern int init_level_sequence[4]; extern int init_priority_sequence[4]; +extern int init_sub_priority_sequence[3]; extern unsigned int seq_level_cnt; extern unsigned int seq_priority_cnt; @@ -298,7 +299,7 @@ ZTEST(device, test_device_init_level) /** * @brief Test initialization priorities for device driver instances * - * details After the defined device instances have initialized, we check the + * @details After the defined device instances have initialized, we check the * sequence number that each driver stored during initialization. If the * sequence of initial priority stored is corresponding with our expectation, it * means assigning the priority for driver instance works. @@ -322,6 +323,25 @@ ZTEST(device, test_device_init_priority) "init sequence is not correct"); } +/** + * @brief Test initialization sub-priorities for device driver instances + * + * @details After the defined device instances have initialized, we check the + * sequence number that each driver stored during initialization. If the + * sequence of initial priority stored is corresponding with our expectation, it + * means using the devicetree for sub-priority sorting works. + * + * @ingroup kernel_device_tests + */ +ZTEST(device, test_device_init_sub_priority) +{ + /* fakedomain_1 depends on fakedomain_0 which depends on fakedomain_2, + * therefore we require that the initialisation runs in the reverse order. + */ + zassert_equal(init_sub_priority_sequence[0], 1, ""); + zassert_equal(init_sub_priority_sequence[1], 2, ""); + zassert_equal(init_sub_priority_sequence[2], 0, ""); +} /** * @brief Test abstraction of device drivers with common functionalities diff --git a/tests/kernel/device/src/test_driver_init.c b/tests/kernel/device/src/test_driver_init.c index 1c468f72a214..e89d6acc7ff4 100644 --- a/tests/kernel/device/src/test_driver_init.c +++ b/tests/kernel/device/src/test_driver_init.c @@ -39,8 +39,10 @@ /* this is for storing sequence during initialization */ __pinned_bss int init_level_sequence[4] = {0}; __pinned_bss int init_priority_sequence[4] = {0}; +__pinned_bss int init_sub_priority_sequence[3] = {0}; __pinned_bss unsigned int seq_level_cnt; __pinned_bss unsigned int seq_priority_cnt; +__pinned_bss unsigned int seq_sub_priority_cnt; /* define driver type 1: for testing initialize levels and priorities */ typedef int (*my_api_configure_t)(const struct device *dev, int dev_config); @@ -126,6 +128,28 @@ static int my_driver_pri_4_init(const struct device *dev) return 0; } +/* driver init function of testing sub_priority */ +static int my_driver_sub_pri_0_init(const struct device *dev) +{ + init_sub_priority_sequence[0] = seq_sub_priority_cnt++; + + return 0; +} + +static int my_driver_sub_pri_1_init(const struct device *dev) +{ + init_sub_priority_sequence[1] = seq_sub_priority_cnt++; + + return 0; +} + +static int my_driver_sub_pri_2_init(const struct device *dev) +{ + init_sub_priority_sequence[2] = seq_sub_priority_cnt++; + + return 0; +} + /** * @brief Test providing control device driver initialization order * @@ -172,3 +196,13 @@ DEVICE_DEFINE(my_driver_priority_2, MY_DRIVER_PRI_2, DEVICE_DEFINE(my_driver_priority_3, MY_DRIVER_PRI_3, &my_driver_pri_3_init, NULL, NULL, NULL, POST_KERNEL, 3, &funcs_my_drivers); + +/* Create several devices at the same init priority that depend on each + * other in devicetree so that we can validate linker sorting. + */ +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_0), my_driver_sub_pri_0_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_1), my_driver_sub_pri_1_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_2), my_driver_sub_pri_2_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); From c72577d709efb68249d23507869245029c8b49f5 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 18:07:12 +1000 Subject: [PATCH 1702/2042] gpio: stellaris: implement `gpio_pin_get_config` Implement `gpio_pin_get_config` for the stellaris platform, and by extension `qemu_cortex_m3`. Signed-off-by: Jordan Yates --- drivers/gpio/gpio_stellaris.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpio/gpio_stellaris.c b/drivers/gpio/gpio_stellaris.c index 433962e10585..e7114fa0e7f1 100644 --- a/drivers/gpio/gpio_stellaris.c +++ b/drivers/gpio/gpio_stellaris.c @@ -107,6 +107,34 @@ static int gpio_stellaris_configure(const struct device *dev, return 0; } +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_stellaris_get_config(const struct device *dev, + gpio_pin_t pin, + gpio_flags_t *out_flags) +{ + const struct gpio_stellaris_config *cfg = dev->config; + uint32_t base = cfg->base; + gpio_flags_t flags = 0; + mm_reg_t mask_addr; + + if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin) == 0) { + flags = GPIO_DISCONNECTED; + } else if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin)) { + mask_addr = GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, BIT(pin)); + + if (sys_test_bit(mask_addr, pin)) { + flags |= GPIO_OUTPUT_HIGH; + } else { + flags |= GPIO_OUTPUT_LOW; + } + } else { + flags = GPIO_INPUT; + } + *out_flags = flags; + return 0; +} +#endif + static int gpio_stellaris_port_get_raw(const struct device *dev, uint32_t *value) { @@ -221,6 +249,9 @@ static int gpio_stellaris_manage_callback(const struct device *dev, static const struct gpio_driver_api gpio_stellaris_driver_api = { .pin_configure = gpio_stellaris_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_stellaris_get_config, +#endif .port_get_raw = gpio_stellaris_port_get_raw, .port_set_masked_raw = gpio_stellaris_port_set_masked_raw, .port_set_bits_raw = gpio_stellaris_port_set_bits_raw, From 84016c1cd3658291a4d16775771fe0c3eb811943 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 11 Apr 2022 21:24:58 +1000 Subject: [PATCH 1703/2042] pm: device: add driver init helper Adds a helper function for initializing devices into the expected power state, through the devices `pm_device_action_cb_t`. This eliminates code duplication between the init functions and the PM callback. The expected device states in order of priority are: * No power applied to device, `OFF` * `zephyr,pm-device-runtime-auto` enabled, `SUSPEND` * Otherwise, `ACTIVE` Signed-off-by: Jordan Yates --- include/zephyr/pm/device.h | 29 +++++++++++++++++++++++++++++ subsys/pm/device.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index 734f6c08a60f..29cd4b26a1e8 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -581,6 +581,22 @@ int pm_device_power_domain_remove(const struct device *dev, * @retval false If device is not currently powered */ bool pm_device_is_powered(const struct device *dev); + +/** + * @brief Setup a device driver into the lowest valid power mode + * + * This helper function is intended to be called at the end of a driver + * init function to automatically setup the device into the lowest power + * mode. It assumes that the device has been configured as if it is in + * @ref PM_DEVICE_STATE_OFF. + * + * @param dev Device instance. + * @param action_cb Device PM control callback function. + * @retval 0 On success. + * @retval -errno Error code from @a action_cb on failure. + */ +int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb); + #else static inline int pm_device_state_get(const struct device *dev, enum pm_device_state *state) @@ -667,6 +683,19 @@ static inline bool pm_device_is_powered(const struct device *dev) ARG_UNUSED(dev); return true; } + +static inline int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb) +{ + int rc; + + /* When power management is not enabled, all drivers should initialise to active state */ + rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); + if (rc == 0) { + rc = action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + return rc; +} + #endif /* CONFIG_PM_DEVICE */ /** @} */ diff --git a/subsys/pm/device.c b/subsys/pm/device.c index baf37983d692..bba0c316257a 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -385,3 +385,41 @@ bool pm_device_is_powered(const struct device *dev) return true; #endif } + +int pm_device_driver_init(const struct device *dev, + pm_device_action_cb_t action_cb) +{ + struct pm_device *pm = dev->pm; + int rc = 0; + + /* Work only needs to be performed if the device is powered */ + if (pm_device_is_powered(dev)) { + /* Run power-up logic */ + rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); + if (rc != 0) { + return rc; + } + /* If device has no PM structure */ + if (pm == NULL) { + /* Device should always be active */ + return action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + /* If device will have PM device runtime enabled */ + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) && + atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_AUTO)) { + /* Init into suspend mode. + * This saves a SUSPENDED->ACTIVE->SUSPENDED cycle. + */ + pm_device_init_suspended(dev); + } + /* No PM enabled on the device by default */ + else { + /* Startup into active mode */ + return action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + } else { + /* Start in off mode */ + pm_device_init_off(dev); + } + return rc; +} From 1f1217e8324370afb8f93799340dd0fb3edf9c62 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 18:10:28 +1000 Subject: [PATCH 1704/2042] power_domain: gpio: compile without `PM_DEVICE_POWER_DOMAIN` Let the driver compile without `PM_DEVICE_POWER_DOMAIN`, in which case the driver only controls the GPIO, without notifying dependant devices. Signed-off-by: Jordan Yates --- drivers/power_domain/power_domain_gpio.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 511564dbc335..88178531504f 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -30,6 +30,8 @@ struct pd_visitor_context { enum pm_device_action action; }; +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + static int pd_on_domain_visitor(const struct device *dev, void *context) { struct pd_visitor_context *visitor_context = context; @@ -43,12 +45,16 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) return 0; } +#endif + static int pd_gpio_pm_action(const struct device *dev, enum pm_device_action action) { +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + struct pd_visitor_context context = {.domain = dev}; +#endif const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; - struct pd_visitor_context context = {.domain = dev}; int64_t next_boot_ticks; int rc = 0; @@ -67,14 +73,18 @@ static int pd_gpio_pm_action(const struct device *dev, LOG_INF("%s is now ON", dev->name); /* Wait for domain to come up */ k_sleep(K_USEC(cfg->startup_delay_us)); +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain they are now powered */ context.action = PM_DEVICE_ACTION_TURN_ON; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); +#endif break; case PM_DEVICE_ACTION_SUSPEND: +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain that power is going down */ context.action = PM_DEVICE_ACTION_TURN_OFF; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); +#endif /* Switch power off */ gpio_pin_set_dt(&cfg->enable, 0); LOG_INF("%s is now OFF", dev->name); From 39b2ec57a0c310f76ab50abab6837be9cc948bf5 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 11:12:34 +1000 Subject: [PATCH 1705/2042] power_domain: gpio: init with `pm_device_driver_init` Startup power domains according to the expected final state given the power supply and PM device runtime support. Signed-off-by: Jordan Yates --- drivers/power_domain/power_domain_gpio.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 88178531504f..c0fb25b3d457 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -113,7 +113,6 @@ static int pd_gpio_init(const struct device *dev) { const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; - int rc; if (!device_is_ready(cfg->enable.port)) { LOG_ERR("GPIO port %s is not ready", cfg->enable.port->name); @@ -122,16 +121,8 @@ static int pd_gpio_init(const struct device *dev) /* We can't know how long the domain has been off for before boot */ data->next_boot = K_TIMEOUT_ABS_US(cfg->off_on_delay_us); - if (pm_device_on_power_domain(dev)) { - /* Device is unpowered */ - pm_device_init_off(dev); - rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); - } else { - pm_device_init_suspended(dev); - rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); - } - - return rc; + /* Boot according to state */ + return pm_device_driver_init(dev, pd_gpio_pm_action); } #define POWER_DOMAIN_DEVICE(id) \ From b82bbf5e31d0163b496334af2f53e92cb0992658 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 17:22:11 +1000 Subject: [PATCH 1706/2042] tests: pm: update power domain behaviour Update the expected power domain behaviour in the tests in line with the driver implementation changes. Signed-off-by: Jordan Yates --- tests/subsys/pm/device_power_domains/src/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/subsys/pm/device_power_domains/src/main.c b/tests/subsys/pm/device_power_domains/src/main.c index 8bc7789fa4b0..50726bcef199 100644 --- a/tests/subsys/pm/device_power_domains/src/main.c +++ b/tests/subsys/pm/device_power_domains/src/main.c @@ -40,17 +40,17 @@ ZTEST(device_power_domain, test_demo) /* Initial power state */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); - zassert_false(pm_device_is_powered(reg_chained), ""); - zassert_false(pm_device_is_powered(dev), ""); + zassert_true(pm_device_is_powered(reg_chained), ""); + zassert_true(pm_device_is_powered(dev), ""); TC_PRINT("Enabling runtime power management on regulators\n"); - pm_device_runtime_enable(reg_0); - pm_device_runtime_enable(reg_1); - pm_device_runtime_enable(reg_chained); pm_device_runtime_enable(dev); + pm_device_runtime_enable(reg_chained); + pm_device_runtime_enable(reg_1); + pm_device_runtime_enable(reg_0); - /* State shouldn't have changed */ + /* Power domains should now be suspended */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); zassert_false(pm_device_is_powered(reg_chained), ""); From a4cfc1eb37c5619fa10ffcc4cd8d45d12e8913a4 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 17:17:32 +1000 Subject: [PATCH 1707/2042] tests: pm: test `pm_device_driver_init` Test that `pm_device_driver_init` puts devices into the appropriate state depending on the devicetree configuration. Signed-off-by: Jordan Yates --- .../pm/device_driver_init/CMakeLists.txt | 8 +++ .../subsys/pm/device_driver_init/app.overlay | 44 ++++++++++++ tests/subsys/pm/device_driver_init/prj.conf | 9 +++ tests/subsys/pm/device_driver_init/src/main.c | 68 +++++++++++++++++++ .../pm/device_driver_init/testcase.yaml | 19 ++++++ 5 files changed, 148 insertions(+) create mode 100644 tests/subsys/pm/device_driver_init/CMakeLists.txt create mode 100644 tests/subsys/pm/device_driver_init/app.overlay create mode 100644 tests/subsys/pm/device_driver_init/prj.conf create mode 100644 tests/subsys/pm/device_driver_init/src/main.c create mode 100644 tests/subsys/pm/device_driver_init/testcase.yaml diff --git a/tests/subsys/pm/device_driver_init/CMakeLists.txt b/tests/subsys/pm/device_driver_init/CMakeLists.txt new file mode 100644 index 000000000000..ddb4b524925a --- /dev/null +++ b/tests/subsys/pm/device_driver_init/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023, CSIRO. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(device_driver_init) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/pm/device_driver_init/app.overlay b/tests/subsys/pm/device_driver_init/app.overlay new file mode 100644 index 000000000000..a5518b74be2c --- /dev/null +++ b/tests/subsys/pm/device_driver_init/app.overlay @@ -0,0 +1,44 @@ +/ { + test_reg: test_reg { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 0 0>; + }; + + test_reg_chained: test_reg_chained { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 1 0>; + power-domain = <&test_reg>; + }; + + test_reg_chained_auto: test_reg_chained_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 2 0>; + power-domain = <&test_reg>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_auto: test_reg_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 3 0>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_auto_chained: test_reg_auto_chained { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 4 0>; + power-domain = <&test_reg_auto>; + }; + + test_reg_auto_chained_auto: test_reg_auto_chained_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 5 0>; + power-domain = <&test_reg_auto>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_disabled: test_reg_disabled { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 6 0>; + status = "disabled"; + }; +}; diff --git a/tests/subsys/pm/device_driver_init/prj.conf b/tests/subsys/pm/device_driver_init/prj.conf new file mode 100644 index 000000000000..e6d05f591acf --- /dev/null +++ b/tests/subsys/pm/device_driver_init/prj.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Commonwealth Scientific and Industrial Research +# Organisation (CSIRO) ABN 41 687 119 230. +CONFIG_ZTEST=y +CONFIG_MP_MAX_NUM_CPUS=1 + +CONFIG_GPIO=y +CONFIG_GPIO_GET_CONFIG=y +CONFIG_POWER_DOMAIN=y +CONFIG_ZTEST_NEW_API=y diff --git a/tests/subsys/pm/device_driver_init/src/main.c b/tests/subsys/pm/device_driver_init/src/main.c new file mode 100644 index 000000000000..bc004ab7a0c5 --- /dev/null +++ b/tests/subsys/pm/device_driver_init/src/main.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023, Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * SPDX-License-Identifier: Apache-2.0 + * + * State checking in this test is done via the GPIO state instead of + * the PM API as this test runs without the PM api enabled. + */ + +#include +#include +#include +#include + +#define POWER_GPIO_CONFIG_IS(node_id, config)\ + {\ + const struct gpio_dt_spec gpio = GPIO_DT_SPEC_GET(node_id, enable_gpios);\ + gpio_flags_t gpio_config; \ + int rc = gpio_pin_get_config_dt(&gpio, &gpio_config); \ + zassert_equal(rc, 0, "GPIO config retrieval failed"); \ + zassert_equal(gpio_config, config, "Unexpected config");\ + } + +#define DEVICE_STATE_IS(node_id, value) \ + rc = pm_device_state_get(DEVICE_DT_GET(node_id), &state); \ + zassert_equal(rc, 0, "Device state retrieval failed"); \ + zassert_equal(state, value, "Unexpected device state"); + +ZTEST(device_driver_init, test_demo) +{ +#if !IS_ENABLED(CONFIG_PM) || !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + /* Every regulator should be in "active" mode automatically. + * State checking via GPIO as PM API is disabled. + */ + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_disabled), GPIO_DISCONNECTED); +#endif + +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + enum pm_device_state state; + int rc; + + /* 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); + + /* 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); + /* 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); +#endif +} + +ZTEST_SUITE(device_driver_init, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/pm/device_driver_init/testcase.yaml b/tests/subsys/pm/device_driver_init/testcase.yaml new file mode 100644 index 000000000000..c7e549b54008 --- /dev/null +++ b/tests/subsys/pm/device_driver_init/testcase.yaml @@ -0,0 +1,19 @@ +tests: + pm.device_driver_init: + tags: pm + platform_allow: qemu_cortex_m3 + pm.device_driver_init.pm: + tags: pm + platform_allow: qemu_cortex_m3 + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_POWER_DOMAIN=y + pm.device_driver_init.pm_device_runtime: + tags: pm + platform_allow: qemu_cortex_m3 + extra_configs: + - CONFIG_PM=y + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_POWER_DOMAIN=y + - CONFIG_PM_DEVICE_RUNTIME=y From 3f4da29a3c78dacbf1a4fc6a46a0747fdd350818 Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Mon, 17 Jul 2023 10:32:08 +0200 Subject: [PATCH 1708/2042] drivers: ieee802154: nrf5: Revert Add transmission with multiple CCA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5443d4127bfe38f3f698ec626907b51569b27eaa. Signed-off-by: Andrzej Kuroś --- drivers/ieee802154/Kconfig.nrf5 | 11 ---------- drivers/ieee802154/ieee802154_nrf5.c | 24 ++------------------ drivers/ieee802154/ieee802154_nrf5.h | 33 ---------------------------- 3 files changed, 2 insertions(+), 66 deletions(-) diff --git a/drivers/ieee802154/Kconfig.nrf5 b/drivers/ieee802154/Kconfig.nrf5 index 1ce67332db00..3ab0d19c3991 100644 --- a/drivers/ieee802154/Kconfig.nrf5 +++ b/drivers/ieee802154/Kconfig.nrf5 @@ -88,15 +88,4 @@ config IEEE802154_NRF5_LOG_RX_FAILURES It can be helpful for the network traffic analyze but it generates also a lot of log records in a stress environment. -config IEEE802154_NRF5_MULTIPLE_CCA - bool "Support for multiple CCA attempts before transmission" - help - This is an optional extension not conforming to IEEE Std. 802.15.4-2015. - When this option is enabled the user of ieee802154_nrf5 has possibility - to express the maximum number of extra CCA attempts for a transmission. - The CCA procedure is repeated back-to-back either until it returns - idle channel and the transmission starts, or until 1 + `extra cca attempts` - CCA attempts are performed. Because of that the moment of transmission can be - delayed by the time taken by the extra CCA operations performed. - endif diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index d77b96147094..5861cd3635e5 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -546,8 +546,7 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) return result; } -static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, - uint8_t *payload, bool cca) +static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) { nrf_802154_transmit_at_metadata_t metadata = { .frame_props = { @@ -562,9 +561,6 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .power = net_pkt_ieee802154_txpwr(pkt), #endif }, -#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) - .extra_cca_attempts = nrf5_radio->extra_cca_attempts -#endif }; uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); @@ -610,7 +606,7 @@ static int nrf5_tx(const struct device *dev, case IEEE802154_TX_MODE_TXTIME: case IEEE802154_TX_MODE_TXTIME_CCA: __ASSERT_NO_MSG(pkt); - ret = nrf5_tx_at(nrf5_radio, pkt, nrf5_radio->tx_psdu, + ret = nrf5_tx_at(pkt, nrf5_radio->tx_psdu, mode == IEEE802154_TX_MODE_TXTIME_CCA); break; #endif /* CONFIG_NET_PKT_TXTIME */ @@ -1166,22 +1162,6 @@ void nrf_802154_serialization_error(const nrf_802154_ser_err_data_t *err) } #endif -#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) -void ieee802154_nrf5_extra_cca_attempts_set(const struct device *dev, uint8_t value) -{ - struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); - - nrf5_radio->extra_cca_attempts = value; -} - -uint8_t ieee802154_nrf5_extra_cca_attempts_get(const struct device *dev) -{ - struct nrf5_802154_data *nrf5_radio = NRF5_802154_DATA(dev); - - return nrf5_radio->extra_cca_attempts; -} -#endif /* defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) */ - static const struct nrf5_802154_config nrf5_radio_cfg = { .irq_config_func = nrf5_irq_config, }; diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index 81c71721dda4..e96fae04ca37 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -87,39 +87,6 @@ struct nrf5_802154_data { /* Indicates if currently processed TX frame has dynamic data updated. */ bool tx_frame_mac_hdr_rdy; - -#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) - /* The maximum number of extra CCA attempts to be performed before transmission. */ - uint8_t extra_cca_attempts; -#endif }; -#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) -/** - * @brief Sets the maximum number of extra CCA attempts to be performed by a transmit operation - * - * The default value of extra cca attempts is 0. - * - * The maximum number of extra cca attempts set by this function is applied to transmissions - * requested with mode IEEE802154_TX_MODE_TXTIME_CCA only. This might change in the future, so - * it is recommended to restore previously used value after each transmission. See - * @ref ieee802154_nrf5_extra_cca_attempts_get. - * - * @param dev Pointer to a ieee802154_nrf5 device - * @param value Value to set. Allowed range is 0...254. - */ -void ieee802154_nrf5_extra_cca_attempts_set(const struct device *dev, uint8_t value); - -/** - * @brief Gets the maximum number of extra CCA attempts to be performed by a transmit operation. - * - * @sa @ref ieee802154_nrf5_extra_cca_attempts_set - * - * @param dev Pointer to a ieee802154_nrf5 device - * @return Maximum number of extra CCA attempts. - */ -uint8_t ieee802154_nrf5_extra_cca_attempts_get(const struct device *dev); - -#endif /* defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) */ - #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ From 83ad3fdafa4669f7335c4776bd25e3ff731664eb Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 18 Jul 2023 08:00:18 +0200 Subject: [PATCH 1709/2042] net: ieee802154_radio: add extension values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ieee802154_tx_mode and ieee802154_config_type types are given values allowing to extend these types elsewhere. Signed-off-by: Andrzej Kuroś --- include/zephyr/net/ieee802154_radio.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 3270f334b5a2..9111555240e8 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -115,8 +115,17 @@ enum ieee802154_hw_caps { IEEE802154_HW_SUB_GHZ = BIT(13), /* Sub-GHz radio supported * TODO: Replace with channel page attribute. */ + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing + * the ieee802154_hw_caps type. + */ }; +/** @brief Number of bits used by ieee802154_hw_caps type. */ +#define IEEE802154_HW_CAPS_BITS_COMMON_COUNT (14) + +/** @brief This and higher values are specific to the protocol- or driver-specific extensions. */ +#define IEEE802154_HW_CAPS_BITS_PRIV_START IEEE802154_HW_CAPS_BITS_COMMON_COUNT + enum ieee802154_filter_type { IEEE802154_FILTER_TYPE_IEEE_ADDR, IEEE802154_FILTER_TYPE_SHORT_ADDR, @@ -188,6 +197,12 @@ enum ieee802154_tx_mode { * Requires IEEE802154_HW_TXTIME capability. */ IEEE802154_TX_MODE_TXTIME_CCA, + + /** Number of modes defined in ieee802154_tx_mode. */ + IEEE802154_TX_MODE_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_TX_MODE_PRIV_START = IEEE802154_TX_MODE_COMMON_COUNT, }; /** IEEE802.15.4 Frame Pending Bit table address matching mode. */ @@ -296,6 +311,12 @@ enum ieee802154_config_type { * should disable it for all enabled addresses. */ IEEE802154_CONFIG_ENH_ACK_HEADER_IE, + + /** Number of types defined in ieee802154_config_type. */ + IEEE802154_CONFIG_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_CONFIG_PRIV_START = IEEE802154_CONFIG_COMMON_COUNT, }; /** IEEE802.15.4 driver configuration data. */ From a04a059ccc09f1d8f38ddf044785ecd56acc655f Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Thu, 20 Jul 2023 18:55:13 +0200 Subject: [PATCH 1710/2042] net: ieee802154_radio: add attribute getter API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `attr_get` method is added to the ieee802154_radio to allow reading of driver specific attributes of given device. The enum `ieee802154_attr` provides common extension pattern allowing to extend the attribute set. Accessor function `ieee802154_radio_attr_get` is provided. Signed-off-by: Andrzej Kuroś --- include/zephyr/net/ieee802154_radio.h | 26 +++++++++++++++++++++ subsys/net/l2/ieee802154/ieee802154_utils.h | 14 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 9111555240e8..6006bd813ece 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -397,6 +397,23 @@ struct ieee802154_config { }; }; +/** IEEE 802.15.4 attributes. */ +enum ieee802154_attr { + /** Number of attributes defined in ieee802154_attr. */ + IEEE802154_ATTR_COMMON_COUNT, + + /** This and higher values are specific to the protocol- or driver-specific extensions. */ + IEEE802154_ATTR_PRIV_START = IEEE802154_ATTR_COMMON_COUNT, +}; + +/** IEEE 802.15.4 attribute value data. */ +struct ieee802154_attr_value { + union { + /* TODO: Please remove when first attribute is added. */ + uint8_t dummy; + }; +}; + /** * @brief IEEE 802.15.4 radio interface API. * @@ -476,6 +493,15 @@ struct ieee802154_radio_api { * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. */ uint8_t (*get_sch_acc)(const struct device *dev); + + /** Get the value of an attribute. + * If the requested attribute is supported by implementation, this function returns 0 + * and fills appropriate version of union in `value`. + * If requested attribute is not supported, this function returns -ENOENT. + */ + int (*attr_get)(const struct device *dev, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value); }; /* Make sure that the network interface API is properly setup inside diff --git a/subsys/net/l2/ieee802154/ieee802154_utils.h b/subsys/net/l2/ieee802154/ieee802154_utils.h index 66ca74e71dc3..4294ba7bd9ff 100644 --- a/subsys/net/l2/ieee802154/ieee802154_utils.h +++ b/subsys/net/l2/ieee802154/ieee802154_utils.h @@ -106,6 +106,20 @@ static inline int ieee802154_radio_stop(struct net_if *iface) return radio->stop(net_if_get_device(iface)); } +static inline int ieee802154_radio_attr_get(struct net_if *iface, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + const struct ieee802154_radio_api *radio = + net_if_get_device(iface)->api; + + if (!radio || !radio->attr_get) { + return -ENOENT; + } + + return radio->attr_get(net_if_get_device(iface), attr, value); +} + /** * Sets the radio drivers extended address filter. * From d6567fc9e2ffa89b4ad718e5e21c31386246c7da Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 18 Jul 2023 10:41:33 +0200 Subject: [PATCH 1711/2042] net: openthread: multiple cca as ieee802154 extensions interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds extenstion interface that extends ieee802154_radio.h New OT-specific capability, transmit mode and configuration parameter is added. Signed-off-by: Andrzej Kuroś --- .../zephyr/net/ieee802154_radio_openthread.h | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 include/zephyr/net/ieee802154_radio_openthread.h diff --git a/include/zephyr/net/ieee802154_radio_openthread.h b/include/zephyr/net/ieee802154_radio_openthread.h new file mode 100644 index 000000000000..56a9bd8de0dd --- /dev/null +++ b/include/zephyr/net/ieee802154_radio_openthread.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief This file extends interface of ieee802154_radio.h for OpenThread. + */ + +#ifndef ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ +#define ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ + +#include + +/** + * OpenThread specific capabilities of ieee802154 driver. + * This type extends @ref ieee802154_hw_caps. + */ +enum ieee802154_openthread_hw_caps { + /** Capability to transmit with @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA + * mode. + */ + IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA = BIT(IEEE802154_HW_CAPS_BITS_PRIV_START), +}; + +enum ieee802154_openthread_tx_mode { + /** + * The @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA mode allows to send + * a scheduled packet if the channel is reported idle after at most + * 1 + max_extra_cca_attempts CCAs performed back-to-back. + * + * This mode is a non-standard experimental OpenThread feature. It allows transmission + * of a packet within a certain time window. + * The earliest transmission time is specified as in the other TXTIME modes: + * When the first CCA reports an idle channel then the first symbol of the packet's SHR + * SHALL be present at the local antenna at the time represented by the scheduled + * TX timestamp (referred to as T_tx below). + * + * If the first CCA reports a busy channel, then additional CCAs up to + * max_extra_cca_attempts will be done until one of them reports an idle channel and + * the packet is sent out or the max number of attempts is reached in which case + * the transmission fails. + * + * The timing of these additional CCAs depends on the capabilities of the driver + * which reports them in the T_recca and T_ccatx driver attributes + * (see @ref IEEE802154_OPENTHREAD_ATTR_T_RECCA and + * @ref IEEE802154_OPENTHREAD_ATTR_T_CCATX). Based on these attributes the upper layer + * can calculate the latest point in time (T_txmax) that the first symbol of the scheduled + * packet's SHR SHALL be present at the local antenna: + * + * T_maxtxdelay = max_extra_cca_attempts * (aCcaTime + T_recca) - T_recca + T_ccatx + * T_txmax = T_tx + T_maxtxdelay + * + * See IEEE 802.15.4-2020, section 11.3, table 11-1 for the definition of aCcaTime. + * + * Drivers implementing this TX mode SHOULD keep T_recca and T_ccatx as short as possible. + * T_ccatx SHALL be less than or equal aTurnaroundTime as defined in ibid., + * section 11.3, table 11-1. + * + * CCA SHALL be executed as defined by the phyCcaMode PHY PIB attribute (see ibid., + * section 11.3, table 11-2). + * + * Requires IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA capability. + */ + IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA = IEEE802154_TX_MODE_PRIV_START +}; + +/** + * OpenThread specific configuration types of ieee802154 driver. + * This type extends @ref ieee802154_config_type. + */ +enum ieee802154_openthread_config_type { + /** Allows to configure extra CCA for transmission requested with mode + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Requires IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA capability. + */ + IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS = IEEE802154_CONFIG_PRIV_START +}; + +/** OpenThread specific configuration data of ieee802154 driver. */ +struct ieee802154_openthread_config { + union { + struct ieee802154_config common; + + /** ``IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS`` + * + * The maximum number of extra CCAs to be performed when transmission is + * requested with mode @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + */ + uint8_t max_extra_cca_attempts; + }; +}; + +/** + * OpenThread specific attributes of ieee802154 driver. + * This type extends @ref ieee802154_attr + */ +enum ieee802154_openthread_attr { + + /** Attribute: Maximum time between consecutive CCAs performed back-to-back. + * + * This is attribute for T_recca parameter mentioned for + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Time is expressed in microseconds. + */ + IEEE802154_OPENTHREAD_ATTR_T_RECCA = IEEE802154_ATTR_PRIV_START, + + /** Attribute: Maximum time between detection of CCA idle channel and the moment of + * start of SHR at the local antenna. + * + * This is attribute for T_ccatx parameter mentioned for + * @ref IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA. + * Time is expressed in microseconds. + */ + IEEE802154_OPENTHREAD_ATTR_T_CCATX +}; + +/** + * OpenThread specific attribute value data of ieee802154 driver. + * This type extends @ref ieee802154_attr_value + */ +struct ieee802154_openthread_attr_value { + union { + struct ieee802154_attr_value common; + + /** @brief Attribute value for @ref IEEE802154_OPENTHREAD_ATTR_T_RECCA */ + uint16_t t_recca; + + /** @brief Attribute value for @ref IEEE802154_OPENTHREAD_ATTR_T_CCATX */ + uint16_t t_ccatx; + + }; +}; + +#endif /* ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_OPENTHREAD_H_ */ From 9babac94a7dc61edb9572773cf10acaf3bf064fc Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Tue, 18 Jul 2023 12:28:33 +0200 Subject: [PATCH 1712/2042] drivers: ieee802154: nrf5: multiple CCA support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The support for capability IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA is added to the ieee802154_nrf5 driver. Signed-off-by: Andrzej Kuroś --- drivers/ieee802154/Kconfig.nrf5 | 6 +++ drivers/ieee802154/ieee802154_nrf5.c | 79 ++++++++++++++++++++++++++-- drivers/ieee802154/ieee802154_nrf5.h | 7 ++- 3 files changed, 86 insertions(+), 6 deletions(-) diff --git a/drivers/ieee802154/Kconfig.nrf5 b/drivers/ieee802154/Kconfig.nrf5 index 3ab0d19c3991..9acb811e6b60 100644 --- a/drivers/ieee802154/Kconfig.nrf5 +++ b/drivers/ieee802154/Kconfig.nrf5 @@ -88,4 +88,10 @@ config IEEE802154_NRF5_LOG_RX_FAILURES It can be helpful for the network traffic analyze but it generates also a lot of log records in a stress environment. +config IEEE802154_NRF5_MULTIPLE_CCA + bool "Support for multiple CCA attempts before transmission" + help + When this option is enabled the OpenThread capability + IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA is supported by the ieee802154_nrf5. + endif diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 5861cd3635e5..d85ae2e71a88 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -1,7 +1,7 @@ /* ieee802154_nrf5.c - nRF5 802.15.4 driver */ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,6 +34,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #if defined(CONFIG_NET_L2_OPENTHREAD) #include +#include #endif #include @@ -229,7 +230,11 @@ 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 | - ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL); + ((caps & NRF_802154_CAPABILITY_SECURITY) ? IEEE802154_HW_TX_SEC : 0UL) +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + | IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA +#endif + ; } /* Radio device API */ @@ -546,8 +551,32 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) return result; } -static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) +static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, + uint8_t *payload, enum ieee802154_tx_mode mode) { + bool cca = false; +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + uint8_t max_extra_cca_attempts = 0; +#endif + + switch (mode) { + case IEEE802154_TX_MODE_TXTIME: + break; + case IEEE802154_TX_MODE_TXTIME_CCA: + cca = true; + break; +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA: + cca = true; + max_extra_cca_attempts = nrf5_radio->max_extra_cca_attempts; + break; +#endif + break; + default: + __ASSERT_NO_MSG(false); + return false; + } + nrf_802154_transmit_at_metadata_t metadata = { .frame_props = { .is_secured = net_pkt_ieee802154_frame_secured(pkt), @@ -561,6 +590,9 @@ static bool nrf5_tx_at(struct net_pkt *pkt, uint8_t *payload, bool cca) .power = net_pkt_ieee802154_txpwr(pkt), #endif }, +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + .extra_cca_attempts = max_extra_cca_attempts, +#endif }; uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); @@ -605,9 +637,11 @@ static int nrf5_tx(const struct device *dev, #if defined(CONFIG_NET_PKT_TXTIME) case IEEE802154_TX_MODE_TXTIME: case IEEE802154_TX_MODE_TXTIME_CCA: +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_TX_MODE_TXTIME_MULTIPLE_CCA: +#endif __ASSERT_NO_MSG(pkt); - ret = nrf5_tx_at(pkt, nrf5_radio->tx_psdu, - mode == IEEE802154_TX_MODE_TXTIME_CCA); + ret = nrf5_tx_at(nrf5_radio, pkt, nrf5_radio->tx_psdu, mode); break; #endif /* CONFIG_NET_PKT_TXTIME */ default: @@ -978,6 +1012,14 @@ static int nrf5_configure(const struct device *dev, break; #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */ +#if defined(IEEE802154_NRF5_MULTIPLE_CCA) + case IEEE802154_OPENTHREAD_CONFIG_MULTIPLE_CCA: + nrf5_data.max_extra_cca_attempts = + ((const struct ieee802154_openthread_config *)config) + ->max_extra_cca_attempts; + break; +#endif /* IEEE802154_NRF5_MULTIPLE_CCA */ + default: return -EINVAL; } @@ -985,6 +1027,32 @@ static int nrf5_configure(const struct device *dev, return 0; } +static int nrf5_attr_get(const struct device *dev, + enum ieee802154_attr attr, + struct ieee802154_attr_value *value) +{ + ARG_UNUSED(dev); + ARG_UNUSED(value); + + switch (attr) { +#if defined(IEEE802154_NRF5_MULTIPLE_CCA) + /* TODO: t_recca and t_ccatx should be provided by the public API of the + * nRF 802.15.4 Radio Driver. + */ + case IEEE802154_OPENTHREAD_ATTR_T_RECCA: + ((struct ieee802154_openthread_attr_value *)value)->t_recca = 0; + break; + case IEEE802154_OPENTHREAD_ATTR_T_CCATX: + ((struct ieee802154_openthread_attr_value *)value)->t_ccatx = 20; + break; +#endif + default: + return -ENOENT; + } + + return 0; +} + /* nRF5 radio driver callbacks */ void nrf_802154_received_timestamp_raw(uint8_t *data, int8_t power, uint8_t lqi, uint64_t time) @@ -1184,6 +1252,7 @@ static struct ieee802154_radio_api nrf5_radio_api = { .get_time = nrf5_get_time, .get_sch_acc = nrf5_get_acc, .configure = nrf5_configure, + .attr_get = nrf5_attr_get }; #if defined(CONFIG_NET_L2_IEEE802154) diff --git a/drivers/ieee802154/ieee802154_nrf5.h b/drivers/ieee802154/ieee802154_nrf5.h index e96fae04ca37..2cb41debbb86 100644 --- a/drivers/ieee802154/ieee802154_nrf5.h +++ b/drivers/ieee802154/ieee802154_nrf5.h @@ -1,7 +1,7 @@ /* ieee802154_nrf5.h - nRF5 802.15.4 driver */ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +87,11 @@ struct nrf5_802154_data { /* Indicates if currently processed TX frame has dynamic data updated. */ bool tx_frame_mac_hdr_rdy; + +#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA) + /* The maximum number of extra CCA attempts to be performed before transmission. */ + uint8_t max_extra_cca_attempts; +#endif }; #endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_NRF5_H_ */ From 00f3e44689f52bb6c86a3bc42434db4f4720f2a1 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Wed, 19 Jul 2023 11:00:02 +0200 Subject: [PATCH 1713/2042] Bluetooth: Controller: Fix missing endianness conversion in scan_enable Both duration and period are uint16 and thus require endianness conversion Signed-off-by: Troels Nilsson --- subsys/bluetooth/controller/hci/hci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 5e4fee9ae4a1..c4db3b1cca5f 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -3830,7 +3830,8 @@ static void le_set_ext_scan_enable(struct net_buf *buf, struct net_buf **evt) } #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ - status = ll_scan_enable(cmd->enable, cmd->duration, cmd->period); + status = ll_scan_enable(cmd->enable, sys_le16_to_cpu(cmd->duration), + sys_le16_to_cpu(cmd->period)); /* NOTE: As filter duplicates is implemented here in HCI source code, * enabling of already enabled scanning shall succeed after From 287916c71ebd84b6c296632b1494ae8a25ac2dec Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 15 Jun 2023 14:30:19 -0700 Subject: [PATCH 1714/2042] logging: sys_t/catalog: fix unaligned access When copying parameters into payload buffer, it is possible that after copying a string over, the pointer to buffer is no longer aligned on 4 or 8 bytes. And some toolchains may decide to treat the copy as aligned since the values being copied are 4 or 8 bytes. This results in unaligned memory access and hardware exception. So change the copy to memcpy to avoid potential unaligned access. Signed-off-by: Daniel Leung --- subsys/logging/log_output_syst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/logging/log_output_syst.c b/subsys/logging/log_output_syst.c index 156cf06f5b5f..be0ee91cb20b 100644 --- a/subsys/logging/log_output_syst.c +++ b/subsys/logging/log_output_syst.c @@ -751,11 +751,11 @@ static int mipi_catalog_formatter(cbprintf_cb out, void *ctx, } if (arg_sz == sizeof(mipi_syst_u64)) { - *((mipi_syst_u64 *)argp) = - (mipi_syst_u64)MIPI_SYST_HTOLE64(val.v64); + val.v64 = MIPI_SYST_HTOLE64(val.v64); + memcpy(argp, &val.v64, sizeof(val.v64)); } else { - *((mipi_syst_u32 *)argp) = - (mipi_syst_u32)MIPI_SYST_HTOLE32(val.v32); + val.v32 = MIPI_SYST_HTOLE32(val.v32); + memcpy(argp, &val.v32, sizeof(val.v32)); } argp += arg_sz; } From 0439dfa9636a7d189f13b192123e3f8d37955341 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Thu, 20 Jul 2023 09:21:00 -0300 Subject: [PATCH 1715/2042] west.yml: update hal_espressif to fix Wi-Fi label redeclaration Fix Wi-Fi build due to label declaration in hal_espressif. Fixes #59881 Signed-off-by: Sylvio Alves --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 15c641492952..ff83119fcc68 100644 --- a/west.yml +++ b/west.yml @@ -147,7 +147,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 9531c1c17873aa4935f85864ebafd20c02062a8f + revision: 322f6389e21d08845486b5ebe1a6e5cb077981b8 path: modules/hal/espressif west-commands: west/west-commands.yml groups: From e439b5e56d5a6c0c70d7fe8d00acc01fd706d86d Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 14:07:55 +1200 Subject: [PATCH 1716/2042] canbus: isotp: Fix context buffer memory leaks Ensure context buffers are free'd when errors occur Signed-off-by: Grant Ramsay --- subsys/canbus/isotp/isotp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index f228a044239b..3a6e8c22e43d 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -1179,6 +1179,7 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev, ret = attach_fc_filter(ctx); if (ret) { LOG_ERR("Can't attach fc filter: %d", ret); + free_send_ctx(&ctx); return ret; } @@ -1190,6 +1191,7 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev, ctx->filter_id = -1; ret = send_sf(ctx); if (ret) { + free_send_ctx(&ctx); return ret == -EAGAIN ? ISOTP_N_TIMEOUT_A : ISOTP_N_ERROR; } From 648355cb69704dfd17492997d7ce7f5ae3830ef8 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 21 Jul 2023 11:07:42 +0200 Subject: [PATCH 1717/2042] tfm: Fix help text for crypto key module functionality Fix help text for crypto key module functionality, which is included in the source file of crypto_key_management.c source file. The crypto_key.c source file contains generic code that is always included. Signed-off-by: Joakim Andersson --- modules/trusted-firmware-m/Kconfig.tfm.crypto_modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules index 1b4f7e1b17a4..1d70a2c44d29 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules +++ b/modules/trusted-firmware-m/Kconfig.tfm.crypto_modules @@ -19,7 +19,7 @@ config TFM_CRYPTO_KEY_MODULE_ENABLED default y help Enables the KEY crypto module within the crypto partition. - Unset this option if the functionality provided by 'crypto_key.c' + Unset this option if the functionality provided by 'crypto_key_management.c' is not used. config TFM_CRYPTO_AEAD_MODULE_ENABLED From e7781626e7c7a483b69e32fe43c2c19ee7ab1c46 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 12:47:07 +0000 Subject: [PATCH 1718/2042] tests: mcumgr: exclude lpcxpresso51u68 The test is failing for lpcxpresso51u68 with: soc_flash_lpc.c:25:2: error: #error No matching compatible for soc_flash_lpc.c 25 | #error No matching compatible for soc_flash_lpc.c | ^~~~~ Add the board to the exclude list, sort the list as well. Signed-off-by: Fabio Baltieri --- .../fs_mgmt_hash_supported/testcase.yaml | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) 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 a958f48c768d..9d32f1110858 100644 --- a/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/fs_mgmt_hash_supported/testcase.yaml @@ -15,26 +15,29 @@ tests: extra_args: > OVERLAY_CONFIG="configuration/crc32.conf" platform_exclude: - - nucleo_h745zi_q_m4 - - arduino_portenta_h7_m4 - - stm32h747i_disco_m4 - arduino_giga_r1_m4 + - arduino_portenta_h7_m4 - esp32_net + - lpcxpresso51u68 + - nucleo_h745zi_q_m4 + - stm32h747i_disco_m4 mgmt.mcumgr.fs.mgmt.hash.supported.sha256: extra_args: > OVERLAY_CONFIG="configuration/sha256.conf" platform_exclude: - - nucleo_h745zi_q_m4 - - arduino_portenta_h7_m4 - - stm32h747i_disco_m4 - arduino_giga_r1_m4 + - arduino_portenta_h7_m4 - esp32_net + - lpcxpresso51u68 + - nucleo_h745zi_q_m4 + - stm32h747i_disco_m4 mgmt.mcumgr.fs.mgmt.hash.supported.all: extra_args: > OVERLAY_CONFIG="configuration/all.conf" platform_exclude: - - nucleo_h745zi_q_m4 - - arduino_portenta_h7_m4 - - stm32h747i_disco_m4 - arduino_giga_r1_m4 + - arduino_portenta_h7_m4 - esp32_net + - lpcxpresso51u68 + - nucleo_h745zi_q_m4 + - stm32h747i_disco_m4 From 06b106a32e1dce921412b306ad6dcc59f9fff66f Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Mon, 24 Jul 2023 16:20:01 +0200 Subject: [PATCH 1719/2042] MAINTAINERS: Add bbilas as LED collaborator Add myself as a collaborator for the LED area. Signed-off-by: Bartosz Bilas --- MAINTAINERS.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a993fe5fa6f8..7a28c6ac1492 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1073,6 +1073,8 @@ Release Notes: maintainers: - Mani-Sadhasivam - simonguinot + collaborators: + - bbilas files: - drivers/led/ - include/zephyr/drivers/led/ From c008bf1720bc0ef35e2d007133fe8b1a226bde03 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 18 Jul 2023 15:55:24 +0200 Subject: [PATCH 1720/2042] tests: pm: power_states: use cpu0 to define cpu-power-states There's no need to define a new CPU, we can re-use cpu0 in native_posix. Signed-off-by: Gerard Marull-Paretas --- .../pm/power_states_api/boards/native_posix.overlay | 9 ++++----- .../dts/bindings/test-power-states-api.yaml | 13 ------------- tests/subsys/pm/power_states_api/src/main.c | 6 +++--- 3 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 tests/subsys/pm/power_states_api/dts/bindings/test-power-states-api.yaml diff --git a/tests/subsys/pm/power_states_api/boards/native_posix.overlay b/tests/subsys/pm/power_states_api/boards/native_posix.overlay index 7e326bd335d9..247ca393448c 100644 --- a/tests/subsys/pm/power_states_api/boards/native_posix.overlay +++ b/tests/subsys/pm/power_states_api/boards/native_posix.overlay @@ -5,11 +5,6 @@ */ / { - power_states: power_states { - compatible = "test-power-states-api"; - cpu-power-states = <&state0 &state1 &state2>; - }; - state0: state0 { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; @@ -29,3 +24,7 @@ power-state-name = "standby"; }; }; + +&cpu0 { + cpu-power-states = <&state0 &state1 &state2>; +}; diff --git a/tests/subsys/pm/power_states_api/dts/bindings/test-power-states-api.yaml b/tests/subsys/pm/power_states_api/dts/bindings/test-power-states-api.yaml deleted file mode 100644 index de43a1514b01..000000000000 --- a/tests/subsys/pm/power_states_api/dts/bindings/test-power-states-api.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2020, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -description: | - This binding provides resources required to build and run the - tests/subsys/power/power_states_api test in Zephyr. - -compatible: "test-power-states-api" - -properties: - cpu-power-states: - type: phandles - description: List of power management states supported by this cpu. diff --git a/tests/subsys/pm/power_states_api/src/main.c b/tests/subsys/pm/power_states_api/src/main.c index 302f57ff660d..a7e76117815c 100644 --- a/tests/subsys/pm/power_states_api/src/main.c +++ b/tests/subsys/pm/power_states_api/src/main.c @@ -21,11 +21,11 @@ static enum pm_state wrong_states[] = {PM_STATE_SUSPEND_TO_DISK, ZTEST(power_states_1cpu, test_power_states) { enum pm_state dts_states[] = - PM_STATE_LIST_FROM_DT_CPU(DT_NODELABEL(power_states)); + PM_STATE_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0)); struct pm_state_info dts_infos[] = - PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(power_states)); + PM_STATE_INFO_LIST_FROM_DT_CPU(DT_NODELABEL(cpu0)); uint32_t dts_states_len = - DT_NUM_CPU_POWER_STATES(DT_NODELABEL(power_states)); + DT_NUM_CPU_POWER_STATES(DT_NODELABEL(cpu0)); zassert_true(ARRAY_SIZE(states) == dts_states_len, "Invalid number of pm states"); From 5eee169cf0fcce2748391863c2b5d0546a4d321c Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:05:47 +0200 Subject: [PATCH 1721/2042] dts: riscv: espressif: esp32: move power-states to soc dts files CPU idle states are not board specific. This patch moves ESP32 idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- .../riscv/esp32c3_devkitm/esp32c3_devkitm.dts | 17 ----------------- boards/riscv/stamp_c3/stamp_c3.dts | 17 ----------------- boards/riscv/xiao_esp32c3/xiao_esp32c3.dts | 17 ----------------- boards/xtensa/esp32/esp32.dts | 18 ------------------ boards/xtensa/esp32s2_saola/esp32s2_saola.dts | 17 ----------------- dts/riscv/espressif/esp32c3.dtsi | 17 +++++++++++++++++ dts/xtensa/espressif/esp32.dtsi | 18 ++++++++++++++++++ dts/xtensa/espressif/esp32s2.dtsi | 17 +++++++++++++++++ 8 files changed, 52 insertions(+), 86 deletions(-) diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index ba761ec33d76..1e4a534df2ae 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -26,22 +26,6 @@ watchdog0 = &wdt0; }; - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; - - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <660>; - exit-latency-us = <105>; - }; - }; - gpio_keys { compatible = "gpio-keys"; user_button1: button_1 { @@ -53,7 +37,6 @@ &cpu0 { clock-frequency = ; - cpu-power-states = <&deep_sleep &light_sleep>; }; &uart0 { diff --git a/boards/riscv/stamp_c3/stamp_c3.dts b/boards/riscv/stamp_c3/stamp_c3.dts index f9f03449f9aa..25bc93992e74 100644 --- a/boards/riscv/stamp_c3/stamp_c3.dts +++ b/boards/riscv/stamp_c3/stamp_c3.dts @@ -26,22 +26,6 @@ watchdog0 = &wdt0; }; - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; - - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <660>; - exit-latency-us = <105>; - }; - }; - gpio_keys { compatible = "gpio-keys"; button0: button0 { @@ -53,7 +37,6 @@ &cpu0 { clock-frequency = ; - cpu-power-states = <&deep_sleep &light_sleep>; }; &uart0 { diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts index 6c15f63ef10b..31d88a0d3aac 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts @@ -26,27 +26,10 @@ i2c-0 = &i2c0; watchdog0 = &wdt0; }; - - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; - - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <660>; - exit-latency-us = <105>; - }; - }; }; &cpu0 { clock-frequency = ; - cpu-power-states = <&deep_sleep &light_sleep>; }; &uart0 { diff --git a/boards/xtensa/esp32/esp32.dts b/boards/xtensa/esp32/esp32.dts index 2295d4ed4349..3d61902581a2 100644 --- a/boards/xtensa/esp32/esp32.dts +++ b/boards/xtensa/esp32/esp32.dts @@ -33,28 +33,10 @@ zephyr,shell-uart = &uart0; zephyr,flash = &flash0; }; - - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; - - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2000>; - exit-latency-us = <212>; - }; - }; - }; &cpu0 { clock-frequency = ; - cpu-power-states = <&light_sleep &deep_sleep>; }; &cpu1 { diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 4195dac59904..4e34faf09a0d 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -26,22 +26,6 @@ zephyr,flash = &flash0; }; - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; - - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2000>; - exit-latency-us = <212>; - }; - }; - gpio_keys { compatible = "gpio-keys"; user_button: user_button { @@ -53,7 +37,6 @@ &cpu0 { clock-frequency = ; - cpu-power-states = <&deep_sleep &light_sleep>; }; &uart0 { diff --git a/dts/riscv/espressif/esp32c3.dtsi b/dts/riscv/espressif/esp32c3.dtsi index 108ac074c13b..8b2e584987ed 100644 --- a/dts/riscv/espressif/esp32c3.dtsi +++ b/dts/riscv/espressif/esp32c3.dtsi @@ -33,6 +33,23 @@ device_type = "cpu"; compatible = "espressif,riscv"; reg = <0>; + cpu-power-states = <&light_sleep &deep_sleep>; + }; + }; + + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; + + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <660>; + exit-latency-us = <105>; }; }; diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32.dtsi index fafd33686899..fe86379081fa 100644 --- a/dts/xtensa/espressif/esp32.dtsi +++ b/dts/xtensa/espressif/esp32.dtsi @@ -28,6 +28,7 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + cpu-power-states = <&light_sleep &deep_sleep>; }; cpu1: cpu@1 { @@ -38,6 +39,23 @@ }; + + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; + + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2000>; + exit-latency-us = <212>; + }; + }; + wifi: wifi { compatible = "espressif,esp32-wifi"; status = "disabled"; diff --git a/dts/xtensa/espressif/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2.dtsi index 75a2ed2bf048..a335abb39247 100644 --- a/dts/xtensa/espressif/esp32s2.dtsi +++ b/dts/xtensa/espressif/esp32s2.dtsi @@ -34,6 +34,23 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx7"; reg = <0>; + cpu-power-states = <&light_sleep &deep_sleep>; + }; + }; + + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; + + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2000>; + exit-latency-us = <212>; }; }; From 262aeed339cae42599488c59a08577ddc81f7e97 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:15:56 +0200 Subject: [PATCH 1722/2042] dts: arm: st: move power-states to soc dts files CPU idle states are not board specific. This patch moves STM32 idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- boards/arm/b_l072z_lrwan1/b_l072z_lrwan1.dts | 11 -------- .../lora_e5_dev_board/lora_e5_dev_board.dts | 25 ------------------- boards/arm/nucleo_l073rz/nucleo_l073rz.dts | 13 ---------- boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts | 19 -------------- dts/arm/st/l0/stm32l0.dtsi | 10 ++++++++ dts/arm/st/wba/stm32wba.dtsi | 16 ++++++++++++ dts/arm/st/wl/stm32wl.dtsi | 1 + 7 files changed, 27 insertions(+), 68 deletions(-) diff --git a/boards/arm/b_l072z_lrwan1/b_l072z_lrwan1.dts b/boards/arm/b_l072z_lrwan1/b_l072z_lrwan1.dts index 2ca0cd962587..5c400c257912 100644 --- a/boards/arm/b_l072z_lrwan1/b_l072z_lrwan1.dts +++ b/boards/arm/b_l072z_lrwan1/b_l072z_lrwan1.dts @@ -58,17 +58,6 @@ lora0 = &lora; }; - power-states { - stop: stop { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <100>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&stop>; }; &clk_lse { 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 c6d30c98a03a..2a20b6b456fc 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 @@ -74,31 +74,6 @@ regulator-boot-on; status = "okay"; }; - - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <900>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; }; &lptim1 { diff --git a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts index c35da231f808..a72aad9ff93d 100644 --- a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts @@ -37,15 +37,6 @@ }; }; - power-states { - stop: state { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <2000>; - exit-latency-us = <750>; - }; - }; - pwmleds: pwmleds { compatible = "pwm-leds"; /* NOTE: disabled by default, PWM2 conflicts with SPI1 */ @@ -67,10 +58,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop>; -}; - &clk_hse { hse-bypass; clock-frequency = ; /* STLink 8MHz clock */ diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index 5fda629625ff..fc5a75a61966 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -23,21 +23,6 @@ zephyr,flash = &flash0; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - }; - leds { compatible = "gpio-leds"; blue_led_1: led_1 { @@ -87,10 +72,6 @@ apb7-prescaler = <1>; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1>; -}; - &usart1 { pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index 4a4e46058a4b..25c1158ba1d6 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -30,6 +30,16 @@ device_type = "cpu"; compatible = "arm,cortex-m0+"; reg = <0>; + cpu-power-states = <&stop>; + }; + }; + + power-states { + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <2000>; + exit-latency-us = <750>; }; }; diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index ed3dc80911ca..03b75e322f47 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -30,6 +30,7 @@ device_type = "cpu"; compatible = "arm,cortex-m33"; reg = <0>; + cpu-power-states = <&stop0 &stop1>; #address-cells = <1>; #size-cells = <1>; @@ -41,6 +42,21 @@ }; }; + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + }; + sram0: memory@20000000 { compatible = "mmio-sram"; }; diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 718d939444f5..5b01255446f2 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -31,6 +31,7 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop0 &stop1 &stop2>; }; }; From 96a121b5eee0c98e6c15e323ad8153e3d4bdf539 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:20:17 +0200 Subject: [PATCH 1723/2042] dts: arm: ti: move power-states to soc dts files CPU idle states are not board specific. This patch moves TI idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- boards/arm/beagle_bcf/beagleconnect_freedom.dts | 16 ---------------- .../arm/cc1352p1_launchxl/cc1352p1_launchxl.dts | 16 ---------------- .../arm/cc1352r1_launchxl/cc1352r1_launchxl.dts | 16 ---------------- .../arm/cc1352r_sensortag/cc1352r_sensortag.dts | 16 ---------------- .../arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts | 16 ---------------- dts/arm/ti/cc13xx_cc26xx.dtsi | 16 ++++++++++++++++ 6 files changed, 16 insertions(+), 80 deletions(-) diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index c41d642ebfe7..c0a6d843813d 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -75,21 +75,6 @@ reg = <0x41>; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; - }; - }; }; &flash0 { @@ -114,7 +99,6 @@ &cpu0 { clock-frequency = <48000000>; - cpu-power-states = <&idle &standby>; }; &trng { diff --git a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts index 50ab7b4fdc4f..a265a1a012cf 100644 --- a/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts +++ b/boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts @@ -79,26 +79,10 @@ label = "Push button 2"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; - }; - }; }; &cpu0 { clock-frequency = <48000000>; - cpu-power-states = <&idle &standby>; }; &trng { diff --git a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts index 4f6cc4864b87..ec94714217e4 100644 --- a/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts +++ b/boards/arm/cc1352r1_launchxl/cc1352r1_launchxl.dts @@ -55,26 +55,10 @@ label = "Push button 2"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; - }; - }; }; &cpu0 { clock-frequency = <48000000>; - cpu-power-states = <&idle &standby>; }; &trng { diff --git a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts index 0d50b59e778e..b4d3b54e8eb2 100644 --- a/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts +++ b/boards/arm/cc1352r_sensortag/cc1352r_sensortag.dts @@ -65,26 +65,10 @@ label = "Push button 2"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; - }; - }; }; &cpu0 { clock-frequency = <48000000>; - cpu-power-states = <&idle &standby>; }; &trng { diff --git a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts index 271e63b920bc..648fb96c1c43 100644 --- a/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts +++ b/boards/arm/cc26x2r1_launchxl/cc26x2r1_launchxl.dts @@ -54,26 +54,10 @@ label = "Push button 2"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; - }; - }; }; &cpu0 { clock-frequency = <48000000>; - cpu-power-states = <&idle &standby>; }; &trng { diff --git a/dts/arm/ti/cc13xx_cc26xx.dtsi b/dts/arm/ti/cc13xx_cc26xx.dtsi index 57c07c2b121d..a536d7b65227 100644 --- a/dts/arm/ti/cc13xx_cc26xx.dtsi +++ b/dts/arm/ti/cc13xx_cc26xx.dtsi @@ -23,6 +23,22 @@ device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; + cpu-power-states = <&idle &standby>; + }; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + }; + + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <5000>; + exit-latency-us = <240>; }; }; From 7e8f9c75959dfe9a584788f3c65af606a0d6fa39 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:23:18 +0200 Subject: [PATCH 1724/2042] dts: arm: microchip: move power-states to soc dts files CPU idle states are not board specific. This patch moves Microchip MEC idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- .../mec1501modular_assy6885.dts | 18 ------------------ .../mec15xxevb_assy6853.dts | 18 ------------------ .../mec172xevb_assy6906.dts | 15 --------------- .../mec172xmodular_assy6930.dts | 15 --------------- dts/arm/microchip/mec1501hsz.dtsi | 15 +++++++++++++++ dts/arm/microchip/mec172xnsz.dtsi | 15 +++++++++++++++ 6 files changed, 30 insertions(+), 66 deletions(-) diff --git a/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts b/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts index 7f696fc6e3ce..852602386a9b 100644 --- a/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts +++ b/boards/arm/mec1501modular_assy6885/mec1501modular_assy6885.dts @@ -29,24 +29,6 @@ kscan0 = &kscan0; watchdog0 = &wdog; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; - - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&idle &suspend_to_ram>; }; &pcr { diff --git a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts index d15c278604ae..a8bb074a8ff2 100644 --- a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts +++ b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts @@ -57,24 +57,6 @@ label = "LED 4"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; - - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&idle &suspend_to_ram>; }; &pcr { diff --git a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts index d01176bf9a6d..2ecd3d413f26 100644 --- a/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/arm/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -47,26 +47,11 @@ label = "LED 5"; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; - - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; - }; - }; }; &cpu0 { clock-frequency = <96000000>; status = "okay"; - cpu-power-states = <&idle &suspend_to_ram>; }; /* Initialize ECIA. Does not initialize child devices */ diff --git a/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts b/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts index f44c554c88c9..631f7ca15b1d 100644 --- a/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts +++ b/boards/arm/mec172xmodular_assy6930/mec172xmodular_assy6930.dts @@ -43,26 +43,11 @@ gpios = ; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; - - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; - }; - }; }; &cpu0 { clock-frequency = <96000000>; status = "okay"; - cpu-power-states = <&idle &suspend_to_ram>; }; /* Initialize ECIA. Does not initialize child devices */ diff --git a/dts/arm/microchip/mec1501hsz.dtsi b/dts/arm/microchip/mec1501hsz.dtsi index dade0c7ca181..1c5896c5ecb2 100644 --- a/dts/arm/microchip/mec1501hsz.dtsi +++ b/dts/arm/microchip/mec1501hsz.dtsi @@ -20,6 +20,21 @@ device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; }; }; diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 75a059e046c9..81b39280afad 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -26,6 +26,21 @@ device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; }; }; From 6552250cb6151de4787ccab4a1545ffaed990f22 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:29:42 +0200 Subject: [PATCH 1725/2042] dts: arm: nxp: move power-states to soc dts files CPU idle states are not board specific. This patch moves NXP idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts | 19 ---------- .../arm/mimxrt595_evk/mimxrt595_evk_cm33.dts | 35 ------------------- .../arm/mimxrt685_evk/mimxrt685_evk_cm33.dts | 17 --------- dts/arm/nxp/nxp_rt10xx.dtsi | 16 +++++++++ dts/arm/nxp/nxp_rt5xx_common.dtsi | 32 +++++++++++++++++ dts/arm/nxp/nxp_rt6xx_common.dtsi | 14 ++++++++ 6 files changed, 62 insertions(+), 71 deletions(-) diff --git a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts index 4627892357b4..92e7644403c7 100644 --- a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts +++ b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts @@ -104,25 +104,6 @@ }; }; }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - exit-latency-us = <4000>; - min-residency-us = <5000>; - }; - suspend: suspend { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - exit-latency-us = <5000>; - min-residency-us = <10000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&idle &suspend>; }; arduino_i2c: &lpi2c1 {}; diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index c82a526a6546..fc43e988ef01 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -118,37 +118,6 @@ <34 0 &gpio0 12 0>; /* Pin 34, BL_PWM */ }; - power-states { - /* This is the setting Sleep Mode */ - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <0>; - exit-latency-us = <0>; - }; - /* This is the setting for Deep-sleep Mode */ - suspend: suspend { - compatible = "nxp,pdcfg-power", "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <500>; - exit-latency-us = <120>; - /* - * These values are written to the PDSLEEPCFG registers to keep certain - * blocks such as LPOSC, SRAM's, FlexSPI0 SRAM powered on during deep - * sleep mode. - */ - deep-sleep-config = <0xC800>, - <0x80000004>, - <0xFFFFFFFF>, - <0>; - }; - /* - * Deep power-down mode is supported in this SoC through 'PM_STATE_SOFT_OFF' state. - * There is no entry for this in device tree, user can call pm_state_force to enter - * this state. - */ - }; - en_mipi_display: enable-mipi-display { compatible = "regulator-fixed"; regulator-name = "en_mipi_display"; @@ -157,10 +126,6 @@ }; }; -&cpu0 { - cpu-power-states = <&idle &suspend>; -}; - /* * RT595 EVK board uses OS timer as the kernel timer * In case we need to switch to SYSTICK timer, then diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts index 9d9c26875c1c..ecca26796fc2 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts @@ -118,23 +118,6 @@ <20 0 &gpio0 17 0>, /* D14 */ <21 0 &gpio0 18 0>; /* D15 */ }; - - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <10>; - }; - suspend: suspend { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&idle &suspend>; }; /* diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index a24eb0ce014b..9a4fe00ed4be 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -26,6 +26,7 @@ compatible = "arm,cortex-m7"; d-cache-line-size = <32>; reg = <0>; + cpu-power-states = <&idle &suspend>; #address-cells = <1>; #size-cells = <1>; @@ -43,6 +44,21 @@ }; }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + exit-latency-us = <4000>; + min-residency-us = <5000>; + }; + suspend: suspend { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + exit-latency-us = <5000>; + min-residency-us = <10000>; + }; + }; + sysclk: system-clock { compatible = "fixed-clock"; clock-frequency = <600000000>; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 034c45a904d5..87d20a445dfe 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -27,6 +27,7 @@ reg = <0>; #address-cells = <1>; #size-cells = <1>; + cpu-power-states = <&idle &suspend>; mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; @@ -35,6 +36,37 @@ }; }; }; + + power-states { + /* This is the setting Sleep Mode */ + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <0>; + exit-latency-us = <0>; + }; + /* This is the setting for Deep-sleep Mode */ + suspend: suspend { + compatible = "nxp,pdcfg-power", "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <500>; + exit-latency-us = <120>; + /* + * These values are written to the PDSLEEPCFG registers to keep certain + * blocks such as LPOSC, SRAM's, FlexSPI0 SRAM powered on during deep + * sleep mode. + */ + deep-sleep-config = <0xC800>, + <0x80000004>, + <0xFFFFFFFF>, + <0>; + }; + /* + * Deep power-down mode is supported in this SoC through 'PM_STATE_SOFT_OFF' state. + * There is no entry for this in device tree, user can call pm_state_force to enter + * this state. + */ + }; }; &sram { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 62fdd0ca705d..20e7c805cbb9 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -23,6 +23,7 @@ cpu0: cpu@0 { compatible = "arm,cortex-m33f"; reg = <0>; + cpu-power-states = <&idle &suspend>; #address-cells = <1>; #size-cells = <1>; @@ -33,6 +34,19 @@ }; }; }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <10>; + }; + suspend: suspend { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + }; + }; }; &sram { From 90ed12d3eb7baa2164ecf07f6d66aa42185dfdf1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 12:32:08 +0200 Subject: [PATCH 1726/2042] dts: arm: nuvoton: move power-states to soc dts files CPU idle states are not board specific. This patch moves Nuvoton idle states to the core SoC dts files. Board can always tweak some state parameters (if needed), but the definition belongs to core SoC dts files, same as e.g. peripherals. Signed-off-by: Gerard Marull-Paretas --- boards/arm/npcx7m6fb_evb/npcx7m6fb_evb.dts | 20 -------------------- boards/arm/npcx9m6f_evb/npcx9m6f_evb.dts | 20 -------------------- dts/arm/nuvoton/npcx/npcx.dtsi | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 40 deletions(-) diff --git a/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb.dts b/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb.dts index 7fab1d9697f8..a1c6d72403be 100644 --- a/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb.dts +++ b/boards/arm/npcx7m6fb_evb/npcx7m6fb_evb.dts @@ -41,26 +41,6 @@ label = "User D7 green"; }; }; - - power-states { - suspend_to_idle0: suspend-to-idle0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <0>; - min-residency-us = <1000>; - }; - - suspend_to_idle1: suspend-to-idle1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <201000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&suspend_to_idle0 &suspend_to_idle1>; }; /* Overwrite default device properties with overlays in board dt file here. */ diff --git a/boards/arm/npcx9m6f_evb/npcx9m6f_evb.dts b/boards/arm/npcx9m6f_evb/npcx9m6f_evb.dts index 2129e70afde3..841883cc38c2 100644 --- a/boards/arm/npcx9m6f_evb/npcx9m6f_evb.dts +++ b/boards/arm/npcx9m6f_evb/npcx9m6f_evb.dts @@ -52,26 +52,6 @@ label = "User D8 red"; }; }; - - power-states { - suspend_to_idle0: suspend-to-idle0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <0>; - min-residency-us = <1000>; - }; - - suspend_to_idle1: suspend-to-idle1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <201000>; - }; - }; -}; - -&cpu0 { - cpu-power-states = <&suspend_to_idle0 &suspend_to_idle1>; }; /* Overwrite default device properties with overlays in board dt file here. */ diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index 3994920af39a..874f88a58689 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -26,6 +26,23 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&suspend_to_idle0 &suspend_to_idle1>; + }; + }; + + power-states { + suspend_to_idle0: suspend-to-idle0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <0>; + min-residency-us = <1000>; + }; + + suspend_to_idle1: suspend-to-idle1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <201000>; }; }; From e4c43e4cc98cba02470e654db9fd29065e5c4ff1 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 11:48:55 +0200 Subject: [PATCH 1727/2042] pm: power-states node needs to be a child of cpus This again aligns with Linux. Signed-off-by: Gerard Marull-Paretas --- dts/arm/microchip/mec1501hsz.dtsi | 22 ++-- dts/arm/microchip/mec172xnsz.dtsi | 22 ++-- dts/arm/nuvoton/npcx/npcx.dtsi | 26 ++--- dts/arm/nxp/nxp_ke1xf.dtsi | 40 +++---- dts/arm/nxp/nxp_rt10xx.dtsi | 26 ++--- dts/arm/nxp/nxp_rt11xx.dtsi | 54 +++++----- dts/arm/nxp/nxp_rt5xx_common.dtsi | 56 +++++----- dts/arm/nxp/nxp_rt6xx_common.dtsi | 22 ++-- dts/arm/silabs/efr32bg2x.dtsi | 102 +++++++++--------- dts/arm/silabs/efr32mg24.dtsi | 14 +-- dts/arm/st/g0/stm32g0.dtsi | 30 +++--- dts/arm/st/g4/stm32g4.dtsi | 30 +++--- dts/arm/st/l0/stm32l0.dtsi | 14 +-- dts/arm/st/l4/stm32l4.dtsi | 42 ++++---- dts/arm/st/l5/stm32l5.dtsi | 42 ++++---- dts/arm/st/u5/stm32u5.dtsi | 42 ++++---- dts/arm/st/wb/stm32wb.dtsi | 42 ++++---- dts/arm/st/wba/stm32wba.dtsi | 26 ++--- dts/arm/st/wl/stm32wl.dtsi | 42 ++++---- dts/arm/ti/cc13xx_cc26xx.dtsi | 24 ++--- dts/riscv/espressif/esp32c3.dtsi | 26 ++--- dts/riscv/ite/it8xxx2.dtsi | 12 +-- dts/xtensa/espressif/esp32.dtsi | 28 +++-- dts/xtensa/espressif/esp32s2.dtsi | 26 ++--- dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi | 32 +++--- dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi | 33 +++--- dts/xtensa/intel/intel_adsp_cavs25.dtsi | 21 ++-- dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi | 21 ++-- include/zephyr/pm/state.h | 55 +++++----- .../boards/native_posix.overlay | 42 ++++---- 30 files changed, 509 insertions(+), 505 deletions(-) diff --git a/dts/arm/microchip/mec1501hsz.dtsi b/dts/arm/microchip/mec1501hsz.dtsi index 1c5896c5ecb2..9648c9bd7822 100644 --- a/dts/arm/microchip/mec1501hsz.dtsi +++ b/dts/arm/microchip/mec1501hsz.dtsi @@ -22,19 +22,19 @@ reg = <0>; cpu-power-states = <&idle &suspend_to_ram>; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; + }; }; }; diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 81b39280afad..8a95e8ec8004 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -28,19 +28,19 @@ reg = <0>; cpu-power-states = <&idle &suspend_to_ram>; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000000>; - }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + }; - suspend_to_ram: suspend_to_ram { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <2000000>; + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <2000000>; + }; }; }; diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index 874f88a58689..f079b8c2b3a4 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -28,21 +28,21 @@ reg = <0>; cpu-power-states = <&suspend_to_idle0 &suspend_to_idle1>; }; - }; - power-states { - suspend_to_idle0: suspend-to-idle0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <0>; - min-residency-us = <1000>; - }; + power-states { + suspend_to_idle0: suspend-to-idle0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <0>; + min-residency-us = <1000>; + }; - suspend_to_idle1: suspend-to-idle1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <201000>; + suspend_to_idle1: suspend-to-idle1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <201000>; + }; }; }; diff --git a/dts/arm/nxp/nxp_ke1xf.dtsi b/dts/arm/nxp/nxp_ke1xf.dtsi index 6a3f10ef2e92..9326b20c9cf7 100644 --- a/dts/arm/nxp/nxp_ke1xf.dtsi +++ b/dts/arm/nxp/nxp_ke1xf.dtsi @@ -29,30 +29,30 @@ compatible = "arm,cortex-m4f"; reg = <0>; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + }; - stop: stop { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <0>; - }; + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <0>; + }; - pstop1: pstop1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - }; + pstop1: pstop1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + }; - pstop2: pstop2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; + pstop2: pstop2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + }; }; }; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 9a4fe00ed4be..46b6aeac2b2d 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -42,20 +42,20 @@ swo-ref-frequency = <132000000>; }; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - exit-latency-us = <4000>; - min-residency-us = <5000>; - }; - suspend: suspend { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - exit-latency-us = <5000>; - min-residency-us = <10000>; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + exit-latency-us = <4000>; + min-residency-us = <5000>; + }; + suspend: suspend { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + exit-latency-us = <5000>; + min-residency-us = <10000>; + }; }; }; diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index 6f907fdb6402..eb423986fb5f 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -52,34 +52,34 @@ arm,num-mpu-regions = <16>; }; }; - }; - power-states { - /* - * Power states are managed with set points (see page 30-35 of RT1170 - * datasheet). These set points correspond to various power - * savings, and associated transition (residency) times. - * - * Set points 1 and 10 were chosen as sane defaults to offer - * limited power savings and quick transitions when entering idle for - * short periods, and better power savings with longer transition - * times for long idle periods - */ - idle: set_point_1_wait { - /* idle corresponds to set point 1 (wait) for RT1170 */ - compatible = "zephyr,power-state"; - power-state-name="runtime-idle"; - substate-id = ; - min-residency-us = <100>; - }; - - suspend: set_point_10_suspend { - /* suspend corresponds to set point 10 for RT1170 */ - compatible = "zephyr,power-state"; - power-state-name="suspend-to-idle"; - substate-id = ; - min-residency-us = <5000>; - exit-latency-us = <500>; + power-states { + /* + * Power states are managed with set points (see page 30-35 of RT1170 + * datasheet). These set points correspond to various power + * savings, and associated transition (residency) times. + * + * Set points 1 and 10 were chosen as sane defaults to offer + * limited power savings and quick transitions when entering idle for + * short periods, and better power savings with longer transition + * times for long idle periods + */ + idle: set_point_1_wait { + /* idle corresponds to set point 1 (wait) for RT1170 */ + compatible = "zephyr,power-state"; + power-state-name="runtime-idle"; + substate-id = ; + min-residency-us = <100>; + }; + + suspend: set_point_10_suspend { + /* suspend corresponds to set point 10 for RT1170 */ + compatible = "zephyr,power-state"; + power-state-name="suspend-to-idle"; + substate-id = ; + min-residency-us = <5000>; + exit-latency-us = <500>; + }; }; }; diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 87d20a445dfe..6040ba3f47a3 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -35,37 +35,39 @@ arm,num-mpu-regions = <8>; }; }; - }; - power-states { - /* This is the setting Sleep Mode */ - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <0>; - exit-latency-us = <0>; - }; - /* This is the setting for Deep-sleep Mode */ - suspend: suspend { - compatible = "nxp,pdcfg-power", "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <500>; - exit-latency-us = <120>; + power-states { + /* This is the setting Sleep Mode */ + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <0>; + exit-latency-us = <0>; + }; + /* This is the setting for Deep-sleep Mode */ + suspend: suspend { + compatible = "nxp,pdcfg-power", "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <500>; + exit-latency-us = <120>; + /* + * These values are written to the PDSLEEPCFG + * registers to keep certain blocks such as + * LPOSC, SRAM's, FlexSPI0 SRAM powered on + * during deep sleep mode. + */ + deep-sleep-config = <0xC800>, + <0x80000004>, + <0xFFFFFFFF>, + <0>; + }; /* - * These values are written to the PDSLEEPCFG registers to keep certain - * blocks such as LPOSC, SRAM's, FlexSPI0 SRAM powered on during deep - * sleep mode. + * Deep power-down mode is supported in this SoC through + * 'PM_STATE_SOFT_OFF' state. There is no entry for this + * in device tree, user can call pm_state_force to enter + * this state. */ - deep-sleep-config = <0xC800>, - <0x80000004>, - <0xFFFFFFFF>, - <0>; }; - /* - * Deep power-down mode is supported in this SoC through 'PM_STATE_SOFT_OFF' state. - * There is no entry for this in device tree, user can call pm_state_force to enter - * this state. - */ }; }; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 20e7c805cbb9..3629772d746d 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -33,18 +33,18 @@ arm,num-mpu-regions = <8>; }; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <10>; - }; - suspend: suspend { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <10>; + }; + suspend: suspend { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + }; }; }; }; diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index bb6a0d847af1..deee10ccdde8 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -17,57 +17,6 @@ zephyr,entropy = &trng; }; - power-states { - /* - * EM1 is a basic "CPU WFI idle", all high-freq clocks remain - * enabled. - */ - pstate_em1: em1 { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <4>; - /* HFXO remains active */ - exit-latency-us = <2>; - }; - - /* - * EM2 is a deepsleep with HF clocks disabled by HW, voltages - * scaled down, etc. - */ - pstate_em2: em2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <260>; - exit-latency-us = <250>; - }; - - /* - * EM3 seems to be exactly the same as EM2 except that - * LFXO & LFRCO should be disabled, so you must use ULFRCO - * as BURTC clock for the system to not lose track of time and - * wake up. - */ - pstate_em3: em3 { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <20000>; - exit-latency-us = <2000>; - }; - - /* - * EM4 does not preserve CPU or RAM state, so system runs - * through a cold boot upon wake up. BURTC can wake up the - * system from EM4 but that has to be manually configured - * by the application in BURTC registers. - */ - pstate_em4: em4 { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <100000>; - exit-latency-us = <80000>; - }; - }; - cpus { #address-cells = <1>; #size-cells = <0>; @@ -89,6 +38,57 @@ */ cpu-power-states = <&pstate_em1>; }; + + power-states { + /* + * EM1 is a basic "CPU WFI idle", all high-freq clocks remain + * enabled. + */ + pstate_em1: em1 { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <4>; + /* HFXO remains active */ + exit-latency-us = <2>; + }; + + /* + * EM2 is a deepsleep with HF clocks disabled by HW, voltages + * scaled down, etc. + */ + pstate_em2: em2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <260>; + exit-latency-us = <250>; + }; + + /* + * EM3 seems to be exactly the same as EM2 except that + * LFXO & LFRCO should be disabled, so you must use ULFRCO + * as BURTC clock for the system to not lose track of time and + * wake up. + */ + pstate_em3: em3 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <20000>; + exit-latency-us = <2000>; + }; + + /* + * EM4 does not preserve CPU or RAM state, so system runs + * through a cold boot upon wake up. BURTC can wake up the + * system from EM4 but that has to be manually configured + * by the application in BURTC registers. + */ + pstate_em4: em4 { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <100000>; + exit-latency-us = <80000>; + }; + }; }; sram0: memory@20000000 { diff --git a/dts/arm/silabs/efr32mg24.dtsi b/dts/arm/silabs/efr32mg24.dtsi index 39f5bc70a5ac..6e75c9b6bbd6 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -27,14 +27,14 @@ reg = <0>; cpu-power-states = <&state0>; }; - }; - power-states { - state0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <50000>; - exit-latency-us = <0>; + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <50000>; + exit-latency-us = <0>; + }; }; }; diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index 1e25aba2eb11..bfc61d8cfea6 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -34,6 +34,21 @@ compatible = "arm,cortex-m0+"; reg = <0>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <20>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <100>; + }; + }; }; sram0: memory@20000000 { @@ -77,21 +92,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <20>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <100>; - }; - }; - soc { flash: flash-controller@40022000 { compatible = "st,stm32-flash-controller", "st,stm32g0-flash-controller"; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index e3dccb86db8b..32d6c4d5f87a 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -33,6 +33,21 @@ compatible = "arm,cortex-m4f"; reg = <0>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <20>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <100>; + }; + }; }; sram0: memory@20000000 { @@ -82,21 +97,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <20>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <100>; - }; - }; - soc { /* * Both adc instances cannot be used in parallel right now. diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index 25c1158ba1d6..2a77be4c6363 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -32,14 +32,14 @@ reg = <0>; cpu-power-states = <&stop>; }; - }; - power-states { - stop: stop { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <2000>; - exit-latency-us = <750>; + power-states { + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <2000>; + exit-latency-us = <750>; + }; }; }; diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index d3e9caa475ed..1b6452119fe4 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -33,6 +33,27 @@ compatible = "arm,cortex-m4f"; reg = <0>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <500>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <700>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <1000>; + }; + }; }; sram0: memory@20000000 { @@ -82,27 +103,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <500>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <700>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <1000>; - }; - }; - soc { flash: flash-controller@40022000 { compatible = "st,stm32-flash-controller", "st,stm32l4-flash-controller"; diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index b8be5a6be4f7..28c7d87491be 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -42,6 +42,27 @@ arm,num-mpu-regions = <8>; }; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; sram0: memory@20000000 { @@ -98,27 +119,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <900>; - }; - }; - soc { flash: flash-controller@40022000 { compatible = "st,stm32-flash-controller", "st,stm32l5-flash-controller"; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 343bc8ed4e2d..91f5822673b9 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -43,6 +43,27 @@ arm,num-mpu-regions = <8>; }; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; sram0: memory@20000000 { @@ -118,27 +139,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <900>; - }; - }; - soc { flash: flash-controller@40022000 { compatible = "st,stm32-flash-controller", "st,stm32l5-flash-controller"; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index 67b8bc87f0f0..84f459dcf6f1 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -32,6 +32,27 @@ compatible = "arm,cortex-m4f"; reg = <0>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; sram0: memory@20000000 { @@ -115,27 +136,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <900>; - }; - }; - soc { flash: flash-controller@58004000 { compatible = "st,stm32-flash-controller", "st,stm32wb-flash-controller"; diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 03b75e322f47..ed4f4ac49a47 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -40,20 +40,20 @@ arm,num-mpu-regions = <8>; }; }; - }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; }; }; diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index 5b01255446f2..26da70106c10 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -33,6 +33,27 @@ reg = <0>; cpu-power-states = <&stop0 &stop1 &stop2>; }; + + power-states { + stop0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <1>; + min-residency-us = <100>; + }; + stop1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <2>; + min-residency-us = <500>; + }; + stop2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <3>; + min-residency-us = <900>; + }; + }; }; sram0: memory@20000000 { @@ -84,27 +105,6 @@ }; }; - power-states { - stop0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <1>; - min-residency-us = <100>; - }; - stop1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <2>; - min-residency-us = <500>; - }; - stop2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - substate-id = <3>; - min-residency-us = <900>; - }; - }; - soc { flash: flash-controller@58004000 { compatible = "st,stm32-flash-controller", "st,stm32l4-flash-controller"; diff --git a/dts/arm/ti/cc13xx_cc26xx.dtsi b/dts/arm/ti/cc13xx_cc26xx.dtsi index a536d7b65227..b57349eb8379 100644 --- a/dts/arm/ti/cc13xx_cc26xx.dtsi +++ b/dts/arm/ti/cc13xx_cc26xx.dtsi @@ -25,20 +25,20 @@ reg = <0>; cpu-power-states = <&idle &standby>; }; - }; - power-states { - idle: idle { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <1000>; - }; + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + }; - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <5000>; - exit-latency-us = <240>; + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <5000>; + exit-latency-us = <240>; + }; }; }; diff --git a/dts/riscv/espressif/esp32c3.dtsi b/dts/riscv/espressif/esp32c3.dtsi index 8b2e584987ed..9d751c1fe7e1 100644 --- a/dts/riscv/espressif/esp32c3.dtsi +++ b/dts/riscv/espressif/esp32c3.dtsi @@ -35,21 +35,21 @@ reg = <0>; cpu-power-states = <&light_sleep &deep_sleep>; }; - }; - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <660>; - exit-latency-us = <105>; + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <660>; + exit-latency-us = <105>; + }; }; }; diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 3fbf0c062520..c0e5933346dc 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -33,13 +33,13 @@ reg = <0>; cpu-power-states = <&standby>; }; - }; - power-states { - standby: standby { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <500>; + power-states { + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <500>; + }; }; }; diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32.dtsi index fe86379081fa..f8acfbdfb9ca 100644 --- a/dts/xtensa/espressif/esp32.dtsi +++ b/dts/xtensa/espressif/esp32.dtsi @@ -37,22 +37,20 @@ reg = <1>; }; - }; - - - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2000>; - exit-latency-us = <212>; + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2000>; + exit-latency-us = <212>; + }; }; }; diff --git a/dts/xtensa/espressif/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2.dtsi index a335abb39247..898701457d4d 100644 --- a/dts/xtensa/espressif/esp32s2.dtsi +++ b/dts/xtensa/espressif/esp32s2.dtsi @@ -36,21 +36,21 @@ reg = <0>; cpu-power-states = <&light_sleep &deep_sleep>; }; - }; - power-states { - light_sleep: light_sleep { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - min-residency-us = <200>; - exit-latency-us = <60>; - }; + power-states { + light_sleep: light_sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <200>; + exit-latency-us = <60>; + }; - deep_sleep: deep_sleep { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2000>; - exit-latency-us = <212>; + deep_sleep: deep_sleep { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2000>; + exit-latency-us = <212>; + }; }; }; diff --git a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi index a786f493296b..1a669d5eb446 100644 --- a/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace15_mtpm.dtsi @@ -34,23 +34,23 @@ reg = <2>; cpu-power-states = <&d0i3 &d3>; }; - }; - power-states { - d0i3: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <200>; - exit-latency-us = <100>; - }; - /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. - * The procedure is triggered by IPC from the HOST (SET_DX). - */ - d3: off { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2147483647>; - exit-latency-us = <0>; + power-states { + d0i3: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <200>; + exit-latency-us = <100>; + }; + /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. + * The procedure is triggered by IPC from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; + }; }; }; diff --git a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi index b5f57ac51830..903d72e0d56c 100644 --- a/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi +++ b/dts/xtensa/intel/intel_adsp_ace20_lnl.dtsi @@ -49,23 +49,22 @@ cpu-power-states = <&d0i3 &d3>; }; - }; - - power-states { - d0i3: idle { - compatible = "zephyr,power-state"; - power-state-name = "runtime-idle"; - min-residency-us = <200>; - exit-latency-us = <100>; - }; - /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. - * The procedure is triggered by IPC from the HOST (SET_DX). - */ - d3: off { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2147483647>; - exit-latency-us = <0>; + power-states { + d0i3: idle { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <200>; + exit-latency-us = <100>; + }; + /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. + * The procedure is triggered by IPC from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; + }; }; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs25.dtsi b/dts/xtensa/intel/intel_adsp_cavs25.dtsi index 02142c30b63a..1039a00b094a 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25.dtsi @@ -41,17 +41,18 @@ reg = <3>; cpu-power-states = <&d3>; }; - }; - power-states { - /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. - * The procedure is triggered by IPC from the HOST (SET_DX). - */ - d3: off { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2147483647>; - exit-latency-us = <0>; + power-states { + /* PM_STATE_SOFT_OFF can be entered only by calling + * pm_state_force. The procedure is triggered by IPC + * from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; + }; }; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi index 6cdd0e4c887c..a03605df5152 100644 --- a/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs25_tgph.dtsi @@ -27,17 +27,18 @@ reg = <1>; cpu-power-states = <&d3>; }; - }; - power-states { - /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force. - * The procedure is triggered by IPC from the HOST (SET_DX). - */ - d3: off { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <2147483647>; - exit-latency-us = <0>; + power-states { + /* PM_STATE_SOFT_OFF can be entered only by calling + * pm_state_force. The procedure is triggered by IPC + * from the HOST (SET_DX). + */ + d3: off { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <2147483647>; + exit-latency-us = <0>; + }; }; }; diff --git a/include/zephyr/pm/state.h b/include/zephyr/pm/state.h index 1f5fd217ed5c..c7fe6f4b4acd 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -227,24 +227,24 @@ struct pm_state_info { * ... * cpu-power-states = <&state0 &state1>; * }; - * }; * - * ... - * power-states { - * state0: state0 { - * compatible = "zephyr,power-state"; - * power-state-name = "suspend-to-idle"; - * min-residency-us = <10000>; - * exit-latency-us = <100>; - * }; + * power-states { + * state0: state0 { + * compatible = "zephyr,power-state"; + * power-state-name = "suspend-to-idle"; + * min-residency-us = <10000>; + * exit-latency-us = <100>; + * }; * - * state1: state1 { - * compatible = "zephyr,power-state"; - * power-state-name = "suspend-to-ram"; - * min-residency-us = <50000>; - * exit-latency-us = <500>; + * state1: state1 { + * compatible = "zephyr,power-state"; + * power-state-name = "suspend-to-ram"; + * min-residency-us = <50000>; + * exit-latency-us = <500>; + * }; * }; * }; + * @endcode * * Example usage: @@ -276,22 +276,21 @@ struct pm_state_info { * ... * cpu-power-states = <&state0 &state1>; * }; - * }; * - * ... - * power-states { - * state0: state0 { - * compatible = "zephyr,power-state"; - * power-state-name = "suspend-to-idle"; - * min-residency-us = <10000>; - * exit-latency-us = <100>; - * }; + * power-states { + * state0: state0 { + * compatible = "zephyr,power-state"; + * power-state-name = "suspend-to-idle"; + * min-residency-us = <10000>; + * exit-latency-us = <100>; + * }; * - * state1: state1 { - * compatible = "zephyr,power-state"; - * power-state-name = "suspend-to-ram"; - * min-residency-us = <50000>; - * exit-latency-us = <500>; + * state1: state1 { + * compatible = "zephyr,power-state"; + * power-state-name = "suspend-to-ram"; + * min-residency-us = <50000>; + * exit-latency-us = <500>; + * }; * }; * }; * @endcode diff --git a/tests/subsys/pm/power_states_api/boards/native_posix.overlay b/tests/subsys/pm/power_states_api/boards/native_posix.overlay index 247ca393448c..79fafb582b0c 100644 --- a/tests/subsys/pm/power_states_api/boards/native_posix.overlay +++ b/tests/subsys/pm/power_states_api/boards/native_posix.overlay @@ -5,26 +5,30 @@ */ / { - state0: state0 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-idle"; - min-residency-us = <10000>; - exit-latency-us = <100>; - }; + cpus { + cpu@0 { + cpu-power-states = <&state0 &state1 &state2>; + }; - state1: state1 { - compatible = "zephyr,power-state"; - power-state-name = "suspend-to-ram"; - min-residency-us = <50000>; - exit-latency-us = <500>; - }; + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <10000>; + exit-latency-us = <100>; + }; - state2: state2 { - compatible = "zephyr,power-state"; - power-state-name = "standby"; - }; -}; + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <50000>; + exit-latency-us = <500>; + }; -&cpu0 { - cpu-power-states = <&state0 &state1 &state2>; + state2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + }; + }; + }; }; From 161d83239ad0a25d737eeab0e76fdfb66ef8093d Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 19 Jul 2023 15:03:39 +0200 Subject: [PATCH 1728/2042] dts: bindings: power: nxp,pdcfg-power: fix YAML formatting Adjust to the expected YAML formatting (2sp). Issue reported by CI compliance checks. Signed-off-by: Gerard Marull-Paretas --- dts/bindings/power/nxp,pdcfg-power.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dts/bindings/power/nxp,pdcfg-power.yaml b/dts/bindings/power/nxp,pdcfg-power.yaml index f2dcf00ceb55..da0f9bccd411 100644 --- a/dts/bindings/power/nxp,pdcfg-power.yaml +++ b/dts/bindings/power/nxp,pdcfg-power.yaml @@ -8,9 +8,10 @@ compatible: "nxp,pdcfg-power" include: zephyr,power-state.yaml properties: - deep-sleep-config: - type: array - description: | - An array of values written to the PDSLEEPCFG registers that controls the power to various blocks - while the CPU is in deep sleep mode. These values are programmed to the sleep configuration registers - before entering deep sleep mode. + deep-sleep-config: + type: array + description: | + An array of values written to the PDSLEEPCFG registers that controls the + power to various blocks while the CPU is in deep sleep mode. These values + are programmed to the sleep configuration registers before entering deep + sleep mode. From 6199ecba6995f1017f120e6bcfc4b4720de30eb8 Mon Sep 17 00:00:00 2001 From: Paul Fagerburg Date: Mon, 24 Jul 2023 16:51:04 +0000 Subject: [PATCH 1729/2042] cbprintf: use type instead of name in sizeof Using `arg + 0` in sizeof causes problems with `void *`, so use the type name instead, but make sure it's at least `sizeof(int)` because the variadic expects a minimum of `int` size. This allows deleting the specialization for `void *`, which the linker wasn't choosing reliably anyway. Signed-off-by: Paul Fagerburg --- include/zephyr/sys/cbprintf_cxx.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/zephyr/sys/cbprintf_cxx.h b/include/zephyr/sys/cbprintf_cxx.h index 3a47237904c6..a1e8c9632856 100644 --- a/include/zephyr/sys/cbprintf_cxx.h +++ b/include/zephyr/sys/cbprintf_cxx.h @@ -96,17 +96,12 @@ static inline size_t z_cbprintf_cxx_arg_size(float f) return sizeof(double); } -static inline size_t z_cbprintf_cxx_arg_size(void *p) -{ - ARG_UNUSED(p); - - return sizeof(void *); -} - template < typename T > static inline size_t z_cbprintf_cxx_arg_size(T arg) { - return sizeof(arg + 0); + ARG_UNUSED(arg); + + return MAX(sizeof(T), sizeof(int)); } /* C++ version for storing arguments. */ From 669407f0292e4efc01cc630e3be826d40b525eef Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Mon, 24 Jul 2023 15:14:28 -0300 Subject: [PATCH 1730/2042] tests: drivers: spi loopback: esp32xx: Use internal loopback Use pinctrl with internal loopback enabled for ESP32 and ESP32C3. Signed-off-by: Lucas Tamborrino --- tests/drivers/spi/spi_loopback/boards/esp32.overlay | 2 +- tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/spi/spi_loopback/boards/esp32.overlay b/tests/drivers/spi/spi_loopback/boards/esp32.overlay index b2af8bbf3cb2..f2dcccfb7bf1 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32.overlay @@ -36,6 +36,6 @@ &spi3 { dma-enabled; - pinctrl-0 = <&spim3_default>; + pinctrl-0 = <&spim3_loopback>; }; diff --git a/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay b/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay index 34a1ab69662b..8e5037e76911 100644 --- a/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay +++ b/tests/drivers/spi/spi_loopback/boards/esp32c3_devkitm.overlay @@ -36,5 +36,5 @@ &spi2 { dma-enabled; - pinctrl-0 = <&spim2_default>; + pinctrl-0 = <&spim2_loopback>; }; From dbb0b30bdd8d3aa1a32faf2aabee441a0c749794 Mon Sep 17 00:00:00 2001 From: Alperen Sener Date: Mon, 24 Jul 2023 12:26:53 +0200 Subject: [PATCH 1731/2042] bluetooth: mesh: increase mesh scan window Increaing mesh scan window in order to reduce the number of messages colliding into scan window end which happens every 30ms currently. Increasing the window to 3000ms in order to improve performance. Keeping 30ms window only for legacy advertiser support. Signed-off-by: Alperen Sener --- subsys/bluetooth/mesh/adv.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/subsys/bluetooth/mesh/adv.h b/subsys/bluetooth/mesh/adv.h index 3d0acf8a7ac5..eec6ae2fd74f 100644 --- a/subsys/bluetooth/mesh/adv.h +++ b/subsys/bluetooth/mesh/adv.h @@ -13,8 +13,14 @@ #define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) #define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +#if defined(CONFIG_BT_EXT_ADV) +#define BT_MESH_SCAN_INTERVAL_MS 3000 +#define BT_MESH_SCAN_WINDOW_MS 3000 +#else #define BT_MESH_SCAN_INTERVAL_MS 30 #define BT_MESH_SCAN_WINDOW_MS 30 +#endif enum bt_mesh_adv_type { BT_MESH_ADV_PROV, From e065e5c600e4e9416cf51a5aa023727b0c6253e2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Mon, 24 Jul 2023 14:08:05 +0000 Subject: [PATCH 1732/2042] soc: silabs_exx32: define an empty pm_state_exit_post_ops Some EFR32 build broke after 3d2194f11e with: pm.c:152: undefined reference to `pm_state_exit_post_ops' Add an extra empty function to make this one build again. Signed-off-by: Fabio Baltieri --- soc/arm/silabs_exx32/common/soc_power_pmgr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/soc/arm/silabs_exx32/common/soc_power_pmgr.c b/soc/arm/silabs_exx32/common/soc_power_pmgr.c index 0286e99e77f5..1980c95a56b5 100644 --- a/soc/arm/silabs_exx32/common/soc_power_pmgr.c +++ b/soc/arm/silabs_exx32/common/soc_power_pmgr.c @@ -73,6 +73,11 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) __enable_irq(); } +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); +} /** * Some SiLabs blobs, such as RAIL, call directly into sl_power_manager, and From f345d6d1d87dd691badcbede9893153f01655bee Mon Sep 17 00:00:00 2001 From: Kai Meinhard Date: Thu, 13 Jul 2023 08:16:43 +0200 Subject: [PATCH 1733/2042] i2c: add target mode to Silicon Labs Gecko I2C driver This commits adds the ability to use Silicon Lab chips as an I2C target. This could be used together with the EEPROM target driver. Signed-off-by: Kai Meinhard --- drivers/i2c/i2c_gecko.c | 161 +++++++++++++++++++++++++++++++++++----- 1 file changed, 141 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/i2c_gecko.c b/drivers/i2c/i2c_gecko.c index c77bea215b46..9d766f78b9e6 100644 --- a/drivers/i2c/i2c_gecko.c +++ b/drivers/i2c/i2c_gecko.c @@ -36,11 +36,18 @@ struct i2c_gecko_config { #else uint8_t loc; #endif +#if defined(CONFIG_I2C_TARGET) + void (*irq_config_func)(const struct device *dev); +#endif }; struct i2c_gecko_data { struct k_sem device_sync_sem; uint32_t dev_config; +#if defined(CONFIG_I2C_TARGET) + struct i2c_target_config *target_cfg; + volatile bool target_read; +#endif }; void i2c_gecko_config_pins(const struct device *dev, @@ -76,6 +83,9 @@ static int i2c_gecko_configure(const struct device *dev, { I2C_TypeDef *base = DEV_BASE(dev); struct i2c_gecko_data *data = dev->data; +#if defined(CONFIG_I2C_TARGET) + const struct i2c_gecko_config *config = dev->config; +#endif I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT; uint32_t baudrate; @@ -100,6 +110,11 @@ static int i2c_gecko_configure(const struct device *dev, data->dev_config = dev_config_raw; i2cInit.freq = baudrate; +#if defined(CONFIG_I2C_TARGET) + i2cInit.master = 0; + BUS_RegBitWrite(&(config->base->CTRL), _I2C_CTRL_AUTOACK_SHIFT, 1); +#endif + I2C_Init(base, &i2cInit); return 0; @@ -189,11 +204,103 @@ static int i2c_gecko_init(const struct device *dev) return 0; } +#if defined(CONFIG_I2C_TARGET) +static int i2c_gecko_target_register(const struct device *dev, struct i2c_target_config *cfg) +{ + const struct i2c_gecko_config *config = dev->config; + struct i2c_gecko_data *data = dev->data; + + data->target_cfg = cfg; + + I2C_SlaveAddressSet(config->base, cfg->address << _I2C_SADDR_ADDR_SHIFT); + I2C_SlaveAddressMaskSet(config->base, _I2C_SADDRMASK_SADDRMASK_MASK); + + I2C_IntDisable(config->base, _I2C_IEN_MASK); + I2C_IntEnable(config->base, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP); + + config->irq_config_func(dev); + + return 0; +} + +static int i2c_gecko_target_unregister(const struct device *dev, struct i2c_target_config *cfg) +{ + const struct i2c_gecko_config *config = dev->config; + struct i2c_gecko_data *data = dev->data; + + data->target_cfg = NULL; + + I2C_IntDisable(config->base, _I2C_IEN_MASK); + + return 0; +} +#endif + static const struct i2c_driver_api i2c_gecko_driver_api = { .configure = i2c_gecko_configure, .transfer = i2c_gecko_transfer, +#if defined(CONFIG_I2C_TARGET) + .target_register = i2c_gecko_target_register, + .target_unregister = i2c_gecko_target_unregister, +#endif }; +#if defined(CONFIG_I2C_TARGET) +static void i2c_gecko_isr(const struct device *dev) +{ + const struct i2c_gecko_config *config = dev->config; + struct i2c_gecko_data *data = dev->data; + uint32_t status; + uint32_t rx_data; + uint8_t tx_byte; + + status = config->base->IF; + + if (status & I2C_IF_ADDR && status & I2C_IF_RXDATAV) { + /* Address Match */ + rx_data = config->base->RXDATA; + if (rx_data & 0x1) { + data->target_read = true; + + data->target_cfg->callbacks->read_requested(data->target_cfg, &tx_byte); + config->base->TXDATA = tx_byte; + + I2C_IntEnable(config->base, I2C_IEN_BUSHOLD); + } else { + data->target_read = false; + data->target_cfg->callbacks->write_requested(data->target_cfg); + } + I2C_IntClear(config->base, I2C_IF_ADDR); + I2C_IntClear(config->base, I2C_IF_RXDATAV); + } else if (status & I2C_IF_RXDATAV) { + if (data->target_read == true) { + LOG_ERR("Unexpected Data"); + } else { + rx_data = config->base->RXDATA; + data->target_cfg->callbacks->write_received(data->target_cfg, rx_data); + } + I2C_IntClear(config->base, I2C_IF_RXDATAV); + } else if (data->target_read && status & I2C_IF_BUSHOLD && !(status & I2C_IF_SSTOP)) { + data->target_cfg->callbacks->read_processed(data->target_cfg, &tx_byte); + config->base->TXDATA = tx_byte; + + I2C_IntClear(config->base, I2C_IF_BUSHOLD); + } + + if (status & I2C_IF_SSTOP) { + if (config->base->STATUS & I2C_STATUS_RXDATAV) { + LOG_ERR("Still valid data"); + } + /* Stop received, reception is ended */ + data->target_cfg->callbacks->stop(data->target_cfg); + + I2C_IntClear(config->base, I2C_IF_SSTOP); + I2C_IntClear(config->base, I2C_IF_BUSHOLD); + I2C_IntDisable(config->base, I2C_IEN_BUSHOLD); + } +} +#endif + #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION #define I2C_LOC_DATA(idx) \ .loc_sda = DT_INST_PROP_BY_IDX(idx, location_sda, 0), \ @@ -208,25 +315,39 @@ static const struct i2c_driver_api i2c_gecko_driver_api = { .loc = DT_INST_PROP_BY_IDX(idx, location_scl, 0) #endif -#define I2C_INIT(idx) \ -I2C_VALIDATE_LOC(idx); \ -static const struct i2c_gecko_config i2c_gecko_config_##idx = { \ - .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ - .clock = cmuClock_I2C##idx, \ - .pin_sda = {DT_INST_PROP_BY_IDX(idx, location_sda, 1), \ - DT_INST_PROP_BY_IDX(idx, location_sda, 2), gpioModeWiredAnd, 1}, \ - .pin_scl = {DT_INST_PROP_BY_IDX(idx, location_scl, 1), \ - DT_INST_PROP_BY_IDX(idx, location_scl, 2), gpioModeWiredAnd, 1}, \ - I2C_LOC_DATA(idx), \ - .bitrate = DT_INST_PROP(idx, clock_frequency), \ -}; \ -\ -static struct i2c_gecko_data i2c_gecko_data_##idx; \ -\ -I2C_DEVICE_DT_INST_DEFINE(idx, i2c_gecko_init, \ - NULL, \ - &i2c_gecko_data_##idx, &i2c_gecko_config_##idx, \ - POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ - &i2c_gecko_driver_api); +#if defined(CONFIG_I2C_TARGET) +#define GECKO_I2C_IRQ_DEF(idx) static void i2c_gecko_config_func_##idx(const struct device *dev); +#define GECKO_I2C_IRQ_DATA(idx) .irq_config_func = i2c_gecko_config_func_##idx, +#define GECKO_I2C_IRQ_HANDLER(idx) \ + static void i2c_gecko_config_func_##idx(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQ(idx, irq), DT_INST_IRQ(idx, priority), i2c_gecko_isr, \ + DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQ(idx, irq)); \ + } +#else +#define GECKO_I2C_IRQ_HANDLER(idx) +#define GECKO_I2C_IRQ_DEF(idx) +#define GECKO_I2C_IRQ_DATA(idx) +#endif + +#define I2C_INIT(idx) \ + I2C_VALIDATE_LOC(idx); \ + GECKO_I2C_IRQ_DEF(idx) \ + static const struct i2c_gecko_config i2c_gecko_config_##idx = { \ + .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ + .clock = cmuClock_I2C##idx, \ + .pin_sda = {DT_INST_PROP_BY_IDX(idx, location_sda, 1), \ + DT_INST_PROP_BY_IDX(idx, location_sda, 2), gpioModeWiredAnd, 1}, \ + .pin_scl = {DT_INST_PROP_BY_IDX(idx, location_scl, 1), \ + DT_INST_PROP_BY_IDX(idx, location_scl, 2), gpioModeWiredAnd, 1}, \ + I2C_LOC_DATA(idx), \ + .bitrate = DT_INST_PROP(idx, clock_frequency), \ + GECKO_I2C_IRQ_DATA(idx)}; \ + static struct i2c_gecko_data i2c_gecko_data_##idx; \ + I2C_DEVICE_DT_INST_DEFINE(idx, i2c_gecko_init, NULL, &i2c_gecko_data_##idx, \ + &i2c_gecko_config_##idx, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ + &i2c_gecko_driver_api); \ + GECKO_I2C_IRQ_HANDLER(idx) DT_INST_FOREACH_STATUS_OKAY(I2C_INIT) From ea846e12bfe89a0370d31fd3e8bfc6d1330624bc Mon Sep 17 00:00:00 2001 From: Kai Meinhard Date: Thu, 13 Jul 2023 11:11:30 +0200 Subject: [PATCH 1734/2042] i2c: Applied clang-format to i2c_gecko.c Minor formatting changes in i2c_gecko.c with the clang-format tool. Signed-off-by: Kai Meinhard --- drivers/i2c/i2c_gecko.c | 45 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/i2c_gecko.c b/drivers/i2c/i2c_gecko.c index 9d766f78b9e6..edeef4704341 100644 --- a/drivers/i2c/i2c_gecko.c +++ b/drivers/i2c/i2c_gecko.c @@ -21,8 +21,7 @@ LOG_MODULE_REGISTER(i2c_gecko); #include "i2c-priv.h" -#define DEV_BASE(dev) \ - ((I2C_TypeDef *)((const struct i2c_gecko_config * const)(dev)->config)->base) +#define DEV_BASE(dev) ((I2C_TypeDef *)((const struct i2c_gecko_config *const)(dev)->config)->base) struct i2c_gecko_config { I2C_TypeDef *base; @@ -50,8 +49,7 @@ struct i2c_gecko_data { #endif }; -void i2c_gecko_config_pins(const struct device *dev, - const struct soc_gpio_pin *pin_sda, +void i2c_gecko_config_pins(const struct device *dev, const struct soc_gpio_pin *pin_sda, const struct soc_gpio_pin *pin_scl) { I2C_TypeDef *base = DEV_BASE(dev); @@ -65,8 +63,7 @@ void i2c_gecko_config_pins(const struct device *dev, base->ROUTELOC0 = (config->loc_sda << _I2C_ROUTELOC0_SDALOC_SHIFT) | (config->loc_scl << _I2C_ROUTELOC0_SCLLOC_SHIFT); #elif defined(GPIO_I2C_ROUTEEN_SCLPEN) && defined(GPIO_I2C_ROUTEEN_SDAPEN) - GPIO->I2CROUTE[I2C_NUM(base)].ROUTEEN = GPIO_I2C_ROUTEEN_SCLPEN | - GPIO_I2C_ROUTEEN_SDAPEN; + GPIO->I2CROUTE[I2C_NUM(base)].ROUTEEN = GPIO_I2C_ROUTEEN_SCLPEN | GPIO_I2C_ROUTEEN_SDAPEN; GPIO->I2CROUTE[I2C_NUM(base)].SCLROUTE = (config->pin_scl.pin << _GPIO_I2C_SCLROUTE_PIN_SHIFT) | (config->pin_scl.port << _GPIO_I2C_SCLROUTE_PORT_SHIFT); @@ -78,16 +75,15 @@ void i2c_gecko_config_pins(const struct device *dev, #endif } -static int i2c_gecko_configure(const struct device *dev, - uint32_t dev_config_raw) +static int i2c_gecko_configure(const struct device *dev, uint32_t dev_config_raw) { I2C_TypeDef *base = DEV_BASE(dev); struct i2c_gecko_data *data = dev->data; + I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT; + uint32_t baudrate; #if defined(CONFIG_I2C_TARGET) const struct i2c_gecko_config *config = dev->config; #endif - I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT; - uint32_t baudrate; if (!(I2C_MODE_CONTROLLER & dev_config_raw)) { return -EINVAL; @@ -120,8 +116,8 @@ static int i2c_gecko_configure(const struct device *dev, return 0; } -static int i2c_gecko_transfer(const struct device *dev, struct i2c_msg *msgs, - uint8_t num_msgs, uint16_t addr) +static int i2c_gecko_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, + uint16_t addr) { I2C_TypeDef *base = DEV_BASE(dev); struct i2c_gecko_data *data = dev->data; @@ -137,7 +133,7 @@ static int i2c_gecko_transfer(const struct device *dev, struct i2c_msg *msgs, do { seq.buf[0].data = msgs->buf; - seq.buf[0].len = msgs->len; + seq.buf[0].len = msgs->len; if ((msgs->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { seq.flags = I2C_FLAG_READ; @@ -147,14 +143,13 @@ static int i2c_gecko_transfer(const struct device *dev, struct i2c_msg *msgs, /* Next message */ msgs++; num_msgs--; - if ((msgs->flags & I2C_MSG_RW_MASK) - == I2C_MSG_READ) { + if ((msgs->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { seq.flags = I2C_FLAG_WRITE_READ; } else { seq.flags = I2C_FLAG_WRITE_WRITE; } seq.buf[1].data = msgs->buf; - seq.buf[1].len = msgs->len; + seq.buf[1].len = msgs->len; } } @@ -213,6 +208,7 @@ static int i2c_gecko_target_register(const struct device *dev, struct i2c_target data->target_cfg = cfg; I2C_SlaveAddressSet(config->base, cfg->address << _I2C_SADDR_ADDR_SHIFT); + /* Match with specified address, no wildcards in address */ I2C_SlaveAddressMaskSet(config->base, _I2C_SADDRMASK_SADDRMASK_MASK); I2C_IntDisable(config->base, _I2C_IEN_MASK); @@ -302,17 +298,16 @@ static void i2c_gecko_isr(const struct device *dev) #endif #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION -#define I2C_LOC_DATA(idx) \ - .loc_sda = DT_INST_PROP_BY_IDX(idx, location_sda, 0), \ +#define I2C_LOC_DATA(idx) \ + .loc_sda = DT_INST_PROP_BY_IDX(idx, location_sda, 0), \ .loc_scl = DT_INST_PROP_BY_IDX(idx, location_scl, 0) #define I2C_VALIDATE_LOC(idx) BUILD_ASSERT(true, "") #else -#define I2C_VALIDATE_LOC(idx) \ - BUILD_ASSERT(DT_INST_PROP_BY_IDX(idx, location_sda, 0) \ - == DT_INST_PROP_BY_IDX(idx, location_scl, 0), \ +#define I2C_VALIDATE_LOC(idx) \ + BUILD_ASSERT(DT_INST_PROP_BY_IDX(idx, location_sda, 0) == \ + DT_INST_PROP_BY_IDX(idx, location_scl, 0), \ "DTS location-* properties must be equal") -#define I2C_LOC_DATA(idx) \ - .loc = DT_INST_PROP_BY_IDX(idx, location_scl, 0) +#define I2C_LOC_DATA(idx) .loc = DT_INST_PROP_BY_IDX(idx, location_scl, 0) #endif #if defined(CONFIG_I2C_TARGET) @@ -338,9 +333,9 @@ static void i2c_gecko_isr(const struct device *dev) .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ .clock = cmuClock_I2C##idx, \ .pin_sda = {DT_INST_PROP_BY_IDX(idx, location_sda, 1), \ - DT_INST_PROP_BY_IDX(idx, location_sda, 2), gpioModeWiredAnd, 1}, \ + DT_INST_PROP_BY_IDX(idx, location_sda, 2), gpioModeWiredAnd, 1}, \ .pin_scl = {DT_INST_PROP_BY_IDX(idx, location_scl, 1), \ - DT_INST_PROP_BY_IDX(idx, location_scl, 2), gpioModeWiredAnd, 1}, \ + DT_INST_PROP_BY_IDX(idx, location_scl, 2), gpioModeWiredAnd, 1}, \ I2C_LOC_DATA(idx), \ .bitrate = DT_INST_PROP(idx, clock_frequency), \ GECKO_I2C_IRQ_DATA(idx)}; \ From 25c96b6434b9fe5ada4c490959e2833d730e9813 Mon Sep 17 00:00:00 2001 From: Kai Meinhard Date: Thu, 13 Jul 2023 11:14:26 +0200 Subject: [PATCH 1735/2042] i2c: Added efr32bg22_brd4184a to I2C target tests Compiling I2C target test for efr32bg22_brd4184a board so that i2c_gecko.c driver is used in target mode. Signed-off-by: Kai Meinhard --- .../i2c_target_api/boards/efr32bg22_brd4184a.conf | 2 ++ .../boards/efr32bg22_brd4184a.overlay | 14 ++++++++++++++ tests/drivers/i2c/i2c_target_api/testcase.yaml | 1 + 3 files changed, 17 insertions(+) create mode 100644 tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.conf create mode 100644 tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.overlay diff --git a/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.conf b/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.conf new file mode 100644 index 000000000000..f3d64527b85f --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.conf @@ -0,0 +1,2 @@ +CONFIG_I2C=y +CONFIG_I2C_TARGET=y diff --git a/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.overlay b/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.overlay new file mode 100644 index 000000000000..ba0a0ce28f04 --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/efr32bg22_brd4184a.overlay @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +&i2c0 { + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index 140d19c7b8ba..0ffc34a78073 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -19,6 +19,7 @@ tests: - nucleo_wl55jc - nucleo_l073rz - rpi_pico + - efr32bg22_brd4184a integration_platforms: - nucleo_f091rc extra_configs: From b88d52e98f6d5d69a1913b4d677f7548df008435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Jul 2023 13:13:22 +0200 Subject: [PATCH 1736/2042] bluetooth: doc: Improve sdp.h Doxygen doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grouped some defines together, documented service classes and attributes, and fixed some missing javadoc-style comments. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/sdp.h | 438 +++++++++++++++++---------------- 1 file changed, 226 insertions(+), 212 deletions(-) diff --git a/include/zephyr/bluetooth/sdp.h b/include/zephyr/bluetooth/sdp.h index ae9409f58f66..686c0e718cb9 100644 --- a/include/zephyr/bluetooth/sdp.h +++ b/include/zephyr/bluetooth/sdp.h @@ -11,6 +11,7 @@ #define ZEPHYR_INCLUDE_BLUETOOTH_SDP_H_ /** + * @file * @brief Service Discovery Protocol (SDP) * @defgroup bt_sdp Service Discovery Protocol (SDP) * @ingroup bluetooth @@ -29,175 +30,183 @@ extern "C" { * of the Bluetooth Specification */ -/* - * Service class identifiers of standard services and service groups - */ -#define BT_SDP_SDP_SERVER_SVCLASS 0x1000 -#define BT_SDP_BROWSE_GRP_DESC_SVCLASS 0x1001 -#define BT_SDP_PUBLIC_BROWSE_GROUP 0x1002 -#define BT_SDP_SERIAL_PORT_SVCLASS 0x1101 -#define BT_SDP_LAN_ACCESS_SVCLASS 0x1102 -#define BT_SDP_DIALUP_NET_SVCLASS 0x1103 -#define BT_SDP_IRMC_SYNC_SVCLASS 0x1104 -#define BT_SDP_OBEX_OBJPUSH_SVCLASS 0x1105 -#define BT_SDP_OBEX_FILETRANS_SVCLASS 0x1106 -#define BT_SDP_IRMC_SYNC_CMD_SVCLASS 0x1107 -#define BT_SDP_HEADSET_SVCLASS 0x1108 -#define BT_SDP_CORDLESS_TELEPHONY_SVCLASS 0x1109 -#define BT_SDP_AUDIO_SOURCE_SVCLASS 0x110a -#define BT_SDP_AUDIO_SINK_SVCLASS 0x110b -#define BT_SDP_AV_REMOTE_TARGET_SVCLASS 0x110c -#define BT_SDP_ADVANCED_AUDIO_SVCLASS 0x110d -#define BT_SDP_AV_REMOTE_SVCLASS 0x110e -#define BT_SDP_AV_REMOTE_CONTROLLER_SVCLASS 0x110f -#define BT_SDP_INTERCOM_SVCLASS 0x1110 -#define BT_SDP_FAX_SVCLASS 0x1111 -#define BT_SDP_HEADSET_AGW_SVCLASS 0x1112 -#define BT_SDP_WAP_SVCLASS 0x1113 -#define BT_SDP_WAP_CLIENT_SVCLASS 0x1114 -#define BT_SDP_PANU_SVCLASS 0x1115 -#define BT_SDP_NAP_SVCLASS 0x1116 -#define BT_SDP_GN_SVCLASS 0x1117 -#define BT_SDP_DIRECT_PRINTING_SVCLASS 0x1118 -#define BT_SDP_REFERENCE_PRINTING_SVCLASS 0x1119 -#define BT_SDP_IMAGING_SVCLASS 0x111a -#define BT_SDP_IMAGING_RESPONDER_SVCLASS 0x111b -#define BT_SDP_IMAGING_ARCHIVE_SVCLASS 0x111c -#define BT_SDP_IMAGING_REFOBJS_SVCLASS 0x111d -#define BT_SDP_HANDSFREE_SVCLASS 0x111e -#define BT_SDP_HANDSFREE_AGW_SVCLASS 0x111f -#define BT_SDP_DIRECT_PRT_REFOBJS_SVCLASS 0x1120 -#define BT_SDP_REFLECTED_UI_SVCLASS 0x1121 -#define BT_SDP_BASIC_PRINTING_SVCLASS 0x1122 -#define BT_SDP_PRINTING_STATUS_SVCLASS 0x1123 -#define BT_SDP_HID_SVCLASS 0x1124 -#define BT_SDP_HCR_SVCLASS 0x1125 -#define BT_SDP_HCR_PRINT_SVCLASS 0x1126 -#define BT_SDP_HCR_SCAN_SVCLASS 0x1127 -#define BT_SDP_CIP_SVCLASS 0x1128 -#define BT_SDP_VIDEO_CONF_GW_SVCLASS 0x1129 -#define BT_SDP_UDI_MT_SVCLASS 0x112a -#define BT_SDP_UDI_TA_SVCLASS 0x112b -#define BT_SDP_AV_SVCLASS 0x112c -#define BT_SDP_SAP_SVCLASS 0x112d -#define BT_SDP_PBAP_PCE_SVCLASS 0x112e -#define BT_SDP_PBAP_PSE_SVCLASS 0x112f -#define BT_SDP_PBAP_SVCLASS 0x1130 -#define BT_SDP_MAP_MSE_SVCLASS 0x1132 -#define BT_SDP_MAP_MCE_SVCLASS 0x1133 -#define BT_SDP_MAP_SVCLASS 0x1134 -#define BT_SDP_GNSS_SVCLASS 0x1135 -#define BT_SDP_GNSS_SERVER_SVCLASS 0x1136 -#define BT_SDP_MPS_SC_SVCLASS 0x113a -#define BT_SDP_MPS_SVCLASS 0x113b -#define BT_SDP_PNP_INFO_SVCLASS 0x1200 -#define BT_SDP_GENERIC_NETWORKING_SVCLASS 0x1201 -#define BT_SDP_GENERIC_FILETRANS_SVCLASS 0x1202 -#define BT_SDP_GENERIC_AUDIO_SVCLASS 0x1203 -#define BT_SDP_GENERIC_TELEPHONY_SVCLASS 0x1204 -#define BT_SDP_UPNP_SVCLASS 0x1205 -#define BT_SDP_UPNP_IP_SVCLASS 0x1206 -#define BT_SDP_UPNP_PAN_SVCLASS 0x1300 -#define BT_SDP_UPNP_LAP_SVCLASS 0x1301 -#define BT_SDP_UPNP_L2CAP_SVCLASS 0x1302 -#define BT_SDP_VIDEO_SOURCE_SVCLASS 0x1303 -#define BT_SDP_VIDEO_SINK_SVCLASS 0x1304 -#define BT_SDP_VIDEO_DISTRIBUTION_SVCLASS 0x1305 -#define BT_SDP_HDP_SVCLASS 0x1400 -#define BT_SDP_HDP_SOURCE_SVCLASS 0x1401 -#define BT_SDP_HDP_SINK_SVCLASS 0x1402 -#define BT_SDP_GENERIC_ACCESS_SVCLASS 0x1800 -#define BT_SDP_GENERIC_ATTRIB_SVCLASS 0x1801 -#define BT_SDP_APPLE_AGENT_SVCLASS 0x2112 - -/* - * Attribute identifier codes +/** + * @name Service class identifiers of standard services and service groups + * @{ */ +#define BT_SDP_SDP_SERVER_SVCLASS 0x1000 /**< Service Discovery Server */ +#define BT_SDP_BROWSE_GRP_DESC_SVCLASS 0x1001 /**< Browse Group Descriptor */ +#define BT_SDP_PUBLIC_BROWSE_GROUP 0x1002 /**< Public Browse Group */ +#define BT_SDP_SERIAL_PORT_SVCLASS 0x1101 /**< Serial Port */ +#define BT_SDP_LAN_ACCESS_SVCLASS 0x1102 /**< LAN Access Using PPP */ +#define BT_SDP_DIALUP_NET_SVCLASS 0x1103 /**< Dialup Networking */ +#define BT_SDP_IRMC_SYNC_SVCLASS 0x1104 /**< IrMC Sync */ +#define BT_SDP_OBEX_OBJPUSH_SVCLASS 0x1105 /**< OBEX Object Push */ +#define BT_SDP_OBEX_FILETRANS_SVCLASS 0x1106 /**< OBEX File Transfer */ +#define BT_SDP_IRMC_SYNC_CMD_SVCLASS 0x1107 /**< IrMC Sync Command */ +#define BT_SDP_HEADSET_SVCLASS 0x1108 /**< Headset */ +#define BT_SDP_CORDLESS_TELEPHONY_SVCLASS 0x1109 /**< Cordless Telephony */ +#define BT_SDP_AUDIO_SOURCE_SVCLASS 0x110a /**< Audio Source */ +#define BT_SDP_AUDIO_SINK_SVCLASS 0x110b /**< Audio Sink */ +#define BT_SDP_AV_REMOTE_TARGET_SVCLASS 0x110c /**< A/V Remote Control Target */ +#define BT_SDP_ADVANCED_AUDIO_SVCLASS 0x110d /**< Advanced Audio Distribution */ +#define BT_SDP_AV_REMOTE_SVCLASS 0x110e /**< A/V Remote Control */ +#define BT_SDP_AV_REMOTE_CONTROLLER_SVCLASS 0x110f /**< A/V Remote Control Controller */ +#define BT_SDP_INTERCOM_SVCLASS 0x1110 /**< Intercom */ +#define BT_SDP_FAX_SVCLASS 0x1111 /**< Fax */ +#define BT_SDP_HEADSET_AGW_SVCLASS 0x1112 /**< Headset AG */ +#define BT_SDP_WAP_SVCLASS 0x1113 /**< WAP */ +#define BT_SDP_WAP_CLIENT_SVCLASS 0x1114 /**< WAP Client */ +#define BT_SDP_PANU_SVCLASS 0x1115 /**< Personal Area Networking User */ +#define BT_SDP_NAP_SVCLASS 0x1116 /**< Network Access Point */ +#define BT_SDP_GN_SVCLASS 0x1117 /**< Group Network */ +#define BT_SDP_DIRECT_PRINTING_SVCLASS 0x1118 /**< Direct Printing */ +#define BT_SDP_REFERENCE_PRINTING_SVCLASS 0x1119 /**< Reference Printing */ +#define BT_SDP_IMAGING_SVCLASS 0x111a /**< Basic Imaging Profile */ +#define BT_SDP_IMAGING_RESPONDER_SVCLASS 0x111b /**< Imaging Responder */ +#define BT_SDP_IMAGING_ARCHIVE_SVCLASS 0x111c /**< Imaging Automatic Archive */ +#define BT_SDP_IMAGING_REFOBJS_SVCLASS 0x111d /**< Imaging Referenced Objects */ +#define BT_SDP_HANDSFREE_SVCLASS 0x111e /**< Handsfree */ +#define BT_SDP_HANDSFREE_AGW_SVCLASS 0x111f /**< Handsfree Audio Gateway */ +#define BT_SDP_DIRECT_PRT_REFOBJS_SVCLASS 0x1120 /**< Direct Printing Reference Objects Service */ +#define BT_SDP_REFLECTED_UI_SVCLASS 0x1121 /**< Reflected UI */ +#define BT_SDP_BASIC_PRINTING_SVCLASS 0x1122 /**< Basic Printing */ +#define BT_SDP_PRINTING_STATUS_SVCLASS 0x1123 /**< Printing Status */ +#define BT_SDP_HID_SVCLASS 0x1124 /**< Human Interface Device Service */ +#define BT_SDP_HCR_SVCLASS 0x1125 /**< Hardcopy Cable Replacement */ +#define BT_SDP_HCR_PRINT_SVCLASS 0x1126 /**< HCR Print */ +#define BT_SDP_HCR_SCAN_SVCLASS 0x1127 /**< HCR Scan */ +#define BT_SDP_CIP_SVCLASS 0x1128 /**< Common ISDN Access */ +#define BT_SDP_VIDEO_CONF_GW_SVCLASS 0x1129 /**< Video Conferencing Gateway */ +#define BT_SDP_UDI_MT_SVCLASS 0x112a /**< UDI MT */ +#define BT_SDP_UDI_TA_SVCLASS 0x112b /**< UDI TA */ +#define BT_SDP_AV_SVCLASS 0x112c /**< Audio/Video */ +#define BT_SDP_SAP_SVCLASS 0x112d /**< SIM Access */ +#define BT_SDP_PBAP_PCE_SVCLASS 0x112e /**< Phonebook Access Client */ +#define BT_SDP_PBAP_PSE_SVCLASS 0x112f /**< Phonebook Access Server */ +#define BT_SDP_PBAP_SVCLASS 0x1130 /**< Phonebook Access */ +#define BT_SDP_MAP_MSE_SVCLASS 0x1132 /**< Message Access Server */ +#define BT_SDP_MAP_MCE_SVCLASS 0x1133 /**< Message Notification Server */ +#define BT_SDP_MAP_SVCLASS 0x1134 /**< Message Access Profile */ +#define BT_SDP_GNSS_SVCLASS 0x1135 /**< GNSS */ +#define BT_SDP_GNSS_SERVER_SVCLASS 0x1136 /**< GNSS Server */ +#define BT_SDP_MPS_SC_SVCLASS 0x113a /**< MPS SC */ +#define BT_SDP_MPS_SVCLASS 0x113b /**< MPS */ +#define BT_SDP_PNP_INFO_SVCLASS 0x1200 /**< PnP Information */ +#define BT_SDP_GENERIC_NETWORKING_SVCLASS 0x1201 /**< Generic Networking */ +#define BT_SDP_GENERIC_FILETRANS_SVCLASS 0x1202 /**< Generic File Transfer */ +#define BT_SDP_GENERIC_AUDIO_SVCLASS 0x1203 /**< Generic Audio */ +#define BT_SDP_GENERIC_TELEPHONY_SVCLASS 0x1204 /**< Generic Telephony */ +#define BT_SDP_UPNP_SVCLASS 0x1205 /**< UPnP Service */ +#define BT_SDP_UPNP_IP_SVCLASS 0x1206 /**< UPnP IP Service */ +#define BT_SDP_UPNP_PAN_SVCLASS 0x1300 /**< UPnP IP PAN */ +#define BT_SDP_UPNP_LAP_SVCLASS 0x1301 /**< UPnP IP LAP */ +#define BT_SDP_UPNP_L2CAP_SVCLASS 0x1302 /**< UPnP IP L2CAP */ +#define BT_SDP_VIDEO_SOURCE_SVCLASS 0x1303 /**< Video Source */ +#define BT_SDP_VIDEO_SINK_SVCLASS 0x1304 /**< Video Sink */ +#define BT_SDP_VIDEO_DISTRIBUTION_SVCLASS 0x1305 /**< Video Distribution */ +#define BT_SDP_HDP_SVCLASS 0x1400 /**< HDP */ +#define BT_SDP_HDP_SOURCE_SVCLASS 0x1401 /**< HDP Source */ +#define BT_SDP_HDP_SINK_SVCLASS 0x1402 /**< HDP Sink */ +#define BT_SDP_GENERIC_ACCESS_SVCLASS 0x1800 /**< Generic Access Profile */ +#define BT_SDP_GENERIC_ATTRIB_SVCLASS 0x1801 /**< Generic Attribute Profile */ +#define BT_SDP_APPLE_AGENT_SVCLASS 0x2112 /**< Apple Agent */ +/** + * @} + */ + #define BT_SDP_SERVER_RECORD_HANDLE 0x0000 -/* +/** + * @name Attribute identifier codes + * * Possible values for attribute-id are listed below. * See SDP Spec, section "Service Attribute Definitions" for more details. + * + * @{ + */ +#define BT_SDP_ATTR_RECORD_HANDLE 0x0000 /**< Service Record Handle */ +#define BT_SDP_ATTR_SVCLASS_ID_LIST 0x0001 /**< Service Class ID List */ +#define BT_SDP_ATTR_RECORD_STATE 0x0002 /**< Service Record State */ +#define BT_SDP_ATTR_SERVICE_ID 0x0003 /**< Service ID */ +#define BT_SDP_ATTR_PROTO_DESC_LIST 0x0004 /**< Protocol Descriptor List */ +#define BT_SDP_ATTR_BROWSE_GRP_LIST 0x0005 /**< Browse Group List */ +#define BT_SDP_ATTR_LANG_BASE_ATTR_ID_LIST 0x0006 /**< Language Base Attribute ID List */ +#define BT_SDP_ATTR_SVCINFO_TTL 0x0007 /**< Service Info Time to Live */ +#define BT_SDP_ATTR_SERVICE_AVAILABILITY 0x0008 /**< Service Availability */ +#define BT_SDP_ATTR_PROFILE_DESC_LIST 0x0009 /**< Bluetooth Profile Descriptor List */ +#define BT_SDP_ATTR_DOC_URL 0x000a /**< Documentation URL */ +#define BT_SDP_ATTR_CLNT_EXEC_URL 0x000b /**< Client Executable URL */ +#define BT_SDP_ATTR_ICON_URL 0x000c /**< Icon URL */ +#define BT_SDP_ATTR_ADD_PROTO_DESC_LIST 0x000d /**< Additional Protocol Descriptor List */ + +#define BT_SDP_ATTR_GROUP_ID 0x0200 /**< Group ID */ +#define BT_SDP_ATTR_IP_SUBNET 0x0200 /**< IP Subnet */ +#define BT_SDP_ATTR_VERSION_NUM_LIST 0x0200 /**< Version Number List */ +#define BT_SDP_ATTR_SUPPORTED_FEATURES_LIST 0x0200 /**< Supported Features List */ +#define BT_SDP_ATTR_GOEP_L2CAP_PSM 0x0200 /**< GOEP L2CAP PSM */ +#define BT_SDP_ATTR_SVCDB_STATE 0x0201 /**< Service Database State */ + +#define BT_SDP_ATTR_MPSD_SCENARIOS 0x0200 /**< MPSD Scenarios */ +#define BT_SDP_ATTR_MPMD_SCENARIOS 0x0201 /**< MPMD Scenarios */ +#define BT_SDP_ATTR_MPS_DEPENDENCIES 0x0202 /**< Supported Profiles & Protocols */ + +#define BT_SDP_ATTR_SERVICE_VERSION 0x0300 /**< Service Version */ +#define BT_SDP_ATTR_EXTERNAL_NETWORK 0x0301 /**< External Network */ +#define BT_SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301 /**< Supported Data Stores List */ +#define BT_SDP_ATTR_DATA_EXCHANGE_SPEC 0x0301 /**< Data Exchange Specification */ +#define BT_SDP_ATTR_NETWORK 0x0301 /**< Network */ +#define BT_SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302 /**< Fax Class 1 Support */ +#define BT_SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302 /**< Remote Audio Volume Control */ +#define BT_SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302 /**< MCAP Supported Procedures */ +#define BT_SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303 /**< Fax Class 2.0 Support */ +#define BT_SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303 /**< Supported Formats List */ +#define BT_SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304 /**< Fax Class 2 Support (vendor-specific)*/ +#define BT_SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305 /**< Audio Feedback Support */ +#define BT_SDP_ATTR_NETWORK_ADDRESS 0x0306 /**< Network Address */ +#define BT_SDP_ATTR_WAP_GATEWAY 0x0307 /**< WAP Gateway */ +#define BT_SDP_ATTR_HOMEPAGE_URL 0x0308 /**< Homepage URL */ +#define BT_SDP_ATTR_WAP_STACK_TYPE 0x0309 /**< WAP Stack Type */ +#define BT_SDP_ATTR_SECURITY_DESC 0x030a /**< Security Description */ +#define BT_SDP_ATTR_NET_ACCESS_TYPE 0x030b /**< Net Access Type */ +#define BT_SDP_ATTR_MAX_NET_ACCESSRATE 0x030c /**< Max Net Access Rate */ +#define BT_SDP_ATTR_IP4_SUBNET 0x030d /**< IPv4 Subnet */ +#define BT_SDP_ATTR_IP6_SUBNET 0x030e /**< IPv6 Subnet */ +#define BT_SDP_ATTR_SUPPORTED_CAPABILITIES 0x0310 /**< BIP Supported Capabilities */ +#define BT_SDP_ATTR_SUPPORTED_FEATURES 0x0311 /**< BIP Supported Features */ +#define BT_SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312 /**< BIP Supported Functions */ +#define BT_SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313 /**< BIP Total Imaging Data Capacity */ +#define BT_SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314 /**< Supported Repositories */ +#define BT_SDP_ATTR_MAS_INSTANCE_ID 0x0315 /**< MAS Instance ID */ +#define BT_SDP_ATTR_SUPPORTED_MESSAGE_TYPES 0x0316 /**< Supported Message Types */ +#define BT_SDP_ATTR_PBAP_SUPPORTED_FEATURES 0x0317 /**< PBAP Supported Features */ +#define BT_SDP_ATTR_MAP_SUPPORTED_FEATURES 0x0317 /**< MAP Supported Features */ + +#define BT_SDP_ATTR_SPECIFICATION_ID 0x0200 /**< Specification ID */ +#define BT_SDP_ATTR_VENDOR_ID 0x0201 /**< Vendor ID */ +#define BT_SDP_ATTR_PRODUCT_ID 0x0202 /**< Product ID */ +#define BT_SDP_ATTR_VERSION 0x0203 /**< Version */ +#define BT_SDP_ATTR_PRIMARY_RECORD 0x0204 /**< Primary Record */ +#define BT_SDP_ATTR_VENDOR_ID_SOURCE 0x0205 /**< Vendor ID Source */ + +#define BT_SDP_ATTR_HID_DEVICE_RELEASE_NUMBER 0x0200 /**< HID Device Release Number */ +#define BT_SDP_ATTR_HID_PARSER_VERSION 0x0201 /**< HID Parser Version */ +#define BT_SDP_ATTR_HID_DEVICE_SUBCLASS 0x0202 /**< HID Device Subclass */ +#define BT_SDP_ATTR_HID_COUNTRY_CODE 0x0203 /**< HID Country Code */ +#define BT_SDP_ATTR_HID_VIRTUAL_CABLE 0x0204 /**< HID Virtual Cable */ +#define BT_SDP_ATTR_HID_RECONNECT_INITIATE 0x0205 /**< HID Reconnect Initiate */ +#define BT_SDP_ATTR_HID_DESCRIPTOR_LIST 0x0206 /**< HID Descriptor List */ +#define BT_SDP_ATTR_HID_LANG_ID_BASE_LIST 0x0207 /**< HID Language ID Base List */ +#define BT_SDP_ATTR_HID_SDP_DISABLE 0x0208 /**< HID SDP Disable */ +#define BT_SDP_ATTR_HID_BATTERY_POWER 0x0209 /**< HID Battery Power */ +#define BT_SDP_ATTR_HID_REMOTE_WAKEUP 0x020a /**< HID Remote Wakeup */ +#define BT_SDP_ATTR_HID_PROFILE_VERSION 0x020b /**< HID Profile Version */ +#define BT_SDP_ATTR_HID_SUPERVISION_TIMEOUT 0x020c /**< HID Supervision Timeout */ +#define BT_SDP_ATTR_HID_NORMALLY_CONNECTABLE 0x020d /**< HID Normally Connectable */ +#define BT_SDP_ATTR_HID_BOOT_DEVICE 0x020e /**< HID Boot Device */ +/** + * @} */ -#define BT_SDP_ATTR_RECORD_HANDLE 0x0000 -#define BT_SDP_ATTR_SVCLASS_ID_LIST 0x0001 -#define BT_SDP_ATTR_RECORD_STATE 0x0002 -#define BT_SDP_ATTR_SERVICE_ID 0x0003 -#define BT_SDP_ATTR_PROTO_DESC_LIST 0x0004 -#define BT_SDP_ATTR_BROWSE_GRP_LIST 0x0005 -#define BT_SDP_ATTR_LANG_BASE_ATTR_ID_LIST 0x0006 -#define BT_SDP_ATTR_SVCINFO_TTL 0x0007 -#define BT_SDP_ATTR_SERVICE_AVAILABILITY 0x0008 -#define BT_SDP_ATTR_PROFILE_DESC_LIST 0x0009 -#define BT_SDP_ATTR_DOC_URL 0x000a -#define BT_SDP_ATTR_CLNT_EXEC_URL 0x000b -#define BT_SDP_ATTR_ICON_URL 0x000c -#define BT_SDP_ATTR_ADD_PROTO_DESC_LIST 0x000d - -#define BT_SDP_ATTR_GROUP_ID 0x0200 -#define BT_SDP_ATTR_IP_SUBNET 0x0200 -#define BT_SDP_ATTR_VERSION_NUM_LIST 0x0200 -#define BT_SDP_ATTR_SUPPORTED_FEATURES_LIST 0x0200 -#define BT_SDP_ATTR_GOEP_L2CAP_PSM 0x0200 -#define BT_SDP_ATTR_SVCDB_STATE 0x0201 - -#define BT_SDP_ATTR_MPSD_SCENARIOS 0x0200 -#define BT_SDP_ATTR_MPMD_SCENARIOS 0x0201 -#define BT_SDP_ATTR_MPS_DEPENDENCIES 0x0202 - -#define BT_SDP_ATTR_SERVICE_VERSION 0x0300 -#define BT_SDP_ATTR_EXTERNAL_NETWORK 0x0301 -#define BT_SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301 -#define BT_SDP_ATTR_DATA_EXCHANGE_SPEC 0x0301 -#define BT_SDP_ATTR_NETWORK 0x0301 -#define BT_SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302 -#define BT_SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302 -#define BT_SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302 -#define BT_SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303 -#define BT_SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303 -#define BT_SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304 -#define BT_SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305 -#define BT_SDP_ATTR_NETWORK_ADDRESS 0x0306 -#define BT_SDP_ATTR_WAP_GATEWAY 0x0307 -#define BT_SDP_ATTR_HOMEPAGE_URL 0x0308 -#define BT_SDP_ATTR_WAP_STACK_TYPE 0x0309 -#define BT_SDP_ATTR_SECURITY_DESC 0x030a -#define BT_SDP_ATTR_NET_ACCESS_TYPE 0x030b -#define BT_SDP_ATTR_MAX_NET_ACCESSRATE 0x030c -#define BT_SDP_ATTR_IP4_SUBNET 0x030d -#define BT_SDP_ATTR_IP6_SUBNET 0x030e -#define BT_SDP_ATTR_SUPPORTED_CAPABILITIES 0x0310 -#define BT_SDP_ATTR_SUPPORTED_FEATURES 0x0311 -#define BT_SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312 -#define BT_SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313 -#define BT_SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314 -#define BT_SDP_ATTR_MAS_INSTANCE_ID 0x0315 -#define BT_SDP_ATTR_SUPPORTED_MESSAGE_TYPES 0x0316 -#define BT_SDP_ATTR_PBAP_SUPPORTED_FEATURES 0x0317 -#define BT_SDP_ATTR_MAP_SUPPORTED_FEATURES 0x0317 - -#define BT_SDP_ATTR_SPECIFICATION_ID 0x0200 -#define BT_SDP_ATTR_VENDOR_ID 0x0201 -#define BT_SDP_ATTR_PRODUCT_ID 0x0202 -#define BT_SDP_ATTR_VERSION 0x0203 -#define BT_SDP_ATTR_PRIMARY_RECORD 0x0204 -#define BT_SDP_ATTR_VENDOR_ID_SOURCE 0x0205 - -#define BT_SDP_ATTR_HID_DEVICE_RELEASE_NUMBER 0x0200 -#define BT_SDP_ATTR_HID_PARSER_VERSION 0x0201 -#define BT_SDP_ATTR_HID_DEVICE_SUBCLASS 0x0202 -#define BT_SDP_ATTR_HID_COUNTRY_CODE 0x0203 -#define BT_SDP_ATTR_HID_VIRTUAL_CABLE 0x0204 -#define BT_SDP_ATTR_HID_RECONNECT_INITIATE 0x0205 -#define BT_SDP_ATTR_HID_DESCRIPTOR_LIST 0x0206 -#define BT_SDP_ATTR_HID_LANG_ID_BASE_LIST 0x0207 -#define BT_SDP_ATTR_HID_SDP_DISABLE 0x0208 -#define BT_SDP_ATTR_HID_BATTERY_POWER 0x0209 -#define BT_SDP_ATTR_HID_REMOTE_WAKEUP 0x020a -#define BT_SDP_ATTR_HID_PROFILE_VERSION 0x020b -#define BT_SDP_ATTR_HID_SUPERVISION_TIMEOUT 0x020c -#define BT_SDP_ATTR_HID_NORMALLY_CONNECTABLE 0x020d -#define BT_SDP_ATTR_HID_BOOT_DEVICE 0x020e /* * These identifiers are based on the SDP spec stating that @@ -213,8 +222,9 @@ extern "C" { #define BT_SDP_ATTR_SVCDESC_PRIMARY (0x0001 + BT_SDP_PRIMARY_LANG_BASE) #define BT_SDP_ATTR_PROVNAME_PRIMARY (0x0002 + BT_SDP_PRIMARY_LANG_BASE) -/* - * The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec) +/** + * @name The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec) + * * These are the exact data type+size descriptor values * that go into the PDU buffer. * @@ -230,40 +240,44 @@ extern "C" { * * TextString and URLString can be of size 2^{8, 16, 32} bytes * DataSequence and DataSequenceAlternates can be of size 2^{8, 16, 32} - * The size are computed post-facto in the API and are not known apriori - */ -#define BT_SDP_DATA_NIL 0x00 -#define BT_SDP_UINT8 0x08 -#define BT_SDP_UINT16 0x09 -#define BT_SDP_UINT32 0x0a -#define BT_SDP_UINT64 0x0b -#define BT_SDP_UINT128 0x0c -#define BT_SDP_INT8 0x10 -#define BT_SDP_INT16 0x11 -#define BT_SDP_INT32 0x12 -#define BT_SDP_INT64 0x13 -#define BT_SDP_INT128 0x14 -#define BT_SDP_UUID_UNSPEC 0x18 -#define BT_SDP_UUID16 0x19 -#define BT_SDP_UUID32 0x1a -#define BT_SDP_UUID128 0x1c -#define BT_SDP_TEXT_STR_UNSPEC 0x20 -#define BT_SDP_TEXT_STR8 0x25 -#define BT_SDP_TEXT_STR16 0x26 -#define BT_SDP_TEXT_STR32 0x27 -#define BT_SDP_BOOL 0x28 -#define BT_SDP_SEQ_UNSPEC 0x30 -#define BT_SDP_SEQ8 0x35 -#define BT_SDP_SEQ16 0x36 -#define BT_SDP_SEQ32 0x37 -#define BT_SDP_ALT_UNSPEC 0x38 -#define BT_SDP_ALT8 0x3d -#define BT_SDP_ALT16 0x3e -#define BT_SDP_ALT32 0x3f -#define BT_SDP_URL_STR_UNSPEC 0x40 -#define BT_SDP_URL_STR8 0x45 -#define BT_SDP_URL_STR16 0x46 -#define BT_SDP_URL_STR32 0x47 + * The size are computed post-facto in the API and are not known apriori. + * @{ + */ +#define BT_SDP_DATA_NIL 0x00 /**< Nil, the null type */ +#define BT_SDP_UINT8 0x08 /**< Unsigned 8-bit integer */ +#define BT_SDP_UINT16 0x09 /**< Unsigned 16-bit integer */ +#define BT_SDP_UINT32 0x0a /**< Unsigned 32-bit integer */ +#define BT_SDP_UINT64 0x0b /**< Unsigned 64-bit integer */ +#define BT_SDP_UINT128 0x0c /**< Unsigned 128-bit integer */ +#define BT_SDP_INT8 0x10 /**< Signed 8-bit integer */ +#define BT_SDP_INT16 0x11 /**< Signed 16-bit integer */ +#define BT_SDP_INT32 0x12 /**< Signed 32-bit integer */ +#define BT_SDP_INT64 0x13 /**< Signed 64-bit integer */ +#define BT_SDP_INT128 0x14 /**< Signed 128-bit integer */ +#define BT_SDP_UUID_UNSPEC 0x18 /**< UUID, unspecified size */ +#define BT_SDP_UUID16 0x19 /**< UUID, 16-bit */ +#define BT_SDP_UUID32 0x1a /**< UUID, 32-bit */ +#define BT_SDP_UUID128 0x1c /**< UUID, 128-bit */ +#define BT_SDP_TEXT_STR_UNSPEC 0x20 /**< Text string, unspecified size */ +#define BT_SDP_TEXT_STR8 0x25 /**< Text string, 8-bit length */ +#define BT_SDP_TEXT_STR16 0x26 /**< Text string, 16-bit length */ +#define BT_SDP_TEXT_STR32 0x27 /**< Text string, 32-bit length */ +#define BT_SDP_BOOL 0x28 /**< Boolean */ +#define BT_SDP_SEQ_UNSPEC 0x30 /**< Data element sequence, unspecified size */ +#define BT_SDP_SEQ8 0x35 /**< Data element sequence, 8-bit length */ +#define BT_SDP_SEQ16 0x36 /**< Data element sequence, 16-bit length */ +#define BT_SDP_SEQ32 0x37 /**< Data element sequence, 32-bit length */ +#define BT_SDP_ALT_UNSPEC 0x38 /**< Data element alternative, unspecified size */ +#define BT_SDP_ALT8 0x3d /**< Data element alternative, 8-bit length */ +#define BT_SDP_ALT16 0x3e /**< Data element alternative, 16-bit length */ +#define BT_SDP_ALT32 0x3f /**< Data element alternative, 32-bit length */ +#define BT_SDP_URL_STR_UNSPEC 0x40 /**< URL string, unspecified size */ +#define BT_SDP_URL_STR8 0x45 /**< URL string, 8-bit length */ +#define BT_SDP_URL_STR16 0x46 /**< URL string, 16-bit length */ +#define BT_SDP_URL_STR32 0x47 /**< URL string, 32-bit length */ +/** + * @} + */ #define BT_SDP_TYPE_DESC_MASK 0xf8 #define BT_SDP_SIZE_DESC_MASK 0x07 @@ -271,25 +285,25 @@ extern "C" { /** @brief SDP Generic Data Element Value. */ struct bt_sdp_data_elem { - uint8_t type; - uint32_t data_size; - uint32_t total_size; + uint8_t type; /**< Type of the data element */ + uint32_t data_size; /**< Size of the data element */ + uint32_t total_size; /**< Total size of the data element */ const void *data; }; /** @brief SDP Attribute Value. */ struct bt_sdp_attribute { - uint16_t id; /* Attribute ID */ - struct bt_sdp_data_elem val; /* Attribute data */ + uint16_t id; /**< Attribute ID */ + struct bt_sdp_data_elem val; /**< Attribute data */ }; /** @brief SDP Service Record Value. */ struct bt_sdp_record { - uint32_t handle; /* Redundant, for quick ref */ - struct bt_sdp_attribute *attrs; /* Base addr of attr array */ - size_t attr_count; /* Number of attributes */ - uint8_t index; /* Index of the record in LL */ - struct bt_sdp_record *next; + uint32_t handle; /**< Redundant, for quick ref */ + struct bt_sdp_attribute *attrs; /**< Base addr of attr array */ + size_t attr_count; /**< Number of attributes */ + uint8_t index; /**< Index of the record in LL */ + struct bt_sdp_record *next; /**< Next service record */ }; /* @@ -463,11 +477,11 @@ int bt_sdp_register_service(struct bt_sdp_record *service); /** @brief Generic SDP Client Query Result data holder */ struct bt_sdp_client_result { - /* buffer containing unparsed SDP record result for given UUID */ + /** buffer containing unparsed SDP record result for given UUID */ struct net_buf *resp_buf; - /* flag pointing that there are more result chunks for given UUID */ + /** flag pointing that there are more result chunks for given UUID */ bool next_record_hint; - /* Reference to UUID object on behalf one discovery was started */ + /** Reference to UUID object on behalf one discovery was started */ const struct bt_uuid *uuid; }; From e5d07588aea3aeff6ac188ad03a059890bf05bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 14:06:57 +0200 Subject: [PATCH 1737/2042] drivers: sdhc: doc: Document sdhc_host_caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Doxygen comments for SD Host controller capability flags. Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/sdhc.h | 74 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/include/zephyr/drivers/sdhc.h b/include/zephyr/drivers/sdhc.h index 3143424b4b3c..78529af2f4b0 100644 --- a/include/zephyr/drivers/sdhc.h +++ b/include/zephyr/drivers/sdhc.h @@ -159,43 +159,43 @@ enum sd_voltage { * driver, using the @ref sdhc_get_host_props api. */ struct sdhc_host_caps { - unsigned int timeout_clk_freq: 5; - unsigned int _rsvd_6: 1; - unsigned int timeout_clk_unit: 1; - unsigned int sd_base_clk: 8; - unsigned int max_blk_len: 2; - unsigned int bus_8_bit_support: 1; - unsigned int bus_4_bit_support: 1; - unsigned int adma_2_support: 1; - unsigned int _rsvd_20: 1; - unsigned int high_spd_support: 1; - unsigned int sdma_support: 1; - unsigned int suspend_res_support: 1; - unsigned int vol_330_support: 1; - unsigned int vol_300_support: 1; - unsigned int vol_180_support: 1; - unsigned int address_64_bit_support_v4: 1; - unsigned int address_64_bit_support_v3: 1; - unsigned int sdio_async_interrupt_support: 1; - unsigned int slot_type: 2; - unsigned int sdr50_support: 1; - unsigned int sdr104_support: 1; - unsigned int ddr50_support: 1; - unsigned int uhs_2_support: 1; - unsigned int drv_type_a_support: 1; - unsigned int drv_type_c_support: 1; - unsigned int drv_type_d_support: 1; - unsigned int _rsvd_39: 1; - unsigned int retune_timer_count: 4; - unsigned int sdr50_needs_tuning: 1; - unsigned int retuning_mode: 2; - unsigned int clk_multiplier: 8; - unsigned int _rsvd_56: 3; - unsigned int adma3_support: 1; - unsigned int vdd2_180_support: 1; - unsigned int _rsvd_61: 3; - unsigned int hs200_support: 1; - unsigned int hs400_support: 1; + unsigned int timeout_clk_freq: 5; /**< Timeout clock frequency */ + unsigned int _rsvd_6: 1; /**< Reserved */ + unsigned int timeout_clk_unit: 1; /**< Timeout clock unit */ + unsigned int sd_base_clk: 8; /**< SD base clock frequency */ + unsigned int max_blk_len: 2; /**< Max block length */ + unsigned int bus_8_bit_support: 1; /**< 8-bit Support for embedded device */ + unsigned int bus_4_bit_support: 1; /**< 4 bit bus support */ + unsigned int adma_2_support: 1; /**< ADMA2 support */ + unsigned int _rsvd_20: 1; /**< Reserved */ + unsigned int high_spd_support: 1; /**< High speed support */ + unsigned int sdma_support: 1; /**< SDMA support */ + unsigned int suspend_res_support: 1; /**< Suspend/Resume support */ + unsigned int vol_330_support: 1; /**< Voltage support 3.3V */ + unsigned int vol_300_support: 1; /**< Voltage support 3.0V */ + unsigned int vol_180_support: 1; /**< Voltage support 1.8V */ + unsigned int address_64_bit_support_v4: 1; /**< 64-bit system address support for V4 */ + unsigned int address_64_bit_support_v3: 1; /**< 64-bit system address support for V3 */ + unsigned int sdio_async_interrupt_support: 1; /**< Asynchronous interrupt support */ + unsigned int slot_type: 2; /**< Slot type */ + unsigned int sdr50_support: 1; /**< SDR50 support */ + unsigned int sdr104_support: 1; /**< SDR104 support */ + unsigned int ddr50_support: 1; /**< DDR50 support */ + unsigned int uhs_2_support: 1; /**< UHS-II support */ + unsigned int drv_type_a_support: 1; /**< Driver type A support */ + unsigned int drv_type_c_support: 1; /**< Driver type C support */ + unsigned int drv_type_d_support: 1; /**< Driver type D support */ + unsigned int _rsvd_39: 1; /**< Reserved */ + unsigned int retune_timer_count: 4; /**< Timer count for re-tuning */ + unsigned int sdr50_needs_tuning: 1; /**< Use tuning for SDR50 */ + unsigned int retuning_mode: 2; /**< Re-tuning mode */ + unsigned int clk_multiplier: 8; /**< Clock multiplier */ + unsigned int _rsvd_56: 3; /**< Reserved */ + unsigned int adma3_support: 1; /**< ADMA3 support */ + unsigned int vdd2_180_support: 1; /**< 1.8V VDD2 support */ + unsigned int _rsvd_61: 3; /**< Reserved */ + unsigned int hs200_support: 1; /**< HS200 support */ + unsigned int hs400_support: 1; /**< HS400 support */ }; /** From d37954249043428bf1c0b07a26e80e17edb551d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 18:19:59 +0200 Subject: [PATCH 1738/2042] bluetooth: iso: doc: Doxygen cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added several missing brief descriptions and documented some of the fields guarded by Kconfig options. Signed-off-by: Benjamin Cabé --- include/zephyr/bluetooth/iso.h | 62 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index c26652a029ac..c5ebd5d7176c 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -12,8 +12,8 @@ #define ZEPHYR_INCLUDE_BLUETOOTH_ISO_H_ /** - * @brief ISO - * @defgroup bt_iso ISO + * @brief Isochronous channels (ISO) + * @defgroup bt_iso Isochronous channels (ISO) * @ingroup bluetooth * @{ */ @@ -110,11 +110,14 @@ enum bt_iso_state { }; +/** + * @brief ISO Channel Type. + */ enum bt_iso_chan_type { - BT_ISO_CHAN_TYPE_NONE, - BT_ISO_CHAN_TYPE_CONNECTED, - BT_ISO_CHAN_TYPE_BROADCASTER, - BT_ISO_CHAN_TYPE_SYNC_RECEIVER + BT_ISO_CHAN_TYPE_NONE, /**< No channel type */ + BT_ISO_CHAN_TYPE_CONNECTED, /**< Connected */ + BT_ISO_CHAN_TYPE_BROADCASTER, /**< Isochronous broadcaster */ + BT_ISO_CHAN_TYPE_SYNC_RECEIVER /**< Synchronized receiver */ }; /** @brief ISO Channel structure. */ @@ -125,14 +128,17 @@ struct bt_iso_chan { struct bt_iso_chan_ops *ops; /** Channel QoS reference */ struct bt_iso_chan_qos *qos; + /** Channel state */ enum bt_iso_state state; -#if defined(CONFIG_BT_SMP) +#if defined(CONFIG_BT_SMP) || defined(__DOXYGEN__) /** @brief The required security level of the channel * * This value can be set as the central before connecting a CIS * with bt_iso_chan_connect(). * The value is overwritten to @ref bt_iso_server::sec_level for the * peripheral once a channel has been accepted. + * + * Only available when @kconfig{CONFIG_BT_SMP} is enabled. */ bt_security_t required_sec_level; #endif /* CONFIG_BT_SMP */ @@ -249,6 +255,7 @@ struct bt_iso_tx_info { /** Opaque type representing an Connected Isochronous Group (CIG). */ struct bt_iso_cig; +/** @brief Connected Isochronous Group (CIG) parameters */ struct bt_iso_cig_param { /** @brief Array of pointers to CIS channels */ struct bt_iso_chan **cis_channels; @@ -295,17 +302,19 @@ struct bt_iso_cig_param { uint8_t framing; }; +/** ISO connection parameters structure */ struct bt_iso_connect_param { - /* The ISO channel to connect */ + /** The ISO channel to connect */ struct bt_iso_chan *iso_chan; - /* The ACL connection */ + /** The ACL connection */ struct bt_conn *acl; }; -/** Opaque type representing an Broadcast Isochronous Group (BIG). */ +/** Opaque type representing a Broadcast Isochronous Group (BIG). */ struct bt_iso_big; +/** @brief Broadcast Isochronous Group (BIG) creation parameters */ struct bt_iso_big_create_param { /** Array of pointers to BIS channels */ struct bt_iso_chan **bis_channels; @@ -360,6 +369,7 @@ struct bt_iso_big_create_param { uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; }; +/** @brief Broadcast Isochronous Group (BIG) Sync Parameters */ struct bt_iso_big_sync_param { /** Array of pointers to BIS channels */ struct bt_iso_chan **bis_channels; @@ -414,6 +424,7 @@ struct bt_iso_big_sync_param { uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; }; +/** @brief Broadcast Isochronous Group (BIG) information */ struct bt_iso_biginfo { /** Address of the advertiser */ const bt_addr_le_t *addr; @@ -517,6 +528,7 @@ struct bt_iso_chan_ops { void (*sent)(struct bt_iso_chan *chan); }; +/** @brief ISO Accept Info Structure */ struct bt_iso_accept_info { /** The ACL connection that is requesting authorization */ struct bt_conn *acl; @@ -536,8 +548,10 @@ struct bt_iso_accept_info { /** @brief ISO Server structure. */ struct bt_iso_server { -#if defined(CONFIG_BT_SMP) - /** Required minimum security level */ +#if defined(CONFIG_BT_SMP) || defined(__DOXYGEN__) + /** Required minimum security level. + * Only available when @kconfig{CONFIG_BT_SMP} is enabled. + */ bt_security_t sec_level; #endif /* CONFIG_BT_SMP */ @@ -703,6 +717,7 @@ int bt_iso_chan_disconnect(struct bt_iso_chan *chan); int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, uint16_t seq_num, uint32_t ts); +/** @brief ISO Unicast TX Info Structure */ struct bt_iso_unicast_tx_info { /** The transport latency in us */ uint32_t latency; @@ -720,6 +735,7 @@ struct bt_iso_unicast_tx_info { uint8_t bn; }; +/** @brief ISO Unicast Info Structure */ struct bt_iso_unicast_info { /** The maximum time in us for all PDUs of all CIS in a CIG event */ uint32_t cig_sync_delay; @@ -730,10 +746,11 @@ struct bt_iso_unicast_info { /** @brief TX information for the central to peripheral data path */ struct bt_iso_unicast_tx_info central; - /** TX information for the peripheral to central data */ + /** TX information for the peripheral to central data */ struct bt_iso_unicast_tx_info peripheral; }; +/** @brief ISO Broadcaster Info Structure */ struct bt_iso_broadcaster_info { /** The maximum time in us for all PDUs of all BIS in a BIG event */ uint32_t sync_delay; @@ -757,6 +774,7 @@ struct bt_iso_broadcaster_info { uint8_t irc; }; +/** @brief ISO Synchronized Receiver Info Structure */ struct bt_iso_sync_receiver_info { /** The transport latency in us */ uint32_t latency; @@ -803,16 +821,22 @@ struct bt_iso_info { /** Connection Type specific Info.*/ union { -#if defined(CONFIG_BT_ISO_UNICAST) - /** Unicast specific Info. */ +#if defined(CONFIG_BT_ISO_UNICAST) || defined(__DOXYGEN__) + /** Unicast specific Info. + * Only available when @kconfig{CONFIG_BT_ISO_UNICAST} is enabled. + */ struct bt_iso_unicast_info unicast; #endif /* CONFIG_BT_ISO_UNICAST */ -#if defined(CONFIG_BT_ISO_BROADCASTER) - /** Broadcaster specific Info. */ +#if defined(CONFIG_BT_ISO_BROADCASTER) || defined(__DOXYGEN__) + /** Broadcaster specific Info. + * Only available when @kconfig{CONFIG_BT_ISO_BROADCASTER} is enabled. + */ struct bt_iso_broadcaster_info broadcaster; #endif /* CONFIG_BT_ISO_BROADCASTER */ -#if defined(CONFIG_BT_ISO_SYNC_RECEIVER) - /** Sync receiver specific Info. */ +#if defined(CONFIG_BT_ISO_SYNC_RECEIVER) || defined(__DOXYGEN__) + /** Sync receiver specific Info. + * Only available when @kconfig{CONFIG_BT_ISO_SYNC_RECEIVER} is enabled. + */ struct bt_iso_sync_receiver_info sync_receiver; #endif /* CONFIG_BT_ISO_SYNC_RECEIVER */ }; From 0a8bbbda4aacae94a249ea49949ed9e546ed09b5 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Fri, 21 Jul 2023 18:14:10 +0200 Subject: [PATCH 1739/2042] Bluetooth: adv: add USE_NRPA advertising option Allows the application to force the use of an NRPA. This is applied regardless of any other roles running (ie scanner) or advertising type. Signed-off-by: Jonathan Rico Co-authored-by: Aleksander Wasaznik --- include/zephyr/bluetooth/bluetooth.h | 14 ++++++++++++++ subsys/bluetooth/host/adv.c | 7 +++++-- subsys/bluetooth/host/id.c | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index 78291949c5be..6f3aeb967753 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -685,6 +685,20 @@ enum { * @note Requires @ref BT_LE_ADV_OPT_USE_NAME */ BT_LE_ADV_OPT_FORCE_NAME_IN_AD = BIT(18), + + /** + * @brief Advertise using a Non-Resolvable Private Address. + * + * A new NRPA is set when updating the advertising parameters. + * + * This is an advanced feature; most users will want to enable + * @kconfig{CONFIG_BT_EXT_ADV} instead. + * + * @note Not implemented when @kconfig{CONFIG_BT_PRIVACY}. + * + * @note Mutually exclusive with BT_LE_ADV_OPT_USE_IDENTITY. + */ + BT_LE_ADV_OPT_USE_NRPA = BIT(19), }; /** LE Advertising Parameters. */ diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 613bf62fa146..6e1311173fbb 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -1130,6 +1130,8 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, cp = net_buf_add(buf, sizeof(*cp)); (void)memset(cp, 0, sizeof(*cp)); + adv->options = param->options; + err = bt_id_set_adv_own_addr(adv, param->options, dir_adv, &cp->own_addr_type); if (err) { @@ -1151,8 +1153,6 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, cp->filter_policy = get_filter_policy(param->options); cp->tx_power = BT_HCI_LE_ADV_TX_POWER_NO_PREF; - adv->options = param->options; - cp->prim_adv_phy = BT_HCI_LE_PHY_1M; if ((param->options & BT_LE_ADV_OPT_EXT_ADV) && !(param->options & BT_LE_ADV_OPT_NO_2M)) { @@ -2206,6 +2206,9 @@ void bt_hci_le_adv_set_terminated(struct net_buf *buf) bt_addr_copy(&conn->le.resp_addr.a, &adv->random_addr.a); } + } else if (adv->options & BT_LE_ADV_OPT_USE_NRPA) { + bt_addr_le_copy(&conn->le.resp_addr, + &adv->random_addr); } else { bt_addr_le_copy(&conn->le.resp_addr, &bt_dev.id_addr[conn->id]); diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index a7a29a14d215..4bbc5e23192a 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -329,6 +329,16 @@ int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) return -EINVAL; } + if (IS_ENABLED(CONFIG_BT_PRIVACY) && + (adv->options & BT_LE_ADV_OPT_USE_NRPA)) { + /* The host doesn't support setting NRPAs when BT_PRIVACY=y. + * In that case you probably want to use an RPA anyway. + */ + LOG_ERR("NRPA not supported when BT_PRIVACY=y"); + + return -ENOSYS; + } + if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { return bt_id_set_private_addr(adv->id); @@ -1754,6 +1764,23 @@ int bt_id_set_adv_own_addr(struct bt_le_ext_adv *adv, uint32_t options, /* Set which local identity address we're advertising with */ id_addr = &bt_dev.id_addr[adv->id]; + /* Short-circuit to force NRPA usage */ + if (options & BT_LE_ADV_OPT_USE_NRPA) { + if (options & BT_LE_ADV_OPT_USE_IDENTITY) { + LOG_ERR("Can't set both IDENTITY & NRPA"); + + return -EINVAL; + } + + err = bt_id_set_adv_private_addr(adv); + if (err) { + return err; + } + *own_addr_type = BT_ADDR_LE_RANDOM; + + return 0; + } + if (options & BT_LE_ADV_OPT_CONNECTABLE) { if (dir_adv && (options & BT_LE_ADV_OPT_DIR_ADDR_RPA) && !BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { From 7483e43f0cecc126457dc1885339f69aff181cc2 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 5 Jul 2023 15:10:32 +0200 Subject: [PATCH 1740/2042] devicetree: Add 'zephyr,memory-attr' and DT helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'zephyr,memory-region-mpu' property was addede gqas a convenient way to create and configure MPU regions using information coming from DT. It has been used a lot since it was introduced so I guess we can consider it a Zephyr success story ™ . Unfortunately it has been proved to be a bit limited and with some important limitations: 1. It was introduced as a property of the compatible zephyr,memory-region that is used to create linker regions and sections from DT data. This means that we can actually create MPU regions only for DT-defined regions and sections. 2. The naming is unfortunate because it is implying that it is used only for MPU. 3. It is misplaced being in include/zephyr/linker/devicetree_regions.h and still it has nothing to do with the linker at all. 4. It is exporting a function called LINKER_DT_REGION_MPU that again has nothing to do with the linker. Point (1) is also particularly limiting because it is preventing us to characterize memory regions that are not generated using the 'zephyr,memory-region' compatible, like generic mmio-sram regions. While we fix all the issues, we also want to extend a bit the range of usefulness of this property. We are renaming it 'zephyr,memory-attr' and it is now carrying information about the type of memory the property is attached to (cacheable, non-cacheable, IO, eXecutable, etc...). The user can use this property and the DT API coming with it to act on the memory node it is accompanied by. We are still providing the DT_MEMORY_ATTR_APPLY() macro that can be used to create the MPU regions as before, but we are adding also a DT_MEMORY_ATTR_FOREACH_NODE() macro that can be used to cycle through the memory nodes and act on those. Signed-off-by: Carlo Caione --- doc/build/dts/api/api.rst | 9 ++ dts/bindings/base/zephyr,memory-attr.yaml | 20 +++ dts/bindings/test/vnd,memory-attr.yaml | 8 ++ include/zephyr/devicetree.h | 1 + include/zephyr/devicetree/memory-attr.h | 163 ++++++++++++++++++++++ tests/lib/devicetree/api/app.overlay | 13 ++ tests/lib/devicetree/api/src/main.c | 64 +++++++++ 7 files changed, 278 insertions(+) create mode 100644 dts/bindings/base/zephyr,memory-attr.yaml create mode 100644 dts/bindings/test/vnd,memory-attr.yaml create mode 100644 include/zephyr/devicetree/memory-attr.h diff --git a/doc/build/dts/api/api.rst b/doc/build/dts/api/api.rst index 7d802838041d..f3a8c2bcb0de 100644 --- a/doc/build/dts/api/api.rst +++ b/doc/build/dts/api/api.rst @@ -294,6 +294,15 @@ and properties related to them. .. doxygengroup:: devicetree-mbox +.. _devicetree-memory-attr-api: + +Memory attributes +================= + +These conveniences may be used for nodes with a memory attribute property. + +.. doxygengroup:: devicetree-memory-attr + .. _devicetree-pinctrl-api: Pinctrl (pin control) diff --git a/dts/bindings/base/zephyr,memory-attr.yaml b/dts/bindings/base/zephyr,memory-attr.yaml new file mode 100644 index 000000000000..e3c19b9b2888 --- /dev/null +++ b/dts/bindings/base/zephyr,memory-attr.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023, Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +include: [base.yaml] + +properties: + zephyr,memory-attr: + type: string + enum: + - "RAM" + - "RAM_NOCACHE" + - "FLASH" + - "PPB" + - "IO" + - "EXTMEM" + description: | + Attribute for the memory region. + + reg: + required: true diff --git a/dts/bindings/test/vnd,memory-attr.yaml b/dts/bindings/test/vnd,memory-attr.yaml new file mode 100644 index 000000000000..0303d255c547 --- /dev/null +++ b/dts/bindings/test/vnd,memory-attr.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Linaro Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: Test memory and memory attributes + +compatible: "vnd,memory-attr" + +include: [base.yaml, "zephyr,memory-attr.yaml"] diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 94ab5b8d3ada..ff0ecb0a33f5 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -4286,5 +4286,6 @@ #include #include #include +#include #endif /* DEVICETREE_H */ diff --git a/include/zephyr/devicetree/memory-attr.h b/include/zephyr/devicetree/memory-attr.h new file mode 100644 index 000000000000..65fcfe0ca506 --- /dev/null +++ b/include/zephyr/devicetree/memory-attr.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_MEMORY_ATTR_H_ +#define ZEPHYR_INCLUDE_MEMORY_ATTR_H_ + +#include +#include +#include + +/** + * @file + * @brief Memory-attr helpers + */ + +/** + * @defgroup devicetree-memory-attr Memory attributes + * @ingroup devicetree + * @{ + */ + +/** @cond INTERNAL_HIDDEN */ + +#define _DT_MEM_ATTR zephyr_memory_attr +#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR) + +#define _UNPACK(node_id, fn) \ + fn(COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region), \ + (LINKER_DT_NODE_REGION_NAME(node_id)), \ + (DT_NODE_FULL_NAME(node_id))), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + _DT_ATTR(DT_STRING_TOKEN(node_id, _DT_MEM_ATTR))), + +#define _APPLY(node_id, fn) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \ + (_UNPACK(node_id, fn)), \ + ()) + + +#define _FILTER(node_id, fn) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \ + (fn(node_id)), \ + ()) + +/** @endcond */ + +/** + * @brief Invokes @p fn for every node in the tree with property + * `zephyr,memory-attr` + * + * The macro @p fn must take one parameter, which will be a node identifier + * with the `zephyr,memory-attr` property. The macro is expanded once for each + * node in the tree. The order that nodes are visited in is not specified. + * + * @param fn macro to invoke + */ +#define DT_MEMORY_ATTR_FOREACH_NODE(fn) \ + DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn) + +/** + * @brief Invokes @p fn for MPU/MMU regions generation from the device tree + * nodes with `zephyr,memory-attr` property. + * + * Helper macro to invoke a @p fn macro on all the memory regions declared + * using the `zephyr,memory-attr` property + * + * The macro @p fn must take the form: + * + * @code{.c} + * #define MPU_FN(name, base, size, attr) ... + * @endcode + * + * The @p name, @p base and @p size parameters are retrieved from the DT node. + * When the `zephyr,memory-region` property is present in the node, the @p name + * parameter is retrived from there, otherwise the full node name is used. + * + * The `zephyr,memory-attr` enum property is passed as an extended token + * to the @p fn macro using the @p attr parameter in the form of a macro + * REGION_{attr}_ATTR. + * + * The following enums are supported for the `zephyr,memory-attr` property (see + * `zephyr,memory-attr.yaml` for a complete list): + * + * - RAM + * - RAM_NOCACHE + * - FLASH + * - PPB + * - IO + * - EXTMEM + * + * This means that usually the user code would provide some macros or defines + * with the same name of the extended property, that is: + * + * - REGION_RAM_ATTR + * - REGION_RAM_NOCACHE_ATTR + * - REGION_FLASH_ATTR + * - REGION_PPB_ATTR + * - REGION_IO_ATTR + * - REGION_EXTMEM_ATTR + * + * Example devicetree fragment: + * + * @code{.dts} + * / { + * soc { + * res0: memory@20000000 { + * reg = <0x20000000 0x4000>; + * zephyr,memory-region = "MY_NAME"; + * zephyr,memory-attr = "RAM_NOCACHE"; + * }; + * + * res1: memory@30000000 { + * reg = <0x30000000 0x2000>; + * zephyr,memory-attr = "RAM"; + * }; + + * }; + * }; + * @endcode + * + * Example usage: + * + * @code{.c} + * #define REGION_RAM_NOCACHE_ATTR 0xAAAA + * #define REGION_RAM_ATTR 0xBBBB + * #define REGION_FLASH_ATTR 0xCCCC + * + * #define MPU_FN(p_name, p_base, p_size, p_attr) \ + * { \ + * .name = p_name, \ + * .base = p_base, \ + * .size = p_size, \ + * .attr = p_attr, \ + * } + * + * static const struct arm_mpu_region mpu_regions[] = { + * DT_MEMORY_ATTR_APPLY(MPU_FN) + * }; + * @endcode + * + * This expands to: + * + * @code{.c} + * static const struct arm_mpu_region mpu_regions[] = { + * { "MY_NAME", 0x20000000, 0x4000, 0xAAAA }, + * { "memory@30000000", 0x30000000, 0x2000, 0xBBBB }, + * }; + * @endcode + * + * @param fn macro to invoke + */ +#define DT_MEMORY_ATTR_APPLY(fn) \ + DT_FOREACH_STATUS_OKAY_NODE_VARGS(_APPLY, fn) + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_MEMORY_ATTR_H_ */ diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 03fd7765570d..446fcfc20296 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -636,6 +636,19 @@ compatible = "vnd,string-array-unquoted"; val = "XA XPLUS XB", "XC XPLUS XD", "XA XMINUS XB", "XC XMINUS XD"; }; + + test_mem_ram: memory@aabbccdd { + compatible = "vnd,memory-attr"; + reg = < 0xaabbccdd 0x4000 >; + zephyr,memory-attr = "RAM"; + }; + + test_mem_ram_nocache: memory@44332211 { + compatible = "vnd,memory-attr"; + reg = < 0x44332211 0x2000 >; + zephyr,memory-attr = "RAM_NOCACHE"; + }; + }; test_64 { diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index eb96de5a81db..adeee59bf1f2 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -2667,6 +2667,70 @@ ZTEST(devicetree_api, test_mbox) DT_NODELABEL(test_mbox_zero_cell)), ""); } +ZTEST(devicetree_api, test_memory_attr) +{ + #define REGION_RAM_ATTR (0xDEDE) + #define REGION_RAM_NOCACHE_ATTR (0xCACA) + + #define TEST_FUNC(p_name, p_base, p_size, p_attr) \ + { .name = (p_name), \ + .base = (p_base), \ + .size = (p_size), \ + .attr = (p_attr), \ + } + + struct vnd_memory_binding { + char *name; + uintptr_t base; + size_t size; + unsigned int attr; + }; + + struct vnd_memory_binding val_apply[] = { + DT_MEMORY_ATTR_APPLY(TEST_FUNC) + }; + + zassert_true(!strcmp(val_apply[0].name, "memory@aabbccdd"), ""); + zassert_equal(val_apply[0].base, 0xaabbccdd, ""); + zassert_equal(val_apply[0].size, 0x4000, ""); + zassert_equal(val_apply[0].attr, 0xDEDE, ""); + + zassert_true(!strcmp(val_apply[1].name, "memory@44332211"), ""); + zassert_equal(val_apply[1].base, 0x44332211, ""); + zassert_equal(val_apply[1].size, 0x2000, ""); + zassert_equal(val_apply[1].attr, 0xCACA, ""); + + #undef TEST_FUNC + #undef REGION_RAM_ATTR + #undef REGION_RAM_NOCACHE_ATTR + + #define TEST_FUNC(node_id) DT_NODE_FULL_NAME(node_id), + + static const char * const val_func[] = { + DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC) + }; + + zassert_true(!strcmp(val_func[0], "memory@aabbccdd"), ""); + zassert_true(!strcmp(val_func[1], "memory@44332211"), ""); + + #undef TEST_FUNC + + #define TEST_FUNC(node_id) \ + COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, \ + zephyr_memory_attr, \ + RAM_NOCACHE), \ + (DT_REG_ADDR(node_id)), \ + ()) + + uintptr_t val_filt[] = { + DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC) + }; + + zassert_equal(val_filt[0], 0x44332211, ""); + + #undef TEST_FUNC +} + ZTEST(devicetree_api, test_string_token) { #undef DT_DRV_COMPAT From 15e84cbfac44d3a6313aa3e690751dfca2e02792 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 5 Jul 2023 16:10:31 +0200 Subject: [PATCH 1741/2042] dts: Move to 'zephyr,memory-attr' Move to 'zephyr,memory-attr' and use the newly introduced helpers. Signed-off-by: Carlo Caione --- .../arduino_giga_r1/arduino_giga_r1_m7.dts | 2 +- .../arm/stm32f746g_disco/stm32f746g_disco.dts | 2 +- boards/arm/stm32f7508_dk/stm32f7508_dk.dts | 2 +- .../arm/stm32f769i_disco/stm32f769i_disco.dts | 2 +- .../stm32h747i_disco/stm32h747i_disco_m7.dts | 2 +- boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts | 2 +- .../fvp_baser_aemv8r/fvp_baser_aemv8r.dts | 2 +- doc/hardware/arch/arm_cortex_m.rst | 18 ++- drivers/adc/adc_stm32.c | 6 +- drivers/dma/dma_stm32_bdma.c | 6 +- dts/arm/nxp/nxp_lpc55S1x_common.dtsi | 2 +- dts/arm/nxp/nxp_lpc55S2x_common.dtsi | 2 +- dts/arm/nxp/nxp_lpc55S6x_common.dtsi | 2 +- dts/arm/nxp/nxp_rt5xx_common.dtsi | 2 +- dts/arm/nxp/nxp_rt6xx_common.dtsi | 2 +- dts/arm/st/f7/stm32f7.dtsi | 2 +- dts/arm/st/h7/stm32h7.dtsi | 2 +- dts/bindings/base/zephyr,memory-region.yaml | 16 +-- include/zephyr/linker/devicetree_regions.h | 114 ------------------ .../openamp/boards/mimxrt1160_evk_cm7.overlay | 2 +- .../openamp/boards/mimxrt1170_evk_cm7.overlay | 2 +- .../boards/mimxrt1170_evkb_cm7.overlay | 2 +- .../remote/boards/mimxrt1160_evk_cm4.overlay | 2 +- .../remote/boards/mimxrt1170_evk_cm4.overlay | 2 +- .../remote/boards/mimxrt1170_evkb_cm4.overlay | 2 +- soc/arm/common/cortex_m/arm_mpu_regions.c | 4 +- soc/arm/nxp_s32/s32k/mpu_regions.c | 2 +- soc/arm/st_stm32/stm32h7/mpu_regions.c | 3 +- soc/arm64/arm/fvp_aemv8r/arm_mpu_regions.c | 4 +- .../arm_mpu_regions/boards/mps2_an385.overlay | 6 +- .../adc/adc_dma/boards/nucleo_h743zi.overlay | 2 +- .../boards/nucleo_h743zi.overlay | 2 +- .../boards/nucleo_h743zi.overlay | 2 +- .../boards/mps2_an521.overlay | 6 +- .../boards/qemu_cortex_a53.overlay | 6 +- .../mem_heap/shared_multi_heap/src/main.c | 4 +- 36 files changed, 55 insertions(+), 186 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 ed693b6e337d..f456227f96f5 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts @@ -29,7 +29,7 @@ device_type = "memory"; reg = <0xc0000000 DT_SIZE_M(8)>; zephyr,memory-region = "SDRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; aliases { diff --git a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts index 93054659df2f..6981ed726e9e 100644 --- a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts +++ b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts @@ -45,7 +45,7 @@ device_type = "memory"; reg = <0xc0000000 DT_SIZE_M(16)>; zephyr,memory-region = "SDRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; aliases { diff --git a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts index c91bc664d7e0..4cc8b7754a72 100644 --- a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts +++ b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts @@ -46,7 +46,7 @@ device_type = "memory"; reg = <0xc0000000 DT_SIZE_M(16)>; zephyr,memory-region = "SDRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; aliases { diff --git a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts index 26dfa4c6c31b..f857d8e48f50 100644 --- a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts +++ b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts @@ -28,7 +28,7 @@ device_type = "memory"; reg = <0xc0000000 DT_SIZE_M(16)>; zephyr,memory-region = "SDRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; leds { diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts index 6104a7c17659..918c61b99784 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts @@ -27,7 +27,7 @@ device_type = "memory"; reg = <0xd0000000 DT_SIZE_M(32)>; zephyr,memory-region = "SDRAM2"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; leds { diff --git a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts index c5102e8a0806..c6c61180281b 100644 --- a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts +++ b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts @@ -48,7 +48,7 @@ device_type = "memory"; reg = <0xd0000000 DT_SIZE_M(16)>; zephyr,memory-region = "SDRAM2"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; transceiver0: can-phy0 { diff --git a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r.dts b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r.dts index 86b95839506b..80d45f513510 100644 --- a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r.dts +++ b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r.dts @@ -41,7 +41,7 @@ compatible = "zephyr,memory-region", "mmio-dram"; reg = <0x80000000 DT_SIZE_M(2048)>; zephyr,memory-region = "DEVICE_REGION"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; }; diff --git a/doc/hardware/arch/arm_cortex_m.rst b/doc/hardware/arch/arm_cortex_m.rst index 15369212cf26..1e70b10cc8c9 100644 --- a/doc/hardware/arch/arm_cortex_m.rst +++ b/doc/hardware/arch/arm_cortex_m.rst @@ -440,9 +440,8 @@ are programmed during system boot. SRAM. (An exception to this setting is when :kconfig:option:`CONFIG_MPU_GAP_FILLING` is disabled (Arm v8-M only); in that case no SRAM MPU programming is done so the access is determined by the default Arm memory map policies, allowing for privileged-only RWX permissions on SRAM). -* All the memory regions defined in the devicetree with the compatible - :dtcompatible:`zephyr,memory-region` and at least the property - ``zephyr,memory-region-mpu`` defining the MPU permissions for the memory region. +* All the memory regions defined in the devicetree with the property + ``zephyr,memory-attr`` defining the MPU permissions for the memory region. See the next section for more details. The above MPU regions are defined in :file:`soc/arm/common/cortex_m/arm_mpu_regions.c`. @@ -453,13 +452,12 @@ configure its own fixed MPU regions in the SoC definition. Fixed MPU regions defined in devicetree --------------------------------------- -The user can define memory regions to be allocated and created in the linker -script using nodes with the :dtcompatible:`zephyr,memory-region` devicetree -compatible. When the property ``zephyr,memory-region-mpu`` is present in such -a node, a new MPU region will be allocated and programmed during system -boot. +When the property ``zephyr,memory-attr`` is present in a memory node, a new MPU +region will be allocated and programmed during system boot. When used with the +:dtcompatible:`zephyr,memory-region` devicetree compatible, it will result in a +linker section being generated associated to that MPU region. -The property ``zephyr,memory-region-mpu`` is a string carrying the attributes +The property ``zephyr,memory-attr`` is a string carrying the attributes for the MPU region. It is converted to a C token for use defining the attributes of the MPU region. @@ -471,7 +469,7 @@ For example, to define a new non-cacheable memory region in devicetree: compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20300000 0x100000>; zephyr,memory-region = "SRAM_NO_CACHE"; - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; This will automatically create a new MPU entry in diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index fbd9c1169c09..ebcea337077d 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -251,7 +251,7 @@ static int adc_stm32_dma_start(const struct device *dev, * The entire buffer must be in a single region. * An example of how the SRAM region can be defined in the DTS: * &sram4 { - * zephyr,memory-region-mpu = "RAM_NOCACHE"; + * zephyr,memory-attr = "RAM_NOCACHE"; * }; */ static bool address_in_non_cacheable_sram(const uint16_t *buffer, const uint16_t size) @@ -259,12 +259,12 @@ static bool address_in_non_cacheable_sram(const uint16_t *buffer, const uint16_t /* Default if no valid SRAM region found or buffer+size not located in a single region */ bool cachable = false; #define IS_NON_CACHEABLE_REGION_FN(node_id) \ - COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_mpu), ({ \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_attr), ({ \ const uint32_t region_start = DT_REG_ADDR(node_id); \ const uint32_t region_end = region_start + DT_REG_SIZE(node_id); \ if (((uint32_t)buffer >= region_start) && \ (((uint32_t)buffer + size) < region_end)) { \ - cachable = strcmp(DT_PROP(node_id, zephyr_memory_region_mpu), \ + cachable = strcmp(DT_PROP(node_id, zephyr_memory_attr), \ "RAM_NOCACHE") == 0; \ } \ }), \ diff --git a/drivers/dma/dma_stm32_bdma.c b/drivers/dma/dma_stm32_bdma.c index 8312f73dd642..797ed9ed794c 100644 --- a/drivers/dma/dma_stm32_bdma.c +++ b/drivers/dma/dma_stm32_bdma.c @@ -809,11 +809,11 @@ static int bdma_stm32_init(const struct device *dev) * This check verifies that the non-cachable flag is set in the DTS. * For example: * &sram4 { - * zephyr,memory-region-mpu = "RAM_NOCACHE"; + * zephyr,memory-attr = "RAM_NOCACHE"; * }; */ -#if DT_NODE_HAS_PROP(DT_NODELABEL(sram4), zephyr_memory_region_mpu) - if (strcmp(DT_PROP(DT_NODELABEL(sram4), zephyr_memory_region_mpu), "RAM_NOCACHE") != 0) { +#if DT_NODE_HAS_PROP(DT_NODELABEL(sram4), zephyr_memory_attr) + if (strcmp(DT_PROP(DT_NODELABEL(sram4), zephyr_memory_attr), "RAM_NOCACHE") != 0) { LOG_ERR("SRAM4 is not set as non-cachable."); return -EIO; } diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 26cdbd50c99d..bbd71e2afa1f 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -61,7 +61,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20010000 DT_SIZE_K(16)>; zephyr,memory-region = "USB_SRAM"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 1098449163fe..1e9222f5d07b 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -75,7 +75,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x40100000 DT_SIZE_K(16)>; zephyr,memory-region = "USB_SRAM"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index f4ccfde8b2b2..1a727654e1a5 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -95,7 +95,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x100000 DT_SIZE_K(16)>; zephyr,memory-region = "USB_SRAM"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; syscon: syscon@0 { diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 6040ba3f47a3..5a84e929f877 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -84,7 +84,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x40140000 DT_SIZE_K(16)>; zephyr,memory-region = "SRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 3629772d746d..abef67f81cf1 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -62,7 +62,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x40140000 DT_SIZE_K(16)>; zephyr,memory-region = "SRAM1"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index ea585fadbd1d..4519c6d65a90 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -47,7 +47,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x90000000 DT_SIZE_M(256)>; zephyr,memory-region = "QSPI"; - zephyr,memory-region-mpu = "EXTMEM"; + zephyr,memory-attr = "EXTMEM"; }; clocks { diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index febaf76bca11..d8688fa2a260 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -48,7 +48,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x90000000 DT_SIZE_M(256)>; zephyr,memory-region = "QSPI"; - zephyr,memory-region-mpu = "EXTMEM"; + zephyr,memory-attr = "EXTMEM"; }; clocks { diff --git a/dts/bindings/base/zephyr,memory-region.yaml b/dts/bindings/base/zephyr,memory-region.yaml index f9db04e2d31e..60308af7173a 100644 --- a/dts/bindings/base/zephyr,memory-region.yaml +++ b/dts/bindings/base/zephyr,memory-region.yaml @@ -5,7 +5,7 @@ description: Compatible for devices resulting in linker memory regions compatible: "zephyr,memory-region" -include: base.yaml +include: [base.yaml, "zephyr,memory-attr.yaml"] properties: zephyr,memory-region: @@ -16,17 +16,3 @@ properties: memory region in the final executable. The region address and size is taken from the property, while the name is the value of this property. - - zephyr,memory-region-mpu: - type: string - enum: - - "RAM" - - "RAM_NOCACHE" - - "FLASH" - - "PPB" - - "IO" - - "EXTMEM" - description: | - Signify that this node should result in a dedicated MPU region. The - region address and size are taken from the property, while the MPU - attribute is the value of this property. diff --git a/include/zephyr/linker/devicetree_regions.h b/include/zephyr/linker/devicetree_regions.h index 1e37a3f22c28..d60d3f9d7b17 100644 --- a/include/zephyr/linker/devicetree_regions.h +++ b/include/zephyr/linker/devicetree_regions.h @@ -92,8 +92,6 @@ #define _DT_SECTION_SIZE(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size) #define _DT_SECTION_LOAD(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start) -#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR) - /** * @brief Declare a memory region * @@ -162,35 +160,6 @@ _DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id); \ _DT_SECTION_LOAD(node_id) = LOADADDR(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)); -/** - * Call the user-provided MPU_FN() macro passing the expected arguments - */ -#define _EXPAND_MPU_FN(node_id, MPU_FN, ...) \ - MPU_FN(LINKER_DT_NODE_REGION_NAME(node_id), \ - DT_REG_ADDR(node_id), \ - DT_REG_SIZE(node_id), \ - _DT_ATTR(DT_STRING_TOKEN(node_id, zephyr_memory_region_mpu))), - -/** - * Check that the node_id has both properties: - * - zephyr,memory-region-mpu - * - zephyr,memory-region - * - * and call the EXPAND_MPU_FN() macro - */ -#define _CHECK_ATTR_FN(node_id, EXPAND_MPU_FN, ...) \ - COND_CODE_1(UTIL_AND(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_mpu), \ - DT_NODE_HAS_PROP(node_id, zephyr_memory_region)), \ - (EXPAND_MPU_FN(node_id, __VA_ARGS__)), \ - ()) - -/** - * Call _CHECK_ATTR_FN() for each enabled node passing EXPAND_MPU_FN() as - * explicit argument and the user-provided MPU_FN() macro in __VA_ARGS__ - */ -#define _CHECK_APPLY_FN(compat, EXPAND_MPU_FN, ...) \ - DT_FOREACH_STATUS_OKAY_VARGS(compat, _CHECK_ATTR_FN, EXPAND_MPU_FN, __VA_ARGS__) - /** @endcond */ /** @@ -211,87 +180,4 @@ #define LINKER_DT_SECTIONS() \ DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE) -/** - * @brief Generate MPU regions from the device tree nodes with compatible - * 'zephyr,memory-region' and 'zephyr,memory-region-mpu' attribute. - * - * Helper macro to apply an MPU_FN macro to all the memory regions declared - * using the 'zephyr,memory-region-mpu' property and the 'zephyr,memory-region' - * compatible. - * - * @p MPU_FN must take the form: - * - * @code{.c} - * #define MPU_FN(name, base, size, attr) ... - * @endcode - * - * The 'name', 'base' and 'size' parameters are taken from the DT node. - * - * The 'zephyr,memory-region-mpu' enum property is passed as an extended token - * to the MPU_FN macro using the 'attr' parameter, in the form - * REGION_{attr}_ATTR. - * - * The following enums are supported for the 'zephyr,memory-region-mpu' - * property: - * - * - RAM - * - RAM_NOCACHE - * - FLASH - * - PPB - * - IO - * - * This means that usually the arch code would provide some macros or defines - * with the same name of the extended property, that is: - * - * - REGION_RAM_ATTR - * - REGION_RAM_NOCACHE_ATTR - * - REGION_FLASH_ATTR - * - REGION_PPB_ATTR - * - REGION_IO_ATTR - * - * Example devicetree fragment: - * - * / { - * soc { - * sram1: memory@2000000 { - * zephyr,memory-region = "MY_NAME"; - * zephyr,memory-region-mpu = "RAM_NOCACHE"; - * }; - * }; - * }; - * - * For detailed information about MPU region attribute define configuration refer - * to the specific architecture MPU header. - * For example: include/zephyr/arch/arm/aarch32/mpu/arm_mpu_v7m.h. - * - * The 'attr' parameter of the MPU_FN function will be the extended - * 'REGION_RAM_NOCACHE_ATTR' token and the arch code will be usually - * implementing a macro with the same name. - * - * Example: - * - * @code{.c} - * - * #define REGION_RAM_NOCACHE_ATTR 0xAAAA - * #define REGION_RAM_ATTR 0xBBBB - * #define REGION_FLASH_ATTR 0xCCCC - * - * #define MPU_FN(p_name, p_base, p_size, p_attr) \ - * { \ - * .name = p_name, \ - * .base = p_base, \ - * .size = p_size, \ - * .attr = p_attr, \ - * } - * - * static const struct arm_mpu_region mpu_regions[] = { - * ... - * LINKER_DT_REGION_MPU(MPU_FN) - * ... - * }; - * @endcode - * - */ -#define LINKER_DT_REGION_MPU(mpu_fn) _CHECK_APPLY_FN(_DT_COMPATIBLE, _EXPAND_MPU_FN, mpu_fn) - #endif /* ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ */ diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1160_evk_cm7.overlay b/samples/subsys/ipc/openamp/boards/mimxrt1160_evk_cm7.overlay index 467595f18e0b..52c68fd5339a 100644 --- a/samples/subsys/ipc/openamp/boards/mimxrt1160_evk_cm7.overlay +++ b/samples/subsys/ipc/openamp/boards/mimxrt1160_evk_cm7.overlay @@ -17,6 +17,6 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1170_evk_cm7.overlay b/samples/subsys/ipc/openamp/boards/mimxrt1170_evk_cm7.overlay index 467595f18e0b..52c68fd5339a 100644 --- a/samples/subsys/ipc/openamp/boards/mimxrt1170_evk_cm7.overlay +++ b/samples/subsys/ipc/openamp/boards/mimxrt1170_evk_cm7.overlay @@ -17,6 +17,6 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay index 39e6c6896e7f..a5d921810bbe 100644 --- a/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay +++ b/samples/subsys/ipc/openamp/boards/mimxrt1170_evkb_cm7.overlay @@ -17,6 +17,6 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay index ae2b4c56250e..fa4d29c3cd1d 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1160_evk_cm4.overlay @@ -33,7 +33,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay index ae2b4c56250e..fa4d29c3cd1d 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evk_cm4.overlay @@ -33,7 +33,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay index 9cdfe651f055..f4ee15de7edd 100644 --- a/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay +++ b/samples/subsys/ipc/openamp/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -33,7 +33,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x202c0000 DT_SIZE_K(16)>; zephyr,memory-region="OCRAM2_OVERLAY"; - zephyr,memory-region-mpu = "IO"; + zephyr,memory-attr = "IO"; }; }; diff --git a/soc/arm/common/cortex_m/arm_mpu_regions.c b/soc/arm/common/cortex_m/arm_mpu_regions.c index 477dc30566c7..512cd4441cd3 100644 --- a/soc/arm/common/cortex_m/arm_mpu_regions.c +++ b/soc/arm/common/cortex_m/arm_mpu_regions.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "arm_mpu_mem_cfg.h" @@ -31,7 +31,7 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* DT-defined regions */ - LINKER_DT_REGION_MPU(ARM_MPU_REGION_INIT) + DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT) }; const struct arm_mpu_config mpu_config = { diff --git a/soc/arm/nxp_s32/s32k/mpu_regions.c b/soc/arm/nxp_s32/s32k/mpu_regions.c index 86060308eacb..cc52e0be30e7 100644 --- a/soc/arm/nxp_s32/s32k/mpu_regions.c +++ b/soc/arm/nxp_s32/s32k/mpu_regions.c @@ -37,7 +37,7 @@ static struct arm_mpu_region mpu_regions[] = { #endif /* DT-defined regions */ - LINKER_DT_REGION_MPU(ARM_MPU_REGION_INIT) + DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT) }; const struct arm_mpu_config mpu_config = { diff --git a/soc/arm/st_stm32/stm32h7/mpu_regions.c b/soc/arm/st_stm32/stm32h7/mpu_regions.c index 03a43a20d241..e253d70c7aef 100644 --- a/soc/arm/st_stm32/stm32h7/mpu_regions.c +++ b/soc/arm/st_stm32/stm32h7/mpu_regions.c @@ -5,7 +5,6 @@ */ #include -#include #include "../../common/cortex_m/arm_mpu_mem_cfg.h" static const struct arm_mpu_region mpu_regions[] = { @@ -32,7 +31,7 @@ static const struct arm_mpu_region mpu_regions[] = { #endif /* DT-defined regions */ - LINKER_DT_REGION_MPU(ARM_MPU_REGION_INIT) + DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT) }; const struct arm_mpu_config mpu_config = { diff --git a/soc/arm64/arm/fvp_aemv8r/arm_mpu_regions.c b/soc/arm64/arm/fvp_aemv8r/arm_mpu_regions.c index ab261e2e45db..65400c672692 100644 --- a/soc/arm64/arm/fvp_aemv8r/arm_mpu_regions.c +++ b/soc/arm64/arm/fvp_aemv8r/arm_mpu_regions.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include static const struct arm_mpu_region mpu_regions[] = { @@ -41,7 +41,7 @@ static const struct arm_mpu_region mpu_regions[] = { REGION_RAM_ATTR), /* Extra regions defined in device tree */ - LINKER_DT_REGION_MPU(MPU_REGION_ENTRY_FROM_DTS) + DT_MEMORY_ATTR_APPLY(MPU_REGION_ENTRY_FROM_DTS) }; const struct arm_mpu_config mpu_config = { diff --git a/tests/arch/arm/arm_mpu_regions/boards/mps2_an385.overlay b/tests/arch/arm/arm_mpu_regions/boards/mps2_an385.overlay index e882e13075d1..4c9f1a5d5a8d 100644 --- a/tests/arch/arm/arm_mpu_regions/boards/mps2_an385.overlay +++ b/tests/arch/arm/arm_mpu_regions/boards/mps2_an385.overlay @@ -16,21 +16,21 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20200000 0x100000>; zephyr,memory-region = "SRAM_CACHE"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; sram_no_cache: memory@20300000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20300000 0x100000>; zephyr,memory-region = "SRAM_NO_CACHE"; - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; sram_dtcm_fake: memory@abcdabcd { compatible = "zephyr,memory-region", "arm,dtcm"; reg = <0xabcdabcd 0x100000>; zephyr,memory-region = "SRAM_DTCM_FAKE"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; sram_no_mpu: memory@deaddead { diff --git a/tests/drivers/adc/adc_dma/boards/nucleo_h743zi.overlay b/tests/drivers/adc/adc_dma/boards/nucleo_h743zi.overlay index af004e793710..22590af7af4b 100644 --- a/tests/drivers/adc/adc_dma/boards/nucleo_h743zi.overlay +++ b/tests/drivers/adc/adc_dma/boards/nucleo_h743zi.overlay @@ -22,7 +22,7 @@ /* ADC driver expects a buffer in a non-cachable memory region */ &sram4 { - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; &dma1 { 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 2114d8959bd3..20c8062f325e 100644 --- a/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay +++ b/tests/drivers/dma/chan_blen_transfer/boards/nucleo_h743zi.overlay @@ -18,7 +18,7 @@ test_dma0: &dmamux1 { * to be non-cachable. */ &sram4 { - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; &bdma1 { diff --git a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.overlay b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.overlay index 2114d8959bd3..20c8062f325e 100644 --- a/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.overlay +++ b/tests/drivers/dma/loop_transfer/boards/nucleo_h743zi.overlay @@ -18,7 +18,7 @@ test_dma0: &dmamux1 { * to be non-cachable. */ &sram4 { - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; &bdma1 { diff --git a/tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay b/tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay index 81e572475e23..c52183dfe81b 100644 --- a/tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay +++ b/tests/kernel/mem_heap/shared_multi_heap/boards/mps2_an521.overlay @@ -17,20 +17,20 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x38100000 0x1000>; zephyr,memory-region = "RES0"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; res1: memory@38200000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x38200000 0x2000>; zephyr,memory-region = "RES1"; - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; res2: memory@38300000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x38300000 0x3000>; zephyr,memory-region = "RES2"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; diff --git a/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay b/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay index 90b0aeca8ac0..a4ec256ad171 100644 --- a/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay +++ b/tests/kernel/mem_heap/shared_multi_heap/boards/qemu_cortex_a53.overlay @@ -10,14 +10,14 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x0 0x42000000 0x0 0x1000>; zephyr,memory-region = "RES0"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; res1: memory@43000000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x0 0x43000000 0x0 0x2000>; zephyr,memory-region = "RES1"; - zephyr,memory-region-mpu = "RAM_NOCACHE"; + zephyr,memory-attr = "RAM_NOCACHE"; }; res_no_mpu: memory@45000000 { @@ -30,7 +30,7 @@ compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x0 0x44000000 0x0 0x3000>; zephyr,memory-region = "RES2"; - zephyr,memory-region-mpu = "RAM"; + zephyr,memory-attr = "RAM"; }; }; }; diff --git a/tests/kernel/mem_heap/shared_multi_heap/src/main.c b/tests/kernel/mem_heap/shared_multi_heap/src/main.c index 17dc081f06e0..c99264430bc3 100644 --- a/tests/kernel/mem_heap/shared_multi_heap/src/main.c +++ b/tests/kernel/mem_heap/shared_multi_heap/src/main.c @@ -27,7 +27,7 @@ struct region_map { .region = { \ .addr = (uintptr_t) DT_INST_REG_ADDR(n), \ .size = DT_INST_REG_SIZE(n), \ - .attr = DT_INST_ENUM_IDX_OR(n, zephyr_memory_region_mpu, \ + .attr = DT_INST_ENUM_IDX_OR(n, zephyr_memory_attr, \ SMH_REG_ATTR_NUM), \ }, \ }, @@ -103,7 +103,7 @@ static void fill_multi_heap(void) for (size_t idx = 0; idx < DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT); idx++) { reg_map = &map[idx]; - /* zephyr,memory-region-mpu property not found. Skip it. */ + /* zephyr,memory-attr property not found. Skip it. */ if (reg_map->region.attr == SMH_REG_ATTR_NUM) { continue; } From aab07357b7f7c1d34670ec7a2467ee3d50aa56c4 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Fri, 7 Jul 2023 15:32:56 +0200 Subject: [PATCH 1742/2042] doc: release: Add DT changes Add DT changes to the 3.5 release notes. Signed-off-by: Carlo Caione --- doc/releases/release-notes-3.5.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index ea22236df2a4..fbfbdbc11eb8 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -262,6 +262,14 @@ USB Devicetree ********** +* ``zephyr,memory-region-mpu`` was renamed ``zephyr,memory-attr`` + +* The following macros were added: + :c:macro:`DT_FOREACH_NODE_VARGS`, + :c:macro:`DT_FOREACH_STATUS_OKAY_NODE_VARGS` + :c:macro:`DT_MEMORY_ATTR_FOREACH_NODE` + :c:macro:`DT_MEMORY_ATTR_APPLY` + Libraries / Subsystems ********************** From 305423ccb81821c83a616933d4d96a303ca2abbe Mon Sep 17 00:00:00 2001 From: Kacper Dalach Date: Fri, 21 Jul 2023 08:32:24 +0200 Subject: [PATCH 1743/2042] drivers: clock_control: stm32h5: Add MCO configuration STM32H5 series lacked support for MCO configuration. Added SOC_SERIES_STM32H5X to approperiate kconfig MCO source configurations. Added new MCO sources from H5 series and updated the clock_stm32_ll_h5.c with MCO configuration. Signed-off-by: Kacper Dalach --- drivers/clock_control/Kconfig.stm32 | 40 +++++++++++++++-------- drivers/clock_control/clock_stm32_ll_h5.c | 4 +++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index 03a53a1cdbcb..8d7890d1fdf8 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -66,7 +66,8 @@ config CLOCK_STM32_MCO1_SRC_LSE depends on SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ SOC_SERIES_STM32L4X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use LSE as source of MCO1 @@ -76,7 +77,8 @@ config CLOCK_STM32_MCO1_SRC_HSE SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ SOC_SERIES_STM32L4X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use HSE as source of MCO1 @@ -97,7 +99,8 @@ config CLOCK_STM32_MCO1_SRC_HSI depends on SOC_SERIES_STM32F1X || \ SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use HSI as source of MCO1 @@ -110,7 +113,8 @@ config CLOCK_STM32_MCO1_SRC_HSI16 config CLOCK_STM32_MCO1_SRC_HSI48 bool "HSI48" depends on SOC_SERIES_STM32L4X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use HSI48 as source of MCO1 @@ -122,7 +126,8 @@ config CLOCK_STM32_MCO1_SRC_PLLCLK config CLOCK_STM32_MCO1_SRC_PLLQCLK bool "PLLQ" - depends on SOC_SERIES_STM32H7X + depends on SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use PLLQ as source of MCO1 @@ -163,11 +168,12 @@ config CLOCK_STM32_MCO1_DIV SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ SOC_SERIES_STM32L4X || \ - SOC_SERIES_STM32H7X \ + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X \ ) default 1 range 1 5 if SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X - range 1 15 if SOC_SERIES_STM32H7X + range 1 15 if SOC_SERIES_STM32H7X || SOC_SERIES_STM32H5X range 1 16 if SOC_SERIES_STM32L4X help Prescaler for MCO1 output clock @@ -185,7 +191,8 @@ config CLOCK_STM32_MCO2_SRC_SYSCLK bool "SYSCLK" depends on SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use SYSCLK as source of MCO2 @@ -199,19 +206,22 @@ config CLOCK_STM32_MCO2_SRC_HSE bool "HSE" depends on SOC_SERIES_STM32F4X || \ SOC_SERIES_STM32F7X || \ - SOC_SERIES_STM32H7X + SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use HSE as source of MCO2 config CLOCK_STM32_MCO2_SRC_LSI bool "LSI" - depends on SOC_SERIES_STM32H7X + depends on SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use LSI as source of MCO2 config CLOCK_STM32_MCO2_SRC_CSI bool "CSI" - depends on SOC_SERIES_STM32H7X + depends on SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use CSI as source of MCO2 @@ -223,13 +233,15 @@ config CLOCK_STM32_MCO2_SRC_PLLCLK config CLOCK_STM32_MCO2_SRC_PLLPCLK bool "PLLPCLK" - depends on SOC_SERIES_STM32H7X + depends on SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use PLLPCLK as source of MC02 config CLOCK_STM32_MCO2_SRC_PLL2PCLK bool "PLL2PCLK" - depends on SOC_SERIES_STM32H7X + depends on SOC_SERIES_STM32H7X || \ + SOC_SERIES_STM32H5X help Use PLL2PCLK as source of MC02 endchoice @@ -243,7 +255,7 @@ config CLOCK_STM32_MCO2_DIV ) default 1 range 1 5 if SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X - range 1 15 if SOC_SERIES_STM32H7X + range 1 15 if SOC_SERIES_STM32H7X || SOC_SERIES_STM32H5X help Prescaler for MCO2 output clock diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index ebb2766f4e0a..a5a6a055f440 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -18,6 +18,7 @@ #include #include #include +#include "clock_stm32_ll_mco.h" /* Macros to fill up prescaler values */ #define z_hsi_divider(v) LL_RCC_HSI_DIV_ ## v @@ -752,6 +753,9 @@ int stm32_clock_control_init(const struct device *dev) /* Update CMSIS variable */ SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; + /* configure MCO1/MCO2 based on Kconfig */ + stm32_clock_control_mco_init(); + return 0; } From 1d56b8e2aaba9fb0783b576ba2ca08e1b1c68a18 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Sun, 16 Jul 2023 19:29:40 +0200 Subject: [PATCH 1744/2042] input: convert cap1203 from kscan Convert the CAP1203 driver to the input subsystem, add to build_all tests. Signed-off-by: Fabian Blatz --- drivers/input/CMakeLists.txt | 1 + drivers/input/Kconfig | 1 + drivers/{kscan => input}/Kconfig.cap1203 | 12 +- .../kscan_cap1203.c => input/input_cap1203.c} | 115 ++++++------------ drivers/kscan/CMakeLists.txt | 1 - drivers/kscan/Kconfig | 1 - dts/bindings/kscan/microchip,cap1203.yaml | 2 +- tests/drivers/build_all/input/app.overlay | 6 + 8 files changed, 51 insertions(+), 88 deletions(-) rename drivers/{kscan => input}/Kconfig.cap1203 (75%) rename drivers/{kscan/kscan_cap1203.c => input/input_cap1203.c} (71%) diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 0f47dd493391..51b25155911b 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) +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_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2be3cfcf6390..3aa5271bf4ee 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -5,6 +5,7 @@ if INPUT menu "Input drivers" +source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_keys" diff --git a/drivers/kscan/Kconfig.cap1203 b/drivers/input/Kconfig.cap1203 similarity index 75% rename from drivers/kscan/Kconfig.cap1203 rename to drivers/input/Kconfig.cap1203 index 2d184050ea76..28a87b6c7045 100644 --- a/drivers/kscan/Kconfig.cap1203 +++ b/drivers/input/Kconfig.cap1203 @@ -1,7 +1,7 @@ # Copyright (c) 2022 Keiya Nobuta # SPDX-License-Identifier: Apache-2.0 -menuconfig KSCAN_CAP1203 +menuconfig INPUT_CAP1203 bool "CAP1203 3-cannel capacitive touch sensor driver" default y depends on DT_HAS_MICROCHIP_CAP1203_ENABLED @@ -10,18 +10,18 @@ menuconfig KSCAN_CAP1203 Enable driver for microchip CAP1203 3-cannel capacitive touch sensor. -if KSCAN_CAP1203 +if INPUT_CAP1203 -config KSCAN_CAP1203_POLL +config INPUT_CAP1203_POLL bool "Polling" help Enable polling mode when interrupt GPIO is not specified. -config KSCAN_CAP1203_PERIOD +config INPUT_CAP1203_PERIOD int "Sample period" - depends on KSCAN_CAP1203_POLL + depends on INPUT_CAP1203_POLL default 10 help Sample period in milliseconds when in polling mode. -endif # KSCAN_CAP1203 +endif # INPUT_CAP1203 diff --git a/drivers/kscan/kscan_cap1203.c b/drivers/input/input_cap1203.c similarity index 71% rename from drivers/kscan/kscan_cap1203.c rename to drivers/input/input_cap1203.c index 798193769cb3..9524b12f56df 100644 --- a/drivers/kscan/kscan_cap1203.c +++ b/drivers/input/input_cap1203.c @@ -6,12 +6,12 @@ #define DT_DRV_COMPAT microchip_cap1203 -#include #include #include +#include #include -LOG_MODULE_REGISTER(cap1203, CONFIG_KSCAN_LOG_LEVEL); +LOG_MODULE_REGISTER(cap1203, CONFIG_INPUT_LOG_LEVEL); #define REG_MAIN_CONTROL 0x0 #define CONTROL_INT 0x1 @@ -28,12 +28,11 @@ struct cap1203_config { }; struct cap1203_data { - struct device *dev; - kscan_callback_t callback; + const struct device *dev; struct k_work work; /* Interrupt GPIO callback. */ struct gpio_callback int_gpio_cb; -#ifdef CONFIG_KSCAN_CAP1203_POLL +#ifdef CONFIG_INPUT_CAP1203_POLL /* Timer (polling mode). */ struct k_timer timer; #endif @@ -96,7 +95,13 @@ static int cap1203_process(const struct device *dev) return r; } - data->callback(dev, 0, col, pressed); + if (pressed) { + input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER); + input_report_abs(dev, INPUT_ABS_Y, 0, false, K_FOREVER); + input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER); + } else { + input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); + } return 0; } @@ -116,7 +121,7 @@ static void cap1203_isr_handler(const struct device *dev, k_work_submit(&data->work); } -#ifdef CONFIG_KSCAN_CAP1203_POLL +#ifdef CONFIG_INPUT_CAP1203_POLL static void cap1203_timer_handler(struct k_timer *timer) { struct cap1203_data *data = CONTAINER_OF(timer, struct cap1203_data, timer); @@ -125,69 +130,6 @@ static void cap1203_timer_handler(struct k_timer *timer) } #endif -static int cap1203_configure(const struct device *dev, - kscan_callback_t callback) -{ - struct cap1203_data *data = dev->data; - const struct cap1203_config *config = dev->config; - - data->callback = callback; - - if (config->int_gpio.port != NULL) { - int r; - - /* Clear pending interrupt */ - r = cap1203_clear_interrupt(&config->i2c); - if (r < 0) { - LOG_ERR("Could not clear interrupt"); - return r; - } - - r = cap1203_enable_interrupt(&config->i2c, true); - if (r < 0) { - LOG_ERR("Could not configure interrupt"); - return r; - } - } - - return 0; -} - -static int cap1203_enable_callback(const struct device *dev) -{ - struct cap1203_data *data = dev->data; - - const struct cap1203_config *config = dev->config; - - if (config->int_gpio.port != NULL) { - gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); - } -#ifdef CONFIG_KSCAN_CAP1203_POLL - else { - k_timer_start(&data->timer, K_MSEC(CONFIG_KSCAN_CAP1203_PERIOD), - K_MSEC(CONFIG_KSCAN_CAP1203_PERIOD)); - } -#endif - return 0; -} - -static int cap1203_disable_callback(const struct device *dev) -{ - struct cap1203_data *data = dev->data; - - const struct cap1203_config *config = dev->config; - - if (config->int_gpio.port != NULL) { - gpio_remove_callback(config->int_gpio.port, &data->int_gpio_cb); - } -#ifdef CONFIG_KSCAN_CAP1203_POLL - else { - k_timer_stop(&data->timer); - } -#endif - return 0; -} - static int cap1203_init(const struct device *dev) { const struct cap1203_config *config = dev->config; @@ -224,8 +166,26 @@ static int cap1203_init(const struct device *dev) gpio_init_callback(&data->int_gpio_cb, cap1203_isr_handler, BIT(config->int_gpio.pin)); + + r = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb); + if (r < 0) { + LOG_ERR("Could not set gpio callback"); + return r; + } + + r = cap1203_clear_interrupt(&config->i2c); + if (r < 0) { + LOG_ERR("Could not clear interrupt"); + return r; + } + + r = cap1203_enable_interrupt(&config->i2c, true); + if (r < 0) { + LOG_ERR("Could not configure interrupt"); + return r; + } } -#ifdef CONFIG_KSCAN_CAP1203_POLL +#ifdef CONFIG_INPUT_CAP1203_POLL else { k_timer_init(&data->timer, cap1203_timer_handler, NULL); @@ -234,18 +194,15 @@ static int cap1203_init(const struct device *dev) LOG_ERR("Could not configure interrupt"); return r; } + + k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_CAP1203_PERIOD), + K_MSEC(CONFIG_INPUT_CAP1203_PERIOD)); } #endif return 0; } -static const struct kscan_driver_api cap1203_driver_api = { - .config = cap1203_configure, - .enable_callback = cap1203_enable_callback, - .disable_callback = cap1203_disable_callback, -}; - #define CAP1203_INIT(index) \ static const struct cap1203_config cap1203_config_##index = { \ .i2c = I2C_DT_SPEC_INST_GET(index), \ @@ -254,7 +211,7 @@ static const struct kscan_driver_api cap1203_driver_api = { static struct cap1203_data cap1203_data_##index; \ DEVICE_DT_INST_DEFINE(index, cap1203_init, NULL, \ &cap1203_data_##index, &cap1203_config_##index, \ - POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ - &cap1203_driver_api); + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); DT_INST_FOREACH_STATUS_OKAY(CAP1203_INIT) diff --git a/drivers/kscan/CMakeLists.txt b/drivers/kscan/CMakeLists.txt index abec7d712ca6..d650f17f9171 100644 --- a/drivers/kscan/CMakeLists.txt +++ b/drivers/kscan/CMakeLists.txt @@ -7,7 +7,6 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_KSCAN_ITE_IT8XXX2 kscan_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c) -zephyr_library_sources_ifdef(CONFIG_KSCAN_CAP1203 kscan_cap1203.c) zephyr_library_sources_ifdef(CONFIG_KSCAN_INPUT kscan_input.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE kscan_handlers.c) diff --git a/drivers/kscan/Kconfig b/drivers/kscan/Kconfig index d82067901c42..02ef0987cc68 100644 --- a/drivers/kscan/Kconfig +++ b/drivers/kscan/Kconfig @@ -13,7 +13,6 @@ if KSCAN source "drivers/kscan/Kconfig.it8xxx2" source "drivers/kscan/Kconfig.xec" source "drivers/kscan/Kconfig.ht16k33" -source "drivers/kscan/Kconfig.cap1203" source "drivers/kscan/Kconfig.input" module = KSCAN diff --git a/dts/bindings/kscan/microchip,cap1203.yaml b/dts/bindings/kscan/microchip,cap1203.yaml index cfa8b0158aad..6a228041e9fa 100644 --- a/dts/bindings/kscan/microchip,cap1203.yaml +++ b/dts/bindings/kscan/microchip,cap1203.yaml @@ -5,7 +5,7 @@ description: CAP1203 3-channel capacitive touch sensor compatible: "microchip,cap1203" -include: [kscan.yaml, i2c-device.yaml] +include: i2c-device.yaml properties: int-gpios: diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index b5be8830bde5..c1d8dd273cca 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -71,6 +71,12 @@ irq-gpios = <&gpio0 0 0>; rst-gpios = <&gpio0 0 0>; }; + + cap1203@3 { + compatible = "microchip,cap1203"; + reg = <0x3>; + int-gpios = <&gpio0 0 0>; + }; }; spi@2 { From e1e4fcc70135e30e7634df80391edd77f5f3ba98 Mon Sep 17 00:00:00 2001 From: Fabian Blatz Date: Sun, 16 Jul 2023 21:24:42 +0200 Subject: [PATCH 1745/2042] input: remove cap1203 kscan-like state report Previously the driver was retrofitted to the kscan api, handling it as a input device with one row and three columns. With the move to the input subsystem each input can have its proper input code instead. Signed-off-by: Fabian Blatz --- drivers/input/input_cap1203.c | 55 +++++++++++------------ dts/bindings/kscan/microchip,cap1203.yaml | 6 +++ tests/drivers/build_all/input/app.overlay | 1 + 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/input/input_cap1203.c b/drivers/input/input_cap1203.c index 9524b12f56df..7fa157965418 100644 --- a/drivers/input/input_cap1203.c +++ b/drivers/input/input_cap1203.c @@ -19,12 +19,15 @@ LOG_MODULE_REGISTER(cap1203, CONFIG_INPUT_LOG_LEVEL); #define REG_INPUT_STATUS 0x03 #define REG_INTERRUPT_ENABLE 0x27 -#define INTERRUPT_ENABLE 0x7 -#define INTERRUPT_DISABLE 0x0 +#define INTERRUPT_ENABLE 0x7 +#define INTERRUPT_DISABLE 0x0 + +#define TOUCH_INPUT_COUNT 3 struct cap1203_config { struct i2c_dt_spec i2c; struct gpio_dt_spec int_gpio; + const uint16_t *input_codes; }; struct cap1203_data { @@ -32,6 +35,7 @@ struct cap1203_data { struct k_work work; /* Interrupt GPIO callback. */ struct gpio_callback int_gpio_cb; + uint8_t prev_input_state; #ifdef CONFIG_INPUT_CAP1203_POLL /* Timer (polling mode). */ struct k_timer timer; @@ -65,24 +69,21 @@ static int cap1203_process(const struct device *dev) struct cap1203_data *data = dev->data; int r; uint8_t input; - uint16_t col; - bool pressed; + uint8_t single_input_state; r = i2c_reg_read_byte_dt(&config->i2c, REG_INPUT_STATUS, &input); if (r < 0) { return r; } - pressed = !!input; - if (input & BIT(0)) { - col = 0; - } - if (input & BIT(1)) { - col = 1; - } - if (input & BIT(2)) { - col = 2; + for (uint8_t i = 0; i < TOUCH_INPUT_COUNT; i++) { + single_input_state = input & BIT(i); + if (single_input_state != (data->prev_input_state & BIT(i))) { + input_report_key(dev, config->input_codes[i], single_input_state, true, + K_FOREVER); + } } + data->prev_input_state = input; LOG_DBG("event: input: %d\n", input); @@ -95,14 +96,6 @@ static int cap1203_process(const struct device *dev) return r; } - if (pressed) { - input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER); - input_report_abs(dev, INPUT_ABS_Y, 0, false, K_FOREVER); - input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER); - } else { - input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER); - } - return 0; } @@ -203,15 +196,17 @@ static int cap1203_init(const struct device *dev) return 0; } -#define CAP1203_INIT(index) \ - static const struct cap1203_config cap1203_config_##index = { \ - .i2c = I2C_DT_SPEC_INST_GET(index), \ - .int_gpio = GPIO_DT_SPEC_INST_GET_OR(index, int_gpios, {0}), \ - }; \ - static struct cap1203_data cap1203_data_##index; \ - DEVICE_DT_INST_DEFINE(index, cap1203_init, NULL, \ - &cap1203_data_##index, &cap1203_config_##index, \ - POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ +#define CAP1203_INIT(index) \ + static const uint16_t cap1203_input_codes_##inst[] = DT_INST_PROP(index, input_codes); \ + BUILD_ASSERT(DT_INST_PROP_LEN(index, input_codes) == TOUCH_INPUT_COUNT); \ + static const struct cap1203_config cap1203_config_##index = { \ + .i2c = I2C_DT_SPEC_INST_GET(index), \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(index, int_gpios, {0}), \ + .input_codes = cap1203_input_codes_##inst, \ + }; \ + static struct cap1203_data cap1203_data_##index; \ + DEVICE_DT_INST_DEFINE(index, cap1203_init, NULL, &cap1203_data_##index, \ + &cap1203_config_##index, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(CAP1203_INIT) diff --git a/dts/bindings/kscan/microchip,cap1203.yaml b/dts/bindings/kscan/microchip,cap1203.yaml index 6a228041e9fa..e6c9ed1fc3ed 100644 --- a/dts/bindings/kscan/microchip,cap1203.yaml +++ b/dts/bindings/kscan/microchip,cap1203.yaml @@ -10,3 +10,9 @@ include: i2c-device.yaml properties: int-gpios: type: phandle-array + + input-codes: + type: array + required: true + description: | + Array of input event key codes (INPUT_KEY_* or INPUT_BTN_*). diff --git a/tests/drivers/build_all/input/app.overlay b/tests/drivers/build_all/input/app.overlay index c1d8dd273cca..4c41459d8a60 100644 --- a/tests/drivers/build_all/input/app.overlay +++ b/tests/drivers/build_all/input/app.overlay @@ -76,6 +76,7 @@ compatible = "microchip,cap1203"; reg = <0x3>; int-gpios = <&gpio0 0 0>; + input-codes = <0 1 2>; }; }; From fb7d40c7573717b22dbbbeee2a65e066c2d3a694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 09:57:49 +0200 Subject: [PATCH 1746/2042] drivers: i2c: nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/i2c/CMakeLists.txt | 4 +-- drivers/i2c/Kconfig.nrfx | 58 +++++++++---------------------------- drivers/i2c/i2c_nrfx_twi.c | 4 +-- drivers/i2c/i2c_nrfx_twim.c | 8 ++--- 4 files changed, 22 insertions(+), 52 deletions(-) diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 82b716ac13c7..c67805e224b5 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -26,8 +26,8 @@ zephyr_library_sources_ifdef(CONFIG_I2C_MCUX i2c_mcux.c) zephyr_library_sources_ifdef(CONFIG_I2C_MCUX_FLEXCOMM i2c_mcux_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_I2C_MCUX_LPI2C i2c_mcux_lpi2c.c) zephyr_library_sources_ifdef(CONFIG_I2C_EMUL i2c_emul.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_TWI i2c_nrfx_twi.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_TWIM i2c_nrfx_twim.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) zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIM i2c_sam4l_twim.c) diff --git a/drivers/i2c/Kconfig.nrfx b/drivers/i2c/Kconfig.nrfx index b58881496261..1be1ba5aa1a8 100644 --- a/drivers/i2c/Kconfig.nrfx +++ b/drivers/i2c/Kconfig.nrfx @@ -13,6 +13,20 @@ menuconfig I2C_NRFX if I2C_NRFX +config I2C_NRFX_TWI + def_bool y + depends on DT_HAS_NORDIC_NRF_TWI_ENABLED + select NRFX_TWI0 if HAS_HW_NRF_TWI0 + select NRFX_TWI1 if HAS_HW_NRF_TWI1 + +config I2C_NRFX_TWIM + def_bool y + depends on DT_HAS_NORDIC_NRF_TWIM_ENABLED + select NRFX_TWIM0 if HAS_HW_NRF_TWIM0 + select NRFX_TWIM1 if HAS_HW_NRF_TWIM1 + select NRFX_TWIM2 if HAS_HW_NRF_TWIM2 + select NRFX_TWIM3 if HAS_HW_NRF_TWIM3 + config I2C_NRFX_TRANSFER_TIMEOUT int "Transfer timeout [ms]" default 500 @@ -21,48 +35,4 @@ config I2C_NRFX_TRANSFER_TIMEOUT 0 means that the driver should use the K_FOREVER value, i.e. it should wait as long as necessary. -config I2C_0_NRF_TWI - def_bool HAS_HW_NRF_TWI0 - select NRFX_TWI0 - help - Enable nRF TWI Master without EasyDMA on port 0. - -config I2C_0_NRF_TWIM - def_bool HAS_HW_NRF_TWIM0 - select NRFX_TWIM0 - help - Enable nRF TWI Master with EasyDMA on port 0. - This peripheral accepts transfers from RAM only, - if provided buffer is placed in flash, transfer will fail. - -config I2C_1_NRF_TWI - def_bool HAS_HW_NRF_TWI1 - select NRFX_TWI1 - help - Enable nRF TWI Master without EasyDMA on port 1. - -config I2C_1_NRF_TWIM - def_bool HAS_HW_NRF_TWIM1 - select NRFX_TWIM1 - help - Enable nRF TWI Master with EasyDMA on port 1. - This peripheral accepts transfers from RAM only, - if provided buffer is placed in flash, transfer will fail. - -config I2C_2_NRF_TWIM - def_bool HAS_HW_NRF_TWIM2 - select NRFX_TWIM2 - help - Enable nRF TWI Master with EasyDMA on port 2. - This peripheral accepts transfers from RAM only, - if provided buffer is placed in flash, transfer will fail. - -config I2C_3_NRF_TWIM - def_bool HAS_HW_NRF_TWIM3 - select NRFX_TWIM3 - help - Enable nRF TWI Master with EasyDMA on port 3. - This peripheral accepts transfers from RAM only, - if provided buffer is placed in flash, transfer will fail. - endif # I2C_NRFX diff --git a/drivers/i2c/i2c_nrfx_twi.c b/drivers/i2c/i2c_nrfx_twi.c index e61ec5b977d8..bbb070e7e0c7 100644 --- a/drivers/i2c/i2c_nrfx_twi.c +++ b/drivers/i2c/i2c_nrfx_twi.c @@ -321,10 +321,10 @@ static int twi_nrfx_pm_action(const struct device *dev, CONFIG_I2C_INIT_PRIORITY, \ &i2c_nrfx_twi_driver_api) -#ifdef CONFIG_I2C_0_NRF_TWI +#ifdef CONFIG_HAS_HW_NRF_TWI0 I2C_NRFX_TWI_DEVICE(0); #endif -#ifdef CONFIG_I2C_1_NRF_TWI +#ifdef CONFIG_HAS_HW_NRF_TWI1 I2C_NRFX_TWI_DEVICE(1); #endif diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index 5d8c329c92ff..a24873fc6f8b 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -436,18 +436,18 @@ static int i2c_nrfx_twim_init(const struct device *dev) CONFIG_I2C_INIT_PRIORITY, \ &i2c_nrfx_twim_driver_api) -#ifdef CONFIG_I2C_0_NRF_TWIM +#ifdef CONFIG_HAS_HW_NRF_TWIM0 I2C_NRFX_TWIM_DEVICE(0); #endif -#ifdef CONFIG_I2C_1_NRF_TWIM +#ifdef CONFIG_HAS_HW_NRF_TWIM1 I2C_NRFX_TWIM_DEVICE(1); #endif -#ifdef CONFIG_I2C_2_NRF_TWIM +#ifdef CONFIG_HAS_HW_NRF_TWIM2 I2C_NRFX_TWIM_DEVICE(2); #endif -#ifdef CONFIG_I2C_3_NRF_TWIM +#ifdef CONFIG_HAS_HW_NRF_TWIM3 I2C_NRFX_TWIM_DEVICE(3); #endif From 8bc0fdaf5651a8c3ba1b2ca3b4d03ac0ab2d7cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 09:58:15 +0200 Subject: [PATCH 1747/2042] drivers: pwm_nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/pwm/pwm_nrfx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 1a671aaf731d..373f8eef7e23 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -351,18 +351,18 @@ static int pwm_nrfx_pm_action(const struct device *dev, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ &pwm_nrfx_drv_api_funcs) -#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm0), okay) +#ifdef CONFIG_HAS_HW_NRF_PWM0 PWM_NRFX_DEVICE(0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm1), okay) +#ifdef CONFIG_HAS_HW_NRF_PWM1 PWM_NRFX_DEVICE(1); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm2), okay) +#ifdef CONFIG_HAS_HW_NRF_PWM2 PWM_NRFX_DEVICE(2); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(pwm3), okay) +#ifdef CONFIG_HAS_HW_NRF_PWM3 PWM_NRFX_DEVICE(3); #endif From fa609e58449392ffd2b60e5bb9b59ef8e959762a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 09:58:43 +0200 Subject: [PATCH 1748/2042] drivers: spi: nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/spi/CMakeLists.txt | 6 +- drivers/spi/Kconfig.nrfx | 122 +++++------------------- drivers/spi/spi_nrfx_spi.c | 6 +- drivers/spi/spi_nrfx_spim.c | 16 +++- drivers/spi/spi_nrfx_spis.c | 8 +- soc/arm/nordic_nrf/nrf52/CMakeLists.txt | 8 +- 6 files changed, 48 insertions(+), 118 deletions(-) diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 91d70e8cbeff..a60bce17df79 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -16,9 +16,9 @@ zephyr_library_sources_ifdef(CONFIG_SPI_SAM spi_sam.c) zephyr_library_sources_ifdef(CONFIG_SPI_SAM0 spi_sam0.c) zephyr_library_sources_ifdef(CONFIG_SPI_SIFIVE spi_sifive.c) zephyr_library_sources_ifdef(CONFIG_SPI_RV32M1_LPSPI spi_rv32m1_lpspi.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_SPI spi_nrfx_spi.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_SPIM spi_nrfx_spim.c) -zephyr_library_sources_ifdef(CONFIG_NRFX_SPIS spi_nrfx_spis.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPI spi_nrfx_spi.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIS spi_nrfx_spis.c) zephyr_library_sources_ifdef(CONFIG_SPI_LITESPI spi_litespi.c) zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c) zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI spi_xec_qmspi.c) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index 56df44355d3c..bc287e18acaa 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -11,6 +11,30 @@ menuconfig SPI_NRFX if SPI_NRFX +config SPI_NRFX_SPI + def_bool y + depends on DT_HAS_NORDIC_NRF_SPI_ENABLED + select NRFX_SPI0 if HAS_HW_NRF_SPI0 + select NRFX_SPI1 if HAS_HW_NRF_SPI1 + select NRFX_SPI2 if HAS_HW_NRF_SPI2 + +config SPI_NRFX_SPIM + def_bool y + depends on DT_HAS_NORDIC_NRF_SPIM_ENABLED + select NRFX_SPIM0 if HAS_HW_NRF_SPIM0 + select NRFX_SPIM1 if HAS_HW_NRF_SPIM1 + select NRFX_SPIM2 if HAS_HW_NRF_SPIM2 + select NRFX_SPIM3 if HAS_HW_NRF_SPIM3 + select NRFX_SPIM4 if HAS_HW_NRF_SPIM4 + +config SPI_NRFX_SPIS + def_bool y + depends on DT_HAS_NORDIC_NRF_SPIS_ENABLED + select NRFX_SPIS0 if HAS_HW_NRF_SPIS0 + select NRFX_SPIS1 if HAS_HW_NRF_SPIS1 + select NRFX_SPIS2 if HAS_HW_NRF_SPIS2 + select NRFX_SPIS3 if HAS_HW_NRF_SPIS3 + config SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 depends on SOC_NRF52832 bool "Allow enabling the SPIM driver despite PAN 58" @@ -28,106 +52,10 @@ config SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 then nRF52832 PPI and GPIOTE resources can be saved by not enabling 'anomaly-58-workaround' via the Devicetree. -config SPI_0_NRF_SPI - def_bool HAS_HW_NRF_SPI0 - select NRFX_SPI0 - help - Enable nRF SPI Master without EasyDMA on port 0. - -config SPI_0_NRF_SPIM - def_bool HAS_HW_NRF_SPIM0 - # This driver is not available for nRF52832 because of Product Anomaly 58 - # (SPIM: An additional byte is clocked out when RXD.MAXCNT == 1 and TXD.MAXCNT <= 1) - # Allow the 'EasyDMA' driver only if this automatic safety-disable is overridden - depends on (!SOC_NRF52832 || SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) - select NRFX_SPIM0 - help - Enable nRF SPI Master with EasyDMA on port 0. - -config SPI_0_NRF_SPIS - def_bool HAS_HW_NRF_SPIS0 - depends on SPI_SLAVE - select NRFX_SPIS0 - help - Enable nRF SPI Slave with EasyDMA on port 0. - Due to hardware limitations the implementation supports only simple - buffers (consisting of one part) located in RAM. - -config SPI_1_NRF_SPI - def_bool HAS_HW_NRF_SPI1 - select NRFX_SPI1 - help - Enable nRF SPI Master without EasyDMA on port 1. - -config SPI_1_NRF_SPIM - def_bool HAS_HW_NRF_SPIM1 - # This driver is not available for nRF52832 because of Product Anomaly 58 - # (SPIM: An additional byte is clocked out when RXD.MAXCNT == 1 and TXD.MAXCNT <= 1) - # Allow the 'EasyDMA' driver only if this automatic safety-disable is overridden - depends on (!SOC_NRF52832 || SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) - select NRFX_SPIM1 - help - Enable nRF SPI Master with EasyDMA on port 1. - -config SPI_1_NRF_SPIS - def_bool HAS_HW_NRF_SPIS1 - depends on SPI_SLAVE - select NRFX_SPIS1 - help - Enable nRF SPI Slave with EasyDMA on port 1. - Due to hardware limitations the implementation supports only simple - buffers (consisting of one part) located in RAM. - -config SPI_2_NRF_SPI - def_bool HAS_HW_NRF_SPI2 - select NRFX_SPI2 - help - Enable nRF SPI Master without EasyDMA on port 2. - -config SPI_2_NRF_SPIM - def_bool HAS_HW_NRF_SPIM2 - # This driver is not available for nRF52832 because of Product Anomaly 58 - # (SPIM: An additional byte is clocked out when RXD.MAXCNT == 1 and TXD.MAXCNT <= 1) - # Allow the 'EasyDMA' driver only if this automatic safety-disable is overridden - depends on (!SOC_NRF52832 || SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) - select NRFX_SPIM2 - help - Enable nRF SPI Master with EasyDMA on port 2. - -config SPI_2_NRF_SPIS - def_bool HAS_HW_NRF_SPIS2 - depends on SPI_SLAVE - select NRFX_SPIS2 - help - Enable nRF SPI Slave with EasyDMA on port 2. - Due to hardware limitations the implementation supports only simple - buffers (consisting of one part) located in RAM. - -config SPI_3_NRF_SPIM - def_bool HAS_HW_NRF_SPIM3 - select NRFX_SPIM3 - help - Enable nRF SPI Master with EasyDMA on port 3. - -config SPI_3_NRF_SPIS - def_bool HAS_HW_NRF_SPIS3 - depends on SPI_SLAVE - select NRFX_SPIS3 - help - Enable nRF SPI Slave with EasyDMA on port 3. - Due to hardware limitations the implementation supports only simple - buffers (consisting of one part) located in RAM. - -config SPI_4_NRF_SPIM - def_bool HAS_HW_NRF_SPIM4 - select NRFX_SPIM4 - help - Enable nRF SPI Master with EasyDMA on port 4. - config SPI_NRFX_RAM_BUFFER_SIZE int "Size of RAM buffers for SPIM peripherals" default 8 - depends on NRFX_SPIM + 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 diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index 75a8745c7d97..df07bf8ef631 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -423,14 +423,14 @@ static int spi_nrfx_init(const struct device *dev) POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &spi_nrfx_driver_api) -#ifdef CONFIG_SPI_0_NRF_SPI +#ifdef CONFIG_HAS_HW_NRF_SPI0 SPI_NRFX_SPI_DEFINE(0); #endif -#ifdef CONFIG_SPI_1_NRF_SPI +#ifdef CONFIG_HAS_HW_NRF_SPI1 SPI_NRFX_SPI_DEFINE(1); #endif -#ifdef CONFIG_SPI_2_NRF_SPI +#ifdef CONFIG_HAS_HW_NRF_SPI2 SPI_NRFX_SPI_DEFINE(2); #endif diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 89a0235d9d38..d160a15e28bf 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -23,6 +23,12 @@ LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" +#if defined(CONFIG_SOC_NRF52832) && !defined(CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) +#error This driver is not available by default for nRF52832 because of Product Anomaly 58 \ + (SPIM: An additional byte is clocked out when RXD.MAXCNT == 1 and TXD.MAXCNT <= 1). \ + Use CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58=y to override this limitation. +#endif + #if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) #define SPI_BUFFER_IN_RAM 1 #endif @@ -613,22 +619,22 @@ static int spi_nrfx_init(const struct device *dev) DT_PHANDLE(SPIM(idx), memory_regions)))))), \ ()) -#ifdef CONFIG_SPI_0_NRF_SPIM +#ifdef CONFIG_HAS_HW_NRF_SPIM0 SPI_NRFX_SPIM_DEFINE(0); #endif -#ifdef CONFIG_SPI_1_NRF_SPIM +#ifdef CONFIG_HAS_HW_NRF_SPIM1 SPI_NRFX_SPIM_DEFINE(1); #endif -#ifdef CONFIG_SPI_2_NRF_SPIM +#ifdef CONFIG_HAS_HW_NRF_SPIM2 SPI_NRFX_SPIM_DEFINE(2); #endif -#ifdef CONFIG_SPI_3_NRF_SPIM +#ifdef CONFIG_HAS_HW_NRF_SPIM3 SPI_NRFX_SPIM_DEFINE(3); #endif -#ifdef CONFIG_SPI_4_NRF_SPIM +#ifdef CONFIG_HAS_HW_NRF_SPIM4 SPI_NRFX_SPIM_DEFINE(4); #endif diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index 27dcc76fbd3d..d16377a42464 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -301,18 +301,18 @@ static int spi_nrfx_init(const struct device *dev) CONFIG_SPI_INIT_PRIORITY, \ &spi_nrfx_driver_api) -#ifdef CONFIG_SPI_0_NRF_SPIS +#ifdef CONFIG_HAS_HW_NRF_SPIS0 SPI_NRFX_SPIS_DEFINE(0); #endif -#ifdef CONFIG_SPI_1_NRF_SPIS +#ifdef CONFIG_HAS_HW_NRF_SPIS1 SPI_NRFX_SPIS_DEFINE(1); #endif -#ifdef CONFIG_SPI_2_NRF_SPIS +#ifdef CONFIG_HAS_HW_NRF_SPIS2 SPI_NRFX_SPIS_DEFINE(2); #endif -#ifdef CONFIG_SPI_3_NRF_SPIS +#ifdef CONFIG_HAS_HW_NRF_SPIS3 SPI_NRFX_SPIS_DEFINE(3); #endif diff --git a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt index c795df3947b3..8d5b7440e1ea 100644 --- a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt @@ -15,10 +15,6 @@ zephyr_library_include_directories( ${ZEPHYR_BASE}/arch/arm/include ) -if(CONFIG_SOC_NRF52832) - if(CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) - if(CONFIG_SPI_0_NRF_SPIM OR CONFIG_SPI_1_NRF_SPIM OR CONFIG_SPI_2_NRF_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") - endif() - endif() +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") endif() From aa7d675935517cce0668fa12491602c321b1a0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 09:59:21 +0200 Subject: [PATCH 1749/2042] drivers: serial: nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/serial/CMakeLists.txt | 4 +- drivers/serial/Kconfig.nrfx | 75 +++++++++----------------------- drivers/serial/uart_nrfx_uarte.c | 32 +++++++------- 3 files changed, 39 insertions(+), 72 deletions(-) diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 365db9eb7423..342fb1fd09cb 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -25,8 +25,8 @@ zephyr_library_sources_ifdef(CONFIG_UART_MCUX_LPSCI uart_mcux_lpsci.c) 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_NRF_UART_PERIPHERAL uart_nrfx_uart.c) -zephyr_library_sources_ifdef(CONFIG_NRF_UARTE_PERIPHERAL uart_nrfx_uarte.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) 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 82c468839ea8..c9c9d687a004 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -17,10 +17,18 @@ menuconfig UART_NRFX if UART_NRFX +config UART_NRFX_UART + def_bool y + depends on DT_HAS_NORDIC_NRF_UART_ENABLED + +config UART_NRFX_UARTE + def_bool y + depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED + config UART_ASYNC_TX_CACHE_SIZE int "TX cache buffer size" depends on UART_ASYNC_API - depends on NRF_UARTE_PERIPHERAL + depends on UART_NRFX_UARTE default 8 help For UARTE, TX cache buffer is used when provided TX buffer is not located @@ -28,26 +36,12 @@ config UART_ASYNC_TX_CACHE_SIZE from RAM. # ----------------- port 0 ----------------- -config UART_0_NRF_UART - def_bool HAS_HW_NRF_UART0 - depends on DT_HAS_NORDIC_NRF_UART_ENABLED - select NRF_UART_PERIPHERAL - help - Enable nRF UART without EasyDMA on port 0. - -config UART_0_NRF_UARTE - def_bool HAS_HW_NRF_UARTE0 - depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED - select NRF_UARTE_PERIPHERAL - help - Enable nRF UART with EasyDMA on port 0. - -if UART_0_NRF_UART || UART_0_NRF_UARTE +if HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 config UART_0_ENHANCED_POLL_OUT bool "Efficient poll out on port 0" default y - depends on UART_0_NRF_UARTE + depends on HAS_HW_NRF_UARTE0 help When enabled, polling out does not trigger interrupt which stops TX. Feature uses a PPI channel. @@ -73,7 +67,7 @@ config UART_0_NRF_PARITY_BIT config UART_0_NRF_TX_BUFFER_SIZE int "Size of RAM buffer" - depends on UART_0_NRF_UARTE + depends on HAS_HW_NRF_UARTE0 range 1 65535 default 32 help @@ -83,7 +77,7 @@ config UART_0_NRF_TX_BUFFER_SIZE config UART_0_NRF_HW_ASYNC bool "Use hardware RX byte counting" - depends on UART_0_NRF_UARTE + depends on HAS_HW_NRF_UARTE0 depends on UART_ASYNC_API help If default driver uses interrupts to count incoming bytes, it is possible @@ -93,7 +87,7 @@ config UART_0_NRF_HW_ASYNC config UART_0_NRF_ASYNC_LOW_POWER bool "Low power mode" - depends on UART_0_NRF_UARTE + depends on HAS_HW_NRF_UARTE0 depends on UART_ASYNC_API help When enabled, UARTE is enabled before each TX or RX usage and disabled @@ -113,17 +107,10 @@ config UART_0_GPIO_MANAGEMENT their default configuration when device is powered down. The GPIOs will be configured back to correct state when UART is powered up. -endif # UART_0_NRF_UART || UART_0_NRF_UARTE +endif # HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0 # ----------------- port 1 ----------------- -config UART_1_NRF_UARTE - def_bool HAS_HW_NRF_UARTE1 - depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED - select NRF_UARTE_PERIPHERAL - help - Enable nRF UART with EasyDMA on port 1. - -if UART_1_NRF_UARTE +if HAS_HW_NRF_UARTE1 config UART_1_INTERRUPT_DRIVEN bool "Interrupt support on port 1" @@ -191,17 +178,10 @@ config UART_1_GPIO_MANAGEMENT their default configuration when device is powered down. The GPIOs will be configured back to correct state when UART is powered up. -endif # UART_1_NRF_UARTE +endif # HAS_HW_NRF_UARTE1 # ----------------- port 2 ----------------- -config UART_2_NRF_UARTE - def_bool HAS_HW_NRF_UARTE2 - depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED - select NRF_UARTE_PERIPHERAL - help - Enable nRF UART with EasyDMA on port 2. - -if UART_2_NRF_UARTE +if HAS_HW_NRF_UARTE2 config UART_2_INTERRUPT_DRIVEN bool "Interrupt support on port 2" @@ -268,17 +248,10 @@ config UART_2_GPIO_MANAGEMENT their default configuration when device is powered down. The GPIOs will be configured back to correct state when UART is powered up. -endif # UART_2_NRF_UARTE +endif # HAS_HW_NRF_UARTE2 # ----------------- port 3 ----------------- -config UART_3_NRF_UARTE - def_bool HAS_HW_NRF_UARTE3 - depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED - select NRF_UARTE_PERIPHERAL - help - Enable nRF UART with EasyDMA on port 3. - -if UART_3_NRF_UARTE +if HAS_HW_NRF_UARTE3 config UART_3_INTERRUPT_DRIVEN bool "Interrupt support on port 3" @@ -345,7 +318,7 @@ config UART_3_GPIO_MANAGEMENT their default configuration when device is powered down. The GPIOs will be configured back to correct state when UART is powered up. -endif # UART_3_NRF_UARTE +endif # HAS_HW_NRF_UARTE3 config NRFX_TIMER0 @@ -402,10 +375,4 @@ config UART_ENHANCED_POLL_OUT select NRFX_PPI if HAS_HW_NRF_PPI select NRFX_DPPI if HAS_HW_NRF_DPPIC -config NRF_UART_PERIPHERAL - bool - -config NRF_UARTE_PERIPHERAL - bool - endif # UART_NRFX diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index c2e8ede305de..bdafe6c7d4c9 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -40,28 +40,28 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #endif -#if (defined(CONFIG_UART_0_NRF_UARTE) && \ +#if (defined(CONFIG_HAS_HW_NRF_UARTE0) && \ defined(CONFIG_UART_0_INTERRUPT_DRIVEN)) || \ - (defined(CONFIG_UART_1_NRF_UARTE) && \ + (defined(CONFIG_HAS_HW_NRF_UARTE1) && \ defined(CONFIG_UART_1_INTERRUPT_DRIVEN)) || \ - (defined(CONFIG_UART_2_NRF_UARTE) && \ + (defined(CONFIG_HAS_HW_NRF_UARTE2) && \ defined(CONFIG_UART_2_INTERRUPT_DRIVEN)) || \ - (defined(CONFIG_UART_3_NRF_UARTE) && \ + (defined(CONFIG_HAS_HW_NRF_UARTE3) && \ defined(CONFIG_UART_3_INTERRUPT_DRIVEN)) #define UARTE_INTERRUPT_DRIVEN 1 #endif -#if (defined(CONFIG_UART_0_NRF_UARTE) && !defined(CONFIG_UART_0_ASYNC)) || \ - (defined(CONFIG_UART_1_NRF_UARTE) && !defined(CONFIG_UART_1_ASYNC)) || \ - (defined(CONFIG_UART_2_NRF_UARTE) && !defined(CONFIG_UART_2_ASYNC)) || \ - (defined(CONFIG_UART_3_NRF_UARTE) && !defined(CONFIG_UART_3_ASYNC)) +#if (defined(CONFIG_HAS_HW_NRF_UARTE0) && !defined(CONFIG_UART_0_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE1) && !defined(CONFIG_UART_1_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE2) && !defined(CONFIG_UART_2_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE3) && !defined(CONFIG_UART_3_ASYNC)) #define UARTE_ANY_NONE_ASYNC 1 #endif -#if (defined(CONFIG_UART_0_NRF_UARTE) && defined(CONFIG_UART_0_ASYNC)) || \ - (defined(CONFIG_UART_1_NRF_UARTE) && defined(CONFIG_UART_1_ASYNC)) || \ - (defined(CONFIG_UART_2_NRF_UARTE) && defined(CONFIG_UART_2_ASYNC)) || \ - (defined(CONFIG_UART_3_NRF_UARTE) && defined(CONFIG_UART_3_ASYNC)) +#if (defined(CONFIG_HAS_HW_NRF_UARTE0) && defined(CONFIG_UART_0_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE1) && defined(CONFIG_UART_1_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE2) && defined(CONFIG_UART_2_ASYNC)) || \ + (defined(CONFIG_HAS_HW_NRF_UARTE3) && defined(CONFIG_UART_3_ASYNC)) #define UARTE_ANY_ASYNC 1 #endif @@ -2068,18 +2068,18 @@ static int uarte_nrfx_pm_action(const struct device *dev, DT_PHANDLE(UARTE(idx), memory_regions)))))), \ ()) -#ifdef CONFIG_UART_0_NRF_UARTE +#ifdef CONFIG_HAS_HW_NRF_UARTE0 UART_NRF_UARTE_DEVICE(0); #endif -#ifdef CONFIG_UART_1_NRF_UARTE +#ifdef CONFIG_HAS_HW_NRF_UARTE1 UART_NRF_UARTE_DEVICE(1); #endif -#ifdef CONFIG_UART_2_NRF_UARTE +#ifdef CONFIG_HAS_HW_NRF_UARTE2 UART_NRF_UARTE_DEVICE(2); #endif -#ifdef CONFIG_UART_3_NRF_UARTE +#ifdef CONFIG_HAS_HW_NRF_UARTE3 UART_NRF_UARTE_DEVICE(3); #endif From f89ca1164c280ef4a5203c5a712a091f8e11690d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 09:59:51 +0200 Subject: [PATCH 1750/2042] drivers: sensor: qdec_nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/sensor/qdec_nrfx/qdec_nrfx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/qdec_nrfx/qdec_nrfx.c index 7d8f71cede20..81c3614fc050 100644 --- a/drivers/sensor/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/qdec_nrfx/qdec_nrfx.c @@ -299,10 +299,10 @@ static int qdec_nrfx_init(const struct device *dev) CONFIG_SENSOR_INIT_PRIORITY, \ &qdec_nrfx_driver_api) -#if DT_NODE_HAS_STATUS(DT_NODELABEL(qdec0), okay) +#ifdef CONFIG_HAS_HW_NRF_QDEC0 SENSOR_NRFX_QDEC_DEVICE(0); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(qdec1), okay) +#ifdef CONFIG_HAS_HW_NRF_QDEC1 SENSOR_NRFX_QDEC_DEVICE(1); #endif From 481963489e992e860d1c528a2cfe10dcb05c6889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 20 Jul 2023 10:00:13 +0200 Subject: [PATCH 1751/2042] drivers: wdt_nrfx: Clean up driver instantiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - use CONFIG_HAS_HW_NRF_* symbols consistently in nRF multi-instance drivers when creating particular driver instances - remove unnecessary hidden Kconfig options that indicated the type of peripheral to be used by a given instance (e.g. SPI, SPIM, or SPIS) and enabled proper nrfx driver instance; instead, use one option per peripheral type and include the corresponding shim driver flavor into compilation basing on that option (not the one that enables the nrfx driver as it was incorrectly done so far in some cases) Signed-off-by: Andrzej Głąbek --- drivers/watchdog/wdt_nrfx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 007ff133a176..8d61f11d6fbe 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -189,10 +189,10 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ &wdt_nrfx_driver_api) -#ifdef CONFIG_NRFX_WDT0 +#ifdef CONFIG_HAS_HW_NRF_WDT0 WDT_NRFX_WDT_DEVICE(0); #endif -#ifdef CONFIG_NRFX_WDT1 +#ifdef CONFIG_HAS_HW_NRF_WDT1 WDT_NRFX_WDT_DEVICE(1); #endif From a22f7e777b01c40025e52971bbb13ce39d1d8e1e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 24 Jul 2023 15:26:32 +0200 Subject: [PATCH 1752/2042] net: dhcpv4: Accept unicast replies Some DHCPv4 servers do not respect BROADCAST flag set on DHCP Discover, replying with unicast packet, making it impossible to obtain DHCP address by Zephyr in such cases. RFC1542 chapter 3.1.1 makes the following statement about the BROADCAST flag: This addition to the protocol is a workaround for old host implementations. Such implementations SHOULD be modified so that they may receive unicast BOOTREPLY messages, thus making use of this workaround unnecessary. In general, the use of this mechanism is discouraged. Making it clear that being able to process unicast replies from the DHCP server is not only an optional behavior, but a recommended solution. Therefore, introduce a support for unicast DHCPv4 in Zephyr. To achieve this, add additional filtering rule at the IPv4 level - in case DHCPv4 is enabled, there is an active query and the packet is destined for the DHCPv4 module, let it through for the DHCPv4 module to process, regardless of the destination IP address. Signed-off-by: Robert Lubos --- subsys/net/ip/Kconfig.ipv4 | 8 +++++++ subsys/net/ip/dhcpv4.c | 47 +++++++++++++++++++++++++++++++++++++- subsys/net/ip/dhcpv4.h | 33 +++++++++++++++++++++++--- subsys/net/ip/ipv4.c | 4 +++- 4 files changed, 87 insertions(+), 5 deletions(-) diff --git a/subsys/net/ip/Kconfig.ipv4 b/subsys/net/ip/Kconfig.ipv4 index a16e025a9482..a5e073051de8 100644 --- a/subsys/net/ip/Kconfig.ipv4 +++ b/subsys/net/ip/Kconfig.ipv4 @@ -82,6 +82,14 @@ config NET_DHCPV4_OPTION_CALLBACKS can be added. These can be used to support otherwise DHCP options not used by the rest of the system. +config NET_DHCPV4_ACCEPT_UNICAST + bool "Accept unicast DHCPv4 traffic" + depends on NET_DHCPV4 + default y + help + If set, the network stack will accept unicast DHCPv4 responses from + servers, before the assigned address is configured on the interface. + config NET_IPV4_AUTO bool "IPv4 autoconfiguration [EXPERIMENTAL]" depends on NET_ARP diff --git a/subsys/net/ip/dhcpv4.c b/subsys/net/ip/dhcpv4.c index be01851bd894..d5aefb3ba90a 100644 --- a/subsys/net/ip/dhcpv4.c +++ b/subsys/net/ip/dhcpv4.c @@ -211,7 +211,8 @@ static struct net_pkt *dhcpv4_create_message(struct net_if *iface, uint8_t type, msg->htype = HARDWARE_ETHERNET_TYPE; msg->hlen = net_if_get_link_addr(iface)->len; msg->xid = htonl(iface->config.dhcpv4.xid); - msg->flags = htons(DHCPV4_MSG_BROADCAST); + msg->flags = IS_ENABLED(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) ? + htons(DHCPV4_MSG_UNICAST) : htons(DHCPV4_MSG_BROADCAST); if (ciaddr) { /* The ciaddr field was zero'd out above, if we are @@ -1397,3 +1398,47 @@ int net_dhcpv4_init(void) #endif return 0; } + +#if defined(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) +bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) +{ + NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr); + struct net_pkt_cursor backup; + struct net_udp_hdr *udp_hdr; + struct net_if *iface; + bool accept = false; + + iface = net_pkt_iface(pkt); + if (iface == NULL) { + return false; + } + + /* Only accept DHCPv4 packets during active query. */ + if (iface->config.dhcpv4.state != NET_DHCPV4_SELECTING && + iface->config.dhcpv4.state != NET_DHCPV4_REQUESTING && + iface->config.dhcpv4.state != NET_DHCPV4_RENEWING && + iface->config.dhcpv4.state != NET_DHCPV4_REBINDING) { + return false; + } + + net_pkt_cursor_backup(pkt, &backup); + net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt)); + + /* Verify destination UDP port. */ + udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access); + if (udp_hdr == NULL) { + goto out; + } + + if (udp_hdr->dst_port != htons(DHCPV4_CLIENT_PORT)) { + goto out; + } + + accept = true; + +out: + net_pkt_cursor_restore(pkt, &backup); + + return accept; +} +#endif /* CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ diff --git a/subsys/net/ip/dhcpv4.h b/subsys/net/ip/dhcpv4.h index 52663f7ee07e..a274e3a6aeae 100644 --- a/subsys/net/ip/dhcpv4.h +++ b/subsys/net/ip/dhcpv4.h @@ -81,9 +81,7 @@ struct dhcp_msg { /* TODO: - * 1) Support for UNICAST flag (some dhcpv4 servers will not reply if - * DISCOVER message contains BROADCAST FLAG). - * 2) Support T2(Rebind) timer. + * 1) Support T2(Rebind) timer. */ /* Maximum number of REQUEST or RENEWAL retransmits before reverting @@ -115,4 +113,33 @@ int net_dhcpv4_init(void); #endif /* CONFIG_NET_DHCPV4 */ +#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_DHCPV4_ACCEPT_UNICAST) + +/** + * @brief Verify if the incoming packet should be accepted for the DHCPv4 + * module to process. + * + * In case server responds with an unicast IP packet, the IP stack needs to + * pass it through for the DHCPv4 module to process, before the actual + * destination IP address is configured on an interface. + * This function allows to determine whether there is an active DHCPv4 query on + * the interface and the packet is destined for the DHCPv4 module to process. + * + * @param pkt A packet to analyze + * + * @return true if the packet shall be accepted, false otherwise + */ +bool net_dhcpv4_accept_unicast(struct net_pkt *pkt); + +#else + +static inline bool net_dhcpv4_accept_unicast(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return false; +} + +#endif /* CONFIG_NET_DHCPV4 && CONFIG_NET_DHCPV4_ACCEPT_UNICAST */ + #endif /* __INTERNAL_DHCPV4_H */ diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 83827303f6e7..922068274f72 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(net_ipv4, CONFIG_NET_IPV4_LOG_LEVEL); #include "icmpv4.h" #include "udp_internal.h" #include "tcp_internal.h" +#include "dhcpv4.h" #include "ipv4.h" BUILD_ASSERT(sizeof(struct in_addr) == NET_IPV4_ADDR_SIZE); @@ -318,7 +319,8 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt) /* RFC 1122 ch. 3.3.6 The 0.0.0.0 is non-standard bcast addr */ (IS_ENABLED(CONFIG_NET_IPV4_ACCEPT_ZERO_BROADCAST) && net_ipv4_addr_cmp((struct in_addr *)hdr->dst, - net_ipv4_unspecified_address()))))) || + net_ipv4_unspecified_address())) || + net_dhcpv4_accept_unicast(pkt)))) || (hdr->proto == IPPROTO_TCP && net_ipv4_is_addr_bcast(net_pkt_iface(pkt), (struct in_addr *)hdr->dst))) { NET_DBG("DROP: not for me"); From 30382daf88eeda00bd2c246c92d1c47a01bc5b29 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 18 Jul 2023 18:07:15 +0200 Subject: [PATCH 1753/2042] net: wifi_shell: Add user input validation for SSID and PSK When parsing user input for "wifi connect" and "wifi ap enable" commands, the SSID and PSK lengths were not verified. It's better to detect invalid connect/AP enable parameters early, so that help text can be printed, instead of letting wifi_mgmt command to fail. For WIFI_SECURITY_TYPE_SAE, follow the Linux convention of limiting the size to 128 bytes. Signed-off-by: Robert Lubos --- include/zephyr/net/wifi.h | 2 ++ subsys/net/l2/wifi/wifi_shell.c | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index e7388fe6f6fe..0a7784f9dc95 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -135,7 +135,9 @@ static inline const char *wifi_band_txt(enum wifi_frequency_bands band) } #define WIFI_SSID_MAX_LEN 32 +#define WIFI_PSK_MIN_LEN 8 #define WIFI_PSK_MAX_LEN 64 +#define WIFI_SAE_PSWD_MAX_LEN 128 #define WIFI_MAC_ADDR_LEN 6 #define WIFI_CHANNEL_MAX 233 diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index a520dc798bfd..ae48a4f9b15c 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -333,6 +333,9 @@ static int __wifi_args_to_params(size_t argc, char *argv[], /* SSID */ params->ssid = argv[0]; params->ssid_length = strlen(params->ssid); + if (params->ssid_length > WIFI_SSID_MAX_LEN) { + return -EINVAL; + } /* Channel (optional) */ if ((idx < argc) && (strlen(argv[idx]) <= 3)) { @@ -378,6 +381,14 @@ static int __wifi_args_to_params(size_t argc, char *argv[], idx++; } } + + if (params->psk_length < WIFI_PSK_MIN_LEN || + (params->security != WIFI_SECURITY_TYPE_SAE && + params->psk_length > WIFI_PSK_MAX_LEN) || + (params->security == WIFI_SECURITY_TYPE_SAE && + params->psk_length > WIFI_SAE_PSWD_MAX_LEN)) { + return -EINVAL; + } } else { params->security = WIFI_SECURITY_TYPE_NONE; } From d02e49c4f02cfcbdac1168f1f01f797b5102ada3 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1754/2042] Revert "tests: pm: test `pm_device_driver_init`" This reverts commit a4cfc1eb37c5619fa10ffcc4cd8d45d12e8913a4. --- .../pm/device_driver_init/CMakeLists.txt | 8 --- .../subsys/pm/device_driver_init/app.overlay | 44 ------------ tests/subsys/pm/device_driver_init/prj.conf | 9 --- tests/subsys/pm/device_driver_init/src/main.c | 68 ------------------- .../pm/device_driver_init/testcase.yaml | 19 ------ 5 files changed, 148 deletions(-) delete mode 100644 tests/subsys/pm/device_driver_init/CMakeLists.txt delete mode 100644 tests/subsys/pm/device_driver_init/app.overlay delete mode 100644 tests/subsys/pm/device_driver_init/prj.conf delete mode 100644 tests/subsys/pm/device_driver_init/src/main.c delete mode 100644 tests/subsys/pm/device_driver_init/testcase.yaml diff --git a/tests/subsys/pm/device_driver_init/CMakeLists.txt b/tests/subsys/pm/device_driver_init/CMakeLists.txt deleted file mode 100644 index ddb4b524925a..000000000000 --- a/tests/subsys/pm/device_driver_init/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2023, CSIRO. -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(device_driver_init) - -target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/pm/device_driver_init/app.overlay b/tests/subsys/pm/device_driver_init/app.overlay deleted file mode 100644 index a5518b74be2c..000000000000 --- a/tests/subsys/pm/device_driver_init/app.overlay +++ /dev/null @@ -1,44 +0,0 @@ -/ { - test_reg: test_reg { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 0 0>; - }; - - test_reg_chained: test_reg_chained { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 1 0>; - power-domain = <&test_reg>; - }; - - test_reg_chained_auto: test_reg_chained_auto { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 2 0>; - power-domain = <&test_reg>; - zephyr,pm-device-runtime-auto; - }; - - test_reg_auto: test_reg_auto { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 3 0>; - zephyr,pm-device-runtime-auto; - }; - - test_reg_auto_chained: test_reg_auto_chained { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 4 0>; - power-domain = <&test_reg_auto>; - }; - - test_reg_auto_chained_auto: test_reg_auto_chained_auto { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 5 0>; - power-domain = <&test_reg_auto>; - zephyr,pm-device-runtime-auto; - }; - - test_reg_disabled: test_reg_disabled { - compatible = "power-domain-gpio"; - enable-gpios = <&gpio0 6 0>; - status = "disabled"; - }; -}; diff --git a/tests/subsys/pm/device_driver_init/prj.conf b/tests/subsys/pm/device_driver_init/prj.conf deleted file mode 100644 index e6d05f591acf..000000000000 --- a/tests/subsys/pm/device_driver_init/prj.conf +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023, Commonwealth Scientific and Industrial Research -# Organisation (CSIRO) ABN 41 687 119 230. -CONFIG_ZTEST=y -CONFIG_MP_MAX_NUM_CPUS=1 - -CONFIG_GPIO=y -CONFIG_GPIO_GET_CONFIG=y -CONFIG_POWER_DOMAIN=y -CONFIG_ZTEST_NEW_API=y diff --git a/tests/subsys/pm/device_driver_init/src/main.c b/tests/subsys/pm/device_driver_init/src/main.c deleted file mode 100644 index bc004ab7a0c5..000000000000 --- a/tests/subsys/pm/device_driver_init/src/main.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023, Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * SPDX-License-Identifier: Apache-2.0 - * - * State checking in this test is done via the GPIO state instead of - * the PM API as this test runs without the PM api enabled. - */ - -#include -#include -#include -#include - -#define POWER_GPIO_CONFIG_IS(node_id, config)\ - {\ - const struct gpio_dt_spec gpio = GPIO_DT_SPEC_GET(node_id, enable_gpios);\ - gpio_flags_t gpio_config; \ - int rc = gpio_pin_get_config_dt(&gpio, &gpio_config); \ - zassert_equal(rc, 0, "GPIO config retrieval failed"); \ - zassert_equal(gpio_config, config, "Unexpected config");\ - } - -#define DEVICE_STATE_IS(node_id, value) \ - rc = pm_device_state_get(DEVICE_DT_GET(node_id), &state); \ - zassert_equal(rc, 0, "Device state retrieval failed"); \ - zassert_equal(state, value, "Unexpected device state"); - -ZTEST(device_driver_init, test_demo) -{ -#if !IS_ENABLED(CONFIG_PM) || !IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) - /* Every regulator should be in "active" mode automatically. - * State checking via GPIO as PM API is disabled. - */ - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained_auto), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained_auto), GPIO_OUTPUT_HIGH); - POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_disabled), GPIO_DISCONNECTED); -#endif - -#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) - enum pm_device_state state; - int rc; - - /* 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); - - /* 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); - /* 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); -#endif -} - -ZTEST_SUITE(device_driver_init, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/pm/device_driver_init/testcase.yaml b/tests/subsys/pm/device_driver_init/testcase.yaml deleted file mode 100644 index c7e549b54008..000000000000 --- a/tests/subsys/pm/device_driver_init/testcase.yaml +++ /dev/null @@ -1,19 +0,0 @@ -tests: - pm.device_driver_init: - tags: pm - platform_allow: qemu_cortex_m3 - pm.device_driver_init.pm: - tags: pm - platform_allow: qemu_cortex_m3 - extra_configs: - - CONFIG_PM=y - - CONFIG_PM_DEVICE=y - - CONFIG_PM_DEVICE_POWER_DOMAIN=y - pm.device_driver_init.pm_device_runtime: - tags: pm - platform_allow: qemu_cortex_m3 - extra_configs: - - CONFIG_PM=y - - CONFIG_PM_DEVICE=y - - CONFIG_PM_DEVICE_POWER_DOMAIN=y - - CONFIG_PM_DEVICE_RUNTIME=y From b74efbe59edca823c4e1bfac70788f5550813fc1 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1755/2042] Revert "tests: pm: update power domain behaviour" This reverts commit b82bbf5e31d0163b496334af2f53e92cb0992658. --- tests/subsys/pm/device_power_domains/src/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/subsys/pm/device_power_domains/src/main.c b/tests/subsys/pm/device_power_domains/src/main.c index 50726bcef199..8bc7789fa4b0 100644 --- a/tests/subsys/pm/device_power_domains/src/main.c +++ b/tests/subsys/pm/device_power_domains/src/main.c @@ -40,17 +40,17 @@ ZTEST(device_power_domain, test_demo) /* Initial power state */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); - zassert_true(pm_device_is_powered(reg_chained), ""); - zassert_true(pm_device_is_powered(dev), ""); + zassert_false(pm_device_is_powered(reg_chained), ""); + zassert_false(pm_device_is_powered(dev), ""); TC_PRINT("Enabling runtime power management on regulators\n"); - pm_device_runtime_enable(dev); - pm_device_runtime_enable(reg_chained); - pm_device_runtime_enable(reg_1); pm_device_runtime_enable(reg_0); + pm_device_runtime_enable(reg_1); + pm_device_runtime_enable(reg_chained); + pm_device_runtime_enable(dev); - /* Power domains should now be suspended */ + /* State shouldn't have changed */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); zassert_false(pm_device_is_powered(reg_chained), ""); From 226f1c5e4bcd6b7ad6eca333fc3cc58016b82f0c Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1756/2042] Revert "power_domain: gpio: init with `pm_device_driver_init`" This reverts commit 39b2ec57a0c310f76ab50abab6837be9cc948bf5. --- drivers/power_domain/power_domain_gpio.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index c0fb25b3d457..88178531504f 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -113,6 +113,7 @@ static int pd_gpio_init(const struct device *dev) { const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; + int rc; if (!device_is_ready(cfg->enable.port)) { LOG_ERR("GPIO port %s is not ready", cfg->enable.port->name); @@ -121,8 +122,16 @@ static int pd_gpio_init(const struct device *dev) /* We can't know how long the domain has been off for before boot */ data->next_boot = K_TIMEOUT_ABS_US(cfg->off_on_delay_us); - /* Boot according to state */ - return pm_device_driver_init(dev, pd_gpio_pm_action); + if (pm_device_on_power_domain(dev)) { + /* Device is unpowered */ + pm_device_init_off(dev); + rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); + } else { + pm_device_init_suspended(dev); + rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); + } + + return rc; } #define POWER_DOMAIN_DEVICE(id) \ From f613074283b14bb6e5bbebddf1c2128ee472f001 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1757/2042] Revert "power_domain: gpio: compile without `PM_DEVICE_POWER_DOMAIN`" This reverts commit 1f1217e8324370afb8f93799340dd0fb3edf9c62. --- drivers/power_domain/power_domain_gpio.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 88178531504f..511564dbc335 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -30,8 +30,6 @@ struct pd_visitor_context { enum pm_device_action action; }; -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - static int pd_on_domain_visitor(const struct device *dev, void *context) { struct pd_visitor_context *visitor_context = context; @@ -45,16 +43,12 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) return 0; } -#endif - static int pd_gpio_pm_action(const struct device *dev, enum pm_device_action action) { -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - struct pd_visitor_context context = {.domain = dev}; -#endif const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; + struct pd_visitor_context context = {.domain = dev}; int64_t next_boot_ticks; int rc = 0; @@ -73,18 +67,14 @@ static int pd_gpio_pm_action(const struct device *dev, LOG_INF("%s is now ON", dev->name); /* Wait for domain to come up */ k_sleep(K_USEC(cfg->startup_delay_us)); -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain they are now powered */ context.action = PM_DEVICE_ACTION_TURN_ON; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); -#endif break; case PM_DEVICE_ACTION_SUSPEND: -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain that power is going down */ context.action = PM_DEVICE_ACTION_TURN_OFF; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); -#endif /* Switch power off */ gpio_pin_set_dt(&cfg->enable, 0); LOG_INF("%s is now OFF", dev->name); From 6edab1f050c1c56dc7c0f34ed413d722c8fddd22 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1758/2042] Revert "pm: device: add driver init helper" This reverts commit 84016c1cd3658291a4d16775771fe0c3eb811943. --- include/zephyr/pm/device.h | 29 ----------------------------- subsys/pm/device.c | 38 -------------------------------------- 2 files changed, 67 deletions(-) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index 29cd4b26a1e8..734f6c08a60f 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -581,22 +581,6 @@ int pm_device_power_domain_remove(const struct device *dev, * @retval false If device is not currently powered */ bool pm_device_is_powered(const struct device *dev); - -/** - * @brief Setup a device driver into the lowest valid power mode - * - * This helper function is intended to be called at the end of a driver - * init function to automatically setup the device into the lowest power - * mode. It assumes that the device has been configured as if it is in - * @ref PM_DEVICE_STATE_OFF. - * - * @param dev Device instance. - * @param action_cb Device PM control callback function. - * @retval 0 On success. - * @retval -errno Error code from @a action_cb on failure. - */ -int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb); - #else static inline int pm_device_state_get(const struct device *dev, enum pm_device_state *state) @@ -683,19 +667,6 @@ static inline bool pm_device_is_powered(const struct device *dev) ARG_UNUSED(dev); return true; } - -static inline int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb) -{ - int rc; - - /* When power management is not enabled, all drivers should initialise to active state */ - rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); - if (rc == 0) { - rc = action_cb(dev, PM_DEVICE_ACTION_RESUME); - } - return rc; -} - #endif /* CONFIG_PM_DEVICE */ /** @} */ diff --git a/subsys/pm/device.c b/subsys/pm/device.c index bba0c316257a..baf37983d692 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -385,41 +385,3 @@ bool pm_device_is_powered(const struct device *dev) return true; #endif } - -int pm_device_driver_init(const struct device *dev, - pm_device_action_cb_t action_cb) -{ - struct pm_device *pm = dev->pm; - int rc = 0; - - /* Work only needs to be performed if the device is powered */ - if (pm_device_is_powered(dev)) { - /* Run power-up logic */ - rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); - if (rc != 0) { - return rc; - } - /* If device has no PM structure */ - if (pm == NULL) { - /* Device should always be active */ - return action_cb(dev, PM_DEVICE_ACTION_RESUME); - } - /* If device will have PM device runtime enabled */ - if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) && - atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_AUTO)) { - /* Init into suspend mode. - * This saves a SUSPENDED->ACTIVE->SUSPENDED cycle. - */ - pm_device_init_suspended(dev); - } - /* No PM enabled on the device by default */ - else { - /* Startup into active mode */ - return action_cb(dev, PM_DEVICE_ACTION_RESUME); - } - } else { - /* Start in off mode */ - pm_device_init_off(dev); - } - return rc; -} From d63999af6e1935cdf341873fdc2fa9a2e2309944 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1759/2042] Revert "gpio: stellaris: implement `gpio_pin_get_config`" This reverts commit c72577d709efb68249d23507869245029c8b49f5. --- drivers/gpio/gpio_stellaris.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpio/gpio_stellaris.c b/drivers/gpio/gpio_stellaris.c index e7114fa0e7f1..433962e10585 100644 --- a/drivers/gpio/gpio_stellaris.c +++ b/drivers/gpio/gpio_stellaris.c @@ -107,34 +107,6 @@ static int gpio_stellaris_configure(const struct device *dev, return 0; } -#ifdef CONFIG_GPIO_GET_CONFIG -static int gpio_stellaris_get_config(const struct device *dev, - gpio_pin_t pin, - gpio_flags_t *out_flags) -{ - const struct gpio_stellaris_config *cfg = dev->config; - uint32_t base = cfg->base; - gpio_flags_t flags = 0; - mm_reg_t mask_addr; - - if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin) == 0) { - flags = GPIO_DISCONNECTED; - } else if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin)) { - mask_addr = GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, BIT(pin)); - - if (sys_test_bit(mask_addr, pin)) { - flags |= GPIO_OUTPUT_HIGH; - } else { - flags |= GPIO_OUTPUT_LOW; - } - } else { - flags = GPIO_INPUT; - } - *out_flags = flags; - return 0; -} -#endif - static int gpio_stellaris_port_get_raw(const struct device *dev, uint32_t *value) { @@ -249,9 +221,6 @@ static int gpio_stellaris_manage_callback(const struct device *dev, static const struct gpio_driver_api gpio_stellaris_driver_api = { .pin_configure = gpio_stellaris_configure, -#ifdef CONFIG_GPIO_GET_CONFIG - .pin_get_config = gpio_stellaris_get_config, -#endif .port_get_raw = gpio_stellaris_port_get_raw, .port_set_masked_raw = gpio_stellaris_port_set_masked_raw, .port_set_bits_raw = gpio_stellaris_port_set_bits_raw, From 3c1149e0588419d1c28c1ef8d53c4d7709018bef Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1760/2042] Revert "tests: kernel: device: test sub-priority" This reverts commit 01e98fcb5f9b672d26758c8c73d64e3d2f2c41ca. --- tests/kernel/device/app.overlay | 17 ---------- .../device/boards/hifive_unmatched.overlay | 17 ---------- .../kernel/device/dts/bindings/fakedomain.yml | 8 ----- tests/kernel/device/src/main.c | 22 +----------- tests/kernel/device/src/test_driver_init.c | 34 ------------------- 5 files changed, 1 insertion(+), 97 deletions(-) delete mode 100644 tests/kernel/device/dts/bindings/fakedomain.yml diff --git a/tests/kernel/device/app.overlay b/tests/kernel/device/app.overlay index d7426f2b6134..aae8873f6b8d 100644 --- a/tests/kernel/device/app.overlay +++ b/tests/kernel/device/app.overlay @@ -51,21 +51,4 @@ "dale"; status = "okay"; }; - - fakedomain_0: fakedomain_0 { - compatible = "fakedomain"; - status = "okay"; - power-domain = <&fakedomain_2>; - }; - - fakedomain_1: fakedomain_1 { - compatible = "fakedomain"; - status = "okay"; - power-domain = <&fakedomain_0>; - }; - - fakedomain_2: fakedomain_2 { - compatible = "fakedomain"; - status = "okay"; - }; }; diff --git a/tests/kernel/device/boards/hifive_unmatched.overlay b/tests/kernel/device/boards/hifive_unmatched.overlay index 40fa5e74adb4..4a7ce8155f5d 100644 --- a/tests/kernel/device/boards/hifive_unmatched.overlay +++ b/tests/kernel/device/boards/hifive_unmatched.overlay @@ -48,21 +48,4 @@ "dale"; status = "okay"; }; - - fakedomain_0: fakedomain_0 { - compatible = "fakedomain"; - status = "okay"; - power-domain = <&fakedomain_2>; - }; - - fakedomain_1: fakedomain_1 { - compatible = "fakedomain"; - status = "okay"; - power-domain = <&fakedomain_0>; - }; - - fakedomain_2: fakedomain_2 { - compatible = "fakedomain"; - status = "okay"; - }; }; diff --git a/tests/kernel/device/dts/bindings/fakedomain.yml b/tests/kernel/device/dts/bindings/fakedomain.yml deleted file mode 100644 index a676419de1fa..000000000000 --- a/tests/kernel/device/dts/bindings/fakedomain.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2023, CSIRO -# SPDX-License-Identifier: Apache-2.0 - -description: Properties for fake power domain - -compatible: "fakedomain" - -include: base.yaml diff --git a/tests/kernel/device/src/main.c b/tests/kernel/device/src/main.c index a3e9430c15a6..cfc89da2f076 100644 --- a/tests/kernel/device/src/main.c +++ b/tests/kernel/device/src/main.c @@ -265,7 +265,6 @@ ZTEST(device, test_sys_init_multiple) /* this is for storing sequence during initialization */ extern int init_level_sequence[4]; extern int init_priority_sequence[4]; -extern int init_sub_priority_sequence[3]; extern unsigned int seq_level_cnt; extern unsigned int seq_priority_cnt; @@ -299,7 +298,7 @@ ZTEST(device, test_device_init_level) /** * @brief Test initialization priorities for device driver instances * - * @details After the defined device instances have initialized, we check the + * details After the defined device instances have initialized, we check the * sequence number that each driver stored during initialization. If the * sequence of initial priority stored is corresponding with our expectation, it * means assigning the priority for driver instance works. @@ -323,25 +322,6 @@ ZTEST(device, test_device_init_priority) "init sequence is not correct"); } -/** - * @brief Test initialization sub-priorities for device driver instances - * - * @details After the defined device instances have initialized, we check the - * sequence number that each driver stored during initialization. If the - * sequence of initial priority stored is corresponding with our expectation, it - * means using the devicetree for sub-priority sorting works. - * - * @ingroup kernel_device_tests - */ -ZTEST(device, test_device_init_sub_priority) -{ - /* fakedomain_1 depends on fakedomain_0 which depends on fakedomain_2, - * therefore we require that the initialisation runs in the reverse order. - */ - zassert_equal(init_sub_priority_sequence[0], 1, ""); - zassert_equal(init_sub_priority_sequence[1], 2, ""); - zassert_equal(init_sub_priority_sequence[2], 0, ""); -} /** * @brief Test abstraction of device drivers with common functionalities diff --git a/tests/kernel/device/src/test_driver_init.c b/tests/kernel/device/src/test_driver_init.c index e89d6acc7ff4..1c468f72a214 100644 --- a/tests/kernel/device/src/test_driver_init.c +++ b/tests/kernel/device/src/test_driver_init.c @@ -39,10 +39,8 @@ /* this is for storing sequence during initialization */ __pinned_bss int init_level_sequence[4] = {0}; __pinned_bss int init_priority_sequence[4] = {0}; -__pinned_bss int init_sub_priority_sequence[3] = {0}; __pinned_bss unsigned int seq_level_cnt; __pinned_bss unsigned int seq_priority_cnt; -__pinned_bss unsigned int seq_sub_priority_cnt; /* define driver type 1: for testing initialize levels and priorities */ typedef int (*my_api_configure_t)(const struct device *dev, int dev_config); @@ -128,28 +126,6 @@ static int my_driver_pri_4_init(const struct device *dev) return 0; } -/* driver init function of testing sub_priority */ -static int my_driver_sub_pri_0_init(const struct device *dev) -{ - init_sub_priority_sequence[0] = seq_sub_priority_cnt++; - - return 0; -} - -static int my_driver_sub_pri_1_init(const struct device *dev) -{ - init_sub_priority_sequence[1] = seq_sub_priority_cnt++; - - return 0; -} - -static int my_driver_sub_pri_2_init(const struct device *dev) -{ - init_sub_priority_sequence[2] = seq_sub_priority_cnt++; - - return 0; -} - /** * @brief Test providing control device driver initialization order * @@ -196,13 +172,3 @@ DEVICE_DEFINE(my_driver_priority_2, MY_DRIVER_PRI_2, DEVICE_DEFINE(my_driver_priority_3, MY_DRIVER_PRI_3, &my_driver_pri_3_init, NULL, NULL, NULL, POST_KERNEL, 3, &funcs_my_drivers); - -/* Create several devices at the same init priority that depend on each - * other in devicetree so that we can validate linker sorting. - */ -DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_0), my_driver_sub_pri_0_init, - NULL, NULL, NULL, APPLICATION, 33, NULL); -DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_1), my_driver_sub_pri_1_init, - NULL, NULL, NULL, APPLICATION, 33, NULL); -DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_2), my_driver_sub_pri_2_init, - NULL, NULL, NULL, APPLICATION, 33, NULL); From 109fc877378cd3b15d6961a2adf3a3aa329a559b Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1761/2042] Revert "init: add sub-priority to internal ordering" This reverts commit bb590b5b6e2e50929c2065dd16822d68b702b2ce. --- include/zephyr/device.h | 22 ++++------------------ include/zephyr/init.h | 10 ++++------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index ce9b6c1312e7..2ea95a2d563a 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -848,17 +848,6 @@ static inline bool z_impl_device_is_ready(const struct device *dev) #endif /* CONFIG_DEVICE_DEPS */ -/** - * @brief Init sub-priority of the device - * - * The sub-priority is defined by the devicetree ordinal, which ensures that - * multiple drivers running at the same priority level run in an order that - * respects the devicetree dependencies. - */ -#define Z_DEVICE_INIT_SUB_PRIO(node_id) \ - COND_CODE_1(DT_NODE_EXISTS(node_id), \ - (DT_DEP_ORD_STR_SORTABLE(node_id)), (0)) - /** * @brief Maximum device name length. * @@ -934,17 +923,14 @@ static inline bool z_impl_device_is_ready(const struct device *dev) /** * @brief Define the init entry for a device. * - * @param node_id Devicetree node id for the device (DT_INVALID_NODE if a - * software device). * @param dev_id Device identifier. * @param init_fn_ Device init function. * @param level Initialization level. * @param prio Initialization priority. */ -#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ - static const Z_DECL_ALIGN(struct init_entry) __used __noasan \ - Z_INIT_ENTRY_SECTION(level, prio, \ - Z_DEVICE_INIT_SUB_PRIO(node_id)) \ +#define Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn_, level, prio) \ + static const Z_DECL_ALIGN(struct init_entry) \ + Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \ Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ .init_fn = {.dev = (init_fn_)}, \ .dev = &DEVICE_NAME_GET(dev_id), \ @@ -981,7 +967,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ \ - Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio) + Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn, level, prio) #if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) /** diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 9b0d2993d620..77e8fddc0cc6 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -128,12 +128,10 @@ struct init_entry { * @brief Init entry section. * * Each init entry is placed in a section with a name crafted so that it allows - * linker scripts to sort them according to the specified - * level/priority/sub-priority. + * linker scripts to sort them according to the specified level/priority. */ -#define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \ - __attribute__((__section__( \ - ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) +#define Z_INIT_ENTRY_SECTION(level, prio) \ + __attribute__((__section__(".z_init_" #level STRINGIFY(prio)"_"))) /** @endcond */ @@ -188,7 +186,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_SECTION(level, prio) __used __noasan \ Z_INIT_ENTRY_NAME(name) = { \ .init_fn = {.sys = (init_fn_)}, \ .dev = NULL, \ From f0958c62e4f721f7dcb8e1ed9902203d6339efa7 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 25 Jul 2023 17:42:20 +1000 Subject: [PATCH 1762/2042] Revert "dts: gen_defines: generate `_ORD_STR_SORTABLE`" This reverts commit 9b7768147342aa65233e9adc802b9cb4b3150ee3. --- include/zephyr/devicetree/ordinals.h | 7 ------- scripts/dts/gen_defines.py | 1 - 2 files changed, 8 deletions(-) diff --git a/include/zephyr/devicetree/ordinals.h b/include/zephyr/devicetree/ordinals.h index 5dd9d00e308a..c8b0302d1c3c 100644 --- a/include/zephyr/devicetree/ordinals.h +++ b/include/zephyr/devicetree/ordinals.h @@ -24,13 +24,6 @@ */ #define DT_DEP_ORD(node_id) DT_CAT(node_id, _ORD) -/** - * @brief Get a node's dependency ordinal in string sortable form - * @param node_id Node identifier - * @return the node's dependency ordinal as a zero-padded integer literal - */ -#define DT_DEP_ORD_STR_SORTABLE(node_id) DT_CAT(node_id, _ORD_STR_SORTABLE) - /** * @brief Get a list of dependency ordinals of a node's direct dependencies * diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 0c95557cda2d..ed47d3ae1512 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -747,7 +747,6 @@ def fmt_dep_list(dep_list): out_comment("Node's dependency ordinal:") out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal) - out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}") out_comment("Ordinals for what this node depends on directly:") out_dt_define(f"{node.z_path_id}_REQUIRES_ORDS", From b2314c83629f170fb766bf5b8e1c78f85ce046d6 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 17 Jul 2023 15:12:36 +0200 Subject: [PATCH 1763/2042] net: if: Add functions to loop over IPv4/IPv6 addresses Add new net_if API functions which allow to loop over all valid IPv4/IPv6 addresses assigned to the interface and execute a callback function on them. Signed-off-by: Robert Lubos --- include/zephyr/net/net_if.h | 34 +++++++++++++++++++++ subsys/net/ip/net_if.c | 60 +++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index 59a5f11b1245..144860c28415 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -1209,6 +1209,29 @@ bool net_if_ipv6_addr_rm(struct net_if *iface, const struct in6_addr *addr); __syscall bool net_if_ipv6_addr_rm_by_index(int index, const struct in6_addr *addr); +/** + * @typedef net_if_ip_addr_cb_t + * @brief Callback used while iterating over network interface IP addresses + * + * @param iface Pointer to the network interface the address belongs to + * @param addr Pointer to current IP address + * @param user_data A valid pointer to user data or NULL + */ +typedef void (*net_if_ip_addr_cb_t)(struct net_if *iface, + struct net_if_addr *addr, + void *user_data); + +/** + * @brief Go through all IPv6 addresses on a network interface and call callback + * for each used address. + * + * @param iface Pointer to the network interface + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_if_ipv6_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data); + /** * @brief Add a IPv6 multicast address to an interface * @@ -1840,6 +1863,17 @@ __syscall bool net_if_ipv4_addr_add_by_index(int index, __syscall bool net_if_ipv4_addr_rm_by_index(int index, const struct in_addr *addr); +/** + * @brief Go through all IPv4 addresses on a network interface and call callback + * for each used address. + * + * @param iface Pointer to the network interface + * @param cb User-supplied callback function to call + * @param user_data User specified data + */ +void net_if_ipv4_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data); + /** * @brief Add a IPv4 multicast address to an interface * diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 62ebe17eefaf..e3a7ff5dfc07 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -1982,6 +1982,36 @@ bool z_vrfy_net_if_ipv6_addr_rm_by_index(int index, #include #endif /* CONFIG_USERSPACE */ +void net_if_ipv6_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data) +{ + struct net_if_ipv6 *ipv6; + + if (iface == NULL) { + return; + } + + net_if_lock(iface); + + ipv6 = iface->config.ip.ipv6; + if (ipv6 == NULL) { + goto out; + } + + for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + struct net_if_addr *if_addr = &ipv6->unicast[i]; + + if (!if_addr->is_used) { + continue; + } + + cb(iface, if_addr, user_data); + } + +out: + net_if_unlock(iface); +} + struct net_if_mcast_addr *net_if_ipv6_maddr_add(struct net_if *iface, const struct in6_addr *addr) { @@ -3784,6 +3814,36 @@ bool z_vrfy_net_if_ipv4_addr_rm_by_index(int index, #include #endif /* CONFIG_USERSPACE */ +void net_if_ipv4_addr_foreach(struct net_if *iface, net_if_ip_addr_cb_t cb, + void *user_data) +{ + struct net_if_ipv4 *ipv4; + + if (iface == NULL) { + return; + } + + net_if_lock(iface); + + ipv4 = iface->config.ip.ipv4; + if (ipv4 == NULL) { + goto out; + } + + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + struct net_if_addr *if_addr = &ipv4->unicast[i]; + + if (!if_addr->is_used) { + continue; + } + + cb(iface, if_addr, user_data); + } + +out: + net_if_unlock(iface); +} + static struct net_if_mcast_addr *ipv4_maddr_find(struct net_if *iface, bool is_used, const struct in_addr *addr) From ea9d8b7295c0f9a09c4630cf6748f2822f881590 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 17 Jul 2023 16:55:00 +0200 Subject: [PATCH 1764/2042] tests: net: if: Add tests to verify net_if_ipv4/6_addr_foreach() Add tests cases which verify that net_if_ipv4/6_addr_foreach() executes callbacks properly on assigned addresses. Signed-off-by: Robert Lubos --- tests/net/iface/src/main.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/net/iface/src/main.c b/tests/net/iface/src/main.c index 12ee3404ef83..a80d478664b6 100644 --- a/tests/net/iface/src/main.c +++ b/tests/net/iface/src/main.c @@ -1069,4 +1069,66 @@ ZTEST(net_iface, test_get_by_index_from_userspace) get_by_index_from_userspace(); } +static void foreach_ipv4_addr_check(struct net_if *iface, + struct net_if_addr *if_addr, + void *user_data) +{ + int *count = (int *)user_data; + + (*count)++; + + zassert_equal_ptr(iface, iface1, "Callback called on wrong interface"); + zassert_mem_equal(&if_addr->address.in_addr, &my_ipv4_addr1, + sizeof(struct in_addr), "Wrong IPv4 address"); +} + +ZTEST(net_iface, test_ipv4_addr_foreach) +{ + int count = 0; + + /* iface1 has one IPv4 address configured */ + net_if_ipv4_addr_foreach(iface1, foreach_ipv4_addr_check, &count); + zassert_equal(count, 1, "Incorrect number of callback calls"); + + count = 0; + + /* iface4 has no IPv4 address configured */ + net_if_ipv4_addr_foreach(iface4, foreach_ipv4_addr_check, &count); + zassert_equal(count, 0, "Incorrect number of callback calls"); +} + +static void foreach_ipv6_addr_check(struct net_if *iface, + struct net_if_addr *if_addr, + void *user_data) +{ + int *count = (int *)user_data; + + (*count)++; + + zassert_equal_ptr(iface, iface1, "Callback called on wrong interface"); + + if (net_ipv6_is_ll_addr(&if_addr->address.in6_addr)) { + zassert_mem_equal(&if_addr->address.in6_addr, &ll_addr, + sizeof(struct in6_addr), "Wrong IPv6 address"); + } else { + zassert_mem_equal(&if_addr->address.in6_addr, &my_addr1, + sizeof(struct in6_addr), "Wrong IPv6 address"); + } +} + +ZTEST(net_iface, test_ipv6_addr_foreach) +{ + int count = 0; + + /* iface1 has two IPv6 addresses configured */ + net_if_ipv6_addr_foreach(iface1, foreach_ipv6_addr_check, &count); + zassert_equal(count, 2, "Incorrect number of callback calls"); + + count = 0; + + /* iface4 has no IPv6 address configured */ + net_if_ipv6_addr_foreach(iface4, foreach_ipv6_addr_check, &count); + zassert_equal(count, 0, "Incorrect number of callback calls"); +} + ZTEST_SUITE(net_iface, NULL, iface_setup, NULL, NULL, iface_teardown); From 9866a5229d697a115a027ce9e39b7e85efc57b80 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 12 Jul 2023 13:39:43 +0200 Subject: [PATCH 1765/2042] samples: net: dns_resolve: Improve DHCPv4 handling There is some ambiguity with the DHCPv4 handling in the dns_resolve sample. On one hand, the sample uses net_config library, which does initiate the DHCPv4 on the interface (if enabled) and may block the initialization until the address is assigned (in case there is no other statically assigned IPv4 addresses.) On the other hand, the sample registers for NET_EVENT_IPV4_ADDR_ADD in case DHCPv4 is in use, delaying the DNS queries until address is assigned. In case net_config delayed the initialization however, this will not work, as the event handler will be registered only after DHCPv4 address is assigned, so the callback will not get executed. Fix this, by checking if DHCPv4 assigned address already exists on an interface - if so, schedule DNS queries immediately. Otherwise (for example in case when net_config was not configured to wait for address) register an event callback, and schedule queries from there. Signed-off-by: Robert Lubos --- samples/net/dns_resolve/src/main.c | 103 ++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 32 deletions(-) diff --git a/samples/net/dns_resolve/src/main.c b/samples/net/dns_resolve/src/main.c index 62cd71d9e22d..0aa5f2a98863 100644 --- a/samples/net/dns_resolve/src/main.c +++ b/samples/net/dns_resolve/src/main.c @@ -152,57 +152,96 @@ static void do_ipv4_lookup(struct k_work *work) LOG_DBG("DNS id %u", dns_id); } +static void schedule_ipv4_queries(void) +{ + k_work_init_delayable(&ipv4_timer, do_ipv4_lookup); + k_work_reschedule(&ipv4_timer, K_NO_WAIT); + +#if defined(CONFIG_MDNS_RESOLVER) + k_work_init_delayable(&mdns_ipv4_timer, do_mdns_ipv4_lookup); + k_work_reschedule(&mdns_ipv4_timer, K_NO_WAIT); +#endif +} + +static void print_dhcpv4_addr(struct net_if *iface, struct net_if_addr *if_addr, + void *user_data) +{ + bool *found = (bool *)user_data; + char hr_addr[NET_IPV4_ADDR_LEN]; + + if (*found) { + return; + } + + if (if_addr->addr_type != NET_ADDR_DHCP) { + return; + } + + LOG_INF("IPv4 address: %s", + net_addr_ntop(AF_INET, &if_addr->address.in_addr, + hr_addr, NET_IPV4_ADDR_LEN)); + LOG_INF("Lease time: %u seconds", iface->config.dhcpv4.lease_time); + LOG_INF("Subnet: %s", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->netmask, + hr_addr, NET_IPV4_ADDR_LEN)); + LOG_INF("Router: %s", + net_addr_ntop(AF_INET, + &iface->config.ip.ipv4->gw, + hr_addr, NET_IPV4_ADDR_LEN)); + + *found = true; +} + static void ipv4_addr_add_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { - char hr_addr[NET_IPV4_ADDR_LEN]; - int i; + + bool found = false; if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) { return; } - for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - struct net_if_addr *if_addr = - &iface->config.ip.ipv4->unicast[i]; - - if (if_addr->addr_type != NET_ADDR_DHCP || !if_addr->is_used) { - continue; - } - - LOG_INF("IPv4 address: %s", - net_addr_ntop(AF_INET, - &if_addr->address.in_addr, - hr_addr, NET_IPV4_ADDR_LEN)); - LOG_INF("Lease time: %u seconds", - iface->config.dhcpv4.lease_time); - LOG_INF("Subnet: %s", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->netmask, - hr_addr, NET_IPV4_ADDR_LEN)); - LOG_INF("Router: %s", - net_addr_ntop(AF_INET, - &iface->config.ip.ipv4->gw, - hr_addr, NET_IPV4_ADDR_LEN)); - break; - } + net_if_ipv4_addr_foreach(iface, print_dhcpv4_addr, &found); /* We cannot run DNS lookup directly from this thread as the * management event thread stack is very small by default. * So run it from work queue instead. */ - k_work_init_delayable(&ipv4_timer, do_ipv4_lookup); - k_work_reschedule(&ipv4_timer, K_NO_WAIT); + schedule_ipv4_queries(); +} -#if defined(CONFIG_MDNS_RESOLVER) - k_work_init_delayable(&mdns_ipv4_timer, do_mdns_ipv4_lookup); - k_work_reschedule(&mdns_ipv4_timer, K_NO_WAIT); -#endif +static void check_dhcpv4_addr(struct net_if *iface, struct net_if_addr *if_addr, + void *user_data) +{ + bool *found = (bool *)user_data; + + if (if_addr->addr_type != NET_ADDR_DHCP) { + return; + } + + *found = true; } static void setup_dhcpv4(struct net_if *iface) { + bool found; + + /* If DHCP registers an IP address before we register the + * ipv4_addr_add_handler() callback, we won't be notified. Check + * whether this is the case. + */ + net_if_ipv4_addr_foreach(iface, check_dhcpv4_addr, &found); + + if (found) { + /* Already have DHCP assigned address, schedule queries. */ + schedule_ipv4_queries(); + return; + } + + /* Otherwise, wait for DHCP to assign an address. */ LOG_INF("Getting IPv4 address via DHCP before issuing DNS query"); net_mgmt_init_event_callback(&mgmt4_cb, ipv4_addr_add_handler, From fbe6ac852f6d06a875a142f371dc7d378136ff29 Mon Sep 17 00:00:00 2001 From: Markus Fuchs Date: Mon, 24 Jul 2023 17:24:22 +0200 Subject: [PATCH 1766/2042] drivers: bluetooth: slz_hci: Fix incoming HCI packet handling Currently, HCI packet handling does not consider the BT_RECV_CONTEXT choice selection. It calls bt_recv() and bt_recv_prio() only depending on the HCI packet type and event flags. However, for selections other than BT_RECV_BLOCKING, the "HCI driver shall not call bt_recv_prio()". Fix that by only calling bt_recv_prio() when CONFIG_BT_RECV_BLOCKING is enabled. Signed-off-by: Markus Fuchs --- drivers/bluetooth/hci/slz_hci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci/slz_hci.c b/drivers/bluetooth/hci/slz_hci.c index 812d01b620eb..59bd8ba5ff9e 100644 --- a/drivers/bluetooth/hci/slz_hci.c +++ b/drivers/bluetooth/hci/slz_hci.c @@ -76,7 +76,8 @@ uint32_t hci_common_transport_transmit(uint8_t *data, int16_t len) } net_buf_add_mem(buf, data, len); - if ((packet_type == h4_event) && (flags & BT_HCI_EVT_FLAG_RECV_PRIO)) { + if (IS_ENABLED(CONFIG_BT_RECV_BLOCKING) && + (packet_type == h4_event) && (flags & BT_HCI_EVT_FLAG_RECV_PRIO)) { bt_recv_prio(buf); } else { bt_recv(buf); From 4d56a318f162b758daf04525143380da373e1814 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 21 Jun 2023 13:50:18 +0200 Subject: [PATCH 1767/2042] bluetooth: tester: Add commands to add and delete virtual addresses Virtual address behavior has been changed in this PR: https://github.com/zephyrproject-rtos/zephyr/pull/57878 Now it is required to register virtual address before using it. Corresponding PR to auto-pts: https://github.com/auto-pts/auto-pts/pull/961 Signed-off-by: Pavel Vasilyev --- tests/bluetooth/tester/src/btp/btp_mesh.h | 13 +++++ tests/bluetooth/tester/src/btp_mesh.c | 63 +++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/tests/bluetooth/tester/src/btp/btp_mesh.h b/tests/bluetooth/tester/src/btp/btp_mesh.h index 096f61bcb161..d7d2b2cdc7b8 100644 --- a/tests/bluetooth/tester/src/btp/btp_mesh.h +++ b/tests/bluetooth/tester/src/btp/btp_mesh.h @@ -747,6 +747,19 @@ struct btp_mesh_cfg_krp_set_rp { uint8_t phase; } __packed; +#define BTP_MESH_VA_ADD 0x4D +struct btp_mesh_va_add_cmd { + uint8_t label_uuid[16]; +} __packed; +struct btp_mesh_va_add_rp { + uint16_t addr; +} __packed; + +#define BTP_MESH_VA_DEL 0x4E +struct btp_mesh_va_del_cmd { + uint8_t label_uuid[16]; +} __packed; + #define BTP_MESH_PROXY_CONNECT 0x77 struct btp_proxy_connect_cmd { diff --git a/tests/bluetooth/tester/src/btp_mesh.c b/tests/bluetooth/tester/src/btp_mesh.c index 37dd04ab3e47..c922c812631d 100644 --- a/tests/bluetooth/tester/src/btp_mesh.c +++ b/tests/bluetooth/tester/src/btp_mesh.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #define LOG_MODULE_NAME bttester_mesh @@ -172,6 +173,8 @@ static uint8_t supported_commands(const void *cmd, uint16_t cmd_len, tester_set_bit(rp->data, BTP_MESH_PROVISION_ADV); tester_set_bit(rp->data, BTP_MESH_CFG_KRP_GET); tester_set_bit(rp->data, BTP_MESH_CFG_KRP_SET); + tester_set_bit(rp->data, BTP_MESH_VA_ADD); + tester_set_bit(rp->data, BTP_MESH_VA_DEL); *rsp_len = sizeof(*rp) + 10; @@ -736,6 +739,10 @@ static uint8_t net_send(const void *cmd, uint16_t cmd_len, .send_ttl = cp->ttl, }; + if (BT_MESH_ADDR_IS_VIRTUAL(ctx.addr)) { + ctx.uuid = bt_mesh_va_uuid_get(ctx.addr, NULL, NULL); + } + LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, ctx.addr, cp->payload_len); @@ -756,6 +763,48 @@ static uint8_t net_send(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +static uint8_t va_add(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_va_add_cmd *cp = cmd; + struct btp_mesh_va_add_rp *rp = rsp; + const struct bt_mesh_va *va; + int err; + + err = bt_mesh_va_add(cp->label_uuid, &va); + if (err) { + LOG_ERR("Failed to add Label UUID (err %d)", err); + return BTP_STATUS_FAILED; + } + + rp->addr = sys_cpu_to_le16(va->addr); + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t va_del(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_va_del_cmd *cp = cmd; + const struct bt_mesh_va *va; + int err; + + va = bt_mesh_va_find(cp->label_uuid); + if (!va) { + LOG_ERR("Failed to find Label UUID"); + return BTP_STATUS_FAILED; + } + + err = bt_mesh_va_del(va->uuid); + if (err) { + LOG_ERR("Failed to delete Label UUID (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + static uint8_t health_generate_faults(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { @@ -815,6 +864,10 @@ static uint8_t model_send(const void *cmd, uint16_t cmd_len, .send_ttl = BT_MESH_TTL_DEFAULT, }; + if (BT_MESH_ADDR_IS_VIRTUAL(ctx.addr)) { + ctx.uuid = bt_mesh_va_uuid_get(ctx.addr, NULL, NULL); + } + src = sys_le16_to_cpu(cp->src); /* Lookup source address */ @@ -2844,6 +2897,16 @@ static const struct btp_handler handlers[] = { .expect_len = sizeof(struct btp_mesh_cfg_krp_set_cmd), .func = config_krp_set, }, + { + .opcode = BTP_MESH_VA_ADD, + .expect_len = sizeof(struct btp_mesh_va_add_cmd), + .func = va_add, + }, + { + .opcode = BTP_MESH_VA_DEL, + .expect_len = sizeof(struct btp_mesh_va_del_cmd), + .func = va_del, + }, #if defined(CONFIG_BT_TESTING) { .opcode = BTP_MESH_LPN_SUBSCRIBE, From a2395e8d5bbf05452ef8c9dd3257d85970876ea2 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 23 Jul 2023 18:19:49 +1000 Subject: [PATCH 1768/2042] mbedtls: add `MBEDTLS_AES_FEWER_TABLES` control Add a kconfig symbol to control the mbedtls option `MBEDTLS_AES_FEWER_TABLES`. 6KiB is a not insignificant ROM/RAM savings, and the extra arthmetic is quite reasonable. Signed-off-by: Jordan Yates --- modules/mbedtls/Kconfig.tls-generic | 9 +++++++++ modules/mbedtls/configs/config-tls-generic.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/modules/mbedtls/Kconfig.tls-generic b/modules/mbedtls/Kconfig.tls-generic index 6275c6570f75..d27c5efea5e9 100644 --- a/modules/mbedtls/Kconfig.tls-generic +++ b/modules/mbedtls/Kconfig.tls-generic @@ -250,6 +250,15 @@ config MBEDTLS_AES_ROM_TABLES bool "Use precomputed AES tables stored in ROM." default y +config MBEDTLS_AES_FEWER_TABLES + depends on MBEDTLS_CIPHER_AES_ENABLED + bool "Reduce the size of precomputed AES tables by ~6kB" + help + Reduce the size of the AES tables at a tradeoff of more + arithmetic operations at runtime. Specifically 4 table + lookups are converted to 1 table lookup, 3 additions + and 6 bit shifts. + config MBEDTLS_CIPHER_CAMELLIA_ENABLED bool "Camellia block cipher" diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index 52a5bb2fd16c..839f9e027241 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -142,6 +142,10 @@ #define MBEDTLS_AES_ROM_TABLES #endif +#if defined(CONFIG_MBEDTLS_AES_FEWER_TABLES) +#define MBEDTLS_AES_FEWER_TABLES +#endif + #if defined(CONFIG_MBEDTLS_CIPHER_CAMELLIA_ENABLED) #define MBEDTLS_CAMELLIA_C #endif From ecf29a77f88873e55dcae4899f4795bcacc74eff Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 11:51:14 +0000 Subject: [PATCH 1769/2042] doc: release: drop the notes about listing github issues Drop the notes about listing all the github issues with the release notes. That was a huge list of github issues sorted by closing time, very noisy and hard to maintain. The unfiltered list of changes is already in the commit history, a distilled list is now in the blog posts and a final list is in the notes summary. The issue list has been skipped in 3.4 already, let's just drop it from the process. Signed-off-by: Fabio Baltieri --- doc/project/release_process.rst | 23 ----------------------- doc/releases/release-notes-3.5.rst | 8 +------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/doc/project/release_process.rst b/doc/project/release_process.rst index efc5012ad3f4..5ffb189dbf1a 100644 --- a/doc/project/release_process.rst +++ b/doc/project/release_process.rst @@ -409,26 +409,3 @@ steps: #. Send an email to the mailing lists (``announce`` and ``devel``) with a link to the release - -Listing all closed GitHub issues -================================= - -The release notes for a final release contain the list of GitHub issues that -have been closed during the development process of that release. - -In order to obtain the list of issues closed during the release development -cycle you can do the following: - -#. Look for the last release before the current one and find the day it was - tagged:: - - $ git show -s --format=%ci v1.10.0 - tag v1.10.0 - Tagger: Kumar Gala - - Zephyr 1.10.0 - 2017-12-08 13:32:22 -0600 - - -#. Use available release tools to list all the issues that have been closed - between that date and the day of the release. diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index fbfbdbc11eb8..a6bb1beaec3d 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -313,11 +313,5 @@ Documentation Tests and Samples ***************** -Issue Related Items -******************* - Known Issues -============ - -Addressed issues -================ +************ From 0f23cda744e81377eaccc4c1ffde14248aa1e47b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 21 Jul 2023 11:51:39 +0000 Subject: [PATCH 1770/2042] scripts: drop list_issues.py This is not used as part for the release process anymore. Signed-off-by: Fabio Baltieri --- scripts/release/list_issues.py | 218 --------------------------------- 1 file changed, 218 deletions(-) delete mode 100755 scripts/release/list_issues.py diff --git a/scripts/release/list_issues.py b/scripts/release/list_issues.py deleted file mode 100755 index f56281d0efb0..000000000000 --- a/scripts/release/list_issues.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2019 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -# Lists all closes issues since a given date - -import argparse -import sys -import os -import re -import time -import threading -import requests - - -args = None - - -class Spinner: - busy = False - delay = 0.1 - - @staticmethod - def spinning_cursor(): - while 1: - for cursor in '|/-\\': - yield cursor - - def __init__(self, delay=None): - self.spinner_generator = self.spinning_cursor() - if delay and float(delay): - self.delay = delay - - def spinner_task(self): - while self.busy: - sys.stdout.write(next(self.spinner_generator)) - sys.stdout.flush() - time.sleep(self.delay) - sys.stdout.write('\b') - sys.stdout.flush() - - def __enter__(self): - self.busy = True - threading.Thread(target=self.spinner_task).start() - - def __exit__(self, exception, value, tb): - self.busy = False - time.sleep(self.delay) - if exception is not None: - return False - - -class Issues: - def __init__(self, org, repo, token): - self.repo = repo - self.org = org - self.issues_url = "https://github.com/%s/%s/issues" % ( - self.org, self.repo) - self.github_url = 'https://api.github.com/repos/%s/%s' % ( - self.org, self.repo) - - self.api_token = token - self.headers = {} - self.headers['Authorization'] = 'token %s' % self.api_token - self.headers['Accept'] = 'application/vnd.github.golden-comet-preview+json' - self.items = [] - - def get_pull(self, pull_nr): - url = ("%s/pulls/%s" % (self.github_url, pull_nr)) - response = requests.get("%s" % (url), headers=self.headers) - if response.status_code != 200: - raise RuntimeError( - "Failed to get issue due to unexpected HTTP status code: {}".format( - response.status_code) - ) - item = response.json() - return item - - def get_issue(self, issue_nr): - url = ("%s/issues/%s" % (self.github_url, issue_nr)) - response = requests.get("%s" % (url), headers=self.headers) - if response.status_code != 200: - return None - - item = response.json() - return item - - def list_issues(self, url): - response = requests.get("%s" % (url), headers=self.headers) - if response.status_code != 200: - raise RuntimeError( - "Failed to get issue due to unexpected HTTP status code: {}".format( - response.status_code) - ) - self.items = self.items + response.json() - - try: - print("Getting more items...") - next_issues = response.links["next"] - if next_issues: - next_url = next_issues['url'] - self.list_issues(next_url) - except KeyError: - pass - - def issues_since(self, date, state="closed"): - self.list_issues("%s/issues?per_page=100&state=%s&since=%s" % - (self.github_url, state, date)) - - def pull_requests(self, base='v1.14-branch', state='closed'): - self.list_issues("%s/pulls?per_page=100&state=%s&base=%s" % - (self.github_url, state, base)) - - -def parse_args(): - global args - - parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) - - parser.add_argument("-o", "--org", default="zephyrproject-rtos", - help="Github organisation") - - parser.add_argument("-r", "--repo", default="zephyr", - help="Github repository") - - parser.add_argument("-f", "--file", required=True, - help="Name of output file.") - - parser.add_argument("-s", "--issues-since", - help="""List issues since date where date - is in the format 2019-09-01.""") - - parser.add_argument("-b", "--issues-in-pulls", - help="List issues in pulls for a given branch") - - parser.add_argument("-c", "--commits-file", - help="""File with all commits (git log a..b) to - be parsed for fixed bugs.""") - - args = parser.parse_args() - - -def main(): - parse_args() - - token = os.environ.get('GITHUB_TOKEN', None) - if not token: - sys.exit("""Github token not set in environment, -set the env. variable GITHUB_TOKEN please and retry.""") - - i = Issues(args.org, args.repo, token) - - if args.issues_since: - i.issues_since(args.issues_since) - count = 0 - with open(args.file, "w") as f: - for issue in i.items: - if 'pull_request' not in issue: - # * :github:`8193` - STM32 config BUILD_OUTPUT_HEX fail - f.write("* :github:`{}` - {}\n".format( - issue['number'], issue['title'].strip())) - count = count + 1 - elif args.issues_in_pulls: - i.pull_requests(base=args.issues_in_pulls) - count = 0 - - bugs = set() - backports = [] - for issue in i.items: - if not isinstance(issue['body'], str): - continue - match = re.findall(r"(Fixes|Closes|Fixed|close):? #([0-9]+)", - issue['body'], re.MULTILINE) - if match: - for mm in match: - bugs.add(mm[1]) - else: - match = re.findall( - r"Backport #([0-9]+)", issue['body'], re.MULTILINE) - if match: - backports.append(match[0]) - - # follow PRs to their origin (backports) - with Spinner(): - for p in backports: - item = i.get_pull(p) - match = re.findall(r"(Fixes|Closes|Fixed|close):? #([0-9]+)", - item['body'], re.MULTILINE) - for mm in match: - bugs.add(mm[1]) - - # now open commits - if args.commits_file: - print("Open commits file and parse for fixed bugs...") - with open(args.commits_file, "r") as commits: - content = commits.read() - match = re.findall(r"(Fixes|Closes|Fixed|close):? #([0-9]+)", - str(content), re.MULTILINE) - for mm in match: - bugs.add(mm[1]) - - print("Create output file...") - with Spinner(): - with open(args.file, "w") as f: - for m in sorted(bugs): - item = i.get_issue(m) - if item: - # * :github:`8193` - STM32 config BUILD_OUTPUT_HEX fail - f.write("* :github:`{}` - {}\n".format( - item['number'], item['title'].strip())) - - -if __name__ == '__main__': - main() From 76ba68cd18005b4b767e05acd605fa6ab3c2dfce Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Fri, 21 Jul 2023 10:38:38 +0200 Subject: [PATCH 1771/2042] drivers: ethernet: stm32 generate_mac Ethernet MAC addresses are not unique enough use unique_device_ID full range (96 bits) call crc32_ieee() to generate last 3 bytes of mac address Signed-off-by: Marc Desvaux --- drivers/ethernet/eth_stm32_hal.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 267bddfb1db4..4d8ea3479f2f 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -1098,6 +1098,9 @@ void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_handle) static void generate_mac(uint8_t *mac_addr) { + uint8_t unique_device_ID_12_bytes[12]; + uint32_t result_mac_32_bits; + #if defined(ETH_STM32_RANDOM_MAC) /* Either CONFIG_ETH_STM32_HAL_RANDOM_MAC or device tree property */ /* "zephyr,random-mac-address" is set, generate a random mac address */ @@ -1116,7 +1119,10 @@ static void generate_mac(uint8_t *mac_addr) mac_addr[5] = CONFIG_ETH_STM32_HAL_MAC5; #else /* Nothing defined by the user, use device id */ - hwinfo_get_device_id(&mac_addr[3], 3); + hwinfo_get_device_id(unique_device_ID_12_bytes, 12); + result_mac_32_bits = crc32_ieee((uint8_t *)unique_device_ID_12_bytes, 12); + memcpy(&mac_addr[3], &result_mac_32_bits, 3); + #endif /* NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0))) */ #endif } From b6e03417c7e2016829acf6e9767d192d290bf036 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 21:47:02 +1000 Subject: [PATCH 1772/2042] dts: gen_defines: generate `_ORD_STR_SORTABLE` Generate a zero padded variant of `_ORD` that is suitable for use in linker scripts with the `SORT` property, so that `6` is correctly placed before `24`, and so on. Signed-off-by: Jordan Yates --- include/zephyr/devicetree/ordinals.h | 7 +++++++ scripts/dts/gen_defines.py | 1 + 2 files changed, 8 insertions(+) diff --git a/include/zephyr/devicetree/ordinals.h b/include/zephyr/devicetree/ordinals.h index c8b0302d1c3c..5dd9d00e308a 100644 --- a/include/zephyr/devicetree/ordinals.h +++ b/include/zephyr/devicetree/ordinals.h @@ -24,6 +24,13 @@ */ #define DT_DEP_ORD(node_id) DT_CAT(node_id, _ORD) +/** + * @brief Get a node's dependency ordinal in string sortable form + * @param node_id Node identifier + * @return the node's dependency ordinal as a zero-padded integer literal + */ +#define DT_DEP_ORD_STR_SORTABLE(node_id) DT_CAT(node_id, _ORD_STR_SORTABLE) + /** * @brief Get a list of dependency ordinals of a node's direct dependencies * diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index ed47d3ae1512..0c95557cda2d 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -747,6 +747,7 @@ def fmt_dep_list(dep_list): out_comment("Node's dependency ordinal:") out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal) + out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}") out_comment("Ordinals for what this node depends on directly:") out_dt_define(f"{node.z_path_id}_REQUIRES_ORDS", From 2790547cbde0b5819146529013c70f496058e4e8 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 21:52:17 +1000 Subject: [PATCH 1773/2042] init: add sub-priority to internal ordering Add a sub-priority field to `Z_INIT_ENTRY_SECTION`, which is used to ensure that multiple drivers running at the same init priority still run in an order that respects their devicetree dependencies. This is primarily useful when multiple instances of the same device are instantiated that can depend on each other, for example power domains and i2c muxes. Signed-off-by: Jordan Yates --- include/zephyr/device.h | 22 ++++++++++++++++++---- include/zephyr/init.h | 10 ++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 2ea95a2d563a..ce9b6c1312e7 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -848,6 +848,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev) #endif /* CONFIG_DEVICE_DEPS */ +/** + * @brief Init sub-priority of the device + * + * The sub-priority is defined by the devicetree ordinal, which ensures that + * multiple drivers running at the same priority level run in an order that + * respects the devicetree dependencies. + */ +#define Z_DEVICE_INIT_SUB_PRIO(node_id) \ + COND_CODE_1(DT_NODE_EXISTS(node_id), \ + (DT_DEP_ORD_STR_SORTABLE(node_id)), (0)) + /** * @brief Maximum device name length. * @@ -923,14 +934,17 @@ static inline bool z_impl_device_is_ready(const struct device *dev) /** * @brief Define the init entry for a device. * + * @param node_id Devicetree node id for the device (DT_INVALID_NODE if a + * software device). * @param dev_id Device identifier. * @param init_fn_ Device init function. * @param level Initialization level. * @param prio Initialization priority. */ -#define Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn_, level, prio) \ - static const Z_DECL_ALIGN(struct init_entry) \ - Z_INIT_ENTRY_SECTION(level, prio) __used __noasan \ +#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ + 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), \ @@ -967,7 +981,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ prio, api, state, Z_DEVICE_DEPS_NAME(dev_id)); \ \ - Z_DEVICE_INIT_ENTRY_DEFINE(dev_id, init_fn, level, prio) + Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn, level, prio) #if defined(CONFIG_HAS_DTS) || defined(__DOXYGEN__) /** diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 77e8fddc0cc6..9b0d2993d620 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -128,10 +128,12 @@ struct init_entry { * @brief Init entry section. * * Each init entry is placed in a section with a name crafted so that it allows - * linker scripts to sort them according to the specified level/priority. + * linker scripts to sort them according to the specified + * level/priority/sub-priority. */ -#define Z_INIT_ENTRY_SECTION(level, prio) \ - __attribute__((__section__(".z_init_" #level STRINGIFY(prio)"_"))) +#define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \ + __attribute__((__section__( \ + ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) /** @endcond */ @@ -186,7 +188,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) __used __noasan \ + Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ Z_INIT_ENTRY_NAME(name) = { \ .init_fn = {.sys = (init_fn_)}, \ .dev = NULL, \ From 96138d233f1a035064ef34830bcb426f8b6e43a2 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 10:46:11 +1000 Subject: [PATCH 1774/2042] tests: kernel: device: test sub-priority Add tests for sorting devices at the same init priority based on their devicetree ordinals. Signed-off-by: Jordan Yates --- tests/kernel/device/app.overlay | 17 ++++++++++ .../device/boards/hifive_unmatched.overlay | 17 ++++++++++ .../kernel/device/dts/bindings/fakedomain.yml | 8 +++++ tests/kernel/device/src/main.c | 22 +++++++++++- tests/kernel/device/src/test_driver_init.c | 34 +++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/kernel/device/dts/bindings/fakedomain.yml diff --git a/tests/kernel/device/app.overlay b/tests/kernel/device/app.overlay index aae8873f6b8d..d7426f2b6134 100644 --- a/tests/kernel/device/app.overlay +++ b/tests/kernel/device/app.overlay @@ -51,4 +51,21 @@ "dale"; status = "okay"; }; + + fakedomain_0: fakedomain_0 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_2>; + }; + + fakedomain_1: fakedomain_1 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_0>; + }; + + fakedomain_2: fakedomain_2 { + compatible = "fakedomain"; + status = "okay"; + }; }; diff --git a/tests/kernel/device/boards/hifive_unmatched.overlay b/tests/kernel/device/boards/hifive_unmatched.overlay index 4a7ce8155f5d..40fa5e74adb4 100644 --- a/tests/kernel/device/boards/hifive_unmatched.overlay +++ b/tests/kernel/device/boards/hifive_unmatched.overlay @@ -48,4 +48,21 @@ "dale"; status = "okay"; }; + + fakedomain_0: fakedomain_0 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_2>; + }; + + fakedomain_1: fakedomain_1 { + compatible = "fakedomain"; + status = "okay"; + power-domain = <&fakedomain_0>; + }; + + fakedomain_2: fakedomain_2 { + compatible = "fakedomain"; + status = "okay"; + }; }; diff --git a/tests/kernel/device/dts/bindings/fakedomain.yml b/tests/kernel/device/dts/bindings/fakedomain.yml new file mode 100644 index 000000000000..a676419de1fa --- /dev/null +++ b/tests/kernel/device/dts/bindings/fakedomain.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, CSIRO +# SPDX-License-Identifier: Apache-2.0 + +description: Properties for fake power domain + +compatible: "fakedomain" + +include: base.yaml diff --git a/tests/kernel/device/src/main.c b/tests/kernel/device/src/main.c index cfc89da2f076..a3e9430c15a6 100644 --- a/tests/kernel/device/src/main.c +++ b/tests/kernel/device/src/main.c @@ -265,6 +265,7 @@ ZTEST(device, test_sys_init_multiple) /* this is for storing sequence during initialization */ extern int init_level_sequence[4]; extern int init_priority_sequence[4]; +extern int init_sub_priority_sequence[3]; extern unsigned int seq_level_cnt; extern unsigned int seq_priority_cnt; @@ -298,7 +299,7 @@ ZTEST(device, test_device_init_level) /** * @brief Test initialization priorities for device driver instances * - * details After the defined device instances have initialized, we check the + * @details After the defined device instances have initialized, we check the * sequence number that each driver stored during initialization. If the * sequence of initial priority stored is corresponding with our expectation, it * means assigning the priority for driver instance works. @@ -322,6 +323,25 @@ ZTEST(device, test_device_init_priority) "init sequence is not correct"); } +/** + * @brief Test initialization sub-priorities for device driver instances + * + * @details After the defined device instances have initialized, we check the + * sequence number that each driver stored during initialization. If the + * sequence of initial priority stored is corresponding with our expectation, it + * means using the devicetree for sub-priority sorting works. + * + * @ingroup kernel_device_tests + */ +ZTEST(device, test_device_init_sub_priority) +{ + /* fakedomain_1 depends on fakedomain_0 which depends on fakedomain_2, + * therefore we require that the initialisation runs in the reverse order. + */ + zassert_equal(init_sub_priority_sequence[0], 1, ""); + zassert_equal(init_sub_priority_sequence[1], 2, ""); + zassert_equal(init_sub_priority_sequence[2], 0, ""); +} /** * @brief Test abstraction of device drivers with common functionalities diff --git a/tests/kernel/device/src/test_driver_init.c b/tests/kernel/device/src/test_driver_init.c index 1c468f72a214..e89d6acc7ff4 100644 --- a/tests/kernel/device/src/test_driver_init.c +++ b/tests/kernel/device/src/test_driver_init.c @@ -39,8 +39,10 @@ /* this is for storing sequence during initialization */ __pinned_bss int init_level_sequence[4] = {0}; __pinned_bss int init_priority_sequence[4] = {0}; +__pinned_bss int init_sub_priority_sequence[3] = {0}; __pinned_bss unsigned int seq_level_cnt; __pinned_bss unsigned int seq_priority_cnt; +__pinned_bss unsigned int seq_sub_priority_cnt; /* define driver type 1: for testing initialize levels and priorities */ typedef int (*my_api_configure_t)(const struct device *dev, int dev_config); @@ -126,6 +128,28 @@ static int my_driver_pri_4_init(const struct device *dev) return 0; } +/* driver init function of testing sub_priority */ +static int my_driver_sub_pri_0_init(const struct device *dev) +{ + init_sub_priority_sequence[0] = seq_sub_priority_cnt++; + + return 0; +} + +static int my_driver_sub_pri_1_init(const struct device *dev) +{ + init_sub_priority_sequence[1] = seq_sub_priority_cnt++; + + return 0; +} + +static int my_driver_sub_pri_2_init(const struct device *dev) +{ + init_sub_priority_sequence[2] = seq_sub_priority_cnt++; + + return 0; +} + /** * @brief Test providing control device driver initialization order * @@ -172,3 +196,13 @@ DEVICE_DEFINE(my_driver_priority_2, MY_DRIVER_PRI_2, DEVICE_DEFINE(my_driver_priority_3, MY_DRIVER_PRI_3, &my_driver_pri_3_init, NULL, NULL, NULL, POST_KERNEL, 3, &funcs_my_drivers); + +/* Create several devices at the same init priority that depend on each + * other in devicetree so that we can validate linker sorting. + */ +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_0), my_driver_sub_pri_0_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_1), my_driver_sub_pri_1_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); +DEVICE_DT_DEFINE(DT_NODELABEL(fakedomain_2), my_driver_sub_pri_2_init, + NULL, NULL, NULL, APPLICATION, 33, NULL); From 60a082b8dde05e9e9a6777c3e4b3f916f419bc9a Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Tue, 18 Jul 2023 18:25:38 +1000 Subject: [PATCH 1775/2042] tests: lib: devicetree: api: test `DT_DEP_ORD_STR_SORTABLE` Add basic testing of the new `DT_DEP_ORD_STR_SORTABLE` macro. Signed-off-by: Jordan Yates --- tests/lib/devicetree/api/src/main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index adeee59bf1f2..5b597c1df9db 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -25,6 +25,8 @@ #include #include +#include + #define TEST_CHILDREN DT_PATH(test, test_children) #define TEST_DEADBEEF DT_PATH(test, gpio_deadbeef) #define TEST_ABCD1234 DT_PATH(test, gpio_abcd1234) @@ -2440,6 +2442,28 @@ ZTEST(devicetree_api, test_dep_ord) } } +ZTEST(devicetree_api, test_dep_ord_str_sortable) +{ + const char *root_ord = STRINGIFY(DT_DEP_ORD_STR_SORTABLE(DT_ROOT)); + + /* Root ordinal is always 0 */ + zassert_mem_equal(root_ord, "00000", 6); + + /* Test string sortable versions equal decimal values. + * We go through the STRINGIFY()->atoi conversion cycle to avoid + * the C compiler treating the number as octal due to leading zeros. + * atoi() simply ignores them. + */ + zassert_equal(atoi(STRINGIFY(DT_DEP_ORD_STR_SORTABLE(DT_ROOT))), + DT_DEP_ORD(DT_ROOT), "Invalid sortable string"); + zassert_equal(atoi(STRINGIFY(DT_DEP_ORD_STR_SORTABLE(TEST_DEADBEEF))), + DT_DEP_ORD(TEST_DEADBEEF), "Invalid sortable string"); + zassert_equal(atoi(STRINGIFY(DT_DEP_ORD_STR_SORTABLE(TEST_TEMP))), + DT_DEP_ORD(TEST_TEMP), "Invalid sortable string"); + zassert_equal(atoi(STRINGIFY(DT_DEP_ORD_STR_SORTABLE(TEST_REG))), + DT_DEP_ORD(TEST_REG), "Invalid sortable string"); +} + ZTEST(devicetree_api, test_path) { zassert_true(!strcmp(DT_NODE_PATH(DT_ROOT), "/"), ""); From 23280f4a547a30cd0d7079ef3420c137f291be5a Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 19 Jul 2023 21:20:18 +1000 Subject: [PATCH 1776/2042] scripts: build: check_init_priorities: parse new naming Update the script to parse the new section naming. The ordering type is converted from an integer to a tuple, which still compares correctly due to the elementwise behaviour of tuple comparison. Signed-off-by: Jordan Yates --- scripts/build/check_init_priorities.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/build/check_init_priorities.py b/scripts/build/check_init_priorities.py index 444bb428f5ef..4036d8984b5e 100755 --- a/scripts/build/check_init_priorities.py +++ b/scripts/build/check_init_priorities.py @@ -76,20 +76,23 @@ class Priority: def __init__(self, name): for idx, level in enumerate(_DEVICE_INIT_LEVELS): if level in name: - _, priority = name.strip("_").split(level) + _, priority_str = name.strip("_").split(level) + priority, sub_priority = priority_str.split("_") self._level = idx self._priority = int(priority) - self._level_priority = self._level * 100 + self._priority + self._sub_priority = int(sub_priority) + # Tuples compare elementwise in order + self._level_priority = (self._level, self._priority, self._sub_priority) return raise ValueError("Unknown level in %s" % name) def __repr__(self): - return "<%s %s %d>" % (self.__class__.__name__, - _DEVICE_INIT_LEVELS[self._level], self._priority) + return "<%s %s %d %d>" % (self.__class__.__name__, + _DEVICE_INIT_LEVELS[self._level], self._priority, self._sub_priority) def __str__(self): - return "%s %d" % (_DEVICE_INIT_LEVELS[self._level], self._priority) + return "%s %d %d" % (_DEVICE_INIT_LEVELS[self._level], self._priority, self._sub_priority) def __lt__(self, other): return self._level_priority < other._level_priority From 50d42dcdb25437b6119fef49d50bfd3089a8ffd4 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 19 Jul 2023 21:21:46 +1000 Subject: [PATCH 1777/2042] scripts: build: check_init_priorities_test: fix Fix the test script for the changes made to section naming. Signed-off-by: Jordan Yates --- scripts/build/check_init_priorities_test.py | 61 +++++++++++---------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/scripts/build/check_init_priorities_test.py b/scripts/build/check_init_priorities_test.py index e704b1f35dea..85185ebc258b 100755 --- a/scripts/build/check_init_priorities_test.py +++ b/scripts/build/check_init_priorities_test.py @@ -19,17 +19,17 @@ class TestPriority(unittest.TestCase): """Tests for the Priority class.""" def test_priority_parsing(self): - prio1 = check_init_priorities.Priority(".rel.z_init_POST_KERNEL12_") - self.assertEqual(prio1._level_priority, 312) + prio1 = check_init_priorities.Priority(".rel.z_init_POST_KERNEL12_0_") + self.assertEqual(prio1._level_priority, (3, 12, 0)) - prio2 = check_init_priorities.Priority("noisenoise_POST_KERNEL99_") - self.assertEqual(prio2._level_priority, 399) + prio2 = check_init_priorities.Priority("noisenoise_POST_KERNEL99_00023_") + self.assertEqual(prio2._level_priority, (3, 99, 23)) - prio3 = check_init_priorities.Priority("_PRE_KERNEL_10_") - self.assertEqual(prio3._level_priority, 100) + prio3 = check_init_priorities.Priority("_PRE_KERNEL_10_99999_") + self.assertEqual(prio3._level_priority, (1, 0, 99999)) - prio4 = check_init_priorities.Priority("_PRE_KERNEL_110_") - self.assertEqual(prio4._level_priority, 110) + prio4 = check_init_priorities.Priority("_PRE_KERNEL_110_00001_") + self.assertEqual(prio4._level_priority, (1, 10, 1)) with self.assertRaises(ValueError): check_init_priorities.Priority("i-am-not-a-priority") @@ -40,32 +40,35 @@ def test_priority_parsing(self): def test_priority_levels(self): prios = [ - check_init_priorities.Priority(".rel.z_init_EARLY0_"), - check_init_priorities.Priority(".rel.z_init_EARLY1_"), - check_init_priorities.Priority(".rel.z_init_EARLY11_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_10_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_11_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_111_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_20_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_21_"), - check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_211_"), - check_init_priorities.Priority(".rel.z_init_POST_KERNEL0_"), - check_init_priorities.Priority(".rel.z_init_POST_KERNEL1_"), - check_init_priorities.Priority(".rel.z_init_POST_KERNEL11_"), - check_init_priorities.Priority(".rel.z_init_APPLICATION0_"), - check_init_priorities.Priority(".rel.z_init_APPLICATION1_"), - check_init_priorities.Priority(".rel.z_init_APPLICATION11_"), - check_init_priorities.Priority(".rel.z_init_SMP0_"), - check_init_priorities.Priority(".rel.z_init_SMP1_"), - check_init_priorities.Priority(".rel.z_init_SMP11_"), + check_init_priorities.Priority(".rel.z_init_EARLY0_0_"), + check_init_priorities.Priority(".rel.z_init_EARLY1_0_"), + check_init_priorities.Priority(".rel.z_init_EARLY11_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_10_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_11_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_111_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_111_1_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_111_00002_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_111_00010_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_20_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_21_0_"), + check_init_priorities.Priority(".rel.z_init_PRE_KERNEL_211_0_"), + check_init_priorities.Priority(".rel.z_init_POST_KERNEL0_0_"), + check_init_priorities.Priority(".rel.z_init_POST_KERNEL1_0_"), + check_init_priorities.Priority(".rel.z_init_POST_KERNEL11_0_"), + check_init_priorities.Priority(".rel.z_init_APPLICATION0_0_"), + check_init_priorities.Priority(".rel.z_init_APPLICATION1_0_"), + check_init_priorities.Priority(".rel.z_init_APPLICATION11_0_"), + check_init_priorities.Priority(".rel.z_init_SMP0_0_"), + check_init_priorities.Priority(".rel.z_init_SMP1_0_"), + check_init_priorities.Priority(".rel.z_init_SMP11_0_"), ] self.assertListEqual(prios, sorted(prios)) def test_priority_strings(self): - prio = check_init_priorities.Priority(".rel.z_init_POST_KERNEL12_") - self.assertEqual(str(prio), "POST_KERNEL 12") - self.assertEqual(repr(prio), "") + prio = check_init_priorities.Priority(".rel.z_init_POST_KERNEL12_00023_") + self.assertEqual(str(prio), "POST_KERNEL 12 23") + self.assertEqual(repr(prio), "") class testZephyrObjectFile(unittest.TestCase): """Tests for the ZephyrObjectFile class.""" From b65ac5b9e012ab83bcaae4a8077d50cd7bb31a5a Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 19 Jul 2023 21:38:49 +1000 Subject: [PATCH 1778/2042] tests: misc: check_init_priorities: force two stage linking Add `CONFIG_DEVICE_DEPS` to force two stage linking, otherwise the following check means the test never runs: ``` if (TARGET zephyr_pre1) add_dependencies(zephyr_pre1 check_init_priorities_output) endif() ``` Signed-off-by: Jordan Yates --- tests/misc/check_init_priorities/prj.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/misc/check_init_priorities/prj.conf b/tests/misc/check_init_priorities/prj.conf index b7db25411d06..bd094fca874f 100644 --- a/tests/misc/check_init_priorities/prj.conf +++ b/tests/misc/check_init_priorities/prj.conf @@ -1 +1,2 @@ -# Empty +# Required to force 2 stage linking +CONFIG_DEVICE_DEPS=y From f38e6aa0d17c9bfa4d2d10753b86850b9f5ca54a Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 19 Jul 2023 21:39:57 +1000 Subject: [PATCH 1779/2042] tests: misc: check_init_priorities: update output Update the expected output of the init priority checking. Signed-off-by: Jordan Yates --- .../validate_check_init_priorities_output.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 5d46a73451fc..1e5f92a1921a 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 @@ -8,12 +8,12 @@ import sys REFERENCE_OUTPUT = [ - "INFO: /i2c@11112222/test-i2c-dev@12 PRE_KERNEL_1 51 > /gpio@ffff PRE_KERNEL_1 50", - "INFO: /i2c@11112222/test-i2c-dev@12 PRE_KERNEL_1 51 > /i2c@11112222 PRE_KERNEL_1 50", - "ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 49 < /gpio@ffff PRE_KERNEL_1 50", - "ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 49 < /i2c@11112222 PRE_KERNEL_1 50", - "WARNING: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 50 == /gpio@ffff PRE_KERNEL_1 50", - "WARNING: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 50 == /i2c@11112222 PRE_KERNEL_1 50", + "INFO: /i2c@11112222/test-i2c-dev@12 PRE_KERNEL_1 51 31 > /gpio@ffff PRE_KERNEL_1 50 27", + "INFO: /i2c@11112222/test-i2c-dev@12 PRE_KERNEL_1 51 31 > /i2c@11112222 PRE_KERNEL_1 50 28", + "ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 49 29 < /gpio@ffff PRE_KERNEL_1 50 27", + "ERROR: /i2c@11112222/test-i2c-dev@10 PRE_KERNEL_1 49 29 < /i2c@11112222 PRE_KERNEL_1 50 28", + "INFO: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 50 30 > /gpio@ffff PRE_KERNEL_1 50 27", + "INFO: /i2c@11112222/test-i2c-dev@11 PRE_KERNEL_1 50 30 > /i2c@11112222 PRE_KERNEL_1 50 28", ] if len(sys.argv) != 2: From 79869f8abd6dfe2609b2e9d1ac72acf415ba5ad8 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Sat, 10 Jun 2023 00:25:52 +0200 Subject: [PATCH 1780/2042] dts: xtensa: esp32xx rework soc/sip list Introduce dtsi files representing the current portfolio of chips and modules based on the followint criteria: - flash size - psram size - gpio count - certification status Update the boards dts files according to which SOC/SIP they are using. Signed-off-by: Marek Matej --- boards/xtensa/esp32/esp32.dts | 2 +- .../esp32_ethernet_kit/esp32_ethernet_kit.dts | 2 +- boards/xtensa/esp32_net/esp32_net.dts | 2 +- .../esp32s2_franzininho.dts | 2 +- boards/xtensa/esp32s2_saola/esp32s2_saola.dts | 4 ++- .../esp32s3_devkitm/esp32s3_devkitm.dts | 2 +- .../xtensa/esp_wrover_kit/esp_wrover_kit.dts | 2 +- .../heltec_wifi_lora32_v2.dts | 7 ++++- boards/xtensa/m5stickc_plus/m5stickc_plus.dts | 2 +- boards/xtensa/odroid_go/odroid_go.dts | 2 +- .../olimex_esp32_evb/olimex_esp32_evb.dts | 2 +- boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts | 2 +- .../{esp32.dtsi => esp32/esp32_common.dtsi} | 15 +++++++++- dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi | 14 +++++++++ .../espressif/esp32/esp32_d0wdr2_v3.dtsi | 20 +++++++++++++ dts/xtensa/espressif/esp32/esp32_net.dtsi | 16 ++++++++++ dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi | 18 ++++++++++++ dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi | 18 ++++++++++++ .../espressif/esp32/esp32_pico_v3_02.dtsi | 24 +++++++++++++++ dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi | 17 +++++++++++ .../espressif/esp32/esp32_wroom_32ue_n16.dtsi | 22 ++++++++++++++ .../espressif/esp32/esp32_wroom_32ue_n4.dtsi | 22 ++++++++++++++ .../espressif/esp32/esp32_wroom_32ue_n8.dtsi | 22 ++++++++++++++ .../espressif/esp32/esp32_wroom_da_n16.dtsi | 23 +++++++++++++++ .../espressif/esp32/esp32_wroom_da_n4.dtsi | 23 +++++++++++++++ .../espressif/esp32/esp32_wroom_da_n8.dtsi | 23 +++++++++++++++ .../espressif/esp32/esp32_wrover_e_n16r2.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n16r4.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n16r8.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n4r2.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n4r8.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n8r2.dtsi | 28 ++++++++++++++++++ .../espressif/esp32/esp32_wrover_e_n8r8.dtsi | 29 +++++++++++++++++++ dts/xtensa/espressif/esp32s2/esp32s2.dtsi | 7 +++++ .../esp32s2_common.dtsi} | 15 +++++++++- dts/xtensa/espressif/esp32s2/esp32s2_fh2.dtsi | 12 ++++++++ dts/xtensa/espressif/esp32s2/esp32s2_fh4.dtsi | 12 ++++++++ .../espressif/esp32s2/esp32s2_fn4r2.dtsi | 18 ++++++++++++ .../espressif/esp32s2/esp32s2_mini_n4.dtsi | 12 ++++++++ .../espressif/esp32s2/esp32s2_mini_n4r2.dtsi | 18 ++++++++++++ dts/xtensa/espressif/esp32s2/esp32s2_r2.dtsi | 13 +++++++++ .../espressif/esp32s2/esp32s2_solo_n16.dtsi | 12 ++++++++ .../espressif/esp32s2/esp32s2_solo_n4.dtsi | 12 ++++++++ .../espressif/esp32s2/esp32s2_solo_n4r2.dtsi | 18 ++++++++++++ .../espressif/esp32s2/esp32s2_solo_n8.dtsi | 12 ++++++++ .../espressif/esp32s2/esp32s2_wroom.dtsi | 12 ++++++++ .../esp32s2/esp32s2_wrover_n16r2.dtsi | 18 ++++++++++++ .../esp32s2/esp32s2_wrover_n4r2.dtsi | 18 ++++++++++++ .../esp32s2/esp32s2_wrover_n8r2.dtsi | 18 ++++++++++++ dts/xtensa/espressif/esp32s3/esp32s3.dtsi | 7 +++++ .../esp32s3_common.dtsi} | 18 ++++++++++-- dts/xtensa/espressif/esp32s3/esp32s3_fn8.dtsi | 12 ++++++++ .../espressif/esp32s3/esp32s3_mini_n4r2.dtsi | 18 ++++++++++++ .../espressif/esp32s3/esp32s3_mini_n8.dtsi | 12 ++++++++ .../espressif/esp32s3/esp32s3_pico_n8r2.dtsi | 18 ++++++++++++ .../espressif/esp32s3/esp32s3_pico_n8r8.dtsi | 18 ++++++++++++ dts/xtensa/espressif/esp32s3/esp32s3_r2.dtsi | 13 +++++++++ dts/xtensa/espressif/esp32s3/esp32s3_r8.dtsi | 13 +++++++++ dts/xtensa/espressif/esp32s3/esp32s3_r8v.dtsi | 13 +++++++++ .../espressif/esp32s3/esp32s3_wroom_n16.dtsi | 12 ++++++++ .../esp32s3/esp32s3_wroom_n16r8.dtsi | 18 ++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n4.dtsi | 12 ++++++++ .../espressif/esp32s3/esp32s3_wroom_n4r8.dtsi | 18 ++++++++++++ .../espressif/esp32s3/esp32s3_wroom_n8.dtsi | 12 ++++++++ .../espressif/esp32s3/esp32s3_wroom_n8r8.dtsi | 17 +++++++++++ 65 files changed, 947 insertions(+), 16 deletions(-) rename dts/xtensa/espressif/{esp32.dtsi => esp32/esp32_common.dtsi} (95%) create mode 100644 dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_net.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi create mode 100644 dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2.dtsi rename dts/xtensa/espressif/{esp32s2.dtsi => esp32s2/esp32s2_common.dtsi} (94%) create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_fh2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_fh4.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_fn4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_mini_n4.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_mini_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_solo_n16.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_solo_n4.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_solo_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_solo_n8.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_wroom.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_wrover_n16r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_wrover_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s2/esp32s2_wrover_n8r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3.dtsi rename dts/xtensa/espressif/{esp32s3.dtsi => esp32s3/esp32s3_common.dtsi} (94%) create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_fn8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_mini_n4r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_mini_n8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_r2.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_r8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_r8v.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8.dtsi create mode 100644 dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi diff --git a/boards/xtensa/esp32/esp32.dts b/boards/xtensa/esp32/esp32.dts index 3d61902581a2..5fcad1aab5db 100644 --- a/boards/xtensa/esp32/esp32.dts +++ b/boards/xtensa/esp32/esp32.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "esp32-pinctrl.dtsi" / { diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts index 0ede058c9f4a..d772cd817d3c 100644 --- a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts +++ b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "esp32_ethernet_kit-pinctrl.dtsi" / { diff --git a/boards/xtensa/esp32_net/esp32_net.dts b/boards/xtensa/esp32_net/esp32_net.dts index 21f56f565fa0..7479d342fb69 100644 --- a/boards/xtensa/esp32_net/esp32_net.dts +++ b/boards/xtensa/esp32_net/esp32_net.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include / { model = "esp32_net"; diff --git a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts index f7492d696620..66c856060974 100644 --- a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts +++ b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "esp32s2_franzininho-pinctrl.dtsi" / { diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 4e34faf09a0d..73c2915f3a4e 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "esp32s2_saola-pinctrl.dtsi" / { @@ -103,8 +103,10 @@ pinctrl-names = "default"; }; + &flash0 { status = "okay"; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index f61034c2d1b7..c52662155615 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "esp32s3_devkitm-pinctrl.dtsi" / { diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts index 8c6ece9cea62..05f7a00b2da0 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "esp_wrover_kit-pinctrl.dtsi" / { 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 e23aedbb50e9..e660a726b093 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 @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "heltec_wifi_lora32_v2-pinctrl.dtsi" / { @@ -111,6 +111,11 @@ }; &flash0 { + /* the board is using plain d0wd SoC part without the flash + * so any additional flash size should be defined at the board level + */ + reg = <0x0 DT_SIZE_M(8)>; + status = "okay"; partitions { compatible = "fixed-partitions"; diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts index c85ac0762f2d..5103997d92a1 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "m5stickc_plus-pinctrl.dtsi" / { diff --git a/boards/xtensa/odroid_go/odroid_go.dts b/boards/xtensa/odroid_go/odroid_go.dts index 19b9b4f361c8..740c9a9f94c5 100644 --- a/boards/xtensa/odroid_go/odroid_go.dts +++ b/boards/xtensa/odroid_go/odroid_go.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include "espressif/esp32.dtsi" +#include #include "odroid_go-pinctrl.dtsi" / { diff --git a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts index 248dc7296572..008e5b326f2b 100644 --- a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts +++ b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "olimex_esp32_evb-pinctrl.dtsi" / { diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index 79e29602f0d1..3090f9ff5aff 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "xiao_esp32s3-pinctrl.dtsi" #include "seeed_xiao_connector.dtsi" diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32/esp32_common.dtsi similarity index 95% rename from dts/xtensa/espressif/esp32.dtsi rename to dts/xtensa/espressif/esp32/esp32_common.dtsi index f8acfbdfb9ca..e862a653e9be 100644 --- a/dts/xtensa/espressif/esp32.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_common.dtsi @@ -129,12 +129,20 @@ flash0: flash@0 { compatible = "soc-nv-flash"; - reg = <0 0x400000>; erase-block-size = <4096>; write-block-size = <4>; + /* Flash size is specified in SOC/SIP dtsi */ }; }; + psram0: psram@3f800000 { + device_type = "memory"; + compatible = "mmio-sram"; + /* PSRAM size is specified in SOC/SIP dtsi */ + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "disabled"; + }; + ipm0: ipm@3ffed238 { compatible = "espressif,esp32-ipm"; reg = <0x3FFED238 0x8>; @@ -243,6 +251,11 @@ reg = <0x3ff44000 0x800>; interrupts = ; interrupt-parent = <&intc>; + /* Maximum available pins (per port) + * Actual occupied pins are specified + * on part number dtsi level, using + * the `gpio-reserved-ranges` property. + */ ngpios = <32>; /* 0..31 */ }; diff --git a/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi new file mode 100644 index 000000000000..6511f3d351a2 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_d0wd_v3.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <20>,<24>,<28 31>; // NC +}; + +/* Add flash or psram on board or application level */ diff --git a/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi new file mode 100644 index 000000000000..eb5e239c1aaa --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_d0wdr2_v3.dtsi @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 10>, // embeddef psram + <11>, // flash CS + <20>,<24>,<28 31>; // NC +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_net.dtsi b/dts/xtensa/espressif/esp32/esp32_net.dtsi new file mode 100644 index 000000000000..00657ac0425f --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_net.dtsi @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <20>,<24>,<28 31>; // NC +}; + +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi new file mode 100644 index 000000000000..8ed101d24bc2 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_pico_d4.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 8>,<11>,<16 17>, // embedded flash + <20>, <24>, <28 31>; // NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi new file mode 100644 index 000000000000..76e4d4c05ebb --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_pico_v3.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <16 18>,<23>, // limitations + <24>,<28 31>; // NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi b/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi new file mode 100644 index 000000000000..249debca7520 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_pico_v3_02.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>, // flash + <24 25>,<28 31>; // NC +}; + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi b/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi new file mode 100644 index 000000000000..d26074898fa2 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_u4wdh.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <20>, <24>, <28 31>; +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi new file mode 100644 index 000000000000..2461a8039544 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n16.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>, // flash + <20>, <24>, <28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi new file mode 100644 index 000000000000..9c8ef71acfdb --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n4.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>, // flash + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi new file mode 100644 index 000000000000..4dee1868cc34 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_32ue_n8.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>, // flash + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi new file mode 100644 index 000000000000..f034a5b28985 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n16.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <2>,<25>, // NC/test + <6 11>, // flash + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi new file mode 100644 index 000000000000..324c1bba2de7 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n4.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <2>,<25>, // NC/test + <6 11>, // flash + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi b/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi new file mode 100644 index 000000000000..ec5583c44067 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wroom_da_n8.dtsi @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <2>,<25>, // NC/test + <6 11>, // flash + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi new file mode 100644 index 000000000000..712d86fc0f4d --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r2.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi new file mode 100644 index 000000000000..119e3e3ed6ae --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r4.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 4MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(4)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi new file mode 100644 index 000000000000..10ab7f11fa12 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n16r8.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi new file mode 100644 index 000000000000..b4367cc223d1 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r2.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi new file mode 100644 index 000000000000..ef6037b394c3 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n4r8.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi new file mode 100644 index 000000000000..e8d902c73ae6 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r2.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi new file mode 100644 index 000000000000..1ab318f35898 --- /dev/null +++ b/dts/xtensa/espressif/esp32/esp32_wrover_e_n8r8.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32_common.dtsi" + +/* Reserved GPIO pins */ +&gpio0 { + gpio-reserved-ranges = <20>, <24>, <28 31>; + gpio-reserved-ranges = <6 11>,<16 17>, // flash&psram + <20>,<24>,<28 31>; // NC +}; + +&gpio1 { + gpio-reserved-ranges = <6>,<7>; // GPIO37-38 NC +}; + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 8MB flash */ +&psram0 { + reg = <0x3f800000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2.dtsi new file mode 100644 index 000000000000..d295a9c27cf8 --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" diff --git a/dts/xtensa/espressif/esp32s2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi similarity index 94% rename from dts/xtensa/espressif/esp32s2.dtsi rename to dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi index 898701457d4d..696e77a8ffb9 100644 --- a/dts/xtensa/espressif/esp32s2.dtsi +++ b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi @@ -108,12 +108,20 @@ flash0: flash@0 { compatible = "soc-nv-flash"; - reg = <0 0x400000>; erase-block-size = <4096>; write-block-size = <4>; + /* Flash size is specified in SOC/SIP dtsi */ }; }; + psram0: psram@3f500000 { + device_type = "memory"; + compatible = "mmio-sram"; + /* PSRAM size is specified in SOC/SIP dtsi */ + reg = <0x3f500000 DT_SIZE_M(2)>; + status = "disabled"; + }; + uart0: uart@3f400000 { compatible = "espressif,esp32-uart"; reg = <0x3f400000 0x400>; @@ -158,6 +166,11 @@ reg = <0x3f404000 0x800>; interrupts = ; interrupt-parent = <&intc>; + /* Maximum available pins (per port) + * Actual occupied pins are specified + * on part number dtsi level, using + * the `gpio-reserved-ranges` property. + */ ngpios = <32>; /* 0..31 */ }; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_fh2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_fh2.dtsi new file mode 100644 index 000000000000..cd14799cef02 --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_fh2.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 2MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_fh4.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_fh4.dtsi new file mode 100644 index 000000000000..036fed0055cc --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_fh4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_fn4r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_fn4r2.dtsi new file mode 100644 index 000000000000..f3175a99233f --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_fn4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3f500000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4.dtsi new file mode 100644 index 000000000000..036fed0055cc --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4r2.dtsi new file mode 100644 index 000000000000..84e3b16cc39b --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_mini_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_r2.dtsi new file mode 100644 index 000000000000..db004992e703 --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_r2.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_solo_n16.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n16.dtsi new file mode 100644 index 000000000000..357735b9e03e --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n16.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 16 MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4.dtsi new file mode 100644 index 000000000000..036fed0055cc --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4r2.dtsi new file mode 100644 index 000000000000..84e3b16cc39b --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_solo_n8.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n8.dtsi new file mode 100644 index 000000000000..a0c57c7ae017 --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_solo_n8.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_wroom.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_wroom.dtsi new file mode 100644 index 000000000000..036fed0055cc --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_wroom.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n16r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n16r2.dtsi new file mode 100644 index 000000000000..77645a3c2e07 --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n16r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n4r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n4r2.dtsi new file mode 100644 index 000000000000..84e3b16cc39b --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n8r2.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n8r2.dtsi new file mode 100644 index 000000000000..92d8775368ef --- /dev/null +++ b/dts/xtensa/espressif/esp32s2/esp32s2_wrover_n8r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s2_common.dtsi" + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + status = "okay"; + reg = <0x3f500000 DT_SIZE_M(2)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3.dtsi new file mode 100644 index 000000000000..c405bfedecdd --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" diff --git a/dts/xtensa/espressif/esp32s3.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi similarity index 94% rename from dts/xtensa/espressif/esp32s3.dtsi rename to dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 6c2337a2a5e7..bf3853ab710a 100644 --- a/dts/xtensa/espressif/esp32s3.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -94,9 +94,18 @@ reg = <0 0x800000>; erase-block-size = <4096>; write-block-size = <4>; + /* Flash size is specified in SOC/SIP dtsi */ }; }; + psram0: psram@3c000000 { + device_type = "memory"; + compatible = "mmio-sram"; + /* PSRAM size is specified in SOC/SIP dtsi */ + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "disabled"; + }; + uart0: uart@60000000 { compatible = "espressif,esp32-uart"; reg = <0x60000000 0x1000>; @@ -144,7 +153,12 @@ reg = <0x60004000 0x800>; interrupts = ; interrupt-parent = <&intc>; - ngpios = <32>; + /* Maximum available pins (per port) + * Actual occupied pins are specified + * on part number dtsi level, using + * the `gpio-reserved-ranges` property. + */ + ngpios = <32>; /* 0..31 */ }; gpio1: gpio@60004800 { @@ -154,7 +168,7 @@ reg = <0x60004800 0x800>; interrupts = ; interrupt-parent = <&intc>; - ngpios = <13>; + ngpios = <22>; /* 32..53 */ }; }; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_fn8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_fn8.dtsi new file mode 100644 index 000000000000..4b2e7404282a --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_fn8.dtsi @@ -0,0 +1,12 @@ +/* + * 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)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_mini_n4r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_mini_n4r2.dtsi new file mode 100644 index 000000000000..b8f733a3c547 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_mini_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_mini_n8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_mini_n8.dtsi new file mode 100644 index 000000000000..4b2e7404282a --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_mini_n8.dtsi @@ -0,0 +1,12 @@ +/* + * 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)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r2.dtsi new file mode 100644 index 000000000000..b77169f172be --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_pico_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_pico_n8r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r8.dtsi new file mode 100644 index 000000000000..34ec0ec5ac1a --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_pico_n8r8.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)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_r2.dtsi new file mode 100644 index 000000000000..187a214078fd --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_r2.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_r8.dtsi new file mode 100644 index 000000000000..29a21140630c --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_r8.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_r8v.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_r8v.dtsi new file mode 100644 index 000000000000..29a21140630c --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_r8v.dtsi @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16.dtsi new file mode 100644 index 000000000000..dbd9c44e52f6 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16.dtsi @@ -0,0 +1,12 @@ +/* + * 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)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r8.dtsi new file mode 100644 index 000000000000..102fd94ec126 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r8.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)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4.dtsi new file mode 100644 index 000000000000..086e7744908b --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4.dtsi @@ -0,0 +1,12 @@ +/* + * 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)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r8.dtsi new file mode 100644 index 000000000000..b17d9f9223b3 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r8.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)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8.dtsi new file mode 100644 index 000000000000..4b2e7404282a --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8.dtsi @@ -0,0 +1,12 @@ +/* + * 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)>; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi new file mode 100644 index 000000000000..eac737e3d619 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi @@ -0,0 +1,17 @@ +/* + * 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)>; +}; + +/* 8MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(8)>; +}; From e033bf6e7a8aede224b7f9b254736ea77c230f05 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Fri, 9 Jun 2023 01:29:56 +0200 Subject: [PATCH 1781/2042] dts: riscv: esp32c3 rework soc/sip list Introduce dtsi files representing the current portfolio of chips and modules based on the: - flash size - psram size - gpio count - certification status Update the boards dts files according to which SOC/SIP they are using. Signed-off-by: Marek Matej --- boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts | 2 +- boards/riscv/icev_wireless/icev_wireless.dts | 2 +- boards/riscv/stamp_c3/stamp_c3.dts | 2 +- boards/riscv/xiao_esp32c3/xiao_esp32c3.dts | 2 +- dts/riscv/espressif/esp32c3/esp32c3.dtsi | 7 +++++++ .../{esp32c3.dtsi => esp32c3/esp32c3_common.dtsi} | 7 ++++++- dts/riscv/espressif/esp32c3/esp32c3_fx4.dtsi | 12 ++++++++++++ dts/riscv/espressif/esp32c3/esp32c3_mini_n4.dtsi | 12 ++++++++++++ dts/riscv/espressif/esp32c3/esp32c3_wroom_h2.dtsi | 12 ++++++++++++ dts/riscv/espressif/esp32c3/esp32c3_wroom_h4.dtsi | 12 ++++++++++++ 10 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 dts/riscv/espressif/esp32c3/esp32c3.dtsi rename dts/riscv/espressif/{esp32c3.dtsi => esp32c3/esp32c3_common.dtsi} (97%) create mode 100644 dts/riscv/espressif/esp32c3/esp32c3_fx4.dtsi create mode 100644 dts/riscv/espressif/esp32c3/esp32c3_mini_n4.dtsi create mode 100644 dts/riscv/espressif/esp32c3/esp32c3_wroom_h2.dtsi create mode 100644 dts/riscv/espressif/esp32c3/esp32c3_wroom_h4.dtsi diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index 1e4a534df2ae..4072136524a1 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "esp32c3_devkitm-pinctrl.dtsi" / { diff --git a/boards/riscv/icev_wireless/icev_wireless.dts b/boards/riscv/icev_wireless/icev_wireless.dts index a88ec3e2310e..88dc0e338348 100644 --- a/boards/riscv/icev_wireless/icev_wireless.dts +++ b/boards/riscv/icev_wireless/icev_wireless.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "icev_wireless-pinctrl.dtsi" / { diff --git a/boards/riscv/stamp_c3/stamp_c3.dts b/boards/riscv/stamp_c3/stamp_c3.dts index 25bc93992e74..27e7a2fe1f62 100644 --- a/boards/riscv/stamp_c3/stamp_c3.dts +++ b/boards/riscv/stamp_c3/stamp_c3.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "stamp_c3-pinctrl.dtsi" / { diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts index 31d88a0d3aac..45823b069c8b 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts @@ -6,7 +6,7 @@ /dts-v1/; -#include +#include #include "xiao_esp32c3-pinctrl.dtsi" #include "seeed_xiao_connector.dtsi" diff --git a/dts/riscv/espressif/esp32c3/esp32c3.dtsi b/dts/riscv/espressif/esp32c3/esp32c3.dtsi new file mode 100644 index 000000000000..43b734399f4c --- /dev/null +++ b/dts/riscv/espressif/esp32c3/esp32c3.dtsi @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32c3_common.dtsi" diff --git a/dts/riscv/espressif/esp32c3.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi similarity index 97% rename from dts/riscv/espressif/esp32c3.dtsi rename to dts/riscv/espressif/esp32c3/esp32c3_common.dtsi index 9d751c1fe7e1..10fc17ac03ad 100644 --- a/dts/riscv/espressif/esp32c3.dtsi +++ b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi @@ -129,7 +129,12 @@ reg = <0x60004000 0x800>; interrupts = ; interrupt-parent = <&intc>; - ngpios = <32>; /* 0..31 */ + /* Maximum available pins (per port) + * Actual occupied pins are specified + * on part number dtsi level, using + * the `gpio-reserved-ranges` property. + */ + ngpios = <26>; /* 0..25 */ }; i2c0: i2c@60013000 { diff --git a/dts/riscv/espressif/esp32c3/esp32c3_fx4.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_fx4.dtsi new file mode 100644 index 000000000000..4061cd177551 --- /dev/null +++ b/dts/riscv/espressif/esp32c3/esp32c3_fx4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32c3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/riscv/espressif/esp32c3/esp32c3_mini_n4.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_mini_n4.dtsi new file mode 100644 index 000000000000..4061cd177551 --- /dev/null +++ b/dts/riscv/espressif/esp32c3/esp32c3_mini_n4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32c3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; diff --git a/dts/riscv/espressif/esp32c3/esp32c3_wroom_h2.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_wroom_h2.dtsi new file mode 100644 index 000000000000..271d13044226 --- /dev/null +++ b/dts/riscv/espressif/esp32c3/esp32c3_wroom_h2.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32c3_common.dtsi" + +/* 2MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(2)>; +}; diff --git a/dts/riscv/espressif/esp32c3/esp32c3_wroom_h4.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_wroom_h4.dtsi new file mode 100644 index 000000000000..4061cd177551 --- /dev/null +++ b/dts/riscv/espressif/esp32c3/esp32c3_wroom_h4.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32c3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; From 3776402f404de76c91142a4487a83dfb37f72bba Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Wed, 12 Jul 2023 20:51:23 +0200 Subject: [PATCH 1782/2042] boards: xtensa: esp32 board split Remove virtual esp32 board and replace it with the real word boards: - esp32_devkitc_wroom - esp32_devkitc_wrover (with PSRAM option) Signed-off-by: Marek Matej --- boards/xtensa/esp32/Kconfig.board | 8 - .../xtensa/esp32_devkitc_wroom/Kconfig.board | 6 + .../Kconfig.defconfig | 4 +- .../Kconfig.sysbuild | 0 .../board.cmake | 2 + .../doc/img/esp32_devkitc_wroom.jpg | Bin 0 -> 61281 bytes .../xtensa/esp32_devkitc_wroom/doc/index.rst | 209 ++++++++++++++++++ .../esp32_devkitc_wroom-pinctrl.dtsi} | 0 .../esp32_devkitc_wroom.dts | 160 ++++++++++++++ .../esp32_devkitc_wroom.yaml} | 4 +- .../esp32_devkitc_wroom_defconfig} | 3 +- .../support/openocd.cfg | 0 .../xtensa/esp32_devkitc_wrover/Kconfig.board | 6 + .../esp32_devkitc_wrover/Kconfig.defconfig | 18 ++ .../esp32_devkitc_wrover/Kconfig.sysbuild | 10 + .../xtensa/esp32_devkitc_wrover/board.cmake | 11 + .../doc/img/esp32_devkitc_wrover.jpg | Bin 0 -> 77420 bytes .../doc/index.rst | 26 ++- .../esp32_devkitc_wrover-pinctrl.dtsi | 77 +++++++ .../esp32_devkitc_wrover.dts} | 8 +- .../esp32_devkitc_wrover.yaml | 23 ++ .../esp32_devkitc_wrover_defconfig | 22 ++ .../esp32_devkitc_wrover/support/openocd.cfg | 5 + boards/xtensa/esp32_net/doc/index.rst | 12 +- samples/arch/smp/pktqueue/sample.yaml | 2 +- samples/basic/blinky_pwm/README.rst | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 samples/basic/hash_map/sample.yaml | 3 + .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 samples/boards/esp32/deep_sleep/README.rst | 6 +- .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 .../boards/esp32/flash_encryption/README.rst | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../boards/esp32/flash_encryption/sample.yaml | 2 +- samples/boards/esp32/spiram_test/README.rst | 2 +- .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 samples/boards/esp32/spiram_test/sample.yaml | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 samples/drivers/adc/sample.yaml | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 samples/drivers/dac/sample.yaml | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../boards/esp32_devkitc_wrover.overlay | 3 + samples/drivers/ipm/ipm_esp32/sample.yaml | 2 +- .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../net/wifi/boards/esp32_devkitc_wrover.conf | 12 + .../wifi/boards/esp32_devkitc_wrover.overlay | 9 + ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 .../espressif_esp32/cache_coex/README.rst | 2 +- .../espressif_esp32/cache_coex/testcase.yaml | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../boards/esp32_devkitc_wrover.overlay | 35 +++ tests/drivers/can/api/testcase.yaml | 2 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../boards/esp32_devkitc_wrover.overlay | 9 + tests/drivers/dac/dac_api/src/test_dac.c | 3 +- ...32.overlay => esp32_devkitc_wroom.overlay} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../{esp32.conf => esp32_devkitc_wroom.conf} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 ...32.overlay => esp32_devkitc_wroom.overlay} | 0 .../boards/esp32_devkitc_wrover.overlay | 25 +++ .../debug/coredump_backends/testcase.yaml | 3 +- 73 files changed, 696 insertions(+), 50 deletions(-) delete mode 100644 boards/xtensa/esp32/Kconfig.board create mode 100644 boards/xtensa/esp32_devkitc_wroom/Kconfig.board rename boards/xtensa/{esp32 => esp32_devkitc_wroom}/Kconfig.defconfig (81%) rename boards/xtensa/{esp32 => esp32_devkitc_wroom}/Kconfig.sysbuild (100%) rename boards/xtensa/{esp32 => esp32_devkitc_wroom}/board.cmake (85%) create mode 100644 boards/xtensa/esp32_devkitc_wroom/doc/img/esp32_devkitc_wroom.jpg create mode 100644 boards/xtensa/esp32_devkitc_wroom/doc/index.rst rename boards/xtensa/{esp32/esp32-pinctrl.dtsi => esp32_devkitc_wroom/esp32_devkitc_wroom-pinctrl.dtsi} (100%) create mode 100644 boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts rename boards/xtensa/{esp32/esp32.yaml => esp32_devkitc_wroom/esp32_devkitc_wroom.yaml} (77%) rename boards/xtensa/{esp32/esp32_defconfig => esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig} (75%) rename boards/xtensa/{esp32 => esp32_devkitc_wroom}/support/openocd.cfg (100%) create mode 100644 boards/xtensa/esp32_devkitc_wrover/Kconfig.board create mode 100644 boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig create mode 100644 boards/xtensa/esp32_devkitc_wrover/Kconfig.sysbuild create mode 100644 boards/xtensa/esp32_devkitc_wrover/board.cmake create mode 100644 boards/xtensa/esp32_devkitc_wrover/doc/img/esp32_devkitc_wrover.jpg rename boards/xtensa/{esp32 => esp32_devkitc_wrover}/doc/index.rst (95%) create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover-pinctrl.dtsi rename boards/xtensa/{esp32/esp32.dts => esp32_devkitc_wrover/esp32_devkitc_wrover.dts} (92%) create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml create mode 100644 boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig create mode 100644 boards/xtensa/esp32_devkitc_wrover/support/openocd.cfg rename samples/basic/blinky_pwm/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/bluetooth/hci_uart/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/bluetooth/hci_uart/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/boards/esp32/deep_sleep/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/boards/esp32/flash_encryption/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/boards/esp32/spiram_test/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/drivers/adc/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/drivers/counter/alarm/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/drivers/dac/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/drivers/ipm/ipm_esp32/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) create mode 100644 samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.overlay rename samples/drivers/watchdog/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/net/wifi/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/net/wifi/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) create mode 100644 samples/net/wifi/boards/esp32_devkitc_wrover.conf create mode 100644 samples/net/wifi/boards/esp32_devkitc_wrover.overlay rename samples/sensor/grow_r502a/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/subsys/ipc/rpmsg_service/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/subsys/ipc/rpmsg_service/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename samples/subsys/nvs/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename samples/subsys/settings/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename tests/drivers/adc/adc_api/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) create mode 100644 tests/drivers/adc/adc_api/boards/esp32_devkitc_wrover.overlay rename tests/drivers/counter/counter_basic_api/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename tests/drivers/dac/dac_api/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) create mode 100644 tests/drivers/dac/dac_api/boards/esp32_devkitc_wrover.overlay rename tests/drivers/gpio/gpio_basic_api/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename tests/drivers/pwm/pwm_api/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename tests/drivers/pwm/pwm_loopback/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename tests/drivers/spi/spi_loopback/boards/{esp32.conf => esp32_devkitc_wroom.conf} (100%) rename tests/drivers/spi/spi_loopback/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) rename tests/subsys/debug/coredump_backends/boards/{esp32.overlay => esp32_devkitc_wroom.overlay} (100%) create mode 100644 tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wrover.overlay diff --git a/boards/xtensa/esp32/Kconfig.board b/boards/xtensa/esp32/Kconfig.board deleted file mode 100644 index c6b85318c7c2..000000000000 --- a/boards/xtensa/esp32/Kconfig.board +++ /dev/null @@ -1,8 +0,0 @@ -# ESP32 board configuration - -# Copyright (c) 2017 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_ESP32 - bool "ESP32 Development Board" - depends on SOC_ESP32 diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board new file mode 100644 index 000000000000..ae0f2c2897b6 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32_DEVKITC_WROOM + bool "ESP32-DEVKITC-WROOM Development Board" + depends on SOC_ESP32 diff --git a/boards/xtensa/esp32/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig similarity index 81% rename from boards/xtensa/esp32/Kconfig.defconfig rename to boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index c2880e62d490..cf2cb4403a16 100644 --- a/boards/xtensa/esp32/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -4,8 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD - default "esp32" - depends on BOARD_ESP32 + default "esp32_devkitc_wroom" + depends on BOARD_ESP32_DEVKITC_WROOM config ENTROPY_GENERATOR default y diff --git a/boards/xtensa/esp32/Kconfig.sysbuild b/boards/xtensa/esp32_devkitc_wroom/Kconfig.sysbuild similarity index 100% rename from boards/xtensa/esp32/Kconfig.sysbuild rename to boards/xtensa/esp32_devkitc_wroom/Kconfig.sysbuild diff --git a/boards/xtensa/esp32/board.cmake b/boards/xtensa/esp32_devkitc_wroom/board.cmake similarity index 85% rename from boards/xtensa/esp32/board.cmake rename to boards/xtensa/esp32_devkitc_wroom/board.cmake index 2f04d1fe8861..ad53de11770b 100644 --- a/boards/xtensa/esp32/board.cmake +++ b/boards/xtensa/esp32_devkitc_wroom/board.cmake @@ -1,8 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # 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) diff --git a/boards/xtensa/esp32_devkitc_wroom/doc/img/esp32_devkitc_wroom.jpg b/boards/xtensa/esp32_devkitc_wroom/doc/img/esp32_devkitc_wroom.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b8317e29ebb247f74c52237070f59c278305b29 GIT binary patch literal 61281 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
D$oL7P>VsWYnYaqX|JABw9eaRP7-UT>WqV zHDH(cs8yTt=Wa;>U#Ku*vbda6e2qpMy0g(E9B3;rxQE0I^+8y8J}Y6ZGcx*h-4B-?k*!ee!sX=n)jq_k!7xw zJF8JqTHmkKUYnxo-}u_;()FPED86zmDAJeD;+Ce_P|QyK=SuYan6+kbvDHUgSftDr zsW0l$)Jt?@ExL{{mBBk|eXsL&qRzA6FWMKLKImI6n9$@SXvPJvMMt!0lvVcFReGiD z?_g}WX*}4hbE6D|%LnKb9gaCzTmTC1xF4|7k-q6VY)yW5M|JG3A>lc&m~_}o zcx}t(8hoT%y)}uX`t-gFNXdSYuyExcRaxcbF7VYZh5ZS6x_>*!T_Pn^`tugHBmLcv zPK$=b%}Gc-uM@RL54N%)UZu?hIjw9nLm%P@#}h6|hRuriz9X$Uyk7H#k(X$su+pbC zwDwQebYg3Sl2o^(gnL*hOK4iqh|uURBs>z=BB8i%s}g{TL0tkzA@AfmR7VE$7o^@W zrLZnt{f`}{f6sf{=X+J;4(ZUcM4pXm zF`~>}h=sFEQSlaAi}XYOECV++KM^*GX3ks1+tAIRwr(o9my8AH4&IQ;SeRcFoyQ-< zX28LWCT5s7YBeS0_pLa8U+yS!q7r#)+;f+DE+l6Uq66>x9Q8YsG~V=@7T#*EPN8m? z&d-WJ)`l(Qi9ZfW@s0Snl|!y5?E(!HK-)a(V7BU1bWD0<@v{9d z9u|N65;WZ^@&fc{*nFCS1wHe-JZPt5Z5bbjF7JviY@mZ<)|=$)2yVq56W3fj74Ba$ zI(GV2I00Kdzljz_k|=zs;BpntQyX&^twPGL&64@EReoDXjc1J zJifw&F`n>*YD5&oM1TQ8rw9~e)i+NCXbh!&6LRQf*ZYGwg$rhUB_Mr zBvR|Fd%DBh@f6_#rYhosabmEy4e<)ol!BSsXZ$??q1$7UyhHNrO%Jzhw=a2;fR-42 z4iF|5?@Bt*&G8>oA=gM{3IA4J5xgVB+vaBCThX1hm}z`#ol89W6<)mm@~3Vu$HLz4 zwszN!bX~R%smE*1k6NB8ohlmQ{aON5TD1+bkD74$gUD+RM(j(OB;Y3_YX$PW4`XYE zrLIJr`m#>b5n$=82Y}WyP143B4fB%zMt$^a7`2Wm%sT}Xs>^ILl^a$FW*vDNwHIYz z%M@pu$bbBI#6#2VfvIaxSo16%F+<93oS49d+y>6Q+B46x%GbT8G!(d_@t$58`f3|g+x(qZ{^pc zin*j9)}qqW1AJd+akPVb?p^`opL*R5+%6p2I?M%2tb`4H7#qAxyVND#42b^9BlmPn zoMiZGwojz)aA7k%Y1DX=1TDS|5~mV=B1ED6*zQPf74J7j%{VBib)E{^WM zKdl}7OI7x6ly&D*cPar3sJ_*mutznW2I43Wx04<=clf0?iC62WhJSaXx`<4?w$tFD zawSY^3_AD#X9InqNE0luGOf=^fx)E~dI`6NB6q>6q+r{;_$CYX+BUNOy!gtkubCwS z2lHG9MCP9M(D;MS6p=IK@8LhrRt2YwE>+^vrF4ko#fSk?prv{JLNvP!ABaQy{Y1iZ zY+Vy4jlX>4mcDEJX%=6lQbn4v;#5wdB@zYuDubonZ5gh)j^m+E0M>)VAJ5JhQLAy1qKBCz}H7x81Jg(E}rbZ#$b<4 za!%6X%JWxOicL>HS>;;OLnGBWryz|M(c}w`w zj@i04i>=vkNTAjBBK3byzCRgS$T>0AZjy;Kre#HvH=J(WNaT}@4u^FH&Ndm6w9$-y zx0TAZavK?@$eloPt-szAyF=8)RD`wxtT<$SxAaevF|)jIRk_aY;~K=R^ab4TdYG)@ zO_psk8(U11>5@qnie@lVXXAC$B0ER(dxTMev@bvywzOrrorpuO|`rj)L6`r^R; zH0_Q?EU=VaB!>BGpP#KLq>Uy8i1qRWKk90(^$$;<%iX>RQXQKipdQ!SQlFVt3@Xwy z7jugOFpp9#E6jlLMB#Rri<~V^@$~Q9J3+mE=rn0=0?3W!<4V@T~p8JNZBX$8b-Khug6|JiLAIgC{$ zCe_QQ^sxniun$btpwJgvif3bfvqx7}vA1w5o3Xy_pV>2O(rb&Zf^6W(ASvc6aCp|~ zNMC-nXOfz5`#)M|713|BQt^re5|H>2osX0uV@@*T+ZkJ#l5KU>C7(hVKg$y>fDZeV z_38&{y1&3~&=C#yEhOGG>_+(VnJ8xONiLQJ{IKin(FS{hoo|!^2Z1?!+bO6nInU;e zvVTOFrDJWA^Ksm~L#2ZfTfzVh*y_FlFuPF48jn4JwdfA+dy9Ds2p!52%)RE&A78ij zV6$_|vraRjtPPbInf&Sli z`l~B`sVoZ=x?#W{$T%%4L5-q+PK2kDv-0N=d~Q$OYzAUICX(DBmueG4QSg$+^9N=G zu&<$&fDS>{$y+uV3;1U0lye1B!HEBVtvqv>5RYt_(PWDZ;s1+qjuYLNBj8r^oQ&1N$<ay)e^6=0q zf(K*>B*)4$Lvxv)Fbi{` zrH3^ZHNkJDeAZhGy!S@7%E08<4DA+B4DMP?V`FUSyEWb?*i@4o@)pgdJ^ro3nGvd< zbK!G`NjE>6ARF*?!iEJ2|H>cPg=uuMCB}t4No_3JMzr?(Kc*kwfRi&#tZNfDd3%;o zl;Fs`Gs8E-sp=EUe?EvE@Wb?lNOnk=w1MM@(sapt`vb9s4$4&77^je~?t$NgKuj^7 zT#u4E*9JJvuGsBDD+~d+Hvtxv=VPheIJM(m9yV5&@ThVl(&_OBhtT1s;BdwY(_b$* zy{-L9ut0e$nt^rgV80AFv@G=r29K+U%iI7mhOnWQGs{s?GkfRqt}X0uY}nrkpjz-I zv!4Wt!7@H<<(-cB1pqQxMkc+LnBIOQ$&Kw8a9Tm=`I?iAjBkk(m?cz|#K@%uXQ!Id zB|tFQ|E2g|{sKS+pZ8XH7uST`O}|IKt>_T{RDNQjXA8fS(g&a74Jg9F6tQoGguF+0 zT!c+(|4D<7y}}vKel}iu;mC6^fZk`d^Ttr8gp%3Euw7hTAd*u2sTtcc;Nm0PB(~Sr zp^Om?Ow{qC8WHA|Gl<=cjAa%0LdKp}xt`^kMA&2uJI&Z&uRlFS?c7Y4_Zw9>9FZ7s z374YuCG^|9q!;VFwG9Xva}lu4H-Ct^XVW>xgT)+mv)_h(^v#}4* zzB8nh{y<_cO|azd;89F}on2+4A(hBp^2EUp$`(R?FF7 zH90{5sQaOt-W%VJv6ou?(u3uJTkGr^b_N4Ik7X?tpvLPAN(&`twOb7oM@vr<7N=Ht zFDlXgZ}e~f;7#+SX*-PZ>Fkes_Jt7OL6@dOpXaHmvFo!JR~79hv=v3u_Kz1Jbw5sY z1Z4r?Yt+&*f71*6CtjHZ`ftw8yeeMC3s9@5{G=}Zt<|8>Z_^`>GXMC0sB%A5T>Hv` z)L2o-ES^hZySnyWMGDWq(61^10)WTj(1^ifri(r4;7CdSs`sCO32^ms!|bPOgM7MY zW^f*}dJQtFX1Te3H+HeAq}|cP3X$FB+RJLR^&_${AlVm0()SdVMCx|E);Mm@&MS?-e9mrJ7G0TsQw=IeCbA4x(7P$xt74@`albJf3;+A zy@L!6BZ@T8#ltk?MVTo)Eqh}=eMnFGxW(Wz)mlp)sPiY-T`htrKtJ9NIq8lUc)A`W zn;pLK@73lk+cJNU?0d8rsc}c-N72pTf(WiE^G@M1Pm1Oj>&K|J#Q2`ea(-ud1)ltI z<9oKRh5FwEs~A0Q1Mhf%f7jmwM|K4y2{yJynB}YaV@==A{Pz6kjP~6wkj|U)-VTCn zFmv04nHxxU<5*$L`K#kR@NM9u?g^_x?unP6 zg9RoL|KTk8v1rn?0hKl(ei=2`4ilRL{4;o`@8fDy8RUH>>S4%Q3|i8vqBKxoJwfOW z`(}XH4N{-c&t{|(Sl18pZ&?vIFwOSS|F`~%OGq%&=fb>BM<wp#4iluAL}1i$Gub&^JcEJOvslZd=Lkzp(qF zV<#D@p}I1*ps^Yo0*HN^z|%?_YZiTVhfRL1w!&N&BYCFk z>uqb0g!C7D=P#qy*Po~F014Z30Jl?5QI@_irg_sRM16g0#?HZ3k!l3YLx=?`vA$oN zab?028!rSvnYW01l_N_{BOHsvxz@xSspXg(fFXbQ{=~&|vv=Yr^4$Xj0Q(Rq6nUIX6<9%uYIo-w|LpRTsSyHyrSAFB_g3!p z2t5pv+UVj45iApLmZ|VAu57o*hQ+UM#$4U>CWRS6QDs}qRds}saG2q@xc`6FKn0+1(gNSo(F)c#K z{C8U7b0_Twj|@XKhVlD_GsW8ⅇ*=1JN@qUG^!tf4cR)`X!+EclTA;*ML9qGY|-H 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 k?(%$i2j;m;O&5ssG0Q9}|B@&;S4c literal 0 HcmV?d00001 diff --git a/boards/xtensa/esp32_devkitc_wroom/doc/index.rst b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst new file mode 100644 index 000000000000..b8856c7b3cb9 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst @@ -0,0 +1,209 @@ +.. _esp32_devkitc_wroom: + +ESP32-DEVKITC-WROOM +################### + +Overview +******** + +ESP32-DEVKITC-WROOM is a series of low cost, low power system on a chip microcontrollers +with integrated Wi-Fi & dual-mode Bluetooth. The ESP32 series employs a +Tensilica Xtensa LX6 microprocessor in both dual-core and single-core +variations. ESP32-WROOM is created and developed by Espressif Systems, a +Shanghai-based Chinese company, and is manufactured by TSMC using their 40nm +process. [1]_ + +The features include the following: + +- Dual core Xtensa microprocessor (LX6), running at 160 or 240MHz +- 520KB of SRAM +- 802.11b/g/n/e/i +- Bluetooth v4.2 BR/EDR and BLE +- Various peripherals: + + - 12-bit ADC with up to 18 channels + - 2x 8-bit DACs + - 10x touch sensors + - Temperature sensor + - 4x SPI + - 2x I2S + - 2x I2C + - 3x UART + - SD/SDIO/MMC host + - Slave (SDIO/SPI) + - Ethernet MAC + - CAN bus 2.0 + - IR (RX/TX) + - Motor PWM + - LED PWM with up to 16 channels + - Hall effect sensor + +- Cryptographic hardware acceleration (RNG, ECC, RSA, SHA-2, AES) +- 5uA deep sleep current + +.. figure:: img/esp32_devkitc_wroom.jpg + :align: center + :alt: ESP32-DEVKITC-WROOM + + ESP32-DevKitC-WROOM-32D DK + +Supported Features +================== + +Current Zephyr's ESP32-WROOM board supports the following features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ ++------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++------------+------------+-------------------------------------+ +| USB-JTAG | on-chip | hardware interface | ++------------+------------+-------------------------------------+ +| SPI Master | on-chip | spi | ++------------+------------+-------------------------------------+ +| Timers | on-chip | counter | ++------------+------------+-------------------------------------+ +| Watchdog | on-chip | watchdog | ++------------+------------+-------------------------------------+ +| TRNG | on-chip | entropy | ++------------+------------+-------------------------------------+ +| LEDC | on-chip | pwm | ++------------+------------+-------------------------------------+ +| MCPWM | on-chip | pwm | ++------------+------------+-------------------------------------+ +| PCNT | on-chip | qdec | ++------------+------------+-------------------------------------+ +| SPI DMA | on-chip | spi | ++------------+------------+-------------------------------------+ +| TWAI | on-chip | can | ++------------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++------------+------------+-------------------------------------+ +| DAC | on-chip | dac | ++------------+------------+-------------------------------------+ +| Wi-Fi | on-chip | | ++------------+------------+-------------------------------------+ +| Bluetooth | on-chip | | ++------------+------------+-------------------------------------+ + +System requirements +=================== + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + 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 +--------- + +ESP32-DEVKITC-WROOM support on OpenOCD is available upstream as of version 0.12.0. +Download and install OpenOCD from `OpenOCD`_. + +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 | ++------------+-----------+ + +Further documentation can be obtained from the SoC vendor in `JTAG debugging +for ESP32`_. + +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 + +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 + +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. + +.. _`JTAG debugging for ESP32`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/jtag-debugging/index.html +.. _`OpenOCD`: https://github.com/openocd-org/openocd + +References +********** + +.. [1] https://en.wikipedia.org/wiki/ESP32 +.. _ESP32 Technical Reference Manual: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf +.. _Hardware Reference: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/index.html diff --git a/boards/xtensa/esp32/esp32-pinctrl.dtsi b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom-pinctrl.dtsi similarity index 100% rename from boards/xtensa/esp32/esp32-pinctrl.dtsi rename to boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom-pinctrl.dtsi diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts new file mode 100644 index 000000000000..c1849a064670 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "esp32_devkitc_wroom-pinctrl.dtsi" + +/ { + model = "Espressif ESP32-DEVKITC-WROOM-32D"; + compatible = "espressif,esp32"; + + aliases { + uart-0 = &uart0; + i2c-0 = &i2c0; + sw0 = &button0; + watchdog0 = &wdt0; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BOOT Button"; + }; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + }; +}; + +&cpu0 { + clock-frequency = ; + cpu-power-states = <&light_sleep &deep_sleep>; +}; + +&cpu1 { + clock-frequency = ; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&uart2 { + current-speed = <115200>; + pinctrl-0 = <&uart2_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 21 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 22 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&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"; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; +}; + +&timer0 { + status = "disabled"; +}; + +&timer1 { + status = "disabled"; +}; + +&timer2 { + status = "disabled"; +}; + +&timer3 { + status = "disabled"; +}; + +&trng0 { + status = "okay"; +}; + +&psram0 { + status = "disabled"; +}; + +&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/esp32/esp32.yaml b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml similarity index 77% rename from boards/xtensa/esp32/esp32.yaml rename to boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml index 7ec642ad72e2..4a937b09491a 100644 --- a/boards/xtensa/esp32/esp32.yaml +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml @@ -1,5 +1,5 @@ -identifier: esp32 -name: ESP-32 +identifier: esp32_devkitc_wroom +name: ESP32-DevkitC-WROOM-32D type: mcu arch: xtensa toolchain: diff --git a/boards/xtensa/esp32/esp32_defconfig b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig similarity index 75% rename from boards/xtensa/esp32/esp32_defconfig rename to boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig index 099b0c850c51..a5c32af0d88f 100644 --- a/boards/xtensa/esp32/esp32_defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig @@ -1,8 +1,9 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 CONFIG_XTENSA_RESET_VECTOR=n -CONFIG_BOARD_ESP32=y +CONFIG_BOARD_ESP32_DEVKITC_WROOM=y CONFIG_SOC_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 diff --git a/boards/xtensa/esp32/support/openocd.cfg b/boards/xtensa/esp32_devkitc_wroom/support/openocd.cfg similarity index 100% rename from boards/xtensa/esp32/support/openocd.cfg rename to boards/xtensa/esp32_devkitc_wroom/support/openocd.cfg diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board new file mode 100644 index 000000000000..0aa7ae576cc8 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ESP32_DEVKITC_WROVER + bool "ESP32-DEVKITC-WROVER-E Development board" + depends on SOC_ESP32 diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig new file mode 100644 index 000000000000..8b977af69436 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "esp32_devkitc_wrover" + depends on BOARD_ESP32_DEVKITC_WROVER + +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/esp32_devkitc_wrover/Kconfig.sysbuild b/boards/xtensa/esp32_devkitc_wrover/Kconfig.sysbuild new file mode 100644 index 000000000000..3a2d17ac5cfd --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/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/esp32_devkitc_wrover/board.cmake b/boards/xtensa/esp32_devkitc_wrover/board.cmake new file mode 100644 index 000000000000..ad53de11770b --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/board.cmake @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# 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_devkitc_wrover/doc/img/esp32_devkitc_wrover.jpg b/boards/xtensa/esp32_devkitc_wrover/doc/img/esp32_devkitc_wrover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9515257dd9a0e1ef73769e91d7226f0dcc9c6c98 GIT binary patch literal 77420 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 tQFb_)*MCSKWmiyOMatY +#include +#include + +&pinctrl { + + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart2_default: uart2_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + spim3_default: spim3_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; +}; diff --git a/boards/xtensa/esp32/esp32.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts similarity index 92% rename from boards/xtensa/esp32/esp32.dts rename to boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts index 5fcad1aab5db..87959ed0b98b 100644 --- a/boards/xtensa/esp32/esp32.dts +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts @@ -1,15 +1,15 @@ /* - * Copyright (c) 2019 Intel Corporation. + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ /dts-v1/; -#include -#include "esp32-pinctrl.dtsi" +#include +#include "esp32_devkitc_wrover-pinctrl.dtsi" / { - model = "esp32"; + model = "Espressif ESP32-DEVKITC-WROVER-E"; compatible = "espressif,esp32"; aliases { diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml new file mode 100644 index 000000000000..3680afba27aa --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml @@ -0,0 +1,23 @@ +identifier: esp32_devkitc_wrover +name: ESP32-DevkitC-WROVER-E +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - adc + - dac + - gpio + - i2c + - watchdog + - uart + - nvs + - pwm + - dac + - spi + - counter + - entropy +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig new file mode 100644 index 000000000000..45db3662dcfa --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_XTENSA_RESET_VECTOR=n + +CONFIG_BOARD_ESP32_DEVKITC_WROVER=y +CONFIG_SOC_ESP32=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + +CONFIG_XTENSA_USE_CORE_CRT1=n + +CONFIG_GPIO=y + +CONFIG_GEN_ISR_TABLES=y +CONFIG_GEN_IRQ_VECTOR_TABLE=n + +CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32_devkitc_wrover/support/openocd.cfg b/boards/xtensa/esp32_devkitc_wrover/support/openocd.cfg new file mode 100644 index 000000000000..338e6e4e6eae --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/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/boards/xtensa/esp32_net/doc/index.rst b/boards/xtensa/esp32_net/doc/index.rst index 06c1df13c01a..5321727aa7db 100644 --- a/boards/xtensa/esp32_net/doc/index.rst +++ b/boards/xtensa/esp32_net/doc/index.rst @@ -35,16 +35,16 @@ Build and flash applications as usual (see :ref:`build_an_application` and .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32 + :board: esp32_devkitc_wroom :goals: build -The usual ``flash`` target will work with the ``esp32`` board +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 + :board: esp32_devkitc_wroom :goals: flash Open the serial monitor using the following command: @@ -59,7 +59,7 @@ message in the monitor: .. code-block:: console ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32 + Hello World! esp32_devkitc_wroom Debugging --------- @@ -76,7 +76,7 @@ Here is an example for building the :ref:`hello_world` application. .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32 + :board: esp32_devkitc_wroom :goals: build flash :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= @@ -84,7 +84,7 @@ You can debug an application in the usual way. Here is an example for the :ref:` .. zephyr-app-commands:: :zephyr-app: samples/hello_world - :board: esp32 + :board: esp32_devkitc_wroom :goals: debug Using JTAG diff --git a/samples/arch/smp/pktqueue/sample.yaml b/samples/arch/smp/pktqueue/sample.yaml index 685de5cfd8f4..890d36653d62 100644 --- a/samples/arch/smp/pktqueue/sample.yaml +++ b/samples/arch/smp/pktqueue/sample.yaml @@ -19,7 +19,7 @@ tests: - smp filter: (CONFIG_MP_MAX_NUM_CPUS > 1) platform_exclude: - - esp32 + - esp32_devkitc_wroom - esp_wrover_kit - esp32_ethernet_kit - heltec_wifi_lora32_v2 diff --git a/samples/basic/blinky_pwm/README.rst b/samples/basic/blinky_pwm/README.rst index bdb80252fca7..ec59a6b3a971 100644 --- a/samples/basic/blinky_pwm/README.rst +++ b/samples/basic/blinky_pwm/README.rst @@ -53,7 +53,7 @@ In these other cases, however, manual wiring is necessary: - connect PWM1 (PA8) to an LED * - :ref:`nucleo_wb55rg_board` - connect PWM1 (PA8) to an LED - * - :ref:`esp32` + * - :ref:`esp32_devkitc_wroom` - connect GPIO2 to an LED * - :ref:`esp32s2_saola` - connect GPIO2 to an LED diff --git a/samples/basic/blinky_pwm/boards/esp32.overlay b/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/basic/blinky_pwm/boards/esp32.overlay rename to samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay diff --git a/samples/basic/hash_map/sample.yaml b/samples/basic/hash_map/sample.yaml index 0ba16fe1fc21..b73474975813 100644 --- a/samples/basic/hash_map/sample.yaml +++ b/samples/basic/hash_map/sample.yaml @@ -16,6 +16,9 @@ common: type: one_line regex: - .*success + platform_exclude: + - esp32_net + tests: # Minimal Libc diff --git a/samples/bluetooth/hci_uart/boards/esp32.conf b/samples/bluetooth/hci_uart/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/bluetooth/hci_uart/boards/esp32.conf rename to samples/bluetooth/hci_uart/boards/esp32_devkitc_wroom.conf diff --git a/samples/bluetooth/hci_uart/boards/esp32.overlay b/samples/bluetooth/hci_uart/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/bluetooth/hci_uart/boards/esp32.overlay rename to samples/bluetooth/hci_uart/boards/esp32_devkitc_wroom.overlay diff --git a/samples/boards/esp32/deep_sleep/README.rst b/samples/boards/esp32/deep_sleep/README.rst index 9506709fa56b..7d258b537c1e 100644 --- a/samples/boards/esp32/deep_sleep/README.rst +++ b/samples/boards/esp32/deep_sleep/README.rst @@ -30,9 +30,9 @@ as wake-up source, deep sleep for 20 seconds, wake up. Requirements ************ -This example should be able to run on any commonly available :ref:`esp32` -development board without any extra hardware if only ``Timer`` is used as -wakeup source. +This example should be able to run on any commonly available +:ref:`esp32_devkitc_wroom` development board without any extra hardware if +only ``Timer`` is used as wakeup source. However, when ``EXT1`` is also enabled, GPIO2 and GPIO4 should be pulled-down by external resistors to avoid floating pins. When triggering a wake up, one diff --git a/samples/boards/esp32/deep_sleep/boards/esp32.conf b/samples/boards/esp32/deep_sleep/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/boards/esp32/deep_sleep/boards/esp32.conf rename to samples/boards/esp32/deep_sleep/boards/esp32_devkitc_wroom.conf diff --git a/samples/boards/esp32/flash_encryption/README.rst b/samples/boards/esp32/flash_encryption/README.rst index 8eaf06835cb8..9d337083e8f9 100644 --- a/samples/boards/esp32/flash_encryption/README.rst +++ b/samples/boards/esp32/flash_encryption/README.rst @@ -69,7 +69,7 @@ Make sure you have your board connected over USB port. .. code-block:: console - west build -b esp32 samples/boards/esp32/flash_encryption + west build -b esp32_devkitc_wrover samples/boards/esp32/flash_encryption west flash Sample Output diff --git a/samples/boards/esp32/flash_encryption/boards/esp32.overlay b/samples/boards/esp32/flash_encryption/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/boards/esp32/flash_encryption/boards/esp32.overlay rename to samples/boards/esp32/flash_encryption/boards/esp32_devkitc_wroom.overlay diff --git a/samples/boards/esp32/flash_encryption/sample.yaml b/samples/boards/esp32/flash_encryption/sample.yaml index 22069c5bf6ad..a5080d25275e 100644 --- a/samples/boards/esp32/flash_encryption/sample.yaml +++ b/samples/boards/esp32/flash_encryption/sample.yaml @@ -3,5 +3,5 @@ sample: name: flash_encryption tests: sample.board.esp32: - platform_allow: esp32 + platform_allow: esp32_devkitc_wroom tags: esp32 diff --git a/samples/boards/esp32/spiram_test/README.rst b/samples/boards/esp32/spiram_test/README.rst index 3d4e13a6915c..b3dea1a68224 100644 --- a/samples/boards/esp32/spiram_test/README.rst +++ b/samples/boards/esp32/spiram_test/README.rst @@ -29,7 +29,7 @@ Make sure you have your board connected over USB port. .. code-block:: console - west build -b esp32 samples/boards/esp32/spiram_test + west build -b esp32_devkitc_wrover samples/boards/esp32/spiram_test west flash If using another supported Espressif board, replace the argument in the above diff --git a/samples/boards/esp32/spiram_test/boards/esp32.conf b/samples/boards/esp32/spiram_test/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/boards/esp32/spiram_test/boards/esp32.conf rename to samples/boards/esp32/spiram_test/boards/esp32_devkitc_wroom.conf diff --git a/samples/boards/esp32/spiram_test/sample.yaml b/samples/boards/esp32/spiram_test/sample.yaml index d8fa92d9b98b..d8cbfaa62d78 100644 --- a/samples/boards/esp32/spiram_test/sample.yaml +++ b/samples/boards/esp32/spiram_test/sample.yaml @@ -3,5 +3,5 @@ sample: name: spiram_test tests: sample.board.esp32.spiram: - platform_allow: esp32 + platform_allow: esp32_devkitc_wrover tags: esp32 diff --git a/samples/drivers/adc/boards/esp32.overlay b/samples/drivers/adc/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/drivers/adc/boards/esp32.overlay rename to samples/drivers/adc/boards/esp32_devkitc_wroom.overlay diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml index 66a57fa561f9..678e0afd8802 100644 --- a/samples/drivers/adc/sample.yaml +++ b/samples/drivers/adc/sample.yaml @@ -18,7 +18,7 @@ tests: - gd32f450i_eval - gd32vf103v_eval - gd32f403z_eval - - esp32 + - esp32_devkitc_wroom - esp32s2_saola - esp32c3_devkitm - gd32l233r_eval diff --git a/samples/drivers/counter/alarm/boards/esp32.overlay b/samples/drivers/counter/alarm/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/drivers/counter/alarm/boards/esp32.overlay rename to samples/drivers/counter/alarm/boards/esp32_devkitc_wroom.overlay diff --git a/samples/drivers/dac/boards/esp32.overlay b/samples/drivers/dac/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/drivers/dac/boards/esp32.overlay rename to samples/drivers/dac/boards/esp32_devkitc_wroom.overlay diff --git a/samples/drivers/dac/sample.yaml b/samples/drivers/dac/sample.yaml index 902371a18053..ee8ea042f5da 100644 --- a/samples/drivers/dac/sample.yaml +++ b/samples/drivers/dac/sample.yaml @@ -11,7 +11,7 @@ tests: - bl654_dvk - bl5340_dvk_cpuapp - disco_l475_iot1 - - esp32 + - esp32_devkitc_wroom - esp32s2_saola - frdm_k22f - frdm_k64f diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/boards/esp32.overlay rename to samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.overlay diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 000000000000..80f7950333f2 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/sample.yaml b/samples/drivers/ipm/ipm_esp32/sample.yaml index aa6092ac48ab..e28e4474e984 100644 --- a/samples/drivers/ipm/ipm_esp32/sample.yaml +++ b/samples/drivers/ipm/ipm_esp32/sample.yaml @@ -2,7 +2,7 @@ sample: name: ESP32 IPM Sample tests: sample.ipm.ipm_esp32: - platform_allow: esp32 + platform_allow: esp32_devkitc_wroom tags: - samples - ipm diff --git a/samples/drivers/watchdog/boards/esp32.conf b/samples/drivers/watchdog/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/drivers/watchdog/boards/esp32.conf rename to samples/drivers/watchdog/boards/esp32_devkitc_wroom.conf diff --git a/samples/net/wifi/boards/esp32.conf b/samples/net/wifi/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/net/wifi/boards/esp32.conf rename to samples/net/wifi/boards/esp32_devkitc_wroom.conf diff --git a/samples/net/wifi/boards/esp32.overlay b/samples/net/wifi/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/net/wifi/boards/esp32.overlay rename to samples/net/wifi/boards/esp32_devkitc_wroom.overlay diff --git a/samples/net/wifi/boards/esp32_devkitc_wrover.conf b/samples/net/wifi/boards/esp32_devkitc_wrover.conf new file mode 100644 index 000000000000..5c37cfc402d3 --- /dev/null +++ b/samples/net/wifi/boards/esp32_devkitc_wrover.conf @@ -0,0 +1,12 @@ +CONFIG_WIFI=y +CONFIG_HEAP_MEM_POOL_SIZE=98304 + +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/esp32_devkitc_wrover.overlay b/samples/net/wifi/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 000000000000..ea9865cf5f8a --- /dev/null +++ b/samples/net/wifi/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wifi { + status = "okay"; +}; diff --git a/samples/sensor/grow_r502a/boards/esp32.overlay b/samples/sensor/grow_r502a/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/sensor/grow_r502a/boards/esp32.overlay rename to samples/sensor/grow_r502a/boards/esp32_devkitc_wroom.overlay diff --git a/samples/subsys/ipc/rpmsg_service/boards/esp32.conf b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/subsys/ipc/rpmsg_service/boards/esp32.conf rename to samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wroom.conf diff --git a/samples/subsys/ipc/rpmsg_service/boards/esp32.overlay b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from samples/subsys/ipc/rpmsg_service/boards/esp32.overlay rename to samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wroom.overlay diff --git a/samples/subsys/nvs/boards/esp32.conf b/samples/subsys/nvs/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/subsys/nvs/boards/esp32.conf rename to samples/subsys/nvs/boards/esp32_devkitc_wroom.conf diff --git a/samples/subsys/settings/boards/esp32.conf b/samples/subsys/settings/boards/esp32_devkitc_wroom.conf similarity index 100% rename from samples/subsys/settings/boards/esp32.conf rename to samples/subsys/settings/boards/esp32_devkitc_wroom.conf diff --git a/tests/boards/espressif_esp32/cache_coex/README.rst b/tests/boards/espressif_esp32/cache_coex/README.rst index 5bee38ea40c5..00a6877841d8 100644 --- a/tests/boards/espressif_esp32/cache_coex/README.rst +++ b/tests/boards/espressif_esp32/cache_coex/README.rst @@ -19,7 +19,7 @@ Make sure you have the ESP32 DevKitC connected over USB port. .. code-block:: console - west build -b esp32 tests/boards/espressif_esp32/cache_coex + west build -b esp32_devkitc_wrover tests/boards/espressif_esp32/cache_coex west flash --esp-device /dev/ttyUSB0 Sample Output diff --git a/tests/boards/espressif_esp32/cache_coex/testcase.yaml b/tests/boards/espressif_esp32/cache_coex/testcase.yaml index bcb037bc99ae..9de6d546a4b3 100644 --- a/tests/boards/espressif_esp32/cache_coex/testcase.yaml +++ b/tests/boards/espressif_esp32/cache_coex/testcase.yaml @@ -1,6 +1,6 @@ tests: boards.esp32.cache_coex: - platform_allow: esp32 esp32s2_saola + platform_allow: esp32_devkitc_wrover esp32s2_saola tags: - spiram - spiflash diff --git a/tests/drivers/adc/adc_api/boards/esp32.overlay b/tests/drivers/adc/adc_api/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/adc/adc_api/boards/esp32.overlay rename to tests/drivers/adc/adc_api/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/adc/adc_api/boards/esp32_devkitc_wrover.overlay b/tests/drivers/adc/adc_api/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 000000000000..c288312aa3aa --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Wolter HV + * Copyright (c) 2023 Benjamin Björnsson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc0 0>, <&adc0 1>; + }; +}; + +&adc0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + 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>; + }; +}; diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index 5048e5c6edbc..9b38220e1e4b 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -12,7 +12,7 @@ tests: extra_args: DTC_OVERLAY_FILE=twai-enable.overlay filter: dt_compat_enabled("espressif,esp32-twai") platform_allow: - - esp32 + - esp32_devkitc_wroom - esp32c3_devkitm - esp32s2_saola - esp32s3_devkitm diff --git a/tests/drivers/counter/counter_basic_api/boards/esp32.overlay b/tests/drivers/counter/counter_basic_api/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/counter/counter_basic_api/boards/esp32.overlay rename to tests/drivers/counter/counter_basic_api/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/dac/dac_api/boards/esp32.overlay b/tests/drivers/dac/dac_api/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/dac/dac_api/boards/esp32.overlay rename to tests/drivers/dac/dac_api/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/dac/dac_api/boards/esp32_devkitc_wrover.overlay b/tests/drivers/dac/dac_api/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 000000000000..c179baef7454 --- /dev/null +++ b/tests/drivers/dac/dac_api/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,9 @@ +/* + * Copyright 2022 Espressif (Shanghai) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&dac { + 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 6e4883d9a9c5..377de463c7ea 100644 --- a/tests/drivers/dac/dac_api/src/test_dac.c +++ b/tests/drivers/dac/dac_api/src/test_dac.c @@ -62,7 +62,8 @@ #define DAC_RESOLUTION 12 #define DAC_CHANNEL_ID 0 -#elif defined(CONFIG_BOARD_ESP32) || \ +#elif defined(CONFIG_BOARD_ESP32_DEVKITC_WROOM) || \ + defined(CONFIG_BOARD_ESP32_DEVKITC_WROVER) || \ defined(CONFIG_BOARD_ESP_WROVER_KIT) || \ defined(CONFIG_BOARD_ESP32S2_SAOLA) || \ defined(CONFIG_BOARD_GD32A503V_EVAL) || \ diff --git a/tests/drivers/gpio/gpio_basic_api/boards/esp32.overlay b/tests/drivers/gpio/gpio_basic_api/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/gpio/gpio_basic_api/boards/esp32.overlay rename to tests/drivers/gpio/gpio_basic_api/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/pwm/pwm_api/boards/esp32.overlay b/tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/pwm/pwm_api/boards/esp32.overlay rename to tests/drivers/pwm/pwm_api/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/pwm/pwm_loopback/boards/esp32.overlay b/tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/pwm/pwm_loopback/boards/esp32.overlay rename to tests/drivers/pwm/pwm_loopback/boards/esp32_devkitc_wroom.overlay diff --git a/tests/drivers/spi/spi_loopback/boards/esp32.conf b/tests/drivers/spi/spi_loopback/boards/esp32_devkitc_wroom.conf similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32.conf rename to tests/drivers/spi/spi_loopback/boards/esp32_devkitc_wroom.conf diff --git a/tests/drivers/spi/spi_loopback/boards/esp32.overlay b/tests/drivers/spi/spi_loopback/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/drivers/spi/spi_loopback/boards/esp32.overlay rename to tests/drivers/spi/spi_loopback/boards/esp32_devkitc_wroom.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/esp32.overlay b/tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wroom.overlay similarity index 100% rename from tests/subsys/debug/coredump_backends/boards/esp32.overlay rename to tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wroom.overlay diff --git a/tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wrover.overlay b/tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 000000000000..eb707ee72211 --- /dev/null +++ b/tests/subsys/debug/coredump_backends/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + partitions { + /* + * Reduce storage_partition to make space for + * coredump_partition + */ + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00005000>; + }; + + coredump_partition: partition@255000 { + label = "coredump-partition"; + reg = <0x255000 DT_SIZE_K(4)>; + }; + + }; +}; diff --git a/tests/subsys/debug/coredump_backends/testcase.yaml b/tests/subsys/debug/coredump_backends/testcase.yaml index 2b4399e09bfd..c8da7138e7a1 100644 --- a/tests/subsys/debug/coredump_backends/testcase.yaml +++ b/tests/subsys/debug/coredump_backends/testcase.yaml @@ -20,7 +20,8 @@ tests: extra_args: CONF_FILE=prj_flash_partition.conf platform_allow: - qemu_x86 - - esp32 + - esp32_devkitc_wroom + - esp32_devkitc_wrover - esp32s2_saola - esp32s3_devkitm - esp32c3_devkitm From 7472ff97d0d986af30d5260a606aa435fecfa8ca Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Mon, 17 Jul 2023 12:52:56 +0200 Subject: [PATCH 1783/2042] boards: mark esp32 board as deprecated Mark the 'esp32' board as deprecated after removing it and replaced by the two real boards. Signed-off-by: Marek Matej --- boards/deprecated.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index 9bf260f443d3..f238347203a8 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -20,3 +20,4 @@ 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 6b57b3b786be8558e7e310b849e0b97bd1eae45c Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Thu, 20 Jul 2023 18:24:09 +0200 Subject: [PATCH 1784/2042] soc: xtensa,riscv: esp32xx: refactor folder structure Refactor the ESP32 target SOCs together with all related boards. Most braking changes includes: - changing the CONFIG_SOC_ESP32* to refer to the actual soc line (esp32,esp32s2,esp32s3,esp32c3) - replacing CONFIG_SOC with the CONFIG_SOC_SERIES - creating CONFIG_SOC_FAMILY_ESP32 to embrace all the ESP32 across all used architectures - introducing CONFIG_SOC_PART_NUMBER_* to provide a SOC model config - introducing the 'common' folder to hide all commonly used configs and files. - updating west.yml to reflect previous changes in hal Signed-off-by: Marek Matej --- Kconfig.zephyr | 2 +- arch/xtensa/Kconfig | 2 +- arch/xtensa/core/coredump.c | 8 +- arch/xtensa/core/xtensa_backtrace.c | 6 +- boards/riscv/esp32c3_devkitm/Kconfig.board | 6 +- .../esp32c3_devkitm/esp32c3_devkitm_defconfig | 6 +- .../icev_wireless/icev_wireless_defconfig | 6 +- boards/riscv/stamp_c3/Kconfig.board | 6 +- boards/riscv/stamp_c3/stamp_c3_defconfig | 7 +- boards/riscv/xiao_esp32c3/Kconfig.board | 6 +- .../riscv/xiao_esp32c3/xiao_esp32c3_defconfig | 6 +- .../xtensa/esp32_devkitc_wroom/Kconfig.board | 6 +- .../esp32_devkitc_wroom_defconfig | 11 +- .../xtensa/esp32_devkitc_wrover/Kconfig.board | 6 +- .../esp32_devkitc_wrover_defconfig | 11 +- .../xtensa/esp32_ethernet_kit/Kconfig.board | 6 +- .../esp32_ethernet_kit_defconfig | 11 +- boards/xtensa/esp32_net/Kconfig.board | 6 +- boards/xtensa/esp32_net/esp32_net_defconfig | 10 +- .../xtensa/esp32s2_franzininho/Kconfig.board | 6 +- .../esp32s2_franzininho_defconfig | 11 +- boards/xtensa/esp32s2_saola/Kconfig.board | 10 +- .../esp32s2_saola/esp32s2_saola_defconfig | 12 +- boards/xtensa/esp32s3_devkitm/Kconfig.board | 9 +- .../esp32s3_devkitm/esp32s3_devkitm_defconfig | 8 +- boards/xtensa/esp_wrover_kit/Kconfig.board | 6 +- .../esp_wrover_kit/esp_wrover_kit_defconfig | 11 +- .../heltec_wifi_lora32_v2/Kconfig.board | 6 +- .../heltec_wifi_lora32_v2_defconfig | 11 +- boards/xtensa/m5stickc_plus/Kconfig.board | 6 +- .../m5stickc_plus/m5stickc_plus_defconfig | 11 +- boards/xtensa/odroid_go/Kconfig.board | 6 +- boards/xtensa/odroid_go/odroid_go_defconfig | 11 +- boards/xtensa/olimex_esp32_evb/Kconfig.board | 6 +- .../olimex_esp32_evb_defconfig | 11 +- boards/xtensa/xiao_esp32s3/Kconfig.board | 6 +- .../xiao_esp32s3/xiao_esp32s3_defconfig | 7 +- drivers/adc/adc_esp32.c | 14 +- drivers/bluetooth/hci/hci_esp32.c | 2 +- drivers/can/can_esp32_twai.c | 30 +- drivers/clock_control/clock_control_esp32.c | 36 +- drivers/counter/counter_esp32_rtc.c | 6 +- drivers/counter/counter_esp32_tmr.c | 4 +- drivers/dma/dma_esp32_gdma.c | 10 +- drivers/ethernet/Kconfig.esp32 | 2 +- drivers/flash/flash_esp32.c | 8 +- drivers/gpio/gpio_esp32.c | 4 +- drivers/hwinfo/hwinfo_esp32.c | 2 +- drivers/i2c/i2c_esp32.c | 2 +- drivers/interrupt_controller/Kconfig.esp32 | 2 +- drivers/interrupt_controller/Kconfig.esp32c3 | 2 +- drivers/mdio/Kconfig.esp32 | 2 +- drivers/pinctrl/pinctrl_esp32.c | 2 +- drivers/sensor/esp32_temp/Kconfig | 2 +- drivers/sensor/esp32_temp/esp32_temp.c | 2 +- drivers/sensor/pcnt_esp32/pcnt_esp32.c | 8 +- drivers/serial/Kconfig.esp32 | 2 +- drivers/serial/uart_esp32.c | 12 +- drivers/spi/spi_esp32_spim.c | 12 +- drivers/timer/Kconfig.esp32c3_sys | 2 +- drivers/watchdog/wdt_esp32.c | 4 +- modules/Kconfig.esp32 | 2 +- .../boards/esp32/flash_encryption/src/main.c | 2 +- soc/riscv/esp32c3/Kconfig.defconfig | 54 --- soc/riscv/espressif_esp32/CMakeLists.txt | 5 + soc/riscv/espressif_esp32/Kconfig | 16 + soc/riscv/espressif_esp32/Kconfig.defconfig | 5 + soc/riscv/espressif_esp32/Kconfig.soc | 4 + .../espressif_esp32/common/CMakeLists.txt | 2 + .../common/Kconfig.defconfig.series | 52 +++ soc/riscv/espressif_esp32/common/Kconfig.soc | 15 + .../esp32c3/CMakeLists.txt | 2 +- .../esp32c3/Kconfig.defconfig.series | 21 + .../espressif_esp32/esp32c3/Kconfig.series | 20 + .../{ => espressif_esp32}/esp32c3/Kconfig.soc | 52 +-- .../{ => espressif_esp32}/esp32c3/default.ld | 0 .../{ => espressif_esp32}/esp32c3/idle.c | 0 .../{ => espressif_esp32}/esp32c3/linker.ld | 0 .../{ => espressif_esp32}/esp32c3/loader.c | 2 +- .../{ => espressif_esp32}/esp32c3/mcuboot.ld | 0 .../esp32c3/pinctrl_soc.h | 0 .../{ => espressif_esp32}/esp32c3/power.c | 0 soc/riscv/{ => espressif_esp32}/esp32c3/soc.c | 0 soc/riscv/{ => espressif_esp32}/esp32c3/soc.h | 0 .../{ => espressif_esp32}/esp32c3/soc_irq.S | 0 .../{ => espressif_esp32}/esp32c3/soc_irq.c | 0 .../{ => espressif_esp32}/esp32c3/vectors.S | 0 soc/xtensa/esp32/include/_soc_inthandlers.h | 365 ----------------- soc/xtensa/esp32s2/Kconfig.defconfig | 55 --- soc/xtensa/esp32s2/include/_soc_inthandlers.h | 371 ------------------ soc/xtensa/espressif_esp32/CMakeLists.txt | 5 + soc/xtensa/espressif_esp32/Kconfig | 16 + soc/xtensa/espressif_esp32/Kconfig.defconfig | 5 + soc/xtensa/espressif_esp32/Kconfig.soc | 4 + .../espressif_esp32/common/CMakeLists.txt | 4 + .../common/Kconfig.defconfig.series} | 55 +-- soc/xtensa/espressif_esp32/common/Kconfig.soc | 194 +++++++++ .../common}/include/_soc_inthandlers.h | 2 +- .../common}/include/gdbstub/soc.h | 0 .../esp32/CMakeLists.txt | 2 +- .../esp32/Kconfig.defconfig.series} | 51 +-- .../espressif_esp32/esp32/Kconfig.series | 18 + .../{ => espressif_esp32}/esp32/Kconfig.soc | 263 +++---------- .../{ => espressif_esp32}/esp32/default.ld | 0 .../{ => espressif_esp32}/esp32/esp32-mp.c | 0 .../{ => espressif_esp32}/esp32/gdbstub.c | 0 .../{ => espressif_esp32}/esp32/linker.ld | 0 .../{ => espressif_esp32}/esp32/loader.c | 2 +- .../{ => espressif_esp32}/esp32/mcuboot.ld | 0 .../{ => espressif_esp32}/esp32/newlib_fix.c | 0 .../{ => espressif_esp32}/esp32/pinctrl_soc.h | 0 .../{ => espressif_esp32}/esp32/power.c | 0 soc/xtensa/{ => espressif_esp32}/esp32/soc.c | 6 +- soc/xtensa/{ => espressif_esp32}/esp32/soc.h | 0 .../esp32_net/CMakeLists.txt | 0 .../esp32_net/Kconfig.defconfig.series} | 15 +- .../espressif_esp32/esp32_net/Kconfig.series | 12 + .../esp32_net/Kconfig.soc | 31 +- .../esp32_net/include/_soc_inthandlers.h | 0 .../esp32_net/include/gdbstub/soc.h | 0 .../{ => espressif_esp32}/esp32_net/linker.ld | 0 .../esp32_net/newlib_fix.c | 0 .../{ => espressif_esp32}/esp32_net/soc.c | 0 .../{ => espressif_esp32}/esp32_net/soc.h | 0 .../esp32s2/CMakeLists.txt | 2 +- .../esp32s2/Kconfig.defconfig.series | 33 ++ .../espressif_esp32/esp32s2/Kconfig.series | 17 + .../{ => espressif_esp32}/esp32s2/Kconfig.soc | 279 ++++++------- .../{ => espressif_esp32}/esp32s2/default.ld | 0 .../{ => espressif_esp32}/esp32s2/linker.ld | 0 .../{ => espressif_esp32}/esp32s2/loader.c | 0 .../{ => espressif_esp32}/esp32s2/mcuboot.ld | 0 .../esp32s2/newlib_fix.c | 0 .../esp32s2/pinctrl_soc.h | 0 .../{ => espressif_esp32}/esp32s2/power.c | 0 .../{ => espressif_esp32}/esp32s2/soc.c | 0 .../{ => espressif_esp32}/esp32s2/soc.h | 0 .../{ => espressif_esp32}/esp32s2/soc_cache.c | 0 .../esp32s3/CMakeLists.txt | 2 +- .../esp32s3/Kconfig.defconfig.series | 30 ++ .../espressif_esp32/esp32s3/Kconfig.series | 16 + .../{ => espressif_esp32}/esp32s3/Kconfig.soc | 78 ++-- .../{ => espressif_esp32}/esp32s3/default.ld | 0 .../{ => espressif_esp32}/esp32s3/linker.ld | 0 .../{ => espressif_esp32}/esp32s3/loader.c | 0 .../{ => espressif_esp32}/esp32s3/mcuboot.ld | 0 .../esp32s3/newlib_fix.c | 0 .../esp32s3/pinctrl_soc.h | 0 .../{ => espressif_esp32}/esp32s3/soc.c | 0 .../{ => espressif_esp32}/esp32s3/soc.h | 0 .../{ => espressif_esp32}/esp32s3/soc_cache.c | 0 tests/drivers/pwm/pwm_api/src/test_pwm.c | 4 +- .../uart/uart_async_api/src/test_uart.h | 2 + west.yml | 2 +- 154 files changed, 1026 insertions(+), 1623 deletions(-) delete mode 100644 soc/riscv/esp32c3/Kconfig.defconfig create mode 100644 soc/riscv/espressif_esp32/CMakeLists.txt create mode 100644 soc/riscv/espressif_esp32/Kconfig create mode 100644 soc/riscv/espressif_esp32/Kconfig.defconfig create mode 100644 soc/riscv/espressif_esp32/Kconfig.soc create mode 100644 soc/riscv/espressif_esp32/common/CMakeLists.txt create mode 100644 soc/riscv/espressif_esp32/common/Kconfig.defconfig.series create mode 100644 soc/riscv/espressif_esp32/common/Kconfig.soc rename soc/riscv/{ => espressif_esp32}/esp32c3/CMakeLists.txt (98%) create mode 100644 soc/riscv/espressif_esp32/esp32c3/Kconfig.defconfig.series create mode 100644 soc/riscv/espressif_esp32/esp32c3/Kconfig.series rename soc/riscv/{ => espressif_esp32}/esp32c3/Kconfig.soc (78%) rename soc/riscv/{ => espressif_esp32}/esp32c3/default.ld (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/idle.c (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/linker.ld (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/loader.c (97%) rename soc/riscv/{ => espressif_esp32}/esp32c3/mcuboot.ld (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/pinctrl_soc.h (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/power.c (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/soc.c (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/soc.h (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/soc_irq.S (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/soc_irq.c (100%) rename soc/riscv/{ => espressif_esp32}/esp32c3/vectors.S (100%) delete mode 100644 soc/xtensa/esp32/include/_soc_inthandlers.h delete mode 100644 soc/xtensa/esp32s2/Kconfig.defconfig delete mode 100644 soc/xtensa/esp32s2/include/_soc_inthandlers.h create mode 100644 soc/xtensa/espressif_esp32/CMakeLists.txt create mode 100644 soc/xtensa/espressif_esp32/Kconfig create mode 100644 soc/xtensa/espressif_esp32/Kconfig.defconfig create mode 100644 soc/xtensa/espressif_esp32/Kconfig.soc create mode 100644 soc/xtensa/espressif_esp32/common/CMakeLists.txt rename soc/xtensa/{esp32s3/Kconfig.defconfig => espressif_esp32/common/Kconfig.defconfig.series} (57%) create mode 100644 soc/xtensa/espressif_esp32/common/Kconfig.soc rename soc/xtensa/{esp32s3 => espressif_esp32/common}/include/_soc_inthandlers.h (99%) rename soc/xtensa/{esp32 => espressif_esp32/common}/include/gdbstub/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/CMakeLists.txt (98%) rename soc/xtensa/{esp32/Kconfig.defconfig => espressif_esp32/esp32/Kconfig.defconfig.series} (56%) create mode 100644 soc/xtensa/espressif_esp32/esp32/Kconfig.series rename soc/xtensa/{ => espressif_esp32}/esp32/Kconfig.soc (56%) rename soc/xtensa/{ => espressif_esp32}/esp32/default.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/esp32-mp.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/gdbstub.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/linker.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/loader.c (97%) rename soc/xtensa/{ => espressif_esp32}/esp32/mcuboot.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/newlib_fix.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/pinctrl_soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/power.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32/soc.c (98%) rename soc/xtensa/{ => espressif_esp32}/esp32/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/CMakeLists.txt (100%) rename soc/xtensa/{esp32_net/Kconfig.defconfig => espressif_esp32/esp32_net/Kconfig.defconfig.series} (62%) create mode 100644 soc/xtensa/espressif_esp32/esp32_net/Kconfig.series rename soc/xtensa/{ => espressif_esp32}/esp32_net/Kconfig.soc (88%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/include/_soc_inthandlers.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/include/gdbstub/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/linker.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/newlib_fix.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/soc.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32_net/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/CMakeLists.txt (98%) create mode 100644 soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series create mode 100644 soc/xtensa/espressif_esp32/esp32s2/Kconfig.series rename soc/xtensa/{ => espressif_esp32}/esp32s2/Kconfig.soc (74%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/default.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/linker.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/loader.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/mcuboot.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/newlib_fix.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/pinctrl_soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/power.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/soc.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s2/soc_cache.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/CMakeLists.txt (98%) create mode 100644 soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series create mode 100644 soc/xtensa/espressif_esp32/esp32s3/Kconfig.series rename soc/xtensa/{ => espressif_esp32}/esp32s3/Kconfig.soc (87%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/default.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/linker.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/loader.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/mcuboot.ld (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/newlib_fix.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/pinctrl_soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/soc.c (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/soc.h (100%) rename soc/xtensa/{ => espressif_esp32}/esp32s3/soc_cache.c (100%) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 6243a03fe7db..15427fa82be8 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -594,7 +594,7 @@ if BUILD_OUTPUT_UF2 config BUILD_OUTPUT_UF2_FAMILY_ID string "UF2 device family ID" - default "0x1c5f21b0" if SOC_ESP32 + default "0x1c5f21b0" if SOC_SERIES_ESP32 default "0x621e937a" if SOC_NRF52833_QIAA default "0xada52840" if SOC_NRF52840_QIAA default "0x4fb2d5bd" if SOC_SERIES_IMX_RT diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 93216a5aa247..5d042c1d4758 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -46,7 +46,7 @@ config XTENSA_USE_CORE_CRT1 config XTENSA_ENABLE_BACKTRACE bool "Backtrace on panic exception" default y - depends on SOC_ESP32 || SOC_FAMILY_INTEL_ADSP + depends on SOC_SERIES_ESP32 || SOC_FAMILY_INTEL_ADSP help Enable this config option to print backtrace on panic exception diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index 55b1a77884e2..8f15ca39c585 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -109,13 +109,13 @@ void arch_coredump_info_dump(const z_arch_esf_t *esf) #if CONFIG_SOC_XTENSA_SAMPLE_CONTROLLER arch_blk.soc = XTENSA_SOC_SAMPLE_CONTROLLER; - #elif CONFIG_SOC_ESP32 - arch_blk.soc = XTENSA_SOC_ESP32; #elif CONFIG_SOC_FAMILY_INTEL_ADSP arch_blk.soc = XTENSA_SOC_INTEL_ADSP; - #elif CONFIG_SOC_ESP32S2 + #elif CONFIG_SOC_SERIES_ESP32 + arch_blk.soc = XTENSA_SOC_ESP32; + #elif CONFIG_SOC_SERIES_ESP32S2 arch_blk.soc = XTENSA_SOC_ESP32S2; - #elif CONFIG_SOC_ESP32S3 + #elif CONFIG_SOC_SERIES_ESP32S3 arch_blk.soc = XTENSA_SOC_ESP32S3; #else arch_blk.soc = XTENSA_SOC_UNKNOWN; diff --git a/arch/xtensa/core/xtensa_backtrace.c b/arch/xtensa/core/xtensa_backtrace.c index 9b5af2e8753e..4f767f690423 100644 --- a/arch/xtensa/core/xtensa_backtrace.c +++ b/arch/xtensa/core/xtensa_backtrace.c @@ -7,7 +7,7 @@ #include "xtensa/corebits.h" #include "xtensa_backtrace.h" #include -#if defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32) #include "soc/soc_memory_layout.h" #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP) #include "debug_helpers.h" @@ -34,7 +34,7 @@ static inline uint32_t z_xtensa_cpu_process_stack_pc(uint32_t pc) static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) { -#if defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32) return esp_stack_ptr_is_sane(sp); #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP) return intel_adsp_ptr_is_sane(sp); @@ -45,7 +45,7 @@ static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) static inline bool z_xtensa_ptr_executable(const void *p) { -#if defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32) return esp_ptr_executable(p); #elif defined(CONFIG_SOC_FAMILY_INTEL_ADSP) return intel_adsp_ptr_executable(p); diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.board b/boards/riscv/esp32c3_devkitm/Kconfig.board index 3a4d97f35236..51f0f3957df9 100644 --- a/boards/riscv/esp32c3_devkitm/Kconfig.board +++ b/boards/riscv/esp32c3_devkitm/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ESP32C3_DEVKITM bool "ESP32C3 Devkit-M Board" - depends on SOC_ESP32C3 + depends on SOC_SERIES_ESP32C3 + +choice SOC_PART_NUMBER + default SOC_ESP32C3_MINI_N4 +endchoice diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig index 080bd50908d8..1ca521d9d959 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm_defconfig @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_ESP32C3_DEVKITM=y -CONFIG_SOC_ESP32C3=y +CONFIG_SOC_SERIES_ESP32C3=y + CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_GPIO=y -CONFIG_CLOCK_CONTROL=y diff --git a/boards/riscv/icev_wireless/icev_wireless_defconfig b/boards/riscv/icev_wireless/icev_wireless_defconfig index 78e4586e0864..c5be5732a71b 100644 --- a/boards/riscv/icev_wireless/icev_wireless_defconfig +++ b/boards/riscv/icev_wireless/icev_wireless_defconfig @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_ICEV_WIRELESS=y -CONFIG_SOC_ESP32C3=y +CONFIG_SOC_SERIES_ESP32C3=y + CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_GPIO=y -CONFIG_CLOCK_CONTROL=y diff --git a/boards/riscv/stamp_c3/Kconfig.board b/boards/riscv/stamp_c3/Kconfig.board index 314bbeb0ce7d..09ec15d63482 100644 --- a/boards/riscv/stamp_c3/Kconfig.board +++ b/boards/riscv/stamp_c3/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_STAMP_C3 bool "M5Stack STAMP-C3 Board" - depends on SOC_ESP32C3 + depends on SOC_SERIES_ESP32C3 + +choice SOC_PART_NUMBER + default SOC_ESP32C3_FX4 +endchoice diff --git a/boards/riscv/stamp_c3/stamp_c3_defconfig b/boards/riscv/stamp_c3/stamp_c3_defconfig index 56515384f21f..3b5efc64fa11 100644 --- a/boards/riscv/stamp_c3/stamp_c3_defconfig +++ b/boards/riscv/stamp_c3/stamp_c3_defconfig @@ -1,12 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_STAMP_C3=y -CONFIG_SOC_ESP32C3=y +CONFIG_SOC_SERIES_ESP32C3=y + CONFIG_MAIN_STACK_SIZE=2048 + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_GPIO=y -CONFIG_CLOCK_CONTROL=y diff --git a/boards/riscv/xiao_esp32c3/Kconfig.board b/boards/riscv/xiao_esp32c3/Kconfig.board index 28d520d15750..f8a7e0ecb5b2 100644 --- a/boards/riscv/xiao_esp32c3/Kconfig.board +++ b/boards/riscv/xiao_esp32c3/Kconfig.board @@ -3,4 +3,8 @@ config BOARD_XIAO_ESP32C3 bool "XIAO ESP32C3 Board" - depends on SOC_ESP32C3 + depends on SOC_SERIES_ESP32C3 + +choice SOC_PART_NUMBER + default SOC_ESP32C3_FX4 +endchoice diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3_defconfig b/boards/riscv/xiao_esp32c3/xiao_esp32c3_defconfig index 28204464d813..0dc868fa60a9 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3_defconfig +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3_defconfig @@ -1,11 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 CONFIG_BOARD_XIAO_ESP32C3=y -CONFIG_SOC_ESP32C3=y +CONFIG_SOC_SERIES_ESP32C3=y + CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_GPIO=y -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board index ae0f2c2897b6..5c3fa887b575 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board @@ -3,4 +3,8 @@ config BOARD_ESP32_DEVKITC_WROOM bool "ESP32-DEVKITC-WROOM Development Board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROOM_32UE_N4 +endchoice diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig index a5c32af0d88f..ead6203b86e5 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_defconfig @@ -1,10 +1,8 @@ # Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP32_DEVKITC_WROOM=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -12,11 +10,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board index 0aa7ae576cc8..b345a9dff448 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board @@ -3,4 +3,8 @@ config BOARD_ESP32_DEVKITC_WROVER bool "ESP32-DEVKITC-WROVER-E Development board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROVER_E_N4R8 +endchoice diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig index 45db3662dcfa..ad08ccede28b 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_defconfig @@ -1,10 +1,8 @@ # Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP32_DEVKITC_WROVER=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -12,11 +10,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32_ethernet_kit/Kconfig.board b/boards/xtensa/esp32_ethernet_kit/Kconfig.board index b4d48cc7f05c..28a8995bbdf2 100644 --- a/boards/xtensa/esp32_ethernet_kit/Kconfig.board +++ b/boards/xtensa/esp32_ethernet_kit/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ESP32_ETHERNET_KIT bool "ESP32-ETHERNET-KIT Development Board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROVER_E_N4R8 +endchoice diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit_defconfig b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit_defconfig index f5be5006b4c2..a9c99bec06b7 100644 --- a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit_defconfig +++ b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP32_ETHERNET_KIT=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,11 +9,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32_net/Kconfig.board b/boards/xtensa/esp32_net/Kconfig.board index e7405295d409..946a59dce7fb 100644 --- a/boards/xtensa/esp32_net/Kconfig.board +++ b/boards/xtensa/esp32_net/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ESP32_NET bool "ESP32 Board configuration for APP_CPU" - depends on SOC_ESP32_NET + depends on SOC_SERIES_ESP32_NET + +choice SOC_PART_NUMBER + default SOC_ESP32_NET +endchoice diff --git a/boards/xtensa/esp32_net/esp32_net_defconfig b/boards/xtensa/esp32_net/esp32_net_defconfig index f7846c524029..94fed73bc459 100644 --- a/boards/xtensa/esp32_net/esp32_net_defconfig +++ b/boards/xtensa/esp32_net/esp32_net_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP32_NET=y -CONFIG_SOC_ESP32_NET=y +CONFIG_SOC_SERIES_ESP32_NET=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,13 +9,7 @@ CONFIG_CONSOLE=n CONFIG_SERIAL=n CONFIG_UART_CONSOLE=n -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=n CONFIG_GPIO_ESP32=n -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - CONFIG_I2C=n -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32s2_franzininho/Kconfig.board b/boards/xtensa/esp32s2_franzininho/Kconfig.board index 3f78d5baf931..7b52b4d88b12 100644 --- a/boards/xtensa/esp32s2_franzininho/Kconfig.board +++ b/boards/xtensa/esp32s2_franzininho/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ESP32S2_FRANZININHO bool "ESP32S2 Franzininho Board" - depends on SOC_ESP32S2 + depends on SOC_SERIES_ESP32S2 + +choice SOC_PART_NUMBER + default SOC_ESP32S2_WROOM +endchoice diff --git a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho_defconfig b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho_defconfig index 3a17ce5b5478..6d95a2f5567b 100644 --- a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho_defconfig +++ b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho_defconfig @@ -1,20 +1,13 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n CONFIG_BOARD_ESP32S2_FRANZININHO=y -CONFIG_SOC_ESP32S2=y +CONFIG_SOC_SERIES_ESP32S2=y + CONFIG_MAIN_STACK_SIZE=2048 CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32s2_saola/Kconfig.board b/boards/xtensa/esp32s2_saola/Kconfig.board index 5accd94308af..7d9e3a717ae2 100644 --- a/boards/xtensa/esp32s2_saola/Kconfig.board +++ b/boards/xtensa/esp32s2_saola/Kconfig.board @@ -1,8 +1,10 @@ -# ESP32S2 saola board configuration - -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 config BOARD_ESP32S2_SAOLA bool "ESP32S2 Saola Board" - depends on SOC_ESP32S2 + depends on SOC_SERIES_ESP32S2 + +choice SOC_PART_NUMBER + default SOC_ESP32S2_WROVER_N4R2 +endchoice diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola_defconfig b/boards/xtensa/esp32s2_saola/esp32s2_saola_defconfig index f1402eace807..c7bacdd2ec62 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola_defconfig +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola_defconfig @@ -1,20 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP32S2_SAOLA=y -CONFIG_SOC_ESP32S2=y +CONFIG_SOC_SERIES_ESP32S2=y + CONFIG_MAIN_STACK_SIZE=2048 CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp32s3_devkitm/Kconfig.board b/boards/xtensa/esp32s3_devkitm/Kconfig.board index 38d8db7a1127..96de0fb06f76 100644 --- a/boards/xtensa/esp32s3_devkitm/Kconfig.board +++ b/boards/xtensa/esp32s3_devkitm/Kconfig.board @@ -1,8 +1,11 @@ -# ESP32S3 DevKitM board configuration - # Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 +# ESP32S3 DevKitM board configuration config BOARD_ESP32S3_DEVKITM bool "ESP32S3 DevKitM Board" - depends on SOC_ESP32S3 + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_MINI_N8 +endchoice diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm_defconfig b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm_defconfig index 65acf1b660d0..1f8b52aa3604 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm_defconfig +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm_defconfig @@ -1,14 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n CONFIG_BOARD_ESP32S3_DEVKITM=y -CONFIG_SOC_ESP32S3=y +CONFIG_SOC_SERIES_ESP32S3=y + CONFIG_MAIN_STACK_SIZE=2048 + CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n CONFIG_GPIO=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/esp_wrover_kit/Kconfig.board b/boards/xtensa/esp_wrover_kit/Kconfig.board index 7067d53cd5cd..eb255c7ec55f 100644 --- a/boards/xtensa/esp_wrover_kit/Kconfig.board +++ b/boards/xtensa/esp_wrover_kit/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ESP_WROVER_KIT bool "ESP-WROVER-KIT Development Board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROVER_E_N4R8 +endchoice diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit_defconfig b/boards/xtensa/esp_wrover_kit/esp_wrover_kit_defconfig index 68ef048f0eb9..f2b8f7b663c2 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit_defconfig +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ESP_WROVER_KIT=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,11 +9,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.board b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.board index bd176b950892..b364fad83fdf 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.board +++ b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_HELTEC_WIFI_LORA32 bool "HELTEC WiFi LoRa 32 (V2) Board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_D0WD_V3 +endchoice diff --git a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_defconfig b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_defconfig index 766659e89ba6..ac8cf88d7494 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_defconfig +++ b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_HELTEC_WIFI_LORA32=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,11 +9,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/m5stickc_plus/Kconfig.board b/boards/xtensa/m5stickc_plus/Kconfig.board index c034b8763ff7..91e31bc95952 100644 --- a/boards/xtensa/m5stickc_plus/Kconfig.board +++ b/boards/xtensa/m5stickc_plus/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_M5STICKC_PLUS bool "M5StickC PLUS Development Board" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_PICO_D4 +endchoice diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus_defconfig b/boards/xtensa/m5stickc_plus/m5stickc_plus_defconfig index 071ce0845c4a..cc30c956bafd 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus_defconfig +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_M5STICKC_PLUS=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,12 +9,5 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - CONFIG_I2C=y -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/odroid_go/Kconfig.board b/boards/xtensa/odroid_go/Kconfig.board index ad5a4838ba69..f815a4e7e882 100644 --- a/boards/xtensa/odroid_go/Kconfig.board +++ b/boards/xtensa/odroid_go/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_ODROID_GO bool "ODROID-GO Game Kit" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROVER_E_N16R2 +endchoice diff --git a/boards/xtensa/odroid_go/odroid_go_defconfig b/boards/xtensa/odroid_go/odroid_go_defconfig index 4a88a4a3365e..3bda04a1ed3a 100644 --- a/boards/xtensa/odroid_go/odroid_go_defconfig +++ b/boards/xtensa/odroid_go/odroid_go_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_ODROID_GO=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,14 +9,7 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y - # required to enable LCD backlight CONFIG_REGULATOR=y diff --git a/boards/xtensa/olimex_esp32_evb/Kconfig.board b/boards/xtensa/olimex_esp32_evb/Kconfig.board index 2b230816edc7..7bb6c2295b79 100644 --- a/boards/xtensa/olimex_esp32_evb/Kconfig.board +++ b/boards/xtensa/olimex_esp32_evb/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_OLIMEX_ESP32_EVB bool "Olimex ESP32-EVB" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROVER_E_N8R2 +endchoice diff --git a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb_defconfig b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb_defconfig index 20f21d98a2a9..a89b387d0844 100644 --- a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb_defconfig +++ b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb_defconfig @@ -1,9 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n - CONFIG_BOARD_OLIMEX_ESP32_EVB=y -CONFIG_SOC_ESP32=y +CONFIG_SOC_SERIES_ESP32=y CONFIG_MAIN_STACK_SIZE=2048 @@ -11,11 +9,4 @@ CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n - CONFIG_GPIO=y - -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n - -CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.board b/boards/xtensa/xiao_esp32s3/Kconfig.board index aa4b08ecf0f0..99669d929e3f 100644 --- a/boards/xtensa/xiao_esp32s3/Kconfig.board +++ b/boards/xtensa/xiao_esp32s3/Kconfig.board @@ -5,4 +5,8 @@ config BOARD_XIAO_ESP32S3 bool "XIAO ESP32S3 Board" - depends on SOC_ESP32S3 + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_WROOM_N8R8 +endchoice diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig b/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig index df75dd7d2836..978da251a589 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig @@ -1,14 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_XTENSA_RESET_VECTOR=n CONFIG_BOARD_XIAO_ESP32S3=y -CONFIG_SOC_ESP32S3=y +CONFIG_SOC_SERIES_ESP32S3=y CONFIG_MAIN_STACK_SIZE=2048 CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_XTENSA_USE_CORE_CRT1=n CONFIG_GPIO=y -CONFIG_GEN_ISR_TABLES=y -CONFIG_GEN_IRQ_VECTOR_TABLE=n -CONFIG_CLOCK_CONTROL=y diff --git a/drivers/adc/adc_esp32.c b/drivers/adc/adc_esp32.c index 01bd54c32b5a..cbf64ea4c458 100644 --- a/drivers/adc/adc_esp32.c +++ b/drivers/adc/adc_esp32.c @@ -20,7 +20,7 @@ #include LOG_MODULE_REGISTER(adc_esp32, CONFIG_ADC_LOG_LEVEL); -#if CONFIG_SOC_ESP32 +#if CONFIG_SOC_SERIES_ESP32 #define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF #define ADC_RESOLUTION_MIN SOC_ADC_DIGI_MIN_BITWIDTH #define ADC_RESOLUTION_MAX SOC_ADC_DIGI_MAX_BITWIDTH @@ -31,12 +31,12 @@ LOG_MODULE_REGISTER(adc_esp32, CONFIG_ADC_LOG_LEVEL); */ #define ADC_CLIP_MVOLT_11DB 2550 -#elif CONFIG_SOC_ESP32S2 +#elif CONFIG_SOC_SERIES_ESP32S2 #define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP #define ADC_RESOLUTION_MIN SOC_ADC_DIGI_MAX_BITWIDTH #define ADC_RESOLUTION_MAX SOC_ADC_MAX_BITWIDTH -#elif CONFIG_SOC_ESP32C3 +#elif CONFIG_SOC_SERIES_ESP32C3 #define ADC_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP #define ADC_RESOLUTION_MIN SOC_ADC_DIGI_MAX_BITWIDTH #define ADC_RESOLUTION_MAX SOC_ADC_DIGI_MAX_BITWIDTH @@ -165,14 +165,14 @@ static int adc_esp32_read(const struct device *dev, const struct adc_sequence *s data->resolution[channel_id] = seq->resolution; -#if CONFIG_SOC_ESP32C3 +#if CONFIG_SOC_SERIES_ESP32C3 /* NOTE: nothing to set on ESP32C3 SoC */ if (conf->unit == ADC_UNIT_1) { adc1_config_width(ADC_WIDTH_BIT_DEFAULT); } #else adc_set_data_width(conf->unit, WIDTH_MASK(data->resolution[channel_id])); -#endif /* CONFIG_SOC_ESP32C3 */ +#endif /* CONFIG_SOC_SERIES_ESP32C3 */ /* Read raw value */ if (conf->unit == ADC_UNIT_1) { @@ -191,13 +191,13 @@ static int adc_esp32_read(const struct device *dev, const struct adc_sequence *s /* Get corrected voltage output */ cal = cal_mv = esp_adc_cal_raw_to_voltage(reading, &data->chars[channel_id]); -#if CONFIG_SOC_ESP32 +#if CONFIG_SOC_SERIES_ESP32 if (data->attenuation[channel_id] == ADC_ATTEN_DB_11) { if (cal > ADC_CLIP_MVOLT_11DB) { cal = ADC_CLIP_MVOLT_11DB; } } -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ /* Fit according to selected attenuation */ atten_to_gain(data->attenuation[channel_id], &cal); diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c index bdcdb7db99aa..8dae220dd944 100644 --- a/drivers/bluetooth/hci/hci_esp32.c +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -280,7 +280,7 @@ static int bt_esp32_ble_init(void) int ret; esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); -#if defined(CONFIG_BT_BREDR) && defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_BT_BREDR) && defined(CONFIG_SOC_SERIES_ESP32) esp_bt_mode_t mode = ESP_BT_MODE_BTDM; #else esp_bt_mode_t mode = ESP_BT_MODE_BLE; diff --git a/drivers/can/can_esp32_twai.c b/drivers/can/can_esp32_twai.c index cd0d6bad6ec3..0d745dccdbef 100644 --- a/drivers/can/can_esp32_twai.c +++ b/drivers/can/can_esp32_twai.c @@ -26,7 +26,7 @@ LOG_MODULE_REGISTER(can_esp32_twai, CONFIG_CAN_LOG_LEVEL); * The names with TWAI_ prefixes from Espressif reference manuals are used for these incompatible * registers. */ -#ifndef CONFIG_SOC_ESP32 +#ifndef CONFIG_SOC_SERIES_ESP32 /* TWAI_BUS_TIMING_0_REG is incompatible with CAN_SJA1000_BTR0 */ #define TWAI_BUS_TIMING_0_REG (6U) @@ -63,7 +63,7 @@ LOG_MODULE_REGISTER(can_esp32_twai, CONFIG_CAN_LOG_LEVEL); #define TWAI_CD_MASK GENMASK(2, 0) #define TWAI_CLOCK_OFF BIT(3) -#endif /* !CONFIG_SOC_ESP32 */ +#endif /* !CONFIG_SOC_SERIES_ESP32 */ struct can_esp32_twai_config { mm_reg_t base; @@ -71,10 +71,10 @@ struct can_esp32_twai_config { const struct device *clock_dev; const clock_control_subsys_t clock_subsys; int irq_source; -#ifndef CONFIG_SOC_ESP32 +#ifndef CONFIG_SOC_SERIES_ESP32 /* 32-bit variant of output clock divider register required for non-ESP32 MCUs */ uint32_t cdr32; -#endif /* !CONFIG_SOC_ESP32 */ +#endif /* !CONFIG_SOC_SERIES_ESP32 */ }; static uint8_t can_esp32_twai_read_reg(const struct device *dev, uint8_t reg) @@ -95,7 +95,7 @@ static void can_esp32_twai_write_reg(const struct device *dev, uint8_t reg, uint sys_write32(val & 0xFF, addr); } -#ifndef CONFIG_SOC_ESP32 +#ifndef CONFIG_SOC_SERIES_ESP32 /* * Required for newer ESP32-series MCUs which violate the original SJA1000 8-bit register size. @@ -157,7 +157,7 @@ static int can_esp32_twai_set_timing(const struct device *dev, const struct can_ return 0; } -#endif /* !CONFIG_SOC_ESP32 */ +#endif /* !CONFIG_SOC_SERIES_ESP32 */ static int can_esp32_twai_get_core_clock(const struct device *dev, uint32_t *rate) { @@ -205,7 +205,7 @@ static int can_esp32_twai_init(const struct device *dev) return err; } -#ifndef CONFIG_SOC_ESP32 +#ifndef CONFIG_SOC_SERIES_ESP32 /* * TWAI_CLOCK_DIVIDER_REG is incompatible with CAN_SJA1000_CDR for non-ESP32 MCUs * - TWAI_CD has length of 8 bits instead of 3 bits @@ -215,7 +215,7 @@ static int can_esp32_twai_init(const struct device *dev) * Overwrite with 32-bit register variant configured via devicetree. */ can_esp32_twai_write_reg32(dev, TWAI_CLOCK_DIVIDER_REG, twai_config->cdr32); -#endif /* !CONFIG_SOC_ESP32 */ +#endif /* !CONFIG_SOC_SERIES_ESP32 */ esp_intr_alloc(twai_config->irq_source, 0, can_esp32_twai_isr, (void *)dev, NULL); @@ -227,11 +227,11 @@ const struct can_driver_api can_esp32_twai_driver_api = { .start = can_sja1000_start, .stop = can_sja1000_stop, .set_mode = can_sja1000_set_mode, -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 .set_timing = can_sja1000_set_timing, #else .set_timing = can_esp32_twai_set_timing, -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ .send = can_sja1000_send, .add_rx_filter = can_sja1000_add_rx_filter, .remove_rx_filter = can_sja1000_remove_rx_filter, @@ -244,7 +244,7 @@ const struct can_driver_api can_esp32_twai_driver_api = { .recover = can_sja1000_recover, #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .timing_min = CAN_SJA1000_TIMING_MIN_INITIALIZER, -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 .timing_max = CAN_SJA1000_TIMING_MAX_INITIALIZER, #else /* larger prescaler allowed for newer ESP32-series MCUs */ @@ -255,16 +255,16 @@ const struct can_driver_api can_esp32_twai_driver_api = { .phase_seg2 = 0x8, .prescaler = 0x2000, } -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ }; -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 #define TWAI_CLKOUT_DIVIDER_MAX (14) #define TWAI_CDR32_INIT(inst) #else #define TWAI_CLKOUT_DIVIDER_MAX (490) #define TWAI_CDR32_INIT(inst) .cdr32 = CAN_ESP32_TWAI_DT_CDR_INST_GET(inst) -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ #define CAN_ESP32_TWAI_ASSERT_CLKOUT_DIVIDER(inst) \ BUILD_ASSERT(COND_CODE_0(DT_INST_NODE_HAS_PROP(inst, clkout_divider), (1), \ @@ -295,7 +295,7 @@ const struct can_driver_api can_esp32_twai_driver_api = { CAN_SJA1000_DT_CONFIG_INST_GET(inst, &can_esp32_twai_config_##inst, \ can_esp32_twai_read_reg, can_esp32_twai_write_reg, \ CAN_SJA1000_OCR_OCMODE_BIPHASE, \ - COND_CODE_0(IS_ENABLED(CONFIG_SOC_ESP32), (0), \ + COND_CODE_0(IS_ENABLED(CONFIG_SOC_SERIES_ESP32), (0), \ (CAN_ESP32_TWAI_DT_CDR_INST_GET(inst)))); \ \ static struct can_sja1000_data can_sja1000_data_##inst = \ diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index d7bda543bb2b..ea8836d8d751 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -9,32 +9,32 @@ #define CPU_RESET_REASON RTC_SW_CPU_RESET -#if defined(CONFIG_SOC_ESP32) || defined(CONFIG_SOC_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) #define DT_CPU_COMPAT cdns_tensilica_xtensa_lx6 #undef CPU_RESET_REASON #define CPU_RESET_REASON SW_CPU_RESET #include #include "esp32/rom/rtc.h" #include "soc/dport_reg.h" -#elif defined(CONFIG_SOC_ESP32S2) +#elif defined(CONFIG_SOC_SERIES_ESP32S2) #define DT_CPU_COMPAT cdns_tensilica_xtensa_lx7 #include #include "esp32s2/rom/rtc.h" #include "soc/dport_reg.h" -#elif defined(CONFIG_SOC_ESP32S3) +#elif defined(CONFIG_SOC_SERIES_ESP32S3) #define DT_CPU_COMPAT cdns_tensilica_xtensa_lx7 #include #include "esp32s3/rom/rtc.h" #include "soc/dport_reg.h" #include "esp32s3/clk.h" -#elif CONFIG_IDF_TARGET_ESP32C3 +#elif CONFIG_SOC_SERIES_ESP32C3 #define DT_CPU_COMPAT espressif_riscv #include #include "esp32c3/rom/rtc.h" #include #include #include -#endif +#endif /* CONFIG_SOC_SERIES_ESP32xx */ #include "esp_rom_sys.h" #include @@ -55,14 +55,16 @@ struct esp32_clock_config { }; static uint8_t const xtal_freq[] = { -#if defined(CONFIG_SOC_ESP32) || defined(CONFIG_SOC_ESP32_NET) || defined(CONFIG_SOC_ESP32S3) +#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, [ESP32_CLK_XTAL_40M] = 40, [ESP32_CLK_XTAL_AUTO] = 0 -#elif defined(CONFIG_SOC_ESP32S2) +#elif defined(CONFIG_SOC_SERIES_ESP32S2) [ESP32_CLK_XTAL_40M] = 40, -#elif defined(CONFIG_SOC_ESP32C3) +#elif defined(CONFIG_SOC_SERIES_ESP32C3) [ESP32_CLK_XTAL_32M] = 32, [ESP32_CLK_XTAL_40M] = 40, #endif @@ -124,7 +126,7 @@ static int clock_control_esp32_get_rate(const struct device *dev, return 0; } -#if defined(CONFIG_SOC_ESP32) || defined(CONFIG_SOC_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk; @@ -217,9 +219,9 @@ static void esp32_clock_perip_init(void) /* Enable RNG clock. */ periph_module_enable(PERIPH_RNG_MODULE); } -#endif +#endif /* CONFIG_SOC_SERIES_ESP32 */ -#if defined(CONFIG_SOC_ESP32S2) +#if defined(CONFIG_SOC_SERIES_ESP32S2) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk; @@ -321,9 +323,9 @@ static void esp32_clock_perip_init(void) /* Enable RNG clock. */ periph_module_enable(PERIPH_RNG_MODULE); } -#endif +#endif /* CONFIG_SOC_SERIES_ESP32S2 */ -#if defined(CONFIG_SOC_ESP32S3) +#if defined(CONFIG_SOC_SERIES_ESP32S3) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; @@ -421,9 +423,9 @@ static void esp32_clock_perip_init(void) esp_rom_uart_tx_wait_idle(0); esp_rom_uart_set_clock_baudrate(0, UART_CLK_FREQ_ROM, 115200); } -#endif +#endif /* CONFIG_SOC_SERIES_ESP32S3 */ -#if defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32C3) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk; @@ -510,7 +512,7 @@ static void esp32_clock_perip_init(void) /* Enable RNG clock. */ periph_module_enable(PERIPH_RNG_MODULE); } -#endif +#endif /* CONFIG_SOC_SERIES_ESP32C3 */ static int clock_control_esp32_init(const struct device *dev) { @@ -596,7 +598,7 @@ DEVICE_DT_DEFINE(DT_NODELABEL(rtc), CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_esp32_api); -#ifndef CONFIG_SOC_ESP32C3 +#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"); diff --git a/drivers/counter/counter_esp32_rtc.c b/drivers/counter/counter_esp32_rtc.c index 7b157414b57d..0b7e8bbbb27c 100644 --- a/drivers/counter/counter_esp32_rtc.c +++ b/drivers/counter/counter_esp32_rtc.c @@ -18,7 +18,7 @@ #include #include -#if defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32C3) #include #else #include @@ -27,7 +27,7 @@ #include LOG_MODULE_REGISTER(esp32_counter_rtc, CONFIG_COUNTER_LOG_LEVEL); -#if defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32C3) #define ESP32_COUNTER_RTC_ISR_HANDLER isr_handler_t #else #define ESP32_COUNTER_RTC_ISR_HANDLER intr_handler_t @@ -88,7 +88,7 @@ static int counter_esp32_get_value(const struct device *dev, uint32_t *ticks) ARG_UNUSED(dev); SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE); -#if defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32) while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID) == 0) { /* might take 1 RTC slowclk period, don't flood RTC bus */ k_sleep(K_USEC(1)); diff --git a/drivers/counter/counter_esp32_tmr.c b/drivers/counter/counter_esp32_tmr.c index d664aed46fc5..77890f5e8fba 100644 --- a/drivers/counter/counter_esp32_tmr.c +++ b/drivers/counter/counter_esp32_tmr.c @@ -17,7 +17,7 @@ #include #include #include -#ifndef CONFIG_SOC_ESP32C3 +#ifndef CONFIG_SOC_SERIES_ESP32C3 #include #else #include @@ -26,7 +26,7 @@ #include LOG_MODULE_REGISTER(esp32_counter, CONFIG_COUNTER_LOG_LEVEL); -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #define ISR_HANDLER isr_handler_t #else #define ISR_HANDLER intr_handler_t diff --git a/drivers/dma/dma_esp32_gdma.c b/drivers/dma/dma_esp32_gdma.c index fc3116bfe493..588b3fe9414e 100644 --- a/drivers/dma/dma_esp32_gdma.c +++ b/drivers/dma/dma_esp32_gdma.c @@ -21,13 +21,13 @@ LOG_MODULE_REGISTER(dma_esp32_gdma, CONFIG_DMA_LOG_LEVEL); #include #include #include -#ifndef CONFIG_SOC_ESP32C3 +#ifndef CONFIG_SOC_SERIES_ESP32C3 #include #else #include #endif -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #define ISR_HANDLER isr_handler_t #else #define ISR_HANDLER intr_handler_t @@ -53,7 +53,7 @@ struct dma_esp32_channel { dma_callback_t cb; void *user_data; dma_descriptor_t desc; -#if defined(CONFIG_SOC_ESP32S3) +#if defined(CONFIG_SOC_SERIES_ESP32S3) struct intr_handle_data_t *intr_handle; #endif }; @@ -120,7 +120,7 @@ static void IRAM_ATTR dma_esp32_isr_handle(const struct device *dev, uint8_t rx_ } } -#if defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32C3) static int dma_esp32_enable_interrupt(const struct device *dev, struct dma_esp32_channel *dma_channel) { @@ -467,7 +467,7 @@ static int dma_esp32_reload(const struct device *dev, uint32_t channel, uint32_t return 0; } -#if defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32C3) static int dma_esp32_configure_irq(const struct device *dev) { struct dma_esp32_config *config = (struct dma_esp32_config *)dev->config; diff --git a/drivers/ethernet/Kconfig.esp32 b/drivers/ethernet/Kconfig.esp32 index e919e10b7079..8adb24cfb771 100644 --- a/drivers/ethernet/Kconfig.esp32 +++ b/drivers/ethernet/Kconfig.esp32 @@ -5,7 +5,7 @@ menuconfig ETH_ESP32 bool "ESP32 Ethernet driver" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 select MDIO help Enable ESP32 Ethernet driver. diff --git a/drivers/flash/flash_esp32.c b/drivers/flash/flash_esp32.c index a7c13b332cbf..419daa342ff7 100644 --- a/drivers/flash/flash_esp32.c +++ b/drivers/flash/flash_esp32.c @@ -30,20 +30,20 @@ #include #include -#if defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32) #include "soc/dport_reg.h" #include "esp32/rom/cache.h" #include "esp32/rom/spi_flash.h" #include "esp32/spiram.h" -#elif defined(CONFIG_SOC_ESP32S2) +#elif defined(CONFIG_SOC_SERIES_ESP32S2) #include "soc/spi_mem_reg.h" #include "esp32s2/rom/cache.h" #include "esp32s2/rom/spi_flash.h" -#elif defined(CONFIG_SOC_ESP32S3) +#elif defined(CONFIG_SOC_SERIES_ESP32S3) #include "soc/spi_mem_reg.h" #include "esp32s3/rom/cache.h" #include "esp32s3/rom/spi_flash.h" -#elif defined(CONFIG_SOC_ESP32C3) +#elif defined(CONFIG_SOC_SERIES_ESP32C3) #include "soc/spi_periph.h" #include "soc/spi_mem_reg.h" #include "soc/dport_access.h" diff --git a/drivers/gpio/gpio_esp32.c b/drivers/gpio/gpio_esp32.c index e67ffd33fee0..3851200b1813 100644 --- a/drivers/gpio/gpio_esp32.c +++ b/drivers/gpio/gpio_esp32.c @@ -20,7 +20,7 @@ #include #include #include -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #include #else #include @@ -33,7 +33,7 @@ #include LOG_MODULE_REGISTER(gpio_esp32, CONFIG_LOG_DEFAULT_LEVEL); -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 /* gpio structs in esp32c3 series are different from xtensa ones */ #define out out.data #define in in.data diff --git a/drivers/hwinfo/hwinfo_esp32.c b/drivers/hwinfo/hwinfo_esp32.c index fd466c32704a..df4d67321120 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_ESP32) && !defined(CONFIG_SOC_ESP32_NET) +#if !defined(CONFIG_SOC_SERIES_ESP32) && !defined(CONFIG_SOC_SERIES_ESP32_NET) 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/i2c/i2c_esp32.c b/drivers/i2c/i2c_esp32.c index 267c49793e4a..0730fd1a6d63 100644 --- a/drivers/i2c/i2c_esp32.c +++ b/drivers/i2c/i2c_esp32.c @@ -255,7 +255,7 @@ static void IRAM_ATTR i2c_esp32_configure_timeout(const struct device *dev) * at least for ESP32-C3 (tested with communication to bq76952 chip). So we set the * timeout to maximum supported value instead. */ -#if defined(CONFIG_SOC_ESP32C3) || defined(CONFIG_SOC_ESP32) +#if defined(CONFIG_SOC_SERIES_ESP32C3) || defined(CONFIG_SOC_SERIES_ESP32) i2c_hal_set_tout(&data->hal, I2C_LL_MAX_TIMEOUT); #else i2c_hal_set_tout_en(&data->hal, 0); diff --git a/drivers/interrupt_controller/Kconfig.esp32 b/drivers/interrupt_controller/Kconfig.esp32 index 6080dcbc318e..dd8599bfbd22 100644 --- a/drivers/interrupt_controller/Kconfig.esp32 +++ b/drivers/interrupt_controller/Kconfig.esp32 @@ -5,7 +5,7 @@ config INTC_ESP32 bool "Interrupt allocator for Xtensa-based Espressif SoCs" - default y if SOC_ESP32 || SOC_ESP32S2 || SOC_ESP32_NET || SOC_ESP32S3 + default y if SOC_FAMILY_ESP32 && !SOC_SERIES_ESP32C3 help Enable custom interrupt allocator for Espressif SoCs based on Xtensa architecture. diff --git a/drivers/interrupt_controller/Kconfig.esp32c3 b/drivers/interrupt_controller/Kconfig.esp32c3 index dfcb0f06f992..c6d4b7da88f6 100644 --- a/drivers/interrupt_controller/Kconfig.esp32c3 +++ b/drivers/interrupt_controller/Kconfig.esp32c3 @@ -3,7 +3,7 @@ config INTC_ESP32C3 bool "ESP32C3 interrupt controller driver" - depends on SOC_ESP32C3 + depends on SOC_SERIES_ESP32C3 default y help Enables the esp32c3 interrupt controller driver to handle ISR diff --git a/drivers/mdio/Kconfig.esp32 b/drivers/mdio/Kconfig.esp32 index 39c98eaa3bd9..bdc8fb1221ee 100644 --- a/drivers/mdio/Kconfig.esp32 +++ b/drivers/mdio/Kconfig.esp32 @@ -3,7 +3,7 @@ config MDIO_ESP32 bool "ESP32 MDIO driver" - depends on SOC_ESP32 + depends on SOC_SERIES_ESP32 default y help Enable ESP32 MCU Family MDIO driver. diff --git a/drivers/pinctrl/pinctrl_esp32.c b/drivers/pinctrl/pinctrl_esp32.c index d716dd4defa4..ee3811604511 100644 --- a/drivers/pinctrl/pinctrl_esp32.c +++ b/drivers/pinctrl/pinctrl_esp32.c @@ -12,7 +12,7 @@ #include #include -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 /* gpio structs in esp32c3 series are different from xtensa ones */ #define out out.data #define in in.data diff --git a/drivers/sensor/esp32_temp/Kconfig b/drivers/sensor/esp32_temp/Kconfig index 93568b416a9e..22f31ed86253 100644 --- a/drivers/sensor/esp32_temp/Kconfig +++ b/drivers/sensor/esp32_temp/Kconfig @@ -5,6 +5,6 @@ config ESP32_TEMP bool "ESP32 Temperature Sensor" default y depends on DT_HAS_ESPRESSIF_ESP32_TEMP_ENABLED - depends on !SOC_ESP32 + depends on !SOC_SERIES_ESP32 help Enable driver for temperature sensor on certain ESP targets. diff --git a/drivers/sensor/esp32_temp/esp32_temp.c b/drivers/sensor/esp32_temp/esp32_temp.c index 1ceb13bde088..5deaecc3430f 100644 --- a/drivers/sensor/esp32_temp/esp32_temp.c +++ b/drivers/sensor/esp32_temp/esp32_temp.c @@ -16,7 +16,7 @@ #include LOG_MODULE_REGISTER(esp32_temp, CONFIG_SENSOR_LOG_LEVEL); -#if CONFIG_SOC_ESP32 +#if CONFIG_SOC_SERIES_ESP32 #error "Temperature sensor not supported on ESP32" #endif /* CONFIG_IDF_TARGET_ESP32 */ diff --git a/drivers/sensor/pcnt_esp32/pcnt_esp32.c b/drivers/sensor/pcnt_esp32/pcnt_esp32.c index 21da92897356..487e1352156a 100644 --- a/drivers/sensor/pcnt_esp32/pcnt_esp32.c +++ b/drivers/sensor/pcnt_esp32/pcnt_esp32.c @@ -29,12 +29,12 @@ LOG_MODULE_REGISTER(pcnt_esp32, CONFIG_SENSOR_LOG_LEVEL); #define PCNT_INTR_UNIT_1 BIT(1) #define PCNT_INTR_UNIT_2 BIT(2) #define PCNT_INTR_UNIT_3 BIT(3) -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 #define PCNT_INTR_UNIT_4 BIT(4) #define PCNT_INTR_UNIT_5 BIT(5) #define PCNT_INTR_UNIT_6 BIT(6) #define PCNT_INTR_UNIT_7 BIT(7) -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ #ifdef CONFIG_PCNT_ESP32_TRIGGER #define PCNT_INTR_THRES_1 BIT(2) @@ -293,7 +293,7 @@ static void IRAM_ATTR pcnt_esp32_isr(const struct device *dev) pcnt_unit_status = pcnt_ll_get_unit_status(data->hal.dev, 2); } else if (pcnt_intr_status & PCNT_INTR_UNIT_3) { pcnt_unit_status = pcnt_ll_get_unit_status(data->hal.dev, 3); -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 } else if (pcnt_intr_status & PCNT_INTR_UNIT_4) { pcnt_unit_status = pcnt_ll_get_unit_status(data->hal.dev, 4); } else if (pcnt_intr_status & PCNT_INTR_UNIT_5) { @@ -302,7 +302,7 @@ static void IRAM_ATTR pcnt_esp32_isr(const struct device *dev) pcnt_unit_status = pcnt_ll_get_unit_status(data->hal.dev, 6); } else if (pcnt_intr_status & PCNT_INTR_UNIT_7) { pcnt_unit_status = pcnt_ll_get_unit_status(data->hal.dev, 7); -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ } else { return; } diff --git a/drivers/serial/Kconfig.esp32 b/drivers/serial/Kconfig.esp32 index 729d61b35ff9..f6fa5ac9d937 100644 --- a/drivers/serial/Kconfig.esp32 +++ b/drivers/serial/Kconfig.esp32 @@ -7,7 +7,7 @@ config UART_ESP32 depends on DT_HAS_ESPRESSIF_ESP32_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT - select SERIAL_SUPPORT_ASYNC if (SOC_ESP32C3 || SOC_ESP32S3) + select SERIAL_SUPPORT_ASYNC if (SOC_SERIES_ESP32C3 || SOC_SERIES_ESP32S3) select GPIO_ESP32 help Enable the ESP32 UART. diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index a1054ba7d853..6608d91a44ad 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -9,19 +9,19 @@ /* Include esp-idf headers first to avoid redefining BIT() macro */ /* TODO: include w/o prefix */ -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 #include #include #include -#elif defined(CONFIG_SOC_ESP32S2) +#elif defined(CONFIG_SOC_SERIES_ESP32S2) #include #include #include -#elif defined(CONFIG_SOC_ESP32S3) +#elif defined(CONFIG_SOC_SERIES_ESP32S3) #include #include #include -#elif defined(CONFIG_SOC_ESP32C3) +#elif defined(CONFIG_SOC_SERIES_ESP32C3) #include #include #include @@ -43,7 +43,7 @@ #include #include -#ifndef CONFIG_SOC_ESP32C3 +#ifndef CONFIG_SOC_SERIES_ESP32C3 #include #else #include @@ -55,7 +55,7 @@ #include LOG_MODULE_REGISTER(uart_esp32, CONFIG_UART_LOG_LEVEL); -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #define ISR_HANDLER isr_handler_t #else #define ISR_HANDLER intr_handler_t diff --git a/drivers/spi/spi_esp32_spim.c b/drivers/spi/spi_esp32_spim.c index 74b5d7c82b9b..3a1a5dc244a7 100644 --- a/drivers/spi/spi_esp32_spim.c +++ b/drivers/spi/spi_esp32_spim.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL); #include #include #include -#ifndef CONFIG_SOC_ESP32C3 +#ifndef CONFIG_SOC_SERIES_ESP32C3 #include #else #include @@ -29,7 +29,7 @@ LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" #include "spi_esp32_spim.h" -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #define ISR_HANDLER isr_handler_t #else #define ISR_HANDLER intr_handler_t @@ -180,11 +180,11 @@ static int spi_esp32_init_dma(const struct device *dev) #else channel_offset = 1; #endif /* SOC_GDMA_SUPPORTED */ -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 /*Connect SPI and DMA*/ DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, cfg->dma_host + 1, ((cfg->dma_host + 1) * 2)); -#endif /* CONFIG_SOC_ESP32 */ +#endif /* CONFIG_SOC_SERIES_ESP32 */ data->hal_config.dma_in = (spi_dma_dev_t *)cfg->spi; data->hal_config.dma_out = (spi_dma_dev_t *)cfg->spi; @@ -351,7 +351,7 @@ static int IRAM_ATTR spi_esp32_configure(const struct device *dev, * Workaround for ESP32S3 and ESP32C3 SoC. This dummy transaction is needed to sync CLK and * software controlled CS when SPI is in mode 3 */ -#if defined(CONFIG_SOC_ESP32S3) || defined(CONFIG_SOC_ESP32C3) +#if defined(CONFIG_SOC_SERIES_ESP32S3) || defined(CONFIG_SOC_SERIES_ESP32C3) if (ctx->num_cs_gpios && (hal_dev->mode & (SPI_MODE_CPOL | SPI_MODE_CPHA))) { spi_esp32_transfer(dev); } @@ -463,7 +463,7 @@ static const struct spi_driver_api spi_api = { .release = spi_esp32_release }; -#ifdef CONFIG_SOC_ESP32 +#ifdef CONFIG_SOC_SERIES_ESP32 #define GET_AS_CS(idx) .as_cs = DT_INST_PROP(idx, clk_as_cs), #else #define GET_AS_CS(idx) diff --git a/drivers/timer/Kconfig.esp32c3_sys b/drivers/timer/Kconfig.esp32c3_sys index 8bf5580c52bf..366cfcd8526e 100644 --- a/drivers/timer/Kconfig.esp32c3_sys +++ b/drivers/timer/Kconfig.esp32c3_sys @@ -5,7 +5,7 @@ config ESP32C3_SYS_TIMER bool "ESP32C3 sys-timer support" - depends on SOC_ESP32C3 + depends on SOC_SERIES_ESP32C3 default y select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER diff --git a/drivers/watchdog/wdt_esp32.c b/drivers/watchdog/wdt_esp32.c index c99c2b6f93a6..460f130c1b5f 100644 --- a/drivers/watchdog/wdt_esp32.c +++ b/drivers/watchdog/wdt_esp32.c @@ -15,7 +15,7 @@ #include #include #include -#ifndef CONFIG_SOC_ESP32C3 +#ifndef CONFIG_SOC_SERIES_ESP32C3 #include #else #include @@ -25,7 +25,7 @@ #include LOG_MODULE_REGISTER(wdt_esp32, CONFIG_WDT_LOG_LEVEL); -#ifdef CONFIG_SOC_ESP32C3 +#ifdef CONFIG_SOC_SERIES_ESP32C3 #define ISR_HANDLER isr_handler_t #else #define ISR_HANDLER intr_handler_t diff --git a/modules/Kconfig.esp32 b/modules/Kconfig.esp32 index 8c432032a9fa..4022f7534b03 100644 --- a/modules/Kconfig.esp32 +++ b/modules/Kconfig.esp32 @@ -3,4 +3,4 @@ config HAS_ESPRESSIF_HAL bool - depends on SOC_ESP32 || SOC_ESP32S2 || SOC_ESP32C3 || SOC_ESP32_NET || SOC_ESP32S3 + depends on SOC_FAMILY_ESP32 diff --git a/samples/boards/esp32/flash_encryption/src/main.c b/samples/boards/esp32/flash_encryption/src/main.c index adbc6326bcef..414376495ca1 100644 --- a/samples/boards/esp32/flash_encryption/src/main.c +++ b/samples/boards/esp32/flash_encryption/src/main.c @@ -16,7 +16,7 @@ #include LOG_MODULE_REGISTER(flash_encryption, CONFIG_LOG_DEFAULT_LEVEL); -#if !defined(CONFIG_SOC_ESP32) +#if !defined(CONFIG_SOC_SERIES_ESP32) #error Flash encryption feature is only available for ESP32 SOC yet. #endif diff --git a/soc/riscv/esp32c3/Kconfig.defconfig b/soc/riscv/esp32c3/Kconfig.defconfig deleted file mode 100644 index adc9eca040ea..000000000000 --- a/soc/riscv/esp32c3/Kconfig.defconfig +++ /dev/null @@ -1,54 +0,0 @@ -# ESP32C3 board configuration - -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_ESP32C3 - -if BOOTLOADER_MCUBOOT - -config HAS_FLASH_LOAD_OFFSET - default y - -config MCUBOOT_GENERATE_UNSIGNED_IMAGE - default y - -config MCUBOOT_GENERATE_CONFIRMED_IMAGE - default y - -config ROM_START_OFFSET - default 0x20 - -endif - -config SOC - default "esp32c3" - -config NUM_IRQS - default 62 - -config GEN_ISR_TABLES - default y - -config GEN_SW_ISR_TABLE - default y - -config GEN_IRQ_VECTOR_TABLE - default n - -config DYNAMIC_INTERRUPTS - default y - -config ISR_STACK_SIZE - default 2048 - -config ATOMIC_OPERATIONS_C - default y - -config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE - default n - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 16000000 - -endif diff --git a/soc/riscv/espressif_esp32/CMakeLists.txt b/soc/riscv/espressif_esp32/CMakeLists.txt new file mode 100644 index 000000000000..31ef76aadeef --- /dev/null +++ b/soc/riscv/espressif_esp32/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) +add_subdirectory(common) diff --git a/soc/riscv/espressif_esp32/Kconfig b/soc/riscv/espressif_esp32/Kconfig new file mode 100644 index 000000000000..0a6d3f90be98 --- /dev/null +++ b/soc/riscv/espressif_esp32/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ESP32 + bool + +if SOC_FAMILY_ESP32 + +config SOC_FAMILY + string + default "espressif_esp32" + +source "soc/riscv/espressif_esp32/common/Kconfig.soc" +source "soc/riscv/espressif_esp32/*/Kconfig.soc" + +endif # SOC_FAMILY_ESP32 diff --git a/soc/riscv/espressif_esp32/Kconfig.defconfig b/soc/riscv/espressif_esp32/Kconfig.defconfig new file mode 100644 index 000000000000..ee9d04c4daba --- /dev/null +++ b/soc/riscv/espressif_esp32/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/espressif_esp32/common/Kconfig.defconfig.series" +source "soc/riscv/espressif_esp32/*/Kconfig.defconfig.series" diff --git a/soc/riscv/espressif_esp32/Kconfig.soc b/soc/riscv/espressif_esp32/Kconfig.soc new file mode 100644 index 000000000000..ce15ddcf10e3 --- /dev/null +++ b/soc/riscv/espressif_esp32/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/espressif_esp32/*/Kconfig.series" diff --git a/soc/riscv/espressif_esp32/common/CMakeLists.txt b/soc/riscv/espressif_esp32/common/CMakeLists.txt new file mode 100644 index 000000000000..9edbe85c8217 --- /dev/null +++ b/soc/riscv/espressif_esp32/common/CMakeLists.txt @@ -0,0 +1,2 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 diff --git a/soc/riscv/espressif_esp32/common/Kconfig.defconfig.series b/soc/riscv/espressif_esp32/common/Kconfig.defconfig.series new file mode 100644 index 000000000000..a0a4b4f49432 --- /dev/null +++ b/soc/riscv/espressif_esp32/common/Kconfig.defconfig.series @@ -0,0 +1,52 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_ESP32 + +config GEN_ISR_TABLES + default y + +config GEN_SW_ISR_TABLE + default y + +config GEN_IRQ_VECTOR_TABLE + default n + +config DYNAMIC_INTERRUPTS + default y + +config ISR_STACK_SIZE + default 2048 + +config ATOMIC_OPERATIONS_C + default y + +config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE + default n + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 16000000 + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE + default n + +config CLOCK_CONTROL + default y + +if BOOTLOADER_MCUBOOT + + config HAS_FLASH_LOAD_OFFSET + default y + config MCUBOOT_GENERATE_UNSIGNED_IMAGE + default y + config MCUBOOT_GENERATE_CONFIRMED_IMAGE + default y + config ROM_START_OFFSET + default 0x20 + +endif # BOOTLOADER_MCUBOOT config + +endif # SOC_FAMILY_ESP32 diff --git a/soc/riscv/espressif_esp32/common/Kconfig.soc b/soc/riscv/espressif_esp32/common/Kconfig.soc new file mode 100644 index 000000000000..5eb40f3b3405 --- /dev/null +++ b/soc/riscv/espressif_esp32/common/Kconfig.soc @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_ESP32 + +config ESPTOOLPY_FLASHFREQ_80M + bool + +config FLASH_SIZE + int + +config FLASH_BASE_ADDRESS + hex + +endif # SOC_FAMILY_ESP32 diff --git a/soc/riscv/esp32c3/CMakeLists.txt b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt similarity index 98% rename from soc/riscv/esp32c3/CMakeLists.txt rename to soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt index 49c3f57b9e89..8f27b8d9d3e6 100644 --- a/soc/riscv/esp32c3/CMakeLists.txt +++ b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt @@ -39,7 +39,7 @@ if(CONFIG_BOOTLOADER_ESP_IDF) ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} -S ${espidf_components_dir}/bootloader/subproject -B ${espidf_build_dir}/bootloader -DSDKCONFIG=${espidf_build_dir}/sdkconfig - -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC} + -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC_SERIES} -DPYTHON_DEPS_CHECKED=1 -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} diff --git a/soc/riscv/espressif_esp32/esp32c3/Kconfig.defconfig.series b/soc/riscv/espressif_esp32/esp32c3/Kconfig.defconfig.series new file mode 100644 index 000000000000..50d52b3f5bfc --- /dev/null +++ b/soc/riscv/espressif_esp32/esp32c3/Kconfig.defconfig.series @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_ESP32C3 + +config SOC_SERIES + default "esp32c3" + +config NUM_IRQS + default 62 + +config ESPTOOLPY_FLASHFREQ_80M + default y + +config FLASH_SIZE + default $(dt_node_reg_size_int,/soc/flash-controller@60002000/flash@0,0) + +config FLASH_BASE_ADDRESS + default $(dt_node_reg_addr_hex,/soc/flash-controller@60002000/flash@0) + +endif # SOC_SERIES_ESP32C3 diff --git a/soc/riscv/espressif_esp32/esp32c3/Kconfig.series b/soc/riscv/espressif_esp32/esp32c3/Kconfig.series new file mode 100644 index 000000000000..d506898f5b23 --- /dev/null +++ b/soc/riscv/espressif_esp32/esp32c3/Kconfig.series @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ESP32C3 + bool "ESP32C3" + select RISCV + select RISCV_GP + select DYNAMIC_INTERRUPTS + select CLOCK_CONTROL + select PINCTRL + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select HAS_ESPRESSIF_HAL + select SOC_FAMILY_ESP32 + select XIP if !MCUBOOT + select HAS_PM + help + Enable support for Espressif ESP32-C3 diff --git a/soc/riscv/esp32c3/Kconfig.soc b/soc/riscv/espressif_esp32/esp32c3/Kconfig.soc similarity index 78% rename from soc/riscv/esp32c3/Kconfig.soc rename to soc/riscv/espressif_esp32/esp32c3/Kconfig.soc index 56d2a64a63ce..dce91fcc86a4 100644 --- a/soc/riscv/esp32c3/Kconfig.soc +++ b/soc/riscv/espressif_esp32/esp32c3/Kconfig.soc @@ -1,42 +1,28 @@ -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -config SOC_ESP32C3 - bool "ESP32C3" - select RISCV - select RISCV_GP - select DYNAMIC_INTERRUPTS - select CLOCK_CONTROL - select PINCTRL - select XIP if !MCUBOOT - select HAS_ESPRESSIF_HAL - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select HAS_PM - -if SOC_ESP32C3 - -config SOC_FAMILY_ESP32 - bool - default y +if SOC_SERIES_ESP32C3 config IDF_TARGET_ESP32C3 bool "ESP32C3 as target board" default y -config ESPTOOLPY_FLASHFREQ_80M - bool - default y +choice SOC_PART_NUMBER + prompt "ESP32-C3 SOC Selection" + depends on SOC_SERIES_ESP32C3 -config FLASH_SIZE - int - default $(dt_node_reg_size_int,/soc/flash-controller@60002000/flash@0,0) + config SOC_ESP32C3 + bool "ESP32C3" + config SOC_ESP32C3_FX4 + bool "ESP32C3_FX4" + config SOC_ESP32C3_MINI_N4 + bool "ESP32C3_MINI_N4" + config SOC_ESP32C3_WROOM_H2 + bool "ESP32C3_MINI_N4" + config SOC_ESP32C3_WROOM_H4 + bool "ESP32C3_MINI_N4" -config FLASH_BASE_ADDRESS - hex - default $(dt_node_reg_addr_hex,/soc/flash-controller@60002000/flash@0) +endchoice # SOC_PART_NUMBER config ESP_SYSTEM_RTC_EXT_XTAL bool @@ -64,7 +50,7 @@ config ESP32C3_RTC_CLK_SRC_EXT_OSC config ESP32C3_RTC_CLK_SRC_INT_8MD256 bool "Internal 8MHz oscillator, divided by 256 (~32kHz)" -endchoice +endchoice # ESP32C3_RTC_CLK_SRC config ESP32C3_RTC_CLK_CAL_CYCLES int "Number of cycles for RTC_SLOW_CLK calibration" @@ -102,7 +88,7 @@ config ESP32_PHY_MAX_TX_POWER config MAC_BB_PD bool "Power down MAC and baseband of Wi-Fi and Bluetooth when PHY is disabled" - depends on SOC_ESP32C3 && TICKLESS_KERNEL + depends on SOC_SERIES_ESP32C3 && TICKLESS_KERNEL default n help If enabled, the MAC and baseband of Wi-Fi and Bluetooth will be powered @@ -110,4 +96,4 @@ config MAC_BB_PD by a small amount but increases RAM use by approximately 4 KB(Wi-Fi only), 2 KB(Bluetooth only) or 5.3 KB(Wi-Fi + Bluetooth). -endif +endif # SOC_SERIES_ESP32C3 diff --git a/soc/riscv/esp32c3/default.ld b/soc/riscv/espressif_esp32/esp32c3/default.ld similarity index 100% rename from soc/riscv/esp32c3/default.ld rename to soc/riscv/espressif_esp32/esp32c3/default.ld diff --git a/soc/riscv/esp32c3/idle.c b/soc/riscv/espressif_esp32/esp32c3/idle.c similarity index 100% rename from soc/riscv/esp32c3/idle.c rename to soc/riscv/espressif_esp32/esp32c3/idle.c diff --git a/soc/riscv/esp32c3/linker.ld b/soc/riscv/espressif_esp32/esp32c3/linker.ld similarity index 100% rename from soc/riscv/esp32c3/linker.ld rename to soc/riscv/espressif_esp32/esp32c3/linker.ld diff --git a/soc/riscv/esp32c3/loader.c b/soc/riscv/espressif_esp32/esp32c3/loader.c similarity index 97% rename from soc/riscv/esp32c3/loader.c rename to soc/riscv/espressif_esp32/esp32c3/loader.c index bf1665d76eb3..d4740fd23549 100644 --- a/soc/riscv/esp32c3/loader.c +++ b/soc/riscv/espressif_esp32/esp32c3/loader.c @@ -18,7 +18,7 @@ #ifdef CONFIG_BOOTLOADER_MCUBOOT #define BOOT_LOG_INF(_fmt, ...) \ - ets_printf("[" CONFIG_SOC "] [INF] " _fmt "\n\r", ##__VA_ARGS__) + ets_printf("[" CONFIG_SOC_SERIES "] [INF] " _fmt "\n\r", ##__VA_ARGS__) #define HDR_ATTR __attribute__((section(".entry_addr"))) __attribute__((used)) diff --git a/soc/riscv/esp32c3/mcuboot.ld b/soc/riscv/espressif_esp32/esp32c3/mcuboot.ld similarity index 100% rename from soc/riscv/esp32c3/mcuboot.ld rename to soc/riscv/espressif_esp32/esp32c3/mcuboot.ld diff --git a/soc/riscv/esp32c3/pinctrl_soc.h b/soc/riscv/espressif_esp32/esp32c3/pinctrl_soc.h similarity index 100% rename from soc/riscv/esp32c3/pinctrl_soc.h rename to soc/riscv/espressif_esp32/esp32c3/pinctrl_soc.h diff --git a/soc/riscv/esp32c3/power.c b/soc/riscv/espressif_esp32/esp32c3/power.c similarity index 100% rename from soc/riscv/esp32c3/power.c rename to soc/riscv/espressif_esp32/esp32c3/power.c diff --git a/soc/riscv/esp32c3/soc.c b/soc/riscv/espressif_esp32/esp32c3/soc.c similarity index 100% rename from soc/riscv/esp32c3/soc.c rename to soc/riscv/espressif_esp32/esp32c3/soc.c diff --git a/soc/riscv/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h similarity index 100% rename from soc/riscv/esp32c3/soc.h rename to soc/riscv/espressif_esp32/esp32c3/soc.h diff --git a/soc/riscv/esp32c3/soc_irq.S b/soc/riscv/espressif_esp32/esp32c3/soc_irq.S similarity index 100% rename from soc/riscv/esp32c3/soc_irq.S rename to soc/riscv/espressif_esp32/esp32c3/soc_irq.S diff --git a/soc/riscv/esp32c3/soc_irq.c b/soc/riscv/espressif_esp32/esp32c3/soc_irq.c similarity index 100% rename from soc/riscv/esp32c3/soc_irq.c rename to soc/riscv/espressif_esp32/esp32c3/soc_irq.c diff --git a/soc/riscv/esp32c3/vectors.S b/soc/riscv/espressif_esp32/esp32c3/vectors.S similarity index 100% rename from soc/riscv/esp32c3/vectors.S rename to soc/riscv/espressif_esp32/esp32c3/vectors.S diff --git a/soc/xtensa/esp32/include/_soc_inthandlers.h b/soc/xtensa/esp32/include/_soc_inthandlers.h deleted file mode 100644 index 9d7e4b29b714..000000000000 --- a/soc/xtensa/esp32/include/_soc_inthandlers.h +++ /dev/null @@ -1,365 +0,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 != 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/esp32s2/Kconfig.defconfig b/soc/xtensa/esp32s2/Kconfig.defconfig deleted file mode 100644 index 24e829d5d43a..000000000000 --- a/soc/xtensa/esp32s2/Kconfig.defconfig +++ /dev/null @@ -1,55 +0,0 @@ -# ESP32S2 board configuration - -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_ESP32S2 - -if BOOTLOADER_MCUBOOT - -config HAS_FLASH_LOAD_OFFSET - default y - -config MCUBOOT_GENERATE_UNSIGNED_IMAGE - default y - -config MCUBOOT_GENERATE_CONFIRMED_IMAGE - default y - -config ROM_START_OFFSET - default 0x20 - -endif - -config SOC - default "esp32s2" - -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32s2" - -config GEN_ISR_TABLES - default y - -config GEN_IRQ_VECTOR_TABLE - default n - -config ISR_STACK_SIZE - default 2048 - -config HEAP_MEM_POOL_SIZE - default 32768 - -config MP_MAX_NUM_CPUS - default 1 - -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 - -endif diff --git a/soc/xtensa/esp32s2/include/_soc_inthandlers.h b/soc/xtensa/esp32s2/include/_soc_inthandlers.h deleted file mode 100644 index becafa7285a2..000000000000 --- a/soc/xtensa/esp32s2/include/_soc_inthandlers.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * 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 != 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/CMakeLists.txt b/soc/xtensa/espressif_esp32/CMakeLists.txt new file mode 100644 index 000000000000..31ef76aadeef --- /dev/null +++ b/soc/xtensa/espressif_esp32/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) +add_subdirectory(common) diff --git a/soc/xtensa/espressif_esp32/Kconfig b/soc/xtensa/espressif_esp32/Kconfig new file mode 100644 index 000000000000..31e176291ab8 --- /dev/null +++ b/soc/xtensa/espressif_esp32/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ESP32 + bool + +if SOC_FAMILY_ESP32 + +config SOC_FAMILY + string + default "espressif_esp32" + +source "soc/xtensa/espressif_esp32/common/Kconfig.soc" +source "soc/xtensa/espressif_esp32/*/Kconfig.soc" + +endif # SOC_FAMILY_ESP32 diff --git a/soc/xtensa/espressif_esp32/Kconfig.defconfig b/soc/xtensa/espressif_esp32/Kconfig.defconfig new file mode 100644 index 000000000000..fedabb82b8c7 --- /dev/null +++ b/soc/xtensa/espressif_esp32/Kconfig.defconfig @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/xtensa/espressif_esp32/common/Kconfig.defconfig.series" +source "soc/xtensa/espressif_esp32/*/Kconfig.defconfig.series" diff --git a/soc/xtensa/espressif_esp32/Kconfig.soc b/soc/xtensa/espressif_esp32/Kconfig.soc new file mode 100644 index 000000000000..6b28e8008689 --- /dev/null +++ b/soc/xtensa/espressif_esp32/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/xtensa/espressif_esp32/*/Kconfig.series" diff --git a/soc/xtensa/espressif_esp32/common/CMakeLists.txt b/soc/xtensa/espressif_esp32/common/CMakeLists.txt new file mode 100644 index 000000000000..e097e8ce4eec --- /dev/null +++ b/soc/xtensa/espressif_esp32/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(include) diff --git a/soc/xtensa/esp32s3/Kconfig.defconfig b/soc/xtensa/espressif_esp32/common/Kconfig.defconfig.series similarity index 57% rename from soc/xtensa/esp32s3/Kconfig.defconfig rename to soc/xtensa/espressif_esp32/common/Kconfig.defconfig.series index 864bc1351562..771976bc66d5 100644 --- a/soc/xtensa/esp32s3/Kconfig.defconfig +++ b/soc/xtensa/espressif_esp32/common/Kconfig.defconfig.series @@ -1,41 +1,44 @@ -# ESP32 board configuration - -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -if SOC_ESP32S3 +if SOC_FAMILY_ESP32 -if BOOTLOADER_MCUBOOT - config HAS_FLASH_LOAD_OFFSET - default y +# Xtensa default options for ESP32 family +config XTENSA_RESET_VECTOR + default n - config MCUBOOT_GENERATE_UNSIGNED_IMAGE - default y +config XTENSA_USE_CORE_CRT1 + default n - config MCUBOOT_GENERATE_CONFIRMED_IMAGE - default y +config GEN_ISR_TABLES + default y - config ROM_START_OFFSET - default 0x20 -endif +config GEN_IRQ_VECTOR_TABLE + default n -config SOC - default "esp32s3" +config CLOCK_CONTROL + default y -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32s3" +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) -config HEAP_MEM_POOL_SIZE - default 32768 +config XTENSA_CCOUNT_HZ + default SYS_CLOCK_HW_CYCLES_PER_SEC 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) +if BOOTLOADER_MCUBOOT -config XTENSA_CCOUNT_HZ - default SYS_CLOCK_HW_CYCLES_PER_SEC + config HAS_FLASH_LOAD_OFFSET + default y + config MCUBOOT_GENERATE_UNSIGNED_IMAGE + default y + config MCUBOOT_GENERATE_CONFIRMED_IMAGE + default y + config ROM_START_OFFSET + default 0x20 + +endif # BOOTLOADER_MCUBOOT -endif +endif # SOC_FAMILY_ESP32 diff --git a/soc/xtensa/espressif_esp32/common/Kconfig.soc b/soc/xtensa/espressif_esp32/common/Kconfig.soc new file mode 100644 index 000000000000..4cf8bf9095f8 --- /dev/null +++ b/soc/xtensa/espressif_esp32/common/Kconfig.soc @@ -0,0 +1,194 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_ESP32 + +config ESPTOOLPY_FLASHFREQ_80M + bool + +config FLASH_SIZE + int + +config FLASH_BASE_ADDRESS + hex + +config ESP_SPIRAM + bool "Support for external, SPI-connected RAM" + help + This enables support for an external SPI RAM chip, connected in + parallel with the main SPI flash chip. + +config ESP_HEAP_MIN_EXTRAM_THRESHOLD + int "Minimum threshold for external RAM allocation" + default 8192 + range 1024 131072 + depends on ESP_SPIRAM + help + Threshold to decide if memory will be allocated from DRAM + or SPIRAM. If value of allocation size is less than this value, + memory will be allocated from internal RAM. + +config ESP_HEAP_SEARCH_ALL_REGIONS + bool "Search for all available heap regions" + depends on ESP_SPIRAM + default y + help + This configuration enables searching all available heap + regions. If the region of desired capability is exhausted, + memory will be allocated from other available region. + +menu "SPI RAM config" + depends on ESP_SPIRAM + +choice SPIRAM_TYPE + prompt "Type of SPI RAM chip in use" + depends on ESP_SPIRAM + default SPIRAM_TYPE_ESPPSRAM16 + +config SPIRAM_TYPE_ESPPSRAM16 + bool "ESP-PSRAM16 or APS1604" + +config SPIRAM_TYPE_ESPPSRAM32 + bool "ESP-PSRAM32 or IS25WP032" + +config SPIRAM_TYPE_ESPPSRAM64 + bool "ESP-PSRAM64 or LY68L6400" + +endchoice # SPIRAM_TYPE + +config ESP_SPIRAM_SIZE + int "Size of SPIRAM part" + default 2097152 if SPIRAM_TYPE_ESPPSRAM16 + default 4194304 if SPIRAM_TYPE_ESPPSRAM32 + default 8388608 if SPIRAM_TYPE_ESPPSRAM64 + help + Specify size of SPIRAM part. + NOTE: If SPIRAM size is greater than 4MB, only + lower 4MB can be allocated using k_malloc(). + +choice SPIRAM_SPEED + prompt "Set RAM clock speed" + default SPIRAM_SPEED_40M + help + Select the speed for the SPI RAM chip. + If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now: + + 1. Flash SPI running at 40MHz and RAM SPI running at 40MHz + 2. Flash SPI running at 80MHz and RAM SPI running at 40MHz + 3. Flash SPI running at 80MHz and RAM SPI running at 80MHz + + Note: If the third mode(80MHz+80MHz) is enabled for SPI RAM of type 32MBit, one of the HSPI/VSPI host + will be occupied by the system. Which SPI host to use can be selected by the config item + SPIRAM_OCCUPY_SPI_HOST. Application code should never touch HSPI/VSPI hardware in this case. The + option to select 80MHz will only be visible if the flash SPI speed is also 80MHz. + (ESPTOOLPY_FLASHFREQ_79M is true) + +config SPIRAM_SPEED_26M + bool "26MHz clock speed" + depends on SOC_SERIES_ESP32S2 + +config SPIRAM_SPEED_20M + bool "20MHz clock speed" + depends on SOC_SERIES_ESP32S2 + +config SPIRAM_SPEED_40M + bool "40MHz clock speed" + +config SPIRAM_SPEED_80M + depends on ESPTOOLPY_FLASHFREQ_80M + bool "80MHz clock speed" + +endchoice # SPIRAM_SPEED + +menu "PSRAM clock and cs IO for ESP32-DOWD" + +config D0WD_PSRAM_CLK_IO + int "PSRAM CLK IO number" + range 0 33 + default 17 + help + The PSRAM CLOCK IO can be any unused GPIO, user can config it based on hardware design. If user use + 1.8V flash and 1.8V psram, this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. + +config D0WD_PSRAM_CS_IO + int "PSRAM CS IO number" + range 0 33 + default 16 + help + The PSRAM CS IO can be any unused GPIO, user can config it based on hardware design. If user use + 1.8V flash and 1.8V psram, this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. + +endmenu # PSRAM clock and cs IO for ESP32-DOWD + +menu "PSRAM clock and cs IO for ESP32-D2WD" + +config D2WD_PSRAM_CLK_IO + int "PSRAM CLK IO number" + range 0 33 + default 9 + help + User can config it based on hardware design. For ESP32-D2WD chip, the psram can only be 1.8V psram, + so this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. + +config D2WD_PSRAM_CS_IO + int "PSRAM CS IO number" + range 0 33 + default 10 + help + User can config it based on hardware design. For ESP32-D2WD chip, the psram can only be 1.8V psram, + so this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. + +endmenu # PSRAM clock and cs IO for ESP32-D2WD + +menu "PSRAM clock and cs IO for ESP32-PICO" + +config PICO_PSRAM_CS_IO + int "PSRAM CS IO number" + range 0 33 + default 10 + help + The PSRAM CS IO can be any unused GPIO, user can config it based on hardware design. + + For ESP32-PICO chip, the psram share clock with flash, so user do not need to configure the clock + IO. + For the reference hardware design, please refer to + https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf + +endmenu # PSRAM clock and cs IO for ESP32-PICO + +config SPIRAM_CUSTOM_SPIWP_SD3_PIN + bool "Use custom SPI PSRAM WP(SD3) Pin when flash pins set in eFuse (read help)" + default y if SPIRAM_SPIWP_SD3_PIN != 7 # backwards compatibility, can remove in IDF 5 + default n + help + This setting is only used if the SPI flash pins have been overridden by setting the eFuses + SPI_PAD_CONFIG_xxx, and the SPI flash mode is DIO or DOUT. + + When this is the case, the eFuse config only defines 3 of the 4 Quad I/O data pins. The WP pin (aka + ESP32 pin "SD_DATA_3" or SPI flash pin "IO2") is not specified in eFuse. The psram only has QPI + mode, so a WP pin setting is necessary. + + If this config item is set to N (default), the correct WP pin will be automatically used for any + Espressif chip or module with integrated flash. If a custom setting is needed, set this config item + to Y and specify the GPIO number connected to the WP pin. + + When flash mode is set to QIO or QOUT, the PSRAM WP pin will be set the same as the SPI Flash WP pin + configured in the bootloader. + +config SPIRAM_SPIWP_SD3_PIN + int "Custom SPI PSRAM WP(SD3) Pin" + range 0 33 + default 7 + help + The option "Use custom SPI PSRAM WP(SD3) pin" must be set or this value is ignored + + If burning a customized set of SPI flash pins in eFuse and using DIO or DOUT mode for flash, set this + value to the GPIO number of the SPIRAM WP pin. + +config SPIRAM + bool + default y + +endmenu # SPI RAM config + +endif # SOC_FAMILY_ESP32 diff --git a/soc/xtensa/esp32s3/include/_soc_inthandlers.h b/soc/xtensa/espressif_esp32/common/include/_soc_inthandlers.h similarity index 99% rename from soc/xtensa/esp32s3/include/_soc_inthandlers.h rename to soc/xtensa/espressif_esp32/common/include/_soc_inthandlers.h index 6980643e71dd..8e6b115bca3d 100644 --- a/soc/xtensa/esp32s3/include/_soc_inthandlers.h +++ b/soc/xtensa/espressif_esp32/common/include/_soc_inthandlers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/soc/xtensa/esp32/include/gdbstub/soc.h b/soc/xtensa/espressif_esp32/common/include/gdbstub/soc.h similarity index 100% rename from soc/xtensa/esp32/include/gdbstub/soc.h rename to soc/xtensa/espressif_esp32/common/include/gdbstub/soc.h diff --git a/soc/xtensa/esp32/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt similarity index 98% rename from soc/xtensa/esp32/CMakeLists.txt rename to soc/xtensa/espressif_esp32/esp32/CMakeLists.txt index 0728e94e2535..6c3039116cb4 100644 --- a/soc/xtensa/esp32/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt @@ -40,7 +40,7 @@ if(CONFIG_BOOTLOADER_ESP_IDF) ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} -S ${espidf_components_dir}/bootloader/subproject -B ${espidf_build_dir}/bootloader -DSDKCONFIG=${espidf_build_dir}/sdkconfig - -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC} + -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC_SERIES} -DPYTHON_DEPS_CHECKED=1 -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} diff --git a/soc/xtensa/esp32/Kconfig.defconfig b/soc/xtensa/espressif_esp32/esp32/Kconfig.defconfig.series similarity index 56% rename from soc/xtensa/esp32/Kconfig.defconfig rename to soc/xtensa/espressif_esp32/esp32/Kconfig.defconfig.series index 229f6fb02e7c..50a7e9e8124f 100644 --- a/soc/xtensa/esp32/Kconfig.defconfig +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.defconfig.series @@ -1,30 +1,28 @@ -# ESP32 board configuration - -# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -if SOC_ESP32 +if SOC_SERIES_ESP32 -if BOOTLOADER_MCUBOOT - config HAS_FLASH_LOAD_OFFSET - default y +config SOC_SERIES + default "esp32" - config MCUBOOT_GENERATE_UNSIGNED_IMAGE - default y +config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE + default n - config MCUBOOT_GENERATE_CONFIRMED_IMAGE - default y +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) - config ROM_START_OFFSET - default 0x20 -endif +config XTENSA_CCOUNT_HZ + default SYS_CLOCK_HW_CYCLES_PER_SEC -config SOC - default "esp32" +config ESPTOOLPY_FLASHFREQ_80M + default y -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32" +config FLASH_SIZE + default $(dt_node_reg_size_int,/soc/flash-controller@3ff42000/flash@0,0) + +config FLASH_BASE_ADDRESS + default $(dt_node_reg_addr_hex,/soc/flash-controller@3ff42000/flash@0) if SMP @@ -37,16 +35,7 @@ config SCHED_CPU_MASK config MP_MAX_NUM_CPUS default 2 -endif - -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 +endif # SMP config if GDBSTUB @@ -55,6 +44,6 @@ if GDBSTUB config GDBSTUB_BUF_SZ default 840 if GDBSTUB -endif +endif # GDBSTUB config -endif +endif # SOC_SERIES_ESP32 config diff --git a/soc/xtensa/espressif_esp32/esp32/Kconfig.series b/soc/xtensa/espressif_esp32/esp32/Kconfig.series new file mode 100644 index 000000000000..dce3176ed53c --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.series @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ESP32 + bool "ESP32 Series" + select XTENSA + select SOC_FAMILY_ESP32 + select CLOCK_CONTROL + select DYNAMIC_INTERRUPTS + select ARCH_HAS_GDBSTUB + select ARCH_SUPPORTS_COREDUMP + select PINCTRL + select XIP if !MCUBOOT + select HAS_ESPRESSIF_HAL + select CPU_HAS_FPU + select HAS_PM + help + Enable support for Espressif ESP32 diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc similarity index 56% rename from soc/xtensa/esp32/Kconfig.soc rename to soc/xtensa/espressif_esp32/esp32/Kconfig.soc index 9e4e0e6892f5..7371c49ed940 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc @@ -1,40 +1,66 @@ -# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -config SOC_ESP32 - bool "ESP32" - select XTENSA - select CLOCK_CONTROL - select DYNAMIC_INTERRUPTS - select ARCH_HAS_GDBSTUB - select ARCH_SUPPORTS_COREDUMP - select PINCTRL - select XIP if !MCUBOOT - select HAS_ESPRESSIF_HAL - select CPU_HAS_FPU - select HAS_PM - -if SOC_ESP32 - -config SOC_FAMILY_ESP32 - bool - default y +if SOC_SERIES_ESP32 config IDF_TARGET_ESP32 bool "ESP32 as target board" default y -config ESPTOOLPY_FLASHFREQ_80M - bool - default y +config SOC_TOOLCHAIN_NAME + string + default "espressif_esp32" + +choice SOC_PART_NUMBER + prompt "ESP32 SOC/SIP Selection" + depends on SOC_SERIES_ESP32 + + # SoC with/without embedded flash + config SOC_ESP32_D0WD_V3 + bool "ESP32_D0WD_V3" + config SOC_ESP32_D0WDR2_V3 + bool "ESP32_D0WDR2_V3" + config SOC_ESP32_U4WDH + bool "ESP32_U4WDH" + config SOC_ESP32_PICO_V3 + bool "ESP32_PICO_V3" + config SOC_ESP32_PICO_V3_02 + bool "ESP32_PICO_V3_02" + config SOC_ESP32_PICO_D4 + bool "ESP32_PICO_D4" + # SiP with external flash / psram + config SOC_ESP32_WROOM_DA_N4 + bool "ESP32_WROOM_DA_N4" + config SOC_ESP32_WROOM_DA_N8 + bool "ESP32_WROOM_DA_N8" + config SOC_ESP32_WROOM_DA_N16 + bool "ESP32_WROOM_DA_N16" + config SOC_ESP32_WROOM_32UE_N4 + bool "ESP32_WROOM_32UE_N4" + config SOC_ESP32_WROOM_32UE_N8 + bool "ESP32_WROOM_32UE_N8" + config SOC_ESP32_WROOM_32UE_N16 + bool "ESP32_WROOM_32UE_N16" + config SOC_ESP32_WROVER_E_N4R2 + bool "ESP32_WROVER_E_N4R2" + config SOC_ESP32_WROVER_E_N8R2 + bool "ESP32_WROVER_E_N8R2" + config SOC_ESP32_WROVER_E_N16R2 + bool "ESP32_WROVER_E_N16R2" + config SOC_ESP32_WROVER_E_N4R8 + bool "ESP32_WROVER_E_N4R8" + config SOC_ESP32_WROVER_E_N8R8 + bool "ESP32_WROVER_E_N8R8" + config SOC_ESP32_WROVER_E_N16R8 + bool "ESP32_WROVER_E_N16R8" + +endchoice # SOC_PART_NUMBER -config FLASH_SIZE - int - default $(dt_node_reg_size_int,/soc/flash-controller@3ff42000/flash@0,0) +config ESP_SYSTEM_RTC_EXT_XTAL + bool -config FLASH_BASE_ADDRESS - hex - default $(dt_node_reg_addr_hex,/soc/flash-controller@3ff42000/flash@0) +config ESP_SYSTEM_RTC_EXT_OSC + bool config ESP32_NETWORK_CORE bool "Uses the ESP32 APP_CPU as Network dedicated core" @@ -55,183 +81,6 @@ config ESP_HEAP_MEM_POOL_REGION_1_SIZE This configuration can be used to add memory from region 1 to heap and can be allocated using k_malloc. -config ESP_SPIRAM - bool "Support for external, SPI-connected RAM" - default n if MCUBOOT - help - This enables support for an external SPI RAM chip, connected in - parallel with the main SPI flash chip. - -config ESP_HEAP_MIN_EXTRAM_THRESHOLD - int "Minimum threshold for external RAM allocation" - default 8192 - range 1024 131072 - depends on ESP_SPIRAM - help - Threshold to decide if memory will be allocated from DRAM - or SPIRAM. If value of allocation size is less than this value, - memory will be allocated from internal RAM. - -config ESP_HEAP_SEARCH_ALL_REGIONS - bool "Search for all available heap regions" - depends on ESP_SPIRAM - default y - help - This configuration enables searching all available heap - regions. If the region of desired capability is exhausted, - memory will be allocated from other available region. - -menu "SPI RAM config" - depends on ESP_SPIRAM - -choice SPIRAM_TYPE - prompt "Type of SPI RAM chip in use" - default SPIRAM_TYPE_ESPPSRAM16 - -config SPIRAM_TYPE_ESPPSRAM16 - bool "ESP-PSRAM16 or APS1604" - -config SPIRAM_TYPE_ESPPSRAM32 - bool "ESP-PSRAM32 or IS25WP032" - -config SPIRAM_TYPE_ESPPSRAM64 - bool "ESP-PSRAM64 or LY68L6400" - -endchoice # SPIRAM_TYPE - -config ESP_SPIRAM_SIZE - int "Size of SPIRAM part" - default 2097152 if SPIRAM_TYPE_ESPPSRAM16 - default 4194304 if SPIRAM_TYPE_ESPPSRAM32 - default 8388608 if SPIRAM_TYPE_ESPPSRAM64 - help - Specify size of SPIRAM part. - NOTE: If SPIRAM size is greater than 4MB, only - lower 4MB can be allocated using k_malloc(). - -choice SPIRAM_SPEED - prompt "Set RAM clock speed" - default SPIRAM_SPEED_40M - help - Select the speed for the SPI RAM chip. - If SPI RAM is enabled, we only support three combinations of SPI speed mode we supported now: - - 1. Flash SPI running at 40MHz and RAM SPI running at 40MHz - 2. Flash SPI running at 80MHz and RAM SPI running at 40MHz - 3. Flash SPI running at 80MHz and RAM SPI running at 80MHz - - Note: If the third mode(80MHz+80MHz) is enabled for SPI RAM of type 32MBit, one of the HSPI/VSPI host - will be occupied by the system. Which SPI host to use can be selected by the config item - SPIRAM_OCCUPY_SPI_HOST. Application code should never touch HSPI/VSPI hardware in this case. The - option to select 80MHz will only be visible if the flash SPI speed is also 80MHz. - (ESPTOOLPY_FLASHFREQ_79M is true) - -config SPIRAM_SPEED_40M - bool "40MHz clock speed" - -config SPIRAM_SPEED_80M - depends on ESPTOOLPY_FLASHFREQ_80M - bool "80MHz clock speed" - -endchoice # SPIRAM_SPEED - -menu "PSRAM clock and cs IO for ESP32-DOWD" - -config D0WD_PSRAM_CLK_IO - int "PSRAM CLK IO number" - range 0 33 - default 17 - help - The PSRAM CLOCK IO can be any unused GPIO, user can config it based on hardware design. If user use - 1.8V flash and 1.8V psram, this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. - -config D0WD_PSRAM_CS_IO - int "PSRAM CS IO number" - range 0 33 - default 16 - help - The PSRAM CS IO can be any unused GPIO, user can config it based on hardware design. If user use - 1.8V flash and 1.8V psram, this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. - -endmenu # PSRAM clock and cs IO for ESP32-DOWD - -menu "PSRAM clock and cs IO for ESP32-D2WD" - -config D2WD_PSRAM_CLK_IO - int "PSRAM CLK IO number" - range 0 33 - default 9 - help - User can config it based on hardware design. For ESP32-D2WD chip, the psram can only be 1.8V psram, - so this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. - -config D2WD_PSRAM_CS_IO - int "PSRAM CS IO number" - range 0 33 - default 10 - help - User can config it based on hardware design. For ESP32-D2WD chip, the psram can only be 1.8V psram, - so this value can only be one of 6, 7, 8, 9, 10, 11, 16, 17. - -endmenu # PSRAM clock and cs IO for ESP32-D2WD - -menu "PSRAM clock and cs IO for ESP32-PICO" - -config PICO_PSRAM_CS_IO - int "PSRAM CS IO number" - range 0 33 - default 10 - help - The PSRAM CS IO can be any unused GPIO, user can config it based on hardware design. - - For ESP32-PICO chip, the psram share clock with flash, so user do not need to configure the clock - IO. - For the reference hardware design, please refer to - https://www.espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf - -endmenu # PSRAM clock and cs IO for ESP32-PICO - -config SPIRAM_CUSTOM_SPIWP_SD3_PIN - bool "Use custom SPI PSRAM WP(SD3) Pin when flash pins set in eFuse (read help)" - default y if SPIRAM_SPIWP_SD3_PIN != 7 # backwards compatibility, can remove in IDF 5 - default n - help - This setting is only used if the SPI flash pins have been overridden by setting the eFuses - SPI_PAD_CONFIG_xxx, and the SPI flash mode is DIO or DOUT. - - When this is the case, the eFuse config only defines 3 of the 4 Quad I/O data pins. The WP pin (aka - ESP32 pin "SD_DATA_3" or SPI flash pin "IO2") is not specified in eFuse. The psram only has QPI - mode, so a WP pin setting is necessary. - - If this config item is set to N (default), the correct WP pin will be automatically used for any - Espressif chip or module with integrated flash. If a custom setting is needed, set this config item - to Y and specify the GPIO number connected to the WP pin. - - When flash mode is set to QIO or QOUT, the PSRAM WP pin will be set the same as the SPI Flash WP pin - configured in the bootloader. - -config SPIRAM_SPIWP_SD3_PIN - int "Custom SPI PSRAM WP(SD3) Pin" - range 0 33 - default 7 - help - The option "Use custom SPI PSRAM WP(SD3) pin" must be set or this value is ignored - - If burning a customized set of SPI flash pins in eFuse and using DIO or DOUT mode for flash, set this - value to the GPIO number of the SPIRAM WP pin. - -config SPIRAM - bool - default y - -endmenu # SPI RAM config - -config ESP_SYSTEM_RTC_EXT_XTAL - bool - -config ESP_SYSTEM_RTC_EXT_OSC - bool - choice ESP32_RTC_CLK_SRC prompt "RTC clock source" default ESP32_RTC_CLK_SRC_INT_RC @@ -417,6 +266,6 @@ config ETH_DMA_TX_BUFFER_NUM Number of DMA transmit buffers. Each buffer's size is ETH_DMA_BUFFER_SIZE. Larger number of buffers could increase throughput somehow. -endif # ESP32_EMAC +endif # ESP32_EMAC config -endif # SOC_ESP32 +endif # SOC_SERIES_ESP32 config diff --git a/soc/xtensa/esp32/default.ld b/soc/xtensa/espressif_esp32/esp32/default.ld similarity index 100% rename from soc/xtensa/esp32/default.ld rename to soc/xtensa/espressif_esp32/esp32/default.ld diff --git a/soc/xtensa/esp32/esp32-mp.c b/soc/xtensa/espressif_esp32/esp32/esp32-mp.c similarity index 100% rename from soc/xtensa/esp32/esp32-mp.c rename to soc/xtensa/espressif_esp32/esp32/esp32-mp.c diff --git a/soc/xtensa/esp32/gdbstub.c b/soc/xtensa/espressif_esp32/esp32/gdbstub.c similarity index 100% rename from soc/xtensa/esp32/gdbstub.c rename to soc/xtensa/espressif_esp32/esp32/gdbstub.c diff --git a/soc/xtensa/esp32/linker.ld b/soc/xtensa/espressif_esp32/esp32/linker.ld similarity index 100% rename from soc/xtensa/esp32/linker.ld rename to soc/xtensa/espressif_esp32/esp32/linker.ld diff --git a/soc/xtensa/esp32/loader.c b/soc/xtensa/espressif_esp32/esp32/loader.c similarity index 97% rename from soc/xtensa/esp32/loader.c rename to soc/xtensa/espressif_esp32/esp32/loader.c index ed18aa8d02a3..5b946bfba415 100644 --- a/soc/xtensa/esp32/loader.c +++ b/soc/xtensa/espressif_esp32/esp32/loader.c @@ -16,7 +16,7 @@ #ifdef CONFIG_BOOTLOADER_MCUBOOT #define BOOT_LOG_INF(_fmt, ...) \ - ets_printf("[" CONFIG_SOC "] [INF] " _fmt "\n\r", ##__VA_ARGS__) + ets_printf("[" CONFIG_SOC_SERIES "] [INF] " _fmt "\n\r", ##__VA_ARGS__) #define HDR_ATTR __attribute__((section(".entry_addr"))) __attribute__((used)) diff --git a/soc/xtensa/esp32/mcuboot.ld b/soc/xtensa/espressif_esp32/esp32/mcuboot.ld similarity index 100% rename from soc/xtensa/esp32/mcuboot.ld rename to soc/xtensa/espressif_esp32/esp32/mcuboot.ld diff --git a/soc/xtensa/esp32/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32/newlib_fix.c similarity index 100% rename from soc/xtensa/esp32/newlib_fix.c rename to soc/xtensa/espressif_esp32/esp32/newlib_fix.c diff --git a/soc/xtensa/esp32/pinctrl_soc.h b/soc/xtensa/espressif_esp32/esp32/pinctrl_soc.h similarity index 100% rename from soc/xtensa/esp32/pinctrl_soc.h rename to soc/xtensa/espressif_esp32/esp32/pinctrl_soc.h diff --git a/soc/xtensa/esp32/power.c b/soc/xtensa/espressif_esp32/esp32/power.c similarity index 100% rename from soc/xtensa/esp32/power.c rename to soc/xtensa/espressif_esp32/esp32/power.c diff --git a/soc/xtensa/esp32/soc.c b/soc/xtensa/espressif_esp32/esp32/soc.c similarity index 98% rename from soc/xtensa/esp32/soc.c rename to soc/xtensa/espressif_esp32/esp32/soc.c index cb1e3433fa8e..0f7537bacfc9 100644 --- a/soc/xtensa/esp32/soc.c +++ b/soc/xtensa/espressif_esp32/esp32/soc.c @@ -31,9 +31,9 @@ #include "esp_app_format.h" #include "hal/wdt_hal.h" -#ifndef CONFIG_SOC_ESP32_NET +#ifndef CONFIG_SOC_SERIES_ESP32_NET #include "esp_clk_internal.h" -#endif /* CONFIG_SOC_ESP32_NET */ +#endif /* CONFIG_SOC_SERIES_ESP32_NET */ #ifdef CONFIG_MCUBOOT #include "bootloader_init.h" @@ -135,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_ESP32_NET +#ifndef CONFIG_SOC_SERIES_ESP32_NET /* Configures the CPU clock, RTC slow and fast clocks, and performs * RTC slow clock calibration. */ diff --git a/soc/xtensa/esp32/soc.h b/soc/xtensa/espressif_esp32/esp32/soc.h similarity index 100% rename from soc/xtensa/esp32/soc.h rename to soc/xtensa/espressif_esp32/esp32/soc.h diff --git a/soc/xtensa/esp32_net/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt similarity index 100% rename from soc/xtensa/esp32_net/CMakeLists.txt rename to soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt diff --git a/soc/xtensa/esp32_net/Kconfig.defconfig b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series similarity index 62% rename from soc/xtensa/esp32_net/Kconfig.defconfig rename to soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series index 7484769fb160..8193bbb6149a 100644 --- a/soc/xtensa/esp32_net/Kconfig.defconfig +++ b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series @@ -1,15 +1,11 @@ -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -if SOC_ESP32_NET +if SOC_SERIES_ESP32_NET -config SOC +config SOC_SERIES default "esp32_net" -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32" - config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE default n @@ -19,4 +15,7 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config XTENSA_CCOUNT_HZ default SYS_CLOCK_HW_CYCLES_PER_SEC -endif +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 new file mode 100644 index 000000000000..55f794f96e05 --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series @@ -0,0 +1,12 @@ +# 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/esp32_net/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc similarity index 88% rename from soc/xtensa/esp32_net/Kconfig.soc rename to soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc index 3b7350717003..975b777b7907 100644 --- a/soc/xtensa/esp32_net/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc @@ -1,26 +1,25 @@ # Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -config SOC_ESP32_NET - bool "ESP32_NET" - select XTENSA - select CLOCK_CONTROL - select DYNAMIC_INTERRUPTS - select HAS_ESPRESSIF_HAL - -if SOC_ESP32_NET - -config SOC_FAMILY_ESP32 - bool - default y +if SOC_SERIES_ESP32_NET config IDF_TARGET_ESP32 bool "ESP32 as target board" default y -config ESPTOOLPY_FLASHFREQ_80M - bool - 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" @@ -76,4 +75,4 @@ config ESP32_UNIVERSAL_MAC_ADDRESSES default 2 if ESP32_UNIVERSAL_MAC_ADDRESSES_TWO default 4 if ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR -endif # SOC_ESP32 +endif # SOC_ESP32_NET diff --git a/soc/xtensa/esp32_net/include/_soc_inthandlers.h b/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h similarity index 100% rename from soc/xtensa/esp32_net/include/_soc_inthandlers.h rename to soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h diff --git a/soc/xtensa/esp32_net/include/gdbstub/soc.h b/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h similarity index 100% rename from soc/xtensa/esp32_net/include/gdbstub/soc.h rename to soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h diff --git a/soc/xtensa/esp32_net/linker.ld b/soc/xtensa/espressif_esp32/esp32_net/linker.ld similarity index 100% rename from soc/xtensa/esp32_net/linker.ld rename to soc/xtensa/espressif_esp32/esp32_net/linker.ld diff --git a/soc/xtensa/esp32_net/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c similarity index 100% rename from soc/xtensa/esp32_net/newlib_fix.c rename to soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c diff --git a/soc/xtensa/esp32_net/soc.c b/soc/xtensa/espressif_esp32/esp32_net/soc.c similarity index 100% rename from soc/xtensa/esp32_net/soc.c rename to soc/xtensa/espressif_esp32/esp32_net/soc.c diff --git a/soc/xtensa/esp32_net/soc.h b/soc/xtensa/espressif_esp32/esp32_net/soc.h similarity index 100% rename from soc/xtensa/esp32_net/soc.h rename to soc/xtensa/espressif_esp32/esp32_net/soc.h diff --git a/soc/xtensa/esp32s2/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt similarity index 98% rename from soc/xtensa/esp32s2/CMakeLists.txt rename to soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt index c520dabda273..18cf77e3248f 100644 --- a/soc/xtensa/esp32s2/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32s2/CMakeLists.txt @@ -38,7 +38,7 @@ if(CONFIG_BOOTLOADER_ESP_IDF) ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} -S ${espidf_components_dir}/bootloader/subproject -B ${espidf_build_dir}/bootloader -DSDKCONFIG=${espidf_build_dir}/sdkconfig - -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC} + -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC_SERIES} -DPYTHON_DEPS_CHECKED=1 -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series new file mode 100644 index 000000000000..c1618783ae59 --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series @@ -0,0 +1,33 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_ESP32S2 + +config SOC_SERIES + default "esp32s2" + +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 MP_MAX_NUM_CPUS + default 1 + +config ISR_STACK_SIZE + default 2048 + +config HEAP_MEM_POOL_SIZE + default 32768 + +config ESPTOOLPY_FLASHFREQ_80M + default y + +config FLASH_SIZE + default $(dt_node_reg_size_int,/soc/flash-controller@3f402000/flash@0,0) + +config FLASH_BASE_ADDRESS + default $(dt_node_reg_addr_hex,/soc/flash-controller@3f402000/flash@0) + +endif # SOC_SERIES_ESP32S2 diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.series new file mode 100644 index 000000000000..88bdcf1a53ae --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.series @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ESP32S2 + bool "ESP32-S2 Series" + select XTENSA + select SOC_FAMILY_ESP32 + select ATOMIC_OPERATIONS_C + select DYNAMIC_INTERRUPTS + select CLOCK_CONTROL + select PINCTRL + select XIP if !MCUBOOT + select HAS_ESPRESSIF_HAL + select ARCH_SUPPORTS_COREDUMP + select HAS_PM + help + Enable support for Espressif ESP32-S2 diff --git a/soc/xtensa/esp32s2/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.soc similarity index 74% rename from soc/xtensa/esp32s2/Kconfig.soc rename to soc/xtensa/espressif_esp32/esp32s2/Kconfig.soc index eef1a489ea2f..85d190d6472b 100644 --- a/soc/xtensa/esp32s2/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.soc @@ -1,39 +1,122 @@ -# Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -config SOC_ESP32S2 - bool "ESP32S2" - select XTENSA - select ATOMIC_OPERATIONS_C - select DYNAMIC_INTERRUPTS - select CLOCK_CONTROL - select PINCTRL - select XIP if !MCUBOOT - select HAS_ESPRESSIF_HAL - select ARCH_SUPPORTS_COREDUMP - select HAS_PM - -if SOC_ESP32S2 - -config SOC_FAMILY_ESP32 - bool - default y +if SOC_SERIES_ESP32S2 config IDF_TARGET_ESP32S2 - bool "ESP32S2 as target board" + bool "ESP32S2 as target SOC" default y -config ESPTOOLPY_FLASHFREQ_80M +config SOC_TOOLCHAIN_NAME + string + default "espressif_esp32s2" + +choice SOC_PART_NUMBER + prompt "ESP32-S2 SOC Selection" + depends on SOC_SERIES_ESP32S2 + + # SoC with/without embedded flash + config SOC_ESP32S2 + bool "ESP32S2" + config SOC_ESP32S2_R2 + bool "ESP32S2_R2" + config SOC_ESP32S2_FH2 + bool "ESP32S2_FH2" + config SOC_ESP32S2_FH4 + bool "ESP32S2_FH4" + config SOC_ESP32S2_FN4R2 + bool "ESP32S2_FN4R2" + # SiP with external flash / psram + config SOC_ESP32S2_SOLO_N4 + bool "ESP32S2_SOLO_N4" + config SOC_ESP32S2_SOLO_N8 + bool "ESP32S2_SOLO_N8" + config SOC_ESP32S2_SOLO_N16 + bool "ESP32S2_SOLO_N16" + config SOC_ESP32S2_SOLO_N4R2 + bool "ESP32S2_SOLO_N4R2" + config SOC_ESP32S2_MINI_N4 + bool "ESP32S2_MINI_N4" + config SOC_ESP32S2_MINI_N4R2 + bool "ESP32S2_MINI_N4R2" + config SOC_ESP32S2_WROOM + bool "ESP32S2_WROOM" + config SOC_ESP32S2_WROVER_N4R2 + bool "ESP32S2_WROVER_N4R2" + config SOC_ESP32S2_WROVER_N8R2 + bool "ESP32S2_WROVER_N8R2" + config SOC_ESP32S2_WROVER_N16R2 + bool "ESP32S2_WROVER_N16R2" + +endchoice # SOC_PART_NUMBER + +config ESP_SYSTEM_RTC_EXT_XTAL bool - default y -config FLASH_SIZE - int - default $(dt_node_reg_size_int,/soc/flash-controller@3f402000/flash@0,0) +config ESP_SYSTEM_RTC_EXT_OSC + bool -config FLASH_BASE_ADDRESS - hex - default $(dt_node_reg_addr_hex,/soc/flash-controller@3f402000/flash@0) +choice ESP32S2_RTC_CLK_SRC + prompt "RTC clock source" + default ESP32S2_RTC_CLK_SRC_INT_RC + help + Choose which clock is used as RTC clock source. + + - "Internal 90kHz oscillator" option provides lowest deep sleep current + consumption, and does not require extra external components. However + frequency stability with respect to temperature is poor, so time may + drift in deep/light sleep modes. + - "External 32kHz crystal" provides better frequency stability, at the + expense of slightly higher (1uA) deep sleep current consumption. + - "External 32kHz oscillator" allows using 32kHz clock generated by an + external circuit. In this case, external clock signal must be connected + to 32K_XN pin. Amplitude should be <1.2V in case of sine wave signal, + and <1V in case of square wave signal. Common mode voltage should be + 0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude. + Additionally, 1nF capacitor must be connected between 32K_XP pin and + ground. 32K_XP pin can not be used as a GPIO in this case. + - "Internal 8MHz oscillator divided by 256" option results in higher + deep sleep current (by 5uA) but has better frequency stability than + the internal 90kHz oscillator. It does not require external components. + +config ESP32S2_RTC_CLK_SRC_INT_RC + bool "Internal 90kHz RC oscillator" + +config ESP32S2_RTC_CLK_SRC_EXT_CRYS + bool "External 32kHz crystal" + select ESP_SYSTEM_RTC_EXT_XTAL + +config ESP32S2_RTC_CLK_SRC_EXT_OSC + bool "External 32kHz oscillator at 32K_XN pin" + select ESP_SYSTEM_RTC_EXT_OSC + +config ESP32S2_RTC_CLK_SRC_INT_8MD256 + bool "Internal 8MHz oscillator, divided by 256 (~32kHz)" + +endchoice + +config ESP32S2_RTC_CLK_CAL_CYCLES + int "Number of cycles for RTC_SLOW_CLK calibration" + default 3000 if ESP32S2_RTC_CLK_SRC_EXT_CRYS || ESP32S2_RTC_CLK_SRC_EXT_OSC || ESP32S2_RTC_CLK_SRC_INT_8MD256 + default 576 if ESP32S2_RTC_CLK_SRC_INT_RC + range 0 125000 + help + When the startup code initializes RTC_SLOW_CLK, it can perform + calibration by comparing the RTC_SLOW_CLK frequency with main XTAL + frequency. This option sets the number of RTC_SLOW_CLK cycles measured + by the calibration routine. Higher numbers increase calibration + precision, which may be important for applications which spend a lot of + time in deep sleep. Lower numbers reduce startup time. + + When this option is set to 0, clock calibration will not be performed at + startup, and approximate clock frequencies will be assumed: + + - 90000 Hz if internal RC oscillator is used as clock source. For this use value 1024. + - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more. + In case more value will help improve the definition of the launch of the crystal. + If the crystal could not start, it will be switched to internal RC. + +menu "Cache config" choice prompt "Instruction cache line size" @@ -98,51 +181,9 @@ config ESP32S2_DATA_CACHE_SIZE default 0x4000 if ESP32S2_DATA_CACHE_16KB default 0x0000 -config ESP_SPIRAM - bool "Support for external, SPI-connected RAM" - help - This enables support for an external SPI RAM chip, connected in - parallel with the main SPI flash chip. - -config ESP_HEAP_MIN_EXTRAM_THRESHOLD - int "Minimum threshold for external RAM allocation" - default 8192 - range 1024 131072 - depends on ESP_SPIRAM - help - Threshold to decide if memory will be allocated from DRAM - or SPIRAM. If value of allocation size is less than this value, - memory will be allocated from internal RAM. - -menu "SPI RAM config" - depends on ESP_SPIRAM - -choice SPIRAM_TYPE - prompt "Type of SPI RAM chip in use" - default SPIRAM_TYPE_ESPPSRAM16 - -config SPIRAM_TYPE_ESPPSRAM16 - bool "ESP-PSRAM16 or APS1604" - -config SPIRAM_TYPE_ESPPSRAM32 - bool "ESP-PSRAM32 or IS25WP032" - -config SPIRAM_TYPE_ESPPSRAM64 - bool "ESP-PSRAM64 or LY68L6400" - -endchoice # SPIRAM_TYPE +endmenu # Cache config -config ESP_SPIRAM_SIZE - int "Size of SPIRAM part" - default 2097152 if SPIRAM_TYPE_ESPPSRAM16 - default 4194304 if SPIRAM_TYPE_ESPPSRAM32 - default 8388608 if SPIRAM_TYPE_ESPPSRAM64 - help - Specify size of SPIRAM part. - NOTE: If SPIRAM size is greater than 4MB, only - lower 4MB can be allocated using k_malloc(). - -menu "PSRAM clock and cs IO for ESP32S2" +menu "PSRAM clock and cs IO for ESP32-S2" depends on ESP_SPIRAM config DEFAULT_PSRAM_CLK_IO @@ -163,98 +204,6 @@ config DEFAULT_PSRAM_CS_IO endmenu # PSRAM clock and cs IO for ESP32S2 -choice SPIRAM_SPEED - prompt "Set RAM clock speed" - default SPIRAM_SPEED_40M - help - Select the speed for the SPI RAM chip. - -config SPIRAM_SPEED_80M - bool "80MHz clock speed" - -config SPIRAM_SPEED_40M - bool "40MHz clock speed" - -config SPIRAM_SPEED_26M - bool "26MHz clock speed" - -config SPIRAM_SPEED_20M - bool "20MHz clock speed" - -endchoice # SPIRAM_SPEED - -config SPIRAM - bool - default y - -endmenu # SPI RAM config - -config ESP_SYSTEM_RTC_EXT_XTAL - bool - -config ESP_SYSTEM_RTC_EXT_OSC - bool - -choice ESP32S2_RTC_CLK_SRC - prompt "RTC clock source" - default ESP32S2_RTC_CLK_SRC_INT_RC - help - Choose which clock is used as RTC clock source. - - - "Internal 90kHz oscillator" option provides lowest deep sleep current - consumption, and does not require extra external components. However - frequency stability with respect to temperature is poor, so time may - drift in deep/light sleep modes. - - "External 32kHz crystal" provides better frequency stability, at the - expense of slightly higher (1uA) deep sleep current consumption. - - "External 32kHz oscillator" allows using 32kHz clock generated by an - external circuit. In this case, external clock signal must be connected - to 32K_XN pin. Amplitude should be <1.2V in case of sine wave signal, - and <1V in case of square wave signal. Common mode voltage should be - 0.1 < Vcm < 0.5Vamp, where Vamp is the signal amplitude. - Additionally, 1nF capacitor must be connected between 32K_XP pin and - ground. 32K_XP pin can not be used as a GPIO in this case. - - "Internal 8MHz oscillator divided by 256" option results in higher - deep sleep current (by 5uA) but has better frequency stability than - the internal 90kHz oscillator. It does not require external components. - -config ESP32S2_RTC_CLK_SRC_INT_RC - bool "Internal 90kHz RC oscillator" - -config ESP32S2_RTC_CLK_SRC_EXT_CRYS - bool "External 32kHz crystal" - select ESP_SYSTEM_RTC_EXT_XTAL - -config ESP32S2_RTC_CLK_SRC_EXT_OSC - bool "External 32kHz oscillator at 32K_XN pin" - select ESP_SYSTEM_RTC_EXT_OSC - -config ESP32S2_RTC_CLK_SRC_INT_8MD256 - bool "Internal 8MHz oscillator, divided by 256 (~32kHz)" - -endchoice - -config ESP32S2_RTC_CLK_CAL_CYCLES - int "Number of cycles for RTC_SLOW_CLK calibration" - default 3000 if ESP32S2_RTC_CLK_SRC_EXT_CRYS || ESP32S2_RTC_CLK_SRC_EXT_OSC || ESP32S2_RTC_CLK_SRC_INT_8MD256 - default 576 if ESP32S2_RTC_CLK_SRC_INT_RC - range 0 125000 - help - When the startup code initializes RTC_SLOW_CLK, it can perform - calibration by comparing the RTC_SLOW_CLK frequency with main XTAL - frequency. This option sets the number of RTC_SLOW_CLK cycles measured - by the calibration routine. Higher numbers increase calibration - precision, which may be important for applications which spend a lot of - time in deep sleep. Lower numbers reduce startup time. - - When this option is set to 0, clock calibration will not be performed at - startup, and approximate clock frequencies will be assumed: - - - 90000 Hz if internal RC oscillator is used as clock source. For this use value 1024. - - 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more. - In case more value will help improve the definition of the launch of the crystal. - If the crystal could not start, it will be switched to internal RC. - choice ESP32S2_UNIVERSAL_MAC_ADDRESSES bool "Number of universally administered (by IEEE) MAC address" default ESP32S2_UNIVERSAL_MAC_ADDRESSES_TWO @@ -274,7 +223,7 @@ choice ESP32S2_UNIVERSAL_MAC_ADDRESSES allocation of MAC addresses in this range (either 1 or 2 per device). config ESP32S2_UNIVERSAL_MAC_ADDRESSES_ONE - bool "Two" + bool "One" select ESP_MAC_ADDR_UNIVERSE_WIFI_STA config ESP32S2_UNIVERSAL_MAC_ADDRESSES_TWO @@ -307,4 +256,4 @@ config ESP32_PHY_MAX_TX_POWER int default ESP32_PHY_MAX_WIFI_TX_POWER -endif # SOC_ESP32S2 +endif # SOC_SERIES_ESP32S2 diff --git a/soc/xtensa/esp32s2/default.ld b/soc/xtensa/espressif_esp32/esp32s2/default.ld similarity index 100% rename from soc/xtensa/esp32s2/default.ld rename to soc/xtensa/espressif_esp32/esp32s2/default.ld diff --git a/soc/xtensa/esp32s2/linker.ld b/soc/xtensa/espressif_esp32/esp32s2/linker.ld similarity index 100% rename from soc/xtensa/esp32s2/linker.ld rename to soc/xtensa/espressif_esp32/esp32s2/linker.ld diff --git a/soc/xtensa/esp32s2/loader.c b/soc/xtensa/espressif_esp32/esp32s2/loader.c similarity index 100% rename from soc/xtensa/esp32s2/loader.c rename to soc/xtensa/espressif_esp32/esp32s2/loader.c diff --git a/soc/xtensa/esp32s2/mcuboot.ld b/soc/xtensa/espressif_esp32/esp32s2/mcuboot.ld similarity index 100% rename from soc/xtensa/esp32s2/mcuboot.ld rename to soc/xtensa/espressif_esp32/esp32s2/mcuboot.ld diff --git a/soc/xtensa/esp32s2/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32s2/newlib_fix.c similarity index 100% rename from soc/xtensa/esp32s2/newlib_fix.c rename to soc/xtensa/espressif_esp32/esp32s2/newlib_fix.c diff --git a/soc/xtensa/esp32s2/pinctrl_soc.h b/soc/xtensa/espressif_esp32/esp32s2/pinctrl_soc.h similarity index 100% rename from soc/xtensa/esp32s2/pinctrl_soc.h rename to soc/xtensa/espressif_esp32/esp32s2/pinctrl_soc.h diff --git a/soc/xtensa/esp32s2/power.c b/soc/xtensa/espressif_esp32/esp32s2/power.c similarity index 100% rename from soc/xtensa/esp32s2/power.c rename to soc/xtensa/espressif_esp32/esp32s2/power.c diff --git a/soc/xtensa/esp32s2/soc.c b/soc/xtensa/espressif_esp32/esp32s2/soc.c similarity index 100% rename from soc/xtensa/esp32s2/soc.c rename to soc/xtensa/espressif_esp32/esp32s2/soc.c diff --git a/soc/xtensa/esp32s2/soc.h b/soc/xtensa/espressif_esp32/esp32s2/soc.h similarity index 100% rename from soc/xtensa/esp32s2/soc.h rename to soc/xtensa/espressif_esp32/esp32s2/soc.h diff --git a/soc/xtensa/esp32s2/soc_cache.c b/soc/xtensa/espressif_esp32/esp32s2/soc_cache.c similarity index 100% rename from soc/xtensa/esp32s2/soc_cache.c rename to soc/xtensa/espressif_esp32/esp32s2/soc_cache.c diff --git a/soc/xtensa/esp32s3/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt similarity index 98% rename from soc/xtensa/esp32s3/CMakeLists.txt rename to soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt index 70cc633e7649..87d717981592 100644 --- a/soc/xtensa/esp32s3/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32s3/CMakeLists.txt @@ -36,7 +36,7 @@ if(CONFIG_BOOTLOADER_ESP_IDF) ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} -S ${espidf_components_dir}/bootloader/subproject -B ${espidf_build_dir}/bootloader -DSDKCONFIG=${espidf_build_dir}/sdkconfig - -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC} + -DIDF_PATH=${ESP_IDF_PATH} -DIDF_TARGET=${CONFIG_SOC_SERIES} -DPYTHON_DEPS_CHECKED=1 -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series new file mode 100644 index 000000000000..31f7bdbff50c --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_ESP32S3 + +config SOC_SERIES + default "esp32s3" + +config HEAP_MEM_POOL_SIZE + default 32768 + +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 + +config FLASH_SIZE + default $(dt_node_reg_size_int,/soc/flash-controller@60002000/flash@0,0) + +config FLASH_BASE_ADDRESS + default $(dt_node_reg_addr_hex,/soc/flash-controller@60002000/flash@0) + +endif # SOC_SERIES_ESP32S3 diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.series new file mode 100644 index 000000000000..1265375c12a2 --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.series @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ESP32S3 + bool "ESP32-S3 Series" + select XTENSA + select SOC_FAMILY_ESP32 + select DYNAMIC_INTERRUPTS + select ARCH_SUPPORTS_COREDUMP + select CLOCK_CONTROL + select PINCTRL + select XIP if !MCUBOOT + select HAS_ESPRESSIF_HAL + select CPU_HAS_FPU + help + Enable support for Espressif ESP32-S3 diff --git a/soc/xtensa/esp32s3/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc similarity index 87% rename from soc/xtensa/esp32s3/Kconfig.soc rename to soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc index 3860bea328b4..7dd8fc4dddb8 100644 --- a/soc/xtensa/esp32s3/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc @@ -1,38 +1,54 @@ -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 -config SOC_ESP32S3 - bool "ESP32S3" - select XTENSA - select CLOCK_CONTROL - select DYNAMIC_INTERRUPTS - select ARCH_SUPPORTS_COREDUMP - select PINCTRL - select XIP if !MCUBOOT - select HAS_ESPRESSIF_HAL - select CPU_HAS_FPU - -if SOC_ESP32S3 - -config SOC_FAMILY_ESP32 - bool - default y +if SOC_SERIES_ESP32S3 config IDF_TARGET_ESP32S3 - bool "ESP32S3 as target board" - default y - -config ESPTOOLPY_FLASHFREQ_80M - bool + bool "ESP32S3 as target SOC" default y -config FLASH_SIZE - int - default $(dt_node_reg_size_int,/soc/flash-controller@60002000/flash@0,0) - -config FLASH_BASE_ADDRESS - hex - default $(dt_node_reg_addr_hex,/soc/flash-controller@60002000/flash@0) +config SOC_TOOLCHAIN_NAME + string + default "espressif_esp32s3" + +choice SOC_PART_NUMBER + prompt "ESP32-S3 SOC Selection" + depends on SOC_SERIES_ESP32S3 + + # SoC with/without embedded flash + config SOC_ESP32S3 + bool "ESP32S3" + config SOC_ESP32S3_R2 + bool "ESP32S3_R2" + config SOC_ESP32S3_R8 + bool "ESP32S3_R8" + config SOC_ESP32S3_R8V + bool "ESP32S3_R8V" + config SOC_ESP32S3_FN8 + bool "ESP32S3_FN8" + config SOC_ESP32S3_PICO_N8R2 + bool "ESP32S3_PICO_N8R2" + config SOC_ESP32S3_PICO_N8R8 + bool "ESP32S3_PICO_N8R8" + # SiP with flash and/or psram + config SOC_ESP32S3_MINI_N8 + bool "ESP32S3_MINI_N8" + config SOC_ESP32S3_MINI_N4R2 + bool "ESP32S3_MINI_N4R2" + config SOC_ESP32S3_WROOM_N4 + bool "ESP32S3_WROOM_N4" + config SOC_ESP32S3_WROOM_N8 + bool "ESP32S3_WROOM_N8" + config SOC_ESP32S3_WROOM_N16 + bool "ESP32S3_WROOM_N16" + config SOC_ESP32S3_WROOM_N4R8 + bool "ESP32S3_WROOM_N4R8" + config SOC_ESP32S3_WROOM_N8R8 + bool "ESP32S3_WROOM_N8R8" + config SOC_ESP32S3_WROOM_N16R8 + bool "ESP32S3_WROOM_N16" + +endchoice # SOC_PART_NUMBER choice ESP32S3_RTC_CLK_SRC prompt "RTC clock source" @@ -268,7 +284,7 @@ config ESP32S3_DATA_CACHE_WRAP config MAC_BB_PD bool "Power down MAC and baseband of Wi-Fi and Bluetooth when PHY is disabled" - depends on SOC_ESP32S3 && TICKLESS_KERNEL + depends on SOC_SERIES_ESP32S3 && TICKLESS_KERNEL default n help If enabled, the MAC and baseband of Wi-Fi and Bluetooth will be powered @@ -277,4 +293,4 @@ config MAC_BB_PD endmenu # Cache config -endif # SOC_ESP32S3 +endif # SOC_SERIES_ESP32S3 diff --git a/soc/xtensa/esp32s3/default.ld b/soc/xtensa/espressif_esp32/esp32s3/default.ld similarity index 100% rename from soc/xtensa/esp32s3/default.ld rename to soc/xtensa/espressif_esp32/esp32s3/default.ld diff --git a/soc/xtensa/esp32s3/linker.ld b/soc/xtensa/espressif_esp32/esp32s3/linker.ld similarity index 100% rename from soc/xtensa/esp32s3/linker.ld rename to soc/xtensa/espressif_esp32/esp32s3/linker.ld diff --git a/soc/xtensa/esp32s3/loader.c b/soc/xtensa/espressif_esp32/esp32s3/loader.c similarity index 100% rename from soc/xtensa/esp32s3/loader.c rename to soc/xtensa/espressif_esp32/esp32s3/loader.c diff --git a/soc/xtensa/esp32s3/mcuboot.ld b/soc/xtensa/espressif_esp32/esp32s3/mcuboot.ld similarity index 100% rename from soc/xtensa/esp32s3/mcuboot.ld rename to soc/xtensa/espressif_esp32/esp32s3/mcuboot.ld diff --git a/soc/xtensa/esp32s3/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32s3/newlib_fix.c similarity index 100% rename from soc/xtensa/esp32s3/newlib_fix.c rename to soc/xtensa/espressif_esp32/esp32s3/newlib_fix.c diff --git a/soc/xtensa/esp32s3/pinctrl_soc.h b/soc/xtensa/espressif_esp32/esp32s3/pinctrl_soc.h similarity index 100% rename from soc/xtensa/esp32s3/pinctrl_soc.h rename to soc/xtensa/espressif_esp32/esp32s3/pinctrl_soc.h diff --git a/soc/xtensa/esp32s3/soc.c b/soc/xtensa/espressif_esp32/esp32s3/soc.c similarity index 100% rename from soc/xtensa/esp32s3/soc.c rename to soc/xtensa/espressif_esp32/esp32s3/soc.c diff --git a/soc/xtensa/esp32s3/soc.h b/soc/xtensa/espressif_esp32/esp32s3/soc.h similarity index 100% rename from soc/xtensa/esp32s3/soc.h rename to soc/xtensa/espressif_esp32/esp32s3/soc.h diff --git a/soc/xtensa/esp32s3/soc_cache.c b/soc/xtensa/espressif_esp32/esp32s3/soc_cache.c similarity index 100% rename from soc/xtensa/esp32s3/soc_cache.c rename to soc/xtensa/espressif_esp32/esp32s3/soc_cache.c diff --git a/tests/drivers/pwm/pwm_api/src/test_pwm.c b/tests/drivers/pwm/pwm_api/src/test_pwm.c index 21f1b10960d7..28b7ea541f2a 100644 --- a/tests/drivers/pwm/pwm_api/src/test_pwm.c +++ b/tests/drivers/pwm/pwm_api/src/test_pwm.c @@ -55,8 +55,8 @@ #endif #if defined(CONFIG_BOARD_COLIBRI_IMX7D_M4) || defined(CONFIG_SOC_MK64F12) || \ - defined(CONFIG_SOC_MKW41Z4) || defined(CONFIG_SOC_ESP32S2) || \ - defined(CONFIG_SOC_ESP32S3) || defined(CONFIG_SOC_ESP32C3) + defined(CONFIG_SOC_MKW41Z4) || defined(CONFIG_SOC_SERIES_ESP32S2) || \ + defined(CONFIG_SOC_ESP32S3) || defined(CONFIG_SOC_SERIES_ESP32C3) #define DEFAULT_PERIOD_CYCLE 1024 #define DEFAULT_PULSE_CYCLE 512 #define DEFAULT_PERIOD_NSEC 2000000 diff --git a/tests/drivers/uart/uart_async_api/src/test_uart.h b/tests/drivers/uart/uart_async_api/src/test_uart.h index b6b5ee66f563..cd9dd3162483 100644 --- a/tests/drivers/uart/uart_async_api/src/test_uart.h +++ b/tests/drivers/uart/uart_async_api/src/test_uart.h @@ -21,6 +21,8 @@ #if DT_NODE_EXISTS(DT_NODELABEL(dut)) #define UART_NODE DT_NODELABEL(dut) +#elif defined(CONFIG_SOC_SERIES_ESP32C3) +#define UART_NODE DT_NODELABEL(uart1) #else #define UART_NODE DT_CHOSEN(zephyr_console) #endif diff --git a/west.yml b/west.yml index ff83119fcc68..3def5691788b 100644 --- a/west.yml +++ b/west.yml @@ -147,7 +147,7 @@ manifest: groups: - hal - name: hal_espressif - revision: 322f6389e21d08845486b5ebe1a6e5cb077981b8 + revision: ae1bd648a1ac701672c46b6ff4eadfa716937ce3 path: modules/hal/espressif west-commands: west/west-commands.yml groups: From 5e1b18526c8fa120e46f83aacae1c255638ee8a1 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Mon, 3 Jul 2023 18:34:59 +0200 Subject: [PATCH 1785/2042] include: dt-bingings: Fix typo Fix minor typo in esp32s3-gpio-sigmap Signed-off-by: Marek Matej --- include/zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h b/include/zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h index 47fd0f91302e..7e12f1d4105b 100644 --- a/include/zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h +++ b/include/zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h @@ -452,4 +452,4 @@ #define ESP_SIG_GPIO_OUT 256 #define ESP_GPIO_MAP_DATE 0x1907040 -#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ESP32S2_GPIO_SIGMAP_H_ */ +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ESP32S3_GPIO_SIGMAP_H_ */ From 938732c00ddf2060ef60103abfa41a90a430b6cd Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Fri, 23 Jun 2023 11:43:03 +0200 Subject: [PATCH 1786/2042] drivers: can: fix long lines Change the line length to comply with the rules. Signed-off-by: Marek Matej --- drivers/can/can_esp32_twai.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/can/can_esp32_twai.c b/drivers/can/can_esp32_twai.c index 0d745dccdbef..794b3bdb8cdf 100644 --- a/drivers/can/can_esp32_twai.c +++ b/drivers/can/can_esp32_twai.c @@ -293,10 +293,10 @@ const struct can_driver_api can_esp32_twai_driver_api = { CAN_ESP32_TWAI_ASSERT_CLKOUT_DIVIDER(inst); \ static const struct can_sja1000_config can_sja1000_config_##inst = \ CAN_SJA1000_DT_CONFIG_INST_GET(inst, &can_esp32_twai_config_##inst, \ - can_esp32_twai_read_reg, can_esp32_twai_write_reg, \ - CAN_SJA1000_OCR_OCMODE_BIPHASE, \ - COND_CODE_0(IS_ENABLED(CONFIG_SOC_SERIES_ESP32), (0), \ - (CAN_ESP32_TWAI_DT_CDR_INST_GET(inst)))); \ + can_esp32_twai_read_reg, can_esp32_twai_write_reg, \ + CAN_SJA1000_OCR_OCMODE_BIPHASE, \ + COND_CODE_0(IS_ENABLED(CONFIG_SOC_SERIES_ESP32), (0), \ + (CAN_ESP32_TWAI_DT_CDR_INST_GET(inst)))); \ \ static struct can_sja1000_data can_sja1000_data_##inst = \ CAN_SJA1000_DATA_INITIALIZER(NULL); \ From 75547dd522edb425cd2d324e591589beab05a5b7 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 13:59:13 +0000 Subject: [PATCH 1787/2042] soc: arm64: Add agilex5 soc folder and its configurations Add Agilex5 soc folder, MMU table and its configurations for Intel SoC FPGA Agilex5 platform for initial bring up. Add ARM Cortex-a76 and Cortex-a55 HMP cluster type. Signed-off-by: Teik Heng Chong Signed-off-by: Girisha Dengi --- arch/arm64/core/Kconfig | 14 +++++++ cmake/compiler/gcc/target_arm64.cmake | 5 +++ cmake/gcc-m-cpu.cmake | 5 +++ .../intel_socfpga/agilex5/CMakeLists.txt | 6 +++ .../agilex5/Kconfig.defconfig.agilex5 | 21 ++++++++++ .../agilex5/Kconfig.defconfig.series | 11 +++++ .../intel_socfpga/agilex5/Kconfig.series | 10 +++++ soc/arm64/intel_socfpga/agilex5/Kconfig.soc | 10 +++++ soc/arm64/intel_socfpga/agilex5/linker.ld | 8 ++++ soc/arm64/intel_socfpga/agilex5/mmu_regions.c | 42 +++++++++++++++++++ .../grp/os_mgmt/include/os_mgmt_processor.h | 4 ++ 11 files changed, 136 insertions(+) create mode 100644 soc/arm64/intel_socfpga/agilex5/CMakeLists.txt create mode 100644 soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.agilex5 create mode 100644 soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.series create mode 100644 soc/arm64/intel_socfpga/agilex5/Kconfig.series create mode 100644 soc/arm64/intel_socfpga/agilex5/Kconfig.soc create mode 100644 soc/arm64/intel_socfpga/agilex5/linker.ld create mode 100644 soc/arm64/intel_socfpga/agilex5/mmu_regions.c diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index bd13eed7478b..46b08db9f684 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -57,6 +57,20 @@ config CPU_CORTEX_A72 help This option signifies the use of a Cortex-A72 CPU +config CPU_CORTEX_A76 + bool + select CPU_CORTEX_A + select ARMV8_A + help + This option signifies the use of a Cortex-A76 CPU + +config CPU_CORTEX_A76_A55 + bool + select CPU_CORTEX_A + select ARMV8_A + help + This option signifies the use of a Cortex-A76 and A55 big little CPU cluster + config CPU_CORTEX_R82 bool select CPU_AARCH64_CORTEX_R diff --git a/cmake/compiler/gcc/target_arm64.cmake b/cmake/compiler/gcc/target_arm64.cmake index 9298fd28d636..f5c8c25440b4 100644 --- a/cmake/compiler/gcc/target_arm64.cmake +++ b/cmake/compiler/gcc/target_arm64.cmake @@ -9,5 +9,10 @@ if(DEFINED GCC_M_ARCH) list(APPEND TOOLCHAIN_LD_FLAGS -march=${GCC_M_ARCH}) endif() +if(DEFINED GCC_M_TUNE) + list(APPEND TOOLCHAIN_C_FLAGS -mtune=${GCC_M_TUNE}) + list(APPEND TOOLCHAIN_LD_FLAGS -mtune=${GCC_M_TUNE}) +endif() + list(APPEND TOOLCHAIN_C_FLAGS -mabi=lp64) list(APPEND TOOLCHAIN_LD_FLAGS -mabi=lp64) diff --git a/cmake/gcc-m-cpu.cmake b/cmake/gcc-m-cpu.cmake index a192a778c0c8..ae10132dfc04 100644 --- a/cmake/gcc-m-cpu.cmake +++ b/cmake/gcc-m-cpu.cmake @@ -75,6 +75,11 @@ elseif("${ARCH}" STREQUAL "arm64") set(GCC_M_CPU cortex-a53) elseif(CONFIG_CPU_CORTEX_A55) set(GCC_M_CPU cortex-a55) + elseif(CONFIG_CPU_CORTEX_A76) + set(GCC_M_CPU cortex-a76) + elseif(CONFIG_CPU_CORTEX_A76_A55) + set(GCC_M_CPU cortex-a76) + set(GCC_M_TUNE cortex-a76.cortex-a55) elseif(CONFIG_CPU_CORTEX_A72) set(GCC_M_CPU cortex-a72) elseif(CONFIG_CPU_CORTEX_R82) diff --git a/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt b/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt new file mode 100644 index 000000000000..f0e79e927d3a --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_library_sources_ifdef(CONFIG_ARM_MMU mmu_regions.c) diff --git a/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.agilex5 b/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.agilex5 new file mode 100644 index 000000000000..d34c7880cd45 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.agilex5 @@ -0,0 +1,21 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AGILEX5 + +config SOC + default "intel_socfpga_agilex5" + +# must be >= the highest interrupt number used +# - include the UART interrupts 173 or 204 +config NUM_IRQS + int + default 205 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 400000000 + +config KERNEL_VM_SIZE + default 0x400000 +endif diff --git a/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.series b/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.series new file mode 100644 index 000000000000..6a511cdfd6e6 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_AGILEX5 + +config SOC_SERIES + default "agilex5" + +source "soc/arm64/intel_socfpga/agilex5/Kconfig.defconfig.agilex5*" + +endif # SOC_SERIES_AGILEX5 diff --git a/soc/arm64/intel_socfpga/agilex5/Kconfig.series b/soc/arm64/intel_socfpga/agilex5/Kconfig.series new file mode 100644 index 000000000000..c64c38dc5577 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_AGILEX5 + bool "Intel SoC FPGA Agilex5 Series" + select ARM64 + select CPU_CORTEX_A76_A55 + select SOC_FAMILY_INTEL_SOCFPGA + help + Enable support for Intel SoC FPGA Series diff --git a/soc/arm64/intel_socfpga/agilex5/Kconfig.soc b/soc/arm64/intel_socfpga/agilex5/Kconfig.soc new file mode 100644 index 000000000000..bb75833db9e8 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/Kconfig.soc @@ -0,0 +1,10 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "Intel SoC FPGA Agilex5" +depends on SOC_SERIES_AGILEX5 + +config SOC_AGILEX5 + bool "Intel SoC FPGA Agilex5" +endchoice diff --git a/soc/arm64/intel_socfpga/agilex5/linker.ld b/soc/arm64/intel_socfpga/agilex5/linker.ld new file mode 100644 index 000000000000..9f5bc4c4f7e0 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/linker.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2022 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include diff --git a/soc/arm64/intel_socfpga/agilex5/mmu_regions.c b/soc/arm64/intel_socfpga/agilex5/mmu_regions.c new file mode 100644 index 000000000000..984c729bddd6 --- /dev/null +++ b/soc/arm64/intel_socfpga/agilex5/mmu_regions.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static const struct arm_mmu_region mmu_regions[] = { + + /* System manager register that required by clock driver */ + MMU_REGION_FLAT_ENTRY("SYSTEM_MANAGER", + DT_REG_ADDR(DT_NODELABEL(sysmgr)), + DT_REG_SIZE(DT_NODELABEL(sysmgr)), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_DEFAULT_SECURE_STATE), + + MMU_REGION_FLAT_ENTRY("PINMUX", + DT_REG_ADDR_BY_IDX(DT_NODELABEL(pinmux), 0), + DT_REG_SIZE_BY_IDX(DT_NODELABEL(pinmux), 0), + MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_DEFAULT_SECURE_STATE), + + MMU_REGION_FLAT_ENTRY("GIC_0", + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gic), 0), + DT_REG_SIZE_BY_IDX(DT_NODELABEL(gic), 0), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_DEFAULT_SECURE_STATE), + + MMU_REGION_FLAT_ENTRY("GIC_1", + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gic), 1), + DT_REG_SIZE_BY_IDX(DT_NODELABEL(gic), 1), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_DEFAULT_SECURE_STATE), + + MMU_REGION_FLAT_ENTRY("GIC_ITS", + DT_REG_ADDR(DT_NODELABEL(its)), + DT_REG_SIZE(DT_NODELABEL(its)), + MT_DEVICE_nGnRnE | MT_P_RW_U_RW | MT_DEFAULT_SECURE_STATE), +}; + +const struct arm_mmu_config mmu_config = { + .num_regions = ARRAY_SIZE(mmu_regions), + .mmu_regions = mmu_regions, +}; diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h index 7dc072f0eeb1..ccb384f6e9d5 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -95,6 +95,10 @@ extern "C" { #define PROCESSOR_NAME "cortex-a57" #elif defined(CONFIG_CPU_CORTEX_A72) #define PROCESSOR_NAME "cortex-a72" +#elif defined(CONFIG_CPU_CORTEX_A76_A55) +#define PROCESSOR_NAME "cortex-a76" +#elif defined(CONFIG_CPU_CORTEX_A76) +#define PROCESSOR_NAME "cortex-a76" #elif defined(CONFIG_CPU_CORTEX_R82) #define PROCESSOR_NAME "armv8.4-a+nolse" #endif From 42477ed68d3823b8d221465cd1aa3bf0da312059 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:03:34 +0000 Subject: [PATCH 1788/2042] boards: arm64: Add Intel SoC FPGA Agilex5 development kit board This is the initial Zephyr support for Intel SoC FPGA Agilex5 support. Agilex5 has dual-core 64-bit ARM Cortex*-A55 and dual-core 64bit ARM Cortex*-A76. The Zephyr will need to be loaded by Intel Arm Trusted Firmware (ATF). Agilex5 Zephyr boot flow: FSBL:ATF BL2(EL3) -> ATF BL31(EL3) -> OS:Zephyr(EL1) Intel ATF can be loaded from: https://github.com/altera-opensource/arm-trusted-firmware.git Signed-off-by: Teik Heng Chong Signed-off-by: Girisha Dengi --- .../intel_socfpga_agilex5_socdk/Kconfig.board | 7 ++ .../Kconfig.defconfig | 9 +++ .../intel_socfpga_agilex5_socdk/doc/index.rst | 80 +++++++++++++++++++ .../intel_socfpga_agilex5_socdk.dts | 27 +++++++ .../intel_socfpga_agilex5_socdk.yaml | 7 ++ .../intel_socfpga_agilex5_socdk_defconfig | 44 ++++++++++ 6 files changed, 174 insertions(+) create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.board create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.defconfig create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/doc/index.rst create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.yaml create mode 100644 boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk_defconfig diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.board b/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.board new file mode 100644 index 000000000000..a23f8c5d1e09 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK + bool "Intel SoC FPGA Development Kit (Agilex5)" + select HAS_COVERAGE_SUPPORT + depends on SOC_AGILEX5 diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.defconfig b/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.defconfig new file mode 100644 index 000000000000..5b832b29c002 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "intel_socfpga_agilex5_socdk" + depends on BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK + +config MAX_THREAD_BYTES + default 5 diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/doc/index.rst b/boards/arm64/intel_socfpga_agilex5_socdk/doc/index.rst new file mode 100644 index 000000000000..537b1628cde8 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/doc/index.rst @@ -0,0 +1,80 @@ +.. _intel_socfpga_agilex5_socdk: + +Intel® Agilex™ 5 SoC FPGA Development Kit +######################################### + +Overview +******** + +The Intel® Agilex™ 5 SoC FPGA Development Kit offers a complete design +environment that includes both hardware and software for developing +Intel® Agilex™ 5 E-Series based FPGA designs. This kit is recommended for +developing custom ARM* processor-based SoC designs and ideal for intelligent +applications at the edge, embedded and more. + +Hardware +******** + +The Intel® Agilex™ 5 Development Kit supports the following physical features: + +- Intel® Agilex™ 5 E-Series FPGA, 50K-656K LEs integrated with + multi-core ARM processors of Dual-core A55 and Dual-core A76 +- On-board 8 GB DDR5 memory +- On-board JTAG Intel FPGA Download Cable II +- QSPI flash daughtercard + +Supported Features +================== +The Intel® Agilex™ 5 SoC Development Kit configuration supports the following +hardware features: + ++-----------+------------+---------------------------------------------+ +| Interface | Controller | Hardware Subsystem Vendor | ++===========+============+=============================================+ +| GIC-600 | on-chip | ARM GICv3 interrupt controller | ++-----------+------------+---------------------------------------------+ +| UART | on-chip | Synopsys Designware,NS16550 compatible | ++-----------+------------+---------------------------------------------+ +| ARM TIMER | on-chip | ARM system timer | ++-----------+------------+---------------------------------------------+ +| Reset | on-chip | Intel Corporation, SoCFPGA Reset controller | ++-----------+------------+---------------------------------------------+ +| Clock | on-chip | Intel Corporation, SoCFPGA Clock controller | ++-----------+------------+---------------------------------------------+ + +NOTE: TODO, more details on dev kit will be updated as and when available. + +The default configuration can be found in the defconfig file: + `boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk_defconfig` + +Programming and Debugging +************************* + +Zephyr Boot Flow +**************** +Zephyr image will need to be loaded by Intel Arm Trusted Firmware (ATF). +ATF BL2 is the First Stage Boot Loader (FSBL) and ATF BL31 is the Run time resident firmware which +provides services like SMC (Secure monitor calls) and PSCI (Power state coordination interface). + +Boot flow: + ATF BL2 (EL3) -> ATF BL31 (EL3) -> Zephyr (EL1) + +Intel Arm Trusted Firmware (ATF) can be downloaded from github: + `altera-opensource/arm-trusted-firmware `_ + +Flashing +======== +Zephyr image can be loaded in DDR memory at address 0x80000000 from +SD Card or QSPI Flash or NAND in ATF BL2. + +Debugging +========= +The Intel® Agilex™ 5 SoC Development Kit includes one JTAG connector on +board, connect it to Intel USB blaster download cables for debugging. + +Zephyr applications running on the Cortex-A55/A76 core can be tested by +observing UART console output. + +References +========== +`Intel® Agilex™ 5 FPGA and SoC FPGA `_ 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 new file mode 100644 index 000000000000..4bc1e1ce9f23 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "Intel SoC FPGA Agilex5"; + compatible = "intel,socfpga-agilex5"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &mem0; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; +}; diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.yaml b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.yaml new file mode 100644 index 000000000000..22f713dea093 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.yaml @@ -0,0 +1,7 @@ +identifier: intel_socfpga_agilex5_socdk +name: Intel SoC FPGA Agilex5 +type: mcu +arch: arm64 +toolchain: + - zephyr + - cross-compile diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk_defconfig b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk_defconfig new file mode 100644 index 000000000000..0985f470c748 --- /dev/null +++ b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk_defconfig @@ -0,0 +1,44 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# The Zephyr build from this defconfig is expected to boot from +# Intel Arm Trusted Firmware (ATF). +# Boot Flow is: ATF BL21 -> ATF BL31 -> Zephyr + +CONFIG_SOC_SERIES_AGILEX5=y +CONFIG_SOC_AGILEX5=y +CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK=y + +# Compiler Options +CONFIG_FORTIFY_SOURCE_RUN_TIME=y + +# Arm Features +CONFIG_ARM_ARCH_TIMER=y +CONFIG_CACHE_MANAGEMENT=y +CONFIG_ARMV8_A_NS=y + +# Serial Drivers +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_NS16550_ACCESS_WORD_ONLY=y + +# Enable Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable Clock Manager +CONFIG_CLOCK_CONTROL=y + +# For Misc Register Map +CONFIG_SYSCON=y + +# Reset Manager +CONFIG_RESET=y + +# PSCI support Enable +CONFIG_PM_CPU_OPS=y +CONFIG_PM_CPU_OPS_PSCI=y + +# Enable SMP support +CONFIG_SMP=y +CONFIG_MP_MAX_NUM_CPUS=4 From 2ca6ffcd79284764ab550cc4d0325ea6eef30120 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:09:24 +0000 Subject: [PATCH 1789/2042] drivers: clock_control: clock driver for Intel Agilex5 platform This is Intel's proprietary IP which supply the clock for all the system peripherals. Clock manager is initialized only one time during boot up by FSBL (ATF BL2) based on external user settings. Signed-off-by: Girisha Dengi --- drivers/clock_control/CMakeLists.txt | 2 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.agilex5 | 9 + drivers/clock_control/clock_control_agilex5.c | 86 +++++++++ .../clock_control/clock_control_agilex5_ll.c | 181 ++++++++++++++++++ .../clock_control/clock_control_agilex5_ll.h | 160 ++++++++++++++++ dts/bindings/clock/intel,agilex5-clock.yaml | 18 ++ .../dt-bindings/clock/intel_socfpga_clock.h | 1 + 8 files changed, 459 insertions(+) create mode 100644 drivers/clock_control/Kconfig.agilex5 create mode 100644 drivers/clock_control/clock_control_agilex5.c create mode 100644 drivers/clock_control/clock_control_agilex5_ll.c create mode 100644 drivers/clock_control/clock_control_agilex5_ll.h create mode 100644 dts/bindings/clock/intel,agilex5-clock.yaml diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 95b0180310e7..8a8d7fbb61a8 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -62,6 +62,8 @@ endif() zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_AGILEX clock_agilex_ll.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_AGILEX clock_agilex.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AGILEX5 clock_control_agilex5_ll.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AGILEX5 clock_control_agilex5.c) if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) zephyr_library_sources(clock_control_renesas_cpg_mssr.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 443bae19d017..f4647930ae3c 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -78,4 +78,6 @@ source "drivers/clock_control/Kconfig.numaker" source "drivers/clock_control/Kconfig.nxp_s32" +source "drivers/clock_control/Kconfig.agilex5" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.agilex5 b/drivers/clock_control/Kconfig.agilex5 new file mode 100644 index 000000000000..fcd5ed7f37cf --- /dev/null +++ b/drivers/clock_control/Kconfig.agilex5 @@ -0,0 +1,9 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_AGILEX5 + bool "Agilex5 SoCFPGA clock control driver" + default y + depends on DT_HAS_INTEL_AGILEX5_CLOCK_ENABLED + help + This option enables the clock driver for Intel Agilex5 SoCFPGA SOC. diff --git a/drivers/clock_control/clock_control_agilex5.c b/drivers/clock_control/clock_control_agilex5.c new file mode 100644 index 000000000000..82ffb0b0961a --- /dev/null +++ b/drivers/clock_control/clock_control_agilex5.c @@ -0,0 +1,86 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2022-2023, Intel Corporation + * + */ + +#include +#include +#include + +#include "clock_control_agilex5_ll.h" + +#define DT_DRV_COMPAT intel_agilex5_clock + +LOG_MODULE_REGISTER(clock_control_agilex5, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +struct clock_control_config { + DEVICE_MMIO_ROM; +}; + +struct clock_control_data { + DEVICE_MMIO_RAM; +}; + +static int clock_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + /* Initialize the low layer clock driver */ + clock_agilex5_ll_init(DEVICE_MMIO_GET(dev)); + + LOG_INF("Intel Agilex5 clock driver initialized!"); + + return 0; +} + +static int clock_get_rate(const struct device *dev, clock_control_subsys_t sub_system, + uint32_t *rate) +{ + ARG_UNUSED(dev); + + switch ((intptr_t)sub_system) { + case INTEL_SOCFPGA_CLOCK_MPU: + *rate = get_mpu_clk(); + break; + + case INTEL_SOCFPGA_CLOCK_WDT: + *rate = get_wdt_clk(); + break; + + case INTEL_SOCFPGA_CLOCK_UART: + *rate = get_uart_clk(); + break; + + case INTEL_SOCFPGA_CLOCK_MMC: + *rate = get_mmc_clk(); + break; + + case INTEL_SOCFPGA_CLOCK_TIMER: + *rate = get_timer_clk(); + break; + + default: + LOG_ERR("Clock ID %ld is not supported\n", (intptr_t)sub_system); + return -ENOTSUP; + } + + return 0; +} + +static const struct clock_control_driver_api clock_api = {.get_rate = clock_get_rate}; + +#define CLOCK_CONTROL_DEVICE(_inst) \ + \ + static struct clock_control_data clock_control_data_##_inst; \ + \ + static const struct clock_control_config clock_control_config_##_inst = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(_inst)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(_inst, clock_init, NULL, &clock_control_data_##_inst, \ + &clock_control_config_##_inst, PRE_KERNEL_1, \ + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_api); + +DT_INST_FOREACH_STATUS_OKAY(CLOCK_CONTROL_DEVICE) diff --git a/drivers/clock_control/clock_control_agilex5_ll.c b/drivers/clock_control/clock_control_agilex5_ll.c new file mode 100644 index 000000000000..a73083233094 --- /dev/null +++ b/drivers/clock_control/clock_control_agilex5_ll.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "clock_control_agilex5_ll.h" + +LOG_MODULE_REGISTER(clock_control_agilex5_ll, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +/* Clock manager individual group base addresses. */ +struct clock_agilex5_ll_params { + mm_reg_t base_addr; + mm_reg_t mainpll_addr; + mm_reg_t peripll_addr; + mm_reg_t ctl_addr; +}; + +/* Clock manager low layer(ll) params object. */ +static struct clock_agilex5_ll_params clock_agilex5_ll; + +/* Initialize the clock ll with the given base address */ +void clock_agilex5_ll_init(mm_reg_t base_addr) +{ + /* Clock manager module base address. */ + clock_agilex5_ll.base_addr = base_addr; + + /* Clock manager main PLL base address. */ + clock_agilex5_ll.mainpll_addr = clock_agilex5_ll.base_addr + CLKMGR_MAINPLL_OFFSET; + + /* Clock manager peripheral PLL base address. */ + clock_agilex5_ll.peripll_addr = clock_agilex5_ll.base_addr + CLKMGR_PERPLL_OFFSET; + + /* Clock manager control module base address. */ + clock_agilex5_ll.ctl_addr = clock_agilex5_ll.base_addr + CLKMGR_INTEL_OFFSET; +} + +/* Extract reference clock from platform clock source */ +static uint32_t get_ref_clk(uint32_t pllglob) +{ + uint32_t arefclkdiv, ref_clk; + uint32_t scr_reg; + + /* + * Based on the clock source, read the values from System Manager boot + * scratch registers. These values are filled by boot loader based on + * hand-off data. + */ + switch (CLKMGR_PSRC(pllglob)) { + case CLKMGR_PLLGLOB_PSRC_EOSC1: + scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1); + ref_clk = sys_read32(scr_reg); + break; + + case CLKMGR_PLLGLOB_PSRC_INTOSC: + ref_clk = CLKMGR_INTOSC_HZ; + break; + + case CLKMGR_PLLGLOB_PSRC_F2S: + scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2); + ref_clk = sys_read32(scr_reg); + break; + + default: + ref_clk = 0; + LOG_ERR("Invalid VCO input clock source"); + break; + } + + /* Reference clock divider, to get the effective reference clock. */ + arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob); + ref_clk /= arefclkdiv; + + return ref_clk; +} + +/* Calculate clock frequency based on parameter */ +static uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc) +{ + uint32_t clk_psrc, mdiv, ref_clk; + uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg; + + clk_psrc = sys_read32(clock_agilex5_ll.mainpll_addr + psrc_reg); + + switch (CLKMGR_PSRC(clk_psrc)) { + case CLKMGR_PSRC_MAIN: + pllm_reg = clock_agilex5_ll.mainpll_addr + CLKMGR_MAINPLL_PLLM; + pllc_reg = clock_agilex5_ll.mainpll_addr + main_pllc; + pllglob_reg = clock_agilex5_ll.mainpll_addr + CLKMGR_MAINPLL_PLLGLOB; + break; + + case CLKMGR_PSRC_PER: + pllm_reg = clock_agilex5_ll.peripll_addr + CLKMGR_PERPLL_PLLM; + pllc_reg = clock_agilex5_ll.peripll_addr + per_pllc; + pllglob_reg = clock_agilex5_ll.peripll_addr + CLKMGR_PERPLL_PLLGLOB; + break; + + default: + return 0; + } + + ref_clk = get_ref_clk(sys_read32(pllglob_reg)); + mdiv = CLKMGR_PLLM_MDIV(sys_read32(pllm_reg)); + ref_clk *= mdiv; + + /* Clock slice divider ration in binary code. */ + pllc_div = CLKMGR_PLLC_DIV(sys_read32(pllc_reg)); + + return ref_clk / pllc_div; +} + +/* Return L3 interconnect clock */ +uint32_t get_l3_clk(void) +{ + uint32_t l3_clk; + + l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1, CLKMGR_PERPLL_PLLC1); + + return l3_clk; +} + +/* Calculate clock frequency to be used for mpu */ +uint32_t get_mpu_clk(void) +{ + uint32_t mpu_clk; + + mpu_clk = get_clk_freq(CLKMGR_MAINPLL_MPUCLK, CLKMGR_MAINPLL_PLLC0, CLKMGR_PERPLL_PLLC0); + + return mpu_clk; +} + +/* Calculate clock frequency to be used for watchdog timer */ +uint32_t get_wdt_clk(void) +{ + uint32_t l4_sys_clk; + + l4_sys_clk = (get_l3_clk() >> 2); + + return l4_sys_clk; +} + +/* Calculate clock frequency to be used for UART driver */ +uint32_t get_uart_clk(void) +{ + uint32_t mainpll_nocdiv, l4_sp_clk; + + mainpll_nocdiv = sys_read32(clock_agilex5_ll.mainpll_addr + CLKMGR_MAINPLL_NOCDIV); + mainpll_nocdiv = CLKMGR_MAINPLL_L4SPDIV(mainpll_nocdiv); + + l4_sp_clk = (get_l3_clk() >> mainpll_nocdiv); + + return l4_sp_clk; +} + +/* Calculate clock frequency to be used for SDMMC driver */ +uint32_t get_mmc_clk(void) +{ + uint32_t sdmmc_ctr, mmc_clk; + + mmc_clk = get_clk_freq(CLKMGR_INTEL_SDMMCCTR, CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3); + + sdmmc_ctr = sys_read32(clock_agilex5_ll.ctl_addr + CLKMGR_INTEL_SDMMCCTR); + sdmmc_ctr = CLKMGR_INTEL_SDMMC_CNT(sdmmc_ctr); + mmc_clk = ((mmc_clk / sdmmc_ctr) >> 2); + + return mmc_clk; +} + +/* Calculate clock frequency to be used for Timer driver */ +uint32_t get_timer_clk(void) +{ + uint32_t l4_sys_clk; + + l4_sys_clk = (get_l3_clk() >> 2); + + return l4_sys_clk; +} diff --git a/drivers/clock_control/clock_control_agilex5_ll.h b/drivers/clock_control/clock_control_agilex5_ll.h new file mode 100644 index 000000000000..57c44fd9be0a --- /dev/null +++ b/drivers/clock_control/clock_control_agilex5_ll.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_AGILEX5_LL_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_AGILEX5_LL_H_ + +#include + +#include + +/* Clock manager register offsets */ +#define CLKMGR_CTRL 0x00 +#define CLKMGR_STAT 0x04 +#define CLKMGR_INTRCLR 0x14 + +/* Clock manager main PLL group register offsets */ +#define CLKMGR_MAINPLL_OFFSET 0x24 +#define CLKMGR_MAINPLL_EN 0x00 +#define CLKMGR_MAINPLL_BYPASS 0x0C +#define CLKMGR_MAINPLL_MPUCLK 0x18 +#define CLKMGR_MAINPLL_BYPASSS 0x10 +#define CLKMGR_MAINPLL_NOCCLK 0x1C +#define CLKMGR_MAINPLL_NOCDIV 0x20 +#define CLKMGR_MAINPLL_PLLGLOB 0x24 +#define CLKMGR_MAINPLL_FDBCK 0x28 +#define CLKMGR_MAINPLL_MEM 0x2C +#define CLKMGR_MAINPLL_MEMSTAT 0x30 +#define CLKMGR_MAINPLL_VCOCALIB 0x34 +#define CLKMGR_MAINPLL_PLLC0 0x38 +#define CLKMGR_MAINPLL_PLLC1 0x3C +#define CLKMGR_MAINPLL_PLLC2 0x40 +#define CLKMGR_MAINPLL_PLLC3 0x44 +#define CLKMGR_MAINPLL_PLLM 0x48 +#define CLKMGR_MAINPLL_LOSTLOCK 0x54 + +/* Clock manager peripheral PLL group register offsets */ +#define CLKMGR_PERPLL_OFFSET 0x7C +#define CLKMGR_PERPLL_EN 0x00 +#define CLKMGR_PERPLL_BYPASS 0x0C +#define CLKMGR_PERPLL_BYPASSS 0x10 +#define CLKMGR_PERPLL_EMACCTL 0x18 +#define CLKMGR_PERPLL_GPIODIV 0x1C +#define CLKMGR_PERPLL_PLLGLOB 0x20 +#define CLKMGR_PERPLL_FDBCK 0x24 +#define CLKMGR_PERPLL_MEM 0x28 +#define CLKMGR_PERPLL_MEMSTAT 0x2C +#define CLKMGR_PERPLL_VCOCALIB 0x30 +#define CLKMGR_PERPLL_PLLC0 0x34 +#define CLKMGR_PERPLL_PLLC1 0x38 +#define CLKMGR_PERPLL_PLLC2 0x3C +#define CLKMGR_PERPLL_PLLC3 0x40 +#define CLKMGR_PERPLL_PLLM 0x44 +#define CLKMGR_PERPLL_LOSTLOCK 0x50 + +/* Clock manager control/intel group register offsets */ +#define CLKMGR_INTEL_OFFSET 0xD0 +#define CLKMGR_INTEL_JTAG 0x00 +#define CLKMGR_INTEL_EMACACTR 0x4 +#define CLKMGR_INTEL_EMACBCTR 0x8 +#define CLKMGR_INTEL_EMACPTPCTR 0x0C +#define CLKMGR_INTEL_GPIODBCTR 0x10 +#define CLKMGR_INTEL_SDMMCCTR 0x14 +#define CLKMGR_INTEL_S2FUSER0CTR 0x18 +#define CLKMGR_INTEL_S2FUSER1CTR 0x1C +#define CLKMGR_INTEL_PSIREFCTR 0x20 +#define CLKMGR_INTEL_EXTCNTRST 0x24 + +/* Clock manager macros */ +#define CLKMGR_CTRL_BOOTMODE_SET_MSK 0x00000001U +#define CLKMGR_STAT_BUSY_E_BUSY 0x1 +#define CLKMGR_STAT_BUSY(x) (((x) & 0x00000001U) >> 0) +#define CLKMGR_STAT_MAINPLLLOCKED(x) (((x) & 0x00000100U) >> 8) +#define CLKMGR_STAT_PERPLLLOCKED(x) (((x) & 0x00010000U) >> 16) +#define CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK 0x00000004U +#define CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK 0x00000008U +#define CLKMGR_MAINPLL_L4SPDIV(x) (((x) >> 16) & 0x3) +#define CLKMGR_INTOSC_HZ 460000000U + +/* Shared Macros */ +#define CLKMGR_PSRC(x) (((x) & 0x00030000U) >> 16) +#define CLKMGR_PSRC_MAIN 0 +#define CLKMGR_PSRC_PER 1 + +#define CLKMGR_PLLGLOB_PSRC_EOSC1 0x0 +#define CLKMGR_PLLGLOB_PSRC_INTOSC 0x1 +#define CLKMGR_PLLGLOB_PSRC_F2S 0x2 + +#define CLKMGR_PLLM_MDIV(x) ((x) & 0x000003FFU) +#define CLKMGR_PLLGLOB_PD_SET_MSK 0x00000001U +#define CLKMGR_PLLGLOB_RST_SET_MSK 0x00000002U + +#define CLKMGR_PLLGLOB_REFCLKDIV(x) (((x) & 0x00003F00) >> 8) +#define CLKMGR_PLLGLOB_AREFCLKDIV(x) (((x) & 0x00000F00) >> 8) +#define CLKMGR_PLLGLOB_DREFCLKDIV(x) (((x) & 0x00003000) >> 12) + +#define CLKMGR_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000003FF) +#define CLKMGR_VCOCALIB_MSCNT_SET(x) (((x) << 16) & 0x00FF0000) + +#define CLKMGR_CLR_LOSTLOCK_BYPASS 0x20000000U +#define CLKMGR_PLLC_DIV(x) ((x) & 0x7FF) +#define CLKMGR_INTEL_SDMMC_CNT(x) (((x) & 0x7FF) + 1) + +/** + * @brief Initialize the low layer clock control driver + * + * @param base_addr : Clock control device MMIO base address + * + * @return void + */ +void clock_agilex5_ll_init(mm_reg_t base_addr); + +/** + * @brief Get MPU(Micro Processor Unit) clock value + * + * @param void + * + * @return returns MPU clock value + */ +uint32_t get_mpu_clk(void); + +/** + * @brief Get Watchdog peripheral clock value + * + * @param void + * + * @return returns Watchdog clock value + */ +uint32_t get_wdt_clk(void); + +/** + * @brief Get UART peripheral clock value + * + * @param void + * + * @return returns UART clock value + */ +uint32_t get_uart_clk(void); + +/** + * @brief Get MMC peripheral clock value + * + * @param void + * + * @return returns MMC clock value + */ +uint32_t get_mmc_clk(void); + +/** + * @brief Get Timer peripheral clock value + * + * @param void + * + * @return returns Timer clock value + */ +uint32_t get_timer_clk(void); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_AGILEX5_LL_H_ */ diff --git a/dts/bindings/clock/intel,agilex5-clock.yaml b/dts/bindings/clock/intel,agilex5-clock.yaml new file mode 100644 index 000000000000..bad045bf89b9 --- /dev/null +++ b/dts/bindings/clock/intel,agilex5-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Agilex5 clock controller node + +compatible: "intel,agilex5-clock" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 1 + +clock-cells: + - clkid diff --git a/include/zephyr/dt-bindings/clock/intel_socfpga_clock.h b/include/zephyr/dt-bindings/clock/intel_socfpga_clock.h index 49d5d82f3ffb..9e98057068e5 100644 --- a/include/zephyr/dt-bindings/clock/intel_socfpga_clock.h +++ b/include/zephyr/dt-bindings/clock/intel_socfpga_clock.h @@ -12,5 +12,6 @@ #define INTEL_SOCFPGA_CLOCK_WDT 1 #define INTEL_SOCFPGA_CLOCK_UART 2 #define INTEL_SOCFPGA_CLOCK_MMC 3 +#define INTEL_SOCFPGA_CLOCK_TIMER 4 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_INTEL_SOCFPGA_CLOCK_H_ */ From 81f0acd5d4938021611535993d665825b3fa9ac6 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:26:16 +0000 Subject: [PATCH 1790/2042] dts: arm64: Add device tree for Intel SoCFPGA Agilex5 platform Device tree for Intel SoCFPGA Agilex5 initial bring up. This is the first version of device tree which enable four cores SMP and basic drivers that needed by 'hello_world' and 'cli' applications. Signed-off-by: Girisha Dengi --- dts/arm64/intel/intel_socfpga_agilex5.dtsi | 119 +++++++++++++++++++++ dts/bindings/cpu/arm,cortex-a76.yaml | 8 ++ dts/bindings/cpu/cpu.yaml | 3 + 3 files changed, 130 insertions(+) create mode 100644 dts/arm64/intel/intel_socfpga_agilex5.dtsi create mode 100644 dts/bindings/cpu/arm,cortex-a76.yaml diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi new file mode 100644 index 000000000000..7c33c9d3fb8e --- /dev/null +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -0,0 +1,119 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2023, Intel Corporation + * + */ + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells= <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x0>; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + enable-method = "psci"; + reg = <0x100>; + }; + + cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + enable-method = "psci"; + reg = <0x200>; + }; + + cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + enable-method = "psci"; + reg = <0x300>; + }; + }; + + gic: interrupt-controller@1d000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0x1d000000 0x10000>, /* GICD */ + <0x1d060000 0x80000>; /* GICR */ + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + #address-cells = <1>; + #size-cells = <1>; + + its: msi-controller@1d040000 { + compatible = "arm,gic-v3-its"; + reg = <0x1d040000 0x20000>; + status = "disabled"; + }; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + sysmgr: sysmgr@10d12000 { + compatible = "syscon"; + reg = <0x10d12000 0x1000>; + }; + + clock: clock@10d10000 { + compatible = "intel,agilex5-clock"; + reg = <0x10d10000 0x1000>; + #clock-cells = <1>; + }; + + psci { + compatible = "arm,psci-1.1"; + method = "smc"; + }; + + /* This is for setting the MMU region for pinmux */ + pinmux: pinmux@10d13000 { + compatible = "syscon"; + reg = <0x10d13000 0x1000>; + }; + + mem0: memory@80100000 { + device_type = "memory"; + reg = <0x80100000 DT_SIZE_M(8)>; + }; + + uart0: uart@10c02000 { + compatible = "ns16550"; + reg-shift = <2>; + reg = <0x10c02000 0x100>; + interrupt-parent = <&gic>; + interrupts = ; + interrupt-names = "irq_0"; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_UART0_RSTLINE>; + status = "disabled"; + }; + + reset: reset-controller@10D11000 { + compatible = "intel,socfpga-reset"; + reg = <0x10D11000 0x100>; + active-low; + #reset-cells = <1>; + status = "okay"; + }; +}; diff --git a/dts/bindings/cpu/arm,cortex-a76.yaml b/dts/bindings/cpu/arm,cortex-a76.yaml new file mode 100644 index 000000000000..bd51fa6e8f8d --- /dev/null +++ b/dts/bindings/cpu/arm,cortex-a76.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Intel Corp. +# SPDX-License-Identifier: Apache-2.0 + +description: This is a representation of ARM Cortex-A76 CPU. + +compatible: "arm,cortex-a76" + +include: cpu.yaml diff --git a/dts/bindings/cpu/cpu.yaml b/dts/bindings/cpu/cpu.yaml index 71a0453b7393..c375ad4cbe1c 100644 --- a/dts/bindings/cpu/cpu.yaml +++ b/dts/bindings/cpu/cpu.yaml @@ -18,3 +18,6 @@ properties: d-cache-line-size: type: int description: d-cache line size + enable-method: + type: string + description: Enable method for cpu, either it is "psci" or "spin-table" From 6639756fae27349952d6768a58b3fca352de5a2e Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:35:51 +0000 Subject: [PATCH 1791/2042] drivers: reset: Add reset controller for Intel Agilex5 platform This is Intel's proprietary IP which controls individual module reset signals. During each system driver initialization, these reset signals will be used to bring module out of reset state. Signed-off-by: Navinkumar Balabakthan Signed-off-by: Girisha Dengi --- drivers/reset/CMakeLists.txt | 1 + drivers/reset/Kconfig | 1 + drivers/reset/Kconfig.intel_socfpga | 9 ++ drivers/reset/reset_intel_socfpga.c | 115 +++++++++++++++ dts/bindings/reset/intel,socfpga-reset.yaml | 21 +++ .../dt-bindings/reset/intel_socfpga_reset.h | 134 ++++++++++++++++++ 6 files changed, 281 insertions(+) create mode 100644 drivers/reset/Kconfig.intel_socfpga create mode 100644 drivers/reset/reset_intel_socfpga.c create mode 100644 dts/bindings/reset/intel,socfpga-reset.yaml create mode 100644 include/zephyr/dt-bindings/reset/intel_socfpga_reset.h diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt index 3dc29327cd63..36c68367d39c 100644 --- a/drivers/reset/CMakeLists.txt +++ b/drivers/reset/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_RESET_RPI_PICO reset_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_RESET_AST10X0 reset_ast10x0.c) zephyr_library_sources_ifdef(CONFIG_RESET_STM32 reset_stm32.c) zephyr_library_sources_ifdef(CONFIG_RESET_NUMAKER reset_numaker.c) +zephyr_library_sources_ifdef(CONFIG_RESET_INTEL_SOCFPGA reset_intel_socfpga.c) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 44117852ade4..f940583c9749 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -32,5 +32,6 @@ rsource "Kconfig.gd32" rsource "Kconfig.aspeed" rsource "Kconfig.stm32" rsource "Kconfig.numaker" +rsource "Kconfig.intel_socfpga" endif # RESET diff --git a/drivers/reset/Kconfig.intel_socfpga b/drivers/reset/Kconfig.intel_socfpga new file mode 100644 index 000000000000..5db76f3b2e57 --- /dev/null +++ b/drivers/reset/Kconfig.intel_socfpga @@ -0,0 +1,9 @@ +# Copyright (c) 2022, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config RESET_INTEL_SOCFPGA + bool "Intel SoC FPGA Reset Controller driver" + default y + depends on DT_HAS_INTEL_SOCFPGA_RESET_ENABLED + help + Enable the Reset driver for Intel SoC FPGA device diff --git a/drivers/reset/reset_intel_socfpga.c b/drivers/reset/reset_intel_socfpga.c new file mode 100644 index 000000000000..c63805d447fe --- /dev/null +++ b/drivers/reset/reset_intel_socfpga.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT intel_socfpga_reset + +#include +#include +#include + +/** regwidth 4 for 32 bit register */ +#define RESET_REG_WIDTH 4 + +struct reset_intel_config { + DEVICE_MMIO_ROM; + /* check peripheral active low / active high */ + bool active_low; +}; + +struct reset_intel_soc_data { + DEVICE_MMIO_RAM; +}; + +static int32_t reset_intel_soc_status(const struct device *dev, uint32_t id, uint8_t *status) +{ + const struct reset_intel_config *config = (const struct reset_intel_config *)dev->config; + uintptr_t base_address = DEVICE_MMIO_GET(dev); + uint32_t value; + uint16_t offset; + uint8_t regbit; + + regbit = (id & ((RESET_REG_WIDTH << (RESET_REG_WIDTH - 1)) - 1)); + offset = (id >> (RESET_REG_WIDTH + 1)) << (RESET_REG_WIDTH >> 1); + value = sys_read32(base_address + offset); + *status = !(value & BIT(regbit)) ^ config->active_low; + return 0; +} + +static void reset_intel_soc_update(const struct device *dev, uint32_t id, bool assert) +{ + const struct reset_intel_config *config = (const struct reset_intel_config *)dev->config; + uintptr_t base_address = DEVICE_MMIO_GET(dev); + uint16_t offset; + uint8_t regbit; + + regbit = (id & ((RESET_REG_WIDTH << (RESET_REG_WIDTH - 1)) - 1)); + offset = (id >> (RESET_REG_WIDTH + 1)) << (RESET_REG_WIDTH >> 1); + + if (assert ^ !config->active_low) { + if (sys_test_bit(base_address + offset, regbit) == 0) { + sys_set_bit(base_address + offset, regbit); + } + } else { + if (sys_test_bit(base_address + offset, regbit) != 0) { + sys_clear_bit(base_address + offset, regbit); + } + } +} + +static int32_t reset_intel_soc_line_assert(const struct device *dev, uint32_t id) +{ + reset_intel_soc_update(dev, id, true); + + return 0; +} + +static int32_t reset_intel_soc_line_deassert(const struct device *dev, uint32_t id) +{ + reset_intel_soc_update(dev, id, false); + + return 0; +} + +static int32_t reset_intel_soc_line_toggle(const struct device *dev, uint32_t id) +{ + (void)reset_intel_soc_line_assert(dev, id); + /* TODO: Add required delay once tested on Emulator/Hardware platform. */ + (void)reset_intel_soc_line_deassert(dev, id); + + return 0; +} + +static int32_t reset_intel_soc_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + return 0; +} + +static const struct reset_driver_api reset_intel_soc_driver_api = { + .status = reset_intel_soc_status, + .line_assert = reset_intel_soc_line_assert, + .line_deassert = reset_intel_soc_line_deassert, + .line_toggle = reset_intel_soc_line_toggle, +}; + +#define INTEL_SOC_RESET_INIT(_inst) \ + static struct reset_intel_soc_data reset_intel_soc_data_##_inst; \ + static const struct reset_intel_config reset_intel_config_##_inst = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(_inst)), \ + .active_low = DT_INST_PROP(_inst, active_low), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(_inst, \ + reset_intel_soc_init, \ + NULL, \ + &reset_intel_soc_data_##_inst, \ + &reset_intel_config_##_inst, \ + PRE_KERNEL_1, \ + CONFIG_RESET_INIT_PRIORITY, \ + &reset_intel_soc_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INTEL_SOC_RESET_INIT); diff --git a/dts/bindings/reset/intel,socfpga-reset.yaml b/dts/bindings/reset/intel,socfpga-reset.yaml new file mode 100644 index 000000000000..c4eb11ca38ad --- /dev/null +++ b/dts/bindings/reset/intel,socfpga-reset.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2022, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Intel SoC FPGA Reset Controller + +compatible: "intel,socfpga-reset" + +include: [base.yaml, reset-controller.yaml] + +properties: + reg: + required: true + active-low: + type: boolean + description: Add this property in dts node if the reset line is active_low, otherwise do not + include this property for active_high lines. + "#reset-cells": + const: 1 + +reset-cells: +- id diff --git a/include/zephyr/dt-bindings/reset/intel_socfpga_reset.h b/include/zephyr/dt-bindings/reset/intel_socfpga_reset.h new file mode 100644 index 000000000000..32336ab11769 --- /dev/null +++ b/include/zephyr/dt-bindings/reset/intel_socfpga_reset.h @@ -0,0 +1,134 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2023, Intel Corporation + * + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_RESET_INTEL_SOCFPGA_RESET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_RESET_INTEL_SOCFPGA_RESET_H_ + +/* The Reset line value will be used by the reset controller driver to + * derive the register offset and the associated device bit to perform + * device assert and de-assert. + * + * The reset lines should be passed as a parameter to the resets property + * of the driver node in dtsi which will call reset-controller driver to + * assert/de-assert itself. + * + * Example: Deriving Reset Line value + * per0modrst register offset = 0x24; + * NAND RSTLINE pin = 5; + * RSTMGR_NAND_RSTLINE = (0x24 * 8) + 5 = 293 + */ + +#define RSTMGR_SDMCOLDRST_RSTLINE 0 +#define RSTMGR_SDMWARMRST_RSTLINE 1 +#define RSTMGR_SDMLASTPORRST_RSTLINE 2 +#define RSTMGR_L4WD0RST_RSTLINE 16 +#define RSTMGR_L4WD1RST_RSTLINE 17 +#define RSTMGR_L4WD2RST_RSTLINE 18 +#define RSTMGR_L4WD3RST_RSTLINE 19 +#define RSTMGR_L4WD4RST_RSTLINE 20 +#define RSTMGR_DEBUGRST_RSTLINE 21 +#define RSTMGR_CSDAPRST_RSTLINE 22 +#define RSTMGR_EMIFTIMEOUT_RSTLINE 64 +#define RSTMGR_FPGAHSTIMEOUT_RSTLINE 66 +#define RSTMGR_ETRSTALLTIMEOUT_RSTLINE 67 +#define RSTMGR_LWSOC2FPGATIMEOUT_RSTLINE 72 +#define RSTMGR_SOC2FPGATIMEOUT_RSTLINE 73 +#define RSTMGR_F2SDRAMTIMEOUT_RSTLINE 74 +#define RSTMGR_F2STIMEOUT_RSTLINE 75 +#define RSTMGR_L3NOCDBGTIMEOUT_RSTLINE 79 +#define RSTMGR_DEBUGL3NOCTIMEOUT_RSTLINE 80 +#define RSTMGR_EMIF_FLUSH_RSTLINE 128 +#define RSTMGR_FPGAHSEN_RSTLINE 130 +#define RSTMGR_ETRSTALLEN_RSTLINE 131 +#define RSTMGR_LWSOC2FPGA_FLUSH_RSTLINE 137 +#define RSTMGR_SOC2FPGA_FLUSH_RSTLINE 138 +#define RSTMGR_F2SDRAM_FLUSH_RSTLINE 139 +#define RSTMGR_F2SOC_FLUSH_RSTLINE 140 +#define RSTMGR_L3NOC_DBG_RSTLINE 144 +#define RSTMGR_DEBUG_L3NOC_RSTLINE 145 +#define RSTMGR_EMIF_FLUSH_REQ_RSTLINE 160 +#define RSTMGR_FPGAHSREQ_RSTLINE 162 +#define RSTMGR_ETRSTALLREQ_RSTLINE 163 +#define RSTMGR_LWSOC2FPGA_FLUSH_REQ_RSTLINE 169 +#define RSTMGR_SOC2FPGA_FLUSH_REQ_RSTLINE 170 +#define RSTMGR_F2SDRAM_FLUSH_REQ_RSTLINE 171 +#define RSTMGR_F2S_FLUSH_REQ_RSTLINE 172 +#define RSTMGR_L3NOC_DBG_REQ_RSTLINE 176 +#define RSTMGR_DEBUG_L3NOC_REQ_RSTLINE 177 +#define RSTMGR_EMIF_FLUSH_ACK_RSTLINE 192 +#define RSTMGR_FPGAHSACK_RSTLINE 194 +#define RSTMGR_ETRSTALLACK_RSTLINE 195 +#define RSTMGR_LWSOC2FPGA_FLUSH_ACK_RSTLINE 201 +#define RSTMGR_SOC2FPGA_FLUSH_ACK_RSTLINE 202 +#define RSTMGR_F2SDRAM_FLUSH_ACK_RSTLINE 203 +#define RSTMGR_F2S_FLUSH_ACK_RSTLINE 204 +#define RSTMGR_L3NOC_DBG_ACK_RSTLINE 208 +#define RSTMGR_DEBUG_L3NOC_ACK_RSTLINE 209 +#define RSTMGR_ETRSTALLWARMRST_RSTLINE 224 +#define RSTMGR_TSN0_RSTLINE 288 +#define RSTMGR_TSN1_RSTLINE 289 +#define RSTMGR_TSN2_RSTLINE 290 +#define RSTMGR_USB0_RSTLINE 291 +#define RSTMGR_USB1_RSTLINE 292 +#define RSTMGR_NAND_RSTLINE 293 +#define RSTMGR_SOFTPHY_RSTLINE 294 +#define RSTMGR_SDMMC_RSTLINE 295 +#define RSTMGR_TSN0ECC_RSTLINE 296 +#define RSTMGR_TSN1ECC_RSTLINE 297 +#define RSTMGR_TSN2ECC_RSTLINE 298 +#define RSTMGR_USB0ECC_RSTLINE 299 +#define RSTMGR_USB1ECC_RSTLINE 300 +#define RSTMGR_NANDECC_RSTLINE 301 +#define RSTMGR_SDMMCECC_RSTLINE 303 +#define RSTMGR_DMA_RSTLINE 304 +#define RSTMGR_SPIM0_RSTLINE 305 +#define RSTMGR_SPIM1_RSTLINE 306 +#define RSTMGR_SPIS0_RSTLINE 307 +#define RSTMGR_SPIS1_RSTLINE 308 +#define RSTMGR_DMAECC_RSTLINE 309 +#define RSTMGR_EMACPTP_RSTLINE 310 +#define RSTMGR_DMAIF0_RSTLINE 312 +#define RSTMGR_DMAIF1_RSTLINE 313 +#define RSTMGR_DMAIF2_RSTLINE 314 +#define RSTMGR_DMAIF3_RSTLINE 315 +#define RSTMGR_DMAIF4_RSTLINE 316 +#define RSTMGR_DMAIF5_RSTLINE 317 +#define RSTMGR_DMAIF6_RSTLINE 318 +#define RSTMGR_DMAIF7_RSTLINE 319 +#define RSTMGR_WATCHDOG0_RSTLINE 320 +#define RSTMGR_WATCHDOG1_RSTLINE 321 +#define RSTMGR_WATCHDOG2_RSTLINE 322 +#define RSTMGR_WATCHDOG3_RSTLINE 323 +#define RSTMGR_L4SYSTIMER0_RSTLINE 324 +#define RSTMGR_L4SYSTIMER1_RSTLINE 325 +#define RSTMGR_SPTIMER0_RSTLINE 326 +#define RSTMGR_SPTIMER1_RSTLINE 327 +#define RSTMGR_I2C0_RSTLINE 328 +#define RSTMGR_I2C1_RSTLINE 329 +#define RSTMGR_I2C2_RSTLINE 330 +#define RSTMGR_I2C3_RSTLINE 331 +#define RSTMGR_I2C4_RSTLINE 332 +#define RSTMGR_I3C0_RSTLINE 333 +#define RSTMGR_I3C1_RSTLINE 334 +#define RSTMGR_UART0_RSTLINE 336 +#define RSTMGR_UART1_RSTLINE 337 +#define RSTMGR_GPIO0_RSTLINE 344 +#define RSTMGR_GPIO1_RSTLINE 345 +#define RSTMGR_WATCHDOG4_RSTLINE 346 +#define RSTMGR_SOC2FPGA_RSTLINE 352 +#define RSTMGR_LWSOC2FPGA_RSTLINE 353 +#define RSTMGR_FPGA2SOC_RSTLINE 354 +#define RSTMGR_FPGA2SDRAM_RSTLINE 355 +#define RSTMGR_MPFE_RSTLINE 358 +#define RSTMGR_DBG_RST_RSTLINE 480 +#define RSTMGR_SOC2FPGA_WARM_RSTLINE 608 +#define RSTMGR_LWSOC2FPGA_WARM_RSTLINE 609 +#define RSTMGR_FPGA2SOC_WARM_RSTLINE 610 +#define RSTMGR_FPGA2SDRAM_WARM_RSTLINE 611 +#define RSTMGR_MPFE_WARM_RSTLINE 614 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_RESET_INTEL_SOCFPGA_RESET_H_ */ From f0ac2347daeda7b1f1bf5ae64b3016549ad60029 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:47:06 +0000 Subject: [PATCH 1792/2042] drivers: serial: Add optional reset line for uart_ns16550 If the optional hardware reset line is available, this change will use that reset line to assert the uart module and bring it out of reset state to use. Signed-off-by: Girisha Dengi --- drivers/serial/uart_ns16550.c | 58 +++++++++++++++++++++++++++++++- dts/bindings/serial/ns16550.yaml | 2 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index da5bd79fa530..c7357d076f11 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -4,7 +4,7 @@ /* * Copyright (c) 2010, 2012-2015 Wind River Systems, Inc. - * Copyright (c) 2020-2022 Intel Corp. + * Copyright (c) 2020-2023 Intel Corp. * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,9 @@ #endif #include +#include + +LOG_MODULE_REGISTER(uart_ns16550, CONFIG_UART_LOG_LEVEL); #define INST_HAS_PCP_HELPER(inst) DT_INST_NODE_HAS_PROP(inst, pcp) || #define INST_HAS_DLF_HELPER(inst) DT_INST_NODE_HAS_PROP(inst, dlf) || @@ -53,6 +56,13 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #include #endif +/* Is UART module 'resets' line property defined */ +#define UART_NS16550_RESET_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + +#if UART_NS16550_RESET_ENABLED +#include +#endif + /* register definitions */ #define REG_THR 0x00 /* Transmitter holding reg. */ @@ -247,6 +257,9 @@ struct uart_ns16550_device_config { #if defined(CONFIG_UART_NS16550_ACCESS_IOPORT) || defined(CONFIG_UART_NS16550_SIMULT_ACCESS) bool io_map; #endif +#if UART_NS16550_RESET_ENABLED + struct reset_dt_spec reset_spec; +#endif }; /** Device data structure */ @@ -580,6 +593,35 @@ static int uart_ns16550_config_get(const struct device *dev, } #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if UART_NS16550_RESET_ENABLED +/** + * @brief Toggle the reset UART line + * + * This routine is called to bring UART IP out of reset state. + * + * @param reset_spec Reset controller device configuration struct + * + * @return 0 if successful, failed otherwise + */ +static int uart_reset_config(const struct reset_dt_spec *reset_spec) +{ + int ret; + + if (!device_is_ready(reset_spec->dev)) { + LOG_ERR("Reset controller device is not ready"); + return -ENODEV; + } + + ret = reset_line_toggle(reset_spec->dev, reset_spec->id); + if (ret != 0) { + LOG_ERR("UART toggle reset line failed"); + return ret; + } + + return 0; +} +#endif /* UART_NS16550_RESET_ENABLED */ + /** * @brief Initialize individual UART port * @@ -597,6 +639,16 @@ static int uart_ns16550_init(const struct device *dev) ARG_UNUSED(dev_cfg); +#if UART_NS16550_RESET_ENABLED + /* Assert the UART reset line if it is defined. */ + if (dev_cfg->reset_spec.dev != NULL) { + ret = uart_reset_config(&(dev_cfg->reset_spec)); + if (ret != 0) { + return ret; + } + } +#endif + #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) if (dev_cfg->pcie) { struct pcie_bar mbar; @@ -1285,6 +1337,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #else #define BOOT_LEVEL(n) PRE_KERNEL_1 #endif +#define UART_RESET_FUNC_INIT(n) \ + .reset_spec = RESET_DT_SPEC_INST_GET(n), #define UART_NS16550_DEVICE_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ @@ -1310,6 +1364,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { DEV_CONFIG_PCIE_INIT(n) \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, pinctrl_0), \ (.pincfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(n)),)) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, resets), \ + (UART_RESET_FUNC_INIT(n))) \ }; \ static struct uart_ns16550_dev_data uart_ns16550_dev_data_##n = { \ .uart_config.baudrate = DT_INST_PROP_OR(n, current_speed, 0), \ diff --git a/dts/bindings/serial/ns16550.yaml b/dts/bindings/serial/ns16550.yaml index 04766ea117b2..da315af42711 100644 --- a/dts/bindings/serial/ns16550.yaml +++ b/dts/bindings/serial/ns16550.yaml @@ -2,7 +2,7 @@ description: ns16550 UART compatible: "ns16550" -include: [uart-controller.yaml, pcie-device.yaml, pinctrl-device.yaml] +include: [uart-controller.yaml, pcie-device.yaml, pinctrl-device.yaml, reset-device.yaml] properties: reg-shift: From 62dbe72cb7ac55d1ae3ce62e5fb1fae47b9b293a Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 14:55:15 +0000 Subject: [PATCH 1793/2042] drivers: pm_cpu_ops: Add support for multiple PSCI versions Each PSCI interface versions have different DT compatible strings like arm,psci-0.2, arm,psci-1.1 and so on. However, the same driver can be used for all the versions by adding #define DT_COMPAT for required version and #undef DT_COMPAT for default version. Add support for PSCI cold reset, warm reset and cpu-on function IDs. Signed-off-by: Girisha Dengi Signed-off-by: Navinkumar Balabakthan --- drivers/pm_cpu_ops/CMakeLists.txt | 2 + drivers/pm_cpu_ops/Kconfig | 10 +- drivers/pm_cpu_ops/pm_cpu_ops_psci.c | 85 +++++++++++++-- drivers/pm_cpu_ops/pm_cpu_ops_psci.h | 125 ++++++++++++++++------ drivers/pm_cpu_ops/psci_shell.c | 73 +++++++++++++ dts/bindings/pm_cpu_ops/arm,psci-0.2.yaml | 14 +-- dts/bindings/pm_cpu_ops/arm,psci-1.1.yaml | 8 ++ dts/bindings/pm_cpu_ops/arm_psci.yaml | 18 ++++ include/zephyr/drivers/pm_cpu_ops.h | 14 +++ 9 files changed, 292 insertions(+), 57 deletions(-) create mode 100644 drivers/pm_cpu_ops/psci_shell.c create mode 100644 dts/bindings/pm_cpu_ops/arm,psci-1.1.yaml create mode 100644 dts/bindings/pm_cpu_ops/arm_psci.yaml diff --git a/drivers/pm_cpu_ops/CMakeLists.txt b/drivers/pm_cpu_ops/CMakeLists.txt index c738d5256bbc..15643f4702a3 100644 --- a/drivers/pm_cpu_ops/CMakeLists.txt +++ b/drivers/pm_cpu_ops/CMakeLists.txt @@ -5,3 +5,5 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops_weak_impl.c) zephyr_library_sources_ifdef(CONFIG_PM_CPU_OPS_PSCI pm_cpu_ops_psci.c) + +zephyr_library_sources_ifdef(CONFIG_PSCI_SHELL psci_shell.c) diff --git a/drivers/pm_cpu_ops/Kconfig b/drivers/pm_cpu_ops/Kconfig index ccab1ea78e76..712480c1d43c 100644 --- a/drivers/pm_cpu_ops/Kconfig +++ b/drivers/pm_cpu_ops/Kconfig @@ -20,7 +20,7 @@ config PM_CPU_OPS_HAS_DRIVER config PM_CPU_OPS_PSCI bool "Support for the ARM Power State Coordination Interface (PSCI)" default y - depends on DT_HAS_ARM_PSCI_0_2_ENABLED + depends on DT_HAS_ARM_PSCI_0_2_ENABLED || DT_HAS_ARM_PSCI_1_1_ENABLED select PM_CPU_OPS_HAS_DRIVER help Say Y here if you want Zephyr to communicate with system firmware @@ -29,4 +29,12 @@ config PM_CPU_OPS_PSCI 0022A ("Power State Coordination Interface System Software on ARM processors"). +config PSCI_SHELL + bool "Support for PSCI interface shell commands" + default y + depends on SHELL && PM_CPU_OPS_PSCI + help + Say Y here if you need to enable PSCI interface shell commands + like 'warm' and 'cold' reset commands. + endif diff --git a/drivers/pm_cpu_ops/pm_cpu_ops_psci.c b/drivers/pm_cpu_ops/pm_cpu_ops_psci.c index 81f750ddd821..c110764e0a8e 100644 --- a/drivers/pm_cpu_ops/pm_cpu_ops_psci.c +++ b/drivers/pm_cpu_ops/pm_cpu_ops_psci.c @@ -1,6 +1,8 @@ /* * Copyright 2020 Carlo Caione * + * Copyright (c) 2023, Intel Corporation. + * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +21,8 @@ LOG_MODULE_REGISTER(psci); #include #include "pm_cpu_ops_psci.h" -static struct psci psci_data; +/* PSCI data object. */ +static struct psci_data_t psci_data; static int psci_to_dev_err(int ret) { @@ -80,6 +83,43 @@ int pm_system_off(void) return psci_to_dev_err(ret); } +/** + * This function checks whether the given ID is supported or not, using + * PSCI_FEATURES command.PSCI_FEATURES is supported from version 1.0 onwards. + */ +static int psci_features_check(unsigned long function_id) +{ + /* PSCI_FEATURES function ID is supported from PSCI 1.0 onwards. */ + if (!(PSCI_VERSION_MAJOR(psci_data.ver) >= 1)) { + LOG_ERR("Function ID %lu not supported", function_id); + return -ENOTSUP; + } + + return psci_data.invoke_psci_fn(PSCI_FN_NATIVE(1_0, PSCI_FEATURES), function_id, 0, 0); +} + +int pm_system_reset(unsigned char reset_type) +{ + int ret; + + if (psci_data.conduit == SMCCC_CONDUIT_NONE) { + return -EINVAL; + } + + if ((reset_type == SYS_WARM_RESET) && + (!psci_features_check(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2)))) { + ret = psci_data.invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0); + } else if (reset_type == SYS_COLD_RESET) { + ret = psci_data.invoke_psci_fn(PSCI_FN_NATIVE(0_2, SYSTEM_RESET), 0, 0, 0); + } else { + LOG_ERR("Invalid system reset type issued"); + return -EINVAL; + } + + return psci_to_dev_err(ret); + +} + static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, unsigned long arg0, unsigned long arg1, @@ -107,16 +147,14 @@ static uint32_t psci_get_version(void) return psci_data.invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); } -static int set_conduit_method(void) +static int set_conduit_method(const struct device *dev) { - const char *method; - - method = DT_PROP(DT_INST(0, DT_DRV_COMPAT), method); + const struct psci_config_t *dev_config = (const struct psci_config_t *)dev->config; - if (!strcmp("hvc", method)) { + if (!strcmp("hvc", dev_config->method)) { psci_data.conduit = SMCCC_CONDUIT_HVC; psci_data.invoke_psci_fn = __invoke_psci_fn_hvc; - } else if (!strcmp("smc", method)) { + } else if (!strcmp("smc", dev_config->method)) { psci_data.conduit = SMCCC_CONDUIT_SMC; psci_data.invoke_psci_fn = __invoke_psci_fn_smc; } else { @@ -154,13 +192,38 @@ static int psci_init(const struct device *dev) { psci_data.conduit = SMCCC_CONDUIT_NONE; - if (set_conduit_method()) { + if (set_conduit_method(dev)) { return -ENOTSUP; } return psci_detect(); } -DEVICE_DT_INST_DEFINE(0, psci_init, NULL, - &psci_data, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - NULL); +/** + * Each PSCI interface versions have different DT compatible strings like arm,psci-0.2, + * arm,psci-1.1 and so on. However, the same driver can be used for all the versions with + * the below mentioned DT method where we need to #undef the default version arm,psci-0.2 + * and #define the required version like arm,psci-1.0 or arm,psci-1.1. + */ +#define PSCI_DEFINE(inst, ver) \ + static const struct psci_config_t psci_config_##inst##ver = { \ + .method = DT_PROP(DT_DRV_INST(inst), method) \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &psci_init, \ + NULL, \ + &psci_data, \ + &psci_config_##inst##ver, \ + PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + NULL); + +#define PSCI_0_2_INIT(n) PSCI_DEFINE(n, PSCI_0_2) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT arm_psci_0_2 +DT_INST_FOREACH_STATUS_OKAY(PSCI_0_2_INIT) + +#define PSCI_1_1_INIT(n) PSCI_DEFINE(n, PSCI_1_1) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT arm_psci_1_1 +DT_INST_FOREACH_STATUS_OKAY(PSCI_1_1_INIT) diff --git a/drivers/pm_cpu_ops/pm_cpu_ops_psci.h b/drivers/pm_cpu_ops/pm_cpu_ops_psci.h index f06b369ee469..606071fbb072 100644 --- a/drivers/pm_cpu_ops/pm_cpu_ops_psci.h +++ b/drivers/pm_cpu_ops/pm_cpu_ops_psci.h @@ -10,55 +10,112 @@ #include #ifdef CONFIG_64BIT -#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name #else -#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name #endif /* PSCI v0.2 interface */ -#define PSCI_0_2_FN_BASE 0x84000000 -#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) -#define PSCI_0_2_64BIT 0x40000000 -#define PSCI_0_2_FN64_BASE \ - (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) -#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) +#define PSCI_0_2_FN_BASE 0x84000000 +#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) +#define PSCI_0_2_64BIT 0x40000000 +#define PSCI_0_2_FN64_BASE (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) +#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) +#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) +#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) +#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) +#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) +#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) +#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) +#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) +#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) +#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) +#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) +#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) +#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) +#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) +#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) +#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) +#define PSCI_0_2_FN64_SYSTEM_RESET PSCI_0_2_FN(9) -#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) -#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) -#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) -#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) -#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) -#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) -#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) -#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) -#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) -#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) +/* PSCI v1.0 interface */ +#define PSCI_1_0_FN_BASE (0x84000000U) +#define PSCI_1_0_64BIT (0x40000000U) +#define PSCI_1_0_FN64_BASE (PSCI_1_0_FN_BASE + PSCI_1_0_64BIT) +#define PSCI_1_0_FN(n) (PSCI_1_0_FN_BASE + (n)) +#define PSCI_1_0_FN64(n) (PSCI_1_0_FN64_BASE + (n)) +#define PSCI_1_0_FN_PSCI_VERSION PSCI_1_0_FN(0) +#define PSCI_1_0_FN_CPU_SUSPEND PSCI_1_0_FN(1) +#define PSCI_1_0_FN_CPU_OFF PSCI_1_0_FN(2) +#define PSCI_1_0_FN_CPU_ON PSCI_1_0_FN(3) +#define PSCI_1_0_FN_AFFINITY_INFO PSCI_1_0_FN(4) +#define PSCI_1_0_FN_MIGRATE PSCI_1_0_FN(5) +#define PSCI_1_0_FN_MIGRATE_INFO_TYPE PSCI_1_0_FN(6) +#define PSCI_1_0_FN_MIGRATE_INFO_UP_CPU PSCI_1_0_FN(7) +#define PSCI_1_0_FN_SYSTEM_OFF PSCI_1_0_FN(8) +#define PSCI_1_0_FN_SYSTEM_RESET PSCI_1_0_FN(9) +#define PSCI_1_0_FN_PSCI_FEATURES PSCI_1_0_FN(10) +#define PSCI_1_0_FN64_CPU_SUSPEND PSCI_1_0_FN64(1) +#define PSCI_1_0_FN64_CPU_ON PSCI_1_0_FN64(3) +#define PSCI_1_0_FN64_AFFINITY_INFO PSCI_1_0_FN64(4) +#define PSCI_1_0_FN64_MIGRATE PSCI_1_0_FN64(5) +#define PSCI_1_0_FN64_MIGRATE_INFO_UP_CPU PSCI_1_0_FN64(7) +/* PSCI function ID is same for both 32 and 64 bit.*/ +#define PSCI_1_0_FN64_SYSTEM_RESET PSCI_1_0_FN(9) +#define PSCI_1_0_FN64_PSCI_FEATURES PSCI_1_0_FN(10) -#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) -#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) -#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) -#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) -#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) +/* PSCI v1.1 interface. */ +#define PSCI_1_1_FN_BASE (0x84000000U) +#define PSCI_1_1_64BIT (0x40000000U) +#define PSCI_1_1_FN64_BASE (PSCI_1_1_FN_BASE + PSCI_1_1_64BIT) +#define PSCI_1_1_FN(n) (PSCI_1_1_FN_BASE + (n)) +#define PSCI_1_1_FN64(n) (PSCI_1_1_FN64_BASE + (n)) +#define PSCI_1_1_FN_PSCI_VERSION PSCI_1_1_FN(0) +#define PSCI_1_1_FN_CPU_SUSPEND PSCI_1_1_FN(1) +#define PSCI_1_1_FN_CPU_OFF PSCI_1_1_FN(2) +#define PSCI_1_1_FN_CPU_ON PSCI_1_1_FN(3) +#define PSCI_1_1_FN_AFFINITY_INFO PSCI_1_1_FN(4) +#define PSCI_1_1_FN_MIGRATE PSCI_1_1_FN(5) +#define PSCI_1_1_FN_MIGRATE_INFO_TYPE PSCI_1_1_FN(6) +#define PSCI_1_1_FN_MIGRATE_INFO_UP_CPU PSCI_1_1_FN(7) +#define PSCI_1_1_FN_SYSTEM_OFF PSCI_1_1_FN(8) +#define PSCI_1_1_FN_SYSTEM_RESET PSCI_1_1_FN(9) +#define PSCI_1_1_FN_PSCI_FEATURES PSCI_1_1_FN(10) +#define PSCI_1_1_FN_SYSTEM_RESET2 PSCI_1_1_FN(18) +#define PSCI_1_1_FN64_CPU_SUSPEND PSCI_1_1_FN64(1) +#define PSCI_1_1_FN64_CPU_ON PSCI_1_1_FN64(3) +#define PSCI_1_1_FN64_AFFINITY_INFO PSCI_1_1_FN64(4) +#define PSCI_1_1_FN64_MIGRATE PSCI_1_1_FN64(5) +#define PSCI_1_1_FN64_MIGRATE_INFO_UP_CPU PSCI_1_1_FN64(7) +/* PSCI function ID is same for both 32 and 64 bit.*/ +#define PSCI_1_1_FN64_SYSTEM_RESET PSCI_1_1_FN(9) +#define PSCI_1_1_FN64_PSCI_FEATURES PSCI_1_1_FN(10) +#define PSCI_1_1_FN64_SYSTEM_RESET2 PSCI_1_1_FN64(18) /* PSCI return values (inclusive of all PSCI versions) */ -#define PSCI_RET_SUCCESS 0 -#define PSCI_RET_NOT_SUPPORTED -1 -#define PSCI_RET_INVALID_PARAMS -2 -#define PSCI_RET_DENIED -3 -#define PSCI_RET_ALREADY_ON -4 -#define PSCI_RET_ON_PENDING -5 -#define PSCI_RET_INTERNAL_FAILURE -6 -#define PSCI_RET_NOT_PRESENT -7 -#define PSCI_RET_DISABLED -8 -#define PSCI_RET_INVALID_ADDRESS -9 +#define PSCI_RET_SUCCESS 0 +#define PSCI_RET_NOT_SUPPORTED -1 +#define PSCI_RET_INVALID_PARAMS -2 +#define PSCI_RET_DENIED -3 +#define PSCI_RET_ALREADY_ON -4 +#define PSCI_RET_ON_PENDING -5 +#define PSCI_RET_INTERNAL_FAILURE -6 +#define PSCI_RET_NOT_PRESENT -7 +#define PSCI_RET_DISABLED -8 +#define PSCI_RET_INVALID_ADDRESS -9 typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); -struct psci { +struct psci_data_t { enum arm_smccc_conduit conduit; psci_fn *invoke_psci_fn; uint32_t ver; }; +/* PSCI configuration data. */ +struct psci_config_t { + const char *method; +}; + #endif /* ZEPHYR_DRIVERS_PSCI_PSCI_H_ */ diff --git a/drivers/pm_cpu_ops/psci_shell.c b/drivers/pm_cpu_ops/psci_shell.c new file mode 100644 index 000000000000..34669b65a08c --- /dev/null +++ b/drivers/pm_cpu_ops/psci_shell.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* Zephyr kernel start address. */ +extern void __start(void); + +static int cmd_reboot_warm(const struct shell *shctx, size_t argc, char **argv) +{ + ARG_UNUSED(shctx); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + int ret; + + ret = pm_system_reset(SYS_WARM_RESET); + if (ret != 0) { + shell_error(shctx, "Failed to perform system warm reset"); + } + + return ret; +} + +static int cmd_reboot_cold(const struct shell *shctx, size_t argc, char **argv) +{ + ARG_UNUSED(shctx); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + int ret; + + ret = pm_system_reset(SYS_COLD_RESET); + if (ret != 0) { + shell_error(shctx, "Failed to perform system cold reset"); + } + + return ret; +} + +static int cmd_psci_cpuon(const struct shell *shctx, size_t argc, char **argv) +{ + ARG_UNUSED(shctx); + ARG_UNUSED(argc); + long cpu_id; + int result; + + errno = 0; + cpu_id = strtol(argv[1], NULL, 10); + if (cpu_id == 0 || cpu_id == LONG_MIN || cpu_id == LONG_MAX) { + if (errno != 0) { + shell_error(shctx, "psci: invalid input:%ld", cpu_id); + return -EINVAL; + } + } + + result = pm_cpu_on((unsigned long)cpu_id, (uintptr_t)&__start); + + return result; +} + +SHELL_STATIC_SUBCMD_SET_CREATE( + sub_reboot, + SHELL_CMD_ARG(warm, NULL, "System warm reset. Usage: ", cmd_reboot_warm, 1, 0), + SHELL_CMD_ARG(cold, NULL, "System cold reset. Usage: ", cmd_reboot_cold, 1, 0), + SHELL_CMD_ARG(cpuon, NULL, "Power-up the secondary CPU. Usage: >", + cmd_psci_cpuon, 2, 0), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +SHELL_CMD_REGISTER(psci, &sub_reboot, "ARM PSCI interface commands", NULL); diff --git a/dts/bindings/pm_cpu_ops/arm,psci-0.2.yaml b/dts/bindings/pm_cpu_ops/arm,psci-0.2.yaml index ebebb1ea5e71..0d7c1a82a8c2 100644 --- a/dts/bindings/pm_cpu_ops/arm,psci-0.2.yaml +++ b/dts/bindings/pm_cpu_ops/arm,psci-0.2.yaml @@ -1,17 +1,9 @@ # Copyright (c) 2020 Carlo Caione +# Copyright (c) 2023, Intel Corporation # SPDX-License-Identifier: Apache-2.0 -description: PSCI +description: Power State Coordination Interface (PSCI) version 0.2. compatible: "arm,psci-0.2" -include: base.yaml - -properties: - method: - type: string - required: true - description: The method of calling the PSCI firmware. - enum: - - smc - - hvc +include: arm_psci.yaml diff --git a/dts/bindings/pm_cpu_ops/arm,psci-1.1.yaml b/dts/bindings/pm_cpu_ops/arm,psci-1.1.yaml new file mode 100644 index 000000000000..507e4f827f80 --- /dev/null +++ b/dts/bindings/pm_cpu_ops/arm,psci-1.1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Power State Coordination Interface (PSCI) version 1.1. + +compatible: "arm,psci-1.1" + +include: arm_psci.yaml diff --git a/dts/bindings/pm_cpu_ops/arm_psci.yaml b/dts/bindings/pm_cpu_ops/arm_psci.yaml new file mode 100644 index 000000000000..3852d627f4bd --- /dev/null +++ b/dts/bindings/pm_cpu_ops/arm_psci.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: This Power State Coordination Interface (PSCI) defines a standard + interface for power management that can be used by operating system + vendors, for supervisory software working at different levels of + privilege on an ARM device. + +include: base.yaml + +properties: + method: + type: string + required: true + description: The method of calling the PSCI firmware. + enum: + - smc + - hvc diff --git a/include/zephyr/drivers/pm_cpu_ops.h b/include/zephyr/drivers/pm_cpu_ops.h index 3e1e6a51a01b..49ea67e155cf 100644 --- a/include/zephyr/drivers/pm_cpu_ops.h +++ b/include/zephyr/drivers/pm_cpu_ops.h @@ -20,6 +20,9 @@ extern "C" { #endif +/* System reset types. */ +#define SYS_WARM_RESET 0 +#define SYS_COLD_RESET 1 /** * @defgroup power_management_cpu_api CPU Power Management * @ingroup subsys_pm @@ -65,6 +68,17 @@ int pm_cpu_on(unsigned long cpuid, uintptr_t entry_point); */ int pm_system_off(void); +/** + * @brief System reset + * + * This function provides a method for performing a system cold or warm reset. + * + * @param reset system reset type, cold or warm. + * + * @retval 0 on success, a negative errno otherwise + */ +int pm_system_reset(unsigned char reset); + #ifdef __cplusplus } #endif From ba40e9fded275e0cb08f4b3dac045c91931eaa8d Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Mon, 17 Jul 2023 14:41:18 +0000 Subject: [PATCH 1794/2042] samples: subsys: shell: Custom configs for intel_socfpga_agilex* boards The intent of this change is to add custom shell configurations for intel_socfpga_agilex* based boards. As of now, configurations are added for 'intel_socfpga_agilex5_socdk' board. Signed-off-by: Girisha Dengi --- .../boards/intel_socfpga_agilex5_socdk.conf | 15 +++++++++++++++ .../boards/intel_socfpga_agilex5_socdk.overlay | 12 ++++++++++++ samples/subsys/shell/shell_module/sample.yaml | 1 + 3 files changed, 28 insertions(+) create mode 100644 samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf create mode 100644 samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay 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 new file mode 100644 index 000000000000..762975e0a44f --- /dev/null +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf @@ -0,0 +1,15 @@ +# Copyright (c) 2022-2023, Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# Misc +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_SHELL_STACK_SIZE=8192 + +# Setting the Shell prompt +CONFIG_SHELL_PROMPT_UART="agilex5$ " + +# Setting the max argc +CONFIG_SHELL_ARGC_MAX=12 + +# Enable the Zephyr boot banner +CONFIG_BOOT_BANNER=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 new file mode 100644 index 000000000000..d222ce070f03 --- /dev/null +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,12 @@ +/* + * 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 shell application for this + * board. + * + * Nothing here as of now. + */ diff --git a/samples/subsys/shell/shell_module/sample.yaml b/samples/subsys/shell/shell_module/sample.yaml index 2c4882297cba..7aac79eac903 100644 --- a/samples/subsys/shell/shell_module/sample.yaml +++ b/samples/subsys/shell/shell_module/sample.yaml @@ -8,6 +8,7 @@ tests: min_ram: 40 integration_platforms: - native_posix + - intel_socfpga_agilex5_socdk sample.shell.shell_module.usb: depends_on: usb_device tags: From 8df81eae7186b2b68a0cd0b1b6d07a236d78a519 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Thu, 6 Jul 2023 15:07:44 +0000 Subject: [PATCH 1795/2042] CODEOWNERS: Add code owners for Intel Agilex5 platform drivers Code owners for all the required Intel Agilex5 platform drivers. Signed-off-by: Girisha Dengi --- CODEOWNERS | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 05d7ad42ca0f..937d4b6539d9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -201,6 +201,7 @@ /boards/arm64/fvp_baser_aemv8r/ @povergoing /boards/arm64/fvp_base_revc_2xaemv8a/ @carlocaione /boards/arm64/intel_socfpga_agilex_socdk/ @siclim @ngboonkhai +/boards/arm64/intel_socfpga_agilex5_socdk/ @chongteikheng /boards/Kconfig @tejlmand @galak @nashif @nordicjm # All cmake related files /cmake/ @tejlmand @nashif @@ -246,7 +247,7 @@ /drivers/can/ @alexanderwachter @henrikbrixandersen /drivers/can/*mcp2515* @karstenkoenig /drivers/can/*rcar* @aaillet @pmarzin -/drivers/clock_control/*agilex* @siclim +/drivers/clock_control/*agilex* @siclim @gdengi /drivers/clock_control/*nrf* @nordic-krch /drivers/clock_control/*esp32* @extremegtx @sylvioalves /drivers/clock_control/*cpg_mssr* @aaillet @@ -368,7 +369,8 @@ /drivers/pinctrl/ @gmarull /drivers/pinctrl/*esp32* @sylvioalves /drivers/pinctrl/*it8xxx2* @ite -/drivers/pm_cpu_ops/ @carlocaione +/drivers/pm_cpu_ops/ @carlocaione @gdengi +/drivers/pm_cpu_ops/psci_shell.c @nbalabak @gdengi /drivers/power_domain/ @ceolin /drivers/ps2/ @franciscomunoz @sjvasanth1 /drivers/ps2/*xec* @franciscomunoz @sjvasanth1 @@ -390,6 +392,8 @@ /drivers/regulator/regulator_pca9420.c @danieldegrasse /drivers/regulator/regulator_shell.c @danieldegrasse /drivers/reset/ @andrei-edward-popa +/drivers/reset/reset_intel_socfpga.c @nbalabak +/drivers/reset/Kconfig.intel_socfpga @nbalabak /drivers/sensor/ @MaureenHelm /drivers/sensor/ams_iAQcore/ @alexanderwachter /drivers/sensor/ens210/ @alexanderwachter @@ -405,7 +409,7 @@ /drivers/serial/*b91* @andy-liu-telink /drivers/serial/uart_altera_jtag.c @nashif @gohshunjing /drivers/serial/uart_altera.c @gohshunjing -/drivers/serial/*ns16550* @dcpleung @nashif +/drivers/serial/*ns16550* @dcpleung @nashif @gdengi /drivers/serial/*nrfx* @anangl /drivers/serial/uart_liteuart.c @mateusz-holenko @kgugala @pgielda /drivers/serial/Kconfig.mcux_iuart @Mani-Sadhasivam @@ -584,6 +588,7 @@ /dts/bindings/smbus/ @finikorg /dts/bindings/sip_svc/ @maheshraotm /dts/bindings/cpu/intel,niosv.yaml @sweeaun +/dts/bindings/reset/intel,socfpga-reset.yaml @nbalabak /dts/common/ @galak /include/ @nashif @carlescufi @galak @MaureenHelm /include/zephyr/drivers/*/*litex* @mateusz-holenko @kgugala @pgielda @@ -740,7 +745,7 @@ /samples/subsys/ipc/ipc_service/icmsg @emob-nordic /samples/subsys/logging/ @nordic-krch @jakub-uC /samples/subsys/logging/syst/ @dcpleung -/samples/subsys/shell/ @jakub-uC @nordic-krch +/samples/subsys/shell/ @jakub-uC @nordic-krch @gdengi /samples/subsys/sip_svc/ @maheshraotm /samples/subsys/mgmt/mcumgr/ @de-nordic @nordicjm /samples/subsys/mgmt/updatehub/ @nandojve @otavio From 4ca1d423c791ca711cfa0921bb9fa407c1d22ec9 Mon Sep 17 00:00:00 2001 From: Girisha Dengi Date: Fri, 21 Jul 2023 17:23:21 +0000 Subject: [PATCH 1796/2042] MAINTAINERS: Add self as maintainer for Intel Agilex platform Add maintainer and collaborators for Intel Agilex platforms and related drivers. Signed-off-by: Girisha Dengi --- MAINTAINERS.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 7a28c6ac1492..1588e5536792 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1236,6 +1236,9 @@ Release Notes: status: maintained maintainers: - carlocaione + collaborators: + - gdengi + - nbalabak files: - drivers/pm_cpu_ops/ - include/zephyr/drivers/pm_cpu_ops/ @@ -2289,6 +2292,22 @@ Intel Platforms (Xtensa): labels: - "platform: Intel ADSP" +Intel Platforms (Agilex): + status: maintained + maintainers: + - gdengi + collaborators: + - nbalabak + - chongteikheng + files: + - boards/arm64/intel_*/ + - soc/arm64/intel_*/ + - dts/arm64/intel/ + - samples/boards/intel_adsp/ + - dts/bindings/*/intel,agilex* + labels: + - "platform: Intel SoC FPGA Agilex" + NXP Platforms: status: maintained maintainers: From 5b432ecda42ee9f5c1192d99685356d0c983592b Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 25 Jul 2023 19:52:54 +0200 Subject: [PATCH 1797/2042] MAINTAINERS: fix path for xtensa/riscv esp32 soc The correct paths are soc/xtensa/espressif_esp32 and soc/riscv/espressif_esp32, not soc/xtensa/esp32 and soc/riscv/esp32. Signed-off-by: Bartosz Bilas --- MAINTAINERS.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 1588e5536792..28b378987830 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2479,9 +2479,9 @@ Espressif Platforms: files: - drivers/*/*esp32*.c - boards/xtensa/esp32*/ - - soc/xtensa/esp32*/ + - soc/xtensa/espressif_esp32*/ - boards/riscv/esp32*/ - - soc/riscv/esp32*/ + - soc/riscv/espressif_esp32*/ - dts/xtensa/espressif/ - dts/riscv/espressif/ - dts/bindings/*/*esp32* From 68f514fc38ecfcd51efcb0bd03e052ec1c7d31be Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 25 Jul 2023 18:10:03 +0000 Subject: [PATCH 1798/2042] scripts: compliance: always run the MaintainersFormat check The check currently only runs if the maintainers file itself is changed, but that means that the check is going to miss every PR that moves directory or delete files that can potentially trigger an error. This check is cheap to run, just run it unconditionally. Signed-off-by: Fabio Baltieri --- scripts/ci/check_compliance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index bf96755ecf38..215d91203fbc 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1073,8 +1073,8 @@ class MaintainersFormat(ComplianceTest): def run(self): MAINTAINERS_FILES = ["MAINTAINERS.yml", "MAINTAINERS.yaml"] - for file in get_files(filter="d"): - if file not in MAINTAINERS_FILES: + for file in MAINTAINERS_FILES: + if not os.path.exists(file): continue try: From b489a75403028d5f505a10461d91a30d41e7b449 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 25 Jul 2023 18:14:53 +0000 Subject: [PATCH 1799/2042] MAINTAINERS: fix a bunch of directory paths Fix various incorrect maintainer file entry for directories. These are currently matching files, but would break few scripts if we were to upgrade the CI image to Python 3.11 due to a change in behavior of Path.glob(). Fixes various: MAINTAINERS.yml: glob pattern '...' in 'files' in area '...' does not match any files on machines running Python 3.11 or newer. Link: https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob Signed-off-by: Fabio Baltieri --- MAINTAINERS.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 28b378987830..d37cf5ac4d1c 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2154,7 +2154,6 @@ GD32 Platforms: - boards/arm/gd32*/ - boards/riscv/gd32*/ - boards/riscv/longan_nano/ - - drivers/*/*gd32*/ - drivers/*/*gd32* - dts/*/gigadevice/ - dts/bindings/*/*gd32* @@ -2524,10 +2523,10 @@ TI SimpleLink Platforms: - boards/arm/cc26*/ - boards/arm/cc32*/ - boards/*/msp*/ - - drivers/*/*cc13*/ - - drivers/*/*cc25*/ - - drivers/*/*cc26*/ - - drivers/*/*cc32*/ + - drivers/*/*cc13* + - drivers/*/*cc25* + - drivers/*/*cc26* + - drivers/*/*cc32* - dts/arm/ti/ - dts/bindings/*/ti,* - soc/arm/ti*/ @@ -2544,8 +2543,7 @@ TI K3 Platforms: files: - boards/*/*phycore_am6*/ - boards/*/*ti_am6*/ - - drivers/*/*ti_k3*/ - - dts/*/ti/*ti_am6*/ + - drivers/*/*ti_k3* - dts/bindings/*/ti,k3* - soc/*/ti_k3/ labels: @@ -2576,8 +2574,6 @@ Infineon Platforms: - boards/arm/cy8ckit_*/ - boards/arm/cy8cproto_*/ - boards/arm/xmc*_relax*/ - - drivers/*/*ifx_cat1*/ - - drivers/*/*ifx_cat1*.c - drivers/*/*ifx_cat1* - drivers/*/*xmc*/ - drivers/*/*xmc*.c From 74f73cd535d3ac381498276561ed6e473c7bd8c3 Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 25 Jul 2023 17:59:06 +0800 Subject: [PATCH 1800/2042] arch/common: add 64bit register access functions for 64bit arch Some 64bit arch SoC happens to have 64bit registers. Signed-off-by: Yong Cong Sin --- include/zephyr/arch/common/sys_io.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/zephyr/arch/common/sys_io.h b/include/zephyr/arch/common/sys_io.h index 49f03c2eb55e..482a7d431ae5 100644 --- a/include/zephyr/arch/common/sys_io.h +++ b/include/zephyr/arch/common/sys_io.h @@ -50,6 +50,16 @@ static ALWAYS_INLINE void sys_write32(uint32_t data, mem_addr_t addr) *(volatile uint32_t *)addr = data; } +static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) +{ + return *(volatile uint64_t *)addr; +} + +static ALWAYS_INLINE void sys_write64(uint64_t data, mem_addr_t addr) +{ + *(volatile uint64_t *)addr = data; +} + #ifdef __cplusplus } #endif From 6758777ddf5a29b0cc979bf13f41cca6e066f433 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 14 Jun 2023 09:19:33 +0200 Subject: [PATCH 1801/2042] drivers: crypto: Add NXP MCUX DCP driver Add a shim driver for NXP's Data Co-Processor (DCP) driver. Signed-off-by: Pieter De Gendt --- drivers/crypto/CMakeLists.txt | 1 + drivers/crypto/Kconfig | 1 + drivers/crypto/Kconfig.mcux_dcp | 21 ++ drivers/crypto/crypto_mcux_dcp.c | 351 ++++++++++++++++++++++++++ dts/bindings/crypto/nxp,mcux-dcp.yaml | 12 + 5 files changed, 386 insertions(+) create mode 100644 drivers/crypto/Kconfig.mcux_dcp create mode 100644 drivers/crypto/crypto_mcux_dcp.c create mode 100644 dts/bindings/crypto/nxp,mcux-dcp.yaml diff --git a/drivers/crypto/CMakeLists.txt b/drivers/crypto/CMakeLists.txt index acb9730d2e0a..07eb8a414ec9 100644 --- a/drivers/crypto/CMakeLists.txt +++ b/drivers/crypto/CMakeLists.txt @@ -10,4 +10,5 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_INTEL_SHA crypto_intel_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_NPCX_SHA crypto_npcx_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCHP_XEC_SYMCR crypto_mchp_xec_symcr.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA crypto_it8xxx2_sha.c) +zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCUX_DCP crypto_mcux_dcp.c) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index d5dbf9e26858..c209ed226f79 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -79,5 +79,6 @@ source "drivers/crypto/Kconfig.intel" source "drivers/crypto/Kconfig.npcx" source "drivers/crypto/Kconfig.xec" source "drivers/crypto/Kconfig.it8xxx2" +source "drivers/crypto/Kconfig.mcux_dcp" endif # CRYPTO diff --git a/drivers/crypto/Kconfig.mcux_dcp b/drivers/crypto/Kconfig.mcux_dcp new file mode 100644 index 000000000000..38f725b40928 --- /dev/null +++ b/drivers/crypto/Kconfig.mcux_dcp @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Basalte bv +# SPDX-License-Identifier: Apache-2.0 + +config CRYPTO_MCUX_DCP + bool "NXP Data Co-Processor (DCP) driver" + default y + depends on HAS_MCUX_CACHE + depends on DT_HAS_NXP_MCUX_DCP_ENABLED + select NOCACHE_MEMORY + select CACHE_MANAGEMENT if DCACHE + help + Enable NXP Data Co-Processor (DCP) driver. + +config CRYPTO_MCUX_DCP_MAX_SESSION + int "Maximum number of sessions NXP DCP crypto driver can handle" + range 1 4 + default 2 + depends on CRYPTO_MCUX_DCP + help + This can be used to tweak the amount of sessions the driver + can handle in parallel. diff --git a/drivers/crypto/crypto_mcux_dcp.c b/drivers/crypto/crypto_mcux_dcp.c new file mode 100644 index 000000000000..7419a340b0bf --- /dev/null +++ b/drivers/crypto/crypto_mcux_dcp.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_mcux_dcp + +#include +LOG_MODULE_REGISTER(mcux_dcp, CONFIG_CRYPTO_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include + +#include + +#define CRYPTO_DCP_CIPHER_CAPS (CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS |\ + CAP_SYNC_OPS | CAP_NO_IV_PREFIX) +#define CRYPTO_DCP_HASH_CAPS (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS) + +struct crypto_dcp_session { + dcp_handle_t handle; + dcp_hash_ctx_t hash_ctx; + bool in_use; +}; + +struct crypto_dcp_config { + DCP_Type *base; +}; + +struct crypto_dcp_data { + struct crypto_dcp_session sessions[CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION]; +}; + +/* Helper function to convert common FSL error status codes to errno codes */ +static inline int fsl_to_errno(status_t status) +{ + switch (status) { + case kStatus_Success: + return 0; + case kStatus_InvalidArgument: + return -EINVAL; + case kStatus_Timeout: + return -EAGAIN; + } + + return -1; +} + +static struct crypto_dcp_session *get_session(const struct device *dev) +{ + struct crypto_dcp_data *data = dev->data; + + for (size_t i = 0; i < CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION; ++i) { + if (!data->sessions[i].in_use) { + data->sessions[i].in_use = true; + + return &data->sessions[i]; + } + } + + return NULL; +} + +static inline void free_session(struct crypto_dcp_session *session) +{ + session->in_use = false; +} + +static int crypto_dcp_query_hw_caps(const struct device *dev) +{ + ARG_UNUSED(dev); + + return CRYPTO_DCP_CIPHER_CAPS | CRYPTO_DCP_HASH_CAPS; +} + +static int crypto_dcp_aes_cbc_encrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) +{ + const struct crypto_dcp_config *cfg = ctx->device->config; + struct crypto_dcp_session *session = ctx->drv_sessn_state; + status_t status; + size_t iv_bytes; + uint8_t *p_iv, iv_loc[16]; + + if ((ctx->flags & CAP_NO_IV_PREFIX) == 0U) { + /* Prefix IV to ciphertext, which is default behavior of Zephyr + * crypto API, unless CAP_NO_IV_PREFIX is requested. + */ + iv_bytes = 16U; + memcpy(pkt->out_buf, iv, 16U); + p_iv = iv; + } else { + iv_bytes = 0U; + memcpy(iv_loc, iv, 16U); + p_iv = iv_loc; + } + + sys_cache_data_disable(); + status = DCP_AES_EncryptCbc(cfg->base, &session->handle, pkt->in_buf, + pkt->out_buf + iv_bytes, pkt->in_len, p_iv); + sys_cache_data_enable(); + + if (status != kStatus_Success) { + return fsl_to_errno(status); + } + + pkt->out_len = pkt->in_len + iv_bytes; + + return 0; +} + +static int crypto_dcp_aes_cbc_decrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) +{ + const struct crypto_dcp_config *cfg = ctx->device->config; + struct crypto_dcp_session *session = ctx->drv_sessn_state; + status_t status; + size_t iv_bytes; + uint8_t *p_iv, iv_loc[16]; + + if ((ctx->flags & CAP_NO_IV_PREFIX) == 0U) { + iv_bytes = 16U; + p_iv = iv; + } else { + iv_bytes = 0U; + memcpy(iv_loc, iv, 16U); + p_iv = iv_loc; + } + + sys_cache_data_disable(); + status = DCP_AES_DecryptCbc(cfg->base, &session->handle, pkt->in_buf + iv_bytes, + pkt->out_buf, pkt->in_len, p_iv); + sys_cache_data_enable(); + + if (status != kStatus_Success) { + return fsl_to_errno(status); + } + + pkt->out_len = pkt->in_len - iv_bytes; + + return 0; +} + +static int crypto_dcp_aes_ecb_encrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt) +{ + const struct crypto_dcp_config *cfg = ctx->device->config; + struct crypto_dcp_session *session = ctx->drv_sessn_state; + status_t status; + + sys_cache_data_disable(); + status = DCP_AES_EncryptEcb(cfg->base, &session->handle, pkt->in_buf, pkt->out_buf, + pkt->in_len); + sys_cache_data_enable(); + + if (status != kStatus_Success) { + return fsl_to_errno(status); + } + + pkt->out_len = pkt->in_len; + + return 0; +} + +static int crypto_dcp_aes_ecb_decrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt) +{ + const struct crypto_dcp_config *cfg = ctx->device->config; + struct crypto_dcp_session *session = ctx->drv_sessn_state; + status_t status; + + sys_cache_data_disable(); + status = DCP_AES_DecryptEcb(cfg->base, &session->handle, pkt->in_buf, pkt->out_buf, + pkt->in_len); + sys_cache_data_enable(); + + if (status != kStatus_Success) { + return fsl_to_errno(status); + } + + pkt->out_len = pkt->in_len; + + return 0; +} + +static int crypto_dcp_cipher_begin_session(const struct device *dev, struct cipher_ctx *ctx, + enum cipher_algo algo, enum cipher_mode mode, + enum cipher_op op_type) +{ + const struct crypto_dcp_config *cfg = dev->config; + struct crypto_dcp_session *session; + status_t status; + + if (algo != CRYPTO_CIPHER_ALGO_AES || + (mode != CRYPTO_CIPHER_MODE_CBC && mode != CRYPTO_CIPHER_MODE_ECB)) { + return -ENOTSUP; + } + + if (ctx->flags & ~(CRYPTO_DCP_CIPHER_CAPS)) { + return -ENOTSUP; + } + + session = get_session(dev); + if (session == NULL) { + return -ENOSPC; + } + + if (mode == CRYPTO_CIPHER_MODE_CBC) { + if (op_type == CRYPTO_CIPHER_OP_DECRYPT) { + ctx->ops.cbc_crypt_hndlr = crypto_dcp_aes_cbc_decrypt; + } else { + ctx->ops.cbc_crypt_hndlr = crypto_dcp_aes_cbc_encrypt; + } + } else { + if (op_type == CRYPTO_CIPHER_OP_DECRYPT) { + ctx->ops.block_crypt_hndlr = crypto_dcp_aes_ecb_decrypt; + } else { + ctx->ops.block_crypt_hndlr = crypto_dcp_aes_ecb_encrypt; + } + } + + ctx->drv_sessn_state = session; + + status = DCP_AES_SetKey(cfg->base, &session->handle, ctx->key.bit_stream, ctx->keylen); + if (status != kStatus_Success) { + free_session(session); + return fsl_to_errno(status); + } + + return 0; +} + +static int crypto_dcp_cipher_free_session(const struct device *dev, struct cipher_ctx *ctx) +{ + struct crypto_dcp_session *session; + + ARG_UNUSED(dev); + + session = ctx->drv_sessn_state; + free_session(session); + + return 0; +} + +static int crypto_dcp_sha256(struct hash_ctx *ctx, struct hash_pkt *pkt, bool finish) +{ + const struct crypto_dcp_config *cfg = ctx->device->config; + struct crypto_dcp_session *session = ctx->drv_sessn_state; + status_t status; + + sys_cache_data_disable(); + status = DCP_HASH_Update(cfg->base, &session->hash_ctx, pkt->in_buf, pkt->in_len); + sys_cache_data_enable(); + + if (status != kStatus_Success) { + return fsl_to_errno(status); + } + + if (finish) { + sys_cache_data_disable(); + status = DCP_HASH_Finish(cfg->base, &session->hash_ctx, pkt->out_buf, NULL); + sys_cache_data_enable(); + } + + return fsl_to_errno(status); +} + +static int crypto_dcp_hash_begin_session(const struct device *dev, struct hash_ctx *ctx, + enum hash_algo algo) +{ + const struct crypto_dcp_config *cfg = dev->config; + struct crypto_dcp_session *session; + status_t status; + + if (algo != CRYPTO_HASH_ALGO_SHA256) { + return -ENOTSUP; + } + + if (ctx->flags & ~(CRYPTO_DCP_HASH_CAPS)) { + return -ENOTSUP; + } + + session = get_session(dev); + if (session == NULL) { + return -ENOSPC; + } + + status = DCP_HASH_Init(cfg->base, &session->handle, &session->hash_ctx, kDCP_Sha256); + if (status != kStatus_Success) { + free_session(session); + return fsl_to_errno(status); + } + + ctx->drv_sessn_state = session; + ctx->hash_hndlr = crypto_dcp_sha256; + + return 0; +} + +static int crypto_dcp_hash_free_session(const struct device *dev, struct hash_ctx *ctx) +{ + struct crypto_dcp_session *session; + + ARG_UNUSED(dev); + + session = ctx->drv_sessn_state; + free_session(session); + + return 0; +} + +static int crypto_dcp_init(const struct device *dev) +{ + const struct crypto_dcp_config *cfg = dev->config; + struct crypto_dcp_data *data = dev->data; + dcp_config_t hal_cfg; + + DCP_GetDefaultConfig(&hal_cfg); + + DCP_Init(cfg->base, &hal_cfg); + + /* Assign unique channels/key slots to each session */ + for (size_t i = 0; i < CONFIG_CRYPTO_MCUX_DCP_MAX_SESSION; ++i) { + data->sessions[i].in_use = false; + data->sessions[i].handle.channel = kDCP_Channel0 << i; + data->sessions[i].handle.keySlot = kDCP_KeySlot0 + i; + data->sessions[i].handle.swapConfig = kDCP_NoSwap; + } + + return 0; +} + +static struct crypto_driver_api crypto_dcp_api = { + .query_hw_caps = crypto_dcp_query_hw_caps, + .cipher_begin_session = crypto_dcp_cipher_begin_session, + .cipher_free_session = crypto_dcp_cipher_free_session, + .hash_begin_session = crypto_dcp_hash_begin_session, + .hash_free_session = crypto_dcp_hash_free_session, +}; + +#define CRYPTO_DCP_DEFINE(inst) \ + static const struct crypto_dcp_config crypto_dcp_config_##inst = { \ + .base = (DCP_Type *)DT_INST_REG_ADDR(inst), \ + }; \ + static struct crypto_dcp_data crypto_dcp_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, crypto_dcp_init, NULL, \ + &crypto_dcp_data_##inst, &crypto_dcp_config_##inst, \ + POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, &crypto_dcp_api); + +DT_INST_FOREACH_STATUS_OKAY(CRYPTO_DCP_DEFINE) diff --git a/dts/bindings/crypto/nxp,mcux-dcp.yaml b/dts/bindings/crypto/nxp,mcux-dcp.yaml new file mode 100644 index 000000000000..de6fcf652663 --- /dev/null +++ b/dts/bindings/crypto/nxp,mcux-dcp.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2023, Basalte bv +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Data Co-Processor (DCP) Crypto accelerator. + +compatible: "nxp,mcux-dcp" + +include: base.yaml + +properties: + reg: + required: true From 80f4a1290038dfcc95b20219d141e8e09b3330c8 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 14 Jun 2023 09:20:50 +0200 Subject: [PATCH 1802/2042] dts: arm: nxp: Enable DCP for i.MX RT10XX SoC Add device tree entry for DCP driver support on i.MX RT10XX platforms. Signed-off-by: Pieter De Gendt --- dts/arm/nxp/nxp_rt10xx.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 46b6aeac2b2d..d817c644f8dd 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -1066,6 +1066,13 @@ reg = <0x403c4000 0x4000>; status = "disabled"; }; + + dcp: dcp@402fc000 { + compatible = "nxp,mcux-dcp"; + reg = <0x402fc000 0x4000>; + interrupts = <50 0>, <51 0>; + status = "okay"; + }; }; }; From 16f34e969b9fef7912cf2b7c4d4d3a43c6e3f08b Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 14 Jun 2023 11:15:53 +0200 Subject: [PATCH 1803/2042] samples: drivers: crypto: Simplify configuration Use a default prj.conf to be used for all samples and use EXTRA_CONF_FILE for specifics. Signed-off-by: Pieter De Gendt --- samples/drivers/crypto/prj.conf | 8 ++------ samples/drivers/crypto/prj_mtls_shim.conf | 5 ----- samples/drivers/crypto/prj_nrf_ecb.conf | 4 ---- samples/drivers/crypto/prj_stm32.conf | 5 ----- samples/drivers/crypto/prj_tinycrypt_shim.conf | 6 ++++++ samples/drivers/crypto/sample.yaml | 10 +++++----- 6 files changed, 13 insertions(+), 25 deletions(-) delete mode 100644 samples/drivers/crypto/prj_nrf_ecb.conf delete mode 100644 samples/drivers/crypto/prj_stm32.conf create mode 100644 samples/drivers/crypto/prj_tinycrypt_shim.conf diff --git a/samples/drivers/crypto/prj.conf b/samples/drivers/crypto/prj.conf index 6735f0ed6398..997396aa8a43 100644 --- a/samples/drivers/crypto/prj.conf +++ b/samples/drivers/crypto/prj.conf @@ -1,10 +1,6 @@ -CONFIG_TINYCRYPT=y -CONFIG_TINYCRYPT_AES=y -CONFIG_TINYCRYPT_AES_CBC=y -CONFIG_TINYCRYPT_AES_CTR=y -CONFIG_TINYCRYPT_AES_CCM=y CONFIG_CRYPTO=y -CONFIG_CRYPTO_TINYCRYPT_SHIM=y CONFIG_CRYPTO_LOG_LEVEL_DBG=y CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y + +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/drivers/crypto/prj_mtls_shim.conf b/samples/drivers/crypto/prj_mtls_shim.conf index c21bc00b258a..c72b663fcf5f 100644 --- a/samples/drivers/crypto/prj_mtls_shim.conf +++ b/samples/drivers/crypto/prj_mtls_shim.conf @@ -1,12 +1,7 @@ -CONFIG_LOG=y -CONFIG_LOG_MODE_MINIMAL=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_HEAP_SIZE=512 CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y CONFIG_MBEDTLS_CIPHER_GCM_ENABLED=y -CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_CRYPTO=y CONFIG_CRYPTO_MBEDTLS_SHIM=y -CONFIG_CRYPTO_LOG_LEVEL_DBG=y diff --git a/samples/drivers/crypto/prj_nrf_ecb.conf b/samples/drivers/crypto/prj_nrf_ecb.conf deleted file mode 100644 index d2d8b9e842f6..000000000000 --- a/samples/drivers/crypto/prj_nrf_ecb.conf +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_LOG=y -CONFIG_LOG_MODE_MINIMAL=y -CONFIG_CRYPTO=y -CONFIG_CRYPTO_LOG_LEVEL_DBG=y diff --git a/samples/drivers/crypto/prj_stm32.conf b/samples/drivers/crypto/prj_stm32.conf deleted file mode 100644 index e22717613b07..000000000000 --- a/samples/drivers/crypto/prj_stm32.conf +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG_LOG=y -CONFIG_MAIN_STACK_SIZE=4096 - -CONFIG_CRYPTO=y -CONFIG_CRYPTO_LOG_LEVEL_DBG=y diff --git a/samples/drivers/crypto/prj_tinycrypt_shim.conf b/samples/drivers/crypto/prj_tinycrypt_shim.conf new file mode 100644 index 000000000000..752c33a9cfc1 --- /dev/null +++ b/samples/drivers/crypto/prj_tinycrypt_shim.conf @@ -0,0 +1,6 @@ +CONFIG_TINYCRYPT=y +CONFIG_TINYCRYPT_AES=y +CONFIG_TINYCRYPT_AES_CBC=y +CONFIG_TINYCRYPT_AES_CTR=y +CONFIG_TINYCRYPT_AES_CCM=y +CONFIG_CRYPTO_TINYCRYPT_SHIM=y diff --git a/samples/drivers/crypto/sample.yaml b/samples/drivers/crypto/sample.yaml index 9712990b4d92..0554962c4ca3 100644 --- a/samples/drivers/crypto/sample.yaml +++ b/samples/drivers/crypto/sample.yaml @@ -7,10 +7,10 @@ common: min_ram: 20 arch_exclude: xtensa tests: - sample.drivers.crypto.mbedtls: + sample.drivers.crypto.tinycrypt: min_flash: 34 harness: console - extra_args: CONF_FILE=prj_mtls_shim.conf + extra_args: EXTRA_CONF_FILE=prj_tinycrypt_shim.conf integration_platforms: - native_posix harness_config: @@ -21,9 +21,10 @@ tests: - ".*: CTR Mode" - ".*: CCM Mode" - ".*: GCM Mode" - sample.drivers.crypto.mbedtls.micro: - tags: crypto + sample.drivers.crypto.mbedtls: + min_flash: 34 harness: console + extra_args: EXTRA_CONF_FILE=prj_mtls_shim.conf integration_platforms: - native_posix harness_config: @@ -37,7 +38,6 @@ tests: sample.drivers.crypto.stm32: tags: crypto filter: dt_compat_enabled("st,stm32-aes") or dt_compat_enabled("st,stm32-cryp") - extra_args: CONF_FILE=prj_stm32.conf integration_platforms: - stm32l562e_dk harness: console From e1e19732bcdd00b55c5a7987580011eae0b640ee Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 14 Jun 2023 11:46:45 +0200 Subject: [PATCH 1804/2042] samples: drivers: crypto: Aligned AES key Some drivers require the encryption key to be 4-byte aligned. Signed-off-by: Pieter De Gendt --- samples/drivers/crypto/src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/drivers/crypto/src/main.c b/samples/drivers/crypto/src/main.c index 139df5d63e7c..4dcf230ee13b 100644 --- a/samples/drivers/crypto/src/main.c +++ b/samples/drivers/crypto/src/main.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(main); #error "You need to enable one crypto device" #endif -static uint8_t key[16] = { +static uint8_t key[16] __aligned(32) = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; From 8cbb6c8a0c871210e4e91d9d0a0e76c873150be4 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Wed, 14 Jun 2023 09:22:11 +0200 Subject: [PATCH 1805/2042] samples: drivers: crypto: Add testcase for NXP MCUX DCP Add a testcase for mimxrt1064_evk to be able to run the crypto sample. Signed-off-by: Pieter De Gendt --- samples/drivers/crypto/sample.yaml | 14 ++++++++++++++ samples/drivers/crypto/src/main.c | 2 ++ 2 files changed, 16 insertions(+) diff --git a/samples/drivers/crypto/sample.yaml b/samples/drivers/crypto/sample.yaml index 0554962c4ca3..d63e7a4a68ab 100644 --- a/samples/drivers/crypto/sample.yaml +++ b/samples/drivers/crypto/sample.yaml @@ -51,3 +51,17 @@ tests: - ".*: CBC mode DECRYPT - Match" - ".*: CTR mode ENCRYPT - Match" - ".*: CTR mode DECRYPT - Match" + sample.drivers.crypto.mcux_dcp: + tags: crypto + filter: dt_compat_enabled("nxp,mcux-dcp") + integration_platforms: + - mimxrt1064_evk + harness: console + harness_config: + type: multi_line + regex: + - ".*: Cipher Sample" + - ".*: ECB mode ENCRYPT - Match" + - ".*: ECB mode DECRYPT - Match" + - ".*: CBC mode ENCRYPT - Match" + - ".*: CBC mode DECRYPT - Match" diff --git a/samples/drivers/crypto/src/main.c b/samples/drivers/crypto/src/main.c index 4dcf230ee13b..9be044bdf2c6 100644 --- a/samples/drivers/crypto/src/main.c +++ b/samples/drivers/crypto/src/main.c @@ -25,6 +25,8 @@ LOG_MODULE_REGISTER(main); #define CRYPTO_DEV_COMPAT st_stm32_cryp #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_aes) #define CRYPTO_DEV_COMPAT st_stm32_aes +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_mcux_dcp) +#define CRYPTO_DEV_COMPAT nxp_mcux_dcp #elif CONFIG_CRYPTO_NRF_ECB #define CRYPTO_DEV_COMPAT nordic_nrf_ecb #else From f4a1d40924d49b0d9287972ec6cda43d46b5031b Mon Sep 17 00:00:00 2001 From: Pavlo Havrylyuk Date: Mon, 24 Jul 2023 07:59:05 -0700 Subject: [PATCH 1806/2042] drivers: counter: Add Infineon CAT1 counter driver Add initial version of Infineon CAT1 counter driver Add initial version of binding file for Infineon Add counters to psco6 dtsi Add external trigger pin that runs counter Signed-off-by: Pavlo Havrylyuk --- .../cy8cproto_062_4343w.dts | 4 + .../cy8cproto_062_4343w.yaml | 1 + drivers/counter/CMakeLists.txt | 1 + drivers/counter/Kconfig | 2 + drivers/counter/Kconfig.ifx_cat1 | 13 + drivers/counter/counter_ifx_cat1.c | 534 ++++++++++++++++++ dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi | 225 ++++++++ dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi | 224 ++++++++ .../counter/infineon,cat1-counter.yaml | 27 + .../dt-bindings/pinctrl/ifx_cat1-pinctrl.h | 16 +- samples/drivers/counter/alarm/src/main.c | 2 + .../counter_basic_api/src/test_counter.c | 3 + 12 files changed, 1048 insertions(+), 4 deletions(-) create mode 100644 drivers/counter/Kconfig.ifx_cat1 create mode 100644 drivers/counter/counter_ifx_cat1.c create mode 100644 dts/bindings/counter/infineon,cat1-counter.yaml diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts index 9c2ba3b345c0..5ad82d742a6a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.dts @@ -28,6 +28,10 @@ }; }; +&counter0_0 { + status = "okay"; +}; + uart5: &scb5 { compatible = "infineon,cat1-uart"; status = "okay"; diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index 99a36b1a24ea..0989469474ef 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -14,6 +14,7 @@ toolchain: - gnuarmemb supported: - adc + - counter - gpio - uart - i2c diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index ffd5068bc93f..7b7c40d46f4d 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -39,6 +39,7 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_RTC_ESP32 counter_esp32_rt zephyr_library_sources_ifdef(CONFIG_COUNTER_SMARTBOND_TIMER counter_smartbond_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MICROCHIP_MCP7940N rtc_mcp7940n.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_ANDES_ATCPIT100 counter_andes_atcpit100.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_INFINEON_CAT1 counter_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_ACE_V1X_ART_COUNTER counter_ace_v1x_art.c) zephyr_library_sources_ifdef(CONFIG_ACE_V1X_RTC_COUNTER counter_ace_v1x_rtc.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_NXP_S32_SYS_TIMER counter_nxp_s32_sys_timer.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index ad29553a7be6..f0060813775c 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -74,6 +74,8 @@ source "drivers/counter/Kconfig.mcp7940n" source "drivers/counter/Kconfig.mcux_ctimer" +source "drivers/counter/Kconfig.ifx_cat1" + source "drivers/counter/Kconfig.andes_atcpit100" source "drivers/counter/Kconfig.nxp_s32" diff --git a/drivers/counter/Kconfig.ifx_cat1 b/drivers/counter/Kconfig.ifx_cat1 new file mode 100644 index 000000000000..4090911dcdb6 --- /dev/null +++ b/drivers/counter/Kconfig.ifx_cat1 @@ -0,0 +1,13 @@ +# Infineon CAT1 counter driver + +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_INFINEON_CAT1 + bool "Infineon CAT1 COUNTER driver" + default y + depends on DT_HAS_INFINEON_CAT1_COUNTER_ENABLED + select USE_INFINEON_TIMER + help + This option enables the COUNTER driver for Infineon CAT1 family. diff --git a/drivers/counter/counter_ifx_cat1.c b/drivers/counter/counter_ifx_cat1.c new file mode 100644 index 000000000000..9b8f3069673b --- /dev/null +++ b/drivers/counter/counter_ifx_cat1.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Counter driver for Infineon CAT1 MCU family. + */ + +#define DT_DRV_COMPAT infineon_cat1_counter + +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(ifx_cat1_counter, CONFIG_COUNTER_LOG_LEVEL); + +struct ifx_cat1_counter_config { + struct counter_config_info counter_info; + TCPWM_CNT_Type *reg_addr; + cyhal_gpio_t external_pin; + IRQn_Type irqn; + uint8_t irq_priority; +}; + +struct ifx_cat1_counter_data { + cyhal_timer_t counter_obj; + cyhal_timer_cfg_t counter_cfg; + struct counter_alarm_cfg alarm_cfg_counter; + struct counter_top_cfg top_value_cfg_counter; + uint32_t guard_period; + cyhal_resource_inst_t hw_resource; + cyhal_source_t signal_source; + bool alarm_irq_flag; +}; + +static const cy_stc_tcpwm_counter_config_t cyhal_timer_default_config = { + .period = 32768, + .clockPrescaler = CY_TCPWM_COUNTER_PRESCALER_DIVBY_1, + .runMode = CY_TCPWM_COUNTER_CONTINUOUS, + .countDirection = CY_TCPWM_COUNTER_COUNT_UP, + .compareOrCapture = CY_TCPWM_COUNTER_MODE_CAPTURE, + .compare0 = 16384, + .compare1 = 16384, + .enableCompareSwap = false, + .interruptSources = CY_TCPWM_INT_NONE, + .captureInputMode = 0x3U, + .captureInput = CY_TCPWM_INPUT_0, + .reloadInputMode = 0x3U, + .reloadInput = CY_TCPWM_INPUT_0, + .startInputMode = 0x3U, + .startInput = CY_TCPWM_INPUT_0, + .stopInputMode = 0x3U, + .stopInput = CY_TCPWM_INPUT_0, + .countInputMode = 0x3U, + .countInput = CY_TCPWM_INPUT_1, +}; + +static int get_hw_block_info(TCPWM_CNT_Type *reg_addr, cyhal_resource_inst_t *hw_resource) +{ + uint32_t i; + + for (i = 0u; i < _CYHAL_TCPWM_INSTANCES; i++) { + uintptr_t base = POINTER_TO_UINT(_CYHAL_TCPWM_DATA[i].base); + uintptr_t cnt = POINTER_TO_UINT(_CYHAL_TCPWM_DATA[i].base->CNT); + uintptr_t reg_addr_ptr = POINTER_TO_UINT(reg_addr); + uintptr_t end_addr = base + sizeof(TCPWM_Type); + + if ((reg_addr_ptr > base) && (reg_addr_ptr < end_addr)) { + + hw_resource->type = CYHAL_RSC_TCPWM; + hw_resource->block_num = i; + hw_resource->channel_num = ((reg_addr_ptr - cnt) / sizeof(TCPWM_CNT_Type)); + + if (hw_resource->channel_num >= _CYHAL_TCPWM_DATA[i].num_channels) { + return -EINVAL; + } + return 0; + } + } + return -EINVAL; +} + +static void ifx_cat1_counter_event_callback(void *callback_arg, cyhal_timer_event_t event) +{ + const struct device *dev = (const struct device *) callback_arg; + struct ifx_cat1_counter_data *const data = dev->data; + const struct ifx_cat1_counter_config *const config = dev->config; + + /* Alarm compare/capture event */ + if ((data->alarm_cfg_counter.callback != NULL) && + (((CYHAL_TIMER_IRQ_CAPTURE_COMPARE & event) == CYHAL_TIMER_IRQ_CAPTURE_COMPARE) || + data->alarm_irq_flag)) { + /* Alarm works as one-shot, so disable event */ + cyhal_timer_enable_event(&data->counter_obj, + CYHAL_TIMER_IRQ_CAPTURE_COMPARE, + config->irq_priority, false); + + /* Call User callback for Alarm */ + data->alarm_cfg_counter.callback(dev, 1, cyhal_timer_read(&data->counter_obj), + data->alarm_cfg_counter.user_data); + data->alarm_irq_flag = false; + } + + /* Top_value terminal count event */ + if ((data->top_value_cfg_counter.callback != NULL) && + ((CYHAL_TIMER_IRQ_TERMINAL_COUNT & event) == CYHAL_TIMER_IRQ_TERMINAL_COUNT)) { + + /* Call User callback for top value */ + data->top_value_cfg_counter.callback(dev, data->top_value_cfg_counter.user_data); + } + + /* NOTE: cyhal handles cleaning of interrupts */ +} + +static void ifx_cat1_counter_set_int_pending(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + const struct ifx_cat1_counter_config *const config = dev->config; + + cyhal_timer_enable_event(&data->counter_obj, CYHAL_TIMER_IRQ_CAPTURE_COMPARE, + config->irq_priority, true); + Cy_TCPWM_SetInterrupt(data->counter_obj.tcpwm.base, + _CYHAL_TCPWM_CNT_NUMBER(data->counter_obj.tcpwm.resource), + CY_TCPWM_INT_ON_CC0); +} + +static int ifx_cat1_counter_init(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + cy_rslt_t rslt; + struct ifx_cat1_counter_data *data = dev->data; + const struct ifx_cat1_counter_config *config = dev->config; + + /* Dedicate Counter HW resource */ + if (get_hw_block_info(config->reg_addr, &data->hw_resource) != 0) { + return -EIO; + } + + cyhal_timer_configurator_t timer_configurator = { + .resource = &data->hw_resource, + .config = &cyhal_timer_default_config, + }; + + /* Initialize timer */ + rslt = cyhal_timer_init_cfg(&data->counter_obj, &timer_configurator); + if (rslt != CY_RSLT_SUCCESS) { + return -EIO; + } + + /* Initialize counter structure */ + data->alarm_irq_flag = false; + data->counter_cfg.compare_value = 0; + data->counter_cfg.period = config->counter_info.max_top_value; + data->counter_cfg.direction = CYHAL_TIMER_DIR_UP; + data->counter_cfg.is_compare = true; + data->counter_cfg.is_continuous = true; + data->counter_cfg.value = 0; + + /* Configure timer */ + rslt = cyhal_timer_configure(&data->counter_obj, &data->counter_cfg); + if (rslt != CY_RSLT_SUCCESS) { + return -EIO; + } + + if (config->external_pin == NC) { + /* Configure frequency */ + rslt = cyhal_timer_set_frequency(&data->counter_obj, config->counter_info.freq); + if (rslt != CY_RSLT_SUCCESS) { + return -EIO; + } + } else { + rslt = cyhal_gpio_init(config->external_pin, CYHAL_GPIO_DIR_INPUT, + CYHAL_GPIO_DRIVE_NONE, 0); + if (rslt != CY_RSLT_SUCCESS) { + LOG_ERR("External pin configuration error"); + return -EIO; + } + + rslt = cyhal_gpio_enable_output(config->external_pin, CYHAL_SIGNAL_TYPE_EDGE, + (cyhal_source_t *)&data->signal_source); + if (rslt != CY_RSLT_SUCCESS) { + if (rslt != CY_RSLT_SUCCESS) { + LOG_ERR("error in the enabling of Counter input pin output"); + return -EIO; + } + } + + rslt = cyhal_timer_connect_digital(&data->counter_obj, data->signal_source, + CYHAL_TIMER_INPUT_COUNT); + if (rslt != CY_RSLT_SUCCESS) { + LOG_ERR("Error connecting signal source"); + return -EIO; + } + } + + /* Register timer event callback */ + cyhal_timer_register_callback(&data->counter_obj, + ifx_cat1_counter_event_callback, + (void *) dev); + + return 0; +} + +static int ifx_cat1_counter_start(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + + if (cyhal_timer_start(&data->counter_obj) != CY_RSLT_SUCCESS) { + return -EIO; + } + return 0; +} + +static int ifx_cat1_counter_stop(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + + if (cyhal_timer_stop(&data->counter_obj) != CY_RSLT_SUCCESS) { + return -EIO; + } + return 0; +} + +static int ifx_cat1_counter_get_value(const struct device *dev, uint32_t *ticks) +{ + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(ticks != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + + *ticks = cyhal_timer_read(&data->counter_obj); + + return 0; +} + +static int ifx_cat1_counter_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(cfg != NULL); + + cy_rslt_t rslt; + struct ifx_cat1_counter_data *const data = dev->data; + const struct ifx_cat1_counter_config *const config = dev->config; + bool ticks_gt_period; + + data->top_value_cfg_counter = *cfg; + data->counter_cfg.period = cfg->ticks; + + /* Check new top value limit */ + if (cfg->ticks > config->counter_info.max_top_value) { + return -ENOTSUP; + } + + ticks_gt_period = cfg->ticks > data->counter_cfg.period; + /* Checks if new period value is not less then old period value */ + if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { + data->counter_cfg.value = 0u; + } else if (ticks_gt_period && (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE)) { + data->counter_cfg.value = 0u; + } else { + /* cyhal_timer_configure resets timer counter register to value + * defined in config structure 'counter_cfg.value', so update + * counter value with current value of counter (read by + * cyhal_timer_read function). + */ + data->counter_cfg.value = cyhal_timer_read(&data->counter_obj); + } + + if ((ticks_gt_period == false) || + ((ticks_gt_period == true) && (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE))) { + + /* Reconfigure timer */ + if (config->external_pin == NC) { + rslt = cyhal_timer_configure(&data->counter_obj, &data->counter_cfg); + if (rslt != CY_RSLT_SUCCESS) { + return -EIO; + } + } else { + TCPWM_CNT_PERIOD(data->counter_obj.tcpwm.base, _CYHAL_TCPWM_CNT_NUMBER( + data->counter_obj.tcpwm.resource)) = cfg->ticks; + } + + /* Register an top_value terminal count event callback handler if + * callback is not NULL. + */ + if (cfg->callback != NULL) { + cyhal_timer_enable_event(&data->counter_obj, CYHAL_TIMER_IRQ_TERMINAL_COUNT, + config->irq_priority, true); + } + } + return 0; +} + + +static uint32_t ifx_cat1_counter_get_top_value(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + + return data->counter_cfg.period; +} + +static inline bool counter_is_bit_mask(uint32_t val) +{ + /* Return true if value equals 2^n - 1 */ + return !(val & (val + 1U)); +} + +static uint32_t ifx_cat1_counter_ticks_add(uint32_t val1, uint32_t val2, uint32_t top) +{ + uint32_t to_top; + + /* refer to https://tbrindus.ca/how-builtin-expect-works/ for 'likely' usage */ + if (likely(counter_is_bit_mask(top))) { + return (val1 + val2) & top; + } + + to_top = top - val1; + + return (val2 <= to_top) ? (val1 + val2) : (val2 - to_top - 1U); +} + +static uint32_t ifx_cat1_counter_ticks_sub(uint32_t val, uint32_t old, uint32_t top) +{ + /* refer to https://tbrindus.ca/how-builtin-expect-works/ for 'likely' usage */ + if (likely(counter_is_bit_mask(top))) { + return (val - old) & top; + } + + /* if top is not 2^n-1 */ + return (val >= old) ? (val - old) : (val + top + 1U - old); +} + +static int ifx_cat1_counter_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + ARG_UNUSED(chan_id); + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(alarm_cfg != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + const struct ifx_cat1_counter_config *const config = dev->config; + + uint32_t val = alarm_cfg->ticks; + uint32_t top_val = ifx_cat1_counter_get_top_value(dev); + uint32_t flags = alarm_cfg->flags; + uint32_t max_rel_val; + bool absolute = ((flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) ? false : true; + bool irq_on_late; + + /* Checks if compare value is not less then period value */ + if (alarm_cfg->ticks > top_val) { + return -EINVAL; + } + + if (absolute) { + max_rel_val = top_val - data->guard_period; + irq_on_late = ((flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE) == 0) ? false : true; + } else { + /* If relative value is smaller than half of the counter range it is assumed + * that there is a risk of setting value too late and late detection algorithm + * must be applied. When late setting is detected, interrupt shall be + * triggered for immediate expiration of the timer. Detection is performed + * by limiting relative distance between CC and counter. + * + * Note that half of counter range is an arbitrary value. + */ + irq_on_late = val < (top_val / 2U); + + /* limit max to detect short relative being set too late. */ + max_rel_val = irq_on_late ? (top_val / 2U) : top_val; + val = ifx_cat1_counter_ticks_add(cyhal_timer_read(&data->counter_obj), + val, top_val); + } + + /* Decrement value to detect also case when val == counter_read(dev). Otherwise, + * condition would need to include comparing diff against 0. + */ + uint32_t curr = cyhal_timer_read(&data->counter_obj); + uint32_t diff = ifx_cat1_counter_ticks_sub((val - 1), curr, top_val); + + /* Interrupt is triggered always for relative alarm and for absolute depending + * on the flag. + */ + if (irq_on_late) { + data->alarm_irq_flag = true; + ifx_cat1_counter_set_int_pending(dev); + } + + if ((absolute && (val < curr)) || (diff > max_rel_val)) { + if (absolute) { + return -ETIME; + } + } else { + /* Setting new compare value */ + cy_rslt_t rslt; + + data->alarm_cfg_counter = *alarm_cfg; + data->counter_cfg.compare_value = val; + + /* cyhal_timer_configure resets timer counter register to value + * defined in config structure 'counter_cfg.value', so update + * counter value with current value of counter (read by + * cyhal_timer_read function). + */ + data->counter_cfg.value = cyhal_timer_read(&data->counter_obj); + + /* Reconfigure timer */ + if (config->external_pin == NC) { + rslt = cyhal_timer_configure(&data->counter_obj, &data->counter_cfg); + if (rslt != CY_RSLT_SUCCESS) { + return -EINVAL; + } + } else { + TCPWM_CNT_CC(data->counter_obj.tcpwm.base, + _CYHAL_TCPWM_CNT_NUMBER(data->counter_obj.tcpwm.resource)) = + data->counter_cfg.compare_value; + } + + cyhal_timer_enable_event(&data->counter_obj, + CYHAL_TIMER_IRQ_CAPTURE_COMPARE, + config->irq_priority, true); + } + + return 0; +} + +static int ifx_cat1_counter_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + ARG_UNUSED(chan_id); + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + const struct ifx_cat1_counter_config *const config = dev->config; + + cyhal_timer_enable_event(&data->counter_obj, CYHAL_TIMER_IRQ_CAPTURE_COMPARE, + config->irq_priority, false); + return 0; +} + +static uint32_t ifx_cat1_counter_get_pending_int(const struct device *dev) +{ + __ASSERT_NO_MSG(dev != NULL); + + const struct ifx_cat1_counter_config *const config = dev->config; + + return NVIC_GetPendingIRQ(config->irqn); +} + +static uint32_t ifx_cat1_counter_get_guard_period(const struct device *dev, uint32_t flags) +{ + ARG_UNUSED(flags); + __ASSERT_NO_MSG(dev != NULL); + + struct ifx_cat1_counter_data *const data = dev->data; + + return data->guard_period; +} + +static int ifx_cat1_counter_set_guard_period(const struct device *dev, uint32_t guard, + uint32_t flags) +{ + ARG_UNUSED(flags); + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(guard < ifx_cat1_counter_get_top_value(dev)); + + struct ifx_cat1_counter_data *const data = dev->data; + + data->guard_period = guard; + return 0; +} + +static const struct counter_driver_api counter_api = { + .start = ifx_cat1_counter_start, + .stop = ifx_cat1_counter_stop, + .get_value = ifx_cat1_counter_get_value, + .set_alarm = ifx_cat1_counter_set_alarm, + .cancel_alarm = ifx_cat1_counter_cancel_alarm, + .set_top_value = ifx_cat1_counter_set_top_value, + .get_pending_int = ifx_cat1_counter_get_pending_int, + .get_top_value = ifx_cat1_counter_get_top_value, + .get_guard_period = ifx_cat1_counter_get_guard_period, + .set_guard_period = ifx_cat1_counter_set_guard_period, +}; + +#define DT_INST_GET_CYHAL_GPIO_OR(inst, gpios_prop, default) \ + COND_CODE_1( \ + DT_INST_NODE_HAS_PROP(inst, gpios_prop), \ + (DT_GET_CYHAL_GPIO_FROM_DT_GPIOS( \ + DT_INST(inst, DT_DRV_COMPAT), gpios_prop)), (default)) + +/* Counter driver init macros */ +#define INFINEON_CAT1_COUNTER_INIT(n) \ + \ + static struct ifx_cat1_counter_data ifx_cat1_counter##n##_data; \ + \ + static const struct ifx_cat1_counter_config ifx_cat1_counter##n##_config = { \ + .counter_info = { \ + .max_top_value = (DT_INST_PROP(n, resolution) == 32) \ + ? UINT32_MAX : UINT16_MAX, \ + .freq = DT_INST_PROP_OR(n, clock_frequency, 10000), \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + .channels = 1 \ + }, \ + .reg_addr = (TCPWM_CNT_Type *)DT_INST_REG_ADDR(n), \ + .irq_priority = DT_INST_IRQ(n, priority), \ + .irqn = DT_INST_IRQN(n), \ + .external_pin = (cyhal_gpio_t) \ + DT_INST_GET_CYHAL_GPIO_OR(n, external_trigger_gpios, NC) \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + ifx_cat1_counter_init, \ + NULL, &ifx_cat1_counter##n##_data, \ + &ifx_cat1_counter##n##_config, PRE_KERNEL_1, \ + CONFIG_COUNTER_INIT_PRIORITY, &counter_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_COUNTER_INIT); diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi index 382f6043b910..0a97178cfad2 100644 --- a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi @@ -311,5 +311,230 @@ interrupts = <24 1>; status = "disabled"; }; + + counter0_0: counter@40380100 { + compatible = "infineon,cat1-counter"; + reg = <0x40380100 0x40>; + interrupts = <90 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_1: counter@40380140 { + compatible = "infineon,cat1-counter"; + reg = <0x40380140 0x40>; + interrupts = <91 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_2: counter@40380180 { + compatible = "infineon,cat1-counter"; + reg = <0x40380180 0x40>; + interrupts = <92 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_3: counter@403801c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403801c0 0x40>; + interrupts = <93 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_4: counter@40380200 { + compatible = "infineon,cat1-counter"; + reg = <0x40380200 0x40>; + interrupts = <94 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_5: counter@40380240 { + compatible = "infineon,cat1-counter"; + reg = <0x40380240 0x40>; + interrupts = <95 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_6: counter@40380280 { + compatible = "infineon,cat1-counter"; + reg = <0x40380280 0x40>; + interrupts = <96 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_7: counter@403802c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403802c0 0x40>; + interrupts = <97 6>; + resolution = <32>; + status = "disabled"; + }; + counter1_0: counter@40390100 { + compatible = "infineon,cat1-counter"; + reg = <0x40390100 0x40>; + interrupts = <98 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_1: counter@40390140 { + compatible = "infineon,cat1-counter"; + reg = <0x40390140 0x40>; + interrupts = <99 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_2: counter@40390180 { + compatible = "infineon,cat1-counter"; + reg = <0x40390180 0x40>; + interrupts = <100 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_3: counter@403901c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403901c0 0x40>; + interrupts = <101 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_4: counter@40390200 { + compatible = "infineon,cat1-counter"; + reg = <0x40390200 0x40>; + interrupts = <102 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_5: counter@40390240 { + compatible = "infineon,cat1-counter"; + reg = <0x40390240 0x40>; + interrupts = <103 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_6: counter@40390280 { + compatible = "infineon,cat1-counter"; + reg = <0x40390280 0x40>; + interrupts = <104 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_7: counter@403902c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403902c0 0x40>; + interrupts = <105 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_8: counter@40390300 { + compatible = "infineon,cat1-counter"; + reg = <0x40390300 0x40>; + interrupts = <106 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_9: counter@40390340 { + compatible = "infineon,cat1-counter"; + reg = <0x40390340 0x40>; + interrupts = <107 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_10: counter@40390380 { + compatible = "infineon,cat1-counter"; + reg = <0x40390380 0x40>; + interrupts = <108 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_11: counter@403903c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403903c0 0x40>; + interrupts = <109 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_12: counter@40390400 { + compatible = "infineon,cat1-counter"; + reg = <0x40390400 0x40>; + interrupts = <110 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_13: counter@40390440 { + compatible = "infineon,cat1-counter"; + reg = <0x40390440 0x40>; + interrupts = <111 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_14: counter@40390480 { + compatible = "infineon,cat1-counter"; + reg = <0x40390480 0x40>; + interrupts = <112 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_15: counter@403904c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403904c0 0x40>; + interrupts = <113 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_16: counter@40390500 { + compatible = "infineon,cat1-counter"; + reg = <0x40390500 0x40>; + interrupts = <114 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_17: counter@40390540 { + compatible = "infineon,cat1-counter"; + reg = <0x40390540 0x40>; + interrupts = <115 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_18: counter@40390580 { + compatible = "infineon,cat1-counter"; + reg = <0x40390580 0x40>; + interrupts = <116 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_19: counter@403905c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403905c0 0x40>; + interrupts = <117 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_20: counter@40390600 { + compatible = "infineon,cat1-counter"; + reg = <0x40390600 0x40>; + interrupts = <118 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_21: counter@40390640 { + compatible = "infineon,cat1-counter"; + reg = <0x40390640 0x40>; + interrupts = <119 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_22: counter@40390680 { + compatible = "infineon,cat1-counter"; + reg = <0x40390680 0x40>; + interrupts = <120 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_23: counter@403906c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403906c0 0x40>; + interrupts = <121 6>; + resolution = <16>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi index 3437420b1069..a4109291dfd2 100644 --- a/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_02/psoc6_02.dtsi @@ -317,5 +317,229 @@ interrupts = <22 6>; status = "disabled"; }; + counter0_0: counter@40380100 { + compatible = "infineon,cat1-counter"; + reg = <0x40380100 0x40>; + interrupts = <123 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_1: counter@40380140 { + compatible = "infineon,cat1-counter"; + reg = <0x40380140 0x40>; + interrupts = <124 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_2: counter@40380180 { + compatible = "infineon,cat1-counter"; + reg = <0x40380180 0x40>; + interrupts = <125 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_3: counter@403801c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403801c0 0x40>; + interrupts = <126 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_4: counter@40380200 { + compatible = "infineon,cat1-counter"; + reg = <0x40380200 0x40>; + interrupts = <127 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_5: counter@40380240 { + compatible = "infineon,cat1-counter"; + reg = <0x40380240 0x40>; + interrupts = <128 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_6: counter@40380280 { + compatible = "infineon,cat1-counter"; + reg = <0x40380280 0x40>; + interrupts = <129 6>; + resolution = <32>; + status = "disabled"; + }; + counter0_7: counter@403802c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403802c0 0x40>; + interrupts = <130 6>; + resolution = <32>; + status = "disabled"; + }; + counter1_0: counter@40390100 { + compatible = "infineon,cat1-counter"; + reg = <0x40390100 0x40>; + interrupts = <131 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_1: counter@40390140 { + compatible = "infineon,cat1-counter"; + reg = <0x40390140 0x40>; + interrupts = <132 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_2: counter@40390180 { + compatible = "infineon,cat1-counter"; + reg = <0x40390180 0x40>; + interrupts = <133 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_3: counter@403901c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403901c0 0x40>; + interrupts = <134 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_4: counter@40390200 { + compatible = "infineon,cat1-counter"; + reg = <0x40390200 0x40>; + interrupts = <135 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_5: counter@40390240 { + compatible = "infineon,cat1-counter"; + reg = <0x40390240 0x40>; + interrupts = <136 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_6: counter@40390280 { + compatible = "infineon,cat1-counter"; + reg = <0x40390280 0x40>; + interrupts = <137 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_7: counter@403902c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403902c0 0x40>; + interrupts = <138 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_8: counter@40390300 { + compatible = "infineon,cat1-counter"; + reg = <0x40390300 0x40>; + interrupts = <139 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_9: counter@40390340 { + compatible = "infineon,cat1-counter"; + reg = <0x40390340 0x40>; + interrupts = <140 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_10: counter@40390380 { + compatible = "infineon,cat1-counter"; + reg = <0x40390380 0x40>; + interrupts = <141 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_11: counter@403903c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403903c0 0x40>; + interrupts = <142 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_12: counter@40390400 { + compatible = "infineon,cat1-counter"; + reg = <0x40390400 0x40>; + interrupts = <143 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_13: counter@40390440 { + compatible = "infineon,cat1-counter"; + reg = <0x40390440 0x40>; + interrupts = <144 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_14: counter@40390480 { + compatible = "infineon,cat1-counter"; + reg = <0x40390480 0x40>; + interrupts = <145 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_15: counter@403904c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403904c0 0x40>; + interrupts = <146 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_16: counter@40390500 { + compatible = "infineon,cat1-counter"; + reg = <0x40390500 0x40>; + interrupts = <147 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_17: counter@40390540 { + compatible = "infineon,cat1-counter"; + reg = <0x40390540 0x40>; + interrupts = <148 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_18: counter@40390580 { + compatible = "infineon,cat1-counter"; + reg = <0x40390580 0x40>; + interrupts = <149 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_19: counter@403905c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403905c0 0x40>; + interrupts = <150 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_20: counter@40390600 { + compatible = "infineon,cat1-counter"; + reg = <0x40390600 0x40>; + interrupts = <151 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_21: counter@40390640 { + compatible = "infineon,cat1-counter"; + reg = <0x40390640 0x40>; + interrupts = <152 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_22: counter@40390680 { + compatible = "infineon,cat1-counter"; + reg = <0x40390680 0x40>; + interrupts = <153 6>; + resolution = <16>; + status = "disabled"; + }; + counter1_23: counter@403906c0 { + compatible = "infineon,cat1-counter"; + reg = <0x403906c0 0x40>; + interrupts = <154 6>; + resolution = <16>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/counter/infineon,cat1-counter.yaml b/dts/bindings/counter/infineon,cat1-counter.yaml new file mode 100644 index 000000000000..88fd001401c0 --- /dev/null +++ b/dts/bindings/counter/infineon,cat1-counter.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon counters + +compatible: "infineon,cat1-counter" + +include: base.yaml + +properties: + resolution: + type: int + description: | + Counter resolution + required: true + + clock-frequency: + type: int + description: | + Frequency that the counter runs + + external-trigger-gpios: + type: phandle-array + description: | + External trigger that runs counter diff --git a/include/zephyr/dt-bindings/pinctrl/ifx_cat1-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/ifx_cat1-pinctrl.h index 45aca8ca2e6a..a763e8ac9e2d 100644 --- a/include/zephyr/dt-bindings/pinctrl/ifx_cat1-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/ifx_cat1-pinctrl.h @@ -93,7 +93,15 @@ #define P19 CYHAL_PORT_19 #define P20 CYHAL_PORT_20 -/* Returns CYHAL GPIO from Board device tree GPIO configuration */ -#define DT_GET_CYHAL_GPIO_FROM_DT_GPIOS(node, gpios_prop) \ - CYHAL_GET_GPIO(DT_STRING_TOKEN(DT_GPIO_CTLR_BY_IDX(node, gpios_prop, 0), label), \ - DT_PHA_BY_IDX(node, gpios_prop, 0, pin)) +/* Returns CYHAL GPIO from Board device tree GPIO configuration + * CYHAL_GET_GPIO(port_number, pin_number), + * port_number = ((REG ADDR of node) - (REG ADDR of gpio_prt0)) / (REG SIZE of gpio_prt0) + * pin_number = DT_PHA_BY_IDX(node, gpios_prop, 0, pin) + */ +#define DT_GET_CYHAL_GPIO_FROM_DT_GPIOS(node, gpios_prop) \ + CYHAL_GET_GPIO( \ + (DT_REG_ADDR_BY_IDX(DT_GPIO_CTLR_BY_IDX(node, gpios_prop, 0), 0) - \ + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gpio_prt0), 0)) / \ + DT_REG_ADDR_BY_IDX(DT_NODELABEL(gpio_prt0), 1), \ + DT_PHA_BY_IDX(node, gpios_prop, 0, pin) \ + ) diff --git a/samples/drivers/counter/alarm/src/main.c b/samples/drivers/counter/alarm/src/main.c index 566cc4eef9dc..d281a902c9ba 100644 --- a/samples/drivers/counter/alarm/src/main.c +++ b/samples/drivers/counter/alarm/src/main.c @@ -45,6 +45,8 @@ struct counter_alarm_cfg alarm_cfg; #define TIMER DT_NODELABEL(rtcc0) #elif defined(CONFIG_COUNTER_GECKO_STIMER) #define TIMER DT_NODELABEL(stimer0) +#elif defined(CONFIG_COUNTER_INFINEON_CAT1) +#define TIMER DT_NODELABEL(counter0_0) #endif static void test_counter_interrupt_fn(const struct device *counter_dev, 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 109198d7b5f5..816569803c7d 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -44,6 +44,9 @@ static const struct device *const devices[] = { #endif #ifdef CONFIG_COUNTER_NATIVE_POSIX DEVICE_DT_GET(DT_NODELABEL(counter0)), +#endif +#ifdef CONFIG_COUNTER_INFINEON_CAT1 + DEVICE_DT_GET(DT_NODELABEL(counter0_0)), #endif /* NOTE: there is no trailing comma, as the DEVS_FOR_DT_COMPAT * handles it. From 9ce202e50cc7084d3e1161be8720ec0a2366f55e Mon Sep 17 00:00:00 2001 From: Bartosz Bilas Date: Tue, 25 Jul 2023 19:09:15 +0200 Subject: [PATCH 1807/2042] lib: json: add helper macro for named array of array Variant of JSON_OBJ_DESCR_ARRAY_ARRAY that can be used when the structure and JSON field names differ. Signed-off-by: Bartosz Bilas --- include/zephyr/data/json.h | 37 +++++++++++++++ tests/lib/json/src/main.c | 92 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/include/zephyr/data/json.h b/include/zephyr/data/json.h index b1e139258ead..b8b386d968ac 100644 --- a/include/zephyr/data/json.h +++ b/include/zephyr/data/json.h @@ -401,6 +401,43 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, }, \ } +/** + * @brief Variant of JSON_OBJ_DESCR_ARRAY_ARRAY that can be used when the + * structure and JSON field names differ. + * + * This is useful when the JSON field is not a valid C identifier. + * + * @param struct_ Struct packing the values + * @param json_field_name_ String, field name in JSON strings + * @param struct_field_name_ Field name in the struct containing the array + * @param max_len_ Maximum number of elements in the array + * @param len_field_ Field name in the struct for the number of elements + * in the array + * @param elem_descr_ Element descriptor, pointer to a descriptor array + * @param elem_descr_len_ Number of elements in elem_descr_ + * + * @see JSON_OBJ_DESCR_ARRAY_ARRAY + */ +#define JSON_OBJ_DESCR_ARRAY_ARRAY_NAMED(struct_, json_field_name_, struct_field_name_, \ + max_len_, len_field_, elem_descr_, elem_descr_len_) \ + { \ + .field_name = (#json_field_name_), \ + .align_shift = Z_ALIGN_SHIFT(struct_), \ + .field_name_len = sizeof(#json_field_name_) - 1, \ + .type = JSON_TOK_ARRAY_START, \ + .offset = offsetof(struct_, struct_field_name_), \ + { \ + .array = { \ + .element_descr = Z_JSON_ELEMENT_DESCR( \ + struct_, len_field_, JSON_TOK_ARRAY_START, \ + Z_JSON_DESCR_ARRAY( \ + elem_descr_, \ + 1 + ZERO_OR_COMPILE_ERROR(elem_descr_len_ == 1))), \ + .n_elements = (max_len_), \ + }, \ + }, \ + } + /** * @brief Variant of JSON_OBJ_DESCR_PRIM that can be used when the * structure and JSON field names differ. diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index 6dd209528d03..b055651ddf23 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -135,6 +135,14 @@ static const struct json_obj_descr array_2dim_extra_descr[] = { ARRAY_SIZE(obj_array_descr)), }; +static const struct json_obj_descr array_2dim_extra_named_descr[] = { + JSON_OBJ_DESCR_PRIM(struct obj_array_2dim_extra, name, JSON_TOK_STRING), + JSON_OBJ_DESCR_PRIM(struct obj_array_2dim_extra, val, JSON_TOK_NUMBER), + JSON_OBJ_DESCR_ARRAY_ARRAY_NAMED(struct obj_array_2dim_extra, data, obj_array_2dim, 3, + obj_array_2dim.objects_array_array_len, obj_array_descr, + ARRAY_SIZE(obj_array_descr)), +}; + ZTEST(lib_json_test, test_json_encoding) { struct test_struct ts = { @@ -698,6 +706,90 @@ ZTEST(lib_json_test, test_json_2dim_arr_extra_obj_encoding) "Encoded two-dimensional extra array is not consistent"); } +ZTEST(lib_json_test, test_json_2dim_arr_extra_named_obj_encoding) +{ + struct obj_array_2dim_extra obj_array_2dim_extra_ts = { + .name = "Paavo Nurmi", + .val = 123, + .obj_array_2dim.objects_array_array = { + [0] = { + .elements = { + [0] = { + .name = "Sim\303\263n Bol\303\255var", + .height = 168 + }, + [1] = { + .name = "Pel\303\251", + .height = 173 + }, + [2] = { + .name = "Usain Bolt", + .height = 195 + }, + }, + .num_elements = 3 + }, + [1] = { + .elements = { + [0] = { + .name = "Muggsy Bogues", + .height = 160 + }, + [1] = { + .name = "Hakeem Olajuwon", + .height = 213 + }, + }, + .num_elements = 2 + }, + [2] = { + .elements = { + [0] = { + .name = "Alex Honnold", + .height = 180 + }, + [1] = { + .name = "Hazel Findlay", + .height = 157 + }, + [2] = { + .name = "Daila Ojeda", + .height = 158 + }, + [3] = { + .name = "Albert Einstein", + .height = 172 + }, + }, + .num_elements = 4 + }, + }, + .obj_array_2dim.objects_array_array_len = 3, + }; + + char encoded[] = "{\"name\":\"Paavo Nurmi\",\"val\":123," + "\"data\":[" + "[{\"name\":\"Sim\303\263n Bol\303\255var\",\"height\":168}," + "{\"name\":\"Pel\303\251\",\"height\":173}," + "{\"name\":\"Usain Bolt\",\"height\":195}]," + "[{\"name\":\"Muggsy Bogues\",\"height\":160}," + "{\"name\":\"Hakeem Olajuwon\",\"height\":213}]," + "[{\"name\":\"Alex Honnold\",\"height\":180}," + "{\"name\":\"Hazel Findlay\",\"height\":157}," + "{\"name\":\"Daila Ojeda\",\"height\":158}," + "{\"name\":\"Albert Einstein\",\"height\":172}]" + "]}"; + char buffer[sizeof(encoded)]; + int ret; + + ret = json_obj_encode_buf(array_2dim_extra_named_descr, + ARRAY_SIZE(array_2dim_extra_named_descr), + &obj_array_2dim_extra_ts, buffer, sizeof(buffer)); + zassert_equal(ret, 0, "Encoding two-dimensional extra named array returned error"); + zassert_true(!strcmp(buffer, encoded), + "Encoded two-dimensional extra named array is not consistent"); +} + ZTEST(lib_json_test, test_json_2dim_obj_arr_decoding) { struct obj_array_2dim oaa; From 905a8ae40286eec8736b8cb8264b07ac50a0c21d Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Thu, 20 Jul 2023 12:29:04 +0200 Subject: [PATCH 1808/2042] drivers: i2c: i2c_nrfx_twim: remove redundant buffer size from config There are two different i2c node properites `zephyr,flash-buf-max-size` and `zephyr,concat-buf-size`. In the end max value of that two is used to define size of the message buffer. It's redundant to store both values in device config structure. Changed config structure to contain only bigger value. Signed-off-by: Adam Wojasinski --- drivers/i2c/i2c_nrfx_twim.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index a24873fc6f8b..bd57406fb869 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -34,8 +34,7 @@ struct i2c_nrfx_twim_data { struct i2c_nrfx_twim_config { nrfx_twim_t twim; nrfx_twim_config_t twim_config; - uint16_t concat_buf_size; - uint16_t flash_buf_max_size; + uint16_t msg_buf_size; void (*irq_connect)(void); const struct pinctrl_dev_config *pcfg; }; @@ -51,7 +50,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, int ret = 0; uint8_t *msg_buf = dev_data->msg_buf; uint16_t msg_buf_used = 0; - uint16_t concat_buf_size = dev_config->concat_buf_size; + uint16_t msg_buf_size = dev_config->msg_buf_size; nrfx_twim_xfer_desc_t cur_xfer = { .address = addr }; @@ -86,14 +85,14 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, * the buffer after verifying there's room. */ if (concat_next || (msg_buf_used != 0)) { - if ((msg_buf_used + msgs[i].len) > concat_buf_size) { + if ((msg_buf_used + msgs[i].len) > buf_size) { LOG_ERR("Need to use concatenation buffer and " "provided size is insufficient " "(%u + %u > %u). " "Adjust the zephyr,concat-buf-size " "property in the \"%s\" node.", msg_buf_used, msgs[i].len, - concat_buf_size, dev->name); + buf_size, dev->name); ret = -ENOSPC; break; } @@ -421,8 +420,7 @@ static int i2c_nrfx_twim_init(const struct device *dev) .skip_psel_cfg = true, \ .frequency = I2C_FREQUENCY(idx), \ }, \ - .concat_buf_size = CONCAT_BUF_SIZE(idx), \ - .flash_buf_max_size = FLASH_BUF_MAX_SIZE(idx), \ + .msg_buf_size = MSG_BUF_SIZE(idx), \ .irq_connect = irq_connect##idx, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \ }; \ From 368acbe2d18759650494d9d5092ce2009a905990 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Fri, 14 Jul 2023 15:51:38 +0200 Subject: [PATCH 1809/2042] drivers: i2c: i2c_nrfx_twim: Utilize memory-region prop from devicetree This commit aligns TWIM shim to utilize memory-region property. The memory-region is not required property that enables user to specify placement of dma buffers in memory region. It is done by assigning to memory-region property, phandle to node with zephyr,memory-region and mimo-sram compatible. When memory-region property is not specified for given instance, buffer is placed in default RAM region with other data. Signed-off-by: Adam Wojasinski --- drivers/i2c/i2c_nrfx_twim.c | 53 ++++++++++++--------------- dts/bindings/i2c/nordic,nrf-twim.yaml | 2 +- dts/bindings/i2c/nordic,nrf-twis.yaml | 2 +- 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index bd57406fb869..a282a60746fb 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,8 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, break; } + bool dma_accessible = nrf_dma_accessible_check(&dev_config->twim, msgs[i].buf); + /* This fragment needs to be merged with the next one if: * - it is not the last fragment * - it does not end a bus transaction @@ -81,18 +84,21 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, == (msgs[i + 1].flags & I2C_MSG_READ)); /* If we need to concatenate the next message, or we've - * already committed to concatenate this message, add it to - * the buffer after verifying there's room. + * already committed to concatenate this message, or its buffer + * is not accessible by DMA, add it to the internal driver + * buffer after verifying there's room. */ - if (concat_next || (msg_buf_used != 0)) { - if ((msg_buf_used + msgs[i].len) > buf_size) { - LOG_ERR("Need to use concatenation buffer and " - "provided size is insufficient " + if (concat_next || (msg_buf_used != 0) || !dma_accessible) { + if ((msg_buf_used + msgs[i].len) > msg_buf_size) { + LOG_ERR("Need to use the internal driver " + "buffer but its size is insufficient " "(%u + %u > %u). " - "Adjust the zephyr,concat-buf-size " - "property in the \"%s\" node.", + "Adjust the zephyr,concat-buf-size or " + "zephyr,flash-buf-max-size property " + "(the one with greater value) in the " + "\"%s\" node.", msg_buf_used, msgs[i].len, - buf_size, dev->name); + msg_buf_size, dev->name); ret = -ENOSPC; break; } @@ -102,25 +108,6 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, msgs[i].len); } msg_buf_used += msgs[i].len; - - /* TWIM peripherals cannot transfer data directly from - * flash. If a buffer located in flash is provided for - * a write transaction, its content must be copied to - * RAM before the transfer can be requested. - */ - } else if (!(msgs[i].flags & I2C_MSG_READ) && - !nrfx_is_in_ram(msgs[i].buf)) { - if (msgs[i].len > dev_config->flash_buf_max_size) { - LOG_ERR("Cannot copy flash buffer of size: %u. " - "Adjust the zephyr,flash-buf-max-size " - "property in the \"%s\" node.", - msgs[i].len, dev->name); - ret = -EINVAL; - break; - } - - memcpy(msg_buf, msgs[i].buf, msgs[i].len); - msg_buf_used = msgs[i].len; } if (concat_next) { @@ -376,6 +363,7 @@ static int i2c_nrfx_twim_init(const struct device *dev) I2C_NRFX_TWIM_INVALID_FREQUENCY) #define I2C(idx) DT_NODELABEL(i2c##idx) +#define I2C_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(I2C(idx), prop) #define I2C_FREQUENCY(idx) \ I2C_NRFX_TWIM_FREQUENCY(DT_PROP(I2C(idx), clock_frequency)) @@ -403,7 +391,8 @@ static int i2c_nrfx_twim_init(const struct device *dev) nrfx_isr, nrfx_twim_##idx##_irq_handler, 0); \ } \ IF_ENABLED(USES_MSG_BUF(idx), \ - (static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)];)) \ + (static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)] \ + I2C_MEMORY_SECTION(idx);)) \ static struct i2c_nrfx_twim_data twim_##idx##_data = { \ .transfer_sync = Z_SEM_INITIALIZER( \ twim_##idx##_data.transfer_sync, 1, 1), \ @@ -434,6 +423,12 @@ static int i2c_nrfx_twim_init(const struct device *dev) CONFIG_I2C_INIT_PRIORITY, \ &i2c_nrfx_twim_driver_api) +#define I2C_MEMORY_SECTION(idx) \ + COND_CODE_1(I2C_HAS_PROP(idx, memory_regions), \ + (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ + DT_PHANDLE(I2C(idx), memory_regions)))))), \ + ()) + #ifdef CONFIG_HAS_HW_NRF_TWIM0 I2C_NRFX_TWIM_DEVICE(0); #endif diff --git a/dts/bindings/i2c/nordic,nrf-twim.yaml b/dts/bindings/i2c/nordic,nrf-twim.yaml index feab0e61bae7..30232ac0afbb 100644 --- a/dts/bindings/i2c/nordic,nrf-twim.yaml +++ b/dts/bindings/i2c/nordic,nrf-twim.yaml @@ -23,7 +23,7 @@ description: | compatible: "nordic,nrf-twim" -include: nordic,nrf-twi-common.yaml +include: ["nordic,nrf-twi-common.yaml", "memory-region.yaml"] properties: zephyr,concat-buf-size: diff --git a/dts/bindings/i2c/nordic,nrf-twis.yaml b/dts/bindings/i2c/nordic,nrf-twis.yaml index 01d39a13627c..cd024c108a7a 100644 --- a/dts/bindings/i2c/nordic,nrf-twis.yaml +++ b/dts/bindings/i2c/nordic,nrf-twis.yaml @@ -27,7 +27,7 @@ description: | compatible: "nordic,nrf-twis" -include: nordic,nrf-twi-common.yaml +include: ["nordic,nrf-twi-common.yaml", "memory-region.yaml"] properties: address-0: From 84b86d9b0cc9e3768bdbbe8ee042b795d3f969fb Mon Sep 17 00:00:00 2001 From: Yong Cong Sin Date: Tue, 25 Jul 2023 17:50:40 +0800 Subject: [PATCH 1810/2042] soc: riscv: Add ability to use custom sys_io functions Add Kconfig RISCV_SOC_HAS_CUSTOM_SYS_IO symbol so that a riscv SoC can set to specify that it has a custom implementation for sys_io functions. Signed-off-by: Yong Cong Sin --- arch/riscv/Kconfig | 10 +++ include/zephyr/arch/riscv/arch.h | 2 +- include/zephyr/arch/riscv/sys_io.h | 85 +++++++++++++++++++ soc/riscv/litex-vexriscv/soc.h | 2 +- .../riscv-privileged/efinix-sapphire/soc.h | 2 +- 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 include/zephyr/arch/riscv/sys_io.h diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 0559e50d4b6f..c008d4184a04 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -90,6 +90,16 @@ config RISCV_SOC_HAS_CUSTOM_IRQ_LOCK_OPS the RISC-V SoC needs to do something different and more than reading and writing the mstatus register to lock and unlock the IRQs. +config RISCV_SOC_HAS_CUSTOM_SYS_IO + bool + help + Hidden option to allow SoC to overwrite sys_read*(), sys_write*() functions with + platform-specific versions named z_soc_sys_read*() and z_soc_sys_write*(). + + Enable this hidden option and specialize the z_soc_* functions when + the RISC-V SoC needs to do something different and more than reading and + writing the registers. + config RISCV_SOC_CONTEXT_SAVE bool "SOC-based context saving in IRQ handlers" select RISCV_SOC_OFFSETS diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 29f854f3ff88..99bccb74a08a 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #if defined(CONFIG_USERSPACE) #include diff --git a/include/zephyr/arch/riscv/sys_io.h b/include/zephyr/arch/riscv/sys_io.h new file mode 100644 index 000000000000..0437053d2a0e --- /dev/null +++ b/include/zephyr/arch/riscv/sys_io.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Memory mapped registers I/O functions in riscv arch C code */ + +#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_SYS_IO_H_ +#define ZEPHYR_INCLUDE_ARCH_RISCV_SYS_IO_H_ + +#ifndef _ASMLANGUAGE + +#include +#include +#include + +#ifndef CONFIG_RISCV_SOC_HAS_CUSTOM_SYS_IO +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_SYS_IO + +extern uint8_t z_soc_sys_read8(mem_addr_t addr); +extern void z_soc_sys_write8(uint8_t data, mem_addr_t addr); +extern uint16_t z_soc_sys_read16(mem_addr_t addr); +extern void z_soc_sys_write16(uint16_t data, mem_addr_t addr); +extern uint32_t z_soc_sys_read32(mem_addr_t addr); +extern void z_soc_sys_write32(uint32_t data, mem_addr_t addr); +extern uint64_t z_soc_sys_read64(mem_addr_t addr); +extern void z_soc_sys_write64(uint64_t data, mem_addr_t addr); + +static ALWAYS_INLINE uint8_t sys_read8(mem_addr_t addr) +{ + return z_soc_sys_read8(addr); +} + +static ALWAYS_INLINE void sys_write8(uint8_t data, mem_addr_t addr) +{ + return z_soc_sys_write8(data, addr); +} + +static ALWAYS_INLINE uint16_t sys_read16(mem_addr_t addr) +{ + return z_soc_sys_read16(addr); +} + +static ALWAYS_INLINE void sys_write16(uint16_t data, mem_addr_t addr) +{ + return z_soc_sys_write16(data, addr); +} + +static ALWAYS_INLINE uint32_t sys_read32(mem_addr_t addr) +{ + return z_soc_sys_read32(addr); +} + +static ALWAYS_INLINE void sys_write32(uint32_t data, mem_addr_t addr) +{ + return z_soc_sys_write32(data, addr); +} + +static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) +{ + return z_soc_sys_read64(addr); +} + +static ALWAYS_INLINE void sys_write64(uint64_t data, mem_addr_t addr) +{ + return z_soc_sys_write64(data, addr); +} + +#endif /* CONFIG_RISCV_SOC_HAS_CUSTOM_SYS_IO */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_SYS_IO_H_ */ diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex-vexriscv/soc.h index d9b1f19c46f4..b738deec7713 100644 --- a/soc/riscv/litex-vexriscv/soc.h +++ b/soc/riscv/litex-vexriscv/soc.h @@ -9,7 +9,7 @@ #include "../riscv-privileged/common/soc_common.h" #include -#include +#include #ifndef _ASMLANGUAGE /* CSR access helpers */ diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h b/soc/riscv/riscv-privileged/efinix-sapphire/soc.h index e06175662263..1d566e2f293d 100644 --- a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h +++ b/soc/riscv/riscv-privileged/efinix-sapphire/soc.h @@ -8,7 +8,7 @@ #define __RISCV32_EFINIX_SAPPHIRE_SOC_H_ #include "soc_common.h" -#include +#include #include #ifndef _ASMLANGUAGE From 5dad9443512308141bd685389495c9a9bd90def7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 7 Jul 2023 13:31:37 -0300 Subject: [PATCH 1811/2042] drivers: memc: add NXP S32 QSPI controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NXP S32 QSPI controller acts as an interface to up to two serial flash memory devices, each with up to eight bidirectional data lines, depending on the platform. It is based on a LUT enginee to interface through commands with different memory types including flash NOR and Hyperram. This patch adds support for the QSPI in S32K344 which supports a single memory device (side A) with up to four bidirectional data lines and SDR only. Nevertheless, the memory controller is implemented flexible enough to be extended to support more feature-rich QSPI blocks. Signed-off-by: Manuel Argüelles --- drivers/memc/CMakeLists.txt | 2 + drivers/memc/Kconfig | 2 + drivers/memc/Kconfig.nxp_s32 | 10 ++ drivers/memc/memc_nxp_s32_qspi.c | 197 ++++++++++++++++++++++++++ drivers/memc/memc_nxp_s32_qspi.h | 29 ++++ dts/bindings/qspi/nxp,s32-qspi.yaml | 208 ++++++++++++++++++++++++++++ west.yml | 2 +- 7 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 drivers/memc/Kconfig.nxp_s32 create mode 100644 drivers/memc/memc_nxp_s32_qspi.c create mode 100644 drivers/memc/memc_nxp_s32_qspi.h create mode 100644 dts/bindings/qspi/nxp,s32-qspi.yaml diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index 114c6495d9b7..a991e4e47168 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -18,3 +18,5 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_HIFIVE_UNMATCHED_DRAM sifive_ddr.c) if((DEFINED CONFIG_FLASH_MCUX_FLEXSPI_XIP) AND (DEFINED CONFIG_FLASH)) zephyr_code_relocate(FILES memc_mcux_flexspi.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) endif() + +zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_S32_QSPI memc_nxp_s32_qspi.c) diff --git a/drivers/memc/Kconfig b/drivers/memc/Kconfig index 28cabd2bda3e..f64165573556 100644 --- a/drivers/memc/Kconfig +++ b/drivers/memc/Kconfig @@ -29,4 +29,6 @@ source "drivers/memc/Kconfig.sam" source "drivers/memc/Kconfig.sifive" +source "drivers/memc/Kconfig.nxp_s32" + endif diff --git a/drivers/memc/Kconfig.nxp_s32 b/drivers/memc/Kconfig.nxp_s32 new file mode 100644 index 000000000000..a1ec0d0d0b6e --- /dev/null +++ b/drivers/memc/Kconfig.nxp_s32 @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MEMC_NXP_S32_QSPI + bool "NXP S32 Quad Serial Peripheral Interface (QSPI) controller" + default y + depends on DT_HAS_NXP_S32_QSPI_ENABLED + select PINCTRL + help + Enable NXP S32 Quad Serial Peripheral Interface (QSPI) controller. diff --git a/drivers/memc/memc_nxp_s32_qspi.c b/drivers/memc/memc_nxp_s32_qspi.c new file mode 100644 index 000000000000..b2dc1466d6fc --- /dev/null +++ b/drivers/memc/memc_nxp_s32_qspi.c @@ -0,0 +1,197 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_s32_qspi + +#include +LOG_MODULE_REGISTER(nxp_s32_qspi_memc, CONFIG_MEMC_LOG_LEVEL); + +#include +#include + +#include +#include "memc_nxp_s32_qspi.h" + +/* Mapping between QSPI chip select signals and devicetree chip select identifiers */ +#define QSPI_PCSFA1 0 +#define QSPI_PCSFA2 1 +#define QSPI_PCSFB1 2 +#define QSPI_PCSFB2 3 + +struct memc_nxp_s32_qspi_data { + uint8_t instance; +}; + +struct memc_nxp_s32_qspi_config { + QuadSPI_Type *base; + const struct pinctrl_dev_config *pincfg; + + const Qspi_Ip_ControllerConfigType *controller_cfg; +}; + +static inline uint8_t get_instance(QuadSPI_Type *base) +{ + QuadSPI_Type *const base_ptrs[QuadSPI_INSTANCE_COUNT] = IP_QuadSPI_BASE_PTRS; + uint8_t i; + + for (i = 0; i < QuadSPI_INSTANCE_COUNT; i++) { + if (base_ptrs[i] == base) { + break; + } + } + __ASSERT_NO_MSG(i < QuadSPI_INSTANCE_COUNT); + + return i; +} + +static int memc_nxp_s32_qspi_init(const struct device *dev) +{ + const struct memc_nxp_s32_qspi_config *config = dev->config; + struct memc_nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + + data->instance = get_instance(config->base); + + if (pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT)) { + return -EIO; + } + + status = Qspi_Ip_ControllerInit(data->instance, config->controller_cfg); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Fail to initialize QSPI controller %d (%d)", + data->instance, status); + return -EIO; + } + + return 0; +} + +uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev) +{ + struct memc_nxp_s32_qspi_data *data = dev->data; + + return data->instance; +} + +#define QSPI_DATA_CFG(n) \ + IF_ENABLED(FEATURE_QSPI_DDR, ( \ + .dataRate = CONCAT(QSPI_IP_DATA_RATE_, \ + DT_INST_STRING_UPPER_TOKEN(n, data_rate)), \ + .dataAlign = COND_CODE_1(DT_INST_PROP(n, hold_time_2x), \ + (QSPI_IP_FLASH_DATA_ALIGN_2X_REFCLK), \ + (QSPI_IP_FLASH_DATA_ALIGN_REFCLK)), \ + )) + +#define QSPI_ADDR_CFG(n) \ + IF_ENABLED(FEATURE_QSPI_ADDR_CFG, ( \ + .columnAddr = DT_INST_PROP_OR(n, column_space, 0), \ + .wordAddresable = DT_INST_PROP(n, word_addressable), \ + )) + +#define QSPI_BYTES_SWAP_ADDR(n) \ + IF_ENABLED(FEATURE_QSPI_BYTES_SWAP_ADDR, \ + (.byteSwap = DT_INST_PROP(n, byte_swapping),)) + +#define QSPI_SAMPLE_DELAY(n) \ + COND_CODE_1(DT_INST_PROP(n, sample_delay_half_cycle), \ + (QSPI_IP_SAMPLE_DELAY_HALFCYCLE_EARLY_DQS), \ + (QSPI_IP_SAMPLE_DELAY_SAME_DQS)) + +#define QSPI_SAMPLE_PHASE(n) \ + COND_CODE_1(DT_INST_PROP(n, sample_phase_inverted), \ + (QSPI_IP_SAMPLE_PHASE_INVERTED), \ + (QSPI_IP_SAMPLE_PHASE_NON_INVERTED)) + +#define QSPI_AHB_BUFFERS(n) \ + { \ + .masters = DT_INST_PROP(n, ahb_buffers_masters), \ + .sizes = DT_INST_PROP(n, ahb_buffers_sizes), \ + .allMasters = (bool)DT_INST_PROP(n, ahb_buffers_all_masters), \ + } + +#define QSPI_DLL_CFG(n, side, side_upper) \ + IF_ENABLED(FEATURE_QSPI_HAS_DLL, ( \ + .dllSettings##side_upper = { \ + .dllMode = CONCAT(QSPI_IP_DLL_, \ + DT_INST_STRING_UPPER_TOKEN(n, side##_dll_mode)), \ + .freqEnable = DT_INST_PROP(n, side##_dll_freq_enable), \ + .coarseDelay = DT_INST_PROP(n, side##_dll_coarse_delay), \ + .fineDelay = DT_INST_PROP(n, side##_dll_fine_delay), \ + .tapSelect = DT_INST_PROP(n, side##_dll_tap_select), \ + IF_ENABLED(FEATURE_QSPI_DLL_LOOPCONTROL, ( \ + .referenceCounter = DT_INST_PROP(n, side##_dll_ref_counter), \ + .resolution = DT_INST_PROP(n, side##_dll_resolution), \ + )) \ + }, \ + )) + +#define QSPI_READ_MODE(n, side, side_upper) \ + CONCAT(QSPI_IP_READ_MODE_, DT_INST_STRING_UPPER_TOKEN(n, side##_rx_clock_source)) + +#define QSPI_IDLE_SIGNAL_DRIVE(n, side, side_upper) \ + IF_ENABLED(FEATURE_QSPI_CONFIGURABLE_ISD, ( \ + .io2IdleValue##side_upper = (uint8_t)DT_INST_PROP(n, side##_io2_idle_high),\ + .io3IdleValue##side_upper = (uint8_t)DT_INST_PROP(n, side##_io3_idle_high),\ + )) + +#define QSPI_PORT_SIZE_FN(node_id, side_upper, port) \ + COND_CODE_1(IS_EQ(DT_REG_ADDR(node_id), QSPI_PCSF##side_upper##port), \ + (COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay), \ + (.memSize##side_upper##port = DT_PROP(node_id, size) / 8,), \ + (.memSize##side_upper##port = 0,))), \ + (EMPTY)) + +#define QSPI_PORT_SIZE(n, side_upper) \ + DT_INST_FOREACH_CHILD_VARGS(n, QSPI_PORT_SIZE_FN, side_upper, 1) \ + DT_INST_FOREACH_CHILD_VARGS(n, QSPI_PORT_SIZE_FN, side_upper, 2) + +#define QSPI_SIDE_CFG(n, side, side_upper) \ + QSPI_IDLE_SIGNAL_DRIVE(n, side, side_upper) \ + QSPI_DLL_CFG(n, side, side_upper) \ + QSPI_PORT_SIZE(n, side_upper) \ + .readMode##side_upper = QSPI_READ_MODE(n, side, side_upper), + +#define MEMC_NXP_S32_QSPI_CONTROLLER_CONFIG(n) \ + BUILD_ASSERT(DT_INST_PROP_LEN(n, ahb_buffers_masters) == QSPI_IP_AHB_BUFFERS, \ + "ahb-buffers-masters must be of size QSPI_IP_AHB_BUFFERS"); \ + BUILD_ASSERT(DT_INST_PROP_LEN(n, ahb_buffers_sizes) == QSPI_IP_AHB_BUFFERS, \ + "ahb-buffers-sizes must be of size QSPI_IP_AHB_BUFFERS"); \ + BUILD_ASSERT( \ + CONCAT(FEATURE_QSPI_, DT_INST_STRING_UPPER_TOKEN(n, a_rx_clock_source)) == 1,\ + "a-rx-clock-source source mode selected is not supported"); \ + \ + static const Qspi_Ip_ControllerConfigType \ + memc_nxp_s32_qspi_controller_cfg_##n = { \ + .csHoldTime = DT_INST_PROP(n, cs_hold_time), \ + .csSetupTime = DT_INST_PROP(n, cs_setup_time), \ + .sampleDelay = QSPI_SAMPLE_DELAY(n), \ + .samplePhase = QSPI_SAMPLE_PHASE(n), \ + .ahbConfig = QSPI_AHB_BUFFERS(n), \ + QSPI_SIDE_CFG(n, a, A) \ + QSPI_DATA_CFG(n) \ + QSPI_ADDR_CFG(n) \ + QSPI_BYTES_SWAP_ADDR(n) \ + } + +#define MEMC_NXP_S32_QSPI_INIT_DEVICE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + MEMC_NXP_S32_QSPI_CONTROLLER_CONFIG(n); \ + static struct memc_nxp_s32_qspi_data memc_nxp_s32_qspi_data_##n; \ + static const struct memc_nxp_s32_qspi_config memc_nxp_s32_qspi_config_##n = { \ + .base = (QuadSPI_Type *)DT_INST_REG_ADDR(n), \ + .controller_cfg = &memc_nxp_s32_qspi_controller_cfg_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + memc_nxp_s32_qspi_init, \ + NULL, \ + &memc_nxp_s32_qspi_data_##n, \ + &memc_nxp_s32_qspi_config_##n, \ + POST_KERNEL, \ + CONFIG_MEMC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MEMC_NXP_S32_QSPI_INIT_DEVICE) diff --git a/drivers/memc/memc_nxp_s32_qspi.h b/drivers/memc/memc_nxp_s32_qspi.h new file mode 100644 index 000000000000..c4f30e97dae7 --- /dev/null +++ b/drivers/memc/memc_nxp_s32_qspi.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/** + * @brief Build a QSPI Look-up Table (LUT) sequence entry. + * + * @param inst instruction + * @param pads pad information + * @param op operand + */ +#define QSPI_LUT_OP(inst, pads, op) \ + ((Qspi_Ip_InstrOpType)((Qspi_Ip_InstrOpType)(inst) \ + | (Qspi_Ip_InstrOpType)(pads) \ + | (Qspi_Ip_InstrOpType)(op))) + +/** + * @brief Get the QSPI peripheral hardware instance number. + * + * @param dev device pointer + */ +uint8_t memc_nxp_s32_qspi_get_instance(const struct device *dev); diff --git a/dts/bindings/qspi/nxp,s32-qspi.yaml b/dts/bindings/qspi/nxp,s32-qspi.yaml new file mode 100644 index 000000000000..7d61e5d81047 --- /dev/null +++ b/dts/bindings/qspi/nxp,s32-qspi.yaml @@ -0,0 +1,208 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 Quad Serial Peripheral Interface (QSPI) Controller. + + QSPI acts as an interface to up to two serial flash memory devices, each with + up to eight bidirectional bidirectional data lines, depending on the platform. + +compatible: "nxp,s32-qspi" + +include: [base.yaml, pinctrl-device.yaml] + +bus: qspi + +properties: + reg: + required: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + data-rate: + type: string + enum: + - SDR + - DDR + description: | + Selects the read mode: + - Single Data Rate (SDR): sampling of incoming data occurs on single edges. + - Double Data Rate (DDR): sampling of incoming data occurs on both edges. + + hold-time-2x: + type: boolean + description: | + Set to align incoming data with 2x serial flash half clock, when in DDR + mode. Otherwise, data will be aligned to the posedge of the controller's + internal reference clock. + + sample-delay-half-cycle: + type: boolean + description: | + Set to use half-cycle early DQS delay when sampling received data. + + sample-phase-inverted: + type: boolean + description: | + Set to sample received data at inverted clock. + + cs-setup-time: + type: int + default: 3 + description: | + Chip select setup time, in serial clock cycles. A bigger value will pull + the CS signal earlier before the transaction starts. + The default corresponds to the reset value of the register field. + + cs-hold-time: + type: int + default: 3 + description: | + Chip select hold time, in serial clock cycles. A bigger value will release + the CS signal later after the transaction ends. + The default corresponds to the reset value of the register field. + + column-space: + type: int + default: 0 + description: | + Column Address Space bit width. For example, if the coulmn 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. + The default corresponds to the reset value of the register field. + + word-addressable: + type: boolean + description: | + Set if the serial flash device connected to this controller is word + (2 bytes) addressable. + + byte-swapping: + type: boolean + description: | + In case of Octal DDR mode, specifies whether a word unit composed of two + bytes from posedge and negedge of a single DQS cycle needs to be swapped. + + ahb-buffers-masters: + type: array + description: | + Masters ID's for the AHB receive buffers. The master ID of every incoming + request is checked and the data is returned or fetched into the + corresponding associated buffer. The maximum number of buffers is SoC + specific. + + ahb-buffers-sizes: + type: array + description: | + Sizes (in bytes) of the AHB receive buffers. The maximum buffer size and + maximum number of buffers is SoC specific. + + ahb-buffers-all-masters: + type: boolean + description: | + Any access from a master not associated with any other buffer is routed to + the last buffer. + + a-rx-clock-source: + type: string + enum: + - LOOPBACK + - LOOPBACK DQS + - INTERNAL DQS + - EXTERNAL DQS + description: | + Selects DQS clock source for sampling read data at side A: + - LOOPBACK: use loopback clock from dummy internal PAD as strobe signal. + - LOOPBACK DQS: use loopback clock from PAD as strobe signal. + - INTERNAL DQS: use internally generated strobe signal. + - EXTERNAL DQS: use external strobe signal. + + a-io2-idle-high: + type: boolean + description: | + Set if the logic level of IO2 signal output of this controller must be + driven high in the inactive state. + This property applies to side A of the controller. + + a-io3-idle-high: + type: boolean + description: | + Set if the logic level of IO3 signal output of this controller must be + driven high in the inactive state. + This property applies to side A of the controller. + + a-dll-mode: + type: string + enum: + - BYPASSED + - MANUAL UPDATE + - AUTO UPDATE + default: BYPASSED + description: | + DLL mode. The supported modes depends on the SoC. + This property applies to side A of the controller. + + a-dll-freq-enable: + type: boolean + description: | + Selects delay-chain for high frequency of operation. + This property applies to side A of the controller. + + a-dll-ref-counter: + type: int + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + default: 1 + description: | + Select the "n+1" interval of DLL phase detection and reference delay + updating interval. + Minimum recommended value is 1 (reset value). + This property applies to side A of the controller. + + a-dll-resolution: + type: int + enum: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + default: 2 + description: | + Minimum resolution for DLL phase detector to remain locked/unlocked based + on flash memory clock jitter. + The minimum value is 2 (reset value). + This property applies to side A of the controller. + + a-dll-coarse-delay: + type: int + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + default: 0 + description: | + This field sets the number of delay elements in each delay tap. The field + is used to overwrite DLL-generated delay values. + Default to 0 (reset value). + This property applies to side A of the controller. + + a-dll-fine-delay: + type: int + enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + default: 0 + description: | + This field sets the number of fine offset delay elements up to 16 in + incoming DQS. + Default to 0 (reset value). + This property applies to side A of the controller. + + a-dll-tap-select: + type: int + enum: [0, 1, 2, 3, 4, 5, 6, 7] + default: 0 + description: | + Selects the Nth tap provided by the slave delay-chain. + Default to 0 (reset value). + This property applies to side A of the controller. + +child-binding: + description: NXP S32 QuadSPI port + + include: nxp,s32-qspi-device.yaml diff --git a/west.yml b/west.yml index 3def5691788b..f3fa27117d4a 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nxp - revision: e0116b8eae46c2d90f2c1b23baef73bb082d00bd + revision: 35b0e5afc4f061cedc5a0411e024dad6d9e8101f path: modules/hal/nxp groups: - hal From 6d0a87652548b098c58e14969681ee601bc646a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 7 Jul 2023 13:31:50 -0300 Subject: [PATCH 1812/2042] drivers: flash: add NXP S32 QSPI flash NOR driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for flash NOR memory devices on a NXP S32 QSPI bus. The driver uses a fixed LUT configuration assuming a default standard page size and erase types, and allows to select between multiple read/program instructions/modes. It is also possible to read the flash device characteristics from the device at run-time as long as the memory is JESD216 compatible, providing more flexibility. Signed-off-by: Manuel Argüelles --- drivers/flash/CMakeLists.txt | 6 + drivers/flash/Kconfig | 2 + drivers/flash/Kconfig.nxp_s32 | 54 + drivers/flash/flash_nxp_s32_qspi_nor.c | 1106 +++++++++++++++++++++ dts/bindings/mtd/nxp,s32-qspi-device.yaml | 22 + dts/bindings/mtd/nxp,s32-qspi-nor.yaml | 38 + 6 files changed, 1228 insertions(+) create mode 100644 drivers/flash/Kconfig.nxp_s32 create mode 100644 drivers/flash/flash_nxp_s32_qspi_nor.c create mode 100644 dts/bindings/mtd/nxp,s32-qspi-device.yaml create mode 100644 dts/bindings/mtd/nxp,s32-qspi-nor.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index fd9aff229e19..50058198de30 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -106,6 +106,12 @@ zephyr_library_include_directories_ifdef( ${ZEPHYR_BASE}/drivers/memc ) +zephyr_library_sources_ifdef(CONFIG_FLASH_NXP_S32_QSPI_NOR flash_nxp_s32_qspi_nor.c) +zephyr_library_include_directories_ifdef( + CONFIG_FLASH_NXP_S32_QSPI_NOR + ${ZEPHYR_BASE}/drivers/memc +) + zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c) zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c) zephyr_library_sources_ifdef(CONFIG_FLASH_INFINEON_CAT1 flash_ifx_cat1.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 8d50a77e78db..9d2192571f95 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -154,4 +154,6 @@ source "drivers/flash/Kconfig.ifx_cat1" source "drivers/flash/Kconfig.numaker" +source "drivers/flash/Kconfig.nxp_s32" + endif # FLASH diff --git a/drivers/flash/Kconfig.nxp_s32 b/drivers/flash/Kconfig.nxp_s32 new file mode 100644 index 000000000000..08a96f1cec9b --- /dev/null +++ b/drivers/flash/Kconfig.nxp_s32 @@ -0,0 +1,54 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config FLASH_NXP_S32_QSPI_NOR + bool "NXP S32 QSPI NOR driver" + default y + depends on DT_HAS_NXP_S32_QSPI_NOR_ENABLED + select MEMC + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select FLASH_JESD216 + help + Enable the Flash driver for a NOR Serial Flash Memory device connected + to an NXP S32 QSPI bus. + +if FLASH_NXP_S32_QSPI_NOR + +config FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME + bool "Read flash parameters at runtime" + help + Read flash device characteristics from the device at runtime. + This option should provide functionality for all supported + JESD216-compatible devices, with the following notes: + - Quad Enable Requirements bitfield (DW15) must be present in the SFDP + tables to configure Quad mode. Otherwise it defaults to Dual or + Single mode as supported by the device. + - Soft Reset bitfield (DW16) must be present in the SFDP tables to + automatically reset the device at initialization time. + - 0-X-X mode discovery not yet implemented by the HAL. + + If not selected, the driver uses a fixed configuration assuming 256 By + page size and 4 KiBy, 32 KiBy and 64 KiBy erase instructions. The + device size and jedec-id properties must be set in devicetree node. + +config FLASH_NXP_S32_QSPI_VERIFY_ERASE + bool "Verify memory after erased" + help + Verify contents of memory after erased. + +config FLASH_NXP_S32_QSPI_VERIFY_WRITE + bool "Verify memory after written" + help + Verify contents of memory after written. + +config FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE + int "Page size to use for FLASH_LAYOUT feature" + default 4096 + help + When CONFIG_FLASH_PAGE_LAYOUT is used this driver will support that API. + By default the page size corresponds to the sector size (4096) for a NOR + flash memory. Other options may include the 32K-byte erase size (32768), + the block size (65536), or any non-zero multiple of the sector size. + +endif # FLASH_NXP_S32_QSPI_NOR diff --git a/drivers/flash/flash_nxp_s32_qspi_nor.c b/drivers/flash/flash_nxp_s32_qspi_nor.c new file mode 100644 index 000000000000..defd1e110bf6 --- /dev/null +++ b/drivers/flash/flash_nxp_s32_qspi_nor.c @@ -0,0 +1,1106 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_s32_qspi_nor + +#include +LOG_MODULE_REGISTER(nxp_s32_qspi_nor, CONFIG_FLASH_LOG_LEVEL); + +#include +#include +#include + +#include + +#include "spi_nor.h" +#include "jesd216.h" + +#include "memc_nxp_s32_qspi.h" + +#define QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, prop, val) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, prop), \ + (IS_EQ(DT_INST_ENUM_IDX(n, prop), val)), \ + (0)) || + +#define QSPI_ANY_INST_HAS_PROP_EQ(prop, val) \ + (DT_INST_FOREACH_STATUS_OKAY_VARGS(QSPI_INST_NODE_HAS_PROP_EQ_AND_OR, prop, val) 0) + +#define QSPI_INST_NODE_NOT_HAS_PROP_AND_OR(n, prop) \ + !DT_INST_NODE_HAS_PROP(n, prop) || + +#define QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(prop) \ + (DT_INST_FOREACH_STATUS_OKAY_VARGS(QSPI_INST_NODE_NOT_HAS_PROP_AND_OR, prop) 0) + +#define QSPI_QER_TYPE(n) \ + _CONCAT(JESD216_DW15_QER_VAL_, \ + DT_INST_STRING_TOKEN_OR(n, quad_enable_requirements, S1B6)) + +#define QSPI_HAS_QUAD_MODE(n) \ + (QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, readoc, 3) \ + QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, readoc, 4) \ + QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, writeoc, 2) \ + QSPI_INST_NODE_HAS_PROP_EQ_AND_OR(n, writeoc, 3) \ + 0) + +#define QSPI_WRITE_SEQ(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, writeoc), \ + (_CONCAT(QSPI_SEQ_PP_, DT_INST_STRING_UPPER_TOKEN(n, writeoc))),\ + (QSPI_SEQ_PP_1_1_1)) + +#define QSPI_READ_SEQ(n) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(n, readoc), \ + (_CONCAT(QSPI_SEQ_READ_, DT_INST_STRING_UPPER_TOKEN(n, readoc))),\ + (QSPI_SEQ_READ_1_1_1)) + +#define QSPI_ERASE_VALUE 0xff +#define QSPI_WRITE_BLOCK_SIZE 1U + +#define QSPI_IS_ALIGNED(addr, bits) (((addr) & BIT_MASK(bits)) == 0) + +#define QSPI_LUT_ENTRY_SIZE (FEATURE_QSPI_LUT_SEQUENCE_SIZE * 2) +#define QSPI_LUT_IDX(n) (n * QSPI_LUT_ENTRY_SIZE) + +#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +/* Size of LUT */ +#define QSPI_SFDP_LUT_SIZE 130U +/* Size of init operations */ +#define QSPI_SFDP_INIT_OP_SIZE 8U +#if defined(CONFIG_FLASH_JESD216_API) +/* Size of all LUT sequences for JESD216 operations */ +#define QSPI_JESD216_SEQ_SIZE 8U +#endif /* CONFIG_FLASH_JESD216_API */ +#endif /* CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */ + +struct nxp_s32_qspi_config { + const struct device *controller; + struct flash_parameters flash_parameters; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) + const Qspi_Ip_MemoryConfigType memory_cfg; + enum jesd216_dw15_qer_type qer_type; + bool quad_mode; +#endif +}; + +struct nxp_s32_qspi_data { + uint8_t instance; + Qspi_Ip_MemoryConnectionType memory_conn_cfg; + uint8_t read_sfdp_lut_idx; +#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) + Qspi_Ip_MemoryConfigType memory_cfg; + Qspi_Ip_InstrOpType lut_ops[QSPI_SFDP_LUT_SIZE]; + Qspi_Ip_InitOperationType init_ops[QSPI_SFDP_INIT_OP_SIZE]; +#endif +#if defined(CONFIG_MULTITHREADING) + struct k_sem sem; +#endif +}; + +enum { + QSPI_SEQ_RDSR, + QSPI_SEQ_RDSR2, + QSPI_SEQ_WRSR, + QSPI_SEQ_WRSR2, + QSPI_SEQ_WREN, + QSPI_SEQ_RESET, + QSPI_SEQ_SE, +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(has_32k_erase) + QSPI_SEQ_BE_32K, +#endif + QSPI_SEQ_BE, + QSPI_SEQ_CE, + QSPI_SEQ_READ_SFDP, + QSPI_SEQ_RDID, +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(readoc) + QSPI_SEQ_READ_1_1_1, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 1) + QSPI_SEQ_READ_1_1_2, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 2) + QSPI_SEQ_READ_1_2_2, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 3) + QSPI_SEQ_READ_1_1_4, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 4) + QSPI_SEQ_READ_1_4_4, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(writeoc) + QSPI_SEQ_PP_1_1_1, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 1) + QSPI_SEQ_PP_1_1_2, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 2) + QSPI_SEQ_PP_1_1_4, +#endif +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 3) + QSPI_SEQ_PP_1_4_4, +#endif +}; + +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +static const Qspi_Ip_InstrOpType nxp_s32_qspi_lut[][QSPI_LUT_ENTRY_SIZE] = { + [QSPI_SEQ_RDSR] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RDSR), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 1U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_RDSR2] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RDSR2), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 1U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_WRSR] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WRSR), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 1U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_WRSR2] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WRSR2), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 1U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_WREN] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_WREN), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_RESET] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RESET_EN), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_PADS_1, 0U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_RESET_MEM), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_PADS_1, 0U), + }, + + [QSPI_SEQ_SE] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_SE), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(has_32k_erase) + [QSPI_SEQ_BE_32K] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_BE_32K), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + + [QSPI_SEQ_BE] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_BE), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_CE] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_CE), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_READ_SFDP] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, JESD216_CMD_READ_SFDP), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 16U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + + [QSPI_SEQ_RDID] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, JESD216_CMD_READ_ID), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, JESD216_READ_ID_LEN), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, + +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(readoc) + [QSPI_SEQ_READ_1_1_1] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_READ_FAST), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 1) + [QSPI_SEQ_READ_1_1_2] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_DREAD), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_2, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 2) + [QSPI_SEQ_READ_1_2_2] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_2READ), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_2, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_2, 4U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_2, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 3) + [QSPI_SEQ_READ_1_1_4] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_QREAD), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_4, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(readoc, 4) + [QSPI_SEQ_READ_1_4_4] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_4READ), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_4, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_MODE, QSPI_IP_LUT_PADS_4, 0U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_4, 4U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_4, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 0) || QSPI_ANY_INST_HAS_PROP_STATUS_NOT_OKAY(writeoc) + [QSPI_SEQ_PP_1_1_1] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_1, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 1) + [QSPI_SEQ_PP_1_1_2] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_1_2), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_2, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 2) + [QSPI_SEQ_PP_1_1_4] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_1_4), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_4, 8U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif + +#if QSPI_ANY_INST_HAS_PROP_EQ(writeoc, 3) + [QSPI_SEQ_PP_1_4_4] = { + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, SPI_NOR_CMD_PP_1_4_4), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_4, 24U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_WRITE, QSPI_IP_LUT_PADS_4, 16U), + QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, QSPI_IP_LUT_SEQ_END), + }, +#endif +}; +#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) */ + +static ALWAYS_INLINE Qspi_Ip_MemoryConfigType *get_memory_config(const struct device *dev) +{ +#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) + return &((struct nxp_s32_qspi_data *)dev->data)->memory_cfg; +#else + return ((Qspi_Ip_MemoryConfigType *) + &((const struct nxp_s32_qspi_config *)dev->config)->memory_cfg); +#endif +} + +static ALWAYS_INLINE bool area_is_subregion(const struct device *dev, off_t offset, size_t size) +{ + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + + return ((offset >= 0) && (offset < memory_cfg->memSize) + && ((size + offset) <= memory_cfg->memSize)); +} + +static inline void nxp_s32_qspi_lock(const struct device *dev) +{ +#ifdef CONFIG_MULTITHREADING + struct nxp_s32_qspi_data *data = dev->data; + + k_sem_take(&data->sem, K_FOREVER); +#else + ARG_UNUSED(dev); +#endif +} + +static inline void nxp_s32_qspi_unlock(const struct device *dev) +{ +#ifdef CONFIG_MULTITHREADING + struct nxp_s32_qspi_data *data = dev->data; + + k_sem_give(&data->sem); +#else + ARG_UNUSED(dev); +#endif +} + +/* Must be called with lock */ +static int nxp_s32_qspi_wait_until_ready(const struct device *dev) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + uint32_t timeout = 0xFFFFFF; + int ret = 0; + + do { + status = Qspi_Ip_GetMemoryStatus(data->instance); + timeout--; + } while ((status == STATUS_QSPI_IP_BUSY) && (timeout > 0)); + + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to read memory status (%d)", status); + ret = -EIO; + } else if (timeout <= 0) { + LOG_ERR("Timeout, memory is busy"); + ret = -ETIMEDOUT; + } + + return ret; +} + +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +static int nxp_s32_qspi_read_status_register(const struct device *dev, + uint8_t reg_num, + uint8_t *val) +{ + struct nxp_s32_qspi_data *data = dev->data; + uint16_t lut_idx; + Qspi_Ip_StatusType status; + int ret = 0; + + switch (reg_num) { + case 1U: + lut_idx = QSPI_LUT_IDX(QSPI_SEQ_RDSR); + break; + case 2U: + lut_idx = QSPI_LUT_IDX(QSPI_SEQ_RDSR2); + break; + default: + LOG_ERR("Reading SR%u is not supported", reg_num); + return -EINVAL; + } + + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_RunReadCommand(data->instance, lut_idx, 0U, val, NULL, sizeof(*val)); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to read SR%u (%d)", reg_num, status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} + +static int nxp_s32_qspi_write_enable(const struct device *dev) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_StatusType status; + int ret = 0; + + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_RunCommand(data->instance, memory_cfg->statusConfig.writeEnableSRLut, 0U); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to enable SR write (%d)", status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} + +static int nxp_s32_qspi_write_status_register(const struct device *dev, + uint8_t reg_num, + uint8_t val) +{ + const struct nxp_s32_qspi_config *config = dev->config; + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + uint8_t buf[2] = { 0 }; + uint16_t lut_idx; + size_t size; + int ret; + + if (reg_num == 1) { + /* buf = [val] or [val, SR2] */ + lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR); + size = 1U; + buf[0] = val; + + if (config->qer_type == JESD216_DW15_QER_S2B1v1) { + /* Writing SR1 clears SR2 */ + size = 2U; + ret = nxp_s32_qspi_read_status_register(dev, 2, &buf[1]); + if (ret < 0) { + return ret; + } + } + } else if (reg_num == 2) { + /* buf = [val] or [SR1, val] */ + if ((config->qer_type == JESD216_DW15_QER_VAL_S2B1v1) || + (config->qer_type == JESD216_DW15_QER_VAL_S2B1v4) || + (config->qer_type == JESD216_DW15_QER_VAL_S2B1v5)) { + /* Writing SR2 requires writing SR1 as well */ + lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR); + size = 2U; + buf[1] = val; + ret = nxp_s32_qspi_read_status_register(dev, 1, &buf[0]); + if (ret < 0) { + return ret; + } + } else { + lut_idx = QSPI_LUT_IDX(QSPI_SEQ_WRSR2); + size = 1U; + buf[0] = val; + } + } else { + return -EINVAL; + } + + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_RunWriteCommand(data->instance, lut_idx, 0U, (const uint8_t *)buf, + (uint32_t)size); + if (status == STATUS_QSPI_IP_SUCCESS) { + /* Wait for the write command to complete */ + ret = nxp_s32_qspi_wait_until_ready(dev); + } else { + LOG_ERR("Failed to write to SR%u (%d)", reg_num, status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} + +static int nxp_s32_qspi_set_quad_mode(const struct device *dev, bool enabled) +{ + const struct nxp_s32_qspi_config *config = dev->config; + uint8_t sr_num; + uint8_t sr_val; + uint8_t qe_mask; + bool qe_state; + int ret; + + switch (config->qer_type) { + case JESD216_DW15_QER_NONE: + /* no QE bit, device detects reads based on opcode */ + return 0; + case JESD216_DW15_QER_S1B6: + sr_num = 1U; + qe_mask = BIT(6U); + break; + case JESD216_DW15_QER_S2B7: + sr_num = 2U; + qe_mask = BIT(7U); + break; + case JESD216_DW15_QER_S2B1v1: + __fallthrough; + case JESD216_DW15_QER_S2B1v4: + __fallthrough; + case JESD216_DW15_QER_S2B1v5: + __fallthrough; + case JESD216_DW15_QER_S2B1v6: + sr_num = 2U; + qe_mask = BIT(1U); + break; + default: + return -ENOTSUP; + } + + ret = nxp_s32_qspi_read_status_register(dev, sr_num, &sr_val); + if (ret < 0) { + return ret; + } + + qe_state = ((sr_val & qe_mask) != 0U); + if (qe_state == enabled) { + return 0; + } + sr_val ^= qe_mask; + + ret = nxp_s32_qspi_write_enable(dev); + if (ret < 0) { + return ret; + } + + ret = nxp_s32_qspi_write_status_register(dev, sr_num, sr_val); + if (ret < 0) { + return ret; + } + + /* Verify write was successful */ + ret = nxp_s32_qspi_read_status_register(dev, sr_num, &sr_val); + if (ret < 0) { + return ret; + } + + qe_state = ((sr_val & qe_mask) != 0U); + if (qe_state != enabled) { + LOG_ERR("Failed to %s Quad mode", enabled ? "enable" : "disable"); + return -EIO; + } + + return ret; +} +#endif /* !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) */ + +static int nxp_s32_qspi_read(const struct device *dev, off_t offset, void *dest, size_t size) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + int ret = 0; + + if (!dest) { + return -EINVAL; + } + + if (!area_is_subregion(dev, offset, size)) { + return -ENODEV; + } + + if (size) { + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_Read(data->instance, (uint32_t)offset, (uint8_t *)dest, + (uint32_t)size); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to read %zu bytes at 0x%lx (%d)", + size, offset, status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + } + + return ret; +} + +static int nxp_s32_qspi_write(const struct device *dev, off_t offset, const void *src, size_t size) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_StatusType status; + size_t max_write = (size_t)MIN(QSPI_IP_MAX_WRITE_SIZE, memory_cfg->pageSize); + size_t len; + int ret = 0; + + if (!src) { + return -EINVAL; + } + + if (!area_is_subregion(dev, offset, size)) { + return -ENODEV; + } + + nxp_s32_qspi_lock(dev); + + while (size) { + len = MIN(max_write - (offset % max_write), size); + status = Qspi_Ip_Program(data->instance, (uint32_t)offset, + (const uint8_t *)src, (uint32_t)len); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to write %zu bytes at 0x%lx (%d)", + len, offset, status); + ret = -EIO; + break; + } + + ret = nxp_s32_qspi_wait_until_ready(dev); + if (ret != 0) { + break; + } + + if (IS_ENABLED(CONFIG_FLASH_NXP_S32_QSPI_VERIFY_WRITE)) { + status = Qspi_Ip_ProgramVerify(data->instance, (uint32_t)offset, + (const uint8_t *)src, (uint32_t)len); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Write verification failed at 0x%lx (%d)", + offset, status); + ret = -EIO; + break; + } + } + + size -= len; + src = (const uint8_t *)src + len; + offset += len; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} + +static int nxp_s32_qspi_erase_block(const struct device *dev, off_t offset, + size_t size, size_t *erase_size) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_EraseVarConfigType *etp = NULL; + Qspi_Ip_EraseVarConfigType *etp_tmp; + Qspi_Ip_StatusType status; + int ret = 0; + + /* + * Find the erase type with bigger size that can erase all or part of the + * requested memory size + */ + for (uint8_t i = 0; i < QSPI_IP_ERASE_TYPES; i++) { + etp_tmp = (Qspi_Ip_EraseVarConfigType *)&(memory_cfg->eraseSettings.eraseTypes[i]); + if ((etp_tmp->eraseLut != QSPI_IP_LUT_INVALID) + && QSPI_IS_ALIGNED(offset, etp_tmp->size) + && (BIT(etp_tmp->size) <= size) + && ((etp == NULL) || (etp_tmp->size > etp->size))) { + + etp = etp_tmp; + } + } + if (etp != NULL) { + *erase_size = BIT(etp->size); + status = Qspi_Ip_EraseBlock(data->instance, (uint32_t)offset, *erase_size); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to erase %zu bytes at 0x%lx (%d)", + *erase_size, (long)offset, status); + ret = -EIO; + } + } else { + LOG_ERR("Can't find erase size to erase %zu bytes", size); + ret = -EINVAL; + } + + return ret; +} + +static int nxp_s32_qspi_erase(const struct device *dev, off_t offset, size_t size) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_StatusType status; + size_t erase_size; + int ret = 0; + + if (!area_is_subregion(dev, offset, size)) { + return -ENODEV; + } + + nxp_s32_qspi_lock(dev); + + if (size == memory_cfg->memSize) { + status = Qspi_Ip_EraseChip(data->instance); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to erase chip (%d)", status); + ret = -EIO; + } + } else { + while (size > 0) { + erase_size = 0; + + ret = nxp_s32_qspi_erase_block(dev, offset, size, &erase_size); + if (ret != 0) { + break; + } + + ret = nxp_s32_qspi_wait_until_ready(dev); + if (ret != 0) { + break; + } + + if (IS_ENABLED(CONFIG_FLASH_NXP_S32_QSPI_VERIFY_ERASE)) { + status = Qspi_Ip_EraseVerify(data->instance, (uint32_t)offset, + erase_size); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Erase verification failed at 0x%lx (%d)", + offset, status); + ret = -EIO; + break; + } + } + + offset += erase_size; + size -= erase_size; + } + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} + +#if defined(CONFIG_FLASH_JESD216_API) || !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +static int nxp_s32_qspi_read_id(const struct device *dev, uint8_t *id) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + int ret = 0; + + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_ReadId(data->instance, id); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to read device ID (%d)", status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} +#endif /* CONFIG_FLASH_JESD216_API || !CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */ + +#if defined(CONFIG_FLASH_JESD216_API) +static int nxp_s32_qspi_sfdp_read(const struct device *dev, off_t offset, void *buf, size_t len) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_StatusType status; + int ret = 0; + + nxp_s32_qspi_lock(dev); + + status = Qspi_Ip_RunReadCommand(data->instance, data->read_sfdp_lut_idx, + (uint32_t)offset, (uint8_t *)buf, NULL, (uint32_t)len); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Failed to read SFDP at 0x%lx (%d)", offset, status); + ret = -EIO; + } + + nxp_s32_qspi_unlock(dev); + + return ret; +} +#endif /* CONFIG_FLASH_JESD216_API */ + +#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) +static int nxp_s32_qspi_sfdp_config(const struct device *dev) +{ + struct nxp_s32_qspi_data *data = dev->data; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_StatusType status; + + /* Populate memory configuration with values obtained from SFDP */ + memory_cfg->memType = QSPI_IP_SERIAL_FLASH; + memory_cfg->lutSequences.opCount = QSPI_SFDP_LUT_SIZE; + memory_cfg->lutSequences.lutOps = (Qspi_Ip_InstrOpType *)data->lut_ops; + memory_cfg->initConfiguration.opCount = QSPI_SFDP_INIT_OP_SIZE; + memory_cfg->initConfiguration.operations = (Qspi_Ip_InitOperationType *)data->init_ops; + + status = Qspi_Ip_ReadSfdp(memory_cfg, &data->memory_conn_cfg); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Fail to read SFDP (%d)", status); + return -EIO; + } + +#if defined(CONFIG_FLASH_JESD216_API) + /* The HAL does not populate LUTs for read SFDP and read ID */ + uint8_t lut_idx = QSPI_SFDP_LUT_SIZE; + + for (int i = 0; i < QSPI_SFDP_LUT_SIZE - 1; i++) { + if ((data->lut_ops[i] == QSPI_IP_LUT_SEQ_END) + && (data->lut_ops[i+1] == QSPI_IP_LUT_SEQ_END)) { + lut_idx = i + 1; + break; + } + } + + /* Make sure there's enough space to add the LUT sequences */ + if ((lut_idx + QSPI_JESD216_SEQ_SIZE - 1) >= QSPI_SFDP_LUT_SIZE) { + return -ENOMEM; + } + + data->read_sfdp_lut_idx = lut_idx; + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, + JESD216_CMD_READ_SFDP); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_ADDR, QSPI_IP_LUT_PADS_1, 24U); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_DUMMY, QSPI_IP_LUT_PADS_1, 8U); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, 16U); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, + QSPI_IP_LUT_SEQ_END); + + memory_cfg->readIdSettings.readIdLut = lut_idx; + memory_cfg->readIdSettings.readIdSize = JESD216_READ_ID_LEN; + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_CMD, QSPI_IP_LUT_PADS_1, + JESD216_CMD_READ_ID); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_READ, QSPI_IP_LUT_PADS_1, + JESD216_READ_ID_LEN); + data->lut_ops[lut_idx++] = QSPI_LUT_OP(QSPI_IP_LUT_INSTR_STOP, QSPI_IP_LUT_SEQ_END, + QSPI_IP_LUT_SEQ_END); +#endif /* CONFIG_FLASH_JESD216_API */ + + return 0; +} +#endif + +static const struct flash_parameters *nxp_s32_qspi_get_parameters(const struct device *dev) +{ + const struct nxp_s32_qspi_config *config = dev->config; + + return &config->flash_parameters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void nxp_s32_qspi_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + const struct nxp_s32_qspi_config *config = dev->config; + + *layout = &config->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static int nxp_s32_qspi_init(const struct device *dev) +{ + struct nxp_s32_qspi_data *data = dev->data; + const struct nxp_s32_qspi_config *config = dev->config; + Qspi_Ip_MemoryConfigType *memory_cfg = get_memory_config(dev); + Qspi_Ip_StatusType status; + static uint8_t instance_cnt; + int ret = 0; + + /* Used by the HAL to retrieve the internal driver state */ + data->instance = instance_cnt++; + __ASSERT_NO_MSG(data->instance < QSPI_IP_MEM_INSTANCE_COUNT); + data->memory_conn_cfg.qspiInstance = memc_nxp_s32_qspi_get_instance(config->controller); + +#if defined(CONFIG_MULTITHREADING) + k_sem_init(&data->sem, 1, 1); +#endif + +#if defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) + nxp_s32_qspi_sfdp_config(dev); +#endif + + /* Init memory device connected to the bus */ + status = Qspi_Ip_Init(data->instance, + (const Qspi_Ip_MemoryConfigType *)memory_cfg, + (const Qspi_Ip_MemoryConnectionType *)&data->memory_conn_cfg); + if (status != STATUS_QSPI_IP_SUCCESS) { + LOG_ERR("Fail to init memory device %d (%d)", data->instance, status); + return -EIO; + } + + +#if !defined(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME) + uint8_t jedec_id[JESD216_READ_ID_LEN]; + + /* Verify connectivity by reading the device ID */ + ret = nxp_s32_qspi_read_id(dev, jedec_id); + if (ret != 0) { + LOG_ERR("JEDEC ID read failed (%d)", ret); + return -ENODEV; + } + + /* + * Check the memory device ID against the one configured from devicetree + * to verify we are talking to the correct device. + */ + if (memcmp(jedec_id, memory_cfg->readIdSettings.readIdExpected, sizeof(jedec_id)) != 0) { + LOG_ERR("Device id %02x %02x %02x does not match config %02x %02x %02x", + jedec_id[0], jedec_id[1], jedec_id[2], + memory_cfg->readIdSettings.readIdExpected[0], + memory_cfg->readIdSettings.readIdExpected[1], + memory_cfg->readIdSettings.readIdExpected[2]); + return -EINVAL; + } + + ret = nxp_s32_qspi_set_quad_mode(dev, config->quad_mode); + if (ret < 0) { + return ret; + } +#endif /* !CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME */ + + return ret; +} + +static const struct flash_driver_api nxp_s32_qspi_api = { + .erase = nxp_s32_qspi_erase, + .write = nxp_s32_qspi_write, + .read = nxp_s32_qspi_read, + .get_parameters = nxp_s32_qspi_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = nxp_s32_qspi_pages_layout, +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = nxp_s32_qspi_sfdp_read, + .read_jedec_id = nxp_s32_qspi_read_id, +#endif /* CONFIG_FLASH_JESD216_API */ +}; + +#define QSPI_PAGE_LAYOUT(n) \ + .layout = { \ + .pages_count = (DT_INST_PROP(n, size) / 8) \ + / CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \ + .pages_size = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \ + } + +#define QSPI_READ_ID_CFG(n) \ + { \ + .readIdLut = QSPI_LUT_IDX(QSPI_SEQ_RDID), \ + .readIdSize = DT_INST_PROP_LEN(n, jedec_id), \ + .readIdExpected = DT_INST_PROP(n, jedec_id), \ + } + +#define QSPI_MEMORY_CONN_CFG(n) \ + { \ + .connectionType = (Qspi_Ip_ConnectionType)DT_INST_REG_ADDR(n), \ + .memAlignment = DT_INST_PROP_OR(n, memory_alignment, 1) \ + } + +#define QSPI_ERASE_CFG(n) \ + { \ + .eraseTypes = { \ + { \ + .eraseLut = QSPI_LUT_IDX(QSPI_SEQ_SE), \ + .size = 12, /* 4 KB */ \ + }, \ + { \ + .eraseLut = QSPI_LUT_IDX(QSPI_SEQ_BE), \ + .size = 16, /* 64 KB */ \ + }, \ + COND_CODE_1(DT_INST_PROP(n, has_32k_erase), ( \ + { \ + .eraseLut = QSPI_LUT_IDX(QSPI_SEQ_BE_32K), \ + .size = 15, /* 32 KB */ \ + }, \ + ), ( \ + { \ + .eraseLut = QSPI_IP_LUT_INVALID, \ + }, \ + )) \ + { \ + .eraseLut = QSPI_IP_LUT_INVALID, \ + }, \ + }, \ + .chipEraseLut = QSPI_LUT_IDX(QSPI_SEQ_CE), \ + } + +#define QSPI_RESET_CFG(n) \ + { \ + .resetCmdLut = QSPI_LUT_IDX(QSPI_SEQ_RESET), \ + .resetCmdCount = 4U, \ + } + +/* + * SR information used internally by the HAL to access fields BUSY and WEL + * during read/write/erase and polling status operations. + */ +#define QSPI_STATUS_REG_CFG(n) \ + { \ + .statusRegInitReadLut = QSPI_LUT_IDX(QSPI_SEQ_RDSR), \ + .statusRegReadLut = QSPI_LUT_IDX(QSPI_SEQ_RDSR), \ + .statusRegWriteLut = QSPI_LUT_IDX(QSPI_SEQ_WRSR), \ + .writeEnableSRLut = QSPI_LUT_IDX(QSPI_SEQ_WREN), \ + .writeEnableLut = QSPI_LUT_IDX(QSPI_SEQ_WREN), \ + .regSize = 1U, \ + .busyOffset = 0U, \ + .busyValue = 1U, \ + .writeEnableOffset = 1U, \ + } + +#define QSPI_INIT_CFG(n) \ + { \ + .opCount = 0U, \ + .operations = NULL, \ + } + +#define QSPI_LUT_CFG(n) \ + { \ + .opCount = ARRAY_SIZE(nxp_s32_qspi_lut), \ + .lutOps = (Qspi_Ip_InstrOpType *)nxp_s32_qspi_lut, \ + } + +#define QSPI_MEMORY_CFG(n) \ + { \ + .memType = QSPI_IP_SERIAL_FLASH, \ + .hfConfig = NULL, \ + .memSize = DT_INST_PROP(n, size) / 8, \ + .pageSize = CONFIG_FLASH_NXP_S32_QSPI_LAYOUT_PAGE_SIZE, \ + .writeLut = QSPI_LUT_IDX(QSPI_WRITE_SEQ(n)), \ + .readLut = QSPI_LUT_IDX(QSPI_READ_SEQ(n)), \ + .read0xxLut = QSPI_IP_LUT_INVALID, \ + .read0xxLutAHB = QSPI_IP_LUT_INVALID, \ + .eraseSettings = QSPI_ERASE_CFG(n), \ + .statusConfig = QSPI_STATUS_REG_CFG(n), \ + .resetSettings = QSPI_RESET_CFG(n), \ + .initResetSettings = QSPI_RESET_CFG(n), \ + .initConfiguration = QSPI_INIT_CFG(n), \ + .lutSequences = QSPI_LUT_CFG(n), \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \ + .readIdSettings = QSPI_READ_ID_CFG(n),) \ + ) \ + .suspendSettings = { \ + .eraseSuspendLut = QSPI_IP_LUT_INVALID, \ + .eraseResumeLut = QSPI_IP_LUT_INVALID, \ + .programSuspendLut = QSPI_IP_LUT_INVALID, \ + .programResumeLut = QSPI_IP_LUT_INVALID, \ + }, \ + .initCallout = NULL, \ + .resetCallout = NULL, \ + .errorCheckCallout = NULL, \ + .eccCheckCallout = NULL, \ + .ctrlAutoCfgPtr = NULL, \ + } + +#define FLASH_NXP_S32_QSPI_INIT_DEVICE(n) \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(n, jedec_id), \ + "jedec-id is required for non-runtime SFDP"); \ + BUILD_ASSERT(DT_INST_PROP_LEN(n, jedec_id) == JESD216_READ_ID_LEN,\ + "jedec-id must be of size JESD216_READ_ID_LEN bytes"); \ + )) \ + \ + static const struct nxp_s32_qspi_config nxp_s32_qspi_config_##n = { \ + .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .flash_parameters = { \ + .write_block_size = QSPI_WRITE_BLOCK_SIZE, \ + .erase_value = QSPI_ERASE_VALUE, \ + }, \ + IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \ + (QSPI_PAGE_LAYOUT(n),)) \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \ + .memory_cfg = QSPI_MEMORY_CFG(n), \ + .qer_type = QSPI_QER_TYPE(n), \ + .quad_mode = QSPI_HAS_QUAD_MODE(n) \ + )) \ + }; \ + \ + static struct nxp_s32_qspi_data nxp_s32_qspi_data_##n = { \ + .memory_conn_cfg = QSPI_MEMORY_CONN_CFG(n), \ + COND_CODE_1(CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME, (), ( \ + .read_sfdp_lut_idx = QSPI_LUT_IDX(QSPI_SEQ_READ_SFDP), \ + )) \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + nxp_s32_qspi_init, \ + NULL, \ + &nxp_s32_qspi_data_##n, \ + &nxp_s32_qspi_config_##n, \ + POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, \ + &nxp_s32_qspi_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_NXP_S32_QSPI_INIT_DEVICE) diff --git a/dts/bindings/mtd/nxp,s32-qspi-device.yaml b/dts/bindings/mtd/nxp,s32-qspi-device.yaml new file mode 100644 index 000000000000..23de077121ec --- /dev/null +++ b/dts/bindings/mtd/nxp,s32-qspi-device.yaml @@ -0,0 +1,22 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + QSPI memory device supporting xSPI or Hyperbus. + +compatible: "nxp,s32-qspi-device" + +include: [base.yaml, "jedec,jesd216.yaml"] + +on-bus: qspi + +properties: + reg: + required: true + + memory-alignment: + type: int + description: | + Memory alignment in bytes, used to calculate padding when performing + unaligned accesses. + If not provided, 1 byte alignment will be selected. diff --git a/dts/bindings/mtd/nxp,s32-qspi-nor.yaml b/dts/bindings/mtd/nxp,s32-qspi-nor.yaml new file mode 100644 index 000000000000..3abe66673b8d --- /dev/null +++ b/dts/bindings/mtd/nxp,s32-qspi-nor.yaml @@ -0,0 +1,38 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + QSPI NOR flash connected to the NXP S32 QSPI bus. + +compatible: "nxp,s32-qspi-nor" + +include: "nxp,s32-qspi-device.yaml" + +properties: + has-32k-erase: + type: boolean + description: | + Set if the memory device supports 32 KiBy block erase operation. + + readoc: + type: string + enum: + - "1-1-1" # 0x0B + - "1-1-2" # 0x3B + - "1-2-2" # 0xBB + - "1-1-4" # 0x6B + - "1-4-4" # 0xEB + description: | + Specify the number of data lines and opcode used for reading. + If not provided, 1-1-1 will be selected. + + writeoc: + type: string + enum: + - "1-1-1" # 0x02 + - "1-1-2" # 0xA2 + - "1-1-4" # 0x32 + - "1-4-4" # 0x38 + description: | + Specify the number of data lines and opcode used for writing. + If not provided, 1-1-1 will be selected. From 3cc1c41f419fa69eb4f1eeaf89551467a17e4ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 7 Jul 2023 13:31:58 -0300 Subject: [PATCH 1813/2042] boards: mr_canhubk3: enable flash controller for QSPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This board has a MX25L6433F memory connected to the only QSPI port available in S32K344. Signed-off-by: Manuel Argüelles --- boards/arm/mr_canhubk3/doc/index.rst | 8 +++++ .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 20 +++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.dts | 36 +++++++++++++++++++ dts/arm/nxp/nxp_s32k344_m7.dtsi | 8 +++++ 4 files changed, 72 insertions(+) diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 00cc3395d03f..5c8c5e2997c3 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -49,6 +49,7 @@ SIUL2 on-chip | pinctrl | gpio | external interrupt controller LPUART on-chip serial +QSPI on-chip flash ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -119,6 +120,13 @@ the watchdog so the FS26 must be started in debug mode following these steps: 3. Power on the board. 4. Reconnect the jumper ``JP1`` (pins 1-2 shorted). +External Flash +============== + +The on-board MX25L6433F 64M-bit multi-I/O Serial NOR Flash memory is connected +to the QSPI controller port A1. This board configuration selects it as the +default flash controller. + Programming and Debugging ************************* diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 2714f448a72e..aedc0ebfb5f4 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -90,4 +90,24 @@ input-enable; }; }; + + qspi0_default: qspi0_default { + group1 { + pinmux = <(PTD11_QUADSPI_IOFA0_O | PTD11_QUADSPI_IOFA0_I)>, + <(PTD7_QUADSPI_IOFA1_O | PTD7_QUADSPI_IOFA1_I)>, + <(PTD12_QUADSPI_IOFA2_O | PTD12_QUADSPI_IOFA2_I)>, + <(PTC2_QUADSPI_IOFA3_O | PTC2_QUADSPI_IOFA3_I)>; + output-enable; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + group3 { + pinmux = ; + output-enable; + bias-pull-up; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index 5a40f2780a84..e068090ec8b9 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -21,6 +21,7 @@ zephyr,code-partition = &code_partition; zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2; + zephyr,flash-controller = &mx25l6433f; }; aliases { @@ -132,3 +133,38 @@ pinctrl-0 = <&lpuart14_default>; pinctrl-names = "default"; }; + +&qspi0 { + pinctrl-0 = <&qspi0_default>; + pinctrl-names = "default"; + data-rate = "SDR"; + a-rx-clock-source = "LOOPBACK"; + a-dll-mode = "BYPASSED"; + ahb-buffers-masters = <0 1 2 3>; + ahb-buffers-sizes = <0 0 0 256>; + ahb-buffers-all-masters; + status = "okay"; + + mx25l6433f: mx25l6433f@0 { + compatible = "nxp,s32-qspi-nor"; + reg = <0>; + size = ; + jedec-id = [c2 20 17]; + quad-enable-requirements = "S1B6"; + readoc = "1-4-4"; + writeoc = "1-4-4"; + has-32k-erase; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0x0 0x100000>; + }; + }; + }; +}; diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 6903cb9edb48..5f2f373e618a 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -415,6 +415,14 @@ clocks = <&clock NXP_S32_LPUART15_CLK>; status = "disabled"; }; + + qspi0: qspi@404cc000 { + compatible = "nxp,s32-qspi"; + reg = <0x404cc000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; }; From 87e40d8b6d6c68a0ce6dc04231e631554a3b8727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 7 Jul 2023 13:32:13 -0300 Subject: [PATCH 1814/2042] samples: enable flash samples for mr_canhubk3 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various samples enabled to use the on-board QSPI memory. Signed-off-by: Manuel Argüelles --- samples/drivers/jesd216/boards/mr_canhubk3.conf | 5 +++++ samples/drivers/jesd216/src/main.c | 2 ++ samples/subsys/fs/littlefs/sample.yaml | 1 + samples/subsys/settings/boards/mr_canhubk3.conf | 8 ++++++++ samples/subsys/settings/sample.yaml | 1 + samples/subsys/shell/fs/sample.yaml | 1 + 6 files changed, 18 insertions(+) create mode 100644 samples/drivers/jesd216/boards/mr_canhubk3.conf create mode 100644 samples/subsys/settings/boards/mr_canhubk3.conf diff --git a/samples/drivers/jesd216/boards/mr_canhubk3.conf b/samples/drivers/jesd216/boards/mr_canhubk3.conf new file mode 100644 index 000000000000..b625f401a1c8 --- /dev/null +++ b/samples/drivers/jesd216/boards/mr_canhubk3.conf @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Override defaults for SPI NOR flash driver +CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 80890fa3301d..795bd5152129 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -20,6 +20,8 @@ #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_qspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_ospi_nor) #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) #else #error Unsupported flash driver #define FLASH_NODE DT_INVALID_NODE diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml index 2a6dbc0853e7..6cccec311eff 100644 --- a/samples/subsys/fs/littlefs/sample.yaml +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -14,6 +14,7 @@ tests: - native_posix - mimxrt1160_evk_cm7 - lpcxpresso55s69_cpu0 + - mr_canhubk3 tags: filesystem integration_platforms: - nrf52840dk_nrf52840 diff --git a/samples/subsys/settings/boards/mr_canhubk3.conf b/samples/subsys/settings/boards/mr_canhubk3.conf new file mode 100644 index 000000000000..6ca210a81ac2 --- /dev/null +++ b/samples/subsys/settings/boards/mr_canhubk3.conf @@ -0,0 +1,8 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Use LittleFS file system as Settings backend +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_SETTINGS_FILE=y +CONFIG_SETTINGS_FILE_PATH="/ff/settings/run" diff --git a/samples/subsys/settings/sample.yaml b/samples/subsys/settings/sample.yaml index 147e03c4891e..47276f1e6975 100644 --- a/samples/subsys/settings/sample.yaml +++ b/samples/subsys/settings/sample.yaml @@ -9,6 +9,7 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - mr_canhubk3 integration_platforms: - native_posix harness: console diff --git a/samples/subsys/shell/fs/sample.yaml b/samples/subsys/shell/fs/sample.yaml index b0e8e09dfe87..e66f984e929d 100644 --- a/samples/subsys/shell/fs/sample.yaml +++ b/samples/subsys/shell/fs/sample.yaml @@ -10,6 +10,7 @@ tests: platform_allow: - reel_board - mimxrt1060_evk + - mr_canhubk3 integration_platforms: - reel_board From 23259aecdd35370d711201ba2c116850ee1f412e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Fri, 7 Jul 2023 13:32:28 -0300 Subject: [PATCH 1815/2042] tests: enable flash tests for mr_canhubk3 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various tests enabled to use the on-board QSPI memory. Signed-off-by: Manuel Argüelles --- tests/drivers/flash/boards/mr_canhubk3.conf | 4 +++ tests/drivers/flash/common/testcase.yaml | 4 +++ .../subsys/fs/fcb/boards/mr_canhubk3.overlay | 16 +++++++++ tests/subsys/fs/fcb/testcase.yaml | 1 + .../fs/littlefs/boards/mr_canhubk3.overlay | 24 +++++++++++++ tests/subsys/fs/littlefs/testcase.yaml | 1 + .../log_backend_fs/boards/mr_canhubk3.overlay | 35 +++++++++++++++++++ .../logging/log_backend_fs/testcase.yaml | 4 +++ tests/subsys/settings/fcb/testcase.yaml | 1 + .../settings/file/boards/mr_canhubk3.overlay | 16 +++++++++ tests/subsys/settings/file/testcase.yaml | 1 + .../settings/functional/fcb/testcase.yaml | 2 ++ .../settings/functional/file/testcase.yaml | 1 + .../flash_map/boards/mr_canhubk3.overlay | 18 ++++++++++ tests/subsys/storage/flash_map/testcase.yaml | 2 ++ 15 files changed, 130 insertions(+) create mode 100644 tests/drivers/flash/boards/mr_canhubk3.conf create mode 100644 tests/subsys/fs/fcb/boards/mr_canhubk3.overlay create mode 100644 tests/subsys/fs/littlefs/boards/mr_canhubk3.overlay create mode 100644 tests/subsys/logging/log_backend_fs/boards/mr_canhubk3.overlay create mode 100644 tests/subsys/settings/file/boards/mr_canhubk3.overlay create mode 100644 tests/subsys/storage/flash_map/boards/mr_canhubk3.overlay diff --git a/tests/drivers/flash/boards/mr_canhubk3.conf b/tests/drivers/flash/boards/mr_canhubk3.conf new file mode 100644 index 000000000000..80524faf3ec8 --- /dev/null +++ b/tests/drivers/flash/boards/mr_canhubk3.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MAIN_STACK_SIZE=1100 diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 942589ec3ece..c37515e91409 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -76,3 +76,7 @@ tests: - DTC_OVERLAY_FILE=boards/nrf52840dk_mx25r_high_perf.overlay integration_platforms: - nrf52840dk_nrf52840 + drivers.flash.common.mr_canhubk3_sfdp_runtime: + platform_allow: mr_canhubk3 + extra_configs: + - CONFIG_FLASH_NXP_S32_QSPI_NOR_SFDP_RUNTIME=y diff --git a/tests/subsys/fs/fcb/boards/mr_canhubk3.overlay b/tests/subsys/fs/fcb/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..c4ac18daf390 --- /dev/null +++ b/tests/subsys/fs/fcb/boards/mr_canhubk3.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Currently there's no support for mcuboot, so create a partition for this test. + */ +&mx25l6433f { + partitions { + slot1_partition: partition@100000 { + reg = <0x100000 0x100000>; + }; + }; +}; diff --git a/tests/subsys/fs/fcb/testcase.yaml b/tests/subsys/fs/fcb/testcase.yaml index d15d9c6e583e..4902bfa2a65b 100644 --- a/tests/subsys/fs/fcb/testcase.yaml +++ b/tests/subsys/fs/fcb/testcase.yaml @@ -6,6 +6,7 @@ tests: - nrf51dk_nrf51422 - native_posix - native_posix_64 + - mr_canhubk3 tags: flash_circural_buffer integration_platforms: - nrf52840dk_nrf52840 diff --git a/tests/subsys/fs/littlefs/boards/mr_canhubk3.overlay b/tests/subsys/fs/littlefs/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..fc8083d4374d --- /dev/null +++ b/tests/subsys/fs/littlefs/boards/mr_canhubk3.overlay @@ -0,0 +1,24 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&mx25l6433f { + partitions { + 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/testcase.yaml b/tests/subsys/fs/littlefs/testcase.yaml index 0bb2c84991b9..cdb12a7b1e10 100644 --- a/tests/subsys/fs/littlefs/testcase.yaml +++ b/tests/subsys/fs/littlefs/testcase.yaml @@ -5,6 +5,7 @@ common: - native_posix - native_posix_64 - mimxrt1060_evk + - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 modules: diff --git a/tests/subsys/logging/log_backend_fs/boards/mr_canhubk3.overlay b/tests/subsys/logging/log_backend_fs/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..a0dd5f7c31f3 --- /dev/null +++ b/tests/subsys/logging/log_backend_fs/boards/mr_canhubk3.overlay @@ -0,0 +1,35 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +/ { + fstab { + compatible = "zephyr,fstab"; + lfs1: lfs1 { + compatible = "zephyr,fstab,littlefs"; + mount-point = "/lfs1"; + partition = <&lfs1_part>; + read-size = <16>; + prog-size = <16>; + cache-size = <64>; + lookahead-size = <32>; + block-cycles = <512>; + }; + }; +}; + +&mx25l6433f { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + lfs1_part: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00010000>; + }; + }; +}; diff --git a/tests/subsys/logging/log_backend_fs/testcase.yaml b/tests/subsys/logging/log_backend_fs/testcase.yaml index 9fc9cea414ed..c9e7e8ace517 100644 --- a/tests/subsys/logging/log_backend_fs/testcase.yaml +++ b/tests/subsys/logging/log_backend_fs/testcase.yaml @@ -12,6 +12,7 @@ tests: - native_posix - native_posix_64 - nrf52840dk_nrf52840 + - mr_canhubk3 integration_platforms: - native_posix logging.log_backend_fs.manualmounted.native_posix: @@ -29,3 +30,6 @@ tests: extra_args: DTC_OVERLAY_FILE="./boards/nrf52840dk_nrf52840.overlay;./boards/automount.overlay" integration_platforms: - nrf52840dk_nrf52840 + logging.log_backend_fs.manualmounted.mr_canhubk3: + platform_allow: mr_canhubk3 + extra_args: DTC_OVERLAY_FILE="./boards/mr_canhubk3.overlay;./boards/automount.overlay" diff --git a/tests/subsys/settings/fcb/testcase.yaml b/tests/subsys/settings/fcb/testcase.yaml index 76d5525f5533..15d286e565dc 100644 --- a/tests/subsys/settings/fcb/testcase.yaml +++ b/tests/subsys/settings/fcb/testcase.yaml @@ -5,6 +5,7 @@ tests: - nrf52dk_nrf52832 - native_posix - native_posix_64 + - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 - native_posix diff --git a/tests/subsys/settings/file/boards/mr_canhubk3.overlay b/tests/subsys/settings/file/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..9ced9abc73d5 --- /dev/null +++ b/tests/subsys/settings/file/boards/mr_canhubk3.overlay @@ -0,0 +1,16 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&mx25l6433f { + partitions { + settings_file_partition: partition@0 { + label = "settings_file_partition"; + reg = <0x00000000 0x00010000>; + }; + }; +}; diff --git a/tests/subsys/settings/file/testcase.yaml b/tests/subsys/settings/file/testcase.yaml index 6b2b4f8e7116..2d1e2635873b 100644 --- a/tests/subsys/settings/file/testcase.yaml +++ b/tests/subsys/settings/file/testcase.yaml @@ -7,6 +7,7 @@ tests: - nrf52840dk_nrf52840 - native_posix - native_posix_64 + - mr_canhubk3 tags: - settings_file - settings_file_littlefs diff --git a/tests/subsys/settings/functional/fcb/testcase.yaml b/tests/subsys/settings/functional/fcb/testcase.yaml index 1e4d3d688dd6..5d02f3c701b8 100644 --- a/tests/subsys/settings/functional/fcb/testcase.yaml +++ b/tests/subsys/settings/functional/fcb/testcase.yaml @@ -5,6 +5,7 @@ tests: - nrf52dk_nrf52832 - native_posix - native_posix_64 + - mr_canhubk3 integration_platforms: - nrf52840dk_nrf52840 tags: settings_fcb @@ -13,6 +14,7 @@ tests: platform_allow: - native_posix - native_posix_64 + - mr_canhubk3 integration_platforms: - native_posix tags: settings_fcb diff --git a/tests/subsys/settings/functional/file/testcase.yaml b/tests/subsys/settings/functional/file/testcase.yaml index 55f89307dc74..49c3e4c32afb 100644 --- a/tests/subsys/settings/functional/file/testcase.yaml +++ b/tests/subsys/settings/functional/file/testcase.yaml @@ -5,6 +5,7 @@ tests: - nrf52dk_nrf52832 - native_posix - native_posix_64 + - mr_canhubk3 integration_platforms: - native_posix tags: settings_file diff --git a/tests/subsys/storage/flash_map/boards/mr_canhubk3.overlay b/tests/subsys/storage/flash_map/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..119d280177df --- /dev/null +++ b/tests/subsys/storage/flash_map/boards/mr_canhubk3.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" + +/* + * Currently there's no support for mcuboot, so create a partition for this test. + */ +&mx25l6433f { + partitions { + slot1_partition: partition@100000 { + reg = <0x100000 0x100000>; + }; + }; +}; diff --git a/tests/subsys/storage/flash_map/testcase.yaml b/tests/subsys/storage/flash_map/testcase.yaml index 307a9520f50d..b9b13002d520 100644 --- a/tests/subsys/storage/flash_map/testcase.yaml +++ b/tests/subsys/storage/flash_map/testcase.yaml @@ -5,6 +5,7 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - mr_canhubk3 tags: flash_map integration_platforms: - native_posix @@ -26,6 +27,7 @@ tests: - qemu_x86 - native_posix - native_posix_64 + - mr_canhubk3 tags: flash_map integration_platforms: - native_posix From 927dda06fa0abc6f7ec3c964b727ed97baddbd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Tue, 25 Jul 2023 12:56:33 +0200 Subject: [PATCH 1816/2042] drivers: spi_nrfx_spis: Fix obtaining dev pointer in event handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to commit 4c20403629df1ae6a58d37a7a5bd73d4698cc11a. CONTAINER_OF() cannot be used to obtain the device pointer from its data pointer as this data is not contained in the device structure. Instead, use a dedicated member in the device data structure to store the device pointer. Signed-off-by: Andrzej Głąbek --- drivers/spi/spi_nrfx_spis.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index d16377a42464..9ea2f9fb7dea 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -17,6 +17,7 @@ LOG_MODULE_REGISTER(spi_nrfx_spis, CONFIG_SPI_LOG_LEVEL); struct spi_nrfx_data { struct spi_context ctx; + const struct device *dev; }; struct spi_nrfx_config { @@ -219,10 +220,10 @@ static const struct spi_driver_api spi_nrfx_driver_api = { static void event_handler(const nrfx_spis_evt_t *p_event, void *p_context) { struct spi_nrfx_data *dev_data = p_context; - struct device *dev = CONTAINER_OF(dev_data, struct device, data); if (p_event->evt_type == NRFX_SPIS_XFER_DONE) { - spi_context_complete(&dev_data->ctx, dev, p_event->rx_amount); + spi_context_complete(&dev_data->ctx, dev_data->dev, + p_event->rx_amount); } } @@ -273,6 +274,7 @@ static int spi_nrfx_init(const struct device *dev) static struct spi_nrfx_data spi_##idx##_data = { \ SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \ + .dev = DEVICE_DT_GET(SPIS(idx)), \ }; \ PINCTRL_DT_DEFINE(SPIS(idx)); \ static const struct spi_nrfx_config spi_##idx##z_config = { \ From 86050556c0e983c527f49de79859d979fa9f2242 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 18:07:12 +1000 Subject: [PATCH 1817/2042] gpio: stellaris: implement `gpio_pin_get_config` Implement `gpio_pin_get_config` for the stellaris platform, and by extension `qemu_cortex_m3`. Signed-off-by: Jordan Yates --- drivers/gpio/gpio_stellaris.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpio/gpio_stellaris.c b/drivers/gpio/gpio_stellaris.c index 433962e10585..e7114fa0e7f1 100644 --- a/drivers/gpio/gpio_stellaris.c +++ b/drivers/gpio/gpio_stellaris.c @@ -107,6 +107,34 @@ static int gpio_stellaris_configure(const struct device *dev, return 0; } +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_stellaris_get_config(const struct device *dev, + gpio_pin_t pin, + gpio_flags_t *out_flags) +{ + const struct gpio_stellaris_config *cfg = dev->config; + uint32_t base = cfg->base; + gpio_flags_t flags = 0; + mm_reg_t mask_addr; + + if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin) == 0) { + flags = GPIO_DISCONNECTED; + } else if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin)) { + mask_addr = GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, BIT(pin)); + + if (sys_test_bit(mask_addr, pin)) { + flags |= GPIO_OUTPUT_HIGH; + } else { + flags |= GPIO_OUTPUT_LOW; + } + } else { + flags = GPIO_INPUT; + } + *out_flags = flags; + return 0; +} +#endif + static int gpio_stellaris_port_get_raw(const struct device *dev, uint32_t *value) { @@ -221,6 +249,9 @@ static int gpio_stellaris_manage_callback(const struct device *dev, static const struct gpio_driver_api gpio_stellaris_driver_api = { .pin_configure = gpio_stellaris_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_stellaris_get_config, +#endif .port_get_raw = gpio_stellaris_port_get_raw, .port_set_masked_raw = gpio_stellaris_port_set_masked_raw, .port_set_bits_raw = gpio_stellaris_port_set_bits_raw, From 5be8664e8dd023b67e6a3bc3ffab28f54c1c3547 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Mon, 11 Apr 2022 21:24:58 +1000 Subject: [PATCH 1818/2042] pm: device: add driver init helper Adds a helper function for initializing devices into the expected power state, through the devices `pm_device_action_cb_t`. This eliminates code duplication between the init functions and the PM callback. The expected device states in order of priority are: * No power applied to device, `OFF` * `zephyr,pm-device-runtime-auto` enabled, `SUSPEND` * Otherwise, `ACTIVE` Signed-off-by: Jordan Yates --- include/zephyr/pm/device.h | 29 +++++++++++++++++++++++++++++ subsys/pm/device.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index 734f6c08a60f..29cd4b26a1e8 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -581,6 +581,22 @@ int pm_device_power_domain_remove(const struct device *dev, * @retval false If device is not currently powered */ bool pm_device_is_powered(const struct device *dev); + +/** + * @brief Setup a device driver into the lowest valid power mode + * + * This helper function is intended to be called at the end of a driver + * init function to automatically setup the device into the lowest power + * mode. It assumes that the device has been configured as if it is in + * @ref PM_DEVICE_STATE_OFF. + * + * @param dev Device instance. + * @param action_cb Device PM control callback function. + * @retval 0 On success. + * @retval -errno Error code from @a action_cb on failure. + */ +int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb); + #else static inline int pm_device_state_get(const struct device *dev, enum pm_device_state *state) @@ -667,6 +683,19 @@ static inline bool pm_device_is_powered(const struct device *dev) ARG_UNUSED(dev); return true; } + +static inline int pm_device_driver_init(const struct device *dev, pm_device_action_cb_t action_cb) +{ + int rc; + + /* When power management is not enabled, all drivers should initialise to active state */ + rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); + if (rc == 0) { + rc = action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + return rc; +} + #endif /* CONFIG_PM_DEVICE */ /** @} */ diff --git a/subsys/pm/device.c b/subsys/pm/device.c index baf37983d692..bba0c316257a 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -385,3 +385,41 @@ bool pm_device_is_powered(const struct device *dev) return true; #endif } + +int pm_device_driver_init(const struct device *dev, + pm_device_action_cb_t action_cb) +{ + struct pm_device *pm = dev->pm; + int rc = 0; + + /* Work only needs to be performed if the device is powered */ + if (pm_device_is_powered(dev)) { + /* Run power-up logic */ + rc = action_cb(dev, PM_DEVICE_ACTION_TURN_ON); + if (rc != 0) { + return rc; + } + /* If device has no PM structure */ + if (pm == NULL) { + /* Device should always be active */ + return action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + /* If device will have PM device runtime enabled */ + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) && + atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_AUTO)) { + /* Init into suspend mode. + * This saves a SUSPENDED->ACTIVE->SUSPENDED cycle. + */ + pm_device_init_suspended(dev); + } + /* No PM enabled on the device by default */ + else { + /* Startup into active mode */ + return action_cb(dev, PM_DEVICE_ACTION_RESUME); + } + } else { + /* Start in off mode */ + pm_device_init_off(dev); + } + return rc; +} From 1ddadaf2553013f8257ced904d0aedaac0b1bdfb Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 18:10:28 +1000 Subject: [PATCH 1819/2042] power_domain: gpio: compile without `PM_DEVICE_POWER_DOMAIN` Let the driver compile without `PM_DEVICE_POWER_DOMAIN`, in which case the driver only controls the GPIO, without notifying dependant devices. Signed-off-by: Jordan Yates --- drivers/power_domain/power_domain_gpio.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 511564dbc335..88178531504f 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -30,6 +30,8 @@ struct pd_visitor_context { enum pm_device_action action; }; +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + static int pd_on_domain_visitor(const struct device *dev, void *context) { struct pd_visitor_context *visitor_context = context; @@ -43,12 +45,16 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) return 0; } +#endif + static int pd_gpio_pm_action(const struct device *dev, enum pm_device_action action) { +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + struct pd_visitor_context context = {.domain = dev}; +#endif const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; - struct pd_visitor_context context = {.domain = dev}; int64_t next_boot_ticks; int rc = 0; @@ -67,14 +73,18 @@ static int pd_gpio_pm_action(const struct device *dev, LOG_INF("%s is now ON", dev->name); /* Wait for domain to come up */ k_sleep(K_USEC(cfg->startup_delay_us)); +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain they are now powered */ context.action = PM_DEVICE_ACTION_TURN_ON; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); +#endif break; case PM_DEVICE_ACTION_SUSPEND: +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN /* Notify devices on the domain that power is going down */ context.action = PM_DEVICE_ACTION_TURN_OFF; (void)device_supported_foreach(dev, pd_on_domain_visitor, &context); +#endif /* Switch power off */ gpio_pin_set_dt(&cfg->enable, 0); LOG_INF("%s is now OFF", dev->name); From 014760234b12ec9c40ef6afd70b183ea083b52c9 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 11:12:34 +1000 Subject: [PATCH 1820/2042] power_domain: gpio: init with `pm_device_driver_init` Startup power domains according to the expected final state given the power supply and PM device runtime support. Signed-off-by: Jordan Yates --- drivers/power_domain/power_domain_gpio.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 88178531504f..c0fb25b3d457 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -113,7 +113,6 @@ static int pd_gpio_init(const struct device *dev) { const struct pd_gpio_config *cfg = dev->config; struct pd_gpio_data *data = dev->data; - int rc; if (!device_is_ready(cfg->enable.port)) { LOG_ERR("GPIO port %s is not ready", cfg->enable.port->name); @@ -122,16 +121,8 @@ static int pd_gpio_init(const struct device *dev) /* We can't know how long the domain has been off for before boot */ data->next_boot = K_TIMEOUT_ABS_US(cfg->off_on_delay_us); - if (pm_device_on_power_domain(dev)) { - /* Device is unpowered */ - pm_device_init_off(dev); - rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); - } else { - pm_device_init_suspended(dev); - rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); - } - - return rc; + /* Boot according to state */ + return pm_device_driver_init(dev, pd_gpio_pm_action); } #define POWER_DOMAIN_DEVICE(id) \ From 40d693371f5a39e50a6cfedcdb842cdb86f297d5 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sun, 16 Jul 2023 17:22:11 +1000 Subject: [PATCH 1821/2042] tests: pm: update power domain behaviour Update the expected power domain behaviour in the tests in line with the driver implementation changes. Signed-off-by: Jordan Yates --- tests/subsys/pm/device_power_domains/src/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/subsys/pm/device_power_domains/src/main.c b/tests/subsys/pm/device_power_domains/src/main.c index 8bc7789fa4b0..50726bcef199 100644 --- a/tests/subsys/pm/device_power_domains/src/main.c +++ b/tests/subsys/pm/device_power_domains/src/main.c @@ -40,17 +40,17 @@ ZTEST(device_power_domain, test_demo) /* Initial power state */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); - zassert_false(pm_device_is_powered(reg_chained), ""); - zassert_false(pm_device_is_powered(dev), ""); + zassert_true(pm_device_is_powered(reg_chained), ""); + zassert_true(pm_device_is_powered(dev), ""); TC_PRINT("Enabling runtime power management on regulators\n"); - pm_device_runtime_enable(reg_0); - pm_device_runtime_enable(reg_1); - pm_device_runtime_enable(reg_chained); pm_device_runtime_enable(dev); + pm_device_runtime_enable(reg_chained); + pm_device_runtime_enable(reg_1); + pm_device_runtime_enable(reg_0); - /* State shouldn't have changed */ + /* Power domains should now be suspended */ zassert_true(pm_device_is_powered(reg_0), ""); zassert_true(pm_device_is_powered(reg_1), ""); zassert_false(pm_device_is_powered(reg_chained), ""); From b979ee9c0ac81913ff09c33acefd00e71d7e0022 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 15 Jul 2023 17:17:32 +1000 Subject: [PATCH 1822/2042] tests: pm: test `pm_device_driver_init` Test that `pm_device_driver_init` puts devices into the appropriate state depending on the devicetree configuration. Signed-off-by: Jordan Yates --- .../pm/device_driver_init/CMakeLists.txt | 8 +++ .../subsys/pm/device_driver_init/app.overlay | 44 +++++++++++++ tests/subsys/pm/device_driver_init/prj.conf | 9 +++ tests/subsys/pm/device_driver_init/src/main.c | 66 +++++++++++++++++++ .../pm/device_driver_init/testcase.yaml | 17 +++++ 5 files changed, 144 insertions(+) create mode 100644 tests/subsys/pm/device_driver_init/CMakeLists.txt create mode 100644 tests/subsys/pm/device_driver_init/app.overlay create mode 100644 tests/subsys/pm/device_driver_init/prj.conf create mode 100644 tests/subsys/pm/device_driver_init/src/main.c create mode 100644 tests/subsys/pm/device_driver_init/testcase.yaml diff --git a/tests/subsys/pm/device_driver_init/CMakeLists.txt b/tests/subsys/pm/device_driver_init/CMakeLists.txt new file mode 100644 index 000000000000..ddb4b524925a --- /dev/null +++ b/tests/subsys/pm/device_driver_init/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023, CSIRO. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(device_driver_init) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/pm/device_driver_init/app.overlay b/tests/subsys/pm/device_driver_init/app.overlay new file mode 100644 index 000000000000..a5518b74be2c --- /dev/null +++ b/tests/subsys/pm/device_driver_init/app.overlay @@ -0,0 +1,44 @@ +/ { + test_reg: test_reg { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 0 0>; + }; + + test_reg_chained: test_reg_chained { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 1 0>; + power-domain = <&test_reg>; + }; + + test_reg_chained_auto: test_reg_chained_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 2 0>; + power-domain = <&test_reg>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_auto: test_reg_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 3 0>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_auto_chained: test_reg_auto_chained { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 4 0>; + power-domain = <&test_reg_auto>; + }; + + test_reg_auto_chained_auto: test_reg_auto_chained_auto { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 5 0>; + power-domain = <&test_reg_auto>; + zephyr,pm-device-runtime-auto; + }; + + test_reg_disabled: test_reg_disabled { + compatible = "power-domain-gpio"; + enable-gpios = <&gpio0 6 0>; + status = "disabled"; + }; +}; diff --git a/tests/subsys/pm/device_driver_init/prj.conf b/tests/subsys/pm/device_driver_init/prj.conf new file mode 100644 index 000000000000..e6d05f591acf --- /dev/null +++ b/tests/subsys/pm/device_driver_init/prj.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Commonwealth Scientific and Industrial Research +# Organisation (CSIRO) ABN 41 687 119 230. +CONFIG_ZTEST=y +CONFIG_MP_MAX_NUM_CPUS=1 + +CONFIG_GPIO=y +CONFIG_GPIO_GET_CONFIG=y +CONFIG_POWER_DOMAIN=y +CONFIG_ZTEST_NEW_API=y diff --git a/tests/subsys/pm/device_driver_init/src/main.c b/tests/subsys/pm/device_driver_init/src/main.c new file mode 100644 index 000000000000..55621b95faaa --- /dev/null +++ b/tests/subsys/pm/device_driver_init/src/main.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023, Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * SPDX-License-Identifier: Apache-2.0 + * + * State checking in this test is done via the GPIO state instead of + * the PM API as this test runs without the PM api enabled. + */ + +#include +#include +#include +#include + +#define POWER_GPIO_CONFIG_IS(node_id, config)\ + {\ + const struct gpio_dt_spec gpio = GPIO_DT_SPEC_GET(node_id, enable_gpios);\ + gpio_flags_t gpio_config; \ + int rc = gpio_pin_get_config_dt(&gpio, &gpio_config); \ + zassert_equal(rc, 0, "GPIO config retrieval failed"); \ + zassert_equal(gpio_config, config, "Unexpected config");\ + } + +#define DEVICE_STATE_IS(node_id, value) \ + rc = pm_device_state_get(DEVICE_DT_GET(node_id), &state); \ + zassert_equal(rc, 0, "Device state retrieval failed"); \ + zassert_equal(state, value, "Unexpected device state"); + +ZTEST(device_driver_init, test_demo) +{ +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + enum pm_device_state state; + int rc; + + /* 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); + + /* 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); + /* 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); +#else + /* Every regulator should be in "active" mode automatically. + * State checking via GPIO as PM API is disabled. + */ + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_chained_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_auto_chained_auto), GPIO_OUTPUT_HIGH); + POWER_GPIO_CONFIG_IS(DT_NODELABEL(test_reg_disabled), GPIO_DISCONNECTED); +#endif +} + +ZTEST_SUITE(device_driver_init, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/pm/device_driver_init/testcase.yaml b/tests/subsys/pm/device_driver_init/testcase.yaml new file mode 100644 index 000000000000..e3e35d97841b --- /dev/null +++ b/tests/subsys/pm/device_driver_init/testcase.yaml @@ -0,0 +1,17 @@ +tests: + pm.device_driver_init: + tags: pm + platform_allow: qemu_cortex_m3 + pm.device_driver_init.pm: + tags: pm + platform_allow: qemu_cortex_m3 + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_POWER_DOMAIN=y + pm.device_driver_init.pm_device_runtime: + tags: pm + platform_allow: qemu_cortex_m3 + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_POWER_DOMAIN=y + - CONFIG_PM_DEVICE_RUNTIME=y From 41e9547ead07f29c16dc5006256d56a029ca8523 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Tue, 25 Jul 2023 10:58:20 +0200 Subject: [PATCH 1823/2042] drivers: usb: fix common misspellings in USB drivers Fix common misspellings in USB drivers. Signed-off-by: Johann Fischer --- drivers/usb/device/usb_dc_it82xx2.c | 4 ++-- drivers/usb/device/usb_dc_kinetis.c | 2 +- drivers/usb/device/usb_dc_sam_usbc.c | 2 +- drivers/usb/device/usb_dc_sam_usbhs.c | 2 +- drivers/usb/device/usb_dw_registers.h | 4 ++-- drivers/usb/udc/udc_kinetis.c | 4 ++-- drivers/usb/udc/udc_nrf.c | 2 +- include/zephyr/drivers/usb/udc.h | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index d90c351841b3..a18244aa1be4 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -301,7 +301,7 @@ static void it8xxx2_usb_dc_wuc_init(const struct device *dev) /* Enabling the WUI */ it8xxx2_wuc_enable(cfg->wuc_list[0].wucs, cfg->wuc_list[0].mask); - /* Connect WU90 (USB D+) interrupt but make it disabled initally */ + /* Connect WU90 (USB D+) interrupt but make it disabled initially */ IRQ_CONNECT(IT8XXX2_WU90_IRQ, 0, it82xx2_wu90_isr, 0, 0); } @@ -1157,7 +1157,7 @@ int usb_dc_ep_enable(const uint8_t ep) if (ep_idx < EP4) { LOG_DBG("ep_idx < 4"); ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; - LOG_DBG("EP%d Enbabled %02x", ep_idx, ep_regs[ep_idx].ep_ctrl); + 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); diff --git a/drivers/usb/device/usb_dc_kinetis.c b/drivers/usb/device/usb_dc_kinetis.c index 9cb78c0230ce..5f45a59f1944 100644 --- a/drivers/usb/device/usb_dc_kinetis.c +++ b/drivers/usb/device/usb_dc_kinetis.c @@ -878,7 +878,7 @@ static void usb_kinetis_isr_handler(void) /* * Device reset is not possible because the stack does not * configure the endpoints after the USB_DC_RESET event, - * therefore, we must reenable the default control 0 endpoint + * therefore, we must re-enable the default control 0 endpoint * after a reset event */ USB0->CTL |= USB_CTL_ODDRST_MASK; diff --git a/drivers/usb/device/usb_dc_sam_usbc.c b/drivers/usb/device/usb_dc_sam_usbc.c index eff44ee8ac31..20162593400c 100644 --- a/drivers/usb/device/usb_dc_sam_usbc.c +++ b/drivers/usb/device/usb_dc_sam_usbc.c @@ -1109,7 +1109,7 @@ int usb_dc_ep_flush(uint8_t ep) dev_data.ep_data[ep_idx].out_at = 0U; - /* Reenable interrupts */ + /* Re-enable interrupts */ usb_dc_ep_enable_interrupts(ep_idx); irq_unlock(key); diff --git a/drivers/usb/device/usb_dc_sam_usbhs.c b/drivers/usb/device/usb_dc_sam_usbhs.c index 5f8288655d52..6415b4abfcf6 100644 --- a/drivers/usb/device/usb_dc_sam_usbhs.c +++ b/drivers/usb/device/usb_dc_sam_usbhs.c @@ -710,7 +710,7 @@ int usb_dc_ep_flush(uint8_t ep) /* Reset the endpoint */ usb_dc_ep_reset(ep_idx); - /* Reenable interrupts */ + /* Re-enable interrupts */ usb_dc_ep_enable_interrupts(ep_idx); LOG_DBG("ep 0x%x", ep); diff --git a/drivers/usb/device/usb_dw_registers.h b/drivers/usb/device/usb_dw_registers.h index 44676232f371..83e67c157ced 100644 --- a/drivers/usb/device/usb_dw_registers.h +++ b/drivers/usb/device/usb_dw_registers.h @@ -198,7 +198,7 @@ BUILD_ASSERT(sizeof(struct usb_dw_reg) <= 0x0D00); * IN endpoint offsets 0x0900 + (0x20 * n), n = 0 .. x, * offset 0x0900 and 0x0B00 are hardcoded to control type. * - * REVISE: Better own defenitions for DIEPTCTL0, DOEPTCTL0... + * REVISE: Better own definitions for DIEPTCTL0, DOEPTCTL0... */ #define USB_DW_DEPCTL_EP_ENA BIT(31) #define USB_DW_DEPCTL_EP_DIS BIT(30) @@ -242,7 +242,7 @@ BUILD_ASSERT(sizeof(struct usb_dw_reg) <= 0x0D00); * IN at offsets 0x0910 + (0x20 * n), n = 0 .. x, * OUT at offsets 0x0B10 + (0x20 * n), n = 0 .. x * - * REVISE: Better own defenitions for DIEPTSIZ0, DOEPTSIZ0... + * REVISE: Better own definitions for DIEPTSIZ0, DOEPTSIZ0... */ #define USB_DW_DEPTSIZ_PKT_CNT_OFFSET 19 #define USB_DW_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19) diff --git a/drivers/usb/udc/udc_kinetis.c b/drivers/usb/udc/udc_kinetis.c index 188fca5f1e82..961e8b3ba082 100644 --- a/drivers/usb/udc/udc_kinetis.c +++ b/drivers/usb/udc/udc_kinetis.c @@ -40,7 +40,7 @@ LOG_MODULE_REGISTER(usbfsotg, CONFIG_UDC_DRIVER_LOG_LEVEL); #define USBFSOTG_REV 0x33 /* - * There is no real advantage to change control enpoint size + * There is no real advantage to change control endpoint size * but we can use it for testing UDC driver API and higher layers. */ #define USBFSOTG_MPS0 UDC_MPS0_64 @@ -498,7 +498,7 @@ static void xfer_work_handler(struct k_work *item) udc_submit_event(ev->dev, UDC_EVT_ERROR, err); } - /* Peek next transer */ + /* Peek next transfer */ if (ev->ep != USB_CONTROL_EP_OUT && !udc_ep_is_busy(ev->dev, ev->ep)) { if (usbfsotg_xfer_next(ev->dev, ep_cfg) == 0) { udc_ep_set_busy(ev->dev, ev->ep, true); diff --git a/drivers/usb/udc/udc_nrf.c b/drivers/usb/udc/udc_nrf.c index ccae117c6f86..4610aff19f87 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -29,7 +29,7 @@ LOG_MODULE_REGISTER(udc_nrf, CONFIG_UDC_DRIVER_LOG_LEVEL); /* - * There is no real advantage to change control enpoint size + * There is no real advantage to change control endpoint size * but we can use it for testing UDC driver API and higher layers. */ #define UDC_NRF_MPS0 UDC_MPS0_64 diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index f5f74ec12782..0f01d877e541 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -478,7 +478,7 @@ static inline int udc_host_wakeup(const struct device *dev) * of the endpoint. All properties of the descriptor, * such as direction, and transfer type, should be set correctly. * If wMaxPacketSize value is zero, it will be - * updated to maximum buffer size of the enpoint. + * updated to maximum buffer size of the endpoint. * * @param[in] dev Pointer to device struct of the driver instance * @param[in] ep Endpoint address (same as bEndpointAddress) From e6bfc7f868d5aed07aa82837af06a1d97400181c Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Tue, 25 Jul 2023 11:15:04 +0200 Subject: [PATCH 1824/2042] usb: fix common misspellings in USB support Fix common misspellings in USB device next and host. Signed-off-by: Johann Fischer --- include/zephyr/usb/usbd.h | 4 ++-- subsys/usb/device_next/class/loopback.c | 2 +- subsys/usb/device_next/class/usbd_msc_scsi.c | 4 ++-- subsys/usb/device_next/usbd_ch9.h | 2 +- subsys/usb/device_next/usbd_class.c | 2 +- subsys/usb/device_next/usbd_class.h | 2 +- subsys/usb/device_next/usbd_class_api.h | 2 +- subsys/usb/device_next/usbd_desc.c | 2 +- subsys/usb/device_next/usbd_desc.h | 2 +- subsys/usb/host/usbh_core.c | 2 +- subsys/usb/host/usbh_shell.c | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index f55047a43a18..aad53b475503 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -126,7 +126,7 @@ enum usbd_ch9_state { struct usbd_ch9_data { /** Setup packet, up-to-date for the respective control request */ struct usb_setup_packet setup; - /** Control type, internaly used for stage verification */ + /** Control type, internally used for stage verification */ int ctrl_type; /** Protocol state of the USB device stack */ enum usbd_ch9_state state; @@ -183,7 +183,7 @@ struct usbd_contex { * @brief Vendor Requests Table */ struct usbd_cctx_vendor_req { - /** Array of vendor requests supportd by the class */ + /** Array of vendor requests supported by the class */ const uint8_t *reqs; /** Length of the array */ uint8_t len; diff --git a/subsys/usb/device_next/class/loopback.c b/subsys/usb/device_next/class/loopback.c index 5400d7c21b96..bdd20717e748 100644 --- a/subsys/usb/device_next/class/loopback.c +++ b/subsys/usb/device_next/class/loopback.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(usb_loopback, CONFIG_USBD_LOOPBACK_LOG_LEVEL); * interface and endpoint configuration. */ -/* Internal buffer for intermidiate test data */ +/* Internal buffer for intermediate test data */ static uint8_t lb_buf[1024]; #define LB_VENDOR_REQ_OUT 0x5b diff --git a/subsys/usb/device_next/class/usbd_msc_scsi.c b/subsys/usb/device_next/class/usbd_msc_scsi.c index 81172670b171..82aa0f50e624 100644 --- a/subsys/usb/device_next/class/usbd_msc_scsi.c +++ b/subsys/usb/device_next/class/usbd_msc_scsi.c @@ -459,7 +459,7 @@ static int fill_inquiry(struct scsi_ctx *ctx, memset(&r, 0, sizeof(struct scsi_inquiry_response)); - /* Accesible; Direct access block device (SBC) */ + /* Accessible; Direct access block device (SBC) */ r.peripheral = 0x00; /* Removable; not a part of conglomerate. Note that when device is * accessible via USB Mass Storage, it should always be marked as @@ -526,7 +526,7 @@ static int fill_vpd_page(struct scsi_ctx *ctx, enum vpd_page_code page, return -ENOTSUP; } - /* Accesible; Direct access block device (SBC) */ + /* Accessible; Direct access block device (SBC) */ buf[0] = 0x00; buf[1] = page; sys_put_be16(offset, &buf[2]); diff --git a/subsys/usb/device_next/usbd_ch9.h b/subsys/usb/device_next/usbd_ch9.h index 3531a97ab91a..657e492f33ad 100644 --- a/subsys/usb/device_next/usbd_ch9.h +++ b/subsys/usb/device_next/usbd_ch9.h @@ -131,7 +131,7 @@ usbd_get_setup_pkt(struct usbd_contex *const uds_ctx) * * @param[in] uds_ctx Pointer to a device context * @param[in] buf Pointer to UDC request buffer - * @param[in] err Trasnfer status + * @param[in] err Transfer status * * @return 0 on success, other values on fail. */ diff --git a/subsys/usb/device_next/usbd_class.c b/subsys/usb/device_next/usbd_class.c index 41d6d7e6ae8e..407e9145258e 100644 --- a/subsys/usb/device_next/usbd_class.c +++ b/subsys/usb/device_next/usbd_class.c @@ -313,7 +313,7 @@ int usbd_register_class(struct usbd_contex *const uds_ctx, /* TODO: does it still need to be atomic ? */ if (atomic_test_bit(&data->state, USBD_CCTX_REGISTERED)) { - LOG_WRN("Class instance allready registered"); + LOG_WRN("Class instance already registered"); ret = -EBUSY; goto register_class_error; } diff --git a/subsys/usb/device_next/usbd_class.h b/subsys/usb/device_next/usbd_class.h index a4d67939c97d..63a32ed57278 100644 --- a/subsys/usb/device_next/usbd_class.h +++ b/subsys/usb/device_next/usbd_class.h @@ -14,7 +14,7 @@ * * @param[in] uds_ctx Pointer to device context * @param[in] buf Pointer to UDC request buffer - * @param[in] err Trasnfer status + * @param[in] err Transfer status * * @return usbd_class_request() return value */ diff --git a/subsys/usb/device_next/usbd_class_api.h b/subsys/usb/device_next/usbd_class_api.h index 244ff873a3c6..ccff5243cac3 100644 --- a/subsys/usb/device_next/usbd_class_api.h +++ b/subsys/usb/device_next/usbd_class_api.h @@ -190,7 +190,7 @@ static inline void usbd_class_resumed(struct usbd_class_node *const node) } /** - * @brief Class associated configuration activ handler + * @brief Class associated configuration active handler * * @note The execution of the handler must not block. * diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c index 2e8cb1c99aa7..825d1b910a0a 100644 --- a/subsys/usb/device_next/usbd_desc.c +++ b/subsys/usb/device_next/usbd_desc.c @@ -68,7 +68,7 @@ static void usbd_ascii7_to_utf16le(struct usbd_desc_node *const dn) /** * @brief Get common USB descriptor * - * Get descriptor from internal descrptor list. + * Get descriptor from internal descriptor list. * * @param[in] dn Pointer to descriptor node * diff --git a/subsys/usb/device_next/usbd_desc.h b/subsys/usb/device_next/usbd_desc.h index ab796ef3f90f..0b3702206d24 100644 --- a/subsys/usb/device_next/usbd_desc.h +++ b/subsys/usb/device_next/usbd_desc.h @@ -12,7 +12,7 @@ /** * @brief Get common USB descriptor * - * Get descriptor from internal descrptor list. + * Get descriptor from internal descriptor list. * * @param[in] ctx Pointer to USB device support context * @param[in] type Descriptor type (bDescriptorType) diff --git a/subsys/usb/host/usbh_core.c b/subsys/usb/host/usbh_core.c index efbf3a84985d..a6aa968bb622 100644 --- a/subsys/usb/host/usbh_core.c +++ b/subsys/usb/host/usbh_core.c @@ -72,7 +72,7 @@ static int ALWAYS_INLINE usbh_event_handler(struct usbh_contex *const ctx, } break; case UHC_EVT_RESETED: - LOG_DBG("Bus reseted"); + LOG_DBG("Bus reset"); /* TODO */ if (class_data && class_data->removed) { ret = class_data->removed(ctx); diff --git a/subsys/usb/host/usbh_shell.c b/subsys/usb/host/usbh_shell.c index 48262c943314..3f331ab543cb 100644 --- a/subsys/usb/host/usbh_shell.c +++ b/subsys/usb/host/usbh_shell.c @@ -510,7 +510,7 @@ static int cmd_bus_reset(const struct shell *sh, if (err) { shell_error(sh, "host: Failed to perform bus reset %d", err); } else { - shell_print(sh, "host: USB bus reseted"); + shell_print(sh, "host: USB bus reset"); } err = uhc_sof_enable(uhs_ctx.dev); From 3744fe2d4983af3a0f31657504388bb5664846e7 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 29 Jun 2023 15:38:05 +0800 Subject: [PATCH 1825/2042] drivers: mbox: Add Andestech mailbox driver Support the Andes mailbox driver via software plic. Signed-off-by: Kevin Wang --- .../riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml | 1 + drivers/mbox/CMakeLists.txt | 1 + drivers/mbox/Kconfig | 1 + drivers/mbox/Kconfig.andes | 14 ++ drivers/mbox/mbox_andes_plic_sw.c | 221 ++++++++++++++++++ dts/bindings/mbox/andestech,plic-sw.yaml | 24 ++ dts/riscv/andes/andes_v5_ae350.dtsi | 16 +- 7 files changed, 267 insertions(+), 11 deletions(-) create mode 100644 drivers/mbox/Kconfig.andes create mode 100644 drivers/mbox/mbox_andes_plic_sw.c create mode 100644 dts/bindings/mbox/andestech,plic-sw.yaml diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml index 37e25bc5d8eb..0d6ed9a59fd2 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350.yaml @@ -13,6 +13,7 @@ supported: - spi - eeprom - watchdog + - mbox testing: ignore_tags: - bluetooth diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index be9d00e36e67..aa39b235522b 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library() 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_ANDES_PLIC_SW mbox_andes_plic_sw.c) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index 79f220794917..a88a84472b48 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -13,6 +13,7 @@ if MBOX # overridden (by defining symbols in multiple locations) source "drivers/mbox/Kconfig.nrfx" source "drivers/mbox/Kconfig.nxp_s32" +source "drivers/mbox/Kconfig.andes" config MBOX_INIT_PRIORITY int "MBOX init priority" diff --git a/drivers/mbox/Kconfig.andes b/drivers/mbox/Kconfig.andes new file mode 100644 index 000000000000..6412e9fb6928 --- /dev/null +++ b/drivers/mbox/Kconfig.andes @@ -0,0 +1,14 @@ +# Kconfig Andes mbox configuration options +# +# Copyright (c) 2022 Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +config MBOX_ANDES_PLIC_SW + bool "MBOX Andes PLIC-SW driver" + default y + depends on DT_HAS_ANDESTECH_PLIC_SW_ENABLED + help + Enable driver for the Andes IPM mailbox controller. + Says n if not sure. diff --git a/drivers/mbox/mbox_andes_plic_sw.c b/drivers/mbox/mbox_andes_plic_sw.c new file mode 100644 index 000000000000..13254c464afe --- /dev/null +++ b/drivers/mbox/mbox_andes_plic_sw.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 Andes Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL +#include +#include +LOG_MODULE_REGISTER(mbox_andes_plic_sw); + +#define DT_DRV_COMPAT andestech_plic_sw + +#define IRQ_REG(n) (n >> 5) +#define PLIC_BASE(dev) \ + ((const struct mbox_andes_conf * const)(dev)->config)->base + +#define REG_PRIORITY(dev, irq) \ + (PLIC_BASE(dev) + 0x0 + (irq << 2)) +#define REG_PENDING(dev, irq) \ + (PLIC_BASE(dev) + 0x1000 + (IRQ_REG(irq) << 2)) +#define REG_ENABLE(dev, hart, irq) \ + (PLIC_BASE(dev) + 0x2000 + (hart << 7) + IRQ_REG(irq)) +#define REG_CLAIM(dev, hart) \ + (PLIC_BASE(dev) + 0x200004 + (hart << 12)) + +#define IPI_NUM DT_INST_PROP(0, channel_max) + +static struct mbox_andes_data { + mbox_callback_t cb[IPI_NUM]; + void *user_data[IPI_NUM]; + uint32_t enabled_channel[CONFIG_MP_NUM_CPUS]; +#ifdef CONFIG_SCHED_IPI_SUPPORTED + uint32_t reg_cb_channel; + uint32_t ipi_channel; +#endif +} andes_mbox_data; + +static struct mbox_andes_conf { + uint32_t base; + uint32_t channel_max; +} andes_mbox_conf = { + .base = DT_INST_REG_ADDR(0), + .channel_max = IPI_NUM, +}; + +static struct k_spinlock mbox_syn; + +static void plic_sw_irq_set_pending(const struct device *dev, uint32_t irq) +{ + uint32_t pend; + k_spinlock_key_t key = k_spin_lock(&mbox_syn); + + pend = sys_read32(REG_PENDING(dev, irq)); + pend |= BIT(irq); + sys_write32(pend, REG_PENDING(dev, irq)); + + k_spin_unlock(&mbox_syn, key); +} + +static inline bool is_channel_valid(const struct device *dev, uint32_t ch) +{ + const struct mbox_andes_conf *conf = dev->config; + + return (ch <= conf->channel_max); +} + +static int mbox_andes_send(const struct device *dev, uint32_t ch, + const struct mbox_msg *msg) +{ + if (msg) { + LOG_WRN("Sending data not supported"); + } + + if (!is_channel_valid(dev, ch)) { + return -EINVAL; + } + + /* Send IPI by triggering the pending register of PLIC SW. */ + plic_sw_irq_set_pending(dev, ch + 1); + + return 0; +} + +static int mbox_andes_register_callback(const struct device *dev, uint32_t ch, + mbox_callback_t cb, void *user_data) +{ + struct mbox_andes_data *data = dev->data; + const struct mbox_andes_conf *conf = dev->config; + int ret = 0; + + k_spinlock_key_t key = k_spin_lock(&mbox_syn); + + if (ch > conf->channel_max) { + ret = -EINVAL; + goto out; + } + +#ifdef CONFIG_SCHED_IPI_SUPPORTED + if (ch & data->ipi_channel & data->reg_cb_channel) { + ret = -EALREADY; + goto out; + } + + data->reg_cb_channel |= BIT(ch); +#endif + data->cb[ch] = cb; + data->user_data[ch] = user_data; + +out: + k_spin_unlock(&mbox_syn, key); + + return 0; +} + +static int mbox_andes_mtu_get(const struct device *dev) +{ + /* We only support signalling */ + return 0; +} + +static uint32_t mbox_andes_max_channels_get(const struct device *dev) +{ + const struct mbox_andes_conf *conf = dev->config; + + return conf->channel_max; +} + +static int mbox_andes_set_enabled(const struct device *dev, uint32_t ch, + bool enable) +{ + uint32_t en, is_enabled_ch, hartid, cpu_id, irq; + struct mbox_andes_data *data = dev->data; + int ret = 0; + + k_spinlock_key_t key = k_spin_lock(&mbox_syn); + + if (!is_channel_valid(dev, ch)) { + ret = -EINVAL; + goto out; + } + + irq = ch + 1; + hartid = arch_proc_id(); + cpu_id = _current_cpu->id; + + is_enabled_ch = data->enabled_channel[cpu_id] & BIT(ch); + + if ((!enable && !is_enabled_ch) || (enable && is_enabled_ch)) { + ret = -EALREADY; + goto out; + } + + if (enable && !(data->cb[ch])) { + LOG_WRN("Enabling channel without a registered callback\n"); + } + + en = sys_read32(REG_ENABLE(dev, hartid, irq)); + + if (enable) { + data->enabled_channel[cpu_id] |= BIT(ch); + sys_write32(1, REG_PRIORITY(dev, irq)); + en |= BIT(irq); + } else { + data->enabled_channel[cpu_id] &= ~BIT(ch); + en &= ~BIT(irq); + } + + sys_write32(en, REG_ENABLE(dev, hartid, irq)); +out: + k_spin_unlock(&mbox_syn, key); + + return ret; +} + +static void andes_plic_sw_irq_handler(const struct device *dev) +{ + struct mbox_andes_data *data = dev->data; + uint32_t irq, ch, hartid; + + hartid = arch_proc_id(); + + /* PLIC claim: Get the SW IRQ number generating the interrupt. */ + irq = sys_read32(REG_CLAIM(dev, hartid)); + ch = irq - 1; + + if (irq) { + sys_write32(irq, REG_CLAIM(dev, hartid)); + + if (data->cb[ch]) { + /* Only one MAILBOX, id is unused and set to 0 */ + data->cb[ch](dev, ch, data->user_data[ch], NULL); + } + } +} + +static int mbox_andes_init(const struct device *dev) +{ + /* Setup IRQ handler for PLIC SW driver */ + IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 1, + andes_plic_sw_irq_handler, DEVICE_DT_INST_GET(0), 0); + +#ifndef CONFIG_SMP + irq_enable(RISCV_MACHINE_SOFT_IRQ); +#endif + return 0; +} + +static const struct mbox_driver_api mbox_andes_driver_api = { + .send = mbox_andes_send, + .register_callback = mbox_andes_register_callback, + .mtu_get = mbox_andes_mtu_get, + .max_channels_get = mbox_andes_max_channels_get, + .set_enabled = mbox_andes_set_enabled, +}; + +DEVICE_DT_INST_DEFINE(0, mbox_andes_init, NULL, &andes_mbox_data, + &andes_mbox_conf, PRE_KERNEL_1, CONFIG_MBOX_INIT_PRIORITY, + &mbox_andes_driver_api); diff --git a/dts/bindings/mbox/andestech,plic-sw.yaml b/dts/bindings/mbox/andestech,plic-sw.yaml new file mode 100644 index 000000000000..f054d8c206b6 --- /dev/null +++ b/dts/bindings/mbox/andestech,plic-sw.yaml @@ -0,0 +1,24 @@ +# +# Copyright (c) 2022, Andes Technology Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + This is a representation of AndesTech PLIC-SW node + +compatible: "andestech,plic-sw" + +include: [base.yaml, mailbox-controller.yaml] + +properties: + reg: + required: true + + channel-max: + type: int + required: true + description: Supported channels max + +mbox-cells: + - channel diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 9c5ad76422da..4a9456520a18 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -183,18 +183,12 @@ &CPU6_intc 11 &CPU7_intc 11>; }; - plic_sw0: interrupt-controller@e6400000 { - compatible = "andestech,plic_sw"; - #address-cells = <1>; - #interrupt-cells = <2>; - interrupt-controller; + mbox: mbox-controller@e6400000 { + compatible = "andestech,plic-sw"; reg = <0xe6400000 0x00400000>; - riscv,max-priority = <255>; - riscv,ndev = <1023>; - interrupts-extended = <&CPU0_intc 3 &CPU1_intc 3 - &CPU2_intc 3 &CPU3_intc 3 - &CPU4_intc 3 &CPU5_intc 3 - &CPU6_intc 3 &CPU7_intc 3>; + #mbox-cells = <1>; + channel-max = <30>; + status = "okay"; }; mtimer: timer@e6000000 { From 7bfe0967879e380bffb850f5d02bc9119791da4a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 29 Jun 2023 15:47:18 +0800 Subject: [PATCH 1826/2042] samples: drivers: mbox: Support the new board adp_xc7k_ae350 Modify the related source in mbox sample to support board adp_xc7k_ae350. Signed-off-by: Kevin Wang --- samples/drivers/mbox/CMakeLists.txt | 2 ++ .../drivers/mbox/boards/adp_xc7k_ae350.conf | 1 + .../mbox/boards/adp_xc7k_ae350.overlay | 19 +++++++++++++++++++ samples/drivers/mbox/remote/CMakeLists.txt | 2 ++ samples/drivers/mbox/remote/sample.yaml | 2 +- samples/drivers/mbox/sample.yaml | 2 +- 6 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 samples/drivers/mbox/boards/adp_xc7k_ae350.conf create mode 100644 samples/drivers/mbox/boards/adp_xc7k_ae350.overlay diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index 5fe78156f383..dd7ab1155704 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -10,6 +10,8 @@ set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/mbox_ipc_remote-prefix/src/mbo if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") +elseif("${BOARD}" STREQUAL "adp_xc7k_ae350") + set(BOARD_REMOTE "adp_xc7k_ae350") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() diff --git a/samples/drivers/mbox/boards/adp_xc7k_ae350.conf b/samples/drivers/mbox/boards/adp_xc7k_ae350.conf new file mode 100644 index 000000000000..bdeaed5e8853 --- /dev/null +++ b/samples/drivers/mbox/boards/adp_xc7k_ae350.conf @@ -0,0 +1 @@ +CONFIG_RV_BOOT_HART=0 diff --git a/samples/drivers/mbox/boards/adp_xc7k_ae350.overlay b/samples/drivers/mbox/boards/adp_xc7k_ae350.overlay new file mode 100644 index 000000000000..e97501416707 --- /dev/null +++ b/samples/drivers/mbox/boards/adp_xc7k_ae350.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + zephyr,sram = &sram; + }; + + sram: memory@0 { + compatible = "mmio-sram"; + reg = <0x00000000 0x10000000 >; + }; +}; diff --git a/samples/drivers/mbox/remote/CMakeLists.txt b/samples/drivers/mbox/remote/CMakeLists.txt index 94e87d6fcdc1..a2efccf2227f 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -8,6 +8,8 @@ cmake_minimum_required(VERSION 3.20.0) if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") message(STATUS "${BOARD} compile as remote in this sample") +elseif("${BOARD}" STREQUAL "adp_xc7k_ae350") + message(STATUS "${BOARD} compile as remote in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") endif() diff --git a/samples/drivers/mbox/remote/sample.yaml b/samples/drivers/mbox/remote/sample.yaml index df30347e98ec..014ad53a1267 100644 --- a/samples/drivers/mbox/remote/sample.yaml +++ b/samples/drivers/mbox/remote/sample.yaml @@ -2,7 +2,7 @@ sample: name: MBOX IPC sample (remote) tests: sample.drivers.mbox_remote: - platform_allow: nrf5340dk_nrf5340_cpunet + platform_allow: nrf5340dk_nrf5340_cpunet adp_xc7k_ae350 integration_platforms: - nrf5340dk_nrf5340_cpunet tags: mbox diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index 8080026435b1..6d1ee5fd2355 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -2,7 +2,7 @@ sample: name: MBOX IPC sample tests: sample.drivers.mbox: - platform_allow: nrf5340dk_nrf5340_cpuapp + platform_allow: nrf5340dk_nrf5340_cpuapp adp_xc7k_ae350 integration_platforms: - nrf5340dk_nrf5340_cpuapp tags: mbox From fbc6a91a5ab717de87a39880a091149cb2705f82 Mon Sep 17 00:00:00 2001 From: Oliver King Date: Sat, 20 May 2023 18:43:50 -0400 Subject: [PATCH 1827/2042] drivers: sensor: a01nyub: added driver Added a driver for the DFRobot A01NYUB distance sensor. This sensor sends its readings via UART at 9600 baud. This driver uses interrupts to read the data from the sensor. Signed-off-by: Oliver King --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/a01nyub/CMakeLists.txt | 6 + drivers/sensor/a01nyub/Kconfig | 10 ++ drivers/sensor/a01nyub/a01nyub.c | 211 +++++++++++++++++++++++ dts/bindings/sensor/dfrobot,a01nyub.yaml | 8 + dts/bindings/vendor-prefixes.txt | 1 + tests/drivers/build_all/sensor/uart.dtsi | 4 + 8 files changed, 242 insertions(+) create mode 100644 drivers/sensor/a01nyub/CMakeLists.txt create mode 100644 drivers/sensor/a01nyub/Kconfig create mode 100644 drivers/sensor/a01nyub/a01nyub.c create mode 100644 dts/bindings/sensor/dfrobot,a01nyub.yaml diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 1bd8ee07f171..ffba30b56896 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 +add_subdirectory_ifdef(CONFIG_A01NYUB a01nyub) add_subdirectory_ifdef(CONFIG_ADC_CMP_NPCX nuvoton_adc_cmp_npcx) add_subdirectory_ifdef(CONFIG_ADT7310 adt7310) add_subdirectory_ifdef(CONFIG_ADT7420 adt7420) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index d86e198a6a90..0dd1140f578a 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -57,6 +57,7 @@ config SENSOR_INFO comment "Device Drivers" +source "drivers/sensor/a01nyub/Kconfig" source "drivers/sensor/adt7310/Kconfig" source "drivers/sensor/adt7420/Kconfig" source "drivers/sensor/adxl345/Kconfig" diff --git a/drivers/sensor/a01nyub/CMakeLists.txt b/drivers/sensor/a01nyub/CMakeLists.txt new file mode 100644 index 000000000000..a95e9b413fc0 --- /dev/null +++ b/drivers/sensor/a01nyub/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 SteadConnect +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(a01nyub.c) diff --git a/drivers/sensor/a01nyub/Kconfig b/drivers/sensor/a01nyub/Kconfig new file mode 100644 index 000000000000..ff40a6f0682e --- /dev/null +++ b/drivers/sensor/a01nyub/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 SteadConnect +# SPDX-License-Identifier: Apache-2.0 + +config A01NYUB + bool "DFRobot A01NYUB distance sensor" + default y + depends on DT_HAS_DFROBOT_A01NYUB_ENABLED + depends on UART_INTERRUPT_DRIVEN + help + Enable driver for the DFRobot A01NYUB distance sensor. diff --git a/drivers/sensor/a01nyub/a01nyub.c b/drivers/sensor/a01nyub/a01nyub.c new file mode 100644 index 000000000000..f1d57becd04d --- /dev/null +++ b/drivers/sensor/a01nyub/a01nyub.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2023 SteadConnect + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://wiki.dfrobot.com/A01NYUB%20Waterproof%20Ultrasonic%20Sensor%20SKU:%20SEN0313 + * + */ + +#define DT_DRV_COMPAT dfrobot_a01nyub + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(a01nyub_sensor, CONFIG_SENSOR_LOG_LEVEL); + +#define A01NYUB_BUF_LEN 4 +#define A01NYUB_CHECKSUM_IDX 3 +#define A01NYUB_HEADER 0xff + +const struct uart_config uart_cfg_a01nyub = { + .baudrate = 9600, + .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 +}; + +struct a01nyub_data { + /* Max data length is 16 bits */ + uint16_t data; + uint8_t xfer_bytes; + uint8_t rd_data[A01NYUB_BUF_LEN]; +}; + +struct a01nyub_cfg { + const struct device *uart_dev; + uart_irq_callback_user_data_t cb; +}; + +static void a01nyub_uart_flush(const struct device *uart_dev) +{ + uint8_t c; + + while (uart_fifo_read(uart_dev, &c, 1) > 0) { + continue; + } +} + +static uint8_t a01nyub_checksum(const uint8_t *data) +{ + uint16_t cs = 0; + + for (uint8_t i = 0; i < A01NYUB_BUF_LEN - 1; i++) { + cs += data[i]; + } + + return (uint8_t) (cs & 0x00FF); +} + +static inline int a01nyub_poll_data(const struct device *dev) +{ + struct a01nyub_data *data = dev->data; + uint8_t checksum; + + checksum = a01nyub_checksum(data->rd_data); + if (checksum != data->rd_data[A01NYUB_CHECKSUM_IDX]) { + LOG_DBG("Checksum mismatch: calculated 0x%x != data checksum 0x%x", + checksum, + data->rd_data[A01NYUB_CHECKSUM_IDX]); + LOG_DBG("Data bytes: (%x,%x,%x,%x)", + data->rd_data[0], + data->rd_data[1], + data->rd_data[2], + data->rd_data[3]); + + return -EBADMSG; + } + + data->data = (data->rd_data[1]<<8) + data->rd_data[2]; + + return 0; +} + +static int a01nyub_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct a01nyub_data *data = dev->data; + + if (chan != SENSOR_CHAN_DISTANCE) { + return -ENOTSUP; + } + /* val1 is meters, val2 is microns. Both are int32_t + * data->data is in mm and units of uint16_t + */ + val->val1 = (uint32_t) (data->data / (uint16_t) 1000); + val->val2 = (uint32_t) ((data->data % 1000) * 1000); + return 0; +} + +static int a01nyub_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + if (chan == SENSOR_CHAN_DISTANCE || chan == SENSOR_CHAN_ALL) { + return a01nyub_poll_data(dev); + } + + return -ENOTSUP; +} + +static const struct sensor_driver_api a01nyub_api_funcs = { + .sample_fetch = a01nyub_sample_fetch, + .channel_get = a01nyub_channel_get, +}; + +static void a01nyub_uart_isr(const struct device *uart_dev, void *user_data) +{ + const struct device *dev = user_data; + struct a01nyub_data *data = dev->data; + + if (uart_dev == NULL) { + LOG_DBG("UART device is NULL"); + return; + } + + if (!uart_irq_update(uart_dev)) { + LOG_DBG("Unable to start processing interrupts"); + return; + } + + if (uart_irq_rx_ready(uart_dev)) { + data->xfer_bytes += uart_fifo_read(uart_dev, &data->rd_data[data->xfer_bytes], + A01NYUB_BUF_LEN - data->xfer_bytes); + + /* The first byte should be A01NYUB_HEADER for a valid read. + * If we do not read A01NYUB_HEADER on what we think is the + * first byte, then reset the number of bytes read until we do + */ + if ((data->rd_data[0] != A01NYUB_HEADER) & (data->xfer_bytes == 1)) { + LOG_DBG("First byte not header! Resetting # of bytes read."); + data->xfer_bytes = 0; + } + + if (data->xfer_bytes == A01NYUB_BUF_LEN) { + LOG_DBG("Read (0x%x,0x%x,0x%x,0x%x)", + data->rd_data[0], + data->rd_data[1], + data->rd_data[2], + data->rd_data[3]); + a01nyub_uart_flush(uart_dev); + data->xfer_bytes = 0; + } + } +} + +static int a01nyub_init(const struct device *dev) +{ + const struct a01nyub_cfg *cfg = dev->config; + int ret = 0; + + uart_irq_rx_disable(cfg->uart_dev); + uart_irq_tx_disable(cfg->uart_dev); + + a01nyub_uart_flush(cfg->uart_dev); + + LOG_DBG("Initializing A01NYUB driver"); + + ret = uart_configure(cfg->uart_dev, &uart_cfg_a01nyub); + if (ret == -ENOSYS) { + LOG_ERR("Unable to configure UART port"); + return -ENOSYS; + } + + ret = uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev); + + if (ret < 0) { + if (ret == -ENOTSUP) { + LOG_ERR("Interrupt-driven UART API support not enabled"); + } else if (ret == -ENOSYS) { + LOG_ERR("UART device does not support interrupt-driven API"); + } else { + LOG_ERR("Error setting UART callback: %d", ret); + } + return ret; + } + + uart_irq_rx_enable(cfg->uart_dev); + + return ret; +} + +#define A01NYUB_INIT(inst) \ + \ + static struct a01nyub_data a01nyub_data_##inst; \ + \ + static const struct a01nyub_cfg a01nyub_cfg_##inst = { \ + .uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .cb = a01nyub_uart_isr, \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, a01nyub_init, NULL, \ + &a01nyub_data_##inst, &a01nyub_cfg_##inst, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &a01nyub_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(A01NYUB_INIT) diff --git a/dts/bindings/sensor/dfrobot,a01nyub.yaml b/dts/bindings/sensor/dfrobot,a01nyub.yaml new file mode 100644 index 000000000000..b40b28602b21 --- /dev/null +++ b/dts/bindings/sensor/dfrobot,a01nyub.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Steadconnect +# SPDX-License-Identifier: Apache-2.0 + +description: DFRobot A01NYUB Distance Sensor + +compatible: "dfrobot,a01nyub" + +include: [sensor-device.yaml, uart-device.yaml] diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index d5c32b0a54f4..31df992ec484 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -150,6 +150,7 @@ delta Delta Electronics, Inc. denx Denx Software Engineering devantech Devantech, Ltd. dfi DFI Inc. +dfrobot DFRobot dh DH electronics GmbH difrnce Shenzhen Yagu Electronic Technology Co., Ltd. digi Digi International Inc. diff --git a/tests/drivers/build_all/sensor/uart.dtsi b/tests/drivers/build_all/sensor/uart.dtsi index 2982e6ea116a..9d63ee3555fe 100644 --- a/tests/drivers/build_all/sensor/uart.dtsi +++ b/tests/drivers/build_all/sensor/uart.dtsi @@ -26,3 +26,7 @@ test_uart_grow_r502a { int-gpios = <&test_gpio 0 0>; }; }; + +test_uart_a01nyub { + compatible = "dfrobot,a01nyub"; +}; From b7e252c2db4174a8f087d7617347045f679dd91f Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 26 Jul 2023 11:41:50 +0200 Subject: [PATCH 1828/2042] shared_multi_heap: Use proper enum instead of int We have an enum for the memory attr, use that instead of a generic unsigned int. Signed-off-by: Carlo Caione --- include/zephyr/multi_heap/shared_multi_heap.h | 7 ++++--- lib/os/shared_multi_heap.c | 9 +++++---- tests/kernel/mem_heap/shared_multi_heap/src/main.c | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/zephyr/multi_heap/shared_multi_heap.h b/include/zephyr/multi_heap/shared_multi_heap.h index 1ab55fc0b658..0d5e66bf293d 100644 --- a/include/zephyr/multi_heap/shared_multi_heap.h +++ b/include/zephyr/multi_heap/shared_multi_heap.h @@ -66,7 +66,7 @@ extern "C" { * Enumeration type for some common memory region attributes. * */ -enum smh_reg_attr { +enum shared_multi_heap_attr { /** cacheable */ SMH_REG_ATTR_CACHEABLE, @@ -126,7 +126,7 @@ int shared_multi_heap_pool_init(void); * @retval ptr a valid pointer to heap memory. * @retval err NULL if no memory is available. */ -void *shared_multi_heap_alloc(unsigned int attr, size_t bytes); +void *shared_multi_heap_alloc(enum shared_multi_heap_attr attr, size_t bytes); /** * @brief Allocate aligned memory from the memory shared multi-heap pool @@ -142,7 +142,8 @@ void *shared_multi_heap_alloc(unsigned int attr, size_t bytes); * @retval ptr a valid pointer to heap memory. * @retval err NULL if no memory is available. */ -void *shared_multi_heap_aligned_alloc(unsigned int attr, size_t align, size_t bytes); +void *shared_multi_heap_aligned_alloc(enum shared_multi_heap_attr attr, + size_t align, size_t bytes); /** * @brief Free memory from the shared multi-heap pool diff --git a/lib/os/shared_multi_heap.c b/lib/os/shared_multi_heap.c index e2ae4bf7d784..6aedcdfbd7cb 100644 --- a/lib/os/shared_multi_heap.c +++ b/lib/os/shared_multi_heap.c @@ -19,10 +19,10 @@ static unsigned int attr_cnt[MAX_SHARED_MULTI_HEAP_ATTR]; static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t size) { struct sys_heap *h; - unsigned int attr; + enum shared_multi_heap_attr attr; void *block; - attr = (unsigned int)(long) cfg; + attr = (enum shared_multi_heap_attr)(long) cfg; if (attr >= MAX_SHARED_MULTI_HEAP_ATTR || size == 0) { return NULL; @@ -78,7 +78,7 @@ void shared_multi_heap_free(void *block) sys_multi_heap_free(&shared_multi_heap, block); } -void *shared_multi_heap_alloc(unsigned int attr, size_t bytes) +void *shared_multi_heap_alloc(enum shared_multi_heap_attr attr, size_t bytes) { if (attr >= MAX_SHARED_MULTI_HEAP_ATTR) { return NULL; @@ -87,7 +87,8 @@ void *shared_multi_heap_alloc(unsigned int attr, size_t bytes) return sys_multi_heap_alloc(&shared_multi_heap, (void *)(long) attr, bytes); } -void *shared_multi_heap_aligned_alloc(unsigned int attr, size_t align, size_t bytes) +void *shared_multi_heap_aligned_alloc(enum shared_multi_heap_attr attr, + size_t align, size_t bytes) { if (attr >= MAX_SHARED_MULTI_HEAP_ATTR) { return NULL; diff --git a/tests/kernel/mem_heap/shared_multi_heap/src/main.c b/tests/kernel/mem_heap/shared_multi_heap/src/main.c index c99264430bc3..d2169f9164a2 100644 --- a/tests/kernel/mem_heap/shared_multi_heap/src/main.c +++ b/tests/kernel/mem_heap/shared_multi_heap/src/main.c @@ -66,7 +66,7 @@ static struct region_map *get_region_map(void *v_addr) return NULL; } -static inline enum smh_reg_attr mpu_to_reg_attr(int mpu_attr) +static inline enum shared_multi_heap_attr mpu_to_reg_attr(int mpu_attr) { /* * All the memory regions defined in the DT with the MPU property `RAM` From 5d6d93c3b5dda1ab7af3e1bbadb207ff9cf04850 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 26 Jul 2023 11:51:58 +0200 Subject: [PATCH 1829/2042] shared_multi_heap: Rename heap counter We are calling the heap counter `attr_cnt` and that is misleading. Rename it. Signed-off-by: Carlo Caione --- lib/os/shared_multi_heap.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/os/shared_multi_heap.c b/lib/os/shared_multi_heap.c index 6aedcdfbd7cb..6ef3143a68bc 100644 --- a/lib/os/shared_multi_heap.c +++ b/lib/os/shared_multi_heap.c @@ -14,7 +14,10 @@ static struct sys_multi_heap shared_multi_heap; static struct sys_heap heap_pool[MAX_SHARED_MULTI_HEAP_ATTR][MAX_MULTI_HEAPS]; -static unsigned int attr_cnt[MAX_SHARED_MULTI_HEAP_ATTR]; +/* + * Number of heaps filled for a given attribute + */ +static unsigned int heap_cnt[MAX_SHARED_MULTI_HEAP_ATTR]; static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t size) { @@ -31,7 +34,7 @@ static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, s /* Set in case the user requested a non-existing attr */ block = NULL; - for (size_t hdx = 0; hdx < attr_cnt[attr]; hdx++) { + for (size_t hdx = 0; hdx < heap_cnt[attr]; hdx++) { h = &heap_pool[attr][hdx]; if (h->heap == NULL) { @@ -49,26 +52,28 @@ static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, s int shared_multi_heap_add(struct shared_multi_heap_region *region, void *user_data) { - static int n_heaps; + enum shared_multi_heap_attr attr; struct sys_heap *h; unsigned int slot; - if (region->attr >= MAX_SHARED_MULTI_HEAP_ATTR) { + attr = region->attr; + + if (attr >= MAX_SHARED_MULTI_HEAP_ATTR) { return -EINVAL; } /* No more heaps available */ - if (n_heaps++ >= MAX_MULTI_HEAPS) { + if (heap_cnt[attr] >= MAX_MULTI_HEAPS) { return -ENOMEM; } - slot = attr_cnt[region->attr]; + slot = heap_cnt[attr]; h = &heap_pool[region->attr][slot]; sys_heap_init(h, (void *) region->addr, region->size); sys_multi_heap_add_heap(&shared_multi_heap, h, user_data); - attr_cnt[region->attr]++; + heap_cnt[attr]++; return 0; } From 561a80d109a7345fd4605078cf3a21caff9664c0 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 26 Jul 2023 12:01:48 +0200 Subject: [PATCH 1830/2042] shared_multi_heap: Use a data struct Embed all the helper structs in one single data struct for easy access indexed on the memory attr. Signed-off-by: Carlo Caione --- lib/os/shared_multi_heap.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/os/shared_multi_heap.c b/lib/os/shared_multi_heap.c index 6ef3143a68bc..57ff2970cdef 100644 --- a/lib/os/shared_multi_heap.c +++ b/lib/os/shared_multi_heap.c @@ -12,12 +12,11 @@ #include static struct sys_multi_heap shared_multi_heap; -static struct sys_heap heap_pool[MAX_SHARED_MULTI_HEAP_ATTR][MAX_MULTI_HEAPS]; -/* - * Number of heaps filled for a given attribute - */ -static unsigned int heap_cnt[MAX_SHARED_MULTI_HEAP_ATTR]; +static struct { + struct sys_heap heap_pool[MAX_MULTI_HEAPS]; + unsigned int heap_cnt; +} smh_data[MAX_SHARED_MULTI_HEAP_ATTR]; static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t size) { @@ -34,8 +33,8 @@ static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, s /* Set in case the user requested a non-existing attr */ block = NULL; - for (size_t hdx = 0; hdx < heap_cnt[attr]; hdx++) { - h = &heap_pool[attr][hdx]; + for (size_t hdx = 0; hdx < smh_data[attr].heap_cnt; hdx++) { + h = &smh_data[attr].heap_pool[hdx]; if (h->heap == NULL) { return NULL; @@ -63,17 +62,17 @@ int shared_multi_heap_add(struct shared_multi_heap_region *region, void *user_da } /* No more heaps available */ - if (heap_cnt[attr] >= MAX_MULTI_HEAPS) { + if (smh_data[attr].heap_cnt >= MAX_MULTI_HEAPS) { return -ENOMEM; } - slot = heap_cnt[attr]; - h = &heap_pool[region->attr][slot]; + slot = smh_data[attr].heap_cnt; + h = &smh_data[attr].heap_pool[slot]; sys_heap_init(h, (void *) region->addr, region->size); sys_multi_heap_add_heap(&shared_multi_heap, h, user_data); - heap_cnt[attr]++; + smh_data[attr].heap_cnt++; return 0; } From ca7e8c6854652f00cf88ba7094f2d0ba048951b4 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 24 Jul 2023 08:54:40 +0100 Subject: [PATCH 1831/2042] west.yaml: MCUboot synchronization from upstream Update Zephyr fork of MCUboot to revision: 76d19b3b8885ea7ae25a6f4f5d8501f7ec646447 Brings following Zephyr relevant fixes: - 76d19b3 boot: bootutil: Fix missing packed attributes, add hash size define - 018b770 imgtool: Fix getpriv error return with private key - 9fad4c1 boot: boot_serial: Fix wrong cbor type for confirm Signed-off-by: Jamie McCrae --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index f3fa27117d4a..1fbcfb6d3265 100644 --- a/west.yml +++ b/west.yml @@ -271,7 +271,7 @@ manifest: groups: - crypto - name: mcuboot - revision: 6a8746d7acd75ff81fb6888d7776f412663f7897 + revision: 76d19b3b8885ea7ae25a6f4f5d8501f7ec646447 path: bootloader/mcuboot - name: mipi-sys-t path: modules/debug/mipi-sys-t From 7ca7f5a39c9a3d9c017fadfefa8974700575ccec Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 24 Jul 2023 08:41:59 +0100 Subject: [PATCH 1832/2042] mgmt: mcumgr: Use MCUboot bootutil file instead of outdated copy Uses the MCUboot bootutil image.h file directly instead of an outdated copy which resides in the zephyr tree. Signed-off-by: Jamie McCrae --- .../zephyr/mgmt/mcumgr/grp/img_mgmt/image.h | 71 ------------------- .../mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 4 +- .../mcumgr/grp/img_mgmt/img_mgmt_callbacks.h | 6 +- .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 4 +- .../mcumgr/grp/img_mgmt/src/img_mgmt_state.c | 1 - .../mcumgr/grp/img_mgmt/src/img_mgmt_util.c | 1 - .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 1 - 7 files changed, 8 insertions(+), 80 deletions(-) delete mode 100644 include/zephyr/mgmt/mcumgr/grp/img_mgmt/image.h diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/image.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/image.h deleted file mode 100644 index 761428446b36..000000000000 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/image.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2018-2021 mcumgr authors - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef H_IMAGE_ -#define H_IMAGE_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define IMAGE_MAGIC 0x96f3b83d -#define IMAGE_TLV_INFO_MAGIC 0x6907 -#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908 - -#define IMAGE_HEADER_SIZE 32 - -/** Image header flags. */ -#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */ -#define IMAGE_F_ROM_FIXED_ADDR 0x00000100 - -/** Image trailer TLV types. */ -#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ - -/** Image TLV-specific definitions. */ -#define IMAGE_HASH_LEN 32 - -struct image_version { - uint8_t iv_major; - uint8_t iv_minor; - uint16_t iv_revision; - uint32_t iv_build_num; -} __packed; - -/** Image header. All fields are in little endian byte order. */ -struct image_header { - uint32_t ih_magic; - uint32_t ih_load_addr; - uint16_t ih_hdr_size; /* Size of image header (bytes). */ - uint16_t _pad2; - uint32_t ih_img_size; /* Does not include header. */ - uint32_t ih_flags; /* IMAGE_F_[...]. */ - struct image_version ih_ver; - uint32_t _pad3; -} __packed; - -/** Image TLV header. All fields in little endian. */ -struct image_tlv_info { - uint16_t it_magic; - uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */ -} __packed; - -/** Image trailer TLV format. All fields in little endian. */ -struct image_tlv { - uint8_t it_type; /* IMAGE_TLV_[...]. */ - uint8_t _pad; - uint16_t it_len; /* Data length (not including TLV header). */ -} __packed; - -_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE, - "struct image_header not required size"); - -#ifdef __cplusplus -} -#endif - -#endif 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 ef5f840c261e..9e8a6e898b5a 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include /** @@ -25,8 +25,6 @@ extern "C" { #endif -#define IMG_MGMT_HASH_STR 48 -#define IMG_MGMT_HASH_LEN 32 #define IMG_MGMT_DATA_SHA_LEN 32 /* SHA256 */ /** diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_callbacks.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_callbacks.h index 4b29f7b99142..a9e05b5d3d11 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_callbacks.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_callbacks.h @@ -8,12 +8,14 @@ #ifndef H_MCUMGR_IMG_MGMT_CALLBACKS_ #define H_MCUMGR_IMG_MGMT_CALLBACKS_ -#include - #ifdef __cplusplus extern "C" { #endif +/* Dummy definitions, include zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h for actual definitions */ +struct img_mgmt_upload_action; +struct img_mgmt_upload_req; + /** * @brief MCUmgr img_mgmt callback API * @defgroup mcumgr_callback_api_img_mgmt MCUmgr img_mgmt callback API diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 42f3bf76c8e2..bcac20bd8431 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -76,6 +75,9 @@ #error "Unsupported code parition is set as active application partition" #endif +_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE, + "struct image_header not required size"); + LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); struct img_mgmt_state g_img_mgmt_state; 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 2e673fff9780..9e55a511063e 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 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_util.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_util.c index 4125889e33af..e52f95854174 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_util.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_util.c @@ -8,7 +8,6 @@ #include #include -#include int img_mgmt_ver_str(const struct image_version *ver, char *dst) 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 a809e2980c4b..3ee7616413a9 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 @@ -16,7 +16,6 @@ #include #include -#include #include From 0c16fea93f51d694684e46987a1410d894e22fbb Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 25 Jul 2023 12:31:46 +0200 Subject: [PATCH 1833/2042] doc: dts: bindings: pinctrl: minor readability improvement Improves readability of input/output-enable/disable flags. Signed-off-by: Florian Grandel --- dts/bindings/pinctrl/pincfg-node.yaml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dts/bindings/pinctrl/pincfg-node.yaml b/dts/bindings/pinctrl/pincfg-node.yaml index 1f66639dc8d5..9c3e126698c2 100644 --- a/dts/bindings/pinctrl/pincfg-node.yaml +++ b/dts/bindings/pinctrl/pincfg-node.yaml @@ -63,14 +63,12 @@ properties: input-enable: type: boolean description: | - enable input on pin (no effect on output, such as enabling an input - buffer) + enable input on pin (e.g. enable an input buffer, no effect on output) input-disable: type: boolean description: | - disable input on pin (no effect on output, such as disabling an input - buffer) + disable input on pin (e.g. disable an input buffer, no effect on output) input-schmitt-enable: type: boolean @@ -99,13 +97,13 @@ properties: output-disable: type: boolean - description: disable output on a pin (such as disable an output buffer) + description: disable output on a pin (e.g. disable an output buffer) output-enable: type: boolean description: | - enable output on a pin without actively driving it (such as enabling - an output buffer) + enable output on a pin without actively driving it (e.g. enable an output + buffer) output-low: type: boolean From 31fb5f53d243f27c2ff3121965dc9ec9b4fb8025 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 25 Jul 2023 12:35:29 +0200 Subject: [PATCH 1834/2042] drivers: cc13xx_cc26xx: pinctrl: fix header conflict CC13/26xx's pinctrl_cc13xx_cc26xx.c driver included ioc.h and (indirectly) pinctrl_soc.h which contained duplicate defines. This change removes the header conflict and redundant definitions. This prepares for subsequent changes in this change set that add additional flags to the pinctrl driver which would otherwise trigger the header conflict. Signed-off-by: Florian Grandel --- drivers/pinctrl/pinctrl_cc13xx_cc26xx.c | 2 -- .../ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h | 21 +------------------ 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/pinctrl/pinctrl_cc13xx_cc26xx.c b/drivers/pinctrl/pinctrl_cc13xx_cc26xx.c index e8aeb660059d..f3e853d0047a 100644 --- a/drivers/pinctrl/pinctrl_cc13xx_cc26xx.c +++ b/drivers/pinctrl/pinctrl_cc13xx_cc26xx.c @@ -8,8 +8,6 @@ #include -#include - static int pinctrl_c13xx_cc26xx_set(uint32_t pin, uint32_t func, uint32_t mode) { if (pin >= NUM_IO_MAX || func >= NUM_IO_PORTS) { diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h index df1ec138fb23..e4536c46872c 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h @@ -9,26 +9,7 @@ #include -/* Defines for enabling/disabling an IO */ -#define IOC_SLEW_ENABLE 0x00001000 -#define IOC_SLEW_DISABLE 0x00000000 -#define IOC_INPUT_ENABLE 0x20000000 -#define IOC_INPUT_DISABLE 0x00000000 -#define IOC_HYST_ENABLE 0x40000000 -#define IOC_HYST_DISABLE 0x00000000 - -/* Defines that can be used to set the IO Mode of an IO */ -#define IOC_IOMODE_NORMAL 0x00000000 -#define IOC_IOMODE_INV 0x01000000 -#define IOC_IOMODE_OPEN_DRAIN_NORMAL 0x04000000 -#define IOC_IOMODE_OPEN_DRAIN_INV 0x05000000 -#define IOC_IOMODE_OPEN_SRC_NORMAL 0x06000000 -#define IOC_IOMODE_OPEN_SRC_INV 0x07000000 - -/* Defines that can be used to set pull on an IO */ -#define IOC_NO_IOPULL 0x00006000 -#define IOC_IOPULL_UP 0x00004000 -#define IOC_IOPULL_DOWN 0x00002000 +#include typedef struct pinctrl_soc_pin { uint32_t pin; From 0dcbb22265257aee3bec04d545cd5c058e2a0c9f Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 25 Jul 2023 12:45:24 +0200 Subject: [PATCH 1835/2042] drivers: cc13xx_cc26xx: pinctrl: support drive strength Introduces support for drive-strength configuration to the CC13/26xx pinctrl driver. Signed-off-by: Florian Grandel --- .../pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml | 25 +++++++++++++++++++ .../ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h | 1 + 2 files changed, 26 insertions(+) diff --git a/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml b/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml index 5c78d9c561ee..9feeb11fc291 100644 --- a/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml +++ b/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml @@ -26,6 +26,7 @@ description: | - bias-pull-up: Enable pull-up resistor. - drive-open-drain: Output driver is open-drain. - drive-open-drain: Output driver is open-source. + - drive-strength: Minimum current that can be sourced from the pin. - input-enable: enable input. - input-schmitt-enable: enable input schmitt circuit. @@ -57,6 +58,16 @@ description: | }; }; + To configure an output pin (e.g. for PWM output): + + &pinctrl { + gpt0_pwm: gpt0_pwm { + pinmux = <16 IOC_PORT_MCU_PORT_EVENT1>; + bias-disable; + drive-strength = <8>; /* in mA */ + }; + }; + compatible: "ti,cc13xx-cc26xx-pinctrl" include: base.yaml @@ -78,6 +89,7 @@ child-binding: - bias-pull-up - drive-open-drain - drive-open-source + - drive-strength - input-enable - input-schmitt-enable @@ -87,3 +99,16 @@ child-binding: type: array description: | CC13XX/CC26XX pin's configuration (IO pin, IO function). + + drive-strength: + enum: + - 2 + - 4 + - 8 + default: 2 + description: | + The drive strength controls the minimum output driver strength of an I/O pin + configured as an output. + 2: min 2 mA (SoC default) + 4: min 4 mA + 8: min 8 mA for for double drive strength IOs, min 4 mA for normal IOs diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h index e4536c46872c..6dd2c6ac7681 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h @@ -24,6 +24,7 @@ typedef struct pinctrl_soc_pin { DT_PROP(node_id, bias_disable) * IOC_NO_IOPULL | \ DT_PROP(node_id, drive_open_drain) * IOC_IOMODE_OPEN_DRAIN_NORMAL | \ DT_PROP(node_id, drive_open_source) * IOC_IOMODE_OPEN_SRC_NORMAL | \ + (DT_PROP(node_id, drive_strength) >> 2) << IOC_IOCFG0_IOCURR_S | \ DT_PROP(node_id, input_enable) * IOC_INPUT_ENABLE | \ DT_PROP(node_id, input_schmitt_enable) * IOC_HYST_ENABLE) From d34709121f4c55095426935eee4891c2dcdffcbc Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 25 Jul 2023 12:49:08 +0200 Subject: [PATCH 1836/2042] drivers: cc13xx_cc26xx: pinctrl: support edge detection Introduces support for SoC-specific input-edge-detect configuration to the CC13/26xx pinctrl driver. Signed-off-by: Florian Grandel --- .../pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml | 22 +++++++++++++++++++ .../pinctrl/cc13xx_cc26xx-pinctrl.h | 6 +++++ .../ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h | 3 ++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml b/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml index 9feeb11fc291..fcc24e8928be 100644 --- a/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml +++ b/dts/bindings/pinctrl/ti,cc13xx-cc26xx-pinctrl.yaml @@ -29,6 +29,7 @@ description: | - drive-strength: Minimum current that can be sourced from the pin. - input-enable: enable input. - input-schmitt-enable: enable input schmitt circuit. + - ti,input-edge-detect: enable and configure edge detection interrupts An example for CC13XX family, include the chip level pinctrl DTSI file in the board level DTS: @@ -58,6 +59,17 @@ description: | }; }; + To configure an input pin with edge detection (e.g. to count pulses): + + &pinctrl { + gpt0_edge_counter: gpt0_edge_counter { + pinmux = <15 IOC_PORT_MCU_PORT_EVENT0>; + input-enable; + bias-pull-up; + ti,input-edge-detect = ; + }; + }; + To configure an output pin (e.g. for PWM output): &pinctrl { @@ -112,3 +124,13 @@ child-binding: 2: min 2 mA (SoC default) 4: min 4 mA 8: min 8 mA for for double drive strength IOs, min 4 mA for normal IOs + + ti,input-edge-detect: + type: int + default: 0 # no edge detection + description: | + Enables or disables the edge detection interrupt and configures it: + IOC_NO_EDGE: No edge detection (SoC default) + IOC_FALLING_EDGE: Edge detection on falling edge + IOC_RISING_EDGE: Edge detection on rising edge + IOC_BOTH_EDGES: Edge detection on both edges diff --git a/include/zephyr/dt-bindings/pinctrl/cc13xx_cc26xx-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/cc13xx_cc26xx-pinctrl.h index 72586136fc6f..042fb9df7a79 100644 --- a/include/zephyr/dt-bindings/pinctrl/cc13xx_cc26xx-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/cc13xx_cc26xx-pinctrl.h @@ -57,4 +57,10 @@ #define IOC_PORT_RFC_SMI_CL_OUT 0x00000037 /* RF Core SMI Command Link Out */ #define IOC_PORT_RFC_SMI_CL_IN 0x00000038 /* RF Core SMI Command Link In */ +/* Edge Detection */ +#define IOC_NO_EDGE 0x00000000 /* No edge detection */ +#define IOC_FALLING_EDGE 0x00010000 /* Edge detection on falling edge */ +#define IOC_RISING_EDGE 0x00020000 /* Edge detection on rising edge */ +#define IOC_BOTH_EDGES 0x00030000 /* Edge detection on both edges */ + #endif /* CC13XX_CC26XX_PINCTRL_COMMON_H_ */ diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h index 6dd2c6ac7681..94d71f51f639 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/pinctrl_soc.h @@ -26,7 +26,8 @@ typedef struct pinctrl_soc_pin { DT_PROP(node_id, drive_open_source) * IOC_IOMODE_OPEN_SRC_NORMAL | \ (DT_PROP(node_id, drive_strength) >> 2) << IOC_IOCFG0_IOCURR_S | \ DT_PROP(node_id, input_enable) * IOC_INPUT_ENABLE | \ - DT_PROP(node_id, input_schmitt_enable) * IOC_HYST_ENABLE) + DT_PROP(node_id, input_schmitt_enable) * IOC_HYST_ENABLE | \ + DT_PROP(node_id, ti_input_edge_detect)) #define CC13XX_CC26XX_DT_PIN(node_id) \ { \ From 40fa96506b674fc6a73fe2dd59e5a99f1e4e927e Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Fri, 21 Jul 2023 17:20:29 +0200 Subject: [PATCH 1837/2042] drivers: pinctrl: Add pinctrl driver for Gecko Series 1 This adds a new pinctrl driver for EFM32. Co-authored-by: Todd Dust Signed-off-by: Wojciech Sipak --- .../efm32pg_stk3402a-pinctrl.dtsi | 19 ++ .../efm32pg_stk3402a_common.dtsi | 5 +- drivers/pinctrl/pinctrl_gecko.c | 227 ++++++++++++++---- drivers/serial/Kconfig.gecko | 1 + dts/arm/silabs/efm32_jg_pg_12b.dtsi | 8 + .../dt-bindings/pinctrl/gecko-pinctrl-s1.h | 113 +++++++++ soc/arm/silabs_exx32/Kconfig | 7 + soc/arm/silabs_exx32/common/pinctrl_soc.h | 4 + .../silabs_exx32/efm32jg12b/Kconfig.series | 1 + .../silabs_exx32/efm32pg12b/Kconfig.series | 1 + 10 files changed, 335 insertions(+), 51 deletions(-) create mode 100644 boards/arm/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi create mode 100644 include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h diff --git a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi new file mode 100644 index 000000000000..4fac2b1a8dfa --- /dev/null +++ b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Silicon Labs + * + * 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_stk3402a/efm32pg_stk3402a_common.dtsi b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi index 8d45639bcb71..dc966f6716f6 100644 --- a/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi +++ b/boards/arm/efm32pg_stk3402a/efm32pg_stk3402a_common.dtsi @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "efm32pg_stk3402a-pinctrl.dtsi" / { model = "Silicon Labs EFM32PG STK3402A board"; @@ -67,8 +68,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/drivers/pinctrl/pinctrl_gecko.c b/drivers/pinctrl/pinctrl_gecko.c index d801ced94bb1..9f377bfb1d1a 100644 --- a/drivers/pinctrl/pinctrl_gecko.c +++ b/drivers/pinctrl/pinctrl_gecko.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Silicon Labs + * Copyright (c) 2023 Silicon Labs * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,39 +11,87 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { USART_TypeDef *base = (USART_TypeDef *)reg; - int usart_num = USART_NUM(base); + LEUART_TypeDef *lebase = (LEUART_TypeDef *)reg; uint8_t loc; +#ifndef CONFIG_SOC_GECKO_SERIES1 + int usart_num = USART_NUM(base); +#endif -#ifdef CONFIG_SPI_GECKO - struct soc_gpio_pin spi_pin_cfg = {0, 0, 0, 0}; -#endif /* CONFIG_SPI_GECKO */ - -#ifdef CONFIG_UART_GECKO - struct soc_gpio_pin rxpin = {0, 0, 0, 0}; - struct soc_gpio_pin txpin = {0, 0, 0, 0}; -#endif /* CONFIG_UART_GECKO */ + struct soc_gpio_pin pin_config = {0, 0, 0, 0}; for (uint8_t i = 0U; i < pin_cnt; i++) { + pin_config.port = GECKO_GET_PORT(pins[i]); + pin_config.pin = GECKO_GET_PIN(pins[i]); + loc = GECKO_GET_LOC(pins[i]); + switch (GECKO_GET_FUN(pins[i])) { #ifdef CONFIG_UART_GECKO case GECKO_FUN_UART_RX: - rxpin.port = GECKO_GET_PORT(pins[i]); - rxpin.pin = GECKO_GET_PIN(pins[i]); - rxpin.mode = gpioModeInput; - rxpin.out = 1; - GPIO_PinModeSet(rxpin.port, rxpin.pin, rxpin.mode, - rxpin.out); + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); break; + case GECKO_FUN_UART_TX: - txpin.port = GECKO_GET_PORT(pins[i]); - txpin.pin = GECKO_GET_PIN(pins[i]); - txpin.mode = gpioModePushPull; - txpin.out = 1; - GPIO_PinModeSet(txpin.port, txpin.pin, txpin.mode, - txpin.out); + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + +#ifdef CONFIG_SOC_GECKO_SERIES1 + case GECKO_FUN_UART_RTS: + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); break; + + case GECKO_FUN_UART_CTS: + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_UART_RX_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_RXPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_RXLOC_SHIFT); + break; + + case GECKO_FUN_UART_TX_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_TXPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_TXLOC_SHIFT); + break; + + case GECKO_FUN_UART_RTS_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_RTSPEN; + base->ROUTELOC1 &= ~_USART_ROUTELOC1_RTSLOC_MASK; + base->ROUTELOC1 |= (loc << _USART_ROUTELOC1_RTSLOC_SHIFT); + break; + + case GECKO_FUN_UART_CTS_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_CTSPEN; + base->ROUTELOC1 &= ~_USART_ROUTELOC1_CTSLOC_MASK; + base->ROUTELOC1 |= (loc << _USART_ROUTELOC1_CTSLOC_SHIFT); + break; + + case GECKO_FUN_LEUART_RX_LOC: + lebase->ROUTEPEN |= LEUART_ROUTEPEN_RXPEN; + lebase->ROUTELOC0 &= ~_LEUART_ROUTELOC0_RXLOC_MASK; + lebase->ROUTELOC0 |= (loc << _LEUART_ROUTELOC0_RXLOC_SHIFT); + break; + + case GECKO_FUN_LEUART_TX_LOC: + lebase->ROUTEPEN |= LEUART_ROUTEPEN_TXPEN; + lebase->ROUTELOC0 &= ~_LEUART_ROUTELOC0_TXLOC_MASK; + lebase->ROUTELOC0 |= (loc << _LEUART_ROUTELOC0_TXLOC_SHIFT); + break; +#else /* CONFIG_SOC_GECKO_SERIES1 */ case GECKO_FUN_UART_LOC: - loc = GECKO_GET_LOC(pins[i]); #ifdef CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION /* For SOCs with configurable pin_cfg locations (set in SOC Kconfig) */ base->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN; @@ -57,11 +105,11 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp GPIO->USARTROUTE[usart_num].ROUTEEN = GPIO_USART_ROUTEEN_TXPEN | GPIO_USART_ROUTEEN_RXPEN; GPIO->USARTROUTE[usart_num].TXROUTE = - (txpin.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | - (txpin.port << _GPIO_USART_TXROUTE_PORT_SHIFT); + (pin_config.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_USART_TXROUTE_PORT_SHIFT); GPIO->USARTROUTE[usart_num].RXROUTE = - (rxpin.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | - (rxpin.port << _GPIO_USART_RXROUTE_PORT_SHIFT); + (pin_config.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_USART_RXROUTE_PORT_SHIFT); #endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */ #ifdef UART_GECKO_HW_FLOW_CONTROL @@ -98,47 +146,128 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp } #endif /* UART_GECKO_HW_FLOW_CONTROL */ break; +#endif /* CONFIG_SOC_GECKO_SERIES1 */ #endif /* CONFIG_UART_GECKO */ + #ifdef CONFIG_SPI_GECKO +#ifdef CONFIG_SOC_GECKO_SERIES1 + case GECKO_FUN_SPIM_SCK: + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIM_MOSI: + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIM_MISO: + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIM_CS: + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIS_SCK: + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIS_MOSI: + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIS_MISO: + pin_config.mode = gpioModePushPull; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPIS_CS: + pin_config.mode = gpioModeInput; + pin_config.out = 1; + GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, + pin_config.out); + break; + + case GECKO_FUN_SPI_SCK_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_CLKPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_CLKLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_CLKLOC_SHIFT); + break; + + case GECKO_FUN_SPI_MOSI_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_TXPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_TXLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_TXLOC_SHIFT); + break; + + case GECKO_FUN_SPI_MISO_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_RXPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_RXLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_RXLOC_SHIFT); + break; + + case GECKO_FUN_SPI_CS_LOC: + base->ROUTEPEN |= USART_ROUTEPEN_CSPEN; + base->ROUTELOC0 &= ~_USART_ROUTELOC0_CSLOC_MASK; + base->ROUTELOC0 |= (loc << _USART_ROUTELOC0_CSLOC_SHIFT); + break; + +#else /* CONFIG_SOC_GECKO_SERIES1 */ case GECKO_FUN_SPI_SCK: - spi_pin_cfg.port = GECKO_GET_PORT(pins[i]); - spi_pin_cfg.pin = GECKO_GET_PIN(pins[i]); - spi_pin_cfg.mode = gpioModePushPull; - spi_pin_cfg.out = 1; + pin_config.mode = gpioModePushPull; + pin_config.out = 1; GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_CLKPEN; GPIO->USARTROUTE[usart_num].CLKROUTE = - (spi_pin_cfg.pin << _GPIO_USART_CLKROUTE_PIN_SHIFT) | - (spi_pin_cfg.port << _GPIO_USART_CLKROUTE_PORT_SHIFT); + (pin_config.pin << _GPIO_USART_CLKROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_USART_CLKROUTE_PORT_SHIFT); break; + case GECKO_FUN_SPI_MOSI: - spi_pin_cfg.port = GECKO_GET_PORT(pins[i]); - spi_pin_cfg.pin = GECKO_GET_PIN(pins[i]); - spi_pin_cfg.mode = gpioModePushPull; - spi_pin_cfg.out = 1; + pin_config.mode = gpioModePushPull; + pin_config.out = 1; GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_TXPEN; GPIO->USARTROUTE[usart_num].TXROUTE = - (spi_pin_cfg.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | - (spi_pin_cfg.port << _GPIO_USART_TXROUTE_PORT_SHIFT); + (pin_config.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_USART_TXROUTE_PORT_SHIFT); break; + case GECKO_FUN_SPI_MISO: - spi_pin_cfg.port = GECKO_GET_PORT(pins[i]); - spi_pin_cfg.pin = GECKO_GET_PIN(pins[i]); - spi_pin_cfg.mode = gpioModeInput; - spi_pin_cfg.out = 1; + pin_config.mode = gpioModeInput; + pin_config.out = 1; GPIO->USARTROUTE[usart_num].ROUTEEN |= GPIO_USART_ROUTEEN_RXPEN; GPIO->USARTROUTE[usart_num].RXROUTE = - (spi_pin_cfg.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | - (spi_pin_cfg.port << _GPIO_USART_RXROUTE_PORT_SHIFT); + (pin_config.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | + (pin_config.port << _GPIO_USART_RXROUTE_PORT_SHIFT); break; +#endif /* CONFIG_SOC_GECKO_SERIES1 */ #endif /* CONFIG_SPI_GECKO */ default: return -ENOTSUP; } -#ifdef CONFIG_SPI_GECKO - GPIO_PinModeSet(spi_pin_cfg.port, spi_pin_cfg.pin, - spi_pin_cfg.mode, spi_pin_cfg.out); -#endif /* CONFIG_SPI_GECKO */ +#if defined(CONFIG_SPI_GECKO) && !defined(CONFIG_SOC_GECKO_SERIES1) + GPIO_PinModeSet(pin_config.port, pin_config.pin, + pin_config.mode, pin_config.out); +#endif /* defined(CONFIG_SPI_GECKO) && !defined(CONFIG_SOC_GECKO_SERIES1) */ } return 0; diff --git a/drivers/serial/Kconfig.gecko b/drivers/serial/Kconfig.gecko index 53f3ebca2ed3..2330fd401c74 100644 --- a/drivers/serial/Kconfig.gecko +++ b/drivers/serial/Kconfig.gecko @@ -10,5 +10,6 @@ config UART_GECKO select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT select SOC_GECKO_USART + select PINCTRL if SOC_GECKO_SERIES1 help Enable the Gecko uart driver. diff --git a/dts/arm/silabs/efm32_jg_pg_12b.dtsi b/dts/arm/silabs/efm32_jg_pg_12b.dtsi index 59680df2c559..ccf8b8acf4d5 100644 --- a/dts/arm/silabs/efm32_jg_pg_12b.dtsi +++ b/dts/arm/silabs/efm32_jg_pg_12b.dtsi @@ -253,6 +253,14 @@ status = "disabled"; #io-channel-cells = <1>; }; + + pinctrl: pin-controller { + /* Pin controller is a "virtual" device since SiLabs SoCs do pin + * control in a distributed way (GPIO registers and PSEL + * registers on each peripheral). + */ + compatible = "silabs,gecko-pinctrl"; + }; }; }; diff --git a/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h new file mode 100644 index 000000000000..425c767b2f34 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/gecko-pinctrl-s1.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Silicon Labs + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_GECKO_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_GECKO_PINCTRL_H_ + +/* + * The whole GECKO_pin configuration information is encoded in a 32-bit bitfield + * organized as follows: + * + * - 31..24: Pin function. + * - 23..16: Reserved. + * - 15..8: Port for UART_RX/UART_TX functions. + * - 7..0: Pin number for UART_RX/UART_TX functions. + * - 15..8: Reserved for UART_LOC function. + * - 7..0: Loc for UART_LOC function. + */ + +/** + * @name GECKO_pin configuration bit field positions and masks. + * @{ + */ + +/** Position of the function field. */ +#define GECKO_FUN_POS 24U +/** Mask for the function field. */ +#define GECKO_FUN_MSK 0xFFFU + +/** Position of the pin field. */ +#define GECKO_PIN_POS 0U +/** Mask for the pin field. */ +#define GECKO_PIN_MSK 0xFFU + +/** Position of the port field. */ +#define GECKO_PORT_POS 8U +/** Mask for the port field. */ +#define GECKO_PORT_MSK 0xFFU + +/** Position of the loc field. */ +#define GECKO_LOC_POS 0U +/** Mask for the pin field. */ +#define GECKO_LOC_MSK 0xFFU + +/** @} */ + +/** + * @name GECKO_pinctrl pin functions. + * @{ + */ + +/** UART TX */ +#define GECKO_FUN_UART_TX 0U +/** UART RX */ +#define GECKO_FUN_UART_RX 1U +/** UART RTS */ +#define GECKO_FUN_UART_RTS 2U +/** UART CTS */ +#define GECKO_FUN_UART_CTS 3U +/** UART RX LOCATION */ +#define GECKO_FUN_UART_RX_LOC 4U +/** UART TX LOCATION */ +#define GECKO_FUN_UART_TX_LOC 5U +/** UART RTS LOCATION */ +#define GECKO_FUN_UART_RTS_LOC 6U +/** UART CTS LOCATION */ +#define GECKO_FUN_UART_CTS_LOC 7U + +#define GECKO_FUN_SPIM_MISO 8U +#define GECKO_FUN_SPIM_MOSI 9U +#define GECKO_FUN_SPIM_CS 10U +#define GECKO_FUN_SPIM_SCK 11U + +#define GECKO_FUN_LEUART_RX_LOC 12U +#define GECKO_FUN_LEUART_TX_LOC 13U + +#define GECKO_FUN_SPIS_MISO 14U +#define GECKO_FUN_SPIS_MOSI 15U +#define GECKO_FUN_SPIS_CS 16U +#define GECKO_FUN_SPIS_SCK 17U + +#define GECKO_FUN_SPI_MISO_LOC 18U +#define GECKO_FUN_SPI_MOSI_LOC 19U +#define GECKO_FUN_SPI_CS_LOC 20U +#define GECKO_FUN_SPI_SCK_LOC 21U + + +/** @} */ + +/** + * @brief Utility macro to build GECKO psels property entry. + * + * @param fun Pin function configuration (see GECKO_FUNC_{name} macros). + * @param port Port (0 or 1). + * @param pin Pin (0..31). + */ +#define GECKO_PSEL(fun, port, pin) \ + (((GECKO_PORT_##port & GECKO_PORT_MSK) << GECKO_PORT_POS) | \ + ((GECKO_PIN(##pin##) & GECKO_PIN_MSK) << GECKO_PIN_POS) | \ + ((GECKO_FUN_##fun & GECKO_FUN_MSK) << GECKO_FUN_POS)) + +/** + * @brief Utility macro to build GECKO_psels property entry. + * + * @param fun Pin function configuration (see GECKO_FUNC_{name} macros). + * @param loc Location. + */ +#define GECKO_LOC(fun, loc) \ + (((GECKO_LOCATION(##loc##) & GECKO_LOC_MSK) << GECKO_LOC_POS) | \ + ((GECKO_FUN_##fun##_LOC & GECKO_FUN_MSK) << GECKO_FUN_POS)) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_GECKO_PINCTRL_H_ */ diff --git a/soc/arm/silabs_exx32/Kconfig b/soc/arm/silabs_exx32/Kconfig index af050de81090..dbfd42526d1f 100644 --- a/soc/arm/silabs_exx32/Kconfig +++ b/soc/arm/silabs_exx32/Kconfig @@ -28,6 +28,13 @@ config SOC_GECKO_SERIES2 This is equivalent of _SILICON_LABS_32B_SERIES_2 definition in HAL code. +config SOC_GECKO_SERIES1 + bool + help + Set if we're building for Gecko Series 1 SoC. + This is equivalent of _SILICON_LABS_32B_SERIES_1 definition in HAL + code. + config SOC_GECKO_BURTC bool help diff --git a/soc/arm/silabs_exx32/common/pinctrl_soc.h b/soc/arm/silabs_exx32/common/pinctrl_soc.h index 7bbcdeab81ba..8cfad9d46883 100644 --- a/soc/arm/silabs_exx32/common/pinctrl_soc.h +++ b/soc/arm/silabs_exx32/common/pinctrl_soc.h @@ -15,7 +15,11 @@ #include #include +#if CONFIG_SOC_GECKO_SERIES1 +#include +#else #include +#endif #ifdef __cplusplus extern "C" { diff --git a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series index 2d9675430bef..c82872f4eec0 100644 --- a/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32jg12b/Kconfig.series @@ -13,6 +13,7 @@ config SOC_SERIES_EFM32JG12B select SOC_FAMILY_EXX32 select SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION select SOC_GECKO_HAS_HFRCO_FREQRANGE + select SOC_GECKO_SERIES1 select SOC_GECKO_CMU select SOC_GECKO_EMU select SOC_GECKO_GPIO diff --git a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series index 6df3aa9b6997..0ab448b6fb72 100644 --- a/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32pg12b/Kconfig.series @@ -13,6 +13,7 @@ config SOC_SERIES_EFM32PG12B select CPU_HAS_FPU select CPU_HAS_ARM_MPU select SOC_FAMILY_EXX32 + select SOC_GECKO_SERIES1 select SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION select SOC_GECKO_HAS_HFRCO_FREQRANGE select SOC_GECKO_CMU From 03370ab22ecb3310cf18994146b379cc0050af1c Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 18 Jul 2023 09:05:21 +0200 Subject: [PATCH 1838/2042] bluetooth: tester: gap: Add support for extended advertising Needed for LE Audio tests. Signed-off-by: Magdalena Kasenberg --- tests/bluetooth/tester/src/btp/btp_gap.h | 15 +++++ tests/bluetooth/tester/src/btp_gap.c | 70 +++++++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/tests/bluetooth/tester/src/btp/btp_gap.h b/tests/bluetooth/tester/src/btp/btp_gap.h index 986e82e90d34..dee7d5be5178 100644 --- a/tests/bluetooth/tester/src/btp/btp_gap.h +++ b/tests/bluetooth/tester/src/btp/btp_gap.h @@ -39,6 +39,8 @@ struct btp_gap_read_controller_index_list_rp { #define BTP_GAP_SETTINGS_PRIVACY 13 #define BTP_GAP_SETTINGS_CONTROLLER_CONFIG 14 #define BTP_GAP_SETTINGS_STATIC_ADDRESS 15 +#define BTP_GAP_SETTINGS_SC_ONLY 16 +#define BTP_GAP_SETTINGS_EXTENDED_ADVERTISING 17 #define BTP_GAP_READ_CONTROLLER_INFO 0x03 struct btp_gap_read_controller_info_rp { @@ -234,6 +236,19 @@ struct btp_gap_set_filter_list { bt_addr_le_t addr[0]; } __packed; +#define BTP_GAP_SET_PRIVACY 0x1d +#define BTP_GAP_SET_SC_ONLY 0x1e +#define BTP_GAP_SET_SC 0x1f +#define BTP_GAP_SET_MIN_ENC_KEY_SIZE 0x20 + +#define BTP_GAP_SET_EXTENDED_ADVERTISING 0x21 +struct btp_gap_set_extended_advertising_cmd { + uint8_t settings; +} __packed; +struct btp_gap_set_extended_advertising_rp { + uint32_t current_settings; +} __packed; + /* events */ #define BTP_GAP_EV_NEW_SETTINGS 0x80 struct btp_gap_new_settings_ev { diff --git a/tests/bluetooth/tester/src/btp_gap.c b/tests/bluetooth/tester/src/btp_gap.c index 3fc01e371f65..48b961e6375c 100644 --- a/tests/bluetooth/tester/src/btp_gap.c +++ b/tests/bluetooth/tester/src/btp_gap.c @@ -32,6 +32,10 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); #define BT_LE_AD_DISCOV_MASK (BT_LE_AD_LIMITED | BT_LE_AD_GENERAL) #define ADV_BUF_LEN (sizeof(struct btp_gap_device_found_ev) + 2 * 31) +#if defined(CONFIG_BT_EXT_ADV) +static struct bt_le_ext_adv *ext_adv; +#endif + static atomic_t current_settings; struct bt_conn_auth_cb cb; static uint8_t oob_legacy_tk[16] = { 0 }; @@ -254,6 +258,9 @@ static uint8_t supported_commands(const void *cmd, uint16_t cmd_len, #endif /* !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) */ tester_set_bit(rp->data, BTP_GAP_SET_MITM); tester_set_bit(rp->data, BTP_GAP_SET_FILTER_LIST); +#if defined(CONFIG_BT_EXT_ADV) + tester_set_bit(rp->data, BTP_GAP_SET_EXTENDED_ADVERTISING); +#endif *rsp_len = sizeof(*rp) + 4; @@ -306,6 +313,7 @@ static uint8_t controller_info(const void *cmd, uint16_t cmd_len, supported_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); supported_settings |= BIT(BTP_GAP_SETTINGS_LE); supported_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + supported_settings |= BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); rp->supported_settings = sys_cpu_to_le32(supported_settings); rp->current_settings = sys_cpu_to_le32(current_settings); @@ -533,6 +541,7 @@ static uint8_t start_advertising(const void *cmd, uint16_t cmd_len, uint32_t duration; uint8_t adv_len; uint8_t sd_len; + int err; int i; /* This command is very unfortunate since after variable data there is @@ -600,8 +609,38 @@ static uint8_t start_advertising(const void *cmd, uint16_t cmd_len, return BTP_STATUS_FAILED; } + if (atomic_test_bit(¤t_settings, BTP_GAP_SETTINGS_EXTENDED_ADVERTISING)) { +#if defined(CONFIG_BT_EXT_ADV) + param.options |= BT_LE_ADV_OPT_EXT_ADV; + if (ext_adv != NULL) { + err = bt_le_ext_adv_delete(ext_adv); + if (err) { + return BTP_STATUS_FAILED; + } + + ext_adv = NULL; + } + + err = bt_le_ext_adv_create(¶m, NULL, &ext_adv); + if (err) { + return BTP_STATUS_FAILED; + } + + err = bt_le_ext_adv_set_data(ext_adv, ad, adv_len, sd_len ? sd : NULL, sd_len); + if (err) { + return BTP_STATUS_FAILED; + } + + err = bt_le_ext_adv_start(ext_adv, BT_LE_EXT_ADV_START_DEFAULT); +#else + return BTP_STATUS_FAILED; +#endif + } else { + err = bt_le_adv_start(¶m, ad, adv_len, sd_len ? sd : NULL, sd_len); + } + /* BTP API don't allow to set empty scan response data. */ - if (bt_le_adv_start(¶m, ad, adv_len, sd_len ? sd : NULL, sd_len) < 0) { + if (err < 0) { LOG_ERR("Failed to start advertising"); return BTP_STATUS_FAILED; } @@ -1212,6 +1251,28 @@ static uint8_t set_filter_list(const void *cmd, uint16_t cmd_len, return BTP_STATUS_SUCCESS; } +static uint8_t set_extended_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_extended_advertising_cmd *cp = cmd; + struct btp_gap_set_extended_advertising_rp *rp = rsp; + + LOG_DBG("ext adv settings: %u", cp->settings); + + if (cp->settings != 0) { + atomic_set_bit(¤t_settings, + BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + } else { + atomic_clear_bit(¤t_settings, + BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + } + + rp->current_settings = sys_cpu_to_le32(current_settings); + + *rsp_len = sizeof(*rp); + return BTP_STATUS_SUCCESS; +} + static const struct btp_handler handlers[] = { { .opcode = BTP_GAP_READ_SUPPORTED_COMMANDS, @@ -1337,6 +1398,13 @@ static const struct btp_handler handlers[] = { .expect_len = BTP_HANDLER_LENGTH_VARIABLE, .func = set_filter_list, }, +#if defined(CONFIG_BT_EXT_ADV) + { + .opcode = BTP_GAP_SET_EXTENDED_ADVERTISING, + .expect_len = sizeof(struct btp_gap_set_extended_advertising_cmd), + .func = set_extended_advertising, + }, +#endif }; uint8_t tester_init_gap(void) From 1295283a8a7210a764eb46eff7976e706aad4578 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 23 Jun 2023 11:41:32 +0300 Subject: [PATCH 1839/2042] soc: xtensa: nxp: add resource_table section in linker script Add resource_table section in linker script for nxp_adsp_imx8m for inter-process communication. Signed-off-by: Iuliana Prodan --- soc/xtensa/nxp_adsp/imx8m/linker.ld | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/soc/xtensa/nxp_adsp/imx8m/linker.ld b/soc/xtensa/nxp_adsp/imx8m/linker.ld index 2f23680d5552..aab0a0b6548f 100644 --- a/soc/xtensa/nxp_adsp/imx8m/linker.ld +++ b/soc/xtensa/nxp_adsp/imx8m/linker.ld @@ -171,6 +171,12 @@ EXTERN(ext_man_fw_ver) SECTIONS { +#ifdef CONFIG_OPENAMP_RSC_TABLE + SECTION_PROLOGUE(.resource_table,, SUBALIGN(4)) + { + KEEP(*(.resource_table*)) + } GROUP_LINK_IN(ROMABLE_REGION) +#endif #include .ResetVector.text : ALIGN(4) From b4293ec026c415e54af9d0af8dd8ada7fd42187b Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Fri, 23 Jun 2023 11:47:58 +0300 Subject: [PATCH 1840/2042] dts: xtensa: nxp: add nodes for IPC Add mailbox and interrupt-controller nodes used for inter-process communication. Add also the dt binding for the interrupt-controller. For now, this is used just to fix some compile errors, since the mailbox requires an interrupt-controller. For DSP, we have a direct interrupt line to the core. Signed-off-by: Iuliana Prodan --- .../interrupt-controller/nxp,irqsteer-intc.yaml | 13 +++++++++++++ dts/xtensa/nxp/nxp_imx8m.dtsi | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml diff --git a/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml new file mode 100644 index 000000000000..03b5d3b39e03 --- /dev/null +++ b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml @@ -0,0 +1,13 @@ +description: i.MX DSP interrupt controller + +compatible: "nxp,irqsteer-intc" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 2 + +interrupt-cells: + - irq + - priority diff --git a/dts/xtensa/nxp/nxp_imx8m.dtsi b/dts/xtensa/nxp/nxp_imx8m.dtsi index badbd5ac858f..9e72a3d59ed7 100644 --- a/dts/xtensa/nxp/nxp_imx8m.dtsi +++ b/dts/xtensa/nxp/nxp_imx8m.dtsi @@ -33,6 +33,14 @@ }; 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)>; @@ -59,5 +67,13 @@ clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; status = "disabled"; }; + + mailbox0: mailbox@30e70000 { + compatible = "nxp,imx-mu-rev2"; + reg = <0x30e70000 0x10000>; + interrupts = <7 0>; + rdc = <0>; + status = "disabled"; + }; }; }; From 393a7e107d480f1266dc36e1aa9eba659d1b6ed3 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Wed, 21 Jun 2023 14:33:37 +0300 Subject: [PATCH 1841/2042] samples: add support for nxp_adsp_imx8m in openamp_rsc_table Add the dts and config overlay for nxp_adsp_imx8m board in order to have the openamp_rsc_table sample working on HiFi4 DSP from i.MX 8M Plus. Signed-off-by: Iuliana Prodan --- .../boards/nxp_adsp_imx8m.conf | 4 ++++ .../boards/nxp_adsp_imx8m.overlay | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.conf create mode 100644 samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.overlay diff --git a/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.conf b/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.conf new file mode 100644 index 000000000000..0f7274227ce4 --- /dev/null +++ b/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.conf @@ -0,0 +1,4 @@ +CONFIG_LOG_PRINTK=n +CONFIG_IPM_IMX_MAX_DATA_SIZE_16=n +CONFIG_IPM_IMX_MAX_DATA_SIZE_4=y +CONFIG_OPENAMP_WITH_DCACHE=y diff --git a/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.overlay b/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.overlay new file mode 100644 index 000000000000..8fefebe54850 --- /dev/null +++ b/samples/subsys/ipc/openamp_rsc_table/boards/nxp_adsp_imx8m.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + zephyr,ipc_shm = &dspsram3; + zephyr,ipc = &mailbox0; + }; + + dspsram3: memory@942f0000 { + compatible = "mmio-sram"; + reg = <0x942f0000 0x110000>; + }; +}; + +&mailbox0 { + status = "okay"; +}; From f4f261bce589a25e0663e43fda29585208aed761 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Mon, 17 Jul 2023 17:19:18 +0300 Subject: [PATCH 1842/2042] samples: openamp_rsc_table: increase stack size While testing openamp_rsc_table sample for HiFi4 DSP from i.MX8MP, realized the stack is not enough. Increase the size based on Thread Analyzer measurements: *** Booting Zephyr OS build zephyr-v3.4.0-971-g9415baf2c211 *** Starting application threads! OpenAMP[remote] linux responder demo started OpenAMP[remote] Linux sample client responder started OpenAMP[remote] Linux tty responder started [00:00:00.020,000] openamp_rsc_table: mailbox_notify: mailbox_notify: msg received [00:00:00.024,000] openamp_rsc_table: mailbox_notify: mailbox_notify: msg received Thread analyze: 0x9240c5a0 : STACK: unused 240 usage 1296 / 1536 (84 %); CPU: 10% : Total CPU cycles used: 3388523 0x9240c628 : STACK: unused 240 usage 784 / 1024 (76 %); CPU: 10% : Total CPU cycles used: 4086621 0x9240c6b0 : STACK: unused 408 usage 616 / 1024 (60 %); CPU: 7% : Total CPU cycles used: 3553673 0x9240c738 : STACK: unused 152 usage 872 / 1024 (85 %); CPU: 44% : Total CPU cycles used: 25529572 0x9240c7c0 : STACK: unused 352 usage 672 / 1024 (65 %); CPU: 21% : Total CPU cycles used: 13742359 0x9240c888 : STACK: unused 936 usage 88 / 1024 (8 %); CPU: 0% : Total CPU cycles used: 0 ISR0 : STACK: unused 1536 usage 512 / 2048 (25 %) Signed-off-by: Iuliana Prodan --- samples/subsys/ipc/openamp_rsc_table/src/main_remote.c | 6 +++--- 1 file changed, 3 insertions(+), 3 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 bea90ddf3ffa..9b6b634952c6 100644 --- a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c +++ b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c @@ -31,10 +31,10 @@ LOG_MODULE_REGISTER(openamp_rsc_table, LOG_LEVEL_DBG); #define SHM_START_ADDR DT_REG_ADDR(SHM_NODE) #define SHM_SIZE DT_REG_SIZE(SHM_NODE) -#define APP_TASK_STACK_SIZE (512) +#define APP_TASK_STACK_SIZE (1024) -/* Add 512 extra bytes for the TTY task stack for the "tx_buff" buffer. */ -#define APP_TTY_TASK_STACK_SIZE (1024) +/* Add 1024 extra bytes for the TTY task stack for the "tx_buff" buffer. */ +#define APP_TTY_TASK_STACK_SIZE (1536) K_THREAD_STACK_DEFINE(thread_mng_stack, APP_TASK_STACK_SIZE); K_THREAD_STACK_DEFINE(thread_rp__client_stack, APP_TASK_STACK_SIZE); From 3945988ac15a43281d77c83d7aaa3420b6191e8c Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Tue, 18 Jul 2023 12:13:06 +0300 Subject: [PATCH 1843/2042] west: update open-amp repo Update open-amp repository with new sha. Signed-off-by: Iuliana Prodan --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 1fbcfb6d3265..16ea3eab6176 100644 --- a/west.yml +++ b/west.yml @@ -290,7 +290,7 @@ manifest: revision: 7a5b67d9ee66d84e4ef5cb1f56c8f0f3252d5aa2 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp - revision: c904a01d4a882bcbb39987e0e2ce5308f49ac7ad + revision: 42b7c577714b8f22ce82a901e19c1814af4609a8 path: modules/lib/open-amp - name: openthread revision: f7690fe7e9d638341921808cba6a3e695ec0131e From 7bfec37247b82e1fbf7b5ee97ea88af2a1b37f32 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 6 Jul 2023 18:08:20 +0200 Subject: [PATCH 1844/2042] usb: device: clarify the impact of Kconfig option USB_COMPOSITE_DEVICE Effectively, this option changes code triple in device descriptor. Although the name is misleading, renaming it would again lead to negative user experiences. Instead, clarify what the option does and always select it where it is required. Signed-off-by: Johann Fischer --- subsys/usb/device/Kconfig | 6 ++++-- subsys/usb/device/class/Kconfig.cdc | 1 + subsys/usb/device/class/audio/Kconfig | 1 + subsys/usb/device/class/audio/audio.c | 2 -- subsys/usb/device/class/audio/usb_audio_internal.h | 5 ----- subsys/usb/device/class/cdc_acm.c | 8 -------- subsys/usb/device/class/netusb/Kconfig | 2 ++ subsys/usb/device/class/netusb/function_ecm.c | 6 ------ 8 files changed, 8 insertions(+), 23 deletions(-) diff --git a/subsys/usb/device/Kconfig b/subsys/usb/device/Kconfig index 20addc2f1c1d..476f7400270c 100644 --- a/subsys/usb/device/Kconfig +++ b/subsys/usb/device/Kconfig @@ -49,9 +49,11 @@ config USB_DEVICE_SN Hardware Information Driver (HWINFO). config USB_COMPOSITE_DEVICE - bool "Composite device driver" + bool "Use Interface Association Descriptor code triple" help - Enable composite USB device driver. + This option modifies the code triple in the device descriptor + to signal that one of the functions has two or more interfaces and + uses the Interface Association Descriptor. config USB_MAX_NUM_TRANSFERS int "Set number of USB transfer data buffers" diff --git a/subsys/usb/device/class/Kconfig.cdc b/subsys/usb/device/class/Kconfig.cdc index af1d8aba3982..7c7480280238 100644 --- a/subsys/usb/device/class/Kconfig.cdc +++ b/subsys/usb/device/class/Kconfig.cdc @@ -6,6 +6,7 @@ menu "USB CDC ACM Class support" config USB_CDC_ACM bool "USB CDC ACM Class support" default y + select USB_COMPOSITE_DEVICE depends on SERIAL depends on DT_HAS_ZEPHYR_CDC_ACM_UART_ENABLED select SERIAL_HAS_DRIVER diff --git a/subsys/usb/device/class/audio/Kconfig b/subsys/usb/device/class/audio/Kconfig index e38bf11f0d57..825f2580a509 100644 --- a/subsys/usb/device/class/audio/Kconfig +++ b/subsys/usb/device/class/audio/Kconfig @@ -6,6 +6,7 @@ config USB_DEVICE_AUDIO bool "USB Audio Device Class Driver" select EXPERIMENTAL + select USB_COMPOSITE_DEVICE help USB Audio Device Class driver. Zephyr USB Audio Class is considered experimental diff --git a/subsys/usb/device/class/audio/audio.c b/subsys/usb/device/class/audio/audio.c index 637096052f77..dc7e15f08d82 100644 --- a/subsys/usb/device/class/audio/audio.c +++ b/subsys/usb/device/class/audio/audio.c @@ -292,12 +292,10 @@ static void audio_interface_config(struct usb_desc_header *head, struct usb_if_descriptor *iface = (struct usb_if_descriptor *)head; struct cs_ac_if_descriptor *header; -#ifdef CONFIG_USB_COMPOSITE_DEVICE struct usb_association_descriptor *iad = (struct usb_association_descriptor *) ((char *)iface - sizeof(struct usb_association_descriptor)); iad->bFirstInterface = bInterfaceNumber; -#endif fix_fu_descriptors(iface); /* Audio Control Interface */ diff --git a/subsys/usb/device/class/audio/usb_audio_internal.h b/subsys/usb/device/class/audio/usb_audio_internal.h index 1cf8a10702d8..c0d5383577d9 100644 --- a/subsys/usb/device/class/audio/usb_audio_internal.h +++ b/subsys/usb/device/class/audio/usb_audio_internal.h @@ -328,13 +328,8 @@ struct dev##_feature_unit_descriptor_##i { \ .iFunction = 0, \ } -#ifdef CONFIG_USB_COMPOSITE_DEVICE #define USB_AUDIO_IAD_DECLARE struct usb_association_descriptor iad; #define USB_AUDIO_IAD(if_cnt) .iad = INIT_IAD(USB_AUDIO_AUDIOCONTROL, if_cnt), -#else -#define USB_AUDIO_IAD_DECLARE -#define USB_AUDIO_IAD(if_cnt) -#endif #define DECLARE_DESCRIPTOR(dev, i, ifaces) \ DECLARE_HEADER(dev, i, ifaces); \ diff --git a/subsys/usb/device/class/cdc_acm.c b/subsys/usb/device/class/cdc_acm.c index ab14732440e1..9262cd5cf78f 100644 --- a/subsys/usb/device/class/cdc_acm.c +++ b/subsys/usb/device/class/cdc_acm.c @@ -80,9 +80,7 @@ LOG_MODULE_REGISTER(usb_cdc_acm, CONFIG_USB_CDC_ACM_LOG_LEVEL); #define ACM_IN_EP_IDX 2 struct usb_cdc_acm_config { -#if (CONFIG_USB_COMPOSITE_DEVICE || CONFIG_CDC_ACM_IAD) struct usb_association_descriptor iad_cdc; -#endif struct usb_if_descriptor if0; struct cdc_header_descriptor if0_header; struct cdc_cm_descriptor if0_cm; @@ -437,9 +435,7 @@ static void cdc_interface_config(struct usb_desc_header *head, desc->if0_union.bControlInterface = bInterfaceNumber; desc->if1.bInterfaceNumber = bInterfaceNumber + 1; desc->if0_union.bSubordinateInterface0 = bInterfaceNumber + 1; -#if (CONFIG_USB_COMPOSITE_DEVICE || CONFIG_CDC_ACM_IAD) desc->iad_cdc.bFirstInterface = bInterfaceNumber; -#endif } /** @@ -1051,7 +1047,6 @@ static const struct uart_driver_api cdc_acm_driver_api = { #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ }; -#if (CONFIG_USB_COMPOSITE_DEVICE || CONFIG_CDC_ACM_IAD) #define INITIALIZER_IAD \ .iad_cdc = { \ .bLength = sizeof(struct usb_association_descriptor), \ @@ -1063,9 +1058,6 @@ static const struct uart_driver_api cdc_acm_driver_api = { .bFunctionProtocol = 0, \ .iFunction = 0, \ }, -#else -#define INITIALIZER_IAD -#endif #define INITIALIZER_IF(iface_num, num_ep, class, subclass) \ { \ diff --git a/subsys/usb/device/class/netusb/Kconfig b/subsys/usb/device/class/netusb/Kconfig index 803322536e89..e358c9b9ac79 100644 --- a/subsys/usb/device/class/netusb/Kconfig +++ b/subsys/usb/device/class/netusb/Kconfig @@ -12,6 +12,7 @@ config USB_DEVICE_NETWORK config USB_DEVICE_NETWORK_ECM bool "USB Ethernet Control Model (ECM) Networking device" select USB_DEVICE_NETWORK + select USB_COMPOSITE_DEVICE help Ethernet Control Model (ECM) is a part of Communications Device Class (CDC) USB protocol specified by USB-IF. @@ -27,6 +28,7 @@ config USB_DEVICE_NETWORK_EEM config USB_DEVICE_NETWORK_RNDIS bool "USB Remote NDIS (RNDIS) Networking device" select USB_DEVICE_NETWORK + select USB_COMPOSITE_DEVICE help Remote NDIS (RNDIS) is commonly used Microsoft vendor protocol with Specification available from Microsoft web site. diff --git a/subsys/usb/device/class/netusb/function_ecm.c b/subsys/usb/device/class/netusb/function_ecm.c index b5eaa0dfd8d2..256cf9b9d1ed 100644 --- a/subsys/usb/device/class/netusb/function_ecm.c +++ b/subsys/usb/device/class/netusb/function_ecm.c @@ -31,9 +31,7 @@ LOG_MODULE_REGISTER(usb_ecm, CONFIG_USB_DEVICE_NETWORK_LOG_LEVEL); static uint8_t tx_buf[NET_ETH_MAX_FRAME_SIZE], rx_buf[NET_ETH_MAX_FRAME_SIZE]; struct usb_cdc_ecm_config { -#ifdef CONFIG_USB_COMPOSITE_DEVICE struct usb_association_descriptor iad; -#endif struct usb_if_descriptor if0; struct cdc_header_descriptor if0_header; struct cdc_union_descriptor if0_union; @@ -48,7 +46,6 @@ struct usb_cdc_ecm_config { } __packed; USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_cdc_ecm_config cdc_ecm_cfg = { -#ifdef CONFIG_USB_COMPOSITE_DEVICE .iad = { .bLength = sizeof(struct usb_association_descriptor), .bDescriptorType = USB_DESC_INTERFACE_ASSOC, @@ -59,7 +56,6 @@ USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_cdc_ecm_config cdc_ecm_cfg = { .bFunctionProtocol = 0, .iFunction = 0, }, -#endif /* Interface descriptor 0 */ /* CDC Communication interface */ .if0 = { @@ -422,9 +418,7 @@ static void ecm_interface_config(struct usb_desc_header *head, cdc_ecm_cfg.if0_union.bSubordinateInterface0 = bInterfaceNumber + 1; cdc_ecm_cfg.if1_0.bInterfaceNumber = bInterfaceNumber + 1; cdc_ecm_cfg.if1_1.bInterfaceNumber = bInterfaceNumber + 1; -#ifdef CONFIG_USB_COMPOSITE_DEVICE cdc_ecm_cfg.iad.bFirstInterface = bInterfaceNumber; -#endif } USBD_DEFINE_CFG_DATA(cdc_ecm_config) = { From 430818ecaab77621339ba0e20e502a2e8d2c819c Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 6 Jul 2023 19:11:55 +0200 Subject: [PATCH 1845/2042] sample/tests: remove CONFIG_USB_COMPOSITE_DEVICE usage This is no longer necessary, as this option is selected as a dependency for class implementations where it is required. Also remove redundant test cases. Signed-off-by: Johann Fischer --- samples/net/sockets/echo_server/sample.yaml | 9 --------- .../usb/cdc_acm/overlay-composite-cdc-dfu.conf | 2 -- .../usb/cdc_acm/overlay-composite-cdc-msc.conf | 2 -- samples/subsys/usb/cdc_acm_composite/prj.conf | 1 - samples/subsys/usb/hid-cdc/prj.conf | 1 - samples/subsys/usb/hid/sample.yaml | 12 ------------ tests/subsys/usb/desc_sections/prj.conf | 1 - tests/subsys/usb/desc_sections/src/desc_sections.c | 4 ---- 8 files changed, 32 deletions(-) diff --git a/samples/net/sockets/echo_server/sample.yaml b/samples/net/sockets/echo_server/sample.yaml index 6c90fa6eee0c..6b4a8d44487e 100644 --- a/samples/net/sockets/echo_server/sample.yaml +++ b/samples/net/sockets/echo_server/sample.yaml @@ -84,15 +84,6 @@ tests: tags: - net - usb - sample.net.sockets.echo_server.usbnet_composite: - depends_on: usb_device - harness: net - extra_args: OVERLAY_CONFIG="overlay-netusb.conf" - extra_configs: - - CONFIG_USB_COMPOSITE_DEVICE=y - tags: - - net - - usb sample.net.sockets.echo_server.nrf_openthread: extra_args: OVERLAY_CONFIG="overlay-ot.conf" slow: true diff --git a/samples/subsys/usb/cdc_acm/overlay-composite-cdc-dfu.conf b/samples/subsys/usb/cdc_acm/overlay-composite-cdc-dfu.conf index 0f84f23b0608..e1fc3c9a994f 100644 --- a/samples/subsys/usb/cdc_acm/overlay-composite-cdc-dfu.conf +++ b/samples/subsys/usb/cdc_acm/overlay-composite-cdc-dfu.conf @@ -6,8 +6,6 @@ # (does not re-enumerates) and thus make it unable for the device # to restart in DFU mode. -CONFIG_USB_COMPOSITE_DEVICE=y - CONFIG_USB_DFU_CLASS=y CONFIG_FLASH=y CONFIG_IMG_MANAGER=y diff --git a/samples/subsys/usb/cdc_acm/overlay-composite-cdc-msc.conf b/samples/subsys/usb/cdc_acm/overlay-composite-cdc-msc.conf index ff01af597910..a272869511ea 100644 --- a/samples/subsys/usb/cdc_acm/overlay-composite-cdc-msc.conf +++ b/samples/subsys/usb/cdc_acm/overlay-composite-cdc-msc.conf @@ -1,8 +1,6 @@ # Overlay file for composite configuration # CDC ACM + Mass Storage (RAM) -CONFIG_USB_COMPOSITE_DEVICE=y - CONFIG_USB_MASS_STORAGE=y CONFIG_USB_MASS_STORAGE_LOG_LEVEL_ERR=y diff --git a/samples/subsys/usb/cdc_acm_composite/prj.conf b/samples/subsys/usb/cdc_acm_composite/prj.conf index 6b029f43a5e8..db41a5ba64dc 100644 --- a/samples/subsys/usb/cdc_acm_composite/prj.conf +++ b/samples/subsys/usb/cdc_acm_composite/prj.conf @@ -7,7 +7,6 @@ CONFIG_UART_LINE_CTRL=y CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC ACM Composite sample" CONFIG_USB_DEVICE_PID=0x0002 -CONFIG_USB_COMPOSITE_DEVICE=y CONFIG_USB_CDC_ACM_RINGBUF_SIZE=512 CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n diff --git a/samples/subsys/usb/hid-cdc/prj.conf b/samples/subsys/usb/hid-cdc/prj.conf index cf274459fb5a..695f97698a3b 100644 --- a/samples/subsys/usb/hid-cdc/prj.conf +++ b/samples/subsys/usb/hid-cdc/prj.conf @@ -1,4 +1,3 @@ -CONFIG_USB_COMPOSITE_DEVICE=y CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PRODUCT="Zephyr HID and CDC ACM sample" CONFIG_USB_DEVICE_PID=0x0003 diff --git a/samples/subsys/usb/hid/sample.yaml b/samples/subsys/usb/hid/sample.yaml index 7cec4d2ec815..7f63562bbf73 100644 --- a/samples/subsys/usb/hid/sample.yaml +++ b/samples/subsys/usb/hid/sample.yaml @@ -11,18 +11,6 @@ tests: regex: - "main: HID Device: dev" - "main: Starting application" - sample.usb.hid_composite: - depends_on: usb_device - extra_configs: - - CONFIG_USB_COMPOSITE_DEVICE=y - tags: usb - arch_exclude: posix - harness: console - harness_config: - type: multi_line - regex: - - "main: HID Device: dev" - - "main: Starting application" sample.usb.hid.buildonly: depends_on: usb_device tags: usb diff --git a/tests/subsys/usb/desc_sections/prj.conf b/tests/subsys/usb/desc_sections/prj.conf index 7358e60b1eb1..a7265e4f03c2 100644 --- a/tests/subsys/usb/desc_sections/prj.conf +++ b/tests/subsys/usb/desc_sections/prj.conf @@ -1,6 +1,5 @@ CONFIG_ZTEST=y CONFIG_USB_DEVICE_STACK=y -CONFIG_USB_COMPOSITE_DEVICE=n CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y CONFIG_LOG=y diff --git a/tests/subsys/usb/desc_sections/src/desc_sections.c b/tests/subsys/usb/desc_sections/src/desc_sections.c index 6297d9fc8854..5100f1b90aef 100644 --- a/tests/subsys/usb/desc_sections/src/desc_sections.c +++ b/tests/subsys/usb/desc_sections/src/desc_sections.c @@ -14,10 +14,6 @@ #include LOG_MODULE_REGISTER(test_main, LOG_LEVEL_DBG); -#ifdef CONFIG_USB_COMPOSITE_DEVICE -#error Do not use composite configuration -#endif - /* Linker-defined symbols bound the USB descriptor structs */ extern struct usb_desc_header __usb_descriptor_start[]; extern struct usb_desc_header __usb_descriptor_end[]; From 740f2697bc99f98e2d84b07893e6cfd692ab2710 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 6 Jul 2023 15:14:36 +0200 Subject: [PATCH 1846/2042] include: usb: revise BOS support header Hide parts that are not relevant to the application and are only used internally by the stack. Add minimal documentation. Signed-off-by: Johann Fischer --- include/zephyr/usb/bos.h | 79 ++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/include/zephyr/usb/bos.h b/include/zephyr/usb/bos.h index f61b30a8cc96..b7a0ef08339f 100644 --- a/include/zephyr/usb/bos.h +++ b/include/zephyr/usb/bos.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,40 +8,53 @@ #ifndef ZEPHYR_INCLUDE_USB_BOS_H_ #define ZEPHYR_INCLUDE_USB_BOS_H_ -#if defined(CONFIG_USB_DEVICE_BOS) -#define USB_DEVICE_BOS_DESC_DEFINE_HDR \ - static __in_section(usb, bos_desc_area, 0) __aligned(1) __used +#include + +/** + * @brief USB Binary Device Object Store support + * @defgroup usb_bos USB BOS support + * @ingroup usb + * @{ + */ + +/** + * @brief Helper macro to place the BOS compatibility descriptor + * in the right memory section. + */ #define USB_DEVICE_BOS_DESC_DEFINE_CAP \ static __in_section(usb, bos_desc_area, 1) __aligned(1) __used -#define USB_BOS_CAPABILITY_EXTENSION 0x02 -#define USB_BOS_CAPABILITY_PLATFORM 0x05 +/** Device capability type codes */ +enum usb_bos_capability_types { + USB_BOS_CAPABILITY_EXTENSION = 0x02, + USB_BOS_CAPABILITY_PLATFORM = 0x05, +}; -/* BOS Capability Descriptor */ -struct usb_bos_platform_descriptor { +/** BOS USB 2.0 extension capability descriptor */ +struct usb_bos_capability_lpm { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDevCapabilityType; - uint8_t bReserved; - uint8_t PlatformCapabilityUUID[16]; + uint32_t bmAttributes; } __packed; -/* BOS Descriptor */ -struct usb_bos_descriptor { +/** BOS platform capability descriptor */ +struct usb_bos_platform_descriptor { uint8_t bLength; uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumDeviceCaps; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t PlatformCapabilityUUID[16]; } __packed; -/* BOS Capability webusb */ +/** WebUSB specific part of platform capability descriptor */ struct usb_bos_capability_webusb { uint16_t bcdVersion; uint8_t bVendorCode; uint8_t iLandingPage; } __packed; -/* BOS Capability MS OS Descriptors version 2 */ +/** Microsoft OS 2.0 descriptor specific part of platform capability descriptor */ struct usb_bos_capability_msos { uint32_t dwWindowsVersion; uint16_t wMSOSDescriptorSetTotalLength; @@ -48,20 +62,47 @@ struct usb_bos_capability_msos { uint8_t bAltEnumCode; } __packed; -struct usb_bos_capability_lpm { +/** + * @brief Register BOS capability descriptor + * + * This function should be used by the application to register BOS capability + * descriptors before the USB device stack is enabled. + * + * @param[in] hdr Pointer to BOS capability descriptor + */ +void usb_bos_register_cap(struct usb_bos_platform_descriptor *hdr); + +/** + * @cond INTERNAL_HIDDEN + * Internally used functions + */ + +/* BOS Descriptor (root descriptor) */ +struct usb_bos_descriptor { uint8_t bLength; uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - uint32_t bmAttributes; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; } __packed; +#define USB_DEVICE_BOS_DESC_DEFINE_HDR \ + static __in_section(usb, bos_desc_area, 0) __aligned(1) __used + size_t usb_bos_get_length(void); + void usb_bos_fix_total_length(void); -void usb_bos_register_cap(struct usb_bos_platform_descriptor *hdr); + const void *usb_bos_get_header(void); + +#if defined(CONFIG_USB_DEVICE_BOS) int usb_handle_bos(struct usb_setup_packet *setup, int32_t *len, uint8_t **data); #else #define usb_handle_bos(x, y, z) -ENOTSUP #endif +/** @endcond */ + +/** + * @} + */ #endif /* ZEPHYR_INCLUDE_USB_BOS_H_ */ From 0595fd028db738ae22f194530e40f416f76cdf89 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 6 Jul 2023 15:18:06 +0200 Subject: [PATCH 1847/2042] doc: usb: add reference to BOS support API Add a reference to the BOS support API. Signed-off-by: Johann Fischer --- doc/connectivity/usb/device/api/index.rst | 1 + doc/connectivity/usb/device/api/usb_device_bos.rst | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 doc/connectivity/usb/device/api/usb_device_bos.rst diff --git a/doc/connectivity/usb/device/api/index.rst b/doc/connectivity/usb/device/api/index.rst index ddc06aa47686..02bf793805e3 100644 --- a/doc/connectivity/usb/device/api/index.rst +++ b/doc/connectivity/usb/device/api/index.rst @@ -9,3 +9,4 @@ USB device support APIs usb_dc.rst usb_device.rst usb_device_hid.rst + usb_device_bos.rst diff --git a/doc/connectivity/usb/device/api/usb_device_bos.rst b/doc/connectivity/usb/device/api/usb_device_bos.rst new file mode 100644 index 000000000000..a40318796467 --- /dev/null +++ b/doc/connectivity/usb/device/api/usb_device_bos.rst @@ -0,0 +1,9 @@ +.. _usb_bos_api: + +Binary Device Object Store (BOS) support API +############################################ + +API reference +************* + +.. doxygengroup:: usb_bos From c435dea191f9d802112766d1491885c31c8845aa Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Mon, 29 May 2023 09:20:49 -0300 Subject: [PATCH 1848/2042] soc: xtensa: esp32s3: add support for SPIRAM Add support for external PSRAM for esp32s3. Signed-off-by: Lucas Tamborrino --- soc/xtensa/espressif_esp32/common/Kconfig.soc | 13 ++++++++ .../espressif_esp32/esp32s3/Kconfig.soc | 19 ++++++++++++ soc/xtensa/espressif_esp32/esp32s3/default.ld | 29 ++++++++++++++++- soc/xtensa/espressif_esp32/esp32s3/soc.c | 31 +++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) diff --git a/soc/xtensa/espressif_esp32/common/Kconfig.soc b/soc/xtensa/espressif_esp32/common/Kconfig.soc index 4cf8bf9095f8..3446e6882434 100644 --- a/soc/xtensa/espressif_esp32/common/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/common/Kconfig.soc @@ -40,6 +40,15 @@ config ESP_HEAP_SEARCH_ALL_REGIONS menu "SPI RAM config" depends on ESP_SPIRAM +choice SPIRAM_MODE + prompt "Mode (QUAD/OCT) of SPI RAM chip in use" + default SPIRAM_MODE_QUAD + +config SPIRAM_MODE_QUAD + bool "Quad Mode PSRAM" + +endchoice # SPIRAM_MODE + choice SPIRAM_TYPE prompt "Type of SPI RAM chip in use" depends on ESP_SPIRAM @@ -98,6 +107,10 @@ config SPIRAM_SPEED_80M depends on ESPTOOLPY_FLASHFREQ_80M bool "80MHz clock speed" +config SPIRAM_SPEED_120M + depends on SPIRAM_MODE_QUAD && SOC_SERIES_ESP32S3 + bool "120MHz clock speed" + endchoice # SPIRAM_SPEED menu "PSRAM clock and cs IO for ESP32-DOWD" diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc index 7dd8fc4dddb8..ac265e5edb01 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc @@ -293,4 +293,23 @@ config MAC_BB_PD endmenu # Cache config +menu "PSRAM Clock and CS IO for ESP32S3" + depends on ESP_SPIRAM + +config DEFAULT_PSRAM_CLK_IO + int "PSRAM CLK IO number" + range 0 33 + default 30 + help + The PSRAM Clock IO can be any unused GPIO, please refer to your hardware design. + +config DEFAULT_PSRAM_CS_IO + int "PSRAM CS IO number" + range 0 33 + default 26 + help + The PSRAM CS IO can be any unused GPIO, please refer to your hardware design. + +endmenu # PSRAM clock and cs IO for ESP32S3 + endif # SOC_SERIES_ESP32S3 diff --git a/soc/xtensa/espressif_esp32/esp32s3/default.ld b/soc/xtensa/espressif_esp32/esp32s3/default.ld index 4361e7b38e3a..cee52c7f1f6d 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s3/default.ld @@ -39,6 +39,8 @@ #define RAMABLE_REGION dram0_0_seg #define ROMABLE_REGION ROM +#define EXT_RAM_ORG (0x3E000000 - CONFIG_ESP_SPIRAM_SIZE) + #ifdef CONFIG_FLASH_SIZE #define FLASH_SIZE CONFIG_FLASH_SIZE #else @@ -70,7 +72,13 @@ MEMORY * Hence, an offset of 0x40 is added to DROM segment origin. */ drom0_0_seg(R): org = 0x3C000040, len = FLASH_SIZE - 0x40 - + /** + * `extern_ram_seg` and `drom0_0_seg` share the same bus and the address region. + * so we allocate `extern_ram_seg` at the end of the address region. + */ +#if defined(CONFIG_ESP_SPIRAM) + ext_ram_seg(RWX): org = EXT_RAM_ORG, len = CONFIG_ESP_SPIRAM_SIZE +#endif /* RTC fast memory (executable). Persists over deep sleep. */ rtc_iram_seg(RWX): org = 0x600fe000, len = 0x2000 @@ -219,6 +227,17 @@ SECTIONS _image_rodata_end = ABSOLUTE(.); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) +#if defined(CONFIG_ESP_SPIRAM) + /* This section holds .ext_ram.bss data, and will be put in PSRAM */ + .ext_ram.bss (NOLOAD) : + { + _ext_ram_bss_start = ABSOLUTE(.); + *(.ext_ram.bss*) + . = ALIGN(4); + _ext_ram_bss_end = ABSOLUTE(.); + } > ext_ram_seg +#endif + /* Send .iram0 code to iram */ .iram0.vectors : ALIGN(4) { @@ -272,6 +291,9 @@ SECTIONS *libsoc.a:rtc_*.*(.literal .text .literal.* .text.*) *libsoc.a:cpu_util.*(.literal .text .literal.* .text.*) *libgcc.a:lib2funcs.*(.literal .text .literal.* .text.*) + *libzephyr.a:spiram*.*(.literal .text .literal.* .text.*) + *libzephyr.a:spi_timing*.*(.literal .text .literal.* .text.*) + *libzephyr.a:spi_flash*.*(.literal .text .literal.* .text.*) *libdrivers__flash.a:flash_esp32.*(.literal .text .literal.* .text.*) *libzephyr.a:windowspill_asm.*(.literal .text .literal.* .text.*) *libzephyr.a:log_noos.*(.literal .text .literal.* .text.*) @@ -642,3 +664,8 @@ SECTIONS ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), "IRAM0 segment data does not fit.") + +#if defined(CONFIG_ESP_SPIRAM) +ASSERT(((ORIGIN(ext_ram_seg)) > _image_rodata_end), + "External RAM segment does not fit.") +#endif diff --git a/soc/xtensa/espressif_esp32/esp32s3/soc.c b/soc/xtensa/espressif_esp32/esp32s3/soc.c index 3e8bb7373202..4d44fe2f004a 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/soc.c +++ b/soc/xtensa/espressif_esp32/esp32s3/soc.c @@ -34,11 +34,18 @@ #include "esp_app_format.h" #include "esp_clk_internal.h" +#include "esp32s3/spiram.h" + #ifdef CONFIG_MCUBOOT #include "bootloader_init.h" #endif /* CONFIG_MCUBOOT */ #include +#if CONFIG_ESP_SPIRAM +extern int _ext_ram_bss_start; +extern int _ext_ram_bss_end; +#endif + extern void z_cstart(void); #ifndef CONFIG_MCUBOOT @@ -104,6 +111,30 @@ void IRAM_ATTR __esp_platform_start(void) /* Apply SoC patches */ esp_errata(); +#if CONFIG_ESP_SPIRAM + esp_err_t err = esp_spiram_init(); + + if (err != ESP_OK) { + printk("Failed to Initialize external RAM, aborting.\n"); + abort(); + } + + esp_spiram_init_cache(); + if (esp_spiram_get_size() < CONFIG_ESP_SPIRAM_SIZE) { + printk("External RAM size is less than configured, aborting.\n"); + abort(); + } + + if (!esp_spiram_test()) { + printk("External RAM failed memory test!\n"); + abort(); + } + + memset(&_ext_ram_bss_start, 0, + (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); + +#endif /* CONFIG_ESP_SPIRAM */ + /* ESP-IDF/MCUboot 2nd stage bootloader enables RTC WDT to check on startup sequence * related issues in application. Hence disable that as we are about to start * Zephyr environment. From 4f1fd56b36e50dddbb77d908ebeb095621dbfb8e Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Wed, 31 May 2023 14:36:12 -0300 Subject: [PATCH 1849/2042] tests: boards: espressif: add esp32s3 to cache coex test Test esp32s3 for cache coexistence. Update test documentation. Signed-off-by: Lucas Tamborrino --- .../espressif_esp32/cache_coex/README.rst | 46 ++++++++++++------- .../espressif_esp32/cache_coex/testcase.yaml | 5 +- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/tests/boards/espressif_esp32/cache_coex/README.rst b/tests/boards/espressif_esp32/cache_coex/README.rst index 00a6877841d8..12bd79143ffc 100644 --- a/tests/boards/espressif_esp32/cache_coex/README.rst +++ b/tests/boards/espressif_esp32/cache_coex/README.rst @@ -12,32 +12,44 @@ with a random generated pattern. At the same time, a whole SPI Flash page is upd value. By the end of the thread iterations, both PSRAM and SPI Flash have its contents compared against expected values to check for integrity. +Supported Boards +**************** +- esp32_devkitc_wrover +- esp32s2_saola +- esp32s3_devkitm + Building and Running ******************** -Make sure you have the ESP32 DevKitC connected over USB port. +Make sure you have the target connected over USB port. .. code-block:: console - west build -b esp32_devkitc_wrover tests/boards/espressif_esp32/cache_coex - west flash --esp-device /dev/ttyUSB0 + west build -b tests/boards/espressif_esp32/cache_coex + west flash && west espressif monitor Sample Output ============= -To check output of this test, any serial console program can be used (i.e. on Linux picocom, putty, screen, etc). -This test uses ``minicom`` on the serial port ``/dev/ttyUS0``. The following lines indicate a successful test: - .. code-block:: console - Running test suite cache_coex_test - =================================================================== - START - flash_integrity_test - PASS - flash_integrity_test in 0.1 seconds - =================================================================== - START - ram_integrity_test - PASS - ram_integrity_test in 0.1 seconds - =================================================================== - Test suite cache_coex_test succeeded - =================================================================== - PROJECT EXECUTION SUCCESSFUL + Running TESTSUITE cache_coex + =================================================================== + START - test_flash_integrity + PASS - test_flash_integrity in 0.001 seconds + =================================================================== + START - test_ram_integrity + PASS - test_ram_integrity in 0.001 seconds + =================================================================== + START - test_using_spiram + PASS - test_using_spiram in 0.001 seconds + =================================================================== + TESTSUITE cache_coex succeeded + ------ TESTSUITE SUMMARY START ------ + SUITE PASS - 100.00% [cache_coex]: pass = 3, fail = 0, skip = 0, total = 3 duration = 0.003 seconds + - PASS - [cache_coex.test_flash_integrity] duration = 0.001 seconds + - PASS - [cache_coex.test_ram_integrity] duration = 0.001 seconds + - PASS - [cache_coex.test_using_spiram] duration = 0.001 seconds + ------ TESTSUITE SUMMARY END ------ + =================================================================== + PROJECT EXECUTION SUCCESSFUL diff --git a/tests/boards/espressif_esp32/cache_coex/testcase.yaml b/tests/boards/espressif_esp32/cache_coex/testcase.yaml index 9de6d546a4b3..063d4e9fb3b0 100644 --- a/tests/boards/espressif_esp32/cache_coex/testcase.yaml +++ b/tests/boards/espressif_esp32/cache_coex/testcase.yaml @@ -1,6 +1,9 @@ tests: boards.esp32.cache_coex: - platform_allow: esp32_devkitc_wrover esp32s2_saola + platform_allow: + - esp32_devkitc_wrover + - esp32s2_saola + - esp32s3_devkitm tags: - spiram - spiflash From 47515f4d7b52195c3b1725d6cfacc6554dcbceef Mon Sep 17 00:00:00 2001 From: Lucas Tamborrino Date: Thu, 1 Jun 2023 16:44:12 -0300 Subject: [PATCH 1850/2042] soc: xtensa: esp32s3: Add external ram noinit section Add section to allocate memory of WiFi and NET stack in SPIRAM Signed-off-by: Lucas Tamborrino --- soc/xtensa/espressif_esp32/esp32s3/default.ld | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/soc/xtensa/espressif_esp32/esp32s3/default.ld b/soc/xtensa/espressif_esp32/esp32s3/default.ld index cee52c7f1f6d..27e27a0a8cba 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s3/default.ld @@ -236,6 +236,17 @@ SECTIONS . = ALIGN(4); _ext_ram_bss_end = ABSOLUTE(.); } > ext_ram_seg + + .ext_ram_noinit (NOLOAD) : + { +#if defined(CONFIG_ESP32_WIFI_NET_ALLOC_SPIRAM) + *libdrivers__wifi.a:(.noinit .noinit.*) + *libsubsys__net__l2__ethernet.a:(.noinit .noinit.*) + *libsubsys__net__lib__config.a:(.noinit .noinit.*) + *libsubsys__net__ip.a:(.noinit .noinit.*) + *libsubsys__net.a:(.noinit .noinit.*) +#endif + } > ext_ram_seg #endif /* Send .iram0 code to iram */ From 7ef8911e8cb75a82e54ad2280658cb039b8ec875 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 26 Jul 2023 13:05:52 +0200 Subject: [PATCH 1851/2042] samples: basic: hash_map: fix libc heap size setting The malloc arena/heap size setting can be adjusted using different Kconfig options, depending on the libc implementation. This means prj.conf can't be used to set this value on projects that can be built for multiple libcs without generating a Kconfig warning. Signed-off-by: Gerard Marull-Paretas --- samples/basic/hash_map/prj.conf | 2 -- samples/basic/hash_map/sample.yaml | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/samples/basic/hash_map/prj.conf b/samples/basic/hash_map/prj.conf index 3f1a62538eec..4eb90ce10ca2 100644 --- a/samples/basic/hash_map/prj.conf +++ b/samples/basic/hash_map/prj.conf @@ -6,8 +6,6 @@ CONFIG_BOOT_BANNER=n CONFIG_LOG=y CONFIG_TEST_RANDOM_GENERATOR=y -CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 -CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192 CONFIG_SYS_HASH_FUNC32=y CONFIG_SYS_HASH_MAP=y diff --git a/samples/basic/hash_map/sample.yaml b/samples/basic/hash_map/sample.yaml index b73474975813..40dec267473c 100644 --- a/samples/basic/hash_map/sample.yaml +++ b/samples/basic/hash_map/sample.yaml @@ -25,11 +25,13 @@ tests: libraries.hash_map.minimal.separate_chaining.djb2: extra_configs: - CONFIG_MINIMAL_LIBC=y + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_SC=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y libraries.hash_map.minimal.open_addressing.djb2: extra_configs: - CONFIG_MINIMAL_LIBC=y + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y # Newlib @@ -37,18 +39,21 @@ tests: filter: TOOLCHAIN_HAS_NEWLIB == 1 extra_configs: - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_SC=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y libraries.hash_map.newlib.open_addressing.djb2: filter: TOOLCHAIN_HAS_NEWLIB == 1 extra_configs: - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y libraries.hash_map.newlib.cxx_unordered_map.djb2: filter: TOOLCHAIN_HAS_NEWLIB == 1 extra_configs: - CONFIG_NEWLIB_LIBC=y + - CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_CXX=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y - CONFIG_MAIN_STACK_SIZE=2048 @@ -56,10 +61,12 @@ tests: libraries.hash_map.picolibc.separate_chaining.djb2: extra_configs: - CONFIG_PICOLIBC=y + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_SC=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y libraries.hash_map.picolibc.open_addressing.djb2: extra_configs: - CONFIG_PICOLIBC=y + - CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=8192 - CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y - CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y From b51dd4ade024ed6fac800f40cf1ece0581562685 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Wed, 26 Jul 2023 13:16:31 +0200 Subject: [PATCH 1852/2042] lib: hash: use new c++ Kconfig symbols SYS_HASH_MAP_CXX was using deprecated C++ symbols. Signed-off-by: Gerard Marull-Paretas --- lib/hash/Kconfig.hash_map | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hash/Kconfig.hash_map b/lib/hash/Kconfig.hash_map index dfbe9e8a82ea..d36a4e124535 100644 --- a/lib/hash/Kconfig.hash_map +++ b/lib/hash/Kconfig.hash_map @@ -39,9 +39,9 @@ config SYS_HASH_MAP_OA_LP config SYS_HASH_MAP_CXX bool "C++ Hashmap" - select CPLUSPLUS - select LIB_CPLUSPLUS - select EXCEPTIONS + select CPP + select REQUIRES_FULL_LIBCPP + select CPP_EXCEPTIONS help This enables a C wrapper around the C++ std::unordered_map. From bff69f538481a76638d295fcb683679c0a894840 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 6 Jul 2023 12:17:46 +0200 Subject: [PATCH 1853/2042] drivers: pinctrl: add driver for EOS S3 This adds a new pinctrl driver for Quicklogic EOS S3 SoC Signed-off-by: Wojciech Sipak --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.eos_s3 | 9 ++ drivers/pinctrl/pinctrl_eos_s3.c | 128 ++++++++++++++++++ drivers/serial/Kconfig.pl011 | 1 + drivers/serial/Kconfig.ql_usbserialport_s3b | 1 + dts/arm/quicklogic/quicklogic_eos_s3.dtsi | 5 + .../pinctrl/quicklogic,eos-s3-pinctrl.yaml | 75 ++++++++++ .../pinctrl/quicklogic-eos-s3-pinctrl.h | 25 ++++ soc/arm/quicklogic_eos_s3/pinctrl_soc.h | 55 ++++++++ 10 files changed, 301 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.eos_s3 create mode 100644 drivers/pinctrl/pinctrl_eos_s3.c create mode 100644 dts/bindings/pinctrl/quicklogic,eos-s3-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/quicklogic-eos-s3-pinctrl.h create mode 100644 soc/arm/quicklogic_eos_s3/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 521f1e61c199..a14ee14286ea 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -33,3 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_K3 pinctrl_ti_k3.c) 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) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 80551869d595..cdecc3ae554b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -62,5 +62,6 @@ source "drivers/pinctrl/Kconfig.ti_k3" source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" +source "drivers/pinctrl/Kconfig.eos_s3" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.eos_s3 b/drivers/pinctrl/Kconfig.eos_s3 new file mode 100644 index 000000000000..04d8cd1cbe17 --- /dev/null +++ b/drivers/pinctrl/Kconfig.eos_s3 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_QUICKLOGIC_EOS_S3 + bool "QuickLogic EOS S3 SoC pinctrl driver" + default y + depends on DT_HAS_QUICKLOGIC_EOS_S3_PINCTRL_ENABLED + help + Enable driver for the QuickLogic EOS S3 SoC pinctrl driver diff --git a/drivers/pinctrl/pinctrl_eos_s3.c b/drivers/pinctrl/pinctrl_eos_s3.c new file mode 100644 index 000000000000..5fcd62711da8 --- /dev/null +++ b/drivers/pinctrl/pinctrl_eos_s3.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT quicklogic_eos_s3_pinctrl + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(pinctrl_eos_s3, CONFIG_PINCTRL_LOG_LEVEL); + +#define FUNCTION_REGISTER(func) (func >> 13) +#define PAD_FUNC_SEL_MASK GENMASK(2, 0) +#define PAD_CTRL_SEL_BIT0 3 +#define PAD_CTRL_SEL_BIT1 4 +#define PAD_OUTPUT_EN_BIT 5 +#define PAD_PULL_UP_BIT 6 +#define PAD_PULL_DOWN_BIT 7 +#define PAD_DRIVE_STRENGTH_BIT0 8 +#define PAD_DRIVE_STRENGTH_BIT1 9 +#define PAD_SLEW_RATE_BIT 10 +#define PAD_INPUT_EN_BIT 11 +#define PAD_SCHMITT_EN_BIT 12 + +/* + * Program IOMUX_func_SEL register. + */ +static int pinctrl_eos_s3_input_selection(uint32_t pin, uint32_t sel_reg) +{ + volatile uint32_t *reg = (uint32_t *)IO_MUX_BASE; + + if (sel_reg <= IO_MUX_MAX_PAD_NR || sel_reg > IO_MUX_REG_MAX_OFFSET) { + return -EINVAL; + } + reg += sel_reg; + *reg = pin; + + return 0; +} + +/* + * Program IOMUX_PAD_x_CTRL register. + */ +static int pinctrl_eos_s3_set(uint32_t pin, uint32_t func) +{ + volatile uint32_t *reg = (uint32_t *)IO_MUX_BASE; + + if (pin > IO_MUX_REG_MAX_OFFSET) { + return -EINVAL; + } + reg += pin; + *reg = func; + + return 0; +} + +static int pinctrl_eos_s3_configure_pin(const pinctrl_soc_pin_t *pin) +{ + uint32_t reg_value = 0; + + /* Set function. */ + reg_value |= (pin->iof & PAD_FUNC_SEL_MASK); + + /* Output enable is active low. */ + WRITE_BIT(reg_value, PAD_OUTPUT_EN_BIT, pin->output_enable ? 0 : 1); + + /* These are active high. */ + WRITE_BIT(reg_value, PAD_INPUT_EN_BIT, pin->input_enable); + WRITE_BIT(reg_value, PAD_SLEW_RATE_BIT, pin->slew_rate); + WRITE_BIT(reg_value, PAD_SCHMITT_EN_BIT, pin->schmitt_enable); + WRITE_BIT(reg_value, PAD_CTRL_SEL_BIT0, pin->control_selection & BIT(0)); + WRITE_BIT(reg_value, PAD_CTRL_SEL_BIT1, pin->control_selection & BIT(1)); + + switch (pin->drive_strength) { + case 2: + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT0, 0); + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT1, 0); + break; + case 4: + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT0, 1); + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT1, 0); + break; + case 8: + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT0, 0); + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT1, 1); + break; + case 12: + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT0, 1); + WRITE_BIT(reg_value, PAD_DRIVE_STRENGTH_BIT1, 1); + break; + default: + LOG_ERR("Selected drive-strength is not supported: %d\n", pin->drive_strength); + } + + /* Enable pull-up by default; overwrite if any setting was chosen. */ + WRITE_BIT(reg_value, PAD_PULL_UP_BIT, 1); + WRITE_BIT(reg_value, PAD_PULL_DOWN_BIT, 0); + if (pin->high_impedance) { + WRITE_BIT(reg_value, PAD_PULL_UP_BIT, 0); + } else if (pin->pull_up | pin->pull_down) { + WRITE_BIT(reg_value, PAD_PULL_UP_BIT, pin->pull_up); + WRITE_BIT(reg_value, PAD_PULL_DOWN_BIT, pin->pull_down); + } + + /* Program registers. */ + pinctrl_eos_s3_set(pin->pin, reg_value); + if (pin->input_enable && FUNCTION_REGISTER(pin->iof)) { + pinctrl_eos_s3_input_selection(pin->pin, FUNCTION_REGISTER(pin->iof)); + } + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (int i = 0; i < pin_cnt; i++) { + pinctrl_eos_s3_configure_pin(&pins[i]); + } + + return 0; +} diff --git a/drivers/serial/Kconfig.pl011 b/drivers/serial/Kconfig.pl011 index 9c48001835a2..95dd947b9dcc 100644 --- a/drivers/serial/Kconfig.pl011 +++ b/drivers/serial/Kconfig.pl011 @@ -7,6 +7,7 @@ menuconfig UART_PL011 depends on DT_HAS_ARM_PL011_ENABLED || DT_HAS_ARM_SBSA_UART_ENABLED select SERIAL_HAS_DRIVER select SERIAL_SUPPORT_INTERRUPT + select PINCTRL if SOC_EOS_S3 help This option enables the UART driver for the PL011 diff --git a/drivers/serial/Kconfig.ql_usbserialport_s3b b/drivers/serial/Kconfig.ql_usbserialport_s3b index 197d26f5faf4..b989c91516e5 100644 --- a/drivers/serial/Kconfig.ql_usbserialport_s3b +++ b/drivers/serial/Kconfig.ql_usbserialport_s3b @@ -8,5 +8,6 @@ config UART_QUICKLOGIC_USBSERIALPORT_S3B default y depends on DT_HAS_QUICKLOGIC_USBSERIALPORT_S3B_ENABLED select SERIAL_HAS_DRIVER + select PINCTRL help This option enables the QuickLogic USBserialport_S3B serial driver. diff --git a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi index 8d3f3998e309..f29b1c482ffd 100644 --- a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi +++ b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi @@ -64,6 +64,11 @@ pin-secondary-config = <0x00>; gpio-controller; }; + + pinctrl: pinctrl@40004c00 { + compatible = "quicklogic,eos-s3-pinctrl"; + reg = <0x40004c00 0x1b0>; + }; }; }; diff --git a/dts/bindings/pinctrl/quicklogic,eos-s3-pinctrl.yaml b/dts/bindings/pinctrl/quicklogic,eos-s3-pinctrl.yaml new file mode 100644 index 000000000000..cd9cd5ac5324 --- /dev/null +++ b/dts/bindings/pinctrl/quicklogic,eos-s3-pinctrl.yaml @@ -0,0 +1,75 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + Quicklogic EOS S3 IO MUX binding covers the 46 IOMUX_PAD_x_CTRL registers + that can be used to set the direction and the function of a pad. + + Device pin configuration should be placed in the child nodes of this node. + Populate the 'pinmux' field with IO function and pin number. + + For example, setting pins 44 and 45 for use as UART would look like this: + + #include + + &pinctrl { + uart0_rx_default: uart0_rx_default { + pinmux = ; + input-enable; + }; + uart0_tx_default: uart0_tx_default { + pinmux = ; + output-enable; + }; + }; + +compatible: "quicklogic,eos-s3-pinctrl" + +include: base.yaml + +properties: + reg: + required: true + +child-binding: + description: | + This binding gives a base representation of the SiFive FE310 pins + configuration. + + include: + - name: pincfg-node.yaml + property-allowlist: + - input-enable + - output-enable + - bias-pull-up + - bias-pull-down + - bias-high-impedance + - input-schmitt-enable + - drive-strength + properties: + pinmux: + required: true + type: array + description: | + Quicklogic EOS S3 pin's configuration (pin, IO function). + slew-rate: + description: | + The default value "slow" matches the power-on reset value. + default: "slow" + type: string + enum: + - "slow" + - "fast" + quicklogic,control-selection: + description: | + Control selection for IO output. + It's either controlled from registers of the A0 always-on domain, + fabric-controlled for signaling with FPGA, + or other-controller for bidirectional signals. + The default value "a0registers" matches the power-on reset value. + default: "a0registers" + type: string + enum: + - "a0registers" + - "others" + - "fabric" diff --git a/include/zephyr/dt-bindings/pinctrl/quicklogic-eos-s3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/quicklogic-eos-s3-pinctrl.h new file mode 100644 index 000000000000..b49e2141444a --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/quicklogic-eos-s3-pinctrl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_QUICKLOGIC_EOS_S3_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_QUICKLOGIC_EOS_S3_PINCTRL_H_ + +#include + +#define IO_MUX_REG_MAX_OFFSET 107 +#define IO_MUX_MAX_PAD_NR 45 + +#define FUNC_SEL_UART_RX (77 << 13) + +#define QUICKLOGIC_EOS_S3_PINMUX(pin, fun) (pin) (fun) + +#define UART_TX_PAD44 QUICKLOGIC_EOS_S3_PINMUX(44, 0x3) +#define UART_RX_PAD45 QUICKLOGIC_EOS_S3_PINMUX(45, FUNC_SEL_UART_RX | BIT(2)) +#define USB_PU_CTRL_PAD23 QUICKLOGIC_EOS_S3_PINMUX(23, 0x0) +#define USB_DN_PAD28 QUICKLOGIC_EOS_S3_PINMUX(28, 0x0) +#define USB_DP_PAD31 QUICKLOGIC_EOS_S3_PINMUX(31, 0x0) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_QUICKLOGIC_EOS_S3_PINCTRL_H_ */ diff --git a/soc/arm/quicklogic_eos_s3/pinctrl_soc.h b/soc/arm/quicklogic_eos_s3/pinctrl_soc.h new file mode 100644 index 000000000000..957129a3d0e3 --- /dev/null +++ b/soc/arm/quicklogic_eos_s3/pinctrl_soc.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_QUICKLOGIC_EOS_S3_PINCTRL_H_ +#define ZEPHYR_SOC_ARM_QUICKLOGIC_EOS_S3_PINCTRL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pinctrl_soc_pin_t { + uint32_t pin; + uint32_t iof; + uint32_t input_enable: 1; + uint32_t output_enable: 1; + uint32_t pull_up: 1; + uint32_t pull_down: 1; + uint32_t high_impedance: 1; + uint32_t slew_rate: 2; + uint8_t drive_strength; + uint32_t schmitt_enable: 1; + uint32_t control_selection: 2; +} pinctrl_soc_pin_t; + +#define QUICKLOGIC_EOS_S3_DT_PIN(node_id) \ + { \ + .pin = DT_PROP_BY_IDX(node_id, pinmux, 0), \ + .iof = DT_PROP_BY_IDX(node_id, pinmux, 1), \ + .input_enable = DT_PROP(node_id, input_enable), \ + .output_enable = DT_PROP(node_id, output_enable), \ + .pull_up = DT_PROP(node_id, bias_pull_up), \ + .pull_down = DT_PROP(node_id, bias_pull_down), \ + .high_impedance = DT_PROP(node_id, bias_high_impedance), \ + .slew_rate = DT_ENUM_IDX(node_id, slew_rate), \ + .drive_strength = DT_PROP_OR(node_id, drive_strength, 4), \ + .schmitt_enable = DT_PROP(node_id, input_schmitt_enable), \ + .control_selection = DT_ENUM_IDX(node_id, quicklogic_control_selection), \ + }, + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + QUICKLOGIC_EOS_S3_DT_PIN(DT_PROP_BY_IDX(node_id, prop, idx)) + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_QUICKLOGIC_EOS_S3_PINCTRL_H_ */ From d1c565244bea652bdf343a634b08332a9300ea23 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 6 Jul 2023 12:18:50 +0200 Subject: [PATCH 1854/2042] boards: quick_feather: use pinctrl driver Pinmuxing was previously done in the board.c file. Now it is done by the pinctrl driver. Signed-off-by: Wojciech Sipak --- boards/arm/quick_feather/CMakeLists.txt | 5 ----- boards/arm/quick_feather/board.c | 23 ---------------------- boards/arm/quick_feather/board.h | 19 ------------------ boards/arm/quick_feather/quick_feather.dts | 14 +++++++++++++ 4 files changed, 14 insertions(+), 47 deletions(-) delete mode 100644 boards/arm/quick_feather/CMakeLists.txt delete mode 100644 boards/arm/quick_feather/board.c delete mode 100644 boards/arm/quick_feather/board.h diff --git a/boards/arm/quick_feather/CMakeLists.txt b/boards/arm/quick_feather/CMakeLists.txt deleted file mode 100644 index 77aee051c0c7..000000000000 --- a/boards/arm/quick_feather/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2020 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library_sources(board.c) -zephyr_include_directories(.) diff --git a/boards/arm/quick_feather/board.c b/boards/arm/quick_feather/board.c deleted file mode 100644 index cf89c208ced0..000000000000 --- a/boards/arm/quick_feather/board.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2020 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -static int eos_s3_board_init(void) -{ - - /* IO MUX setup for UART */ - eos_s3_io_mux(UART_TX_PAD, UART_TX_PAD_CFG); - eos_s3_io_mux(UART_RX_PAD, UART_RX_PAD_CFG); - - IO_MUX->UART_rxd_SEL = UART_RX_SEL; - - return 0; -} - -SYS_INIT(eos_s3_board_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY); diff --git a/boards/arm/quick_feather/board.h b/boards/arm/quick_feather/board.h deleted file mode 100644 index 857a6edd0372..000000000000 --- a/boards/arm/quick_feather/board.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -#include - -#define UART_TX_PAD 44 -#define UART_TX_PAD_CFG UART_TXD_PAD44 -#define UART_RX_PAD 45 -#define UART_RX_PAD_CFG UART_RXD_PAD45 - -#define UART_RX_SEL UART_RXD_SEL_PAD45 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/quick_feather/quick_feather.dts b/boards/arm/quick_feather/quick_feather.dts index 9bde6c938c34..2dc8053255a0 100644 --- a/boards/arm/quick_feather/quick_feather.dts +++ b/boards/arm/quick_feather/quick_feather.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include / { model = "QuickLogic Quick Feather board"; @@ -56,6 +57,17 @@ }; }; +&pinctrl { + uart_rx_default: uart_rx_default { + pinmux = ; + input-enable; + }; + uart_tx_default: uart_tx_default { + pinmux = ; + output-enable; + }; +}; + &cpu0 { clock-frequency = <61440000>; }; @@ -67,4 +79,6 @@ &uart0 { status = "okay"; current-speed = <115200>; + pinctrl-0 = <&uart_rx_default &uart_tx_default>; + pinctrl-names = "default"; }; From 36b5769b128f4b7d41ee1f52447abd56d34a75ab Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 6 Jul 2023 12:19:36 +0200 Subject: [PATCH 1855/2042] boards: qomu: use pinctrl driver Pinmuxing was previously done in the board.c file. Now it is done by the pinctrl driver. Signed-off-by: Wojciech Sipak --- boards/arm/qomu/CMakeLists.txt | 4 ---- boards/arm/qomu/board.c | 28 ---------------------------- boards/arm/qomu/board.h | 25 ------------------------- boards/arm/qomu/qomu.dts | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 57 deletions(-) delete mode 100644 boards/arm/qomu/CMakeLists.txt delete mode 100644 boards/arm/qomu/board.c delete mode 100644 boards/arm/qomu/board.h diff --git a/boards/arm/qomu/CMakeLists.txt b/boards/arm/qomu/CMakeLists.txt deleted file mode 100644 index a17def9a2314..000000000000 --- a/boards/arm/qomu/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2022 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -zephyr_library_sources(board.c) diff --git a/boards/arm/qomu/board.c b/boards/arm/qomu/board.c deleted file mode 100644 index d6752dff9133..000000000000 --- a/boards/arm/qomu/board.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2022 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "board.h" - -static int qomu_board_init(void) -{ - - /* IO MUX setup for UART */ - eos_s3_io_mux(UART_TX_PAD, UART_TX_PAD_CFG); - eos_s3_io_mux(UART_RX_PAD, UART_RX_PAD_CFG); - - IO_MUX->UART_rxd_SEL = UART_RX_SEL; - - /* IO MUX setup for USB */ - eos_s3_io_mux(USB_PU_CTRL_PAD, USB_PAD_CFG); - eos_s3_io_mux(USB_DN_PAD, USB_PAD_CFG); - eos_s3_io_mux(USB_DP_PAD, USB_PAD_CFG); - - return 0; -} - -SYS_INIT(qomu_board_init, PRE_KERNEL_1, CONFIG_BOARD_INIT_PRIORITY); diff --git a/boards/arm/qomu/board.h b/boards/arm/qomu/board.h deleted file mode 100644 index 9bcd5820b10f..000000000000 --- a/boards/arm/qomu/board.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2022 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __INC_BOARD_H -#define __INC_BOARD_H - -#include - -#define USB_PU_CTRL_PAD 23 -#define USB_DN_PAD 28 -#define USB_DP_PAD 31 -#define USB_PAD_CFG (PAD_E_4MA | PAD_P_Z | PAD_OEN_NORMAL | PAD_SMT_DISABLE \ - | PAD_REN_DISABLE | PAD_SR_SLOW | PAD_CTRL_SEL_FPGA) - -#define UART_TX_PAD 44 -#define UART_TX_PAD_CFG UART_TXD_PAD44 -#define UART_RX_PAD 45 -#define UART_RX_PAD_CFG UART_RXD_PAD45 - -#define UART_RX_SEL UART_RXD_SEL_PAD45 - -#endif /* __INC_BOARD_H */ diff --git a/boards/arm/qomu/qomu.dts b/boards/arm/qomu/qomu.dts index c58825a5f4f6..dfdb9a14c18c 100644 --- a/boards/arm/qomu/qomu.dts +++ b/boards/arm/qomu/qomu.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include / { model = "QuickLogic Qomu board"; @@ -56,6 +57,35 @@ }; }; +&pinctrl { + uart1_rx_default: uart1_rx_default { + pinmux = ; + input-enable; + }; + uart1_tx_default: uart1_tx_default { + pinmux = ; + output-enable; + }; + usb_pu_default: usb_pu_default { + pinmux = ; + bias-high-impedance; + quicklogic,control-selection = "fabric"; + output-enable; + }; + usb_dn_default: usb_dn_default { + pinmux = ; + bias-high-impedance; + quicklogic,control-selection = "fabric"; + output-enable; + }; + usb_dp_default: usb_dp_default { + pinmux = ; + bias-high-impedance; + quicklogic,control-selection = "fabric"; + output-enable; + }; +}; + &cpu0 { clock-frequency = <61440000>; }; @@ -71,4 +101,7 @@ &uart1 { status = "okay"; current-speed = <115200>; + pinctrl-0 = <&uart1_rx_default &uart1_tx_default + &usb_pu_default &usb_dn_default &usb_dp_default>; + pinctrl-names = "default"; }; From 69d0f03ebdce92a0a9679114bb18d39eb5dbbba6 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 6 Jul 2023 12:20:21 +0200 Subject: [PATCH 1856/2042] soc: quicklogic_eos_s3: remove unneeded code Pinmuxing is now done by a pinctrl driver, not by board.c, so the code used previously for pinmuxing can be removed. Fixes #59186. Signed-off-by: Wojciech Sipak --- soc/arm/quicklogic_eos_s3/soc.c | 14 -------------- soc/arm/quicklogic_eos_s3/soc.h | 4 ---- soc/arm/quicklogic_eos_s3/soc_pinmap.h | 10 ---------- 3 files changed, 28 deletions(-) diff --git a/soc/arm/quicklogic_eos_s3/soc.c b/soc/arm/quicklogic_eos_s3/soc.c index 81d070df427c..ed2cdb70ef96 100644 --- a/soc/arm/quicklogic_eos_s3/soc.c +++ b/soc/arm/quicklogic_eos_s3/soc.c @@ -20,20 +20,6 @@ void eos_s3_lock_disable(void) MISC_CTRL->LOCK_KEY_CTRL = 1; } -int eos_s3_io_mux(uint32_t pad_nr, uint32_t pad_cfg) -{ - volatile uint32_t *p = (uint32_t *)IO_MUX_BASE; - - if (pad_nr > EOS_S3_MAX_PAD_NR) { - return -EINVAL; - } - - p += pad_nr; - *p = pad_cfg; - - return 0; -} - static void eos_s3_cru_init(void) { /* Set desired frequency */ diff --git a/soc/arm/quicklogic_eos_s3/soc.h b/soc/arm/quicklogic_eos_s3/soc.h index b294be96e9bb..a82e5399248c 100644 --- a/soc/arm/quicklogic_eos_s3/soc.h +++ b/soc/arm/quicklogic_eos_s3/soc.h @@ -46,11 +46,7 @@ #define OSC_SET_FREQ_INC(FREQ) (AIP->OSC_CTRL_1 = ((FREQ / 32768) - 3) & 0xFFF) #define OSC_GET_FREQ_INC() (((AIP->OSC_CTRL_1 & 0xFFF) + 3) * 32768) -#define EOS_S3_MAX_PAD_NR 45 - void eos_s3_lock_enable(void); void eos_s3_lock_disable(void); -int eos_s3_io_mux(uint32_t pad_nr, uint32_t pad_cfg); - #endif /* _SOC__H_ */ diff --git a/soc/arm/quicklogic_eos_s3/soc_pinmap.h b/soc/arm/quicklogic_eos_s3/soc_pinmap.h index 65715300c611..1acee4443649 100644 --- a/soc/arm/quicklogic_eos_s3/soc_pinmap.h +++ b/soc/arm/quicklogic_eos_s3/soc_pinmap.h @@ -9,14 +9,4 @@ #include -/* Set UART TX to PAD44 */ -#define UART_TXD_PAD44 (UART_TXD_SEL_PAD44 | PAD_CTRL_SEL_AO_REG \ - | PAD_OEN_NORMAL | PAD_P_Z | PAD_SR_SLOW \ - | PAD_E_4MA | PAD_REN_DISABLE | PAD_SMT_DISABLE) - -/* Set UART RX to PAD45 */ -#define UART_RXD_PAD45 (UART_RXD_SEL_PAD45 | PAD_CTRL_SEL_AO_REG \ - | PAD_OEN_DISABLE | PAD_P_Z | PAD_SR_SLOW \ - | PAD_E_4MA | PAD_REN_ENABLE | PAD_SMT_DISABLE) - #endif /* _QUICKLOGIC_EOS_S3_SOC_PINMAP_H_ */ From 2cfd831209f630e8e9e3715813f3d2ee9d12bd1a Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Fri, 9 Jun 2023 08:23:26 -0400 Subject: [PATCH 1857/2042] boards: arm: xmc45_relax_kit: Update supported drivers Updates list of supported drivers on the xmc45_relax_kit. Signed-off-by: Andriy Gelman --- boards/arm/xmc45_relax_kit/doc/index.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/boards/arm/xmc45_relax_kit/doc/index.rst b/boards/arm/xmc45_relax_kit/doc/index.rst index ee107a66fb9b..33084d0f777c 100644 --- a/boards/arm/xmc45_relax_kit/doc/index.rst +++ b/boards/arm/xmc45_relax_kit/doc/index.rst @@ -45,6 +45,14 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | SPI | on-chip | spi | +-----------+------------+-----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-----------------------+ +| FLASH | on-chip | flash | ++-----------+------------+-----------------------+ +| ADC | on-chip | adc | ++-----------+------------+-----------------------+ +| DMA | on-chip | dma | ++-----------+------------+-----------------------+ More details about the supported peripherals are available in `XMC4500 TRM`_ Other hardware features are not currently supported by the Zephyr kernel. From 23b6e4f507e9724988296d5f73bdf739ba85326d Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sun, 4 Jun 2023 21:36:17 -0400 Subject: [PATCH 1858/2042] drivers: pwm: Add driver for xmc4xxx using ccu4 module Adds driver for pwm on xmc4xxx using Capture Compare Unit 4 (CCU4) module. There are four CCU4 with each one having four channels Thus it's possible to have up to 16 pwm output signals. The output of each channel can only be connected to a specific port/pin. The possible connection and gpio configurations are defined using pinctrl. The CCU4 module also has a capture mode. Capture support will be added in the future. Signed-off-by: Andriy Gelman --- boards/arm/xmc45_relax_kit/doc/index.rst | 2 + .../xmc45_relax_kit-pinctrl.dtsi | 12 ++ .../arm/xmc45_relax_kit/xmc45_relax_kit.dts | 20 ++++ boards/arm/xmc47_relax_kit/doc/index.rst | 2 + drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.xmc4xxx_ccu4 | 9 ++ drivers/pwm/pwm_xmc4xxx_ccu4.c | 112 ++++++++++++++++++ .../infineon/xmc4500_F100x1024-pinctrl.dtsi | 43 +++++++ .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 97 +++++++++++++++ dts/arm/infineon/xmc4xxx.dtsi | 28 +++++ .../pwm/infineon,xmc4xxx-ccu4-pwm.yaml | 84 +++++++++++++ modules/Kconfig.infineon | 5 + .../blinky_pwm/boards/xmc45_relax_kit.overlay | 13 ++ soc/arm/infineon_xmc/4xxx/Kconfig.series | 1 + soc/arm/infineon_xmc/4xxx/soc.c | 6 +- 16 files changed, 436 insertions(+), 1 deletion(-) create mode 100644 drivers/pwm/Kconfig.xmc4xxx_ccu4 create mode 100644 drivers/pwm/pwm_xmc4xxx_ccu4.c create mode 100644 dts/bindings/pwm/infineon,xmc4xxx-ccu4-pwm.yaml create mode 100644 samples/basic/blinky_pwm/boards/xmc45_relax_kit.overlay diff --git a/boards/arm/xmc45_relax_kit/doc/index.rst b/boards/arm/xmc45_relax_kit/doc/index.rst index 33084d0f777c..17669cedcbe1 100644 --- a/boards/arm/xmc45_relax_kit/doc/index.rst +++ b/boards/arm/xmc45_relax_kit/doc/index.rst @@ -53,6 +53,8 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | DMA | on-chip | dma | +-----------+------------+-----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-----------------------+ 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 790bb49bbc05..04156e2890ce 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi @@ -15,3 +15,15 @@ drive-strength = "strong-soft-edge"; hwctrl = "disabled"; }; + +&pwm_out_p1_0_ccu40_ch3 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&pwm_out_p1_1_ccu40_ch2 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + 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 4033b530ad57..a6fe5e5942ca 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts @@ -10,6 +10,7 @@ #include #include +#include #include "xmc45_relax_kit-pinctrl.dtsi" / { @@ -20,6 +21,7 @@ aliases { led0 = &led1; die-temp0 = &die_temp; + pwm-led0 = &pwm_led1; }; leds { @@ -33,6 +35,18 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + pwm_led1: pwm_led1 { + pwms = <&pwm_ccu40 2 PWM_SEC(1) PWM_POLARITY_NORMAL>; + label = "PWM LED1"; + }; + pwm_led2: pwm_led2 { + pwms = <&pwm_ccu40 3 PWM_SEC(1) PWM_POLARITY_NORMAL>; + label = "PWM LED2"; + }; + }; + chosen { zephyr,sram = &dsram1; zephyr,flash = &flash0; @@ -102,3 +116,9 @@ &gpio1 { status = "okay"; }; + +&pwm_ccu40 { + slice-prescaler = <15 15 15 15>; + pinctrl-0 = <&pwm_out_p1_0_ccu40_ch3 &pwm_out_p1_1_ccu40_ch2>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/xmc47_relax_kit/doc/index.rst b/boards/arm/xmc47_relax_kit/doc/index.rst index 891f7c0952fb..fea191f4c30b 100644 --- a/boards/arm/xmc47_relax_kit/doc/index.rst +++ b/boards/arm/xmc47_relax_kit/doc/index.rst @@ -56,6 +56,8 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | DMA | on-chip | dma | +-----------+------------+-----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-----------------------+ 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/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index 4f2fde5fd4fe..93f63d2e681b 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_TEST pwm_test.c) zephyr_library_sources_ifdef(CONFIG_PWM_RPI_PICO pwm_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c) zephyr_library_sources_ifdef(CONFIG_PWM_INTEL_BLINKY pwm_intel_blinky.c) +zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU4 pwm_xmc4xxx_ccu4.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c) zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 796989048f0b..96cc11c638b9 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -89,4 +89,6 @@ source "drivers/pwm/Kconfig.rpi_pico" source "drivers/pwm/Kconfig.intel_blinky" +source "drivers/pwm/Kconfig.xmc4xxx_ccu4" + endif # PWM diff --git a/drivers/pwm/Kconfig.xmc4xxx_ccu4 b/drivers/pwm/Kconfig.xmc4xxx_ccu4 new file mode 100644 index 000000000000..9301182ef233 --- /dev/null +++ b/drivers/pwm/Kconfig.xmc4xxx_ccu4 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +config PWM_XMC4XXX_CCU4 + bool "Infineon XMC4XXX CCU4 driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_CCU4_PWM_ENABLED + help + Enables Infineon XMC4XXX CCU4 PWM driver. diff --git a/drivers/pwm/pwm_xmc4xxx_ccu4.c b/drivers/pwm/pwm_xmc4xxx_ccu4.c new file mode 100644 index 000000000000..9800003df396 --- /dev/null +++ b/drivers/pwm/pwm_xmc4xxx_ccu4.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_ccu4_pwm + +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(pwm_xmc4xxx_ccu4, CONFIG_PWM_LOG_LEVEL); + +#define NUM_SLICES 4 +#define NUM_CHANNELS NUM_SLICES +#define SLICE_ADDR_FROM_MODULE(module_ptr, idx) ((uint32_t)(module_ptr) + ((idx) + 1) * 0x100) + +struct pwm_xmc4xxx_ccu4_config { + XMC_CCU4_MODULE_t *ccu4; + const struct pinctrl_dev_config *pcfg; + const uint8_t slice_prescaler[NUM_SLICES]; +}; + +static int pwm_xmc4xxx_ccu4_init(const struct device *dev) +{ + const struct pwm_xmc4xxx_ccu4_config *config = dev->config; + + /* enables the CCU4 clock and ungates clock to CCU4x */ + XMC_CCU4_EnableModule(config->ccu4); + XMC_CCU4_StartPrescaler(config->ccu4); + + for (int i = 0; i < NUM_SLICES; i++) { + XMC_CCU4_SLICE_t *slice; + XMC_CCU4_SLICE_COMPARE_CONFIG_t slice_conf = { + .prescaler_initval = config->slice_prescaler[i] + }; + + slice = (XMC_CCU4_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu4, i); + XMC_CCU4_SLICE_CompareInit(slice, &slice_conf); + } + + return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); +} + +static int pwm_xmc4xxx_ccu4_set_cycles(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + pwm_flags_t flags) +{ + const struct pwm_xmc4xxx_ccu4_config *config = dev->config; + XMC_CCU4_SLICE_t *slice; + int slice_idx = channel; + + if (channel >= NUM_CHANNELS) { + return -EINVAL; + } + + if (period_cycles == 0 || period_cycles > UINT16_MAX + 1 || pulse_cycles > UINT16_MAX) { + return -EINVAL; + } + + slice = (XMC_CCU4_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu4, slice_idx); + slice->PRS = period_cycles - 1; + slice->CRS = period_cycles - pulse_cycles; + slice->PSL = flags & PWM_POLARITY_INVERTED; + + XMC_CCU4_EnableShadowTransfer(config->ccu4, BIT(slice_idx * 4)); + + /* start if not already running */ + XMC_CCU4_EnableClock(config->ccu4, slice_idx); + XMC_CCU4_SLICE_StartTimer(slice); + + return 0; +} + +static int pwm_xmc4xxx_ccu4_get_cycles_per_sec(const struct device *dev, uint32_t channel, + uint64_t *cycles) +{ + const struct pwm_xmc4xxx_ccu4_config *config = dev->config; + int slice_idx = channel; + + if (channel >= NUM_SLICES) { + return -EINVAL; + } + + *cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[slice_idx]; + + return 0; +} + +static const struct pwm_driver_api pwm_xmc4xxx_ccu4_driver_api = { + .set_cycles = pwm_xmc4xxx_ccu4_set_cycles, + .get_cycles_per_sec = pwm_xmc4xxx_ccu4_get_cycles_per_sec, +}; + +#define PWM_XMC4XXX_CCU4_INIT(n) \ +PINCTRL_DT_INST_DEFINE(n); \ + \ +static const struct pwm_xmc4xxx_ccu4_config config##n = { \ + .ccu4 = (CCU4_GLOBAL_TypeDef *)DT_INST_REG_ADDR(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .slice_prescaler = DT_INST_PROP(n, slice_prescaler)}; \ + \ +DEVICE_DT_INST_DEFINE(n, pwm_xmc4xxx_ccu4_init, NULL, NULL, &config##n, POST_KERNEL, \ + CONFIG_PWM_INIT_PRIORITY, &pwm_xmc4xxx_ccu4_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PWM_XMC4XXX_CCU4_INIT) diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index 9b9e0a96542e..ecc1fa79bb57 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -199,4 +199,47 @@ /omit-if-no-ref/ spi_sclk_p5_2_u2c0: spi_sclk_p5_2_u2c0 { pinmux = ; }; + + /omit-if-no-ref/ pwm_out_p0_12_ccu40_ch3: pwm_out_p0_12_ccu40_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_0_ccu40_ch3: pwm_out_p1_0_ccu40_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_1_ccu40_ch2: pwm_out_p1_1_ccu40_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_2_ccu40_ch1: pwm_out_p1_2_ccu40_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_3_ccu40_ch0: pwm_out_p1_3_ccu40_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_2_ccu41_ch3: pwm_out_p2_2_ccu41_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_3_ccu41_ch2: pwm_out_p2_3_ccu41_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_4_ccu41_ch1: pwm_out_p2_4_ccu41_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_5_ccu41_ch0: pwm_out_p2_5_ccu41_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_0_ccu42_ch0: pwm_out_p3_0_ccu42_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_3_ccu42_ch3: pwm_out_p3_3_ccu42_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_4_ccu42_ch2: pwm_out_p3_4_ccu42_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_5_ccu42_ch1: pwm_out_p3_5_ccu42_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_6_ccu42_ch0: pwm_out_p3_6_ccu42_ch0 { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index dd03fad36174..84c42b5555c7 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -714,4 +714,101 @@ /omit-if-no-ref/ i2c_target_sda_p3_5_u2c1: i2c_target_sda_p3_5_u2c1 { pinmux = ; }; + + /omit-if-no-ref/ pwm_out_p0_12_ccu40_ch3: pwm_out_p0_12_ccu40_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_13_ccu40_ch2: pwm_out_p0_13_ccu40_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_14_ccu40_ch1: pwm_out_p0_14_ccu40_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_15_ccu40_ch0: pwm_out_p0_15_ccu40_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_0_ccu40_ch3: pwm_out_p1_0_ccu40_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_1_ccu40_ch2: pwm_out_p1_1_ccu40_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_2_ccu40_ch1: pwm_out_p1_2_ccu40_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_3_ccu40_ch0: pwm_out_p1_3_ccu40_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_2_ccu41_ch3: pwm_out_p2_2_ccu41_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_3_ccu41_ch2: pwm_out_p2_3_ccu41_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_4_ccu41_ch1: pwm_out_p2_4_ccu41_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_5_ccu41_ch0: pwm_out_p2_5_ccu41_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_0_ccu42_ch0: pwm_out_p3_0_ccu42_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_3_ccu42_ch3: pwm_out_p3_3_ccu42_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_4_ccu42_ch2: pwm_out_p3_4_ccu42_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_5_ccu42_ch1: pwm_out_p3_5_ccu42_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_6_ccu42_ch0: pwm_out_p3_6_ccu42_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_7_ccu41_ch3: pwm_out_p3_7_ccu41_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_8_ccu41_ch2: pwm_out_p3_8_ccu41_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_9_ccu41_ch1: pwm_out_p3_9_ccu41_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_10_ccu41_ch0: pwm_out_p3_10_ccu41_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_11_ccu42_ch3: pwm_out_p3_11_ccu42_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_12_ccu42_ch2: pwm_out_p3_12_ccu42_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p3_13_ccu42_ch1: pwm_out_p3_13_ccu42_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p4_3_ccu43_ch3: pwm_out_p4_3_ccu43_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p4_4_ccu43_ch2: pwm_out_p4_4_ccu43_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p4_5_ccu43_ch1: pwm_out_p4_5_ccu43_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p4_6_ccu43_ch0: pwm_out_p4_6_ccu43_ch0 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_2_ccu43_ch3: pwm_out_p6_2_ccu43_ch3 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_3_ccu43_ch2: pwm_out_p6_3_ccu43_ch2 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_4_ccu43_ch1: pwm_out_p6_4_ccu43_ch1 { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_5_ccu43_ch0: pwm_out_p6_5_ccu43_ch0 { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 250876eb969d..08e492565127 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -187,6 +187,34 @@ compatible = "infineon,xmc4xxx-temp"; status = "disabled"; }; + + pwm_ccu40: ccu40@4000c000 { + compatible = "infineon,xmc4xxx-ccu4-pwm"; + reg = <0x4000c000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ccu41: ccu41@40010000 { + compatible = "infineon,xmc4xxx-ccu4-pwm"; + reg = <0x40010000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ccu42: ccu42@40014000 { + compatible = "infineon,xmc4xxx-ccu4-pwm"; + reg = <0x40014000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ccu43: ccu43@48004000 { + compatible = "infineon,xmc4xxx-ccu4-pwm"; + reg = <0x48004000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/pwm/infineon,xmc4xxx-ccu4-pwm.yaml b/dts/bindings/pwm/infineon,xmc4xxx-ccu4-pwm.yaml new file mode 100644 index 000000000000..408f9b348d0a --- /dev/null +++ b/dts/bindings/pwm/infineon,xmc4xxx-ccu4-pwm.yaml @@ -0,0 +1,84 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: | + Infineon XMC4XXX PWM Capture Compare Unit 4 (CCU4) module + + The are four CCU4 modules with dts node labels: + pwm_ccu40, pwm_ccu41, pwm_ccu42, pwm_ccu43. + Each module has four slices and each slice has one channel. + A channel is connected to a particular gpio pin, which are defined + using pinctrl in: + dts/arm/infineon/xmc4xxx_xxx-pinctrl.dtsi + + The CCU4 modules uses the CCU clock source. Each slice applies a separate + prescalar which divides the clock. + + Device tree example: + A node can define a 'pwm' field, usually referenced in a 'pwms' + property, where the entries include the PWM module phandle, + channel number, pulse period (in nanoseconds or set using + PWM_XX() macros), and a channela + flag (PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED). + + The pwm ccu4 node must define the slice-prescaler values and the pinctrl nodes: + &pwm_ccu40 { + slice-prescaler = <15 15 15 15>; + pinctrl-0 = <&pwm_out_p1_1_ccu40_ch2>; + pinctrl-names = "default"; + }; + + Another node can reference the PWM as follows: + &test_node { + ... + pwms = <&pwm_ccu40 0 PWM_SEC(1) PWM_POLARITY_NORMAL>; + ... + }; + + The user must also explicitly set pinctrl properties. + The pin should be configured with drive-push-pull bool option and hwctrl should be set + to disabled. The drive-strength field can be set to any of the supported values: + &pwm_out_p1_1_ccu40_ch2 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + hwctrl = "disabled"; + }; + + The CCU4 pinctrl nodes have a node labels in the format + pwm_out_p{PORT}_{PIN}_ccu4{MODULE_IDX}_ch{CHANNEL_IDX}, where MODULE_IDX and + CHANNEL_IDX refers to specific pwm_ccu4x module and channel, respectively. + PORT/PIN pair defines what gpio the channel connects to. + +compatible: "infineon,xmc4xxx-ccu4-pwm" + +include: + - name: base.yaml + - name: pwm-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + slice-prescaler: + type: array + required: true + description: | + Defines the clock divider for each channel. + The entry in the array will divide CCU clock by (2 << value). + The range for the prescaler values is [0, 15]. + Reducing prescaler value will improve resolution but decrease the maximum period. + + "#pwm-cells": + const: 3 + +pwm-cells: + - channel + - period + - flags diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 87d140bc9af4..348305ccbf73 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -45,4 +45,9 @@ config HAS_XMCLIB_I2C help Enable XMCLIB I2C +config HAS_XMCLIB_CCU + bool + help + Enable XMCLIB CCU4/CCU8 + endif # HAS_XMCLIB diff --git a/samples/basic/blinky_pwm/boards/xmc45_relax_kit.overlay b/samples/basic/blinky_pwm/boards/xmc45_relax_kit.overlay new file mode 100644 index 000000000000..c480721420ed --- /dev/null +++ b/samples/basic/blinky_pwm/boards/xmc45_relax_kit.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pwm_led1 { + status = "okay"; +}; + +&pwm_ccu40 { + status = "okay"; +}; diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 66a93102352c..5bfdb994fe43 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -19,5 +19,6 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_DMA select HAS_XMCLIB_SPI select HAS_XMCLIB_I2C + select HAS_XMCLIB_CCU 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 9f1b2162333f..6f30b8a76b65 100644 --- a/soc/arm/infineon_xmc/4xxx/soc.c +++ b/soc/arm/infineon_xmc/4xxx/soc.c @@ -31,7 +31,11 @@ void z_arm_platform_init(void) temp |= PMU_FLASH_WS; FLASH0->FCON = temp; - XMC_SCU_CLOCK_SetSleepConfig(XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_SYSCLK_FPLL); + XMC_SCU_CLOCK_SetSleepConfig(XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_SYSCLK_FPLL +#ifdef CONFIG_PWM_XMC4XXX_CCU4 + | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU +#endif + ); /* configure PLL & system clock */ SystemCoreClockSetup(); From d8f955e3751db2e4191a7c26b034a3711e8c329c Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Mon, 12 Jun 2023 17:43:50 -0400 Subject: [PATCH 1859/2042] drivers: pwm: Add driver for xmc4xxx using ccu8 module Adds driver for pwm on xmc4xxx using Capture Compare Unit 8 (CCU8) module. There are two CCU8 nodes with each one having four slices. Each slice has two output channels. Unlike CCU4, this module can generate complementary high-side/low-side signals for each output channel. A variable dead time can be added during the off to on transitions to make sure that the high-side/low-side signals are not on at the same time. Signed-off-by: Andriy Gelman --- .../xmc47_relax_kit-pinctrl.dtsi | 12 ++ .../arm/xmc47_relax_kit/xmc47_relax_kit.dts | 25 +++ drivers/pwm/CMakeLists.txt | 1 + drivers/pwm/Kconfig | 2 + drivers/pwm/Kconfig.xmc4xxx_ccu8 | 9 + drivers/pwm/pwm_xmc4xxx_ccu8.c | 171 ++++++++++++++++++ .../infineon/xmc4500_F100x1024-pinctrl.dtsi | 100 ++++++++++ .../infineon/xmc4700_F144x2048-pinctrl.dtsi | 136 ++++++++++++++ dts/arm/infineon/xmc4xxx.dtsi | 14 ++ .../pwm/infineon,xmc4xxx-ccu8-pwm.yaml | 126 +++++++++++++ .../blinky_pwm/boards/xmc47_relax_kit.overlay | 13 ++ soc/arm/infineon_xmc/4xxx/soc.c | 3 + 12 files changed, 612 insertions(+) create mode 100644 drivers/pwm/Kconfig.xmc4xxx_ccu8 create mode 100644 drivers/pwm/pwm_xmc4xxx_ccu8.c create mode 100644 dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml create mode 100644 samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay 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 9a4b8fde34d8..c8dbbd27a5ed 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -43,3 +43,15 @@ drive-push-pull; hwctrl = "disabled"; }; + +&pwm_out_p5_9_ccu80_ch4_high { + drive-strength = "strong-medium-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&pwm_out_p5_8_ccu80_ch0_low { + drive-strength = "strong-medium-edge"; + drive-push-pull; + 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 c02b4215d91e..3f0a6e8b0c91 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -9,6 +9,7 @@ #include #include +#include #include "xmc47_relax_kit-pinctrl.dtsi" #include "arduino_r3_connector.dtsi" @@ -19,6 +20,7 @@ aliases { led0 = &led1; die-temp0 = &die_temp; + pwm-led0 = &pwm_led1; }; leds { @@ -32,6 +34,18 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + pwm_led1: pwm_led1 { + pwms = <&pwm_ccu80 4 PWM_SEC(1) PWM_POLARITY_NORMAL>; + label = "PWM LED1"; + }; + pwm_led2: pwm_led2 { + pwms = <&pwm_ccu80 0 PWM_SEC(1) PWM_POLARITY_NORMAL>; + label = "PWM LED2"; + }; + }; + chosen { zephyr,sram = &psram1; zephyr,flash = &flash0; @@ -135,3 +149,14 @@ &gpio5 { status = "okay"; }; + +/* this example is not using the high-side/low-side signals of the same channel */ +/* the PWM signals are only used for the blink led example */ +&pwm_ccu80 { + slice-prescaler = <15 15 15 15>; + slice-deadtime-prescaler = <3 3 3 3>; + channel-deadtime-high = <0 0 0 0 0 0 0 0>; + channel-deadtime-low = <0 0 0 0 0 0 0 0>; + pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p5_8_ccu80_ch0_low>; + pinctrl-names = "default"; +}; diff --git a/drivers/pwm/CMakeLists.txt b/drivers/pwm/CMakeLists.txt index 93f63d2e681b..4619914abcb5 100644 --- a/drivers/pwm/CMakeLists.txt +++ b/drivers/pwm/CMakeLists.txt @@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_RPI_PICO pwm_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_PWM_BBLED_XEC pwm_mchp_xec_bbled.c) zephyr_library_sources_ifdef(CONFIG_PWM_INTEL_BLINKY pwm_intel_blinky.c) zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU4 pwm_xmc4xxx_ccu4.c) +zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU8 pwm_xmc4xxx_ccu8.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c) zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 96cc11c638b9..0c467faf5621 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -91,4 +91,6 @@ source "drivers/pwm/Kconfig.intel_blinky" source "drivers/pwm/Kconfig.xmc4xxx_ccu4" +source "drivers/pwm/Kconfig.xmc4xxx_ccu8" + endif # PWM diff --git a/drivers/pwm/Kconfig.xmc4xxx_ccu8 b/drivers/pwm/Kconfig.xmc4xxx_ccu8 new file mode 100644 index 000000000000..299bf86aab80 --- /dev/null +++ b/drivers/pwm/Kconfig.xmc4xxx_ccu8 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +config PWM_XMC4XXX_CCU8 + bool "Infineon XMC4XXX CCU4 driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_CCU8_PWM_ENABLED + help + Enables Infineon XMC4XXX CCU8 PWM driver. diff --git a/drivers/pwm/pwm_xmc4xxx_ccu8.c b/drivers/pwm/pwm_xmc4xxx_ccu8.c new file mode 100644 index 000000000000..e6d68cb115b4 --- /dev/null +++ b/drivers/pwm/pwm_xmc4xxx_ccu8.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_ccu8_pwm + +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(pwm_xmc4xxx_ccu8, CONFIG_PWM_LOG_LEVEL); + +#define NUM_SLICES 4 +#define NUM_CHANNELS (NUM_SLICES * 2) +#define MAX_DEAD_TIME_VALUE 255 +#define MAX_SLICE_PRESCALER 15 +#define MAX_DEADTIME_PRESCALER 3 +#define SLICE_ADDR_FROM_MODULE(module_ptr, idx) ((uint32_t)(module_ptr) + ((idx) + 1) * 0x100) + +struct pwm_xmc4xxx_ccu8_config { + XMC_CCU8_MODULE_t *ccu8; + const struct pinctrl_dev_config *pcfg; + const uint8_t slice_prescaler[NUM_SLICES]; + const uint8_t slice_deadtime_prescaler[NUM_SLICES]; + const uint32_t deadtime_high_ns[NUM_CHANNELS]; + const uint32_t deadtime_low_ns[NUM_CHANNELS]; +}; + +static int pwm_xmc4xxx_ccu8_init(const struct device *dev) +{ + const struct pwm_xmc4xxx_ccu8_config *config = dev->config; + + /* enables the CCU8 clock and ungates clock to CCU8x */ + XMC_CCU8_EnableModule(config->ccu8); + XMC_CCU8_StartPrescaler(config->ccu8); + + for (int i = 0; i < NUM_SLICES; i++) { + XMC_CCU8_SLICE_t *slice; + XMC_CCU8_SLICE_DEAD_TIME_CONFIG_t deadtime_conf = {0}; + XMC_CCU8_SLICE_COMPARE_CONFIG_t slice_conf = { + .prescaler_initval = config->slice_prescaler[i], + .invert_out1 = 1, + .invert_out3 = 1, + }; + + if (config->slice_prescaler[i] > MAX_SLICE_PRESCALER) { + LOG_ERR("Invalid slice_prescaler value %d. Range [0, 15]", + config->slice_prescaler[i]); + return -EINVAL; + } + + if (config->slice_deadtime_prescaler[i] > MAX_DEADTIME_PRESCALER) { + LOG_ERR("Invalid dead time prescaler value %d. Range [0, 3]", + config->slice_deadtime_prescaler[i]); + return -EINVAL; + } + + slice = (XMC_CCU8_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu8, i); + XMC_CCU8_SLICE_CompareInit(slice, &slice_conf); + + deadtime_conf.div = config->slice_deadtime_prescaler[i]; + if (config->deadtime_high_ns[2*i] > 0 || config->deadtime_low_ns[2*i] > 0) { + deadtime_conf.enable_dead_time_channel1 = 1; + } + deadtime_conf.channel1_st_path = config->deadtime_high_ns[2*i] > 0; + deadtime_conf.channel1_inv_st_path = config->deadtime_low_ns[2*i] > 0; + + if (config->deadtime_high_ns[2*i + 1] > 0 || config->deadtime_low_ns[2*i + 1] > 0) { + deadtime_conf.enable_dead_time_channel2 = 1; + } + deadtime_conf.channel2_st_path = config->deadtime_high_ns[2*i + 1] > 0; + deadtime_conf.channel2_inv_st_path = config->deadtime_low_ns[2*i + 1] > 0; + + XMC_CCU8_SLICE_DeadTimeInit(slice, &deadtime_conf); + } + + return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); +} + +static int pwm_xmc4xxx_ccu8_set_cycles(const struct device *dev, uint32_t channel, + uint32_t period_cycles, uint32_t pulse_cycles, + pwm_flags_t flags) +{ + const struct pwm_xmc4xxx_ccu8_config *config = dev->config; + XMC_CCU8_SLICE_t *slice; + uint32_t high_deadtime_value = 0, low_deadtime_value = 0; + uint64_t cycles; + int slice_idx = channel / 2; + + if (channel >= NUM_CHANNELS) { + return -EINVAL; + } + + if (period_cycles == 0 || period_cycles > UINT16_MAX + 1 || pulse_cycles > UINT16_MAX) { + return -EINVAL; + } + + slice = (XMC_CCU8_SLICE_t *)SLICE_ADDR_FROM_MODULE(config->ccu8, slice_idx); + slice->PRS = period_cycles - 1; + + if (channel & 0x1) { + slice->CR2S = period_cycles - pulse_cycles; + } else { + slice->CR1S = period_cycles - pulse_cycles; + } + slice->PSL = flags & PWM_POLARITY_INVERTED; + + /* set channel dead time */ + cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[slice_idx]; + cycles >>= config->slice_deadtime_prescaler[slice_idx]; + high_deadtime_value = config->deadtime_high_ns[channel] * cycles / NSEC_PER_SEC; + low_deadtime_value = config->deadtime_low_ns[channel] * cycles / NSEC_PER_SEC; + + if (high_deadtime_value > MAX_DEAD_TIME_VALUE || low_deadtime_value > MAX_DEAD_TIME_VALUE) { + return -EINVAL; + } + + XMC_CCU8_SLICE_SetDeadTimeValue(slice, channel & 0x1, high_deadtime_value, + low_deadtime_value); + + XMC_CCU8_EnableShadowTransfer(config->ccu8, BIT(slice_idx * 4)); + + /* start if not already running */ + XMC_CCU8_EnableClock(config->ccu8, slice_idx); + XMC_CCU8_SLICE_StartTimer(slice); + + return 0; +} + +static int pwm_xmc4xxx_ccu8_get_cycles_per_sec(const struct device *dev, uint32_t channel, + uint64_t *cycles) +{ + const struct pwm_xmc4xxx_ccu8_config *config = dev->config; + + if (channel >= NUM_CHANNELS) { + return -EINVAL; + } + + *cycles = XMC_SCU_CLOCK_GetCcuClockFrequency() >> config->slice_prescaler[channel / 2]; + + return 0; +} + +static const struct pwm_driver_api pwm_xmc4xxx_ccu8_driver_api = { + .set_cycles = pwm_xmc4xxx_ccu8_set_cycles, + .get_cycles_per_sec = pwm_xmc4xxx_ccu8_get_cycles_per_sec, +}; + +#define PWM_XMC4XXX_CCU8_INIT(n) \ +PINCTRL_DT_INST_DEFINE(n); \ + \ +static const struct pwm_xmc4xxx_ccu8_config config##n = { \ + .ccu8 = (CCU8_GLOBAL_TypeDef *)DT_INST_REG_ADDR(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .slice_prescaler = DT_INST_PROP(n, slice_prescaler), \ + .slice_deadtime_prescaler = DT_INST_PROP(n, slice_deadtime_prescaler), \ + .deadtime_high_ns = DT_INST_PROP(n, channel_deadtime_high), \ + .deadtime_low_ns = DT_INST_PROP(n, channel_deadtime_low), \ +}; \ + \ +DEVICE_DT_INST_DEFINE(n, pwm_xmc4xxx_ccu8_init, NULL, NULL, &config##n, POST_KERNEL, \ + CONFIG_PWM_INIT_PRIORITY, &pwm_xmc4xxx_ccu8_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PWM_XMC4XXX_CCU8_INIT) diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index ecc1fa79bb57..251d4291a6f6 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -242,4 +242,104 @@ /omit-if-no-ref/ pwm_out_p3_6_ccu42_ch0: pwm_out_p3_6_ccu42_ch0 { pinmux = ; }; + + /omit-if-no-ref/ pwm_out_p0_0_ccu80_ch2_low: pwm_out_p0_0_ccu80_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_1_ccu80_ch1_low: pwm_out_p0_1_ccu80_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_2_ccu80_ch0_low: pwm_out_p0_2_ccu80_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_3_ccu80_ch2_high: pwm_out_p0_3_ccu80_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_4_ccu80_ch1_high: pwm_out_p0_4_ccu80_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_5_ccu80_ch0_high: pwm_out_p0_5_ccu80_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_6_ccu80_ch3_high: pwm_out_p0_6_ccu80_ch3_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_9_ccu80_ch1_high: pwm_out_p0_9_ccu80_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_10_ccu80_ch0_high: pwm_out_p0_10_ccu80_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_11_ccu80_ch3_low: pwm_out_p0_11_ccu80_ch3_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_4_ccu80_ch3_low: pwm_out_p1_4_ccu80_ch3_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_4_ccu81_ch2_high: pwm_out_p1_4_ccu81_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_5_ccu80_ch2_low: pwm_out_p1_5_ccu80_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_5_ccu81_ch1_high: pwm_out_p1_5_ccu81_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_10_ccu81_ch2_low: pwm_out_p1_10_ccu81_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_11_ccu81_ch1_low: pwm_out_p1_11_ccu81_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_12_ccu81_ch0_low: pwm_out_p1_12_ccu81_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_13_ccu81_ch2_high: pwm_out_p1_13_ccu81_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_14_ccu81_ch1_high: pwm_out_p1_14_ccu81_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_15_ccu81_ch0_high: pwm_out_p1_15_ccu81_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_0_ccu81_ch2_low: pwm_out_p2_0_ccu81_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_1_ccu81_ch1_low: pwm_out_p2_1_ccu81_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_2_ccu81_ch0_low: pwm_out_p2_2_ccu81_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_6_ccu80_ch1_low: pwm_out_p2_6_ccu80_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_7_ccu80_ch0_low: pwm_out_p2_7_ccu80_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_8_ccu80_ch3_high: pwm_out_p2_8_ccu80_ch3_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_9_ccu80_ch2_high: pwm_out_p2_9_ccu80_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_14_ccu80_ch2_low: pwm_out_p2_14_ccu80_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_15_ccu80_ch1_low: pwm_out_p2_15_ccu80_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_0_ccu81_ch3_low: pwm_out_p5_0_ccu81_ch3_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_1_ccu81_ch3_high: pwm_out_p5_1_ccu81_ch3_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_2_ccu81_ch2_low: pwm_out_p5_2_ccu81_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_7_ccu81_ch0_high: pwm_out_p5_7_ccu81_ch0_high { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 84c42b5555c7..1ef8961968dc 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -811,4 +811,140 @@ /omit-if-no-ref/ pwm_out_p6_5_ccu43_ch0: pwm_out_p6_5_ccu43_ch0 { pinmux = ; }; + + /omit-if-no-ref/ pwm_out_p0_0_ccu80_ch4_low: pwm_out_p0_0_ccu80_ch4_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_1_ccu80_ch2_low: pwm_out_p0_1_ccu80_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_2_ccu80_ch0_low: pwm_out_p0_2_ccu80_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_3_ccu80_ch4_high: pwm_out_p0_3_ccu80_ch4_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_4_ccu80_ch2_high: pwm_out_p0_4_ccu80_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_5_ccu80_ch0_high: pwm_out_p0_5_ccu80_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_6_ccu80_ch6_high: pwm_out_p0_6_ccu80_ch6_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_9_ccu80_ch3_high: pwm_out_p0_9_ccu80_ch3_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_10_ccu80_ch1_high: pwm_out_p0_10_ccu80_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p0_11_ccu80_ch6_low: pwm_out_p0_11_ccu80_ch6_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_4_ccu80_ch7_low: pwm_out_p1_4_ccu80_ch7_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_4_ccu81_ch4_high: pwm_out_p1_4_ccu81_ch4_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_5_ccu80_ch5_low: pwm_out_p1_5_ccu80_ch5_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_5_ccu81_ch2_high: pwm_out_p1_5_ccu81_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_10_ccu81_ch4_low: pwm_out_p1_10_ccu81_ch4_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_11_ccu81_ch2_low: pwm_out_p1_11_ccu81_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_12_ccu81_ch0_low: pwm_out_p1_12_ccu81_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_13_ccu81_ch4_high: pwm_out_p1_13_ccu81_ch4_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_14_ccu81_ch2_high: pwm_out_p1_14_ccu81_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p1_15_ccu81_ch0_high: pwm_out_p1_15_ccu81_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_0_ccu81_ch4_low: pwm_out_p2_0_ccu81_ch4_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_1_ccu81_ch2_low: pwm_out_p2_1_ccu81_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_2_ccu81_ch0_low: pwm_out_p2_2_ccu81_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_6_ccu80_ch3_low: pwm_out_p2_6_ccu80_ch3_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_7_ccu80_ch1_low: pwm_out_p2_7_ccu80_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_8_ccu80_ch7_high: pwm_out_p2_8_ccu80_ch7_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_9_ccu80_ch5_high: pwm_out_p2_9_ccu80_ch5_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_11_ccu80_ch5_high: pwm_out_p2_11_ccu80_ch5_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_12_ccu81_ch7_low: pwm_out_p2_12_ccu81_ch7_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_14_ccu80_ch4_low: pwm_out_p2_14_ccu80_ch4_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p2_15_ccu80_ch2_low: pwm_out_p2_15_ccu80_ch2_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_0_ccu81_ch7_low: pwm_out_p5_0_ccu81_ch7_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_1_ccu81_ch7_high: pwm_out_p5_1_ccu81_ch7_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_2_ccu81_ch5_low: pwm_out_p5_2_ccu81_ch5_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_3_ccu81_ch5_high: pwm_out_p5_3_ccu81_ch5_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_4_ccu81_ch3_low: pwm_out_p5_4_ccu81_ch3_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_5_ccu81_ch3_high: pwm_out_p5_5_ccu81_ch3_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_6_ccu81_ch1_low: pwm_out_p5_6_ccu81_ch1_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_7_ccu81_ch1_high: pwm_out_p5_7_ccu81_ch1_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_8_ccu80_ch0_low: pwm_out_p5_8_ccu80_ch0_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_9_ccu80_ch4_high: pwm_out_p5_9_ccu80_ch4_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_10_ccu80_ch2_high: pwm_out_p5_10_ccu80_ch2_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p5_11_ccu80_ch0_high: pwm_out_p5_11_ccu80_ch0_high { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_0_ccu81_ch6_low: pwm_out_p6_0_ccu81_ch6_low { + pinmux = ; + }; + /omit-if-no-ref/ pwm_out_p6_1_ccu81_ch6_high: pwm_out_p6_1_ccu81_ch6_high { + pinmux = ; + }; }; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 08e492565127..54a5744be152 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -215,6 +215,20 @@ #pwm-cells = <3>; status = "disabled"; }; + + pwm_ccu80: ccu80@40020000 { + compatible = "infineon,xmc4xxx-ccu8-pwm"; + reg = <0x40020000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ccu81: ccu81@40024000 { + compatible = "infineon,xmc4xxx-ccu8-pwm"; + reg = <0x40024000 0x4000>; + #pwm-cells = <3>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml b/dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml new file mode 100644 index 000000000000..9f2a2c256b80 --- /dev/null +++ b/dts/bindings/pwm/infineon,xmc4xxx-ccu8-pwm.yaml @@ -0,0 +1,126 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: | + Infineon XMC4XXX PWM Capture Compare Unit 8 (CCU8) module + + The PWM CCU8 module can automatically generate a high-side + and a low-side PWM signal, where the two signals are complementary + to each other. + + The module supports adding a dead time between the high-side and + low-side PWM signals. + + The dead time ensures that there is a delay before the PWM state + transitions from 0 to 1, preventing the high-side and low-side + switches from being on simultaneously. + + There are two CCU8 modules with DTS node labels: pwm_ccu80 and + pwm_ccu81. Each module has four slices, and each slice has + two channels. A channel consists of a corresponding high-side + and low-side PWM signal. + + The CCU8 modules use the CCU clock source. Each slice applies + a separate prescaler to divide the clock. The clock divider is + defined by the 'slice-prescaler' property. Additionally, each + slice has a dead time prescaler, which divides the slice clock + for the dead time counter. + + Device tree example: + A node can define a 'pwm' field, usually referenced in a 'pwms' + property, where the entries include the PWM module phandle, + channel number, pulse period (in nanoseconds or set using + PWM_XX() macros), and a channel + flag (PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED). + + The 'pwm_ccu8' node must define the following fields: + &pwm_ccu80 { + slice-prescaler = <15 15 15 15>; + slice-deadtime-prescaler = <3 3 3 3>; + channel-deadtime-high = <0 0 0 0 PWM_MSEC(100) 0 0 0>; + channel-deadtime-low = <0 0 0 0 PWM_MSEC(100) 0 0 0>; + pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p0_0_ccu80_ch4_low>; + pinctrl-names = "default"; + }; + + This will configure channel 4 with a 100msec deadtime on the high + and low side PWM signals. + + Another node can reference the PWM as follows: + &test_node { + ... + pwms = <&pwm_ccu80 0 PWM_SEC(1) PWM_POLARITY_NORMAL>; + ... + }; + + The 'pwm_out_p{PORT}_{PIN}_ccu8{MODULE_IDX}_ch{CHANNEL_IDX}_{HIGH_LOW}' + format is used for CCU8 pinctrl nodes. 'MODULE_IDX' and 'CHANNEL_IDX' + refer to a specific 'pwm_ccu8x' module and channel, respectively. + 'PORT/PIN' defines the GPIO that the channel connects to. + 'HIGH_LOW' indicates whether the pin is for the high or low-side signal. + + It's not necessary to specify both the high and low pinctrls. Only the low-side + signal can, for example, be used as PWM, but note that the duty cycle of the + low signal will be (1 - duty) as set via the API. + + Note that a slice has two channels. Channels 0/1 are in slice 0, + channels 2/3 are in slice 1, and so on. Each channel can have its own + duty cycle and high/low dead times. But the pulse duration applies to + both channels. Thus, when using the PWM control api to modify the pulse width + on a channel 0, it will also be updated for channel 1 since they are + in the same slice. + +compatible: "infineon,xmc4xxx-ccu8-pwm" + +include: + - name: base.yaml + - name: pwm-controller.yaml + - name: pinctrl-device.yaml + +properties: + reg: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + slice-prescaler: + type: array + required: true + description: | + Defines the clock divider for each slice. + The entry in the array will divide CCU clock by (2 << value). + The range for the prescaler values is [0, 15]. + Reducing prescaler value will improve resolution but decrease the maximum period. + + slice-deadtime-prescaler: + type: array + required: true + description: | + Defines the clock divider for dead time counter for each slice. + The range for the values is [0, 3]. + Reducing prescaler value will improve dead time resolution but decrease the + maximum dead time. + + channel-deadtime-high: + type: array + required: true + description: | + Defines the dead time in nanoseconds for the high-side PWM signal for each channel. + + channel-deadtime-low: + type: array + required: true + description: | + Defines the dead time in nanoseconds for the low-side PWM signal for each channel. + + "#pwm-cells": + const: 3 + +pwm-cells: + - channel + - period + - flags diff --git a/samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay b/samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay new file mode 100644 index 000000000000..33db6bf0d1df --- /dev/null +++ b/samples/basic/blinky_pwm/boards/xmc47_relax_kit.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pwm_led1 { + status = "okay"; +}; + +&pwm_ccu80 { + status = "okay"; +}; diff --git a/soc/arm/infineon_xmc/4xxx/soc.c b/soc/arm/infineon_xmc/4xxx/soc.c index 6f30b8a76b65..0d4060568a33 100644 --- a/soc/arm/infineon_xmc/4xxx/soc.c +++ b/soc/arm/infineon_xmc/4xxx/soc.c @@ -34,6 +34,9 @@ void z_arm_platform_init(void) XMC_SCU_CLOCK_SetSleepConfig(XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_SYSCLK_FPLL #ifdef CONFIG_PWM_XMC4XXX_CCU4 | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU +#endif +#ifdef CONFIG_PWM_XMC4XXX_CCU8 + | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU #endif ); From 5fc1777055df75618f4e558cfabf122da7896e44 Mon Sep 17 00:00:00 2001 From: Marco Argiolas Date: Sat, 24 Jun 2023 17:41:53 +0800 Subject: [PATCH 1860/2042] drivers: sensor: add mutex to cmd_get_sensor() Add a mutex to protect shared data-structures, since shell can have multiple backends. Signed-off-by: Marco Argiolas --- drivers/sensor/sensor_shell.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index b8c828297318..bdd5e64b2ad5 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -154,6 +155,9 @@ enum dynamic_command_context { static enum dynamic_command_context current_cmd_ctx = NONE; +/* Mutex for accessing shared RTIO/IODEV data structures */ +K_MUTEX_DEFINE(cmd_get_mutex); + /* Crate a single common config for one-shot reading */ static enum sensor_channel iodev_sensor_shell_channels[SENSOR_CHAN_ALL]; static struct sensor_read_config iodev_sensor_shell_read_config = { @@ -299,28 +303,32 @@ static void sensor_shell_processing_callback(int result, uint8_t *buf, uint32_t static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) { const struct device *dev; + int count = 0; int err; + err = k_mutex_lock(&cmd_get_mutex, K_NO_WAIT); + if (err < 0) { + shell_error(sh, "Another sensor reading in progress"); + return err; + } + dev = device_get_binding(argv[1]); if (dev == NULL) { shell_error(sh, "Device unknown (%s)", argv[1]); + k_mutex_unlock(&cmd_get_mutex); return -ENODEV; } if (argc == 2) { /* read all channels */ - int count = 0; - for (int i = 0; i < ARRAY_SIZE(iodev_sensor_shell_channels); ++i) { if (SENSOR_CHANNEL_3_AXIS(i)) { continue; } iodev_sensor_shell_channels[count++] = i; } - iodev_sensor_shell_read_config.count = count; } else { /* read specific channels */ - iodev_sensor_shell_read_config.count = 0; for (int i = 2; i < argc; ++i) { int chan = parse_named_int(argv[i], sensor_channel_name, ARRAY_SIZE(sensor_channel_name)); @@ -329,16 +337,17 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) shell_error(sh, "Failed to read channel (%s)", argv[i]); continue; } - iodev_sensor_shell_channels[iodev_sensor_shell_read_config.count++] = - chan; + iodev_sensor_shell_channels[count++] = chan; } } - if (iodev_sensor_shell_read_config.count == 0) { + if (count == 0) { shell_error(sh, "No channels to read, bailing"); + k_mutex_unlock(&cmd_get_mutex); return -EINVAL; } iodev_sensor_shell_read_config.sensor = dev; + iodev_sensor_shell_read_config.count = count; struct sensor_shell_processing_context ctx = { .dev = dev, @@ -350,6 +359,8 @@ static int cmd_get_sensor(const struct shell *sh, size_t argc, char *argv[]) } sensor_processing_with_callback(&sensor_read_rtio, sensor_shell_processing_callback); + k_mutex_unlock(&cmd_get_mutex); + return 0; } From 68452bd4cc6c1b9e7f63ff898b1b8e10889c5da0 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 15:19:03 +0200 Subject: [PATCH 1861/2042] pm: device_runtime: allow calling pm_device_runtime_get from ISRs pm_device_runtime_get() uses a semaphore to protect resources. pm_device_runtime_get() blocked forever until obtaining the lock, making it unusable from contexts where blocking is not allowed, e.g. ISRs. With this patch, we give the chance to use the function from an ISR by not waiting on the lock and returning -EWOULDBLOCK instead. If device is suspending (from a previous put_async() operation) the same value is returned as we can't wait either. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/pm/device_runtime.h | 4 ++++ subsys/pm/device_runtime.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 42a833432f50..09bf0c04278e 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -81,12 +81,16 @@ int pm_device_runtime_disable(const struct device *dev); * pm_device_runtime_put_async(), this function will wait for the operation to * finish to then resume the device. * + * @note It is safe to use this function in contexts where blocking is not + * allowed, e.g. ISR, provided the device PM implementation does not block. + * * @funcprops \pre_kernel_ok * * @param dev Device instance. * * @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. + * @retval -EWOUDBLOCK If call would block but it is not allowed (e.g. in ISR). * @retval -errno Other negative errno, result of the PM action callback. */ int pm_device_runtime_get(const struct device *dev); diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index 393c0e734783..804cd5d2f576 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -145,7 +145,15 @@ int pm_device_runtime_get(const struct device *dev) } if (!k_is_pre_kernel()) { - (void)k_sem_take(&pm->lock, K_FOREVER); + ret = k_sem_take(&pm->lock, k_is_in_isr() ? K_NO_WAIT : K_FOREVER); + if (ret < 0) { + return -EWOULDBLOCK; + } + } + + if (k_is_in_isr() && (pm->state == PM_DEVICE_STATE_SUSPENDING)) { + ret = -EWOULDBLOCK; + goto unlock; } /* From e6b925ac8258f96d4ef820a9ab0a770d557f21cc Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 11:06:29 +0200 Subject: [PATCH 1862/2042] dts: arm: st: move cpu-power-states to SoC dts files The `cpu-power-states` property needs to be defined at SoC dts files, since it's a property of the SoC, not board. Signed-off-by: Gerard Marull-Paretas --- boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts | 6 ------ boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi | 4 ---- boards/arm/disco_l475_iot1/disco_l475_iot1.dts | 4 ---- boards/arm/nucleo_g070rb/nucleo_g070rb.dts | 4 ---- boards/arm/nucleo_g071rb/nucleo_g071rb.dts | 4 ---- boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts | 4 ---- boards/arm/nucleo_g474re/nucleo_g474re.dts | 6 ------ boards/arm/nucleo_l476rg/nucleo_l476rg.dts | 4 ---- boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts | 4 ---- boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts | 4 ---- .../olimex_lora_stm32wl_devkit.dts | 4 ---- boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi | 4 ---- dts/arm/st/g0/stm32g0.dtsi | 1 + dts/arm/st/g4/stm32g4.dtsi | 1 + dts/arm/st/l4/stm32l4.dtsi | 1 + dts/arm/st/l5/stm32l5.dtsi | 1 + dts/arm/st/u5/stm32u5.dtsi | 1 + dts/arm/st/wb/stm32wb.dtsi | 1 + 18 files changed, 6 insertions(+), 52 deletions(-) diff --git a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts index 81bd492989b9..734db554969f 100644 --- a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts +++ b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts @@ -63,12 +63,6 @@ }; }; - cpus { - cpu@0 { - cpu-power-states = <&stop0 &stop1>; - }; - }; - aliases { led0 = &blue_led_2; led1 = &orange_led_3; 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 9ac10f360e9e..4c85d4944004 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -71,10 +71,6 @@ apb3-prescaler = <1>; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index c4f9273383e9..86504d2fb1ea 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -71,10 +71,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &clk_lsi { status = "okay"; }; diff --git a/boards/arm/nucleo_g070rb/nucleo_g070rb.dts b/boards/arm/nucleo_g070rb/nucleo_g070rb.dts index 7795983eaad4..94c577c09813 100644 --- a/boards/arm/nucleo_g070rb/nucleo_g070rb.dts +++ b/boards/arm/nucleo_g070rb/nucleo_g070rb.dts @@ -158,10 +158,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1>; -}; - &vref { status = "okay"; }; diff --git a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts index 4494cc20d703..873c6fdd8a15 100644 --- a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts +++ b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts @@ -166,10 +166,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1>; -}; - &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts index ca6666bdcc16..fdffaff74b4a 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts @@ -209,10 +209,6 @@ zephyr_udc0: &usb { }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1>; -}; - &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; diff --git a/boards/arm/nucleo_g474re/nucleo_g474re.dts b/boards/arm/nucleo_g474re/nucleo_g474re.dts index 36761654136c..41619d7ea27a 100644 --- a/boards/arm/nucleo_g474re/nucleo_g474re.dts +++ b/boards/arm/nucleo_g474re/nucleo_g474re.dts @@ -45,12 +45,6 @@ }; }; - cpus { - cpu@0 { - cpu-power-states = <&stop0 &stop1>; - }; - }; - aliases { led0 = &green_led; pwm-led0 = &green_pwm_led; diff --git a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts index 7d9ac593d77f..20b0620e9a85 100644 --- a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts +++ b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts @@ -73,10 +73,6 @@ apb2-prescaler = <1>; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; diff --git a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts index fa23301d389b..f580993a8cd5 100644 --- a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts +++ b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts @@ -103,10 +103,6 @@ apb2-prescaler = <1>; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &usart1 { pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; pinctrl-names = "default"; diff --git a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts index fe439d6da870..1959ad16127c 100644 --- a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts @@ -66,10 +66,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &clk_lsi { 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 8655ee06add6..434fa8b5fb72 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 @@ -43,10 +43,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index f9a13cceb34d..fff6676bdac4 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -37,10 +37,6 @@ }; }; -&cpu0 { - cpu-power-states = <&stop0 &stop1 &stop2>; -}; - &clk_hsi48 { status = "okay"; }; diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index bfc61d8cfea6..8c9120472ff6 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -33,6 +33,7 @@ device_type = "cpu"; compatible = "arm,cortex-m0+"; reg = <0>; + cpu-power-states = <&stop0 &stop1>; }; power-states { diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index 32d6c4d5f87a..33d46e66af8e 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -32,6 +32,7 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop0 &stop1>; }; power-states { diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index 1b6452119fe4..b37f95def3ed 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -32,6 +32,7 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop0 &stop1 &stop2>; }; power-states { diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index 28c7d87491be..e5b9f1b7a622 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -35,6 +35,7 @@ reg = <0>; #address-cells = <1>; #size-cells = <1>; + cpu-power-states = <&stop0 &stop1 &stop2>; mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 91f5822673b9..28b5f38d9acb 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -36,6 +36,7 @@ reg = <0>; #address-cells = <1>; #size-cells = <1>; + cpu-power-states = <&stop0 &stop1 &stop2>; mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index 84f459dcf6f1..6f9f0ba48581 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -31,6 +31,7 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&stop0 &stop1 &stop2>; }; power-states { From 068cffd78b654d5e451b71c2b6db72e8f929a60f Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 11:11:15 +0200 Subject: [PATCH 1863/2042] dts: arm: nxp: ke1xf: move cpu-power-states to SoC dts files CPU power states are not board dependent, but a property of the SoC. Signed-off-by: Gerard Marull-Paretas --- boards/arm/twr_ke18f/twr_ke18f.dts | 1 - dts/arm/nxp/nxp_ke1xf.dtsi | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/twr_ke18f/twr_ke18f.dts b/boards/arm/twr_ke18f/twr_ke18f.dts index d58804dff507..465ef203fb44 100644 --- a/boards/arm/twr_ke18f/twr_ke18f.dts +++ b/boards/arm/twr_ke18f/twr_ke18f.dts @@ -140,7 +140,6 @@ &cpu0 { clock-frequency = <120000000>; - cpu-power-states = <&idle &stop>; }; &idle { diff --git a/dts/arm/nxp/nxp_ke1xf.dtsi b/dts/arm/nxp/nxp_ke1xf.dtsi index 9326b20c9cf7..e0ad94d0894e 100644 --- a/dts/arm/nxp/nxp_ke1xf.dtsi +++ b/dts/arm/nxp/nxp_ke1xf.dtsi @@ -28,6 +28,7 @@ device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&idle &stop &pstop1 &pstop2>; }; power-states { From a05371d353b5cd930abbaf16c9196a1f5cd490b3 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 11:43:52 +0200 Subject: [PATCH 1864/2042] pm: state: allow disabling certain power states In some platforms it may be desirable to disable certain CPU power states, for example, because they have extra requirements not available on all boards/applications. Because `cpu-power-states` are defined at SoC dts file levels, the only way to achieve that now was by re-defining `cpu-power-states` property in e.g. a board file. With this patch, one can now selectively set `status = "disabled";` to any power state and it will be skipped by the PM subsystem. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/pm/state.h | 49 +++++++++++++------ subsys/pm/state.c | 6 +-- .../boards/native_posix.overlay | 8 ++- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/include/zephyr/pm/state.h b/include/zephyr/pm/state.h index c7fe6f4b4acd..1d21ffd997a9 100644 --- a/include/zephyr/pm/state.h +++ b/include/zephyr/pm/state.h @@ -158,25 +158,42 @@ struct pm_state_info { /** @cond INTERNAL_HIDDEN */ +/** + * @brief Helper macro that expands to 1 if a phandle node is enabled, 0 otherwise. + * + * @param node_id Node identifier. + * @param prop Property holding phandle-array. + * @param idx Index within the array. + */ +#define Z_DT_PHANDLE_01(node_id, prop, idx) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, prop, idx), okay), \ + (1), (0)) + /** * @brief Helper macro to initialize an entry of a struct pm_state_info array * when using UTIL_LISTIFY in PM_STATE_INFO_LIST_FROM_DT_CPU. * + * @note Only enabled states are initialized. + * * @param i UTIL_LISTIFY entry index. * @param node_id A node identifier with compatible zephyr,power-state */ -#define Z_PM_STATE_INFO_FROM_DT_CPU(i, node_id) \ - PM_STATE_INFO_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)) +#define Z_PM_STATE_INFO_FROM_DT_CPU(i, node_id) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i), okay), \ + (PM_STATE_INFO_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ()) /** * @brief Helper macro to initialize an entry of a struct pm_state array when * using UTIL_LISTIFY in PM_STATE_LIST_FROM_DT_CPU. * + * @note Only enabled states are initialized. + * * @param i UTIL_LISTIFY entry index. * @param node_id A node identifier with compatible zephyr,power-state */ -#define Z_PM_STATE_FROM_DT_CPU(i, node_id) \ - PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)) +#define Z_PM_STATE_FROM_DT_CPU(i, node_id) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i), okay), \ + (PM_STATE_DT_INIT(DT_PHANDLE_BY_IDX(node_id, cpu_power_states, i)),), ()) /** @endcond */ @@ -204,18 +221,20 @@ struct pm_state_info { DT_ENUM_IDX(node_id, power_state_name) /** - * @brief Obtain number of CPU power states supported by the given CPU node - * identifier. + * @brief Obtain number of CPU power states supported and enabled by the given + * CPU node identifier. * * @param node_id A CPU node identifier. - * @return Number of supported CPU power states. + * @return Number of supported and enabled CPU power states. */ -#define DT_NUM_CPU_POWER_STATES(node_id) \ - DT_PROP_LEN_OR(node_id, cpu_power_states, 0) +#define DT_NUM_CPU_POWER_STATES(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, cpu_power_states), \ + (DT_FOREACH_PROP_ELEM_SEP(node_id, cpu_power_states, Z_DT_PHANDLE_01, (+))), \ + (0)) /** * @brief Initialize an array of struct pm_state_info with information from all - * the states present in the given CPU node identifier. + * the states present and enabled in the given CPU node identifier. * * Example devicetree fragment: * @@ -258,13 +277,13 @@ struct pm_state_info { */ #define PM_STATE_INFO_LIST_FROM_DT_CPU(node_id) \ { \ - LISTIFY(DT_NUM_CPU_POWER_STATES(node_id), \ - Z_PM_STATE_INFO_FROM_DT_CPU, (,), node_id) \ + LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \ + Z_PM_STATE_INFO_FROM_DT_CPU, (), node_id) \ } /** * @brief Initialize an array of struct pm_state with information from all the - * states present in the given CPU node identifier. + * states present and enabled in the given CPU node identifier. * * Example devicetree fragment: * @@ -305,8 +324,8 @@ struct pm_state_info { */ #define PM_STATE_LIST_FROM_DT_CPU(node_id) \ { \ - LISTIFY(DT_NUM_CPU_POWER_STATES(node_id), \ - Z_PM_STATE_FROM_DT_CPU, (,), node_id) \ + LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \ + Z_PM_STATE_FROM_DT_CPU, (), node_id) \ } diff --git a/subsys/pm/state.c b/subsys/pm/state.c index 14352dfe2df5..297d28a37680 100644 --- a/subsys/pm/state.c +++ b/subsys/pm/state.c @@ -33,7 +33,7 @@ BUILD_ASSERT(DT_NODE_EXISTS(DT_PATH(cpus)), * @param node_id A CPU node identifier. */ #define CHECK_POWER_STATES_CONSISTENCY(node_id) \ - LISTIFY(DT_NUM_CPU_POWER_STATES(node_id), \ + LISTIFY(DT_PROP_LEN_OR(node_id, cpu_power_states, 0), \ CHECK_POWER_STATE_CONSISTENCY, (;), node_id); \ /* Check that all power states are consistent */ @@ -48,12 +48,12 @@ DT_FOREACH_CHILD(DT_PATH(cpus), DEFINE_CPU_STATES); /** CPU power states information for each CPU */ static const struct pm_state_info *cpus_states[] = { - DT_FOREACH_CHILD_SEP(DT_PATH(cpus), CPU_STATE_REF, (,)) + DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), CPU_STATE_REF, (,)) }; /** Number of states for each CPU */ static const uint8_t states_per_cpu[] = { - DT_FOREACH_CHILD_SEP(DT_PATH(cpus), DT_NUM_CPU_POWER_STATES, (,)) + DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_NUM_CPU_POWER_STATES, (,)) }; uint8_t pm_state_cpu_get_all(uint8_t cpu, const struct pm_state_info **states) diff --git a/tests/subsys/pm/power_states_api/boards/native_posix.overlay b/tests/subsys/pm/power_states_api/boards/native_posix.overlay index 79fafb582b0c..e7222630000b 100644 --- a/tests/subsys/pm/power_states_api/boards/native_posix.overlay +++ b/tests/subsys/pm/power_states_api/boards/native_posix.overlay @@ -7,7 +7,7 @@ / { cpus { cpu@0 { - cpu-power-states = <&state0 &state1 &state2>; + cpu-power-states = <&state0 &state1 &state2 &state3>; }; power-states { @@ -29,6 +29,12 @@ compatible = "zephyr,power-state"; power-state-name = "standby"; }; + + state3: state3 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + status = "disabled"; + }; }; }; }; From 1c0ec37931686d0c0370b539ad57d8ea9d7246bf Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 11:13:08 +0200 Subject: [PATCH 1865/2042] dts: arm: silabs: move cpu-power-states to SoC dts files CPU power states is a property of the SoC, not dts. Signed-off-by: Gerard Marull-Paretas --- boards/arm/efr32_thunderboard/thunderboard.dtsi | 8 ++++---- dts/arm/silabs/efr32bg2x.dtsi | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/boards/arm/efr32_thunderboard/thunderboard.dtsi b/boards/arm/efr32_thunderboard/thunderboard.dtsi index 2d36a291a682..236e8ec479b0 100644 --- a/boards/arm/efr32_thunderboard/thunderboard.dtsi +++ b/boards/arm/efr32_thunderboard/thunderboard.dtsi @@ -62,10 +62,10 @@ &cpu0 { clock-frequency = <76800000>; - /* Enable EM1,2. This means BURTC has to be used as sys_clock - * or the system won't wake up - */ - cpu-power-states = <&pstate_em1 &pstate_em2>; +}; + +&pstate_em3 { + status = "disabled"; }; &usart0 { diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index deee10ccdde8..439a63366436 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -36,7 +36,7 @@ * has implications on system performance. Read * KConfig documentation entry before enabling it. */ - cpu-power-states = <&pstate_em1>; + cpu-power-states = <&pstate_em1 &pstate_em2 &pstate_em3>; }; power-states { From 00f0054cf63ce8c0572b4b032cd39d3a3d0bb4d9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Tue, 25 Jul 2023 11:48:32 +0200 Subject: [PATCH 1866/2042] dts: arm: silabs: remove redundant pstate_em4 state This state is never used in practice, even if handled by the PM subsystem hooks. Shutdown-like states are always invoked manually, so they don't need to be described in DT. Signed-off-by: Gerard Marull-Paretas --- dts/arm/silabs/efr32bg2x.dtsi | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index 439a63366436..e1f3726e4297 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -75,19 +75,6 @@ min-residency-us = <20000>; exit-latency-us = <2000>; }; - - /* - * EM4 does not preserve CPU or RAM state, so system runs - * through a cold boot upon wake up. BURTC can wake up the - * system from EM4 but that has to be manually configured - * by the application in BURTC registers. - */ - pstate_em4: em4 { - compatible = "zephyr,power-state"; - power-state-name = "soft-off"; - min-residency-us = <100000>; - exit-latency-us = <80000>; - }; }; }; From d7c00ee7c25b48ca31ee6702dc6516786d98963a Mon Sep 17 00:00:00 2001 From: Jacques Supcik Date: Wed, 26 Jul 2023 15:37:30 +0200 Subject: [PATCH 1867/2042] boards: arm: stm32f412g_disco: Fix LED4 pin On the stm32f412g_disco board, the LED LD4 (blue LED) is actually on the pin 3 of GPIOE and not on the pin 4 (see https://www.st.com/resource/en/user_manual/um2032-discovery-kit-with-stm32f412zg-mcu-stmicroelectronics.pdf, page 31) Signed-off-by: Jacques Supcik --- boards/arm/stm32f412g_disco/stm32f412g_disco.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts index 56704e923d48..959a3706f533 100644 --- a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts +++ b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts @@ -35,7 +35,7 @@ label = "User LD3"; }; blue_led_4: led_4 { - gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>; + gpios = <&gpioe 3 GPIO_ACTIVE_HIGH>; label = "User LD4"; }; }; From 43601095b5825b981326ee29cc7cd3d2643a0131 Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Wed, 26 Jul 2023 13:55:15 -0600 Subject: [PATCH 1868/2042] emul: sbs_gauge: Return err or unsupported feature The fuel gauge emulators will attempt to access a 0 pointer when running a backend emulator function that hasn't been implemented. Add an explicit runtime check to return -ENOTSUP to signify the emulator feature is not supported. We do not ASSERT here so we can write tests that are generic and can run with various emulators that support a variety of features. Signed-off-by: Aaron Massey --- include/zephyr/drivers/emul_fuel_gauge.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/zephyr/drivers/emul_fuel_gauge.h b/include/zephyr/drivers/emul_fuel_gauge.h index 47044d09318e..c8af1c91a561 100644 --- a/include/zephyr/drivers/emul_fuel_gauge.h +++ b/include/zephyr/drivers/emul_fuel_gauge.h @@ -59,6 +59,10 @@ static inline int emul_fuel_gauge_set_battery_charging(const struct emul *target const struct fuel_gauge_emul_driver_api *backend_api = (const struct fuel_gauge_emul_driver_api *)target->backend_api; + if (backend_api->set_battery_charging == 0) { + return -ENOTSUP; + } + return backend_api->set_battery_charging(target, uV, uA); } From 41f16c3dd7d801a59aa2440eaa0aa85686074640 Mon Sep 17 00:00:00 2001 From: Sylvio Alves Date: Wed, 26 Jul 2023 11:08:52 -0300 Subject: [PATCH 1869/2042] driver: wifi: esp32: increase default stack values When testing Wi-Fi with MQTT/HTTP/Socket features, network stacks can be full very fast, causing network issues and eventual crash. By analyzing used stacks,increasing the stack size described in this PR fixes most use cases related above. Signed-off-by: Sylvio Alves --- drivers/wifi/esp32/Kconfig.esp32 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/wifi/esp32/Kconfig.esp32 b/drivers/wifi/esp32/Kconfig.esp32 index d746d113153a..4d92bc8f37b6 100644 --- a/drivers/wifi/esp32/Kconfig.esp32 +++ b/drivers/wifi/esp32/Kconfig.esp32 @@ -22,6 +22,15 @@ menuconfig WIFI_ESP32 if WIFI_ESP32 +config NET_TCP_WORKQ_STACK_SIZE + default 2048 + +config NET_RX_STACK_SIZE + default 2048 + +config NET_MGMT_EVENT_STACK_SIZE + default 2048 + config ESP32_WIFI_STA_AUTO_DHCPV4 bool "Automatically starts DHCP4 negotiation" depends on NET_DHCPV4 From 43b385ae65f418a6328a6ddec6a21ed407d7dd31 Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Tue, 25 Jul 2023 11:38:57 -0600 Subject: [PATCH 1870/2042] tests: sbs_gauge: Factor fixture out of test In the near future we'll be adding SBS tests that are linked in based on configs. Extract the test fixture as a header that can be shared by multiple tests. Signed-off-by: Aaron Massey --- tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt | 2 ++ .../fuel_gauge/sbs_gauge/include/test_sbs_gauge.h | 14 ++++++++++++++ .../fuel_gauge/sbs_gauge/src/test_sbs_gauge.c | 6 +----- 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 tests/drivers/fuel_gauge/sbs_gauge/include/test_sbs_gauge.h diff --git a/tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt b/tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt index 9aaf0d0cd938..151d3bf8ce9d 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt +++ b/tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt @@ -5,4 +5,6 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(device) FILE(GLOB app_sources src/test_sbs_gauge.c) + +target_include_directories(app PRIVATE include) target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/fuel_gauge/sbs_gauge/include/test_sbs_gauge.h b/tests/drivers/fuel_gauge/sbs_gauge/include/test_sbs_gauge.h new file mode 100644 index 000000000000..e7c3adab57ac --- /dev/null +++ b/tests/drivers/fuel_gauge/sbs_gauge/include/test_sbs_gauge.h @@ -0,0 +1,14 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +struct sbs_gauge_new_api_fixture { + const struct device *dev; + const struct emul *sbs_fuel_gauge; + const struct fuel_gauge_driver_api *api; +}; diff --git a/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c b/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c index 5a67149181d3..2e5cea196095 100644 --- a/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c +++ b/tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c @@ -16,11 +16,7 @@ #include #include -struct sbs_gauge_new_api_fixture { - const struct device *dev; - const struct emul *sbs_fuel_gauge; - const struct fuel_gauge_driver_api *api; -}; +#include "test_sbs_gauge.h" static void *sbs_gauge_new_api_setup(void) { From bdeb62d11653bd11ad75d13ac946eca377a9b152 Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Wed, 26 Jul 2023 12:43:50 +0200 Subject: [PATCH 1871/2042] shell: fix possible negative indexing Fixes #60808 Signed-off-by: Jakub Rzeszutko --- subsys/shell/shell_ops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subsys/shell/shell_ops.c b/subsys/shell/shell_ops.c index b8ff0f0e56c6..db68c62155ba 100644 --- a/subsys/shell/shell_ops.c +++ b/subsys/shell/shell_ops.c @@ -161,16 +161,16 @@ void z_shell_op_cursor_word_move(const struct shell *sh, int16_t val) void z_shell_op_word_remove(const struct shell *sh) { - char *str = &sh->ctx->cmd_buff[sh->ctx->cmd_buff_pos - 1]; - char *str_start = &sh->ctx->cmd_buff[0]; - uint16_t chars_to_delete; - /* Line must not be empty and cursor must not be at 0 to continue. */ if ((sh->ctx->cmd_buff_len == 0) || (sh->ctx->cmd_buff_pos == 0)) { return; } + char *str = &sh->ctx->cmd_buff[sh->ctx->cmd_buff_pos - 1]; + char *str_start = &sh->ctx->cmd_buff[0]; + uint16_t chars_to_delete; + /* Start at the current position. */ chars_to_delete = 0U; From e0370f54397452cbc9b6b4c18e40870d32965836 Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Thu, 13 Jul 2023 11:19:04 +0200 Subject: [PATCH 1872/2042] Bluetooth: Controller: Stop following aux ptr if DATA_LEN_MAX is hit If the aux scanner already has CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX advertising data, there is no point in following an aux ptr - instead flush the data and produce an incomplete report Signed-off-by: Troels Nilsson --- subsys/bluetooth/controller/ll_sw/ull_scan_aux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index 8758a677c8af..194252da87fa 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -537,6 +537,10 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) } else { aux->data_len += data_len; + + if (aux->data_len >= CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + goto ull_scan_aux_rx_flush; + } } /* In sync context we can dispatch rx immediately, in scan context we From c0649ef694ae16964d30076429ca8e5688ec657a Mon Sep 17 00:00:00 2001 From: Troels Nilsson Date: Thu, 13 Jul 2023 11:22:55 +0200 Subject: [PATCH 1873/2042] Bluetooth: Controller: Fix truncation of adv. data Truncation of advertising data has to be done at a PDU boundary; Including only part of a PDUs advertising data is not allowed Signed-off-by: Troels Nilsson --- subsys/bluetooth/controller/hci/hci.c | 33 +++++++++++---------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index c4db3b1cca5f..4e63d45678d9 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -6969,6 +6969,19 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, LOG_DBG(" AD Data (%u): ", data_len); } + if (data_len_total + data_len_curr > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { + /* Truncating advertising data + * Note that this has to be done at a PDU boundary, so stop + * processing nodes from this one forward + */ + if (scan_data) { + scan_data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } else { + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; + } + break; + } + if (node_rx_curr == node_rx) { evt_type = evt_type_curr; adv_addr_type = adv_addr_type_curr; @@ -7102,16 +7115,6 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, } } - /* Restrict data length to maximum scan data length */ - if (data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { - data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; - if (data_len > data_len_total) { - data_len = data_len_total; - } - - data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; - } - /* Set directed advertising bit */ if (direct_addr) { evt_type |= BT_HCI_LE_ADV_EVT_TYPE_DIRECT; @@ -7151,16 +7154,6 @@ static void le_ext_adv_report(struct pdu_data *pdu_data, return; } - /* Restrict scan response data length to maximum scan data length */ - if (scan_data_len_total > CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX) { - scan_data_len_total = CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX; - if (scan_data_len > scan_data_len_total) { - scan_data_len = scan_data_len_total; - } - - scan_data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE; - } - /* Set scan response bit */ evt_type |= BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP; From 88f161778ad7d7acaf359b97e9bc185ea72db965 Mon Sep 17 00:00:00 2001 From: Rubin Gerritsen Date: Mon, 10 Jul 2023 15:26:15 +0200 Subject: [PATCH 1874/2042] Bluetooth: Controller: Kconfig: Move BT_LL_SW_SPLIT specific configs These configs are very tied to the BT_LL_SW_SPLIT implementation, so it makes sense that these are only visible when that link layer is used. For the ones that may be used by other controllers in the future, a dependency has been added. Signed-off-by: Rubin Gerritsen --- subsys/bluetooth/controller/Kconfig | 102 +---------------- .../bluetooth/controller/Kconfig.ll_sw_split | 105 ++++++++++++++++++ 2 files changed, 108 insertions(+), 99 deletions(-) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 56314ed47326..4a32448ef2f7 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -142,31 +142,10 @@ config BT_CTLR_HCI_VS_BUILD_INFO character is required at the beginning to separate it from the already included information. -config BT_CTLR_AD_DATA_BACKUP - bool "Legacy AD Data backup" - depends on BT_PERIPHERAL || BT_CTLR_ADV_EXT - default y - help - Backup Legacy Advertising Data when switching to Legacy Directed or - to Extended Advertising mode, and restore it when switching back to - Legacy Non-Directed Advertising mode. - Application can disable this feature if not using Directed - Advertising or switch between Legacy and Extended Advertising. - -config BT_CTLR_HCI_ADV_HANDLE_MAPPING - bool "Advertising set handle mapping between HCI and LL" - depends on BT_CTLR_ADV_EXT - default y if BT_HCI_RAW - help - Enable mapping of advertising set handles between HCI and LL when - using external host since it can use arbitrary numbers as set handles - (as defined by Core specification) as opposed to LL which always uses - zero-based numbering. When using with Zephyr host this option can be - disabled to remove extra mapping logic. - config BT_CTLR_DUP_FILTER_LEN int "Number of addresses in the scan duplicate filter" depends on BT_OBSERVER + depends on BT_LL_SW_SPLIT default 16 help Set the number of unique BLE addresses that can be filtered as @@ -175,32 +154,16 @@ config BT_CTLR_DUP_FILTER_LEN config BT_CTLR_DUP_FILTER_ADV_SET_MAX int "Number of Extended Advertising Sets in the scan duplicate filter" depends on BT_OBSERVER && BT_CTLR_ADV_EXT && (BT_CTLR_DUP_FILTER_LEN > 0) + depends on BT_LL_SW_SPLIT range 1 16 default 1 help Set the number of unique Advertising Set ID per Bluetooth Low Energy addresses that can be filtered as duplicates while Extended Scanning. -config BT_CTLR_MESH_SCAN_FILTERS - int "Number of Mesh scan filters" - depends on BT_HCI_MESH_EXT - default 1 - range 1 15 - help - Set the number of unique Mesh Scan Filters available as part of - the Intel Mesh Vendor Specific Extensions. - -config BT_CTLR_MESH_SF_PATTERNS - int "Number of Mesh scan filter patterns" - depends on BT_HCI_MESH_EXT - default 15 - range 1 15 - help - Set the number of unique Mesh Scan Filter patterns available per - Scan Filter as part of the Intel Mesh Vendor Specific Extensions. - config BT_CTLR_RX_BUFFERS int "Number of Rx buffers" + depends on BT_LL_SW_SPLIT default 6 if BT_HCI_RAW default 1 range 1 18 @@ -530,10 +493,6 @@ config BT_CTLR_CONN_RSSI help Enable connection RSSI measurement. -config BT_CTLR_CHECK_SAME_PEER_CONN - bool - default BT_MAX_CONN > 1 && !BT_CTLR_ALLOW_SAME_PEER_CONN - endif # BT_CONN config BT_CTLR_FILTER_ACCEPT_LIST @@ -644,22 +603,6 @@ config BT_CTLR_ADV_DATA_LEN_MAX help Maximum Extended Advertising Data Length. -config BT_CTLR_ADV_EXT_RX_PDU_LEN_MAX - int "Maximum Advertising Extensions Receive PDU Length" - depends on BT_OBSERVER - range 255 255 if BT_HCI_RAW - range 31 255 - default 255 - help - Maximum Advertising Extensions Receive PDU Length. - -config BT_CTLR_SCAN_DATA_LEN_MAX - int "Maximum Extended Scanning Data Length" - depends on BT_OBSERVER - range 31 1650 - help - Maximum Extended Scanning Data Length. - config BT_CTLR_ADV_PERIODIC bool "LE Periodic Advertising in Advertising State" depends on BT_BROADCASTER && BT_CTLR_ADV_PERIODIC_SUPPORT @@ -748,11 +691,6 @@ config BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING Enable filtering of periodic advertisements depending on type of Constant Tone Extension. -config BT_CTLR_CHECK_SAME_PEER_SYNC - # Hidden Kconfig to add same peer synchronization check - bool - default BT_PER_ADV_SYNC_MAX > 1 - config BT_CTLR_SYNC_TRANSFER_RECEIVER bool "Periodic Advertising Sync Transfer receiver" depends on BT_CTLR_SYNC_TRANSFER_RECEIVER_SUPPORT @@ -931,13 +869,6 @@ config BT_CTLR_CONN_ISO_STREAMS_PER_GROUP help Maximum supported CISes per CIG. -config BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA - bool "Do not pass invalid SDUs on HCI datapath" - depends on BT_CTLR_CONN_ISO - help - This allows for applications to decide whether to - forward invalid SDUs through HCI upwards. - config BT_CTLR_CONN_ISO_PDU_LEN_MAX int "Maximum Connected Isochronous Channel PDU Length" depends on BT_CTLR_CONN_ISO @@ -963,28 +894,6 @@ config BT_CTLR_CONN_ISO_STREAMS_MAX_NSE help Maximum number of CIS subevents. -choice - prompt "CIS Creation Policy Selection" - default BT_CTLR_CONN_ISO_RELIABILITY_POLICY - -config BT_CTLR_CONN_ISO_RELIABILITY_POLICY - bool "CIS creation policy for reliability" - depends on BT_CTLR_CENTRAL_ISO - help - Select this option to use reliability policy for CIS creation. This - favors a CIS layout/configuration which utilizes the full range of the - Max_Transmission_Latency for maximum retransmission and payload - recovery. - -config BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY - bool "CIS creation policy for low latency" - depends on BT_CTLR_CENTRAL_ISO - help - Select this option to use low latency policy for CIS creation. This - favors a CIS layout/configuration which compacts payload transmission - for lowest possible latency. -endchoice - config BT_CTLR_ISO bool default BT_CTLR_BROADCAST_ISO || BT_CTLR_CONN_ISO @@ -1033,11 +942,6 @@ config BT_CTLR_ASSERT_HANDLER and will be invoked whenever the controller code encounters an unrecoverable error. -config BT_CTLR_TEST - bool "Run in-system unit tests" - help - Run in-system unit tests - endif # BT_CTLR config BT_CTLR_DEBUG_PINS_CPUAPP diff --git a/subsys/bluetooth/controller/Kconfig.ll_sw_split b/subsys/bluetooth/controller/Kconfig.ll_sw_split index 9dd013c47868..b1affdd55884 100644 --- a/subsys/bluetooth/controller/Kconfig.ll_sw_split +++ b/subsys/bluetooth/controller/Kconfig.ll_sw_split @@ -133,11 +133,116 @@ config BT_CTLR_SUBVERSION_NUMBER help Set the Subversion Number that will be used in VERSION_IND PDU. +config BT_CTLR_AD_DATA_BACKUP + bool "Legacy AD Data backup" + depends on BT_PERIPHERAL || BT_CTLR_ADV_EXT + default y + help + Backup Legacy Advertising Data when switching to Legacy Directed or + to Extended Advertising mode, and restore it when switching back to + Legacy Non-Directed Advertising mode. + Application can disable this feature if not using Directed + Advertising or switch between Legacy and Extended Advertising. + +config BT_CTLR_HCI_ADV_HANDLE_MAPPING + bool "Advertising set handle mapping between HCI and LL" + depends on BT_CTLR_ADV_EXT + default y if BT_HCI_RAW + help + Enable mapping of advertising set handles between HCI and LL when + using external host since it can use arbitrary numbers as set handles + (as defined by Core specification) as opposed to LL which always uses + zero-based numbering. When using with Zephyr host this option can be + disabled to remove extra mapping logic. + +config BT_CTLR_MESH_SCAN_FILTERS + int "Number of Mesh scan filters" + depends on BT_HCI_MESH_EXT + default 1 + range 1 15 + help + Set the number of unique Mesh Scan Filters available as part of + the Intel Mesh Vendor Specific Extensions. + +config BT_CTLR_MESH_SF_PATTERNS + int "Number of Mesh scan filter patterns" + depends on BT_HCI_MESH_EXT + default 15 + range 1 15 + help + Set the number of unique Mesh Scan Filter patterns available per + Scan Filter as part of the Intel Mesh Vendor Specific Extensions. + +config BT_CTLR_CHECK_SAME_PEER_CONN + bool + depends on BT_CONN + default BT_MAX_CONN > 1 && !BT_CTLR_ALLOW_SAME_PEER_CONN + +if BT_CTLR_ADV_EXT + +config BT_CTLR_ADV_EXT_RX_PDU_LEN_MAX + int "Maximum Advertising Extensions Receive PDU Length" + depends on BT_OBSERVER + range 255 255 if BT_HCI_RAW + range 31 255 + default 255 + help + Maximum Advertising Extensions Receive PDU Length. + +config BT_CTLR_SCAN_DATA_LEN_MAX + int "Maximum Extended Scanning Data Length" + depends on BT_OBSERVER + range 31 1650 + help + Maximum Extended Scanning Data Length. + +config BT_CTLR_CHECK_SAME_PEER_SYNC + # Hidden Kconfig to add same peer synchronization check + bool + depends on BT_CTLR_SYNC_PERIODIC + default BT_PER_ADV_SYNC_MAX > 1 + +endif # BT_CTLR_ADV_EXT + +config BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA + bool "Do not pass invalid SDUs on HCI datapath" + depends on BT_CTLR_CONN_ISO + help + This allows for applications to decide whether to + forward invalid SDUs through HCI upwards. + 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 + +config BT_CTLR_CONN_ISO_RELIABILITY_POLICY + bool "CIS creation policy for reliability" + depends on BT_CTLR_CENTRAL_ISO + help + Select this option to use reliability policy for CIS creation. This + favors a CIS layout/configuration which utilizes the full range of the + Max_Transmission_Latency for maximum retransmission and payload + recovery. + +config BT_CTLR_CONN_ISO_LOW_LATENCY_POLICY + bool "CIS creation policy for low latency" + depends on BT_CTLR_CENTRAL_ISO + help + Select this option to use low latency policy for CIS creation. This + favors a CIS layout/configuration which compacts payload transmission + for lowest possible latency. +endchoice + +config BT_CTLR_TEST + bool "Run in-system unit tests" + help + Run in-system unit tests + menu "Advanced features" visible if BT_CTLR_ADVANCED_FEATURES From b140963557d990af950db8217de3911e486466c2 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 26 Jul 2023 15:51:05 +0200 Subject: [PATCH 1875/2042] soc: nordic_nrf: Add nRF52840 QFAA variant This variant has fewer pins. Signed-off-by: Carles Cufi --- dts/arm/nordic/nrf52840_qfaa.dtsi | 23 +++++++++++++++++++ .../nrf52/Kconfig.defconfig.nrf52840_QFAA | 14 +++++++++++ soc/arm/nordic_nrf/nrf52/Kconfig.soc | 6 ++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 dts/arm/nordic/nrf52840_qfaa.dtsi create mode 100644 soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52840_QFAA diff --git a/dts/arm/nordic/nrf52840_qfaa.dtsi b/dts/arm/nordic/nrf52840_qfaa.dtsi new file mode 100644 index 000000000000..19d6d5a6c29a --- /dev/null +++ b/dts/arm/nordic/nrf52840_qfaa.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,nRF52840-QFAA", "nordic,nRF52840", + "nordic,nRF52", "simple-bus"; + }; +}; diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52840_QFAA b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52840_QFAA new file mode 100644 index 000000000000..451fea911b45 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52840_QFAA @@ -0,0 +1,14 @@ +# Nordic Semiconductor nRF52840 MCU + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF52840_QFAA + +config SOC + default "nRF52840_QFAA" + +config NUM_IRQS + default 48 + +endif # SOC_NRF52840_QFAA diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index d423779a63ff..11d454e69c10 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -68,6 +68,10 @@ config SOC_NRF52833_QIAA bool "NRF52833_QIAA" select SOC_NRF52833 +config SOC_NRF52840_QFAA + bool "NRF52840_QFAA" + select SOC_NRF52840 + config SOC_NRF52840_QIAA bool "NRF52840_QIAA" select SOC_NRF52840 @@ -81,7 +85,7 @@ config SOC_DCDC_NRF52X config SOC_DCDC_NRF52X_HV bool - depends on SOC_NRF52840 + depends on SOC_NRF52840_QIAA help Enable nRF52 series System on Chip High Voltage DC/DC converter. From acb8f6bf0b49369f1bada12eaaa4ea9e12c5dea0 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Wed, 26 Jul 2023 16:39:57 +0200 Subject: [PATCH 1876/2042] soc: nordic_nrf: Add nRF52833 QDAA variant This variant has fewer pins. Signed-off-by: Carles Cufi --- dts/arm/nordic/nrf52833_qdaa.dtsi | 23 +++++++++++++++++++ .../nrf52/Kconfig.defconfig.nrf52833_QDAA | 16 +++++++++++++ soc/arm/nordic_nrf/nrf52/Kconfig.soc | 4 ++++ 3 files changed, 43 insertions(+) create mode 100644 dts/arm/nordic/nrf52833_qdaa.dtsi create mode 100644 soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52833_QDAA diff --git a/dts/arm/nordic/nrf52833_qdaa.dtsi b/dts/arm/nordic/nrf52833_qdaa.dtsi new file mode 100644 index 000000000000..78c962303e81 --- /dev/null +++ b/dts/arm/nordic/nrf52833_qdaa.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(512)>; +}; + +&sram0 { + reg = <0x20000000 DT_SIZE_K(128)>; +}; + +/ { + soc { + compatible = "nordic,nRF52833-QDAA", "nordic,nRF52833", + "nordic,nRF52", "simple-bus"; + }; +}; diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52833_QDAA b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52833_QDAA new file mode 100644 index 000000000000..237bee5813a2 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52833_QDAA @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF52833 MCU + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF52833_QDAA + +config SOC + string + default "nRF52833_QDAA" + +config NUM_IRQS + int + default 48 + +endif # SOC_NRF52833_QDAA diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index 11d454e69c10..13a2fef932b0 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -64,6 +64,10 @@ config SOC_NRF52832_QFAB bool "NRF52832_QFAB" select SOC_NRF52832 +config SOC_NRF52833_QDAA + bool "NRF52833_QDAA" + select SOC_NRF52833 + config SOC_NRF52833_QIAA bool "NRF52833_QIAA" select SOC_NRF52833 From 8ecedf2dfb0e11f8cb755399d78edebd82383a4a Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 27 Jul 2023 08:58:55 +0100 Subject: [PATCH 1877/2042] mgmt: mcumgr: grp: img_mgmt: Fix renamed define Fixes an issue whereby a define was renamed in one place but not another. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3ee7616413a9..894fdee1ce9e 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 @@ -615,7 +615,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, } #if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT) - if (hdr->ih_flags & IMAGE_F_ROM_FIXED_ADDR) { + if (hdr->ih_flags & IMAGE_F_ROM_FIXED) { const struct flash_area *fa; rc = flash_area_open(action->area_id, &fa); From 9f56995d357ca3b6ceac89352d05d2b5c459d892 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 27 Jul 2023 08:58:07 +0100 Subject: [PATCH 1878/2042] tests: mgmt: mcumgr: all_options: Add additional checks Adds additional checks to enable more options for the build-only check that compilation is successful. Signed-off-by: Jamie McCrae --- .../mcumgr/all_options/other-options.conf | 20 ++++++++++++ tests/subsys/mgmt/mcumgr/all_options/prj.conf | 31 +++++++++++-------- .../mgmt/mcumgr/all_options/testcase.yaml | 19 +++++++----- 3 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 tests/subsys/mgmt/mcumgr/all_options/other-options.conf diff --git a/tests/subsys/mgmt/mcumgr/all_options/other-options.conf b/tests/subsys/mgmt/mcumgr/all_options/other-options.conf new file mode 100644 index 000000000000..36ade8751a3d --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/all_options/other-options.conf @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR=y +CONFIG_MCUMGR_GRP_IMG_MUTEX=y +CONFIG_MCUMGR_GRP_IMG_VERSION_CMP_USE_BUILD_NUMBER=y +CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD=y +CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT=y +CONFIG_MCUMGR_GRP_OS_TASKSTAT_STACK_INFO=y +CONFIG_MCUMGR_GRP_OS_INFO=y +CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=y +CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME=y +CONFIG_MCUMGR_GRP_SHELL_LEGACY_RC_RETURN_CODE=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=2048 +CONFIG_MCUMGR_TRANSPORT_SHELL=n +CONFIG_MCUMGR_TRANSPORT_UART=y +CONFIG_MCUMGR_TRANSPORT_SHELL_INPUT_TIMEOUT=n +CONFIG_MCUMGR_TRANSPORT_DUMMY=n diff --git a/tests/subsys/mgmt/mcumgr/all_options/prj.conf b/tests/subsys/mgmt/mcumgr/all_options/prj.conf index e44d2420909f..613ba6d8eea2 100644 --- a/tests/subsys/mgmt/mcumgr/all_options/prj.conf +++ b/tests/subsys/mgmt/mcumgr/all_options/prj.conf @@ -17,18 +17,29 @@ CONFIG_FLASH_MAP=y CONFIG_STREAM_FLASH=y CONFIG_IMG_MANAGER=y CONFIG_MCUMGR=y +CONFIG_MCUMGR_TRANSPORT_BT=y +CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=n +CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y +CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y +CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=y CONFIG_MCUMGR_TRANSPORT_DUMMY=y CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=512 +CONFIG_MCUMGR_TRANSPORT_SHELL=y +CONFIG_MCUMGR_TRANSPORT_SHELL_INPUT_TIMEOUT=y +CONFIG_MCUMGR_TRANSPORT_UDP=y +CONFIG_MCUMGR_TRANSPORT_UDP_IPV4=y +CONFIG_MCUMGR_TRANSPORT_UDP_IPV6=y CONFIG_MCUMGR_GRP_FS=y -CONFIG_MCUMGR_GRP_FS_FILE_STATUS=n +CONFIG_MCUMGR_GRP_FS_FILE_STATUS=y CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH=y CONFIG_MCUMGR_GRP_FS_CHECKSUM_HASH_SUPPORTED_CMD=y CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS=y -CONFIG_MCUMGR_GRP_FS=y CONFIG_MCUMGR_GRP_FS_DL_CHUNK_SIZE_LIMIT=y CONFIG_MCUMGR_GRP_FS_DL_CHUNK_SIZE=128 CONFIG_MCUMGR_GRP_FS_FILE_ACCESS_HOOK=y +CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y +CONFIG_MCUMGR_GRP_OS_TASKSTAT=y CONFIG_MCUMGR_GRP_IMG=y CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR=y CONFIG_MCUMGR_GRP_IMG_FRUGAL_LIST=y @@ -41,8 +52,6 @@ CONFIG_MCUMGR_GRP_SHELL=y CONFIG_MCUMGR_GRP_STAT=y CONFIG_MCUMGR_GRP_ZBASIC=y CONFIG_MCUMGR_GRP_ZBASIC_STORAGE_ERASE=y -CONFIG_MCUMGR_TRANSPORT_DUMMY=y -CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=512 CONFIG_SHELL=y CONFIG_SHELL_BACKEND_DUMMY=y CONFIG_STATS=y @@ -50,13 +59,9 @@ CONFIG_BT=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=y CONFIG_BT_SMP=y -CONFIG_MCUMGR_TRANSPORT_BT=y -CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=n -CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y -CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y -CONFIG_MCUMGR_TRANSPORT_SHELL=y -CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN=y -CONFIG_MCUMGR_GRP_FS_FILE_STATUS=y -CONFIG_MCUMGR_GRP_FS_HASH_SHA256=y -CONFIG_MCUMGR_GRP_OS_TASKSTAT=y CONFIG_BOOTLOADER_MCUBOOT=y +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_L2_DUMMY=y +CONFIG_NET_SOCKETS=y diff --git a/tests/subsys/mgmt/mcumgr/all_options/testcase.yaml b/tests/subsys/mgmt/mcumgr/all_options/testcase.yaml index f0c46171de85..471a96a935f6 100644 --- a/tests/subsys/mgmt/mcumgr/all_options/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/all_options/testcase.yaml @@ -1,12 +1,17 @@ # -# Copyright (c) 2022 Nordic Semiconductor ASA +# Copyright (c) 2022-2023 Nordic Semiconductor ASA # # SPDX-License-Identifier: Apache-2.0 # +common: + platform_allow: nrf52840dk_nrf52840 + tags: + - mgmt + - mcumgr + - all_options + build_only: true tests: - mgmt.mcumgr.all.options: - platform_allow: nrf52840dk_nrf52840 - tags: - - mgmt - - mcumgr - - all_options + mgmt.mcumgr.all.options: {} + mgmt.mcumgr.all.options.other: + extra_args: + - OVERLAY_CONFIG="other-options.conf" From b89ff1b3d6816606d24403738844a8257c2db173 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 27 Jul 2023 10:32:10 +0200 Subject: [PATCH 1879/2042] manifest: Update nRF HW models to latest The nRF HW models have been updated to include the following fixes and improvements. * RADIO: Improve T_IFS support, and fix for low latency mode * docs: Miscelaneous improvements 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 16ea3eab6176..47d52666a7f9 100644 --- a/west.yml +++ b/west.yml @@ -287,7 +287,7 @@ manifest: groups: - tools - name: nrf_hw_models - revision: 7a5b67d9ee66d84e4ef5cb1f56c8f0f3252d5aa2 + revision: cee41373eb0bb720a370586de1ee5eb693e62c95 path: modules/bsim_hw_models/nrf_hw_models - name: open-amp revision: 42b7c577714b8f22ce82a901e19c1814af4609a8 From f53041cb791feafbed25a61dff236b55cd2129b8 Mon Sep 17 00:00:00 2001 From: Adam Wojasinski Date: Wed, 26 Jul 2023 16:44:42 +0200 Subject: [PATCH 1880/2042] manifest: hal_nordic: Pull PWM driver fix for nrfx_pwm_stopped_check() When `nrfx_pwm_stopped_check()` was called multiple times it was returning incorrect value after second and next calls. Signed-off-by: Adam Wojasinski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 47d52666a7f9..a358b56064ff 100644 --- a/west.yml +++ b/west.yml @@ -173,7 +173,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 20ae0a7be9030dd58fb59db1c74315a60efb076f + revision: cf6e9fc5f7c2c98df26f2a4227a95df9a50823e7 path: modules/hal/nordic groups: - hal From dd8a1f16bd6764ed6e04818f9f55ec61bf45eb3a Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 27 Jul 2023 11:24:56 +0200 Subject: [PATCH 1881/2042] soc: nordic_nrf: nrf52840-qfaa has no USB The QFN48 version has no USB peripheral, remove it from the Devicetree. Signed-off-by: Carles Cufi --- dts/arm/nordic/nrf52840_qfaa.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dts/arm/nordic/nrf52840_qfaa.dtsi b/dts/arm/nordic/nrf52840_qfaa.dtsi index 19d6d5a6c29a..b64cc6d40249 100644 --- a/dts/arm/nordic/nrf52840_qfaa.dtsi +++ b/dts/arm/nordic/nrf52840_qfaa.dtsi @@ -20,4 +20,6 @@ compatible = "nordic,nRF52840-QFAA", "nordic,nRF52840", "nordic,nRF52", "simple-bus"; }; + + /delete-node/ &usbd; }; From 641b438de0483916bed642448a540472f974d788 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 27 Jul 2023 11:52:32 +0200 Subject: [PATCH 1882/2042] soc: nordic: Make all compatibles lower case Devicetree specification v0.4, Section 2.3.1: "The compatible string should consist only of lowercase letters, digits and dashes, and should start with a letter." Signed-off-by: Carles Cufi --- dts/arm/nordic/nrf51822_qfaa.dtsi | 3 ++- dts/arm/nordic/nrf51822_qfab.dtsi | 3 ++- dts/arm/nordic/nrf51822_qfac.dtsi | 3 ++- dts/arm/nordic/nrf52805_caaa.dtsi | 3 ++- dts/arm/nordic/nrf52810_qfaa.dtsi | 3 ++- dts/arm/nordic/nrf52811_qfaa.dtsi | 3 ++- dts/arm/nordic/nrf52820_qdaa.dtsi | 3 ++- dts/arm/nordic/nrf52832_ciaa.dtsi | 3 ++- dts/arm/nordic/nrf52832_qfaa.dtsi | 3 ++- dts/arm/nordic/nrf52832_qfab.dtsi | 3 ++- dts/arm/nordic/nrf52833_qdaa.dtsi | 4 ++-- dts/arm/nordic/nrf52833_qiaa.dtsi | 3 ++- dts/arm/nordic/nrf52840_qfaa.dtsi | 4 ++-- dts/arm/nordic/nrf52840_qiaa.dtsi | 3 ++- dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi | 3 ++- dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi | 3 ++- dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi | 3 ++- dts/arm/nordic/nrf9160_sica.dtsi | 3 ++- dts/arm/nordic/nrf9160ns_sica.dtsi | 3 ++- dts/arm/nordic/nrf9161_sica.dtsi | 3 ++- dts/arm/nordic/nrf9161ns_sica.dtsi | 3 ++- 21 files changed, 42 insertions(+), 23 deletions(-) diff --git a/dts/arm/nordic/nrf51822_qfaa.dtsi b/dts/arm/nordic/nrf51822_qfaa.dtsi index 3543b23c3388..07fc5dd1cce9 100644 --- a/dts/arm/nordic/nrf51822_qfaa.dtsi +++ b/dts/arm/nordic/nrf51822_qfaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF51822-QFAA", "nordic,nRF51822", "nordic,nRF51", "simple-bus"; + compatible = "nordic,nrf51822-qfaa", "nordic,nrf51822", + "nordic,nrf51", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf51822_qfab.dtsi b/dts/arm/nordic/nrf51822_qfab.dtsi index cccfb48e5a26..7fb4364d0379 100644 --- a/dts/arm/nordic/nrf51822_qfab.dtsi +++ b/dts/arm/nordic/nrf51822_qfab.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF51822-QFAB", "nordic,nRF51822", "nordic,nRF51", "simple-bus"; + compatible = "nordic,nrf51822-qfab", "nordic,nrf51822", + "nordic,nrf51", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf51822_qfac.dtsi b/dts/arm/nordic/nrf51822_qfac.dtsi index d348645ccc10..59a2ed265e67 100644 --- a/dts/arm/nordic/nrf51822_qfac.dtsi +++ b/dts/arm/nordic/nrf51822_qfac.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF51822-QFAC", "nordic,nRF51822", "nordic,nRF51", "simple-bus"; + compatible = "nordic,nrf51822-qfac", "nordic,nrf51822", + "nordic,nrf51", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52805_caaa.dtsi b/dts/arm/nordic/nrf52805_caaa.dtsi index 5463725fbeaa..b7d24861893a 100644 --- a/dts/arm/nordic/nrf52805_caaa.dtsi +++ b/dts/arm/nordic/nrf52805_caaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52805-CAAA", "nordic,nRF52805", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52805-caaa", "nordic,nrf52805", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52810_qfaa.dtsi b/dts/arm/nordic/nrf52810_qfaa.dtsi index a505cfed2fce..98fbd9a09369 100644 --- a/dts/arm/nordic/nrf52810_qfaa.dtsi +++ b/dts/arm/nordic/nrf52810_qfaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52810-QFAA", "nordic,nRF52810", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52810-qfaa", "nordic,nrf52810", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52811_qfaa.dtsi b/dts/arm/nordic/nrf52811_qfaa.dtsi index 1941dc41b82c..3bb1556eadb7 100644 --- a/dts/arm/nordic/nrf52811_qfaa.dtsi +++ b/dts/arm/nordic/nrf52811_qfaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52811-QFAA", "nordic,nRF52811", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52811-qfaa", "nordic,nrf52811", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52820_qdaa.dtsi b/dts/arm/nordic/nrf52820_qdaa.dtsi index d2008dcbe7c2..c1d4a5a95f5a 100644 --- a/dts/arm/nordic/nrf52820_qdaa.dtsi +++ b/dts/arm/nordic/nrf52820_qdaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52820-QDAA", "nordic,nRF52820", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52820-qdaa", "nordic,nrf52820", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52832_ciaa.dtsi b/dts/arm/nordic/nrf52832_ciaa.dtsi index f46f2274690d..88f16574bbb9 100644 --- a/dts/arm/nordic/nrf52832_ciaa.dtsi +++ b/dts/arm/nordic/nrf52832_ciaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52832-CIAA", "nordic,nRF52832", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52832-ciaa", "nordic,nrf52832", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52832_qfaa.dtsi b/dts/arm/nordic/nrf52832_qfaa.dtsi index 42b139691dfd..2943de6d1155 100644 --- a/dts/arm/nordic/nrf52832_qfaa.dtsi +++ b/dts/arm/nordic/nrf52832_qfaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52832-QFAA", "nordic,nRF52832", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52832-qfaa", "nordic,nrf52832", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52832_qfab.dtsi b/dts/arm/nordic/nrf52832_qfab.dtsi index 1e00142ff278..fe1605394e72 100644 --- a/dts/arm/nordic/nrf52832_qfab.dtsi +++ b/dts/arm/nordic/nrf52832_qfab.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52832-QFAB", "nordic,nRF52832", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52832-qfab", "nordic,nrf52832", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52833_qdaa.dtsi b/dts/arm/nordic/nrf52833_qdaa.dtsi index 78c962303e81..7f9be6f22550 100644 --- a/dts/arm/nordic/nrf52833_qdaa.dtsi +++ b/dts/arm/nordic/nrf52833_qdaa.dtsi @@ -17,7 +17,7 @@ / { soc { - compatible = "nordic,nRF52833-QDAA", "nordic,nRF52833", - "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52833-qdaa", "nordic,nrf52833", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52833_qiaa.dtsi b/dts/arm/nordic/nrf52833_qiaa.dtsi index 71efb1cad5e0..68eabb08bcf7 100644 --- a/dts/arm/nordic/nrf52833_qiaa.dtsi +++ b/dts/arm/nordic/nrf52833_qiaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52833-QIAA", "nordic,nRF52833", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52833-qiaa", "nordic,nrf52833", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf52840_qfaa.dtsi b/dts/arm/nordic/nrf52840_qfaa.dtsi index b64cc6d40249..4483bbd6a434 100644 --- a/dts/arm/nordic/nrf52840_qfaa.dtsi +++ b/dts/arm/nordic/nrf52840_qfaa.dtsi @@ -17,8 +17,8 @@ / { soc { - compatible = "nordic,nRF52840-QFAA", "nordic,nRF52840", - "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52840-qfaa", "nordic,nrf52840", + "nordic,nrf52", "simple-bus"; }; /delete-node/ &usbd; diff --git a/dts/arm/nordic/nrf52840_qiaa.dtsi b/dts/arm/nordic/nrf52840_qiaa.dtsi index d460f0582cca..7007fa4dbf48 100644 --- a/dts/arm/nordic/nrf52840_qiaa.dtsi +++ b/dts/arm/nordic/nrf52840_qiaa.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF52840-QIAA", "nordic,nRF52840", "nordic,nRF52", "simple-bus"; + compatible = "nordic,nrf52840-qiaa", "nordic,nrf52840", + "nordic,nrf52", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi index 3e8b110e5837..9a730a394068 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi @@ -21,6 +21,7 @@ / { soc { - compatible = "nordic,nRF5340-CPUAPP-QKAA", "nordic,nRF5340-CPUAPP", "nordic,nRF53", "simple-bus"; + compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", + "nordic,nrf53", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi index 63e239b00183..e4f38769d8fa 100644 --- a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi @@ -21,6 +21,7 @@ / { soc { - compatible = "nordic,nRF5340-CPUAPP-QKAA", "nordic,nRF5340-CPUAPP", "nordic,nRF53", "simple-bus"; + compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", + "nordic,nrf53", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi index 3f30d43a8c91..c8047ebf9051 100644 --- a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi @@ -25,6 +25,7 @@ / { soc { - compatible = "nordic,nRF5340-CPUNET-QKAA", "nordic,nRF5340-CPUNET", "nordic,nRF53", "simple-bus"; + compatible = "nordic,nrf5340-cpunet-qkaa", "nordic,nrf5340-cpunet", + "nordic,nrf53", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf9160_sica.dtsi b/dts/arm/nordic/nrf9160_sica.dtsi index e04347fc0261..15096534016d 100644 --- a/dts/arm/nordic/nrf9160_sica.dtsi +++ b/dts/arm/nordic/nrf9160_sica.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF9160-SICA", "nordic,nRF9160", "nordic,nRF91", "simple-bus"; + compatible = "nordic,nrf9160-sica", "nordic,nrf9160", + "nordic,nrf91", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf9160ns_sica.dtsi b/dts/arm/nordic/nrf9160ns_sica.dtsi index 7e35dd76b62f..c6adbaa7ca2f 100644 --- a/dts/arm/nordic/nrf9160ns_sica.dtsi +++ b/dts/arm/nordic/nrf9160ns_sica.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF9160-SICA", "nordic,nRF9160", "nordic,nRF91", "simple-bus"; + compatible = "nordic,nrf9160-sica", "nordic,nrf9160", + "nordic,nrf91", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf9161_sica.dtsi b/dts/arm/nordic/nrf9161_sica.dtsi index d6ae975ceaad..113ee14617c2 100644 --- a/dts/arm/nordic/nrf9161_sica.dtsi +++ b/dts/arm/nordic/nrf9161_sica.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF9161-SICA", "nordic,nRF9120", "nordic,nRF91", "simple-bus"; + compatible = "nordic,nrf9161-sica", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; }; }; diff --git a/dts/arm/nordic/nrf9161ns_sica.dtsi b/dts/arm/nordic/nrf9161ns_sica.dtsi index 1ff4f1d9ee9a..479021d11070 100644 --- a/dts/arm/nordic/nrf9161ns_sica.dtsi +++ b/dts/arm/nordic/nrf9161ns_sica.dtsi @@ -17,6 +17,7 @@ / { soc { - compatible = "nordic,nRF9161-SICA", "nordic,nRF9120", "nordic,nRF91", "simple-bus"; + compatible = "nordic,nrf9161-sica", "nordic,nrf9120", + "nordic,nrf91", "simple-bus"; }; }; From e473dd5333b90b536037c3f560c10cf2725fc9e8 Mon Sep 17 00:00:00 2001 From: Wojciech Sipak Date: Thu, 27 Jul 2023 10:20:50 +0200 Subject: [PATCH 1883/2042] pinctrl: gecko: fix compilation and UART handling LEUART_Typedef isn't defined for every possible target. It should be included in the conditional compilation part. For proper handling of UART location, the driver needs to remember pin configuration of both TX and RX. This was broken in #60695 is brought back here. Signed-off-by: Wojciech Sipak --- drivers/pinctrl/pinctrl_gecko.c | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/pinctrl/pinctrl_gecko.c b/drivers/pinctrl/pinctrl_gecko.c index 9f377bfb1d1a..2aede54a3255 100644 --- a/drivers/pinctrl/pinctrl_gecko.c +++ b/drivers/pinctrl/pinctrl_gecko.c @@ -11,12 +11,18 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { USART_TypeDef *base = (USART_TypeDef *)reg; - LEUART_TypeDef *lebase = (LEUART_TypeDef *)reg; uint8_t loc; -#ifndef CONFIG_SOC_GECKO_SERIES1 +#ifdef CONFIG_SOC_GECKO_SERIES1 + LEUART_TypeDef *lebase = (LEUART_TypeDef *)reg; +#else int usart_num = USART_NUM(base); #endif +#ifdef CONFIG_UART_GECKO + struct soc_gpio_pin rxpin = {0, 0, 0, 0}; + struct soc_gpio_pin txpin = {0, 0, 0, 0}; +#endif /* CONFIG_UART_GECKO */ + struct soc_gpio_pin pin_config = {0, 0, 0, 0}; for (uint8_t i = 0U; i < pin_cnt; i++) { @@ -27,17 +33,21 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp switch (GECKO_GET_FUN(pins[i])) { #ifdef CONFIG_UART_GECKO case GECKO_FUN_UART_RX: - pin_config.mode = gpioModeInput; - pin_config.out = 1; - GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, - pin_config.out); + rxpin.port = GECKO_GET_PORT(pins[i]); + rxpin.pin = GECKO_GET_PIN(pins[i]); + rxpin.mode = gpioModeInput; + rxpin.out = 1; + GPIO_PinModeSet(rxpin.port, rxpin.pin, rxpin.mode, + rxpin.out); break; case GECKO_FUN_UART_TX: - pin_config.mode = gpioModePushPull; - pin_config.out = 1; - GPIO_PinModeSet(pin_config.port, pin_config.pin, pin_config.mode, - pin_config.out); + txpin.port = GECKO_GET_PORT(pins[i]); + txpin.pin = GECKO_GET_PIN(pins[i]); + txpin.mode = gpioModePushPull; + txpin.out = 1; + GPIO_PinModeSet(txpin.port, txpin.pin, txpin.mode, + txpin.out); break; #ifdef CONFIG_SOC_GECKO_SERIES1 @@ -105,11 +115,11 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintp GPIO->USARTROUTE[usart_num].ROUTEEN = GPIO_USART_ROUTEEN_TXPEN | GPIO_USART_ROUTEEN_RXPEN; GPIO->USARTROUTE[usart_num].TXROUTE = - (pin_config.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | - (pin_config.port << _GPIO_USART_TXROUTE_PORT_SHIFT); + (txpin.pin << _GPIO_USART_TXROUTE_PIN_SHIFT) | + (txpin.port << _GPIO_USART_TXROUTE_PORT_SHIFT); GPIO->USARTROUTE[usart_num].RXROUTE = - (pin_config.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | - (pin_config.port << _GPIO_USART_RXROUTE_PORT_SHIFT); + (rxpin.pin << _GPIO_USART_RXROUTE_PIN_SHIFT) | + (rxpin.port << _GPIO_USART_RXROUTE_PORT_SHIFT); #endif /* CONFIG_SOC_GECKO_HAS_INDIVIDUAL_PIN_LOCATION */ #ifdef UART_GECKO_HW_FLOW_CONTROL From 0cf26615db6c515ad621890b2ab15624fc35c384 Mon Sep 17 00:00:00 2001 From: Huifeng Zhang Date: Wed, 21 Jun 2023 17:42:10 +0800 Subject: [PATCH 1884/2042] drivers: eth_smsc91x: Fix the missing of selecting bank 3 Fix the missing of selecting bank 3 at the beginning of the function `smsc_miibus_writereg`. Signed-off-by: Huifeng Zhang --- drivers/ethernet/eth_smsc91x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ethernet/eth_smsc91x.c b/drivers/ethernet/eth_smsc91x.c index b36cd5fe969c..013a36f2f423 100644 --- a/drivers/ethernet/eth_smsc91x.c +++ b/drivers/ethernet/eth_smsc91x.c @@ -252,6 +252,8 @@ static void smsc_miibus_writereg(struct smsc_data *sc, int phy, int reg, uint16_ irq_disable(sc->irq); SMSC_LOCK(sc); + smsc_select_bank(sc, 3); + smsc_miibus_sync(sc); smsc_miibus_sendbits(sc, MII_COMMAND_START, 2); From 5797e4241e8978a25025ef949676bd181ce717b3 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 29 Mar 2023 13:27:45 +0300 Subject: [PATCH 1885/2042] mgmt: smp: SMP Client enabler SMP client support for generate request and handling response message. Updated SMP transport for send request. Added API for register SMP transport. Signed-off-by: Juha Heiskanen --- include/zephyr/mgmt/mcumgr/smp/smp_client.h | 109 ++++++ include/zephyr/mgmt/mcumgr/transport/smp.h | 45 +++ subsys/mgmt/mcumgr/CMakeLists.txt | 1 + subsys/mgmt/mcumgr/Kconfig | 6 + subsys/mgmt/mcumgr/smp/src/smp.c | 61 ++-- subsys/mgmt/mcumgr/smp_client/CMakeLists.txt | 9 + subsys/mgmt/mcumgr/smp_client/Kconfig | 42 +++ subsys/mgmt/mcumgr/smp_client/src/client.c | 327 ++++++++++++++++++ .../mgmt/mcumgr/transport/smp_internal.h | 10 + subsys/mgmt/mcumgr/transport/src/smp.c | 43 +++ subsys/mgmt/mcumgr/transport/src/smp_bt.c | 12 + subsys/mgmt/mcumgr/transport/src/smp_shell.c | 11 + subsys/mgmt/mcumgr/transport/src/smp_uart.c | 8 + subsys/mgmt/mcumgr/transport/src/smp_udp.c | 21 +- 14 files changed, 681 insertions(+), 24 deletions(-) create mode 100644 include/zephyr/mgmt/mcumgr/smp/smp_client.h create mode 100644 subsys/mgmt/mcumgr/smp_client/CMakeLists.txt create mode 100644 subsys/mgmt/mcumgr/smp_client/Kconfig create mode 100644 subsys/mgmt/mcumgr/smp_client/src/client.c diff --git a/include/zephyr/mgmt/mcumgr/smp/smp_client.h b/include/zephyr/mgmt/mcumgr/smp/smp_client.h new file mode 100644 index 000000000000..88b2af701b09 --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/smp/smp_client.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_CLIENT_ +#define H_SMP_CLIENT_ + +#include +#include +#include +#include +#include + +/** + * @brief SMP client object + */ +struct smp_client_object { + /** Must be the first member. */ + struct k_work work; + /** FIFO for client TX queue */ + struct k_fifo tx_fifo; + /** SMP transport object */ + struct smp_transport *smpt; + /** SMP SEQ */ + uint8_t smp_seq; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize a SMP client object. + * + * @param smp_client The Client to construct. + * @param smp_type SMP transport type for discovering transport object + * + * @return 0 if successful + * @return mcumgr_err_t code on failure + */ +int smp_client_object_init(struct smp_client_object *smp_client, int smp_type); + +/** + * @brief Response callback for SMP send. + * + * @param nb net_buf for response + * @param user_data same user data that was provided as part of the request + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +typedef int (*smp_client_res_fn)(struct net_buf *nb, void *user_data); + +/** + * @brief SMP client response handler. + * + * @param nb response net_buf + * @param res_hdr Parsed SMP header + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int smp_client_single_response(struct net_buf *nb, const struct smp_hdr *res_hdr); + +/** + * @brief Allocate buffer and initialize with SMP header. + * + * @param smp_client SMP client object + * @param group SMP group id + * @param command_id SMP command id + * @param op SMP operation type + * @param version SMP MCUmgr version + * + * @return A newly-allocated buffer net_buf on success + * @return NULL on failure. + */ +struct net_buf *smp_client_buf_allocation(struct smp_client_object *smp_client, uint16_t group, + uint8_t command_id, uint8_t op, + enum smp_mcumgr_version_t version); +/** + * @brief Free a SMP client buffer. + * + * @param nb The net_buf to free. + */ +void smp_client_buf_free(struct net_buf *nb); + +/** + * @brief SMP client data send request. + * + * @param smp_client SMP client object + * @param nb net_buf packet for send + * @param cb Callback for response handler + * @param user_data user defined data pointer which will be returned back to response callback + * @param timeout_in_sec Timeout in seconds for send process. Client will retry transport + * based CONFIG_SMP_CMD_RETRY_TIME + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, + smp_client_res_fn cb, void *user_data, int timeout_in_sec); + +#ifdef __cplusplus +} +#endif + +#endif /* H_SMP_CLIENT_ */ diff --git a/include/zephyr/mgmt/mcumgr/transport/smp.h b/include/zephyr/mgmt/mcumgr/transport/smp.h index 55c9c7b0826e..d8cec6878f79 100644 --- a/include/zephyr/mgmt/mcumgr/transport/smp.h +++ b/include/zephyr/mgmt/mcumgr/transport/smp.h @@ -134,6 +134,35 @@ struct smp_transport { #endif }; +/** + * @brief SMP transport type for client registration + */ +enum smp_transport_type { + /** SMP serial */ + SMP_SERIAL_TRANSPORT = 0, + /** SMP bluetooth */ + SMP_BLUETOOTH_TRANSPORT, + /** SMP shell*/ + SMP_SHELL_TRANSPORT, + /** SMP UDP IPv4 */ + SMP_UDP_IPV4_TRANSPORT, + /** SMP UDP IPv6 */ + SMP_UDP_IPV6_TRANSPORT, + /** SMP user defined type */ + SMP_USER_DEFINED_TRANSPORT +}; + +/** + * @brief SMP Client transport structure + */ +struct smp_client_transport_entry { + sys_snode_t node; + /** Transport structure pointer */ + struct smp_transport *smpt; + /** Transport type */ + int smpt_type; +}; + /** * @brief Initializes a Zephyr SMP transport object. * @@ -162,6 +191,22 @@ void smp_rx_remove_invalid(struct smp_transport *zst, void *arg); */ void smp_rx_clear(struct smp_transport *zst); +/** + * @brief Register a Zephyr SMP transport object for client. + * + * @param entry The transport to construct. + */ +void smp_client_transport_register(struct smp_client_transport_entry *entry); + +/** + * @brief Discover a registered SMP transport client object. + * + * @param smpt_type Type of transport + * + * @return Pointer to registered object. Unknown type return NULL. + */ +struct smp_transport *smp_client_transport_get(int smpt_type); + /** * @} */ diff --git a/subsys/mgmt/mcumgr/CMakeLists.txt b/subsys/mgmt/mcumgr/CMakeLists.txt index c977160f05b0..39d4a4ca8ce0 100644 --- a/subsys/mgmt/mcumgr/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/CMakeLists.txt @@ -13,5 +13,6 @@ add_subdirectory(smp) add_subdirectory(util) add_subdirectory(grp) add_subdirectory(transport) +add_subdirectory_ifdef(CONFIG_SMP_CLIENT smp_client) zephyr_library_link_libraries(mgmt_mcumgr) diff --git a/subsys/mgmt/mcumgr/Kconfig b/subsys/mgmt/mcumgr/Kconfig index 0aa02b04437d..107ee3263e94 100644 --- a/subsys/mgmt/mcumgr/Kconfig +++ b/subsys/mgmt/mcumgr/Kconfig @@ -33,6 +33,12 @@ config MCUMGR_SMP_LEGACY_RC_BEHAVIOUR response will be empty with the new behaviour enabled, as opposed to the old behaviour where the rc field will be present in the response. +menu "SMP Client" + +rsource "smp_client/Kconfig" + +endmenu + menu "Command Handlers" rsource "grp/Kconfig" diff --git a/subsys/mgmt/mcumgr/smp/src/smp.c b/subsys/mgmt/mcumgr/smp/src/smp.c index 42bf633f09d5..6de806d7e6d7 100644 --- a/subsys/mgmt/mcumgr/smp/src/smp.c +++ b/subsys/mgmt/mcumgr/smp/src/smp.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -50,12 +51,9 @@ static int smp_translate_error_code(uint16_t group, uint16_t ret) static void cbor_nb_reader_init(struct cbor_nb_reader *cnr, struct net_buf *nb) { - /* Skip the smp_hdr */ - void *new_ptr = net_buf_pull(nb, sizeof(struct smp_hdr)); - cnr->nb = nb; - zcbor_new_decode_state(cnr->zs, ARRAY_SIZE(cnr->zs), new_ptr, - cnr->nb->len, 1); + zcbor_new_decode_state(cnr->zs, ARRAY_SIZE(cnr->zs), nb->data, + nb->len, 1); } static void cbor_nb_writer_init(struct cbor_nb_writer *cnw, struct net_buf *nb) @@ -391,37 +389,54 @@ int smp_process_request_packet(struct smp_streamer *streamer, void *vreq) if (rc != 0) { rc = MGMT_ERR_ECORRUPT; break; - } else { - valid_hdr = true; } + + valid_hdr = true; + /* Skip the smp_hdr */ + net_buf_pull(req, sizeof(struct smp_hdr)); /* Does buffer contain whole message? */ - if (req->len < (req_hdr.nh_len + MGMT_HDR_SIZE)) { + if (req->len < req_hdr.nh_len) { rc = MGMT_ERR_ECORRUPT; break; } - rsp = smp_alloc_rsp(req, streamer->smpt); - if (rsp == NULL) { - rc = MGMT_ERR_ENOMEM; - break; - } + if (req_hdr.nh_op == MGMT_OP_READ || req_hdr.nh_op == MGMT_OP_WRITE) { + rsp = smp_alloc_rsp(req, streamer->smpt); + if (rsp == NULL) { + rc = MGMT_ERR_ENOMEM; + break; + } - cbor_nb_reader_init(streamer->reader, req); - cbor_nb_writer_init(streamer->writer, rsp); + cbor_nb_reader_init(streamer->reader, req); + 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); - if (rc != 0) { - break; + /* Process the request payload and build the response. */ + rc = smp_handle_single_req(streamer, &req_hdr, &handler_found, &rsn); + if (rc != 0) { + break; + } + + /* Send the response. */ + rc = streamer->smpt->functions.output(rsp); + rsp = NULL; + } else if (IS_ENABLED(CONFIG_SMP_CLIENT) && (req_hdr.nh_op == MGMT_OP_READ_RSP || + req_hdr.nh_op == MGMT_OP_WRITE_RSP)) { + rc = smp_client_single_response(req, &req_hdr); + + if (rc == MGMT_ERR_EOK) { + handler_found = true; + } else { + /* Server shuold not send error response for response */ + valid_hdr = false; + } + + } else { + rc = MGMT_ERR_ENOTSUP; } - /* Send the response. */ - rc = streamer->smpt->functions.output(rsp); - rsp = NULL; if (rc != 0) { break; } - /* Trim processed request to free up space for subsequent responses. */ net_buf_pull(req, req_hdr.nh_len); diff --git a/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt b/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt new file mode 100644 index 000000000000..061d28b30638 --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# Protocol API is only exposed to MCUmgr internals. + +zephyr_library(mgmt_mcumgr_client_protocol) +zephyr_library_sources(src/client.c) diff --git a/subsys/mgmt/mcumgr/smp_client/Kconfig b/subsys/mgmt/mcumgr/smp_client/Kconfig new file mode 100644 index 000000000000..b946efe1b324 --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/Kconfig @@ -0,0 +1,42 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to smp_client subdirectory of MCUmgr +# subsystem and provides Kconfig options to control aspects of +# Simple Management Protocol Client (SMP) processing source code provided +# under the subdirectory. + +config SMP_CLIENT + bool "SMP Client support" + help + This will enable SMP Request generation and response handling. + +if SMP_CLIENT || ZTEST + +config SMP_CMD_DEFAULT_LIFE_TIME + int "SMP command lifetime in seconds" + range 2 30 + default 5 + help + This define lifetime for SMP client send request. This configure is used if a request + with a timeout of 0 is used. + +config SMP_CMD_RETRY_TIME + int "SMP command re-send period in ms" + range 100 1000 + default 500 + help + The time (in ms) which the SMP client will wait for a response before re-sending + a command. + +config SMP_CLIENT_CMD_MAX + int "SMP client max buffer count" + default 4 + help + Define how many active requests that the client can handle + +module = MCUMGR_SMP_CLIENT +module-str = mcumgr_smp_client +source "subsys/logging/Kconfig.template.log_config" + +endif # SMP_CLIENT diff --git a/subsys/mgmt/mcumgr/smp_client/src/client.c b/subsys/mgmt/mcumgr/smp_client/src/client.c new file mode 100644 index 000000000000..cca1738f117e --- /dev/null +++ b/subsys/mgmt/mcumgr/smp_client/src/client.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** SMP - Simple Management Client Protocol. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mcumgr_smp_client, CONFIG_MCUMGR_SMP_CLIENT_LOG_LEVEL); + +struct smp_client_cmd_req { + sys_snode_t node; + struct net_buf *nb; + struct smp_client_object *smp_client; + void *user_data; + smp_client_res_fn cb; + int64_t timestamp; + int retry_cnt; +}; + +struct smp_client_data_base { + struct k_work_delayable work_delay; + sys_slist_t cmd_free_list; + sys_slist_t cmd_list; +}; + +static struct smp_client_cmd_req smp_cmd_req_bufs[CONFIG_SMP_CLIENT_CMD_MAX]; +static struct smp_client_data_base smp_client_data; + +static void smp_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr); +static void smp_client_cmd_req_free(struct smp_client_cmd_req *cmd_req); + +/** + * Send all SMP client request packets. + */ +static void smp_client_handle_reqs(struct k_work *work) +{ + struct smp_client_object *smp_client; + struct smp_transport *smpt; + struct net_buf *nb; + + smp_client = (void *)work; + smpt = smp_client->smpt; + + while ((nb = net_buf_get(&smp_client->tx_fifo, K_NO_WAIT)) != NULL) { + smpt->functions.output(nb); + } +} + +static void smp_header_init(struct smp_hdr *header, uint16_t group, uint8_t id, uint8_t op, + uint16_t payload_len, uint8_t seq, enum smp_mcumgr_version_t version) +{ + /* Pre config SMP header structure */ + memset(header, 0, sizeof(struct smp_hdr)); + header->nh_version = version; + header->nh_op = op; + header->nh_len = sys_cpu_to_be16(payload_len); + header->nh_group = sys_cpu_to_be16(group); + header->nh_id = id; + header->nh_seq = seq; +} + +static void smp_client_transport_work_fn(struct k_work *work) +{ + struct smp_client_cmd_req *entry, *tmp; + smp_client_res_fn cb; + void *user_data; + int backoff_ms = CONFIG_SMP_CMD_RETRY_TIME; + int64_t time_stamp_cmp; + int64_t time_stamp_ref; + int64_t time_stamp_delta; + + ARG_UNUSED(work); + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* No more packet for Transport */ + return; + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&smp_client_data.cmd_list, entry, tmp, node) { + time_stamp_ref = entry->timestamp; + /* Check Time delta and get current time to reference */ + time_stamp_delta = k_uptime_delta(&time_stamp_ref); + + if (time_stamp_delta < 0) { + time_stamp_cmp = entry->timestamp - time_stamp_ref; + if (time_stamp_cmp < CONFIG_SMP_CMD_RETRY_TIME && + time_stamp_cmp < backoff_ms) { + /* Update new shorter shedule */ + backoff_ms = time_stamp_cmp; + } + continue; + } else if (entry->retry_cnt) { + /* Increment reference for re-transmission */ + entry->nb = net_buf_ref(entry->nb); + entry->retry_cnt--; + entry->timestamp = time_stamp_ref + CONFIG_SMP_CMD_RETRY_TIME; + net_buf_put(&entry->smp_client->tx_fifo, entry->nb); + smp_tx_req(&entry->smp_client->work); + continue; + } + + cb = entry->cb; + user_data = entry->user_data; + smp_client_cmd_req_free(entry); + if (cb) { + cb(NULL, user_data); + } + } + + if (!sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* Re-schedule new timeout to next */ + k_work_reschedule(&smp_client_data.work_delay, K_MSEC(backoff_ms)); + } +} + +static int smp_client_init(void) +{ + k_work_init_delayable(&smp_client_data.work_delay, smp_client_transport_work_fn); + sys_slist_init(&smp_client_data.cmd_list); + sys_slist_init(&smp_client_data.cmd_free_list); + for (int i = 0; i < CONFIG_SMP_CLIENT_CMD_MAX; i++) { + sys_slist_append(&smp_client_data.cmd_free_list, &smp_cmd_req_bufs[i].node); + } + return 0; +} + +static struct smp_client_cmd_req *smp_client_cmd_req_allocate(void) +{ + sys_snode_t *cmd_node; + struct smp_client_cmd_req *req; + + cmd_node = sys_slist_get(&smp_client_data.cmd_free_list); + if (!cmd_node) { + return NULL; + } + + req = SYS_SLIST_CONTAINER(cmd_node, req, node); + + return req; +} + +static void smp_cmd_add_to_list(struct smp_client_cmd_req *cmd_req) +{ + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* Enable timer */ + k_work_reschedule(&smp_client_data.work_delay, K_MSEC(CONFIG_SMP_CMD_RETRY_TIME)); + } + sys_slist_append(&smp_client_data.cmd_list, &cmd_req->node); +} + +static void smp_client_cmd_req_free(struct smp_client_cmd_req *cmd_req) +{ + smp_client_buf_free(cmd_req->nb); + cmd_req->nb = NULL; + sys_slist_find_and_remove(&smp_client_data.cmd_list, &cmd_req->node); + /* Add to free list */ + sys_slist_append(&smp_client_data.cmd_free_list, &cmd_req->node); + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + /* cancel delay */ + k_work_cancel_delayable(&smp_client_data.work_delay); + } +} + +static struct smp_client_cmd_req *smp_client_response_discover(const struct smp_hdr *res_hdr) +{ + struct smp_hdr smp_header; + enum mcumgr_op_t response; + struct smp_client_cmd_req *cmd_req; + + if (sys_slist_is_empty(&smp_client_data.cmd_list)) { + return NULL; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&smp_client_data.cmd_list, cmd_req, node) { + smp_read_hdr(cmd_req->nb, &smp_header); + if (smp_header.nh_op == MGMT_OP_READ) { + response = MGMT_OP_READ_RSP; + } else { + response = MGMT_OP_WRITE_RSP; + } + + if (smp_header.nh_seq != res_hdr->nh_seq) { + continue; + } else if (res_hdr->nh_op != response) { + continue; + } + + return cmd_req; + } + return NULL; +} + +int smp_client_object_init(struct smp_client_object *smp_client, int smp_type) +{ + smp_client->smpt = smp_client_transport_get(smp_type); + if (!smp_client->smpt) { + return MGMT_ERR_EINVAL; + } + + /* Init TX FIFO */ + k_work_init(&smp_client->work, smp_client_handle_reqs); + k_fifo_init(&smp_client->tx_fifo); + + return MGMT_ERR_EOK; +} + +int smp_client_single_response(struct net_buf *nb, const struct smp_hdr *res_hdr) +{ + struct smp_client_cmd_req *cmd_req; + smp_client_res_fn cb; + void *user_data; + + /* Discover request for incoming response */ + cmd_req = smp_client_response_discover(res_hdr); + LOG_DBG("Response Header len %d, flags %d OP: %d group %d id %d seq %d", res_hdr->nh_len, + res_hdr->nh_flags, res_hdr->nh_op, res_hdr->nh_group, res_hdr->nh_id, + res_hdr->nh_seq); + + if (cmd_req) { + cb = cmd_req->cb; + user_data = cmd_req->user_data; + smp_client_cmd_req_free(cmd_req); + if (cb) { + cb(nb, user_data); + return MGMT_ERR_EOK; + } + } + + return MGMT_ERR_ENOENT; +} + +struct net_buf *smp_client_buf_allocation(struct smp_client_object *smp_client, uint16_t group, + uint8_t command_id, uint8_t op, + enum smp_mcumgr_version_t version) +{ + struct net_buf *nb; + struct smp_hdr smp_header; + + nb = smp_packet_alloc(); + + if (nb) { + /* Write SMP header with payload length 0 */ + smp_header_init(&smp_header, group, command_id, op, 0, smp_client->smp_seq++, + version); + memcpy(nb->data, &smp_header, sizeof(smp_header)); + nb->len = sizeof(smp_header); + } + return nb; +} + +void smp_client_buf_free(struct net_buf *nb) +{ + smp_packet_free(nb); +} + +static void smp_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + +int smp_client_send_cmd(struct smp_client_object *smp_client, struct net_buf *nb, + smp_client_res_fn cb, void *user_data, int timeout_in_sec) +{ + struct smp_hdr smp_header; + struct smp_client_cmd_req *cmd_req; + + if (timeout_in_sec > 30) { + LOG_ERR("Command timeout can't be over 30 seconds"); + return MGMT_ERR_EINVAL; + } + + if (timeout_in_sec == 0) { + timeout_in_sec = CONFIG_SMP_CMD_DEFAULT_LIFE_TIME; + } + + smp_read_hdr(nb, &smp_header); + if (nb->len < sizeof(smp_header)) { + return MGMT_ERR_EINVAL; + } + /* Update Length */ + smp_header.nh_len = sys_cpu_to_be16(nb->len - sizeof(smp_header)); + smp_header.nh_group = sys_cpu_to_be16(smp_header.nh_group), + memcpy(nb->data, &smp_header, sizeof(smp_header)); + + cmd_req = smp_client_cmd_req_allocate(); + if (!cmd_req) { + return MGMT_ERR_ENOMEM; + } + + LOG_DBG("Command send Header flags %d OP: %d group %d id %d seq %d", smp_header.nh_flags, + smp_header.nh_op, sys_be16_to_cpu(smp_header.nh_group), smp_header.nh_id, + smp_header.nh_seq); + cmd_req->nb = nb; + cmd_req->cb = cb; + cmd_req->smp_client = smp_client; + cmd_req->user_data = user_data; + cmd_req->retry_cnt = timeout_in_sec * (1000 / CONFIG_SMP_CMD_RETRY_TIME); + cmd_req->timestamp = k_uptime_get() + CONFIG_SMP_CMD_RETRY_TIME; + /* Increment reference for re-transmission and read smp header */ + nb = net_buf_ref(nb); + smp_cmd_add_to_list(cmd_req); + net_buf_put(&smp_client->tx_fifo, nb); + smp_tx_req(&smp_client->work); + return MGMT_ERR_EOK; +} + +SYS_INIT(smp_client_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h b/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h index 828a15ffb162..898f2134c26c 100644 --- a/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h +++ b/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h @@ -9,6 +9,7 @@ #define MGMT_MCUMGR_SMP_INTERNAL_H_ #include +#include #include #include @@ -47,6 +48,15 @@ struct zephyr_smp_transport; */ void smp_rx_req(struct smp_transport *smtp, struct net_buf *nb); +#ifdef CONFIG_SMP_CLIENT +/** + * @brief Trig SMP client request packet for transmission. + * + * @param work The transport to use to send the corresponding response(s). + */ +void smp_tx_req(struct k_work *work); +#endif + __deprecated static inline void zephyr_smp_rx_req(struct zephyr_smp_transport *smpt, struct net_buf *nb) { diff --git a/subsys/mgmt/mcumgr/transport/src/smp.c b/subsys/mgmt/mcumgr/transport/src/smp.c index 1052b82cd04f..0f23bd4c44db 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp.c @@ -31,6 +31,10 @@ K_THREAD_STACK_DEFINE(smp_work_queue_stack, CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_ST static struct k_work_q smp_work_queue; +#ifdef CONFIG_SMP_CLIENT +static sys_slist_t smp_transport_clients; +#endif + static const struct k_work_queue_config smp_work_queue_config = { .name = "mcumgr smp" }; @@ -131,6 +135,7 @@ smp_handle_reqs(struct k_work *work) smpt = (void *)work; + /* Read and handle received messages */ while ((nb = net_buf_get(&smpt->fifo, K_NO_WAIT)) != NULL) { smp_process_packet(smpt, nb); } @@ -155,6 +160,33 @@ int smp_transport_init(struct smp_transport *smpt) return 0; } +#ifdef CONFIG_SMP_CLIENT +struct smp_transport *smp_client_transport_get(int smpt_type) +{ + struct smp_client_transport_entry *entry; + + SYS_SLIST_FOR_EACH_CONTAINER(&smp_transport_clients, entry, node) { + if (entry->smpt_type == smpt_type) { + return entry->smpt; + } + } + + return NULL; +} + +void smp_client_transport_register(struct smp_client_transport_entry *entry) +{ + if (smp_client_transport_get(entry->smpt_type)) { + /* Already in list */ + return; + } + + sys_slist_append(&smp_transport_clients, &entry->node); + +} + +#endif /* CONFIG_SMP_CLIENT */ + /** * @brief Enqueues an incoming SMP request packet for processing. * @@ -171,6 +203,13 @@ smp_rx_req(struct smp_transport *smpt, struct net_buf *nb) k_work_submit_to_queue(&smp_work_queue, &smpt->work); } +#ifdef CONFIG_SMP_CLIENT +void smp_tx_req(struct k_work *work) +{ + k_work_submit_to_queue(&smp_work_queue, work); +} +#endif + void smp_rx_remove_invalid(struct smp_transport *zst, void *arg) { struct net_buf *nb; @@ -227,6 +266,10 @@ void smp_rx_clear(struct smp_transport *zst) static int smp_init(void) { +#ifdef CONFIG_SMP_CLIENT + sys_slist_init(&smp_transport_clients); +#endif + k_work_queue_init(&smp_work_queue); k_work_queue_start(&smp_work_queue, smp_work_queue_stack, diff --git a/subsys/mgmt/mcumgr/transport/src/smp_bt.c b/subsys/mgmt/mcumgr/transport/src/smp_bt.c index 6cd2d53d9ffd..87706fd8f47f 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_bt.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_bt.c @@ -109,6 +109,10 @@ BT_CONN_CB_DEFINE(mcumgr_bt_callbacks) = { .disconnected = disconnected, }; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif + /* Helper function that allocates conn_param_data for a conn. */ static struct conn_param_data *conn_param_data_alloc(struct bt_conn *conn) { @@ -665,6 +669,14 @@ static void smp_bt_setup(void) rc = smp_bt_register(); } +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + smp_client_transport.smpt = &smp_bt_transport; + smp_client_transport.smpt_type = SMP_BLUETOOTH_TRANSPORT; + rc = smp_client_transport_register(&smp_client_transport); + } +#endif + if (rc != 0) { LOG_ERR("Bluetooth SMP transport register failed (err %d)", rc); } diff --git a/subsys/mgmt/mcumgr/transport/src/smp_shell.c b/subsys/mgmt/mcumgr/transport/src/smp_shell.c index ac196c100854..c30874070bac 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_shell.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_shell.c @@ -39,6 +39,10 @@ static struct smp_transport smp_shell_transport; static struct mcumgr_serial_rx_ctxt smp_shell_rx_ctxt; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif + /** SMP mcumgr frame fragments. */ enum smp_shell_esc_mcumgr { ESC_MCUMGR_PKT_1, @@ -241,6 +245,13 @@ int smp_shell_init(void) smp_shell_transport.functions.get_mtu = smp_shell_get_mtu; rc = smp_transport_init(&smp_shell_transport); +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + smp_client_transport.smpt = &CONFIG_SMP_CLIENT; + smp_client_transport.smpt_type = SMP_SHELL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); + } +#endif return rc; } diff --git a/subsys/mgmt/mcumgr/transport/src/smp_uart.c b/subsys/mgmt/mcumgr/transport/src/smp_uart.c index 9c3dade2f8e3..643caf6eb48a 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_uart.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_uart.c @@ -31,6 +31,9 @@ K_WORK_DEFINE(smp_uart_work, smp_uart_process_rx_queue); static struct mcumgr_serial_rx_ctxt smp_uart_rx_ctxt; static struct smp_transport smp_uart_transport; +#ifdef CONFIG_SMP_CLIENT +static struct smp_client_transport_entry smp_client_transport; +#endif /** * Processes a single line (fragment) coming from the mcumgr UART driver. @@ -101,6 +104,11 @@ static int smp_uart_init(void) if (rc == 0) { uart_mcumgr_register(smp_uart_rx_frag); +#ifdef CONFIG_SMP_CLIENT + smp_client_transport.smpt = &smp_uart_transport; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); +#endif } return rc; diff --git a/subsys/mgmt/mcumgr/transport/src/smp_udp.c b/subsys/mgmt/mcumgr/transport/src/smp_udp.c index e772cf499de7..6f8f9a137353 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_udp.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_udp.c @@ -66,9 +66,15 @@ struct config { struct configs { #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV4 struct config ipv4; +#ifdef CONFIG_SMP_CLIENT + struct smp_client_transport_entry ipv4_transport; +#endif #endif #ifdef CONFIG_MCUMGR_TRANSPORT_UDP_IPV6 struct config ipv6; +#ifdef CONFIG_SMP_CLIENT + struct smp_client_transport_entry ipv6_transport; +#endif #endif }; @@ -381,7 +387,13 @@ static void smp_udp_start(void) configs.ipv4.smp_transport.functions.ud_copy = smp_udp_ud_copy; rc = smp_transport_init(&configs.ipv4.smp_transport); - +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + configs.ipv4_transport.smpt = &configs.ipv4.smp_transport; + configs.ipv4_transport.smpt_type = SMP_UDP_IPV4_TRANSPORT; + smp_client_transport_register(&configs.ipv4_transport); + } +#endif if (rc) { LOG_ERR("Failed to register IPv4 UDP MCUmgr SMP transport: %d", rc); } @@ -394,6 +406,13 @@ static void smp_udp_start(void) configs.ipv6.smp_transport.functions.ud_copy = smp_udp_ud_copy; rc = smp_transport_init(&configs.ipv6.smp_transport); +#ifdef CONFIG_SMP_CLIENT + if (rc == 0) { + configs.ipv6_transport.smpt = &configs.ipv6.smp_transport; + configs.ipv6_transport.smpt_type = SMP_UDP_IPV6_TRANSPORT; + smp_client_transport_register(&configs.ipv6_transport); + } +#endif if (rc) { LOG_ERR("Failed to register IPv6 UDP MCUmgr SMP transport: %d", rc); From d77a657526bff5a0e75ae2f535a3400ab5fdccec Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Tue, 30 May 2023 12:06:03 +0300 Subject: [PATCH 1886/2042] mgmt: smp: MCUmgr Client support MCUmgr client basic implementation for support Image and OS grpup commands. Image Group: * Image state read/write * Image Upload secondary slot * Image Erase secondary slot OS group: * Reset * Echo service, disabled by default Opeartion's are blocked call and cant't call inside worker queue. IMG and OS need to be SMP client object for transport. Signed-off-by: Juha Heiskanen --- .../mcumgr/grp/img_mgmt/img_mgmt_client.h | 193 ++++++ .../mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h | 61 ++ subsys/mgmt/mcumgr/grp/CMakeLists.txt | 14 +- subsys/mgmt/mcumgr/grp/Kconfig | 4 + .../mcumgr/grp/img_mgmt_client/CMakeLists.txt | 15 + .../mgmt/mcumgr/grp/img_mgmt_client/Kconfig | 39 ++ .../grp/img_mgmt_client/src/img_mgmt_client.c | 606 ++++++++++++++++++ .../mcumgr/grp/os_mgmt_client/CMakeLists.txt | 11 + subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig | 35 + .../grp/os_mgmt_client/src/os_mgmt_client.c | 168 +++++ 10 files changed, 1140 insertions(+), 6 deletions(-) create mode 100644 include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h create mode 100644 include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h create mode 100644 subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt create mode 100644 subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig create mode 100644 subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c create mode 100644 subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt create mode 100644 subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig create mode 100644 subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h new file mode 100644 index 000000000000..6ee12fb5a612 --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_IMG_MGMT_CLIENT_ +#define H_IMG_MGMT_CLIENT_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Image list flags. + */ +struct mcumgr_image_list_flags { + /** Bootable image */ + bool bootable: 1; + /** Pending update state */ + bool pending: 1; + /** Confirmed image */ + bool confirmed: 1; + /** Active image */ + bool active: 1; + /** Permanent image state */ + bool permanent: 1; +}; + +/** + * @brief Image list data. + */ +struct mcumgr_image_data { + /** Image slot num */ + uint32_t slot_num; + /** Image number */ + uint32_t img_num; + /** Image SHA256 checksum */ + char hash[IMG_MGMT_HASH_LEN]; + /** Image Version */ + char version[IMG_MGMT_VER_MAX_STR_LEN + 1]; + /** Image Flags */ + struct mcumgr_image_list_flags flags; +}; + +/** + * @brief MCUmgr Image list response. + */ +struct mcumgr_image_state { + /** Status */ + enum mcumgr_err_t status; + /** Length of image_list */ + int image_list_length; + /** Image list pointer */ + struct mcumgr_image_data *image_list; +}; + +/** + * @brief MCUmgr Image upload response. + */ +struct mcumgr_image_upload { + /** Status */ + enum mcumgr_err_t status; + /** Reported image offset */ + size_t image_upload_offset; +}; + +/** + * @brief IMG mgmt client upload structure + * + * Structure is used internally by the client + */ +struct img_gr_upload { + /** Image 256-bit hash */ + char sha256[IMG_MGMT_HASH_LEN]; + /** True when Hash is configured, false when not */ + bool hash_initialized; + /** Image size */ + size_t image_size; + /** Image upload offset state */ + size_t offset; + /** Worst case init upload message size */ + size_t upload_header_size; + /** Image slot num */ + uint32_t image_num; +}; + +/** + * @brief IMG mgmt client object. + */ +struct img_mgmt_client { + /** SMP client object */ + struct smp_client_object *smp_client; + /** Image Upload state data for client internal use */ + struct img_gr_upload upload; + /** Client image list buffer size */ + int image_list_length; + /** Image list buffer */ + struct mcumgr_image_data *image_list; + /** Command status */ + int status; +}; + +/** + * @brief Inilialize image group client. + * + * Function initializes image group client for given SMP client using supplied image data. + * + * @param client IMG mgmt client object + * @param smp_client SMP client object + * @param image_list_size Length of image_list buffer. + * @param image_list Image list buffer pointer. + * + */ +void img_mgmt_client_init(struct img_mgmt_client *client, struct smp_client_object *smp_client, + int image_list_size, struct mcumgr_image_data *image_list); + +/** + * @brief Initialize image upload. + * + * @param client IMG mgmt client object + * @param image_size Size of image in bytes. + * @param image_num Image slot Num. + * @param image_hash Pointer to HASH for image must be SHA256 hash of entire upload + * if present (32 bytes). Use NULL when HASH from image is not available. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size, + uint32_t image_num, const char *image_hash); + +/** + * @brief Upload part of image. + * + * @param client IMG mgmt client object + * @param data Pointer to data. + * @param length Length of data + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length, + struct mcumgr_image_upload *res_buf); + +/** + * @brief Write image state. + * + * @param client IMG mgmt client object + * @param hash Pointer to Hash (Needed for test). + * @param confirm Set false for test and true for confirmation. + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ + +int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm, + struct mcumgr_image_state *res_buf); + +/** + * @brief Read image state. + * + * @param client IMG mgmt client object + * @param res_buf Pointer for command response structure. + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf); + +/** + * @brief Erase selected Image Slot + * + * @param client IMG mgmt client object + * @param slot Slot number + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ + +int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot); + +#ifdef __cplusplus +} +#endif + +#endif /* H_IMG_MGMT_CLIENT_ */ 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 new file mode 100644 index 000000000000..12e8abde246c --- /dev/null +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_OS_MGMT_CLIENT_ +#define H_OS_MGMT_CLIENT_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief OS mgmt client object + */ +struct os_mgmt_client { + /** SMP client object */ + struct smp_client_object *smp_client; + /** Command status */ + int status; +}; + +/** + * @brief Initialize OS management client. + * + * @param client OS mgmt client object + * @param smp_client SMP client object + * + */ +void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client); + +/** + * @brief Send SMP message for Echo command. + * + * @param client OS mgmt client object + * @param echo_string 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); + +/** + * @brief Send SMP Reset command. + * + * @param client OS mgmt client object + * + * @return 0 on success. + * @return @ref mcumgr_err_t code on failure. + */ +int os_mgmt_client_reset(struct os_mgmt_client *client); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_MGMT_CLIENT_ */ diff --git a/subsys/mgmt/mcumgr/grp/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/CMakeLists.txt index 56df0fb51766..b77fcddf25e0 100644 --- a/subsys/mgmt/mcumgr/grp/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/grp/CMakeLists.txt @@ -5,9 +5,11 @@ # SPDX-License-Identifier: Apache-2.0 # -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_FS fs_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG img_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS os_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_STAT stat_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SHELL shell_mgmt) -add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_ZBASIC zephyr_basic) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_FS fs_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG img_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_IMG_CLIENT img_mgmt_client) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS os_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS_CLIENT os_mgmt_client) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_STAT stat_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SHELL shell_mgmt) +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_ZBASIC zephyr_basic) diff --git a/subsys/mgmt/mcumgr/grp/Kconfig b/subsys/mgmt/mcumgr/grp/Kconfig index b0a018ca4d3e..6005d57a8504 100644 --- a/subsys/mgmt/mcumgr/grp/Kconfig +++ b/subsys/mgmt/mcumgr/grp/Kconfig @@ -6,8 +6,12 @@ rsource "fs_mgmt/Kconfig" rsource "img_mgmt/Kconfig" +rsource "img_mgmt_client/Kconfig" + rsource "os_mgmt/Kconfig" +rsource "os_mgmt_client/Kconfig" + rsource "shell_mgmt/Kconfig" rsource "stat_mgmt/Kconfig" diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt new file mode 100644 index 000000000000..693891896d8e --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Image management client group public API is exported by MCUmgr interface API, +# when Image Management client is enabled. + +zephyr_library(mcumgr_grp_img_client) +zephyr_library_sources( + src/img_mgmt_client.c +) + +zephyr_library_include_directories(include) diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig b/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig new file mode 100644 index 000000000000..dbdb4c4eb603 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/Kconfig @@ -0,0 +1,39 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to Application Image management group of +# of MCUmgr client subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_IMG_CLIENT_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. + +menuconfig MCUMGR_GRP_IMG_CLIENT + bool "MCUmgr client handlers for image management" + depends on SMP_CLIENT + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_3 + help + Enables MCUmgr client handlers for image management. + +if MCUMGR_GRP_IMG_CLIENT + +config MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE + int "MCUmgr upload data alignment size" + default 4 + help + Change default value when platform needs different data alignment. + +config MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT + int "MCUmgr reset or upload command timeout" + default 15 + help + Change default value when platform needs a different time. + +module = MCUMGR_GRP_IMG_CLIENT +module-str = mcumgr_grp_img_client +source "subsys/logging/Kconfig.template.log_config" + +endif 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 new file mode 100644 index 000000000000..2bb9743160db --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/img_mgmt_client/src/img_mgmt_client.c @@ -0,0 +1,606 @@ +/* + * 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 +#include + +#include +LOG_MODULE_REGISTER(mcumgr_grp_img_client, CONFIG_MCUMGR_GRP_IMG_CLIENT_LOG_LEVEL); + +#define MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE 128 + +/* Pointer for active Client */ +static struct img_mgmt_client *active_client; +/* Image State read or set response pointer */ +static struct mcumgr_image_state *image_info; +/* Image upload response pointer */ +static struct mcumgr_image_upload *image_upload_buf; + +static K_SEM_DEFINE(mcumgr_img_client_grp_sem, 0, 1); +static K_MUTEX_DEFINE(mcumgr_img_client_grp_mutex); + +static const char smp_images_str[] = "images"; +#define IMAGES_STR_LEN (sizeof(smp_images_str) - 1) + +static int image_state_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + struct zcbor_string value = {0}; + int buf_len, rc; + uint32_t img_num, slot_num; + struct zcbor_string hash, version; + bool bootable, pending, confirmed, active, permanent, ok; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + /* Mandatory */ + ZCBOR_MAP_DECODE_KEY_DECODER("version", zcbor_tstr_decode, &version), + ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash), + ZCBOR_MAP_DECODE_KEY_DECODER("slot", zcbor_uint32_decode, &slot_num), + /* Optional */ + ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num), + ZCBOR_MAP_DECODE_KEY_DECODER("bootable", zcbor_bool_decode, &bootable), + ZCBOR_MAP_DECODE_KEY_DECODER("pending", zcbor_bool_decode, &pending), + ZCBOR_MAP_DECODE_KEY_DECODER("confirmed", zcbor_bool_decode, &confirmed), + ZCBOR_MAP_DECODE_KEY_DECODER("active", zcbor_bool_decode, &active), + ZCBOR_MAP_DECODE_KEY_DECODER("permanent", zcbor_bool_decode, &permanent) + }; + + buf_len = active_client->image_list_length; + + if (!nb) { + image_info->status = MGMT_ERR_ETIMEOUT; + goto out; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + ok = zcbor_map_start_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + + ok = zcbor_tstr_decode(zsd, &value); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + if (value.len != IMAGES_STR_LEN || memcmp(value.value, smp_images_str, IMAGES_STR_LEN)) { + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + + ok = zcbor_list_start_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + goto out; + } + + rc = 0; + /* Parse Image map info to configured buffer */ + while (rc == 0) { + decoded = 0; + zcbor_map_decode_bulk_reset(list_res_decode, ARRAY_SIZE(list_res_decode)); + /* Init buffer values */ + active = false; + bootable = false; + confirmed = false; + pending = false; + permanent = false; + img_num = 0; + slot_num = UINT32_MAX; + hash.len = 0; + version.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), + &decoded); + if (rc) { + if (image_info->image_list_length) { + /* No more map */ + break; + } + LOG_ERR("Corrupted Image data %d", rc); + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + /* Check that mandatory parameters have decoded */ + if (hash.len != IMG_MGMT_HASH_LEN || !version.len || + !zcbor_map_decode_bulk_key_found(list_res_decode, ARRAY_SIZE(list_res_decode), + "slot")) { + LOG_ERR("Missing mandatory parametrs"); + image_info->status = MGMT_ERR_EINVAL; + goto out; + } + /* Store parsed values */ + if (buf_len) { + image_info->image_list[image_info->image_list_length].img_num = img_num; + image_info->image_list[image_info->image_list_length].slot_num = slot_num; + memcpy(image_info->image_list[image_info->image_list_length].hash, + hash.value, IMG_MGMT_HASH_LEN); + if (version.len > IMG_MGMT_VER_MAX_STR_LEN) { + LOG_WRN("Version truncated len %d -> %d", version.len, + IMG_MGMT_VER_MAX_STR_LEN); + version.len = IMG_MGMT_VER_MAX_STR_LEN; + } + memcpy(image_info->image_list[image_info->image_list_length].version, + version.value, version.len); + image_info->image_list[image_info->image_list_length].version[version.len] = + '\0'; + /* Set Image flags */ + image_info->image_list[image_info->image_list_length].flags.bootable = + bootable; + image_info->image_list[image_info->image_list_length].flags.pending = + pending; + image_info->image_list[image_info->image_list_length].flags.confirmed = + confirmed; + image_info->image_list[image_info->image_list_length].flags.active = active; + image_info->image_list[image_info->image_list_length].flags.permanent = + permanent; + /* Update valid image count */ + image_info->image_list_length++; + buf_len--; + } else { + LOG_INF("User configured image list buffer size %d can't store all info", + active_client->image_list_length); + } + } + + ok = zcbor_list_end_decode(zsd); + if (!ok) { + image_info->status = MGMT_ERR_ECORRUPT; + } else { + + image_info->status = MGMT_ERR_EOK; + } + +out: + if (image_info->status != MGMT_ERR_EOK) { + image_info->image_list_length = 0; + } + rc = image_info->status; + k_sem_give(user_data); + return rc; +} + +static int image_upload_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + int rc; + int32_t res_rc = MGMT_ERR_EOK; + + struct zcbor_map_decode_key_val upload_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, + &image_upload_buf->image_upload_offset), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &res_rc)}; + + if (!nb) { + image_upload_buf->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + 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) { + image_upload_buf->status = MGMT_ERR_EINVAL; + goto end; + } + image_upload_buf->status = res_rc; + + active_client->upload.offset = image_upload_buf->image_upload_offset; +end: + /* Set status for Upload request handler */ + rc = image_upload_buf->status; + k_sem_give(user_data); + return rc; +} + +static int erase_res_fn(struct net_buf *nb, void *user_data) +{ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + int rc, status = MGMT_ERR_EOK; + + struct zcbor_map_decode_key_val upload_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &status) + }; + + if (!nb) { + active_client->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); + if (rc) { + LOG_ERR("Erase fail %d", rc); + active_client->status = MGMT_ERR_EINVAL; + goto end; + } + active_client->status = status; +end: + rc = active_client->status; + k_sem_give(user_data); + return rc; +} + +static size_t upload_message_header_size(struct img_gr_upload *upload_state) +{ + bool ok; + size_t cbor_length; + int map_count; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + uint8_t temp_buf[MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE]; + uint8_t temp_data; + + /* Calculation of message header with data length of 1 */ + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), temp_buf, MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE, + 0); + if (upload_state->hash_initialized) { + map_count = 12; + } else { + map_count = 10; + } + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, upload_state->image_num) && zcbor_tstr_put_lit(zse, "data") && + zcbor_bstr_encode_ptr(zse, &temp_data, 1) && zcbor_tstr_put_lit(zse, "len") && + zcbor_size_put(zse, upload_state->image_size) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, upload_state->offset); + + /* Write hash when it defined and offset is 0 */ + if (ok && upload_state->hash_initialized) { + ok = zcbor_tstr_put_lit(zse, "sha") && + zcbor_bstr_encode_ptr(zse, upload_state->sha256, IMG_MGMT_HASH_LEN); + } + + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + LOG_ERR("Failed to encode Image Upload packet"); + return 0; + } + cbor_length = zse->payload - temp_buf; + /* Return Message header length */ + return cbor_length + (CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE - 1); +} + +void img_mgmt_client_init(struct img_mgmt_client *client, struct smp_client_object *smp_client, + int image_list_size, struct mcumgr_image_data *image_list) +{ + client->smp_client = smp_client; + client->image_list_length = image_list_size; + client->image_list = image_list; +} + +int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size, + uint32_t image_num, const char *image_hash) +{ + int rc; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + client->upload.image_size = image_size; + client->upload.offset = 0; + client->upload.image_num = image_num; + if (image_hash) { + memcpy(client->upload.sha256, image_hash, IMG_MGMT_HASH_LEN); + client->upload.hash_initialized = true; + } else { + client->upload.hash_initialized = false; + } + + /* Calculate worst case header size for adapt payload length */ + client->upload.upload_header_size = upload_message_header_size(&client->upload); + if (client->upload.upload_header_size) { + rc = MGMT_ERR_EOK; + } else { + rc = MGMT_ERR_ENOMEM; + } + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length, + struct mcumgr_image_upload *res_buf) +{ + struct net_buf *nb; + const uint8_t *write_ptr; + int rc; + uint32_t map_count; + bool ok; + size_t write_length, max_data_length, offset_before_send, request_length, wrote_length; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + image_upload_buf = res_buf; + + request_length = length; + wrote_length = 0; + /* Calculate max data length based on net_buf size - (SMP header + CBOR message_len) */ + max_data_length = CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE - + (active_client->upload.upload_header_size + MGMT_HDR_SIZE); + /* Trim length based on CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE */ + if (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE) { + max_data_length -= + (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE); + } + + while (request_length != wrote_length) { + write_ptr = data + wrote_length; + write_length = request_length - wrote_length; + if (write_length > max_data_length) { + write_length = max_data_length; + } + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_UPLOAD, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + if (!nb) { + image_upload_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, + net_buf_tailroom(nb), 0); + if (active_client->upload.offset) { + map_count = 6; + } else if (active_client->upload.hash_initialized) { + map_count = 12; + } else { + map_count = 10; + } + + /* Init map start and write image info, data and offset */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, active_client->upload.image_num) && + zcbor_tstr_put_lit(zse, "data") && + zcbor_bstr_encode_ptr(zse, write_ptr, write_length) && + zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, active_client->upload.offset); + /* Write Len and configured hash when offset is zero */ + if (ok && !active_client->upload.offset) { + ok = zcbor_tstr_put_lit(zse, "len") && + zcbor_size_put(zse, active_client->upload.image_size); + if (ok && active_client->upload.hash_initialized) { + ok = zcbor_tstr_put_lit(zse, "sha") && + zcbor_bstr_encode_ptr(zse, active_client->upload.sha256, + IMG_MGMT_HASH_LEN); + } + } + + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + LOG_ERR("Failed to encode Image Upload packet"); + smp_packet_free(nb); + image_upload_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + offset_before_send = active_client->upload.offset; + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + + image_upload_buf->status = MGMT_ERR_EINVAL; + image_upload_buf->image_upload_offset = SIZE_MAX; + + rc = smp_client_send_cmd(active_client->smp_client, nb, image_upload_res_fn, + &mcumgr_img_client_grp_sem, + CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); + if (rc) { + LOG_ERR("Failed to send SMP Upload init packet, err: %d", rc); + smp_packet_free(nb); + image_upload_buf->status = rc; + goto end; + + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); + if (image_upload_buf->status) { + LOG_ERR("Upload Fail: %d", image_upload_buf->status); + goto end; + } + + if (offset_before_send + write_length < active_client->upload.offset) { + /* Offset further than expected which indicate upload session resume */ + goto end; + } + + wrote_length += write_length; + } +end: + rc = image_upload_buf->status; + active_client = NULL; + image_upload_buf = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + + return rc; +} + +int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm, + struct mcumgr_image_state *res_buf) +{ + struct net_buf *nb; + int rc; + uint32_t map_count; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + image_info = res_buf; + /* Init Response */ + res_buf->image_list_length = 0; + res_buf->image_list = active_client->image_list; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_STATE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + if (hash) { + map_count = 4; + } else { + map_count = 2; + } + + /* Write map start init and confirm params */ + ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "confirm") && + zcbor_bool_put(zse, confirm); + /* Write hash data */ + if (ok && hash) { + ok = zcbor_tstr_put_lit(zse, "hash") && + zcbor_bstr_encode_ptr(zse, hash, IMG_MGMT_HASH_LEN); + } + /* Close map */ + if (ok) { + ok = zcbor_map_end_encode(zse, map_count); + } + + if (!ok) { + smp_packet_free(nb); + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, + &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + res_buf->status = rc; + smp_packet_free(nb); + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = res_buf->status; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf) +{ + struct net_buf *nb; + int rc; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + /* Init Response */ + res_buf->image_list_length = 0; + res_buf->image_list = active_client->image_list; + + image_info = res_buf; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_STATE, MGMT_OP_READ, SMP_MCUMGR_VERSION_1); + if (!nb) { + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); + ok = zcbor_map_start_encode(zse, 1) && zcbor_map_end_encode(zse, 1); + if (!ok) { + smp_packet_free(nb); + res_buf->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, + &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + smp_packet_free(nb); + res_buf->status = rc; + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = res_buf->status; + image_info = NULL; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} + +int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot) +{ + struct net_buf *nb; + int rc; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + bool ok; + + k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); + active_client = client; + + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, + IMG_MGMT_ID_ERASE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + 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, "slot") && + zcbor_uint32_put(zse, slot) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_packet_free(nb); + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + k_sem_reset(&mcumgr_img_client_grp_sem); + rc = smp_client_send_cmd(client->smp_client, nb, erase_res_fn, &mcumgr_img_client_grp_sem, + CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); + if (rc) { + smp_packet_free(nb); + active_client->status = rc; + goto end; + } + k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); +end: + rc = active_client->status; + active_client = NULL; + k_mutex_unlock(&mcumgr_img_client_grp_mutex); + return rc; +} diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt new file mode 100644 index 000000000000..b033b363fa67 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# OS Management client group public API is exposed through zephyr_interface, +# when OS Management is enabled. +zephyr_library(mgmt_mcumgr_grp_os_client) +zephyr_library_sources(src/os_mgmt_client.c) +zephyr_library_include_directories(include) diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig b/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig new file mode 100644 index 000000000000..46c95a3cf871 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/Kconfig @@ -0,0 +1,35 @@ +# Copyright Nordic Semiconductor ASA 2023. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# The Kconfig file is dedicated to OS management group of +# of MCUmgr client subsystem and provides Kconfig options to configure +# group commands behaviour and other aspects. +# +# Options defined in this file should be prefixed: +# MCUMGR_GRP_OS_CLIENT_ -- general group options; +# +# When adding Kconfig options, that control the same feature, +# try to group them together by the same stem after prefix. + +menuconfig MCUMGR_GRP_OS_CLIENT + bool "MCUmgr client request and response handlers for OS management" + depends on SMP_CLIENT + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_3 + help + Enables MCUmgr client request and response handlers for OS management. + +if MCUMGR_GRP_OS_CLIENT + +config MCUMGR_GRP_OS_CLIENT_ECHO + default y + bool "Support for echo command request" + +config MCUMGR_GRP_OS_CLIENT_RESET + default y + bool "support for reset command request" + +module = MCUMGR_GRP_OS_CLIENT +module-str = mcumgr_grp_os_client +source "subsys/logging/Kconfig.template.log_config" + +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 new file mode 100644 index 000000000000..2bd804494c41 --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt_client/src/os_mgmt_client.c @@ -0,0 +1,168 @@ +/* + * 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 +#include + +#include +LOG_MODULE_REGISTER(mcumgr_grp_os_client, CONFIG_MCUMGR_GRP_OS_CLIENT_LOG_LEVEL); + +static struct os_mgmt_client *active_client; +static K_SEM_DEFINE(mcummgr_os_client_grp_sem, 0, 1); +static K_MUTEX_DEFINE(mcummgr_os_client_grp_mutex); + +void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object *smp_client) +{ + client->smp_client = smp_client; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_RESET + +static int reset_res_fn(struct net_buf *nb, void *user_data) +{ + if (!nb) { + active_client->status = MGMT_ERR_ETIMEOUT; + } else { + active_client->status = MGMT_ERR_EOK; + } + k_sem_give(user_data); + return 0; +} + +int os_mgmt_client_reset(struct os_mgmt_client *client) +{ + struct net_buf *nb; + int rc; + + k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER); + active_client = client; + /* allocate buffer */ + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, + OS_MGMT_ID_RESET, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + k_sem_reset(&mcummgr_os_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, reset_res_fn, + &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + active_client->status = rc; + smp_packet_free(nb); + goto end; + } + /* Wait for process end update event */ + k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER); +end: + rc = active_client->status; + active_client = NULL; + k_mutex_unlock(&mcummgr_os_client_grp_mutex); + return rc; +} + +#endif /* CONFIG_MCUMGR_GRP_OS_CLIENT_RESET */ + +#ifdef CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO + +static int echo_res_fn(struct net_buf *nb, void *user_data) +{ + struct zcbor_string val = {0}; + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + size_t decoded; + bool ok; + int rc; + struct zcbor_map_decode_key_val echo_response[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("r", zcbor_tstr_decode, &val) + }; + + if (!nb) { + LOG_ERR("Echo command timeout"); + active_client->status = MGMT_ERR_ETIMEOUT; + goto end; + } + + /* Init ZCOR decoder state */ + zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, echo_response, ARRAY_SIZE(echo_response), &decoded) == 0; + + if (!ok) { + active_client->status = MGMT_ERR_ECORRUPT; + goto end; + } + active_client->status = MGMT_ERR_EOK; +end: + rc = active_client->status; + k_sem_give(user_data); + return rc; +} + +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string) +{ + struct net_buf *nb; + int rc; + bool ok; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; + + k_mutex_lock(&mcummgr_os_client_grp_mutex, K_FOREVER); + active_client = client; + nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_OS, OS_MGMT_ID_ECHO, + MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (!nb) { + rc = active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + 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_map_end_encode(zse, 2); + + if (!ok) { + smp_packet_free(nb); + rc = active_client->status = MGMT_ERR_ENOMEM; + goto end; + } + + nb->len = zse->payload - nb->data; + + LOG_DBG("Echo Command packet len %d", nb->len); + k_sem_reset(&mcummgr_os_client_grp_sem); + rc = smp_client_send_cmd(active_client->smp_client, nb, echo_res_fn, + &mcummgr_os_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); + if (rc) { + smp_packet_free(nb); + } else { + k_sem_take(&mcummgr_os_client_grp_sem, K_FOREVER); + /* Take response status */ + rc = active_client->status; + } +end: + active_client = NULL; + k_mutex_unlock(&mcummgr_os_client_grp_mutex); + return rc; +} +#endif From 9a06ce19ad7aa92582a2ab13e08aab88e88cb93d Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Mon, 22 May 2023 14:37:54 +0300 Subject: [PATCH 1887/2042] tests: mcumgr: MCUmgr and smp client unit test Added unit test for testing IMG and OS group component's. Added Unit test for SMP Client. Signed-off-by: Juha Heiskanen --- .../mgmt/mcumgr/mcumgr_client/CMakeLists.txt | 17 + .../subsys/mgmt/mcumgr/mcumgr_client/prj.conf | 25 ++ .../mcumgr/mcumgr_client/src/img_gr_stub.c | 298 ++++++++++++++++++ .../mcumgr/mcumgr_client/src/img_gr_stub.h | 34 ++ .../mgmt/mcumgr/mcumgr_client/src/main.c | 256 +++++++++++++++ .../mcumgr/mcumgr_client/src/os_gr_stub.c | 98 ++++++ .../mcumgr/mcumgr_client/src/os_gr_stub.h | 24 ++ .../mgmt/mcumgr/mcumgr_client/src/smp_stub.c | 124 ++++++++ .../mgmt/mcumgr/mcumgr_client/src/smp_stub.h | 30 ++ .../mgmt/mcumgr/smp_client/CMakeLists.txt | 15 + tests/subsys/mgmt/mcumgr/smp_client/prj.conf | 19 ++ .../subsys/mgmt/mcumgr/smp_client/src/main.c | 128 ++++++++ .../smp_client/src/smp_transport_stub.c | 51 +++ .../smp_client/src/smp_transport_stub.h | 24 ++ 14 files changed, 1143 insertions(+) create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c create mode 100644 tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h create mode 100644 tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/smp_client/prj.conf create mode 100644 tests/subsys/mgmt/mcumgr/smp_client/src/main.c create mode 100644 tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c create mode 100644 tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt new file mode 100644 index 000000000000..a0f765546295 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# 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(mcumgr_client) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) + +add_compile_definitions(CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER=1) diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf b/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf new file mode 100644 index 000000000000..46835a49dc78 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/prj.conf @@ -0,0 +1,25 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# ZTEST config +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 + +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +# Enable mcumgr +CONFIG_MCUMGR=y +CONFIG_SMP_CLIENT=y +CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER=1 +CONFIG_MCUMGR_GRP_OS_CLIENT=y +CONFIG_MCUMGR_GRP_IMG_CLIENT=y +CONFIG_MCUMGR_GRP_OS_CLIENT_ECHO=y +CONFIG_MCUMGR_GRP_OS_CLIENT_RESET=y + +# Extend System Workqueue stack size +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 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 new file mode 100644 index 000000000000..5bd784a3954b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.c @@ -0,0 +1,298 @@ +/* + * 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 "smp_stub.h" +#include "img_gr_stub.h" + +static struct mcumgr_image_data image_dummy_info[2]; +static size_t test_offset; +static uint8_t *image_hash_ptr; + +#define ZCBOR_ENCODE_FLAG(zse, label, value) \ + (zcbor_tstr_put_lit(zse, label) && zcbor_bool_put(zse, value)) + +void img_upload_stub_init(void) +{ + test_offset = 0; +} + +void img_upload_response(size_t offset, int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + if (status) { + ok = zcbor_map_start_encode(zse, 4) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4); + } else { + /* Drop Status away from response */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "off") && + zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4); + } + + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_fail_response(int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_read_response(int count) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + ok = zcbor_map_start_encode(zse, 15) && zcbor_tstr_put_lit(zse, "images") && + zcbor_list_start_encode(zse, 2); + + for (int i = 0; ok && i < count; i++) { + + ok = zcbor_map_start_encode(zse, 15) && + ((zcbor_tstr_put_lit(zse, "image") && + zcbor_uint32_put(zse, image_dummy_info[i].img_num))) && + 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, "hash") && + zcbor_bstr_encode_ptr(zse, image_dummy_info[i].hash, IMG_MGMT_HASH_LEN) && + ZCBOR_ENCODE_FLAG(zse, "bootable", image_dummy_info[i].flags.bootable) && + ZCBOR_ENCODE_FLAG(zse, "pending", image_dummy_info[i].flags.pending) && + ZCBOR_ENCODE_FLAG(zse, "confirmed", image_dummy_info[i].flags.confirmed) && + ZCBOR_ENCODE_FLAG(zse, "active", image_dummy_info[i].flags.active) && + ZCBOR_ENCODE_FLAG(zse, "permanent", image_dummy_info[i].flags.permanent) && + zcbor_map_end_encode(zse, 15); + } + + ok = ok && zcbor_list_end_encode(zse, 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER); + + ok = ok && zcbor_map_end_encode(zse, 15); + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_erase_response(int status) +{ + struct net_buf *nb; + zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void img_state_write_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + int rc; + struct zcbor_string hash; + bool confirm; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm), + 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); + + decoded = 0; + /* Init buffer values */ + confirm = false; + hash.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc) { + printf("Corrupted data %d\r\n", rc); + img_fail_response(MGMT_ERR_EINVAL); + return; + } + if (hash.len) { + printf("HASH %d", hash.len); + if (memcmp(hash.value, image_dummy_info[1].hash, 32) == 0) { + if (confirm) { + /* Set Permanent bit */ + image_dummy_info[1].flags.permanent = true; + } else { + /* Set pending */ + image_dummy_info[1].flags.pending = true; + } + img_read_response(2); + } else { + img_fail_response(MGMT_ERR_EINVAL); + } + } else { + if (confirm) { + image_dummy_info[0].flags.confirmed = true; + } + img_read_response(2); + } +} + +void img_upload_init_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; + int rc; + uint32_t image; + struct zcbor_string sha, data; + size_t decoded, length, offset; + struct zcbor_map_decode_key_val list_res_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &image), + ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &data), + ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &length), + ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &offset), + 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); + + decoded = 0; + /* Init buffer values */ + sha.len = 0; + data.len = 0; + length = SIZE_MAX; + offset = SIZE_MAX; + image = UINT32_MAX; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc || data.len == 0 || offset == SIZE_MAX || image != TEST_IMAGE_NUM) { + printf("Corrupted data %d or %d data len\r\n", rc, data.len); + img_upload_response(0, MGMT_ERR_EINVAL); + return; + } + + if (sha.len) { + if (memcmp(sha.value, image_hash_ptr, 32)) { + printf("Hash not same\r\n"); + img_upload_response(0, MGMT_ERR_EINVAL); + return; + } + } + + if (offset != test_offset) { + printf("Offset not exepected %d vs received %d\r\n", test_offset, offset); + } + + if (offset == 0) { + if (length != TEST_IMAGE_SIZE) { + img_upload_response(0, MGMT_ERR_EINVAL); + } + } + + test_offset += data.len; + printf("Upload offset %d\r\n", test_offset); + if (test_offset <= TEST_IMAGE_SIZE) { + img_upload_response(test_offset, MGMT_ERR_EOK); + } else { + img_upload_response(0, MGMT_ERR_EINVAL); + } +} + +void img_gr_stub_data_init(uint8_t *hash_ptr) +{ + image_hash_ptr = hash_ptr; + for (int i = 0; i < 32; i++) { + image_hash_ptr[i] = i; + image_dummy_info[0].hash[i] = i + 32; + image_dummy_info[1].hash[i] = i + 64; + } + /* Set dummy image list data */ + for (int i = 0; i < 2; i++) { + image_dummy_info[i].img_num = i; + image_dummy_info[i].slot_num = i; + /* Write version */ + snprintf(image_dummy_info[i].version, IMG_MGMT_VER_MAX_STR_LEN, "1.1.%u", i); + image_dummy_info[i].version[sizeof(image_dummy_info[i].version) - 1] = '\0'; + image_dummy_info[i].flags.bootable = true; + image_dummy_info[i].flags.pending = false; + if (i) { + image_dummy_info[i].flags.confirmed = false; + image_dummy_info[i].flags.active = false; + } else { + image_dummy_info[i].flags.confirmed = true; + image_dummy_info[i].flags.active = true; + } + image_dummy_info[i].flags.permanent = false; + } +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h new file mode 100644 index 000000000000..95fdbc8203b2 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/img_gr_stub.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_IMG_GR_STUB_ +#define H_IMG_GR_STUB_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define TEST_IMAGE_NUM 1 +#define TEST_IMAGE_SIZE 2048 +#define TEST_SLOT_NUMBER 2 + +void img_upload_stub_init(void); +void img_upload_response(size_t offset, int status); +void img_fail_response(int status); +void img_read_response(int count); +void img_erase_response(int status); +void img_upload_init_verify(struct net_buf *nb); +void img_state_write_verify(struct net_buf *nb); +void img_gr_stub_data_init(uint8_t *hash_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* H_IMG_GR_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c new file mode 100644 index 000000000000..a15e82f17a64 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/main.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* Include stubbed test helpers */ +#include "smp_stub.h" +#include "img_gr_stub.h" +#include "os_gr_stub.h" + +/* IMG group data */ +static uint8_t image_hash[32]; +static struct mcumgr_image_data image_info[2]; +static uint8_t image_dummy[1024]; + +static const char os_echo_test[] = "TestString"; +static struct smp_client_object smp_client; +static struct img_mgmt_client img_client; +static struct os_mgmt_client os_client; + +ZTEST(mcumgr_client, img_upload) +{ + int rc; + struct mcumgr_image_upload response; + + smp_stub_set_rx_data_verify(NULL); + img_upload_stub_init(); + + img_mgmt_client_init(&img_client, &smp_client, 2, image_info); + + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + /* Start upload and test Timeout */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + zassert_equal(MGMT_ERR_ETIMEOUT, response.status, "Expected to receive %d response %d\n", + MGMT_ERR_ETIMEOUT, response.status); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + /* Start upload and test Timeout */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + zassert_equal(MGMT_ERR_ETIMEOUT, response.status, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, response.status); + + smp_client_send_status_stub(MGMT_ERR_EOK); + + /* Allocate response buf */ + img_upload_response(0, MGMT_ERR_EINVAL); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EINVAL, rc, "Expected to receive %d response %d", MGMT_ERR_EINVAL, + rc); + zassert_equal(MGMT_ERR_EINVAL, response.status, "Expected to receive %d response %d", + MGMT_ERR_EINVAL, response.status); + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, image_hash); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d\n", MGMT_ERR_EOK, rc); + img_upload_response(1024, MGMT_ERR_EOK); + + smp_stub_set_rx_data_verify(img_upload_init_verify); + img_upload_stub_init(); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(1024, response.image_upload_offset, + "Expected to receive offset %d response %d", 1024, + response.image_upload_offset); + /* Send last frame from image */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(TEST_IMAGE_SIZE, response.image_upload_offset, + "Expected to receive offset %d response %d", TEST_IMAGE_SIZE, + response.image_upload_offset); + + /* Test without hash */ + rc = img_mgmt_client_upload_init(&img_client, TEST_IMAGE_SIZE, TEST_IMAGE_NUM, NULL); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + img_upload_stub_init(); + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(1024, response.image_upload_offset, + "Expected to receive offset %d response %d", 1024, + response.image_upload_offset); + /* Send last frame from image */ + rc = img_mgmt_client_upload(&img_client, image_dummy, 1024, &response); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(MGMT_ERR_EOK, response.status, "Expected to receive %d response %d", + MGMT_ERR_EOK, response.status); + zassert_equal(TEST_IMAGE_SIZE, response.image_upload_offset, + "Expected to receive offset %d response %d", TEST_IMAGE_SIZE, + response.image_upload_offset); +} + +ZTEST(mcumgr_client, img_erase) +{ + int rc; + + smp_client_send_status_stub(MGMT_ERR_EOK); + + /* Test timeout */ + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + + /* Test erase fail */ + img_erase_response(MGMT_ERR_EINVAL); + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_EINVAL, rc, "Expected to receive %d response %d", MGMT_ERR_EINVAL, + rc); + /* Tesk ok */ + img_erase_response(MGMT_ERR_EOK); + rc = img_mgmt_client_erase(&img_client, TEST_SLOT_NUMBER); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +ZTEST(mcumgr_client, image_state_read) +{ + int rc; + struct mcumgr_image_state res_buf; + + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + /* Testing read successfully 1 image info and print that */ + img_read_response(1); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(1, res_buf.image_list_length, "Expected to receive %d response %d", 1, + res_buf.image_list_length); + img_read_response(2); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); +} + +ZTEST(mcumgr_client, image_state_set) +{ + int rc; + char hash[32]; + struct mcumgr_image_state res_buf; + + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = img_mgmt_client_state_write(&img_client, NULL, false, &res_buf); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + + printf("Timeout OK\r\n"); + /* Read secondary image hash for testing */ + img_read_response(2); + rc = img_mgmt_client_state_read(&img_client, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(false, image_info[1].flags.pending, "Expected to receive %d response %d", + false, image_info[1].flags.pending); + /* Copy hash for set pending flag */ + memcpy(hash, image_info[1].hash, 32); + printf("Read OK\r\n"); + + /* Read secondary image hash for testing */ + smp_stub_set_rx_data_verify(img_state_write_verify); + rc = img_mgmt_client_state_write(&img_client, hash, false, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(true, image_info[1].flags.pending, "Expected to receive %d response %d", + true, image_info[1].flags.pending); + /* Test to set confirmed bit */ + image_info[0].flags.confirmed = false; + smp_stub_set_rx_data_verify(img_state_write_verify); + rc = img_mgmt_client_state_write(&img_client, NULL, true, &res_buf); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + zassert_equal(2, res_buf.image_list_length, "Expected to receive %d response %d", 2, + res_buf.image_list_length); + zassert_equal(true, image_info[0].flags.confirmed, "Expected to receive %d response %d", + true, image_info[0].flags.confirmed); +} + +ZTEST(mcumgr_client, os_reset) +{ + int rc; + + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); + + smp_client_send_status_stub(MGMT_ERR_EOK); + /* Test timeout */ + rc = os_mgmt_client_reset(&os_client); + zassert_equal(MGMT_ERR_ETIMEOUT, rc, "Expected to receive %d response %d", + MGMT_ERR_ETIMEOUT, rc); + /* Testing reset successfully handling */ + os_reset_response(); + rc = os_mgmt_client_reset(&os_client); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +ZTEST(mcumgr_client, os_echo) +{ + int rc; + + smp_client_response_buf_clean(); + 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); + 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); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); +} + +static void *setup_custom_os(void) +{ + stub_smp_client_transport_register(); + smp_client_object_init(&smp_client, SMP_SERIAL_TRANSPORT); + os_mgmt_client_init(&os_client, &smp_client); + img_mgmt_client_init(&img_client, &smp_client, 2, image_info); + + img_gr_stub_data_init(image_hash); + os_stub_init(os_echo_test); + return NULL; +} + +static void cleanup_test(void *p) +{ + smp_client_response_buf_clean(); + smp_stub_set_rx_data_verify(NULL); +} + +/* Main test set */ +ZTEST_SUITE(mcumgr_client, NULL, setup_custom_os, NULL, cleanup_test, NULL); 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 new file mode 100644 index 000000000000..888f00dba38d --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.c @@ -0,0 +1,98 @@ +/* + * 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 "smp_stub.h" + +static const char *echo_ptr; + +void os_stub_init(const char *echo_str) +{ + echo_ptr = echo_str; +} + +void os_reset_response(void) +{ + struct net_buf *nb; + + nb = smp_response_buf_allocation(); + if (nb) { + nb->len = 0; + } +} + +static void os_echo_response(int status, struct zcbor_string *echo_data) +{ + struct net_buf *nb; + zcbor_state_t zse[3 + 2]; + bool ok; + + nb = smp_response_buf_allocation(); + + if (!nb) { + return; + } + + zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0); + + if (status) { + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") && + zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2); + } else { + /* Init map start and write image info and data */ + ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "r") && + zcbor_tstr_encode_ptr(zse, echo_data->value, echo_data->len) && + zcbor_map_end_encode(zse, 2); + } + + if (!ok) { + smp_client_response_buf_clean(); + } else { + nb->len = zse->payload - nb->data; + } +} + +void os_echo_verify(struct net_buf *nb) +{ + /* Parse CBOR data: hash and confirm */ + zcbor_state_t zsd[3 + 2]; + int rc; + int response_status; + struct zcbor_string echo_data; + size_t decoded; + struct zcbor_map_decode_key_val list_res_decode[] = { + 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); + echo_data.len = 0; + + rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded); + if (rc || !echo_data.len) { + printf("Corrupted data %d or no echo data %d\r\n", rc, echo_data.len); + response_status = MGMT_ERR_EINVAL; + } else if (memcmp(echo_data.value, echo_ptr, echo_data.len)) { + response_status = MGMT_ERR_EINVAL; + } else { + response_status = MGMT_ERR_EOK; + } + + os_echo_response(response_status, &echo_data); +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h new file mode 100644 index 000000000000..ec6f3408979f --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/os_gr_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_OS_GR_STUB_ +#define H_OS_GR_STUB_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void os_stub_init(const char *echo_str); +void os_reset_response(void); +void os_echo_verify(struct net_buf *nb); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_GR_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c new file mode 100644 index 000000000000..9b476082dd8e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "smp_stub.h" + +K_THREAD_STACK_DEFINE(smp_stub_work_queue_stack, CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE); + +static mcmgr_client_data_check_fn rx_verify_cb; +static int send_client_failure; +static struct net_buf *response_buf; +static struct smp_hdr res_hdr; +static struct smp_transport smpt_test; +static struct smp_client_transport_entry smp_client_transport; +static struct k_work_q smp_work_queue; +static struct k_work stub_work; + +static const struct k_work_queue_config smp_work_queue_config = { + .name = "mcumgr smp" +}; + +void smp_stub_set_rx_data_verify(mcmgr_client_data_check_fn cb) +{ + rx_verify_cb = cb; +} + +void smp_client_send_status_stub(int status) +{ + send_client_failure = status; +} + +struct net_buf *smp_response_buf_allocation(void) +{ + smp_client_response_buf_clean(); + + response_buf = smp_packet_alloc(); + + return response_buf; +} + +void smp_client_response_buf_clean(void) +{ + if (response_buf) { + smp_client_buf_free(response_buf); + response_buf = NULL; + } +} + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + + +static uint16_t smp_uart_get_mtu(const struct net_buf *nb) +{ + return 256; +} + +static int smp_uart_tx_pkt(struct net_buf *nb) +{ + if (send_client_failure) { + /* Test Send cmd fail */ + return send_client_failure; + } + + memcpy(&res_hdr, nb->data, sizeof(res_hdr)); + res_hdr.nh_len = sys_be16_to_cpu(res_hdr.nh_len); + res_hdr.nh_group = sys_be16_to_cpu(res_hdr.nh_group); + res_hdr.nh_op += 1; /* Request to response */ + + /* Validate Input data if callback is configured */ + if (rx_verify_cb) { + rx_verify_cb(nb); + } + + /* Free tx buf */ + net_buf_unref(nb); + + if (response_buf) { + k_work_submit_to_queue(&smp_work_queue, &stub_work); + } + + return 0; +} + +static void smp_client_handle_reqs(struct k_work *work) +{ + if (response_buf) { + smp_client_single_response(response_buf, &res_hdr); + } +} + +void stub_smp_client_transport_register(void) +{ + + smpt_test.functions.output = smp_uart_tx_pkt; + smpt_test.functions.get_mtu = smp_uart_get_mtu; + + smp_transport_init(&smpt_test); + smp_client_transport.smpt = &smpt_test; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); + + + k_work_queue_init(&smp_work_queue); + + k_work_queue_start(&smp_work_queue, smp_stub_work_queue_stack, + K_THREAD_STACK_SIZEOF(smp_stub_work_queue_stack), + CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_THREAD_PRIO, &smp_work_queue_config); + + k_work_init(&stub_work, smp_client_handle_reqs); +} diff --git a/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h new file mode 100644 index 000000000000..c8668a033d2e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/mcumgr_client/src/smp_stub.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_SMP_STUB_ +#define H_SMP_STUB_ + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*mcmgr_client_data_check_fn)(struct net_buf *nb); + +void smp_stub_set_rx_data_verify(mcmgr_client_data_check_fn cb); +void smp_client_send_status_stub(int status); +void smp_client_response_buf_clean(void); +struct net_buf *smp_response_buf_allocation(void); +void stub_smp_client_transport_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_SMP_STUB_ */ diff --git a/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt new file mode 100644 index 000000000000..2d5fea068dbc --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# 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(smp_client) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/mgmt/mcumgr/smp_client/prj.conf b/tests/subsys/mgmt/mcumgr/smp_client/prj.conf new file mode 100644 index 000000000000..22740657b784 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/prj.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +# ZTEST config +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 + +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_CRC=y +CONFIG_ZCBOR=y +CONFIG_MCUMGR=y +CONFIG_SMP_CLIENT=y + +# Extend System Workqueue stack size +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/main.c b/tests/subsys/mgmt/mcumgr/smp_client/src/main.c new file mode 100644 index 000000000000..be1a3968274a --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/main.c @@ -0,0 +1,128 @@ +/* + * 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 "smp_transport_stub.h" + +static struct net_buf *buf[5]; + +static uint32_t testing_user_data; +static void *response_ptr; +static struct net_buf *res_buf; +static struct smp_client_object smp_client; + +int smp_client_res_cb(struct net_buf *nb, void *user_data) +{ + res_buf = nb; + response_ptr = user_data; + return 0; +} + +ZTEST(smp_client, buf_alloc) +{ + struct smp_client_object smp_client; + + /* Allocate all 4 buffer's and verify that 5th fail */ + for (int i = 0; i < 5; i++) { + buf[i] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, + MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); + if (i == 4) { + zassert_is_null(buf[i], "Buffer was not Null"); + } else { + zassert_not_null(buf[i], "Buffer was Null"); + zassert_equal(sizeof(struct smp_hdr), buf[i]->len, + "Expected to receive %d response %d", + sizeof(struct smp_hdr), buf[i]->len); + } + } + + for (int i = 0; i < 4; i++) { + smp_client_buf_free(buf[i]); + buf[i] = NULL; + } +} + +ZTEST(smp_client, msg_send_timeout) +{ + struct net_buf *nb; + + int rc; + + nb = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(nb, "Buffer was Null"); + rc = smp_client_send_cmd(&smp_client, nb, smp_client_res_cb, &testing_user_data, 2); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + k_sleep(K_SECONDS(3)); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_equal_ptr(response_ptr, &testing_user_data, "User data not returned correctly"); +} + +ZTEST(smp_client, msg_response_handler) +{ + struct smp_hdr dst_hdr; + int rc; + + + response_ptr = NULL; + res_buf = NULL; + + buf[0] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(buf[0], "Buffer was Null"); + rc = smp_client_send_cmd(&smp_client, buf[0], smp_client_res_cb, &testing_user_data, 8); + zassert_equal(MGMT_ERR_EOK, rc, "Expected to receive %d response %d", MGMT_ERR_EOK, rc); + buf[1] = smp_client_buf_allocation(&smp_client, MGMT_GROUP_ID_IMAGE, 1, MGMT_OP_WRITE, + SMP_MCUMGR_VERSION_1); + zassert_not_null(buf[0], "Buffer was Null"); + /* Read Pushed packet Header */ + smp_transport_read_hdr(buf[0], &dst_hdr); + smp_client_single_response(buf[1], &dst_hdr); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_is_null(response_ptr, "NULL pointer was not returned"); + /* Set Correct OP */ + dst_hdr.nh_op = MGMT_OP_WRITE_RSP; + smp_client_single_response(buf[1], &dst_hdr); + zassert_equal_ptr(res_buf, buf[1], "Response Buf not correct"); + zassert_equal_ptr(response_ptr, &testing_user_data, "User data not returned correctly"); + response_ptr = NULL; + res_buf = NULL; + smp_client_single_response(buf[1], &dst_hdr); + zassert_is_null(res_buf, "NULL pointer was not returned"); + zassert_is_null(response_ptr, "NULL pointer was not returned"); +} + +static void *setup_custom_os(void) +{ + /* Registre tarnsport and init client */ + stub_smp_client_transport_register(); + smp_client_object_init(&smp_client, SMP_SERIAL_TRANSPORT); + return NULL; +} + +static void cleanup_test(void *p) +{ + for (int i = 0; i < 5; i++) { + if (buf[i]) { + smp_client_buf_free(buf[i]); + buf[i] = NULL; + } + } +} + +/* Main test set */ +ZTEST_SUITE(smp_client, NULL, setup_custom_os, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c new file mode 100644 index 000000000000..d3248755e5ab --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct smp_transport smpt_test; +static struct smp_client_transport_entry smp_client_transport; + +/* Stubbed functions */ + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr) +{ + memcpy(dst_hdr, nb->data, sizeof(*dst_hdr)); + dst_hdr->nh_len = sys_be16_to_cpu(dst_hdr->nh_len); + dst_hdr->nh_group = sys_be16_to_cpu(dst_hdr->nh_group); +} + + + + +static uint16_t smp_uart_get_mtu(const struct net_buf *nb) +{ + return 256; +} + +static int smp_uart_tx_pkt(struct net_buf *nb) +{ + smp_packet_free(nb); + return 0; +} + +void stub_smp_client_transport_register(void) +{ + + smpt_test.functions.output = smp_uart_tx_pkt; + smpt_test.functions.get_mtu = smp_uart_get_mtu; + + smp_transport_init(&smpt_test); + smp_client_transport.smpt = &smpt_test; + smp_client_transport.smpt_type = SMP_SERIAL_TRANSPORT; + smp_client_transport_register(&smp_client_transport); +} diff --git a/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h new file mode 100644 index 000000000000..9046aff622c0 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/smp_client/src/smp_transport_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_OS_GR_STUB_ +#define H_OS_GR_STUB_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void smp_transport_read_hdr(const struct net_buf *nb, struct smp_hdr *dst_hdr); +void stub_smp_client_transport_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_GR_STUB_ */ From 17fb2a1fb596ee4737962a377ad4e54e5509e701 Mon Sep 17 00:00:00 2001 From: Josep Puigdemont Date: Thu, 27 Jul 2023 09:43:58 +0200 Subject: [PATCH 1888/2042] sensor: bme280: return ENOTSUP on invalid channel ENOTSUP should be returned for unsupported channels. Signed-off-by: Josep Puigdemont --- drivers/sensor/bme280/bme280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/sensor/bme280/bme280.c b/drivers/sensor/bme280/bme280.c index 082bacf1b1b8..0b2b3954616d 100644 --- a/drivers/sensor/bme280/bme280.c +++ b/drivers/sensor/bme280/bme280.c @@ -254,7 +254,7 @@ static int bme280_channel_get(const struct device *dev, val->val2 = (((data->comp_humidity & 0x3ff) * 1000U * 1000U) >> 10); break; default: - return -EINVAL; + return -ENOTSUP; } return 0; From 677d377299f5a919c2fcd8f5769f9b2d14708187 Mon Sep 17 00:00:00 2001 From: Josep Puigdemont Date: Fri, 21 Jul 2023 17:48:36 +0200 Subject: [PATCH 1889/2042] sensor: bme280: BMP280 has no humidity sensor Return ENOTSUP when getting the humidity channel if the driver is used with a BMP280, since this device does not provide humidity readings. Signed-off-by: Josep Puigdemont --- drivers/sensor/bme280/bme280.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/sensor/bme280/bme280.c b/drivers/sensor/bme280/bme280.c index 0b2b3954616d..f2bd7514c019 100644 --- a/drivers/sensor/bme280/bme280.c +++ b/drivers/sensor/bme280/bme280.c @@ -245,6 +245,10 @@ static int bme280_channel_get(const struct device *dev, (((data->comp_press & 0xff) * 1000U) >> 8); break; case SENSOR_CHAN_HUMIDITY: + /* The BMP280 doesn't have a humidity sensor */ + if (data->chip_id != BME280_CHIP_ID) { + return -ENOTSUP; + } /* * data->comp_humidity has 22 integer bits and 10 * fractional. Output value of 47445 represents From 16d9d4d1a57bc2c993337879bb30778aa1dbb36f Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 22 Mar 2023 15:09:48 +0100 Subject: [PATCH 1890/2042] Kconfig: Provide name to orphan configuration choice symbol Kconfig choice section for LINKER_ORPHAN configuration has no name. This prevents configuring a default value in .defconfig files and constrain to set in _defconfig /.prj files. Then it is not possible to generalize this setting to a whole set of boards (soc series for instance) or make it dependent on another symbol. Provide it a name to add this flexibility. Signed-off-by: Erwan Gouriou --- Kconfig.zephyr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 15427fa82be8..b53bac57e734 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -56,7 +56,7 @@ menu "Build and Link Features" menu "Linker Options" -choice +choice LINKER_ORPHAN_CONFIGURATION prompt "Linker Orphan Section Handling" default LINKER_ORPHAN_SECTION_WARN From c044b2e9166c2d30a4b9dd6f8a92e6000749173f Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 27 Jul 2023 11:16:42 +0200 Subject: [PATCH 1891/2042] posix arch: Fix very rare segfault on program termination In some very rare cases (< 1/1000 runs), in very loaded machines, a race in the glibc pthread_cancel() seems to be triggered. In this the cancelled thread cleanup overtakes the pthread_cancel() code, and frees the pthread structure before pthread_cancel() has finished, resulting in a dereference into already free'd memory, and therefore a segfault. Calling pthread_cancel() during cleanup is not required beyond preventing a valgrind memory leak report (all threads will be stopped immediately on exit). Therefore we stop doing this, to avoid this very rare crashes. This issue was reproduced in Ubuntu 22.04, with its default gcc 11.3.0 and glibc 2.35. The issue may also have been seen very rarely in Zephyr's CI. Signed-off-by: Alberto Escolar Piedras --- arch/posix/core/posix_core.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/posix/core/posix_core.c b/arch/posix/core/posix_core.c index 2492c7d19e48..89310f11d940 100644 --- a/arch/posix/core/posix_core.c +++ b/arch/posix/core/posix_core.c @@ -48,6 +48,7 @@ #define ERPREFIX PREFIX"error on " #define NO_MEM_ERR PREFIX"Can't allocate memory\n" +#define PC_ENABLE_CANCEL 0 /* See Note.c1 */ #define PC_ALLOC_CHUNK_SIZE 64 #define PC_REUSE_ABORTED_ENTRIES 0 /* tests/kernel/threads/scheduling/schedule_api fails when setting @@ -363,6 +364,10 @@ int posix_new_thread(void *ptr) threads_table[t_slot].thead_cnt = thread_create_count++; threads_table[t_slot].t_status = ptr; + /* + * Note: If you are here due to a valgrind reported memory leak in + * pthread_create() please use the provided valgrind.supp suppression file. + */ PC_SAFE_CALL(pthread_create(&threads_table[t_slot].thread, NULL, posix_thread_starter, @@ -422,6 +427,7 @@ void posix_arch_clean_up(void) terminate = true; +#if (PC_ENABLE_CANCEL) for (int i = 0; i < threads_table_size; i++) { if (threads_table[i].state != USED) { continue; @@ -435,6 +441,7 @@ void posix_arch_clean_up(void) } /* LCOV_EXCL_STOP */ } +#endif free(threads_table); threads_table = NULL; @@ -516,4 +523,17 @@ int posix_arch_get_unique_thread_id(int thread_idx) * Some other code will never or only very rarely trigger and is therefore * excluded with LCOV_EXCL_LINE * + * + * Notes about (memory) cleanup: + * + * Note.c1: + * + * In some very rare cases in very loaded machines, a race in the glibc pthread_cancel() + * seems to be triggered. + * In this, the cancelled thread cleanup overtakes the pthread_cancel() code, and frees the + * pthread structure before pthread_cancel() has finished, resulting in a dereference into already + * free'd memory, and therefore a segfault. + * Calling pthread_cancel() during cleanup is not required beyond preventing a valgrind + * memory leak report (all threads will be canceled immediately on exit). + * Therefore we do not do this, to avoid this very rare crashes. */ From a3fb2dcc2f6aa85f2bce9ad1d7e6332ae92f81e2 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Wed, 14 Jun 2023 14:44:34 +0700 Subject: [PATCH 1892/2042] drivers: can: add kconfig CAN_MAX_MB Each CAN instance of S32K344 has different maximum number of message buffers, depends on payload. Add kconfig that defines maximum number of message buffers for concurrent active instances and update driver to compatible support S32k344. Signed-off-by: Cong Nguyen Huu --- drivers/can/Kconfig.mcux | 9 +++++++++ drivers/can/can_mcux_flexcan.c | 13 +++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index f97671bf613d..6ccaad15e453 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -21,12 +21,21 @@ config CAN_MCUX_FLEXCAN_FD help Enable support for CAN-FD capable NXP FlexCAN devices. +config CAN_MAX_MB + int "Maximum number of message buffers for concurrent active instances" + default 16 + depends on SOC_SERIES_S32K3_M7 + range 1 96 + help + Defines maximum number of message buffers for concurrent active instances. + config CAN_MAX_FILTER int "Maximum number of concurrent active RX filters" default 5 range 1 15 if SOC_SERIES_KINETIS_KE1XF || SOC_SERIES_KINETIS_K6X 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_S32K3_M7 help Defines maximum number of concurrent active RX filters diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 974fda4ca09f..fd754a184a59 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -49,14 +49,19 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL); #define RX_START_IDX 0 #endif +/* The maximum number of message buffers for concurrent active instances */ +#ifdef CONFIG_CAN_MAX_MB +#define MCUX_FLEXCAN_MAX_MB CONFIG_CAN_MAX_MB +#else +#define MCUX_FLEXCAN_MAX_MB FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0) +#endif + /* * RX message buffers (filters) will take up the first N message * buffers. The rest are available for TX use. */ #define MCUX_FLEXCAN_MAX_RX (CONFIG_CAN_MAX_FILTER + RX_START_IDX) -#define MCUX_FLEXCAN_MAX_TX \ - (FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0) \ - - MCUX_FLEXCAN_MAX_RX) +#define MCUX_FLEXCAN_MAX_TX (MCUX_FLEXCAN_MAX_MB - MCUX_FLEXCAN_MAX_RX) /* * Convert from RX message buffer index to allocated filter ID and @@ -1246,7 +1251,7 @@ static int mcux_flexcan_init(const struct device *dev) data->dev = dev; FLEXCAN_GetDefaultConfig(&flexcan_config); - flexcan_config.maxMbNum = FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0); + flexcan_config.maxMbNum = MCUX_FLEXCAN_MAX_MB; flexcan_config.clkSrc = config->clk_source; flexcan_config.baudRate = clock_freq / (1U + data->timing.prop_seg + data->timing.phase_seg1 + From 36d63e132d97ed2928bd99e03083d2d18bb4c4e1 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Wed, 14 Jun 2023 14:20:41 +0700 Subject: [PATCH 1893/2042] boards: arm: mr_canhubk3: enable support for FlexCAN Reuse existing MCUX-based shim driver for FlexCAN. Enable flexcan0 for Zephyr canbus to run tests. Signed-off-by: Cong Nguyen Huu --- boards/arm/mr_canhubk3/doc/index.rst | 68 +++++++++ .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 66 +++++++++ boards/arm/mr_canhubk3/mr_canhubk3.dts | 140 ++++++++++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.yaml | 1 + boards/arm/mr_canhubk3/mr_canhubk3_defconfig | 1 + dts/arm/nxp/nxp_s32k344_m7.dtsi | 61 ++++++++ soc/arm/nxp_s32/s32k/Kconfig.series | 1 + west.yml | 2 +- 8 files changed, 339 insertions(+), 1 deletion(-) diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 5c8c5e2997c3..bbdfd79c3ec0 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -50,6 +50,7 @@ SIUL2 on-chip | pinctrl | external interrupt controller LPUART on-chip serial QSPI on-chip flash +FLEXCAN on-chip can ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -107,6 +108,73 @@ P6.2 PTA9 LPUART2_TX P6.3 PTA8 LPUART2_RX ========= ===== ============ +CAN +=== + +CAN is provided through FLEXCAN interface with 6 instances. + +=============== ======= =============== ============= +Devicetree node Pin Pin Function Bus Connector +=============== ======= =============== ============= +flexcan0 | PTA6 | PTA6_CAN0_RX P12/P13 + | PTA7 | PTA7_CAN0_TX +flexcan1 | PTC9 | PTC9_CAN0_RX P14/P15 + | PTC8 | PTC8_CAN0_TX +flexcan2 | PTE25 | PTE25_CAN0_RX P16/P17 + | PTE24 | PTE24_CAN0_TX +flexcan3 | PTC29 | PTC29_CAN0_RX P18/019 + | PTC28 | PTC28_CAN0_TX +flexcan4 | PTC31 | PTC31_CAN0_RX P20/P21 + | PTC30 | PTC30_CAN0_TX +flexcan5 | PTC11 | PTC11_CAN0_RX P22/P23 + | PTC10 | PTC10_CAN0_TX +=============== ======= =============== ============= + +.. note:: + There is limitation by HAL SDK, so CAN only has support maximum 64 message buffers (MBs) + and support maximum 32 message buffers for concurrent active instances with 8 bytes + payload. We need to pay attention to configuration options: + + 1. :kconfig:option:`CONFIG_CAN_MAX_MB` must be less or equal than the + maximum number of message buffers that is according to the table below. + + 2. :kconfig:option:`CONFIG_CAN_MAX_FILTER` must be less or equal than + :kconfig:option:`CONFIG_CAN_MAX_MB`. + +=============== ========== ================ ================ +Devicetree node Payload Hardware support Software support +=============== ========== ================ ================ +flexcan0 | 8 bytes | 96 MBs | 64 MBs + | 16 bytes | 63 MBs | 42 MBs + | 32 bytes | 36 MBs | 24 MBs + | 64 bytes | 21 MBs | 14 MBs +flexcan1 | 8 bytes | 64 MBs | 64 MBs + | 16 bytes | 42 MBs | 42 MBs + | 32 bytes | 24 MBs | 24 MBs + | 64 bytes | 14 MBs | 14 MBs +flexcan2 | 8 bytes | 64 MBs | 64 MBs + | 16 bytes | 42 MBs | 42 MBs + | 32 bytes | 24 MBs | 24 MBs + | 64 bytes | 14 MBs | 14 MBs +flexcan3 | 8 bytes | 32 MBs | 32 MBs + | 16 bytes | 21 MBs | 21 MBs + | 32 bytes | 12 MBs | 12 MBs + | 64 bytes | 7 MBs | 7 MBs +flexcan4 | 8 bytes | 32 MBs | 32 MBs + | 16 bytes | 21 MBs | 21 MBs + | 32 bytes | 12 MBs | 12 MBs + | 64 bytes | 7 MBs | 7 MBs +flexcan5 | 8 bytes | 32 MBs | 32 MBs + | 16 bytes | 21 MBs | 21 MBs + | 32 bytes | 12 MBs | 12 MBs + | 64 bytes | 7 MBs | 7 MBs +=============== ========== ================ ================ + +.. note:: + A CAN bus usually requires 60 Ohm termination at both ends of the bus. This may be + accomplished using one of the included CAN termination boards. For more details, refer + to the section ``6.3 CAN Connectors`` in the Hardware User Manual of `NXP MR-CANHUBK3`_. + FS26 SBC Watchdog ================= diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index aedc0ebfb5f4..029a386e2b04 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -110,4 +110,70 @@ bias-pull-up; }; }; + + flexcan0_default: flexcan0_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + + flexcan1_default: flexcan1_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + + flexcan2_default: flexcan2_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + + flexcan3_default: flexcan3_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + + flexcan4_default: flexcan4_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + + flexcan5_default: flexcan5_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index e068090ec8b9..65d90dfa2cda 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -22,6 +22,7 @@ zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2; zephyr,flash-controller = &mx25l6433f; + zephyr,canbus = &flexcan0; }; aliases { @@ -59,6 +60,54 @@ gpios = <&gpioa_h 9 GPIO_ACTIVE_HIGH>; }; }; + + can_phy0: can-phy0 { + compatible = "nxp,tja1443", "can-transceiver-gpio"; + enable-gpios = <&gpioc_h 8 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpioc_h 5 GPIO_ACTIVE_LOW>; + max-bitrate = <5000000>; + #phy-cells = <0>; + }; + + can_phy1: can-phy1 { + compatible = "nxp,tja1443", "can-transceiver-gpio"; + enable-gpios = <&gpiod_l 2 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 7 GPIO_ACTIVE_LOW>; + max-bitrate = <5000000>; + #phy-cells = <0>; + }; + + can_phy2: can-phy2 { + compatible = "nxp,tja1463", "can-transceiver-gpio"; + enable-gpios = <&gpiod_l 4 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 6 GPIO_ACTIVE_LOW>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy3: can-phy3 { + compatible = "nxp,tja1463", "can-transceiver-gpio"; + enable-gpios = <&gpiob_l 0 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiob_l 1 GPIO_ACTIVE_LOW>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy4: can-phy4 { + compatible = "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioc_h 10 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpioc_h 9 GPIO_ACTIVE_LOW>; + max-bitrate = <2000000>; + #phy-cells = <0>; + }; + + can_phy5: can-phy5 { + compatible = "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioe_h 1 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpiod_h 14 GPIO_ACTIVE_LOW>; + max-bitrate = <2000000>; + #phy-cells = <0>; + }; }; &flash0 { @@ -87,10 +136,28 @@ status = "okay"; }; +/* Enable gpio to control the CAN transceivers */ + +&gpioc_h { + status = "okay"; +}; + &gpiod_l { status = "okay"; }; +&gpiod_h { + status = "okay"; +}; + +&gpiob_l { + status = "okay"; +}; + +&gpioe_h { + status = "okay"; +}; + &eirq0 { pinctrl-0 = <&eirq0_default>; pinctrl-names = "default"; @@ -168,3 +235,76 @@ }; }; }; + +&flexcan0 { + pinctrl-0 = <&flexcan0_default>; + pinctrl-names = "default"; + phys = <&can_phy0>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; + status = "okay"; +}; + +&flexcan1 { + pinctrl-0 = <&flexcan1_default>; + pinctrl-names = "default"; + phys = <&can_phy1>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; +}; + +&flexcan2 { + pinctrl-0 = <&flexcan2_default>; + pinctrl-names = "default"; + phys = <&can_phy2>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; +}; + +&flexcan3 { + pinctrl-0 = <&flexcan3_default>; + pinctrl-names = "default"; + phys = <&can_phy3>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; +}; + +&flexcan4 { + pinctrl-0 = <&flexcan4_default>; + pinctrl-names = "default"; + phys = <&can_phy4>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; +}; + +&flexcan5 { + pinctrl-0 = <&flexcan5_default>; + pinctrl-names = "default"; + phys = <&can_phy5>; + bus-speed = <125000>; + sample-point = <875>; + sjw = <1>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + sjw-data = <1>; +}; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.yaml b/boards/arm/mr_canhubk3/mr_canhubk3.yaml index 97abfd20b502..ca04df51ab82 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.yaml +++ b/boards/arm/mr_canhubk3/mr_canhubk3.yaml @@ -12,3 +12,4 @@ toolchain: supported: - gpio - uart + - can diff --git a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig index 91ebfcc17d2c..2cf92c9598b9 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig @@ -21,6 +21,7 @@ CONFIG_NOCACHE_MEMORY=y # Drivers CONFIG_PINCTRL=y CONFIG_SERIAL=y +CONFIG_GPIO=y # Enable support for GPIO controlled CAN transceivers # Serial console CONFIG_CONSOLE=y diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 5f2f373e618a..ed217192c879 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -423,6 +423,67 @@ #size-cells = <0>; status = "disabled"; }; + + flexcan0: can@40304000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40304000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANA_CLK>; + clk-source = <0>; + interrupts = <109 0>, <110 0>, <111 0>, <112 0>; + interrupt-names = "ored", "ored_0_31_mb", + "ored_32_63_mb", "ored_64_95_mb"; + status = "disabled"; + }; + + flexcan1: can@40308000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40308000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANA_CLK>; + clk-source = <0>; + interrupts = <113 0>, <114 0>, <115 0>; + interrupt-names = "ored", "ored_0_31_mb", "ored_32_63_mb"; + status = "disabled"; + }; + + flexcan2: can@4030c000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x4030c000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANA_CLK>; + clk-source = <0>; + interrupts = <116 0>, <117 0>, <118 0>; + interrupt-names = "ored", "ored_0_31_mb", "ored_32_63_mb"; + status = "disabled"; + }; + + flexcan3: can@40310000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40310000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANB_CLK>; + clk-source = <0>; + interrupts = <119 0>, <120 0>; + interrupt-names = "ored", "ored_0_31_mb"; + status = "disabled"; + }; + + flexcan4: can@40314000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40314000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANB_CLK>; + clk-source = <0>; + interrupts = <121 0>, <122 0>; + interrupt-names = "ored", "ored_0_31_mb"; + status = "disabled"; + }; + + flexcan5: can@40318000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40318000 0x4000>; + clocks = <&clock NXP_S32_FLEXCANB_CLK>; + clk-source = <0>; + interrupts = <123 0>, <124 0>; + interrupt-names = "ored", "ored_0_31_mb"; + status = "disabled"; + }; }; }; diff --git a/soc/arm/nxp_s32/s32k/Kconfig.series b/soc/arm/nxp_s32/s32k/Kconfig.series index 3bee28013eaf..28532cf18094 100644 --- a/soc/arm/nxp_s32/s32k/Kconfig.series +++ b/soc/arm/nxp_s32/s32k/Kconfig.series @@ -16,5 +16,6 @@ config SOC_SERIES_S32K3_M7 select CLOCK_CONTROL select HAS_MCUX select HAS_MCUX_LPUART + select HAS_MCUX_FLEXCAN help Enable support for NXP S32K3 MCUs family on Cortex-M7 cores diff --git a/west.yml b/west.yml index a358b56064ff..17fed2a7f10f 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 35b0e5afc4f061cedc5a0411e024dad6d9e8101f + revision: 9fb917ffde77b6ad7e9bfac35b0cb4012709e68c path: modules/hal/nxp groups: - hal From ae72fa7bf649e97535e7005b83f2c4adf05e685b Mon Sep 17 00:00:00 2001 From: Marc Desvaux Date: Wed, 28 Jun 2023 15:46:55 +0200 Subject: [PATCH 1894/2042] samples: net: zperf: add Ethernet twister test add one Ethernet twister test for nucleo_h563zi, nucleo_h743zi, nucleo_f429zi, nucleo_f746zg. remove the common: harnesses: net that are not supported leave harnesses: net for all other test execpt the one we use Signed-off-by: Marc Desvaux --- samples/net/zperf/sample.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/samples/net/zperf/sample.yaml b/samples/net/zperf/sample.yaml index 558b4f7d69de..82b8b519e79a 100644 --- a/samples/net/zperf/sample.yaml +++ b/samples/net/zperf/sample.yaml @@ -1,5 +1,4 @@ common: - harness: net tags: - net - zperf @@ -14,12 +13,26 @@ sample: name: zperf tests: sample.net.zperf: + harness: net platform_allow: qemu_x86 + sample.net.zperf_st: + harness: console + harness_config: + type: multi_line + regex: + - "coming up" + platform_allow: + - nucleo_h563zi + - nucleo_h743zi + - nucleo_f429zi + - nucleo_f746zg sample.net.zperf_no_shell: + harness: net extra_configs: - CONFIG_NET_SHELL=n platform_allow: qemu_x86 sample.net.zperf.netusb_ecm: + harness: net extra_args: OVERLAY_CONFIG="overlay-netusb.conf" tags: - usb @@ -27,12 +40,14 @@ tests: - zperf depends_on: usb_device sample.net.zperf.device_next_ecm: + harness: net extra_args: OVERLAY_CONFIG="overlay-usbd_next_ecm.conf" DTC_OVERLAY_FILE="usbd_next_ecm.overlay" platform_allow: nrf52840dk_nrf52840 frdm_k64f tags: usb net zperf depends_on: usb_device sample.net.zperf.netusb_eem: + harness: net extra_args: OVERLAY_CONFIG="overlay-netusb.conf" extra_configs: - CONFIG_USB_DEVICE_NETWORK_ECM=n @@ -43,6 +58,7 @@ tests: - zperf depends_on: usb_device sample.net.zperf.netusb_rndis: + harness: net extra_args: OVERLAY_CONFIG="overlay-netusb.conf" extra_configs: - CONFIG_USB_DEVICE_NETWORK_ECM=n @@ -53,6 +69,7 @@ tests: - zperf depends_on: usb_device sample.net.zperf.shield: + harness: net platform_allow: reel_board extra_args: SHIELD=link_board_eth tags: From 3d1285bc40312fdf6491d2438aab81b7f231d58f Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Mon, 10 Jul 2023 13:37:46 +0700 Subject: [PATCH 1895/2042] drivers: i2c_mcux: update to compatible with S32K344 Update to shim driver compatible with the hardware block in S32K344. Configure the pins before initializing I2C to avoid happening bus busy. Signed-off-by: Cong Nguyen Huu --- boards/arm/mr_canhubk3/doc/index.rst | 16 ++++++++++++++ .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 18 ++++++++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.dts | 12 +++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.yaml | 1 + drivers/i2c/i2c_mcux_lpi2c.c | 10 ++++----- dts/arm/nxp/nxp_s32k344_m7.dtsi | 21 +++++++++++++++++++ soc/arm/nxp_s32/s32k/Kconfig.series | 1 + 7 files changed, 74 insertions(+), 5 deletions(-) diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index bbdfd79c3ec0..9de092bf0b7e 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -51,6 +51,7 @@ SIUL2 on-chip | pinctrl LPUART on-chip serial QSPI on-chip flash FLEXCAN on-chip can +LPI2C on-chip i2c ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -175,6 +176,21 @@ flexcan5 | 8 bytes | 32 MBs | 32 MBs accomplished using one of the included CAN termination boards. For more details, refer to the section ``6.3 CAN Connectors`` in the Hardware User Manual of `NXP MR-CANHUBK3`_. +I2C +=== + +I2C is provided through LPI2C interface with 2 instances ``lpi2c0`` and ``lpi2c1`` +on corresponding connectors ``P4``, ``P3``. + +========= ===== ============ +Connector Pin Pin Function +========= ===== ============ +P3.2 PTD9 LPI2C1_SCL +P3.3 PTD8 LPI2C1_SDA +P4.3 PTD14 LPI2C0_SCL +P4.4 PTD13 LPI2C0_SDA +========= ===== ============ + FS26 SBC Watchdog ================= diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 029a386e2b04..460a4e35b468 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -176,4 +176,22 @@ output-enable; }; }; + + lpi2c0_default: lpi2c0_default { + group1 { + pinmux = <(PTD13_LPI2C0_SDA_I | PTD13_LPI2C0_SDA_O)>, + <(PTD14_LPI2C0_SCL_I | PTD14_LPI2C0_SCL_O)>; + input-enable; + output-enable; + }; + }; + + lpi2c1_default: lpi2c1_default { + group1 { + pinmux = <(PTD8_LPI2C1_SDA_I | PTD8_LPI2C1_SDA_O)>, + <(PTD9_LPI2C1_SCL_I | PTD9_LPI2C1_SCL_O)>; + input-enable; + output-enable; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index 65d90dfa2cda..df1f85c84b87 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -308,3 +308,15 @@ sample-point-data = <875>; sjw-data = <1>; }; + +&lpi2c0 { + pinctrl-0 = <&lpi2c0_default>; + pinctrl-names = "default"; + clock-frequency = ; +}; + +&lpi2c1 { + pinctrl-0 = <&lpi2c1_default>; + pinctrl-names = "default"; + clock-frequency = ; +}; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.yaml b/boards/arm/mr_canhubk3/mr_canhubk3.yaml index ca04df51ab82..1875c7cb5b09 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.yaml +++ b/boards/arm/mr_canhubk3/mr_canhubk3.yaml @@ -13,3 +13,4 @@ supported: - gpio - uart - can + - i2c diff --git a/drivers/i2c/i2c_mcux_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index 605ac838ef59..dea6d110eb07 100644 --- a/drivers/i2c/i2c_mcux_lpi2c.c +++ b/drivers/i2c/i2c_mcux_lpi2c.c @@ -494,6 +494,11 @@ static int mcux_lpi2c_init(const struct device *dev) return -ENODEV; } + error = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (error) { + return error; + } + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, &clock_freq)) { return -EINVAL; @@ -513,11 +518,6 @@ static int mcux_lpi2c_init(const struct device *dev) return error; } - error = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); - if (error) { - return error; - } - config->irq_config_func(dev); return 0; diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index ed217192c879..a434f2e7928a 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include / { cpus { @@ -484,6 +485,26 @@ interrupt-names = "ored", "ored_0_31_mb"; status = "disabled"; }; + + lpi2c0: i2c@40350000 { + compatible = "nxp,imx-lpi2c"; + reg = <0x40350000 0x10000>; + clocks = <&clock NXP_S32_LPI2C0_CLK>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <161 0>; + status = "disabled"; + }; + + lpi2c1: i2c@40354000 { + compatible = "nxp,imx-lpi2c"; + reg = <0x40354000 0x10000>; + clocks = <&clock NXP_S32_LPI2C1_CLK>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <162 0>; + status = "disabled"; + }; }; }; diff --git a/soc/arm/nxp_s32/s32k/Kconfig.series b/soc/arm/nxp_s32/s32k/Kconfig.series index 28532cf18094..5d41e1bc1dc9 100644 --- a/soc/arm/nxp_s32/s32k/Kconfig.series +++ b/soc/arm/nxp_s32/s32k/Kconfig.series @@ -17,5 +17,6 @@ config SOC_SERIES_S32K3_M7 select HAS_MCUX select HAS_MCUX_LPUART select HAS_MCUX_FLEXCAN + select HAS_MCUX_LPI2C help Enable support for NXP S32K3 MCUs family on Cortex-M7 cores From b77d40d1fe4b2fd2bdcc4c640c4388b92999156a Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Mon, 10 Jul 2023 13:47:12 +0700 Subject: [PATCH 1896/2042] tests: drivers: enable tests eeprom and i2c for mr_canhubk3 Enable tests: tests/drivers/eeprom/api, tests/drivers/i2c/i2c_target_api. Signed-off-by: Cong Nguyen Huu --- .../eeprom/api/boards/mr_canhubk3.overlay | 25 +++++++++++++++++++ .../i2c_target_api/boards/mr_canhubk3.overlay | 25 +++++++++++++++++++ .../drivers/i2c/i2c_target_api/testcase.yaml | 1 + west.yml | 2 +- 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/drivers/eeprom/api/boards/mr_canhubk3.overlay create mode 100644 tests/drivers/i2c/i2c_target_api/boards/mr_canhubk3.overlay diff --git a/tests/drivers/eeprom/api/boards/mr_canhubk3.overlay b/tests/drivers/eeprom/api/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..f63d3498b12d --- /dev/null +++ b/tests/drivers/eeprom/api/boards/mr_canhubk3.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Connect I2C0 (connector P4) to the external eeprom Microchip AT24C01C-XHM */ + +/ { + aliases { + eeprom-0 = &eeprom0; + }; +}; + +&lpi2c0 { + status = "okay"; + eeprom0: eeprom@50 { + compatible = "atmel,at24"; + reg = <0x50>; + size = <128>; + pagesize = <8>; + address-width = <8>; + timeout = <5>; + }; +}; diff --git a/tests/drivers/i2c/i2c_target_api/boards/mr_canhubk3.overlay b/tests/drivers/i2c/i2c_target_api/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..9bf7ca16907d --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/mr_canhubk3.overlay @@ -0,0 +1,25 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Connect P3.2 <-> P4.3 and P3.3 <-> P4.4 */ + +&lpi2c0 { + status = "okay"; + eeprom0: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <1024>; + }; +}; + +&lpi2c1 { + status = "okay"; + eeprom1: eeprom@56 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x56>; + size = <1024>; + }; +}; diff --git a/tests/drivers/i2c/i2c_target_api/testcase.yaml b/tests/drivers/i2c/i2c_target_api/testcase.yaml index 0ffc34a78073..bd7b34e03195 100644 --- a/tests/drivers/i2c/i2c_target_api/testcase.yaml +++ b/tests/drivers/i2c/i2c_target_api/testcase.yaml @@ -20,6 +20,7 @@ tests: - nucleo_l073rz - rpi_pico - efr32bg22_brd4184a + - mr_canhubk3 integration_platforms: - nucleo_f091rc extra_configs: diff --git a/west.yml b/west.yml index 17fed2a7f10f..27523c7b7653 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 9fb917ffde77b6ad7e9bfac35b0cb4012709e68c + revision: 3aed18634b19102cc0f9e56fcff88bd04edba6ec path: modules/hal/nxp groups: - hal From 724a5cd54f78c30813a2e0e78ca0168a1b4c1584 Mon Sep 17 00:00:00 2001 From: David Ullmann Date: Sat, 15 Jul 2023 19:21:35 -0400 Subject: [PATCH 1897/2042] board: add cy8ckit 062 pioneer Tested with hello_world and blinky projects Signed-off-by: David Ullmann --- CODEOWNERS | 1 + boards/arm/cy8ckit_062s4/Kconfig.board | 6 + boards/arm/cy8ckit_062s4/Kconfig.defconfig | 10 ++ boards/arm/cy8ckit_062s4/board.cmake | 5 + boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.dts | 57 ++++++++ .../arm/cy8ckit_062s4/cy8ckit_062s4_m4.yaml | 14 ++ .../cy8ckit_062s4/cy8ckit_062s4_m4_defconfig | 16 +++ .../cy8ckit_062s4/doc/img/cy8ckit_062s4.png | Bin 0 -> 85643 bytes boards/arm/cy8ckit_062s4/doc/index.rst | 115 ++++++++++++++++ .../psoc6/mpns/CY8C6244LQI_S4D92.dtsi | 2 +- .../psoc6/Kconfig.defconfig.soc.psoc6_04 | 37 ++++++ .../infineon_cat1/psoc6/Kconfig.soc.psoc6_04 | 125 ++++++++++++++++++ 12 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 boards/arm/cy8ckit_062s4/Kconfig.board create mode 100644 boards/arm/cy8ckit_062s4/Kconfig.defconfig create mode 100644 boards/arm/cy8ckit_062s4/board.cmake create mode 100644 boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.dts create mode 100644 boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.yaml create mode 100644 boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4_defconfig create mode 100644 boards/arm/cy8ckit_062s4/doc/img/cy8ckit_062s4.png create mode 100644 boards/arm/cy8ckit_062s4/doc/index.rst create mode 100644 soc/arm/infineon_cat1/psoc6/Kconfig.defconfig.soc.psoc6_04 create mode 100644 soc/arm/infineon_cat1/psoc6/Kconfig.soc.psoc6_04 diff --git a/CODEOWNERS b/CODEOWNERS index 937d4b6539d9..faf9d41e54b6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -111,6 +111,7 @@ /boards/arm/cc26x2r1_launchxl/ @bwitherspoon /boards/arm/cc3220sf_launchxl/ @vanti /boards/arm/cy8ckit_062_ble/ @ifyall @npal-cy +/boards/arm/cy8ckit_062s4/ @DaWei8823 /boards/arm/cy8ckit_062_wifi_bt/ @ifyall @npal-cy /boards/arm/cy8cproto_062_4343w/ @ifyall @npal-cy /boards/arm/disco_l475_iot1/ @erwango diff --git a/boards/arm/cy8ckit_062s4/Kconfig.board b/boards/arm/cy8ckit_062s4/Kconfig.board new file mode 100644 index 000000000000..ab9cc0284e61 --- /dev/null +++ b/boards/arm/cy8ckit_062s4/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 David Ullmann +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_CY8CKIT_062S4_M4 + bool "PSoC 62S4 pioneer kit" + depends on SOC_CY8C6244LQI_S4D92 diff --git a/boards/arm/cy8ckit_062s4/Kconfig.defconfig b/boards/arm/cy8ckit_062s4/Kconfig.defconfig new file mode 100644 index 000000000000..616fc65bb130 --- /dev/null +++ b/boards/arm/cy8ckit_062s4/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 David Ullmann +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_CY8CKIT_062S4_M4 + +config BOARD + default "cy8ckit_062s4_m4" if BOARD_CY8CKIT_062S4_M4 + + +endif #BOARD_CY8CKIT_062S4_M4 diff --git a/boards/arm/cy8ckit_062s4/board.cmake b/boards/arm/cy8ckit_062s4/board.cmake new file mode 100644 index 000000000000..7d0818b00d18 --- /dev/null +++ b/boards/arm/cy8ckit_062s4/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023 David Ullmann +# spdx-license-identifier: apache-2.0 + +board_runner_args(pyocd "--target=cy8c6xxa") +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.dts b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.dts new file mode 100644 index 000000000000..6695a24a4b88 --- /dev/null +++ b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.dts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 David Ullmann + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include + +/ { + model = "Infineon PSoC 62S4 Pioneer Kit"; + compatible ="cypress,psoc6"; + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart2; + zephyr,shell-uart = &uart2; + }; + + aliases { + led0 = &user_led; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_0 { + label = "LED_0"; + gpios = <&gpio_prt2 5 GPIO_ACTIVE_HIGH>; + }; + + }; + +}; + +&p3_1_scb2_uart_tx { + drive-push-pull; +}; + +&p3_0_scb2_uart_rx { + input-enable; +}; + + +uart2: &scb2 { + compatible = "infineon,cat1-uart"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&p3_0_scb2_uart_rx &p3_1_scb2_uart_tx>; + pinctrl-names = "default"; +}; + +&gpio_prt3 { + status = "okay"; +}; + +&gpio_prt2 { + status = "okay"; +}; diff --git a/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.yaml b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.yaml new file mode 100644 index 000000000000..4cf64830fcf6 --- /dev/null +++ b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4.yaml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 David Ullmann + +identifier: cy8ckit_062s4_m4 +name: CY8CKIT-062S4 PSoC 62S4 +type: mcu +arch: arm +ram: 128 +flash: 256 +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio diff --git a/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4_defconfig b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4_defconfig new file mode 100644 index 000000000000..1bbb92065f9d --- /dev/null +++ b/boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4_defconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 David Ullmann + +CONFIG_SOC_SERIES_PSOC_62=y +CONFIG_BOARD_CY8CKIT_062S4_M4=y +CONFIG_SOC_CY8C6244LQI_S4D92=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y + +CONFIG_PINCTRL=y +CONFIG_SOC_PSOC6_CM0P_IMAGE_SLEEP=y + +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_CORTEX_M_SYSTICK=y +CONFIG_XIP=y diff --git a/boards/arm/cy8ckit_062s4/doc/img/cy8ckit_062s4.png b/boards/arm/cy8ckit_062s4/doc/img/cy8ckit_062s4.png new file mode 100644 index 0000000000000000000000000000000000000000..b33384dab51c6bf38887f79e252a76e8d8d64c32 GIT binary patch literal 85643 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 iR53I) + +Hardware +******** + +`CY8CKIT 062S4 Pioneer Kit Website`_ +`CY8CKIT 062S4 Pioneer Kit Guide`_ +`CY8CKIT 062S4 Pioneer Kit Schematic`_ +`CY8CKIT 062S4 Pioneer Kit Technical Reference Manual`_ +`CY8CKIT 062S4 Pioneer Kit Datasheet`_ + +Supported Features +================== + +The board configuration supports the following hardware features: + ++-----------+------------+-----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=======================+ +| NVIC | on-chip | nested vectored | +| | | interrupt controller | ++-----------+------------+-----------------------+ +| SYSTICK | on-chip | system clock | ++-----------+------------+-----------------------+ +| PINCTRL | on-chip | pin control | ++-----------+------------+-----------------------+ +| UART | on-chip | serial port-polling; | ++-----------+------------+-----------------------+ + +The default configuration can be found in the Kconfig +:zephyr_file:`boards/arm/cy8ckit_062s4/cy8ckit_062s4_m4_defconfig`. + +Clock Configuration +=================== + ++-----------+------------+-----------------------+ +| Clock | Source | Output Frequency | ++===========+============+=======================+ +| FLL | IMO | 100.0 MHz | ++-----------+------------+-----------------------+ +| PLL | IMO | 48.0 MHz | ++-----------+------------+-----------------------+ +| CLK_HF0 | CLK_PATH0 | 100.0 MHz | ++-----------+------------+-----------------------+ + +Fetch Binary Blobs +================== + +.. code-block:: console + + west blobs fetch hal_infineon + + +Build and flash hello world sample +********************************** + + +.. code-block:: console + + cd zephyr/samples/hello_world + west build -p auto -b cy8ckit_062s4_m4 --pristine + west flash + picocom /dev/ttyACM0 -b 115200 + +OpenOCD Installation +==================== + +To get the OpenOCD package, it is required that you + +1. Download the software ModusToolbox 3.1. https://softwaretools.infineon.com/tools/com.ifx.tb.tool.modustoolbox +2. Once downloaded add the path to access the Scripts folder provided by ModusToolbox + export PATH=$PATH:/path/to/ModusToolbox/tools_3.1/openocd/scripts +3. Add the OpenOCD executable file's path to west flash/debug. +4. Flash using: west flash --openocd path/to/infineon/openocd/bin/openocd +5. Debug using: west debug --openocd path/to/infineon/openocd/bin/openocd + +References +********** + +.. _CY8CKIT 062S4 Pioneer Kit Guide: + https://www.infineon.com/dgdl/Infineon-CY8CKIT_062S4_PSoC62S4_pioneer_kit_guide-UserManual-v01_00-EN.pdf?fileId=8ac78c8c7e7124d1017e962f98992207 + +.. _CY8CKIT 062S4 Pioneer Kit Website: + https://www.infineon.com/cms/en/product/evaluation-boards/cy8ckit-062s4/?redirId=VL1508&utm_medium=referral&utm_source=cypress&utm_campaign=202110_globe_en_all_integration-dev_kit + +.. _CY8CKIT 062S4 Pioneer Kit Schematic: + https://www.infineon.com/dgdl/Infineon-CY8CKIT-062S4_PSoC_62S4_Pioneer_Kit_Schematic-PCBDesignData-v01_00-EN.pdf?fileId=8ac78c8c7d710014017d7153484d2081 + +.. _CY8CKIT 062S4 Pioneer Kit Technical Reference Manual: + https://www.infineon.com/dgdl/Infineon-PSOC_6_MCU_CY8C61X4CY8C62X4_REGISTERS_TECHNICAL_REFERENCE_MANUAL_(TRM)_PSOC_61_PSOC_62_MCU-AdditionalTechnicalInformation-v03_00-EN.pdf?fileId=8ac78c8c7d0d8da4017d0fb34f0627a7 + +.. _CY8CKIT 062S4 Pioneer Kit Datasheet: + https://www.infineon.com/dgdl/Infineon-PSoC_6_MCU_CY8C62X4-DataSheet-v12_00-EN.pdf?fileId=8ac78c8c7ddc01d7017ddd026d585901 diff --git a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi b/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi index 48795999d1bd..c5561e9f074f 100644 --- a/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi +++ b/dts/arm/infineon/psoc6/mpns/CY8C6244LQI_S4D92.dtsi @@ -8,7 +8,7 @@ #include #include "../psoc6_04/psoc6_04.68-qfn.dtsi" -/delete-node/ &scb3; +/delete-node/ &flash1; &nvic { arm,num-irq-priority-bits = <3>; diff --git a/soc/arm/infineon_cat1/psoc6/Kconfig.defconfig.soc.psoc6_04 b/soc/arm/infineon_cat1/psoc6/Kconfig.defconfig.soc.psoc6_04 new file mode 100644 index 000000000000..622a0af848f3 --- /dev/null +++ b/soc/arm/infineon_cat1/psoc6/Kconfig.defconfig.soc.psoc6_04 @@ -0,0 +1,37 @@ +# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# Copyright (c) David Ullmann +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_04 based MCU default configuration + +if SOC_DIE_PSOC6_04 + +config NUM_IRQS + default 16 if CPU_CORTEX_M0PLUS + default 175 if CPU_CORTEX_M4 + +config SOC + default "CY8C6244AZI_S4D92" if SOC_CY8C6244AZI_S4D92 + default "CY8C6244LQI_S4D92" if SOC_CY8C6244LQI_S4D92 + default "CY8C6244AZI_S4D93" if SOC_CY8C6244AZI_S4D93 + default "CY8C6244AZI_S4D82" if SOC_CY8C6244AZI_S4D82 + default "CY8C6244LQI_S4D82" if SOC_CY8C6244LQI_S4D82 + default "CY8C6244AZI_S4D83" if SOC_CY8C6244AZI_S4D83 + default "CY8C6244AZI_S4D62" if SOC_CY8C6244AZI_S4D62 + default "CY8C6244LQI_S4D62" if SOC_CY8C6244LQI_S4D62 + default "CY8C6244AZI_S4D12" if SOC_CY8C6244AZI_S4D12 + default "CY8C6244LQI_S4D12" if SOC_CY8C6244LQI_S4D12 + default "CY8C6144AZI_S4F92" if SOC_CY8C6144AZI_S4F92 + default "CY8C6144LQI_S4F92" if SOC_CY8C6144LQI_S4F92 + default "CY8C6144AZI_S4F93" if SOC_CY8C6144AZI_S4F93 + default "CY8C6144AZI_S4F82" if SOC_CY8C6144AZI_S4F82 + default "CY8C6144LQI_S4F82" if SOC_CY8C6144LQI_S4F82 + default "CY8C6144AZI_S4F83" if SOC_CY8C6144AZI_S4F83 + default "CY8C6144AZI_S4F62" if SOC_CY8C6144AZI_S4F62 + default "CY8C6144LQI_S4F62" if SOC_CY8C6144LQI_S4F62 + default "CY8C6144AZI_S4F12" if SOC_CY8C6144AZI_S4F12 + default "CY8C6144LQI_S4F12" if SOC_CY8C6144LQI_S4F12 + + +endif # SOC_DIE_PSOC6_04 diff --git a/soc/arm/infineon_cat1/psoc6/Kconfig.soc.psoc6_04 b/soc/arm/infineon_cat1/psoc6/Kconfig.soc.psoc6_04 new file mode 100644 index 000000000000..b18e8ecaa825 --- /dev/null +++ b/soc/arm/infineon_cat1/psoc6/Kconfig.soc.psoc6_04 @@ -0,0 +1,125 @@ +# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Infineon PSoC6_04 series MCUs + +config SOC_CY8C6244AZI_S4D92 + bool "CY8C6244AZI_S4D92" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244LQI_S4D92 + bool "CY8C6244LQI_S4D92" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244AZI_S4D93 + bool "CY8C6244AZI_S4D93" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244AZI_S4D82 + bool "CY8C6244AZI_S4D82" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244LQI_S4D82 + bool "CY8C6244LQI_S4D82" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244AZI_S4D83 + bool "CY8C6244AZI_S4D83" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244AZI_S4D62 + bool "CY8C6244AZI_S4D62" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244LQI_S4D62 + bool "CY8C6244LQI_S4D62" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244AZI_S4D12 + bool "CY8C6244AZI_S4D12" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6244LQI_S4D12 + bool "CY8C6244LQI_S4D12" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_62 + +config SOC_CY8C6144AZI_S4F92 + bool "CY8C6144AZI_S4F92" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144LQI_S4F92 + bool "CY8C6144LQI_S4F92" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144AZI_S4F93 + bool "CY8C6144AZI_S4F93" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144AZI_S4F82 + bool "CY8C6144AZI_S4F82" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144LQI_S4F82 + bool "CY8C6144LQI_S4F82" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144AZI_S4F83 + bool "CY8C6144AZI_S4F83" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_80_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144AZI_S4F62 + bool "CY8C6144AZI_S4F62" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144LQI_S4F62 + bool "CY8C6144LQI_S4F62" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144AZI_S4F12 + bool "CY8C6144AZI_S4F12" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_64_TQFP + depends on SOC_SERIES_PSOC_61 + +config SOC_CY8C6144LQI_S4F12 + bool "CY8C6144LQI_S4F12" + select SOC_DIE_PSOC6_04 + select SOC_PACKAGE_PSOC6_04_68_QFN + depends on SOC_SERIES_PSOC_61 From 7da7742c66843b66ad00d6f6e97cde2626acbf1a Mon Sep 17 00:00:00 2001 From: Bruno Mendes Date: Thu, 27 Jul 2023 11:39:13 +0100 Subject: [PATCH 1898/2042] west debugserver: openocd: configure rtos This enables thread awareness in the spawned OpenOCD server. Signed-off-by: Bruno Mendes --- scripts/west_commands/runners/openocd.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/west_commands/runners/openocd.py b/scripts/west_commands/runners/openocd.py index 0346935a22e5..ff92d4f58f45 100644 --- a/scripts/west_commands/runners/openocd.py +++ b/scripts/west_commands/runners/openocd.py @@ -356,6 +356,11 @@ def do_debugserver(self, **kwargs): pre_init_cmd.append("-c") pre_init_cmd.append(i) + if self.thread_info_enabled and self.supports_thread_info(): + pre_init_cmd.append("-c") + rtos_command = '${} configure -rtos Zephyr'.format(self.target_handle) + pre_init_cmd.append(rtos_command) + cmd = (self.openocd_cmd + self.cfg_cmd + ['-c', 'tcl_port {}'.format(self.tcl_port), '-c', 'telnet_port {}'.format(self.telnet_port), From 74859013f13a1310f1f8959d47fd9dd74f30b7a6 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Thu, 27 Jul 2023 11:52:22 +0200 Subject: [PATCH 1899/2042] lib: cpp: name the choice group for selecting C++ standard Add a name to the choice group for selecting the C++ standard to be able to override the default standard in Kconfig.* files. Signed-off-by: Damian Krolik --- lib/cpp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cpp/Kconfig b/lib/cpp/Kconfig index 3cfb8ac57e9d..52084fbe6906 100644 --- a/lib/cpp/Kconfig +++ b/lib/cpp/Kconfig @@ -12,7 +12,7 @@ config CPP if CPP -choice +choice STD_CPP prompt "C++ Standard" default STD_CPP11 help From aecb1ca2e79ddcd2142a47715b6ad9aea4410476 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Thu, 27 Jul 2023 15:57:08 +0200 Subject: [PATCH 1900/2042] usb: device: move the content of usb_msc.h to implementation file The usb_msc.h header does not provide any API. The content is only used by the MSC implementation for the current USB device stack and is not required for any use of MSC by the application. The content has no proper namespace and must not be reused for anything else in (new) USB support. Signed-off-by: Johann Fischer --- include/zephyr/usb/class/usb_msc.h | 109 ----------------------------- subsys/usb/device/class/msc.c | 61 +++++++++++++++- 2 files changed, 60 insertions(+), 110 deletions(-) delete mode 100644 include/zephyr/usb/class/usb_msc.h diff --git a/include/zephyr/usb/class/usb_msc.h b/include/zephyr/usb/class/usb_msc.h deleted file mode 100644 index add76ac68bf5..000000000000 --- a/include/zephyr/usb/class/usb_msc.h +++ /dev/null @@ -1,109 +0,0 @@ -/* usb_msc.h - USB MSC public header */ - -/* - * Copyright (c) 2017 PHYTEC Messtechnik GmbH - * - * SPDX-License-Identifier: Apache-2.0 - * - * This file is based on mass_storage.h - * - * This file are derived from material that is - * Copyright (c) 2010-2011 mbed.org, MIT License - * Copyright (c) 2016 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - - -/** - * @file - * @brief USB Mass Storage Class public header - * - * Header follows the Mass Storage Class Specification - * (Mass_Storage_Specification_Overview_v1.4_2-19-2010.pdf) and - * Mass Storage Class Bulk-Only Transport Specification - * (usbmassbulk_10.pdf). - * Header is limited to Bulk-Only Transfer protocol. - */ - -#ifndef ZEPHYR_INCLUDE_USB_CLASS_USB_MSC_H_ -#define ZEPHYR_INCLUDE_USB_CLASS_USB_MSC_H_ - -/** MSC Subclass and Protocol Codes */ -#define SCSI_TRANSPARENT_SUBCLASS 0x06 -#define BULK_ONLY_TRANSPORT_PROTOCOL 0x50 - -/** MSC Request Codes for Bulk-Only Transport */ -#define MSC_REQUEST_GET_MAX_LUN 0xFE -#define MSC_REQUEST_RESET 0xFF - -/** MSC Command Block Wrapper (CBW) Signature */ -#define CBW_Signature 0x43425355 - -/** MSC Command Block Wrapper Flags */ -#define CBW_DIRECTION_DATA_IN 0x80 - -/** MSC Bulk-Only Command Block Wrapper (CBW) */ -struct CBW { - uint32_t Signature; - uint32_t Tag; - uint32_t DataLength; - uint8_t Flags; - uint8_t LUN; - uint8_t CBLength; - uint8_t CB[16]; -} __packed; - -/** MSC Command Status Wrapper (CBW) Signature */ -#define CSW_Signature 0x53425355 - -/** MSC Command Block Status Values */ -#define CSW_STATUS_CMD_PASSED 0x00 -#define CSW_STATUS_CMD_FAILED 0x01 -#define CSW_STATUS_PHASE_ERROR 0x02 - -/** MSC Bulk-Only Command Status Wrapper (CSW) */ -struct CSW { - uint32_t Signature; - uint32_t Tag; - uint32_t DataResidue; - uint8_t Status; -} __packed; - -/** SCSI transparent command set used by MSC */ -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define FORMAT_UNIT 0x04 -#define INQUIRY 0x12 -#define MODE_SELECT6 0x15 -#define MODE_SENSE6 0x1A -#define START_STOP_UNIT 0x1B -#define MEDIA_REMOVAL 0x1E -#define READ_FORMAT_CAPACITIES 0x23 -#define READ_CAPACITY 0x25 -#define READ10 0x28 -#define WRITE10 0x2A -#define VERIFY10 0x2F -#define READ12 0xA8 -#define WRITE12 0xAA -#define MODE_SELECT10 0x55 -#define MODE_SENSE10 0x5A - -#endif /* ZEPHYR_INCLUDE_USB_CLASS_USB_MSC_H_ */ diff --git a/subsys/usb/device/class/msc.c b/subsys/usb/device/class/msc.c index 037381cbafc0..6eae1f6a3aba 100644 --- a/subsys/usb/device/class/msc.c +++ b/subsys/usb/device/class/msc.c @@ -39,13 +39,72 @@ #include #include #include -#include #include #include #include LOG_MODULE_REGISTER(usb_msc, CONFIG_USB_MASS_STORAGE_LOG_LEVEL); +/* MSC Subclass and Protocol Codes */ +#define SCSI_TRANSPARENT_SUBCLASS 0x06 +#define BULK_ONLY_TRANSPORT_PROTOCOL 0x50 + +/* MSC Request Codes for Bulk-Only Transport */ +#define MSC_REQUEST_GET_MAX_LUN 0xFE +#define MSC_REQUEST_RESET 0xFF + +/* MSC Command Block Wrapper (CBW) Signature */ +#define CBW_Signature 0x43425355 + +/* MSC Command Block Wrapper Flags */ +#define CBW_DIRECTION_DATA_IN 0x80 + +/* MSC Bulk-Only Command Block Wrapper (CBW) */ +struct CBW { + uint32_t Signature; + uint32_t Tag; + uint32_t DataLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; +} __packed; + +/* MSC Command Status Wrapper (CBW) Signature */ +#define CSW_Signature 0x53425355 + +/* MSC Command Block Status Values */ +#define CSW_STATUS_CMD_PASSED 0x00 +#define CSW_STATUS_CMD_FAILED 0x01 +#define CSW_STATUS_PHASE_ERROR 0x02 + +/* MSC Bulk-Only Command Status Wrapper (CSW) */ +struct CSW { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; +} __packed; + +/* SCSI transparent command set used by MSC */ +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +#define MODE_SELECT6 0x15 +#define MODE_SENSE6 0x1A +#define START_STOP_UNIT 0x1B +#define MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITIES 0x23 +#define READ_CAPACITY 0x25 +#define READ10 0x28 +#define WRITE10 0x2A +#define VERIFY10 0x2F +#define READ12 0xA8 +#define WRITE12 0xAA +#define MODE_SELECT10 0x55 +#define MODE_SENSE10 0x5A + /* max USB packet size */ #define MAX_PACKET CONFIG_MASS_STORAGE_BULK_EP_MPS From 85059866d5f4ea57ece549e84911682e3e33e9be Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Thu, 27 Jul 2023 17:14:24 +0200 Subject: [PATCH 1901/2042] native_simulator: Align with upstream latest Upstream SHA: c8d3e4134ee24f8c3bbc598dfc80520c5a0c46d5 Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/common/src/nct.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/scripts/native_simulator/common/src/nct.c b/scripts/native_simulator/common/src/nct.c index d048f52954f6..c56ee2034d4c 100644 --- a/scripts/native_simulator/common/src/nct.c +++ b/scripts/native_simulator/common/src/nct.c @@ -79,6 +79,7 @@ #define ERPREFIX PREFIX"error on " #define NO_MEM_ERR PREFIX"Can't allocate memory\n" +#define NCT_ENABLE_CANCEL 0 /* See Note.c1 */ #define NCT_ALLOC_CHUNK_SIZE 64 /* In how big chunks we grow the thread table */ #define NCT_REUSE_ABORTED_ENTRIES 0 /* For the Zephyr OS, tests/kernel/threads/scheduling/schedule_api fails when setting @@ -552,7 +553,6 @@ void *nct_init(void (*fptr)(void *)) void nct_clean_up(void *this_arg) { struct te_status_t *this = (struct te_status_t *)this_arg; - struct threads_table_el *tt_el; if (!this || !this->threads_table) { /* LCOV_EXCL_BR_LINE */ return; /* LCOV_EXCL_LINE */ @@ -560,7 +560,8 @@ void nct_clean_up(void *this_arg) this->terminate = true; - tt_el = this->threads_table; +#if (NCT_ENABLE_CANCEL) + struct threads_table_el *tt_el = this->threads_table; for (int i = 0; i < this->threads_table_size; i++, tt_el = tt_el->next) { if (tt_el->state != USED) { @@ -575,7 +576,7 @@ void nct_clean_up(void *this_arg) } /* LCOV_EXCL_STOP */ } - +#endif /* * This is the cleanup we do not do: * @@ -687,4 +688,17 @@ int nct_get_unique_thread_id(void *this_arg, int thread_idx) * Some other code will never or only very rarely trigger and is therefore * excluded with LCOV_EXCL_LINE * + * + * Notes about (memory) cleanup: + * + * Note.c1: + * + * In some very rare cases in very loaded machines, a race in the glibc pthread_cancel() + * seems to be triggered. + * In this, the cancelled thread cleanup overtakes the pthread_cancel() code, and frees the + * pthread structure before pthread_cancel() has finished, resulting in a dereference into already + * free'd memory, and therefore a segfault. + * Calling pthread_cancel() during cleanup is not required beyond preventing a valgrind + * memory leak report (all threads will be canceled immediately on exit). + * Therefore we do not do this, to avoid this very rare crashes. */ From 16e1526866219ce648731dd5e93a10bfa2d619d3 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Thu, 27 Jul 2023 13:45:02 -0400 Subject: [PATCH 1902/2042] tests: thrift: check for channel closure before throwing Previously, the binary protocol variant of ThriftTest would fail consistently in CI for `qemu_x86_64` with the message below. ``` E: failed to poll fds -1, -1: 1 ``` Note: 1 corresponds to EPERM The root cause of this is that we do not yet have support for standard synchronization primitives in C++, and there is slightly racey behaviour in thrift until we do have support for standard synchronization primitives. With the addition of dynamic thread stacks, conforming pthreads, and some additional work in the toolchain area (re gthr-posix.h), we should soon be able to enable proper synchronization primitives. This change is a temporary workaround but solves the test failure (which would occur even when tests all passed). Signed-off-by: Christopher Friedt --- modules/thrift/src/thrift/server/TFDServer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/thrift/src/thrift/server/TFDServer.cpp b/modules/thrift/src/thrift/server/TFDServer.cpp index 30cb1e3ad8b1..f87bcb5684e0 100644 --- a/modules/thrift/src/thrift/server/TFDServer.cpp +++ b/modules/thrift/src/thrift/server/TFDServer.cpp @@ -71,6 +71,11 @@ class xport : public TVirtualTransport r = poll(&pollfds.front(), pollfds.size(), -1); if (r == -1) { + if (efd == -1 || fd == -1) { + /* channel has been closed */ + return 0; + } + LOG_ERR("failed to poll fds %d, %d: %d", fd, efd, errno); throw system_error(errno, system_category(), "poll"); } From 5818031af72646bd7f5656a27316d7d1cefafa1c Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Wed, 26 Jul 2023 19:21:38 +0000 Subject: [PATCH 1903/2042] boards: arm: stm32f746g_disco: Use specified USB serial The 'west flash' command allows specifying the port where the target is attached via the '--serial' option, allowing users to set the USB serial port for flashing. However, the 'stm32f746g_disco' script file currently ignores the _ZEPHYR_BOARD_SERIAL variable set by this option, preventing effective port specification. This commit fixes it by correctly setting the openocd adapter serial when _ZEPHYR_BOARD_SERIAL variable is set, enabling proper USB serial port specification during flashing. Signed-off-by: Gustavo Romero --- boards/arm/stm32f746g_disco/support/openocd.cfg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/boards/arm/stm32f746g_disco/support/openocd.cfg b/boards/arm/stm32f746g_disco/support/openocd.cfg index ad005693e338..2dd9cf42c1c0 100644 --- a/boards/arm/stm32f746g_disco/support/openocd.cfg +++ b/boards/arm/stm32f746g_disco/support/openocd.cfg @@ -11,9 +11,13 @@ $_TARGETNAME configure -event gdb-detach { resume } +if { [info exists _ZEPHYR_BOARD_SERIAL] } { + adapter serial $_ZEPHYR_BOARD_SERIAL +} + # Event reset-init already uses the maximum speed however adapter speed # inherited from stm32f7x.cfg for reset-start defaults to 2000 kHz, so # override that speed setting it also to the maximum speed. $_TARGETNAME configure -event reset-start { - adapter speed 4000 + adapter speed 4000 } From cbb83d64ab768efcb1f75ad41c56505fe7d9bf31 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 27 Jul 2023 21:05:32 +0200 Subject: [PATCH 1904/2042] dts: bindings: rename st-morpho-header pin identifiers So far pin identifiers were named after CN7 and CN10 connector names on Nucleo-64 boards. In case of Nucleo-144 there are ST Morpho connectors on both sides, but bigger (up to 72 instead of 38 pins on each side). First 38 pins out of 72 on each side usually map to the same pins (e.g. PA5 being 13th pin on right ST Morpho connector). This means that single ST Morpho connector definition will suffice. Leaving CN7 and CN10 (name of pin headers on Nucleo-64 boards) is confusing in context of Nucleo-144 boards, since corresponding pin headers are named CN11 and CN12. Rename: * s/ST_MORPHO_CN7_/ST_MORPHO_L_/ * s/ST_MORPHO_CN10_/ST_MORPHO_R_/ so that pin identifiers make more sense in context of Nucleo-144 boards. Signed-off-by: Marcin Niestroj --- .../nucleo_f030r8/st_morpho_connector.dtsi | 110 ++++++------- .../nucleo_f070rb/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_f091rc/st_morpho_connector.dtsi | 104 ++++++------ .../nucleo_f103rb/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_f302r8/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_f303re/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_f334r8/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_f401re/st_morpho_connector.dtsi | 100 ++++++------ .../nucleo_f410rb/st_morpho_connector.dtsi | 100 ++++++------ .../nucleo_f411re/st_morpho_connector.dtsi | 100 ++++++------ .../nucleo_f446re/st_morpho_connector.dtsi | 100 ++++++------ .../nucleo_g431rb/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_l053r8/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_l073rz/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_l152re/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_l452re/st_morpho_connector.dtsi | 102 ++++++------ .../nucleo_l476rg/st_morpho_connector.dtsi | 102 ++++++------ dts/bindings/gpio/st-morpho-header.yaml | 7 +- .../dt-bindings/gpio/st-morpho-header.h | 153 +++++++++--------- 19 files changed, 949 insertions(+), 947 deletions(-) diff --git a/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi b/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi index 6ab1c8ce24d6..745c50a5ca93 100644 --- a/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f030r8/st_morpho_connector.dtsi @@ -12,60 +12,60 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi index 0727b65bc252..5f05f019a2cf 100644 --- a/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f070rb/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi b/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi index 354dab3052f2..900d50219859 100644 --- a/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f091rc/st_morpho_connector.dtsi @@ -12,57 +12,57 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi index 3bfb0315db3a..46f13702e072 100644 --- a/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f103rb/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f302r8/st_morpho_connector.dtsi b/boards/arm/nucleo_f302r8/st_morpho_connector.dtsi index 61a86c06c429..4b0b19bb2232 100644 --- a/boards/arm/nucleo_f302r8/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f302r8/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f303re/st_morpho_connector.dtsi b/boards/arm/nucleo_f303re/st_morpho_connector.dtsi index 0727b65bc252..5f05f019a2cf 100644 --- a/boards/arm/nucleo_f303re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f303re/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi b/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi index 0727b65bc252..5f05f019a2cf 100644 --- a/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f334r8/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f401re/st_morpho_connector.dtsi b/boards/arm/nucleo_f401re/st_morpho_connector.dtsi index 2385545b7f28..eb4c8f0e4f75 100644 --- a/boards/arm/nucleo_f401re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f401re/st_morpho_connector.dtsi @@ -12,55 +12,55 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi b/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi index b4d0911921a7..d91c931f633b 100644 --- a/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f410rb/st_morpho_connector.dtsi @@ -12,55 +12,55 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f411re/st_morpho_connector.dtsi b/boards/arm/nucleo_f411re/st_morpho_connector.dtsi index 2385545b7f28..eb4c8f0e4f75 100644 --- a/boards/arm/nucleo_f411re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f411re/st_morpho_connector.dtsi @@ -12,55 +12,55 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_f446re/st_morpho_connector.dtsi b/boards/arm/nucleo_f446re/st_morpho_connector.dtsi index 2385545b7f28..eb4c8f0e4f75 100644 --- a/boards/arm/nucleo_f446re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_f446re/st_morpho_connector.dtsi @@ -12,55 +12,55 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_g431rb/st_morpho_connector.dtsi b/boards/arm/nucleo_g431rb/st_morpho_connector.dtsi index 61a86c06c429..4b0b19bb2232 100644 --- a/boards/arm/nucleo_g431rb/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_g431rb/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi b/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi index 30c9999389c2..3c0d419f02f9 100644 --- a/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_l053r8/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi b/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi index 30c9999389c2..3c0d419f02f9 100644 --- a/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_l073rz/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_l152re/st_morpho_connector.dtsi b/boards/arm/nucleo_l152re/st_morpho_connector.dtsi index 30c9999389c2..3c0d419f02f9 100644 --- a/boards/arm/nucleo_l152re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_l152re/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_l452re/st_morpho_connector.dtsi b/boards/arm/nucleo_l452re/st_morpho_connector.dtsi index 30c9999389c2..3c0d419f02f9 100644 --- a/boards/arm/nucleo_l452re/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_l452re/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi b/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi index 30c9999389c2..3c0d419f02f9 100644 --- a/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi +++ b/boards/arm/nucleo_l476rg/st_morpho_connector.dtsi @@ -12,56 +12,56 @@ #gpio-cells = <2>; gpio-map-mask = ; gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; - gpio-map = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , /* SB56=ON, SB46=OFF */ - , - , /* SB51=ON, SB52=OFF */ - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB56=ON, SB46=OFF */ + , + , /* SB51=ON, SB52=OFF */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; }; diff --git a/dts/bindings/gpio/st-morpho-header.yaml b/dts/bindings/gpio/st-morpho-header.yaml index fb6568d2f11f..c1726b7a2d66 100644 --- a/dts/bindings/gpio/st-morpho-header.yaml +++ b/dts/bindings/gpio/st-morpho-header.yaml @@ -4,9 +4,10 @@ description: | GPIO pins exposed on ST Morpho connector. - The ST morpho connector consists in male pin headers (CN7 and CN10) accessible - on both sides of any Nucleo board. They can be used to connect shields. All - signals and power pins of the STM32 are available on the ST morpho connector. + The ST morpho connector consists in male pin headers (CN7 and CN10 in case of + Nucleo-64, CN11 and CN12 in case of Nucleo-144) accessible on both sides of + any Nucleo board. They can be used to connect shields. All signals and power + pins of the STM32 are available on the ST morpho connector. compatible: "st-morpho-header" diff --git a/include/zephyr/dt-bindings/gpio/st-morpho-header.h b/include/zephyr/dt-bindings/gpio/st-morpho-header.h index c2365fdc7ffe..1d0e9e6a8808 100644 --- a/include/zephyr/dt-bindings/gpio/st-morpho-header.h +++ b/include/zephyr/dt-bindings/gpio/st-morpho-header.h @@ -12,82 +12,83 @@ * @name ST Morpho pin identifiers * @{ */ -#define ST_MORPHO_CN7_1 0 -#define ST_MORPHO_CN7_2 1 -#define ST_MORPHO_CN7_3 2 -#define ST_MORPHO_CN7_4 3 -#define ST_MORPHO_CN7_5 4 -#define ST_MORPHO_CN7_6 5 -#define ST_MORPHO_CN7_7 6 -#define ST_MORPHO_CN7_8 7 -#define ST_MORPHO_CN7_9 8 -#define ST_MORPHO_CN7_10 9 -#define ST_MORPHO_CN7_11 10 -#define ST_MORPHO_CN7_12 11 -#define ST_MORPHO_CN7_13 12 -#define ST_MORPHO_CN7_14 13 -#define ST_MORPHO_CN7_15 14 -#define ST_MORPHO_CN7_16 15 -#define ST_MORPHO_CN7_17 16 -#define ST_MORPHO_CN7_18 17 -#define ST_MORPHO_CN7_19 18 -#define ST_MORPHO_CN7_20 19 -#define ST_MORPHO_CN7_21 20 -#define ST_MORPHO_CN7_22 21 -#define ST_MORPHO_CN7_23 22 -#define ST_MORPHO_CN7_24 23 -#define ST_MORPHO_CN7_25 24 -#define ST_MORPHO_CN7_26 25 -#define ST_MORPHO_CN7_27 26 -#define ST_MORPHO_CN7_28 27 -#define ST_MORPHO_CN7_29 28 -#define ST_MORPHO_CN7_30 29 -#define ST_MORPHO_CN7_31 30 -#define ST_MORPHO_CN7_32 31 -#define ST_MORPHO_CN7_33 32 -#define ST_MORPHO_CN7_34 33 -#define ST_MORPHO_CN7_35 34 -#define ST_MORPHO_CN7_36 35 -#define ST_MORPHO_CN7_37 36 -#define ST_MORPHO_CN7_38 37 -#define ST_MORPHO_CN10_1 38 -#define ST_MORPHO_CN10_2 39 -#define ST_MORPHO_CN10_3 40 -#define ST_MORPHO_CN10_4 41 -#define ST_MORPHO_CN10_5 42 -#define ST_MORPHO_CN10_6 43 -#define ST_MORPHO_CN10_7 44 -#define ST_MORPHO_CN10_8 45 -#define ST_MORPHO_CN10_9 46 -#define ST_MORPHO_CN10_10 47 -#define ST_MORPHO_CN10_11 48 -#define ST_MORPHO_CN10_12 49 -#define ST_MORPHO_CN10_13 50 -#define ST_MORPHO_CN10_14 51 -#define ST_MORPHO_CN10_15 52 -#define ST_MORPHO_CN10_16 53 -#define ST_MORPHO_CN10_17 54 -#define ST_MORPHO_CN10_18 55 -#define ST_MORPHO_CN10_19 56 -#define ST_MORPHO_CN10_20 57 -#define ST_MORPHO_CN10_21 58 -#define ST_MORPHO_CN10_22 59 -#define ST_MORPHO_CN10_23 60 -#define ST_MORPHO_CN10_24 61 -#define ST_MORPHO_CN10_25 62 -#define ST_MORPHO_CN10_26 63 -#define ST_MORPHO_CN10_27 64 -#define ST_MORPHO_CN10_28 65 -#define ST_MORPHO_CN10_29 66 -#define ST_MORPHO_CN10_30 67 -#define ST_MORPHO_CN10_31 68 -#define ST_MORPHO_CN10_32 69 -#define ST_MORPHO_CN10_33 70 -#define ST_MORPHO_CN10_34 71 -#define ST_MORPHO_CN10_35 72 -#define ST_MORPHO_CN10_36 73 -#define ST_MORPHO_CN10_37 74 -#define ST_MORPHO_CN10_38 75 +#define ST_MORPHO_L_1 0 +#define ST_MORPHO_L_2 1 +#define ST_MORPHO_L_3 2 +#define ST_MORPHO_L_4 3 +#define ST_MORPHO_L_5 4 +#define ST_MORPHO_L_6 5 +#define ST_MORPHO_L_7 6 +#define ST_MORPHO_L_8 7 +#define ST_MORPHO_L_9 8 +#define ST_MORPHO_L_10 9 +#define ST_MORPHO_L_11 10 +#define ST_MORPHO_L_12 11 +#define ST_MORPHO_L_13 12 +#define ST_MORPHO_L_14 13 +#define ST_MORPHO_L_15 14 +#define ST_MORPHO_L_16 15 +#define ST_MORPHO_L_17 16 +#define ST_MORPHO_L_18 17 +#define ST_MORPHO_L_19 18 +#define ST_MORPHO_L_20 19 +#define ST_MORPHO_L_21 20 +#define ST_MORPHO_L_22 21 +#define ST_MORPHO_L_23 22 +#define ST_MORPHO_L_24 23 +#define ST_MORPHO_L_25 24 +#define ST_MORPHO_L_26 25 +#define ST_MORPHO_L_27 26 +#define ST_MORPHO_L_28 27 +#define ST_MORPHO_L_29 28 +#define ST_MORPHO_L_30 29 +#define ST_MORPHO_L_31 30 +#define ST_MORPHO_L_32 31 +#define ST_MORPHO_L_33 32 +#define ST_MORPHO_L_34 33 +#define ST_MORPHO_L_35 34 +#define ST_MORPHO_L_36 35 +#define ST_MORPHO_L_37 36 +#define ST_MORPHO_L_38 37 + +#define ST_MORPHO_R_1 38 +#define ST_MORPHO_R_2 39 +#define ST_MORPHO_R_3 40 +#define ST_MORPHO_R_4 41 +#define ST_MORPHO_R_5 42 +#define ST_MORPHO_R_6 43 +#define ST_MORPHO_R_7 44 +#define ST_MORPHO_R_8 45 +#define ST_MORPHO_R_9 46 +#define ST_MORPHO_R_10 47 +#define ST_MORPHO_R_11 48 +#define ST_MORPHO_R_12 49 +#define ST_MORPHO_R_13 50 +#define ST_MORPHO_R_14 51 +#define ST_MORPHO_R_15 52 +#define ST_MORPHO_R_16 53 +#define ST_MORPHO_R_17 54 +#define ST_MORPHO_R_18 55 +#define ST_MORPHO_R_19 56 +#define ST_MORPHO_R_20 57 +#define ST_MORPHO_R_21 58 +#define ST_MORPHO_R_22 59 +#define ST_MORPHO_R_23 60 +#define ST_MORPHO_R_24 61 +#define ST_MORPHO_R_25 62 +#define ST_MORPHO_R_26 63 +#define ST_MORPHO_R_27 64 +#define ST_MORPHO_R_28 65 +#define ST_MORPHO_R_29 66 +#define ST_MORPHO_R_30 67 +#define ST_MORPHO_R_31 68 +#define ST_MORPHO_R_32 69 +#define ST_MORPHO_R_33 70 +#define ST_MORPHO_R_34 71 +#define ST_MORPHO_R_35 72 +#define ST_MORPHO_R_36 73 +#define ST_MORPHO_R_37 74 +#define ST_MORPHO_R_38 75 /** @} */ From e47175becd6d08c8d4b1ee2ab0a97df588b84fc3 Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 27 Jul 2023 21:30:48 +0200 Subject: [PATCH 1905/2042] dts: bindings: extend st-morpho-header to support Nucleo-144 Nucleo-144 boards have up to 72 pins (there are boards with only 70) on each ST Morpho header. Extend pin identifiers to support that number. Signed-off-by: Marcin Niestroj --- .../dt-bindings/gpio/st-morpho-header.h | 148 +++++++++++++----- 1 file changed, 108 insertions(+), 40 deletions(-) diff --git a/include/zephyr/dt-bindings/gpio/st-morpho-header.h b/include/zephyr/dt-bindings/gpio/st-morpho-header.h index 1d0e9e6a8808..82047c391cb0 100644 --- a/include/zephyr/dt-bindings/gpio/st-morpho-header.h +++ b/include/zephyr/dt-bindings/gpio/st-morpho-header.h @@ -5,8 +5,8 @@ #ifndef INCLUDE_ZEPHYR_DT_BINDINGS_GPIO_ST_MORPHO_HEADER_H_ #define INCLUDE_ZEPHYR_DT_BINDINGS_GPIO_ST_MORPHO_HEADER_H_ -/** ST Morpho pin mask (0...75). */ -#define ST_MORPHO_PIN_MASK 0x7F +/** ST Morpho pin mask (0...143). */ +#define ST_MORPHO_PIN_MASK 0xFF /** * @name ST Morpho pin identifiers @@ -50,45 +50,113 @@ #define ST_MORPHO_L_36 35 #define ST_MORPHO_L_37 36 #define ST_MORPHO_L_38 37 +#define ST_MORPHO_L_39 38 +#define ST_MORPHO_L_40 39 +#define ST_MORPHO_L_41 40 +#define ST_MORPHO_L_42 41 +#define ST_MORPHO_L_43 42 +#define ST_MORPHO_L_44 43 +#define ST_MORPHO_L_45 44 +#define ST_MORPHO_L_46 45 +#define ST_MORPHO_L_47 46 +#define ST_MORPHO_L_48 47 +#define ST_MORPHO_L_49 48 +#define ST_MORPHO_L_50 49 +#define ST_MORPHO_L_51 50 +#define ST_MORPHO_L_52 51 +#define ST_MORPHO_L_53 52 +#define ST_MORPHO_L_54 53 +#define ST_MORPHO_L_55 54 +#define ST_MORPHO_L_56 55 +#define ST_MORPHO_L_57 56 +#define ST_MORPHO_L_58 57 +#define ST_MORPHO_L_59 58 +#define ST_MORPHO_L_60 59 +#define ST_MORPHO_L_61 60 +#define ST_MORPHO_L_62 61 +#define ST_MORPHO_L_63 62 +#define ST_MORPHO_L_64 63 +#define ST_MORPHO_L_65 64 +#define ST_MORPHO_L_66 65 +#define ST_MORPHO_L_67 66 +#define ST_MORPHO_L_68 67 +#define ST_MORPHO_L_69 68 +#define ST_MORPHO_L_70 69 +#define ST_MORPHO_L_71 70 +#define ST_MORPHO_L_72 71 -#define ST_MORPHO_R_1 38 -#define ST_MORPHO_R_2 39 -#define ST_MORPHO_R_3 40 -#define ST_MORPHO_R_4 41 -#define ST_MORPHO_R_5 42 -#define ST_MORPHO_R_6 43 -#define ST_MORPHO_R_7 44 -#define ST_MORPHO_R_8 45 -#define ST_MORPHO_R_9 46 -#define ST_MORPHO_R_10 47 -#define ST_MORPHO_R_11 48 -#define ST_MORPHO_R_12 49 -#define ST_MORPHO_R_13 50 -#define ST_MORPHO_R_14 51 -#define ST_MORPHO_R_15 52 -#define ST_MORPHO_R_16 53 -#define ST_MORPHO_R_17 54 -#define ST_MORPHO_R_18 55 -#define ST_MORPHO_R_19 56 -#define ST_MORPHO_R_20 57 -#define ST_MORPHO_R_21 58 -#define ST_MORPHO_R_22 59 -#define ST_MORPHO_R_23 60 -#define ST_MORPHO_R_24 61 -#define ST_MORPHO_R_25 62 -#define ST_MORPHO_R_26 63 -#define ST_MORPHO_R_27 64 -#define ST_MORPHO_R_28 65 -#define ST_MORPHO_R_29 66 -#define ST_MORPHO_R_30 67 -#define ST_MORPHO_R_31 68 -#define ST_MORPHO_R_32 69 -#define ST_MORPHO_R_33 70 -#define ST_MORPHO_R_34 71 -#define ST_MORPHO_R_35 72 -#define ST_MORPHO_R_36 73 -#define ST_MORPHO_R_37 74 -#define ST_MORPHO_R_38 75 +#define ST_MORPHO_R_1 72 +#define ST_MORPHO_R_2 73 +#define ST_MORPHO_R_3 74 +#define ST_MORPHO_R_4 75 +#define ST_MORPHO_R_5 76 +#define ST_MORPHO_R_6 77 +#define ST_MORPHO_R_7 78 +#define ST_MORPHO_R_8 79 +#define ST_MORPHO_R_9 80 +#define ST_MORPHO_R_10 81 +#define ST_MORPHO_R_11 82 +#define ST_MORPHO_R_12 83 +#define ST_MORPHO_R_13 84 +#define ST_MORPHO_R_14 85 +#define ST_MORPHO_R_15 86 +#define ST_MORPHO_R_16 87 +#define ST_MORPHO_R_17 88 +#define ST_MORPHO_R_18 89 +#define ST_MORPHO_R_19 90 +#define ST_MORPHO_R_20 91 +#define ST_MORPHO_R_21 92 +#define ST_MORPHO_R_22 93 +#define ST_MORPHO_R_23 94 +#define ST_MORPHO_R_24 95 +#define ST_MORPHO_R_25 96 +#define ST_MORPHO_R_26 97 +#define ST_MORPHO_R_27 98 +#define ST_MORPHO_R_28 99 +#define ST_MORPHO_R_29 100 +#define ST_MORPHO_R_30 101 +#define ST_MORPHO_R_31 102 +#define ST_MORPHO_R_32 103 +#define ST_MORPHO_R_33 104 +#define ST_MORPHO_R_34 105 +#define ST_MORPHO_R_35 106 +#define ST_MORPHO_R_36 107 +#define ST_MORPHO_R_37 108 +#define ST_MORPHO_R_38 109 +#define ST_MORPHO_R_39 110 +#define ST_MORPHO_R_40 111 +#define ST_MORPHO_R_41 112 +#define ST_MORPHO_R_42 113 +#define ST_MORPHO_R_43 114 +#define ST_MORPHO_R_44 115 +#define ST_MORPHO_R_45 116 +#define ST_MORPHO_R_46 117 +#define ST_MORPHO_R_47 118 +#define ST_MORPHO_R_48 119 +#define ST_MORPHO_R_49 120 +#define ST_MORPHO_R_50 121 +#define ST_MORPHO_R_51 122 +#define ST_MORPHO_R_52 123 +#define ST_MORPHO_R_53 124 +#define ST_MORPHO_R_54 125 +#define ST_MORPHO_R_55 126 +#define ST_MORPHO_R_56 127 +#define ST_MORPHO_R_57 128 +#define ST_MORPHO_R_58 129 +#define ST_MORPHO_R_59 130 +#define ST_MORPHO_R_60 131 +#define ST_MORPHO_R_61 132 +#define ST_MORPHO_R_62 133 +#define ST_MORPHO_R_63 134 +#define ST_MORPHO_R_64 135 +#define ST_MORPHO_R_65 136 +#define ST_MORPHO_R_66 137 +#define ST_MORPHO_R_67 138 +#define ST_MORPHO_R_68 139 +#define ST_MORPHO_R_69 140 +#define ST_MORPHO_R_70 141 +#define ST_MORPHO_R_71 142 +#define ST_MORPHO_R_72 143 /** @} */ From 96768ea2d215bc5d009a645e4f41f96a73cbcdbf Mon Sep 17 00:00:00 2001 From: Marcin Niestroj Date: Thu, 27 Jul 2023 22:18:31 +0200 Subject: [PATCH 1906/2042] boards: nucleo_h563zi: add ST Morpho connector nexus node Add a new GPIO nexus node for the ST Morpho connector in the board. Signed-off-by: Marcin Niestroj --- .../nucleo_h563zi/nucleo_h563zi-common.dtsi | 1 + .../nucleo_h563zi/st_morpho_connector.dtsi | 129 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 boards/arm/nucleo_h563zi/st_morpho_connector.dtsi diff --git a/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi b/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi index 6b72080177d5..2c87df305e9f 100644 --- a/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi +++ b/boards/arm/nucleo_h563zi/nucleo_h563zi-common.dtsi @@ -8,6 +8,7 @@ #include #include #include "arduino_r3_connector.dtsi" +#include "st_morpho_connector.dtsi" / { leds { diff --git a/boards/arm/nucleo_h563zi/st_morpho_connector.dtsi b/boards/arm/nucleo_h563zi/st_morpho_connector.dtsi new file mode 100644 index 000000000000..b348ad313a5b --- /dev/null +++ b/boards/arm/nucleo_h563zi/st_morpho_connector.dtsi @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + st_morpho_header: st-morpho-header { + compatible = "st-morpho-header"; + #gpio-cells = <2>; + gpio-map-mask = ; + gpio-map-pass-thru = <0x0 GPIO_DT_FLAGS_MASK>; + gpio-map = , + , + , + , + , + , + , + , + , + , + , + , /* SB45=ON, R34=OFF */ + , /* SB44=ON, R35=OFF */ + , + , + , /* SB58=OFF */ + , + , /* SB56=OFF */ + , /* LD1 green LED if SB43=ON */ + , + , /* SB62=OFF */ + , + , + , + , + , + , + , + , + , + , /* SB64=ON */ + , /* SB78=ON */ + , /* SB8=ON */ + , /* SB9=ON */ + , + , + , + , + , + , + , + , + , + , /* SB68=ON */ + , + , + , + , + , /* SB37=OFF */ + , /* SB75=ON, SB18=OFF, SB65=OFF */ + , /* SB34=OFF */ + + , + , + , + , + , + , /* SB36=OFF */ + , + , /* LD1 green LED if SB51=ON */ + , /* SB22=ON, SB28=OFF */ + , + , /* SB21=ON, SB27=OFF */ + , /* SB38=OFF */ + , + , + , + , /* SB31=OFF */ + , + , + , + , + , /* JP6=OFF */ + , + , /* SB30=OFF */ + , + , /* SB29=OFF */ + , /* SB39=OFF */ + , + , /* SB42=OFF */ + , /* SB69=OFF */ + , + , + , /* LD2 yellow LED */ + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , /* SB74=OFF */ + , + , /* LD3 red LED */ + ; + }; +}; From 199486546ac93fa5d45fa82aafe7704bb8e615fe Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 25 Jul 2023 22:47:16 +0200 Subject: [PATCH 1907/2042] drivers: flash: stm32l5: use write-block-size when validating STM32L5 have a write block size of 8, but STM32U5 and STM32H5 have a write block size of 16. Use write-block-size from the device tree instead of hardcoding this value when validating the range of write operations. Fixes #60724 Signed-off-by: Florian Vaussard --- drivers/flash/flash_stm32.h | 6 ++++++ drivers/flash/flash_stm32l5x.c | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index dd8628f81d77..e0fba89a5503 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -257,6 +257,12 @@ static inline bool flash_stm32_range_exists(const struct device *dev, } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ +static inline bool flash_stm32_valid_write(off_t offset, uint32_t len) +{ + return ((offset % FLASH_STM32_WRITE_BLOCK_SIZE == 0) && + (len % FLASH_STM32_WRITE_BLOCK_SIZE == 0U)); +} + bool flash_stm32_valid_range(const struct device *dev, off_t offset, uint32_t len, bool write); diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index a0b692b45c80..b4381289ad10 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -128,7 +128,7 @@ static int icache_wait_for_invalidate_complete(void) #endif /* CONFIG_SOC_SERIES_STM32H5X */ /* - * offset and len must be aligned on 8 for write, + * offset and len must be aligned on write-block-size for write, * positive and not beyond end of flash */ bool flash_stm32_valid_range(const struct device *dev, off_t offset, @@ -149,8 +149,10 @@ bool flash_stm32_valid_range(const struct device *dev, off_t offset, } } - return (!write || (offset % 8 == 0 && len % 8 == 0U)) && - flash_stm32_range_exists(dev, offset, len); + if (write && !flash_stm32_valid_write(offset, len)) { + return false; + } + return flash_stm32_range_exists(dev, offset, len); } static int write_dword(const struct device *dev, off_t offset, uint64_t val) From 4c9e42925ea781c3171cc1c0638561029c8c7c6b Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 25 Jul 2023 22:47:16 +0200 Subject: [PATCH 1908/2042] drivers: flash: stm32l5: use write-block-size when writing STM32L5 have a write block size of 8, but STM32U5 and STM32H5 have a write block size of 16. Convert write_dword() and flash_stm32_write_range() to write write-block-size data at a time. Fixes #60724 Signed-off-by: Florian Vaussard --- drivers/flash/flash_stm32l5x.c | 36 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index b4381289ad10..8ece9b22492d 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -155,13 +155,15 @@ bool flash_stm32_valid_range(const struct device *dev, off_t offset, return flash_stm32_range_exists(dev, offset, len); } -static int write_dword(const struct device *dev, off_t offset, uint64_t val) +static int write_nwords(const struct device *dev, off_t offset, const uint32_t *buff, size_t n) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + bool full_zero = true; uint32_t tmp; int rc; + int i; /* if the non-secure control register is locked,do not fail silently */ if (regs->NSCR & FLASH_STM32_NSLOCK) { @@ -175,16 +177,26 @@ static int write_dword(const struct device *dev, off_t offset, uint64_t val) return rc; } - /* Check if this double word is erased and value isn't 0. + /* Check if this double/quad word is erased and value isn't 0. * - * It is allowed to write only zeros over an already written dword + * It is allowed to write only zeros over an already written dword / qword * See 6.3.7 in STM32L5 reference manual. * See 7.3.7 in STM32U5 reference manual. + * See 7.3.5 in STM32H5 reference manual. */ - if ((flash[0] != 0xFFFFFFFFUL || - flash[1] != 0xFFFFFFFFUL) && val != 0UL) { - LOG_ERR("Word at offs %ld not erased", (long)offset); - return -EIO; + for (i = 0; i < n; i++) { + if (buff[i] != 0) { + full_zero = false; + break; + } + } + if (!full_zero) { + for (i = 0; i < n; i++) { + if (flash[i] != 0xFFFFFFFFUL) { + LOG_ERR("Word at offs %ld not erased", (long)(offset + i)); + return -EIO; + } + } } /* Set the NSPG bit */ @@ -194,8 +206,9 @@ static int write_dword(const struct device *dev, off_t offset, uint64_t val) tmp = regs->NSCR; /* Perform the data write operation at the desired memory address */ - flash[0] = (uint32_t)val; - flash[1] = (uint32_t)(val >> 32); + for (i = 0; i < n; i++) { + flash[i] = buff[i]; + } /* Wait until the NSBSY bit is cleared */ rc = flash_stm32_wait_flash_idle(dev); @@ -343,8 +356,9 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, } } - for (i = 0; i < len; i += 8, offset += 8) { - rc = write_dword(dev, offset, ((const uint64_t *) data)[i>>3]); + for (i = 0; i < len; i += FLASH_STM32_WRITE_BLOCK_SIZE) { + rc = write_nwords(dev, offset + i, ((const uint32_t *) data + (i>>2)), + FLASH_STM32_WRITE_BLOCK_SIZE / 4); if (rc < 0) { break; } From 8bac51be1e56ebe223d39bae5e3f7601c0ef618e Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 25 Jul 2023 22:47:17 +0200 Subject: [PATCH 1909/2042] drivers: flash: stm32: add a weak flash_stm32_valid_range() Most implementations have the same logic, with only a different write block size. Now that we are using write-block-size from the device tree, it is possible to use a default implementation that can be overridden if necessary. Signed-off-by: Florian Vaussard --- drivers/flash/flash_stm32.c | 9 +++++++++ drivers/flash/flash_stm32f1x.c | 11 ----------- drivers/flash/flash_stm32g0x.c | 14 -------------- drivers/flash/flash_stm32g4x.c | 6 ++++-- drivers/flash/flash_stm32l4x.c | 10 ---------- drivers/flash/flash_stm32wbax.c | 12 ------------ drivers/flash/flash_stm32wbx.c | 11 ----------- 7 files changed, 13 insertions(+), 60 deletions(-) diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index f6daea97fe30..cba4a76a9690 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -45,6 +45,15 @@ static const struct flash_parameters flash_stm32_parameters = { static int flash_stm32_write_protection(const struct device *dev, bool enable); +bool __weak 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); +} + int __weak flash_stm32_check_configuration(void) { return 0; diff --git a/drivers/flash/flash_stm32f1x.c b/drivers/flash/flash_stm32f1x.c index 71d5ffbeece0..0c54d3f69fef 100644 --- a/drivers/flash/flash_stm32f1x.c +++ b/drivers/flash/flash_stm32f1x.c @@ -163,17 +163,6 @@ static int write_value(const struct device *dev, off_t offset, return rc; } -/* offset and len must be aligned on 2 for write - * positive and not beyond end of flash - */ -bool flash_stm32_valid_range(const struct device *dev, off_t offset, - uint32_t len, - bool write) -{ - return (!write || (offset % 2 == 0 && len % 2 == 0U)) && - flash_stm32_range_exists(dev, offset, len); -} - int flash_stm32_block_erase_loop(const struct device *dev, unsigned int offset, unsigned int len) diff --git a/drivers/flash/flash_stm32g0x.c b/drivers/flash/flash_stm32g0x.c index a3be761f391c..07eea9ce32b4 100644 --- a/drivers/flash/flash_stm32g0x.c +++ b/drivers/flash/flash_stm32g0x.c @@ -40,20 +40,6 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #define STM32G0_PAGES_PER_BANK \ ((STM32G0_FLASH_SIZE / STM32G0_FLASH_PAGE_SIZE) / STM32G0_BANK_COUNT) -/* - * offset and len must be aligned on 8 for write, - * positive and not beyond end of flash - * On dual-bank SoCs memory accesses starting on the first bank and continuing - * beyond the first bank into the second bank are allowed. - */ -bool flash_stm32_valid_range(const struct device *dev, off_t offset, - uint32_t len, - bool write) -{ - return (!write || (offset % 8 == 0 && len % 8 == 0)) && - flash_stm32_range_exists(dev, offset, len); -} - static inline void flush_cache(FLASH_TypeDef *regs) { if (regs->ACR & FLASH_ACR_ICEN) { diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c index af2535840641..e1f012c254b5 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -42,8 +42,10 @@ bool flash_stm32_valid_range(const struct device *dev, off_t offset, } #endif - return (!write || (offset % 8 == 0 && len % 8 == 0U)) && - flash_stm32_range_exists(dev, offset, len); + if (write && !flash_stm32_valid_write(offset, len)) { + return false; + } + return flash_stm32_range_exists(dev, offset, len); } static inline void flush_cache(FLASH_TypeDef *regs) diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index 56fe85e1fad6..24644aba95e4 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -32,16 +32,6 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #define CONTROL_DCACHE #endif -/* offset and len must be aligned on 8 for write - * , positive and not beyond end of flash */ -bool flash_stm32_valid_range(const struct device *dev, off_t offset, - uint32_t len, - bool write) -{ - return (!write || (offset % 8 == 0 && len % 8 == 0U)) && - flash_stm32_range_exists(dev, offset, len); -} - static inline void flush_cache(FLASH_TypeDef *regs) { if (regs->ACR & FLASH_ACR_DCEN) { diff --git a/drivers/flash/flash_stm32wbax.c b/drivers/flash/flash_stm32wbax.c index 605b727ddfbc..0796b9a5be40 100644 --- a/drivers/flash/flash_stm32wbax.c +++ b/drivers/flash/flash_stm32wbax.c @@ -105,18 +105,6 @@ static int icache_wait_for_invalidate_complete(void) return status; } -/* - * offset and len must be aligned on 16 for write, - * positive and not beyond end of flash - */ -bool flash_stm32_valid_range(const struct device *dev, off_t offset, - uint32_t len, - bool write) -{ - return (!write || (offset % 16 == 0 && len % 16 == 0U)) && - flash_stm32_range_exists(dev, offset, len); -} - static int write_qword(const struct device *dev, off_t offset, const uint32_t *buff) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); diff --git a/drivers/flash/flash_stm32wbx.c b/drivers/flash/flash_stm32wbx.c index 90746d10b170..e72fddf756f7 100644 --- a/drivers/flash/flash_stm32wbx.c +++ b/drivers/flash/flash_stm32wbx.c @@ -26,17 +26,6 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #define STM32WBX_PAGE_SHIFT 12 -/* offset and len must be aligned on 8 for write, - * positive and not beyond end of flash - */ -bool flash_stm32_valid_range(const struct device *dev, off_t offset, - uint32_t len, - bool write) -{ - return (!write || (offset % 8 == 0 && len % 8 == 0U)) && - flash_stm32_range_exists(dev, offset, len); -} - /* * Up to 255 4K pages */ From d620511c22b3fa6c0cd69bd0f0c102b47746bb15 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 7 Jul 2023 18:18:31 +0000 Subject: [PATCH 1910/2042] drivers: mipi_dsi: dsi_mcux: add support for MIPI generic long write CMD Add support for MIPI generic long write commands to DSI MCUX driver. Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mipi_dsi/dsi_mcux.c b/drivers/mipi_dsi/dsi_mcux.c index 6326ace79121..f0eceb4697ef 100644 --- a/drivers/mipi_dsi/dsi_mcux.c +++ b/drivers/mipi_dsi/dsi_mcux.c @@ -261,6 +261,9 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam; break; + case MIPI_DSI_GENERIC_LONG_WRITE: + dsi_xfer.txDataType = kDSI_TxDataGenLongWr; + break; case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: __fallthrough; case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: From 918c79706d75c86ab4be12fb8fbdbac1ef966e55 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 7 Jul 2023 19:14:57 +0000 Subject: [PATCH 1911/2042] drivers: mipi_dsi: dsi_mcux_2l: add support for MIPI generic long write CMD Add support for MIPI generic long write commands to DSI MCUX 2L driver Signed-off-by: Daniel DeGrasse --- drivers/mipi_dsi/dsi_mcux_2l.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mipi_dsi/dsi_mcux_2l.c b/drivers/mipi_dsi/dsi_mcux_2l.c index 044b27bef78f..9f4dcdf09572 100644 --- a/drivers/mipi_dsi/dsi_mcux_2l.c +++ b/drivers/mipi_dsi/dsi_mcux_2l.c @@ -191,6 +191,9 @@ static ssize_t dsi_mcux_transfer(const struct device *dev, uint8_t channel, case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: dsi_xfer.txDataType = kDSI_TxDataGenShortWrTwoParam; break; + case MIPI_DSI_GENERIC_LONG_WRITE: + dsi_xfer.txDataType = kDSI_TxDataGenLongWr; + break; case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: __fallthrough; case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: From a3b8f062f88c8ac3ba0e7c3278afe7c231b24391 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 7 Jul 2023 18:20:53 +0000 Subject: [PATCH 1912/2042] drivers: display: add driver for HX8394 TFT LCD controller Add driver for HX8394 TFT LCD controller. This controller is driven via MIPI DSI, and is configured for a 720x1280 display Signed-off-by: Daniel DeGrasse --- drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.hx8394 | 10 + drivers/display/display_hx8394.c | 801 +++++++++++++++++++++++++ dts/bindings/display/himax,hx8394.yaml | 24 + 5 files changed, 837 insertions(+) create mode 100644 drivers/display/Kconfig.hx8394 create mode 100644 drivers/display/display_hx8394.c create mode 100644 dts/bindings/display/himax,hx8394.yaml diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 30e31ed2b116..20bd8659afff 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -22,6 +22,7 @@ zephyr_library_sources_ifdef(CONFIG_ST7735R display_st7735r.c) 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_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 6654f14d87e7..f6a39f0f9847 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -39,5 +39,6 @@ source "drivers/display/Kconfig.max7219" source "drivers/display/Kconfig.intel_multibootfb" source "drivers/display/Kconfig.mcux_dcnano_lcdif" source "drivers/display/Kconfig.otm8009a" +source "drivers/display/Kconfig.hx8394" endif # DISPLAY diff --git a/drivers/display/Kconfig.hx8394 b/drivers/display/Kconfig.hx8394 new file mode 100644 index 000000000000..0c36e125e1c6 --- /dev/null +++ b/drivers/display/Kconfig.hx8394 @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config HX8394 + bool "HX8394 display driver" + default y + depends on MIPI_DSI + depends on DT_HAS_HIMAX_HX8394_ENABLED + help + Enable driver for HX8394 display driver. diff --git a/drivers/display/display_hx8394.c b/drivers/display/display_hx8394.c new file mode 100644 index 000000000000..9a71197b481c --- /dev/null +++ b/drivers/display/display_hx8394.c @@ -0,0 +1,801 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT himax_hx8394 + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(hx8394, CONFIG_DISPLAY_LOG_LEVEL); + +struct hx8394_config { + const struct device *mipi_dsi; + const struct gpio_dt_spec reset_gpio; + const struct gpio_dt_spec bl_gpio; + uint8_t num_of_lanes; + uint8_t pixel_format; + uint16_t panel_width; + uint16_t panel_height; + uint8_t channel; +}; + +/* MIPI DCS commands specific to this display driver */ +#define HX8394_SETMIPI 0xBA +#define HX8394_MIPI_LPTX_BTA_READ BIT(6) +#define HX8394_MIPI_LP_CD_DIS BIT(5) +#define HX8394_MIPI_TA_6TL 0x3 +#define HX8394_MIPI_DPHYCMD_LPRX_8NS 0x40 +#define HX8394_MIPI_DPHYCMD_LPRX_66mV 0x10 +#define HX8394_MIPI_DPHYCMD_LPTX_SRLIM 0x8 +#define HX8394_MIPI_DPHYCMD_LDO_1_55V 0x60 +#define HX8394_MIPI_DPHYCMD_HSRX_7X 0x8 +#define HX8394_MIPI_DPHYCMD_HSRX_100OHM 0x2 +#define HX8394_MIPI_DPHYCMD_LPCD_1X 0x1 + +#define HX8394_SET_ADDRESS 0x36 +#define HX8394_FLIP_HORIZONTAL BIT(1) +#define HX8394_FLIP_VERTICAL BIT(0) + +#define HX8394_SETPOWER 0xB1 +#define HX8394_POWER_AP_1_0UA 0x8 +#define HX8394_POWER_HX5186 0x40 +#define HX8394_POWER_VRHP_4_8V 0x12 +#define HX8394_POWER_VRHN_4_8V 0x12 +#define HX8394_POWER_VPPS_8_25V 0x60 +#define HX8394_POWER_XDK_X2 0x1 +#define HX8394_POWER_VSP_FBOFF 0x8 +#define HX8394_POWER_FS0_DIV_8 0x2 +#define HX8394_POWER_CLK_OPT_VGH_HSYNC_RST 0x10 +#define HX8394_POWER_CLK_OPT_VGL_HSYNC_RST 0x20 +#define HX8394_POWER_FS2_DIV_192 0x4 +#define HX8394_POWER_FS1_DIV_224 0x50 +#define HX8394_POWER_BTP_5_55V 0x11 +#define HX8394_POWER_VGH_RATIO_2VSPVSN 0x60 +#define HX8394_POWER_BTN_5_55V 0x11 +#define HX8394_POWER_VGL_RATIO_2VSPVSN 0x60 +#define HX8394_POWER_VGHS_16V 0x57 +#define HX8394_POWER_VGLS_12_4V 0x47 + +#define HX8394_SETDISP 0xB2 +#define HX8394_DISP_COL_INV 0x0 +#define HX8394_DISP_MESSI_ENB 0x80 +#define HX8394_DISP_NL_1280 0x64 +#define HX8394_DISP_BP_14 0xC +#define HX8394_DISP_FP_15 0xD +#define HX8394_DISP_RTN_144 0x2F + +#define HX8394_SETCYC 0xB4 + +#define HX8394_SETGIP0 0xD3 +#define HX8394_GIP0_EQ_OPT_BOTH 0x0 +#define HX8394_GIP0_EQ_HSYNC_NORMAL 0x0 +#define HX8394_GIP0_EQ_VSEL_VSSA 0x0 +#define HX8394_SHP_START_4 0x40 +#define HX8394_SCP_WIDTH_7X_HSYNC 0x7 +#define HX8394_CHR0_12X_HSYNC 0xA +#define HX8394_CHR1_18X_HSYNC 0x10 + +#define HX8394_SETGIP1 0xD5 + +#define HX8394_SETGIP2 0xD6 + +#define HX8394_SETVCOM 0xB6 +#define HX8394_VCMC_F_1_76V 0x92 +#define HX8394_VCMC_B_1_76V 0x92 + +#define HX8394_SETGAMMA 0xE0 + +#define HX8394_SETPANEL 0xCC +#define HX8394_COLOR_BGR BIT(0) +#define HX8394_REV_PANEL BIT(1) + +#define HX8394_SETBANK 0xBD + +#define HX8394_SET_TEAR 0x35 +#define HX8394_TEAR_VBLANK 0x0 + +#define HX8394_SETEXTC 0xB9 +#define HX8394_EXTC1_MAGIC 0xFF +#define HX8394_EXTC2_MAGIC 0x83 +#define HX8394_EXTC3_MAGIC 0x94 + + +const uint8_t enable_extension[] = { + HX8394_SETEXTC, + HX8394_EXTC1_MAGIC, + HX8394_EXTC2_MAGIC, + HX8394_EXTC3_MAGIC, +}; + +const uint8_t address_config[] = { + HX8394_SET_ADDRESS, + HX8394_FLIP_HORIZONTAL +}; + +const uint8_t power_config[] = { + HX8394_SETPOWER, + (HX8394_POWER_HX5186 | HX8394_POWER_AP_1_0UA), + HX8394_POWER_VRHP_4_8V, + (HX8394_POWER_VPPS_8_25V | HX8394_POWER_VRHN_4_8V), + (HX8394_POWER_VSP_FBOFF | HX8394_POWER_XDK_X2), + (HX8394_POWER_CLK_OPT_VGL_HSYNC_RST | + HX8394_POWER_CLK_OPT_VGH_HSYNC_RST | + HX8394_POWER_FS0_DIV_8), + (HX8394_POWER_FS1_DIV_224 | HX8394_POWER_FS2_DIV_192), + (HX8394_POWER_VGH_RATIO_2VSPVSN | HX8394_POWER_BTP_5_55V), + (HX8394_POWER_VGL_RATIO_2VSPVSN | HX8394_POWER_BTN_5_55V), + HX8394_POWER_VGHS_16V, + HX8394_POWER_VGLS_12_4V +}; + +const uint8_t line_config[] = { + HX8394_SETDISP, + HX8394_DISP_COL_INV, + HX8394_DISP_MESSI_ENB, + HX8394_DISP_NL_1280, + HX8394_DISP_BP_14, + HX8394_DISP_FP_15, + HX8394_DISP_RTN_144 +}; + +const uint8_t cycle_config[] = { + HX8394_SETCYC, + 0x73, /* SPON delay */ + 0x74, /* SPOFF delay */ + 0x73, /* CON delay */ + 0x74, /* COFF delay */ + 0x73, /* CON1 delay */ + 0x74, /* COFF1 delay */ + 0x1, /* EQON time */ + 0xC, /* SON time */ + 0x86, /* SOFF time */ + 0x75, /* SAP1_P, SAP2 (1st and second stage op amp bias) */ + 0x00, /* DX2 off, EQ off, EQ_MI off */ + 0x3F, /* DX2 off period setting */ + 0x73, /* SPON_MPU delay */ + 0x74, /* SPOFF_MPU delay */ + 0x73, /* CON_MPU delay */ + 0x74, /* COFF_MPU delay */ + 0x73, /* CON1_MPU delay */ + 0x74, /* COFF1_MPU delay */ + 0x1, /* EQON_MPU time */ + 0xC, /* SON_MPU time */ + 0x86 /* SOFF_MPU time */ +}; + +const uint8_t gip0_config[] = { + HX8394_SETGIP0, + (HX8394_GIP0_EQ_OPT_BOTH | HX8394_GIP0_EQ_HSYNC_NORMAL), + HX8394_GIP0_EQ_VSEL_VSSA, + 0x7, /* EQ_DELAY_ON1 (in cycles of TCON CLK */ + 0x7, /* EQ_DELAY_OFF1 (in cycles of TCON CLK */ + 0x40, /* GPWR signal frequency (64x per frame) */ + 0x7, /* GPWR signal non overlap timing (in cycles of TCON */ + 0xC, /* GIP dummy clock for first CKV */ + 0x00, /* GIP dummy clock for second CKV */ + /* Group delays. Sets start/end signal delay from VYSNC + * falling edge in multiples of HSYNC + */ + 0x8, /* SHR0_2 = 8, SHR0_3 = 0 */ + 0x10, /* SHR0_1 = 1, SHR0[11:8] = 0x0 */ + 0x8, /* SHR0 = 0x8 */ + 0x0, /* SHR0_GS[11:8]. Unset. */ + 0x8, /* SHR0_GS = 0x8 */ + 0x54, /* SHR1_3 = 0x5, SHR1_2 = 0x4 */ + 0x15, /* SHR1_1 = 0x1, SHR1[11:8] = 0x5 */ + 0xA, /* SHR1[7:0] = 0xA (SHR1 = 0x50A) */ + 0x5, /* SHR1_GS[11:8] = 0x5 */ + 0xA, /* SHR1_GS[7:0] = 0xA (SHR1_GS = 0x50A) */ + 0x2, /* SHR2_3 = 0x0, SHR2_2 = 0x2 */ + 0x15, /* SHR2_1 = 0x1, SHR2[11:8] = 0x5 */ + 0x6, /* SHR2[7:0] = 0x6 (SHR2 = 0x506) */ + 0x5, /* SHR2_GS[11:8] = 0x5 */ + 0x6, /* SHR2_GS[7:0 = 0x6 (SHR2_GS = 0x506) */ + (HX8394_SHP_START_4 | HX8394_SCP_WIDTH_7X_HSYNC), + 0x44, /* SHP2 = 0x4, SHP1 = 0x4 */ + HX8394_CHR0_12X_HSYNC, + HX8394_CHR0_12X_HSYNC, + 0x4B, /* CHP0 = 4x hsync, CCP0 = 0xB */ + HX8394_CHR1_18X_HSYNC, + 0x7, /* CHR1_GS = 9x hsync */ + 0x7, /* CHP1 = 1x hsync, CCP1 = 0x7 */ + /* These parameters are not documented in datasheet */ + 0xC, + 0x40 +}; + +const uint8_t gip1_config[] = { + HX8394_SETGIP1, + /* Select output clock sources + * See COSn_L/COSn_R values in datasheet + */ + 0x1C, /* COS1_L */ + 0x1C, /* COS1_R */ + 0x1D, /* COS2_L */ + 0x1D, /* COS2_R */ + 0x00, /* COS3_L */ + 0x01, /* COS3_R */ + 0x02, /* COS4_L */ + 0x03, /* COS4_R */ + 0x04, /* COS5_L */ + 0x05, /* COS5_R */ + 0x06, /* COS6_L */ + 0x07, /* COS6_R */ + 0x08, /* COS7_L */ + 0x09, /* COS7_R */ + 0x0A, /* COS8_L */ + 0x0B, /* COS8_R */ + 0x24, /* COS9_L */ + 0x25, /* COS9_R */ + 0x18, /* COS10_L */ + 0x18, /* COS10_R */ + 0x26, /* COS11_L */ + 0x27, /* COS11_R */ + 0x18, /* COS12_L */ + 0x18, /* COS12_R */ + 0x18, /* COS13_L */ + 0x18, /* COS13_R */ + 0x18, /* COS14_L */ + 0x18, /* COS14_R */ + 0x18, /* COS15_L */ + 0x18, /* COS15_R */ + 0x18, /* COS16_L */ + 0x18, /* COS16_R */ + 0x18, /* COS17_L */ + 0x18, /* COS17_R */ + 0x18, /* COS18_L */ + 0x18, /* COS18_R */ + 0x18, /* COS19_L */ + 0x18, /* COS19_R */ + 0x20, /* COS20_L */ + 0x21, /* COS20_R */ + 0x18, /* COS21_L */ + 0x18, /* COS21_R */ + 0x18, /* COS22_L */ + 0x18 /* COS22_R */ +}; + +const uint8_t gip2_config[] = { + HX8394_SETGIP2, + /* Select output clock sources for GS mode. + * See COSn_L_GS/COSn_R_GS values in datasheet + */ + 0x1C, /* COS1_L_GS */ + 0x1C, /* COS1_R_GS */ + 0x1D, /* COS2_L_GS */ + 0x1D, /* COS2_R_GS */ + 0x07, /* COS3_L_GS */ + 0x06, /* COS3_R_GS */ + 0x05, /* COS4_L_GS */ + 0x04, /* COS4_R_GS */ + 0x03, /* COS5_L_GS */ + 0x02, /* COS5_R_GS */ + 0x01, /* COS6_L_GS */ + 0x00, /* COS6_R_GS */ + 0x0B, /* COS7_L_GS */ + 0x0A, /* COS7_R_GS */ + 0x09, /* COS8_L_GS */ + 0x08, /* COS8_R_GS */ + 0x21, /* COS9_L_GS */ + 0x20, /* COS9_R_GS */ + 0x18, /* COS10_L_GS */ + 0x18, /* COS10_R_GS */ + 0x27, /* COS11_L_GS */ + 0x26, /* COS11_R_GS */ + 0x18, /* COS12_L_GS */ + 0x18, /* COS12_R_GS */ + 0x18, /* COS13_L_GS */ + 0x18, /* COS13_R_GS */ + 0x18, /* COS14_L_GS */ + 0x18, /* COS14_R_GS */ + 0x18, /* COS15_L_GS */ + 0x18, /* COS15_R_GS */ + 0x18, /* COS16_L_GS */ + 0x18, /* COS16_R_GS */ + 0x18, /* COS17_L_GS */ + 0x18, /* COS17_R_GS */ + 0x18, /* COS18_L_GS */ + 0x18, /* COS18_R_GS */ + 0x18, /* COS19_L_GS */ + 0x18, /* COS19_R_GS */ + 0x25, /* COS20_L_GS */ + 0x24, /* COS20_R_GS */ + 0x18, /* COS21_L_GS */ + 0x18, /* COS21_R_GS */ + 0x18, /* COS22_L_GS */ + 0x18 /* COS22_R_GS */ +}; + +const uint8_t vcom_config[] = { + HX8394_SETVCOM, + HX8394_VCMC_F_1_76V, + HX8394_VCMC_B_1_76V +}; + +const uint8_t gamma_config[] = { + HX8394_SETGAMMA, + 0x00, /* VHP0 */ + 0x0A, /* VHP1 */ + 0x15, /* VHP2 */ + 0x1B, /* VHP3 */ + 0x1E, /* VHP4 */ + 0x21, /* VHP5 */ + 0x24, /* VHP6 */ + 0x22, /* VHP7 */ + 0x47, /* VMP0 */ + 0x56, /* VMP1 */ + 0x65, /* VMP2 */ + 0x66, /* VMP3 */ + 0x6E, /* VMP4 */ + 0x82, /* VMP5 */ + 0x88, /* VMP6 */ + 0x8B, /* VMP7 */ + 0x9A, /* VMP8 */ + 0x9D, /* VMP9 */ + 0x98, /* VMP10 */ + 0xA8, /* VMP11 */ + 0xB9, /* VMP12 */ + 0x5D, /* VLP0 */ + 0x5C, /* VLP1 */ + 0x61, /* VLP2 */ + 0x66, /* VLP3 */ + 0x6A, /* VLP4 */ + 0x6F, /* VLP5 */ + 0x7F, /* VLP6 */ + 0x7F, /* VLP7 */ + 0x00, /* VHN0 */ + 0x0A, /* VHN1 */ + 0x15, /* VHN2 */ + 0x1B, /* VHN3 */ + 0x1E, /* VHN4 */ + 0x21, /* VHN5 */ + 0x24, /* VHN6 */ + 0x22, /* VHN7 */ + 0x47, /* VMN0 */ + 0x56, /* VMN1 */ + 0x65, /* VMN2 */ + 0x65, /* VMN3 */ + 0x6E, /* VMN4 */ + 0x81, /* VMN5 */ + 0x87, /* VMN6 */ + 0x8B, /* VMN7 */ + 0x98, /* VMN8 */ + 0x9D, /* VMN9 */ + 0x99, /* VMN10 */ + 0xA8, /* VMN11 */ + 0xBA, /* VMN12 */ + 0x5D, /* VLN0 */ + 0x5D, /* VLN1 */ + 0x62, /* VLN2 */ + 0x67, /* VLN3 */ + 0x6B, /* VLN4 */ + 0x72, /* VLN5 */ + 0x7F, /* VLN6 */ + 0x7F /* VLN7 */ +}; + +const uint8_t hx8394_cmd1[] = {0xC0U, 0x1FU, 0x31U}; + +const uint8_t panel_config[] = { + HX8394_SETPANEL, + (HX8394_COLOR_BGR | HX8394_REV_PANEL) +}; + +const uint8_t hx8394_cmd2[] = {0xD4, 0x2}; + +const uint8_t hx8394_bank2[] = { + 0xD8U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, + 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, + 0xFFU +}; + +const uint8_t hx8394_bank1[] = {0xB1U, 0x00U}; + +const uint8_t hx8394_bank0[] = { + 0xBFU, 0x40U, 0x81U, 0x50U, + 0x00U, 0x1AU, 0xFCU, 0x01 +}; + +const uint8_t hx8394_cmd3[] = {0xC6U, 0xEDU}; + +const uint8_t tear_config[] = {HX8394_SET_TEAR, HX8394_TEAR_VBLANK | 0x3}; + +static int hx8394_write(const struct device *dev, const uint16_t x, + const uint16_t y, + const struct display_buffer_descriptor *desc, + const void *buf) +{ + LOG_WRN("Write not supported, use LCD controller display driver"); + 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; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 1); + } else { + return -ENOTSUP; + } +} + +static int hx8394_blanking_on(const struct device *dev) +{ + const struct hx8394_config *config = dev->config; + + if (config->bl_gpio.port != NULL) { + return gpio_pin_set_dt(&config->bl_gpio, 0); + } else { + return -ENOTSUP; + } +} + +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) +{ + const struct hx8394_config *config = dev->config; + + if (pixel_format == config->pixel_format) { + return 0; + } + LOG_WRN("Pixel format change not implemented"); + return -ENOTSUP; +} + +static int hx8394_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + const struct hx8394_config *config = dev->config; + uint8_t param[2] = {0}; + + /* Note- this simply flips the scan direction of the display + * driver. Can be useful if your application needs the display + * flipped on the X or Y axis + */ + param[0] = HX8394_SET_ADDRESS; + switch (orientation) { + case DISPLAY_ORIENTATION_NORMAL: + /* Default orientation for this display flips image on x axis */ + param[1] = HX8394_FLIP_HORIZONTAL; + break; + case DISPLAY_ORIENTATION_ROTATED_90: + param[1] = HX8394_FLIP_VERTICAL; + break; + case DISPLAY_ORIENTATION_ROTATED_180: + param[1] = 0; + break; + case DISPLAY_ORIENTATION_ROTATED_270: + param[1] = HX8394_FLIP_HORIZONTAL | HX8394_FLIP_VERTICAL; + break; + default: + return -ENOTSUP; + } + return mipi_dsi_generic_write(config->mipi_dsi, config->channel, param, 2); +} + +static void hx8394_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct hx8394_config *config = dev->config; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = config->panel_width; + capabilities->y_resolution = config->panel_height; + capabilities->supported_pixel_formats = config->pixel_format; + capabilities->current_pixel_format = config->pixel_format; + capabilities->current_orientation = DISPLAY_ORIENTATION_NORMAL; +} + +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, +}; + +static int hx8394_init(const struct device *dev) +{ + const struct hx8394_config *config = dev->config; + int ret; + struct mipi_dsi_device mdev; + uint8_t param[2]; + uint8_t setmipi[7] = { + HX8394_SETMIPI, + (HX8394_MIPI_LPTX_BTA_READ | HX8394_MIPI_LP_CD_DIS), + HX8394_MIPI_TA_6TL, + (HX8394_MIPI_DPHYCMD_LPRX_8NS | + HX8394_MIPI_DPHYCMD_LPRX_66mV | + HX8394_MIPI_DPHYCMD_LPTX_SRLIM), + (HX8394_MIPI_DPHYCMD_LDO_1_55V | + HX8394_MIPI_DPHYCMD_HSRX_7X | + HX8394_MIPI_DPHYCMD_HSRX_100OHM | + HX8394_MIPI_DPHYCMD_LPCD_1X), + /* The remaining parameters here are not documented */ + 0xB2U, 0xC0U}; + + mdev.data_lanes = config->num_of_lanes; + mdev.pixfmt = config->pixel_format; + /* HX8394 runs in video mode */ + mdev.mode_flags = MIPI_DSI_MODE_VIDEO; + + ret = mipi_dsi_attach(config->mipi_dsi, config->channel, &mdev); + if (ret < 0) { + LOG_ERR("Could not attach to MIPI-DSI host"); + return ret; + } + + if (gpio_is_ready_dt(&config->reset_gpio)) { + /* Regulator API will have supplied power to the display + * driver. Per datasheet, we must wait 1ms for the RESX + * pin to be valid. + */ + k_sleep(K_MSEC(1)); + /* Initialize reset GPIO */ + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + return ret; + } + /* Pull reset GPIO low */ + gpio_pin_set_dt(&config->reset_gpio, 0); + /* Datasheet says we must keep reset pin low at least 10us. + * hold it low for 1ms to be safe. + */ + k_sleep(K_MSEC(1)); + gpio_pin_set_dt(&config->reset_gpio, 1); + /* Per datasheet, we must delay at least 50ms before first + * host command + */ + k_sleep(K_MSEC(50)); + } + /* Enable extended commands */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + enable_extension, sizeof(enable_extension)); + if (ret < 0) { + return ret; + } + + /* Set the number of lanes to DSISETUP0 parameter */ + setmipi[1] |= (config->num_of_lanes - 1); + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + setmipi, sizeof(setmipi)); + if (ret < 0) { + return ret; + } + + /* Set scan direction */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + address_config, sizeof(address_config)); + if (ret < 0) { + return ret; + } + + /* Set voltage and current targets */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + power_config, sizeof(power_config)); + if (ret < 0) { + return ret; + } + + /* Setup display line count and front/back porch size */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + line_config, sizeof(line_config)); + if (ret < 0) { + return ret; + } + + /* Setup display cycle counts (in counts of TCON CLK) */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + cycle_config, sizeof(cycle_config)); + if (ret < 0) { + return ret; + } + + /* Set group delay values */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + gip0_config, sizeof(gip0_config)); + if (ret < 0) { + return ret; + } + + + /* Set group clock selections */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + gip1_config, sizeof(gip1_config)); + if (ret < 0) { + return ret; + } + + /* Set group clock selections for GS mode */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + gip2_config, sizeof(gip2_config)); + if (ret < 0) { + return ret; + } + + /* Delay for a moment before setting VCOM. It is not clear + * from the datasheet why this is required, but without this + * delay the panel stops responding to additional commands + */ + k_msleep(1); + /* Set VCOM voltage config */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + vcom_config, sizeof(vcom_config)); + if (ret < 0) { + return ret; + } + + /* Set manufacturer supplied gamma values */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + gamma_config, sizeof(gamma_config)); + if (ret < 0) { + return ret; + } + + /* This command is not documented in datasheet, but is included + * in the display initialization done by MCUXpresso SDK + */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_cmd1, sizeof(hx8394_cmd1)); + if (ret < 0) { + return ret; + } + + /* Set panel to BGR mode, and reverse colors */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + panel_config, sizeof(panel_config)); + if (ret < 0) { + return ret; + } + + /* This command is not documented in datasheet, but is included + * in the display initialization done by MCUXpresso SDK + */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_cmd2, sizeof(hx8394_cmd2)); + if (ret < 0) { + return ret; + } + + /* Write values to manufacturer register banks */ + param[0] = HX8394_SETBANK; + param[1] = 0x2; + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + param, 2); + if (ret < 0) { + return ret; + } + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_bank2, sizeof(hx8394_bank2)); + if (ret < 0) { + return ret; + } + param[1] = 0x0; + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + param, 2); + if (ret < 0) { + return ret; + } + /* Select bank 1 */ + param[1] = 0x1; + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + param, 2); + if (ret < 0) { + return ret; + } + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_bank1, sizeof(hx8394_bank1)); + if (ret < 0) { + return ret; + } + /* Select bank 0 */ + param[1] = 0x0; + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + param, 2); + if (ret < 0) { + return ret; + } + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_bank0, sizeof(hx8394_bank0)); + if (ret < 0) { + return ret; + } + + /* This command is not documented in datasheet, but is included + * in the display initialization done by MCUXpresso SDK + */ + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + hx8394_cmd3, sizeof(hx8394_cmd3)); + if (ret < 0) { + return ret; + } + + ret = mipi_dsi_generic_write(config->mipi_dsi, config->channel, + tear_config, sizeof(tear_config)); + if (ret < 0) { + return ret; + } + + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + return ret; + } + /* We must delay 120ms after exiting sleep mode per datasheet */ + k_sleep(K_MSEC(120)); + ret = mipi_dsi_dcs_write(config->mipi_dsi, config->channel, + MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + + if (config->bl_gpio.port != NULL) { + ret = gpio_pin_configure_dt(&config->bl_gpio, GPIO_OUTPUT_ACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure bl GPIO (%d)", ret); + return ret; + } + } + + return ret; +} + +#define HX8394_PANEL(id) \ + static const struct hx8394_config hx8394_config_##id = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(id)), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(id, reset_gpios, {0}), \ + .bl_gpio = GPIO_DT_SPEC_INST_GET_OR(id, bl_gpios, {0}), \ + .num_of_lanes = DT_INST_PROP_BY_IDX(id, data_lanes, 0), \ + .pixel_format = DT_INST_PROP(id, pixel_format), \ + .panel_width = DT_INST_PROP(id, width), \ + .panel_height = DT_INST_PROP(id, height), \ + .channel = DT_INST_REG_ADDR(id), \ + }; \ + DEVICE_DT_INST_DEFINE(id, \ + &hx8394_init, \ + NULL, \ + NULL, \ + &hx8394_config_##id, \ + POST_KERNEL, \ + CONFIG_APPLICATION_INIT_PRIORITY, \ + &hx8394_api); + +DT_INST_FOREACH_STATUS_OKAY(HX8394_PANEL) diff --git a/dts/bindings/display/himax,hx8394.yaml b/dts/bindings/display/himax,hx8394.yaml new file mode 100644 index 000000000000..c137ad60fb2d --- /dev/null +++ b/dts/bindings/display/himax,hx8394.yaml @@ -0,0 +1,24 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Himax HX8394 Panel + +compatible: "himax,hx8394" + +include: [mipi-dsi-device.yaml, display-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + description: | + The RESX pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + + bl-gpios: + type: phandle-array + description: | + The BLn pin is asserted to control the backlight of the panel. + The sensor receives this as an active-high signal. From 638e3d5d9c40b27ef745d6ebb131406aad728f53 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Fri, 7 Jul 2023 18:24:05 +0000 Subject: [PATCH 1913/2042] boards: shields: add rk055hdmipi4ma0 shield Add rk055hdmipi4ma0 shield, which uses an HX8394 TFT LCD controller and GT911 touch IC. This shield is enabled on the RT595 and RT1170 EVK, which have 40 pin FFC interfaces capable of connecting to the display. Signed-off-by: Daniel DeGrasse --- boards/arm/mimxrt1170_evk/doc/index.rst | 5 +- boards/arm/mimxrt595_evk/doc/index.rst | 3 +- .../shields/rk055hdmipi4ma0/Kconfig.defconfig | 56 ++++++++++++ boards/shields/rk055hdmipi4ma0/Kconfig.shield | 5 + .../boards/mimxrt595_evk_cm33.conf | 14 +++ .../boards/mimxrt595_evk_cm33.overlay | 18 ++++ boards/shields/rk055hdmipi4ma0/doc/index.rst | 68 ++++++++++++++ .../rk055hdmipi4ma0/rk055hdmipi4ma0.overlay | 91 +++++++++++++++++++ 8 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 boards/shields/rk055hdmipi4ma0/Kconfig.defconfig create mode 100644 boards/shields/rk055hdmipi4ma0/Kconfig.shield create mode 100644 boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.conf create mode 100644 boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.overlay create mode 100644 boards/shields/rk055hdmipi4ma0/doc/index.rst create mode 100644 boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index f62bd6c63dac..63b0e5ddbe66 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -131,8 +131,9 @@ RT1170 EVKB (`mimxrt1170_evkb_cm7/cm4`) | HWINFO | on-chip | Unique device serial number | Supported (M7) | Supported (M7) | +-----------+------------+-------------------------------------+-----------------+-----------------+ | DISPLAY | on-chip | eLCDIF; MIPI-DSI. Tested with | Supported (M7) | Supported (M7) | -| | | :ref:`rk055hdmipi4m` and | | | -| | | :ref:`g1120b0mipi` shields | | | +| | | :ref:`rk055hdmipi4m`, | | | +| | | :ref:`rk055hdmipi4ma0`, | | | +| | | and :ref:`g1120b0mipi` shields | | | +-----------+------------+-------------------------------------+-----------------+-----------------+ | ACMP | on-chip | analog comparator | Supported | No support | +-----------+------------+-------------------------------------+-----------------+-----------------+ diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index a7b53ea763ce..61ed427858a1 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -109,7 +109,8 @@ already supported, which can also be re-used on this mimxrt595_evk board: | I2S | on-chip | i2s | +-----------+------------+-------------------------------------+ | DISPLAY | on-chip | LCDIF; MIPI-DSI. Tested with | -| | | :ref:`rk055hdmipi4m` and | +| | | :ref:`rk055hdmipi4m`, | +| | | :ref:`rk055hdmipi4ma0`, and | | | | :ref:`g1120b0mipi` display shields | +-----------+------------+-------------------------------------+ diff --git a/boards/shields/rk055hdmipi4ma0/Kconfig.defconfig b/boards/shields/rk055hdmipi4ma0/Kconfig.defconfig new file mode 100644 index 000000000000..6b7c77037b4d --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/Kconfig.defconfig @@ -0,0 +1,56 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_RK055HDMIPI4MA0 + +if DISPLAY + +# Enable MIPI DSI, as this display controller requires it. + +config MIPI_DSI + default y + +endif # DISPLAY + +if LVGL + +# Configure LVGL to use touchscreen with KSCAN API + +config KSCAN + default y + +config INPUT + default y if KSCAN + +config INPUT_GT911_INTERRUPT + default y + +config LV_Z_POINTER_KSCAN + default y + +# LVGL should allocate buffers equal to size of display +config LV_Z_VDB_SIZE + default 100 + +# Enable double buffering +config LV_Z_DOUBLE_VDB + default y + +# Force full refresh. This prevents memory copy associated with partial +# display refreshes, which is not necessary for the eLCDIF driver +config LV_Z_FULL_REFRESH + default y + +config LV_Z_BITS_PER_PIXEL + default 16 + +config LV_DPI_DEF + default 128 + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 +endchoice + +endif # LVGL + +endif # SHIELD_RK055HDMIPI4MA0 diff --git a/boards/shields/rk055hdmipi4ma0/Kconfig.shield b/boards/shields/rk055hdmipi4ma0/Kconfig.shield new file mode 100644 index 000000000000..96702b2dce69 --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_RK055HDMIPI4MA0 + def_bool $(shields_list_contains,rk055hdmipi4ma0) diff --git a/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.conf b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.conf new file mode 100644 index 000000000000..bf60c87c6934 --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.conf @@ -0,0 +1,14 @@ +# +# Copyright 2023, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Use external framebuffer memory +CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_MEM=y +CONFIG_LV_Z_VBD_CUSTOM_SECTION=y +# Use FlexSPI2 for framebuffer (pSRAM is present on this bus) +CONFIG_MCUX_DCNANO_LCDIF_EXTERNAL_FB_ADDR=0x38400000 +# M33 core and LCDIF both access FlexSPI2 through the same cache, +# so coherency does not need to be managed. +CONFIG_MCUX_DCNANO_LCDIF_MAINTAIN_CACHE=n diff --git a/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.overlay b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 000000000000..38bc21b8de71 --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,18 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Configure FlexSPI2 to use 1KB of AHB RX buffer for GPU/Display master. + * This will improve performance when using external pSRAM. + */ +&flexspi2 { + rx-buffer-config = <1 7 11 1024>; +}; + +/* GT911 IRQ GPIO is active low on this board */ +&touch_controller_rk055hdmipi4ma0 { + irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_LOW>; +}; diff --git a/boards/shields/rk055hdmipi4ma0/doc/index.rst b/boards/shields/rk055hdmipi4ma0/doc/index.rst new file mode 100644 index 000000000000..887a70fb2467 --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/doc/index.rst @@ -0,0 +1,68 @@ +.. _rk055hdmipi4ma0: + +RK055HDMIPI4MA0 MIPI Display +############################ + +Overview +******** + +The Rocktech RK055HDMIPI4MA0 MIPI Display is a 5.5 inch TFT 720x1280 pixels +panel with LED backlighting, full viewing angle, MIPI interface and +capacitive touch panel from Rocktech. + +More information about the shield can be found +at the `RK055HDMIPI4MA0 product page`_. + +This display uses a 40 pin FPC interface, which is available on many +NXP EVKs. + +Pins Assignment of the Rocktech RK055HDMIPI4MA0 MIPI Display +============================================================ + ++-----------------------+------------------------+ +| FPC Connector Pin | Function | ++=======================+========================+ +| 1 | LED backlight cathode | ++-----------------------+------------------------+ +| 21 | Controller reset | ++-----------------------+------------------------+ +| 22 | Controller LPTE | ++-----------------------+------------------------+ +| 26 | Touch ctrl I2C SDA | ++-----------------------+------------------------+ +| 27 | Touch ctrl I2C SCL | ++-----------------------+------------------------+ +| 28 | Touch ctrl reset | ++-----------------------+------------------------+ +| 29 | Touch ctrl interrupt | ++-----------------------+------------------------+ +| 32 | LCD power enable | ++-----------------------+------------------------+ +| 34 | Backlight power enable | ++-----------------------+------------------------+ + +Requirements +************ + +This shield can only be used with a board which provides a configuration +for the 40 pin FPC interface + +Programming +*********** + +Set ``-DSHIELD=rk055hdmipi4ma0`` when you invoke ``west build``. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/display + :board: mixmrt1170_evk_cm7 + :shield: rk055hdmipi4ma0 + :goals: build + +References +********** + +.. target-notes:: + +.. _RK055HDMIPI4MA0 product page: + https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/5-5-lcd-panel:RK055HDMIPI4MA0 diff --git a/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay b/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay new file mode 100644 index 000000000000..c7e5e3966a97 --- /dev/null +++ b/boards/shields/rk055hdmipi4ma0/rk055hdmipi4ma0.overlay @@ -0,0 +1,91 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/{ + aliases { + kscan0 = &kscan_input_gt911; + }; + + chosen { + zephyr,display = &lcdif; + zephyr,keyboard-scan = &kscan_input_gt911; + }; + + en_mipi_display_rk055hdmipi4ma0: enable-mipi-display-rk055hdmipi4ma0 { + compatible = "regulator-fixed"; + regulator-name = "en_mipi_display"; + enable-gpios = <&nxp_mipi_connector 32 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; +}; + +&nxp_mipi_i2c { + status = "okay"; + touch_controller_rk055hdmipi4ma0: gt911-rk055hdmipi4ma0@5d { + compatible = "goodix,gt911"; + reg = <0x5d>; + irq-gpios = <&nxp_mipi_connector 29 GPIO_ACTIVE_HIGH>; + reset-gpios = <&nxp_mipi_connector 28 GPIO_ACTIVE_HIGH>; + kscan_input_gt911: kscan-input { + compatible = "zephyr,kscan-input"; + }; + }; +}; + +&zephyr_lcdif { + status = "okay"; + width = <720>; + height = <1280>; + display-timings { + compatible = "zephyr,panel-timing"; + hsync-len = <6>; + hfront-porch = <12>; + hback-porch = <24>; + vsync-len = <2>; + vfront-porch = <16>; + vback-porch = <14>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + /* + * Pixel clock is given by the following formula: + * (height + vsync-len + vfront-porch + vback-porch) * + * (width + hsync-len + hfront-porch + hback-porch) * frame rate + */ + clock-frequency = <62346240>; + }; + pixel-format = ; + data-bus-width = "24-bit"; + backlight-gpios = <&nxp_mipi_connector 0 GPIO_ACTIVE_HIGH>; +}; + +&zephyr_mipi_dsi { + status = "okay"; + nxp,lcdif = <&lcdif>; + dpi-color-coding = "24-bit"; + dpi-pixel-packet = "24-bit"; + dpi-video-mode = "burst"; + dpi-bllp-mode = "low-power"; + autoinsert-eotp; + /* + * PHY clock is given by the following formula: + * (pixel clock * bits per pixel) / MIPI data lanes + */ + phy-clock = <748154880>; + hx8394-rk055hdmipi4ma0@0 { + status = "okay"; + compatible = "himax,hx8394"; + reg = <0x0>; + reset-gpios = <&nxp_mipi_connector 21 GPIO_ACTIVE_HIGH>; + data-lanes = <2>; + width = <720>; + height = <1280>; + pixel-format = ; + }; +}; From bd34c946fc25f86d617bd6421336211bbff6af32 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 14 Jul 2023 23:23:15 +0200 Subject: [PATCH 1914/2042] net: introduce scalar nanosecond time representation Introduces a well-defined intermediate concept of syntonized scalar nanosecond resolution time with overflow protection above low-level counters/cycles/ticks and below higher level time abstractions (timescales, calenders, etc.). The rationale of this type has been extensively documented and contrasted to already existing time representations to ensure that it fills a well defined gap without overlap. This change prepares for later changes in this change set that will unify the usage of time across the network subsystem (RX/TX timestamps, timed TX, CSL, scheduled reception windows, (g)PTP integration, etc.). The type is EXPERIMENTAL and named net_time_t while it is not used in a larger clock subsystems, the details of which are still being discussed (see #60400 for details). See https://github.com/zephyrproject-rtos/zephyr/issues/19030#issuecomment-1597226731 for its embedding in a larger clock subsystem architecture relevant to the network stack, IEEE 802.15.4 and the POSIX roadmap. Signed-off-by: Florian Grandel --- include/zephyr/net/net_time.h | 115 ++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 include/zephyr/net/net_time.h diff --git a/include/zephyr/net/net_time.h b/include/zephyr/net/net_time.h new file mode 100644 index 000000000000..6277ea994c86 --- /dev/null +++ b/include/zephyr/net/net_time.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023 Zephyr Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Representation of nanosecond resolution elapsed time and timestamps in + * the network stack. + * + * Inspired by + * https://github.com/torvalds/linux/blob/master/include/linux/ktime.h and + * https://github.com/torvalds/linux/blob/master/[tools/]include/linux/time64.h + */ + +#ifndef ZEPHYR_INCLUDE_NET_NET_TIME_H_ +#define ZEPHYR_INCLUDE_NET_NET_TIME_H_ + +/* Include required for NSEC_PER_* constants. */ +#include "zephyr/sys_clock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Any occurrence of net_time_t specifies a concept of nanosecond + * resolution scalar time span, future (positive) or past (negative) relative + * time or absolute timestamp referred to some local network uptime reference + * clock that does not wrap during uptime and is - in a certain, well-defined + * sense - common to all local network interfaces, sometimes even to remote + * interfaces on the same network. + * + * This type is EXPERIMENTAL. Usage is currently restricted to representation of + * time within the network subsystem. + * + * @details Timed network protocols (PTP, TDMA, ...) usually require several + * local or remote interfaces to share a common notion of elapsed time within + * well-defined tolerances. Network uptime therefore differs from time + * represented by a single hardware counter peripheral in that it will need to + * be represented in several distinct hardware peripherals with different + * frequencies, accuracy and precision. To co-operate, these hardware counters + * will have to be "syntonized" or "disciplined" (i.e. frequency and phase + * locked) with respect to a common local or remote network reference time + * signal. Be aware that while syntonized clocks share the same frequency and + * phase, they do not usually share the same epoch (zero-point). + * + * This also explains why network time, if represented as a cycle value of some + * specific hardware counter, will never be "precise" but only can be "good + * enough" with respect to the tolerances (resolution, drift, jitter) required + * by a given network protocol. All counter peripherals involved in a timed + * network protocol must comply with these tolerances. + * + * Please use specific cycle/tick counter values rather than net_time_t whenever + * possible especially when referring to the kernel system clock or values of + * any single counter peripheral. + * + * net_time_t cannot represent general clocks referred to an arbitrary epoch as + * it only covers roughly +/- ~290 years. It also cannot be used to represent + * time according to a more complex timescale (e.g. including leap seconds, time + * adjustments, complex calendars or time zones). In these cases you may use + * @ref timespec (C11, POSIX.1-2001), @ref timeval (POSIX.1-2001) or broken down + * time as in @ref tm (C90). The advantage of net_time_t over these structured + * time representations is lower memory footprint, faster and simpler scalar + * arithmetics and easier conversion from/to low-level hardware counter values. + * Also net_time_t can be used in the network stack as well as in applications + * while POSIX concepts cannot. Converting net_time_t from/to structured time + * representations is possible in a limited way but - except for @ref timespec - + * requires concepts that must be implemented by higher-level APIs. Utility + * functions converting from/to @ref timespec will be provided as part of the + * net_time_t API as and when needed. + * + * If you want to represent more coarse grained scalar time in network + * applications, use @ref time_t (C99, POSIX.1-2001) which is specified to + * represent seconds or @ref suseconds_t (POSIX.1-2001) for microsecond + * resolution. Kernel @ref k_ticks_t and cycles (both specific to Zephyr) have + * an unspecified resolution but are useful to represent kernel timer values and + * implement high resolution spinning. + * + * If you need even finer grained time resolution, you may want to look at + * (g)PTP concepts, see @ref net_ptp_extended_time. + * + * The reason why we don't use int64_t directly to represent scalar nanosecond + * resolution times in the network stack is that it has been shown in the past + * that fields using generic type will often not be used correctly (e.g. with + * the wrong resolution or to represent underspecified concepts of time with + * unclear syntonization semantics). + * + * Any API that exposes or consumes net_time_t values SHALL ensure that it + * maintains the specified contract including all protocol specific tolerances + * and therefore clients can rely on common semantics of this type. This makes + * times coming from different hardware peripherals and even from different + * network nodes comparable within well-defined limits and therefore net_time_t + * is the ideal intermediate building block for timed network protocols. + */ +typedef int64_t net_time_t; + +/** The largest positive time value that can be represented by net_time_t */ +#define NET_TIME_MAX INT64_MAX + +/** The smallest negative time value that can be represented by net_time_t */ +#define NET_TIME_MIN INT64_MIN + +/** The largest positive number of seconds that can be safely represented by net_time_t */ +#define NET_TIME_SEC_MAX (NET_TIME_MAX / NSEC_PER_SEC) + +/** The smallest negative number of seconds that can be safely represented by net_time_t */ +#define NET_TIME_SEC_MIN (NET_TIME_MIN / NSEC_PER_SEC) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_NET_NET_TIME_H_ */ From 7378b9129407640403058362414909e9f4854b39 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 11 Jul 2023 18:45:08 +0200 Subject: [PATCH 1915/2042] doc: net: ptp: PTP structs Improves documentation of PTP structs and explains basic underlying concepts to increase the probability that these structs will be used correctly and consistently. Also introduces references to the underlying specifications. Note: We currently (ab)use the PTP structs for timestamps in the IEEE 802.15.4 context for which they are undefined. It is also not ideal that the generic `struct net_pkt` depends directly on PTP. Future changes will therefore have to remove the reference to PTP structs in net_pkt and replace them by net_time_t. Clients will then have to convert these to PTP structures if required. Signed-off-by: Florian Grandel --- include/zephyr/net/ptp_time.h | 94 +++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/include/zephyr/net/ptp_time.h b/include/zephyr/net/ptp_time.h index 81c445511369..c85d9b69dd39 100644 --- a/include/zephyr/net/ptp_time.h +++ b/include/zephyr/net/ptp_time.h @@ -8,6 +8,8 @@ * @file * @brief Public functions for the Precision Time Protocol time specification. * + * References are to version 2019 of IEEE 1588, ("PTP") + * and version 2020 of IEEE 802.1AS ("gPTP"). */ #ifndef ZEPHYR_INCLUDE_NET_PTP_TIME_H_ @@ -28,13 +30,80 @@ extern "C" { #endif /** - * @brief Precision Time Protocol Timestamp format. + * @brief (Generalized) Precision Time Protocol Timestamp format. * - * This structure represents a timestamp according - * to the Precision Time Protocol standard. + * @details This structure represents a timestamp according to the Precision + * Time Protocol standard ("PTP", IEEE 1588, section 5.3.3), the Generalized + * Precision Time Protocol standard ("gPTP", IEEE 802.1AS, section 6.4.3.4), or + * any other well-defined context in which precision structured timestamps are + * required on network messages in Zephyr. * - * Seconds are encoded as a 48 bits unsigned integer. - * Nanoseconds are encoded as a 32 bits unsigned integer. + * Seconds are encoded as a 48 bits unsigned integer. Nanoseconds are encoded + * as a 32 bits unsigned integer. + * + * In the context of (g)PTP, @em timestamps designate the time, relative to a + * local clock ("LocalClock") at which the message timestamp point passes a + * reference plane marking the boundary between the PTP Instance and the network + * medium (IEEE 1855, section 7.3.4.2; IEEE 802.1AS, section 8.4.3). + * + * The exact definitions of the message timestamp point and + * reference plane depends on the network medium and use case. + * + * For (g)PTP the media-specific message timestamp points and reference planes + * are defined in the standard. In non-PTP contexts specific to Zephyr, + * timestamps are measured relative to the same local clock but with a + * context-specific message timestamp point and reference plane, defined below + * per use case. + * + * A @em "LocalClock" is a freerunning clock, embedded into a well-defined + * entity (e.g. a PTP Instance) and provides a common time to that entity + * relative to an arbitrary epoch (IEEE 1855, section 3.1.26, IEEE 802.1AS, + * section 3.16). + * + * In Zephyr, the local clock is usually any instance of a kernel system clock + * driver, counter driver, RTC API driver or low-level counter/timer peripheral + * (e.g. an ethernet peripheral with hardware timestamp support or a radio + * timer) with sufficient precision for the context in which it is used. + * + * See IEEE 802.1AS, Annex B for specific performance requirements regarding + * conformance of local clocks in the gPTP context. See IEEE 1588, Annex A, + * section A5.4 for general performance requirements regarding PTP local clocks. + * See IEEE 802.15.4-2020, section 15.7 for requirements in the context of + * ranging applications and ibid., section 6.7.6 for the relation between guard + * times and clock accuracy which again influence the precision required for + * subprotocols like CSL, TSCH, RIT, etc. + * + * Applications that use timestamps across different subsystems or media must + * ensure that they understand the definition of the respective reference planes + * and interpret timestamps accordingly. Applications must further ensure that + * timestamps are either all referenced to the same local clock or convert + * between clocks based on sufficiently precise conversion algorithms. + * + * Timestamps may be measured on ingress (RX timestamps) or egress (TX + * timestamps) of network messages. Timestamps can also be used to schedule a + * network message to a well-defined point in time in the future at which it is + * to be sent over the medium (timed TX). A future timestamp and a duration, + * both referenced to the local clock, may be given to specify a time window at + * which a network device should expect incoming messages (RX window). + * + * In Zephyr this timestamp structure is currently used in the following + * contexts: + * * gPTP for Full Duplex Point-to-Point IEEE 802.3 links (IEEE 802.1AS, + * section 11): the reference plane and message timestamp points are as + * defined in the standard. + * * IEEE 802.15.4 timed TX and RX: Timestamps designate the point in time at + * which the end of the last symbol of the start-of-frame delimiter (SFD) (or + * equivalently, the start of the first symbol of the PHY header) is at the + * local antenna. The standard also refers to this as the "RMARKER" (IEEE + * 802.15.4-2020, section 6.9.1) or "symbol boundary" (ibid., section 6.5.2), + * depending on the context. In the context of beacon timestamps, the + * difference between the timestamp measurement plane and the reference plane + * is defined by the MAC PIB attribute "macSyncSymbolOffset", ibid., section + * 8.4.3.1, table 8-94. + * + * If further use cases are added to Zephyr using this timestamp structure, + * their clock performance requirements, message timestamp points and reference + * plane definition SHALL be added to the above list. */ struct net_ptp_time { /** Seconds encoded on 48 bits. */ @@ -62,14 +131,17 @@ struct net_ptp_time { #endif /** - * @brief Precision Time Protocol Extended Timestamp format. + * @brief Generalized Precision Time Protocol Extended Timestamp format. + * + * @details This structure represents an extended timestamp according to the + * Generalized Precision Time Protocol standard (IEEE 802.1AS), see section + * 6.4.3.5. * - * This structure represents an extended timestamp according - * to the Precision Time Protocol standard. + * Seconds are encoded as 48 bits unsigned integer. Fractional nanoseconds are + * encoded as 48 bits, their unit is 2*(-16) ns. * - * Seconds are encoded as 48 bits unsigned integer. - * Fractional nanoseconds are encoded as 48 bits, their unit - * is 2*(-16) ns. + * A precise definition of PTP timestamps and their uses in Zephyr is given in + * the description of @ref net_ptp_time. */ struct net_ptp_extended_time { /** Seconds encoded on 48 bits. */ From 69212bb1699c775c2abd659f5f34febfaadf30ae Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 11 Jul 2023 17:50:35 +0200 Subject: [PATCH 1916/2042] doc: drivers: ieee802154: radio API Improves the documentation of the IEEE 802.15.4 radio API. Signed-off-by: Florian Grandel --- include/zephyr/net/ieee802154_radio.h | 488 ++++++++++++++++++++------ subsys/net/ip/Kconfig | 3 +- 2 files changed, 391 insertions(+), 100 deletions(-) diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 6006bd813ece..5e2d35ca9caf 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -97,24 +97,83 @@ enum ieee802154_channel { }; enum ieee802154_hw_caps { - IEEE802154_HW_FCS = BIT(0), /* Frame Check-Sum supported */ - IEEE802154_HW_PROMISC = BIT(1), /* Promiscuous mode supported */ - IEEE802154_HW_FILTER = BIT(2), /* Filter PAN ID, long/short addr */ - IEEE802154_HW_CSMA = BIT(3), /* Executes CSMA-CA procedure on TX */ - IEEE802154_HW_RETRANSMISSION = BIT(4), /* Handles retransmission on TX ACK timeout */ - IEEE802154_HW_TX_RX_ACK = BIT(5), /* Waits for ACK on TX if AR bit is set in TX pkt */ - IEEE802154_HW_RX_TX_ACK = BIT(6), /* Sends ACK on RX if AR bit is set in RX pkt */ - IEEE802154_HW_ENERGY_SCAN = BIT(7), /* Energy scan supported */ - IEEE802154_HW_TXTIME = BIT(8), /* TX at specified time supported */ - IEEE802154_HW_SLEEP_TO_TX = BIT(9), /* TX directly from sleep supported */ - IEEE802154_HW_TX_SEC = BIT(10), /* TX security handling supported */ - IEEE802154_HW_RXTIME = BIT(11), /* RX at specified time supported */ - IEEE802154_HW_2_4_GHZ = BIT(12), /* 2.4Ghz radio supported - * TODO: Replace with channel page attribute. - */ - IEEE802154_HW_SUB_GHZ = BIT(13), /* Sub-GHz radio supported - * TODO: Replace with channel page attribute. - */ + + /* + * PHY capabilities + * + * The following capabilities describe features of the underlying radio + * hardware (PHY/L1). + * + * Note: A device driver must support the mandatory channel pages, + * frequency bands and channels of at least one IEEE 802.15.4 PHY. + */ + + /** + * 2.4Ghz radio supported + * + * TODO: Replace with channel page attribute. + */ + IEEE802154_HW_2_4_GHZ = BIT(0), + + /** + * Sub-GHz radio supported + * + * TODO: Replace with channel page attribute. + */ + IEEE802154_HW_SUB_GHZ = BIT(1), + + /** Energy detection (ED) supported (optional) */ + IEEE802154_HW_ENERGY_SCAN = BIT(2), + + + /* + * MAC offloading capabilities (optional) + * + * The following MAC/L2 features may optionally be offloaded to + * specialized hardware or proprietary driver firmware ("hard MAC"). + * + * L2 implementations will have to provide a "soft MAC" fallback for + * these features in case the driver does not support them natively. + * + * Note: Some of these offloading capabilities may be mandatory in + * practice to stay within timing requirements of certain IEEE 802.15.4 + * protocols, e.g. CPUs may not be fast enough to send ACKs within the + * required delays in the 2.4 GHz band without hard MAC support. + */ + + /** Frame checksum verification supported */ + IEEE802154_HW_FCS = BIT(3), + + /** Filtering of PAN ID, extended and short address supported */ + IEEE802154_HW_FILTER = BIT(4), + + /** Promiscuous mode supported */ + IEEE802154_HW_PROMISC = BIT(5), + + /** CSMA-CA procedure supported on TX */ + IEEE802154_HW_CSMA = BIT(6), + + /** Waits for ACK on TX if AR bit is set in TX pkt */ + IEEE802154_HW_TX_RX_ACK = BIT(7), + + /** Supports retransmission on TX ACK timeout */ + IEEE802154_HW_RETRANSMISSION = BIT(8), + + /** Sends ACK on RX if AR bit is set in RX pkt */ + IEEE802154_HW_RX_TX_ACK = BIT(9), + + /** TX at specified time supported */ + IEEE802154_HW_TXTIME = BIT(10), + + /** TX directly from sleep supported */ + IEEE802154_HW_SLEEP_TO_TX = BIT(11), + + /** Timed RX window scheduling supported */ + IEEE802154_HW_RXTIME = BIT(12), + + /** TX security supported (key management, encryption and authentication) */ + IEEE802154_HW_TX_SEC = BIT(13), + /* Note: Update also IEEE802154_HW_CAPS_BITS_COMMON_COUNT when changing * the ieee802154_hw_caps type. */ @@ -155,13 +214,13 @@ typedef void (*ieee802154_event_cb_t)(const struct device *dev, void *event_params); struct ieee802154_filter { -/** @cond ignore */ +/** @cond INTERNAL_HIDDEN */ union { uint8_t *ieee_addr; /* in little endian */ uint16_t short_addr; /* in CPU byte order */ uint16_t pan_id; /* in CPU byte order */ }; -/* @endcond */ +/** @endcond */ }; struct ieee802154_key { @@ -181,20 +240,23 @@ enum ieee802154_tx_mode { IEEE802154_TX_MODE_CCA, /** - * Perform full CSMA CA procedure before packet transmission. - * Requires IEEE802154_HW_CSMA capability. + * Perform full CSMA/CA procedure before packet transmission. + * + * @note requires IEEE802154_HW_CSMA capability. */ IEEE802154_TX_MODE_CSMA_CA, /** * Transmit packet in the future, at specified time, no CCA. - * Requires IEEE802154_HW_TXTIME capability. + * + * @note requires IEEE802154_HW_TXTIME capability. */ IEEE802154_TX_MODE_TXTIME, /** * Transmit packet in the future, perform CCA before transmission. - * Requires IEEE802154_HW_TXTIME capability. + * + * @note requires IEEE802154_HW_TXTIME capability. */ IEEE802154_TX_MODE_TXTIME_CCA, @@ -254,14 +316,14 @@ enum ieee802154_config_type { IEEE802154_CONFIG_FRAME_COUNTER, /** Sets the current MAC frame counter value if the provided value is greater than - * the current one. + * the current one. */ - IEEE802154_CONFIG_FRAME_COUNTER_IF_LARGER, - /** Configure a radio reception slot. This can be used for any scheduled reception, e.g.: - * Zigbee GP device, CSL, TSCH, etc. - * Requires IEEE802154_HW_RXTIME capability. + /** Configure a radio reception window. This can be used for any + * scheduled reception, e.g.: Zigbee GP device, CSL, TSCH, etc. + * + * @note requires IEEE802154_HW_RXTIME capability. */ IEEE802154_CONFIG_RX_SLOT, @@ -270,19 +332,19 @@ enum ieee802154_config_type { * In order to configure a CSL receiver the upper layer should combine several * configuration options in the following way: * 1. Use ``IEEE802154_CONFIG_ENH_ACK_HEADER_IE`` once to inform the radio driver of the - * short and extended addresses of the peer to which it should inject CSL IEs. + * short and extended addresses of the peer to which it should inject CSL IEs. * 2. Use ``IEEE802154_CONFIG_CSL_RX_TIME`` periodically, before each use of - * ``IEEE802154_CONFIG_CSL_PERIOD`` setting parameters of the nearest CSL RX window, and - * before each use of IEEE_CONFIG_RX_SLOT setting parameters of the following (not the - * nearest one) CSL RX window, to allow the radio driver to calculate the proper CSL Phase - * to the nearest CSL window to inject in the CSL IEs for both transmitted data and ack - * frames. + * ``IEEE802154_CONFIG_CSL_PERIOD`` setting parameters of the nearest CSL RX window, + * and before each use of IEEE_CONFIG_RX_SLOT setting parameters of the following (not + * the nearest one) CSL RX window, to allow the radio driver to calculate the proper + * CSL Phase to the nearest CSL window to inject in the CSL IEs for both transmitted + * data and ACK frames. * 3. Use ``IEEE802154_CONFIG_CSL_PERIOD`` on each value change to update the current CSL - * period value which will be injected in the CSL IEs together with the CSL Phase based on - * ``IEEE802154_CONFIG_CSL_RX_TIME``. + * period value which will be injected in the CSL IEs together with the CSL Phase + * based on ``IEEE802154_CONFIG_CSL_RX_TIME``. * 4. Use ``IEEE802154_CONFIG_RX_SLOT`` periodically to schedule the immediate receive - * window earlier enough before the expected window start time, taking into account - * possible clock drifts and scheduling uncertainties. + * window earlier enough before the expected window start time, taking into account + * possible clock drifts and scheduling uncertainties. * * This diagram shows the usage of the four options over time: * Start CSL Schedule CSL window @@ -301,8 +363,8 @@ enum ieee802154_config_type { */ IEEE802154_CONFIG_CSL_PERIOD, - /** Configure the next CSL receive window center, in units of microseconds, - * based on the radio time. + /** Configure the next CSL receive window (i.e. "channel sample") center, + * in units of microseconds relative to the network subsystem's local clock. */ IEEE802154_CONFIG_CSL_RX_TIME, @@ -364,40 +426,68 @@ struct ieee802154_config { /** ``IEEE802154_CONFIG_RX_SLOT`` */ struct { uint8_t channel; + + /** + * Microsecond resolution timestamp relative to the + * network subsystem's local clock defining the start of + * the RX window during which the receiver is expected + * to be listening (i.e. not including any startup + * times). + */ uint32_t start; + + /** + * Microsecond resolution duration of the RX window + * relative to the above RX window start time during + * which the receiver is expected to be listening (i.e. + * not including any shutdown times). + */ uint32_t duration; } rx_slot; - /** ``IEEE802154_CONFIG_CSL_PERIOD`` */ - uint32_t csl_period; /* in CPU byte order */ + /** + * ``IEEE802154_CONFIG_CSL_PERIOD`` + * + * The CSL period in units of 10 symbol periods, + * see section 7.4.2.3. + * + * in CPU byte order + */ + uint32_t csl_period; - /** ``IEEE802154_CONFIG_CSL_RX_TIME`` */ - uint32_t csl_rx_time; /* in microseconds, - * based on ieee802154_radio_api.get_time() - */ + /** + * ``IEEE802154_CONFIG_CSL_RX_TIME`` + * + * Microsecond resolution timestamp relative to the network + * subsystem's local clock defining the center of the CSL RX window + * at which the receiver is expected to be fully started up + * (i.e. not including any startup times). + */ + uint32_t csl_rx_time; /** ``IEEE802154_CONFIG_ENH_ACK_HEADER_IE`` */ struct { - const uint8_t *data; /* header IEs to be added to the Enh-Ack frame in - * little endian byte order - */ - uint16_t data_len; - uint16_t short_addr; /* in CPU byte order */ /** - * The extended address is expected to be passed starting - * with the most significant octet and ending with the - * least significant octet. - * A device with an extended address 01:23:45:67:89:ab:cd:ef - * as written in the usual big-endian hex notation should - * provide a pointer to an array containing values in the - * exact same order. + * header IEs to be added to the Enh-Ack frame + * + * in little endian */ - const uint8_t *ext_addr; /* in big endian */ + const uint8_t *data; + uint16_t data_len; + /** in CPU byte order */ + uint16_t short_addr; + /** in big endian */ + const uint8_t *ext_addr; } ack_ie; }; }; -/** IEEE 802.15.4 attributes. */ +/** + * @brief IEEE 802.15.4 driver attributes. + * + * See @ref ieee802154_attr_value and @ref ieee802154_radio_api for usage + * details. + */ enum ieee802154_attr { /** Number of attributes defined in ieee802154_attr. */ IEEE802154_ATTR_COMMON_COUNT, @@ -406,11 +496,28 @@ enum ieee802154_attr { IEEE802154_ATTR_PRIV_START = IEEE802154_ATTR_COMMON_COUNT, }; -/** IEEE 802.15.4 attribute value data. */ +/** + * @brief IEEE 802.15.4 driver attributes. + * + * @details This structure is reserved to scalar and structured attributes that + * originate in the driver implementation and can neither be implemented as + * boolean @ref ieee802154_hw_caps nor be derived directly or indirectly by the + * MAC (L2) layer. In particular this structure MUST NOT be used to return + * configuration data that originate from L2. + * + * @note To keep this union reasonably small, any attribute requiring a large + * memory area, SHALL be provided pointing to memory allocated from the driver's + * stack. Clients that need to persist the attribute value SHALL therefore copy + * such memory before returning control to the driver. + */ struct ieee802154_attr_value { union { /* TODO: Please remove when first attribute is added. */ uint8_t dummy; + + /* TODO: Add driver specific PHY attributes (symbol rate, + * aTurnaroundTime, aCcaTime, channels, channel pages, etc.) + */ }; }; @@ -420,84 +527,268 @@ struct ieee802154_attr_value { */ struct ieee802154_radio_api { /** - * Mandatory to get in first position. - * A network device should indeed provide a pointer on such - * net_if_api structure. So we make current structure pointer - * that can be casted to a net_if_api structure pointer. + * @brief network interface API + * + * @note Network devices must extend the network interface API. It is + * therefore mandatory to place it at the top of the radio API struct so + * that it can be cast to a network interface. */ struct net_if_api iface_api; - /** Get the device capabilities */ + /** + * @brief Get the device driver capabilities. + * + * @param dev pointer to radio device + * + * @return Bit field with all supported device driver capabilities. + */ enum ieee802154_hw_caps (*get_capabilities)(const struct device *dev); - /** Clear Channel Assessment - Check channel's activity */ + /** + * @brief Clear Channel Assessment - Check channel's activity + * + * @param dev pointer to radio device + * + * @retval 0 the channel is available + * @retval -EBUSY The channel is busy. + * @retval -EIO The CCA procedure could not be executed. + * @retval -ENOTSUP CCA is not supported by this driver. + */ int (*cca)(const struct device *dev); - /** Set current channel, channel is in CPU byte order. */ + /** + * @brief Set current channel + * + * @param dev pointer to radio device + * @param channel the number of the channel to be set in CPU byte order + * + * @retval 0 channel was successfully set + * @retval -EINVAL The given channel is not within the range of valid + * channels of the driver's current channel page. + * @retval -ENOTSUP The given channel is within the range of valid + * channels of the driver's current channel page but unsupported by the + * current driver. + * @retval -EIO The channel could not be set. + */ int (*set_channel)(const struct device *dev, uint16_t channel); - /** Set/Unset filters. Requires IEEE802154_HW_FILTER capability. */ + /** + * @brief Set/Unset PAN ID, extended or short address filters. + * + * @note requires IEEE802154_HW_FILTER capability. + * + * @param dev pointer to radio device + * @param set true to set the filter, false to remove it + * @param type the type of entity to be added/removed from the filter + * list (a PAN ID or a source/destination address) + * @param filter the entity to be added/removed from the filter list + * + * @retval 0 The filter was successfully added/removed. + * @retval -EINVAL The given filter entity or filter entity type + * was not valid. + * @retval -ENOTSUP Setting/removing this filter or filter type + * is not supported by this driver. + * @retval -EIO Error while setting/removing the filter. + */ int (*filter)(const struct device *dev, bool set, enum ieee802154_filter_type type, const struct ieee802154_filter *filter); - /** Set TX power level in dbm */ + /** + * @brief Set TX power level in dbm + * + * @param dev pointer to radio device + * @param dbm TX power in dbm + * + * @retval 0 The TX power was successfully set. + * @retval -EINVAL The given dbm value is invalid or not supported by + * the driver. + * @retval -EIO The TX power could not be set. + */ int (*set_txpower)(const struct device *dev, int16_t dbm); - /** Transmit a packet fragment */ + /** + * @brief Transmit a packet fragment as a single frame + * + * @warning The driver must not take ownership of the given network + * packet and frame (fragment) buffer. Any data required by the driver + * (including the actual frame content) must be read synchronously and + * copied internally if transmission is delayed or executed + * asynchronously. Both, the packet and the buffer may be re-used or + * released immediately after the function returns. + * + * @note Depending on the level of offloading features supported by the + * driver, the frame may not be fully encrypted/authenticated, may not + * contain an FCS or may contain incomplete information elements (IEs). + * It is the responsibility of L2 implementations to prepare the frame + * according to the offloading capabilities announced by the driver and + * to decide whether CCA, CSMA/CA or ACK procedures need to be executed + * in software ("soft MAC") or will be provided by the driver itself + * ("hard MAC"). + * + * @param dev pointer to radio device + * @param mode the transmission mode, some of which require specific + * offloading capabilities. + * @param pkt pointer to the network packet to be transmitted. + * @param frag pointer to a network buffer containing a single fragment + * with the frame data to be transmitted + * + * @retval 0 The frame was successfully sent or scheduled. If the driver + * supports ACK offloading and the frame requested acknowlegment (AR bit + * set), this means that the packet was successfully acknowledged by its + * peer. + * @retval -ENOTSUP The given TX mode is not supported. + * @retval -EIO The frame could not be sent due to some unspecified + * error. + * @retval -EBUSY The frame could not be sent because the medium was + * busy (CSMA/CA or CCA offloading feature only). + * @retval -ENOMSG The frame was not confirmed by an ACK packet (TX ACK + * offloading feature only). + * @retval -ENOBUFS The frame could not be scheduled due to missing + * internal buffer resources (timed TX offloading feature only). + */ int (*tx)(const struct device *dev, enum ieee802154_tx_mode mode, struct net_pkt *pkt, struct net_buf *frag); - /** Start the device */ + /** + * @brief Start the device and place it in receive mode. + * + * @param dev pointer to radio device + * + * @retval 0 The driver was successfully started. + * @retval -EIO The driver could not be started. + */ int (*start)(const struct device *dev); - /** Stop the device */ + /** + * @brief Stop the device and switch off the receiver (sleep mode). + * + * @param dev pointer to radio device + * + * @retval 0 The driver was successfully stopped. + * @retval -EIO The driver could not be stopped. + */ int (*stop)(const struct device *dev); - /** Start continuous carrier wave transmission. - * To leave this mode, `start()` or `stop()` API function should be called, - * resulting in changing radio's state to receive or sleep, respectively. + /** + * @brief Start continuous carrier wave transmission. + * + * @details To leave this mode, `start()` or `stop()` should be called, + * putting the radio driver in receive or sleep mode, respectively. + * + * @param dev pointer to radio device + * + * @retval 0 continuous carrier wave transmission started + * @retval -EIO not started */ int (*continuous_carrier)(const struct device *dev); - /** Set specific radio driver configuration. */ + /** + * @brief Set radio driver configuration. + * + * @param dev pointer to radio device + * @param type the configuration type to be set + * @param config the configuration parameters to be set for the given + * configuration type + * + * @retval 0 configuration successful + * @retval -ENOTSUP The given configuration type is not supported by + * this driver. + * @retval -EINVAL The configuration parameters are invalid for the + * given configuration type. + * @retval -ENOMEM The configuration cannot be saved due to missing + * memory resources. + * @retval -ENOENT The resource referenced in the configuration + * parameters cannot be found in the configuration. + */ int (*configure)(const struct device *dev, enum ieee802154_config_type type, const struct ieee802154_config *config); /** - * Get the available amount of Sub-GHz channels - * TODO: Replace with a combination of channel page and channel attributes. + * @brief Get the available amount of Sub-GHz channels. + * + * TODO: Replace with a combination of channel page and channel + * attributes. + * + * @param dev pointer to radio device + * + * @return number of available channels in the sub-gigahertz band */ uint16_t (*get_subg_channel_count)(const struct device *dev); - /** Run an energy detection scan. - * Note: channel must be set prior to request this function. - * duration parameter is in ms. - * Requires IEEE802154_HW_ENERGY_SCAN capability. + /** + * @brief Run an energy detection scan. + * + * @note requires IEEE802154_HW_ENERGY_SCAN capability + * + * @note The radio channel must be set prior to calling this function. + * + * @param dev pointer to radio device + * @param duration duration of energy scan in ms + * @param done_cb function called when the energy scan has finished + * + * @retval 0 the energy detection scan was successfully scheduled + * + * @retval -EBUSY the energy detection scan could not be scheduled at + * this time + * @retval -EALREADY a previous energy detection scan has not finished + * yet. + * @retval -ENOTSUP This driver does not support energy scans. */ int (*ed_scan)(const struct device *dev, uint16_t duration, energy_scan_done_cb_t done_cb); - /** Get the current radio time in microseconds - * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. + /** + * @brief Get the current time in microseconds relative to the network + * subsystem's local clock. + * + * @note requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME + * capabilities. + * + * @param dev pointer to radio device + * + * @return microseconds relative to the network subsystem's local clock */ uint64_t (*get_time)(const struct device *dev); - /** Get the current accuracy, in units of ± ppm, of the clock used for - * scheduling delayed receive or transmit radio operations. - * Note: Implementations may optimize this value based on operational - * conditions (i.e.: temperature). - * Requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME capabilities. + /** + * @brief Get the current estimated worst case accuracy (maximum ± + * deviation from the nominal frequency) of the network subsystem's + * local clock used to calculate tolerances and guard times when + * scheduling delayed receive or transmit radio operations. + * + * The deviation is given in units of PPM (parts per million). + * + * @note requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME + * capabilities. + * + * @note Implementations may estimate this value based on current + * operating conditions (e.g. temperature). + * + * @param dev pointer to radio device + * + * @return current estimated clock accuracy in PPM */ uint8_t (*get_sch_acc)(const struct device *dev); - /** Get the value of an attribute. - * If the requested attribute is supported by implementation, this function returns 0 - * and fills appropriate version of union in `value`. - * If requested attribute is not supported, this function returns -ENOENT. + /** + * @brief Get the value of a driver specific attribute. + * + * @note This function SHALL NOT return any values configurable by the + * MAC (L2) layer. It is reserved to non-boolean (i.e. scalar or + * structured) attributes that originate from the driver implementation + * and cannot be directly or indirectly derived by L2. Boolean + * attributes SHALL be implemented as @ref ieee802154_hw_caps. + * + * @retval 0 The requested attribute is supported by the driver and the + * value can be retrieved from the corresponding @ref ieee802154_attr_value + * member. + * + * @retval -ENOENT The driver does not provide the requested attribute. + * The value structure has does not been updated with attribute data. */ int (*attr_get)(const struct device *dev, enum ieee802154_attr attr, @@ -515,11 +806,10 @@ BUILD_ASSERT(offsetof(struct ieee802154_radio_api, iface_api) == 0); * @brief Check if AR flag is set on the frame inside given net_pkt * * @param frag A valid pointer on a net_buf structure, must not be NULL, - * and its length should be at least made of 1 byte (ACK frames - * are the smallest frames on 15.4 and made of 3 bytes, not - * not counting the FCS part). + * and its length should be at least 1 byte (ImmAck frames are the + * shortest supported frames with 3 bytes excluding FCS). * - * @return True if AR flag is set, False otherwise + * @return true if AR flag is set, false otherwise */ static inline bool ieee802154_is_ar_flag_set(struct net_buf *frag) { diff --git a/subsys/net/ip/Kconfig b/subsys/net/ip/Kconfig index 3b9947eb50b0..ea592a9a26ef 100644 --- a/subsys/net/ip/Kconfig +++ b/subsys/net/ip/Kconfig @@ -840,7 +840,8 @@ config NET_PKT_TIMESTAMP help Enable network packet timestamp support. This is needed for example in gPTP which needs to know how long it takes to send - a network packet. + a network packet or for timed radio protocols like IEEE 802.15.4 + CSL and TSCH. config NET_PKT_TIMESTAMP_THREAD bool "Create TX timestamp thread" From 29988b5c04e2942144710adf1f0ae073462327d2 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 13 Jul 2023 00:15:45 +0200 Subject: [PATCH 1917/2042] drivers: ieee802154: nRF5: fix return type Adapts a return type to the API specification. The changed return type is not referenced anywhere so it can be changed without breaking backwards compatibility. Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_nrf5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index d85ae2e71a88..573bbb7f84ac 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -291,7 +291,7 @@ static int nrf5_energy_scan_start(const struct device *dev, if (nrf_802154_energy_detection(duration * 1000) == false) { nrf5_data.energy_scan_done = NULL; - err = -EPERM; + err = -EBUSY; } } else { err = -EALREADY; From 8737550f48ebafee7b517b2a555f450a485b7962 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 12 Jul 2023 23:23:51 +0200 Subject: [PATCH 1918/2042] tests: subsys: openthread: simplify configure mocks Removes redundant fakes. Signed-off-by: Florian Grandel --- tests/subsys/openthread/radio_test.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index c7837016927d..d0010be4a618 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -52,8 +52,6 @@ FAKE_VALUE_FUNC(int, start_mock, const struct device *); FAKE_VALUE_FUNC(int, stop_mock, const struct device *); FAKE_VALUE_FUNC(int, configure_mock, const struct device *, enum ieee802154_config_type, const struct ieee802154_config *); -FAKE_VALUE_FUNC(int, configure_promiscuous_mock, const struct device *, enum ieee802154_config_type, - const struct ieee802154_config *); FAKE_VALUE_FUNC(enum ieee802154_hw_caps, get_capabilities_caps_mock, const struct device *); static enum ieee802154_hw_caps get_capabilities(const struct device *dev); @@ -128,9 +126,6 @@ static enum ieee802154_hw_caps get_capabilities(const struct device *dev) IEEE802154_HW_FILTER | IEEE802154_HW_ENERGY_SCAN | IEEE802154_HW_SLEEP_TO_TX; } -FAKE_VALUE_FUNC(int, configure_match_mock, const struct device *, enum ieee802154_config_type, - const struct ieee802154_config *); - FAKE_VALUE_FUNC(otError, otIp6Send, otInstance *, otMessage *); otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings) @@ -432,9 +427,8 @@ static void set_expected_match_values(enum ieee802154_config_type type, uint8_t ZTEST(openthread_radio, test_source_match_test) { otExtAddress ext_addr; - configure_match_mock_fake.custom_fake = custom_configure_match_mock; + configure_mock_fake.custom_fake = custom_configure_match_mock; - rapi.configure = configure_match_mock; /* Enable/Disable */ set_expected_match_values(IEEE802154_CONFIG_AUTO_ACK_FPB, NULL, false, true); otPlatRadioEnableSrcMatch(ot, true); @@ -473,8 +467,6 @@ ZTEST(openthread_radio, test_source_match_test) set_expected_match_values(IEEE802154_CONFIG_ACK_FPB, NULL, true, false); otPlatRadioClearSrcMatchExtEntries(ot); - - rapi.configure = configure_mock; } static bool custom_configure_promiscuous_mock_promiscuous; @@ -495,27 +487,22 @@ static int custom_configure_promiscuous_mock(const struct device *dev, */ ZTEST(openthread_radio, test_promiscuous_mode_set_test) { - rapi.configure = configure_promiscuous_mock; - zassert_false(otPlatRadioGetPromiscuous(ot), "By default promiscuous mode shall be disabled."); - configure_promiscuous_mock_fake.custom_fake = custom_configure_promiscuous_mock; + configure_mock_fake.custom_fake = custom_configure_promiscuous_mock; otPlatRadioSetPromiscuous(ot, true); zassert_true(otPlatRadioGetPromiscuous(ot), "Mode not enabled."); - zassert_equal(1, configure_promiscuous_mock_fake.call_count); + zassert_equal(1, configure_mock_fake.call_count); zassert_true(custom_configure_promiscuous_mock_promiscuous); - RESET_FAKE(configure_promiscuous_mock); - FFF_RESET_HISTORY(); + RESET_FAKE(configure_mock); - configure_promiscuous_mock_fake.custom_fake = custom_configure_promiscuous_mock; + configure_mock_fake.custom_fake = custom_configure_promiscuous_mock; otPlatRadioSetPromiscuous(ot, false); zassert_false(otPlatRadioGetPromiscuous(ot), "Mode still enabled."); - zassert_equal(1, configure_promiscuous_mock_fake.call_count); + zassert_equal(1, configure_mock_fake.call_count); zassert_false(custom_configure_promiscuous_mock_promiscuous); - - rapi.configure = configure_mock; } /** @@ -900,7 +887,6 @@ static void openthread_radio_before(void *f) RESET_FAKE(start_mock); RESET_FAKE(stop_mock); RESET_FAKE(configure_mock); - RESET_FAKE(configure_promiscuous_mock); RESET_FAKE(get_capabilities_caps_mock); RESET_FAKE(otPlatRadioEnergyScanDone); RESET_FAKE(otPlatRadioTxDone); From 7232dd260ee827ab25d6e6e50f21b2e35c5594e8 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 12 Jul 2023 12:06:28 +0200 Subject: [PATCH 1919/2042] tests: subsys: openthread: support TXTIME Adds a test suite configuration that enables TXTIME. Signed-off-by: Florian Grandel --- tests/subsys/openthread/radio_test.c | 50 +++++++++++++++++++++------ tests/subsys/openthread/testcase.yaml | 18 ++++++---- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index d0010be4a618..5487fea4da01 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -120,10 +120,16 @@ FAKE_VOID_FUNC(otPlatRadioTxDone, otInstance *, otRadioFrame *, otRadioFrame *, static enum ieee802154_hw_caps get_capabilities(const struct device *dev) { + enum ieee802154_hw_caps caps; + zassert_equal(dev, radio, "Device handle incorrect."); - return IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_TX_RX_ACK | + caps = IEEE802154_HW_FCS | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_FILTER | IEEE802154_HW_ENERGY_SCAN | IEEE802154_HW_SLEEP_TO_TX; + if (IS_ENABLED(CONFIG_NET_PKT_TXTIME)) { + caps |= IEEE802154_HW_TXTIME; + } + return caps; } FAKE_VALUE_FUNC(otError, otIp6Send, otInstance *, otMessage *); @@ -255,6 +261,7 @@ ZTEST(openthread_radio, test_tx_test) const uint8_t chan = 20; uint8_t chan2 = chan - 1; const int8_t power = -3; + uint64_t expected_target_time = 0; otRadioFrame *frm = otPlatRadioGetTransmitBuffer(ot); @@ -276,12 +283,21 @@ ZTEST(openthread_radio, test_tx_test) RESET_FAKE(start_mock); FFF_RESET_HISTORY(); + if (IS_ENABLED(CONFIG_NET_PKT_TXTIME)) { + frm->mInfo.mTxInfo.mTxDelayBaseTime = 3U; + frm->mInfo.mTxInfo.mTxDelay = 5U; + expected_target_time = + (frm->mInfo.mTxInfo.mTxDelayBaseTime + frm->mInfo.mTxInfo.mTxDelay) * + NSEC_PER_USEC; + } + /* ACKed frame */ frm->mChannel = chan2; frm->mInfo.mTxInfo.mCsmaCaEnabled = true; frm->mPsdu[0] = IEEE802154_AR_FLAG_SET; set_channel_mock_fake.return_val = 0; zassert_equal(otPlatRadioTransmit(ot, frm), OT_ERROR_NONE, "Transmit failed."); + k_yield(); create_ack_frame(); make_sure_sem_set(Z_TIMEOUT_MS(100)); @@ -289,12 +305,20 @@ ZTEST(openthread_radio, test_tx_test) platformRadioProcess(ot); zassert_equal(1, set_channel_mock_fake.call_count); zassert_equal(chan2, set_channel_mock_fake.arg1_val); - zassert_equal(1, cca_mock_fake.call_count); - zassert_equal_ptr(radio, cca_mock_fake.arg0_val, NULL); + if (IS_ENABLED(CONFIG_NET_PKT_TXTIME)) { + zassert_equal(0, cca_mock_fake.call_count); + } else { + zassert_equal(1, cca_mock_fake.call_count); + zassert_equal_ptr(radio, cca_mock_fake.arg0_val, NULL); + } zassert_equal(1, set_txpower_mock_fake.call_count); zassert_equal(power, set_txpower_mock_fake.arg1_val); zassert_equal(1, tx_mock_fake.call_count); zassert_equal_ptr(frm->mPsdu, tx_mock_fake.arg3_val->data, NULL); + zassert_equal(expected_target_time, net_pkt_txtime(tx_mock_fake.arg2_val)); + zassert_equal(IS_ENABLED(CONFIG_NET_PKT_TXTIME) ? IEEE802154_TX_MODE_TXTIME_CCA + : IEEE802154_TX_MODE_DIRECT, + tx_mock_fake.arg1_val); zassert_equal(1, otPlatRadioTxDone_fake.call_count); zassert_equal_ptr(ot, otPlatRadioTxDone_fake.arg0_val, NULL); zassert_equal(OT_ERROR_NONE, otPlatRadioTxDone_fake.arg3_val); @@ -532,10 +556,6 @@ ZTEST(openthread_radio, test_get_caps_test) "Incorrect capabilities returned."); /* not implemented or not fully supported */ - get_capabilities_caps_mock_fake.return_val = IEEE802154_HW_TXTIME; - zassert_equal(otPlatRadioGetCaps(ot), OT_RADIO_CAPS_NONE, - "Incorrect capabilities returned."); - get_capabilities_caps_mock_fake.return_val = IEEE802154_HW_PROMISC; zassert_equal(otPlatRadioGetCaps(ot), OT_RADIO_CAPS_NONE, "Incorrect capabilities returned."); @@ -553,6 +573,12 @@ ZTEST(openthread_radio, test_get_caps_test) zassert_equal(otPlatRadioGetCaps(ot), OT_RADIO_CAPS_ACK_TIMEOUT, "Incorrect capabilities returned."); + get_capabilities_caps_mock_fake.return_val = IEEE802154_HW_TXTIME; + zassert_equal(otPlatRadioGetCaps(ot), + IS_ENABLED(CONFIG_NET_PKT_TXTIME) ? OT_RADIO_CAPS_TRANSMIT_TIMING + : OT_RADIO_CAPS_NONE, + "Incorrect capabilities returned."); + get_capabilities_caps_mock_fake.return_val = IEEE802154_HW_SLEEP_TO_TX; zassert_equal(otPlatRadioGetCaps(ot), OT_RADIO_CAPS_SLEEP_TO_TX, "Incorrect capabilities returned."); @@ -563,10 +589,12 @@ ZTEST(openthread_radio, test_get_caps_test) IEEE802154_HW_CSMA | IEEE802154_HW_2_4_GHZ | IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_SUB_GHZ | IEEE802154_HW_ENERGY_SCAN | IEEE802154_HW_TXTIME | IEEE802154_HW_SLEEP_TO_TX; - zassert_equal(otPlatRadioGetCaps(ot), - OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_ENERGY_SCAN | - OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_SLEEP_TO_TX, - "Incorrect capabilities returned."); + zassert_equal( + otPlatRadioGetCaps(ot), + OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_ACK_TIMEOUT | + OT_RADIO_CAPS_SLEEP_TO_TX | + (IS_ENABLED(CONFIG_NET_PKT_TXTIME) ? OT_RADIO_CAPS_TRANSMIT_TIMING : 0), + "Incorrect capabilities returned."); rapi.get_capabilities = get_capabilities; } diff --git a/tests/subsys/openthread/testcase.yaml b/tests/subsys/openthread/testcase.yaml index fb860a4798f0..56da6bc65cc5 100644 --- a/tests/subsys/openthread/testcase.yaml +++ b/tests/subsys/openthread/testcase.yaml @@ -1,8 +1,12 @@ +common: + platform_allow: + - native_posix + - native_posix_64 + integration_platforms: + - native_posix + tags: ot_radio tests: - openthread.radio: - platform_allow: - - native_posix - - native_posix_64 - integration_platforms: - - native_posix - tags: ot_radio + tests.subsys.openthread.radio_test.min: {} + tests.subsys.openthread.radio_test.timed_tx: + extra_configs: + - CONFIG_NET_PKT_TXTIME=y From 2668a7d83f814463044a46c3ce8b07cfed474729 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Wed, 12 Jul 2023 23:52:49 +0200 Subject: [PATCH 1920/2042] tests: subsys: openthread: support CSL Introduces coverage for OpenThread CSL platform API as far as channel samples are concerned. Signed-off-by: Florian Grandel --- tests/subsys/openthread/radio_test.c | 55 +++++++++++++++++++++++++++ tests/subsys/openthread/testcase.yaml | 4 ++ 2 files changed, 59 insertions(+) diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index 5487fea4da01..b86057be8289 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -897,6 +897,61 @@ ZTEST(openthread_radio, test_net_pkt_transmit) zassert_equal_ptr(ip_msg, otIp6Send_fake.arg1_val, NULL); } +#ifdef CONFIG_OPENTHREAD_CSL_RECEIVER +static int64_t custom_configure_csl_rx_time_mock_csl_rx_time; +static int custom_configure_csl_rx_time(const struct device *dev, + enum ieee802154_config_type type, + const struct ieee802154_config *config) +{ + zassert_equal(dev, radio, "Device handle incorrect."); + zassert_equal(type, IEEE802154_CONFIG_CSL_RX_TIME, "Config type incorrect."); + custom_configure_csl_rx_time_mock_csl_rx_time = config->csl_rx_time; + + return 0; +} + +ZTEST(openthread_radio, test_csl_receiver_sample_time) +{ + uint32_t sample_time = 50U; + + configure_mock_fake.custom_fake = custom_configure_csl_rx_time; + otPlatRadioUpdateCslSampleTime(NULL, sample_time); + zassert_equal(1, configure_mock_fake.call_count); + zassert_equal(sample_time, custom_configure_csl_rx_time_mock_csl_rx_time); +} + + +static struct ieee802154_config custom_configure_rx_slot_mock_config; +static int custom_configure_csl_rx_slot(const struct device *dev, + enum ieee802154_config_type type, + const struct ieee802154_config *config) +{ + zassert_equal(dev, radio, "Device handle incorrect."); + zassert_equal(type, IEEE802154_CONFIG_RX_SLOT, "Config type incorrect."); + custom_configure_rx_slot_mock_config.rx_slot.channel = config->rx_slot.channel; + custom_configure_rx_slot_mock_config.rx_slot.start = config->rx_slot.start; + custom_configure_rx_slot_mock_config.rx_slot.duration = config->rx_slot.duration; + + return 0; +} + +ZTEST(openthread_radio, test_csl_receiver_receive_at) +{ + uint8_t channel = 11U; + uint32_t start = 1000U; + uint32_t duration = 100U; + int res; + + configure_mock_fake.custom_fake = custom_configure_csl_rx_slot; + res = otPlatRadioReceiveAt(NULL, channel, start, duration); + zassert_ok(res); + zassert_equal(1, configure_mock_fake.call_count); + zassert_equal(channel, custom_configure_rx_slot_mock_config.rx_slot.channel); + zassert_equal(start, custom_configure_rx_slot_mock_config.rx_slot.start); + zassert_equal(duration, custom_configure_rx_slot_mock_config.rx_slot.duration); +} +#endif + static void *openthread_radio_setup(void) { platformRadioInit(); diff --git a/tests/subsys/openthread/testcase.yaml b/tests/subsys/openthread/testcase.yaml index 56da6bc65cc5..a442535a2783 100644 --- a/tests/subsys/openthread/testcase.yaml +++ b/tests/subsys/openthread/testcase.yaml @@ -10,3 +10,7 @@ tests: tests.subsys.openthread.radio_test.timed_tx: extra_configs: - CONFIG_NET_PKT_TXTIME=y + tests.subsys.openthread.radio_test.csl: + # Hack to enable CSL w/o having to enable CONFIG_OPENTHREAD + extra_args: + - EXTRA_CPPFLAGS=-DCONFIG_OPENTHREAD_CSL_RECEIVER From a4cd5cee40fa3ceb991cf942a7a3ac8cce8b125c Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Tue, 11 Jul 2023 17:54:00 +0200 Subject: [PATCH 1921/2042] drivers: ieee802154: consistent high res timestamps The IEEE 802.15.4 API and networking subsystem were using several inconsistent timestamp resolutions and types. This change defines all timestamps with nanosecond resolution and reduces the number of available types to represent timestamps to two: * `struct net_ptp_time` for PTP timestamps * `net_time_t` for all other high resolution timestamps All timestamps (including PTP timestamps) are now referred to a "virtual" local network subsystem clock source based on the well-defined types above. It is the responsibility of network subsystem L2/driver implementations (notably Ethernet and IEEE 802.15.4 L2 stacks) to ensure consistency of all timestamps and radio timer values exposed by the driver API to such a network subsystem uptime reference clock independent of internal implementation details. The "virtual" network clock source may be implemented based on arbitrary hardware peripherals (e.g. a coarse low power RTC counter during sleep time plus a high resolution/high precision radio timer while receiving or sending). Such implementation details must be hidden from API clients, as if the driver used a single high resolution clock source instead. For IEEE 802.15.4, whenever timestamps refer to packet send or receive times, they are measured when the end of the IEEE 802.15.4 SFD (message timestamp point) is present at the local antenna (reference plane). Due to its limited range of ~290 years, net_time_t timestamps (and therefore net_pkt timestamps and times) must not be used to represent absolute points in time referred to an external epoch independent of system uptime (e.g. UTC, TAI, PTP, NTP, ...). Signed-off-by: Florian Grandel --- drivers/ieee802154/ieee802154_nrf5.c | 33 ++++++++-------- include/zephyr/net/ieee802154_radio.h | 31 ++++++++------- include/zephyr/net/net_pkt.h | 55 +++++++++++++++++---------- include/zephyr/net/ptp_time.h | 45 ++++++++++++++++++++++ modules/openthread/platform/radio.c | 13 ++++--- samples/net/sockets/txtime/src/main.c | 13 +++---- subsys/net/ip/net_context.c | 5 ++- tests/net/socket/udp/src/main.c | 10 ++--- tests/subsys/openthread/radio_test.c | 12 +++--- 9 files changed, 143 insertions(+), 74 deletions(-) diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 573bbb7f84ac..7403583026ab 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -486,8 +486,11 @@ static bool nrf5_tx_csma_ca(struct net_pkt *pkt, uint8_t *payload) #if defined(CONFIG_NET_PKT_TXTIME) /** * @brief Convert 32-bit target time to absolute 64-bit target time. + * + * @param target_time_ns_wrapped time in nanoseconds referred to the radio clock + * modulo (UINT32_MAX * NSEC_PER_USEC). */ -static uint64_t target_time_convert_to_64_bits(uint32_t target_time) +static uint64_t target_time_convert_to_64_bits(uint64_t target_time_ns_wrapped) { /** * Target time is provided as two 32-bit integers defining a moment in time @@ -501,9 +504,10 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) * time. Let's assume that half of the 32-bit range can be used for specifying * target times in the future, and the other half - in the past. */ + uint32_t target_time_us_wrapped = target_time_ns_wrapped / NSEC_PER_USEC; uint64_t now_us = nrf_802154_time_get(); uint32_t now_us_wrapped = (uint32_t)now_us; - uint32_t time_diff = target_time - now_us_wrapped; + uint32_t time_diff = target_time_us_wrapped - now_us_wrapped; uint64_t result = UINT64_C(0); if (time_diff < 0x80000000) { @@ -511,32 +515,32 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) * Target time is assumed to be in the future. Check if a 32-bit overflow * occurs between the current time and the target time. */ - if (now_us_wrapped > target_time) { + if (now_us_wrapped > target_time_us_wrapped) { /** * Add a 32-bit overflow and replace the least significant 32 bits * with the provided target time. */ result = now_us + UINT32_MAX + 1; result &= ~(uint64_t)UINT32_MAX; - result |= target_time; + result |= target_time_us_wrapped; } else { /** * Leave the most significant 32 bits and replace the least significant * 32 bits with the provided target time. */ - result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; + result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time_us_wrapped; } } else { /** * Target time is assumed to be in the past. Check if a 32-bit overflow * occurs between the target time and the current time. */ - if (now_us_wrapped > target_time) { + if (now_us_wrapped > target_time_us_wrapped) { /** * Leave the most significant 32 bits and replace the least significant * 32 bits with the provided target time. */ - result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time; + result = (now_us & (~(uint64_t)UINT32_MAX)) | target_time_us_wrapped; } else { /** * Subtract a 32-bit overflow and replace the least significant @@ -544,7 +548,7 @@ static uint64_t target_time_convert_to_64_bits(uint32_t target_time) */ result = now_us - UINT32_MAX - 1; result &= ~(uint64_t)UINT32_MAX; - result |= target_time; + result |= target_time_us_wrapped; } } @@ -594,7 +598,7 @@ static bool nrf5_tx_at(struct nrf5_802154_data *nrf5_radio, struct net_pkt *pkt, .extra_cca_attempts = max_extra_cca_attempts, #endif }; - uint64_t tx_at = target_time_convert_to_64_bits(net_pkt_txtime(pkt) / NSEC_PER_USEC); + uint64_t tx_at = target_time_convert_to_64_bits(net_ptp_time_to_ns(net_pkt_timestamp(pkt))); return nrf_802154_transmit_raw_at(payload, tx_at, &metadata); } @@ -703,11 +707,11 @@ static int nrf5_tx(const struct device *dev, } } -static uint64_t nrf5_get_time(const struct device *dev) +static net_time_t nrf5_get_time(const struct device *dev) { ARG_UNUSED(dev); - return nrf_802154_time_get(); + return (net_time_t)nrf_802154_time_get() * NSEC_PER_USEC; } static uint8_t nrf5_get_acc(const struct device *dev) @@ -998,13 +1002,12 @@ static int nrf5_configure(const struct device *dev, * anchor_time will be used for calculations. * * `target_time_convert_to_64_bits()` is a workaround until OpenThread - * (the only CSL user in Zephyr so far) is able to schedule RX windows - * using 64-bit time. + * is able to schedule RX windows using 64-bit time. */ uint64_t start = target_time_convert_to_64_bits(config->rx_slot.start); - nrf_802154_receive_at(start, config->rx_slot.duration, config->rx_slot.channel, - DRX_SLOT_RX); + nrf_802154_receive_at(start, config->rx_slot.duration / NSEC_PER_USEC, + config->rx_slot.channel, DRX_SLOT_RX); } break; case IEEE802154_CONFIG_CSL_PERIOD: diff --git a/include/zephyr/net/ieee802154_radio.h b/include/zephyr/net/ieee802154_radio.h index 5e2d35ca9caf..cc8ac4d20bca 100644 --- a/include/zephyr/net/ieee802154_radio.h +++ b/include/zephyr/net/ieee802154_radio.h @@ -15,9 +15,9 @@ #define ZEPHYR_INCLUDE_NET_IEEE802154_RADIO_H_ #include -#include #include #include +#include #include #include @@ -364,7 +364,7 @@ enum ieee802154_config_type { IEEE802154_CONFIG_CSL_PERIOD, /** Configure the next CSL receive window (i.e. "channel sample") center, - * in units of microseconds relative to the network subsystem's local clock. + * in units of nanoseconds relative to the network subsystem's local clock. */ IEEE802154_CONFIG_CSL_RX_TIME, @@ -425,24 +425,24 @@ struct ieee802154_config { /** ``IEEE802154_CONFIG_RX_SLOT`` */ struct { - uint8_t channel; - /** - * Microsecond resolution timestamp relative to the + * Nanosecond resolution timestamp relative to the * network subsystem's local clock defining the start of * the RX window during which the receiver is expected * to be listening (i.e. not including any startup * times). */ - uint32_t start; + net_time_t start; /** - * Microsecond resolution duration of the RX window + * Nanosecond resolution duration of the RX window * relative to the above RX window start time during * which the receiver is expected to be listening (i.e. * not including any shutdown times). */ - uint32_t duration; + net_time_t duration; + + uint8_t channel; } rx_slot; /** @@ -458,12 +458,12 @@ struct ieee802154_config { /** * ``IEEE802154_CONFIG_CSL_RX_TIME`` * - * Microsecond resolution timestamp relative to the network + * Nanosecond resolution timestamp relative to the network * subsystem's local clock defining the center of the CSL RX window * at which the receiver is expected to be fully started up * (i.e. not including any startup times). */ - uint32_t csl_rx_time; + net_time_t csl_rx_time; /** ``IEEE802154_CONFIG_ENH_ACK_HEADER_IE`` */ struct { @@ -742,17 +742,20 @@ struct ieee802154_radio_api { energy_scan_done_cb_t done_cb); /** - * @brief Get the current time in microseconds relative to the network - * subsystem's local clock. + * @brief Get the current time in nanoseconds relative to the network + * subsystem's local uptime clock as represented by this network + * interface. + * + * See @ref net_time_t for semantic details. * * @note requires IEEE802154_HW_TXTIME and/or IEEE802154_HW_RXTIME * capabilities. * * @param dev pointer to radio device * - * @return microseconds relative to the network subsystem's local clock + * @return nanoseconds relative to the network subsystem's local clock */ - uint64_t (*get_time)(const struct device *dev); + net_time_t (*get_time)(const struct device *dev); /** * @brief Get the current estimated worst case accuracy (maximum ± diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index d540a91d9ffa..fbc2d2773d1d 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -94,10 +95,24 @@ struct net_pkt { struct net_if *orig_iface; /* Original network interface */ #endif -#if defined(CONFIG_NET_PKT_TIMESTAMP) +#if defined(CONFIG_NET_PKT_TIMESTAMP) || defined(CONFIG_NET_PKT_TXTIME) /** - * Timestamp if available. - * For IEEE 802.15.4 packets this refers to the first symbol of the MAC Header. + * TX or RX timestamp if available + * + * For packets that have been sent over the medium, the timestamp refers + * to the time the message timestamp point was encountered at the + * reference plane. + * + * Unsent packages can be scheduled by setting the timestamp to a future + * point in time. + * + * All timestamps refer to the network subsystem's local clock. + * + * See @ref net_ptp_time for definitions of local clock, message + * timestamp point and reference plane. See @ref net_time_t for + * semantics of the network reference clock. + * + * TODO: Replace with net_time_t to decouple from PTP. */ struct net_ptp_time timestamp; #endif @@ -123,11 +138,6 @@ struct net_pkt { }; #endif /* CONFIG_NET_PKT_RXTIME_STATS || CONFIG_NET_PKT_TXTIME_STATS */ -#if defined(CONFIG_NET_PKT_TXTIME) - /** Network packet TX time in the future (in nanoseconds) */ - uint64_t txtime; -#endif /* CONFIG_NET_PKT_TXTIME */ - /** Reference counter */ atomic_t atomic_ref; @@ -943,7 +953,7 @@ static inline void net_pkt_set_vlan_tci(struct net_pkt *pkt, uint16_t tci) } #endif -#if defined(CONFIG_NET_PKT_TIMESTAMP) +#if defined(CONFIG_NET_PKT_TIMESTAMP) || defined(CONFIG_NET_PKT_TXTIME) static inline struct net_ptp_time *net_pkt_timestamp(struct net_pkt *pkt) { return &pkt->timestamp; @@ -969,7 +979,7 @@ static inline void net_pkt_set_timestamp(struct net_pkt *pkt, ARG_UNUSED(pkt); ARG_UNUSED(timestamp); } -#endif /* CONFIG_NET_PKT_TIMESTAMP */ +#endif /* CONFIG_NET_PKT_TIMESTAMP || CONFIG_NET_PKT_TXTIME */ #if defined(CONFIG_NET_PKT_RXTIME_STATS) || defined(CONFIG_NET_PKT_TXTIME_STATS) static inline uint32_t net_pkt_create_time(struct net_pkt *pkt) @@ -998,30 +1008,33 @@ static inline void net_pkt_set_create_time(struct net_pkt *pkt, } #endif /* CONFIG_NET_PKT_RXTIME_STATS || CONFIG_NET_PKT_TXTIME_STATS */ -#if defined(CONFIG_NET_PKT_TXTIME) +/** + * @deprecated Use @ref net_pkt_timestamp instead. + */ static inline uint64_t net_pkt_txtime(struct net_pkt *pkt) { - return pkt->txtime; -} - -static inline void net_pkt_set_txtime(struct net_pkt *pkt, uint64_t txtime) -{ - pkt->txtime = txtime; -} +#if defined(CONFIG_NET_PKT_TXTIME) + return pkt->timestamp.second * NSEC_PER_SEC + pkt->timestamp.nanosecond; #else -static inline uint64_t net_pkt_txtime(struct net_pkt *pkt) -{ ARG_UNUSED(pkt); return 0; +#endif /* CONFIG_NET_PKT_TXTIME */ } +/** + * @deprecated Use @ref net_pkt_set_timestamp instead. + */ static inline void net_pkt_set_txtime(struct net_pkt *pkt, uint64_t txtime) { +#if defined(CONFIG_NET_PKT_TXTIME) + pkt->timestamp.second = txtime / NSEC_PER_SEC; + pkt->timestamp.nanosecond = txtime % NSEC_PER_SEC; +#else ARG_UNUSED(pkt); ARG_UNUSED(txtime); -} #endif /* CONFIG_NET_PKT_TXTIME */ +} #if defined(CONFIG_NET_PKT_TXTIME_STATS_DETAIL) || \ defined(CONFIG_NET_PKT_RXTIME_STATS_DETAIL) diff --git a/include/zephyr/net/ptp_time.h b/include/zephyr/net/ptp_time.h index c85d9b69dd39..99c5037e7ba0 100644 --- a/include/zephyr/net/ptp_time.h +++ b/include/zephyr/net/ptp_time.h @@ -23,6 +23,7 @@ */ #include +#include #include #ifdef __cplusplus @@ -177,6 +178,50 @@ struct net_ptp_extended_time { }; } __packed; +/** + * @brief Convert a PTP timestamp to a nanosecond precision timestamp, both + * related to the local network reference clock. + * + * @note Only timestamps representing up to ~290 years can be converted to + * nanosecond timestamps. Larger timestamps will return the maximum + * representable nanosecond precision timestamp. + * + * @param ts the PTP timestamp + * + * @return the corresponding nanosecond precision timestamp + */ +static inline net_time_t net_ptp_time_to_ns(struct net_ptp_time *ts) +{ + if (!ts) { + return 0; + } + + if (ts->second >= NET_TIME_SEC_MAX) { + return NET_TIME_MAX; + } + + return ((int64_t)ts->second * NSEC_PER_SEC) + ts->nanosecond; +} + +/** + * @brief Convert a nanosecond precision timestamp to a PTP timestamp, both + * related to the local network reference clock. + * + * @param nsec a nanosecond precision timestamp + * + * @return the corresponding PTP timestamp + */ +static inline struct net_ptp_time ns_to_net_ptp_time(net_time_t nsec) +{ + struct net_ptp_time ts; + + __ASSERT_NO_MSG(nsec >= 0); + + ts.second = nsec / NSEC_PER_SEC; + ts.nanosecond = nsec % NSEC_PER_SEC; + return ts; +} + /** * @} */ diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 16a282ff93f6..60bf5f503958 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); #include #include #include +#include #include #include @@ -316,7 +317,9 @@ void transmit_message(struct k_work *tx_job) (sTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)) { uint64_t tx_at = sTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime + sTransmitFrame.mInfo.mTxInfo.mTxDelay; - net_pkt_set_txtime(tx_pkt, NSEC_PER_USEC * tx_at); + struct net_ptp_time timestamp = ns_to_net_ptp_time(tx_at * NSEC_PER_USEC); + + net_pkt_set_timestamp(tx_pkt, ×tamp); tx_err = radio_api->tx(radio_dev, IEEE802154_TX_MODE_TXTIME_CCA, tx_pkt, tx_payload); } else if (sTransmitFrame.mInfo.mTxInfo.mCsmaCaEnabled) { @@ -663,8 +666,8 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, struct ieee802154_config config = { .rx_slot.channel = aChannel, - .rx_slot.start = aStart, - .rx_slot.duration = aDuration, + .rx_slot.start = (net_time_t)aStart * NSEC_PER_USEC, + .rx_slot.duration = (net_time_t)aDuration * NSEC_PER_USEC, }; result = radio_api->configure(radio_dev, IEEE802154_CONFIG_RX_SLOT, @@ -1051,7 +1054,7 @@ uint64_t otPlatTimeGet(void) if (radio_api == NULL || radio_api->get_time == NULL) { return k_ticks_to_us_floor64(k_uptime_ticks()); } else { - return radio_api->get_time(radio_dev); + return radio_api->get_time(radio_dev) / NSEC_PER_USEC; } } @@ -1192,7 +1195,7 @@ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTi { ARG_UNUSED(aInstance); - struct ieee802154_config config = { .csl_rx_time = aCslSampleTime }; + struct ieee802154_config config = { .csl_rx_time = aCslSampleTime * NSEC_PER_USEC }; (void)radio_api->configure(radio_dev, IEEE802154_CONFIG_CSL_RX_TIME, &config); } diff --git a/samples/net/sockets/txtime/src/main.c b/samples/net/sockets/txtime/src/main.c index 38ed702797b3..bec25977680a 100644 --- a/samples/net/sockets/txtime/src/main.c +++ b/samples/net/sockets/txtime/src/main.c @@ -153,15 +153,14 @@ static void tx(struct app_data *data) struct cmsghdr hdr; unsigned char buf[CMSG_SPACE(sizeof(uint64_t))]; } cmsgbuf; - uint64_t txtime, delay, interval; + net_time_t txtime, delay, interval; int ret; int print_offset; print_offset = IS_ENABLED(CONFIG_NET_SAMPLE_PACKET_SOCKET) ? sizeof(struct net_eth_hdr) : 0; - interval = CONFIG_NET_SAMPLE_PACKET_INTERVAL * NSEC_PER_USEC * - USEC_PER_MSEC; + interval = CONFIG_NET_SAMPLE_PACKET_INTERVAL * NSEC_PER_MSEC; delay = CONFIG_NET_SAMPLE_PACKET_TXTIME * NSEC_PER_USEC; io_vector[0].iov_base = (void *)txtime_str; @@ -182,14 +181,14 @@ static void tx(struct app_data *data) LOG_DBG("Sending network packets with SO_TXTIME"); ptp_clock_get(data->clk, &time); - txtime = (time.second * NSEC_PER_SEC) + time.nanosecond; + txtime = net_ptp_time_to_ns(&time); snprintk(txtime_str + print_offset, - sizeof(txtime_str) - print_offset, "%"PRIx64, txtime); + sizeof(txtime_str) - print_offset, "%"PRIx64, (uint64_t)txtime); io_vector[0].iov_len = sizeof(txtime_str); while (1) { - *(uint64_t *)CMSG_DATA(cmsg) = txtime + delay; + *(net_time_t *)CMSG_DATA(cmsg) = txtime + delay; ret = sendmsg(data->sock, &msg, 0); if (ret < 0) { @@ -202,7 +201,7 @@ static void tx(struct app_data *data) txtime += interval; snprintk(txtime_str + print_offset, - sizeof(txtime_str) - print_offset, "%"PRIx64, txtime); + sizeof(txtime_str) - print_offset, "%"PRIx64, (uint64_t)txtime); k_sleep(K_NSEC(interval)); } diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index a32a673de4ac..c7755c52ddd1 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -1459,9 +1459,10 @@ static void set_pkt_txtime(struct net_pkt *pkt, const struct msghdr *msghdr) if (cmsg->cmsg_len == CMSG_LEN(sizeof(uint64_t)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TXTIME) { - uint64_t txtime = *(uint64_t *)CMSG_DATA(cmsg); + struct net_ptp_time txtime = + ns_to_net_ptp_time(*(net_time_t *)CMSG_DATA(cmsg)); - net_pkt_set_txtime(pkt, txtime); + net_pkt_set_timestamp(pkt, &txtime); break; } } diff --git a/tests/net/socket/udp/src/main.c b/tests/net/socket/udp/src/main.c index da13de8ee099..f1affe585274 100644 --- a/tests/net/socket/udp/src/main.c +++ b/tests/net/socket/udp/src/main.c @@ -939,7 +939,7 @@ static struct net_linkaddr server_link_addr = { }; #define MY_IPV6_ADDR_ETH "2001:db8:100::1" #define PEER_IPV6_ADDR_ETH "2001:db8:100::2" -#define TEST_TXTIME 0xff112233445566ff +#define TEST_TXTIME INT64_MAX #define WAIT_TIME K_MSEC(250) static void eth_fake_iface_init(struct net_if *iface) @@ -958,7 +958,7 @@ static void eth_fake_iface_init(struct net_if *iface) static int eth_fake_send(const struct device *dev, struct net_pkt *pkt) { - uint64_t txtime; + net_time_t txtime; ARG_UNUSED(dev); ARG_UNUSED(pkt); @@ -967,7 +967,7 @@ static int eth_fake_send(const struct device *dev, struct net_pkt *pkt) return 0; } - txtime = net_pkt_txtime(pkt); + txtime = net_ptp_time_to_ns(net_pkt_timestamp(pkt)); if (txtime != TEST_TXTIME) { test_failed = true; } else { @@ -1032,7 +1032,7 @@ ZTEST_USER(net_socket_udp, test_18_v6_sendmsg_with_txtime) int rv; int client_sock; bool optval; - uint64_t txtime; + net_time_t txtime; struct sockaddr_in6 client_addr; struct msghdr msg; struct cmsghdr *cmsg; @@ -1066,7 +1066,7 @@ ZTEST_USER(net_socket_udp, test_18_v6_sendmsg_with_txtime) cmsg->cmsg_len = CMSG_LEN(sizeof(txtime)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_TXTIME; - *(uint64_t *)CMSG_DATA(cmsg) = txtime; + *(net_time_t *)CMSG_DATA(cmsg) = txtime; optval = true; rv = setsockopt(client_sock, SOL_SOCKET, SO_TXTIME, &optval, diff --git a/tests/subsys/openthread/radio_test.c b/tests/subsys/openthread/radio_test.c index b86057be8289..d9aec8473274 100644 --- a/tests/subsys/openthread/radio_test.c +++ b/tests/subsys/openthread/radio_test.c @@ -261,7 +261,7 @@ ZTEST(openthread_radio, test_tx_test) const uint8_t chan = 20; uint8_t chan2 = chan - 1; const int8_t power = -3; - uint64_t expected_target_time = 0; + net_time_t expected_target_time = 0; otRadioFrame *frm = otPlatRadioGetTransmitBuffer(ot); @@ -315,7 +315,8 @@ ZTEST(openthread_radio, test_tx_test) zassert_equal(power, set_txpower_mock_fake.arg1_val); zassert_equal(1, tx_mock_fake.call_count); zassert_equal_ptr(frm->mPsdu, tx_mock_fake.arg3_val->data, NULL); - zassert_equal(expected_target_time, net_pkt_txtime(tx_mock_fake.arg2_val)); + zassert_equal(expected_target_time, + net_ptp_time_to_ns(net_pkt_timestamp(tx_mock_fake.arg2_val))); zassert_equal(IS_ENABLED(CONFIG_NET_PKT_TXTIME) ? IEEE802154_TX_MODE_TXTIME_CCA : IEEE802154_TX_MODE_DIRECT, tx_mock_fake.arg1_val); @@ -917,7 +918,7 @@ ZTEST(openthread_radio, test_csl_receiver_sample_time) configure_mock_fake.custom_fake = custom_configure_csl_rx_time; otPlatRadioUpdateCslSampleTime(NULL, sample_time); zassert_equal(1, configure_mock_fake.call_count); - zassert_equal(sample_time, custom_configure_csl_rx_time_mock_csl_rx_time); + zassert_equal(sample_time * NSEC_PER_USEC, custom_configure_csl_rx_time_mock_csl_rx_time); } @@ -947,8 +948,9 @@ ZTEST(openthread_radio, test_csl_receiver_receive_at) zassert_ok(res); zassert_equal(1, configure_mock_fake.call_count); zassert_equal(channel, custom_configure_rx_slot_mock_config.rx_slot.channel); - zassert_equal(start, custom_configure_rx_slot_mock_config.rx_slot.start); - zassert_equal(duration, custom_configure_rx_slot_mock_config.rx_slot.duration); + zassert_equal(start * NSEC_PER_USEC, custom_configure_rx_slot_mock_config.rx_slot.start); + zassert_equal(duration * NSEC_PER_USEC, + custom_configure_rx_slot_mock_config.rx_slot.duration); } #endif From 3a0615d048076f5e1d2ca959a4cbae70a42eeac1 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 27 Jul 2023 11:31:41 +0200 Subject: [PATCH 1922/2042] doc: release-notes: document net subsys time consolidation Documents the changes to the internal API in the release notes. Signed-off-by: Florian Grandel --- doc/releases/release-notes-3.5.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index a6bb1beaec3d..ac174f415e21 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -24,6 +24,14 @@ Changes in this release ``16``). Bootloaders that use a part of the SRAM should set this value to an appropriate size. :github:`60371` +* Time and timestamps in the network subsystem, PTP and IEEE 802.15.4 + were more precisely specified and all in-tree call sites updated accordingly. + Fields for timed TX and TX/RX timestamps have been consolidated. See + :c:type:`net_time_t`, :c:struct:`net_ptp_time`, :c:struct:`ieee802154_config`, + :c:struct:`ieee802154_radio_api` and :c:struct:`net_pkt` for extensive + documentation. As this is largely an internal API, existing applications will + most probably continue to work unchanged. + Removed APIs in this release ============================ From f9daa0397cc91ff801ffd5ec5c65b0fc25930208 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Thu, 20 Jul 2023 10:11:54 -0500 Subject: [PATCH 1923/2042] drivers: sdhc: enable pwr-gpios property within SPI SDHC driver Enable SPI SDHC driver to manage card power via pwr-gpios property. Control for this property was previously partially implemented. When this property is present, the SPI SDHC driver will use it to control power to the SD card. Power is toggled during SD init, so this power control can make SD init more reliable as the power toggle will insure the SD card state is reset. Signed-off-by: Daniel DeGrasse --- drivers/sdhc/sdhc_spi.c | 13 ++++++++++++- dts/bindings/sdhc/zephyr,sdhc-spi-slot.yaml | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/sdhc/sdhc_spi.c b/drivers/sdhc/sdhc_spi.c index 8c656175d6b5..422470441430 100644 --- a/drivers/sdhc/sdhc_spi.c +++ b/drivers/sdhc/sdhc_spi.c @@ -738,14 +738,25 @@ static int sdhc_spi_init(const struct device *dev) { const struct sdhc_spi_config *cfg = dev->config; struct sdhc_spi_data *data = dev->data; + int ret = 0; if (!device_is_ready(cfg->spi_dev)) { return -ENODEV; } + if (cfg->pwr_gpio.port) { + if (!gpio_is_ready_dt(&cfg->pwr_gpio)) { + return -ENODEV; + } + ret = gpio_pin_configure_dt(&cfg->pwr_gpio, GPIO_OUTPUT_INACTIVE); + if (ret != 0) { + LOG_ERR("Could not configure power gpio (%d)", ret); + return ret; + } + } data->power_mode = SDHC_POWER_OFF; data->spi_cfg = &data->cfg_a; data->spi_cfg->frequency = 0; - return 0; + return ret; } static struct sdhc_driver_api sdhc_spi_api = { diff --git a/dts/bindings/sdhc/zephyr,sdhc-spi-slot.yaml b/dts/bindings/sdhc/zephyr,sdhc-spi-slot.yaml index 500eb0d90352..fe1d118f31d3 100644 --- a/dts/bindings/sdhc/zephyr,sdhc-spi-slot.yaml +++ b/dts/bindings/sdhc/zephyr,sdhc-spi-slot.yaml @@ -27,4 +27,11 @@ properties: capture will occur on low to high transition and high to low if this option is not set (default). + pwr-gpios: + type: phandle-array + description: | + Power pin + This pin defaults to active high when consumed by the SPI SDHC driver. + It can be used to toggle card power via an external control circuit + bus: sd From 42dcc4e57f5629e04cd0b95398f880e9a72a73ec Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 13:39:25 +1200 Subject: [PATCH 1924/2042] canbus: isotp: Fix ISO-TP padding config usage ISOTP_ENABLE_TX_PADDING makes the device transmit frames with TX padding. ISOTP_REQUIRE_RX_PADDING ensures other devices on the bus use TX padding, by rejecting non-padded RX frames Signed-off-by: Grant Ramsay --- subsys/canbus/isotp/Kconfig | 2 +- subsys/canbus/isotp/isotp.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/subsys/canbus/isotp/Kconfig b/subsys/canbus/isotp/Kconfig index f0aaf8eb69f9..86c61cbc4e29 100644 --- a/subsys/canbus/isotp/Kconfig +++ b/subsys/canbus/isotp/Kconfig @@ -51,7 +51,7 @@ config ISOTP_CR_TIMEOUT config ISOTP_REQUIRE_RX_PADDING bool "Require padding for received messages" help - If enabled, SFs and the last CF must always have a DLC of 8 bytes + If enabled, SFs, FCs and the last CF must always have a DLC of 8 bytes (for classic CAN) and unused bytes must be padded by the sending device. This setting allows to be compliant to AUTOSAR Specification of CAN Transport Layer. diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index 3a6e8c22e43d..dfe43bb9e245 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -137,8 +137,7 @@ static void receive_send_fc(struct isotp_recv_ctx *ctx, uint8_t fs) *data++ = ctx->opts.stmin; payload_len = data - frame.data; -#if defined(CONFIG_ISOTP_REQUIRE_RX_PADDING) || \ - defined(CONFIG_ISOTP_ENABLE_TX_PADDING) +#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING /* AUTOSAR requirement SWS_CanTp_00347 */ memset(&frame.data[payload_len], 0xCC, ISOTP_CAN_DL - payload_len); frame.dlc = ISOTP_CAN_DL; @@ -776,7 +775,7 @@ static void send_process_fc(struct isotp_send_ctx *ctx, return; } -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING /* AUTOSAR requirement SWS_CanTp_00349 */ if (frame->dlc != ISOTP_CAN_DL) { LOG_ERR("FC DL invalid. Ignore"); From e98fa4e590c275857dc40261627e357d66534af6 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 13:43:44 +1200 Subject: [PATCH 1925/2042] canbus: isotp: Enable TX padding by default if RX padding is required It would be strange to enforce padding for other bus participants but not use it yourself. This default suggests the likely proper usage, although it is not a hard dependency Signed-off-by: Grant Ramsay --- subsys/canbus/isotp/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/subsys/canbus/isotp/Kconfig b/subsys/canbus/isotp/Kconfig index 86c61cbc4e29..b533bf6d1e8f 100644 --- a/subsys/canbus/isotp/Kconfig +++ b/subsys/canbus/isotp/Kconfig @@ -60,6 +60,7 @@ config ISOTP_REQUIRE_RX_PADDING config ISOTP_ENABLE_TX_PADDING bool "Padding for transmitted messages" + default y if ISOTP_REQUIRE_RX_PADDING help Add padding bytes 0xCC (as recommended by Bosch) if the PDU payload does not fit exactly into the CAN frame. From e326b72bc022abd876d077363624e7ad0bfac695 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 21 Jul 2023 13:51:12 +1200 Subject: [PATCH 1926/2042] tests: canbus: isotp: conformance: Update test to check padding correctly The tests now properly validate frames under all padding configurations. Part of test_sender_fc_errors was testing a receive FC error, this sub-test is moved to test_receiver_fc_errors Signed-off-by: Grant Ramsay --- .../canbus/isotp/conformance/src/main.c | 103 ++++++++++++------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index b72b2a6d8272..62583842573e 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -15,6 +15,7 @@ #define DATA_SIZE_CF 7 #define DATA_SIZE_SF_EXT 6 #define DATA_SIZE_FF 6 +#define DATA_SIZE_FC 3 #define CAN_DL 8 #define DATA_SEND_LENGTH 272 #define SF_PCI_TYPE 0 @@ -38,13 +39,6 @@ #define STMIN_VAL_2 50 #define STMIN_UPPER_TOLERANCE 5 -#if defined(CONFIG_ISOTP_ENABLE_TX_PADDING) || \ - defined(CONFIG_ISOTP_ENABLE_TX_PADDING) -#define DATA_SIZE_FC CAN_DL -#else -#define DATA_SIZE_FC 3 -#endif - #define BS_TIMEOUT_UPPER_MS 1100 #define BS_TIMEOUT_LOWER_MS 1000 @@ -258,17 +252,12 @@ static void check_frame_series(struct frame_desired *frames, size_t length, zassert_equal(ret, 0, "Timeout waiting for msg nr %d. ret: %d", i, ret); -#if !defined(CONFIG_ISOTP_REQUIRE_RX_PADDING) && \ - !defined(CONFIG_ISOTP_ENABLE_TX_PADDING) zassert_equal(frame.dlc, desired->length, "DLC of frame nr %d differ. Desired: %d, Got: %d", i, desired->length, frame.dlc); -#endif -#if !defined(CONFIG_ISOTP_ENABLE_TX_PADDING) ret = check_data(frame.data, desired->data, desired->length); zassert_equal(ret, 0, "Data differ"); -#endif desired++; } @@ -294,7 +283,7 @@ static int add_rx_msgq(uint32_t id, uint32_t mask) } static void prepare_cf_frames(struct frame_desired *frames, size_t frames_cnt, - const uint8_t *data, size_t data_len) + const uint8_t *data, size_t data_len, bool tx) { int i; const uint8_t *data_ptr = data; @@ -306,9 +295,13 @@ static void prepare_cf_frames(struct frame_desired *frames, size_t frames_cnt, memcpy(&des_frames[i].data[1], data_ptr, DATA_SIZE_CF); if (remaining_length < DATA_SIZE_CF) { -#ifndef CONFIG_ISOTP_ENABLE_TX_PADDING - frames[i].length = remaining_length + 1; -#endif + if ((IS_ENABLED(CONFIG_ISOTP_ENABLE_TX_PADDING) && tx) || + (IS_ENABLED(CONFIG_ISOTP_REQUIRE_RX_PADDING) && !tx)) { + memset(&des_frames[i].data[remaining_length + 1], 0xCC, + CAN_DL - remaining_length - 1); + } else { + frames[i].length = remaining_length + 1; + } remaining_length = 0; } @@ -497,10 +490,15 @@ ZTEST(isotp_conformance, test_send_data) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(0); fc_frame.data[2] = FC_PCI_BYTE_3(0); +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, - remaining_length); + remaining_length, true); filter_id = add_rx_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", @@ -536,10 +534,15 @@ ZTEST(isotp_conformance, test_send_data_blocks) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); fc_frame.data[2] = FC_PCI_BYTE_3(0); +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, - remaining_length); + remaining_length, true); remaining_length = DATA_SEND_LENGTH; @@ -600,10 +603,15 @@ ZTEST(isotp_conformance, test_receive_data) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts_single.bs); fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts_single.stmin); +#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, - remaining_length); + remaining_length, false); filter_id = add_rx_msgq(tx_addr.std_id, CAN_STD_ID_MASK); @@ -644,10 +652,15 @@ ZTEST(isotp_conformance, test_receive_data_blocks) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); +#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, - remaining_length); + remaining_length, false); remaining_frames = DIV_ROUND_UP(remaining_length, DATA_SIZE_CF); @@ -695,7 +708,12 @@ ZTEST(isotp_conformance, test_send_timeouts) fc_cts_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_cts_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); fc_cts_frame.data[2] = FC_PCI_BYTE_3(0); +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING + memset(&fc_cts_frame.data[3], 0xCC, CAN_DL - 3); + fc_cts_frame.length = CAN_DL; +#else fc_cts_frame.length = DATA_SIZE_FC; +#endif /* Test timeout for first FC*/ start_time = k_uptime_get_32(); @@ -801,7 +819,12 @@ ZTEST(isotp_conformance, test_stmin) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(2); fc_frame.data[2] = FC_PCI_BYTE_3(STMIN_VAL_1); +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif filter_id = add_rx_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", @@ -856,7 +879,12 @@ ZTEST(isotp_conformance, test_receiver_fc_errors) fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); +#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif filter_id = add_rx_msgq(tx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", @@ -871,7 +899,7 @@ ZTEST(isotp_conformance, test_receiver_fc_errors) check_frame_series(&fc_frame, 1, &frame_msgq); prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), random_data + DATA_SIZE_FF, - sizeof(random_data) - DATA_SIZE_FF); + sizeof(random_data) - DATA_SIZE_FF, false); /* SN should be 2 but is set to 3 for this test */ des_frames[1].data[0] = CF_PCI_BYTE_1 | (3 & 0x0F); send_frame_series(des_frames, fc_opts.bs, rx_addr.std_id); @@ -883,6 +911,22 @@ ZTEST(isotp_conformance, test_receiver_fc_errors) zassert_equal(ret, ISOTP_N_WRONG_SN, "Expected wrong SN but got %d", ret); + /* buffer overflow */ + ff_frame.data[0] = FF_PCI_BYTE_1(0xFFF); + ff_frame.data[1] = FF_PCI_BYTE_2(0xFFF); + + fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_OVFLW); + fc_frame.data[1] = FC_PCI_BYTE_2(0); + fc_frame.data[2] = FC_PCI_BYTE_3(0); + + isotp_unbind(&recv_ctx); + ret = isotp_bind(&recv_ctx, can_dev, &rx_addr, &tx_addr, + &fc_opts_single, K_NO_WAIT); + zassert_equal(ret, ISOTP_N_OK, "Binding failed [%d]", ret); + + send_frame_series(&ff_frame, 1, rx_addr.std_id); + check_frame_series(&fc_frame, 1, &frame_msgq); + can_remove_rx_filter(can_dev, filter_id); k_msgq_cleanup(&frame_msgq); isotp_unbind(&recv_ctx); @@ -904,7 +948,12 @@ ZTEST(isotp_conformance, test_sender_fc_errors) fc_frame.data[0] = FC_PCI_BYTE_1(3); fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); +#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING + memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); + fc_frame.length = CAN_DL; +#else fc_frame.length = DATA_SIZE_FC; +#endif k_sem_reset(&send_compl_sem); ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH, @@ -918,18 +967,6 @@ ZTEST(isotp_conformance, test_sender_fc_errors) zassert_equal(ret, 0, "Send complete callback not called"); /* buffer overflow */ - can_remove_rx_filter(can_dev, filter_id); - ret = isotp_bind(&recv_ctx, can_dev, &tx_addr, &rx_addr, - &fc_opts_single, K_NO_WAIT); - zassert_equal(ret, ISOTP_N_OK, "Binding failed [%d]", ret); - - ret = isotp_send(&send_ctx, can_dev, random_data, 5*1024, - &tx_addr, &rx_addr, NULL, NULL); - zassert_equal(ret, ISOTP_N_BUFFER_OVERFLW, - "Expected overflow but got %d", ret); - isotp_unbind(&recv_ctx); - filter_id = add_rx_msgq(tx_addr.std_id, CAN_STD_ID_MASK); - k_sem_reset(&send_compl_sem); ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH, &tx_addr, &rx_addr, send_complete_cb, From b7f88b4301b0a6bb8a2a55fb9651bf5bdb2ff80f Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 28 Jul 2023 09:53:25 +1200 Subject: [PATCH 1927/2042] tests: canbus: isotp: conformance: Add helper function to prepare FC frames This reduces duplication in the tests Signed-off-by: Grant Ramsay --- .../canbus/isotp/conformance/src/main.c | 98 +++++-------------- 1 file changed, 26 insertions(+), 72 deletions(-) diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index 62583842573e..1e4a0bca6a92 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -282,6 +282,21 @@ static int add_rx_msgq(uint32_t id, uint32_t mask) return filter_id; } +static void prepare_fc_frame(struct frame_desired *frame, uint8_t st, + const struct isotp_fc_opts *opts, bool tx) +{ + frame->data[0] = FC_PCI_BYTE_1(st); + frame->data[1] = FC_PCI_BYTE_2(opts->bs); + frame->data[2] = FC_PCI_BYTE_3(opts->stmin); + if ((IS_ENABLED(CONFIG_ISOTP_ENABLE_TX_PADDING) && tx) || + (IS_ENABLED(CONFIG_ISOTP_REQUIRE_RX_PADDING) && !tx)) { + memset(&frame->data[DATA_SIZE_FC], 0xCC, CAN_DL - DATA_SIZE_FC); + frame->length = CAN_DL; + } else { + frame->length = DATA_SIZE_FC; + } +} + static void prepare_cf_frames(struct frame_desired *frames, size_t frames_cnt, const uint8_t *data, size_t data_len, bool tx) { @@ -487,15 +502,7 @@ ZTEST(isotp_conformance, test_send_data) data_ptr += DATA_SIZE_FF; remaining_length -= DATA_SIZE_FF; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(0); - fc_frame.data[2] = FC_PCI_BYTE_3(0); -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts_single, false); prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length, true); @@ -531,15 +538,7 @@ ZTEST(isotp_conformance, test_send_data_blocks) data_ptr += DATA_SIZE_FF; remaining_length -= DATA_SIZE_FF; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); - fc_frame.data[2] = FC_PCI_BYTE_3(0); -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts, false); prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length, true); @@ -600,15 +599,7 @@ ZTEST(isotp_conformance, test_receive_data) data_ptr += DATA_SIZE_FF; remaining_length -= DATA_SIZE_FF; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts_single.bs); - fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts_single.stmin); -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts_single, true); prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length, false); @@ -649,15 +640,7 @@ ZTEST(isotp_conformance, test_receive_data_blocks) data_ptr += DATA_SIZE_FF; remaining_length -= DATA_SIZE_FF; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); - fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts, true); prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length, false); @@ -705,15 +688,7 @@ ZTEST(isotp_conformance, test_send_timeouts) uint32_t start_time, time_diff; struct frame_desired fc_cts_frame; - fc_cts_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_cts_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); - fc_cts_frame.data[2] = FC_PCI_BYTE_3(0); -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - memset(&fc_cts_frame.data[3], 0xCC, CAN_DL - 3); - fc_cts_frame.length = CAN_DL; -#else - fc_cts_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_cts_frame, FC_PCI_CTS, &fc_opts, false); /* Test timeout for first FC*/ start_time = k_uptime_get_32(); @@ -805,6 +780,9 @@ ZTEST(isotp_conformance, test_stmin) struct frame_desired fc_frame, ff_frame; struct can_frame raw_frame; uint32_t start_time, time_diff; + struct isotp_fc_opts fc_opts_stmin = { + .bs = 2, .stmin = STMIN_VAL_1 + }; if (CONFIG_SYS_CLOCK_TICKS_PER_SEC < 1000) { /* This test requires millisecond tick resolution */ @@ -816,15 +794,7 @@ ZTEST(isotp_conformance, test_stmin) memcpy(&ff_frame.data[2], random_data, DATA_SIZE_FF); ff_frame.length = DATA_SIZE_FF + 2; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(2); - fc_frame.data[2] = FC_PCI_BYTE_3(STMIN_VAL_1); -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts_stmin, false); filter_id = add_rx_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", @@ -876,15 +846,7 @@ ZTEST(isotp_conformance, test_receiver_fc_errors) memcpy(&ff_frame.data[2], random_data, DATA_SIZE_FF); ff_frame.length = DATA_SIZE_FF + 2; - fc_frame.data[0] = FC_PCI_BYTE_1(FC_PCI_CTS); - fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); - fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, FC_PCI_CTS, &fc_opts, true); filter_id = add_rx_msgq(tx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", @@ -945,15 +907,7 @@ ZTEST(isotp_conformance, test_sender_fc_errors) filter_id = add_rx_msgq(tx_addr.std_id, CAN_STD_ID_MASK); /* invalid flow status */ - fc_frame.data[0] = FC_PCI_BYTE_1(3); - fc_frame.data[1] = FC_PCI_BYTE_2(fc_opts.bs); - fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - memset(&fc_frame.data[3], 0xCC, CAN_DL - 3); - fc_frame.length = CAN_DL; -#else - fc_frame.length = DATA_SIZE_FC; -#endif + prepare_fc_frame(&fc_frame, 3, &fc_opts, false); k_sem_reset(&send_compl_sem); ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH, From 0b49b86f06825990491199c2a5e15c6af0b91162 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 27 Jul 2023 14:41:06 +0200 Subject: [PATCH 1928/2042] soc: arm: st_stm32: remove redundant PM_STATE_ACTIVE case pm_state_exit_post_ops() will never be called with PM_STATE_ACTIVE. Signed-off-by: Gerard Marull-Paretas --- soc/arm/st_stm32/stm32l4/power.c | 2 -- soc/arm/st_stm32/stm32u5/power.c | 2 -- soc/arm/st_stm32/stm32wba/power.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/soc/arm/st_stm32/stm32l4/power.c b/soc/arm/st_stm32/stm32l4/power.c index 8b1a68fc767e..44fe58e8f49d 100644 --- a/soc/arm/st_stm32/stm32l4/power.c +++ b/soc/arm/st_stm32/stm32l4/power.c @@ -132,8 +132,6 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) case PM_STATE_SOFT_OFF: /* We should not get there */ __fallthrough; - case PM_STATE_ACTIVE: - __fallthrough; case PM_STATE_SUSPEND_TO_RAM: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: diff --git a/soc/arm/st_stm32/stm32u5/power.c b/soc/arm/st_stm32/stm32u5/power.c index 4cd5834cf8be..4d6034a8c47f 100644 --- a/soc/arm/st_stm32/stm32u5/power.c +++ b/soc/arm/st_stm32/stm32u5/power.c @@ -105,8 +105,6 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) case PM_STATE_SOFT_OFF: /* We should not get there */ __fallthrough; - case PM_STATE_ACTIVE: - __fallthrough; case PM_STATE_SUSPEND_TO_RAM: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 83073b7b293c..4d7fd0d04910 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -82,8 +82,6 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) case PM_STATE_SOFT_OFF: /* We should not get there */ __fallthrough; - case PM_STATE_ACTIVE: - __fallthrough; case PM_STATE_SUSPEND_TO_RAM: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: From bc522affc72ba02985a17d9ecab45e590f1dc141 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 27 Jul 2023 14:42:15 +0200 Subject: [PATCH 1929/2042] samples: subsys: pm: latency: remove redundant PM_STATE_ACTIVE case pm_state_set() will never be called with PM_STATE_ACTIVE. Signed-off-by: Gerard Marull-Paretas --- samples/subsys/pm/latency/src/pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/subsys/pm/latency/src/pm.c b/samples/subsys/pm/latency/src/pm.c index d1e7beeba4d9..c7dee14900e0 100644 --- a/samples/subsys/pm/latency/src/pm.c +++ b/samples/subsys/pm/latency/src/pm.c @@ -13,8 +13,6 @@ LOG_MODULE_REGISTER(soc_pm, CONFIG_APP_LOG_LEVEL); static const char *state2str(enum pm_state state) { switch (state) { - case PM_STATE_ACTIVE: - return "ACTIVE"; case PM_STATE_RUNTIME_IDLE: return "RUNTIME_IDLE"; case PM_STATE_SUSPEND_TO_IDLE: From 8081fb3150f48c120e7ad101085187085e41d6f5 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Thu, 27 Jul 2023 14:47:40 +0200 Subject: [PATCH 1930/2042] tests: subsys: pm: pwer_mgmt_multicore: remove PM_STATE_ACTIVE pm_state_set() is never called with PM_STATE_ACTIVE. Signed-off-by: Gerard Marull-Paretas --- tests/subsys/pm/power_mgmt_multicore/src/main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/subsys/pm/power_mgmt_multicore/src/main.c b/tests/subsys/pm/power_mgmt_multicore/src/main.c index 60a35b269c00..6915694a6d82 100644 --- a/tests/subsys/pm/power_mgmt_multicore/src/main.c +++ b/tests/subsys/pm/power_mgmt_multicore/src/main.c @@ -34,9 +34,6 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) ARG_UNUSED(substate_id); switch (state_testing[_current_cpu->id]) { - case PM_STATE_ACTIVE: - zassert_equal(PM_STATE_ACTIVE, state); - break; case PM_STATE_RUNTIME_IDLE: zassert_equal(PM_STATE_RUNTIME_IDLE, state); break; From bba6a1d69e0bad8c1541ac7432801edf936c2cfb Mon Sep 17 00:00:00 2001 From: ferar alashkar Date: Sat, 17 Jun 2023 17:49:05 -0400 Subject: [PATCH 1931/2042] lib: os: hex: add explicit unsigned suffices add explicit unsigned suffices to various immediate numbers, matching them to size_t, complying with required [misra-c2012-10.4] rule which states; Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category. Found as a coding guideline violation (Rule 10.4) by static code scanning tool. Note: Tested on STM32L5 Nucleo-144 board (stm32l552xx). Signed-off-by: ferar alashkar --- lib/os/hex.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/os/hex.c b/lib/os/hex.c index b26c470d1c36..26bba541fbed 100644 --- a/lib/os/hex.c +++ b/lib/os/hex.c @@ -39,33 +39,33 @@ int hex2char(uint8_t x, char *c) size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen) { - if (hexlen < (buflen * 2 + 1)) { + if (hexlen < (buflen * 2U + 1U)) { return 0; } for (size_t i = 0; i < buflen; i++) { - if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) { + if (hex2char(buf[i] >> 4, &hex[2U * i]) < 0) { return 0; } - if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) { + if (hex2char(buf[i] & 0xf, &hex[2U * i + 1U]) < 0) { return 0; } } - hex[2 * buflen] = '\0'; - return 2 * buflen; + hex[2U * buflen] = '\0'; + return 2U * buflen; } size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen) { uint8_t dec; - if (buflen < hexlen / 2 + hexlen % 2) { + if (buflen < hexlen / 2U + hexlen % 2U) { return 0; } /* if hexlen is uneven, insert leading zero nibble */ - if (hexlen % 2) { + if (hexlen % 2U) { if (char2hex(hex[0], &dec) < 0) { return 0; } @@ -75,17 +75,17 @@ size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen) } /* regular hex conversion */ - for (size_t i = 0; i < hexlen / 2; i++) { - if (char2hex(hex[2 * i], &dec) < 0) { + for (size_t i = 0; i < hexlen / 2U; i++) { + if (char2hex(hex[2U * i], &dec) < 0) { return 0; } buf[i] = dec << 4; - if (char2hex(hex[2 * i + 1], &dec) < 0) { + if (char2hex(hex[2U * i + 1U], &dec) < 0) { return 0; } buf[i] += dec; } - return hexlen / 2 + hexlen % 2; + return hexlen / 2U + hexlen % 2U; } From dddc034923fab5e6ce6f97eb8122ea417ae6fc79 Mon Sep 17 00:00:00 2001 From: ferar alashkar Date: Sat, 17 Jun 2023 17:16:08 -0400 Subject: [PATCH 1932/2042] lib: os: hex: correct explicit cast type change explicit type cast of essential character type, complying with required [misra-c2012-10.2] rule which states; Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations. Found as a coding guideline violation (Rule 10.2) by static code scanning tool. Note: Tested on STM32L5 Nucleo-144 board (stm32l552xx). Signed-off-by: ferar alashkar --- lib/os/hex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/os/hex.c b/lib/os/hex.c index 26bba541fbed..58383f9c977b 100644 --- a/lib/os/hex.c +++ b/lib/os/hex.c @@ -27,9 +27,9 @@ int char2hex(char c, uint8_t *x) int hex2char(uint8_t x, char *c) { if (x <= 9) { - *c = x + '0'; + *c = x + (char)'0'; } else if (x <= 15) { - *c = x - 10 + 'a'; + *c = x - 10 + (char)'a'; } else { return -EINVAL; } From 595bcda87cbadb828c9b595dc81102c611187e4b Mon Sep 17 00:00:00 2001 From: ferar alashkar Date: Sat, 10 Jun 2023 16:53:19 -0400 Subject: [PATCH 1933/2042] lib: os: dec: add misra-c2012 compliance changes 1. change explicit type cast of essential character type, complying with required [misra-c2012-10.2] rule which states; Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations, and 2. add explicit boolean type to 'if' statement controlling expression, consolidating it with 'buflen' type, thus improving code readability and maintainability , complying with required [misra-c2012-14.4] rule which states; ; The controlling expression of an if statement and the controlling expression of an iteration-statement shall have essentially boolean type, and 3. add enclosing parentheses enforcing and clarifying precedence of operators, improving code readability and maintainability, complying with *advisory* [misra-c2012-12.1] rule which states; The precedence of operators within expressions should be made explicit. Found as a coding guideline violation (Rules 10.2, 14.4), and coding guideline recommendation (Rule 12.1) by static code scanning tool. Note: Tested on STM32L5 Nucleo-144 board (stm32l552xx). Signed-off-by: ferar alashkar --- lib/os/dec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/os/dec.c b/lib/os/dec.c index d087fa1635b2..188235ff80d5 100644 --- a/lib/os/dec.c +++ b/lib/os/dec.c @@ -12,10 +12,10 @@ uint8_t u8_to_dec(char *buf, uint8_t buflen, uint8_t value) uint8_t num_digits = 0; uint8_t digit; - while (buflen > 0 && divisor > 0) { + while ((buflen > 0) && (divisor > 0)) { digit = value / divisor; - if (digit != 0 || divisor == 1 || num_digits != 0) { - *buf = (char)digit + '0'; + if ((digit != 0) || (divisor == 1) || (num_digits != 0)) { + *buf = digit + (char)'0'; buf++; buflen--; num_digits++; @@ -25,7 +25,7 @@ uint8_t u8_to_dec(char *buf, uint8_t buflen, uint8_t value) divisor /= 10; } - if (buflen) { + if (buflen != 0) { *buf = '\0'; } From 5920159f0fdf26804edd06685a4c4ff23a18fece Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Fri, 28 Jul 2023 09:43:41 +0700 Subject: [PATCH 1934/2042] boards: mr_canhubk3: enable GPIO when CAN is enabled Currently, mr_canhubk3 is enabling GPIO by default. GPIO will be built even if it is not necessary. Update to enable it for supporting CAN transceiver when CAN is enabled. Signed-off-by: Cong Nguyen Huu --- boards/arm/mr_canhubk3/Kconfig.defconfig | 7 +++++++ boards/arm/mr_canhubk3/mr_canhubk3_defconfig | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/boards/arm/mr_canhubk3/Kconfig.defconfig b/boards/arm/mr_canhubk3/Kconfig.defconfig index 32f284540472..72675122196b 100644 --- a/boards/arm/mr_canhubk3/Kconfig.defconfig +++ b/boards/arm/mr_canhubk3/Kconfig.defconfig @@ -13,4 +13,11 @@ config UART_CONSOLE endif # SERIAL +if CAN + +config GPIO + default y + +endif # CAN + endif # BOARD_MR_CANHUBK3 diff --git a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig index 2cf92c9598b9..91ebfcc17d2c 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig @@ -21,7 +21,6 @@ CONFIG_NOCACHE_MEMORY=y # Drivers CONFIG_PINCTRL=y CONFIG_SERIAL=y -CONFIG_GPIO=y # Enable support for GPIO controlled CAN transceivers # Serial console CONFIG_CONSOLE=y From 3d37cc3da98b127eb9a86beb68a89e3e66a0253a Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Thu, 27 Jul 2023 17:48:32 +0200 Subject: [PATCH 1935/2042] doc: bin blobs: State that blobs will not be fetched in CI As a follow-up to a recent discussion in the PR below: https://github.com/zephyrproject-rtos/zephyr/pull/59991 document that binary blobs will not be fetched in CI. Signed-off-by: Carles Cufi --- doc/contribute/bin_blobs.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index f821cac1d254..661007927a0d 100644 --- a/doc/contribute/bin_blobs.rst +++ b/doc/contribute/bin_blobs.rst @@ -217,6 +217,12 @@ over bit-rot, security issues, etc. The submitter of the proposal to integrate a binary blob must commit to maintain the integration of such blob for the foreseeable future. +Regarding Continuous Integration, binary blobs will **not** be fetched in the +project's CI infrastructure that builds and optionally executes tests and samples +to prevent regressions and issues from entering the codebase. This includes +both CI ran when a new GitHub Pull Request is opened as well as any other +regularly scheduled execution of the CI infrastructure. + .. _blobs-process: Submission and review process From 3e398cbb0b64e5057b4a27593f7870d532e58026 Mon Sep 17 00:00:00 2001 From: Maciej Perkowski Date: Thu, 27 Jul 2023 14:52:36 +0200 Subject: [PATCH 1936/2042] twister: bugfix: Make BuildError exception cause test to report error When no/too many elf files are detected after a build a BuildError exception is raised. However, it was not being counted as an issue with a test. With the patch satuses of tests' with such exception are reported as errors. Whithout it, twister finished without reported errors and was getting green CI checks. Signed-off-by: Maciej Perkowski --- scripts/pylib/twister/twisterlib/runner.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 3509c9c6fdc4..af84994e5cbc 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -25,6 +25,7 @@ from domains import Domains from twisterlib.cmakecache import CMakeCache from twisterlib.environment import canonical_zephyr_base +from twisterlib.error import BuildError import elftools from elftools.elf.elffile import ELFFile @@ -618,8 +619,14 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "report", "test": self.instance}) else: logger.debug(f"Determine test cases for test instance: {self.instance.name}") - self.determine_testcases(results) - pipeline.put({"op": "gather_metrics", "test": self.instance}) + try: + self.determine_testcases(results) + pipeline.put({"op": "gather_metrics", "test": self.instance}) + except BuildError as e: + logger.error(str(e)) + self.instance.status = "error" + self.instance.reason = str(e) + pipeline.put({"op": "report", "test": self.instance}) elif op == "gather_metrics": self.gather_metrics(self.instance) From 2a66f9432604ee47078e06fa9ae082f6d5354548 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 25 Jul 2023 09:08:08 -0700 Subject: [PATCH 1937/2042] boards: up_squared: override CPU devicetree node to have 2 CPUs The device tree file for up_squared includes the base dts file for Apollo Lake which only defines 1 CPU. UP Squared have different SKUs with different CPUs, and overall has a minimal of 2 CPUs. So amend the up_squared device tree overlay to have 2 CPU nodes. Signed-off-by: Daniel Leung --- boards/x86/up_squared/up_squared.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/boards/x86/up_squared/up_squared.dts b/boards/x86/up_squared/up_squared.dts index 9d3ff269ba1c..987125da950d 100644 --- a/boards/x86/up_squared/up_squared.dts +++ b/boards/x86/up_squared/up_squared.dts @@ -29,6 +29,25 @@ zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart1; }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "intel,apollo_lake"; + d-cache-line-size = <64>; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "intel,apollo_lake"; + d-cache-line-size = <64>; + reg = <1>; + }; + }; }; &hpet { From 56a8123eed2eb2700324fc9ec7d48e075d68f036 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Tue, 25 Jul 2023 12:00:43 -0700 Subject: [PATCH 1938/2042] toolchain: xcc/xt-clang: include llvm.h for xt-clang... ...and removed the copied macros. This allows xt-clang to inherit macros from llvm.h to align with any LLVM related additions. Signed-off-by: Daniel Leung --- include/zephyr/toolchain/xcc.h | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/include/zephyr/toolchain/xcc.h b/include/zephyr/toolchain/xcc.h index c9344926c52a..65ddc7ea35ed 100644 --- a/include/zephyr/toolchain/xcc.h +++ b/include/zephyr/toolchain/xcc.h @@ -19,21 +19,10 @@ #endif #ifdef __clang__ -#if __clang_major__ >= 10 -#define __fallthrough __attribute__((fallthrough)) -#endif - -#define TOOLCHAIN_CLANG_VERSION \ - ((__clang_major__ * 10000) + (__clang_minor__ * 100) + \ - __clang_patchlevel__) - -#if TOOLCHAIN_CLANG_VERSION >= 30800 -#define TOOLCHAIN_HAS_C_GENERIC 1 -#define TOOLCHAIN_HAS_C_AUTO_TYPE 1 -#endif -#endif - +#include +#else #include +#endif #ifndef __clang__ #undef __BYTE_ORDER__ From 250748bfe671a7b2e9801c152539f05efa363375 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Thu, 27 Jul 2023 12:27:06 -0700 Subject: [PATCH 1939/2042] intel_adsp: Add option about switch off hpsram Add an option to control whether or not hpsram banks should be switched off during the power down. This is particular useful when running tests because we don't want to lose the contents of the memory window before we capture it. Signed-off-by: Flavio Ceolin --- soc/xtensa/intel_adsp/Kconfig | 7 +++++++ soc/xtensa/intel_adsp/ace/power.c | 5 ++++- soc/xtensa/intel_adsp/cavs/power.c | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index a2b9c1011d2e..f04286ccae12 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -95,6 +95,13 @@ config ADSP_INIT_HPSRAM help Need to init HP SRAM. +config ADSP_POWER_DOWN_HPSRAM + bool + default n if ZTEST + default y + help + Switch off HP SRAM during power down. + config ADSP_DISABLE_L2CACHE_AT_BOOT bool diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index cb9159882981..620a6852bd63 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -282,9 +282,12 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) (void *)rom_entry; sys_cache_data_flush_range(imr_layout, sizeof(*imr_layout)); #endif /* CONFIG_ADSP_IMR_CONTEXT_SAVE */ + uint32_t hpsram_mask = 0; +#ifdef CONFIG_ADSP_POWER_DOWN_HPSRAM /* turn off all HPSRAM banks - get a full bitmap */ uint32_t ebb_banks = ace_hpsram_get_bank_count(); - uint32_t hpsram_mask = (1 << ebb_banks) - 1; + hpsram_mask = (1 << ebb_banks) - 1; +#endif /* CONFIG_ADSP_POWER_DOWN_HPSRAM */ /* do power down - this function won't return */ power_down(true, uncache_to_cache(&hpsram_mask), true); diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index 42598e9b56fd..8bb18f316f34 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -87,7 +87,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) soc_cpus_active[cpu] = false; sys_cache_data_flush_and_invd_all(); if (cpu == 0) { - uint32_t hpsram_mask[HPSRAM_SEGMENTS]; + uint32_t hpsram_mask[HPSRAM_SEGMENTS] = {0}; struct imr_header hdr = { .adsp_imr_magic = ADSP_IMR_MAGIC_VALUE, @@ -97,9 +97,11 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) arch_xtensa_uncached_ptr((struct imr_layout *)L3_MEM_BASE_ADDR); imr_layout->imr_state.header = hdr; +#ifdef CONFIG_ADSP_POWER_DOWN_HPSRAM /* turn off all HPSRAM banks - get a full bitmap */ for (int i = 0; i < HPSRAM_SEGMENTS; i++) hpsram_mask[i] = HPSRAM_MEMMASK(i); +#endif /* CONFIG_ADSP_POWER_DOWN_HPSRAM */ /* do power down - this function won't return */ power_down_cavs(true, uncache_to_cache(&hpsram_mask[0])); } else { From 3191d0813003fd5c44646382c4948a16f7f60505 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Thu, 27 Jul 2023 12:41:07 +0000 Subject: [PATCH 1940/2042] twister: improve handling of ELF file parsing We have been dealing with missing and multiple binaries the same way and both would result in a build error, which is not accurate. multiple binaries in the build directory are fine, we just need to pick the right one for parsing. If we get no binaries, raise an exception and report failure, however, if we have multiple binaries, filter intermediate artifacts out and parse what remains. qemu binaries generated after a run are also being filtered here. Those are not build artificats and appear only after running in qemu. However they have been causing issues on retries. Signed-off-by: Anas Nashif --- scripts/pylib/twister/twisterlib/runner.py | 4 +++- scripts/pylib/twister/twisterlib/testinstance.py | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index af84994e5cbc..2d8805903343 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -680,7 +680,8 @@ def determine_testcases(self, results): yaml_testsuite_name = self.instance.testsuite.id logger.debug(f"Determine test cases for test suite: {yaml_testsuite_name}") - elf = ELFFile(open(self.instance.get_elf_file(), "rb")) + elf_file = self.instance.get_elf_file() + elf = ELFFile(open(elf_file, "rb")) logger.debug(f"Test instance {self.instance.name} already has {len(self.instance.testcases)} cases.") new_ztest_unit_test_regex = re.compile(r"z_ztest_unit_test__([^\s]*)__([^\s]*)") @@ -702,6 +703,7 @@ def determine_testcases(self, results): detected_cases.append(testcase_id) if detected_cases: + logger.debug(f"{', '.join(detected_cases)} in {elf_file}") self.instance.testcases.clear() self.instance.testsuite.testcases.clear() diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 62b0dd8cd335..4632de8c2b61 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -290,15 +290,17 @@ def get_elf_file(self) -> str: build_dir = self.build_dir fns = glob.glob(os.path.join(build_dir, "zephyr", "*.elf")) - fns.extend(glob.glob(os.path.join(build_dir, "zephyr", "*.exe"))) fns.extend(glob.glob(os.path.join(build_dir, "testbinary"))) blocklist = [ 'remapped', # used for xtensa plaforms 'zefi', # EFI for Zephyr - '_pre' ] + 'qemu', # elf files generated after running in qemu + '_pre'] fns = [x for x in fns if not any(bad in os.path.basename(x) for bad in blocklist)] - if len(fns) != 1 and self.platform.type != 'native': - raise BuildError("Missing/multiple output ELF binary") + if not fns: + raise BuildError("Missing output binary") + elif len(fns) > 1: + logger.warning(f"multiple ELF files detected: {', '.join(fns)}") return fns[0] def get_buildlog_file(self) -> str: From f809614136c748707d365a1342128e0158145d55 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 20 Jun 2023 14:05:07 +0700 Subject: [PATCH 1941/2042] drivers: adc: add NXP S32 ADC SAR driver Add support ADC SAR for NXP S32. ADC SAR diver support 3 group channels (precision, standard and external), run normal trigger in oneshot conversion mode with 2 callbacks normal end of conversion and normal end chain callbacks. An instance only run on 1 group channel and 1 kind of callback at the same time. Signed-off-by: Cong Nguyen Huu --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.nxp_s32 | 9 + drivers/adc/adc_nxp_s32_adc_sar.c | 446 ++++++++++++++++++++++++++ dts/bindings/adc/nxp,s32-adc-sar.yaml | 49 +++ 5 files changed, 507 insertions(+) create mode 100644 drivers/adc/Kconfig.nxp_s32 create mode 100644 drivers/adc/adc_nxp_s32_adc_sar.c create mode 100644 dts/bindings/adc/nxp,s32-adc-sar.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index daf2dff347e6..f10326d4d195 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -43,3 +43,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_INFINEON_CAT1 adc_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_GPADC adc_smartbond_gpadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_SMARTBOND_SDADC adc_smartbond_sdadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_TLA2021 adc_tla2021.c) +zephyr_library_sources_ifdef(CONFIG_ADC_NXP_S32_ADC_SAR adc_nxp_s32_adc_sar.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 48c57c71a359..a915fa18fc05 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -110,4 +110,6 @@ source "drivers/adc/Kconfig.smartbond" source "drivers/adc/Kconfig.tla2021" +source "drivers/adc/Kconfig.nxp_s32" + endif # ADC diff --git a/drivers/adc/Kconfig.nxp_s32 b/drivers/adc/Kconfig.nxp_s32 new file mode 100644 index 000000000000..e57d21a9a0fe --- /dev/null +++ b/drivers/adc/Kconfig.nxp_s32 @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config ADC_NXP_S32_ADC_SAR + bool "NXP S32 ADC SAR driver" + default y + depends on DT_HAS_NXP_S32_ADC_SAR_ENABLED + help + This option enables the NXP S32 ADC SAR driver. diff --git a/drivers/adc/adc_nxp_s32_adc_sar.c b/drivers/adc/adc_nxp_s32_adc_sar.c new file mode 100644 index 000000000000..7cb5baf5b5cf --- /dev/null +++ b/drivers/adc/adc_nxp_s32_adc_sar.c @@ -0,0 +1,446 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#define DT_DRV_COMPAT nxp_s32_adc_sar +LOG_MODULE_REGISTER(adc_nxp_s32_adc_sar, CONFIG_ADC_LOG_LEVEL); + +/* Convert channel of group ADC to channel of physical ADC instance */ +#define ADC_NXP_S32_GROUPCHAN_2_PHYCHAN(group, channel) \ + (ADC_SAR_IP_HW_REG_SIZE * group + channel) + +struct adc_nxp_s32_config { + ADC_Type *base; + uint8_t instance; + uint8_t group_channel; + uint8_t callback_select; + Adc_Sar_Ip_ConfigType *adc_cfg; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pin_cfg; +}; + +struct adc_nxp_s32_data { + const struct device *dev; + struct adc_context ctx; + uint16_t *buffer; + uint16_t *buf_end; + uint16_t *repeat_buffer; + uint32_t mask_channels; + uint8_t num_channels; +}; + +static int adc_nxp_s32_init(const struct device *dev) +{ + const struct adc_nxp_s32_config *config = dev->config; + struct adc_nxp_s32_data *data = dev->data; + Adc_Sar_Ip_StatusType status; + /* This array shows max number of channels of each group */ + uint8_t map_chan_group[ADC_SAR_IP_INSTANCE_COUNT][ADC_SAR_IP_NUM_GROUP_CHAN] + = FEATURE_ADC_MAX_CHN_COUNT; + + data->num_channels = map_chan_group[config->instance][config->group_channel]; + + if (config->pin_cfg) { + if (pinctrl_apply_state(config->pin_cfg, PINCTRL_STATE_DEFAULT)) { + return -EIO; + } + } + + status = Adc_Sar_Ip_Init(config->instance, config->adc_cfg); + if (status) { + return -EIO; + } + +#if FEATURE_ADC_HAS_CALIBRATION + status = Adc_Sar_Ip_DoCalibration(config->instance); + if (status) { + return -EIO; + } +#endif + + Adc_Sar_Ip_EnableNotifications(config->instance, + config->callback_select ? + ADC_SAR_IP_NOTIF_FLAG_NORMAL_ENDCHAIN + : ADC_SAR_IP_NOTIF_FLAG_NORMAL_EOC); + + data->dev = dev; + config->irq_config_func(dev); + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static int adc_nxp_s32_channel_setup(const struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + struct adc_nxp_s32_data *data = dev->data; + + if (channel_cfg->channel_id >= data->num_channels) { + LOG_ERR("Channel %d is not valid", channel_cfg->channel_id); + return -EINVAL; + } + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Unsupported channel acquisition time"); + return -ENOTSUP; + } + + if (channel_cfg->differential) { + LOG_ERR("Differential channels are not supported"); + return -ENOTSUP; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Unsupported channel gain %d", channel_cfg->gain); + return -ENOTSUP; + } + + if (channel_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Unsupported channel reference"); + return -ENOTSUP; + } + + return 0; +} + +static int adc_nxp_s32_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + uint8_t active_channels = 0; + size_t needed_size; + + active_channels = POPCOUNT(sequence->channels); + + needed_size = active_channels * sizeof(uint16_t); + if (sequence->options) { + needed_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_size) { + return -ENOSPC; + } + + return 0; +} + +#if FEATURE_ADC_HAS_AVERAGING +static int adc_nxp_s32_set_averaging(const struct device *dev, uint8_t oversampling) +{ + const struct adc_nxp_s32_config *config = dev->config; + Adc_Sar_Ip_AvgSelectType avg_sel = ADC_SAR_IP_AVG_4_CONV; + bool avg_en = true; + + switch (oversampling) { + case 0: + avg_en = false; + break; + case 2: + avg_sel = ADC_SAR_IP_AVG_4_CONV; + break; + case 3: + avg_sel = ADC_SAR_IP_AVG_8_CONV; + break; + case 4: + avg_sel = ADC_SAR_IP_AVG_16_CONV; + break; + case 5: + avg_sel = ADC_SAR_IP_AVG_32_CONV; + break; + default: + LOG_ERR("Unsupported oversampling value"); + return -ENOTSUP; + } + Adc_Sar_Ip_SetAveraging(config->instance, avg_en, avg_sel); + + return 0; +} +#endif + +#if (ADC_SAR_IP_SET_RESOLUTION == STD_ON) +static int adc_nxp_s32_set_resolution(const struct device *dev, uint8_t adc_resol) +{ + const struct adc_nxp_s32_config *config = dev->config; + Adc_Sar_Ip_Resolution resolution; + + switch (adc_resol) { + case 8: + resolution = ADC_SAR_IP_RESOLUTION_8; + break; + case 10: + resolution = ADC_SAR_IP_RESOLUTION_10; + break; + case 12: + resolution = ADC_SAR_IP_RESOLUTION_12; + break; + case 14: + resolution = ADC_SAR_IP_RESOLUTION_14; + break; + default: + LOG_ERR("Unsupported resolution"); + return -ENOTSUP; + } + Adc_Sar_Ip_SetResolution(config->instance, resolution); + + return 0; +} +#endif + +static int adc_nxp_s32_start_read_async(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct adc_nxp_s32_config *config = dev->config; + struct adc_nxp_s32_data *data = dev->data; + int error; + uint32_t mask; + uint8_t channel; + + if (find_msb_set(sequence->channels) > data->num_channels) { + LOG_ERR("Channels out of bit map"); + return -EINVAL; + } + + error = adc_nxp_s32_validate_buffer_size(dev, sequence); + if (error) { + LOG_ERR("Buffer size isn't enough"); + return -EINVAL; + } + +#if FEATURE_ADC_HAS_AVERAGING + error = adc_nxp_s32_set_averaging(dev, sequence->oversampling); + if (error) { + return -ENOTSUP; + } +#else + if (sequence->oversampling) { + LOG_ERR("Oversampling can't be changed"); + return -ENOTSUP; + } +#endif + +#if (ADC_SAR_IP_SET_RESOLUTION == STD_ON) + error = adc_nxp_s32_set_resolution(dev, sequence->resolution); + if (error) { + return -ENOTSUP; + } +#else + if (sequence->resolution != ADC_SAR_IP_MAX_RESOLUTION) { + LOG_ERR("Resolution can't be changed"); + return -ENOTSUP; + } +#endif + + if (sequence->calibrate) { +#if FEATURE_ADC_HAS_CALIBRATION + error = Adc_Sar_Ip_DoCalibration(config->instance); + if (error) { + LOG_ERR("Error during calibration"); + return -EIO; + } +#else + LOG_ERR("Unsupported calibration"); + return -ENOTSUP; +#endif + } + + for (int i = 0; i < data->num_channels; i++) { + mask = (sequence->channels >> i) & 0x1; + channel = ADC_NXP_S32_GROUPCHAN_2_PHYCHAN(config->group_channel, i); + if (mask) { + Adc_Sar_Ip_EnableChannelNotifications(config->instance, + channel, ADC_SAR_IP_CHAN_NOTIF_EOC); + Adc_Sar_Ip_EnableChannel(config->instance, + ADC_SAR_IP_CONV_CHAIN_NORMAL, channel); + } else { + Adc_Sar_Ip_DisableChannelNotifications(config->instance, + channel, ADC_SAR_IP_CHAN_NOTIF_EOC); + Adc_Sar_Ip_DisableChannel(config->instance, + ADC_SAR_IP_CONV_CHAIN_NORMAL, channel); + } + } + + /* Save ADC sequence sampling buffer and its end pointer address */ + data->buffer = sequence->buffer; + if (config->callback_select) { + data->buf_end = data->buffer + sequence->buffer_size / sizeof(uint16_t); + } + + adc_context_start_read(&data->ctx, sequence); + error = adc_context_wait_for_completion(&data->ctx); + + return error; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_nxp_s32_data *data = CONTAINER_OF(ctx, struct adc_nxp_s32_data, ctx); + const struct adc_nxp_s32_config *config = data->dev->config; + + data->mask_channels = ctx->sequence.channels; + data->repeat_buffer = data->buffer; + + Adc_Sar_Ip_StartConversion(config->instance, ADC_SAR_IP_CONV_CHAIN_NORMAL); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_nxp_s32_data *const data = + CONTAINER_OF(ctx, struct adc_nxp_s32_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static int adc_nxp_s32_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_nxp_s32_data *data = dev->data; + int error = 0; + + adc_context_lock(&data->ctx, async ? true : false, async); + error = adc_nxp_s32_start_read_async(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +static int adc_nxp_s32_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + return adc_nxp_s32_read_async(dev, sequence, NULL); +} + +static void adc_nxp_s32_isr(const struct device *dev) +{ + const struct adc_nxp_s32_config *config = dev->config; + + Adc_Sar_Ip_IRQHandler(config->instance); +} + +#define ADC_NXP_S32_DRIVER_API(n) \ + static const struct adc_driver_api adc_nxp_s32_driver_api_##n = { \ + .channel_setup = adc_nxp_s32_channel_setup, \ + .read = adc_nxp_s32_read, \ + IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = adc_nxp_s32_read_async,))\ + .ref_internal = DT_INST_PROP(n, vref_mv), \ + }; + +#define ADC_NXP_S32_IRQ_CONFIG(n) \ + static void adc_nxp_s32_adc_sar_config_func_##n(const struct device *dev)\ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + adc_nxp_s32_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + }; + +#define ADC_NXP_S32_CALLBACK_DEFINE(n) \ + void adc_nxp_s32_normal_end_conversion_callback##n(const uint16 PhysicalChanId)\ + { \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ + const struct adc_nxp_s32_config *config = dev->config; \ + struct adc_nxp_s32_data *data = dev->data; \ + uint16_t result = 0; \ + \ + result = Adc_Sar_Ip_GetConvData(n, PhysicalChanId); \ + LOG_DBG("End conversion, channel %d, group %d, result = %d", \ + ADC_SAR_IP_CHAN_2_BIT(PhysicalChanId), \ + config->group_channel, result); \ + \ + *data->buffer++ = result; \ + data->mask_channels &= \ + ~BIT(ADC_SAR_IP_CHAN_2_BIT(PhysicalChanId)); \ + \ + if (!data->mask_channels) { \ + adc_context_on_sampling_done(&data->ctx, \ + (struct device *)dev); \ + } \ + }; \ + void adc_nxp_s32_normal_endchain_callback##n(void) \ + { \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ + const struct adc_nxp_s32_config *config = dev->config; \ + struct adc_nxp_s32_data *data = dev->data; \ + uint16_t result = 0; \ + uint8_t channel; \ + \ + while (data->mask_channels) { \ + channel = ADC_NXP_S32_GROUPCHAN_2_PHYCHAN( \ + config->group_channel, \ + (find_lsb_set(data->mask_channels)-1)); \ + result = Adc_Sar_Ip_GetConvData(n, channel); \ + LOG_DBG("End chain, channel %d, group %d, result = %d", \ + ADC_SAR_IP_CHAN_2_BIT(channel), \ + config->group_channel, result); \ + if (data->buffer < data->buf_end) { \ + *data->buffer++ = result; \ + } \ + data->mask_channels &= \ + ~BIT(ADC_SAR_IP_CHAN_2_BIT(channel)); \ + } \ + \ + adc_context_on_sampling_done(&data->ctx, (struct device *)dev); \ + }; + +#define ADC_NXP_S32_INSTANCE_CHECK(indx, n) \ + ((DT_INST_REG_ADDR(n) == IP_ADC_##indx##_BASE) ? indx : 0) +#define ADC_NXP_S32_GET_INSTANCE(n) \ + LISTIFY(__DEBRACKET ADC_INSTANCE_COUNT, ADC_NXP_S32_INSTANCE_CHECK, (|), n) + +#define ADC_NXP_S32_INIT_DEVICE(n) \ + ADC_NXP_S32_DRIVER_API(n) \ + ADC_NXP_S32_CALLBACK_DEFINE(n) \ + ADC_NXP_S32_IRQ_CONFIG(n) \ + COND_CODE_1(DT_INST_NUM_PINCTRL_STATES(n), \ + (PINCTRL_DT_INST_DEFINE(n);), (EMPTY)) \ + static const Adc_Sar_Ip_ConfigType adc_nxp_s32_default_config##n = \ + { \ + .ConvMode = ADC_SAR_IP_CONV_MODE_ONESHOT, \ + .AdcResolution = ADC_SAR_IP_RESOLUTION_14, \ + .HighSpeedConvEn = DT_INST_PROP(n, high_speed), \ + .EndOfNormalChainNotification = \ + adc_nxp_s32_normal_endchain_callback##n, \ + .EndOfConvNotification = \ + adc_nxp_s32_normal_end_conversion_callback##n, \ + }; \ + static struct adc_nxp_s32_data adc_nxp_s32_data_##n = { \ + ADC_CONTEXT_INIT_TIMER(adc_nxp_s32_data_##n, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_nxp_s32_data_##n, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_nxp_s32_data_##n, ctx), \ + }; \ + static const struct adc_nxp_s32_config adc_nxp_s32_config_##n = { \ + .base = (ADC_Type *)DT_INST_REG_ADDR(n), \ + .instance = ADC_NXP_S32_GET_INSTANCE(n), \ + .group_channel = DT_INST_ENUM_IDX(n, group_channel), \ + .callback_select = DT_INST_ENUM_IDX(n, callback_select), \ + .adc_cfg = (Adc_Sar_Ip_ConfigType *)&adc_nxp_s32_default_config##n,\ + .irq_config_func = adc_nxp_s32_adc_sar_config_func_##n, \ + .pin_cfg = COND_CODE_1(DT_INST_NUM_PINCTRL_STATES(n), \ + (PINCTRL_DT_INST_DEV_CONFIG_GET(n)), (NULL)), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &adc_nxp_s32_init, \ + NULL, \ + &adc_nxp_s32_data_##n, \ + &adc_nxp_s32_config_##n, \ + POST_KERNEL, \ + CONFIG_ADC_INIT_PRIORITY, \ + &adc_nxp_s32_driver_api_##n); + +DT_INST_FOREACH_STATUS_OKAY(ADC_NXP_S32_INIT_DEVICE) diff --git a/dts/bindings/adc/nxp,s32-adc-sar.yaml b/dts/bindings/adc/nxp,s32-adc-sar.yaml new file mode 100644 index 000000000000..f7201698f793 --- /dev/null +++ b/dts/bindings/adc/nxp,s32-adc-sar.yaml @@ -0,0 +1,49 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP S32 ADC SAR controller + +compatible: "nxp,s32-adc-sar" + +include: [adc-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + vref-mv: + type: int + default: 3300 + description: Indicates the reference voltage of the ADC in mV. + + group-channel: + type: string + required: true + enum: + - "precision" + - "standard" + - "external" + description: The ADC group channel. + + high-speed: + type: boolean + description: Use high speed during conversion, calibration. + + callback-select: + type: string + default: "normal-end-conversion" + enum: + - "normal-end-conversion" + - "normal-end-chain" + description: | + Select normal end conversion callback to reduce interrupt handling time. + Select normal end chain callback to reduce the number of interrupt occurrences. + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input From a0db65e6ae4d22ff965d18268ac768ebd29a7044 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 20 Jun 2023 16:17:28 +0700 Subject: [PATCH 1942/2042] boards: mr_canhubk3: add support adc Add device tree of adc instances for s32k344 Signed-off-by: Cong Nguyen Huu --- boards/arm/mr_canhubk3/doc/index.rst | 10 ++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.yaml | 1 + dts/arm/nxp/nxp_s32k344_m7.dtsi | 24 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 9de092bf0b7e..0ae9bccccc10 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -52,6 +52,7 @@ LPUART on-chip serial QSPI on-chip flash FLEXCAN on-chip can LPI2C on-chip i2c +ADC SAR on-chip adc ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -191,6 +192,15 @@ P4.3 PTD14 LPI2C0_SCL P4.4 PTD13 LPI2C0_SDA ========= ===== ============ +ADC +=== + +ADC is provided through ADC SAR controller with 3 instances. ADC channels are divided into +3 groups (precision, standard and external). + +.. note:: + All channels of an instance only run on 1 group channel at the same time. + FS26 SBC Watchdog ================= diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.yaml b/boards/arm/mr_canhubk3/mr_canhubk3.yaml index 1875c7cb5b09..32648c36efac 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.yaml +++ b/boards/arm/mr_canhubk3/mr_canhubk3.yaml @@ -14,3 +14,4 @@ supported: - uart - can - i2c + - adc diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index a434f2e7928a..798f0d123e58 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -505,6 +505,30 @@ interrupts = <162 0>; status = "disabled"; }; + + adc0: adc@400a0000 { + compatible = "nxp,s32-adc-sar"; + reg = <0x400a0000 0x1000>; + interrupts = <180 0>; + #io-channel-cells = <1>; + status = "disabled"; + }; + + adc1: adc@400a4000 { + compatible = "nxp,s32-adc-sar"; + reg = <0x400a4000 0x1000>; + interrupts = <181 0>; + #io-channel-cells = <1>; + status = "disabled"; + }; + + adc2: adc@400a8000 { + compatible = "nxp,s32-adc-sar"; + reg = <0x400a8000 0x1000>; + interrupts = <182 0>; + #io-channel-cells = <1>; + status = "disabled"; + }; }; }; From 5ea07017caae68d3ec2d480c7e136bf42ec1de87 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 20 Jun 2023 14:18:00 +0700 Subject: [PATCH 1943/2042] tests: drivers: adc: adc_api: enbale test for mr_canhubk3 Enable adc0 with 2 channels 22, 23 on standard group with normal end of conversion callback. Channels correspond to VREFL(0V), VREFH(3.3V). Signed-off-by: Cong Nguyen Huu --- .../adc/adc_api/boards/mr_canhubk3.overlay | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/mr_canhubk3.overlay diff --git a/tests/drivers/adc/adc_api/boards/mr_canhubk3.overlay b/tests/drivers/adc/adc_api/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..0e1443dec89c --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/mr_canhubk3.overlay @@ -0,0 +1,36 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 22>, <&adc0 23>; + }; +}; + +&adc0 { + group-channel = "standard"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@16 { + reg = <22>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; + + channel@17 { + reg = <23>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; +}; From 19f33b8ecb2667c267d527bf90aee97bc0940aa6 Mon Sep 17 00:00:00 2001 From: Cong Nguyen Huu Date: Tue, 20 Jun 2023 14:43:24 +0700 Subject: [PATCH 1944/2042] samples: drivers: adc: enbale test for mr_canhubk3 Enable all channels that available connector on board. ADC0 channel 6 on precision group with normal end chain callback. ADC1 channel 2 on precision group with normal end of conversion callback. ADC2 channels 3, 4, 5 on precision group with normal end of conversion callback. Signed-off-by: Cong Nguyen Huu --- .../drivers/adc/boards/mr_canhubk3.overlay | 77 +++++++++++++++++++ samples/drivers/adc/sample.yaml | 1 + west.yml | 2 +- 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 samples/drivers/adc/boards/mr_canhubk3.overlay diff --git a/samples/drivers/adc/boards/mr_canhubk3.overlay b/samples/drivers/adc/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..3f60c3c465c0 --- /dev/null +++ b/samples/drivers/adc/boards/mr_canhubk3.overlay @@ -0,0 +1,77 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + zephyr,user { + io-channels = <&adc0 6>, <&adc1 2>, <&adc2 3>, <&adc2 4>, <&adc2 5>; + }; +}; + +&adc0 { + group-channel = "precision"; + callback-select = "normal-end-chain"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@6 { + reg = <6>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; +}; + +&adc1 { + group-channel = "precision"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; + +}; + + +&adc2 { + group-channel = "precision"; + status = "okay"; + #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 = <14>; + }; + + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; + + channel@5 { + reg = <5>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <14>; + }; +}; diff --git a/samples/drivers/adc/sample.yaml b/samples/drivers/adc/sample.yaml index 678e0afd8802..0187d38ac54a 100644 --- a/samples/drivers/adc/sample.yaml +++ b/samples/drivers/adc/sample.yaml @@ -23,6 +23,7 @@ tests: - esp32c3_devkitm - gd32l233r_eval - lpcxpresso55s36 + - mr_canhubk3 integration_platforms: - nucleo_l073rz - nrf52840dk_nrf52840 diff --git a/west.yml b/west.yml index 27523c7b7653..c7545d6a7fbe 100644 --- a/west.yml +++ b/west.yml @@ -183,7 +183,7 @@ manifest: groups: - hal - name: hal_nxp - revision: 3aed18634b19102cc0f9e56fcff88bd04edba6ec + revision: 1a55ccfde649a97df74a8853cbd9787ddd34bfc4 path: modules/hal/nxp groups: - hal From 1b3e2d98e4c889002a651fd2ae91effe12bb06d5 Mon Sep 17 00:00:00 2001 From: Daniel Gaston Ochoa Date: Tue, 25 Jul 2023 10:43:34 +0100 Subject: [PATCH 1945/2042] drivers: stm32: SPI: Check that SPI buffers are in a nocache region DMA only works with non-cached memory regions in H7. Check them and return an error if they don't match this condition. Signed-off-by: Daniel Gaston Ochoa --- drivers/spi/spi_ll_stm32.c | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 8590cc6fd580..65dadb8d4a7b 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -51,6 +51,36 @@ LOG_MODULE_REGISTER(spi_ll_stm32); #endif /* CONFIG_SOC_SERIES_STM32MP1X */ #ifdef CONFIG_SPI_STM32_DMA + +#ifdef CONFIG_SOC_SERIES_STM32H7X + +#define IS_NOCACHE_MEM_REGION(node_id) \ + COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, zephyr_memory_attr, RAM_NOCACHE), \ + (1), \ + (0)) + +#define GET_MEM_REGION(node_id) \ + { \ + .start = DT_REG_ADDR(node_id), \ + .end = (DT_REG_ADDR(node_id) + DT_REG_SIZE(node_id)) - 1, \ + }, + +#define GET_MEM_REGION_IF_NOCACHE(node_id) \ + COND_CODE_1(IS_NOCACHE_MEM_REGION(node_id), \ + ( \ + GET_MEM_REGION(node_id) \ + ), ()) + +struct mem_region { + uintptr_t start; + uintptr_t end; +}; + +static const struct mem_region nocache_mem_regions[] = { + DT_MEMORY_ATTR_FOREACH_NODE(GET_MEM_REGION_IF_NOCACHE) +}; +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + /* dummy value used for transferring NOP when tx buf is null * and use as dummy sink for when rx buf is null */ @@ -723,6 +753,34 @@ static int wait_dma_rx_tx_done(const struct device *dev) return res; } +#ifdef CONFIG_SOC_SERIES_STM32H7X +static bool buf_in_nocache(uintptr_t buf, size_t len_bytes) +{ + for (size_t i = 0; i < ARRAY_SIZE(nocache_mem_regions); i++) { + const struct mem_region *mem_reg = &nocache_mem_regions[i]; + + const bool buf_within_bounds = + (buf >= mem_reg->start) && ((buf + len_bytes - 1) <= mem_reg->end); + if (buf_within_bounds) { + return true; + } + } + return false; +} + +static bool spi_buf_set_in_nocache(const struct spi_buf_set *bufs) +{ + for (size_t i = 0; i < bufs->count; i++) { + const struct spi_buf *buf = &bufs->buffers[i]; + + if (!buf_in_nocache((uintptr_t)buf->buf, buf->len)) { + return false; + } + } + return true; +} +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + static int transceive_dma(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -744,6 +802,13 @@ static int transceive_dma(const struct device *dev, return -ENOTSUP; } +#ifdef CONFIG_SOC_SERIES_STM32H7X + if ((tx_bufs != NULL && !spi_buf_set_in_nocache(tx_bufs)) || + (rx_bufs != NULL && !spi_buf_set_in_nocache(rx_bufs))) { + return -EFAULT; + } +#endif /* CONFIG_SOC_SERIES_STM32H7X */ + spi_context_lock(&data->ctx, asynchronous, cb, userdata, config); k_sem_reset(&data->status_sem); From ff54350ef02152d27c4cf6c8194d143864e126cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Battrel?= Date: Mon, 10 Jul 2023 14:20:09 +0200 Subject: [PATCH 1946/2042] Bluetooth: Host: Remove 'Experimental' flag of EAD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nordic Semiconductor has been testing the feature extensively on its CI. The tests includes the sample data and the PTS tests. Signed-off-by: Théo Battrel --- subsys/bluetooth/lib/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/subsys/bluetooth/lib/Kconfig b/subsys/bluetooth/lib/Kconfig index 15cfa142b131..4e72027b5ee9 100644 --- a/subsys/bluetooth/lib/Kconfig +++ b/subsys/bluetooth/lib/Kconfig @@ -2,8 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 config BT_EAD - bool "Encrypted Advertising Data [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Encrypted Advertising Data" select BT_HOST_CCM help Enable the Encrypted Advertising Data library From 4f8c90ead2dc0a5a58e2b5b1615f49044ae460ca Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Thu, 13 Jul 2023 15:41:12 -0600 Subject: [PATCH 1947/2042] sensor: akm09918c: Fix conversion constant The sensor driver uses the value 500 to convert bit counts to microgauss values, but it should actually be 1500. Edit the driver unit test to use the macro instead of a magic number. Signed-off-by: Tristan Honscheid --- drivers/sensor/akm09918c/akm09918c.h | 13 ++++++++++++- tests/drivers/sensor/akm09918c/src/main.c | 13 +++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/sensor/akm09918c/akm09918c.h b/drivers/sensor/akm09918c/akm09918c.h index 9bb1b6db4062..1745715287e8 100644 --- a/drivers/sensor/akm09918c/akm09918c.h +++ b/drivers/sensor/akm09918c/akm09918c.h @@ -7,6 +7,7 @@ #define ZEPHYR_DRIVERS_SENSOR_AKM09918C_AKM09918C_H_ #include +#include #include #include "akm09918c_reg.h" @@ -15,7 +16,17 @@ #define AKM09918C_MEASURE_TIME_US 9000 /* Conversion values */ -#define AKM09918C_MICRO_GAUSS_PER_BIT INT64_C(500) +#define AKM09918C_MICRO_GAUSS_PER_BIT INT64_C(1500) + +/* Maximum and minimum raw register values for magnetometer data per datasheet */ +#define AKM09918C_MAGN_MAX_DATA_REG (32752) +#define AKM09918C_MAGN_MIN_DATA_REG (-32752) + +/* Maximum and minimum magnetometer values in microgauss. +/-32752 is the maximum range of the + * data registers (slightly less than the range of int16). This works out to +/- 49,128,000 uGs + */ +#define AKM09918C_MAGN_MAX_MICRO_GAUSS (AKM09918C_MAGN_MAX_DATA_REG * AKM09918C_MICRO_GAUSS_PER_BIT) +#define AKM09918C_MAGN_MIN_MICRO_GAUSS (AKM09918C_MAGN_MIN_DATA_REG * AKM09918C_MICRO_GAUSS_PER_BIT) struct akm09918c_data { int16_t x_sample; diff --git a/tests/drivers/sensor/akm09918c/src/main.c b/tests/drivers/sensor/akm09918c/src/main.c index 132e450f1360..580bf64b761f 100644 --- a/tests/drivers/sensor/akm09918c/src/main.c +++ b/tests/drivers/sensor/akm09918c/src/main.c @@ -10,6 +10,7 @@ #include #include +#include "akm09918c.h" #include "akm09918c_emul.h" #include "akm09918c_reg.h" @@ -72,19 +73,19 @@ static void test_fetch_magnetic_field(const struct akm09918c_fixture *fixture, /* Assert the data is within 0.000005 Gauss */ actual_ugauss = values[0].val1 * INT64_C(1000000) + values[0].val2; - expect_ugauss = magn_percent[0] * INT64_C(500); + expect_ugauss = magn_percent[0] * AKM09918C_MICRO_GAUSS_PER_BIT; zassert_within(expect_ugauss, actual_ugauss, INT64_C(5), "(X) expected %" PRIi64 " micro-gauss, got %" PRIi64 " micro-gauss", expect_ugauss, actual_ugauss); actual_ugauss = values[1].val1 * INT64_C(1000000) + values[1].val2; - expect_ugauss = magn_percent[1] * INT64_C(500); + expect_ugauss = magn_percent[1] * AKM09918C_MICRO_GAUSS_PER_BIT; zassert_within(expect_ugauss, actual_ugauss, INT64_C(5), "(Y) expected %" PRIi64 " micro-gauss, got %" PRIi64 " micro-gauss", expect_ugauss, actual_ugauss); actual_ugauss = values[2].val1 * INT64_C(1000000) + values[2].val2; - expect_ugauss = magn_percent[2] * INT64_C(500); + expect_ugauss = magn_percent[2] * AKM09918C_MICRO_GAUSS_PER_BIT; zassert_within(expect_ugauss, actual_ugauss, INT64_C(5), "(Z) expected %" PRIi64 " micro-gauss, got %" PRIi64 " micro-gauss", expect_ugauss, actual_ugauss); @@ -94,9 +95,9 @@ ZTEST_F(akm09918c, test_fetch_magn) { /* Use (0.25, -0.33..., 0.91) as the factors */ const int16_t magn_percent[3] = { - INT16_C(32752) / INT16_C(4), - INT16_C(-32751) / INT16_C(3), - (int16_t)(INT16_C(32752) * INT32_C(91) / INT32_C(100)), + INT16_C(AKM09918C_MAGN_MAX_DATA_REG) / INT16_C(4), + INT16_C(AKM09918C_MAGN_MIN_DATA_REG) / INT16_C(3), + (int16_t)(INT16_C(AKM09918C_MAGN_MAX_DATA_REG) * INT32_C(91) / INT32_C(100)), }; test_fetch_magnetic_field(fixture, magn_percent); From 171c1fc9d94ad2e004d53808a1b61312deb5f038 Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Thu, 13 Jul 2023 15:56:59 -0600 Subject: [PATCH 1948/2042] emul: Introduce emulator backend API and generic sensor test This PR introduces a backend API to be implemented by sensor emulators that creates a standardized mechanism for setting expected sensor readings in tests. This unlocks the ability to create a generic sensor test that can automatically set expected values in supported sensor emulators and verify them through the existing sensor API. An implementation of this API is provided for the AKM09918C magnetometer. A generic sensor test is also created to exercise this implementation. Observe that this test knows nothing about the AKM09918C; info about supported channels and sample ranges is discovered through the backend API. The test iterates over all devices attached to the virtual I2C and SPI buses in the test binary's device tree, which (theoretically) covers all sensors. Sensors whose emulator does not exist yet or does not support the backend API are skipped. Signed-off-by: Tristan Honscheid --- doc/hardware/peripherals/sensor.rst | 1 + drivers/sensor/akm09918c/akm09918c_emul.c | 81 +++++- include/zephyr/drivers/emul_sensor.h | 113 +++++++++ tests/drivers/build_all/sensor/CMakeLists.txt | 5 +- tests/drivers/build_all/sensor/Kconfig | 24 ++ .../build_all/sensor/src/generic_test.c | 238 ++++++++++++++++++ tests/drivers/build_all/sensor/testcase.yaml | 9 + 7 files changed, 468 insertions(+), 3 deletions(-) create mode 100644 include/zephyr/drivers/emul_sensor.h create mode 100644 tests/drivers/build_all/sensor/Kconfig create mode 100644 tests/drivers/build_all/sensor/src/generic_test.c diff --git a/doc/hardware/peripherals/sensor.rst b/doc/hardware/peripherals/sensor.rst index d0dcf8f20d3a..5c7817b627bb 100644 --- a/doc/hardware/peripherals/sensor.rst +++ b/doc/hardware/peripherals/sensor.rst @@ -228,3 +228,4 @@ API Reference ************** .. doxygengroup:: sensor_interface +.. doxygengroup:: sensor_emulator_backend diff --git a/drivers/sensor/akm09918c/akm09918c_emul.c b/drivers/sensor/akm09918c/akm09918c_emul.c index 3f16a2fe67cf..2112acc8c001 100644 --- a/drivers/sensor/akm09918c/akm09918c_emul.c +++ b/drivers/sensor/akm09918c/akm09918c_emul.c @@ -7,10 +7,13 @@ #include #include +#include #include #include #include +#include +#include "akm09918c.h" #include "akm09918c_emul.h" #include "akm09918c_reg.h" @@ -130,14 +133,90 @@ static int akm09918c_emul_init(const struct emul *target, const struct device *p return 0; } +static int akm09918c_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + q31_t value, int8_t shift) +{ + if (!target || !target->data) { + return -EINVAL; + } + + struct akm09918c_emul_data *data = target->data; + uint8_t reg; + + switch (ch) { + case SENSOR_CHAN_MAGN_X: + reg = AKM09918C_REG_HXL; + break; + case SENSOR_CHAN_MAGN_Y: + reg = AKM09918C_REG_HYL; + break; + case SENSOR_CHAN_MAGN_Z: + reg = AKM09918C_REG_HZL; + break; + /* This function only supports setting single channels, so skip MAGN_XYZ */ + default: + return -ENOTSUP; + } + + /* Set the ST1 register to show we have data */ + 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); + + int16_t reg_val = + CLAMP(microgauss, AKM09918C_MAGN_MIN_MICRO_GAUSS, AKM09918C_MAGN_MAX_MICRO_GAUSS) / + AKM09918C_MICRO_GAUSS_PER_BIT; + + /* Insert reading into registers */ + data->reg[reg] = reg_val & 0xFF; + data->reg[reg + 1] = (reg_val >> 8) & 0xFF; + + return 0; +} + +static int akm09918c_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) +{ + ARG_UNUSED(target); + + if (!lower || !upper || !epsilon || !shift) { + return -EINVAL; + } + + switch (ch) { + case SENSOR_CHAN_MAGN_X: + case SENSOR_CHAN_MAGN_Y: + case SENSOR_CHAN_MAGN_Z: + /* +/- 49.12 Gs is the measurement range. 0.0015 Gs is the granularity */ + *shift = 6; + *upper = (int64_t)(49.12 * ((int64_t)INT32_MAX + 1)) >> *shift; + *lower = -*upper; + *epsilon = (int64_t)(0.0015 * ((int64_t)INT32_MAX + 1)) >> *shift; + break; + default: + return -ENOTSUP; + } + + return 0; +} + static const struct i2c_emul_api akm09918c_emul_api_i2c = { .transfer = akm09918c_emul_transfer_i2c, }; +static const struct emul_sensor_backend_api akm09918c_emul_sensor_backend_api = { + .set_channel = akm09918c_emul_backend_set_channel, + .get_sample_range = akm09918c_emul_backend_get_sample_range, +}; + #define AKM09918C_EMUL(n) \ const struct akm09918c_emul_cfg akm09918c_emul_cfg_##n; \ struct akm09918c_emul_data akm09918c_emul_data_##n; \ EMUL_DT_INST_DEFINE(n, akm09918c_emul_init, &akm09918c_emul_data_##n, \ - &akm09918c_emul_cfg_##n, &akm09918c_emul_api_i2c, NULL) + &akm09918c_emul_cfg_##n, &akm09918c_emul_api_i2c, \ + &akm09918c_emul_sensor_backend_api) DT_INST_FOREACH_STATUS_OKAY(AKM09918C_EMUL) diff --git a/include/zephyr/drivers/emul_sensor.h b/include/zephyr/drivers/emul_sensor.h new file mode 100644 index 000000000000..44a497ee4019 --- /dev/null +++ b/include/zephyr/drivers/emul_sensor.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/** + * @brief Sensor emulator backend API + * @defgroup sensor_emulator_backend Sensor emulator backend API + * @ingroup io_interfaces + * @{ + */ + +/** + * @cond INTERNAL_HIDDEN + * + * These are for internal use only, so skip these in public documentation. + */ + +/** + * @brief Collection of function pointers implementing a common backend API for sensor emulators + */ +__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, + 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); +}; +/** + * @endcond + */ + +/** + * @brief Check if a given sensor emulator supports the backend API + * + * @param target Pointer to emulator instance to query + * + * @return True if supported, false if unsupported or if \p target is NULL. + */ +static inline bool emul_sensor_backend_is_supported(const struct emul *target) +{ + return target && target->backend_api; +} + +/** + * @brief Set an expected value for a given channel on a given sensor emulator + * + * @param target Pointer to emulator instance to operate on + * @param ch Sensor channel to set expected value for + * @param value Expected value in fixed-point format using standard SI unit for sensor type + * @param shift Shift value (scaling factor) applied to \p value + * + * @return 0 if successful + * @return -ENOTSUP if no backend API or if channel not supported by emul + * @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) +{ + if (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->set_channel) { + return api->set_channel(target, ch, value, shift); + } + return -ENOTSUP; +} + +/** + * @brief Query an emulator for a channel's supported sample value range and tolerance + * + * @param target Pointer to emulator instance to operate on + * @param ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP` + * @param[out] lower Minimum supported sample value in SI units, fixed-point format + * @param[out] upper Maximum supported sample value in SI units, fixed-point format + * @param[out] epsilon Tolerance to use comparing expected and actual values to account for rounding + * and sensor precision issues. This can usually be set to the minimum sample value step + * size. Uses SI units and fixed-point format. + * @param[out] shift The shift value (scaling factor) associated with \p lower, \p upper, and + * \p epsilon. + * + * @return 0 if successful + * @return -ENOTSUP if no backend API or if channel not supported by emul + * + */ +static inline int emul_sensor_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 (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->get_sample_range) { + return api->get_sample_range(target, ch, lower, upper, epsilon, shift); + } + return -ENOTSUP; +} + +/** + * @} + */ diff --git a/tests/drivers/build_all/sensor/CMakeLists.txt b/tests/drivers/build_all/sensor/CMakeLists.txt index 518596a02f78..459749709aef 100644 --- a/tests/drivers/build_all/sensor/CMakeLists.txt +++ b/tests/drivers/build_all/sensor/CMakeLists.txt @@ -4,5 +4,6 @@ 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}) +# Exclude main when running the generic test because ztest supplies its own +target_sources_ifndef(CONFIG_GENERIC_SENSOR_TEST app PRIVATE src/main.c) +target_sources_ifdef(CONFIG_GENERIC_SENSOR_TEST app PRIVATE src/generic_test.c) diff --git a/tests/drivers/build_all/sensor/Kconfig b/tests/drivers/build_all/sensor/Kconfig new file mode 100644 index 000000000000..10730a1f50b8 --- /dev/null +++ b/tests/drivers/build_all/sensor/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config GENERIC_SENSOR_TEST + bool "Compile and run the generic sensor tests" + depends on ZTEST && ZTEST_NEW_API + help + Enables building and running the generic sensor test suite that will + iterate through the device tree and run sample path tests on any + sensor that supports the backend sensor emulator API. + +config GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS + int "Number of expected values to use in test" + default 5 + depends on GENERIC_SENSOR_TEST + help + Controls the number of expected values to use in the generic sensor + test, interpolated from the sensor's reported lower and upper sample + range boundaries. The test will run one iteration for each expected + value. For example, if GENERIC_TEST_NUM_EXPECTED_VALS == 5, and the + sensor range is 0..100, the test will run 5 times with expected values + 0, 25, 50, 75, and 100. These iterations are run in parallel. + +source "Kconfig.zephyr" diff --git a/tests/drivers/build_all/sensor/src/generic_test.c b/tests/drivers/build_all/sensor/src/generic_test.c new file mode 100644 index 000000000000..0df8b953da99 --- /dev/null +++ b/tests/drivers/build_all/sensor/src/generic_test.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(generic_test); + +/* + * Set up an RTIO context that can be shared for all sensors + */ + +static enum sensor_channel iodev_all_channels[SENSOR_CHAN_ALL]; +static struct sensor_read_config iodev_read_config = { + .channels = iodev_all_channels, + .max = SENSOR_CHAN_ALL, +}; +RTIO_IODEV_DEFINE(iodev_read, &__sensor_iodev_api, &iodev_read_config); + +/* Create the RTIO context to service the reading */ +RTIO_DEFINE_WITH_MEMPOOL(sensor_read_rtio_ctx, 1, 1, 1, 64, 4); + +/** + * @brief Prepare the RTIO context for next test + */ +static void before(void *args) +{ + ARG_UNUSED(args); + + /* Clear the array of requested channels */ + memset(iodev_all_channels, 0, sizeof(iodev_all_channels)); + + /* Reset the channel count */ + iodev_read_config.count = 0; + + /* Remove previous sensor pointer */ + iodev_read_config.sensor = NULL; + + /* Wipe the mempool by marking every block free */ + zassert_ok(sys_bitarray_clear_region(sensor_read_rtio_ctx_block_pool.mempool->bitmap, + sensor_read_rtio_ctx_block_pool.mempool->num_blocks, + 0)); + + /* Flush the SQ and CQ */ + rtio_sqe_drop_all(&sensor_read_rtio_ctx); + while (rtio_cqe_consume(&sensor_read_rtio_ctx)) + ; +} + +/** + * @brief Helper function the carries out the generic sensor test for a given sensor device. + * Verifies that the device has a suitable emulator that implements the backend API and + * skips the test gracefully if not. + */ +static void run_generic_test(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 loaded. */ + if (!emul) { + ztest_test_skip(); + } + + /* Also skip if this emulator does not implement the backend API. */ + if (!emul_sensor_backend_is_supported(emul)) { + ztest_test_skip(); + } + + /* + * Begin the actual test sequence + */ + + static struct { + bool supported; + bool received; + q31_t expected_values[CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS]; + q31_t epsilon; + int8_t expected_value_shift; + } channel_table[SENSOR_CHAN_ALL]; + + memset(channel_table, 0, sizeof(channel_table)); + + /* Discover supported channels on this device and fill out our sensor read request */ + for (enum sensor_channel ch = 0; ch < ARRAY_SIZE(channel_table); ch++) { + if (SENSOR_CHANNEL_3_AXIS(ch)) { + continue; + } + + q31_t lower, upper; + int8_t shift; + + if (emul_sensor_backend_get_sample_range(emul, ch, &lower, &upper, + &channel_table[ch].epsilon, &shift) == 0) { + /* This channel is supported */ + channel_table[ch].supported = true; + + LOG_INF("CH %d: lower=%d, upper=%d, eps=%d, shift=%d", ch, lower, upper, + channel_table[ch].epsilon, shift); + + /* Add to the list of channels to read */ + iodev_all_channels[iodev_read_config.count++] = ch; + + /* Generate a set of CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS test + * values. + */ + + channel_table[ch].expected_value_shift = shift; + for (size_t i = 0; i < CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS; i++) { + channel_table[ch].expected_values[i] = + lower + + (i * ((int64_t)upper - lower) / + (CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS - 1)); + LOG_INF("CH %d: Expected value %d/%d: %d", ch, i + 1, + CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS, + channel_table[ch].expected_values[i]); + } + } + } + iodev_read_config.sensor = dev; + + /* Do a read of all channels for quantity CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS + * iterations. + */ + + for (size_t iteration = 0; iteration < CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS; + iteration++) { + int rv; + + /* Reset received flag */ + for (size_t i = 0; i < ARRAY_SIZE(channel_table); i++) { + channel_table[i].received = false; + } + + /* Set this iteration's expected values in emul for every supported channel */ + for (size_t i = 0; i < iodev_read_config.count; i++) { + enum sensor_channel ch = iodev_all_channels[i]; + + rv = emul_sensor_backend_set_channel( + emul, ch, channel_table[ch].expected_values[iteration], + channel_table[ch].expected_value_shift); + zassert_ok( + rv, + "Cannot set value 0x%08x on channel %d (error %d, iteration %d/%d)", + channel_table[i].expected_values[iteration], ch, rv, iteration + 1, + CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS); + } + + /* Perform the actual sensor read */ + rv = sensor_read(&iodev_read, &sensor_read_rtio_ctx, NULL); + zassert_ok(rv, "Could not read sensor (error %d, iteration %d/%d)", rv, + iteration + 1, CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS); + + /* Wait for a CQE */ + struct rtio_cqe *cqe = rtio_cqe_consume_block(&sensor_read_rtio_ctx); + + zassert_ok(cqe->result, "CQE has failed status (error %d, iteration %d/%d)", + cqe->result, iteration + 1, + CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS); + + uint8_t *buf = NULL; + uint32_t buf_len = 0; + + /* Cache the data from the CQE */ + rtio_cqe_get_mempool_buffer(&sensor_read_rtio_ctx, cqe, &buf, &buf_len); + + /* Release the CQE */ + rtio_cqe_release(&sensor_read_rtio_ctx, cqe); + + enum sensor_channel channel; + sensor_frame_iterator_t fit = {0}; + sensor_channel_iterator_t cit = {0}; + const struct sensor_decoder_api *decoder; + int8_t shift; + q31_t q; + + zassert_ok(sensor_get_decoder(dev, &decoder)); + + /* Decode the buffer and verify all channels */ + while (decoder->decode(buf, &fit, &cit, &channel, &q, 1) > 0) { + zassert_true(channel_table[channel].supported); + zassert_false(channel_table[channel].received); + channel_table[channel].received = true; + + zassert_ok(decoder->get_shift(buf, channel, &shift)); + + /* Align everything to be a 64-bit Q32.32 number for comparison */ + int64_t expected_shifted = + (int64_t)channel_table[channel].expected_values[iteration] + << channel_table[channel].expected_value_shift; + int64_t actual_shifted = (int64_t)q << shift; + int64_t epsilon_shifted = (int64_t)channel_table[channel].epsilon + << channel_table[channel].expected_value_shift; + + zassert_within(expected_shifted, actual_shifted, epsilon_shifted, + "Expected %lld, got %lld (shift %d, ch %d, iteration %d/%d, " + "Error %lld, Epsilon %lld)", + expected_shifted, actual_shifted, shift, channel, + iteration + 1, CONFIG_GENERIC_SENSOR_TEST_NUM_EXPECTED_VALS, + expected_shifted - actual_shifted, epsilon_shifted); + } + + /* Release the memory */ + rtio_release_buffer(&sensor_read_rtio_ctx, buf, buf_len); + + /* Ensure all supported channels were received */ + int missing_channel_count = 0; + + for (size_t i = 0; i < ARRAY_SIZE(channel_table); i++) { + if (channel_table[i].supported && !channel_table[i].received) { + missing_channel_count++; + } + } + + zassert_equal(0, missing_channel_count); + } +} + +#define DECLARE_ZTEST_PER_DEVICE(n) \ + ZTEST(generic, test_##n) \ + { \ + run_generic_test(DEVICE_DT_GET(n)); \ + } + +/* Iterate through each of the emulated buses and create a test for each device. */ +DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(test_i2c), DECLARE_ZTEST_PER_DEVICE) +DT_FOREACH_CHILD_STATUS_OKAY(DT_NODELABEL(test_spi), DECLARE_ZTEST_PER_DEVICE) + +ZTEST_SUITE(generic, NULL, NULL, before, NULL, NULL); diff --git a/tests/drivers/build_all/sensor/testcase.yaml b/tests/drivers/build_all/sensor/testcase.yaml index e94945e3cebd..53ee3ac85836 100644 --- a/tests/drivers/build_all/sensor/testcase.yaml +++ b/tests/drivers/build_all/sensor/testcase.yaml @@ -19,3 +19,12 @@ tests: extra_configs: - CONFIG_PM=y - CONFIG_PM_DEVICE=y + sensors.generic_test: + extra_configs: + - CONFIG_GENERIC_SENSOR_TEST=y + - CONFIG_ZTEST=y + - CONFIG_ZTEST_NEW_API=y + - CONFIG_EMUL=y + - CONFIG_NATIVE_UART_0_ON_STDINOUT=y + - CONFIG_SENSOR_ASYNC_API=y + build_only: false From 445f9d28c43723d22bc8354236e1764e6244a222 Mon Sep 17 00:00:00 2001 From: Dong Wang Date: Fri, 31 Mar 2023 12:57:56 -0500 Subject: [PATCH 1949/2042] boards: x86: Add boards and SoCs for Intel ISH Adds new boards and SoCs for the Intel Sensor Hub (ISH). Signed-off-by: Dong Wang --- boards/x86/intel_ish/Kconfig.board | 16 +++ boards/x86/intel_ish/Kconfig.defconfig | 25 +++++ boards/x86/intel_ish/doc/index.rst | 78 ++++++++++++++ boards/x86/intel_ish/intel_ish_5_4_1.dts | 20 ++++ boards/x86/intel_ish/intel_ish_5_4_1.yaml | 13 +++ .../x86/intel_ish/intel_ish_5_4_1_defconfig | 15 +++ boards/x86/intel_ish/intel_ish_5_6_0.dts | 20 ++++ boards/x86/intel_ish/intel_ish_5_6_0.yaml | 13 +++ .../x86/intel_ish/intel_ish_5_6_0_defconfig | 15 +++ boards/x86/intel_ish/intel_ish_5_8_0.dts | 20 ++++ boards/x86/intel_ish/intel_ish_5_8_0.yaml | 13 +++ .../x86/intel_ish/intel_ish_5_8_0_defconfig | 15 +++ dts/bindings/cpu/intel,ish.yaml | 9 ++ dts/x86/intel/intel_ish5.dtsi | 62 +++++++++++ dts/x86/intel/intel_ish5_8.dtsi | 19 ++++ soc/x86/intel_ish/CMakeLists.txt | 7 ++ soc/x86/intel_ish/Kconfig | 13 +++ soc/x86/intel_ish/Kconfig.defconfig | 30 ++++++ soc/x86/intel_ish/Kconfig.soc | 8 ++ soc/x86/intel_ish/doc/supported_features.txt | 7 ++ soc/x86/intel_ish/intel_ish5/CMakeLists.txt | 10 ++ .../intel_ish5/Kconfig.defconfig.series | 18 ++++ soc/x86/intel_ish/intel_ish5/Kconfig.series | 8 ++ soc/x86/intel_ish/intel_ish5/Kconfig.soc | 19 ++++ soc/x86/intel_ish/intel_ish5/linker.ld | 8 ++ soc/x86/intel_ish/intel_ish5/soc.c | 23 ++++ soc/x86/intel_ish/intel_ish5/soc.h | 40 +++++++ .../intel_ish/utils/build_ish_firmware.cmake | 10 ++ soc/x86/intel_ish/utils/build_ish_firmware.py | 102 ++++++++++++++++++ 29 files changed, 656 insertions(+) create mode 100644 boards/x86/intel_ish/Kconfig.board create mode 100644 boards/x86/intel_ish/Kconfig.defconfig create mode 100644 boards/x86/intel_ish/doc/index.rst create mode 100644 boards/x86/intel_ish/intel_ish_5_4_1.dts create mode 100644 boards/x86/intel_ish/intel_ish_5_4_1.yaml create mode 100644 boards/x86/intel_ish/intel_ish_5_4_1_defconfig create mode 100644 boards/x86/intel_ish/intel_ish_5_6_0.dts create mode 100644 boards/x86/intel_ish/intel_ish_5_6_0.yaml create mode 100644 boards/x86/intel_ish/intel_ish_5_6_0_defconfig create mode 100644 boards/x86/intel_ish/intel_ish_5_8_0.dts create mode 100644 boards/x86/intel_ish/intel_ish_5_8_0.yaml create mode 100644 boards/x86/intel_ish/intel_ish_5_8_0_defconfig create mode 100644 dts/bindings/cpu/intel,ish.yaml create mode 100644 dts/x86/intel/intel_ish5.dtsi create mode 100644 dts/x86/intel/intel_ish5_8.dtsi create mode 100644 soc/x86/intel_ish/CMakeLists.txt create mode 100644 soc/x86/intel_ish/Kconfig create mode 100644 soc/x86/intel_ish/Kconfig.defconfig create mode 100644 soc/x86/intel_ish/Kconfig.soc create mode 100644 soc/x86/intel_ish/doc/supported_features.txt create mode 100644 soc/x86/intel_ish/intel_ish5/CMakeLists.txt create mode 100644 soc/x86/intel_ish/intel_ish5/Kconfig.defconfig.series create mode 100644 soc/x86/intel_ish/intel_ish5/Kconfig.series create mode 100644 soc/x86/intel_ish/intel_ish5/Kconfig.soc create mode 100644 soc/x86/intel_ish/intel_ish5/linker.ld create mode 100644 soc/x86/intel_ish/intel_ish5/soc.c create mode 100644 soc/x86/intel_ish/intel_ish5/soc.h create mode 100644 soc/x86/intel_ish/utils/build_ish_firmware.cmake create mode 100644 soc/x86/intel_ish/utils/build_ish_firmware.py diff --git a/boards/x86/intel_ish/Kconfig.board b/boards/x86/intel_ish/Kconfig.board new file mode 100644 index 000000000000..77962495a12e --- /dev/null +++ b/boards/x86/intel_ish/Kconfig.board @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BOARD_INTEL_ISH_5_4_1 + bool "Intel ISH 5.4.1 board" + depends on SOC_INTEL_ISH_5_4_1 + +config BOARD_INTEL_ISH_5_6_0 + bool "Intel ISH 5.6.0 board" + depends on SOC_INTEL_ISH_5_6_0 + +config BOARD_INTEL_ISH_5_8_0 + bool "Intel ISH 5.8.0 board" + depends on SOC_INTEL_ISH_5_8_0 diff --git a/boards/x86/intel_ish/Kconfig.defconfig b/boards/x86/intel_ish/Kconfig.defconfig new file mode 100644 index 000000000000..f989dfcd6ed3 --- /dev/null +++ b/boards/x86/intel_ish/Kconfig.defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +if BOARD_INTEL_ISH_5_4_1 || BOARD_INTEL_ISH_5_6_0 || BOARD_INTEL_ISH_5_8_0 + +config BOARD + default "intel_ish_5_4_1" if BOARD_INTEL_ISH_5_4_1 + default "intel_ish_5_6_0" if BOARD_INTEL_ISH_5_6_0 + default "intel_ish_5_8_0" if BOARD_INTEL_ISH_5_8_0 + +if TEST +config TEST_EXTRA_STACK_SIZE + int + default 1024 +endif # TEST + +config HPET_TIMER + default y + +config SYS_CLOCK_TICKS_PER_SEC + default 2048 if HPET_TIMER # HPET is 32768 HZ + +endif # BOARD_INTEL_ISH_5_4_1 || BOARD_INTEL_ISH_5_6_0 || BOARD_INTEL_ISH_5_8_0 diff --git a/boards/x86/intel_ish/doc/index.rst b/boards/x86/intel_ish/doc/index.rst new file mode 100644 index 000000000000..2f621483f1c9 --- /dev/null +++ b/boards/x86/intel_ish/doc/index.rst @@ -0,0 +1,78 @@ +.. _intel_ish: + +Intel Integrated Sensor Hub (ISH) +################################# + +Overview +******** +Intel Integrated Sensor Hub (ISH) is a lower-power/always-on co-processor +inside many Intel Processors. It helps offload sensor processing tasks from +the core processor for better power saving. + +Hardware +******** + +- LMT MinuteIA Core, with + . 16KB instruction cache and 16KB data cache. + . 640KB SRAM space for code and data - implemented as L2 SRAM. + . 8KB AON RF space for code resident during deep D0i2/3 PG states. +- Interface-to-Sensor peripherals (I2C, SPI, UART, I3C, GPIO, DMA). +- Inter Process Communications (IPC) to core processor and other IP processors. + +.. include:: ../../../../soc/x86/intel_ish/doc/supported_features.txt + +Programming and Debugging +************************* +Use the following procedures for booting an ISH image on a ADL RVP board +for Chrome. + +.. contents:: + :depth: 1 + :local: + :backlinks: top + +Build Zephyr application +======================== + +#. Build a Zephyr application; for instance, to build the ``hello_world`` + application for ISH 5.4.1 on Intel ADL Processor: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: intel_ish_5_4_1 + :goals: build + + .. note:: + + A Zephyr image file named :file:`ish_fw.bin` is automatically + created in the build directory after the application is built. + +Run ish_fw.bin on ADL RVP board for Chrome +========================================== + +# Power on the ADL RVP board. + +# Log in Chrome OS. (Note: the user must have root access right.) + +# Re-mount the root filesystem as read-write: + + .. code-block:: console + + $ mount -o remount,rw / + + If re-mount fails, execute below commands to Remove rootfs verification: + + .. code-block:: console + + $ /usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification --partitions + $ reboot + +# Go to the ISH firmware direcoty: + + .. code-block:: console + + $ cd /lib/firmware/intel + + Relace the file adlrvp_ish.bin with zephyr image built out, ish_fw.bin. + +# Reboot, then observe zephyr log output via ISH UART0. diff --git a/boards/x86/intel_ish/intel_ish_5_4_1.dts b/boards/x86/intel_ish/intel_ish_5_4_1.dts new file mode 100644 index 000000000000..04479034cf41 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_4_1.dts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "intel/intel_ish5.dtsi" + +/ { + model = "intel_ish_5_4_1"; + compatible = "intel,ish_5_4_1"; + + chosen { + zephyr,sram = &sram; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; diff --git a/boards/x86/intel_ish/intel_ish_5_4_1.yaml b/boards/x86/intel_ish/intel_ish_5_4_1.yaml new file mode 100644 index 000000000000..a04b3c0e5d0b --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_4_1.yaml @@ -0,0 +1,13 @@ +identifier: intel_ish_5_4_1 +name: Intel ISH 5.4.1 SoC +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 640 +supported: + - serial +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/x86/intel_ish/intel_ish_5_4_1_defconfig b/boards/x86/intel_ish/intel_ish_5_4_1_defconfig new file mode 100644 index 000000000000..527466ad337b --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_4_1_defconfig @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_FAMILY_INTEL_ISH=y +CONFIG_SOC_SERIES_INTEL_ISH5=y +CONFIG_SOC_INTEL_ISH_5_4_1=y +CONFIG_BOARD_INTEL_ISH_5_4_1=y + +# uart & console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y diff --git a/boards/x86/intel_ish/intel_ish_5_6_0.dts b/boards/x86/intel_ish/intel_ish_5_6_0.dts new file mode 100644 index 000000000000..431180843de6 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_6_0.dts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "intel/intel_ish5.dtsi" + +/ { + model = "intel_ish_5_6_0"; + compatible = "intel,ish_5_6_0"; + + chosen { + zephyr,sram = &sram; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; diff --git a/boards/x86/intel_ish/intel_ish_5_6_0.yaml b/boards/x86/intel_ish/intel_ish_5_6_0.yaml new file mode 100644 index 000000000000..42044c0d14cd --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_6_0.yaml @@ -0,0 +1,13 @@ +identifier: intel_ish_5_6_0 +name: Intel ISH 5.6.0 SoC +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 640 +supported: + - serial +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/x86/intel_ish/intel_ish_5_6_0_defconfig b/boards/x86/intel_ish/intel_ish_5_6_0_defconfig new file mode 100644 index 000000000000..74b00676d399 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_6_0_defconfig @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_FAMILY_INTEL_ISH=y +CONFIG_SOC_SERIES_INTEL_ISH5=y +CONFIG_SOC_INTEL_ISH_5_6_0=y +CONFIG_BOARD_INTEL_ISH_5_6_0=y + +# uart & console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y diff --git a/boards/x86/intel_ish/intel_ish_5_8_0.dts b/boards/x86/intel_ish/intel_ish_5_8_0.dts new file mode 100644 index 000000000000..34c5ef2f7336 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_8_0.dts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include "intel/intel_ish5_8.dtsi" + +/ { + model = "intel_ish_5_8_0"; + compatible = "intel,ish_5_8_0"; + + chosen { + zephyr,sram = &sram; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; diff --git a/boards/x86/intel_ish/intel_ish_5_8_0.yaml b/boards/x86/intel_ish/intel_ish_5_8_0.yaml new file mode 100644 index 000000000000..e750d236d064 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_8_0.yaml @@ -0,0 +1,13 @@ +identifier: intel_ish_5_8_0 +name: Intel ISH 5.8.0 SoC +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 640 +supported: + - serial +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/x86/intel_ish/intel_ish_5_8_0_defconfig b/boards/x86/intel_ish/intel_ish_5_8_0_defconfig new file mode 100644 index 000000000000..ee319557f761 --- /dev/null +++ b/boards/x86/intel_ish/intel_ish_5_8_0_defconfig @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_SOC_FAMILY_INTEL_ISH=y +CONFIG_SOC_SERIES_INTEL_ISH5=y +CONFIG_SOC_INTEL_ISH_5_8_0=y +CONFIG_BOARD_INTEL_ISH_5_8_0=y + +# uart & console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y diff --git a/dts/bindings/cpu/intel,ish.yaml b/dts/bindings/cpu/intel,ish.yaml new file mode 100644 index 000000000000..10ac4b2eeb9d --- /dev/null +++ b/dts/bindings/cpu/intel,ish.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: INTEL ISH CPU + +compatible: "intel,ish" + +include: cpu.yaml diff --git a/dts/x86/intel/intel_ish5.dtsi b/dts/x86/intel/intel_ish5.dtsi new file mode 100644 index 000000000000..0a4720a5f346 --- /dev/null +++ b/dts/x86/intel/intel_ish5.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" +#include +#include + +/ { + chosen { + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu0@0 { + device_type = "cpu"; + compatible = "intel,ish"; + reg = <0>; + }; + }; + + intc: ioapic@fec00000 { + compatible = "intel,ioapic"; + reg = <0xfec00000 0x100000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + sram: memory@ff200000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0xff200000 DT_SIZE_K(640)>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + hpet: hpet@4700000{ + compatible = "intel,hpet"; + reg = <0x04700000 0x400>; + interrupt-parent = <&intc>; + interrupts = <14 IRQ_TYPE_FIXED_LEVEL_HIGH 2>; + status = "okay"; + }; + + uart0: uart@8100000 { + compatible = "intel,sedi-uart"; + reg = <0x08100000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <23 IRQ_TYPE_LOWEST_EDGE_RISING 6>; + current-speed = <115200>; + status = "okay"; + }; + }; +}; diff --git a/dts/x86/intel/intel_ish5_8.dtsi b/dts/x86/intel/intel_ish5_8.dtsi new file mode 100644 index 000000000000..fb22f65d1754 --- /dev/null +++ b/dts/x86/intel/intel_ish5_8.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&hpet { + interrupts = <17 IRQ_TYPE_FIXED_LEVEL_HIGH 2>; + + status = "okay"; +}; + +&uart0 { + interrupts = <28 IRQ_TYPE_LOWEST_EDGE_RISING 6>; + + status = "okay"; +}; diff --git a/soc/x86/intel_ish/CMakeLists.txt b/soc/x86/intel_ish/CMakeLists.txt new file mode 100644 index 000000000000..667c8ac97e4c --- /dev/null +++ b/soc/x86/intel_ish/CMakeLists.txt @@ -0,0 +1,7 @@ +# Intel ISH SoC family +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/x86/intel_ish/Kconfig b/soc/x86/intel_ish/Kconfig new file mode 100644 index 000000000000..2f0183490a3f --- /dev/null +++ b/soc/x86/intel_ish/Kconfig @@ -0,0 +1,13 @@ +# Intel ISH family configuration options +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_INTEL_ISH + bool "Intel ISH SoC family" + select X86 + select X86_NO_SPECULATIVE_VULNERABILITIES + select IOAPIC + select LOAPIC + select CPU_HAS_FPU diff --git a/soc/x86/intel_ish/Kconfig.defconfig b/soc/x86/intel_ish/Kconfig.defconfig new file mode 100644 index 000000000000..adcca64b9a80 --- /dev/null +++ b/soc/x86/intel_ish/Kconfig.defconfig @@ -0,0 +1,30 @@ +# Intel ISH family default configuration options +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_INTEL_ISH + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 if HPET_TIMER + +config SOC_FAMILY + string + default "intel_ish" + +config X86_VERY_EARLY_CONSOLE + default n + +config SRAM_OFFSET + hex + default 0x0 + +# Target platforms are not PC-compatible +# (e.g. without BIOS, ACPI, CMOS, etc.). +config X86_PC_COMPATIBLE + default n + +endif # SOC_FAMILY_INTEL_ISH + +rsource "*/Kconfig.defconfig.series" diff --git a/soc/x86/intel_ish/Kconfig.soc b/soc/x86/intel_ish/Kconfig.soc new file mode 100644 index 000000000000..b4b1e1456b93 --- /dev/null +++ b/soc/x86/intel_ish/Kconfig.soc @@ -0,0 +1,8 @@ +# Intel ISH family selection +# +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +rsource "*/Kconfig.series" +rsource "*/Kconfig.soc" diff --git a/soc/x86/intel_ish/doc/supported_features.txt b/soc/x86/intel_ish/doc/supported_features.txt new file mode 100644 index 000000000000..41d34a732b8c --- /dev/null +++ b/soc/x86/intel_ish/doc/supported_features.txt @@ -0,0 +1,7 @@ +Supported Features +================== + +In addition to the standard architecture devices (HPET, local and I/O APICs, +etc.), Zephyr supports the following ISH-specific SoC devices: + +* HSUART diff --git a/soc/x86/intel_ish/intel_ish5/CMakeLists.txt b/soc/x86/intel_ish/intel_ish5/CMakeLists.txt new file mode 100644 index 000000000000..ee4d915f9b19 --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_cc_option(-march=pentium -mtune=i486) + +zephyr_sources(soc.c) + +include(../utils/build_ish_firmware.cmake) diff --git a/soc/x86/intel_ish/intel_ish5/Kconfig.defconfig.series b/soc/x86/intel_ish/intel_ish5/Kconfig.defconfig.series new file mode 100644 index 000000000000..a7865f8fd939 --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/Kconfig.defconfig.series @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +if SOC_SERIES_INTEL_ISH5 + +config SOC_SERIES + string + default "intel_ish5" + +config SOC + string + default "intel_ish_5_4_1" if SOC_INTEL_ISH_5_4_1 + default "intel_ish_5_6_0" if SOC_INTEL_ISH_5_6_0 + default "intel_ish_5_8_0" if SOC_INTEL_ISH_5_8_0 + +endif # SOC_SERIES_INTEL_ISH5 diff --git a/soc/x86/intel_ish/intel_ish5/Kconfig.series b/soc/x86/intel_ish/intel_ish5/Kconfig.series new file mode 100644 index 000000000000..ef39ee29c20a --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/Kconfig.series @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config SOC_SERIES_INTEL_ISH5 + bool "Intel ISH5 SoC" + select SOC_FAMILY_INTEL_ISH diff --git a/soc/x86/intel_ish/intel_ish5/Kconfig.soc b/soc/x86/intel_ish/intel_ish5/Kconfig.soc new file mode 100644 index 000000000000..bbc4a76fdae4 --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/Kconfig.soc @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +choice + prompt "Intel ISH5 SoCs" + depends on SOC_SERIES_INTEL_ISH5 + +config SOC_INTEL_ISH_5_4_1 + bool "Intel ISH 5.4.1 SoC" + +config SOC_INTEL_ISH_5_6_0 + bool "Intel ISH 5.6.0 SoC" + +config SOC_INTEL_ISH_5_8_0 + bool "Intel ISH 5.8.0 SoC" + +endchoice diff --git a/soc/x86/intel_ish/intel_ish5/linker.ld b/soc/x86/intel_ish/intel_ish5/linker.ld new file mode 100644 index 000000000000..0795cf8a6f50 --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/linker.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include diff --git a/soc/x86/intel_ish/intel_ish5/soc.c b/soc/x86/intel_ish/intel_ish5/soc.c new file mode 100644 index 000000000000..ccf044824a7f --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/soc.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc.h" + +#if defined(CONFIG_HPET_TIMER) +#include "sedi_driver_hpet.h" +#endif + +static int intel_ish_init(void) +{ +#if defined(CONFIG_HPET_TIMER) + sedi_hpet_set_min_delay(HPET_CMP_MIN_DELAY); +#endif + + return 0; +} + +SYS_INIT(intel_ish_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/x86/intel_ish/intel_ish5/soc.h b/soc/x86/intel_ish/intel_ish5/soc.h new file mode 100644 index 000000000000..69528a74b688 --- /dev/null +++ b/soc/x86/intel_ish/intel_ish5/soc.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SOC_H_ +#define __SOC_H_ + +#include + +#ifndef _ASMLANGUAGE +#include +#include + +#ifdef CONFIG_HPET_TIMER +#include "sedi_driver_hpet.h" + +#define HPET_USE_CUSTOM_REG_ACCESS_FUNCS + +/* COUNTER_CLK_PERIOD (CLK_PERIOD_REG) is in picoseconds (1e-12 sec) */ +#define HPET_COUNTER_CLK_PERIOD (1000000000000ULL) + +#define HPET_CMP_MIN_DELAY (5) + +__pinned_func +static inline void hpet_timer_comparator_set(uint64_t next) +{ + sedi_hpet_set_comparator(HPET_0, next); +} + +#endif /*CONFIG_HPET_TIMER */ + +#endif /* !_ASMLANGUAGE */ + +/* ISH specific DMA channel direction */ +#define IMR_TO_MEMORY (DMA_CHANNEL_DIRECTION_PRIV_START) +#define MEMORY_TO_IMR (DMA_CHANNEL_DIRECTION_PRIV_START + 1) + +#endif /* __SOC_H_ */ diff --git a/soc/x86/intel_ish/utils/build_ish_firmware.cmake b/soc/x86/intel_ish/utils/build_ish_firmware.cmake new file mode 100644 index 000000000000..faaab0c5f5eb --- /dev/null +++ b/soc/x86/intel_ish/utils/build_ish_firmware.cmake @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/build_ish_firmware.py + ARGS -k ${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.bin + -o ${PROJECT_BINARY_DIR}/ish_fw.bin +) diff --git a/soc/x86/intel_ish/utils/build_ish_firmware.py b/soc/x86/intel_ish/utils/build_ish_firmware.py new file mode 100644 index 000000000000..3db3909e66f1 --- /dev/null +++ b/soc/x86/intel_ish/utils/build_ish_firmware.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*-" + +# Copyright 2019 The Chromium OS Authors. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Script to pack EC binary with manifest header. + +Package ecos main FW binary (kernel) and AON task binary into final EC binary +image with a manifest header, ISH shim loader will parse this header and load +each binaries into right memory location. +""" + +import argparse +import struct +import os + +MANIFEST_ENTRY_SIZE = 0x80 +HEADER_SIZE = 0x1000 +PAGE_SIZE = 0x1000 + +def parseargs(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("-k", "--kernel", + help="EC kernel binary to pack, \ + usually ec.RW.bin or ec.RW.flat.", + required=True) + parser.add_argument("-a", "--aon", + help="EC aontask binary to pack, \ + usually ish_aontask.bin.", + required=False) + parser.add_argument("-o", "--output", + help="Output flash binary file") + + return parser.parse_args() + +def gen_manifest(ext_id, comp_app_name, code_offset, module_size): + """Returns a binary blob that represents a manifest entry""" + m = bytearray(MANIFEST_ENTRY_SIZE) + + # 4 bytes of ASCII encode ID (little endian) + struct.pack_into('<4s', m, 0, ext_id) + # 8 bytes of ASCII encode ID (little endian) + struct.pack_into('<8s', m, 32, comp_app_name) + # 4 bytes of code offset (little endian) + struct.pack_into(' 0) + +def main(): + args = parseargs() + print(" Packing EC image file for ISH") + + with open(args.output, 'wb') as f: + kernel_size = os.path.getsize(args.kernel) + + if args.aon is not None: + aon_size = os.path.getsize(args.aon) + + print(" kernel binary size:", kernel_size) + kern_rdup_pg_size = roundup_page(kernel_size) + # Add manifest for main ISH binary + f.write(gen_manifest(b'ISHM', b'ISH_KERN', HEADER_SIZE, kern_rdup_pg_size)) + + if args.aon is not None: + print(" AON binary size: ", aon_size) + aon_rdup_pg_size = roundup_page(aon_size) + # Add manifest for aontask binary + f.write(gen_manifest(b'ISHM', b'AON_TASK', + (HEADER_SIZE + kern_rdup_pg_size * PAGE_SIZE - + MANIFEST_ENTRY_SIZE), aon_rdup_pg_size)) + + # Add manifest that signals end of manifests + f.write(gen_manifest(b'ISHE', b'', 0, 0)) + + # Pad the remaining HEADER with 0s + if args.aon is not None: + f.write(b'\x00' * (HEADER_SIZE - (MANIFEST_ENTRY_SIZE * 3))) + else: + f.write(b'\x00' * (HEADER_SIZE - (MANIFEST_ENTRY_SIZE * 2))) + + # Append original kernel image + with open(args.kernel, 'rb') as in_file: + f.write(in_file.read()) + # Filling padings due to size round up as pages + f.write(b'\x00' * (kern_rdup_pg_size * PAGE_SIZE - kernel_size)) + + if args.aon is not None: + # Append original aon image + with open(args.aon, 'rb') as in_file: + f.write(in_file.read()) + # Filling padings due to size round up as pages + f.write(b'\x00' * (aon_rdup_pg_size * PAGE_SIZE - aon_size)) + +if __name__ == '__main__': + main() From fb03964a2651162808b8b7c6ba1fca4c2287e9ea Mon Sep 17 00:00:00 2001 From: Dong Wang Date: Mon, 17 Jul 2023 16:32:35 +0800 Subject: [PATCH 1950/2042] manifest: west.yml: add Intel HAL as a new HAL module It provides a low level Hardware Abstraction Layer for Intel specific hardware, like Intel ISH Signed-off-by: Dong Wang --- west.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/west.yml b/west.yml index c7545d6a7fbe..1485e3ade818 100644 --- a/west.yml +++ b/west.yml @@ -167,6 +167,11 @@ manifest: path: modules/hal/infineon groups: - hal + - name: hal_intel + revision: 89a0db5d9155484624447d62a5211bcf6f6f0387 + path: modules/hal/intel + groups: + - hal - name: hal_microchip revision: 5d079f1683a00b801373bbbbf5d181d4e33b30d5 path: modules/hal/microchip From 4e3ec6207d779f111bf1fd8cd4a37ba4558ecef2 Mon Sep 17 00:00:00 2001 From: Dong Wang Date: Thu, 1 Jun 2023 15:55:43 +0800 Subject: [PATCH 1951/2042] ish: add module Kconfig for Intel HAL Add a new Kconfig option to enable the build of Intel HAL and select it always for ish SoCs Signed-off-by: Dong Wang --- modules/Kconfig | 1 + modules/Kconfig.intel | 8 ++++++++ soc/x86/intel_ish/Kconfig | 1 + 3 files changed, 10 insertions(+) create mode 100644 modules/Kconfig.intel diff --git a/modules/Kconfig b/modules/Kconfig index f35dfdcbd486..8f5a9b55d781 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -45,6 +45,7 @@ source "modules/Kconfig.wurthelektronik" source "modules/Kconfig.xtensa" source "modules/zcbor/Kconfig" source "modules/Kconfig.mcuboot" +source "modules/Kconfig.intel" comment "Unavailable modules, please install those via the project manifest." diff --git a/modules/Kconfig.intel b/modules/Kconfig.intel new file mode 100644 index 000000000000..7ce9101497d9 --- /dev/null +++ b/modules/Kconfig.intel @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config INTEL_HAL + bool + help + Build the Intel HAL module during build process. + This is selected by the ARCH kconfig automatically. diff --git a/soc/x86/intel_ish/Kconfig b/soc/x86/intel_ish/Kconfig index 2f0183490a3f..9c13acba9d55 100644 --- a/soc/x86/intel_ish/Kconfig +++ b/soc/x86/intel_ish/Kconfig @@ -11,3 +11,4 @@ config SOC_FAMILY_INTEL_ISH select IOAPIC select LOAPIC select CPU_HAS_FPU + select INTEL_HAL From 9f6d6a0fa79db075108f69c8499c18d2ad3b5040 Mon Sep 17 00:00:00 2001 From: Nachiketa Kumar Date: Mon, 3 Apr 2023 12:49:42 -0500 Subject: [PATCH 1952/2042] drivers: serial: Add Intel SEDI driver Adds a new serial shim driver for Intel SoCs. Builds upon the SEDI bare metal UART driver in the hal-intel module. Signed-off-by: Nachiketa Kumar Signed-off-by: Dong Wang --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 2 + drivers/serial/Kconfig.sedi | 15 + drivers/serial/uart_sedi.c | 597 +++++++++++++++++++++++ dts/bindings/serial/intel,sedi-uart.yaml | 16 + 5 files changed, 631 insertions(+) create mode 100644 drivers/serial/Kconfig.sedi create mode 100644 drivers/serial/uart_sedi.c create mode 100644 dts/bindings/serial/intel,sedi-uart.yaml diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 342fb1fd09cb..de3ec08af8ba 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -63,6 +63,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_HOSTLINK uart_hostlink.c) zephyr_library_sources_ifdef(CONFIG_UART_EMUL uart_emul.c) zephyr_library_sources_ifdef(CONFIG_UART_NUMAKER uart_numaker.c) 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_USERSPACE uart_handlers.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a803c152919c..39156777336c 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -239,4 +239,6 @@ source "drivers/serial/Kconfig.numaker" source "drivers/serial/Kconfig.efinix_sapphire" +source "drivers/serial/Kconfig.sedi" + endif # SERIAL diff --git a/drivers/serial/Kconfig.sedi b/drivers/serial/Kconfig.sedi new file mode 100644 index 000000000000..4710dfa15c4a --- /dev/null +++ b/drivers/serial/Kconfig.sedi @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config UART_SEDI + bool "Intel SEDI UART driver" + default y + depends on DT_HAS_INTEL_SEDI_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + This option enables the Intel SEDI UART driver. + This driver is simply a shim driver built upon the SEDI + bare metal UART driver in the hal-intel module diff --git a/drivers/serial/uart_sedi.c b/drivers/serial/uart_sedi.c new file mode 100644 index 000000000000..e082f97ce57b --- /dev/null +++ b/drivers/serial/uart_sedi.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include "sedi_driver_uart.h" + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static void uart_sedi_isr(void *arg); +static void uart_sedi_cb(struct device *port); +#endif + +#define DT_DRV_COMPAT intel_sedi_uart + +/* Helper macro to set flow control. */ +#define UART_CONFIG_FLOW_CTRL_SET(n) \ + .hw_fc = DT_INST_PROP(n, hw_flow_control) + +/* Helper macro to set line control. */ +#define UART_CONFIG_LINE_CTRL_SET \ + .line_ctrl = SEDI_UART_LC_8N1 + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +/* UART IRQ handler declaration. */ +#define UART_IRQ_HANDLER_DECL(n) \ + static void irq_config_uart_##n(const struct device *dev) + +/* Setting configuration function. */ +#define UART_CONFIG_IRQ_HANDLER_SET(n) \ + .uart_irq_config_func = irq_config_uart_##n +#define UART_IRQ_HANDLER_DEFINE(n) \ + static void irq_config_uart_##n(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), uart_sedi_isr, \ + DEVICE_DT_GET(DT_NODELABEL(uart##n)), \ + DT_INST_IRQ(n, sense)); \ + irq_enable(DT_INST_IRQN(n)); \ + } +#else /*CONFIG_UART_INTERRUPT_DRIVEN */ +#define UART_IRQ_HANDLER_DECL(n) +#define UART_CONFIG_IRQ_HANDLER_SET(n) (0) + +#define UART_IRQ_HANDLER_DEFINE(n) +#endif /* !CONFIG_UART_INTERRUPT_DRIVEN */ + +/* Device init macro for UART instance. As multiple uart instances follow a + * similar definition of data structures differing only in the instance + * number.This macro makes adding instances simpler. + */ +#define UART_SEDI_DEVICE_INIT(n) \ + UART_IRQ_HANDLER_DECL(n); \ + static K_MUTEX_DEFINE(uart_##n##_mutex); \ + static K_SEM_DEFINE(uart_##n##_tx_sem, 1, 1); \ + static K_SEM_DEFINE(uart_##n##_rx_sem, 1, 1); \ + static K_SEM_DEFINE(uart_##n##_sync_read_sem, 0, 1); \ + static const struct uart_sedi_config_info config_info_##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .instance = SEDI_UART_##n, \ + .baud_rate = DT_INST_PROP(n, current_speed), \ + UART_CONFIG_FLOW_CTRL_SET(n), \ + UART_CONFIG_LINE_CTRL_SET, \ + .mutex = &uart_##n##_mutex, \ + .tx_sem = &uart_##n##_tx_sem, \ + .rx_sem = &uart_##n##_rx_sem, \ + .sync_read_sem = &uart_##n##_sync_read_sem, \ + UART_CONFIG_IRQ_HANDLER_SET(n) \ + }; \ + \ + static struct uart_sedi_drv_data drv_data_##n; \ + PM_DEVICE_DT_DEFINE(DT_NODELABEL(uart##n), \ + uart_sedi_pm_action); \ + DEVICE_DT_DEFINE(DT_NODELABEL(uart##n), \ + &uart_sedi_init, \ + PM_DEVICE_DT_GET(DT_NODELABEL(uart##n)), \ + &drv_data_##n, &config_info_##n, \ + PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, &api); \ + UART_IRQ_HANDLER_DEFINE(n) + + + +/* Convenient macro to get the controller instance. */ +#define GET_CONTROLLER_INSTANCE(dev) \ + (((const struct uart_sedi_config_info *) \ + dev->config)->instance) + +/* Convenient macro to get tx semamphore */ +#define GET_TX_SEM(dev) \ + (((const struct uart_sedi_config_info *) \ + dev->config)->tx_sem) + + +/* Convenient macro to get rx sempahore */ +#define GET_RX_SEM(dev) \ + (((const struct uart_sedi_config_info *) \ + dev->config)->rx_sem) + +/* Convenient macro to get sync_read sempahore */ +#define GET_SYNC_READ_SEM(dev) \ + (((const struct uart_sedi_config_info *) \ + dev->config)->sync_read_sem) + +#define GET_MUTEX(dev) \ + (((const struct uart_sedi_config_info *) \ + dev->config)->mutex) + +struct uart_sedi_config_info { + DEVICE_MMIO_ROM; + /* Specifies the uart instance for configuration. */ + sedi_uart_t instance; + + /* Specifies the baudrate for the uart instance. */ + uint32_t baud_rate; + + /* Specifies the port line contorl settings */ + sedi_uart_lc_t line_ctrl; + + struct k_mutex *mutex; + struct k_sem *tx_sem; + struct k_sem *rx_sem; + struct k_sem *sync_read_sem; + /* Enable / disable hardware flow control for UART. */ + + bool hw_fc; + + /* UART irq configuration function when supporting interrupt + * mode. + */ + uart_irq_config_func_t uart_irq_config_func; +}; + + +static int uart_sedi_init(const struct device *dev); + +struct uart_sedi_drv_data { + DEVICE_MMIO_RAM; + uart_irq_callback_user_data_t user_cb; + void *unsol_rx_usr_cb_param; + uint32_t sync_rx_len; + uint32_t sync_rx_status; + void *user_data; + void *usr_rx_buff; + uint32_t usr_rx_size; + uint8_t iir_cache; + uint8_t busy_count; +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +static void uart_busy_set(const struct device *dev) +{ + + struct uart_sedi_drv_data *context = dev->data; + + context->busy_count++; + + if (context->busy_count == 1) { + pm_device_busy_set(dev); + } +} + +static void uart_busy_clear(const struct device *dev) +{ + + struct uart_sedi_drv_data *context = dev->data; + + context->busy_count--; + + if (context->busy_count == 0) { + pm_device_busy_clear(dev); + } +} +#endif + +#ifdef CONFIG_PM_DEVICE + +#ifndef CONFIG_UART_CONSOLE + +static int uart_suspend_device(const struct device *dev) +{ + const struct uart_sedi_config_info *config = dev->config; + + if (pm_device_is_busy(dev)) { + return -EBUSY; + } + + int ret = sedi_uart_set_power(config->instance, SEDI_POWER_SUSPEND); + + if (ret != SEDI_DRIVER_OK) { + return -EIO; + } + + return 0; +} + +static int uart_resume_device_from_suspend(const struct device *dev) +{ + const struct uart_sedi_config_info *config = dev->config; + int ret; + + ret = sedi_uart_set_power(config->instance, SEDI_POWER_FULL); + if (ret != SEDI_DRIVER_OK) { + return -EIO; + } + + return 0; +} + +static int uart_sedi_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = uart_suspend_device(dev); + break; + case PM_DEVICE_ACTION_RESUME: + ret = uart_resume_device_from_suspend(dev); + break; + + default: + ret = -ENOTSUP; + } + return ret; +} + +#else + +static int uart_sedi_pm_action(const struct device *dev, + enum pm_device_action action) +{ + /* do nothing if using UART print log to avoid clock gating + * pm driver already handled power management for uart. + */ + return 0; +} + +#endif /* CONFIG_UART_CONSOLE */ + +#endif /* CONFIG_PM_DEVICE */ + +static int uart_sedi_poll_in(const struct device *dev, unsigned char *data) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + uint32_t status; + int ret = 0; + + sedi_uart_get_status(instance, (uint32_t *) &status); + + /* In order to check if there is any data to read from UART + * controller we should check if the SEDI_UART_RX_BUSY bit from + * 'status' is not set. This bit is set only if there is any + * pending character to read. + */ + if (!(status & SEDI_UART_RX_BUSY)) { + ret = -1; + } else { + if (sedi_uart_read(instance, data, (uint32_t *)&status)) { + ret = -1; + } + } + return ret; +} + +static void uart_sedi_poll_out(const struct device *dev, + unsigned char data) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_write(instance, data); +} + +#ifdef CONFIG_UART_LINE_CTRL +static int get_xfer_error(int bsp_err) +{ + int err; + + switch (bsp_err) { + case SEDI_DRIVER_OK: + err = 0; + break; + case SEDI_USART_ERROR_CANCELED: + err = -ECANCELED; + break; + case SEDI_DRIVER_ERROR: + err = -EIO; + break; + case SEDI_DRIVER_ERROR_PARAMETER: + err = -EINVAL; + break; + case SEDI_DRIVER_ERROR_UNSUPPORTED: + err = -ENOTSUP; + break; + default: + err = -EFAULT; + } + return err; +} +#endif /* CONFIG_UART_LINE_CTRL */ + +static int uart_sedi_err_check(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + uint32_t status; + int ret_status = 0; + + sedi_uart_get_status(instance, (uint32_t *const)&status); + if (status & SEDI_UART_RX_OE) { + ret_status = UART_ERROR_OVERRUN; + } + + if (status & SEDI_UART_RX_PE) { + ret_status = UART_ERROR_PARITY; + } + + if (status & SEDI_UART_RX_FE) { + ret_status = UART_ERROR_FRAMING; + } + + if (status & SEDI_UART_RX_BI) { + ret_status = UART_BREAK; + } + + return ret_status; +} + + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static int uart_sedi_fifo_fill(const struct device *dev, const uint8_t *tx_data, + int size) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_fifo_fill(instance, tx_data, size); +} + +static int uart_sedi_fifo_read(const struct device *dev, uint8_t *rx_data, + const int size) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_fifo_read(instance, rx_data, size); +} + +static void uart_sedi_irq_tx_enable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_irq_tx_enable(instance); +} + +static void uart_sedi_irq_tx_disable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_irq_tx_disable(instance); +} + +static int uart_sedi_irq_tx_ready(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_irq_tx_ready(instance); +} + +static int uart_sedi_irq_tx_complete(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_is_tx_complete(instance); +} + +static void uart_sedi_irq_rx_enable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + uart_busy_set(dev); + sedi_uart_irq_rx_enable(instance); +} + +static void uart_sedi_irq_rx_disable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_irq_rx_disable(instance); + uart_busy_clear(dev); +} + +static int uart_sedi_irq_rx_ready(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_is_irq_rx_ready(instance); +} + +static void uart_sedi_irq_err_enable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_irq_err_enable(instance); +} + +static void uart_sedi_irq_err_disable(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_irq_err_disable(instance); +} + +static int uart_sedi_irq_is_pending(const struct device *dev) +{ + + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + return sedi_uart_is_irq_pending(instance); +} + +static int uart_sedi_irq_update(const struct device *dev) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + + sedi_uart_update_irq_cache(instance); + return 1; +} + +static void uart_sedi_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct uart_sedi_drv_data *drv_data = dev->data; + + drv_data->user_cb = cb; + drv_data->user_data = user_data; + +} + +static void uart_sedi_isr(void *arg) +{ + struct device *dev = arg; + struct uart_sedi_drv_data *drv_data = dev->data; + + if (drv_data->user_cb) { + drv_data->user_cb(dev, drv_data->user_data); + } else { + uart_sedi_cb(dev); + } +} + +/* Called from generic callback of zephyr , set by set_cb. */ +static void uart_sedi_cb(struct device *port) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(port); + + sedi_uart_isr_handler(instance); +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#ifdef CONFIG_UART_LINE_CTRL +static int uart_sedi_line_ctrl_set(struct device *dev, + uint32_t ctrl, uint32_t val) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + sedi_uart_config_t cfg; + uint32_t mask; + int ret; + + k_mutex_lock(GET_MUTEX(dev), K_FOREVER); + switch (ctrl) { + case UART_LINE_CTRL_BAUD_RATE: + sedi_uart_get_config(instance, &cfg); + cfg.baud_rate = val; + ret = sedi_uart_set_config(instance, &cfg); + break; + + default: + ret = -ENODEV; + } + k_mutex_unlock(GET_MUTEX(dev)); + ret = get_xfer_error(ret); + return ret; +} + +static int uart_sedi_line_ctrl_get(struct device *dev, + uint32_t ctrl, uint32_t *val) +{ + sedi_uart_t instance = GET_CONTROLLER_INSTANCE(dev); + sedi_uart_config_t cfg; + uint32_t mask; + int ret; + + k_mutex_lock(GET_MUTEX(dev), K_FOREVER); + switch (ctrl) { + case UART_LINE_CTRL_BAUD_RATE: + ret = sedi_uart_get_config(instance, &cfg); + *val = cfg.baud_rate; + break; + + case UART_LINE_CTRL_LOOPBACK: + ret = sedi_uart_get_loopback_mode(instance, (uint32_t *)val); + break; + + case UART_LINE_CTRL_AFCE: + ret = sedi_uart_get_config(instance, &cfg); + *val = cfg.hw_fc; + break; + + case UART_LINE_CTRL_LINE_STATUS_REPORT_MASK: + mask = 0; + *val = 0; + ret = sedi_get_ln_status_report_mask(instance, + (uint32_t *)&mask); + *val |= ((mask & SEDI_UART_RX_OE) ? UART_ERROR_OVERRUN : 0); + *val |= ((mask & SEDI_UART_RX_PE) ? UART_ERROR_PARITY : 0); + *val |= ((mask & SEDI_UART_RX_FE) ? UART_ERROR_FRAMING : 0); + *val |= ((mask & SEDI_UART_RX_BI) ? UART_BREAK : 0); + break; + + case UART_LINE_CTRL_RTS: + ret = sedi_uart_read_rts(instance, (uint32_t *)val); + break; + + case UART_LINE_CTRL_CTS: + ret = sedi_uart_read_cts(instance, (uint32_t *)val); + break; + + + default: + ret = -ENODEV; + } + k_mutex_unlock(GET_MUTEX(dev)); + ret = get_xfer_error(ret); + return ret; +} + +#endif /* CONFIG_UART_LINE_CTRL */ + +static const struct uart_driver_api api = { + .poll_in = uart_sedi_poll_in, + .poll_out = uart_sedi_poll_out, + .err_check = uart_sedi_err_check, +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_sedi_fifo_fill, + .fifo_read = uart_sedi_fifo_read, + .irq_tx_enable = uart_sedi_irq_tx_enable, + .irq_tx_disable = uart_sedi_irq_tx_disable, + .irq_tx_ready = uart_sedi_irq_tx_ready, + .irq_tx_complete = uart_sedi_irq_tx_complete, + .irq_rx_enable = uart_sedi_irq_rx_enable, + .irq_rx_disable = uart_sedi_irq_rx_disable, + .irq_rx_ready = uart_sedi_irq_rx_ready, + .irq_err_enable = uart_sedi_irq_err_enable, + .irq_err_disable = uart_sedi_irq_err_disable, + .irq_is_pending = uart_sedi_irq_is_pending, + .irq_update = uart_sedi_irq_update, + .irq_callback_set = uart_sedi_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_LINE_CTRL + .line_ctrl_set = uart_sedi_line_ctrl_set, + .line_ctrl_get = uart_sedi_line_ctrl_get, +#endif /* CONFIG_UART_LINE_CTRL */ + +}; + +static int uart_sedi_init(const struct device *dev) +{ + + const struct uart_sedi_config_info *config = dev->config; + sedi_uart_config_t cfg; + + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + sedi_uart_init(config->instance, (void *)DEVICE_MMIO_GET(dev)); + + cfg.line_control = config->line_ctrl; + cfg.baud_rate = config->baud_rate; + cfg.hw_fc = config->hw_fc; + + /* Setting to full power and enabling clk. */ + sedi_uart_set_power(config->instance, SEDI_POWER_FULL); + + sedi_uart_set_config(config->instance, &cfg); + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + config->uart_irq_config_func(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + return 0; +} + +DT_INST_FOREACH_STATUS_OKAY(UART_SEDI_DEVICE_INIT) diff --git a/dts/bindings/serial/intel,sedi-uart.yaml b/dts/bindings/serial/intel,sedi-uart.yaml new file mode 100644 index 000000000000..36eb79cfcf83 --- /dev/null +++ b/dts/bindings/serial/intel,sedi-uart.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: INTEL SEDI UART + +compatible: "intel,sedi-uart" + +include: uart-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true From 1f39e9e5048691d0b154661220eec2574bf4f5b2 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Thu, 20 Jul 2023 09:30:08 -0600 Subject: [PATCH 1953/2042] rtio: Update documentation Revise the documentation around canceling pending SQEs. Signed-off-by: Yuval Peress --- doc/services/rtio/index.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/services/rtio/index.rst b/doc/services/rtio/index.rst index 11f5602b1157..63761ce5f642 100644 --- a/doc/services/rtio/index.rst +++ b/doc/services/rtio/index.rst @@ -122,6 +122,14 @@ does this work is up to the author of the iodev, perhaps the entire queue of operations can be converted to a set of DMA transfer descriptors, meaning the hardware does almost all of the real work. +Cancellation +************ + +Canceling an already queued operation is possible but not guaranteed. If the +SQE has not yet started, it's likely that a call to :c:func:`rtio_sqe_cancel` +will remove the SQE and never run it. If, however, the SQE already started +running, the cancel request will be ignored. + Memory pools ************ From 488fd89e2bd64c60354378fdec33b7e65c713d38 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Fri, 28 Jul 2023 09:58:57 +0200 Subject: [PATCH 1954/2042] boards: adafruit_feather_m0_basic_proto: add zephyr_udc0 nodelabel Add zephyr_udc0 nodelabel to allow building all USB device samples for adafruit_feather_m0_basic_proto board out of the box. Signed-off-by: Johann Fischer --- .../adafruit_feather_m0_basic_proto.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/adafruit_feather_m0_basic_proto/adafruit_feather_m0_basic_proto.dts b/boards/arm/adafruit_feather_m0_basic_proto/adafruit_feather_m0_basic_proto.dts index 0dd6c6e70a41..df83c6d6dddd 100644 --- a/boards/arm/adafruit_feather_m0_basic_proto/adafruit_feather_m0_basic_proto.dts +++ b/boards/arm/adafruit_feather_m0_basic_proto/adafruit_feather_m0_basic_proto.dts @@ -104,7 +104,7 @@ }; }; -&usb0 { +zephyr_udc0: &usb0 { status = "okay"; pinctrl-0 = <&usb_dc_default>; From 6009182731ae821dafc7a174bd4726584641276c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 28 Jul 2023 13:41:14 -0700 Subject: [PATCH 1955/2042] MAINTAINERS: move to my ampere account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm using a new account now. Do the corresponding CODEOWNERS change just for consistency as well. Signed-off-by: Martí Bolívar --- CODEOWNERS | 28 ++++++++++++++-------------- MAINTAINERS.yml | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index faf9d41e54b6..3ec9727fce25 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -71,7 +71,7 @@ /soc/arm64/arm/fvp_aemv8a/ @carlocaione /soc/arm64/intel_socfpga/* @siclim /soc/Kconfig @tejlmand @galak @nashif @nordicjm -/submanifests/* @mbolivar-nordic +/submanifests/* @mbolivar-ampere /arch/x86/ @jhedberg @nashif /arch/nios2/ @nashif /arch/posix/ @aescolar @daor-oti @@ -167,7 +167,7 @@ /boards/arm/rcar_h3ulcb/ @aaillet @pmarzin /boards/arm/ubx_bmd345eval_nrf52840/ @Navin-Sankar @brec-u-blox /boards/arm/nrf5340_audio_dk_nrf5340 @koffes @alexsven @erikrobstad @rick1082 @gWacey -/boards/common/ @mbolivar-nordic +/boards/common/ @mbolivar-ampere /boards/deprecated.cmake @tejlmand /boards/mips/ @frantony /boards/nios2/ @nashif @@ -216,7 +216,7 @@ /doc/CMakeLists.txt @carlescufi /doc/_scripts/ @carlescufi /doc/connectivity/bluetooth/ @alwa-nordic @jhedberg @Vudentz -/doc/build/dts/ @galak @mbolivar-nordic +/doc/build/dts/ @galak @mbolivar-ampere /doc/build/sysbuild/ @tejlmand @nordicjm /doc/hardware/peripherals/canbus/ @alexanderwachter @henrikbrixandersen /doc/security/ @ceolin @d3zd3z @@ -322,8 +322,8 @@ /drivers/i2c/Kconfig.i2c_emul @sjg20 /drivers/i2c/Kconfig.it8xxx2 @GTLin08 /drivers/i2c/target/*eeprom* @henrikbrixandersen -/drivers/i2c/Kconfig.test @mbolivar-nordic -/drivers/i2c/i2c_test.c @mbolivar-nordic +/drivers/i2c/Kconfig.test @mbolivar-ampere +/drivers/i2c/i2c_test.c @mbolivar-ampere /drivers/i2c/*rcar* @aaillet /drivers/i2s/*litex* @mateusz-holenko @kgugala @pgielda /drivers/i2s/i2s_ll_stm32* @avisconti @@ -354,7 +354,7 @@ /drivers/kscan/*ft5336* @MaureenHelm /drivers/kscan/*ht16k33* @henrikbrixandersen /drivers/led/ @Mani-Sadhasivam -/drivers/led_strip/ @mbolivar-nordic +/drivers/led_strip/ @mbolivar-ampere /drivers/lora/ @Mani-Sadhasivam /drivers/mbox/ @carlocaione /drivers/misc/ @tejlmand @@ -612,7 +612,7 @@ /include/zephyr/drivers/pcie/ @dcpleung /include/zephyr/drivers/hwinfo.h @alexanderwachter /include/zephyr/drivers/led.h @Mani-Sadhasivam -/include/zephyr/drivers/led_strip.h @mbolivar-nordic +/include/zephyr/drivers/led_strip.h @mbolivar-ampere /include/zephyr/drivers/sensor.h @MaureenHelm /include/zephyr/drivers/smbus.h @finikorg /include/zephyr/drivers/spi.h @tbursztyka @@ -770,7 +770,7 @@ /scripts/build/gen_app_partitions.py @dcpleung @nashif scripts/build/gen_image_info.py @tejlmand /scripts/get_maintainer.py @nashif -/scripts/dts/ @mbolivar-nordic @galak +/scripts/dts/ @mbolivar-ampere @galak /scripts/release/ @nashif /scripts/ci/ @nashif /scripts/ci/check_compliance.py @nashif @carlescufi @@ -779,11 +779,11 @@ scripts/build/gen_image_info.py @tejlmand /scripts/build/gen_kobject_list.py @dcpleung @nashif /scripts/build/gen_kobject_placeholders.py @dcpleung /scripts/build/gen_syscalls.py @dcpleung @nashif -/scripts/list_boards.py @mbolivar-nordic +/scripts/list_boards.py @mbolivar-ampere /scripts/build/process_gperf.py @dcpleung @nashif /scripts/build/gen_relocate_app.py @dcpleung /scripts/generate_usb_vif/ @madhurimaparuchuri -/scripts/requirements*.txt @mbolivar-nordic @galak @nashif +/scripts/requirements*.txt @mbolivar-ampere @galak @nashif /scripts/tests/build/test_subfolder_list.py @rmstoi /scripts/tracing/ @nashif /scripts/pylib/twister/ @nashif @@ -791,12 +791,12 @@ scripts/build/gen_image_info.py @tejlmand /scripts/series-push-hook.sh @erwango /scripts/utils/pinctrl_nrf_migrate.py @gmarull /scripts/utils/migrate_mcumgr_kconfigs.py @de-nordic -/scripts/west_commands/ @mbolivar-nordic +/scripts/west_commands/ @mbolivar-ampere /scripts/west_commands/blobs.py @carlescufi /scripts/west_commands/fetchers/ @carlescufi -/scripts/west_commands/runners/gd32isp.py @mbolivar-nordic @nandojve -/scripts/west_commands/tests/test_gd32isp.py @mbolivar-nordic @nandojve -/scripts/west-commands.yml @mbolivar-nordic +/scripts/west_commands/runners/gd32isp.py @mbolivar-ampere @nandojve +/scripts/west_commands/tests/test_gd32isp.py @mbolivar-ampere @nandojve +/scripts/west-commands.yml @mbolivar-ampere /scripts/zephyr_module.py @tejlmand /scripts/build/uf2conv.py @petejohanson /scripts/build/user_wordsize.py @cfriedt diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index d37cf5ac4d1c..20b57422135e 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -518,7 +518,7 @@ DFU: Devicetree: status: maintained maintainers: - - mbolivar-nordic + - mbolivar-ampere - galak files: - scripts/dts/ @@ -1088,7 +1088,7 @@ Release Notes: "Drivers: LED Strip": status: maintained maintainers: - - mbolivar-nordic + - mbolivar-ampere - simonguinot files: - drivers/led_strip/ @@ -2755,7 +2755,7 @@ VFS: West: status: maintained maintainers: - - mbolivar-nordic + - mbolivar-ampere collaborators: - carlescufi - swinslow From 1f278d9ae4980415a64efa667e8ffb0816df2ced Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 28 Jul 2023 08:04:42 -0400 Subject: [PATCH 1956/2042] thrift: add temporary Mutex implementation The Thrift library has its own abstraction for mutexes, which normally just a wrapper around `std::mutex` using the PIMPL idiom (pointer-to-impl). Since Zephyr does not yet support `std::mutex`, a workaround was added in Zephyr that was essentially no-op, and actually the PIMPL idiom made it quite easy to do that. However, pretending there is no synchronization requirement is not a solution for it. We can't yet just use a `struct k_mutex` yet, because we don't yet support userspace, but for now we can fake a mutex interface with a spinlock. We hope to eventually drop this workaround entirely and just support `std::mutex`. Signed-off-by: Christopher Friedt --- .../thrift/src/thrift/concurrency/Mutex.cpp | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/modules/thrift/src/thrift/concurrency/Mutex.cpp b/modules/thrift/src/thrift/concurrency/Mutex.cpp index 422914349136..20848f6ed80a 100644 --- a/modules/thrift/src/thrift/concurrency/Mutex.cpp +++ b/modules/thrift/src/thrift/concurrency/Mutex.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include namespace apache @@ -13,31 +15,52 @@ namespace thrift namespace concurrency { +class Mutex::impl +{ +public: + k_spinlock_key_t key; + struct k_spinlock lock; +}; + Mutex::Mutex() { + impl_ = std::make_shared(); } void Mutex::lock() const { + while (!trylock()) { + k_msleep(1); + } } bool Mutex::trylock() const { - return false; + return k_spin_trylock(&impl_->lock, &impl_->key) == 0; } bool Mutex::timedlock(int64_t milliseconds) const { + k_timepoint_t end = sys_timepoint_calc(K_MSEC(milliseconds)); + + do { + if (trylock()) { + return true; + } + k_msleep(5); + } while(!sys_timepoint_expired(end)); + return false; } void Mutex::unlock() const { + k_spin_unlock(&impl_->lock, impl_->key); } void *Mutex::getUnderlyingImpl() const { - return nullptr; + return &impl_->lock; } } // namespace concurrency } // namespace thrift From 9dc531be481a2e67da5c2875339b4386e93e823c Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Fri, 28 Jul 2023 08:11:35 -0400 Subject: [PATCH 1957/2042] tests: thrift: replace unused variable with NULL in pthread_join There is no need to pass a second parameter to `pthread_join()` if it is unused. Just use `NULL` instead. Signed-off-by: Christopher Friedt --- tests/lib/thrift/ThriftTest/src/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/lib/thrift/ThriftTest/src/main.cpp b/tests/lib/thrift/ThriftTest/src/main.cpp index b8ac60480084..f42090ee37e2 100644 --- a/tests/lib/thrift/ThriftTest/src/main.cpp +++ b/tests/lib/thrift/ThriftTest/src/main.cpp @@ -148,11 +148,10 @@ static void thrift_test_before(void *data) static void thrift_test_after(void *data) { ARG_UNUSED(data); - void *unused; context.server->stop(); - pthread_join(context.server_thread, &unused); + pthread_join(context.server_thread, NULL); context.server.reset(); context.client.reset(); From 5b4d275a995df3a63ef9aac0f9a89cbe55fa1685 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 30 Jul 2023 10:49:02 -0400 Subject: [PATCH 1958/2042] tests: drivers: build_all: sensor: do not run build-only testsuite A recent modification to the `build_all/sensor` testsuite changed `build-only` to `false` in `testcase.yaml`, which is causing CI to go bonkers. https://bit.ly/3rSe0Te Do not run build-only testsuites. Signed-off-by: Christopher Friedt --- tests/drivers/build_all/sensor/testcase.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/drivers/build_all/sensor/testcase.yaml b/tests/drivers/build_all/sensor/testcase.yaml index 53ee3ac85836..ef07b4a5886a 100644 --- a/tests/drivers/build_all/sensor/testcase.yaml +++ b/tests/drivers/build_all/sensor/testcase.yaml @@ -27,4 +27,3 @@ tests: - CONFIG_EMUL=y - CONFIG_NATIVE_UART_0_ON_STDINOUT=y - CONFIG_SENSOR_ASYNC_API=y - build_only: false From 52f00882d127dd1bcbdbcc2376b0655018b6454a Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 30 Jul 2023 12:10:21 -0400 Subject: [PATCH 1959/2042] posix: pthread: report appropriate return value instead of 0 Discovered this while implementing c11 threads, but there was a regression recently that made it so that `pthread_join()` would report success when attempting to join a thread that had been detached with `pthread_detach()`. Technically now that is undefined behaviour, but historically, we have reported `EINVAL`, which was the older specified return value. 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 a6505d4f9d33..bc676c7e8bd2 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -658,7 +658,7 @@ int pthread_join(pthread_t pthread, void **status) __ASSERT_NO_MSG(err == 0); } - return 0; + return ret; } /** From 033d772d073a81a54636c70cc271bc020343408d Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 30 Jul 2023 12:12:14 -0400 Subject: [PATCH 1960/2042] tests: posix: common: pthread_join should fail on detached A thread that has been previously detached using `pthread_detach()` should not be able to be joined. A recent change made it so that `pthread_join()` would always report success (0), even when `ret` (return value) had an error. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index e88703bae404..985393bd9907 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -812,3 +812,27 @@ ZTEST(posix_apis, test_pthread_dynamic_stacks) zassert_ok(pthread_join(th, NULL)); zassert_equal(0xB105F00D, x); } + +static void *detached(void *arg) +{ + ARG_UNUSED(arg); + + return NULL; +} + +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_detach(pth)); + /* note, this was required to be EINVAL previously but is now undefined behaviour */ + zassert_equal(EINVAL, pthread_join(pth, NULL)); + + /* need to allow this thread to be clean-up by the recycler */ + k_msleep(500); +} From 73bf557a9514e425bade4ade5af2980b11ccda40 Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 30 Jul 2023 11:16:12 -0400 Subject: [PATCH 1961/2042] posix: pthread: thread return value not set by pthread_join() Ensure that the thread return value is set by `pthread_join()` when `status` is non-NULL. Additionally, we have an opportunity to synchronously clean up thread stacks in `pthread_join()`, which is preferable. Signed-off-by: Christopher Friedt --- lib/posix/pthread.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index bc676c7e8bd2..0b5ca1865301 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -623,7 +623,6 @@ int pthread_join(pthread_t pthread, void **status) { int err; int ret; - k_spinlock_key_t key; struct posix_thread *t; if (pthread == pthread_self()) { @@ -636,29 +635,41 @@ int pthread_join(pthread_t pthread, void **status) } ret = 0; - key = k_spin_lock(&pthread_pool_lock); - if (t->detachstate != PTHREAD_CREATE_JOINABLE) { - ret = EINVAL; - } else if (t->qid == POSIX_THREAD_READY_Q) { - /* marginal chance thread has moved to ready_q between to_posix_thread() and here */ - ret = ESRCH; - } else { + K_SPINLOCK(&pthread_pool_lock) + { + if (t->detachstate != PTHREAD_CREATE_JOINABLE) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } + + 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; + } + /* * 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; - ret = 0; } - k_spin_unlock(&pthread_pool_lock, key); - if (ret == 0) { - err = k_thread_join(&t->thread, K_FOREVER); - /* other possibilities? */ - __ASSERT_NO_MSG(err == 0); + if (ret != 0) { + return ret; } - return ret; + err = k_thread_join(&t->thread, K_FOREVER); + /* other possibilities? */ + __ASSERT_NO_MSG(err == 0); + + if (status != NULL) { + *status = t->retval; + } + + posix_thread_recycle(); + + return 0; } /** From e7c23b392fc36f89655a206d3071889afe3d9bca Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sun, 30 Jul 2023 11:17:04 -0400 Subject: [PATCH 1962/2042] tests: posix: common: check return value in pthread_join() Ensure that the thread return value is set by `pthread_join()` when `status` is non-NULL. Signed-off-by: Christopher Friedt --- tests/posix/common/src/pthread.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 985393bd9907..f02570d70ef0 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -793,9 +793,12 @@ ZTEST(posix_apis, test_pthread_equal) 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) = 0xB105F00D; + *((uint32_t *)arg) = BIOS_FOOD; return NULL; } @@ -810,7 +813,28 @@ ZTEST(posix_apis, test_pthread_dynamic_stacks) zassert_ok(pthread_create(&th, NULL, fun, &x)); zassert_ok(pthread_join(th, NULL)); - zassert_equal(0xB105F00D, x); + zassert_equal(BIOS_FOOD, x); +} + +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; + 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_join(pth, &ret)); + zassert_equal(ret, (void *)BIOS_FOOD); } static void *detached(void *arg) @@ -831,7 +855,7 @@ ZTEST(posix_apis, test_pthread_join_detached) zassert_ok(pthread_create(&pth, &attr, detached, NULL)); zassert_ok(pthread_detach(pth)); /* note, this was required to be EINVAL previously but is now undefined behaviour */ - zassert_equal(EINVAL, pthread_join(pth, NULL)); + zassert_not_equal(0, pthread_join(pth, NULL)); /* need to allow this thread to be clean-up by the recycler */ k_msleep(500); From f3f1ed65954e0b6f48d85c2148984d4d7666f729 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Fri, 23 Jun 2023 09:55:15 +0200 Subject: [PATCH 1963/2042] boards: stm32: Fix vendor name when required Now that vendor name in board compatible is meant to be actually used, it should be properly filled. Update when not correct and don't put any name when vendor is not known Signed-off-by: Erwan Gouriou --- .../adafruit_feather_stm32f405/adafruit_feather_stm32f405.dts | 2 +- boards/arm/black_f407ve/black_f407ve.dts | 2 +- boards/arm/stm32_min_dev/stm32_min_dev_black.dts | 2 +- boards/arm/stm32_min_dev/stm32_min_dev_blue.dts | 2 +- boards/arm/stm32f030_demo/stm32f030_demo.dts | 2 +- boards/arm/stm32f103_mini/stm32f103_mini.dts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/boards/arm/adafruit_feather_stm32f405/adafruit_feather_stm32f405.dts b/boards/arm/adafruit_feather_stm32f405/adafruit_feather_stm32f405.dts index 356e804aaa36..cc1cb7020626 100644 --- a/boards/arm/adafruit_feather_stm32f405/adafruit_feather_stm32f405.dts +++ b/boards/arm/adafruit_feather_stm32f405/adafruit_feather_stm32f405.dts @@ -11,7 +11,7 @@ / { model = "Adafruit Feather STM32F405 Express"; - compatible = "st,adafruit_feather_stm32f405", "st,stm32f405"; + compatible = "adafruit,adafruit_feather_stm32f405", "st,stm32f405"; chosen { zephyr,console = &usart3; diff --git a/boards/arm/black_f407ve/black_f407ve.dts b/boards/arm/black_f407ve/black_f407ve.dts index 2ae87ca05042..5ea58801fdca 100644 --- a/boards/arm/black_f407ve/black_f407ve.dts +++ b/boards/arm/black_f407ve/black_f407ve.dts @@ -10,7 +10,7 @@ / { model = "black_f407ve board"; - compatible = "st,stm32f407"; + compatible = "black-stm32f407"; chosen { zephyr,console = &usart1; diff --git a/boards/arm/stm32_min_dev/stm32_min_dev_black.dts b/boards/arm/stm32_min_dev/stm32_min_dev_black.dts index 8df88f45052f..80c283d24d93 100644 --- a/boards/arm/stm32_min_dev/stm32_min_dev_black.dts +++ b/boards/arm/stm32_min_dev/stm32_min_dev_black.dts @@ -9,7 +9,7 @@ / { model = "STM32 Minimum Development Board (Black)"; - compatible = "st,stm32_min_dev_black", "st,stm32f103c8"; + compatible = "stm32_min_dev_black", "st,stm32f103c8"; leds { led: led { diff --git a/boards/arm/stm32_min_dev/stm32_min_dev_blue.dts b/boards/arm/stm32_min_dev/stm32_min_dev_blue.dts index fe3c23e34810..8d0f3419b866 100644 --- a/boards/arm/stm32_min_dev/stm32_min_dev_blue.dts +++ b/boards/arm/stm32_min_dev/stm32_min_dev_blue.dts @@ -9,7 +9,7 @@ / { model = "STM32 Minimum Development Board (Blue)"; - compatible = "st,stm32_min_dev_blue", "st,stm32f103c8"; + compatible = "stm32_min_dev_blue", "st,stm32f103c8"; leds { led: led { diff --git a/boards/arm/stm32f030_demo/stm32f030_demo.dts b/boards/arm/stm32f030_demo/stm32f030_demo.dts index 794cc7dce8e6..5bb5b80da34c 100644 --- a/boards/arm/stm32f030_demo/stm32f030_demo.dts +++ b/boards/arm/stm32f030_demo/stm32f030_demo.dts @@ -10,7 +10,7 @@ / { model = "STM32F030 DEMO board"; - compatible = "st,stm32f030-demo"; + compatible = "stm32f030-demo"; chosen { zephyr,console = &usart1; diff --git a/boards/arm/stm32f103_mini/stm32f103_mini.dts b/boards/arm/stm32f103_mini/stm32f103_mini.dts index 95a6cc5233aa..1a158b9be7e7 100644 --- a/boards/arm/stm32f103_mini/stm32f103_mini.dts +++ b/boards/arm/stm32f103_mini/stm32f103_mini.dts @@ -10,7 +10,7 @@ / { model = "stm32f103_mini board"; - compatible = "st,stm32f103"; + compatible = "stm32f103"; chosen { zephyr,console = &usart1; From d8bc8c0f1d6db17f2db3896fbe90476b92bc1e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Tue, 18 Jul 2023 11:14:58 +0200 Subject: [PATCH 1964/2042] drivers: w1: doc: Doxygen doc for 1-Wire commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added Doxygen comments for 1-Wire commands Signed-off-by: Benjamin Cabé --- include/zephyr/drivers/w1.h | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/zephyr/drivers/w1.h b/include/zephyr/drivers/w1.h index 4c56d246510f..a23f3577c5b9 100644 --- a/include/zephyr/drivers/w1.h +++ b/include/zephyr/drivers/w1.h @@ -348,13 +348,55 @@ static inline int z_impl_w1_configure(const struct device *dev, * @name 1-Wire ROM Commands * @{ */ + +/** + * This command allows the bus master to read the slave devices without + * providing their ROM code. + */ #define W1_CMD_SKIP_ROM 0xCC + +/** + * This command allows the bus master to address a specific slave device by + * providing its ROM code. + */ #define W1_CMD_MATCH_ROM 0x55 + +/** + * This command allows the bus master to resume a previous read out from where + * it left off. + */ #define W1_CMD_RESUME 0xA5 + +/** + * This command allows the bus master to read the ROM code from a single slave + * device. + * This command should be used when there is only a single slave device on the + * bus. + */ #define W1_CMD_READ_ROM 0x33 + +/** + * This command allows the bus master to discover the addresses (i.e., ROM + * codes) of all slave devices on the bus. + */ #define W1_CMD_SEARCH_ROM 0xF0 + +/** + * This command allows the bus master to identify which devices have experienced + * an alarm condition. + */ #define W1_CMD_SEARCH_ALARM 0xEC + +/** + * This command allows the bus master to address all devices on the bus and then + * switch them to overdrive speed. + */ #define W1_CMD_OVERDRIVE_SKIP_ROM 0x3C + +/** + * This command allows the bus master to address a specific device and switch it + * to overdrive speed. + */ #define W1_CMD_OVERDRIVE_MATCH_ROM 0x69 /** @} */ From 0ae1e37ead8d77158660c709753718bc81b4b3bf Mon Sep 17 00:00:00 2001 From: Ryan McClelland Date: Wed, 19 Jul 2023 11:55:13 -0700 Subject: [PATCH 1965/2042] tests: logging: fix double-promotion warnings Double promotion warnings are generated with the flag -Wdouble-promotion Signed-off-by: Ryan McClelland --- tests/subsys/logging/log_api/src/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/subsys/logging/log_api/src/main.c b/tests/subsys/logging/log_api/src/main.c index ddc8ccc25438..7c790531a60b 100644 --- a/tests/subsys/logging/log_api/src/main.c +++ b/tests/subsys/logging/log_api/src/main.c @@ -184,16 +184,16 @@ ZTEST(test_log_api, test_log_various_messages) LOG_DBG(TEST_MSG_0, ll, ull, i); #ifdef CONFIG_FPU - float f = -1.2356; + float f = -1.2356f; double d = -1.2356; - snprintk(str, sizeof(str), TEST_MSG_1, f, 100, d); + snprintk(str, sizeof(str), TEST_MSG_1, (double)f, 100, d); mock_log_frontend_record(LOG_CURRENT_MODULE_ID(), LOG_LEVEL_INF, str); mock_log_backend_record(&backend1, LOG_CURRENT_MODULE_ID(), Z_LOG_LOCAL_DOMAIN_ID, LOG_LEVEL_INF, exp_timestamp++, str); - LOG_INF(TEST_MSG_1, f, 100, d); + LOG_INF(TEST_MSG_1, (double)f, 100, d); #endif /* CONFIG_FPU */ snprintk(str, sizeof(str), "wrn %s", dstr); From 38352ae13c64cac1a892f66cb50ed144f9343295 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Tue, 25 Jul 2023 14:10:22 -0400 Subject: [PATCH 1966/2042] test: Relocate posix mqueue receive buffer For platforms that select Kconfig option CONFIG_KERNEL_COHERENCE, the receive buffer used in mq_timedreceive() must not be on the stack. This is because the k_msgq that underlies the POSIX mqueue will attempt to perform a direct to buffer copy from the sender when there is a waiting reader. Fixes #60796 Signed-off-by: Peter Mitsis --- tests/posix/common/src/mqueue.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/posix/common/src/mqueue.c b/tests/posix/common/src/mqueue.c index 74c16da6bfd5..7d1ec257323d 100644 --- a/tests/posix/common/src/mqueue.c +++ b/tests/posix/common/src/mqueue.c @@ -21,8 +21,18 @@ K_THREAD_STACK_ARRAY_DEFINE(stacks, N_THR, STACKSZ); char queue[16] = "server"; + char send_data[MESSAGE_SIZE] = "timed data send"; +/* + * For platforms that select CONFIG_KERNEL_COHERENCE, the receive buffer can + * not be on the stack as the k_msgq that underlies the mq_timedsend() will + * copy directly to the receiver's buffer when there is already a waiting + * receiver. + */ + +char rec_data[MESSAGE_SIZE]; + void *sender_thread(void *p1) { mqd_t mqd; @@ -44,7 +54,6 @@ void *sender_thread(void *p1) void *receiver_thread(void *p1) { mqd_t mqd; - char rec_data[MESSAGE_SIZE]; struct timespec curtime; mqd = mq_open(queue, O_RDONLY); From 67268f5cbdf8154195062f8a6f3ff42c1a424bb9 Mon Sep 17 00:00:00 2001 From: Joshua Lilly Date: Wed, 26 Jul 2023 09:50:10 -0700 Subject: [PATCH 1967/2042] drivers: interrupt_controller: plic: support edge triggered interrupts This adds a check and option for edge triggered interrupts Signed-off-by: Joshua Lilly --- drivers/interrupt_controller/Kconfig.plic | 6 +++ drivers/interrupt_controller/intc_plic.c | 42 ++++++++++++++++++- .../sifive,plic-1.0.0.yaml | 4 ++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/interrupt_controller/Kconfig.plic b/drivers/interrupt_controller/Kconfig.plic index c1e16c7c1c55..fd5f3b95de4b 100644 --- a/drivers/interrupt_controller/Kconfig.plic +++ b/drivers/interrupt_controller/Kconfig.plic @@ -10,3 +10,9 @@ config PLIC help Platform Level Interrupt Controller provides support for external interrupt lines defined by the RISC-V SoC. + +config PLIC_SUPPORTS_EDGE_IRQ + bool "The given interrupt controller supports edge interrupts" + help + The given interrupt controller supports edge triggered + interrupts. diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 11d41e2f191a..67a5313287c2 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -29,6 +29,9 @@ #define PLIC_IRQS (CONFIG_NUM_IRQS - CONFIG_2ND_LVL_ISR_TBL_OFFSET) #define PLIC_EN_SIZE ((PLIC_IRQS >> 5) + 1) +#define PLIC_EDGE_TRIG_TYPE (PLIC_MAX_PRIO + DT_INST_PROP(0, riscv_trigger_reg_offset)) +#define PLIC_EDGE_TRIG_SHIFT 5 + struct plic_regs_t { uint32_t threshold_prio; uint32_t claim_complete; @@ -36,6 +39,28 @@ struct plic_regs_t { static int save_irq; +/** + * @brief return edge irq value or zero + * + * 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 + * routine will return 0 + * + * @param irq IRQ number to add to the trigger + * + * @return irq value when enabled 0 otherwise + */ +static int riscv_plic_is_edge_irq(uint32_t irq) +{ + if (IS_ENABLED(CONFIG_PLIC_SUPPORTS_EDGE_IRQ)) { + volatile uint32_t *trig = (volatile uint32_t *)PLIC_EDGE_TRIG_TYPE; + + trig += (irq >> PLIC_EDGE_TRIG_SHIFT); + return *trig & BIT(irq); + } + return 0; +} + /** * @brief Enable a riscv PLIC-specific interrupt line * @@ -135,6 +160,7 @@ static void plic_irq_handler(const void *arg) uint32_t irq; struct _isr_table_entry *ite; + int edge_irq; /* Get the IRQ number generating the interrupt */ irq = regs->claim_complete; @@ -154,6 +180,16 @@ static void plic_irq_handler(const void *arg) if (irq == 0U || irq >= PLIC_IRQS) z_irq_spurious(NULL); + edge_irq = riscv_plic_is_edge_irq(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. + */ + if (edge_irq) + regs->claim_complete = save_irq; + irq += CONFIG_2ND_LVL_ISR_TBL_OFFSET; /* Call the corresponding IRQ handler in _sw_isr_table */ @@ -162,9 +198,11 @@ static void plic_irq_handler(const void *arg) /* * Write to claim_complete register to indicate to - * PLIC controller that the IRQ has been handled. + * PLIC controller that the IRQ has been handled + * for level triggered interrupts. */ - regs->claim_complete = save_irq; + if (!edge_irq) + regs->claim_complete = save_irq; } /** diff --git a/dts/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/dts/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index 4698d7f85150..839506f33ea0 100644 --- a/dts/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/dts/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -12,3 +12,7 @@ properties: type: int description: Number of external interrupts supported required: true + riscv,trigger-reg-offset: + type: int + default: 4224 + description: Offset of the trigger type register if supported From e14935ec6c6f13014868eb6d0e636c11c2f06268 Mon Sep 17 00:00:00 2001 From: Sjors Hettinga Date: Thu, 27 Jul 2023 14:28:35 +0200 Subject: [PATCH 1968/2042] net: tcp: Avoid partial ACK canceling retransmission timer At any ack, the retransmission timer was cancelled. This means when an ACK is only partially acknowledging pending data, followed by a packet loss, the connection ended in a deadlock eventually timing out. By checking if there is any pending data for transmission before canceling the retransmission timer, there is no risk of this lock-up any more. Signed-off-by: Sjors Hettinga --- subsys/net/ip/tcp.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index ae9d59e7e16d..4cc6fa32bde3 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -2343,6 +2343,10 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) } } #endif + NET_ASSERT((conn->send_data_total == 0) || + k_work_delayable_is_pending(&conn->send_data_timer), + "conn: %p, Missing a subscription " + "of the send_data queue timer", conn); if (th && (net_tcp_seq_cmp(th_ack(th), conn->seq) > 0)) { uint32_t len_acked = th_ack(th) - conn->seq; @@ -2383,19 +2387,16 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) conn_send_data_dump(conn); - if (!k_work_delayable_remaining_get( - &conn->send_data_timer)) { - NET_DBG("conn: %p, Missing a subscription " - "of the send_data queue timer", conn); - break; - } conn->send_data_retries = 0; - k_work_cancel_delayable(&conn->send_data_timer); if (conn->data_mode == TCP_DATA_MODE_RESEND) { conn->unacked_len = 0; tcp_derive_rto(conn); } conn->data_mode = TCP_DATA_MODE_SEND; + if (conn->send_data_total > 0) { + k_work_reschedule_for_queue(&tcp_work_q, &conn->send_data_timer, + K_MSEC(TCP_RTO_MS)); + } /* We are closing the connection, send a FIN to peer */ if (conn->in_close && conn->send_data_total == 0) { @@ -2457,6 +2458,20 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt) verdict = NET_OK; } } + + /* Check if there is any data left to retransmit possibly*/ + if (conn->send_data_total == 0) { + conn->send_data_retries = 0; + k_work_cancel_delayable(&conn->send_data_timer); + } + + /* A lot could have happened to the transmission window check the situation here */ + if (tcp_window_full(conn)) { + (void)k_sem_take(&conn->tx_sem, K_NO_WAIT); + } else { + k_sem_give(&conn->tx_sem); + } + break; case TCP_CLOSE_WAIT: tcp_out(conn, FIN); From c2f4200ad5f086d7e04f537e844b87862dd3f738 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Thu, 27 Jul 2023 14:45:22 +0000 Subject: [PATCH 1969/2042] bindings: ethernet: replace phy-dev with phy-handle Rename the phy-dev property with phy-handle to match the Linux ethernet-controller binding and move it up to ethernet.yaml so that it can be used by other drivers. Signed-off-by: Fabio Baltieri --- boards/arm/s32z270dc2_r52/s32z270dc2_r52.dtsi | 2 +- drivers/ethernet/eth_nxp_s32_netc_psi.c | 2 +- dts/bindings/ethernet/ethernet.yaml | 6 ++++++ dts/bindings/ethernet/nxp,s32-netc-psi.yaml | 5 +---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_r52.dtsi b/boards/arm/s32z270dc2_r52/s32z270dc2_r52.dtsi index 1471d56a3382..d6d58aa9a858 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_r52.dtsi +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_r52.dtsi @@ -109,7 +109,7 @@ pinctrl-0 = <ð0_default>; pinctrl-names = "default"; clock-frequency = <300000000>; - phy-dev = <&phy0>; + phy-handle = <&phy0>; status = "okay"; }; diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index bd00d13fdcf9..375767de97df 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -27,7 +27,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth_psi); #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_dev) +#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 diff --git a/dts/bindings/ethernet/ethernet.yaml b/dts/bindings/ethernet/ethernet.yaml index cd30125ea15d..a5a9cec2700c 100644 --- a/dts/bindings/ethernet/ethernet.yaml +++ b/dts/bindings/ethernet/ethernet.yaml @@ -9,6 +9,7 @@ properties: local-mac-address: type: uint8-array description: Specifies the MAC address that was assigned to the network device + zephyr,random-mac-address: type: boolean description: | @@ -21,3 +22,8 @@ properties: It is driver specific how the OUI octets are handled. If set we ignore any setting of the local-mac-address property. + + phy-handle: + type: phandle + description: | + Specifies a reference to a node representing a PHY device. diff --git a/dts/bindings/ethernet/nxp,s32-netc-psi.yaml b/dts/bindings/ethernet/nxp,s32-netc-psi.yaml index f9296a2d52bf..dc15b8d22990 100644 --- a/dts/bindings/ethernet/nxp,s32-netc-psi.yaml +++ b/dts/bindings/ethernet/nxp,s32-netc-psi.yaml @@ -22,11 +22,8 @@ properties: mbox-names: required: true - phy-dev: + phy-handle: required: true - type: phandle - description: | - Ethernet PHY device managed by this network interface. vsis: type: array From 258fc16570ddabd4c931844cce300039d6e474cc Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sat, 29 Jul 2023 16:54:42 +0000 Subject: [PATCH 1970/2042] bindings: ethernet: rename ethernet to ethernet-controller Rename the ethernet.yaml template to ethernet-controller.yaml to match the Linux one. Signed-off-by: Fabio Baltieri --- dts/bindings/ethernet/atmel,gmac-common.yaml | 2 +- dts/bindings/ethernet/espressif,esp32-eth.yaml | 2 +- .../ethernet/{ethernet.yaml => ethernet-controller.yaml} | 0 dts/bindings/ethernet/litex,eth0.yaml | 2 +- dts/bindings/ethernet/microchip,enc28j60.yaml | 2 +- dts/bindings/ethernet/microchip,enc424j600.yaml | 2 +- dts/bindings/ethernet/nxp,kinetis-ethernet.yaml | 2 +- dts/bindings/ethernet/nxp,s32-netc-psi.yaml | 2 +- dts/bindings/ethernet/nxp,s32-netc-vsi.yaml | 2 +- dts/bindings/ethernet/siemens,ivshmem-eth.yaml | 2 +- dts/bindings/ethernet/silabs,gecko-ethernet.yaml | 2 +- dts/bindings/ethernet/snps,designware-ethernet.yaml | 2 +- dts/bindings/ethernet/snps,ethernet-cyclonev.yaml | 2 +- dts/bindings/ethernet/st,stm32-ethernet.yaml | 2 +- dts/bindings/ethernet/ti,stellaris-ethernet.yaml | 2 +- dts/bindings/ethernet/wiznet,w5500.yaml | 2 +- dts/bindings/ethernet/xlnx,gem.yaml | 2 +- dts/bindings/ethernet/zephyr,cdc-ecm-ethernet.yaml | 2 +- 18 files changed, 17 insertions(+), 17 deletions(-) rename dts/bindings/ethernet/{ethernet.yaml => ethernet-controller.yaml} (100%) diff --git a/dts/bindings/ethernet/atmel,gmac-common.yaml b/dts/bindings/ethernet/atmel,gmac-common.yaml index 95e063323178..93cbb4edc447 100644 --- a/dts/bindings/ethernet/atmel,gmac-common.yaml +++ b/dts/bindings/ethernet/atmel,gmac-common.yaml @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 include: - - name: ethernet.yaml + - name: ethernet-controller.yaml - name: pinctrl-device.yaml properties: diff --git a/dts/bindings/ethernet/espressif,esp32-eth.yaml b/dts/bindings/ethernet/espressif,esp32-eth.yaml index 35aa4a6f7a6e..b3021da7ca33 100644 --- a/dts/bindings/ethernet/espressif,esp32-eth.yaml +++ b/dts/bindings/ethernet/espressif,esp32-eth.yaml @@ -6,7 +6,7 @@ description: ESP32 Ethernet compatible: "espressif,esp32-eth" include: - - name: ethernet.yaml + - name: ethernet-controller.yaml properties: phy-connection-type: diff --git a/dts/bindings/ethernet/ethernet.yaml b/dts/bindings/ethernet/ethernet-controller.yaml similarity index 100% rename from dts/bindings/ethernet/ethernet.yaml rename to dts/bindings/ethernet/ethernet-controller.yaml diff --git a/dts/bindings/ethernet/litex,eth0.yaml b/dts/bindings/ethernet/litex,eth0.yaml index 50885777b197..decdc96a48ed 100644 --- a/dts/bindings/ethernet/litex,eth0.yaml +++ b/dts/bindings/ethernet/litex,eth0.yaml @@ -5,7 +5,7 @@ description: LiteX Ethernet compatible: "litex,eth0" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/microchip,enc28j60.yaml b/dts/bindings/ethernet/microchip,enc28j60.yaml index 7fd0c46bc4c1..f456b3c14faa 100644 --- a/dts/bindings/ethernet/microchip,enc28j60.yaml +++ b/dts/bindings/ethernet/microchip,enc28j60.yaml @@ -5,7 +5,7 @@ description: ENC28J60 standalone 10BASE-T Ethernet controller with SPI interface compatible: "microchip,enc28j60" -include: [spi-device.yaml, ethernet.yaml] +include: [spi-device.yaml, ethernet-controller.yaml] properties: int-gpios: diff --git a/dts/bindings/ethernet/microchip,enc424j600.yaml b/dts/bindings/ethernet/microchip,enc424j600.yaml index 767684f3a720..799917fc4da5 100644 --- a/dts/bindings/ethernet/microchip,enc424j600.yaml +++ b/dts/bindings/ethernet/microchip,enc424j600.yaml @@ -6,7 +6,7 @@ description: | compatible: "microchip,enc424j600" -include: [spi-device.yaml, ethernet.yaml] +include: [spi-device.yaml, ethernet-controller.yaml] properties: int-gpios: diff --git a/dts/bindings/ethernet/nxp,kinetis-ethernet.yaml b/dts/bindings/ethernet/nxp,kinetis-ethernet.yaml index df95dabf8fa2..84e0e009f7a0 100644 --- a/dts/bindings/ethernet/nxp,kinetis-ethernet.yaml +++ b/dts/bindings/ethernet/nxp,kinetis-ethernet.yaml @@ -5,7 +5,7 @@ description: NXP Kinetis Ethernet compatible: "nxp,kinetis-ethernet" -include: ["ethernet.yaml", "ethernet,fixed-link.yaml", "pinctrl-device.yaml"] +include: ["ethernet-controller.yaml", "ethernet,fixed-link.yaml", "pinctrl-device.yaml"] properties: reg: diff --git a/dts/bindings/ethernet/nxp,s32-netc-psi.yaml b/dts/bindings/ethernet/nxp,s32-netc-psi.yaml index dc15b8d22990..4ab34c506138 100644 --- a/dts/bindings/ethernet/nxp,s32-netc-psi.yaml +++ b/dts/bindings/ethernet/nxp,s32-netc-psi.yaml @@ -5,7 +5,7 @@ description: NXP S32 NETC Physical Station Interface (PSI) compatible: "nxp,s32-netc-psi" -include: [ethernet.yaml, pinctrl-device.yaml] +include: [ethernet-controller.yaml, pinctrl-device.yaml] properties: reg: diff --git a/dts/bindings/ethernet/nxp,s32-netc-vsi.yaml b/dts/bindings/ethernet/nxp,s32-netc-vsi.yaml index 2201232589c6..c2174b21f9a2 100644 --- a/dts/bindings/ethernet/nxp,s32-netc-vsi.yaml +++ b/dts/bindings/ethernet/nxp,s32-netc-vsi.yaml @@ -5,7 +5,7 @@ description: NXP S32 NETC Virtual Station Interface (VSI) compatible: "nxp,s32-netc-vsi" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/siemens,ivshmem-eth.yaml b/dts/bindings/ethernet/siemens,ivshmem-eth.yaml index 2c16b40c403b..6bd4de0a13f0 100644 --- a/dts/bindings/ethernet/siemens,ivshmem-eth.yaml +++ b/dts/bindings/ethernet/siemens,ivshmem-eth.yaml @@ -5,7 +5,7 @@ description: IVSHMEM Ethernet compatible: "siemens,ivshmem-eth" -include: ethernet.yaml +include: ethernet-controller.yaml properties: diff --git a/dts/bindings/ethernet/silabs,gecko-ethernet.yaml b/dts/bindings/ethernet/silabs,gecko-ethernet.yaml index 1445669f41f5..136e4cc6280f 100644 --- a/dts/bindings/ethernet/silabs,gecko-ethernet.yaml +++ b/dts/bindings/ethernet/silabs,gecko-ethernet.yaml @@ -6,7 +6,7 @@ description: SiLabs Gecko Ethernet compatible: "silabs,gecko-ethernet" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/snps,designware-ethernet.yaml b/dts/bindings/ethernet/snps,designware-ethernet.yaml index b610a7c8a02b..734eb1cced7c 100644 --- a/dts/bindings/ethernet/snps,designware-ethernet.yaml +++ b/dts/bindings/ethernet/snps,designware-ethernet.yaml @@ -5,7 +5,7 @@ description: Synopsys DesignWare Ethernet compatible: "snps,designware-ethernet" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/snps,ethernet-cyclonev.yaml b/dts/bindings/ethernet/snps,ethernet-cyclonev.yaml index e0497c08c7ed..9aa0c94039fb 100644 --- a/dts/bindings/ethernet/snps,ethernet-cyclonev.yaml +++ b/dts/bindings/ethernet/snps,ethernet-cyclonev.yaml @@ -5,7 +5,7 @@ description: Ethernet driver for Cyclone V SoC compatible: "snps,ethernet-cyclonev" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/st,stm32-ethernet.yaml b/dts/bindings/ethernet/st,stm32-ethernet.yaml index 4420006b9000..b0e5665f3374 100644 --- a/dts/bindings/ethernet/st,stm32-ethernet.yaml +++ b/dts/bindings/ethernet/st,stm32-ethernet.yaml @@ -5,7 +5,7 @@ description: ST STM32 Ethernet compatible: "st,stm32-ethernet" -include: [ethernet.yaml, pinctrl-device.yaml] +include: [ethernet-controller.yaml, pinctrl-device.yaml] properties: reg: diff --git a/dts/bindings/ethernet/ti,stellaris-ethernet.yaml b/dts/bindings/ethernet/ti,stellaris-ethernet.yaml index f9310d773c64..8a60fba0ce2c 100644 --- a/dts/bindings/ethernet/ti,stellaris-ethernet.yaml +++ b/dts/bindings/ethernet/ti,stellaris-ethernet.yaml @@ -5,7 +5,7 @@ description: TI Stellaris Ethernet compatible: "ti,stellaris-ethernet" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/wiznet,w5500.yaml b/dts/bindings/ethernet/wiznet,w5500.yaml index b37db750d1c4..1490f0763b94 100644 --- a/dts/bindings/ethernet/wiznet,w5500.yaml +++ b/dts/bindings/ethernet/wiznet,w5500.yaml @@ -5,7 +5,7 @@ description: W5500 standalone 10/100BASE-T Ethernet controller with SPI interfac compatible: "wiznet,w5500" -include: [spi-device.yaml, ethernet.yaml] +include: [spi-device.yaml, ethernet-controller.yaml] properties: int-gpios: diff --git a/dts/bindings/ethernet/xlnx,gem.yaml b/dts/bindings/ethernet/xlnx,gem.yaml index 0b1727f64de8..a4c16094b08d 100644 --- a/dts/bindings/ethernet/xlnx,gem.yaml +++ b/dts/bindings/ethernet/xlnx,gem.yaml @@ -7,7 +7,7 @@ description: Xilinx GEM Ethernet controller compatible: "xlnx,gem" -include: ethernet.yaml +include: ethernet-controller.yaml properties: reg: diff --git a/dts/bindings/ethernet/zephyr,cdc-ecm-ethernet.yaml b/dts/bindings/ethernet/zephyr,cdc-ecm-ethernet.yaml index 6a19507a21f6..24f670f9afb8 100644 --- a/dts/bindings/ethernet/zephyr,cdc-ecm-ethernet.yaml +++ b/dts/bindings/ethernet/zephyr,cdc-ecm-ethernet.yaml @@ -5,7 +5,7 @@ description: USB CDC ECM virtual Ethernet controller compatible: "zephyr,cdc-ecm-ethernet" -include: ethernet.yaml +include: ethernet-controller.yaml properties: remote-mac-address: From 07d2b62cc7c5da4b1b7abebc115e82ace7b6cf9b Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 28 Jul 2023 10:19:10 +0200 Subject: [PATCH 1971/2042] tests: subsys: canbus changing the test thread priority The test thread and the system workqueue have the same priority, so it is a bit arbitrary whether the workqueue cleans up the send context before the next send. Signed-off-by: Francois Ramu --- tests/subsys/canbus/isotp/implementation/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/canbus/isotp/implementation/prj.conf b/tests/subsys/canbus/isotp/implementation/prj.conf index af7b76b9fc38..4ab0fe51d381 100644 --- a/tests/subsys/canbus/isotp/implementation/prj.conf +++ b/tests/subsys/canbus/isotp/implementation/prj.conf @@ -7,3 +7,4 @@ CONFIG_ISOTP_ENABLE_CONTEXT_BUFFERS=y CONFIG_ISOTP_RX_BUF_COUNT=2 CONFIG_ISOTP_RX_BUF_SIZE=56 CONFIG_ISOTP_RX_SF_FF_BUF_COUNT=2 +CONFIG_ZTEST_THREAD_PRIORITY=0 From 248cd365054d9b380512c5e680519a6b8d5d4040 Mon Sep 17 00:00:00 2001 From: Francois Ramu Date: Fri, 28 Jul 2023 10:51:14 +0200 Subject: [PATCH 1972/2042] samples: subsys: nvs on nucleo_g474re requires 6kB for storage partition Add the overlay for running the samples/subsys/nvs/ application on the nucleo_g474re. Define a 6kB storage_partition at the end of the 512kB flash. Signed-off-by: Francois Ramu --- samples/subsys/nvs/boards/nucleo_g474re.overlay | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 samples/subsys/nvs/boards/nucleo_g474re.overlay diff --git a/samples/subsys/nvs/boards/nucleo_g474re.overlay b/samples/subsys/nvs/boards/nucleo_g474re.overlay new file mode 100644 index 000000000000..c6f256628b4b --- /dev/null +++ b/samples/subsys/nvs/boards/nucleo_g474re.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 512KB flash */ + storage_partition: partition@7e800 { + label = "storage"; + reg = <0x0007e800 DT_SIZE_K(6)>; + }; + }; +}; From 71a7afacbd4fb35ca66a8d92fb59d00257ef92d4 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 28 Jul 2023 21:06:17 +0200 Subject: [PATCH 1973/2042] drivers: can: mcan: add CAN_MCAN_DT_MRBA() and CAN_MCAN_DT_INST_MRBA() Add CAN_MCAN_DT_MRBA() and CAN_MCAN_DT_INST_MRBA() macros for retrieving the Bosch M_CAN Message RAM Base Address (MRBA) and clarify that the existing CAN_MCAN_DT_MRAM_ADDR() and CAN_MCAN_DT_INST_MRAM_ADDR() macros do not retrieve the base address, but rather the base address + the offset, if any. Signed-off-by: Henrik Brix Andersen --- include/zephyr/drivers/can/can_mcan.h | 28 +++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index e2162894eeaf..c1a1fb9f85d2 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -573,13 +573,25 @@ * @brief Get the Bosch M_CAN Message RAM base address * * For devicetree nodes with dedicated Message RAM area defined via devicetree, this macro returns - * the base address of the Message RAM, taking in the Message RAM offset into account. + * the base address of the Message RAM. * * @param node_id node identifier - * @return the Bosch M_CAN Message RAM base address + * @return the Bosch M_CAN Message RAM base address (MRBA) + */ +#define CAN_MCAN_DT_MRBA(node_id) \ + (mem_addr_t)DT_REG_ADDR_BY_NAME(node_id, message_ram) + +/** + * @brief Get the Bosch M_CAN Message RAM address + * + * For devicetree nodes with dedicated Message RAM area defined via devicetree, this macro returns + * the address of the Message RAM, taking in the Message RAM offset into account. + * + * @param node_id node identifier + * @return the Bosch M_CAN Message RAM address */ #define CAN_MCAN_DT_MRAM_ADDR(node_id) \ - (mem_addr_t)(DT_REG_ADDR_BY_NAME(node_id, message_ram) + CAN_MCAN_DT_MRAM_OFFSET(node_id)) + (mem_addr_t)(CAN_MCAN_DT_MRBA(node_id) + CAN_MCAN_DT_MRAM_OFFSET(node_id)) /** * @brief Get the Bosch M_CAN Message RAM size @@ -782,10 +794,18 @@ */ #define CAN_MCAN_DT_INST_MCAN_ADDR(inst) CAN_MCAN_DT_MCAN_ADDR(DT_DRV_INST(inst)) +/** + * @brief Equivalent to CAN_MCAN_DT_MRBA(DT_DRV_INST(inst)) + * @param inst DT_DRV_COMPAT instance number + * @return the Bosch M_CAN Message RAM Base Address (MRBA) + * @see CAN_MCAN_DT_MRBA() + */ +#define CAN_MCAN_DT_INST_MRBA(inst) CAN_MCAN_DT_MRBA(DT_DRV_INST(inst)) + /** * @brief Equivalent to CAN_MCAN_DT_MRAM_ADDR(DT_DRV_INST(inst)) * @param inst DT_DRV_COMPAT instance number - * @return the Bosch M_CAN Message RAM base address + * @return the Bosch M_CAN Message RAM address * @see CAN_MCAN_DT_MRAM_ADDR() */ #define CAN_MCAN_DT_INST_MRAM_ADDR(inst) CAN_MCAN_DT_MRAM_ADDR(DT_DRV_INST(inst)) From b809d5ce1049f541def9408112bef4e540f2a7b6 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Fri, 28 Jul 2023 21:09:56 +0200 Subject: [PATCH 1974/2042] drivers: can: stm32h7: fix message RAM address calculations Calculate the Bosch M_CAN Message RAM addresses relative to the Message RAM Base Address (MRBA), not the offset. Fixes: #59624 Signed-off-by: Henrik Brix Andersen --- drivers/can/can_stm32h7.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/can/can_stm32h7.c b/drivers/can/can_stm32h7.c index 7ff6fcd1eb9c..ecffd4ce1cba 100644 --- a/drivers/can/can_stm32h7.c +++ b/drivers/can/can_stm32h7.c @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); 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; @@ -132,7 +133,7 @@ static int can_stm32h7_init(const struct device *dev) return ret; } - ret = can_mcan_configure_mram(dev, stm32h7_cfg->mram, stm32h7_cfg->mram); + ret = can_mcan_configure_mram(dev, stm32h7_cfg->mrba, stm32h7_cfg->mram); if (ret != 0) { return ret; } @@ -205,6 +206,7 @@ static const struct can_mcan_ops can_stm32h7_ops = { \ 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), \ From b42212eeaa677f04056010277bc9438d65b88bca Mon Sep 17 00:00:00 2001 From: Christopher Friedt Date: Sat, 29 Jul 2023 19:46:32 -0400 Subject: [PATCH 1975/2042] tests: thrift: re-order shared_ptr reset to prevent fd leak This change fixes a file descriptor leak that snuck-in undetected in the original `gsoc-2022-thrift` project. Signed-off-by: Christopher Friedt --- tests/lib/thrift/ThriftTest/overlay-tls.conf | 16 ++++++++++++++++ tests/lib/thrift/ThriftTest/prj.conf | 14 +++++++++++++- tests/lib/thrift/ThriftTest/src/main.cpp | 6 +++--- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/tests/lib/thrift/ThriftTest/overlay-tls.conf b/tests/lib/thrift/ThriftTest/overlay-tls.conf index 2930b1fdc45c..b98beb610c33 100644 --- a/tests/lib/thrift/ThriftTest/overlay-tls.conf +++ b/tests/lib/thrift/ThriftTest/overlay-tls.conf @@ -1,5 +1,21 @@ CONFIG_THRIFT_SSL_SOCKET=y +# Currenty, in Zephyr's MBedTLS IPPROTO_TLS_1_0 implementation, 2 sockets are +# needed for every connection. +# +# Additionally, upstream Apache Thrift uses socketpair for cancellation rather +# than eventfd, since the latter is not portable to some operating systems. +# +# File Descriptor Usage +# --------------------- +# stdin, stdout, stderr: 3 +# tcp socket (accept): 1 +# tls socket (accept): 1 +# tcp sockets (client, server): 2 +# tls sockets (client, server): 2 +# socketpairs for cancellation (accept, client, server): 6 +CONFIG_POSIX_MAX_FDS=15 + # TLS configuration CONFIG_MBEDTLS=y CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y diff --git a/tests/lib/thrift/ThriftTest/prj.conf b/tests/lib/thrift/ThriftTest/prj.conf index 35361bf9b72f..4d2b145b13c4 100755 --- a/tests/lib/thrift/ThriftTest/prj.conf +++ b/tests/lib/thrift/ThriftTest/prj.conf @@ -39,7 +39,19 @@ CONFIG_NET_BUF_TX_COUNT=20 CONFIG_NET_PKT_TX_COUNT=20 CONFIG_NET_BUF_RX_COUNT=20 CONFIG_NET_PKT_RX_COUNT=20 -CONFIG_POSIX_MAX_FDS=16 + +# We can get away with using fewer sockets in the non-TLS tests because we use +# TFDServer.cpp for our server and socketpair() for our channel. We do not +# need an accept socket for the server (in contrast to TCP), it only needs 1 +# eventfd for server cancellation, and there are no cancellation sockets +# required because we close them in the testsuite. +# +# File Descriptor Usage +# --------------------- +# stdin, stdout, stderr: 3 +# socketpair for channel: 2 +# eventfd for cancellation: 1 +CONFIG_POSIX_MAX_FDS=6 # Network address config CONFIG_NET_IPV4=y diff --git a/tests/lib/thrift/ThriftTest/src/main.cpp b/tests/lib/thrift/ThriftTest/src/main.cpp index f42090ee37e2..b903f3c8a9b3 100644 --- a/tests/lib/thrift/ThriftTest/src/main.cpp +++ b/tests/lib/thrift/ThriftTest/src/main.cpp @@ -153,13 +153,13 @@ static void thrift_test_after(void *data) pthread_join(context.server_thread, NULL); - context.server.reset(); - context.client.reset(); - for (auto &fd : context.fds) { close(fd); fd = -1; } + + context.client.reset(); + context.server.reset(); } ZTEST_SUITE(thrift, NULL, thrift_test_setup, thrift_test_before, thrift_test_after, NULL); From dfeb2d902756863c7bb1ae47c0996be678669f20 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 30 Jul 2023 20:37:35 +0100 Subject: [PATCH 1976/2042] ethernet: eth_stm32_hal: fix unused variable build warning Fix an unused variable build warning that was happening in certain configurations. Move the variables in the only condition where they are actually used. west build -p -b nucleo_f429zi \ -T samples/net/cloud/aws_iot_mqtt/sample.net.cloud.aws_iot_mqtt Signed-off-by: Fabio Baltieri --- 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 4d8ea3479f2f..bdb4771d01f3 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -1098,9 +1098,6 @@ void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_handle) static void generate_mac(uint8_t *mac_addr) { - uint8_t unique_device_ID_12_bytes[12]; - uint32_t result_mac_32_bits; - #if defined(ETH_STM32_RANDOM_MAC) /* Either CONFIG_ETH_STM32_HAL_RANDOM_MAC or device tree property */ /* "zephyr,random-mac-address" is set, generate a random mac address */ @@ -1118,6 +1115,9 @@ static void generate_mac(uint8_t *mac_addr) mac_addr[4] = CONFIG_ETH_STM32_HAL_MAC4; mac_addr[5] = CONFIG_ETH_STM32_HAL_MAC5; #else + uint8_t unique_device_ID_12_bytes[12]; + uint32_t result_mac_32_bits; + /* Nothing defined by the user, use device id */ hwinfo_get_device_id(unique_device_ID_12_bytes, 12); result_mac_32_bits = crc32_ieee((uint8_t *)unique_device_ID_12_bytes, 12); From 097c568c819551c18afde2ecf2822c64f3eb3513 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 31 Jul 2023 07:48:20 +0100 Subject: [PATCH 1977/2042] mgmt: mcumgr: grp: fs_mgmt: Fix wrong error checking Fixes an issue with not properly checking error responses. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 4cbd6b893b3f..876e28c385e2 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -280,9 +280,9 @@ static int fs_mgmt_file_download(struct smp_streamer *ctxt) rc = fs_open(&fs_mgmt_ctxt.file, path, FS_O_READ); if (rc != 0) { - if (rc == EINVAL) { + if (rc == -EINVAL) { rc = FS_MGMT_RET_RC_FILE_INVALID_NAME; - } else if (ENOENT) { + } else if (rc == -ENOENT) { rc = FS_MGMT_RET_RC_FILE_NOT_FOUND; } else { rc = FS_MGMT_RET_RC_UNKNOWN; @@ -422,9 +422,9 @@ static int fs_mgmt_file_upload(struct smp_streamer *ctxt) rc = fs_open(&fs_mgmt_ctxt.file, file_name, FS_O_CREATE | FS_O_WRITE); if (rc != 0) { - if (rc == EINVAL) { + if (rc == -EINVAL) { rc = FS_MGMT_RET_RC_FILE_INVALID_NAME; - } else if (ENOENT) { + } else if (rc == -ENOENT) { rc = FS_MGMT_RET_RC_FILE_NOT_FOUND; } else { rc = FS_MGMT_RET_RC_UNKNOWN; @@ -741,9 +741,9 @@ static int fs_mgmt_file_hash_checksum(struct smp_streamer *ctxt) rc = fs_open(&file, path, FS_O_READ); if (rc != 0) { - if (rc == EINVAL) { + if (rc == -EINVAL) { rc = FS_MGMT_RET_RC_FILE_INVALID_NAME; - } else if (ENOENT) { + } else if (rc == -ENOENT) { rc = FS_MGMT_RET_RC_FILE_NOT_FOUND; } else { rc = FS_MGMT_RET_RC_UNKNOWN; From 8a2e768ff716e5302186b375794df1cf6edd960c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 28 Jul 2023 09:51:52 +0100 Subject: [PATCH 1978/2042] doc: services: device_mgmt: smp_groups: Clarify img_mgmt upload Clarifies the details in the upload section of img_mgmt for MCUmgr to better describe when fields should be sent, including a note when a server responds with offset of 0. Signed-off-by: Jamie McCrae --- .../device_mgmt/smp_groups/smp_group_1.rst | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_1.rst b/doc/services/device_mgmt/smp_groups/smp_group_1.rst index 61622ee71b2e..2389d9758ad4 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_1.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_1.rst @@ -269,7 +269,7 @@ CBOR data of request: (str,opt)"len" : (uint) (str)"off" : (uint) (str,opt)"sha" : (byte str) - (str,opt)"data" : (byte str) + (str)"data" : (byte str) (str,opt)"upgrade" : (bool) } @@ -278,41 +278,45 @@ where: .. table:: :align: center - +-----------------------+---------------------------------------------------+ - | "image" | optional image number, it does not have to appear | - | | in request at all, in which case it is assumed to | - | | be 0; only request with "off" 0 can contain | - | | image number | - +-----------------------+---------------------------------------------------+ - | "len" | optional length of an image, it only appears in | - | | the first packet of request, where "off" is 0 | - +-----------------------+---------------------------------------------------+ - | "off" | offset of image chunk the request carries | - +-----------------------+---------------------------------------------------+ - | "sha" | SHA256 hash of an upload; this is used to | - | | identify an upload session (e.g. to allow MCUmgr | - | | to continue a broken session), and for image | - | | verification purposes. This must be a full SHA256 | - | | hash of the whole image being uploaded, or not | - | | included if the hash is not available (in which | - | | case, upload session continuation and image | - | | verification functionality will be unavailable). | - | | Should only be present if "off" is zero. | - +-----------------------+---------------------------------------------------+ - | "data" | optional image data | - +-----------------------+---------------------------------------------------+ - | "upgrade" | optional flag that states that only upgrade | - | | should be allowed, so if the version of uploaded | - | | software is not higher then already on a device, | - | | the image upload will be rejected. | - | | Zephyr only compares major, minor and revision | - | | (x.y.z). | - +-----------------------+---------------------------------------------------+ + +-----------+--------------------------------------------------------------------------------+ + | "image" | optional image number, it does not have to appear in request at all, in which | + | | case it is assumed to be 0. Should only be present when "off" is 0. | + +-----------+--------------------------------------------------------------------------------+ + | "len" | optional length of an image. Must appear when "off" is 0. | + +-----------+--------------------------------------------------------------------------------+ + | "off" | offset of image chunk the request carries. | + +-----------+--------------------------------------------------------------------------------+ + | "sha" | SHA256 hash of an upload; this is used to identify an upload session (e.g. to | + | | allow MCUmgr to continue a broken session), and for image verification | + | | purposes. This must be a full SHA256 hash of the whole image being uploaded, | + | | or not included if the hash is not available (in which case, upload session | + | | continuation and image verification functionality will be unavailable). Should | + | | only be present when "off" is 0. | + +-----------+--------------------------------------------------------------------------------+ + | "data" | image data to write at provided offset. | + +-----------+--------------------------------------------------------------------------------+ + | "upgrade" | optional flag that states that only upgrade should be allowed, so if the | + | | version of uploaded software is not higher then already on a device, the image | + | | upload will be rejected. Zephyr compares major, minor and revision (x.y.z) by | + | | default unless | + | | :kconfig:option:`CONFIG_MCUMGR_GRP_IMG_VERSION_CMP_USE_BUILD_NUMBER` is set, | + | | whereby it will compare build numbers too. Should only be present when "off" | + | | is 0. | + +-----------+--------------------------------------------------------------------------------+ .. note:: There is no field representing size of chunk that is carried as "data" because that information is embedded within "data" field itself. +.. note:: + It is possible that a server will respond to an upload with "off" of 0, this + may happen if an upload on another transport (or outside of MCUmgr entirely) + is started, if the device has rebooted or if a packet has been lost. If this + happens, a client must re-send all the required and optional fields that it + sent in the original first packet so that the upload state can be re-created + by the server. If the original fields are not included, the upload will be + unable to continue. + The MCUmgr library uses "sha" field to tag ongoing update session, to be able to continue it in case when it gets broken, and for upload verification purposes. From 9422fc6e20e0734997b2f3c6d637dd460db6a169 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 28 Jul 2023 08:36:28 +0100 Subject: [PATCH 1979/2042] mgmt: mcumgr: grp: img_mgmt: Fix not checking image upload size Fixes an issue whereby upload image size would not be checked in the first packet of an upload, which would allow an image to be uploaded until it reached the point of it being too large to fit anymore. Signed-off-by: Jamie McCrae --- .../mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 4 +++ .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 2 ++ .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 33 +++++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) 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 9e8a6e898b5a..2ab4e67ab73b 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -150,6 +150,9 @@ enum img_mgmt_ret_code_t { /** The image vector table is invalid. */ IMG_MGMT_RET_RC_INVALID_IMAGE_VECTOR_TABLE, + + /** The image it too large to fit. */ + IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE, }; /** @@ -352,6 +355,7 @@ extern const char *img_mgmt_err_str_flash_erase_failed; extern const char *img_mgmt_err_str_flash_write_failed; extern const char *img_mgmt_err_str_downgrade; extern const char *img_mgmt_err_str_image_bad_flash_addr; +extern const char *img_mgmt_err_str_image_too_large; #else #define IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, rsn) #define IMG_MGMT_UPLOAD_ACTION_RC_RSN(action) NULL diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index bcac20bd8431..848c6cce72b9 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -96,6 +96,7 @@ const char *img_mgmt_err_str_flash_erase_failed = "fa erase fail"; const char *img_mgmt_err_str_flash_write_failed = "fa write fail"; const char *img_mgmt_err_str_downgrade = "downgrade"; const char *img_mgmt_err_str_image_bad_flash_addr = "img addr mismatch"; +const char *img_mgmt_err_str_image_too_large = "img too large"; #endif void img_mgmt_take_lock(void) @@ -811,6 +812,7 @@ static int img_mgmt_translate_error_code(uint16_t ret) case IMG_MGMT_RET_RC_FLASH_AREA_DEVICE_NULL: case IMG_MGMT_RET_RC_INVALID_IMAGE_HEADER_MAGIC: case IMG_MGMT_RET_RC_INVALID_IMAGE_VECTOR_TABLE: + case IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE: case IMG_MGMT_RET_RC_UNKNOWN: default: rc = MGMT_ERR_EUNKNOWN; 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 894fdee1ce9e..597271cbd938 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 @@ -570,6 +570,8 @@ 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 (req->img_data.len < sizeof(struct image_header)) { /* Image header is the first thing in the image */ IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed); @@ -614,30 +616,35 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, return IMG_MGMT_RET_RC_NO_FREE_SLOT; } -#if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT) - if (hdr->ih_flags & IMAGE_F_ROM_FIXED) { - const struct flash_area *fa; + rc = flash_area_open(action->area_id, &fa); + 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", action->area_id, rc); + return IMG_MGMT_RET_RC_FLASH_OPEN_FAILED; + } - rc = flash_area_open(action->area_id, &fa); - 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", action->area_id, - rc); - return IMG_MGMT_RET_RC_FLASH_OPEN_FAILED; - } + /* Check that the area is of sufficient size to store the new image */ + if (req->size > fa->fa_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: %u > %u", req->size, fa->fa_size); + return IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE; + } +#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) { IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_image_bad_flash_addr); flash_area_close(fa); return IMG_MGMT_RET_RC_INVALID_FLASH_ADDRESS; } - - flash_area_close(fa); } #endif + flash_area_close(fa); if (req->upgrade) { /* User specified upgrade-only. Make sure new image version is From 588f6acbd5641ca469d05345900aff22396d443b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 28 Jul 2023 09:13:30 +0100 Subject: [PATCH 1980/2042] mgmt: mcumgr: grp: img_mgmt: Fix not checking write bounds Fixes an issue whereby the data packets were not checked to ensure that the client has not attempted to write more data than the size that was provided in the original upload packet. Signed-off-by: Jamie McCrae --- include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h | 4 ++++ subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 2 ++ subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 8 ++++++++ 3 files changed, 14 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 2ab4e67ab73b..3a86873e4088 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -153,6 +153,9 @@ enum img_mgmt_ret_code_t { /** The image it too large to fit. */ IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE, + + /** The amount of data sent is larger than the provided image size. */ + IMG_MGMT_RET_RC_INVALID_IMAGE_DATA_OVERRUN, }; /** @@ -356,6 +359,7 @@ extern const char *img_mgmt_err_str_flash_write_failed; extern const char *img_mgmt_err_str_downgrade; extern const char *img_mgmt_err_str_image_bad_flash_addr; extern const char *img_mgmt_err_str_image_too_large; +extern const char *img_mgmt_err_str_data_overrun; #else #define IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, rsn) #define IMG_MGMT_UPLOAD_ACTION_RC_RSN(action) NULL diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 848c6cce72b9..967ff37483a3 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -97,6 +97,7 @@ const char *img_mgmt_err_str_flash_write_failed = "fa write fail"; const char *img_mgmt_err_str_downgrade = "downgrade"; const char *img_mgmt_err_str_image_bad_flash_addr = "img addr mismatch"; const char *img_mgmt_err_str_image_too_large = "img too large"; +const char *img_mgmt_err_str_data_overrun = "data overrun"; #endif void img_mgmt_take_lock(void) @@ -813,6 +814,7 @@ static int img_mgmt_translate_error_code(uint16_t ret) case IMG_MGMT_RET_RC_INVALID_IMAGE_HEADER_MAGIC: case IMG_MGMT_RET_RC_INVALID_IMAGE_VECTOR_TABLE: case IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE: + case IMG_MGMT_RET_RC_INVALID_IMAGE_DATA_OVERRUN: case IMG_MGMT_RET_RC_UNKNOWN: default: rc = MGMT_ERR_EUNKNOWN; 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 597271cbd938..4a995989bbad 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 @@ -682,6 +682,14 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, */ return IMG_MGMT_RET_RC_OK; } + + if ((req->off + req->img_data.len) > action->size) { + /* Data overrun, the amount of data written would be more than the size + * of the image that the client originally sent + */ + IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_data_overrun); + return IMG_MGMT_RET_RC_INVALID_IMAGE_DATA_OVERRUN; + } } action->write_bytes = req->img_data.len; From 63aca8d8686448bc23673948b7379d57550b2bde Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 19 Jan 2023 21:25:12 +0100 Subject: [PATCH 1981/2042] Bluetooth: ISO: Add advanced unicast ISO parameters Add support for setting advanced unicast ISO parameters using the ISO test commands. This allows the host to set ISO parameters that the controller normally would handle. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/iso.h | 92 +++++++++++- subsys/bluetooth/Kconfig.iso | 8 + subsys/bluetooth/host/iso.c | 258 +++++++++++++++++++++++++++++++-- 3 files changed, 341 insertions(+), 17 deletions(-) diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index c5ebd5d7176c..6eafa66f9443 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -49,6 +49,10 @@ extern "C" { #define BT_ISO_SDU_INTERVAL_MIN 0x0000FFU /** Maximum interval value in microseconds */ #define BT_ISO_SDU_INTERVAL_MAX 0x0FFFFFU +/** Minimum ISO interval (N * 1.25 ms) */ +#define BT_ISO_ISO_INTERVAL_MIN 0x0004U +/** Maximum ISO interval (N * 1.25 ms) */ +#define BT_ISO_ISO_INTERVAL_MAX 0x0C80U /** Minimum latency value in milliseconds */ #define BT_ISO_LATENCY_MIN 0x0005 /** Maximum latency value in milliseconds */ @@ -63,8 +67,28 @@ extern "C" { #define BT_ISO_FRAMING_FRAMED 0x01 /** Maximum number of isochronous channels in a single group */ #define BT_ISO_MAX_GROUP_ISO_COUNT 0x1F +/** Minimum SDU size */ +#define BT_ISO_MIN_SDU 0x0001 /** Maximum SDU size */ #define BT_ISO_MAX_SDU 0x0FFF +/** Minimum PDU size */ +#define BT_ISO_CONNECTED_PDU_MIN 0x0000U +/** Minimum PDU size */ +#define BT_ISO_BROADCAST_PDU_MIN 0x0001U +/** Maximum PDU size */ +#define BT_ISO_PDU_MAX 0x00FBU +/** Minimum burst number */ +#define BT_ISO_BN_MIN 0x01U +/** Maximum burst number */ +#define BT_ISO_BN_MAX 0x0FU +/** Minimum flush timeout */ +#define BT_ISO_FT_MIN 0x01U +/** Maximum flush timeout */ +#define BT_ISO_FT_MAX 0xFFU +/** Minimum number of subevents */ +#define BT_ISO_NSE_MIN 0x01U +/** Maximum number of subevents */ +#define BT_ISO_NSE_MAX 0x1FU /** Minimum BIG sync timeout value (N * 10 ms) */ #define BT_ISO_SYNC_TIMEOUT_MIN 0x000A /** Maximum BIG sync timeout value (N * 10 ms) */ @@ -154,7 +178,10 @@ struct bt_iso_chan_io_qos { * Setting BT_GAP_LE_PHY_NONE is invalid. */ uint8_t phy; - /** Channel Retransmission Number. */ + /** @brief Channel Retransmission Number. + * + * This value is ignored if any advanced ISO parameters are set. + */ uint8_t rtn; /** @brief Channel data path reference * @@ -162,6 +189,27 @@ struct bt_iso_chan_io_qos { * to BT_ISO_DATA_PATH_HCI). */ struct bt_iso_chan_path *path; + +#if defined(CONFIG_BT_ISO_ADVANCED) + /** @brief Maximum PDU size + * + * Maximum size, in octets, of the payload from link layer to link + * layer. + * + * Value range @ref BT_ISO_CONNECTED_PDU_MIN to @ref BT_ISO_PDU_MAX for + * connected ISO. + * + * Value range @ref BT_ISO_BROADCAST_PDU_MIN to @ref BT_ISO_PDU_MAX for + * broadcast ISO. + */ + uint16_t max_pdu; + + /** @brief Burst number + * + * Value range @ref BT_ISO_BN_MIN to @ref BT_ISO_BN_MAX. + */ + uint8_t burst_number; +#endif /* CONFIG_BT_ISO_ADVANCED */ }; /** @brief ISO Channel QoS structure. */ @@ -182,6 +230,16 @@ struct bt_iso_chan_qos { * isochronous transmitter. */ struct bt_iso_chan_io_qos *tx; + +#if defined(CONFIG_BT_ISO_ADVANCED) + /** @brief Number of subevents + * + * Maximum number of subevents in each CIS or BIS event. + * + * Value range @ref BT_ISO_NSE_MIN to @ref BT_ISO_NSE_MAX. + */ + uint8_t num_subevents; +#endif /* CONFIG_BT_ISO_ADVANCED */ }; /** @brief ISO Channel Data Path structure. */ @@ -276,6 +334,8 @@ struct bt_iso_cig_param { /** @brief Channel Latency in ms. * * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. */ uint16_t latency; @@ -300,6 +360,36 @@ struct bt_iso_cig_param { * BT_ISO_FRAMING_FRAMED for framed. */ uint8_t framing; + +#if defined(CONFIG_BT_ISO_ADVANCED) + /** @brief Central to Peripheral flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Central to Peripheral. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX + */ + uint8_t c_to_p_ft; + + /** @brief Peripheral to Central flush timeout + * + * The flush timeout in multiples of ISO_Interval for each payload sent + * from the Peripheral to Central. + * + * Value range from @ref BT_ISO_FT_MIN to @ref BT_ISO_FT_MAX. + */ + uint8_t p_to_c_ft; + + /** @brief ISO interval + * + * Time between consecutive CIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to + * @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_ADVANCED */ + }; /** ISO connection parameters structure */ diff --git a/subsys/bluetooth/Kconfig.iso b/subsys/bluetooth/Kconfig.iso index f77fe75c2ea2..553ff3a7fb42 100644 --- a/subsys/bluetooth/Kconfig.iso +++ b/subsys/bluetooth/Kconfig.iso @@ -114,6 +114,14 @@ config BT_ISO_RX_MTU help Maximum MTU for Isochronous channels RX buffers. +config BT_ISO_ADVANCED + bool "Advanced ISO parameters" + help + Enabling advanced ISO parameters will allow the use of the ISO test + parameters for creating a CIG or a BIG. These test parameters were + intended for testing, but can be used to allow the host to set more + settings that are otherwise usually controlled by the controller. + if BT_ISO_UNICAST config BT_ISO_MAX_CIG diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 0dd182fd2bd5..3416f4b9b4c4 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -815,21 +815,55 @@ int bt_iso_chan_send(struct bt_iso_chan *chan, struct net_buf *buf, #if defined(CONFIG_BT_ISO_CENTRAL) || defined(CONFIG_BT_ISO_BROADCASTER) static bool valid_chan_io_qos(const struct bt_iso_chan_io_qos *io_qos, - bool is_tx) + bool is_tx, bool is_broadcast, bool advanced) { const size_t max_mtu = (is_tx ? CONFIG_BT_ISO_TX_MTU : CONFIG_BT_ISO_RX_MTU); const size_t max_sdu = MIN(max_mtu, BT_ISO_MAX_SDU); if (io_qos->sdu > max_sdu) { - LOG_DBG("sdu (%u) shall be smaller than %zu", io_qos->sdu, max_sdu); + LOG_DBG("sdu (%u) shall be smaller or equal to %zu", io_qos->sdu, max_sdu); + return false; } - if (io_qos->phy > BT_GAP_LE_PHY_CODED) { - LOG_DBG("Invalid phy %u", io_qos->phy); + if (!IN_RANGE(io_qos->phy, BT_GAP_LE_PHY_1M, BT_GAP_LE_PHY_CODED)) { + LOG_DBG("Invalid PHY %u", io_qos->phy); + return false; } +#if defined(CONFIG_BT_ISO_ADVANCED) + if (advanced) { + if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && is_broadcast) { + if (!IN_RANGE(io_qos->max_pdu, + BT_ISO_BROADCAST_PDU_MIN, + BT_ISO_PDU_MAX)) { + LOG_DBG("Invalid PDU %u", io_qos->max_pdu); + + return false; + } + } else if (IS_ENABLED(CONFIG_BT_ISO_CENTRAL)) { + if (!IN_RANGE(io_qos->max_pdu, + BT_ISO_CONNECTED_PDU_MIN, + BT_ISO_PDU_MAX)) { + LOG_DBG("Invalid PDU %u", io_qos->max_pdu); + + return false; + } + } + + if (!IN_RANGE(io_qos->burst_number, + BT_ISO_BN_MIN, + BT_ISO_BN_MAX)) { + LOG_DBG("Invalid BN %u", io_qos->burst_number); + + return false; + } + } +#else + ARG_UNUSED(advanced); +#endif /* CONFIG_BT_ISO_ADVANCED */ + return true; } #endif /* CONFIG_BT_ISO_CENTRAL || CONFIG_BT_ISO_BROADCASTER */ @@ -1399,10 +1433,19 @@ static void bt_iso_remove_data_path(struct bt_conn *iso) } } -static bool valid_chan_qos(const struct bt_iso_chan_qos *qos) +static bool valid_chan_qos(const struct bt_iso_chan_qos *qos, bool advanced) { +#if defined(CONFIG_BT_ISO_ADVANCED) + if (advanced && + !IN_RANGE(qos->num_subevents, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) { + LOG_DBG("Invalid NSE: %u", qos->num_subevents); + + return false; + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + if (qos->rx != NULL) { - if (!valid_chan_io_qos(qos->rx, false)) { + if (!valid_chan_io_qos(qos->rx, false, false, advanced)) { LOG_DBG("Invalid rx qos"); return false; } @@ -1412,7 +1455,7 @@ static bool valid_chan_qos(const struct bt_iso_chan_qos *qos) } if (qos->tx != NULL) { - if (!valid_chan_io_qos(qos->tx, true)) { + if (!valid_chan_io_qos(qos->tx, true, false, advanced)) { LOG_DBG("Invalid tx qos"); return false; } @@ -1526,6 +1569,138 @@ static struct net_buf *hci_le_set_cig_params(const struct bt_iso_cig *cig, return rsp; } +#if defined(CONFIG_BT_ISO_ADVANCED) +static struct net_buf *hci_le_set_cig_test_params(const struct bt_iso_cig *cig, + const struct bt_iso_cig_param *param) +{ + struct bt_hci_cp_le_set_cig_params_test *req; + struct bt_hci_cis_params_test *cis_param; + struct net_buf *buf; + struct net_buf *rsp; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_CIG_PARAMS_TEST, + sizeof(*req) + sizeof(*cis_param) * param->num_cis); + if (!buf) { + return NULL; + } + + req = net_buf_add(buf, sizeof(*req)); + + memset(req, 0, sizeof(*req)); + + req->cig_id = cig->id; + sys_put_le24(param->interval, req->c_interval); + sys_put_le24(param->interval, req->p_interval); + + req->c_ft = param->c_to_p_ft; + req->p_ft = param->p_to_c_ft; + req->iso_interval = sys_cpu_to_le16(param->iso_interval); + req->sca = param->sca; + req->packing = param->packing; + req->framing = param->framing; + req->num_cis = param->num_cis; + + LOG_DBG("id %u, SDU interval %u, c_ft %u, p_ft %u, iso_interval %u, " + "sca %u, packing %u, framing %u, num_cis %u", + cig->id, param->interval, param->c_to_p_ft, param->p_to_c_ft, + param->iso_interval, param->sca, param->packing, + param->framing, param->num_cis); + + /* Program the cis parameters */ + for (uint8_t i = 0U; i < param->num_cis; i++) { + const struct bt_iso_chan *cis = param->cis_channels[i]; + const struct bt_iso_chan_qos *qos = cis->qos; + + cis_param = net_buf_add(buf, sizeof(*cis_param)); + + memset(cis_param, 0, sizeof(*cis_param)); + + cis_param->cis_id = cis->iso->iso.cis_id; + cis_param->nse = qos->num_subevents; + + if (!qos->tx && !qos->rx) { + LOG_ERR("Both TX and RX QoS are disabled"); + net_buf_unref(buf); + return NULL; + } + + if (!qos->tx) { + /* Use RX PHY if TX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->c_phy = qos->rx->phy; + } else { + cis_param->c_sdu = sys_cpu_to_le16(qos->tx->sdu); + cis_param->c_pdu = sys_cpu_to_le16(qos->tx->max_pdu); + cis_param->c_phy = qos->tx->phy; + cis_param->c_bn = qos->tx->burst_number; + } + + if (!qos->rx) { + /* Use TX PHY if RX is not set (disabled) + * to avoid setting invalid values + */ + cis_param->p_phy = qos->tx->phy; + } else { + cis_param->p_sdu = sys_cpu_to_le16(qos->rx->sdu); + cis_param->p_pdu = sys_cpu_to_le16(qos->rx->max_pdu); + cis_param->p_phy = qos->rx->phy; + cis_param->p_bn = qos->rx->burst_number; + } + + LOG_DBG("[%d]: id %u, nse %u c_sdu %u, p_sdu %u, c_pdu %u, " + "p_pdu %u, c_phy %u, p_phy %u, c_bn %u, p_bn %u", + i, cis_param->cis_id, cis_param->nse, cis_param->c_sdu, + cis_param->p_sdu, cis_param->c_pdu, cis_param->p_pdu, + cis_param->c_phy, cis_param->p_phy, cis_param->c_bn, + cis_param->p_bn); + } + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_CIG_PARAMS_TEST, buf, &rsp); + if (err) { + return NULL; + } + + return rsp; +} + +static bool is_advanced_cig_param(const struct bt_iso_cig_param *param) +{ + if (param->c_to_p_ft != 0U || + param->p_to_c_ft != 0U || + param->iso_interval != 0U) { + return true; + } + + /* Check if any of the CIS contain any test-param-only values */ + for (uint8_t i = 0U; i < param->num_cis; i++) { + const struct bt_iso_chan *cis = param->cis_channels[i]; + const struct bt_iso_chan_qos *qos = cis->qos; + + if (qos->num_subevents > 0U) { + return true; + } + + if (qos->tx != NULL) { + if (qos->tx->max_pdu > 0U || + qos->tx->burst_number > 0U) { + return true; + } + } + + if (qos->rx != NULL) { + if (qos->rx->max_pdu > 0U || + qos->rx->burst_number > 0U) { + return true; + } + } + } + + return false; +} +#endif /* CONFIG_BT_ISO_ADVANCED */ + static struct bt_iso_cig *get_cig(const struct bt_iso_chan *iso_chan) { if (iso_chan->iso == NULL) { @@ -1607,7 +1782,7 @@ static void cleanup_cig(struct bt_iso_cig *cig) memset(cig, 0, sizeof(*cig)); } -static bool valid_cig_param(const struct bt_iso_cig_param *param) +static bool valid_cig_param(const struct bt_iso_cig_param *param, bool advanced) { if (param == NULL) { return false; @@ -1626,7 +1801,7 @@ static bool valid_cig_param(const struct bt_iso_cig_param *param) return false; } - if (!valid_chan_qos(cis->qos)) { + if (!valid_chan_qos(cis->qos, advanced)) { LOG_DBG("cis_channels[%d]: Invalid QOS", i); return false; } @@ -1664,12 +1839,39 @@ static bool valid_cig_param(const struct bt_iso_cig_param *param) return false; } - if (param->latency < BT_ISO_LATENCY_MIN || - param->latency > BT_ISO_LATENCY_MAX) { + if (!advanced && + (param->latency < BT_ISO_LATENCY_MIN || + param->latency > BT_ISO_LATENCY_MAX)) { LOG_DBG("Invalid latency: %u", param->latency); return false; } +#if defined(CONFIG_BT_ISO_ADVANCED) + if (advanced) { + if (!IN_RANGE(param->c_to_p_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + LOG_DBG("Invalid Central to Peripheral FT %u", + param->c_to_p_ft); + + return false; + } + + if (!IN_RANGE(param->p_to_c_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + LOG_DBG("Invalid Peripheral to Central FT %u", + param->p_to_c_ft); + + return false; + } + + if (!IN_RANGE(param->iso_interval, + BT_ISO_ISO_INTERVAL_MIN, + BT_ISO_ISO_INTERVAL_MAX)) { + LOG_DBG("Invalid ISO interval %u", param->iso_interval); + + return false; + } + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + return true; } @@ -1681,6 +1883,7 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param, struct bt_iso_cig *cig; struct bt_hci_rp_le_set_cig_params *cig_rsp; struct bt_iso_chan *cis; + bool advanced = false; int i; CHECKIF(out_cig == NULL) { @@ -1706,7 +1909,11 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param, return -EINVAL; } - CHECKIF(!valid_cig_param(param)) { +#if defined(CONFIG_BT_ISO_ADVANCED) + advanced = is_advanced_cig_param(param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + + CHECKIF(!valid_cig_param(param, advanced)) { LOG_DBG("Invalid CIG params"); return -EINVAL; } @@ -1724,7 +1931,14 @@ int bt_iso_cig_create(const struct bt_iso_cig_param *param, return err; } - rsp = hci_le_set_cig_params(cig, param); + if (!advanced) { + rsp = hci_le_set_cig_params(cig, param); +#if defined(CONFIG_BT_ISO_ADVANCED) + } else { + rsp = hci_le_set_cig_test_params(cig, param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + } + if (rsp == NULL) { LOG_WRN("Unexpected response to hci_le_set_cig_params"); err = -EIO; @@ -1785,6 +1999,7 @@ int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, struct bt_hci_rp_le_set_cig_params *cig_rsp; uint8_t existing_num_cis; struct bt_iso_chan *cis; + bool advanced = false; struct net_buf *rsp; int err; int i; @@ -1799,7 +2014,11 @@ int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, return -EINVAL; } - CHECKIF(!valid_cig_param(param)) { +#if defined(CONFIG_BT_ISO_ADVANCED) + advanced = is_advanced_cig_param(param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + + CHECKIF(!valid_cig_param(param, advanced)) { LOG_DBG("Invalid CIG params"); return -EINVAL; } @@ -1825,7 +2044,14 @@ int bt_iso_cig_reconfigure(struct bt_iso_cig *cig, return err; } - rsp = hci_le_set_cig_params(cig, param); + if (!advanced) { + rsp = hci_le_set_cig_params(cig, param); +#if defined(CONFIG_BT_ISO_ADVANCED) + } else { + rsp = hci_le_set_cig_test_params(cig, param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + } + if (rsp == NULL) { LOG_WRN("Unexpected response to hci_le_set_cig_params"); err = -EIO; @@ -2375,7 +2601,7 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param } CHECKIF(bis->qos->tx == NULL || - !valid_chan_io_qos(bis->qos->tx, true)) { + !valid_chan_io_qos(bis->qos->tx, true, true, false)) { LOG_DBG("bis_channels[%u]: Invalid QOS", i); return -EINVAL; } From 5a66daa94d60cd1bd64611a1b248c3cd571af9d0 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 27 Jan 2023 10:19:03 +0100 Subject: [PATCH 1982/2042] Bluetooth: ISO: Add broadcast RTN check in valid_chan_io_qos The RTN value range for broadcast is more limited than connected ISO. Signed-off-by: Emil Gydesen --- subsys/bluetooth/host/iso.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 3416f4b9b4c4..101fa458a08e 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -832,6 +832,14 @@ static bool valid_chan_io_qos(const struct bt_iso_chan_io_qos *io_qos, return false; } + if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && + is_broadcast && + io_qos->rtn > BT_ISO_BROADCAST_RTN_MAX) { + LOG_DBG("Invalid RTN %u", io_qos->phy); + + return false; + } + #if defined(CONFIG_BT_ISO_ADVANCED) if (advanced) { if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) && is_broadcast) { From 2187f6b29c80b05356d69f3431ff62b4ad0f5b33 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 19 Jan 2023 22:18:39 +0100 Subject: [PATCH 1983/2042] samples: Bluetooth: ISO connected benchmark advanced ISO Add (optional) advanced ISO support for the benchmark ISO sample. The CONFIG_BT_ISO_ADVANCED Kconfig simply needs to be enabled in order to support the advanced settings. This also reduces the number of default channels supported to 1. Signed-off-by: Emil Gydesen --- .../iso_connected_benchmark/src/main.c | 230 +++++++++++++++++- 1 file changed, 228 insertions(+), 2 deletions(-) diff --git a/samples/bluetooth/iso_connected_benchmark/src/main.c b/samples/bluetooth/iso_connected_benchmark/src/main.c index ed2bd0f3b28b..7eb5b05cbb9f 100644 --- a/samples/bluetooth/iso_connected_benchmark/src/main.c +++ b/samples/bluetooth/iso_connected_benchmark/src/main.c @@ -35,9 +35,17 @@ enum benchmark_role { #define DEFAULT_CIS_SDU_SIZE CONFIG_BT_ISO_TX_MTU #define DEFAULT_CIS_PACKING 0 #define DEFAULT_CIS_FRAMING 0 -#define DEFAULT_CIS_COUNT CONFIG_BT_ISO_MAX_CHAN +#define DEFAULT_CIS_COUNT 1U #define DEFAULT_CIS_SEC_LEVEL BT_SECURITY_L1 +#if defined(CONFIG_BT_ISO_ADVANCED) +#define DEFAULT_CIS_NSE BT_ISO_NSE_MIN +#define DEFAULT_CIS_BN BT_ISO_BN_MIN +#define DEFAULT_CIS_PDU_SIZE CONFIG_BT_ISO_TX_MTU +#define DEFAULT_CIS_FT BT_ISO_FT_MIN +#define DEFAULT_CIS_ISO_INTERVAL DEFAULT_CIS_INTERVAL_US / 1250U /* N * 1.25 ms */ +#endif /* CONFIG_BT_ISO_ADVANCED */ + #define BUFFERS_ENQUEUED 2 /* Number of buffers enqueue for each channel */ BUILD_ASSERT(BUFFERS_ENQUEUED * CONFIG_BT_ISO_MAX_CHAN <= CONFIG_BT_ISO_TX_BUF_COUNT, @@ -83,17 +91,28 @@ static struct bt_iso_chan_io_qos iso_tx_qos = { .sdu = DEFAULT_CIS_SDU_SIZE, /* bytes */ .rtn = DEFAULT_CIS_RTN, .phy = DEFAULT_CIS_PHY, +#if defined(CONFIG_BT_ISO_ADVANCED) + .max_pdu = DEFAULT_CIS_PDU_SIZE, + .burst_number = DEFAULT_CIS_BN, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static struct bt_iso_chan_io_qos iso_rx_qos = { .sdu = DEFAULT_CIS_SDU_SIZE, /* bytes */ .rtn = DEFAULT_CIS_RTN, .phy = DEFAULT_CIS_PHY, +#if defined(CONFIG_BT_ISO_ADVANCED) + .max_pdu = DEFAULT_CIS_PDU_SIZE, + .burst_number = DEFAULT_CIS_BN, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static struct bt_iso_chan_qos iso_qos = { .tx = &iso_tx_qos, .rx = &iso_rx_qos, +#if defined(CONFIG_BT_ISO_ADVANCED) + .num_subevents = DEFAULT_CIS_NSE, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static struct bt_iso_cig_param cig_create_param = { @@ -103,7 +122,12 @@ static struct bt_iso_cig_param cig_create_param = { .packing = DEFAULT_CIS_PACKING, .framing = DEFAULT_CIS_FRAMING, .cis_channels = cis, - .num_cis = DEFAULT_CIS_COUNT + .num_cis = DEFAULT_CIS_COUNT, +#if defined(CONFIG_BT_ISO_ADVANCED) + .c_to_p_ft = DEFAULT_CIS_FT, + .p_to_c_ft = DEFAULT_CIS_FT, + .iso_interval = DEFAULT_CIS_ISO_INTERVAL, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static enum benchmark_role device_role_select(void) @@ -608,6 +632,154 @@ static int parse_sdu_arg(struct bt_iso_chan_io_qos *qos) return (int)sdu; } +#if defined(CONFIG_BT_ISO_ADVANCED) +static int parse_c_to_p_ft_arg(void) +{ + char buffer[4]; + size_t char_count; + uint64_t c_to_p_ft; + + printk("Set central to peripheral flush timeout (current %u, default %u)\n", + cig_create_param.c_to_p_ft, DEFAULT_CIS_FT); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_FT; + } + + c_to_p_ft = strtoul(buffer, NULL, 0); + if (!IN_RANGE(c_to_p_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + printk("Invalid central to peripheral flush timeout %llu", + c_to_p_ft); + + return -EINVAL; + } + + return (int)c_to_p_ft; +} + +static int parse_p_to_c_ft_arg(void) +{ + char buffer[4]; + size_t char_count; + uint64_t p_to_c_ft; + + printk("Set peripheral to central flush timeout (current %u, default %u)\n", + cig_create_param.p_to_c_ft, DEFAULT_CIS_FT); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_FT; + } + + p_to_c_ft = strtoul(buffer, NULL, 0); + if (!IN_RANGE(p_to_c_ft, BT_ISO_FT_MIN, BT_ISO_FT_MAX)) { + printk("Invalid peripheral to central flush timeout %llu", + p_to_c_ft); + + return -EINVAL; + } + + return (int)p_to_c_ft; +} + +static int parse_iso_interval_arg(void) +{ + char buffer[8]; + size_t char_count; + uint64_t iso_interval; + + printk("Set ISO interval (current %u, default %u)\n", + cig_create_param.iso_interval, DEFAULT_CIS_ISO_INTERVAL); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_ISO_INTERVAL; + } + + iso_interval = strtoul(buffer, NULL, 0); + if (IN_RANGE(iso_interval, BT_ISO_ISO_INTERVAL_MIN, BT_ISO_ISO_INTERVAL_MAX)) { + printk("Invalid ISO interval %llu", iso_interval); + + return -EINVAL; + } + + return (int)iso_interval; +} + +static int parse_nse_arg(struct bt_iso_chan_qos *qos) +{ + char buffer[4]; + size_t char_count; + uint64_t nse; + + printk("Set number of subevents (current %u, default %u)\n", + qos->num_subevents, DEFAULT_CIS_NSE); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_NSE; + } + + nse = strtoul(buffer, NULL, 0); + if (IN_RANGE(nse, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) { + printk("Invalid number of subevents %llu", nse); + + return -EINVAL; + } + + return (int)nse; +} + +static int parse_pdu_arg(const struct bt_iso_chan_io_qos *qos) +{ + char buffer[6]; + size_t char_count; + uint64_t pdu; + + printk("Set PDU (current %u, default %u)\n", + qos->max_pdu, DEFAULT_CIS_PDU_SIZE); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_PDU_SIZE; + } + + pdu = strtoul(buffer, NULL, 0); + if (pdu > BT_ISO_PDU_MAX) { + printk("Invalid PDU %llu", pdu); + + return -EINVAL; + } + + return (int)pdu; +} + +static int parse_bn_arg(const struct bt_iso_chan_io_qos *qos) +{ + char buffer[4]; + size_t char_count; + uint64_t bn; + + printk("Set burst number (current %u, default %u)\n", + qos->burst_number, DEFAULT_CIS_BN); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_CIS_PDU_SIZE; + } + + bn = strtoul(buffer, NULL, 0); + if (!IN_RANGE(bn, BT_ISO_BN_MIN, BT_ISO_BN_MAX)) { + printk("Invalid burst number %llu", bn); + + return -EINVAL; + } + + return (int)bn; +} +#endif /* CONFIG_BT_ISO_ADVANCED */ + static int parse_cis_count_arg(void) { char buffer[4]; @@ -636,6 +808,12 @@ static int parse_cig_args(void) int interval; int latency; int cis_count; +#if defined(CONFIG_BT_ISO_ADVANCED) + int c_to_p_ft; + int p_to_c_ft; + int iso_interval; + int num_subevents; +#endif /* CONFIG_BT_ISO_ADVANCED */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -654,9 +832,37 @@ static int parse_cig_args(void) return -EINVAL; } +#if defined(CONFIG_BT_ISO_ADVANCED) + c_to_p_ft = parse_c_to_p_ft_arg(); + if (c_to_p_ft < 0) { + return -EINVAL; + } + + p_to_c_ft = parse_p_to_c_ft_arg(); + if (p_to_c_ft < 0) { + return -EINVAL; + } + + iso_interval = parse_iso_interval_arg(); + if (iso_interval < 0) { + return -EINVAL; + } + + num_subevents = parse_nse_arg(&iso_qos); + if (num_subevents < 0) { + return -EINVAL; + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + cig_create_param.interval = interval; cig_create_param.latency = latency; cig_create_param.num_cis = cis_count; +#if defined(CONFIG_BT_ISO_ADVANCED) + cig_create_param.c_to_p_ft = c_to_p_ft; + cig_create_param.p_to_c_ft = p_to_c_ft; + cig_create_param.iso_interval = iso_interval; + iso_qos.num_subevents = num_subevents; +#endif /* CONFIG_BT_ISO_ADVANCED */ return 0; } @@ -666,6 +872,10 @@ static int parse_cis_args(struct bt_iso_chan_io_qos *qos) int rtn; int phy; int sdu; +#if defined(CONFIG_BT_ISO_ADVANCED) + int max_pdu; + int burst_number; +#endif /* CONFIG_BT_ISO_ADVANCED */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -684,9 +894,25 @@ static int parse_cis_args(struct bt_iso_chan_io_qos *qos) return -EINVAL; } +#if defined(CONFIG_BT_ISO_ADVANCED) + max_pdu = parse_pdu_arg(qos); + if (max_pdu < 0) { + return -EINVAL; + } + + burst_number = parse_bn_arg(qos); + if (burst_number < 0) { + return -EINVAL; + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + qos->rtn = rtn; qos->phy = phy; qos->sdu = sdu; +#if defined(CONFIG_BT_ISO_ADVANCED) + qos->max_pdu = max_pdu; + qos->burst_number = burst_number; +#endif /* CONFIG_BT_ISO_ADVANCED */ return 0; } From 0081ecd626ac6cae61250fed6192f45f294e6e83 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Fri, 20 Jan 2023 12:51:02 +0100 Subject: [PATCH 1984/2042] Bluetooth: ISO: Add advanced broadcast ISO parameters Add support for setting advanced broadcast ISO parameters using the ISO test commands. This allows the host to set ISO parameters that the controller normally would handle. Signed-off-by: Emil Gydesen --- include/zephyr/bluetooth/iso.h | 40 +++++++ subsys/bluetooth/host/iso.c | 201 +++++++++++++++++++++++++++++---- 2 files changed, 219 insertions(+), 22 deletions(-) diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index 6eafa66f9443..6d8ed75dfc72 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -109,6 +109,16 @@ extern "C" { #define BT_ISO_BIS_INDEX_MIN 0x01 /** Highest BIS index */ #define BT_ISO_BIS_INDEX_MAX 0x1F +/** Minimum Immediate Repetition Count */ +#define BT_ISO_IRC_MIN 0x01U +/** Maximum Immediate Repetition Count */ +#define BT_ISO_IRC_MAX 0x0FU +/** Minimum pre-transmission offset */ +#define BT_ISO_PTO_MIN 0x00U +/** Maximum pre-transmission offset */ +#define BT_ISO_PTO_MAX 0x0FU + + /** Omit time stamp when sending to controller * * Using this value will enqueue the ISO SDU in a FIFO manner, instead of @@ -425,6 +435,8 @@ struct bt_iso_big_create_param { /** @brief Channel Latency in ms. * * Value range BT_ISO_LATENCY_MIN - BT_ISO_LATENCY_MAX. + * + * This value is ignored if any advanced ISO parameters are set. */ uint16_t latency; @@ -457,6 +469,34 @@ struct bt_iso_big_create_param { * [42 72 6F 61 64 63 61 73 74 20 43 6F 64 65 00 00] */ uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE]; + +#if defined(CONFIG_BT_ISO_ADVANCED) + /** @brief Immediate Repetition Count + * + * The number of times the scheduled payloads are transmitted in a + * given event. + * + * Value range from @ref BT_ISO_MIN_IRC to @ref BT_ISO_MAX_IRC. + */ + uint8_t irc; + + /** @brief Pre-transmission offset + * + * Offset used for pre-transmissions. + * + * Value range from @ref BT_ISO_MIN_PTO to @ref BT_ISO_MAX_PTO. + */ + uint8_t pto; + + /** @brief ISO interval + * + * Time between consecutive BIS anchor points. + * + * Value range from @ref BT_ISO_ISO_INTERVAL_MIN to + * @ref BT_ISO_ISO_INTERVAL_MAX. + */ + uint16_t iso_interval; +#endif /* CONFIG_BT_ISO_ADVANCED */ }; /** @brief Broadcast Isochronous Group (BIG) Sync Parameters */ diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 101fa458a08e..daae434ac1bb 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -2569,25 +2569,113 @@ static int hci_le_create_big(struct bt_le_ext_adv *padv, struct bt_iso_big *big, return err; } -int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, - struct bt_iso_big **out_big) +#if defined(CONFIG_BT_ISO_ADVANCED) +static int hci_le_create_big_test(const struct bt_le_ext_adv *padv, + struct bt_iso_big *big, + const struct bt_iso_big_create_param *param) { + struct bt_hci_cp_le_create_big_test *req; + struct bt_hci_cmd_state_set state; + const struct bt_iso_chan_qos *qos; + struct bt_iso_chan *bis; + struct net_buf *buf; int err; - struct bt_iso_big *big; - if (!atomic_test_bit(padv->flags, BT_PER_ADV_PARAMS_SET)) { - LOG_DBG("PA params not set; invalid adv object"); - return -EINVAL; + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_BIG_TEST, sizeof(*req)); + + if (!buf) { + return -ENOBUFS; } + bis = SYS_SLIST_PEEK_HEAD_CONTAINER(&big->bis_channels, bis, node); + __ASSERT(bis != NULL, "bis was NULL"); + + /* All BIS will share the same QOS */ + qos = bis->qos; + + req = net_buf_add(buf, sizeof(*req)); + req->big_handle = big->handle; + req->adv_handle = padv->handle; + req->num_bis = big->num_bis; + sys_put_le24(param->interval, req->sdu_interval); + req->iso_interval = sys_cpu_to_le16(param->iso_interval); + req->nse = qos->num_subevents; + req->max_sdu = sys_cpu_to_le16(qos->tx->sdu); + req->max_pdu = sys_cpu_to_le16(qos->tx->max_pdu); + req->phy = qos->tx->phy; + req->packing = param->packing; + req->framing = param->framing; + req->bn = qos->tx->burst_number; + req->irc = param->irc; + req->pto = param->pto; + req->encryption = param->encryption; + if (req->encryption) { + memcpy(req->bcode, param->bcode, sizeof(req->bcode)); + } else { + memset(req->bcode, 0, sizeof(req->bcode)); + } + + LOG_DBG("BIG handle %u, adv handle %u, num_bis %u, SDU interval %u, " + "ISO interval %u, NSE %u, SDU %u, PDU %u, PHY %u, packing %u, " + "framing %u, BN %u, IRC %u, PTO %u, encryption %u", + req->big_handle, req->adv_handle, req->num_bis, param->interval, + param->iso_interval, req->nse, req->max_sdu, req->max_pdu, + req->phy, req->packing, req->framing, req->bn, req->irc, + req->pto, req->encryption); + + bt_hci_cmd_state_set_init(buf, &state, big->flags, BT_BIG_PENDING, true); + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_BIG_TEST, buf, NULL); + if (err) { + return err; + } + + SYS_SLIST_FOR_EACH_CONTAINER(&big->bis_channels, bis, node) { + bt_iso_chan_set_state(bis, BT_ISO_STATE_CONNECTING); + } + + return err; +} + +static bool is_advanced_big_param(const struct bt_iso_big_create_param *param) +{ + if (param->irc != 0U || + param->iso_interval != 0U) { + return true; + } + + /* Check if any of the CIS contain any test-param-only values */ + for (uint8_t i = 0U; i < param->num_bis; i++) { + const struct bt_iso_chan *bis = param->bis_channels[i]; + const struct bt_iso_chan_qos *qos = bis->qos; + + if (qos->num_subevents > 0U) { + return true; + } + + __ASSERT(qos->tx != NULL, "TX cannot be NULL for broadcaster"); + + if (qos->tx->max_pdu > 0U || qos->tx->burst_number > 0U) { + return true; + } + } + + return false; +} +#endif /* CONFIG_BT_ISO_ADVANCED */ + +static bool valid_big_param(const struct bt_iso_big_create_param *param, + bool advanced) +{ CHECKIF(!param->bis_channels) { LOG_DBG("NULL BIS channels"); - return -EINVAL; + + return false; } CHECKIF(!param->num_bis) { LOG_DBG("Invalid number of BIS %u", param->num_bis); - return -EINVAL; + + return false; } for (uint8_t i = 0; i < param->num_bis; i++) { @@ -2595,54 +2683,116 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param CHECKIF(bis == NULL) { LOG_DBG("bis_channels[%u]: NULL channel", i); - return -EINVAL; + + return false; } if (bis->iso) { LOG_DBG("bis_channels[%u]: already allocated", i); - return -EALREADY; + + return false; } CHECKIF(bis->qos == NULL) { LOG_DBG("bis_channels[%u]: qos is NULL", i); - return -EINVAL; + + return false; } CHECKIF(bis->qos->tx == NULL || - !valid_chan_io_qos(bis->qos->tx, true, true, false)) { + !valid_chan_io_qos(bis->qos->tx, true, true, + advanced)) { LOG_DBG("bis_channels[%u]: Invalid QOS", i); - return -EINVAL; + + return false; } } CHECKIF(param->framing != BT_ISO_FRAMING_UNFRAMED && param->framing != BT_ISO_FRAMING_FRAMED) { LOG_DBG("Invalid framing parameter: %u", param->framing); - return -EINVAL; + + return false; } CHECKIF(param->packing != BT_ISO_PACKING_SEQUENTIAL && param->packing != BT_ISO_PACKING_INTERLEAVED) { LOG_DBG("Invalid packing parameter: %u", param->packing); - return -EINVAL; + + return false; } CHECKIF(param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { LOG_DBG("num_bis (%u) shall be lower than: %u", param->num_bis, MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); - return -EINVAL; + + return false; } - CHECKIF(param->interval < BT_ISO_SDU_INTERVAL_MIN || - param->interval > BT_ISO_SDU_INTERVAL_MAX) { + CHECKIF(!IN_RANGE(param->interval, + BT_ISO_SDU_INTERVAL_MIN, + BT_ISO_SDU_INTERVAL_MAX)) { LOG_DBG("Invalid interval: %u", param->interval); - return -EINVAL; + + return false; } - CHECKIF(param->latency < BT_ISO_LATENCY_MIN || - param->latency > BT_ISO_LATENCY_MAX) { + CHECKIF(!advanced && + !IN_RANGE(param->latency, + BT_ISO_LATENCY_MIN, + BT_ISO_LATENCY_MAX)) { LOG_DBG("Invalid latency: %u", param->latency); + + return false; + } + +#if defined(CONFIG_BT_ISO_ADVANCED) + if (advanced) { + CHECKIF(!IN_RANGE(param->irc, BT_ISO_IRC_MIN, BT_ISO_IRC_MAX)) { + LOG_DBG("Invalid IRC %u", param->irc); + + return false; + } + + CHECKIF(!IN_RANGE(param->pto, BT_ISO_PTO_MIN, BT_ISO_PTO_MAX)) { + LOG_DBG("Invalid PTO %u", param->pto); + + return false; + } + + CHECKIF(!IN_RANGE(param->iso_interval, + BT_ISO_ISO_INTERVAL_MIN, + BT_ISO_ISO_INTERVAL_MAX)) { + LOG_DBG("Invalid ISO interval %u", param->iso_interval); + + return false; + } + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + + return true; +} + +int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param *param, + struct bt_iso_big **out_big) +{ + int err; + struct bt_iso_big *big; + bool advanced = false; + + if (!atomic_test_bit(padv->flags, BT_PER_ADV_PARAMS_SET)) { + LOG_DBG("PA params not set; invalid adv object"); + return -EINVAL; + } + +#if defined(CONFIG_BT_ISO_ADVANCED) + advanced = is_advanced_big_param(param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + + if (!valid_big_param(param, advanced)) { + LOG_DBG("Invalid BIG parameters"); + return -EINVAL; } @@ -2660,7 +2810,14 @@ int bt_iso_big_create(struct bt_le_ext_adv *padv, struct bt_iso_big_create_param } big->num_bis = param->num_bis; - err = hci_le_create_big(padv, big, param); + if (!advanced) { + err = hci_le_create_big(padv, big, param); +#if defined(CONFIG_BT_ISO_ADVANCED) + } else { + err = hci_le_create_big_test(padv, big, param); +#endif /* CONFIG_BT_ISO_ADVANCED */ + } + if (err) { LOG_DBG("Could not create BIG %d", err); cleanup_big(big); From ef7c775fc2eae141bd790d8bbaf2a2844b9b402c Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Sat, 21 Jan 2023 00:10:17 +0100 Subject: [PATCH 1985/2042] samples: Bluetooth: ISO broadcash benchmark advanced ISO Add (optional) advanced ISO support for the benchmark ISO sample. The CONFIG_BT_ISO_ADVANCED Kconfig simply needs to be enabled in order to support the advanced settings. Signed-off-by: Emil Gydesen --- .../iso_broadcast_benchmark/src/broadcaster.c | 230 +++++++++++++++++- 1 file changed, 222 insertions(+), 8 deletions(-) diff --git a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c index 620471805680..735ac7a3318b 100644 --- a/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c +++ b/samples/bluetooth/iso_broadcast_benchmark/src/broadcaster.c @@ -14,14 +14,22 @@ #include LOG_MODULE_REGISTER(iso_broadcast_broadcaster, LOG_LEVEL_DBG); -#define DEFAULT_BIS_RTN 2 -#define DEFAULT_BIS_INTERVAL_US 7500 -#define DEFAULT_BIS_LATENCY_MS 10 -#define DEFAULT_BIS_PHY BT_GAP_LE_PHY_2M -#define DEFAULT_BIS_SDU CONFIG_BT_ISO_TX_MTU -#define DEFAULT_BIS_PACKING 0 -#define DEFAULT_BIS_FRAMING 0 -#define DEFAULT_BIS_COUNT CONFIG_BT_ISO_MAX_CHAN +#define DEFAULT_BIS_RTN 2 +#define DEFAULT_BIS_INTERVAL_US 7500 +#define DEFAULT_BIS_LATENCY_MS 10 +#define DEFAULT_BIS_PHY BT_GAP_LE_PHY_2M +#define DEFAULT_BIS_SDU CONFIG_BT_ISO_TX_MTU +#define DEFAULT_BIS_PACKING 0 +#define DEFAULT_BIS_FRAMING 0 +#define DEFAULT_BIS_COUNT CONFIG_BT_ISO_MAX_CHAN +#if defined(CONFIG_BT_ISO_ADVANCED) +#define DEFAULT_BIS_NSE BT_ISO_NSE_MIN +#define DEFAULT_BIS_BN BT_ISO_BN_MIN +#define DEFAULT_BIS_PDU_SIZE CONFIG_BT_ISO_TX_MTU +#define DEFAULT_BIS_IRC BT_ISO_IRC_MIN +#define DEFAULT_BIS_PTO BT_ISO_PTO_MIN +#define DEFAULT_BIS_ISO_INTERVAL DEFAULT_BIS_INTERVAL_US / 1250U /* N * 10 ms */ +#endif /* CONFIG_BT_ISO_ADVANCED */ NET_BUF_POOL_FIXED_DEFINE(bis_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), @@ -45,6 +53,11 @@ static struct bt_iso_big_create_param big_create_param = { .framing = DEFAULT_BIS_FRAMING, /* 0 - unframed, 1 - framed */ .interval = DEFAULT_BIS_INTERVAL_US, /* in microseconds */ .latency = DEFAULT_BIS_LATENCY_MS, /* milliseconds */ +#if defined(CONFIG_BT_ISO_ADVANCED) + .irc = DEFAULT_BIS_IRC, + .pto = DEFAULT_BIS_PTO, + .iso_interval = DEFAULT_BIS_ISO_INTERVAL, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static void iso_connected(struct bt_iso_chan *chan) @@ -78,10 +91,17 @@ static struct bt_iso_chan_io_qos iso_tx_qos = { .sdu = DEFAULT_BIS_SDU, /* bytes */ .rtn = DEFAULT_BIS_RTN, .phy = DEFAULT_BIS_PHY, +#if defined(CONFIG_BT_ISO_ADVANCED) + .max_pdu = DEFAULT_BIS_PDU_SIZE, + .burst_number = DEFAULT_BIS_BN, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static struct bt_iso_chan_qos bis_iso_qos = { .tx = &iso_tx_qos, +#if defined(CONFIG_BT_ISO_ADVANCED) + .num_subevents = DEFAULT_BIS_NSE, +#endif /* CONFIG_BT_ISO_ADVANCED */ }; static size_t get_chars(char *buffer, size_t max_size) @@ -221,6 +241,152 @@ static int parse_sdu_arg(void) return (int)sdu; } +#if defined(CONFIG_BT_ISO_ADVANCED) +static int parse_irc_arg(void) +{ + size_t char_count; + char buffer[4]; + uint64_t irc; + + printk("Set IRC (current %u, default %u)\n", + big_create_param.irc, DEFAULT_BIS_IRC); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_IRC; + } + + irc = strtoul(buffer, NULL, 0); + if (!IN_RANGE(irc, BT_ISO_IRC_MIN, BT_ISO_IRC_MAX)) { + printk("Invalid IRC %llu", irc); + + return -EINVAL; + } + + return (int)irc; +} + +static int parse_pto_arg(void) +{ + size_t char_count; + char buffer[4]; + uint64_t pto; + + printk("Set PTO (current %u, default %u)\n", + big_create_param.pto, DEFAULT_BIS_PTO); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_PTO; + } + + pto = strtoul(buffer, NULL, 0); + if (!IN_RANGE(pto, BT_ISO_PTO_MIN, BT_ISO_PTO_MAX)) { + printk("Invalid PTO %llu", pto); + + return -EINVAL; + } + + return (int)pto; +} + +static int parse_iso_interval_arg(void) +{ + uint64_t iso_interval; + size_t char_count; + char buffer[8]; + + printk("Set ISO interval (current %u, default %u)\n", + big_create_param.iso_interval, DEFAULT_BIS_ISO_INTERVAL); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_ISO_INTERVAL; + } + + iso_interval = strtoul(buffer, NULL, 0); + if (!IN_RANGE(iso_interval, BT_ISO_ISO_INTERVAL_MIN, BT_ISO_ISO_INTERVAL_MAX)) { + printk("Invalid ISO interval %llu", iso_interval); + + return -EINVAL; + } + + return (int)iso_interval; +} + +static int parse_nse_arg(void) +{ + uint64_t num_subevents; + size_t char_count; + char buffer[4]; + + printk("Set number of subevents (current %u, default %u)\n", + bis_iso_qos.num_subevents, DEFAULT_BIS_NSE); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_NSE; + } + + num_subevents = strtoul(buffer, NULL, 0); + if (!IN_RANGE(num_subevents, BT_ISO_NSE_MIN, BT_ISO_NSE_MAX)) { + printk("Invalid number of subevents %llu", num_subevents); + + return -EINVAL; + } + + return (int)num_subevents; +} + +static int parse_max_pdu_arg(void) +{ + size_t char_count; + uint64_t max_pdu; + char buffer[6]; + + printk("Set max PDU (current %u, default %u)\n", + iso_tx_qos.max_pdu, DEFAULT_BIS_PDU_SIZE); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_PDU_SIZE; + } + + max_pdu = strtoul(buffer, NULL, 0); + if (max_pdu > BT_ISO_PDU_MAX) { + printk("Invalid max PDU %llu", max_pdu); + + return -EINVAL; + } + + return (int)max_pdu; +} + +static int parse_bn_arg(void) +{ + uint64_t burst_number; + size_t char_count; + char buffer[4]; + + printk("Set burst number (current %u, default %u)\n", + iso_tx_qos.burst_number, DEFAULT_BIS_BN); + + char_count = get_chars(buffer, sizeof(buffer) - 1); + if (char_count == 0) { + return DEFAULT_BIS_PDU_SIZE; + } + + burst_number = strtoul(buffer, NULL, 0); + if (!IN_RANGE(burst_number, BT_ISO_BN_MIN, BT_ISO_BN_MAX)) { + printk("Invalid burst number %llu", burst_number); + + return -EINVAL; + } + + return (int)burst_number; +} +#endif /* CONFIG_BT_ISO_ADVANCED */ + static int parse_packing_arg(void) { char buffer[3]; @@ -302,6 +468,14 @@ static int parse_args(void) int packing; int framing; int bis_count; +#if defined(CONFIG_BT_ISO_ADVANCED) + int num_subevents; + int iso_interval; + int burst_number; + int max_pdu; + int irc; + int pto; +#endif /* CONFIG_BT_ISO_ADVANCED */ printk("Follow the prompts. Press enter to use default values.\n"); @@ -345,6 +519,38 @@ static int parse_args(void) return -EINVAL; } +#if defined(CONFIG_BT_ISO_ADVANCED) + irc = parse_irc_arg(); + if (irc < 0) { + return -EINVAL; + } + + pto = parse_pto_arg(); + if (pto < 0) { + return -EINVAL; + } + + iso_interval = parse_iso_interval_arg(); + if (iso_interval < 0) { + return -EINVAL; + } + + num_subevents = parse_nse_arg(); + if (num_subevents < 0) { + return -EINVAL; + } + + max_pdu = parse_max_pdu_arg(); + if (max_pdu < 0) { + return -EINVAL; + } + + burst_number = parse_bn_arg(); + if (burst_number < 0) { + return -EINVAL; + } +#endif /* CONFIG_BT_ISO_ADVANCED */ + iso_tx_qos.rtn = rtn; iso_tx_qos.phy = phy; iso_tx_qos.sdu = sdu; @@ -353,6 +559,14 @@ static int parse_args(void) big_create_param.packing = packing; big_create_param.framing = framing; big_create_param.num_bis = bis_count; +#if defined(CONFIG_BT_ISO_ADVANCED) + bis_iso_qos.num_subevents = num_subevents; + iso_tx_qos.max_pdu = max_pdu; + iso_tx_qos.burst_number = burst_number; + big_create_param.irc = irc; + big_create_param.pto = pto; + big_create_param.iso_interval = iso_interval; +#endif /* CONFIG_BT_ISO_ADVANCED */ return 0; } From 076df4ebe2867fa1300ebbf26be7eb82f184f623 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 23 Jan 2023 13:48:03 +0100 Subject: [PATCH 1986/2042] tests: Bluetooth: Refactor ISO broadcast ISO BSIM test Refactor the test function to split it into multiple smaller functions. This makes the main function much shorter and easier to follow, and allows reusing of the individual steps. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/ll/bis/src/main.c | 153 ++++++++++++++++++------- 1 file changed, 109 insertions(+), 44 deletions(-) diff --git a/tests/bsim/bluetooth/ll/bis/src/main.c b/tests/bsim/bluetooth/ll/bis/src/main.c index 7b8a0b4338f9..a0db87374a2b 100644 --- a/tests/bsim/bluetooth/ll/bis/src/main.c +++ b/tests/bsim/bluetooth/ll/bis/src/main.c @@ -147,23 +147,12 @@ bool ll_data_path_sink_create(uint16_t handle, struct ll_iso_datapath *datapath, } #endif /* CONFIG_BT_CTLR_ISO_VENDOR_DATA_PATH */ -static void test_iso_main(void) +static void setup_ext_adv(struct bt_le_ext_adv **adv) { - struct bt_le_ext_adv *adv; int err; - printk("\n*ISO broadcast test*\n"); - - printk("Bluetooth initializing..."); - err = bt_enable(NULL); - if (err) { - FAIL("Could not init BT: %d\n", err); - return; - } - printk("success.\n"); - printk("Create 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_NCONN_NAME, NULL, adv); if (err) { FAIL("Failed to create advertising set (err %d)\n", err); return; @@ -171,7 +160,7 @@ static void test_iso_main(void) printk("success.\n"); printk("Setting 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_DEFAULT); if (err) { FAIL("Failed to set periodic advertising parameters (err %d)\n", err); @@ -180,7 +169,7 @@ static void test_iso_main(void) printk("success.\n"); printk("Enable Periodic Advertising..."); - err = bt_le_per_adv_start(adv); + err = bt_le_per_adv_start(*adv); if (err) { FAIL("Failed to enable periodic advertising (err %d)\n", err); return; @@ -188,29 +177,60 @@ static void test_iso_main(void) printk("success.\n"); printk("Start extended advertising..."); - err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + 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; } printk("success.\n"); +} + +static void teardown_ext_adv(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Stop Periodic Advertising..."); + err = bt_le_per_adv_stop(adv); + if (err) { + FAIL("Failed to stop periodic advertising (err %d)\n", err); + return; + } + printk("success.\n"); + + printk("Stop Extended Advertising..."); + err = bt_le_ext_adv_stop(adv); + if (err) { + FAIL("Failed to stop extended advertising (err %d)\n", err); + return; + } + printk("success.\n"); + printk("Deleting Extended Advertising..."); + err = bt_le_ext_adv_delete(adv); + if (err) { + FAIL("Failed to delete extended advertising (err %d)\n", err); + return; + } + printk("success.\n"); +} #if TEST_LL_INTERFACE - printk("Creating BIG..."); +static void create_ll_big(uint8_t big_handle, struct bt_le_ext_adv *adv) +{ uint16_t max_sdu = CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX; uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE] = { 0 }; uint32_t sdu_interval = 10000; /* us */ uint16_t max_latency = 10; /* ms */ uint8_t encryption = 0; - uint8_t big_handle = 0; uint8_t bis_count = 1; /* TODO: Add support for multiple BIS per BIG */ uint8_t phy = BIT(1); uint8_t packing = 0; uint8_t framing = 0; uint8_t adv_handle; uint8_t rtn = 0; + int err; + printk("Creating LL BIG..."); /* Assume that index == handle */ adv_handle = bt_le_ext_adv_get_index(adv); @@ -222,12 +242,28 @@ static void test_iso_main(void) return; } printk("success.\n"); -#endif +} - printk("Creating BIG...\n"); +static void terminate_ll_big(uint8_t big_handle) +{ + int err; + + printk("Terminating LL BIG..."); + err = ll_big_terminate(big_handle, BT_HCI_ERR_LOCALHOST_TERM_CONN); + if (err) { + FAIL("Could not terminate BIG: %d\n", err); + return; + } + printk("success.\n"); +} +#endif /* TEST_LL_INTERFACE */ + +static void create_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) +{ struct bt_iso_big_create_param big_create_param; - struct bt_iso_big *big; + int err; + printk("Creating BIG...\n"); big_create_param.bis_channels = bis_channels; big_create_param.num_bis = BIS_ISO_CHAN_COUNT; big_create_param.encryption = false; @@ -240,7 +276,7 @@ static void test_iso_main(void) iso_tx_qos.phy = BT_GAP_LE_PHY_2M; bis_iso_qos.tx = &iso_tx_qos; bis_iso_qos.rx = NULL; - err = bt_iso_big_create(adv, &big_create_param, &big); + err = bt_iso_big_create(adv, &big_create_param, big); if (err) { FAIL("Could not create BIG: %d\n", err); return; @@ -252,10 +288,27 @@ static void test_iso_main(void) k_sleep(K_MSEC(100)); } printk("ISO connected\n"); +} + +static void terminate_big(struct bt_iso_big *big) +{ + int err; + printk("Terminating BIG...\n"); + err = bt_iso_big_terminate(big); + if (err) { + FAIL("Could not terminate BIG: %d\n", err); + return; + } + printk("success.\n"); +} + +static void send_iso_data(void) +{ uint32_t iso_send_count = 0; uint8_t iso_data[sizeof(iso_send_count)] = { 0 }; struct net_buf *buf; + int err; buf = net_buf_alloc(&bis_tx_pool, K_FOREVER); net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); @@ -268,6 +321,35 @@ static void test_iso_main(void) return; } printk("Sending value %u\n", iso_send_count); +} + +static void test_iso_main(void) +{ + struct bt_le_ext_adv *adv; + struct bt_iso_big *big; + int err; + + printk("\n*ISO broadcast test*\n"); + + printk("Bluetooth initializing..."); + err = bt_enable(NULL); + if (err) { + FAIL("Could not init BT: %d\n", err); + return; + } + printk("success.\n"); + + setup_ext_adv(&adv); + +#if TEST_LL_INTERFACE + uint8_t big_handle = 0; + + create_ll_big(big_handle, adv); +#endif + + create_big(adv, &big); + + send_iso_data(); k_sleep(K_MSEC(5000)); @@ -303,33 +385,16 @@ static void test_iso_main(void) k_sleep(K_MSEC(5000)); #if TEST_LL_INTERFACE - printk("Terminating BIG..."); - err = ll_big_terminate(big_handle, BT_HCI_ERR_LOCALHOST_TERM_CONN); - if (err) { - FAIL("Could not terminate BIG: %d\n", err); - return; - } - printk("success.\n"); + terminate_ll_big(big_handle); #endif - printk("Terminating BIG...\n"); - err = bt_iso_big_terminate(big); - if (err) { - FAIL("Could not terminate BIG: %d\n", err); - return; - } - printk("success.\n"); + terminate_big(big); + big = NULL; k_sleep(K_MSEC(10000)); - printk("Stop Periodic Advertising..."); - err = bt_le_per_adv_stop(adv); - if (err) { - FAIL("Failed to stop periodic advertising (err %d)\n", err); - return; - } - printk("success.\n"); - + teardown_ext_adv(adv); + adv = NULL; PASS("ISO tests Passed\n"); From 5555ac331cd2c71b518da6b635b4bda4a2a3339b Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Mon, 23 Jan 2023 14:33:54 +0100 Subject: [PATCH 1987/2042] tests: Bluetooth: Add advanced BIG create BSIM test Extended the ISO broadcaster BSIM test with an additional step to create a BIG using the test parameters. Since this isn't properly implemented in the controller, CONFIG_BT_ISO_ADVANCED has not been enabled in the prj.conf yet. Signed-off-by: Emil Gydesen --- tests/bsim/bluetooth/ll/bis/src/main.c | 62 ++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/tests/bsim/bluetooth/ll/bis/src/main.c b/tests/bsim/bluetooth/ll/bis/src/main.c index a0db87374a2b..23d9db61c2e5 100644 --- a/tests/bsim/bluetooth/ll/bis/src/main.c +++ b/tests/bsim/bluetooth/ll/bis/src/main.c @@ -58,6 +58,7 @@ static const struct bt_data per_ad_data2[] = { static uint8_t chan_map[] = { 0x1F, 0XF1, 0x1F, 0xF1, 0x1F }; static bool volatile is_iso_connected; +static uint8_t volatile is_iso_disconnected; static bool volatile deleting_pa_sync; static void iso_connected(struct bt_iso_chan *chan); static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason); @@ -260,7 +261,7 @@ static void terminate_ll_big(uint8_t big_handle) static void create_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) { - struct bt_iso_big_create_param big_create_param; + struct bt_iso_big_create_param big_create_param = { 0 }; int err; printk("Creating BIG...\n"); @@ -290,6 +291,47 @@ static void create_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) printk("ISO connected\n"); } +#if defined(CONFIG_BT_ISO_ADVANCED) +static void create_advanced_big(struct bt_le_ext_adv *adv, struct bt_iso_big **big) +{ + struct bt_iso_big_create_param big_create_param; + int err; + + printk("Creating BIG...\n"); + big_create_param.bis_channels = bis_channels; + big_create_param.num_bis = BIS_ISO_CHAN_COUNT; + big_create_param.encryption = false; + big_create_param.interval = 10000; /* us */ + big_create_param.packing = 0; /* 0 - sequential; 1 - interleaved */ + big_create_param.framing = 0; /* 0 - unframed; 1 - framed */ + big_create_param.irc = BT_ISO_IRC_MIN; + big_create_param.pto = BT_ISO_PTO_MIN; + big_create_param.iso_interval = big_create_param.interval / 1250U; /* N * 10 ms */ + + iso_tx_qos.sdu = 502; /* bytes */ + iso_tx_qos.phy = BT_GAP_LE_PHY_2M; + iso_tx_qos.max_pdu = BT_ISO_PDU_MAX; + iso_tx_qos.burst_number = BT_ISO_BN_MIN; + + bis_iso_qos.tx = &iso_tx_qos; + bis_iso_qos.rx = NULL; + bis_iso_qos.num_subevents = BT_ISO_NSE_MIN; + + err = bt_iso_big_create(adv, &big_create_param, big); + if (err) { + FAIL("Could not create BIG: %d\n", err); + return; + } + printk("success.\n"); + + printk("Wait for ISO connected callback..."); + while (!is_iso_connected) { + k_sleep(K_MSEC(100)); + } + printk("ISO connected\n"); +} +#endif /* CONFIG_BT_ISO_ADVANCED */ + static void terminate_big(struct bt_iso_big *big) { int err; @@ -301,6 +343,12 @@ static void terminate_big(struct bt_iso_big *big) return; } printk("success.\n"); + + printk("Wait for ISO disconnected callback..."); + while (is_iso_disconnected == 0U) { + k_sleep(K_MSEC(100)); + } + printk("ISO disconnected\n"); } static void send_iso_data(void) @@ -391,6 +439,16 @@ static void test_iso_main(void) terminate_big(big); big = NULL; +#if defined(CONFIG_BT_ISO_ADVANCED) + /* Quick check to just verify that creating a BIG using advanced/test + * parameters work + */ + create_advanced_big(adv, &big); + + terminate_big(big); + big = NULL; +#endif /* CONFIG_BT_ISO_ADVANCED */ + k_sleep(K_MSEC(10000)); teardown_ext_adv(adv); @@ -427,8 +485,6 @@ static void iso_connected(struct bt_iso_chan *chan) is_iso_connected = true; } -static uint8_t volatile is_iso_disconnected; - static void iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) { printk("ISO Channel %p disconnected with reason 0x%02x\n", chan, reason); From dbea999347128c67a3e06eb34ee67f49be923658 Mon Sep 17 00:00:00 2001 From: Antoine Bout Date: Fri, 23 Jun 2023 11:52:40 +0200 Subject: [PATCH 1988/2042] soc/arm/silabs: Kconfig: add SOC_GECKO_USE_RAIL kconfig option Currently on zephyr, RAIL is used only for bluetooth. RAIL library is needed to use efr32 radio regardless of the protocol used. We add SOC_GECKO_USE_RAIL kconfig option to indicate if we use radio. FPU is needed when using RAIL, we configure it if SOC_GECKO_USE_RAIL is set. Signed-off-by: Antoine Bout --- boards/arm/efr32_radio/Kconfig.defconfig | 7 +++++++ boards/arm/efr32_thunderboard/Kconfig.defconfig | 7 +++++++ boards/arm/efr32xg24_dk2601b/Kconfig.defconfig | 7 +++++++ drivers/bluetooth/hci/Kconfig | 1 + soc/arm/silabs_exx32/Kconfig | 7 +++++++ 5 files changed, 29 insertions(+) diff --git a/boards/arm/efr32_radio/Kconfig.defconfig b/boards/arm/efr32_radio/Kconfig.defconfig index 830a4c90f5fc..cf4be7c9dde1 100644 --- a/boards/arm/efr32_radio/Kconfig.defconfig +++ b/boards/arm/efr32_radio/Kconfig.defconfig @@ -29,6 +29,13 @@ config LOG_BACKEND_SWO_FREQ_HZ default 875000 depends on LOG_BACKEND_SWO +if SOC_GECKO_USE_RAIL + +config FPU + default y + +endif # SOC_GECKO_USE_RAIL + if BT config FPU diff --git a/boards/arm/efr32_thunderboard/Kconfig.defconfig b/boards/arm/efr32_thunderboard/Kconfig.defconfig index 35059d030c84..d73779fd61a4 100644 --- a/boards/arm/efr32_thunderboard/Kconfig.defconfig +++ b/boards/arm/efr32_thunderboard/Kconfig.defconfig @@ -23,6 +23,13 @@ config CMU_HFXO_FREQ config CMU_LFXO_FREQ default 32768 +if SOC_GECKO_USE_RAIL + +config FPU + default y + +endif # SOC_GECKO_USE_RAIL + if BT config FPU diff --git a/boards/arm/efr32xg24_dk2601b/Kconfig.defconfig b/boards/arm/efr32xg24_dk2601b/Kconfig.defconfig index 14405984017a..0f0cf9aa1633 100644 --- a/boards/arm/efr32xg24_dk2601b/Kconfig.defconfig +++ b/boards/arm/efr32xg24_dk2601b/Kconfig.defconfig @@ -18,6 +18,13 @@ config FLASH_BASE_ADDRESS hex default 0x08000000 +if SOC_GECKO_USE_RAIL + +config FPU + default y + +endif # SOC_GECKO_USE_RAIL + if BT config FPU diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index d7ac4f59115c..8a50caa92f05 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -60,6 +60,7 @@ config BT_SILABS_HCI bool "Silicon Labs Bluetooth interface" depends on SOC_SERIES_EFR32BG22 || SOC_SERIES_EFR32MG24 || SOC_SERIES_EFR32BG27 depends on !PM || SOC_GECKO_PM_BACKEND_PMGR + select SOC_GECKO_USE_RAIL select ENTROPY_GENERATOR select MBEDTLS select MBEDTLS_PSA_CRYPTO_C diff --git a/soc/arm/silabs_exx32/Kconfig b/soc/arm/silabs_exx32/Kconfig index dbfd42526d1f..d2faeca4bf64 100644 --- a/soc/arm/silabs_exx32/Kconfig +++ b/soc/arm/silabs_exx32/Kconfig @@ -319,4 +319,11 @@ config SOC_GECKO_HAS_HFRCO_FREQRANGE If disabled, indicates that configuration of HFRCO frequency for corresponding SOC is not supported via this field. This is the case for e.g. efm32hg, efm32wg series. +config SOC_GECKO_USE_RAIL + bool "Use RAIL (Radio Abstraction Interface Layer)" + help + RAIL (Radio Abstraction Interface Layer) is a library needed to use the EFR radio + hardware. This option enable the proper set of features to allow to properly compile + with the RAIL blob. + endif # SOC_FAMILY_EXX32 From a0a9539d0223a53d73a907c5a2f75faa131a41db Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 31 Jul 2023 08:13:34 +0100 Subject: [PATCH 1989/2042] mgmt: mcumgr: grp: Fix error translation function indent Fixes lines not being indented and looking like a single blob Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c | 12 +++++------ .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 20 +++++++++---------- subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 6 +++--- .../mcumgr/grp/shell_mgmt/src/shell_mgmt.c | 6 +++--- .../mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c | 10 +++++----- .../mcumgr/grp/zephyr_basic/src/basic_mgmt.c | 10 +++++----- 6 files changed, 32 insertions(+), 32 deletions(-) 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 876e28c385e2..23978686170e 100644 --- a/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/fs_mgmt/src/fs_mgmt.c @@ -911,13 +911,13 @@ static int fs_mgmt_translate_error_code(uint16_t ret) switch (ret) { case FS_MGMT_RET_RC_FILE_INVALID_NAME: case FS_MGMT_RET_RC_CHECKSUM_HASH_NOT_FOUND: - rc = MGMT_ERR_EINVAL; - break; + rc = MGMT_ERR_EINVAL; + break; case FS_MGMT_RET_RC_FILE_NOT_FOUND: case FS_MGMT_RET_RC_FILE_IS_DIRECTORY: - rc = MGMT_ERR_ENOENT; - break; + rc = MGMT_ERR_ENOENT; + break; case FS_MGMT_RET_RC_UNKNOWN: case FS_MGMT_RET_RC_FILE_OPEN_FAILED: @@ -928,8 +928,8 @@ static int fs_mgmt_translate_error_code(uint16_t ret) case FS_MGMT_RET_RC_FILE_WRITE_FAILED: case FS_MGMT_RET_RC_FILE_OFFSET_NOT_VALID: case FS_MGMT_RET_RC_FILE_OFFSET_LARGER_THAN_FILE: - default: - rc = MGMT_ERR_EUNKNOWN; + default: + rc = MGMT_ERR_EUNKNOWN; } return rc; diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 967ff37483a3..06c04e0b17a9 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -775,18 +775,18 @@ static int img_mgmt_translate_error_code(uint16_t ret) switch (ret) { case IMG_MGMT_RET_RC_NO_IMAGE: case IMG_MGMT_RET_RC_NO_TLVS: - rc = MGMT_ERR_ENOENT; - break; + rc = MGMT_ERR_ENOENT; + break; case IMG_MGMT_RET_RC_NO_FREE_SLOT: case IMG_MGMT_RET_RC_CURRENT_VERSION_IS_NEWER: case IMG_MGMT_RET_RC_IMAGE_ALREADY_PENDING: - rc = MGMT_ERR_EBADSTATE; - break; + rc = MGMT_ERR_EBADSTATE; + break; case IMG_MGMT_RET_RC_NO_FREE_MEMORY: - rc = MGMT_ERR_ENOMEM; - break; + rc = MGMT_ERR_ENOMEM; + break; case IMG_MGMT_RET_RC_INVALID_SLOT: case IMG_MGMT_RET_RC_INVALID_PAGE_OFFSET: @@ -795,8 +795,8 @@ static int img_mgmt_translate_error_code(uint16_t ret) case IMG_MGMT_RET_RC_INVALID_IMAGE_HEADER: case IMG_MGMT_RET_RC_INVALID_HASH: case IMG_MGMT_RET_RC_INVALID_FLASH_ADDRESS: - rc = MGMT_ERR_EINVAL; - break; + rc = MGMT_ERR_EINVAL; + break; case IMG_MGMT_RET_RC_FLASH_CONFIG_QUERY_FAIL: case IMG_MGMT_RET_RC_VERSION_GET_FAILED: @@ -816,8 +816,8 @@ static int img_mgmt_translate_error_code(uint16_t ret) case IMG_MGMT_RET_RC_INVALID_IMAGE_TOO_LARGE: case IMG_MGMT_RET_RC_INVALID_IMAGE_DATA_OVERRUN: case IMG_MGMT_RET_RC_UNKNOWN: - default: - rc = MGMT_ERR_EUNKNOWN; + default: + rc = MGMT_ERR_EUNKNOWN; } return 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 8b0c3dd02468..761d77d9e632 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -688,12 +688,12 @@ static int os_mgmt_translate_error_code(uint16_t ret) switch (ret) { case OS_MGMT_RET_RC_INVALID_FORMAT: - rc = MGMT_ERR_EINVAL; - break; + rc = MGMT_ERR_EINVAL; + break; case OS_MGMT_RET_RC_UNKNOWN: default: - rc = MGMT_ERR_EUNKNOWN; + rc = MGMT_ERR_EUNKNOWN; } return rc; diff --git a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c index d0f2a3949731..2aa141671a36 100644 --- a/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/shell_mgmt/src/shell_mgmt.c @@ -143,11 +143,11 @@ static int shell_mgmt_translate_error_code(uint16_t ret) switch (ret) { case SHELL_MGMT_RET_RC_COMMAND_TOO_LONG: case SHELL_MGMT_RET_RC_EMPTY_COMMAND: - rc = MGMT_ERR_EINVAL; - break; + rc = MGMT_ERR_EINVAL; + break; default: - rc = MGMT_ERR_EUNKNOWN; + rc = MGMT_ERR_EUNKNOWN; } return rc; 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 9f9b93011680..1e4a3332e8e1 100644 --- a/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/stat_mgmt/src/stat_mgmt.c @@ -254,16 +254,16 @@ static int stat_mgmt_translate_error_code(uint16_t ret) switch (ret) { case STAT_MGMT_RET_RC_INVALID_GROUP: case STAT_MGMT_RET_RC_INVALID_STAT_NAME: - rc = MGMT_ERR_ENOENT; - break; + rc = MGMT_ERR_ENOENT; + break; case STAT_MGMT_RET_RC_INVALID_STAT_SIZE: - rc = MGMT_ERR_EINVAL; - break; + rc = MGMT_ERR_EINVAL; + break; case STAT_MGMT_RET_RC_WALK_ABORTED: default: - rc = MGMT_ERR_EUNKNOWN; + rc = MGMT_ERR_EUNKNOWN; } return rc; diff --git a/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c b/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c index 4ccf95b2e71f..ba1cc4caf405 100644 --- a/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/zephyr_basic/src/basic_mgmt.c @@ -78,16 +78,16 @@ static int zephyr_basic_group_translate_error_code(uint16_t ret) switch (ret) { case ZEPHYR_MGMT_GRP_CMD_RC_FLASH_OPEN_FAILED: - rc = MGMT_ERR_ENOENT; - break; + rc = MGMT_ERR_ENOENT; + break; case ZEPHYR_MGMT_GRP_CMD_RC_FLASH_CONFIG_QUERY_FAIL: case ZEPHYR_MGMT_GRP_CMD_RC_FLASH_ERASE_FAILED: - rc = MGMT_ERR_EOK; - break; + rc = MGMT_ERR_EOK; + break; default: - rc = MGMT_ERR_EUNKNOWN; + rc = MGMT_ERR_EUNKNOWN; } return rc; From 1f3cb08fdc1481202d0f8e708e28d3239520fc91 Mon Sep 17 00:00:00 2001 From: Sjors Hettinga Date: Mon, 31 Jul 2023 08:55:16 +0200 Subject: [PATCH 1990/2042] net: tcp: Remove trigger of send_data_timer when window full Likely this trigger of the send_data_timer was an alternative for the function that has been filled in by the ZWP transmission. At the moment this timer has the potential to cause spurious retransmissions that can degrade the throughput of the network stack. Second to that it can accelerate the retransmission process, quickly running to the number of retransmissions, causing a connection failure. Signed-off-by: Sjors Hettinga --- subsys/net/ip/tcp.c | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 4cc6fa32bde3..5df354c94b62 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -2775,41 +2775,11 @@ int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt) k_mutex_lock(&conn->lock, K_FOREVER); + /* If there is no space to transmit, try at a later time. + * The ZWP will make sure the window becomes available at + * some point in time. + */ if (tcp_window_full(conn)) { - if (conn->send_win == 0) { - /* No point retransmiting if the current TX window size - * is 0. - */ - ret = -EAGAIN; - goto out; - } - - /* Trigger resend if the timer is not active */ - /* TODO: use k_work_delayable for send_data_timer so we don't - * have to directly access the internals of the legacy object. - * - * NOTE: It is not permitted to access any fields of k_work or - * k_work_delayable directly. This replacement does so, but - * only as a temporary workaround until the legacy - * k_delayed_work structure is replaced with k_work_delayable; - * at that point k_work_schedule() can be invoked to cause the - * work to be scheduled if it is not already scheduled. - * - * This solution diverges from the original, which would - * invoke the retransmit function directly here. Because that - * function is given a k_work pointer, again this cannot be - * done without accessing the internal data of the - * k_work_delayable structure. - * - * The original inline retransmission could be supported by - * refactoring the work_handler to delegate to a function that - * takes conn directly, rather than the work item in which - * conn is embedded, and calling that function directly here - * and in the work handler. - */ - (void)k_work_schedule_for_queue(&tcp_work_q, - &conn->send_data_timer, - K_NO_WAIT); ret = -EAGAIN; goto out; } From c8ac3070ccdd8421696c9163323171d34f55035e Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Fri, 28 Jul 2023 13:05:58 +0300 Subject: [PATCH 1991/2042] net: sockets: socketpair: Allow statically allocated socketpairs When the target board does not have heap by default, allows statically reserving the space for required socketpairs. Signed-off-by: Seppo Takalo --- subsys/net/lib/sockets/Kconfig | 24 ++++++++++++++++++++++-- subsys/net/lib/sockets/socketpair.c | 18 ++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index b4c2ada0d6c0..1d8da5867013 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -246,18 +246,38 @@ config NET_SOCKETS_CAN_RECEIVERS config NET_SOCKETPAIR bool "Support for socketpair" select PIPES - depends on HEAP_MEM_POOL_SIZE != 0 help Communicate over a pair of connected, unnamed UNIX domain sockets. +if NET_SOCKETPAIR + config NET_SOCKETPAIR_BUFFER_SIZE int "Size of the intermediate buffer, in bytes" default 64 range 1 4096 - depends on NET_SOCKETPAIR help Buffer size for socketpair(2) +choice + prompt "Memory management for socketpair" + default NET_SOCKETPAIR_HEAP if HEAP_MEM_POOL_SIZE != 0 + +config NET_SOCKETPAIR_STATIC + bool "Pre-allocate memory statically" + +config NET_SOCKETPAIR_HEAP + bool "Use heap for allocating socketpairs" + depends on HEAP_MEM_POOL_SIZE != 0 + +endchoice + +if NET_SOCKETPAIR_STATIC +config NET_SOCKETPAIR_MAX + int "How many socketpairs to pre-allocate" + default 1 +endif +endif + config NET_SOCKETS_NET_MGMT bool "Network management socket support [EXPERIMENTAL]" depends on NET_MGMT_EVENT diff --git a/subsys/net/lib/sockets/socketpair.c b/subsys/net/lib/sockets/socketpair.c index 3adeeab14ded..b16fb32d1e54 100644 --- a/subsys/net/lib/sockets/socketpair.c +++ b/subsys/net/lib/sockets/socketpair.c @@ -56,6 +56,11 @@ __net_socket struct spair { uint8_t buf[CONFIG_NET_SOCKETPAIR_BUFFER_SIZE]; }; +#ifdef CONFIG_NET_SOCKETPAIR_STATIC +K_MEM_SLAB_DEFINE_STATIC(spair_slab, sizeof(struct spair), CONFIG_NET_SOCKETPAIR_MAX * 2, + __alignof__(struct spair)); +#endif /* CONFIG_NET_SOCKETPAIR_STATIC */ + /* forward declaration */ static const struct socket_op_vtable spair_fd_op_vtable; @@ -188,7 +193,9 @@ static void spair_delete(struct spair *spair) /* ensure no private information is released to the memory pool */ memset(spair, 0, sizeof(*spair)); -#ifdef CONFIG_USERSPACE +#ifdef CONFIG_NET_SOCKETPAIR_STATIC + k_mem_slab_free(&spair_slab, (void **) &spair); +#elif CONFIG_USERSPACE k_object_free(spair); #else k_free(spair); @@ -213,7 +220,14 @@ static struct spair *spair_new(void) struct spair *spair; int res; -#ifdef CONFIG_USERSPACE +#ifdef CONFIG_NET_SOCKETPAIR_STATIC + + res = k_mem_slab_alloc(&spair_slab, (void **) &spair, K_NO_WAIT); + if (res != 0) { + spair = NULL; + } + +#elif CONFIG_USERSPACE struct z_object *zo = z_dynamic_object_create(sizeof(*spair)); if (zo == NULL) { From fce06403364b1330a8dd2b72a148a6c0cc347e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hejnak=20=28LeHack=29?= Date: Sun, 30 Jul 2023 20:33:59 +0200 Subject: [PATCH 1992/2042] boards: nucleo_l552ze_q: Fix green led port/pin definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the definition of the green led pin on the nucleo-L552ZE-Q board The new port/pin for this led (LED1) can be confirmed using docs from os.mbed.com for this board. Additionally I tested it on my own hardware. Also updated the LD2 entry in the docs which was incorrect. Signed-off-by: Łukasz Hejnak (LeHack) --- boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst | 2 +- boards/arm/nucleo_l552ze_q/nucleo_l552ze_q-common.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst index 56de207e45ad..37dee841eab2 100644 --- a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst +++ b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst @@ -261,7 +261,7 @@ Default Zephyr Peripheral Mapping: - SPI_3_MOSI : PC12 - PWM_2_CH1 : PA0 - USER_PB : PC13 -- LD2 : PA5 +- LD2 : PB7 - DAC1 : PA4 - ADC1 : PC0 diff --git a/boards/arm/nucleo_l552ze_q/nucleo_l552ze_q-common.dtsi b/boards/arm/nucleo_l552ze_q/nucleo_l552ze_q-common.dtsi index aa782aa16f3d..057cbebe2c59 100644 --- a/boards/arm/nucleo_l552ze_q/nucleo_l552ze_q-common.dtsi +++ b/boards/arm/nucleo_l552ze_q/nucleo_l552ze_q-common.dtsi @@ -12,7 +12,7 @@ leds { compatible = "gpio-leds"; green_led_1: led_1 { - gpios = <&gpioa 5 GPIO_ACTIVE_HIGH>; + gpios = <&gpioc 7 GPIO_ACTIVE_HIGH>; label = "User LD1"; }; blue_led_1: led_2 { From ee5c99825769d73ee4bb7f0ee4a4ac98db89f3cc Mon Sep 17 00:00:00 2001 From: Matthias Hauser Date: Wed, 28 Jun 2023 14:13:30 +0200 Subject: [PATCH 1993/2042] drivers: sensor: fetch all channels on WSEN_ITDS sensor fetch all channels on WSEN_ITDS sensor Signed-off-by: Matthias Hauser --- drivers/sensor/wsen_itds/itds.c | 12 ++++++++---- drivers/sensor/wsen_itds/itds.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/wsen_itds/itds.c b/drivers/sensor/wsen_itds/itds.c index 79553d8040f2..1849619e55cf 100644 --- a/drivers/sensor/wsen_itds/itds.c +++ b/drivers/sensor/wsen_itds/itds.c @@ -146,7 +146,7 @@ static int itds_attr_set(const struct device *dev, enum sensor_channel chan, } } -static int itds_fetch_temprature(struct itds_device_data *ddata, +static int itds_fetch_temperature(struct itds_device_data *ddata, const struct itds_device_config *cfg) { uint8_t rval; @@ -169,7 +169,7 @@ static int itds_fetch_temprature(struct itds_device_data *ddata, return ret; } - ddata->temprature = sys_le16_to_cpu(temp_raw); + ddata->temperature = sys_le16_to_cpu(temp_raw); return 0; } @@ -228,7 +228,11 @@ static int itds_sample_fetch(const struct device *dev, return itds_fetch_accel(ddata, cfg); case SENSOR_CHAN_DIE_TEMP: - return itds_fetch_temprature(ddata, cfg); + return itds_fetch_temperature(ddata, cfg); + + case SENSOR_CHAN_ALL: + return itds_fetch_accel(ddata, cfg) || + itds_fetch_temperature(ddata, cfg); default: return -EINVAL; @@ -276,7 +280,7 @@ static int itds_temp_channel_get(const struct device *dev, int32_t temp_processed; struct itds_device_data *ddata = dev->data; - temp_processed = (ddata->temprature >> 4) * ITDS_TEMP_CONST; + temp_processed = (ddata->temperature >> 4) * ITDS_TEMP_CONST; val->val1 = ITDS_TEMP_OFFSET; val->val2 = temp_processed; diff --git a/drivers/sensor/wsen_itds/itds.h b/drivers/sensor/wsen_itds/itds.h index 8f56fc313128..2f2c624e43b0 100644 --- a/drivers/sensor/wsen_itds/itds.h +++ b/drivers/sensor/wsen_itds/itds.h @@ -106,7 +106,7 @@ struct itds_device_data { struct k_work work; #endif int16_t samples[ITDS_SAMPLE_SIZE]; - int16_t temprature; + int16_t temperature; uint16_t scale; enum operation_mode op_mode; const struct device *dev; From edc21bd50c40f85c25708bd5204a728f4b28905e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Ku=C5=BAnia?= Date: Mon, 31 Jul 2023 13:29:43 +0200 Subject: [PATCH 1994/2042] ipc: fix icmsg-me maybe-uninitialized compile warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sent_bytes variable was not initialized in all possible execution branches before return. Signed-off-by: Rafał Kuźnia --- subsys/ipc/ipc_service/lib/icmsg_me.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/ipc/ipc_service/lib/icmsg_me.c b/subsys/ipc/ipc_service/lib/icmsg_me.c index c836d71b7b4e..870dca0d483c 100644 --- a/subsys/ipc/ipc_service/lib/icmsg_me.c +++ b/subsys/ipc/ipc_service/lib/icmsg_me.c @@ -168,7 +168,7 @@ int icmsg_me_send(const struct icmsg_config_t *conf, const void *msg, size_t len) { int r; - int sent_bytes; + int sent_bytes = 0; if (user_buffer_len_to_icmsg_buffer_len(len) >= SEND_BUF_SIZE) { return -EBADMSG; From c896e1ed1564ac70c59f3efbac02c4c3af2cde68 Mon Sep 17 00:00:00 2001 From: Dong D Wang Date: Sat, 29 Jul 2023 09:06:40 +0800 Subject: [PATCH 1995/2042] drivers: serial: sedi: add new dts attri peripheral-id It's used to pass right device index to hal_intel module. DT_INST_FOREACH_STATUS_OKAY() does not guarantee the node ordering. Signed-off-by: Dong D Wang --- drivers/serial/uart_sedi.c | 3 ++- dts/bindings/serial/intel,sedi-uart.yaml | 5 +++++ dts/x86/intel/intel_ish5.dtsi | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/serial/uart_sedi.c b/drivers/serial/uart_sedi.c index e082f97ce57b..8ca8379a8256 100644 --- a/drivers/serial/uart_sedi.c +++ b/drivers/serial/uart_sedi.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include @@ -61,7 +62,7 @@ static void uart_sedi_cb(struct device *port); static K_SEM_DEFINE(uart_##n##_sync_read_sem, 0, 1); \ static const struct uart_sedi_config_info config_info_##n = { \ DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ - .instance = SEDI_UART_##n, \ + .instance = DT_INST_PROP(n, peripheral_id), \ .baud_rate = DT_INST_PROP(n, current_speed), \ UART_CONFIG_FLOW_CTRL_SET(n), \ UART_CONFIG_LINE_CTRL_SET, \ diff --git a/dts/bindings/serial/intel,sedi-uart.yaml b/dts/bindings/serial/intel,sedi-uart.yaml index 36eb79cfcf83..27393b7ef82f 100644 --- a/dts/bindings/serial/intel,sedi-uart.yaml +++ b/dts/bindings/serial/intel,sedi-uart.yaml @@ -14,3 +14,8 @@ properties: interrupts: required: true + + peripheral-id: + type: int + description: peripheral ID + required: true diff --git a/dts/x86/intel/intel_ish5.dtsi b/dts/x86/intel/intel_ish5.dtsi index 0a4720a5f346..7e1e97de303e 100644 --- a/dts/x86/intel/intel_ish5.dtsi +++ b/dts/x86/intel/intel_ish5.dtsi @@ -55,6 +55,7 @@ reg = <0x08100000 0x1000>; interrupt-parent = <&intc>; interrupts = <23 IRQ_TYPE_LOWEST_EDGE_RISING 6>; + peripheral-id = <0>; current-speed = <115200>; status = "okay"; }; From 6fd3cf6a5b4339f453a93573599f4098e1231c78 Mon Sep 17 00:00:00 2001 From: Dong D Wang Date: Sat, 29 Jul 2023 09:58:31 +0800 Subject: [PATCH 1996/2042] drivers: serial: sedi: cleanup init code remove semaphores unused currently remove two init helper maro Signed-off-by: Dong D Wang --- drivers/serial/uart_sedi.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/drivers/serial/uart_sedi.c b/drivers/serial/uart_sedi.c index 8ca8379a8256..6bbecb407cf9 100644 --- a/drivers/serial/uart_sedi.c +++ b/drivers/serial/uart_sedi.c @@ -17,14 +17,6 @@ static void uart_sedi_cb(struct device *port); #define DT_DRV_COMPAT intel_sedi_uart -/* Helper macro to set flow control. */ -#define UART_CONFIG_FLOW_CTRL_SET(n) \ - .hw_fc = DT_INST_PROP(n, hw_flow_control) - -/* Helper macro to set line control. */ -#define UART_CONFIG_LINE_CTRL_SET \ - .line_ctrl = SEDI_UART_LC_8N1 - #ifdef CONFIG_UART_INTERRUPT_DRIVEN /* UART IRQ handler declaration. */ #define UART_IRQ_HANDLER_DECL(n) \ @@ -64,12 +56,9 @@ static void uart_sedi_cb(struct device *port); DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ .instance = DT_INST_PROP(n, peripheral_id), \ .baud_rate = DT_INST_PROP(n, current_speed), \ - UART_CONFIG_FLOW_CTRL_SET(n), \ - UART_CONFIG_LINE_CTRL_SET, \ + .hw_fc = DT_INST_PROP(n, hw_flow_control), \ + .line_ctrl = SEDI_UART_LC_8N1, \ .mutex = &uart_##n##_mutex, \ - .tx_sem = &uart_##n##_tx_sem, \ - .rx_sem = &uart_##n##_rx_sem, \ - .sync_read_sem = &uart_##n##_sync_read_sem, \ UART_CONFIG_IRQ_HANDLER_SET(n) \ }; \ \ @@ -91,22 +80,6 @@ static void uart_sedi_cb(struct device *port); (((const struct uart_sedi_config_info *) \ dev->config)->instance) -/* Convenient macro to get tx semamphore */ -#define GET_TX_SEM(dev) \ - (((const struct uart_sedi_config_info *) \ - dev->config)->tx_sem) - - -/* Convenient macro to get rx sempahore */ -#define GET_RX_SEM(dev) \ - (((const struct uart_sedi_config_info *) \ - dev->config)->rx_sem) - -/* Convenient macro to get sync_read sempahore */ -#define GET_SYNC_READ_SEM(dev) \ - (((const struct uart_sedi_config_info *) \ - dev->config)->sync_read_sem) - #define GET_MUTEX(dev) \ (((const struct uart_sedi_config_info *) \ dev->config)->mutex) @@ -123,11 +96,8 @@ struct uart_sedi_config_info { sedi_uart_lc_t line_ctrl; struct k_mutex *mutex; - struct k_sem *tx_sem; - struct k_sem *rx_sem; - struct k_sem *sync_read_sem; - /* Enable / disable hardware flow control for UART. */ + /* Enable / disable hardware flow control for UART. */ bool hw_fc; /* UART irq configuration function when supporting interrupt From de656c1169d6f878e15d54f386c1f89fd71dffe6 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 17 Jul 2023 08:31:48 +0200 Subject: [PATCH 1997/2042] drivers: can: sam: do not select cache management Do not select CONFIG_CACHE_MANAGEMENT in the Microchip SAM CAN driver Kconfig but rather leave it up to the SoC/platform Kconfig to enable it as needed and enable CACHE_MANAGEMENT by default for the Atmel SAM E70/V71 SoC series. Signed-off-by: Henrik Brix Andersen --- drivers/can/Kconfig.sam | 1 - soc/arm/atmel_sam/same70/Kconfig.defconfig.series | 3 +++ soc/arm/atmel_sam/samv71/Kconfig.defconfig.series | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/can/Kconfig.sam b/drivers/can/Kconfig.sam index bfe116638f57..cfb3d9d2709d 100644 --- a/drivers/can/Kconfig.sam +++ b/drivers/can/Kconfig.sam @@ -7,4 +7,3 @@ config CAN_SAM default y depends on DT_HAS_ATMEL_SAM_CAN_ENABLED select CAN_MCAN - select CACHE_MANAGEMENT diff --git a/soc/arm/atmel_sam/same70/Kconfig.defconfig.series b/soc/arm/atmel_sam/same70/Kconfig.defconfig.series index 7c56022d4ca3..a02f44dc99a8 100644 --- a/soc/arm/atmel_sam/same70/Kconfig.defconfig.series +++ b/soc/arm/atmel_sam/same70/Kconfig.defconfig.series @@ -37,4 +37,7 @@ config NUM_IRQS default 74 if SOC_ATMEL_SAME70_REVB default 71 +config CACHE_MANAGEMENT + default y + endif # SOC_SERIES_SAME70 diff --git a/soc/arm/atmel_sam/samv71/Kconfig.defconfig.series b/soc/arm/atmel_sam/samv71/Kconfig.defconfig.series index ca85305d5788..49fe0d65a517 100644 --- a/soc/arm/atmel_sam/samv71/Kconfig.defconfig.series +++ b/soc/arm/atmel_sam/samv71/Kconfig.defconfig.series @@ -38,4 +38,7 @@ config NUM_IRQS default 74 if SOC_ATMEL_SAMV71_REVB default 71 +config CACHE_MANAGEMENT + default y + endif # SOC_SERIES_SAMV71 From 8f3e0fdc025e4bebe8ab97978222890c2c73fcb4 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 27 Jul 2023 11:19:03 +0200 Subject: [PATCH 1998/2042] Bluetooth: att: fix `bt_eatt_count()` Make `bt_eatt_count()` return what it says on the tin, ie. the number of channels that are actually connected. Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/att.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 0f741d23aaf3..d77513bce0ac 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -3289,7 +3289,8 @@ size_t bt_eatt_count(struct bt_conn *conn) } SYS_SLIST_FOR_EACH_CONTAINER(&att->chans, chan, node) { - if (bt_att_is_enhanced(chan)) { + if (bt_att_is_enhanced(chan) && + atomic_test_bit(chan->flags, ATT_CONNECTED)) { eatt_count++; } } From a7cf7eb3936baef93472cf72171c87f83a726b33 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 27 Jul 2023 11:21:04 +0200 Subject: [PATCH 1999/2042] Bluetooth: l2cap: change `connected` cb call condition for ECRED This was recently refactored (in #58440). But it introduced a bug in which some channels were connected but not the whole list asked for by the peer. In that case, `result` will not be `SUCCESS` but we still want to call the `connected` callback as the peer will consider those channels to be connected when we send the response. The symptom is that EATT channels are being instantiated, but not considered connected (ie. usable by the stack). Also introduce a test that has asymmetric channel resources (5 on central vs 2 on peripheral) to reproduce the bug. Fixes #60212 Signed-off-by: Jonathan Rico --- subsys/bluetooth/host/l2cap.c | 2 +- .../bluetooth/host/att/eatt/CMakeLists.txt | 1 + .../host/att/eatt/prj_autoconnect.conf | 1 + .../bluetooth/host/att/eatt/prj_lowres.conf | 17 +++++ tests/bsim/bluetooth/host/att/eatt/src/main.c | 2 + .../bluetooth/host/att/eatt/src/main_lowres.c | 62 +++++++++++++++++++ .../host/att/eatt/tests_scripts/lowres.sh | 22 +++++++ tests/bsim/bluetooth/host/compile.sh | 1 + 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/bsim/bluetooth/host/att/eatt/prj_lowres.conf create mode 100644 tests/bsim/bluetooth/host/att/eatt/src/main_lowres.c create mode 100755 tests/bsim/bluetooth/host/att/eatt/tests_scripts/lowres.sh diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index ff8c712bf096..37cc7892fe8b 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -1320,7 +1320,7 @@ static void le_ecred_conn_req(struct bt_l2cap *l2cap, uint8_t ident, if (ecred_cb && ecred_cb->ecred_conn_req) { ecred_cb->ecred_conn_req(conn, result, psm); } - if (rsp_queued && result == BT_L2CAP_LE_SUCCESS) { + if (rsp_queued) { for (i = 0; i < req_cid_count; i++) { /* Raise connected callback for established channels */ if ((dcid[i] != 0x00) && (chan[i]->ops->connected != NULL)) { diff --git a/tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt b/tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt index 680fc7120c22..9f42ea3eb565 100644 --- a/tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt +++ b/tests/bsim/bluetooth/host/att/eatt/CMakeLists.txt @@ -11,6 +11,7 @@ target_sources(app PRIVATE src/main_collision.c src/main_autoconnect.c src/main_reconfigure.c + src/main_lowres.c src/main.c ) diff --git a/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf b/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf index 39caef2b6302..a65c56908b43 100644 --- a/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf +++ b/tests/bsim/bluetooth/host/att/eatt/prj_autoconnect.conf @@ -14,3 +14,4 @@ CONFIG_LOG=y CONFIG_ASSERT=y CONFIG_BT_L2CAP_TX_MTU=200 +CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/att/eatt/prj_lowres.conf b/tests/bsim/bluetooth/host/att/eatt/prj_lowres.conf new file mode 100644 index 000000000000..936fdeaa4201 --- /dev/null +++ b/tests/bsim/bluetooth/host/att/eatt/prj_lowres.conf @@ -0,0 +1,17 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_DEVICE_NAME="EATT test" +CONFIG_BT_EATT=y +CONFIG_BT_L2CAP_ECRED=y +CONFIG_BT_EATT_MAX=2 +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_EATT_AUTO_CONNECT=n + +CONFIG_BT_TESTING=y +CONFIG_LOG=y +CONFIG_ASSERT=y + +CONFIG_BT_L2CAP_LOG_LEVEL_DBG=y diff --git a/tests/bsim/bluetooth/host/att/eatt/src/main.c b/tests/bsim/bluetooth/host/att/eatt/src/main.c index 737eac339e26..f40585ffb4ba 100644 --- a/tests/bsim/bluetooth/host/att/eatt/src/main.c +++ b/tests/bsim/bluetooth/host/att/eatt/src/main.c @@ -9,11 +9,13 @@ extern struct bst_test_list *test_main_collision_install(struct bst_test_list *tests); extern struct bst_test_list *test_main_autoconnect_install(struct bst_test_list *tests); extern struct bst_test_list *test_main_reconfigure_install(struct bst_test_list *tests); +extern struct bst_test_list *test_main_lowres_install(struct bst_test_list *tests); bst_test_install_t test_installers[] = { test_main_collision_install, test_main_autoconnect_install, test_main_reconfigure_install, + test_main_lowres_install, NULL, }; diff --git a/tests/bsim/bluetooth/host/att/eatt/src/main_lowres.c b/tests/bsim/bluetooth/host/att/eatt/src/main_lowres.c new file mode 100644 index 000000000000..dc5831ca72fd --- /dev/null +++ b/tests/bsim/bluetooth/host/att/eatt/src/main_lowres.c @@ -0,0 +1,62 @@ +/* main_lowres.c - Application main entry point */ + +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.h" + +static void test_peripheral_main(void) +{ + peripheral_setup_and_connect(); + + while (bt_eatt_count(default_conn) < CONFIG_BT_EATT_MAX) { + k_sleep(K_MSEC(10)); + } + + disconnect(); + + PASS("EATT Peripheral tests Passed\n"); +} + +static void test_central_main(void) +{ + central_setup_and_connect(); + + /* Central (us) will try to open 5 channels. + * Peripheral will only accept and open 2. + * + * The purpose of the test is to verify that the accepted EATT channels + * still get opened when the response to the ecred conn req is "Some + * connections refused - not enough resources available". + */ + + wait_for_disconnect(); + + PASS("EATT Central tests Passed\n"); +} + +static const struct bst_test_instance test_def[] = { + { + .test_id = "peripheral_lowres", + .test_descr = "Peripheral lowres", + .test_post_init_f = test_init, + .test_tick_f = test_tick, + .test_main_f = test_peripheral_main, + }, + { + .test_id = "central_lowres", + .test_descr = "Central lowres", + .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_lowres_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_def); +} diff --git a/tests/bsim/bluetooth/host/att/eatt/tests_scripts/lowres.sh b/tests/bsim/bluetooth/host/att/eatt/tests_scripts/lowres.sh new file mode 100755 index 000000000000..4c7ff4ff773f --- /dev/null +++ b/tests/bsim/bluetooth/host/att/eatt/tests_scripts/lowres.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +simulation_id="lowres" +verbosity_level=2 +EXECUTE_TIMEOUT=20 + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_autoconnect_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=central_lowres + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_att_eatt_prj_lowres_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=peripheral_lowres + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \ + -D=2 -sim_length=200e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index dd5ef2347188..039f2b93ae2d 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -27,6 +27,7 @@ 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 app=tests/bsim/bluetooth/host/adv/encrypted/ead_sample compile +app=tests/bsim/bluetooth/host/att/eatt conf_file=prj_lowres.conf compile app=tests/bsim/bluetooth/host/att/eatt conf_file=prj_collision.conf compile app=tests/bsim/bluetooth/host/att/eatt conf_file=prj_multiple_conn.conf compile app=tests/bsim/bluetooth/host/att/eatt conf_file=prj_autoconnect.conf compile From 96bc04f7ac0aa23e5a9dbb64d8ae5383e3923062 Mon Sep 17 00:00:00 2001 From: Lars Knudsen Date: Mon, 31 Jul 2023 14:36:28 +0200 Subject: [PATCH 2000/2042] shell: Fix faulty error check in bt shell bt_addr_le_to_str returns a length of bytes needed for string conversion, not an error code. Signed-off-by: Lars Knudsen --- subsys/bluetooth/shell/bt.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index 37868e444dcb..af17b3460b90 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -361,13 +361,8 @@ bool passes_scan_filter(const struct bt_le_scan_recv_info *info, const struct ne if (scan_filter.addr_set) { char le_addr[BT_ADDR_LE_STR_LEN] = {0}; - int err; - err = bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); - if (err != 0) { - shell_error(ctx_shell, "Failed to convert addr to string: %d", err); - return false; - } + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); if (!is_substring(scan_filter.addr, le_addr)) { return false; From cd78028e15308a80a730b4e634710f2aeb473949 Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:28:20 -0300 Subject: [PATCH 2001/2042] drivers: spi: mcux_lpspi: allow to configure data pins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add binding properties to allow configuring the direction of data pins SDI and SDO. Signed-off-by: Manuel Argüelles --- drivers/spi/spi_mcux_lpspi.c | 4 ++++ dts/bindings/spi/nxp,imx-lpspi.yaml | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 7cca7947cb91..2ddee4a2b097 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -33,6 +33,7 @@ struct spi_mcux_config { uint32_t sck_pcs_delay; uint32_t transfer_delay; const struct pinctrl_dev_config *pincfg; + lpspi_pin_config_t data_pin_config; }; #ifdef CONFIG_SPI_MCUX_LPSPI_DMA @@ -212,6 +213,8 @@ static int spi_mcux_configure(const struct device *dev, master_config.lastSckToPcsDelayInNanoSec = config->sck_pcs_delay; master_config.betweenTransferDelayInNanoSec = config->transfer_delay; + master_config.pinCfg = config->data_pin_config; + if (!device_is_ready(config->clock_dev)) { LOG_ERR("clock control device not ready"); return -ENODEV; @@ -638,6 +641,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { DT_INST_NODE_HAS_PROP(n, transfer_delay), \ DT_INST_PROP(n, transfer_delay)), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .data_pin_config = DT_INST_ENUM_IDX(n, data_pin_config),\ }; \ \ static struct spi_mcux_data spi_mcux_data_##n = { \ diff --git a/dts/bindings/spi/nxp,imx-lpspi.yaml b/dts/bindings/spi/nxp,imx-lpspi.yaml index 1a830d17bf13..16b309a08126 100644 --- a/dts/bindings/spi/nxp,imx-lpspi.yaml +++ b/dts/bindings/spi/nxp,imx-lpspi.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2018, NXP +# Copyright (c) 2018,2023 NXP # SPDX-License-Identifier: Apache-2.0 description: NXP i.MX LPSPI controller @@ -34,3 +34,15 @@ properties: description: | Delay in nanoseconds from the chip select deassert to the next chip select assert. If not set, the minimum supported delay is used. + + data-pin-config: + type: string + enum: + - "sdi-in,sdo-out" + - "sdi-in,sdi-out" + - "sdo-in,sdo-out" + - "sdo-in,sdi-out" + default: "sdi-in,sdo-out" + description: | + Configures which pins (SDO and SDI) are used for input and output data + during single bit transfers. From c7200cac0021244bfb4fb535a2773fc0a4118691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Thu, 6 Jul 2023 17:49:58 -0300 Subject: [PATCH 2002/2042] soc: nxp_s32: add LPSPI to S32K344 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse existing NXP LPSPI binding for this SoC since the hardware block for this device is the same as the one supported for other NXP devices. Signed-off-by: Manuel Argüelles --- dts/arm/nxp/nxp_s32k344_m7.dtsi | 60 +++++++++++++++++++++++++++++ soc/arm/nxp_s32/s32k/Kconfig.series | 1 + 2 files changed, 61 insertions(+) diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 798f0d123e58..701b7342339d 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -529,6 +529,66 @@ #io-channel-cells = <1>; status = "disabled"; }; + + lpspi0: spi@40358000 { + compatible = "nxp,imx-lpspi"; + reg = <0x40358000 0x4000>; + interrupts = <165 0>; + clocks = <&clock NXP_S32_LPSPI0_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi1: spi@4035c000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4035c000 0x4000>; + interrupts = <166 0>; + clocks = <&clock NXP_S32_LPSPI1_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi2: spi@40360000 { + compatible = "nxp,imx-lpspi"; + reg = <0x40360000 0x4000>; + interrupts = <167 0>; + clocks = <&clock NXP_S32_LPSPI2_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi3: spi@40364000 { + compatible = "nxp,imx-lpspi"; + reg = <0x40364000 0x4000>; + interrupts = <168 0>; + clocks = <&clock NXP_S32_LPSPI3_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi4: spi@404bc000 { + compatible = "nxp,imx-lpspi"; + reg = <0x404bc000 0x4000>; + interrupts = <169 0>; + clocks = <&clock NXP_S32_LPSPI4_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi5: spi@404c0000 { + compatible = "nxp,imx-lpspi"; + reg = <0x404c0000 0x4000>; + interrupts = <170 0>; + clocks = <&clock NXP_S32_LPSPI5_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; }; diff --git a/soc/arm/nxp_s32/s32k/Kconfig.series b/soc/arm/nxp_s32/s32k/Kconfig.series index 5d41e1bc1dc9..b489a8bea5d3 100644 --- a/soc/arm/nxp_s32/s32k/Kconfig.series +++ b/soc/arm/nxp_s32/s32k/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_S32K3_M7 select HAS_MCUX_LPUART select HAS_MCUX_FLEXCAN select HAS_MCUX_LPI2C + select HAS_MCUX_LPSPI help Enable support for NXP S32K3 MCUs family on Cortex-M7 cores From 565e582b8dcbe655bb5b1e5a11ad803da085b0db Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:29:42 -0300 Subject: [PATCH 2003/2042] boards: arm: mr_canhubk3: enable support for LPSPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configure LPSPI instances on this board. All of them are routed with SDI and SDO data pins inverted. Enable SPI tests without DMA support for the moment. Signed-off-by: Manuel Argüelles --- boards/arm/mr_canhubk3/doc/index.rst | 1 + .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 59 +++++++++++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.dts | 30 ++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.yaml | 1 + .../spi_loopback/boards/mr_canhubk3.overlay | 21 +++++++ 5 files changed, 112 insertions(+) create mode 100644 tests/drivers/spi/spi_loopback/boards/mr_canhubk3.overlay diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 0ae9bccccc10..66e0134fe80a 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -53,6 +53,7 @@ QSPI on-chip flash FLEXCAN on-chip can LPI2C on-chip i2c ADC SAR on-chip adc +LPSPI on-chip spi ============ ========== ================================ The default configuration can be found in the Kconfig file diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 460a4e35b468..e3bd65f54a52 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -194,4 +194,63 @@ output-enable; }; }; + + lpspi1_default: lpspi1_default { + group1 { + pinmux = , , + , ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + lpspi2_default: lpspi2_default { + group1 { + pinmux = , , + , ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + lpspi3_default: lpspi3_default { + group1 { + pinmux = , , + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + lpspi4_default: lpspi4_default { + group1 { + pinmux = , , + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + lpspi5_default: lpspi5_default { + group1 { + pinmux = , ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index df1f85c84b87..9516d52dd35a 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -320,3 +320,33 @@ pinctrl-names = "default"; clock-frequency = ; }; + +&lpspi1 { + pinctrl-0 = <&lpspi1_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi2 { + pinctrl-0 = <&lpspi2_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi3 { + pinctrl-0 = <&lpspi3_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi4 { + pinctrl-0 = <&lpspi4_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; + +&lpspi5 { + pinctrl-0 = <&lpspi5_default>; + pinctrl-names = "default"; + data-pin-config = "sdo-in,sdi-out"; +}; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.yaml b/boards/arm/mr_canhubk3/mr_canhubk3.yaml index 32648c36efac..a48ea1e78fc8 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.yaml +++ b/boards/arm/mr_canhubk3/mr_canhubk3.yaml @@ -15,3 +15,4 @@ supported: - can - i2c - adc + - spi diff --git a/tests/drivers/spi/spi_loopback/boards/mr_canhubk3.overlay b/tests/drivers/spi/spi_loopback/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..928f05a9929b --- /dev/null +++ b/tests/drivers/spi/spi_loopback/boards/mr_canhubk3.overlay @@ -0,0 +1,21 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&lpspi1 { + 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 = <5000000>; + }; +}; From 3d36af15fadcba83f75f9b0295c3e06bf90c852a Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:30:01 -0300 Subject: [PATCH 2004/2042] drivers: watchdog: support NXP FS26 watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce support for NXP FS26 SBC watchdog. Both Challenger and Simple watchdog types are supported. Only watchdog functionalities of the device are supported and any other monitoring feature is either not supported or disabled. Signed-off-by: Manuel Argüelles --- drivers/watchdog/CMakeLists.txt | 1 + drivers/watchdog/Kconfig | 2 + drivers/watchdog/Kconfig.nxp_fs26 | 76 ++ drivers/watchdog/wdt_nxp_fs26.c | 838 +++++++++++++++++++++++ drivers/watchdog/wdt_nxp_fs26.h | 580 ++++++++++++++++ dts/bindings/watchdog/nxp,fs26-wdog.yaml | 64 ++ 6 files changed, 1561 insertions(+) create mode 100644 drivers/watchdog/Kconfig.nxp_fs26 create mode 100644 drivers/watchdog/wdt_nxp_fs26.c create mode 100644 drivers/watchdog/wdt_nxp_fs26.h create mode 100644 dts/bindings/watchdog/nxp,fs26-wdog.yaml diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 0870f0a66ef2..8faf4c82fbef 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -42,5 +42,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_OPENTITAN wdt_opentitan.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c) zephyr_library_sources_ifdef(CONFIG_WDT_ANDES_ATCWDT200 wdt_andes_atcwdt200.c) +zephyr_library_sources_ifdef(CONFIG_WDT_NXP_FS26 wdt_nxp_fs26.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 52359b1cd775..4f01881fd096 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -114,4 +114,6 @@ source "drivers/watchdog/Kconfig.opentitan" source "drivers/watchdog/Kconfig.andes_atcwdt200" +source "drivers/watchdog/Kconfig.nxp_fs26" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.nxp_fs26 b/drivers/watchdog/Kconfig.nxp_fs26 new file mode 100644 index 000000000000..933cd96530f1 --- /dev/null +++ b/drivers/watchdog/Kconfig.nxp_fs26 @@ -0,0 +1,76 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig WDT_NXP_FS26 + bool "NXP FS26 SBC watchdog driver" + default y + depends on DT_HAS_NXP_FS26_WDOG_ENABLED + select SPI + select GPIO + help + Enable the NXP FS26 SBC watchdog driver. + +if WDT_NXP_FS26 + +config WDT_NXP_FS26_INIT_PRIORITY + int + default 80 + help + Device driver initialization priority. Device is connected to SPI bus, + so it has to be initialized after SPI driver. + +config WDT_NXP_FS26_ERROR_COUNTER_LIMIT + int "Watchdog error counter limit" + default 6 + help + Sets the maximum value of the watchdog error counter. Each time a + watchdog failure occurs, the device increments this counter by 2. The + watchdog error counter is decremented by 1 each time the watchdog is + properly refreshed. + + Possible values are 2, 4, 6, 8. + +config WDT_NXP_FS26_REFRESH_COUNTER_LIMIT + int "Watchdog refresh counter limit" + default 6 + help + Sets the maximum value of the watchdog refresh counter. Each time the + watchdog is properly refreshed, this counter is incremented by 1. Each + time this counter reaches its maximum value and if the next refresh is + also good, the fault error counter is decremented by 1. Each time + there is a bad watchdog refresh, this counter is reset to 0. + + Possible values are 1, 2, 4, 6. + +config WDT_NXP_FS26_SEED + hex "Watchdog seed" + default 0x5ab2 + range 0x0 0xffff + help + Seed to pass to the device. This property can be used with both simple + and challenger watchdog configurations. In simple watchdog + configuration, values 0xffff and 0x0000 are not allowed. In challenger + watchdog configuration, value 0x0000 is not allowed. + +config WDT_NXP_FS26_EXIT_DEBUG_MODE + bool "Exit DEBUG mode" + help + If the device is started in DEBUG mode, the driver will exit this mode + so that the watchdog is enabled. Otherwise, if the device is in DEBUG + mode and this driver is enabled, it will fail to initialize. + +config WDT_NXP_FS26_INT_THREAD_STACK_SIZE + int "Stack size for internal interrupt handler" + default 1024 + help + Size of the stack used for internal thread which is ran for + interrupt processing. + +config WDT_NXP_FS26_INT_THREAD_PRIO + int "Priority for internal incoming packet handler" + default 2 + help + Priority level for internal cooperative thread which is ran for + interrupt processing. + +endif # WDT_NXP_FS26 diff --git a/drivers/watchdog/wdt_nxp_fs26.c b/drivers/watchdog/wdt_nxp_fs26.c new file mode 100644 index 000000000000..07cddc1bd3b3 --- /dev/null +++ b/drivers/watchdog/wdt_nxp_fs26.c @@ -0,0 +1,838 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_fs26_wdog + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(wdt_nxp_fs26); + +#include "wdt_nxp_fs26.h" + +#if defined(CONFIG_BIG_ENDIAN) +#define SWAP_ENDIANNESS +#endif + +#define FS26_CRC_TABLE_SIZE 256U +#define FS26_CRC_INIT 0xff +#define FS26_FS_WD_TOKEN_DEFAULT 0x5ab2 +#define FS26_INIT_FS_TIMEOUT_MS 1000U + +/* Helper macros to set register values from Kconfig options */ +#define WD_ERR_LIMIT(x) CONCAT(WD_ERR_LIMIT_, x) +#define WD_RFR_LIMIT(x) CONCAT(WD_RFR_LIMIT_, x) +#define WDW_PERIOD(x) CONCAT(CONCAT(WDW_PERIOD_, x), MS) + +#define BAD_WD_REFRESH_ERROR_STRING(x) \ + ((((x) & BAD_WD_DATA) ? "error in the data" : \ + (((x) & BAD_WD_TIMING) ? "error in the timing (window)" \ + : "unknown error"))) + +enum fs26_wd_type { + FS26_WD_SIMPLE, + FS26_WD_CHALLENGER +}; + +struct fs26_spi_rx_frame { + union { + struct { + uint8_t m_aval : 1; + uint8_t fs_en : 1; + uint8_t fs_g : 1; + uint8_t com_g : 1; + uint8_t wio_g : 1; + uint8_t vsup_g : 1; + uint8_t reg_g : 1; + uint8_t tsd_g : 1; + }; + uint8_t raw; + } status; + uint16_t data; +}; + +struct fs26_spi_tx_frame { + bool write; + uint8_t addr; + uint16_t data; +}; + +struct wdt_nxp_fs26_config { + struct spi_dt_spec spi; + enum fs26_wd_type wd_type; + struct gpio_dt_spec int_gpio; +}; + +struct wdt_nxp_fs26_data { + wdt_callback_t callback; + uint16_t token; /* local copy of the watchdog token */ + bool timeout_installed; + uint8_t window_period; + uint8_t window_duty_cycle; + uint8_t fs_reaction; + struct gpio_callback int_gpio_cb; + struct k_sem int_sem; + struct k_thread int_thread; + + K_KERNEL_STACK_MEMBER(int_thread_stack, CONFIG_WDT_NXP_FS26_INT_THREAD_STACK_SIZE); +}; + +/* + * Allowed values for watchdog period and duty cycle (CLOSED window). + * The index is the value to write to the register. Keep values in ascending order. + */ +static const uint32_t fs26_period_values[] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 64, 128, 256, 512, 1024 +}; + +static const double fs26_dc_closed_values[] = { + 0.3125, 0.375, 0.5, 0.625, 0.6875, 0.75, 0.8125 +}; + +/* CRC lookup table */ +static const uint8_t FS26_CRC_TABLE[FS26_CRC_TABLE_SIZE] = { + 0x00u, 0x1du, 0x3au, 0x27u, 0x74u, 0x69u, 0x4eu, 0x53u, 0xe8u, + 0xf5u, 0xd2u, 0xcfu, 0x9cu, 0x81u, 0xa6u, 0xbbu, 0xcdu, 0xd0u, + 0xf7u, 0xeau, 0xb9u, 0xa4u, 0x83u, 0x9eu, 0x25u, 0x38u, 0x1fu, + 0x02u, 0x51u, 0x4cu, 0x6bu, 0x76u, 0x87u, 0x9au, 0xbdu, 0xa0u, + 0xf3u, 0xeeu, 0xc9u, 0xd4u, 0x6fu, 0x72u, 0x55u, 0x48u, 0x1bu, + 0x06u, 0x21u, 0x3cu, 0x4au, 0x57u, 0x70u, 0x6du, 0x3eu, 0x23u, + 0x04u, 0x19u, 0xa2u, 0xbfu, 0x98u, 0x85u, 0xd6u, 0xcbu, 0xecu, + 0xf1u, 0x13u, 0x0eu, 0x29u, 0x34u, 0x67u, 0x7au, 0x5du, 0x40u, + 0xfbu, 0xe6u, 0xc1u, 0xdcu, 0x8fu, 0x92u, 0xb5u, 0xa8u, 0xdeu, + 0xc3u, 0xe4u, 0xf9u, 0xaau, 0xb7u, 0x90u, 0x8du, 0x36u, 0x2bu, + 0x0cu, 0x11u, 0x42u, 0x5fu, 0x78u, 0x65u, 0x94u, 0x89u, 0xaeu, + 0xb3u, 0xe0u, 0xfdu, 0xdau, 0xc7u, 0x7cu, 0x61u, 0x46u, 0x5bu, + 0x08u, 0x15u, 0x32u, 0x2fu, 0x59u, 0x44u, 0x63u, 0x7eu, 0x2du, + 0x30u, 0x17u, 0x0au, 0xb1u, 0xacu, 0x8bu, 0x96u, 0xc5u, 0xd8u, + 0xffu, 0xe2u, 0x26u, 0x3bu, 0x1cu, 0x01u, 0x52u, 0x4fu, 0x68u, + 0x75u, 0xceu, 0xd3u, 0xf4u, 0xe9u, 0xbau, 0xa7u, 0x80u, 0x9du, + 0xebu, 0xf6u, 0xd1u, 0xccu, 0x9fu, 0x82u, 0xa5u, 0xb8u, 0x03u, + 0x1eu, 0x39u, 0x24u, 0x77u, 0x6au, 0x4du, 0x50u, 0xa1u, 0xbcu, + 0x9bu, 0x86u, 0xd5u, 0xc8u, 0xefu, 0xf2u, 0x49u, 0x54u, 0x73u, + 0x6eu, 0x3du, 0x20u, 0x07u, 0x1au, 0x6cu, 0x71u, 0x56u, 0x4bu, + 0x18u, 0x05u, 0x22u, 0x3fu, 0x84u, 0x99u, 0xbeu, 0xa3u, 0xf0u, + 0xedu, 0xcau, 0xd7u, 0x35u, 0x28u, 0x0fu, 0x12u, 0x41u, 0x5cu, + 0x7bu, 0x66u, 0xddu, 0xc0u, 0xe7u, 0xfau, 0xa9u, 0xb4u, 0x93u, + 0x8eu, 0xf8u, 0xe5u, 0xc2u, 0xdfu, 0x8cu, 0x91u, 0xb6u, 0xabu, + 0x10u, 0x0du, 0x2au, 0x37u, 0x64u, 0x79u, 0x5eu, 0x43u, 0xb2u, + 0xafu, 0x88u, 0x95u, 0xc6u, 0xdbu, 0xfcu, 0xe1u, 0x5au, 0x47u, + 0x60u, 0x7du, 0x2eu, 0x33u, 0x14u, 0x09u, 0x7fu, 0x62u, 0x45u, + 0x58u, 0x0bu, 0x16u, 0x31u, 0x2cu, 0x97u, 0x8au, 0xadu, 0xb0u, + 0xe3u, 0xfeu, 0xd9u, 0xc4u +}; + +static uint8_t fs26_calcrc(const uint8_t *data, size_t size) +{ + uint8_t crc; + uint8_t tableidx; + uint8_t i; + + /* Set CRC token value */ + crc = FS26_CRC_INIT; + + for (i = size; i > 0; i--) { + tableidx = crc ^ data[i]; + crc = FS26_CRC_TABLE[tableidx]; + } + + return crc; +} + +static int fs26_spi_transceive(const struct spi_dt_spec *spi, + struct fs26_spi_tx_frame *tx_frame, + struct fs26_spi_rx_frame *rx_frame) +{ + uint32_t tx_buf; + uint32_t rx_buf; + uint8_t crc; + int retval; + + struct spi_buf spi_tx_buf = { + .buf = &tx_buf, + .len = sizeof(tx_buf) + }; + struct spi_buf spi_rx_buf = { + .buf = &rx_buf, + .len = sizeof(rx_buf) + }; + struct spi_buf_set spi_tx_set = { + .buffers = &spi_tx_buf, + .count = 1U + }; + struct spi_buf_set spi_rx_set = { + .buffers = &spi_rx_buf, + .count = 1U + }; + + /* Create frame to Tx, always for Fail Safe */ + tx_buf = (uint32_t)(FS26_SET_REG_ADDR(tx_frame->addr) + | FS26_SET_DATA(tx_frame->data) + | (tx_frame->write ? FS26_RW : 0)); + + crc = fs26_calcrc((uint8_t *)&tx_buf, sizeof(tx_buf) - 1); + tx_buf |= (uint32_t)FS26_SET_CRC(crc); + +#if defined(SWAP_ENDIANNESS) + tx_buf = __builtin_bswap32(tx_buf); +#endif + + retval = spi_transceive_dt(spi, &spi_tx_set, &spi_rx_set); + if (retval) { + goto error; + } + +#if defined(SWAP_ENDIANNESS) + rx_buf = __builtin_bswap32(rx_buf); +#endif + + /* Verify CRC of Rx frame */ + crc = fs26_calcrc((uint8_t *)&rx_buf, sizeof(rx_buf) - 1); + if (crc != ((uint8_t)FS26_GET_CRC(rx_buf))) { + LOG_ERR("Rx invalid CRC"); + retval = -EIO; + goto error; + } + + if (rx_frame) { + rx_frame->status.raw = (uint8_t)FS26_GET_DEV_STATUS(rx_buf); + rx_frame->data = (uint16_t)FS26_GET_DATA(rx_buf); + } + +error: + return retval; +} + +/** + * @brief Get value of register with address @p addr + * + * @param spi SPI specs for interacting with the device + * @param addr Register address + * @param rx_frame SPI frame containing read data and device status flags + * + * @return 0 on success, error code otherwise + */ +static int fs26_getreg(const struct spi_dt_spec *spi, uint8_t addr, + struct fs26_spi_rx_frame *rx_frame) +{ + struct fs26_spi_tx_frame tx_frame = { + .addr = addr, + .write = 0, + .data = 0 + }; + + return fs26_spi_transceive(spi, &tx_frame, rx_frame); +} + +/** + * @brief Set @p regval value in register with address @p addr + * + * @param spi SPI specs for interacting with the device + * @param addr Register address + * @param regval Register value to set + * + * @return 0 on success, error code otherwise + */ +static int fs26_setreg(const struct spi_dt_spec *spi, uint8_t addr, uint16_t regval) +{ + struct fs26_spi_tx_frame tx_frame = { + .addr = addr, + .write = true, + .data = regval + }; + + return fs26_spi_transceive(spi, &tx_frame, NULL); +} + +/** + * @brief Calculate watchdog answer based on received token + * + * @return answer value to write to FS_WD_ANSWER + */ +static inline uint16_t fs26_wd_compute_answer(uint16_t token) +{ + uint32_t tmp = token; + + tmp *= 4U; + tmp += 6U; + tmp -= 4U; + tmp = ~tmp; + tmp /= 4U; + + return (uint16_t)tmp; +} + +/** + * @brief Refresh the watchdog and verify the refresh was good. + * + * @return 0 on success, error code otherwise + */ +static int fs26_wd_refresh(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct wdt_nxp_fs26_data *data = dev->data; + int retval = 0; + int key; + uint16_t answer; + struct fs26_spi_rx_frame rx_frame; + + if (config->wd_type == FS26_WD_SIMPLE) { + if (fs26_setreg(&config->spi, FS26_FS_WD_ANSWER, data->token) == 0) { + LOG_ERR("Failed to write answer"); + retval = -EIO; + } + } else if (config->wd_type == FS26_WD_CHALLENGER) { + key = irq_lock(); + + /* Read challenge token generated by the device */ + if (fs26_getreg(&config->spi, FS26_FS_WD_TOKEN, &rx_frame)) { + LOG_ERR("Failed to obtain watchdog token"); + retval = -EIO; + } else { + data->token = rx_frame.data; + LOG_DBG("Watchdog token is %x", data->token); + + answer = fs26_wd_compute_answer(data->token); + if (fs26_setreg(&config->spi, FS26_FS_WD_ANSWER, answer)) { + LOG_ERR("Failed to write answer"); + retval = -EIO; + } + } + + irq_unlock(key); + } else { + retval = -EINVAL; + } + + /* Check if watchdog refresh was successful */ + if (!retval) { + if (!fs26_getreg(&config->spi, FS26_FS_GRL_FLAGS, &rx_frame)) { + if ((rx_frame.data & FS_WD_G_MASK) == FS_WD_G) { + if (!fs26_getreg(&config->spi, FS26_FS_DIAG_SAFETY1, &rx_frame)) { + LOG_ERR("Bad watchdog refresh, %s", + BAD_WD_REFRESH_ERROR_STRING(rx_frame.data)); + } + retval = -EIO; + } else { + LOG_DBG("Refreshed the watchdog"); + } + } + } + + return retval; +} + +/** + * @brief Wait for state machine to be at in INIT_FS state + * + * @return 0 on success, -ETIMEDOUT if timedout + */ +static int fs26_poll_for_init_fs_state(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct fs26_spi_rx_frame rx_frame; + uint32_t regval = 0; + int64_t timeout; + int64_t now; + + timeout = k_uptime_get() + FS26_INIT_FS_TIMEOUT_MS; + + do { + if (!fs26_getreg(&config->spi, FS26_FS_STATES, &rx_frame)) { + regval = rx_frame.data; + } + k_sleep(K_MSEC(1)); + now = k_uptime_get(); + } while ((now < timeout) && (regval & FS_STATES_MASK) != FS_STATES_INIT_FS); + + if (now >= timeout) { + LOG_ERR("Timedout waiting for INIT_FS state"); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * @brief Go to INIT_FS state from any FS state after INIT_FS + * + * After INIT_FS closure, it is possible to come back to INIT_FS with the + * GOTO_INIT bit in FS_SAFE_IOS_1 register from any FS state after INIT_FS. + * + * @return 0 on success, error code otherwise + */ +static int fs26_goto_init_fs_state(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct fs26_spi_rx_frame rx_frame; + uint32_t current_state; + int retval = -EIO; + + if (!fs26_getreg(&config->spi, FS26_FS_STATES, &rx_frame)) { + current_state = rx_frame.data & FS_STATES_MASK; + if (current_state < FS_STATES_INIT_FS) { + LOG_ERR("Cannot go to INIT_FS from current state %x", current_state); + retval = -EIO; + } else if (current_state == FS_STATES_INIT_FS) { + retval = 0; + } else { + fs26_setreg(&config->spi, FS26_FS_SAFE_IOS_1, (uint32_t)FS_GOTO_INIT); + retval = fs26_poll_for_init_fs_state(dev); + } + } + + return retval; +} + +/** + * @brief Close INIT_FS phase with a (good) watchdog refresh. + * + * @return 0 on success, error code otherwise + */ +static inline int fs26_exit_init_fs_state(const struct device *dev) +{ + return fs26_wd_refresh(dev); +} + +static int wdt_nxp_fs26_feed(const struct device *dev, int channel_id) +{ + struct wdt_nxp_fs26_data *data = dev->data; + + if (channel_id != 0) { + LOG_ERR("Invalid channel ID"); + return -EINVAL; + } + + if (!data->timeout_installed) { + LOG_ERR("No timeout installed"); + return -EINVAL; + } + + return fs26_wd_refresh(dev); +} + +static int wdt_nxp_fs26_setup(const struct device *dev, uint8_t options) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct wdt_nxp_fs26_data *data = dev->data; + uint32_t regval; + + if (!data->timeout_installed) { + LOG_ERR("No timeout installed"); + return -EINVAL; + } + + if ((options & WDT_OPT_PAUSE_IN_SLEEP) || (options & WDT_OPT_PAUSE_HALTED_BY_DBG)) { + return -ENOTSUP; + } + + /* + * Apply fail-safe reaction configuration on RSTB and/or the safety output(s), + * configurable during the initialization phase. + */ + if (fs26_goto_init_fs_state(dev)) { + LOG_ERR("Failed to go to INIT_FS"); + return -EIO; + } + + regval = WD_ERR_LIMIT(CONFIG_WDT_NXP_FS26_ERROR_COUNTER_LIMIT) + | WD_RFR_LIMIT(CONFIG_WDT_NXP_FS26_REFRESH_COUNTER_LIMIT) + | ((data->fs_reaction << WD_FS_REACTION_SHIFT) & WD_FS_REACTION_MASK); + + fs26_setreg(&config->spi, FS26_FS_I_WD_CFG, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_WD_CFG, ~regval); + + /* Apply watchdog window configuration, configurable during any FS state */ + regval = ((data->window_period << WDW_PERIOD_SHIFT) & WDW_PERIOD_MASK) + | ((data->window_duty_cycle << WDW_DC_SHIFT) & WDW_DC_MASK) + | WDW_RECOVERY_DISABLE; + + fs26_setreg(&config->spi, FS26_FS_WDW_DURATION, regval); + fs26_setreg(&config->spi, FS26_FS_NOT_WDW_DURATION, ~regval); + + /* + * The new watchdog window is effective after the next watchdog refresh, + * so feed the watchdog once to make it effective after exiting this + * function. Also it's required to close init phase. + */ + if (fs26_exit_init_fs_state(dev)) { + LOG_ERR("Failed to close INIT_FS"); + return -EIO; + } + + return 0; +} + +static int wdt_nxp_fs26_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct wdt_nxp_fs26_data *data = dev->data; + uint32_t window_min; + uint8_t i; + + if (data->timeout_installed) { + LOG_ERR("No more timeouts can be installed"); + return -ENOMEM; + } + + if ((cfg->window.max == 0) || (cfg->window.max > 1024) + || (cfg->window.max <= cfg->window.min)) { + LOG_ERR("Invalid timeout value"); + return -EINVAL; + } + + /* Find nearest period value (rounded up) */ + for (i = 0; i < ARRAY_SIZE(fs26_period_values); i++) { + if (fs26_period_values[i] >= cfg->window.max) { + break; + } + } + data->window_period = i; + LOG_DBG("window.max requested %d ms, using %d ms", + cfg->window.max, fs26_period_values[data->window_period]); + + /* + * Find nearest duty cycle value based on new period, that results in a + * window's minimum near the requested (rounded up) + */ + for (i = 0; i < ARRAY_SIZE(fs26_dc_closed_values); i++) { + window_min = (uint32_t)(fs26_dc_closed_values[i] + * fs26_period_values[data->window_period]); + if (window_min >= cfg->window.min) { + break; + } + } + if (i >= ARRAY_SIZE(fs26_dc_closed_values)) { + LOG_ERR("Watchdog opened window too small"); + return -EINVAL; + } + data->window_duty_cycle = i; + + LOG_DBG("window.min requested %d ms, using %d ms (%.2f%%)", + cfg->window.min, window_min, + fs26_dc_closed_values[data->window_duty_cycle] * 100); + + /* Fail-safe reaction configuration */ + switch (cfg->flags) { + case WDT_FLAG_RESET_SOC: + __fallthrough; + case WDT_FLAG_RESET_CPU_CORE: + data->fs_reaction = WD_FS_REACTION_RSTB_FS0B >> WD_FS_REACTION_SHIFT; + LOG_DBG("Configuring reset mode"); + break; + case WDT_FLAG_RESET_NONE: + data->fs_reaction = WD_FS_REACTION_NO_ACTION >> WD_FS_REACTION_SHIFT; + LOG_DBG("Configuring non-reset mode"); + break; + default: + LOG_ERR("Unsupported watchdog configuration flag"); + return -EINVAL; + } + + data->callback = cfg->callback; + data->timeout_installed = true; + + /* Always return channel ID equal to 0 */ + return 0; +} + +static int wdt_nxp_fs26_disable(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct wdt_nxp_fs26_data *data = dev->data; + struct fs26_spi_rx_frame rx_frame; + uint32_t regval; + + if (fs26_getreg(&config->spi, FS26_FS_WDW_DURATION, &rx_frame)) { + return -EIO; + } + if ((rx_frame.data & WDW_PERIOD_MASK) == WDW_PERIOD_DISABLE) { + LOG_ERR("Watchdog already disabled"); + return -EFAULT; + } + + /* The watchdog window can be disabled only during the initialization phase */ + if (fs26_goto_init_fs_state(dev)) { + LOG_ERR("Failed to go to INIT_FS"); + return -EIO; + } + + regval = WDW_PERIOD_DISABLE | WDW_RECOVERY_DISABLE; + fs26_setreg(&config->spi, FS26_FS_WDW_DURATION, regval); + fs26_setreg(&config->spi, FS26_FS_NOT_WDW_DURATION, ~regval); + + /* The watchdog disabling is effective when the initialization phase is closed */ + if (fs26_exit_init_fs_state(dev)) { + LOG_ERR("Failed to close INIT_FS"); + return -EIO; + } + + LOG_DBG("Watchdog disabled"); + data->timeout_installed = false; + + return 0; +} + +static void wdt_nxp_fs26_int_thread(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct wdt_nxp_fs26_data *data = dev->data; + struct fs26_spi_rx_frame rx_frame; + uint32_t regval; + + while (1) { + k_sem_take(&data->int_sem, K_FOREVER); + + if ((!fs26_getreg(&config->spi, FS26_FS_GRL_FLAGS, &rx_frame)) + && ((rx_frame.data & FS_WD_G_MASK) == FS_WD_G)) { + + if ((!fs26_getreg(&config->spi, FS26_FS_DIAG_SAFETY1, &rx_frame)) + && (rx_frame.data & BAD_WD_TIMING)) { + + /* Clear flag */ + regval = BAD_WD_TIMING; + fs26_setreg(&config->spi, FS26_FS_DIAG_SAFETY1, regval); + + /* Invoke user callback */ + if (data->callback && data->timeout_installed) { + data->callback(dev, 0); + } + } + } + } +} + +static void wdt_nxp_fs26_int_callback(const struct device *dev, + struct gpio_callback *cb, + uint32_t pins) +{ + struct wdt_nxp_fs26_data *data = CONTAINER_OF(cb, struct wdt_nxp_fs26_data, + int_gpio_cb); + + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + k_sem_give(&data->int_sem); +} + +static int wdt_nxp_fs26_init(const struct device *dev) +{ + const struct wdt_nxp_fs26_config *config = dev->config; + struct wdt_nxp_fs26_data *data = dev->data; + struct fs26_spi_rx_frame rx_frame; + uint32_t regval; + + /* Validate bus is ready */ + if (!spi_is_ready_dt(&config->spi)) { + return -ENODEV; + } + + k_sem_init(&data->int_sem, 0, 1); + + /* Configure GPIO used for INTB signal */ + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO port %s not ready", config->int_gpio.port->name); + return -ENODEV; + } + + if (gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT)) { + LOG_ERR("Unable to configure GPIO pin %u", config->int_gpio.pin); + return -EIO; + } + + gpio_init_callback(&(data->int_gpio_cb), wdt_nxp_fs26_int_callback, + BIT(config->int_gpio.pin)); + + if (gpio_add_callback(config->int_gpio.port, &(data->int_gpio_cb))) { + return -EINVAL; + } + + if (gpio_pin_interrupt_configure_dt(&config->int_gpio, + GPIO_INT_EDGE_FALLING)) { + return -EINVAL; + } + + k_thread_create(&data->int_thread, data->int_thread_stack, + CONFIG_WDT_NXP_FS26_INT_THREAD_STACK_SIZE, + (k_thread_entry_t)wdt_nxp_fs26_int_thread, + (void *)dev, NULL, NULL, + K_PRIO_COOP(CONFIG_WDT_NXP_FS26_INT_THREAD_PRIO), + 0, K_NO_WAIT); + + /* Verify FS BIST before proceeding */ + if (fs26_getreg(&config->spi, FS26_FS_DIAG_SAFETY1, &rx_frame)) { + return -EIO; + } + + if ((rx_frame.data & (ABIST1_PASS_MASK | LBIST_STATUS_MASK)) + != (ABIST1_PASS | LBIST_STATUS_OK)) { + + LOG_ERR("BIST failed 0x%x", rx_frame.data); + return -EIO; + } + + /* Get FS state machine state */ + if (fs26_getreg(&config->spi, FS26_FS_STATES, &rx_frame)) { + return -EIO; + } + + /* Verify if in DEBUG mode */ + if ((rx_frame.data & DBG_MODE_MASK) == DBG_MODE) { + if (IS_ENABLED(CONFIG_WDT_NXP_FS26_EXIT_DEBUG_MODE)) { + LOG_DBG("Exiting DEBUG mode"); + regval = rx_frame.data | EXIT_DBG_MODE; + fs26_setreg(&config->spi, FS26_FS_STATES, regval); + } else { + LOG_ERR("In DEBUG mode, watchdog is disabled"); + return -EIO; + } + } + + /* Go to INIT_FS state, if not already there */ + if (fs26_goto_init_fs_state(dev)) { + LOG_ERR("Failed to go to INIT_FS"); + return -EIO; + } + + /* Clear pending FS diagnostic flags before initializing */ + regval = BAD_WD_DATA | BAD_WD_TIMING | ABIST2_PASS | ABIST2_DONE + | SPI_FS_CLK | SPI_FS_REQ | SPI_FS_CRC | FS_OSC_DRIFT; + fs26_setreg(&config->spi, FS26_FS_DIAG_SAFETY1, regval); + + /* + * Perform the following sequence for all INIT_FS registers (FS_I_xxxx) + * - Write the desired data in the FS_I_Register_A (data) + * - Write the opposite in the FS_I_NOT_Register_A (~data) + */ + + /* OVUV_SAFE_REACTION1 */ + regval = VMON_PRE_OV_FS_REACTION_NO_EFFECT | + VMON_PRE_UV_FS_REACTION_NO_EFFECT | + VMON_CORE_OV_FS_REACTION_NO_EFFECT | + VMON_CORE_UV_FS_REACTION_NO_EFFECT | + VMON_LDO1_OV_FS_REACTION_NO_EFFECT | + VMON_LDO1_UV_FS_REACTION_NO_EFFECT | + VMON_LDO2_OV_FS_REACTION_NO_EFFECT | + VMON_LDO2_UV_FS_REACTION_NO_EFFECT; + + fs26_setreg(&config->spi, FS26_FS_I_OVUV_SAFE_REACTION1, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_OVUV_SAFE_REACTION1, ~regval); + + /* OVUV_SAFE_REACTION2 */ + regval = VMON_EXT_OV_FS_REACTION_NO_EFFECT | + VMON_EXT_UV_FS_REACTION_NO_EFFECT | + VMON_REF_OV_FS_REACTION_NO_EFFECT | + VMON_REF_UV_FS_REACTION_NO_EFFECT | + VMON_TRK2_OV_FS_REACTION_NO_EFFECT | + VMON_TRK2_UV_FS_REACTION_NO_EFFECT | + VMON_TRK1_OV_FS_REACTION_NO_EFFECT | + VMON_TRK1_UV_FS_REACTION_NO_EFFECT; + + fs26_setreg(&config->spi, FS26_FS_I_OVUV_SAFE_REACTION2, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_OVUV_SAFE_REACTION2, ~regval); + + /* FS_I_SAFE_INPUTS */ + regval = FCCU_CFG_NO_MONITORING | ERRMON_ACK_TIME_32MS; + + fs26_setreg(&config->spi, FS26_FS_I_SAFE_INPUTS, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_SAFE_INPUTS, ~regval); + + /* FS_I_FSSM */ + regval = FLT_ERR_REACTION_NO_EFFECT | CLK_MON_DIS | DIS8S; + + fs26_setreg(&config->spi, FS26_FS_I_FSSM, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_FSSM, ~regval); + + /* FS_I_WD_CFG */ + regval = WD_ERR_LIMIT(CONFIG_WDT_NXP_FS26_ERROR_COUNTER_LIMIT) + | WD_RFR_LIMIT(CONFIG_WDT_NXP_FS26_REFRESH_COUNTER_LIMIT) + | WD_FS_REACTION_NO_ACTION; + + fs26_setreg(&config->spi, FS26_FS_I_WD_CFG, regval); + fs26_setreg(&config->spi, FS26_FS_I_NOT_WD_CFG, ~regval); + + /* FS_WDW_DURATION */ + /* Watchdog always disabled at boot */ + regval = WDW_PERIOD_DISABLE | WDW_RECOVERY_DISABLE; + + fs26_setreg(&config->spi, FS26_FS_WDW_DURATION, regval); + fs26_setreg(&config->spi, FS26_FS_NOT_WDW_DURATION, ~regval); + + /* Set watchdog seed if not using the default */ + if (data->token != FS26_FS_WD_TOKEN_DEFAULT) { + LOG_DBG("Set seed to %x", data->token); + fs26_setreg(&config->spi, FS26_FS_WD_TOKEN, data->token); + } + + /* Mask all Fail-Safe interrupt sources except for watchdog bad refresh */ + regval = ~BAD_WD_M; + fs26_setreg(&config->spi, FS26_FS_INTB_MASK, regval); + + /* Mask all main interrupt souces */ + regval = 0xffff; + fs26_setreg(&config->spi, FS26_M_TSD_MSK, regval); + fs26_setreg(&config->spi, FS26_M_REG_MSK, regval); + fs26_setreg(&config->spi, FS26_M_VSUP_MSK, regval); + fs26_setreg(&config->spi, FS26_M_WIO_MSK, regval); + fs26_setreg(&config->spi, FS26_M_COM_MSK, regval); + + /* INIT_FS must be closed before the 256 ms timeout */ + if (fs26_exit_init_fs_state(dev)) { + LOG_ERR("Failed to close INIT_FS"); + return -EIO; + } + + /* After INIT_FS is completed, check for data corruption in init registers */ + if (!fs26_getreg(&config->spi, FS26_FS_STATES, &rx_frame)) { + if ((rx_frame.data & REG_CORRUPT_MASK) == REG_CORRUPT) { + LOG_ERR("Data content corruption detected in init registers"); + return -EIO; + } + } + + return 0; +} + +static const struct wdt_driver_api wdt_nxp_fs26_api = { + .setup = wdt_nxp_fs26_setup, + .disable = wdt_nxp_fs26_disable, + .install_timeout = wdt_nxp_fs26_install_timeout, + .feed = wdt_nxp_fs26_feed, +}; + +#define FS26_WDT_DEVICE_INIT(n) \ + COND_CODE_1(DT_INST_ENUM_IDX(n, type), \ + (BUILD_ASSERT(CONFIG_WDT_NXP_FS26_SEED != 0x0, \ + "Seed value 0x0000 is not allowed");), \ + (BUILD_ASSERT((CONFIG_WDT_NXP_FS26_SEED != 0x0) \ + && (CONFIG_WDT_NXP_FS26_SEED != 0xffff), \ + "Seed values 0x0000 and 0xffff are not allowed");)) \ + \ + static struct wdt_nxp_fs26_data wdt_nxp_fs26_data_##n = { \ + .token = CONFIG_WDT_NXP_FS26_SEED, \ + }; \ + \ + static const struct wdt_nxp_fs26_config wdt_nxp_fs26_config_##n = { \ + .spi = SPI_DT_SPEC_INST_GET(n, \ + SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(32), 0), \ + .wd_type = CONCAT(FS26_WD_, DT_INST_STRING_UPPER_TOKEN(n, type)), \ + .int_gpio = GPIO_DT_SPEC_INST_GET(n, int_gpios), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + wdt_nxp_fs26_init, \ + NULL, \ + &wdt_nxp_fs26_data_##n, \ + &wdt_nxp_fs26_config_##n, \ + POST_KERNEL, \ + CONFIG_WDT_NXP_FS26_INIT_PRIORITY, \ + &wdt_nxp_fs26_api); + +DT_INST_FOREACH_STATUS_OKAY(FS26_WDT_DEVICE_INIT) diff --git a/drivers/watchdog/wdt_nxp_fs26.h b/drivers/watchdog/wdt_nxp_fs26.h new file mode 100644 index 000000000000..25787ba355cf --- /dev/null +++ b/drivers/watchdog/wdt_nxp_fs26.h @@ -0,0 +1,580 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_WATCHDOG_WDT_NXP_FS26_H_ +#define ZEPHYR_DRIVERS_WATCHDOG_WDT_NXP_FS26_H_ + +/* FS26 SPI Tx frame fields */ + +/* Main or Fail-safe register selection (M/FS) */ +#define FS26_M_FS (0x1 << 31) +/* Register Address + M/FS */ +#define FS26_REG_ADDR_SHIFT (25) +#define FS26_REG_ADDR_MASK (0x7f << FS26_REG_ADDR_SHIFT) +#define FS26_SET_REG_ADDR(n) (((n) << FS26_REG_ADDR_SHIFT) & FS26_REG_ADDR_MASK) +#define FS26_GET_REG_ADDR(n) (((n) & FS26_REG_ADDR_MASK) >> FS26_REG_ADDR_SHIFT) +/* Read/Write (reading = 0) */ +#define FS26_RW (0x1 << 24) + +/* FS26 SPI Rx frame fields */ + +/* Device status flags */ +#define FS26_DEV_STATUS_SHIFT (24) +#define FS26_DEV_STATUS_MASK (0xff << FS26_DEV_STATUS_SHIFT) +#define FS26_GET_DEV_STATUS(n) (((n) << FS26_DEV_STATUS_SHIFT) & FS26_DEV_STATUS_MASK) +/* Main State machine availability (M_AVAL) */ +#define FS26_M_AVAL (0x1 << 31) +/* Fail Safe State machine status (FS_EN) */ +#define FS26_FS_EN (0x1 << 30) +/* Interrupt notification from the Fail-Safe domain */ +#define FS26_FS_G (0x1 << 29) +/* Interrupt notification from the M_COM_FLG register */ +#define FS26_COM_G (0x1 << 28) +/* Interrupt notification from the M_WIO_FLG register */ +#define FS26_WIO_G (0x1 << 27) +/* Interrupt notification from the M_VSUP_FLG register */ +#define FS26_VSUP_G (0x1 << 26) +/* Interrupt notification from the M_REG_FLG register */ +#define FS26_REG_G (0x1 << 25) +/* Interrupt notification from the M_TSD_FLG register */ +#define FS26_TSD_G (0x1 << 24) + +/* FS26 SPI Tx/Rx frame common fields */ + +/* DATA_MSB */ +#define FS26_DATA_SHIFT (8) +#define FS26_DATA_MASK (0xffff << FS26_DATA_SHIFT) +#define FS26_SET_DATA(n) (((n) << FS26_DATA_SHIFT) & FS26_DATA_MASK) +#define FS26_GET_DATA(n) (((n) & FS26_DATA_MASK) >> FS26_DATA_SHIFT) +/* DATA_LSB */ +#define FS26_DATA_LSB_SHIFT (8) +#define FS26_DATA_LSB_MASK (0xff << FS26_DATA_LSB_SHIFT) +#define FS26_SET_DATA_LSB(n) (((n) << FS26_DATA_LSB_SHIFT) & FS26_DATA_LSB_MASK) +#define FS26_GET_DATA_LSB(n) (((n) & FS26_DATA_LSB_MASK) >> FS26_DATA_LSB_SHIFT) +/* DATA_MSB */ +#define FS26_DATA_MSB_SHIFT (16) +#define FS26_DATA_MSB_MASK (0xff << FS26_DATA_MSB_SHIFT) +#define FS26_SET_DATA_MSB(n) (((n) << FS26_DATA_MSB_SHIFT) & FS26_DATA_MSB_MASK) +#define FS26_GET_DATA_MSB(n) (((n) & FS26_DATA_MSB_MASK) >> FS26_DATA_MSB_SHIFT) +/* CRC */ +#define FS26_CRC_SHIFT (0) +#define FS26_CRC_MASK (0xff << FS26_CRC_SHIFT) +#define FS26_SET_CRC(n) (((n) << FS26_CRC_SHIFT) & FS26_CRC_MASK) +#define FS26_GET_CRC(n) (((n) & FS26_CRC_MASK) >> FS26_CRC_SHIFT) + +/* FS26 SPI register map */ + +#define FS26_M_DEVICE_ID (0x0) +#define FS26_M_PROGID (0x1) +#define FS26_M_STATUS (0x2) +#define FS26_M_TSD_FLG (0x3) +#define FS26_M_TSD_MSK (0x4) +#define FS26_M_REG_FLG (0x5) +#define FS26_M_REG_MSK (0x6) +#define FS26_M_VSUP_FLG (0x7) +#define FS26_M_VSUP_MSK (0x8) +#define FS26_M_WIO_FLG (0x9) +#define FS26_M_WIO_MSK (0xa) +#define FS26_M_COM_FLG (0xb) +#define FS26_M_COM_MSK (0xc) +#define FS26_M_SYS_CFG (0xd) +#define FS26_M_TSD_CFG (0xe) +#define FS26_M_REG_CFG (0xf) +#define FS26_M_WIO_CFG (0x10) +#define FS26_M_REG_CTRL1 (0x11) +#define FS26_M_REG_CTRL2 (0x12) +#define FS26_M_AMUX_CTRL (0x13) +#define FS26_M_LDT_CFG1 (0x14) +#define FS26_M_LDT_CFG2 (0x15) +#define FS26_M_LDT_CFG3 (0x16) +#define FS26_M_LDT_CTRL (0x17) +#define FS26_M_MEMORY0 (0x18) +#define FS26_M_MEMORY1 (0x19) + +/* FS26 Fail Safe register map */ + +#define FS26_FS_GRL_FLAGS (0x40) +#define FS26_FS_I_OVUV_SAFE_REACTION1 (0x41) +#define FS26_FS_I_NOT_OVUV_SAFE_REACTION1 (0x42) +#define FS26_FS_I_OVUV_SAFE_REACTION2 (0x43) +#define FS26_FS_I_NOT_OVUV_SAFE_REACTION2 (0x44) +#define FS26_FS_I_WD_CFG (0x45) +#define FS26_FS_I_NOT_WD_CFG (0x46) +#define FS26_FS_I_SAFE_INPUTS (0x47) +#define FS26_FS_I_NOT_SAFE_INPUTS (0x48) +#define FS26_FS_I_FSSM (0x49) +#define FS26_FS_I_NOT_FSSM (0x4a) +#define FS26_FS_WDW_DURATION (0x4b) +#define FS26_FS_NOT_WDW_DURATION (0x4c) +#define FS26_FS_WD_ANSWER (0x4d) +#define FS26_FS_WD_TOKEN (0x4e) +#define FS26_FS_ABIST_ON_DEMAND (0x4f) +#define FS26_FS_OVUV_REG_STATUS (0x50) +#define FS26_FS_RELEASE_FS0B_FS1B (0x51) +#define FS26_FS_SAFE_IOS_1 (0x52) +#define FS26_FS_SAFE_IOS_2 (0x53) +#define FS26_FS_DIAG_SAFETY1 (0x54) +#define FS26_FS_DIAG_SAFETY2 (0x55) +#define FS26_FS_INTB_MASK (0x56) +#define FS26_FS_STATES (0x57) +#define FS26_FS_LP_REQ (0x58) +#define FS26_FS_LDT_LPSEL (0x59) + +/* FS_I_OVUV_SAFE_REACTION1 register */ + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_PRE */ +#define VMON_PRE_OV_FS_REACTION_SHIFT (14) +#define VMON_PRE_OV_FS_REACTION_MASK (0x3 << VMON_PRE_OV_FS_REACTION_SHIFT) +#define VMON_PRE_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_PRE_OV_FS_REACTION_SHIFT) +#define VMON_PRE_OV_FS_REACTION_FS0B (0x1 << VMON_PRE_OV_FS_REACTION_SHIFT) +#define VMON_PRE_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_PRE_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_PRE */ +#define VMON_PRE_UV_FS_REACTION_SHIFT (12) +#define VMON_PRE_UV_FS_REACTION_MASK (0x3 << VMON_PRE_UV_FS_REACTION_SHIFT) +#define VMON_PRE_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_PRE_UV_FS_REACTION_SHIFT) +#define VMON_PRE_UV_FS_REACTION_FS0B (0x1 << VMON_PRE_UV_FS_REACTION_SHIFT) +#define VMON_PRE_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_PRE_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_CORE */ +#define VMON_CORE_OV_FS_REACTION_SHIFT (10) +#define VMON_CORE_OV_FS_REACTION_MASK (0x3 << VMON_CORE_OV_FS_REACTION_SHIFT) +#define VMON_CORE_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_CORE_OV_FS_REACTION_SHIFT) +#define VMON_CORE_OV_FS_REACTION_FS0B (0x1 << VMON_CORE_OV_FS_REACTION_SHIFT) +#define VMON_CORE_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_CORE_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_CORE */ +#define VMON_CORE_UV_FS_REACTION_SHIFT (8) +#define VMON_CORE_UV_FS_REACTION_MASK (0x3 << VMON_CORE_UV_FS_REACTION_SHIFT) +#define VMON_CORE_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_CORE_UV_FS_REACTION_SHIFT) +#define VMON_CORE_UV_FS_REACTION_FS0B (0x1 << VMON_CORE_UV_FS_REACTION_SHIFT) +#define VMON_CORE_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_CORE_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_LDO1 */ +#define VMON_LDO1_OV_FS_REACTION_SHIFT (6) +#define VMON_LDO1_OV_FS_REACTION_MASK (0x3 << VMON_LDO1_OV_FS_REACTION_SHIFT) +#define VMON_LDO1_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_LDO1_OV_FS_REACTION_SHIFT) +#define VMON_LDO1_OV_FS_REACTION_FS0B (0x1 << VMON_LDO1_OV_FS_REACTION_SHIFT) +#define VMON_LDO1_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_LDO1_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_LDO1 */ +#define VMON_LDO1_UV_FS_REACTION_SHIFT (4) +#define VMON_LDO1_UV_FS_REACTION_MASK (0x3 << VMON_LDO1_UV_FS_REACTION_SHIFT) +#define VMON_LDO1_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_LDO1_UV_FS_REACTION_SHIFT) +#define VMON_LDO1_UV_FS_REACTION_FS0B (0x1 << VMON_LDO1_UV_FS_REACTION_SHIFT) +#define VMON_LDO1_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_LDO1_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_LDO2 */ +#define VMON_LDO2_OV_FS_REACTION_SHIFT (2) +#define VMON_LDO2_OV_FS_REACTION_MASK (0x3 << VMON_LDO2_OV_FS_REACTION_SHIFT) +#define VMON_LDO2_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_LDO2_OV_FS_REACTION_SHIFT) +#define VMON_LDO2_OV_FS_REACTION_FS0B (0x1 << VMON_LDO2_OV_FS_REACTION_SHIFT) +#define VMON_LDO2_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_LDO2_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_LDO2 */ +#define VMON_LDO2_UV_FS_REACTION_SHIFT (0) +#define VMON_LDO2_UV_FS_REACTION_MASK (0x3 << VMON_LDO2_UV_FS_REACTION_SHIFT) +#define VMON_LDO2_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_LDO2_UV_FS_REACTION_SHIFT) +#define VMON_LDO2_UV_FS_REACTION_FS0B (0x1 << VMON_LDO2_UV_FS_REACTION_SHIFT) +#define VMON_LDO2_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_LDO2_UV_FS_REACTION_SHIFT) + +/* FS_I_OVUV_SAFE_REACTION2 register */ + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_EXT */ +#define VMON_EXT_OV_FS_REACTION_SHIFT (14) +#define VMON_EXT_OV_FS_REACTION_MASK (0x3 << VMON_EXT_OV_FS_REACTION_SHIFT) +#define VMON_EXT_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_EXT_OV_FS_REACTION_SHIFT) +#define VMON_EXT_OV_FS_REACTION_FS0B (0x1 << VMON_EXT_OV_FS_REACTION_SHIFT) +#define VMON_EXT_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_EXT_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_EXT */ +#define VMON_EXT_UV_FS_REACTION_SHIFT (12) +#define VMON_EXT_UV_FS_REACTION_MASK (0x3 << VMON_EXT_UV_FS_REACTION_SHIFT) +#define VMON_EXT_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_EXT_UV_FS_REACTION_SHIFT) +#define VMON_EXT_UV_FS_REACTION_FS0B (0x1 << VMON_EXT_UV_FS_REACTION_SHIFT) +#define VMON_EXT_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_EXT_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_REF */ +#define VMON_REF_OV_FS_REACTION_SHIFT (10) +#define VMON_REF_OV_FS_REACTION_MASK (0x3 << VMON_REF_OV_FS_REACTION_SHIFT) +#define VMON_REF_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_REF_OV_FS_REACTION_SHIFT) +#define VMON_REF_OV_FS_REACTION_FS0B (0x1 << VMON_REF_OV_FS_REACTION_SHIFT) +#define VMON_REF_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_REF_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_REF */ +#define VMON_REF_UV_FS_REACTION_SHIFT (8) +#define VMON_REF_UV_FS_REACTION_MASK (0x3 << VMON_REF_UV_FS_REACTION_SHIFT) +#define VMON_REF_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_REF_UV_FS_REACTION_SHIFT) +#define VMON_REF_UV_FS_REACTION_FS0B (0x1 << VMON_REF_UV_FS_REACTION_SHIFT) +#define VMON_REF_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_REF_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_TRK2 */ +#define VMON_TRK2_OV_FS_REACTION_SHIFT (6) +#define VMON_TRK2_OV_FS_REACTION_MASK (0x3 << VMON_TRK2_OV_FS_REACTION_SHIFT) +#define VMON_TRK2_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_TRK2_OV_FS_REACTION_SHIFT) +#define VMON_TRK2_OV_FS_REACTION_FS0B (0x1 << VMON_TRK2_OV_FS_REACTION_SHIFT) +#define VMON_TRK2_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_TRK2_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_TRK2 */ +#define VMON_TRK2_UV_FS_REACTION_SHIFT (4) +#define VMON_TRK2_UV_FS_REACTION_MASK (0x3 << VMON_TRK2_UV_FS_REACTION_SHIFT) +#define VMON_TRK2_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_TRK2_UV_FS_REACTION_SHIFT) +#define VMON_TRK2_UV_FS_REACTION_FS0B (0x1 << VMON_TRK2_UV_FS_REACTION_SHIFT) +#define VMON_TRK2_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_TRK2_UV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of OV detection on VMON_TRK1 */ +#define VMON_TRK1_OV_FS_REACTION_SHIFT (2) +#define VMON_TRK1_OV_FS_REACTION_MASK (0x3 << VMON_TRK1_OV_FS_REACTION_SHIFT) +#define VMON_TRK1_OV_FS_REACTION_NO_EFFECT (0x0 << VMON_TRK1_OV_FS_REACTION_SHIFT) +#define VMON_TRK1_OV_FS_REACTION_FS0B (0x1 << VMON_TRK1_OV_FS_REACTION_SHIFT) +#define VMON_TRK1_OV_FS_REACTION_RSTB_FS0B (0x2 << VMON_TRK1_OV_FS_REACTION_SHIFT) + +/* Reaction on RSTB or FAIL SAFE outputs in case of UV detection on VMON_TRK1 */ +#define VMON_TRK1_UV_FS_REACTION_SHIFT (0) +#define VMON_TRK1_UV_FS_REACTION_MASK (0x3 << VMON_TRK1_UV_FS_REACTION_SHIFT) +#define VMON_TRK1_UV_FS_REACTION_NO_EFFECT (0x0 << VMON_TRK1_UV_FS_REACTION_SHIFT) +#define VMON_TRK1_UV_FS_REACTION_FS0B (0x1 << VMON_TRK1_UV_FS_REACTION_SHIFT) +#define VMON_TRK1_UV_FS_REACTION_RSTB_FS0B (0x2 << VMON_TRK1_UV_FS_REACTION_SHIFT) + +/* FS26_FS_I_WD_CFG register */ + +/* Watchdog error counter limit */ +#define WD_ERR_LIMIT_SHIFT (14) +#define WD_ERR_LIMIT_MASK (0x3 << WD_ERR_LIMIT_SHIFT) +#define WD_ERR_LIMIT_8 (0x0 << WD_ERR_LIMIT_SHIFT) +#define WD_ERR_LIMIT_6 (0x1 << WD_ERR_LIMIT_SHIFT) +#define WD_ERR_LIMIT_4 (0x2 << WD_ERR_LIMIT_SHIFT) +#define WD_ERR_LIMIT_2 (0x3 << WD_ERR_LIMIT_SHIFT) + +/* Watchdog refresh counter limit */ +#define WD_RFR_LIMIT_SHIFT (11) +#define WD_RFR_LIMIT_MASK (0x3 << WD_RFR_LIMIT_SHIFT) +#define WD_RFR_LIMIT_6 (0x0 << WD_RFR_LIMIT_SHIFT) +#define WD_RFR_LIMIT_4 (0x1 << WD_RFR_LIMIT_SHIFT) +#define WD_RFR_LIMIT_2 (0x2 << WD_RFR_LIMIT_SHIFT) +#define WD_RFR_LIMIT_1 (0x3 << WD_RFR_LIMIT_SHIFT) + +/* Reaction on RSTB or FAIL SAFE output in case of BAD Watchdog (data or timing) */ +#define WD_FS_REACTION_SHIFT (8) +#define WD_FS_REACTION_MASK (0x3 << WD_FS_REACTION_SHIFT) +#define WD_FS_REACTION_NO_ACTION (0x0 << WD_FS_REACTION_SHIFT) +#define WD_FS_REACTION_FS0B (0x1 << WD_FS_REACTION_SHIFT) +#define WD_FS_REACTION_RSTB_FS0B (0x2 << WD_FS_REACTION_SHIFT) + +/* Reflect the value of the Watchdog Refresh Counter */ +#define WD_RFR_CNT_SHIFT (8) +#define WD_RFR_CNT_MASK (0x7 << WD_RFR_CNT_SHIFT) +#define WD_RFR_CNT(n) ((n) & (0x7 << WD_RFR_CNT_SHIFT)) + +/* Reflect the value of the Watchdog Error Counter */ +#define WD_ERR_CNT_SHIFT (0) +#define WD_ERR_CNT_MASK (0xf << WD_ERR_CNT_SHIFT) +#define WD_ERR_CNT(n) \ + (((n) & (0x7 << WD_RFR_CNT_SHIFT)) > 11) ? (11) : (((n) & (0x7 << WD_RFR_CNT_SHIFT))) + +/* FS26_FS_I_SAFE_INPUTS register */ + +/* FCCU Monitoring Configuration */ +#define FCCU_CFG_SHIFT (13) +#define FCCU_CFG_MASK (0x7 << FCCU_CFG_SHIFT) +#define FCCU_CFG_NO_MONITORING (0x0 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU1_FCCU2_PAIR (0x1 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU1_FCCU2_SINGLE (0x2 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU1_ONLY (0x3 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU2_ONLY (0x4 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU1_FCCU2_PWM (0x5 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU1_PWM_FCCU2_SINGLE (0x6 << FCCU_CFG_SHIFT) +#define FCCU_CFG_FCCU2_PWM_FCCU1_SINGLE (0x7 << FCCU_CFG_SHIFT) + +/* FCCU12 Fault Polarity */ +#define FCCU12_FLT_POL_SHIFT (12) +#define FCCU12_FLT_POL_MASK (0x1 << FCCU12_FLT_POL_SHIFT) +#define FCCU12_FLT_POL_FCCU1_0_FCCU2_1_IS_FAULT (0x0 << FCCU12_FLT_POL_SHIFT) +#define FCCU12_FLT_POL_FCCU1_1_FCCU2_0_IS_FAULT (0x1 << FCCU12_FLT_POL_SHIFT) + +/* FCCU1 Fault Polarity */ +#define FCCU1_FLT_POL_SHIFT (11) +#define FCCU1_FLT_POL_MASK (0x1 << FCCU1_FLT_POL_SHIFT) +#define FCCU1_FLT_POL_LOW (0x0 << FCCU1_FLT_POL_SHIFT) +#define FCCU1_FLT_POL_HIGH (0x1 << FCCU1_FLT_POL_SHIFT) + +/* FCCU2 Fault Polarity */ +#define FCCU2_FLT_POL_SHIFT (10) +#define FCCU2_FLT_POL_MASK (0x1 << FCCU2_FLT_POL_SHIFT) +#define FCCU2_FLT_POL_LOW (0x0 << FCCU2_FLT_POL_SHIFT) +#define FCCU2_FLT_POL_HIGH (0x1 << FCCU2_FLT_POL_SHIFT) + +/* Reaction on RSTB or FAIL SAFE output in case of FAULT DETECTION ON FCCU12 */ +#define FCCU12_FS_REACTION_SHIFT (9) +#define FCCU12_FS_REACTION_MASK (0x1 << FCCU12_FS_REACTION_SHIFT) +#define FCCU12_FS_REACTION (FCCU12_FS_REACTION_MASK) + +/* Reaction on RSTB or FAIL SAFE output in case of FAULT DETECTION ON FCCU1 */ +#define FCCU1_FS_REACTION_SHIFT (8) +#define FCCU1_FS_REACTION_MASK (0x1 << FCCU1_FS_REACTION_SHIFT) +#define FCCU1_FS_REACTION (FCCU1_FS_REACTION_MASK) + +/* Reaction on RSTB or FAIL SAFE output in case of FAULT DETECTION ON FCCU2 */ +#define FCCU2_FS_REACTION_SHIFT (7) +#define FCCU2_FS_REACTION_MASK (0x1 << FCCU2_FS_REACTION_SHIFT) +#define FCCU2_FS_REACTION (FCCU2_FS_REACTION_MASK) + +/* ERRORMON Fault Polarity */ +#define ERRMON_FLT_POLARITY_SHIFT (5) +#define ERRMON_FLT_POLARITY_MASK (0x1 << ERRMON_FLT_POLARITY_SHIFT) +#define ERRMON_FLT_POLARITY_LOW (0x0 << ERRMON_FLT_POLARITY_SHIFT) +#define ERRMON_FLT_POLARITY_HIGH (0x1 << ERRMON_FLT_POLARITY_SHIFT) + +/* Acknowledge timing following a fault detection on ERRMON */ +#define ERRMON_ACK_TIME_SHIFT (3) +#define ERRMON_ACK_TIME_MASK (0x3 << ERRMON_ACK_TIME_SHIFT) +#define ERRMON_ACK_TIME_1MS (0x0 << ERRMON_ACK_TIME_SHIFT) +#define ERRMON_ACK_TIME_8MS (0x1 << ERRMON_ACK_TIME_SHIFT) +#define ERRMON_ACK_TIME_16MS (0x2 << ERRMON_ACK_TIME_SHIFT) +#define ERRMON_ACK_TIME_32MS (0x3 << ERRMON_ACK_TIME_SHIFT) + +/* Reaction on RSTB or Fail Safe output in case of fault detection on ERRMON */ +#define ERRMON_FS_REACTION_SHIFT (2) +#define ERRMON_FS_REACTION_MASK (0x1 << FCCU2_FS_REACTION_SHIFT) +#define ERRMON_FS_REACTION (FCCU2_FS_REACTION_MASK) + +/* FCCU pin filtering time settings */ +#define FCCU12_FILT_SHIFT (0) +#define FCCU12_FILT_MASK (0x3 << FCCU12_FILT_SHIFT) +#define FCCU12_FILT_3US (0x0 << FCCU12_FILT_SHIFT) +#define FCCU12_FILT_6US (0x1 << FCCU12_FILT_SHIFT) +#define FCCU12_FILT_10US (0x2 << FCCU12_FILT_SHIFT) +#define FCCU12_FILT_20US (0x3 << FCCU12_FILT_SHIFT) + +/* FS26_FS_I_FSSM register */ + +/* Configure the maximum level of the fault counter */ +#define FLT_ERR_CNT_LIMIT_SHIFT (14) +#define FLT_ERR_CNT_LIMIT_MASK (0x3 << FLT_ERR_CNT_LIMIT_SHIFT) +#define FLT_ERR_CNT_LIMIT_2 (0x0 << FLT_ERR_CNT_LIMIT_SHIFT) +#define FLT_ERR_CNT_LIMIT_6 (0x1 << FLT_ERR_CNT_LIMIT_SHIFT) +#define FLT_ERR_CNT_LIMIT_8 (0x2 << FLT_ERR_CNT_LIMIT_SHIFT) +#define FLT_ERR_CNT_LIMIT_12 (0x3 << FLT_ERR_CNT_LIMIT_SHIFT) + +/* Configure the RSTB and FS0B behavior when fault error counter ≥ intermediate value */ +#define FLT_ERR_REACTION_SHIFT (8) +#define FLT_ERR_REACTION_MASK (0x3 << FLT_ERR_REACTION_SHIFT) +#define FLT_ERR_REACTION_NO_EFFECT (0x0 << FLT_ERR_REACTION_SHIFT) +#define FLT_ERR_REACTION_FS0B (0x1 << FLT_ERR_REACTION_SHIFT) +#define FLT_ERR_REACTION_RSTB_FS0B (0x2 << FLT_ERR_REACTION_SHIFT) + +/* Reset duration configuration */ +#define RSTB_DUR_SHIFT (9) +#define RSTB_DUR_MASK (0x1 << RSTB_DUR_SHIFT) +#define RSTB_DUR_1MS (RSTB_DUR_MASK) +#define RSTB_DUR_10MS (0) + +/* Assert RSTB in case a short to high is detected on FS0B */ +#define BACKUP_SAFETY_PATH_FS0B_SHIFT (7) +#define BACKUP_SAFETY_PATH_FS0B_MASK (0x1 << BACKUP_SAFETY_PATH_FS0B_SHIFT) +#define BACKUP_SAFETY_PATH_FS0B (BACKUP_SAFETY_PATH_FS0B_MASK) + +/* Assert RSTB in case a short to high is detected on FS1B */ +#define BACKUP_SAFETY_PATH_FS1B_SHIFT (6) +#define BACKUP_SAFETY_PATH_FS1B_MASK (0x1 << BACKUP_SAFETY_PATH_FS1B_SHIFT) +#define BACKUP_SAFETY_PATH_FS1B (BACKUP_SAFETY_PATH_FS1B_MASK) + +/* Disable CLK Monitoring */ +#define CLK_MON_DIS_SHIFT (5) +#define CLK_MON_DIS_MASK (0x1 << CLK_MON_DIS_SHIFT) +#define CLK_MON_DIS (CLK_MON_DIS_MASK) + +/* Disable 8s RSTB timer */ +#define DIS8S_SHIFT (4) +#define DIS8S_MASK (0x1 << DIS8S_SHIFT) +#define DIS8S (DIS8S_MASK) + +/* Reflect the value of the Watchdog Error Counter */ +#define FLT_ERR_CNT_SHIFT (0) +#define FLT_ERR_CNT_MASK (0xf << FLT_ERR_CNT_SHIFT) +#define FLT_ERR_CNT(n) \ + ((n & (0x7 << FLT_ERR_CNT_SHIFT)) > 12) ? (12) : ((n & (0x7 << FLT_ERR_CNT_SHIFT))) + +/* FS26_FS_WDW_DURATION register */ + +/* Watchdog window period */ +#define WDW_PERIOD_SHIFT (12) +#define WDW_PERIOD_MASK (0xf << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_DISABLE (0x0 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_1MS (0x1 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_2MS (0x2 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_3MS (0x3 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_4MS (0x4 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_6MS (0x5 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_8MS (0x6 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_12MS (0x7 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_16MS (0x8 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_24MS (0x9 << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_32MS (0xa << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_64MS (0xb << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_128MS (0xc << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_256MS (0xd << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_512MS (0xe << WDW_PERIOD_SHIFT) +#define WDW_PERIOD_1024MS (0xf << WDW_PERIOD_SHIFT) + +/* Watchdog window duty cycle */ +#define WDW_DC_SHIFT (6) +#define WDW_DC_MASK (0x7 << WDW_DC_SHIFT) +#define WDW_DC_31_68 (0x0 << WDW_PERIOD_SHIFT) +#define WDW_DC_37_62 (0x1 << WDW_PERIOD_SHIFT) +#define WDW_DC_50_50 (0x2 << WDW_PERIOD_SHIFT) +#define WDW_DC_62_37 (0x3 << WDW_PERIOD_SHIFT) +#define WDW_DC_68_31 (0x4 << WDW_PERIOD_SHIFT) + +/* Watchdog window period */ +#define WDW_RECOVERY_SHIFT (0) +#define WDW_RECOVERY_MASK (0xf << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_DISABLE (0x0 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_1MS (0x1 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_2MS (0x2 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_3MS (0x3 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_4MS (0x4 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_6MS (0x5 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_8MS (0x6 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_12MS (0x7 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_16MS (0x8 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_24MS (0x9 << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_32MS (0xa << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_64MS (0xb << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_128MS (0xc << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_256MS (0xd << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_512MS (0xe << WDW_RECOVERY_SHIFT) +#define WDW_RECOVERY_1024MS (0xf << WDW_RECOVERY_SHIFT) + +/* FS26_FS_DIAG_SAFETY1 register */ + +/* Bad WD refresh, Error in the data */ +#define BAD_WD_DATA_SHIFT (10) +#define BAD_WD_DATA_MASK (0x1 << BAD_WD_DATA_SHIFT) +#define BAD_WD_DATA (BAD_WD_DATA_MASK) + +/* Bad WD refresh, Error in the timing */ +#define BAD_WD_TIMING_SHIFT (9) +#define BAD_WD_TIMING_MASK (0x1 << BAD_WD_TIMING_SHIFT) +#define BAD_WD_TIMING (BAD_WD_TIMING_MASK) + +/* ABIST 1 pass */ +#define ABIST1_PASS_SHIFT (8) +#define ABIST1_PASS_MASK (0x1 << ABIST1_PASS_SHIFT) +#define ABIST1_PASS (ABIST1_PASS_MASK) + +/* ABIST 2 pass */ +#define ABIST2_PASS_SHIFT (7) +#define ABIST2_PASS_MASK (0x1 << ABIST2_PASS_SHIFT) +#define ABIST2_PASS (ABIST2_PASS_MASK) + +/* ABIST 2 done */ +#define ABIST2_DONE_SHIFT (6) +#define ABIST2_DONE_MASK (0x1 << ABIST2_DONE_SHIFT) +#define ABIST2_DONE (ABIST2_DONE_MASK) + +/* SPI CLK error */ +#define SPI_FS_CLK_SHIFT (5) +#define SPI_FS_CLK_MASK (0x1 << SPI_FS_CLK_SHIFT) +#define SPI_FS_CLK (SPI_FS_CLK_MASK) + +/* SPI invalid read/write error */ +#define SPI_FS_REQ_SHIFT (4) +#define SPI_FS_REQ_MASK (0x1 << SPI_FS_REQ_SHIFT) +#define SPI_FS_REQ (SPI_FS_REQ_MASK) + +/* SPI CRC error */ +#define SPI_FS_CRC_SHIFT (3) +#define SPI_FS_CRC_MASK (0x1 << SPI_FS_CRC_SHIFT) +#define SPI_FS_CRC (SPI_FS_CRC_MASK) + +/* FS OSC drift */ +#define FS_OSC_DRIFT_SHIFT (2) +#define FS_OSC_DRIFT_MASK (0x1 << FS_OSC_DRIFT_SHIFT) +#define FS_OSC_DRIFT (FS_OSC_DRIFT_MASK) + +/* LBIST STATUS */ +#define LBIST_STATUS_SHIFT (0) +#define LBIST_STATUS_MASK (0x3 << LBIST_STATUS_SHIFT) +#define LBIST_STATUS (LBIST_STATUS_MASK) +#define LBIST_STATUS_FAIL (0x0 << LBIST_STATUS_SHIFT) +#define LBIST_STATUS_BYPASSED (0x1 << LBIST_STATUS_SHIFT) +#define LBIST_STATUS_FAIL2 (0x2 << LBIST_STATUS_SHIFT) +#define LBIST_STATUS_OK (0x3 << LBIST_STATUS_SHIFT) + +/* FS26_FS_STATES register */ + +/* Leave debug mode */ +#define EXIT_DBG_MODE_SHIFT (14) +#define EXIT_DBG_MODE_MASK (0x1 << EXIT_DBG_MODE_SHIFT) +#define EXIT_DBG_MODE (EXIT_DBG_MODE_MASK) + +/* debug mode */ +#define DBG_MODE_SHIFT (13) +#define DBG_MODE_MASK (0x1 << DBG_MODE_SHIFT) +#define DBG_MODE (DBG_MODE_MASK) + +/* OTP crc error */ +#define OTP_CORRUPT_SHIFT (12) +#define OTP_CORRUPT_MASK (0x1 << OTP_CORRUPT_SHIFT) +#define OTP_CORRUPT (OTP_CORRUPT_MASK) + +/* INIT register error */ +#define REG_CORRUPT_SHIFT (11) +#define REG_CORRUPT_MASK (0x1 << REG_CORRUPT_SHIFT) +#define REG_CORRUPT (REG_CORRUPT_MASK) + +/* LBIST STATUS */ +#define FS_STATES_SHIFT (0) +#define FS_STATES_MASK (0x1f << FS_STATES_SHIFT) +#define FS_STATES (FS_STATES_MASK) +#define FS_STATES_DEBUG_ENTRY (0x4 << FS_STATES_SHIFT) +#define FS_STATES_ENABLE_MON (0x6 << FS_STATES_SHIFT) +#define FS_STATES_RSTB_RELEASE (0x8 << FS_STATES_SHIFT) +#define FS_STATES_INIT_FS (0x9 << FS_STATES_SHIFT) +#define FS_STATES_SAFETY_OUT_NOT (0xa << FS_STATES_SHIFT) +#define FS_STATES_NORMAL (0xb << FS_STATES_SHIFT) + +/* FS26_FS_GRL_FLAGS register */ + +/* Report an issue in the communication (SPI) */ +#define FS_COM_G_SHIFT (15) +#define FS_COM_G_MASK (0x1 << FS_COM_G_SHIFT) +#define FS_COM_G (FS_COM_G_MASK) + +/* Report an issue on the Watchdog Refresh */ +#define FS_WD_G_SHIFT (14) +#define FS_WD_G_MASK (0x1 << FS_WD_G_SHIFT) +#define FS_WD_G (FS_WD_G_MASK) + +/* Report an issue in one of the Fail Safe IOs */ +#define FS_IO_G_SHIFT (13) +#define FS_IO_G_MASK (0x1 << FS_IO_G_SHIFT) +#define FS_IO_G (FS_IO_G_MASK) + +/* Report an issue in one of the voltage monitoring (OV or UV) */ +#define FS_REG_OVUV_G_SHIFT (12) +#define FS_REG_OVUV_G_MASK (0x1 << FS_REG_OVUV_G_SHIFT) +#define FS_REG_OVUV_G (FS_REG_OVUV_G_MASK) + +/* Report an issue on BIST (Logical or Analog) */ +#define FS_BIST_G_SHIFT (11) +#define FS_BIST_G_MASK (0x1 << FS_BIST_G_SHIFT) +#define FS_BIST_G (FS_BIST_G_MASK) + +/* FS26_FS_SAFE_IOS_1 register */ + +/* Go Back to INIT Fail Safe Request */ +#define FS_GOTO_INIT_SHIFT (1) +#define FS_GOTO_INIT_MASK (0x1 << FS_GOTO_INIT_SHIFT) +#define FS_GOTO_INIT (FS_GOTO_INIT_MASK) + +/* FS26_FS_INTB_MASK register */ + +/* Interrupt Mask on BAD_WD_REFRESH */ +#define BAD_WD_M (0x1 << 5) + +#endif /* ZEPHYR_DRIVERS_WATCHDOG_WDT_NXP_FS26_H_ */ diff --git a/dts/bindings/watchdog/nxp,fs26-wdog.yaml b/dts/bindings/watchdog/nxp,fs26-wdog.yaml new file mode 100644 index 000000000000..a27f2e9b1a03 --- /dev/null +++ b/dts/bindings/watchdog/nxp,fs26-wdog.yaml @@ -0,0 +1,64 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + FS26 System Basis Chip (SBC) watchdog driver. + + The FS26 features multiple voltage regulators to supply the microcontroller, + peripheral ICs and communication interfaces. The FS26 also offers various + functionalities for system control and monitoring, including a configurable + watchdog counter to ensure the microcontroller is able to communicate with the + FS26, which can react to any failure condition and place the system in a safe + state. This driver covers only the watchdog functionality of FS26. The rest + of the functionalities are not implemented. + + The FS26 uses a 32-bit SPI interface. The MCU is the primary driving MOSI and + FS26 is the secondary driving MISO. Therefore the FS26 devicetree node must be + in a SPI bus. For example, if FS26 is connected to spi3 bus, on Chip Select 0: + + &spi3 { + // here there should be spi3 properties as needed + status = "okay"; + + fs26_wdt: watchdog@0 { + compatible = "nxp,fs26-wdog"; + reg = <0>; + spi-max-frequency = ; + type = "challenger"; + int-gpios = <&gpioa_h 3 GPIO_ACTIVE_LOW>; + status = "okay"; + }; + }; + + When an FS26 internal interrupt occurs, the INTB pin generates a pulse to + inform the microcontroller. The driver masks all interrupt sources except for + bad watchdog refresh (BAD_WD_M). The GPIO pin where the interrupt signal is + received must be configured from devicetree. In the example above, this is + indicated through int-gpios property. It is also required to configure the + external interrupt controller to receive interrupts on this pin. + +compatible: "nxp,fs26-wdog" + +include: spi-device.yaml + +properties: + type: + required: true + type: string + enum: + - simple + - challenger + description: | + Watchdog type enabled on this device. + + The Challenger watchdog monitoring feature is enabled for ASIL D devices. + This mode is based on a question/answer process with the microcontroller. + + The Simple watchdog monitoring feature is enabled for ASIL B devices. This + mode uses a unique seed. + + int-gpios: + type: phandle-array + required: true + description: | + GPIO to use to receive external interrupts from INTB signal. From f2ff27bd73249fcb9ff80ab41acfba4f7dd821ab Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:30:15 -0300 Subject: [PATCH 2005/2042] boards: arm: mr_canhubk3: enable NXP FS26 wdt support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configure the NXP FS26 SBC on the LPSPI3 bus and enable it by default on this board configuration so that there is no need to start the FS26 in debug mode. Signed-off-by: Manuel Argüelles --- boards/arm/mr_canhubk3/doc/index.rst | 18 ++++++++++++------ .../arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi | 2 +- boards/arm/mr_canhubk3/mr_canhubk3.dts | 12 ++++++++++++ boards/arm/mr_canhubk3/mr_canhubk3.yaml | 1 + boards/arm/mr_canhubk3/mr_canhubk3_defconfig | 1 + 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 66e0134fe80a..4853057f3e1c 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -54,6 +54,7 @@ FLEXCAN on-chip can LPI2C on-chip i2c ADC SAR on-chip adc LPSPI on-chip spi +WDT FS26 SBC watchdog ============ ========== ================================ The default configuration can be found in the Kconfig file @@ -207,13 +208,18 @@ FS26 SBC Watchdog On normal operation after the board is powered on, there is a window of 256 ms on which the FS26 watchdog must be serviced with a good token refresh, otherwise -the watchdog will signal a reset to the MCU. Currently there is no driver for -the watchdog so the FS26 must be started in debug mode following these steps: +the watchdog will signal a reset to the MCU. This board configuration enables +the FS26 watchdog driver that handles this initialization. -1. Power off the board. -2. Remove the jumper ``JP1`` (pins 1-2 open), which is connected by default. -3. Power on the board. -4. Reconnect the jumper ``JP1`` (pins 1-2 shorted). +.. note:: + + The FS26 can also be started in debug mode (watchdog disabled) following + these steps: + + 1. Power off the board. + 2. Remove the jumper ``JP1`` (pins 1-2 open), which is connected by default. + 3. Power on the board. + 4. Reconnect the jumper ``JP1`` (pins 1-2 shorted). External Flash ============== diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index e3bd65f54a52..eb091e158e8f 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 9516d52dd35a..236d15fef3f7 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include #include "mr_canhubk3-pinctrl.dtsi" / { @@ -31,6 +32,7 @@ led2 = &user_led1_blue; sw0 = &user_button_1; sw1 = &user_button_2; + watchdog0 = &fs26_wdt; }; leds { @@ -337,6 +339,16 @@ pinctrl-0 = <&lpspi3_default>; pinctrl-names = "default"; data-pin-config = "sdo-in,sdi-out"; + status = "okay"; + + fs26_wdt: watchdog@0 { + compatible = "nxp,fs26-wdog"; + reg = <0>; + spi-max-frequency = ; + type = "challenger"; + int-gpios = <&gpioa_h 2 GPIO_ACTIVE_LOW>; + status = "okay"; + }; }; &lpspi4 { diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.yaml b/boards/arm/mr_canhubk3/mr_canhubk3.yaml index a48ea1e78fc8..74f146f7646d 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.yaml +++ b/boards/arm/mr_canhubk3/mr_canhubk3.yaml @@ -16,3 +16,4 @@ supported: - i2c - adc - spi + - watchdog diff --git a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig index 91ebfcc17d2c..68613d22f111 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3_defconfig +++ b/boards/arm/mr_canhubk3/mr_canhubk3_defconfig @@ -21,6 +21,7 @@ CONFIG_NOCACHE_MEMORY=y # Drivers CONFIG_PINCTRL=y CONFIG_SERIAL=y +CONFIG_WATCHDOG=y # Serial console CONFIG_CONSOLE=y From cb54a31b28706aa1ae532370401fe7a4cf0b1fce Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:30:32 -0300 Subject: [PATCH 2006/2042] samples: watchdog: add support for NXP FS26 watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This watchdog doesn't allow to stop on CPU halt by debugger. It also requires a minimum window value different than zero so that the watchdog is refreshed during the open window. Signed-off-by: Manuel Argüelles --- samples/drivers/watchdog/src/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/samples/drivers/watchdog/src/main.c b/samples/drivers/watchdog/src/main.c index 2cfcf6e7ba5f..cad88ebcf664 100644 --- a/samples/drivers/watchdog/src/main.c +++ b/samples/drivers/watchdog/src/main.c @@ -2,6 +2,7 @@ * Copyright (c) 2015 Intel Corporation * Copyright (c) 2018 Nordic Semiconductor * Copyright (c) 2019 Centaur Analytics, Inc + * Copyright 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,6 +35,11 @@ #elif DT_HAS_COMPAT_STATUS_OKAY(intel_tco_wdt) #define WDT_ALLOW_CALLBACK 0 #define WDT_MAX_WINDOW 3000U +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_fs26_wdog) +#define WDT_MAX_WINDOW 1024U +#define WDT_MIN_WINDOW 320U +#define WDT_OPT 0 +#define WDG_FEED_INTERVAL (WDT_MIN_WINDOW + ((WDT_MAX_WINDOW - WDT_MIN_WINDOW) / 4)) #endif #ifndef WDT_ALLOW_CALLBACK @@ -52,6 +58,10 @@ #define WDG_FEED_INTERVAL 50U #endif +#ifndef WDT_OPT +#define WDT_OPT WDT_OPT_PAUSE_HALTED_BY_DBG +#endif + #if WDT_ALLOW_CALLBACK static void wdt_callback(const struct device *wdt_dev, int channel_id) { @@ -111,7 +121,7 @@ int main(void) return 0; } - err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG); + err = wdt_setup(wdt, WDT_OPT); if (err < 0) { printk("Watchdog setup error\n"); return 0; From 42e8678d2a4ddc80448551611e2e428e1ace6db8 Mon Sep 17 00:00:00 2001 From: Manuel Arguelles Date: Thu, 6 Jul 2023 17:30:46 -0300 Subject: [PATCH 2007/2042] samples: task_wdt: add scenario without hw fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new sample scenario without using a hardware watchdog as fallback. This is used for the moment only for the mr_canhubk3 board, but a generic configuration is introduced that can be used by other boards if needed. Signed-off-by: Manuel Argüelles --- .../task_wdt/boards/mr_canhubk3.overlay | 15 +++++++ .../subsys/task_wdt/prj_no_hw_fallback.conf | 8 ++++ samples/subsys/task_wdt/sample.yaml | 39 +++++++++++-------- 3 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 samples/subsys/task_wdt/boards/mr_canhubk3.overlay create mode 100644 samples/subsys/task_wdt/prj_no_hw_fallback.conf diff --git a/samples/subsys/task_wdt/boards/mr_canhubk3.overlay b/samples/subsys/task_wdt/boards/mr_canhubk3.overlay new file mode 100644 index 000000000000..8138d3846795 --- /dev/null +++ b/samples/subsys/task_wdt/boards/mr_canhubk3.overlay @@ -0,0 +1,15 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * FS26 watchdog cannot be used as hardware watchdog fallback on this SoC, since + * the SPI driver being used to communicate with the device, cannot transceive + * from interrupt context. In order to run this sample, FS26 must be started in + * DEBUG mode (see board documentation). + */ +&fs26_wdt { + status = "disabled"; +}; diff --git a/samples/subsys/task_wdt/prj_no_hw_fallback.conf b/samples/subsys/task_wdt/prj_no_hw_fallback.conf new file mode 100644 index 000000000000..9de301105712 --- /dev/null +++ b/samples/subsys/task_wdt/prj_no_hw_fallback.conf @@ -0,0 +1,8 @@ +CONFIG_LOG=y +CONFIG_LOG_MODE_IMMEDIATE=y + +CONFIG_WATCHDOG=n + +CONFIG_TASK_WDT=y + +CONFIG_THREAD_NAME=y diff --git a/samples/subsys/task_wdt/sample.yaml b/samples/subsys/task_wdt/sample.yaml index c3ebffebf42d..1c9c300a8782 100644 --- a/samples/subsys/task_wdt/sample.yaml +++ b/samples/subsys/task_wdt/sample.yaml @@ -1,23 +1,28 @@ sample: name: Task Watchdog Subsytem Sample +common: + tags: subsys + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "Task watchdog sample application." + - "Control thread started." + - "Main thread still alive..." + - "Control thread getting stuck..." + - "Task watchdog channel 1 callback, thread: control" + - "Resetting device...(.*)" + - "Task watchdog sample application." + depends_on: watchdog + platform_exclude: + - s32z270dc2_rtu0_r52 + - s32z270dc2_rtu1_r52 tests: sample.subsys.task_wdt: - tags: subsys - harness: console - harness_config: - type: multi_line - ordered: true - regex: - - "Task watchdog sample application." - - "Control thread started." - - "Main thread still alive..." - - "Control thread getting stuck..." - - "Task watchdog channel 1 callback, thread: control" - - "Resetting device...(.*)" - - "Task watchdog sample application." - depends_on: watchdog integration_platforms: - nucleo_g474re - platform_exclude: - - s32z270dc2_rtu0_r52 - - s32z270dc2_rtu1_r52 + sample.subsys.task_wdt.no_hw_fallback: + extra_args: CONF_FILE="prj_no_hw_fallback.conf" + platform_allow: + - mr_canhubk3 From eb3a56d8cd0bf6e8fca183f103a248b7818e6b00 Mon Sep 17 00:00:00 2001 From: Josep Puigdemont Date: Fri, 28 Jul 2023 19:39:47 +0200 Subject: [PATCH 2008/2042] sensor: dht: return error if channel not supported The driver would return the temperature for all channels requested except relative humidity. Instead, ENOTSUP should be returned for unsupported channels. Signed-off-by: Josep Puigdemont --- drivers/sensor/dht/dht.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/sensor/dht/dht.c b/drivers/sensor/dht/dht.c index 8c5e35a861fb..6bd447ba5107 100644 --- a/drivers/sensor/dht/dht.c +++ b/drivers/sensor/dht/dht.c @@ -184,7 +184,7 @@ static int dht_channel_get(const struct device *dev, + drv_data->sample[1]; val->val1 = raw_val / 10; val->val2 = (raw_val % 10) * 100000; - } else { /* chan == SENSOR_CHAN_AMBIENT_TEMP */ + } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { raw_val = (drv_data->sample[2] << 8) + drv_data->sample[3]; @@ -199,15 +199,19 @@ static int dht_channel_get(const struct device *dev, val->val1 = -val->val1; val->val2 = -val->val2; } + } else { + return -ENOTSUP; } } else { /* use only integral data byte */ if (chan == SENSOR_CHAN_HUMIDITY) { val->val1 = drv_data->sample[0]; val->val2 = 0; - } else { /* chan == SENSOR_CHAN_AMBIENT_TEMP */ + } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { val->val1 = drv_data->sample[2]; val->val2 = 0; + } else { + return -ENOTSUP; } } From 2143502f5466a25ec1e814eaeaab42fd58e730c7 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 31 Jul 2023 15:47:23 -0400 Subject: [PATCH 2009/2042] include: util: Add Z_DETECT_POINTER_OVERFLOW() The Z_DETECT_POINTER_OVERFLOW() macro is intended detect whether or not a buffer spans a region of memory that goes beyond the highest possible address (thereby overflowing the pointer). Signed-off-by: Peter Mitsis --- include/zephyr/sys/util.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index f352e7b7a80b..208d71e4776b 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -25,6 +25,7 @@ #include #include +#include /** @brief Number of bits that make up a type */ #define NUM_BITS(t) (sizeof(t) * 8) @@ -588,6 +589,22 @@ char *utf8_lcpy(char *dst, const char *src, size_t n); */ #define NHPOT(x) ((x) < 1 ? 1 : ((x) > (1ULL<<63) ? 0 : 1ULL << LOG2CEIL(x))) +/** + * @brief Determine if a buffer exceeds highest address + * + * This macro determines if a buffer identified by a starting address @a addr + * and length @a buflen spans a region of memory that goes beond the highest + * possible address (thereby resulting in a pointer overflow). + * + * @param addr Buffer starting address + * @param buflen Length of the buffer + * + * @return true if pointer overflow detected, false otherwise + */ +#define Z_DETECT_POINTER_OVERFLOW(addr, buflen) \ + (((buflen) != 0) && \ + ((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1)))) + #ifdef __cplusplus } #endif From bd5839ec9e13090865982e533455ba7dba795960 Mon Sep 17 00:00:00 2001 From: Peter Mitsis Date: Mon, 31 Jul 2023 14:25:53 -0400 Subject: [PATCH 2010/2042] kernel: Fix wrap-around check in kernel/mmu.h Fixes the buffer wrap-around check so that it will not be ignored by the GNU C compiler. Signed-off-by: Peter Mitsis --- kernel/include/mmu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index 3768240db666..f51c0adeda0d 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -204,7 +204,7 @@ static inline void z_mem_assert_virtual_region(uint8_t *addr, size_t size) "unaligned addr %p", addr); __ASSERT(size % CONFIG_MMU_PAGE_SIZE == 0U, "unaligned size %zu", size); - __ASSERT(addr + size > addr, + __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, "invalid virtual address region %p (%zu)", addr, size); From fb8f214f46c742f64e63e31df04b6011c3544a7b Mon Sep 17 00:00:00 2001 From: Yasushi SHOJI Date: Sun, 18 Jun 2023 18:25:22 +0900 Subject: [PATCH 2011/2042] scripts: gen_defines.py: Update doc reference interrupts.rst has been moved to doc/kernel/services/. Signed-off-by: Yasushi SHOJI --- scripts/dts/gen_defines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 0c95557cda2d..d21fdc756464 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -454,7 +454,7 @@ def map_arm_gic_irq_type(irq, irq_num): err(f"Invalid interrupt type specified for {irq!r}") def encode_zephyr_multi_level_irq(irq, irq_num): - # See doc/reference/kernel/other/interrupts.rst for details + # See doc/kernel/services/interrupts.rst for details # on how this encoding works irq_ctrl = irq.controller From e4eadfa784668d5f417a9cf63560f3cfc693c14d Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Mon, 19 Jun 2023 12:34:00 +0200 Subject: [PATCH 2012/2042] boards: arm: add initial support for efr32bg22_brd4184b This adds basic support for 'B' revision of the Silicon Labs EFR32BG BRD4184 (Thunderboard BG22) board. Due to missing drivers, some of the on-board peripherals are currently unsupported: - Silicon Labs Si7021 relative humidity and temperature sensor - Vishay VEML6035 ambient light sensor - Knowles SPK0641HT4H-1 MEMS microphones - TDK InvenSense ICM-20648 6-axis inertial sensor Signed-off-by: Piotr Dymacz --- boards/arm/efr32_thunderboard/Kconfig.board | 5 ++ .../arm/efr32_thunderboard/Kconfig.defconfig | 7 +++ boards/arm/efr32_thunderboard/board.cmake | 2 +- .../efr32_thunderboard/efr32bg22_brd4184.dtsi | 58 +++++++++++++++++++ .../efr32_thunderboard/efr32bg22_brd4184a.dts | 55 +----------------- .../efr32_thunderboard/efr32bg22_brd4184b.dts | 33 +++++++++++ .../efr32bg22_brd4184b.yaml | 20 +++++++ .../efr32bg22_brd4184b_defconfig | 22 +++++++ west.yml | 2 +- 9 files changed, 149 insertions(+), 55 deletions(-) create mode 100644 boards/arm/efr32_thunderboard/efr32bg22_brd4184.dtsi create mode 100644 boards/arm/efr32_thunderboard/efr32bg22_brd4184b.dts create mode 100644 boards/arm/efr32_thunderboard/efr32bg22_brd4184b.yaml create mode 100644 boards/arm/efr32_thunderboard/efr32bg22_brd4184b_defconfig diff --git a/boards/arm/efr32_thunderboard/Kconfig.board b/boards/arm/efr32_thunderboard/Kconfig.board index e2c318b7627f..de6124d9e49a 100644 --- a/boards/arm/efr32_thunderboard/Kconfig.board +++ b/boards/arm/efr32_thunderboard/Kconfig.board @@ -8,6 +8,11 @@ config BOARD_EFR32BG22_BRD4184A depends on SOC_SERIES_EFR32BG22 select SOC_PART_NUMBER_EFR32BG22C224F512IM40 +config BOARD_EFR32BG22_BRD4184B + bool "SiLabs EFR32BG22-BRD4184B (Thunderboard EFR32BG22)" + depends on SOC_SERIES_EFR32BG22 + select SOC_PART_NUMBER_EFR32BG22C224F512IM40 + config BOARD_EFR32BG27_BRD2602A bool "SiLabs EFR32BG27-BRD2602A (EFR32BG27 +8 dBm Dev Kit Board)" depends on SOC_SERIES_EFR32BG27 diff --git a/boards/arm/efr32_thunderboard/Kconfig.defconfig b/boards/arm/efr32_thunderboard/Kconfig.defconfig index d73779fd61a4..71f5800df5ed 100644 --- a/boards/arm/efr32_thunderboard/Kconfig.defconfig +++ b/boards/arm/efr32_thunderboard/Kconfig.defconfig @@ -10,6 +10,13 @@ config BOARD endif # BOARD_EFR32BG22_BRD4184A +if BOARD_EFR32BG22_BRD4184B + +config BOARD + default "efr32bg22_brd4184b" + +endif # BOARD_EFR32BG22_BRD4184B + if BOARD_EFR32BG27_BRD2602A config BOARD diff --git a/boards/arm/efr32_thunderboard/board.cmake b/boards/arm/efr32_thunderboard/board.cmake index a81d8164a635..cc0f48cee82d 100644 --- a/boards/arm/efr32_thunderboard/board.cmake +++ b/boards/arm/efr32_thunderboard/board.cmake @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -if(CONFIG_BOARD_EFR32BG22_BRD4184A) +if(CONFIG_BOARD_EFR32BG22_BRD4184A OR CONFIG_BOARD_EFR32BG22_BRD4184B) board_runner_args(jlink "--device=EFR32BG22C224F512IM40" "--reset-after-load") include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/efr32_thunderboard/efr32bg22_brd4184.dtsi b/boards/arm/efr32_thunderboard/efr32bg22_brd4184.dtsi new file mode 100644 index 000000000000..7badab451585 --- /dev/null +++ b/boards/arm/efr32_thunderboard/efr32bg22_brd4184.dtsi @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Sateesh Kotapati + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "thunderboard.dtsi" + +/ { + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + sw0 = &button0; + spi-flash0 = &mx25r80; + spi0 = &usart0; + watchdog0 = &wdog0; + /* If enabled, MCUboot uses this for recovery mode entrance */ + mcuboot-led0 = &led0; + mcuboot-button0 = &button0; + }; + + chosen { + zephyr,code-partition = &slot0_partition; + }; +}; + +&flash0 { + partitions { + /* Reserve 48 KiB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000c000>; + read-only; + }; + + /* Reserve 224 KiB for the application in slot 0 */ + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 0x00038000>; + }; + + /* Reserve 224 KiB for the application in slot 1 */ + slot1_partition: partition@44000 { + label = "image-1"; + reg = <0x00044000 0x00038000>; + }; + + /* Set 16 KiB of storage at the end of the 512 KiB of flash */ + storage_partition: partition@7c000 { + label = "storage"; + reg = <0x0007c000 0x00004000>; + }; + }; +}; + +&sw_imu_enable { + enable-gpios = <&gpiob GECKO_PIN(4) GPIO_ACTIVE_HIGH>; +}; diff --git a/boards/arm/efr32_thunderboard/efr32bg22_brd4184a.dts b/boards/arm/efr32_thunderboard/efr32bg22_brd4184a.dts index e12401864eb7..48a599789119 100644 --- a/boards/arm/efr32_thunderboard/efr32bg22_brd4184a.dts +++ b/boards/arm/efr32_thunderboard/efr32bg22_brd4184a.dts @@ -7,69 +7,18 @@ /dts-v1/; #include #include -#include "thunderboard.dtsi" +#include "efr32bg22_brd4184.dtsi" / { model = "Silicon Labs EFR32BG BRD4184A (aka Thunderboard BG22)"; - compatible = "silabs,efr32bg22c224f512im40", "silabs,efr32bg_brd4184", + compatible = "silabs,efr32bg22c224f512im40", "silabs,efr32bg_brd4184a", "silabs,efr32bg22"; - - /* These aliases are provided for compatibility with samples */ - aliases { - led0 = &led0; - sw0 = &button0; - spi-flash0 = &mx25r80; - spi0 = &usart0; - watchdog0 = &wdog0; - /* If enabled, MCUboot uses this for recovery mode entrance */ - mcuboot-led0 = &led0; - mcuboot-button0 = &button0; - }; - - chosen { - zephyr,code-partition = &slot0_partition; - }; -}; - -&flash0 { - partitions { - /* Reserve 48 KiB for the bootloader */ - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000c000>; - read-only; - }; - - /* Reserve 224 KiB for the application in slot 0 */ - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000c000 0x00038000>; - }; - - /* Reserve 224 KiB for the application in slot 1 */ - slot1_partition: partition@44000 { - label = "image-1"; - reg = <0x00044000 0x00038000>; - }; - - /* Set 16 KiB of storage at the end of the 512 KiB of flash */ - storage_partition: partition@7c000 { - label = "storage"; - reg = <0x0007c000 0x00004000>; - }; - }; }; &sw_sensor_enable { enable-gpios = <&gpioa GECKO_PIN(4) GPIO_ACTIVE_HIGH>; }; - &sw_mic_enable { enable-gpios = <&gpioa GECKO_PIN(0) GPIO_ACTIVE_HIGH>; }; - - -&sw_imu_enable { - enable-gpios = <&gpiob GECKO_PIN(4) GPIO_ACTIVE_HIGH>; -}; diff --git a/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.dts b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.dts new file mode 100644 index 000000000000..9dded5746bd6 --- /dev/null +++ b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.dts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Sateesh Kotapati + * Copyright (c) 2023 Piotr Dymacz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "efr32bg22_brd4184.dtsi" + +/ { + model = "Silicon Labs EFR32BG BRD4184B (aka Thunderboard BG22)"; + compatible = "silabs,efr32bg22c224f512im40", "silabs,efr32bg_brd4184b", + "silabs,efr32bg22"; +}; + +&button0 { + gpios = <&gpiob GECKO_PIN(3) GPIO_ACTIVE_LOW>; +}; + +&led0 { + gpios = <&gpioa GECKO_PIN(4) GPIO_ACTIVE_HIGH>; +}; + +&sw_sensor_enable { + enable-gpios = <&gpioc GECKO_PIN(6) GPIO_ACTIVE_HIGH>; +}; + +&sw_mic_enable { + enable-gpios = <&gpioc GECKO_PIN(7) GPIO_ACTIVE_HIGH>; +}; diff --git a/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.yaml b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.yaml new file mode 100644 index 000000000000..86e8e01dae36 --- /dev/null +++ b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b.yaml @@ -0,0 +1,20 @@ +identifier: efr32bg22_brd4184b +name: EFR32BG22-BRD4184B +type: mcu +arch: arm +ram: 32 +flash: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - counter + - gpio + - uart + - i2c + - spi +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/arm/efr32_thunderboard/efr32bg22_brd4184b_defconfig b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b_defconfig new file mode 100644 index 000000000000..2d2e5f1ad7e2 --- /dev/null +++ b/boards/arm/efr32_thunderboard/efr32bg22_brd4184b_defconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM_MPU=y +CONFIG_SOC_SERIES_EFR32BG22=y +CONFIG_BOARD_EFR32BG22_BRD4184B=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_SOC_GECKO_EMU_DCDC=y +CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_PINCTRL=y + +# Used if SysTick is enabled, ignored for BURTC +# (BURTC uses TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=76800000 + +# Use BURTC as system clock source +CONFIG_GECKO_BURTC_TIMER=y +CONFIG_CMU_BURTCCLK_LFXO=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1024 diff --git a/west.yml b/west.yml index 1485e3ade818..fc52919c5357 100644 --- a/west.yml +++ b/west.yml @@ -214,7 +214,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 5fbe78d3676b5500585f8e4534a8e56e7dae74a8 + revision: fbb47a4067c460a2c26917ff34189fb4f32f654f path: modules/hal/silabs groups: - hal From e36b0a415718e3c85aaf22695dfe7d8de1ddcb52 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Mon, 19 Jun 2023 12:44:29 +0200 Subject: [PATCH 2013/2042] boards: arm: doc: update EFR32BG BRD4184 documentation This updates Silicon Labs EFR32BG BRD4184 (Thunderboard BG22) board documentation, adding information about the 'B' revision. Signed-off-by: Piotr Dymacz --- boards/arm/efr32_thunderboard/doc/brd4184.rst | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/boards/arm/efr32_thunderboard/doc/brd4184.rst b/boards/arm/efr32_thunderboard/doc/brd4184.rst index cd8bac2e4404..56685b310799 100644 --- a/boards/arm/efr32_thunderboard/doc/brd4184.rst +++ b/boards/arm/efr32_thunderboard/doc/brd4184.rst @@ -7,9 +7,6 @@ BRD4184 is a board based on EFR32BG22 SoC and is one of :ref:`efr32_thunderboard`. It comes in two revisions, which differ from each other slightly: BRD4184A and BRD4184B. -.. note:: - Currently only the "A" revision is fully supported and tested. - .. image:: ./efr32bg_sltb010a.jpg :align: center :alt: EFR32BG-SLTB010A @@ -22,9 +19,11 @@ Hardware - Macronix ultra low power 8-Mbit SPI flash (MX25R8035F) - 2.4 GHz ceramic antenna for wireless transmission - Silicon Labs Si7021 relative humidity and temperature sensor -- Silicon Labs Si1133 UV index and ambient light sensor +- Silicon Labs Si1133 UV index and ambient light sensor (EFR32BG22-BRD4184A) +- Vishay VEML6035 ambient light sensor (EFR32BG22-BRD4184B) - Silicon Labs Si7210 hall effect sensor - TDK InvenSense ICM-20648 6-axis inertial sensor +- Two Knowles SPK0641HT4H-1 MEMS microphones with PDM output (EFR32BG22-BRD4184B) - One LED and one push button - Power enable signals and isolation switches for ultra low power operation - On-board SEGGER J-Link debugger for easy programming and debugging, which @@ -42,14 +41,15 @@ For more information about the EFR32BG SoC and Thunderboard EFR32BG22 board: - `EFR32BG22 Datasheet`_ - `EFR32xG22 Reference Manual`_ - `Thunderboard EFR32BG22 Website`_ -- `EFR32BG22-BRD4184 User Guide`_ +- `EFR32BG22-BRD4184A User Guide`_ +- `EFR32BG22-BRD4184B User Guide`_ - `EFR32BG22-BRD4184A Schematics`_ - `EFR32BG22-BRD4184B Schematics`_ Supported Features ================== -The efr32bg22_brd4184a board configuration supports the following hardware features: +The efr32bg22_brd4184a/b board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | Interface | Controller | Driver/Component | @@ -79,8 +79,9 @@ The efr32bg22_brd4184a board configuration supports the following hardware featu | RADIO | on-chip | bluetooth | +-----------+------------+-------------------------------------+ -The default configuration can be found in the defconfig file: -``boards/arm/efr32_thunderboard/efr32bg22_brd4184a_defconfig``. +The default configuration can be found in the defconfig files: +- ``boards/arm/efr32_thunderboard/efr32bg22_brd4184a_defconfig`` +- ``boards/arm/efr32_thunderboard/efr32bg22_brd4184b_defconfig`` Connections and IOs =================== @@ -139,11 +140,20 @@ Connect your device to your host computer using the USB port. The sample application :ref:`hello_world` is used for this example. Build the Zephyr kernel and application, then flash it to the device: +BRD4184A: + .. zephyr-app-commands:: :zephyr-app: samples/hello_world :board: efr32bg22_brd4184a :goals: flash +BRD4184B: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: efr32bg22_brd4184b + :goals: flash + .. note:: `west flash` requires `SEGGER J-Link software`_ to be installed on you host computer. @@ -158,10 +168,18 @@ Open a serial terminal (minicom, putty, etc.) with the following settings: Reset the board and you should be able to see on the corresponding Serial Port the following message: +BRD4184A: + .. code-block:: console Hello World! efr32bg22_brd4184a +BRD4184B: + +.. code-block:: console + + Hello World! efr32bg22_brd4184b + Bluetooth ========= @@ -176,18 +194,30 @@ Then build the Zephyr kernel and a Bluetooth sample with the following command. The :ref:`bluetooth-observer-sample` sample application is used in this example. +BRD4184A: + .. zephyr-app-commands:: :zephyr-app: samples/bluetooth/observer :board: efr32bg22_brd4184a :goals: build +BRD4184B: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/observer + :board: efr32bg22_brd4184b + :goals: build + .. _Thunderboard EFR32BG22 Website: https://www.silabs.com/development-tools/thunderboard/thunderboard-bg22-kit -.. _EFR32BG22-BRD4184 User Guide: +.. _EFR32BG22-BRD4184A User Guide: https://www.silabs.com/documents/public/user-guides/ug415-sltb010a-user-guide.pdf +.. _EFR32BG22-BRD4184B User Guide: + https://www.silabs.com/documents/public/user-guides/ug464-brd4184b-user-guide.pdf + .. _EFR32BG22-BRD4184A Schematics: https://www.silabs.com/documents/public/schematic-files/BRD4184A-A01-schematic.pdf From f16f1ae8197e0ac7890277b0b1b1acb38fc3bd33 Mon Sep 17 00:00:00 2001 From: Arkadiusz Balys Date: Mon, 31 Jul 2023 14:36:57 +0200 Subject: [PATCH 2014/2042] net: openthread: Initialize PSA crypto when random is initializing The psa_generate_random function requires the psa_crypto_init call before the usage. This can be ensured by calling the psa_crypto_init in otPlatCryptoRandomInitfunction. Signed-off-by: Arkadiusz Balys --- modules/openthread/platform/crypto_psa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index d9deb114f369..b5a63d60e436 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -415,6 +415,7 @@ otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint void otPlatCryptoRandomInit(void) { + psa_crypto_init(); } void otPlatCryptoRandomDeinit(void) From e4de669bedf3b24fd2790458807df25867e85704 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Thu, 8 Jun 2023 14:05:45 +0200 Subject: [PATCH 2015/2042] Revert "cmake: linker: arm: put RAM sections in RAM region" This reverts commit f5eada5553467c732e7e5bf283e72b66d7be71a9. Fixes #57590. In order to fix incorrect program headers with CMAKE_LINKER_GENERATOR, issue #59064 needs to be addressed first. Until then, revert to the status quo from several versions back. Signed-off-by: Grzegorz Swiderski --- cmake/linker_script/arm/linker.cmake | 14 +++++++------- cmake/modules/extensions.cmake | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 15a2ebd1130e..0c7310ab9052 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -49,7 +49,7 @@ else() set(rom_start ${RAM_ADDR}) endif() -zephyr_linker_group(NAME RAM_REGION VMA RAM LMA RAM) +zephyr_linker_group(NAME RAM_REGION VMA RAM LMA ROM_REGION) zephyr_linker_group(NAME TEXT_REGION GROUP ROM_REGION SYMBOL SECTION) zephyr_linker_group(NAME RODATA_REGION GROUP ROM_REGION) zephyr_linker_group(NAME DATA_REGION GROUP RAM_REGION SYMBOL SECTION) @@ -122,7 +122,7 @@ include(${COMMON_ZEPHYR_LINKER_DIR}/common-ram.cmake) #include(kobject.ld) if(NOT CONFIG_USERSPACE) - zephyr_linker_section(NAME .bss VMA RAM LMA RAM_REGION TYPE BSS) + zephyr_linker_section(NAME .bss VMA RAM LMA FLASH TYPE BSS) zephyr_linker_section_configure(SECTION .bss INPUT COMMON) zephyr_linker_section_configure(SECTION .bss INPUT ".kernel_bss.*") # As memory is cleared in words only, it is simpler to ensure the BSS @@ -137,11 +137,11 @@ endif() include(${COMMON_ZEPHYR_LINKER_DIR}/ram-end.cmake) -zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_start EXPR "(@__bss_start@)") -zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_end EXPR "(${RAM_ADDR} + ${RAM_SIZE})") -zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL __kernel_ram_size EXPR "(@__kernel_ram_end@ - @__bss_start@)") -zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL _image_ram_start EXPR "(${RAM_ADDR})" SUBALIGN 32) # ToDo calculate 32 correctly -zephyr_linker_symbol(OBJECT REGION_RAM SYMBOL ARM_LIB_STACKHEAP EXPR "(${RAM_ADDR} + ${RAM_SIZE})" SIZE -0x1000) +zephyr_linker_symbol(SYMBOL __kernel_ram_start EXPR "(@__bss_start@)") +zephyr_linker_symbol(SYMBOL __kernel_ram_end EXPR "(${RAM_ADDR} + ${RAM_SIZE})") +zephyr_linker_symbol(SYMBOL __kernel_ram_size EXPR "(@__kernel_ram_end@ - @__bss_start@)") +zephyr_linker_symbol(SYMBOL _image_ram_start EXPR "(${RAM_ADDR})" SUBALIGN 32) # ToDo calculate 32 correctly +zephyr_linker_symbol(SYMBOL ARM_LIB_STACKHEAP EXPR "(${RAM_ADDR} + ${RAM_SIZE})" SIZE -0x1000) set(VECTOR_ALIGN 4) if(CONFIG_CPU_CORTEX_M_HAS_VTOR) diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index c5b3c8fd85ad..c892976d1eda 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -4495,7 +4495,7 @@ endfunction() # zephyr_linker_symbol(SYMBOL bar EXPR "(@foo@ + 1024)") # function(zephyr_linker_symbol) - set(single_args "EXPR;SYMBOL;OBJECT") + set(single_args "EXPR;SYMBOL") cmake_parse_arguments(SYMBOL "" "${single_args}" "" ${ARGN}) if(SECTION_UNPARSED_ARGUMENTS) From f132f55e3229bdb70cf55c137fc61e1094458f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 27 Jul 2023 11:07:02 +0200 Subject: [PATCH 2016/2042] drivers: spi_nrfx_spis: Refactor prepare_for_transfer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the function to make the execution flow in transceive() clearer. In particular, return error codes directly, not through spi_context_complete() which is unnecessary in this case. Signed-off-by: Andrzej Głąbek --- drivers/spi/spi_nrfx_spis.c | 45 +++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index 9ea2f9fb7dea..d2448af7a67d 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -106,36 +106,30 @@ static int configure(const struct device *dev, return 0; } -static void prepare_for_transfer(const struct device *dev, - const uint8_t *tx_buf, size_t tx_buf_len, - uint8_t *rx_buf, size_t rx_buf_len) +static int prepare_for_transfer(const struct device *dev, + const uint8_t *tx_buf, size_t tx_buf_len, + uint8_t *rx_buf, size_t rx_buf_len) { - struct spi_nrfx_data *dev_data = dev->data; const struct spi_nrfx_config *dev_config = dev->config; - int status; + nrfx_err_t result; if (tx_buf_len > dev_config->max_buf_len || rx_buf_len > dev_config->max_buf_len) { LOG_ERR("Invalid buffer sizes: Tx %d/Rx %d", tx_buf_len, rx_buf_len); - status = -EINVAL; - } else { - nrfx_err_t result; - - result = nrfx_spis_buffers_set(&dev_config->spis, - tx_buf, tx_buf_len, - rx_buf, rx_buf_len); - if (result == NRFX_SUCCESS) { - return; - } + return -EINVAL; + } - status = -EIO; + result = nrfx_spis_buffers_set(&dev_config->spis, + tx_buf, tx_buf_len, + rx_buf, rx_buf_len); + if (result != NRFX_SUCCESS) { + return -EIO; } - spi_context_complete(&dev_data->ctx, dev, status); + return 0; } - static int transceive(const struct device *dev, const struct spi_config *spi_cfg, const struct spi_buf_set *tx_bufs, @@ -161,13 +155,14 @@ static int transceive(const struct device *dev, LOG_ERR("Only buffers located in RAM are supported"); error = -ENOTSUP; } else { - prepare_for_transfer(dev, - tx_bufs ? tx_bufs->buffers[0].buf : NULL, - tx_bufs ? tx_bufs->buffers[0].len : 0, - rx_bufs ? rx_bufs->buffers[0].buf : NULL, - rx_bufs ? rx_bufs->buffers[0].len : 0); - - error = spi_context_wait_for_completion(&dev_data->ctx); + error = prepare_for_transfer(dev, + tx_bufs ? tx_bufs->buffers[0].buf : NULL, + tx_bufs ? tx_bufs->buffers[0].len : 0, + rx_bufs ? rx_bufs->buffers[0].buf : NULL, + rx_bufs ? rx_bufs->buffers[0].len : 0); + if (error == 0) { + error = spi_context_wait_for_completion(&dev_data->ctx); + } } spi_context_release(&dev_data->ctx, error); From 7974ff2665196c564215587e343dfc224d83ca19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 31 Jul 2023 14:16:17 +0200 Subject: [PATCH 2017/2042] drivers: spi_nrfx_*: Add support for optional WAKE line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add option to use (by defining the `wake-gpios` devicetree properties) an additional signal line between SPI master and SPI slave that allows the latter to stay in low-power state and wake up only when a transfer is to occur. Signed-off-by: Andrzej Głąbek --- drivers/spi/CMakeLists.txt | 6 +- drivers/spi/Kconfig.nrfx | 9 ++ drivers/spi/spi_nrfx_common.c | 75 +++++++++++++++ drivers/spi/spi_nrfx_common.h | 17 ++++ drivers/spi/spi_nrfx_spi.c | 31 ++++++ drivers/spi/spi_nrfx_spim.c | 31 ++++++ drivers/spi/spi_nrfx_spis.c | 100 ++++++++++++++++++++ dts/bindings/spi/nordic,nrf-spi-common.yaml | 24 +++++ 8 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 drivers/spi/spi_nrfx_common.c create mode 100644 drivers/spi/spi_nrfx_common.h diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index a60bce17df79..2eb499366ea8 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -16,8 +16,10 @@ zephyr_library_sources_ifdef(CONFIG_SPI_SAM spi_sam.c) zephyr_library_sources_ifdef(CONFIG_SPI_SAM0 spi_sam0.c) zephyr_library_sources_ifdef(CONFIG_SPI_SIFIVE spi_sifive.c) zephyr_library_sources_ifdef(CONFIG_SPI_RV32M1_LPSPI spi_rv32m1_lpspi.c) -zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPI spi_nrfx_spi.c) -zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPI spi_nrfx_spi.c + spi_nrfx_common.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c + spi_nrfx_common.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIS spi_nrfx_spis.c) zephyr_library_sources_ifdef(CONFIG_SPI_LITESPI spi_litespi.c) zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index bc287e18acaa..d2030a1a2ea7 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -66,4 +66,13 @@ config SPI_NRFX_RAM_BUFFER_SIZE supplying buffers located in flash to the driver, otherwise such transfers will fail. +config SPI_NRFX_WAKE_TIMEOUT_US + int "Maximum time to wait for SPI slave to wake up" + default 200 + help + Maximum amount of time (in microseconds) that SPI master should wait + for SPI slave to wake up after the WAKE line is asserted. Used only + by instances that have the WAKE line configured (see the wake-gpios + devicetree property). + endif # SPI_NRFX diff --git a/drivers/spi/spi_nrfx_common.c b/drivers/spi/spi_nrfx_common.c new file mode 100644 index 000000000000..1ef233cfab38 --- /dev/null +++ b/drivers/spi/spi_nrfx_common.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "spi_nrfx_common.h" +#include +#include + +int spi_nrfx_wake_init(uint32_t wake_pin) +{ + nrfx_gpiote_input_config_t input_config = { + .pull = NRF_GPIO_PIN_PULLDOWN, + }; + uint8_t ch; + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, + .p_in_channel = &ch, + }; + nrfx_err_t res; + + res = nrfx_gpiote_channel_alloc(&ch); + if (res != NRFX_SUCCESS) { + return -ENODEV; + } + + res = nrfx_gpiote_input_configure(wake_pin, + &input_config, + &trigger_config, + NULL); + if (res != NRFX_SUCCESS) { + nrfx_gpiote_channel_free(ch); + return -EIO; + } + + return 0; +} + +int spi_nrfx_wake_request(uint32_t wake_pin) +{ + nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(wake_pin); + uint32_t start_cycles; + uint32_t max_wait_cycles = + DIV_ROUND_UP(CONFIG_SPI_NRFX_WAKE_TIMEOUT_US * + CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, + 1000000); + int err = 0; + + /* Enable the trigger (a high-to-low transition) without its interrupt. + * 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); + /* 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. + */ + 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)) { + uint32_t elapsed_cycles = k_cycle_get_32() - start_cycles; + + if (elapsed_cycles >= max_wait_cycles) { + err = -ETIMEDOUT; + break; + } + } + + nrfx_gpiote_trigger_disable(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 new file mode 100644 index 000000000000..515ed5c6f1f2 --- /dev/null +++ b/drivers/spi/spi_nrfx_common.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ +#define ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ + +#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); + +#endif /* ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ */ diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index df07bf8ef631..fc4b66e176e3 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(spi_nrfx_spi, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" +#include "spi_nrfx_common.h" struct spi_nrfx_data { struct spi_context ctx; @@ -29,6 +30,7 @@ struct spi_nrfx_config { nrfx_spi_config_t def_config; void (*irq_connect)(void); const struct pinctrl_dev_config *pcfg; + uint32_t wake_pin; }; static void event_handler(const nrfx_spi_evt_t *p_event, void *p_context); @@ -231,6 +233,18 @@ static int transceive(const struct device *dev, if (error == 0) { dev_data->busy = true; + if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { + error = spi_nrfx_wake_request(dev_config->wake_pin); + if (error == -ETIMEDOUT) { + LOG_WRN("Waiting for WAKE acknowledgment timed out"); + /* If timeout occurs, try to perform the transfer + * anyway, just in case the slave device was unable + * to signal that it was already awaken and prepared + * for the transfer. + */ + } + } + spi_context_buffers_setup(&dev_data->ctx, tx_bufs, rx_bufs, 1); spi_context_cs_control(&dev_data->ctx, true); @@ -363,6 +377,18 @@ static int spi_nrfx_init(const struct device *dev) return err; } + if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { + err = spi_nrfx_wake_init(dev_config->wake_pin); + if (err == -ENODEV) { + LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); + return err; + } + if (err == -EIO) { + LOG_ERR("Failed to configure WAKE pin"); + return err; + } + } + dev_config->irq_connect(); err = spi_context_cs_configure_all(&dev_data->ctx); @@ -413,7 +439,12 @@ static int spi_nrfx_init(const struct device *dev) }, \ .irq_connect = irq_connect##idx, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(SPI(idx)), \ + .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPI(idx), wake_gpios, \ + WAKE_PIN_NOT_USED), \ }; \ + BUILD_ASSERT(!DT_NODE_HAS_PROP(SPI(idx), wake_gpios) || \ + !(DT_GPIO_FLAGS(SPI(idx), wake_gpios) & GPIO_ACTIVE_LOW), \ + "WAKE line must be configured as active high"); \ PM_DEVICE_DT_DEFINE(SPI(idx), spi_nrfx_pm_action); \ DEVICE_DT_DEFINE(SPI(idx), \ spi_nrfx_init, \ diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index d160a15e28bf..55ff51cc7b32 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -22,6 +22,7 @@ LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL); #include "spi_context.h" +#include "spi_nrfx_common.h" #if defined(CONFIG_SOC_NRF52832) && !defined(CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58) #error This driver is not available by default for nRF52832 because of Product Anomaly 58 \ @@ -59,6 +60,7 @@ struct spi_nrfx_config { #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 bool anomaly_58_workaround; #endif + uint32_t wake_pin; }; static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context); @@ -393,6 +395,18 @@ static int transceive(const struct device *dev, if (error == 0) { dev_data->busy = true; + if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { + error = spi_nrfx_wake_request(dev_config->wake_pin); + if (error == -ETIMEDOUT) { + LOG_WRN("Waiting for WAKE acknowledgment timed out"); + /* If timeout occurs, try to perform the transfer + * anyway, just in case the slave device was unable + * to signal that it was already awaken and prepared + * for the transfer. + */ + } + } + spi_context_buffers_setup(&dev_data->ctx, tx_bufs, rx_bufs, 1); spi_context_cs_control(&dev_data->ctx, true); @@ -529,6 +543,18 @@ static int spi_nrfx_init(const struct device *dev) return err; } + if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { + err = spi_nrfx_wake_init(dev_config->wake_pin); + if (err == -ENODEV) { + LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); + return err; + } + if (err == -EIO) { + LOG_ERR("Failed to configure WAKE pin"); + return err; + } + } + dev_config->irq_connect(); err = spi_context_cs_configure_all(&dev_data->ctx); @@ -603,7 +629,12 @@ static int spi_nrfx_init(const struct device *dev) (.anomaly_58_workaround = \ SPIM_PROP(idx, anomaly_58_workaround),), \ ()) \ + .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) || \ + !(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); \ DEVICE_DT_DEFINE(SPIM(idx), \ spi_nrfx_init, \ diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index d2448af7a67d..d6c3eb9ce0e5 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -18,6 +19,8 @@ LOG_MODULE_REGISTER(spi_nrfx_spis, CONFIG_SPI_LOG_LEVEL); struct spi_nrfx_data { struct spi_context ctx; const struct device *dev; + struct k_sem wake_sem; + struct gpio_callback wake_cb_data; }; struct spi_nrfx_config { @@ -26,6 +29,7 @@ struct spi_nrfx_config { void (*irq_connect)(void); uint16_t max_buf_len; const struct pinctrl_dev_config *pcfg; + struct gpio_dt_spec wake_gpio; }; static inline nrf_spis_mode_t get_nrf_spis_mode(uint16_t operation) @@ -130,6 +134,32 @@ static int prepare_for_transfer(const struct device *dev, return 0; } +static void wake_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct spi_nrfx_data *dev_data = + CONTAINER_OF(cb, struct spi_nrfx_data, wake_cb_data); + const struct spi_nrfx_config *dev_config = dev_data->dev->config; + + (void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio, + GPIO_INT_DISABLE); + k_sem_give(&dev_data->wake_sem); +} + +static void wait_for_wake(struct spi_nrfx_data *dev_data, + const struct spi_nrfx_config *dev_config) +{ + /* If the WAKE line is low, wait until it goes high - this is a signal + * from the master that it wants to perform a transfer. + */ + if (gpio_pin_get_raw(dev_config->wake_gpio.port, + dev_config->wake_gpio.pin) == 0) { + (void)gpio_pin_interrupt_configure_dt(&dev_config->wake_gpio, + GPIO_INT_LEVEL_HIGH); + (void)k_sem_take(&dev_data->wake_sem, K_FOREVER); + } +} + static int transceive(const struct device *dev, const struct spi_config *spi_cfg, const struct spi_buf_set *tx_bufs, @@ -139,6 +169,7 @@ static int transceive(const struct device *dev, void *userdata) { struct spi_nrfx_data *dev_data = dev->data; + const struct spi_nrfx_config *dev_config = dev->config; int error; spi_context_lock(&dev_data->ctx, asynchronous, cb, userdata, spi_cfg); @@ -155,14 +186,41 @@ static int transceive(const struct device *dev, LOG_ERR("Only buffers located in RAM are supported"); error = -ENOTSUP; } else { + if (dev_config->wake_gpio.port) { + wait_for_wake(dev_data, dev_config); + + nrf_spis_enable(dev_config->spis.p_reg); + } + error = prepare_for_transfer(dev, tx_bufs ? tx_bufs->buffers[0].buf : NULL, tx_bufs ? tx_bufs->buffers[0].len : 0, rx_bufs ? rx_bufs->buffers[0].buf : NULL, rx_bufs ? rx_bufs->buffers[0].len : 0); if (error == 0) { + if (dev_config->wake_gpio.port) { + /* Set the WAKE line low (tie it to ground) + * to signal readiness to handle the transfer. + */ + gpio_pin_set_raw(dev_config->wake_gpio.port, + dev_config->wake_gpio.pin, + 0); + /* Set the WAKE line back high (i.e. disconnect + * output for its pin since it's configured in + * open drain mode) so that it can be controlled + * by the other side again. + */ + gpio_pin_set_raw(dev_config->wake_gpio.port, + dev_config->wake_gpio.pin, + 1); + } + error = spi_context_wait_for_completion(&dev_data->ctx); } + + if (dev_config->wake_gpio.port) { + nrf_spis_disable(dev_config->spis.p_reg); + } } spi_context_release(&dev_data->ctx, error); @@ -245,6 +303,42 @@ static int spi_nrfx_init(const struct device *dev) return -EBUSY; } + if (dev_config->wake_gpio.port) { + if (!device_is_ready(dev_config->wake_gpio.port)) { + return -ENODEV; + } + + /* In open drain mode, the output is disconnected when set to + * the high state, so the following will effectively configure + * the pin as an input only. + */ + err = gpio_pin_configure_dt(&dev_config->wake_gpio, + GPIO_INPUT | + GPIO_OUTPUT_HIGH | + GPIO_OPEN_DRAIN); + if (err < 0) { + return err; + } + + gpio_init_callback(&dev_data->wake_cb_data, wake_callback, + BIT(dev_config->wake_gpio.pin)); + err = gpio_add_callback(dev_config->wake_gpio.port, + &dev_data->wake_cb_data); + if (err < 0) { + return err; + } + + /* When the WAKE line is used, the SPIS peripheral is enabled + * only after the master signals that it wants to perform a + * transfer and it is disabled right after the transfer is done. + * Waiting for the WAKE line to go high, what can be done using + * the GPIO PORT event, instead of just waiting for the transfer + * with the SPIS peripheral enabled, significantly reduces idle + * power consumption. + */ + nrf_spis_disable(dev_config->spis.p_reg); + } + spi_context_unlock_unconditionally(&dev_data->ctx); return 0; @@ -270,6 +364,8 @@ static int spi_nrfx_init(const struct device *dev) SPI_CONTEXT_INIT_LOCK(spi_##idx##_data, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \ .dev = DEVICE_DT_GET(SPIS(idx)), \ + .wake_sem = Z_SEM_INITIALIZER( \ + spi_##idx##_data.wake_sem, 0, 1), \ }; \ PINCTRL_DT_DEFINE(SPIS(idx)); \ static const struct spi_nrfx_config spi_##idx##z_config = { \ @@ -288,7 +384,11 @@ static int spi_nrfx_init(const struct device *dev) .irq_connect = irq_connect##idx, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(SPIS(idx)), \ .max_buf_len = BIT_MASK(SPIS_PROP(idx, easydma_maxcnt_bits)), \ + .wake_gpio = GPIO_DT_SPEC_GET_OR(SPIS(idx), wake_gpios, {0}), \ }; \ + BUILD_ASSERT(!DT_NODE_HAS_PROP(SPIS(idx), wake_gpios) || \ + !(DT_GPIO_FLAGS(SPIS(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ + "WAKE line must be configured as active high"); \ DEVICE_DT_DEFINE(SPIS(idx), \ spi_nrfx_init, \ NULL, \ diff --git a/dts/bindings/spi/nordic,nrf-spi-common.yaml b/dts/bindings/spi/nordic,nrf-spi-common.yaml index d9c0d2f9ae3a..ed504a5902b2 100644 --- a/dts/bindings/spi/nordic,nrf-spi-common.yaml +++ b/dts/bindings/spi/nordic,nrf-spi-common.yaml @@ -36,3 +36,27 @@ properties: description: | Maximum number of bits available in the EasyDMA MAXCNT register. This property must be set at SoC level DTS files. + + wake-gpios: + type: phandle-array + description: | + Optional bi-directional line that allows SPI master to indicate to SPI + slave (by setting the line high) that a transfer is to occur, so that + the latter can prepare (and indicate its readiness) for handling that + transfer when it is actually needed, and stay in any desired low-power + state otherwise. + The protocol is as follows: + - initially, SPI slave configures its WAKE line pin as an input and SPI + master keeps the line in the low state + - when a transfer is to be performed, SPI master configures its WAKE + line pin as an input with pull-up; this changes the line state to + high but allows SPI slave to override that state + - when SPI slave detects the high state of the WAKE line, it prepares + for the transfer and when everything is ready, it drives the WAKE + line low by configuring its pin as an output + - the generated high-to-low transition on the WAKE line is a signal + to SPI master that it can proceed with the transfer + - SPI slave releases the line by configuring its pin back to be an input + and SPI master again keeps the line in the low state + Please note that the line must be configured and properly handled on + both sides for the mechanism to work correctly. From 77dde5dc9fc0fdd61da00230d63480011342a858 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Mon, 17 Jul 2023 16:38:45 +0200 Subject: [PATCH 2018/2042] llvm: Add ARMv6-M, ARMv7-M, ARMv8-M Mainline and Baseline targets Introduce more specific ARM targets basing on enabled options in Kconfig. Signed-off-by: Patryk Duda --- cmake/toolchain/llvm/target.cmake | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cmake/toolchain/llvm/target.cmake b/cmake/toolchain/llvm/target.cmake index 0d180304c8ee..cef6c3296e7a 100644 --- a/cmake/toolchain/llvm/target.cmake +++ b/cmake/toolchain/llvm/target.cmake @@ -7,7 +7,25 @@ elseif(CONFIG_LLVM_USE_LLD) endif() if("${ARCH}" STREQUAL "arm") - set(triple arm-none-eabi) + if(DEFINED CONFIG_ARMV8_M_MAINLINE) + # ARMv8-M mainline is ARMv7-M with additional features from ARMv8-M. + set(triple armv8m.main-none-eabi) + elseif(DEFINED CONFIG_ARMV8_M_BASELINE) + # ARMv8-M baseline is ARMv6-M with additional features from ARMv8-M. + set(triple armv8m.base-none-eabi) + elseif(DEFINED CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + # ARMV7_M_ARMV8_M_MAINLINE means that ARMv7-M or backward compatible ARMv8-M + # processor is used. + set(triple armv7m-cros-eabi) + elseif(DEFINED CONFIG_ARMV6_M_ARMV8_M_BASELINE) + # ARMV6_M_ARMV8_M_BASELINE means that ARMv6-M or ARMv8-M supporting the + # Baseline implementation processor is used. + set(triple armv6m-none-eabi) + else() + # Default ARM target supported by all processors. + set(triple arm-none-eabi) + endif() + set(CMAKE_EXE_LINKER_FLAGS_INIT "--specs=nosys.specs") elseif("${ARCH}" STREQUAL "x86") if(CONFIG_64BIT) From cf55f8329ede3fb533d7fac28bf95c3c13f04e2c Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Mon, 17 Jul 2023 16:15:40 +0200 Subject: [PATCH 2019/2042] core: aarch32: Fix standard for _Float16 in CONFIG_FP16 help message Both Clang[1] and GCC[2] says that _Float16 type is defined by ISO/IEC TS 18661-3:2015 not the IEEE 754-2008. Fix help message under FP16 config option. [1] https://clang.llvm.org/docs/LanguageExtensions.html#half-precision-floating-point [2] https://gcc.gnu.org/onlinedocs/gcc/Half-Precision.html Signed-off-by: Patryk Duda --- arch/arm/core/aarch32/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/core/aarch32/Kconfig b/arch/arm/core/aarch32/Kconfig index d9cc9b885b4e..6e26d0bb8ae1 100644 --- a/arch/arm/core/aarch32/Kconfig +++ b/arch/arm/core/aarch32/Kconfig @@ -289,7 +289,7 @@ config FP16 help This option enables the half-precision (16-bit) floating point support via the `__fp16` (both IEEE and ARM alternative formats) and the - `_Float16` (IEEE format only) types. + `_Float16` (defined by ISO/IEC TS 18661-3:2015) types. choice prompt "FP16 format" From f16c4324a7e28c929f7226dd06fef87d951431c9 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Mon, 17 Jul 2023 16:23:55 +0200 Subject: [PATCH 2020/2042] clang: Don't specify FP16 format Support for 16 bit floats is enabled by default in Clang [1]. The ARM alternative format is not supported, so __fp16 always uses IEEE 754-2008 format [2]. [1] https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/ARM/ARMAsmPrinter.cpp#L750-L755 [2] https://clang.llvm.org/docs/LanguageExtensions.html#half-precision-floating-point Fixes: #55562 Signed-off-by: Patryk Duda --- arch/arm/core/aarch32/Kconfig | 2 ++ cmake/compiler/clang/target.cmake | 2 +- cmake/compiler/clang/target_arm.cmake | 38 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 cmake/compiler/clang/target_arm.cmake diff --git a/arch/arm/core/aarch32/Kconfig b/arch/arm/core/aarch32/Kconfig index 6e26d0bb8ae1..a14bcd0cb62c 100644 --- a/arch/arm/core/aarch32/Kconfig +++ b/arch/arm/core/aarch32/Kconfig @@ -312,6 +312,8 @@ config FP16_ALT so that this format can represent normalized values in the range of 2^(-14) to 131008. + Please note that Clang doesn't support the ARM alternative format. + endchoice rsource "cortex_m/Kconfig" diff --git a/cmake/compiler/clang/target.cmake b/cmake/compiler/clang/target.cmake index 536c0209ee18..85bfb807e8f9 100644 --- a/cmake/compiler/clang/target.cmake +++ b/cmake/compiler/clang/target.cmake @@ -29,7 +29,7 @@ if(NOT "${ARCH}" STREQUAL "posix") -fshort-enums ) - include(${ZEPHYR_BASE}/cmake/compiler/gcc/target_arm.cmake) + include(${ZEPHYR_BASE}/cmake/compiler/clang/target_arm.cmake) endif() foreach(file_name include/stddef.h) diff --git a/cmake/compiler/clang/target_arm.cmake b/cmake/compiler/clang/target_arm.cmake new file mode 100644 index 000000000000..53a68cfb1627 --- /dev/null +++ b/cmake/compiler/clang/target_arm.cmake @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(ARM_C_FLAGS) + +list(APPEND ARM_C_FLAGS -mcpu=${GCC_M_CPU}) + +if(CONFIG_COMPILER_ISA_THUMB2) + list(APPEND ARM_C_FLAGS -mthumb) +endif() + +list(APPEND ARM_C_FLAGS -mabi=aapcs) + +if(CONFIG_FPU) + list(APPEND ARM_C_FLAGS -mfpu=${GCC_M_FPU}) + + if(CONFIG_DCLS AND NOT CONFIG_FP_HARDABI) + # If the processor is equipped with VFP and configured in DCLS topology, + # the FP "hard" ABI must be used in order to facilitate the FP register + # initialisation and synchronisation. + set(FORCE_FP_HARDABI TRUE) + endif() + + if (CONFIG_FP_HARDABI OR FORCE_FP_HARDABI) + list(APPEND ARM_C_FLAGS -mfloat-abi=hard) + elseif(CONFIG_FP_SOFTABI) + list(APPEND ARM_C_FLAGS -mfloat-abi=softfp) + endif() +endif() + +if(CONFIG_FP16) + # Clang only supports IEEE 754-2008 format for __fp16. It's enabled by + # default, so no need to do anything when CONFIG_FP16_IEEE is selected. + if(CONFIG_FP16_ALT) + message(FATAL_ERROR "Clang doesn't support ARM alternative format for FP16") + endif() +endif() +list(APPEND TOOLCHAIN_C_FLAGS ${ARM_C_FLAGS}) +list(APPEND TOOLCHAIN_LD_FLAGS NO_SPLIT ${ARM_C_FLAGS}) From 624fcbaa5c4d96aff92341be5db9cb58a82f05e6 Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Thu, 29 Jun 2023 18:37:31 +0200 Subject: [PATCH 2021/2042] clang: Use rtlib provided by compiler instead of hardcoding libgcc Clang provides runtime library `libclang_rt.builtins..a` but `libgcc.a` is also supported. The compiler can provide full path to the selected library using the `--print-libgcc-file-name` option, for example: ``` /usr/lib64/clang/17/lib/baremetal/libclang_rt.builtins-armv7m.a ``` If `--rtlib=libgcc` option is provided, clang will also provide appropriate path. This patch replaces hardcoded `libgcc` with library name extracted from path, so we are compatible with both libraries. Signed-off-by: Patryk Duda --- cmake/compiler/clang/target.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/compiler/clang/target.cmake b/cmake/compiler/clang/target.cmake index 85bfb807e8f9..ada96392f8e3 100644 --- a/cmake/compiler/clang/target.cmake +++ b/cmake/compiler/clang/target.cmake @@ -58,16 +58,16 @@ if(NOT "${ARCH}" STREQUAL "posix") # This libgcc code is partially duplicated in compiler/*/target.cmake execute_process( COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} --print-libgcc-file-name - OUTPUT_VARIABLE LIBGCC_FILE_NAME + OUTPUT_VARIABLE RTLIB_FILE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE ) - get_filename_component(LIBGCC_DIR ${LIBGCC_FILE_NAME} DIRECTORY) + get_filename_component(RTLIB_DIR ${RTLIB_FILE_NAME} DIRECTORY) + get_filename_component(RTLIB_NAME_WITH_PREFIX ${RTLIB_FILE_NAME} NAME_WLE) + string(REPLACE lib "" RTLIB_NAME ${RTLIB_NAME_WITH_PREFIX}) - list(APPEND LIB_INCLUDE_DIR "-L\"${LIBGCC_DIR}\"") - if(LIBGCC_DIR) - list(APPEND TOOLCHAIN_LIBS gcc) - endif() + list(APPEND LIB_INCLUDE_DIR -L${RTLIB_DIR}) + list(APPEND TOOLCHAIN_LIBS ${RTLIB_NAME}) list(APPEND CMAKE_REQUIRED_FLAGS -nostartfiles -nostdlib ${isystem_include_flags}) string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") From 3a97fe256ceb05eb8e9335e5ed6879b74b01f11d Mon Sep 17 00:00:00 2001 From: Patryk Duda Date: Fri, 14 Jul 2023 19:30:05 +0200 Subject: [PATCH 2022/2042] clang: Provide --target option when determining path to runtime library Clang/LLVM is natively a cross-compiler, so one set of applications can compile code to all supported targets. The default target can be changed using '--target' option. CMake supports this type of compilers. To change compiling target, one should set CMAKE_C_COMPILER_TARGET accorgindly. The '--target' option has impact on the path to clang-rt library returned by compiler when run with '--print-libgcc-file-name' option. Without specifying target, Clang will return path to runtime library of the host target (e.g. x86_64-pc-linux-gnu). Signed-off-by: Patryk Duda --- cmake/compiler/clang/target.cmake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/compiler/clang/target.cmake b/cmake/compiler/clang/target.cmake index ada96392f8e3..2289856941fe 100644 --- a/cmake/compiler/clang/target.cmake +++ b/cmake/compiler/clang/target.cmake @@ -32,6 +32,10 @@ if(NOT "${ARCH}" STREQUAL "posix") include(${ZEPHYR_BASE}/cmake/compiler/clang/target_arm.cmake) endif() + if(DEFINED CMAKE_C_COMPILER_TARGET) + set(clang_target_flag "--target=${CMAKE_C_COMPILER_TARGET}") + endif() + foreach(file_name include/stddef.h) execute_process( COMMAND ${CMAKE_C_COMPILER} --print-file-name=${file_name} @@ -57,7 +61,8 @@ if(NOT "${ARCH}" STREQUAL "posix") # This libgcc code is partially duplicated in compiler/*/target.cmake execute_process( - COMMAND ${CMAKE_C_COMPILER} ${TOOLCHAIN_C_FLAGS} --print-libgcc-file-name + COMMAND ${CMAKE_C_COMPILER} ${clang_target_flag} ${TOOLCHAIN_C_FLAGS} + --print-libgcc-file-name OUTPUT_VARIABLE RTLIB_FILE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE ) From 49fefcfddf2b4ba4a56555cea95a0d5744b881be Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Fri, 21 Jul 2023 14:33:24 +0200 Subject: [PATCH 2023/2042] Bluetooth: audio: tbs: Fix List_Item_Length value in CCL This fixes setting invalid List_Item_Length in Current Calls List. The fix complements 9c7ef8e. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index 6956253e04b8..a7b480c61ef2 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -426,9 +426,8 @@ static void net_buf_put_current_calls(const void *inst_p) } uri_length = strlen(call->remote_uri); - item_len = sizeof(call->index != BT_TBS_FREE_CALL_INDEX) + - sizeof(call->state) + - sizeof(call->flags) + uri_length; + 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); From d511ef44edab09c5a38a77bdcc36a14fb8d3a6a7 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 18 Jul 2023 15:10:32 +0200 Subject: [PATCH 2024/2042] Bluetooth: audio: tbs: Refactor service definition macro This removes code duplications by unifying GTBS and TBS service definition macros. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/tbs.c | 60 +++++++++++++----------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/subsys/bluetooth/audio/tbs.c b/subsys/bluetooth/audio/tbs.c index a7b480c61ef2..fe971482da7b 100644 --- a/subsys/bluetooth/audio/tbs.c +++ b/subsys/bluetooth/audio/tbs.c @@ -1685,44 +1685,26 @@ static void in_call_cfg_changed(const struct bt_gatt_attr *attr, read_friendly_name, NULL, inst), \ BT_AUDIO_CCC(friendly_name_cfg_changed) -#define BT_TBS_SERVICE_DEFINITION(inst) {\ - BT_GATT_PRIMARY_SERVICE(BT_UUID_TBS), \ - BT_TBS_CHR_PROVIDER_NAME(&inst), \ - BT_TBS_CHR_UCI(&inst), \ - BT_TBS_CHR_TECHNOLOGY(&inst), \ - BT_TBS_CHR_URI_LIST(&inst), \ - BT_TBS_CHR_SIGNAL_STRENGTH(&inst), \ - BT_TBS_CHR_SIGNAL_INTERVAL(&inst), \ - BT_TBS_CHR_CURRENT_CALLS(&inst), \ - BT_TBS_CHR_CCID(&inst), \ - BT_TBS_CHR_STATUS_FLAGS(&inst), \ - BT_TBS_CHR_INCOMING_URI(&inst), \ - BT_TBS_CHR_CALL_STATE(&inst), \ - BT_TBS_CHR_CONTROL_POINT(&inst), \ - BT_TBS_CHR_OPTIONAL_OPCODES(&inst), \ - BT_TBS_CHR_TERMINATE_REASON(&inst), \ - BT_TBS_CHR_INCOMING_CALL(&inst), \ - BT_TBS_CHR_FRIENDLY_NAME(&inst) \ - } - -#define BT_GTBS_SERVICE_DEFINITION(inst) \ - BT_GATT_PRIMARY_SERVICE(BT_UUID_GTBS), \ - BT_TBS_CHR_PROVIDER_NAME(inst), \ - BT_TBS_CHR_UCI(inst), \ - BT_TBS_CHR_TECHNOLOGY(inst), \ - BT_TBS_CHR_URI_LIST(inst), \ - BT_TBS_CHR_SIGNAL_STRENGTH(inst), \ - BT_TBS_CHR_SIGNAL_INTERVAL(inst), \ - BT_TBS_CHR_CURRENT_CALLS(inst), \ - BT_TBS_CHR_CCID(inst), \ - BT_TBS_CHR_STATUS_FLAGS(inst), \ - BT_TBS_CHR_INCOMING_URI(inst), \ - BT_TBS_CHR_CALL_STATE(inst), \ - BT_TBS_CHR_CONTROL_POINT(inst), \ - BT_TBS_CHR_OPTIONAL_OPCODES(inst), \ - BT_TBS_CHR_TERMINATE_REASON(inst), \ - BT_TBS_CHR_INCOMING_CALL(inst), \ - BT_TBS_CHR_FRIENDLY_NAME(inst) +#define BT_TBS_SERVICE_DEFINE(_uuid, _inst) \ + BT_GATT_PRIMARY_SERVICE(_uuid), \ + BT_TBS_CHR_PROVIDER_NAME(_inst), \ + BT_TBS_CHR_UCI(_inst), \ + BT_TBS_CHR_TECHNOLOGY(_inst), \ + BT_TBS_CHR_URI_LIST(_inst), \ + BT_TBS_CHR_SIGNAL_STRENGTH(_inst), \ + BT_TBS_CHR_SIGNAL_INTERVAL(_inst), \ + BT_TBS_CHR_CURRENT_CALLS(_inst), \ + BT_TBS_CHR_CCID(_inst), \ + BT_TBS_CHR_STATUS_FLAGS(_inst), \ + BT_TBS_CHR_INCOMING_URI(_inst), \ + BT_TBS_CHR_CALL_STATE(_inst), \ + BT_TBS_CHR_CONTROL_POINT(_inst), \ + BT_TBS_CHR_OPTIONAL_OPCODES(_inst), \ + BT_TBS_CHR_TERMINATE_REASON(_inst), \ + 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)) } /* * Defining this as extern make it possible to link code that otherwise would @@ -1732,7 +1714,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_GTBS_SERVICE_DEFINITION(>bs_inst)); +BT_GATT_SERVICE_DEFINE(gtbs_svc, BT_TBS_SERVICE_DEFINE(BT_UUID_GTBS, >bs_inst)); #endif /* CONFIG_BT_GTBS */ BT_GATT_SERVICE_INSTANCE_DEFINE(tbs_service_list, svc_insts, CONFIG_BT_TBS_BEARER_COUNT, From 598fd31d51cc3f98dd00a28982494ca74ee1dd72 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 31 Jul 2023 15:26:51 -0500 Subject: [PATCH 2025/2042] drivers: sensor: Fix return value for unsupported channels Fixes sensor drivers to consistently return -ENOTSUP when an unsupported channel argument is passed to the sensor_channel_get function. Signed-off-by: Maureen Helm --- drivers/sensor/ak8975/ak8975.c | 4 +++- drivers/sensor/akm09918c/akm09918c.c | 2 +- drivers/sensor/bmc150_magn/bmc150_magn.c | 2 +- drivers/sensor/bme680/bme680.c | 2 +- drivers/sensor/bmi323/bmi323.c | 2 +- drivers/sensor/bmm150/bmm150.c | 2 +- drivers/sensor/dps310/dps310.c | 2 +- drivers/sensor/grow_r502a/grow_r502a.c | 2 +- drivers/sensor/hmc5883l/hmc5883l.c | 4 +++- drivers/sensor/max31855/max31855.c | 2 +- drivers/sensor/max31865/max31865.c | 2 +- drivers/sensor/mcp9808/mcp9808.c | 4 ++++ drivers/sensor/mpr/mpr.c | 4 ++++ drivers/sensor/mpu6050/mpu6050.c | 4 +++- drivers/sensor/ms5607/ms5607.c | 2 +- drivers/sensor/ms5837/ms5837.c | 2 +- drivers/sensor/pms7003/pms7003.c | 2 +- drivers/sensor/si7210/si7210.c | 2 +- drivers/sensor/sx9500/sx9500.c | 4 ++++ drivers/sensor/ti_hdc20xx/ti_hdc20xx.c | 2 +- drivers/sensor/vl53l1x/vl53l1.c | 4 ++++ 21 files changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/sensor/ak8975/ak8975.c b/drivers/sensor/ak8975/ak8975.c index 286aa2904a49..d23c107d080f 100644 --- a/drivers/sensor/ak8975/ak8975.c +++ b/drivers/sensor/ak8975/ak8975.c @@ -77,8 +77,10 @@ static int ak8975_channel_get(const struct device *dev, ak8975_convert(val, drv_data->x_sample, drv_data->x_adj); } else if (chan == SENSOR_CHAN_MAGN_Y) { ak8975_convert(val, drv_data->y_sample, drv_data->y_adj); - } else { /* chan == SENSOR_CHAN_MAGN_Z */ + } else if (chan == SENSOR_CHAN_MAGN_Z) { ak8975_convert(val, drv_data->z_sample, drv_data->z_adj); + } else { + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/akm09918c/akm09918c.c b/drivers/sensor/akm09918c/akm09918c.c index 759c00c91f48..f9c72ec21b9f 100644 --- a/drivers/sensor/akm09918c/akm09918c.c +++ b/drivers/sensor/akm09918c/akm09918c.c @@ -86,7 +86,7 @@ static int akm09918c_channel_get(const struct device *dev, enum sensor_channel c akm09918c_convert(val, data->z_sample); } else { LOG_WRN("Invalid channel %d", chan); - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/bmc150_magn/bmc150_magn.c b/drivers/sensor/bmc150_magn/bmc150_magn.c index 40038abeadf0..32b0cf8f25b8 100644 --- a/drivers/sensor/bmc150_magn/bmc150_magn.c +++ b/drivers/sensor/bmc150_magn/bmc150_magn.c @@ -347,7 +347,7 @@ static int bmc150_magn_channel_get(const struct device *dev, bmc150_magn_convert(val + 2, data->sample_z); break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/bme680/bme680.c b/drivers/sensor/bme680/bme680.c index b900c20869e7..2a9a21db889b 100644 --- a/drivers/sensor/bme680/bme680.c +++ b/drivers/sensor/bme680/bme680.c @@ -291,7 +291,7 @@ static int bme680_channel_get(const struct device *dev, val->val2 = 0; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/bmi323/bmi323.c b/drivers/sensor/bmi323/bmi323.c index ddca1d9ed908..a77e42710700 100644 --- a/drivers/sensor/bmi323/bmi323.c +++ b/drivers/sensor/bmi323/bmi323.c @@ -1096,7 +1096,7 @@ static int bosch_bmi323_driver_api_channel_get(const struct device *dev, enum se break; default: - ret = -ENODEV; + ret = -ENOTSUP; break; } diff --git a/drivers/sensor/bmm150/bmm150.c b/drivers/sensor/bmm150/bmm150.c index ae1a09657e08..6c480190a67a 100644 --- a/drivers/sensor/bmm150/bmm150.c +++ b/drivers/sensor/bmm150/bmm150.c @@ -371,7 +371,7 @@ static int bmm150_channel_get(const struct device *dev, bmm150_convert(val + 2, drv_data->sample_z); break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/dps310/dps310.c b/drivers/sensor/dps310/dps310.c index 2e41e8083251..3d91f5a7c48c 100644 --- a/drivers/sensor/dps310/dps310.c +++ b/drivers/sensor/dps310/dps310.c @@ -703,7 +703,7 @@ static int dps310_channel_get(const struct device *dev, val->val2 = data->psr_val2; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/grow_r502a/grow_r502a.c b/drivers/sensor/grow_r502a/grow_r502a.c index f677c324c4f2..1985d4997907 100644 --- a/drivers/sensor/grow_r502a/grow_r502a.c +++ b/drivers/sensor/grow_r502a/grow_r502a.c @@ -634,7 +634,7 @@ static int grow_r502a_channel_get(const struct device *dev, enum sensor_channel val->val1 = drv_data->template_count; } else { LOG_ERR("Invalid channel"); - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/hmc5883l/hmc5883l.c b/drivers/sensor/hmc5883l/hmc5883l.c index c2908ecd2779..053b431ba0e4 100644 --- a/drivers/sensor/hmc5883l/hmc5883l.c +++ b/drivers/sensor/hmc5883l/hmc5883l.c @@ -41,13 +41,15 @@ static int hmc5883l_channel_get(const struct device *dev, } else if (chan == SENSOR_CHAN_MAGN_Z) { hmc5883l_convert(val, drv_data->z_sample, hmc5883l_gain[drv_data->gain_idx]); - } else { /* chan == SENSOR_CHAN_MAGN_XYZ */ + } else if (chan == SENSOR_CHAN_MAGN_XYZ) { hmc5883l_convert(val, drv_data->x_sample, hmc5883l_gain[drv_data->gain_idx]); hmc5883l_convert(val + 1, drv_data->y_sample, hmc5883l_gain[drv_data->gain_idx]); hmc5883l_convert(val + 2, drv_data->z_sample, hmc5883l_gain[drv_data->gain_idx]); + } else { + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/max31855/max31855.c b/drivers/sensor/max31855/max31855.c index bbb34a820d6a..aa71ad7cfbe4 100644 --- a/drivers/sensor/max31855/max31855.c +++ b/drivers/sensor/max31855/max31855.c @@ -97,7 +97,7 @@ static int max31855_channel_get(const struct device *dev, enum sensor_channel ch break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/max31865/max31865.c b/drivers/sensor/max31865/max31865.c index d88bd656b5f1..bced243b1a87 100644 --- a/drivers/sensor/max31865/max31865.c +++ b/drivers/sensor/max31865/max31865.c @@ -270,7 +270,7 @@ static int max31865_channel_get(const struct device *dev, enum sensor_channel ch case SENSOR_CHAN_AMBIENT_TEMP: return sensor_value_from_double(val, data->temperature); default: - return -EINVAL; + return -ENOTSUP; } } diff --git a/drivers/sensor/mcp9808/mcp9808.c b/drivers/sensor/mcp9808/mcp9808.c index 10898d25ba76..0563a558559b 100644 --- a/drivers/sensor/mcp9808/mcp9808.c +++ b/drivers/sensor/mcp9808/mcp9808.c @@ -83,6 +83,10 @@ static int mcp9808_channel_get(const struct device *dev, __ASSERT_NO_MSG(chan == SENSOR_CHAN_AMBIENT_TEMP); + if (chan != SENSOR_CHAN_AMBIENT_TEMP) { + return -ENOTSUP; + } + val->val1 = temp / MCP9808_TEMP_SCALE_CEL; temp -= val->val1 * MCP9808_TEMP_SCALE_CEL; val->val2 = (temp * 1000000) / MCP9808_TEMP_SCALE_CEL; diff --git a/drivers/sensor/mpr/mpr.c b/drivers/sensor/mpr/mpr.c index a6dc6214bd1c..c01a16c84634 100644 --- a/drivers/sensor/mpr/mpr.c +++ b/drivers/sensor/mpr/mpr.c @@ -113,6 +113,10 @@ static int mpr_channel_get(const struct device *dev, __ASSERT_NO_MSG(chan == SENSOR_CHAN_PRESS); + if (chan != SENSOR_CHAN_PRESS) { + return -ENOTSUP; + } + uint64_t value; mpr_convert_reg(&data->reg_val, &value); diff --git a/drivers/sensor/mpu6050/mpu6050.c b/drivers/sensor/mpu6050/mpu6050.c index 99c1159d13bc..9476b420bce9 100644 --- a/drivers/sensor/mpu6050/mpu6050.c +++ b/drivers/sensor/mpu6050/mpu6050.c @@ -102,8 +102,10 @@ static int mpu6050_channel_get(const struct device *dev, mpu6050_convert_gyro(val, drv_data->gyro_z, drv_data->gyro_sensitivity_x10); break; - default: /* chan == SENSOR_CHAN_DIE_TEMP */ + case SENSOR_CHAN_DIE_TEMP: mpu6050_convert_temp(val, drv_data->temp); + default: + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/ms5607/ms5607.c b/drivers/sensor/ms5607/ms5607.c index 15bf80ee3c65..77258e0ba96b 100644 --- a/drivers/sensor/ms5607/ms5607.c +++ b/drivers/sensor/ms5607/ms5607.c @@ -155,7 +155,7 @@ static int ms5607_channel_get(const struct device *dev, val->val2 = data->pressure % 100 * 10000; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/ms5837/ms5837.c b/drivers/sensor/ms5837/ms5837.c index 3dc645be6e96..9e1cdbfd7d07 100644 --- a/drivers/sensor/ms5837/ms5837.c +++ b/drivers/sensor/ms5837/ms5837.c @@ -184,7 +184,7 @@ static int ms5837_channel_get(const struct device *dev, val->val2 = data->pressure % 1000 * 1000; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/pms7003/pms7003.c b/drivers/sensor/pms7003/pms7003.c index 02d92825d0ad..a154baafcfd0 100644 --- a/drivers/sensor/pms7003/pms7003.c +++ b/drivers/sensor/pms7003/pms7003.c @@ -162,7 +162,7 @@ static int pms7003_channel_get(const struct device *dev, val->val1 = drv_data->pm_10; val->val2 = 0; } else { - return -EINVAL; + return -ENOTSUP; } return 0; } diff --git a/drivers/sensor/si7210/si7210.c b/drivers/sensor/si7210/si7210.c index a1e8b235a679..68525ba695a6 100644 --- a/drivers/sensor/si7210/si7210.c +++ b/drivers/sensor/si7210/si7210.c @@ -414,7 +414,7 @@ static int si7210_channel_get(const struct device *dev, val->val2 = tmp % 1000000; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/sx9500/sx9500.c b/drivers/sensor/sx9500/sx9500.c index 77b182efc208..888359a89132 100644 --- a/drivers/sensor/sx9500/sx9500.c +++ b/drivers/sensor/sx9500/sx9500.c @@ -64,6 +64,10 @@ static int sx9500_channel_get(const struct device *dev, __ASSERT_NO_MSG(chan == SENSOR_CHAN_PROX); + if (chan != SENSOR_CHAN_PROX) { + return -ENOTSUP; + } + val->val1 = !!(data->prox_stat & (1 << (4 + CONFIG_SX9500_PROX_CHANNEL))); val->val2 = 0; diff --git a/drivers/sensor/ti_hdc20xx/ti_hdc20xx.c b/drivers/sensor/ti_hdc20xx/ti_hdc20xx.c index 53e86408a131..3d7ce7cc032d 100644 --- a/drivers/sensor/ti_hdc20xx/ti_hdc20xx.c +++ b/drivers/sensor/ti_hdc20xx/ti_hdc20xx.c @@ -128,7 +128,7 @@ static int ti_hdc20xx_channel_get(const struct device *dev, val->val2 = ((tmp & 0xFFFF) * 15625U) >> 10; break; default: - return -EINVAL; + return -ENOTSUP; } return 0; diff --git a/drivers/sensor/vl53l1x/vl53l1.c b/drivers/sensor/vl53l1x/vl53l1.c index 34ae02e6869b..a5bca21a3075 100644 --- a/drivers/sensor/vl53l1x/vl53l1.c +++ b/drivers/sensor/vl53l1x/vl53l1.c @@ -342,6 +342,10 @@ static int vl53l1x_channel_get(const struct device *dev, __ASSERT_NO_MSG(chan == SENSOR_CHAN_DISTANCE); + if (chan != SENSOR_CHAN_DISTANCE) { + return -ENOTSUP; + } + /* Calling VL53L1_WaitMeasurementDataReady regardless of using interrupt or * polling method ensures user does not have to consider the time between * calling fetch and get. From 73944c615775a67a793afd5ded926339e19d22d8 Mon Sep 17 00:00:00 2001 From: Vadim Shakirov Date: Mon, 24 Jul 2023 15:42:52 +0300 Subject: [PATCH 2026/2042] kernel/sched: fix thread selection when ABORTING + PENDING In commit d537267f, the check on thread abortion was moved from next_up to z_get_next_switch_handle. However, next_up is also called from z_swap_next_thread, so the check on thread abortion is now missing there. This sometimes caused the thread to be stuck in ABORTING + PENDING state during the test_smp_switch_torture in test/kernel/smp To avoid such cases in the future, it is worth leaving the check in next_up Signed-off-by: Vadim Shakirov --- kernel/sched.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index fd2f52190ce2..38c6ba037064 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -314,6 +314,12 @@ static inline bool is_aborting(struct k_thread *thread) static ALWAYS_INLINE struct k_thread *next_up(void) { +#ifdef CONFIG_SMP + if (is_aborting(_current)) { + end_thread(_current); + } +#endif + struct k_thread *thread = runq_best(); #if (CONFIG_NUM_METAIRQ_PRIORITIES > 0) && (CONFIG_NUM_COOP_PRIORITIES > 0) @@ -1082,10 +1088,6 @@ void *z_get_next_switch_handle(void *interrupted) K_SPINLOCK(&sched_spinlock) { struct k_thread *old_thread = _current, *new_thread; - if (is_aborting(_current)) { - end_thread(_current); - } - if (IS_ENABLED(CONFIG_SMP)) { old_thread->switch_handle = NULL; } From 1dfa711167bc792867abc9b2504e32df5a330bc3 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 27 Jul 2023 13:13:56 +0300 Subject: [PATCH 2027/2042] net: lwm2m: Create socketpair that can wake up zsock_poll() Allow socket-loop to wake up immediately, if there are changes, instead of waiting for zsock_poll() to timeout. This change makes engine more reactive and removes hard coded timeout from zsock_poll(). Signed-off-by: Seppo Takalo --- samples/net/lwm2m_client/README.rst | 3 + .../net/lwm2m_client/overlay-tickless.conf | 2 + subsys/net/lib/lwm2m/Kconfig | 14 ++ subsys/net/lib/lwm2m/lwm2m_engine.c | 176 ++++++++++++------ subsys/net/lib/lwm2m/lwm2m_engine.h | 9 + subsys/net/lib/lwm2m/lwm2m_message_handling.c | 2 + subsys/net/lib/lwm2m/lwm2m_observation.c | 1 + tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c | 19 +- 8 files changed, 165 insertions(+), 61 deletions(-) create mode 100644 samples/net/lwm2m_client/overlay-tickless.conf diff --git a/samples/net/lwm2m_client/README.rst b/samples/net/lwm2m_client/README.rst index 6299c097cf62..00ad1a679e28 100644 --- a/samples/net/lwm2m_client/README.rst +++ b/samples/net/lwm2m_client/README.rst @@ -52,6 +52,9 @@ samples/net/lwm2m_client directory: - :file:`overlay-queue.conf` This overlay config can be added to enable LWM2M Queue Mode support. +- :file:`overlay-tickless.conf` + This overlay config can be used to stop LwM2M engine for periodically interrupting socket polls. It can have significant effect on power usage on certain devices. + Build the lwm2m-client sample application like this: .. zephyr-app-commands:: diff --git a/samples/net/lwm2m_client/overlay-tickless.conf b/samples/net/lwm2m_client/overlay-tickless.conf new file mode 100644 index 000000000000..132515f6380f --- /dev/null +++ b/samples/net/lwm2m_client/overlay-tickless.conf @@ -0,0 +1,2 @@ +CONFIG_NET_SOCKETPAIR=y +CONFIG_LWM2M_TICKLESS=y diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index be770b798031..b33ce66f0853 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -77,6 +77,20 @@ config LWM2M_DNS_SUPPORT bool "DNS support in the LWM2M client" default y if DNS_RESOLVER +choice + prompt "LwM2M Engine operation mode" + default LWM2M_TICKLESS if NET_SOCKETPAIR + default LWM2M_INTERVAL if !NET_SOCKETPAIR + +config LWM2M_TICKLESS + bool "Tickless operation mode" + depends on NET_SOCKETPAIR + +config LWM2M_INTERVAL + bool "Interval based polling mode" + +endchoice + config LWM2M_ENGINE_STACK_SIZE int "LWM2M engine stack size" default 2560 if NET_LOG diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index fa74666f0925..2aeed5a1359e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -73,7 +73,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1) #endif -#define ENGINE_UPDATE_INTERVAL_MS 500 +#define ENGINE_SLEEP_MS 500 #ifdef CONFIG_LWM2M_VERSION_1_1 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER * 3 @@ -91,7 +91,7 @@ struct service_node { sys_snode_t node; k_work_handler_t service_work; uint32_t min_call_period; /* ms */ - uint64_t last_timestamp; /* ms */ + int64_t last_timestamp; /* ms */ }; static struct service_node service_node_data[MAX_PERIODIC_SERVICE]; @@ -107,6 +107,7 @@ static struct zsock_pollfd sock_fds[MAX_POLL_FD]; static struct lwm2m_ctx *sock_ctx[MAX_POLL_FD]; static int sock_nfds; +static int control_sock; /* Resource wrappers */ #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) @@ -126,6 +127,13 @@ static int lwm2m_socket_update(struct lwm2m_ctx *ctx); /* utility functions */ +void lwm2m_engine_wake_up(void) +{ + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + zsock_send(control_sock, &(char){0}, 1, 0); + } +} + int lwm2m_open_socket(struct lwm2m_ctx *client_ctx) { if (client_ctx->sock_fd < 0) { @@ -344,14 +352,15 @@ int bootstrap_delete(struct lwm2m_message *msg) return ret; } #endif -/* returns ms until the next retransmission is due, or INT32_MAX + +/* returns timestamp when next retransmission is due, or INT64_MAX * if no retransmissions are necessary */ -static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t timestamp) +static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t timestamp) { struct lwm2m_message *msg; struct coap_pending *p; - int32_t remaining, next_retransmission = INT32_MAX; + int64_t remaining, next = INT64_MAX; int i; for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) { @@ -359,8 +368,9 @@ static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t t continue; } - remaining = p->t0 + p->timeout - timestamp; - if (remaining < 0) { + /* TODO: will roll over in 47 days */ + remaining = p->t0 + p->timeout; + if (remaining < timestamp) { msg = find_msg(p, NULL); if (!msg) { LOG_ERR("pending has no valid LwM2M message!"); @@ -386,35 +396,27 @@ static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t t lwm2m_send_message_async(msg); break; } - if (remaining < next_retransmission) { - next_retransmission = remaining; + if (remaining < next) { + next = remaining; } } - return next_retransmission; + return next; } -static int32_t engine_next_service_timeout_ms(uint32_t max_timeout, const int64_t timestamp) +static int64_t engine_next_service_timestamp(void) { struct service_node *srv; - uint64_t time_left_ms; - uint32_t timeout = max_timeout; + int64_t event, next = INT64_MAX; SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - time_left_ms = srv->last_timestamp + srv->min_call_period; - - /* service is due */ - if (time_left_ms < timestamp) { - return 0; - } + event = srv->last_timestamp + srv->min_call_period; - /* service timeout is less than the current timeout */ - time_left_ms -= timestamp; - if (time_left_ms < timeout) { - timeout = time_left_ms; + if (event < next) { + next = event; } } - return timeout; + return next; } int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) @@ -447,6 +449,8 @@ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) sys_slist_append(&engine_service_list, &service_node_data[i].node); + lwm2m_engine_wake_up(); + return 0; } @@ -457,6 +461,7 @@ int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period for (i = 0; i < MAX_PERIODIC_SERVICE; i++) { if (service_node_data[i].service_work == service) { service_node_data[i].min_call_period = period_ms; + lwm2m_engine_wake_up(); return 0; } } @@ -464,7 +469,7 @@ int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period return -ENOENT; } -static int32_t lwm2m_engine_service(const int64_t timestamp) +static int64_t lwm2m_engine_service(const int64_t timestamp) { struct service_node *srv; int64_t service_due_timestamp; @@ -479,15 +484,22 @@ static int32_t lwm2m_engine_service(const int64_t timestamp) } /* calculate how long to sleep till the next service */ - return engine_next_service_timeout_ms(ENGINE_UPDATE_INTERVAL_MS, timestamp); + return engine_next_service_timestamp(); } /* LwM2M Socket Integration */ int lwm2m_socket_add(struct lwm2m_ctx *ctx) { - if (sock_nfds >= MAX_POLL_FD) { - return -ENOMEM; + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* Last poll-handle is reserved for control socket */ + if (sock_nfds >= (MAX_POLL_FD - 1)) { + return -ENOMEM; + } + } else { + if (sock_nfds >= MAX_POLL_FD) { + return -ENOMEM; + } } sock_ctx[sock_nfds] = ctx; @@ -495,6 +507,8 @@ int lwm2m_socket_add(struct lwm2m_ctx *ctx) sock_fds[sock_nfds].events = ZSOCK_POLLIN; sock_nfds++; + lwm2m_engine_wake_up(); + return 0; } @@ -505,6 +519,7 @@ static int lwm2m_socket_update(struct lwm2m_ctx *ctx) continue; } sock_fds[i].fd = ctx->sock_fd; + lwm2m_engine_wake_up(); return 0; } return -1; @@ -531,6 +546,7 @@ void lwm2m_socket_del(struct lwm2m_ctx *ctx) sock_fds[sock_nfds].fd = -1; break; } + lwm2m_engine_wake_up(); } static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp) @@ -635,10 +651,12 @@ static int socket_send_message(struct lwm2m_ctx *client_ctx) static void socket_reset_pollfd_events(void) { - for (int i = 0; i < sock_nfds; ++i) { + for (int i = 0; i < MAX_POLL_FD; ++i) { sock_fds[i].events = ZSOCK_POLLIN | - (sys_slist_is_empty(&sock_ctx[i]->pending_sends) ? 0 : ZSOCK_POLLOUT); + (!sock_ctx[i] || sys_slist_is_empty(&sock_ctx[i]->pending_sends) + ? 0 + : ZSOCK_POLLOUT); sock_fds[i].revents = 0; } } @@ -647,8 +665,8 @@ static void socket_reset_pollfd_events(void) static void socket_loop(void) { int i, rc; - int64_t timestamp; - int32_t timeout, next_retransmit; + int64_t now, next; + int64_t timeout, next_retransmit; bool rd_client_paused; while (1) { @@ -675,46 +693,53 @@ static void socket_loop(void) } } - timestamp = k_uptime_get(); - timeout = lwm2m_engine_service(timestamp); - - /* wait for sockets */ - if (sock_nfds < 1) { - k_msleep(timeout); - continue; - } + now = k_uptime_get(); + next = lwm2m_engine_service(now); for (i = 0; i < sock_nfds; ++i) { - if (sock_ctx[i] != NULL && - sys_slist_is_empty(&sock_ctx[i]->pending_sends)) { - next_retransmit = retransmit_request(sock_ctx[i], timestamp); - if (next_retransmit < timeout) { - timeout = next_retransmit; - } + if (sock_ctx[i] == NULL) { + continue; + } + 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; } - if (sock_ctx[i] != NULL && - sys_slist_is_empty(&sock_ctx[i]->pending_sends) && - lwm2m_rd_client_is_registred(sock_ctx[i])) { - check_notifications(sock_ctx[i], timestamp); + if (lwm2m_rd_client_is_registred(sock_ctx[i])) { + check_notifications(sock_ctx[i], now); } } socket_reset_pollfd_events(); - /* - * FIXME: Currently we timeout and restart poll in case fds - * were modified. - */ - rc = zsock_poll(sock_fds, sock_nfds, timeout); + timeout = next > now ? next - now : 0; + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* prevent roll-over */ + timeout = timeout > INT32_MAX ? INT32_MAX : timeout; + } else { + timeout = timeout > ENGINE_SLEEP_MS ? ENGINE_SLEEP_MS : timeout; + } + + rc = zsock_poll(sock_fds, MAX_POLL_FD, timeout); if (rc < 0) { LOG_ERR("Error in poll:%d", errno); errno = 0; - k_msleep(ENGINE_UPDATE_INTERVAL_MS); + k_msleep(ENGINE_SLEEP_MS); continue; } - for (i = 0; i < sock_nfds; i++) { + for (i = 0; i < MAX_POLL_FD; i++) { + if (sock_fds[i].revents & ZSOCK_POLLIN && sock_fds[i].fd != -1 && + sock_ctx[i] == NULL) { + /* This is the control socket, just read and ignore the data */ + char tmp; + + zsock_recv(sock_fds[i].fd, &tmp, 1, 0); + continue; + } if (sock_ctx[i] != NULL && sock_ctx[i]->sock_fd < 0) { continue; } @@ -1135,12 +1160,43 @@ int lwm2m_engine_resume(void) static int lwm2m_engine_init(void) { - int i; - - for (i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { + for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { sys_slist_append(lwm2m_obs_obj_path_list(), &observe_paths[i].node); } + /* Reset all socket handles to -1 so unused ones are ignored by zsock_poll() */ + for (int i = 0; i < MAX_POLL_FD; ++i) { + sock_fds[i].fd = -1; + } + + if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) { + /* Create socketpair that is used to wake zsock_poll() in the main loop */ + int s[2]; + int ret = zsock_socketpair(AF_UNIX, SOCK_STREAM, 0, s); + + if (ret) { + LOG_ERR("Error; socketpair() returned %d", ret); + return ret; + } + /* Last poll-handle is reserved for control socket */ + sock_fds[MAX_POLL_FD - 1].fd = s[0]; + control_sock = s[1]; + ret = zsock_fcntl(s[0], F_SETFL, O_NONBLOCK); + if (ret) { + LOG_ERR("zsock_fcntl() %d", ret); + zsock_close(s[0]); + zsock_close(s[1]); + return ret; + } + ret = zsock_fcntl(s[1], F_SETFL, O_NONBLOCK); + if (ret) { + LOG_ERR("zsock_fcntl() %d", ret); + zsock_close(s[0]); + zsock_close(s[1]); + return ret; + } + } + lwm2m_clear_block_contexts(); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) (void)memset(output_block_contexts, 0, sizeof(output_block_contexts)); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 2e589ef15a26..da1f9ef3df55 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -306,4 +306,13 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx); /* Resources */ struct lwm2m_ctx **lwm2m_sock_ctx(void); int lwm2m_sock_nfds(void); + +/** + * @brief Trigger the LwM2M engine to run. + * + * This function wakes up ongoing poll() from the socket-loop. + * It should be called when new transmissions are scheduled or service schedules are modified. + */ +void lwm2m_engine_wake_up(void); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 6186f8d50a04..deaf77b92154 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -676,6 +676,7 @@ int lwm2m_send_message_async(struct lwm2m_message *msg) if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { engine_update_tx_time(); } + lwm2m_engine_wake_up(); return ret; } @@ -692,6 +693,7 @@ int lwm2m_information_interface_send(struct lwm2m_message *msg) if (msg->ctx->buffer_client_messages) { sys_slist_append(&msg->ctx->queued_messages, &msg->node); + lwm2m_engine_wake_up(); return 0; } #endif diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 696b5e9210f5..91ab9c1709ae 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -373,6 +373,7 @@ int lwm2m_notify_observer_path(const struct lwm2m_obj_path *path) LOG_DBG("NOTIFY EVENT %u/%u/%u", path->obj_id, path->obj_inst_id, path->res_id); ret++; + lwm2m_engine_wake_up(); } } } diff --git a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c index 95790e39cdb0..5632e8fc6c62 100644 --- a/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c @@ -78,11 +78,24 @@ int z_impl_zsock_close(int sock) return 0; } +#define PAIR_IN 10 +#define PAIR_OUT 11 + +int z_impl_zsock_socketpair(int family, int type, int proto, int *sv) +{ + sv[0] = PAIR_IN; + sv[1] = PAIR_OUT; + return 0; +} + DEFINE_FAKE_VALUE_FUNC(int, z_impl_zsock_connect, int, const struct sockaddr *, socklen_t); ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { + if (sock == PAIR_OUT) { + return 1; + } k_sleep(K_MSEC(1)); if (my_events & ZSOCK_POLLOUT) { my_events = 0; @@ -93,6 +106,10 @@ ssize_t z_impl_zsock_sendto(int sock, const void *buf, size_t len, int flags, ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { + if (sock == PAIR_IN) { + return 1; + } + k_sleep(K_MSEC(1)); if (my_events & ZSOCK_POLLIN) { my_events = 0; @@ -104,7 +121,7 @@ ssize_t z_impl_zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, int z_impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int poll_timeout) { - k_sleep(K_MSEC(poll_timeout)); + k_sleep(K_MSEC(1)); fds->revents = my_events; return 0; } From 2da8844d190e10f4bc4e4c3536b5d405e1651dcb Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 27 Jul 2023 16:18:14 +0300 Subject: [PATCH 2028/2042] net: lwm2m: Add support for non-periodic services Engine now allows registering service callbacks that are called only once on a given timestamp. This allows tickless services to be developed. Signed-off-by: Seppo Takalo --- include/zephyr/net/lwm2m.h | 15 ------ subsys/net/lib/lwm2m/lwm2m_engine.c | 79 ++++++++++++++++++++--------- subsys/net/lib/lwm2m/lwm2m_engine.h | 30 +++++++++++ 3 files changed, 86 insertions(+), 38 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index dea6c1ebb538..6bf0ef0bb371 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -1911,21 +1911,6 @@ int lwm2m_engine_delete_res_inst(const char *pathstr); */ int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path); -/** - * @brief Update the period of a given service. - * - * Allow the period modification on an existing service created with - * lwm2m_engine_add_service(). - * Example to frequency at which a periodic_service changes it's values : - * lwm2m_engine_update_service(device_periodic_service,5*MSEC_PER_SEC); - * - * @param[in] service Handler of the periodic_service - * @param[in] period_ms New period for the periodic_service (in milliseconds) - * - * @return 0 for success or negative in case of error. - */ -int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms); - /** * @brief Update the period of the device service. * diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 2aeed5a1359e..778815b138f5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -90,8 +90,8 @@ static bool active_engine_thread; struct service_node { sys_snode_t node; k_work_handler_t service_work; - uint32_t min_call_period; /* ms */ - int64_t last_timestamp; /* ms */ + uint32_t call_period; /* ms */ + int64_t next_timestamp; /* ms */ }; static struct service_node service_node_data[MAX_PERIODIC_SERVICE]; @@ -406,20 +406,18 @@ static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t ti static int64_t engine_next_service_timestamp(void) { struct service_node *srv; - int64_t event, next = INT64_MAX; + int64_t next = INT64_MAX; SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - event = srv->last_timestamp + srv->min_call_period; - - if (event < next) { - next = event; + if (srv->next_timestamp < next) { + next = srv->next_timestamp; } } return next; } -int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) +static int engine_add_srv(k_work_handler_t service, uint32_t period_ms, int64_t next) { int i; @@ -444,8 +442,8 @@ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) } service_node_data[i].service_work = service; - service_node_data[i].min_call_period = period_ms; - service_node_data[i].last_timestamp = 0U; + service_node_data[i].call_period = period_ms; + service_node_data[i].next_timestamp = next; sys_slist_append(&engine_service_list, &service_node_data[i].node); @@ -454,15 +452,36 @@ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) return 0; } +int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms) +{ + return engine_add_srv(service, period_ms, k_uptime_get() + period_ms); +} + +int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp) +{ + return engine_add_srv(service, 0, timestamp); +} + +int lwm2m_engine_call_now(k_work_handler_t service) +{ + return engine_add_srv(service, 0, k_uptime_get()); +} + int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms) { int i = 0; for (i = 0; i < MAX_PERIODIC_SERVICE; i++) { if (service_node_data[i].service_work == service) { - service_node_data[i].min_call_period = period_ms; - lwm2m_engine_wake_up(); - return 0; + if (period_ms) { + service_node_data[i].call_period = period_ms; + service_node_data[i].next_timestamp = k_uptime_get() + period_ms; + lwm2m_engine_wake_up(); + return 0; + } + sys_slist_find_and_remove(&engine_service_list, &service_node_data[i].node); + service_node_data[i].service_work = NULL; + return 1; } } @@ -471,17 +490,31 @@ int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period static int64_t lwm2m_engine_service(const int64_t timestamp) { - struct service_node *srv; - int64_t service_due_timestamp; - - SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - service_due_timestamp = srv->last_timestamp + srv->min_call_period; - /* service is due */ - if (timestamp >= service_due_timestamp) { - srv->last_timestamp = k_uptime_get(); - srv->service_work(NULL); + struct service_node *srv, *tmp; + bool restart; + + do { + restart = false; + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&engine_service_list, srv, tmp, node) { + /* service is due */ + if (timestamp >= srv->next_timestamp) { + k_work_handler_t work = srv->service_work; + + if (srv->call_period) { + srv->next_timestamp = k_uptime_get() + srv->call_period; + } else { + sys_slist_find_and_remove(&engine_service_list, &srv->node); + srv->service_work = NULL; + } + if (work) { + work(NULL); + } + /* List might have been modified by the callback */ + restart = true; + break; + } } - } + } while (restart); /* calculate how long to sleep till the next service */ return engine_next_service_timestamp(); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index da1f9ef3df55..2306fced197c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -94,6 +94,36 @@ int bootstrap_delete(struct lwm2m_message *msg); */ int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms); +/** + * @brief Update the period of a given service or remove it. + * + * Allow the period modification on an existing service created with + * lwm2m_engine_add_service(). When period is zero, service is removed. + * + * @param[in] service Handler of the periodic_service + * @param[in] period_ms New period for the periodic_service (in milliseconds) or zero. + * + * @return 0 for success, 1 when service was removed or negative in case of error. + */ +int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms); + +/** + * @brief Call specific service handler only once at given timestamp. + * + * @param[in] service service to be called + * @param[in] timestamp Time when to call + * @return 0 for success or negative in case of error + */ +int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp); + +/** + * @brief Call given handler from engine context. + * + * @param[in] service Service callback to be called. + * @return 0 for success or negative in case of error + */ +int lwm2m_engine_call_now(k_work_handler_t service); + /** * @brief Returns the index in the security objects list corresponding to the object instance * id given by @p obj_inst_id From 518bbc130327bfa0463a2b075d7f88b1b233990a Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 27 Jul 2023 16:35:05 +0300 Subject: [PATCH 2029/2042] net: lwm2m: Refactor RD client to be tickless Call RD client service only when there is state transitioning. Remove periodic 500 ms timer. Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 72 ++++++++++++++----- .../net/lib/lwm2m/lwm2m_rd_client/src/main.c | 22 ++---- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.c | 25 ++++--- .../net/lib/lwm2m/lwm2m_rd_client/src/stubs.h | 3 - 4 files changed, 75 insertions(+), 47 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 3686b8855a24..6bdaad2078d3 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -64,18 +64,16 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_util.h" #define LWM2M_RD_CLIENT_URI "rd" - #define SECONDS_TO_UPDATE_EARLY CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY -#define STATE_MACHINE_UPDATE_INTERVAL_MS 500 - #define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH - #define CLIENT_BINDING_LEN sizeof("UQ") #define CLIENT_QUEUE_LEN sizeof("Q") static void sm_handle_registration_update_failure(void); static int sm_send_registration_msg(void); static bool sm_is_suspended(void); +static void lwm2m_rd_client_service(struct k_work *work); +static int64_t calc_next_event(void); /* The states for the RD client state machine */ /* @@ -117,6 +115,7 @@ struct lwm2m_rd_client_info { int64_t last_update; int64_t last_tx; + int64_t next_event; char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; @@ -167,6 +166,11 @@ void engine_update_tx_time(void) client.last_tx = k_uptime_get(); } +static void next_event_at(int64_t timestamp) +{ + (void)lwm2m_engine_call_at(lwm2m_rd_client_service, timestamp); +} + static void set_sm_state(uint8_t sm_state) { k_mutex_lock(&client.mutex, K_FOREVER); @@ -228,6 +232,7 @@ static void set_sm_state(uint8_t sm_state) lwm2m_close_socket(client.ctx); } } + next_event_at(0); k_mutex_unlock(&client.mutex); } @@ -453,6 +458,7 @@ int engine_trigger_bootstrap(void) client.use_bootstrap = true; client.trigger_update = false; client.engine_state = ENGINE_INIT; + next_event_at(0); k_mutex_unlock(&client.mutex); return 0; #else @@ -1000,6 +1006,7 @@ static void sm_handle_registration_update_failure(void) client.engine_state = ENGINE_SEND_REGISTRATION; lwm2m_engine_context_close(client.ctx); k_mutex_unlock(&client.mutex); + next_event_at(0); } static int sm_send_registration_msg(void) @@ -1079,28 +1086,49 @@ static int sm_do_registration(void) return ret; } -static int sm_registration_done(void) +static int64_t next_update(void) { - k_mutex_lock(&client.mutex, K_FOREVER); - int ret = 0; - /* * check for lifetime seconds - SECONDS_TO_UPDATE_EARLY * so that we can update early and avoid lifetime timeout */ + return client.last_update + (client.lifetime - SECONDS_TO_UPDATE_EARLY) * 1000; +} + +static int64_t next_rx_off(void) +{ + if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { + return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * 1000; + } else { + return next_update(); + } +} + +/** Return timestamp to next even whether it is RX_OFF or update event */ +static int64_t calc_next_event(void) +{ + return Z_MIN(next_update(), next_rx_off()); +} + +static void sm_registration_done(void) +{ + k_mutex_lock(&client.mutex, K_FOREVER); + + int64_t now = k_uptime_get(); + if (sm_is_registered() && (client.trigger_update || - ((client.lifetime - SECONDS_TO_UPDATE_EARLY) <= - (k_uptime_get() - client.last_update) / 1000))) { + now >= next_update())) { set_sm_state(ENGINE_UPDATE_REGISTRATION); } else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) && - (((k_uptime_get() - client.last_tx) / 1000) >= - CONFIG_LWM2M_QUEUE_MODE_UPTIME)) { + (now >= next_rx_off())) { set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF); + next_event_at(next_update()); + } else { + next_event_at(calc_next_event()); } k_mutex_unlock(&client.mutex); - return ret; } static int update_registration(void) @@ -1214,7 +1242,9 @@ static void sm_do_network_error(void) { int err; - if (--client.retry_delay > 0) { + if (client.retry_delay) { + client.retry_delay = 0; + next_event_at(k_uptime_get() + client.retry_delay * 1000); return; } @@ -1252,6 +1282,7 @@ static void lwm2m_rd_client_service(struct k_work *work) k_mutex_lock(&client.mutex, K_FOREVER); if (client.ctx) { + LOG_DBG("State: %d", get_sm_state()); switch (get_sm_state()) { case ENGINE_IDLE: if (client.ctx->sock_fd > -1) { @@ -1374,7 +1405,10 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, client.ep_name[CLIENT_EP_LEN - 1] = '\0'; LOG_INF("Start LWM2M Client: %s", client.ep_name); + next_event_at(0); + k_mutex_unlock(&client.mutex); + return 0; } @@ -1402,12 +1436,14 @@ int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx, k_mutex_unlock(&client.mutex); + return 0; } int lwm2m_rd_client_pause(void) { enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED; + LOG_DBG("lwm2m_rd_client_pause()"); k_mutex_lock(&client.mutex, K_FOREVER); @@ -1482,6 +1518,7 @@ int lwm2m_rd_client_resume(void) } } + next_event_at(0); k_mutex_unlock(&client.mutex); return 0; @@ -1490,6 +1527,7 @@ int lwm2m_rd_client_resume(void) void lwm2m_rd_client_update(void) { engine_trigger_update(false); + next_event_at(0); } struct lwm2m_ctx *lwm2m_rd_client_ctx(void) @@ -1520,6 +1558,7 @@ int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx) client.engine_state = ENGINE_DO_REGISTRATION; } } + next_event_at(0); return 0; } @@ -1536,6 +1575,7 @@ int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx) k_mutex_lock(&client.mutex, K_FOREVER); LOG_WRN("Confirmable Timeout -> Re-connect and register"); client.engine_state = ENGINE_DO_REGISTRATION; + next_event_at(0); k_mutex_unlock(&client.mutex); return 0; } @@ -1565,9 +1605,7 @@ int lwm2m_rd_client_init(void) client.engine_state = ENGINE_IDLE; k_mutex_init(&client.mutex); - return lwm2m_engine_add_service(lwm2m_rd_client_service, - STATE_MACHINE_UPDATE_INTERVAL_MS); - + return 0; } static int sys_lwm2m_rd_client_init(void) 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 4d20c3700f27..91f7a18776fa 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c @@ -167,7 +167,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_ok) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -198,10 +197,8 @@ ZTEST(lwm2m_rd_client, test_timeout_resume_registration) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); - wait_for_service(1); lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_fake_default; lwm2m_sprint_ip_addr_fake.custom_fake = lwm2m_sprint_ip_addr_fake_default; @@ -228,7 +225,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_timeout) test_prepare_pending_message_cb(&message_reply_timeout_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -250,7 +246,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_fail) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -272,7 +267,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -300,7 +294,6 @@ ZTEST(lwm2m_rd_client, test_rx_off) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -329,7 +322,6 @@ ZTEST(lwm2m_rd_client, test_start_registration_update_fail) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -359,7 +351,6 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -376,12 +367,12 @@ ZTEST(lwm2m_rd_client, test_registration_update_timeout) test_prepare_pending_message_cb(&message_reply_timeout_cb_default); lwm2m_rd_client_update(); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 2)); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 3), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE, 1)); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT, 2), NULL); test_prepare_pending_message_cb(&message_reply_cb_default); - zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 4), + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, 3), NULL); } @@ -393,7 +384,6 @@ ZTEST(lwm2m_rd_client, test_deregistration_timeout) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -421,7 +411,6 @@ ZTEST(lwm2m_rd_client, test_error_on_registration_update) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -448,7 +437,6 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration) (void)memset(&ctx, 0x0, sizeof(ctx)); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -461,6 +449,8 @@ ZTEST(lwm2m_rd_client, test_network_error_on_registration) coap_packet_append_option_fake.custom_fake = coap_packet_append_option_fake_err; zassert_true(lwm2m_rd_client_start(&ctx, "Test", 0, lwm2m_event_cb, lwm2m_observe_cb) == 0, NULL); + wait_for_service(100); + zassert_true(check_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR, 0), NULL); } @@ -472,7 +462,6 @@ ZTEST(lwm2m_rd_client, test_suspend_resume_registration) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); @@ -506,7 +495,6 @@ ZTEST(lwm2m_rd_client, test_socket_error) test_prepare_pending_message_cb(&message_reply_cb_default); - lwm2m_engine_add_service_fake.custom_fake = lwm2m_engine_add_service_fake_default; lwm2m_rd_client_init(); test_lwm2m_engine_start_service(); wait_for_service(1); 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 c0df43d3b931..72c59de8c6f8 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.c @@ -80,14 +80,14 @@ 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_engine_add_service, k_work_handler_t, uint32_t); -k_work_handler_t lwm2m_engine_add_service_service; -uint32_t lwm2m_engine_add_service_period_ms = 20; -int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms) +k_work_handler_t service; +int64_t next; + +int lwm2m_engine_call_at(k_work_handler_t work, int64_t timestamp) { - lwm2m_engine_add_service_service = service; - lwm2m_engine_add_service_period_ms = period_ms; + service = work; + next = timestamp ? timestamp : 1; return 0; } @@ -97,18 +97,23 @@ void *(*pending_message_cb)(); static void service_work_fn(struct k_work *work) { - while (lwm2m_engine_add_service_service != NULL) { + while (true) { if (pending_message != NULL && pending_message_cb != NULL) { pending_message_cb(pending_message); pending_message = NULL; } - lwm2m_engine_add_service_service(work); - k_sleep(K_MSEC(lwm2m_engine_add_service_period_ms)); + if (next && next < k_uptime_get()) { + printk("Event!\n"); + next = 0; + service(NULL); + } + k_sleep(K_MSEC(10)); counter--; /* avoid endless loop if rd client is stuck somewhere */ if (counter == 0) { + printk("Counter!\n"); break; } } @@ -119,7 +124,7 @@ void wait_for_service(uint16_t cycles) uint16_t end = counter - cycles; while (counter > end) { - k_sleep(K_MSEC(1)); + k_sleep(K_MSEC(10)); } } 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 70c073afbdbc..d15b40f3e444 100644 --- a/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h +++ b/tests/net/lib/lwm2m/lwm2m_rd_client/src/stubs.h @@ -61,8 +61,6 @@ 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_engine_add_service, k_work_handler_t, uint32_t); -int lwm2m_engine_add_service_fake_default(k_work_handler_t service, uint32_t period_ms); void wait_for_service(uint16_t cycles); void test_lwm2m_engine_start_service(void); void test_lwm2m_engine_stop_service(void); @@ -107,7 +105,6 @@ DECLARE_FAKE_VALUE_FUNC(int, do_register_op_link_format, struct lwm2m_message *) FUNC(lwm2m_sprint_ip_addr) \ FUNC(lwm2m_server_short_id_to_inst) \ FUNC(lwm2m_security_index_to_inst_id) \ - FUNC(lwm2m_engine_add_service) \ FUNC(lwm2m_init_message) \ FUNC(lwm2m_reset_message) \ FUNC(lwm2m_send_message_async) \ From 4f613031729b1a0669706d059d7e31c3c9a5f113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Mon, 31 Jul 2023 12:15:15 +0700 Subject: [PATCH 2030/2042] maintainers: add NXP orphaned files to its area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assign orphaned files related to NXP area. Signed-off-by: Manuel Argüelles --- MAINTAINERS.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index 20b57422135e..56747c09d9e3 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -2326,13 +2326,19 @@ NXP Platforms: - boards/arm/frdm_k*/ - boards/arm/lpcxpress*/ - boards/arm/twr_*/ + - boards/arm/s32*/ + - boards/arm/mr_canhubk3/ - soc/arm/nxp_*/ - drivers/*/*imx* - drivers/*/*lpc*.c - drivers/*/*mcux*.c + - drivers/*/*nxp* - dts/arm/nxp/ - dts/bindings/*/nxp* - soc/xtensa/nxp_adsp/ + - samples/boards/nxp*/ + - include/zephyr/dt-bindings/*/nxp* + - include/zephyr/drivers/*/*nxp* labels: - "platform: NXP" From 5037e3a902caff636e1581b64ef5e134c35c2dcb Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 25 Jul 2023 20:44:50 +0000 Subject: [PATCH 2031/2042] ethernet: sam-gmac: make phy a phandle of the ethernet device Make ethernet phys childs of the mdio device and move the mdio device up a level on the tree. That makes the device hierarchy coherent with the required initialization priority and allows keeping the sequence in check with CHECK_INIT_PRIORITIES. Signed-off-by: Fabio Baltieri --- boards/arm/atsame54_xpro/atsame54_xpro.dts | 15 ++++++++------- boards/arm/sam4e_xpro/sam4e_xpro.dts | 14 ++++++++------ .../sam_e70_xplained/sam_e70_xplained-common.dtsi | 15 ++++++++------- boards/arm/sam_v71_xult/sam_v71_xult-common.dtsi | 15 ++++++++------- drivers/ethernet/eth_sam_gmac.c | 6 +----- drivers/mdio/mdio_sam.c | 2 +- dts/arm/atmel/sam4e.dtsi | 9 +++++---- dts/arm/atmel/same5x.dtsi | 9 +++++---- dts/arm/atmel/same70.dtsi | 9 +++++---- dts/bindings/ethernet/atmel,gmac-common.yaml | 3 +++ 10 files changed, 52 insertions(+), 45 deletions(-) diff --git a/boards/arm/atsame54_xpro/atsame54_xpro.dts b/boards/arm/atsame54_xpro/atsame54_xpro.dts index 370a5c612683..83f735234b2f 100644 --- a/boards/arm/atsame54_xpro/atsame54_xpro.dts +++ b/boards/arm/atsame54_xpro/atsame54_xpro.dts @@ -121,13 +121,7 @@ zephyr_udc0: &usb0 { pinctrl-names = "default"; mac-eeprom = <&eeprom>; - - phy: phy { - compatible = "ethernet-phy"; - status = "okay"; - address = <0>; - mdio = <&mdio>; - }; + phy-handle = <&phy>; }; &mdio { @@ -135,4 +129,11 @@ zephyr_udc0: &usb0 { pinctrl-0 = <&mdio_default>; pinctrl-names = "default"; + + phy: phy { + compatible = "ethernet-phy"; + status = "okay"; + address = <0>; + mdio = <&mdio>; + }; }; diff --git a/boards/arm/sam4e_xpro/sam4e_xpro.dts b/boards/arm/sam4e_xpro/sam4e_xpro.dts index 24bcfc7f4a84..cdfdcc630abb 100644 --- a/boards/arm/sam4e_xpro/sam4e_xpro.dts +++ b/boards/arm/sam4e_xpro/sam4e_xpro.dts @@ -187,12 +187,7 @@ zephyr,random-mac-address; - phy: phy { - compatible = "ethernet-phy"; - status = "okay"; - address = <0>; - mdio = <&mdio>; - }; + phy-handle = <&phy>; }; &mdio { @@ -200,6 +195,13 @@ pinctrl-0 = <&mdio_default>; pinctrl-names = "default"; + + phy: phy { + compatible = "ethernet-phy"; + status = "okay"; + address = <0>; + mdio = <&mdio>; + }; }; &pwm0 { diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained-common.dtsi b/boards/arm/sam_e70_xplained/sam_e70_xplained-common.dtsi index bfa3f0e4bbdb..486b7c02af48 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained-common.dtsi +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained-common.dtsi @@ -125,13 +125,7 @@ zephyr_udc0: &usbhs { pinctrl-names = "default"; mac-eeprom = <&eeprom>; - - phy: phy { - compatible = "ethernet-phy"; - status = "okay"; - address = <0>; - mdio = <&mdio>; - }; + phy-handle = <&phy>; }; &mdio { @@ -139,6 +133,13 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&mdio_default>; pinctrl-names = "default"; + + phy: phy { + compatible = "ethernet-phy"; + status = "okay"; + address = <0>; + mdio = <&mdio>; + }; }; &pwm0 { diff --git a/boards/arm/sam_v71_xult/sam_v71_xult-common.dtsi b/boards/arm/sam_v71_xult/sam_v71_xult-common.dtsi index a6bb26a11938..11fcb87c520b 100644 --- a/boards/arm/sam_v71_xult/sam_v71_xult-common.dtsi +++ b/boards/arm/sam_v71_xult/sam_v71_xult-common.dtsi @@ -233,13 +233,7 @@ zephyr_udc0: &usbhs { pinctrl-names = "default"; mac-eeprom = <&eeprom>; - - phy: phy { - compatible = "ethernet-phy"; - status = "okay"; - address = <0>; - mdio = <&mdio>; - }; + phy-handle = <&phy>; }; &mdio { @@ -247,6 +241,13 @@ zephyr_udc0: &usbhs { pinctrl-0 = <&mdio_default>; pinctrl-names = "default"; + + phy: phy { + compatible = "ethernet-phy"; + status = "okay"; + address = <0>; + mdio = <&mdio>; + }; }; &pwm0 { diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index 05aa7e10d17a..f2fbe8acf53d 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -2222,11 +2222,7 @@ static const struct eth_sam_dev_cfg eth0_config = { .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(0), #endif .config_func = eth0_irq_config, -#if DT_NODE_EXISTS(DT_INST_CHILD(0, phy)) - .phy_dev = DEVICE_DT_GET(DT_INST_CHILD(0, phy)) -#else -#error "No PHY driver specified" -#endif + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, phy_handle)) }; static struct eth_sam_dev_data eth0_data = { diff --git a/drivers/mdio/mdio_sam.c b/drivers/mdio/mdio_sam.c index 3fda9c79ef98..950dfe7f00f1 100644 --- a/drivers/mdio/mdio_sam.c +++ b/drivers/mdio/mdio_sam.c @@ -132,7 +132,7 @@ static const struct mdio_driver_api mdio_sam_driver_api = { #define MDIO_SAM_CONFIG(n) \ static const struct mdio_sam_dev_config mdio_sam_dev_config_##n = { \ - .regs = (Gmac *)DT_REG_ADDR(DT_INST_PARENT(n)), \ + .regs = (Gmac *)DT_INST_REG_ADDR(n), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .protocol = DT_INST_ENUM_IDX(n, protocol), \ }; diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 63a1c6e69995..6aaf079e821e 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -166,11 +166,12 @@ num-queues = <1>; phy-connection-type = "mii"; status = "disabled"; + }; - mdio: mdio { - compatible = "atmel,sam-mdio"; - status = "disabled"; - }; + mdio: mdio@40034000 { + compatible = "atmel,sam-mdio"; + reg = <0x40034000 0x4000>; + status = "disabled"; }; pinctrl: pinctrl@400e0e00 { diff --git a/dts/arm/atmel/same5x.dtsi b/dts/arm/atmel/same5x.dtsi index 2bd27fc5731b..341d6e9d1ade 100644 --- a/dts/arm/atmel/same5x.dtsi +++ b/dts/arm/atmel/same5x.dtsi @@ -16,11 +16,12 @@ num-queues = <1>; local-mac-address = [00 00 00 00 00 00]; status = "disabled"; + }; - mdio: mdio { - compatible = "atmel,sam-mdio"; - status = "disabled"; - }; + mdio: mdio@42000800 { + compatible = "atmel,sam-mdio"; + reg = <0x42000800 0x400>; + status = "disabled"; }; }; }; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index 804202af4796..cd021e8a3bd8 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -328,11 +328,12 @@ num-queues = <3>; local-mac-address = [00 00 00 00 00 00]; status = "disabled"; + }; - mdio: mdio { - compatible = "atmel,sam-mdio"; - status = "disabled"; - }; + mdio: mdio@40050000 { + compatible = "atmel,sam-mdio"; + reg = <0x40050000 0x4000>; + status = "disabled"; }; tc0: tc@4000c000 { diff --git a/dts/bindings/ethernet/atmel,gmac-common.yaml b/dts/bindings/ethernet/atmel,gmac-common.yaml index 93cbb4edc447..f17d78df696f 100644 --- a/dts/bindings/ethernet/atmel,gmac-common.yaml +++ b/dts/bindings/ethernet/atmel,gmac-common.yaml @@ -10,6 +10,9 @@ properties: reg: required: true + phy-handle: + required: true + num-queues: type: int required: true From 838ab80bca0c1460ff27aa78d58dc03ae39fdfd1 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 1 Aug 2023 12:31:30 +0300 Subject: [PATCH 2032/2042] net: coap: Use 64bit timestamps Use 64bit timestamps from k_uptime_get() so they don't roll over during the expected device lifetime. Fixes #60826 Signed-off-by: Seppo Takalo --- include/zephyr/net/coap.h | 2 +- samples/net/sockets/coap_server/src/coap-server.c | 4 ++-- subsys/net/lib/coap/coap.c | 6 +++--- subsys/net/lib/lwm2m/lwm2m_engine.c | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/zephyr/net/coap.h b/include/zephyr/net/coap.h index 216278fd3447..d06a7b23dcd1 100644 --- a/include/zephyr/net/coap.h +++ b/include/zephyr/net/coap.h @@ -269,7 +269,7 @@ typedef int (*coap_reply_t)(const struct coap_packet *response, */ struct coap_pending { struct sockaddr addr; - uint32_t t0; + int64_t t0; uint32_t timeout; uint16_t id; uint8_t *data; diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c index 0d126bf28d98..fbd112da5eac 100644 --- a/samples/net/sockets/coap_server/src/coap-server.c +++ b/samples/net/sockets/coap_server/src/coap-server.c @@ -954,8 +954,8 @@ static int large_create_post(struct coap_resource *resource, static void schedule_next_retransmission(void) { struct coap_pending *pending; - int32_t remaining; - uint32_t now = k_uptime_get_32(); + int64_t remaining; + int64_t now = k_uptime_get(); /* Get the first pending retransmission to expire after cycling. */ pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS); diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c index b0a30510fba7..a4dab38eee80 100644 --- a/subsys/net/lib/coap/coap.c +++ b/subsys/net/lib/coap/coap.c @@ -1287,7 +1287,7 @@ int coap_pending_init(struct coap_pending *pending, pending->data = request->data; pending->len = request->offset; - pending->t0 = k_uptime_get_32(); + pending->t0 = k_uptime_get(); pending->retries = retries; return 0; @@ -1382,7 +1382,7 @@ struct coap_pending *coap_pending_next_to_expire( { struct coap_pending *p, *found = NULL; size_t i; - uint32_t expiry, min_expiry; + int64_t expiry, min_expiry = INT64_MAX; for (i = 0, p = pendings; i < len; i++, p++) { if (!p->timeout) { @@ -1391,7 +1391,7 @@ struct coap_pending *coap_pending_next_to_expire( expiry = p->t0 + p->timeout; - if (!found || (int32_t)(expiry - min_expiry) < 0) { + if (expiry < min_expiry) { min_expiry = expiry; found = p; } diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 778815b138f5..27a625105cda 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -368,7 +368,6 @@ static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t ti continue; } - /* TODO: will roll over in 47 days */ remaining = p->t0 + p->timeout; if (remaining < timestamp) { msg = find_msg(p, NULL); From a451a030e478bda77b1c4e197313d7216af255b3 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 1 Aug 2023 13:20:24 +0300 Subject: [PATCH 2033/2042] doc: release-notes: Add release notes about LwM2M and CoAP changes CoAP fixes contain 64bit timer values. LwM2M now supports tickless mode. Signed-off-by: Seppo Takalo --- doc/releases/release-notes-3.5.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index ac174f415e21..93a65f7f34a7 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -260,6 +260,18 @@ Drivers and Sensors Networking ********** +* CoAP: + + * Use 64 bit timer values for calculating transmission timeouts. This fixes potential problems for + devices that stay on for more than 49 days when the 32 bit uptime counter might roll over and + cause CoAP packets to not timeout at all on this event. + +* LwM2M: + + * Added support for tickless mode. This removes the 500 ms timeout from the socket loop + so the engine does not constantly wake up the CPU. This can be enabled by + :kconfig:option:`CONFIG_LWM2M_TICKLESS`. + * Wi-Fi * Added Passive scan support. * The Wi-Fi scan API updated with Wi-Fi scan parameter to allow scan mode selection. From 68ee177a01f362f74718df016f42a5578bc2f633 Mon Sep 17 00:00:00 2001 From: Andriy Gelman Date: Sat, 17 Jun 2023 10:56:41 -0400 Subject: [PATCH 2034/2042] linker: devicetree_regions: Infer VMA when defining section Explicitly setting the start of VMA can intefere if the memory region was used in another section, for example indirectly via zephyr_code_relocate(). Signed-off-by: Andriy Gelman --- include/zephyr/linker/devicetree_regions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/zephyr/linker/devicetree_regions.h b/include/zephyr/linker/devicetree_regions.h index d60d3f9d7b17..e1d91627bb0d 100644 --- a/include/zephyr/linker/devicetree_regions.h +++ b/include/zephyr/linker/devicetree_regions.h @@ -136,7 +136,7 @@ * will result in: * * @code{.unparsed} - * FOOBAR 0x20010000 (NOLOAD) : + * FOOBAR (NOLOAD) : * { * __FOOBAR_start = .; * KEEP(*(FOOBAR)) @@ -150,7 +150,7 @@ * @param node_id devicetree node identifier */ #define _SECTION_DECLARE(node_id) \ - LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) DT_REG_ADDR(node_id) (NOLOAD) : \ + LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) (NOLOAD) : \ { \ _DT_SECTION_START(node_id) = .; \ KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))) \ From 623fb0ee8137e60452d2dcf3fc8826de22c0302c Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 31 Jul 2023 16:30:12 +0200 Subject: [PATCH 2035/2042] build: relocation: Fix long command-line invocations For applications relocating big parts of the code with many sections, builds were failing on Windows due to hitting the max command-line length on that platform. Fix this by using a file to store the dictionary passed to the python script. Fixes https://github.com/zephyrproject-rtos/zephyr/issues/60994. Signed-off-by: Carles Cufi --- cmake/linker/ld/target_relocation.cmake | 10 +++++++++- scripts/build/gen_relocate_app.py | 11 ++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index 2057c7104eb2..c290a330484c 100644 --- a/cmake/linker/ld/target_relocation.cmake +++ b/cmake/linker/ld/target_relocation.cmake @@ -10,6 +10,14 @@ macro(toolchain_ld_relocation) "${PROJECT_BINARY_DIR}/include/generated/linker_sram_bss_relocate.ld") set(MEM_RELOCATION_CODE "${PROJECT_BINARY_DIR}/code_relocation.c") set(MEM_REGION_DEFAULT_RAM RAM) + set(DICT_FILE "${PROJECT_BINARY_DIR}/relocation_dict.txt") + + file(GENERATE + OUTPUT + ${DICT_FILE} + CONTENT + $ + ) add_custom_command( OUTPUT ${MEM_RELOCATION_CODE} ${MEM_RELOCATION_LD} @@ -18,7 +26,7 @@ macro(toolchain_ld_relocation) ${ZEPHYR_BASE}/scripts/build/gen_relocate_app.py $<$:--verbose> -d ${APPLICATION_BINARY_DIR} - -i \"$\" + -i ${DICT_FILE} -o ${MEM_RELOCATION_LD} -s ${MEM_RELOCATION_SRAM_DATA_LD} -b ${MEM_RELOCATION_SRAM_BSS_LD} diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 9082b62f8fd0..1d7783cd38a9 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -456,8 +456,8 @@ def parse_args(): formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) parser.add_argument("-d", "--directory", required=True, help="obj file's directory") - parser.add_argument("-i", "--input_rel_dict", required=True, - help="input src:memory type(sram2 or ccm or aon etc) string") + parser.add_argument("-i", "--input_rel_dict", required=True, type=argparse.FileType('r'), + help="input file with dict src:memory type(sram2 or ccm or aon etc)") parser.add_argument("-o", "--output", required=False, help="Output ld file") parser.add_argument("-s", "--output_sram_data", required=False, help="Output sram data ld file") @@ -490,7 +490,7 @@ def get_obj_filename(searchpath, filename): # Returns a 4-tuple with them: (mem_region, program_header, flag, file_name) # If no `program_header` is defined, returns an empty string def parse_input_string(line): - line = line.replace('\\ :', ':') + line = line.replace(' :', ':') flag_sep = ':NOCOPY:' if ':NOCOPY' in line else ':COPY:' mem_region_phdr, copy_flag, file_name = line.partition(flag_sep) @@ -508,9 +508,10 @@ def create_dict_wrt_mem(): rel_dict = dict() phdrs = dict() - if args.input_rel_dict == '': + input_rel_dict = args.input_rel_dict.read() + if input_rel_dict == '': sys.exit("Disable CONFIG_CODE_DATA_RELOCATION if no file needs relocation") - for line in args.input_rel_dict.split('|'): + for line in input_rel_dict.split('|'): if ':' not in line: continue From ee73cad7a40f83b6938b58126d4b6dcfd99230ce Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:01:34 +0000 Subject: [PATCH 2036/2042] tests: remove tests. prefix from identifier We know this is a test already. Signed-off-by: Anas Nashif --- .../code_relocation/testcase.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/application_development/code_relocation/testcase.yaml b/tests/application_development/code_relocation/testcase.yaml index ab18b1cfefc5..12e7595424d2 100644 --- a/tests/application_development/code_relocation/testcase.yaml +++ b/tests/application_development/code_relocation/testcase.yaml @@ -1,21 +1,21 @@ common: tags: linker tests: - tests.application_development.code_relocation: + application_development.code_relocation: filter: not CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") arch_allow: arm extra_configs: - CONFIG_RELOCATE_TO_ITCM=y platform_allow: - mimxrt1060_evk - tests.application_development.code_relocation_kinetis: + application_development.code_relocation_kinetis: filter: CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC arch_allow: arm extra_configs: - CONFIG_MPU_ALLOW_FLASH_WRITE=y platform_allow: - frdm_k64f - tests.application_development.code_relocation.nxp_s32: + application_development.code_relocation.nxp_s32: filter: not CONFIG_CPU_HAS_NXP_MPU and CONFIG_MINIMAL_LIBC and dt_chosen_enabled("zephyr,itcm") arch_allow: arm extra_configs: @@ -23,7 +23,7 @@ tests: - CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y platform_allow: - mr_canhubk3 - tests.application_development.code_relocation.no_itcm: + application_development.code_relocation.no_itcm: filter: not CONFIG_CPU_HAS_NXP_MPU and not dt_chosen_enabled("zephyr,itcm") arch_allow: arm extra_sections: @@ -38,11 +38,11 @@ tests: - sam_e70_xplained integration_platforms: - qemu_cortex_m3 - tests.application_development.code_relocation.riscv: + application_development.code_relocation.riscv: extra_args: CONF_FILE="prj_riscv.conf" platform_allow: - qemu_riscv32 - qemu_riscv64 - tests.application_development.code_relocation.xtensa: + application_development.code_relocation.xtensa: extra_args: CONF_FILE="prj_xtensa.conf" platform_allow: qemu_xtensa From bc72b13c88c8be13db64440276491da5f10f1d15 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:02:19 +0000 Subject: [PATCH 2037/2042] tests: cmake: fix identifier config_dir is part of cmake testsuite. Signed-off-by: Anas Nashif --- tests/cmake/config_dir/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cmake/config_dir/testcase.yaml b/tests/cmake/config_dir/testcase.yaml index b553882293f1..86bbfd786d82 100644 --- a/tests/cmake/config_dir/testcase.yaml +++ b/tests/cmake/config_dir/testcase.yaml @@ -1,5 +1,5 @@ tests: - config_dir.user_defined: + cmake.config_dir.user_defined: platform_allow: native_posix build_only: true extra_args: APPLICATION_CONFIG_DIR:PATH=foo From 27c67f2982782aee4a22f6c8624cd9aa1d70191c Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:03:14 +0000 Subject: [PATCH 2038/2042] tests: coredump: unify identifiers of tests coredump is part of debug subsystem, unify identifiers to have everything in one bucket. Signed-off-by: Anas Nashif --- tests/drivers/coredump/coredump_api/testcase.yaml | 4 ++-- tests/subsys/debug/coredump/testcase.yaml | 2 +- tests/subsys/debug/coredump_backends/testcase.yaml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/drivers/coredump/coredump_api/testcase.yaml b/tests/drivers/coredump/coredump_api/testcase.yaml index ba52fcfbda5b..3f18bedd22e2 100644 --- a/tests/drivers/coredump/coredump_api/testcase.yaml +++ b/tests/drivers/coredump/coredump_api/testcase.yaml @@ -7,7 +7,7 @@ common: ignore_faults: true ignore_qemu_crash: true tests: - drivers.coredump.api.qemu_riscv32: + debug.coredump.drivers.api.qemu_riscv32: filter: CONFIG_ARCH_SUPPORTS_COREDUMP platform_allow: qemu_riscv32 harness: console @@ -30,7 +30,7 @@ tests: - "E: #CD:4([dD])([0-9a-fA-F]+)" - "E: #CD:babababa" - "E: #CD:END#" - drivers.coredump.api: + debug.coredump.drivers.api: filter: CONFIG_ARCH_SUPPORTS_COREDUMP platform_exclude: qemu_riscv32 harness: console diff --git a/tests/subsys/debug/coredump/testcase.yaml b/tests/subsys/debug/coredump/testcase.yaml index 75f4bcfe67b7..55e181216e03 100644 --- a/tests/subsys/debug/coredump/testcase.yaml +++ b/tests/subsys/debug/coredump/testcase.yaml @@ -1,5 +1,5 @@ tests: - coredump.logging_backend: + debug.coredump.logging_backend: tags: coredump ignore_faults: true ignore_qemu_crash: true diff --git a/tests/subsys/debug/coredump_backends/testcase.yaml b/tests/subsys/debug/coredump_backends/testcase.yaml index c8da7138e7a1..d7c8fccdaa9d 100644 --- a/tests/subsys/debug/coredump_backends/testcase.yaml +++ b/tests/subsys/debug/coredump_backends/testcase.yaml @@ -5,7 +5,7 @@ common: integration_platforms: - qemu_x86 tests: - coredump.backends.logging: + debug.coredump.backends.logging: filter: CONFIG_ARCH_SUPPORTS_COREDUMP platform_exclude: acrn_ehl_crb harness: console @@ -15,7 +15,7 @@ tests: - "E: #CD:BEGIN#" - "E: #CD:5([aA])45([0-9a-fA-F]+)" - "E: #CD:END#" - coredump.backends.flash: + debug.coredump.backends.flash: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_flash_partition.conf platform_allow: @@ -25,7 +25,7 @@ tests: - esp32s2_saola - esp32s3_devkitm - esp32c3_devkitm - coredump.backends.other: + debug.coredump.backends.other: filter: CONFIG_ARCH_SUPPORTS_COREDUMP extra_args: CONF_FILE=prj_backend_other.conf platform_exclude: acrn_ehl_crb From 63adf9e830c53927d8a1009e02a436da4bb7afc4 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:04:41 +0000 Subject: [PATCH 2039/2042] tests: openthread: fix identifiers Remove tests.subsys from identifier, fixed tag. Signed-off-by: Anas Nashif --- tests/subsys/openthread/testcase.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/subsys/openthread/testcase.yaml b/tests/subsys/openthread/testcase.yaml index a442535a2783..dfa48f75aad8 100644 --- a/tests/subsys/openthread/testcase.yaml +++ b/tests/subsys/openthread/testcase.yaml @@ -4,13 +4,14 @@ common: - native_posix_64 integration_platforms: - native_posix - tags: ot_radio + tags: + - openthread tests: - tests.subsys.openthread.radio_test.min: {} - tests.subsys.openthread.radio_test.timed_tx: + openthread.radio_test.min: {} + openthread.radio_test.timed_tx: extra_configs: - CONFIG_NET_PKT_TXTIME=y - tests.subsys.openthread.radio_test.csl: + openthread.radio_test.csl: # Hack to enable CSL w/o having to enable CONFIG_OPENTHREAD extra_args: - EXTRA_CPPFLAGS=-DCONFIG_OPENTHREAD_CSL_RECEIVER From 79e2f22c6e85d4ab97d95d5258065406d50562be Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:05:15 +0000 Subject: [PATCH 2040/2042] tests: misc: fix identifiers Do no use misc as component for test identifier. Signed-off-by: Anas Nashif --- tests/misc/check_init_priorities/testcase.yaml | 2 +- tests/misc/iterable_sections/testcase.yaml | 2 +- tests/misc/kconfigoptions/testcase.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/misc/check_init_priorities/testcase.yaml b/tests/misc/check_init_priorities/testcase.yaml index 98edd4332164..e136e4ae3899 100644 --- a/tests/misc/check_init_priorities/testcase.yaml +++ b/tests/misc/check_init_priorities/testcase.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 tests: - misc.check_init_priorities: + init.check_init_priorities: build_only: true platform_allow: native_posix native_posix_64 integration_platforms: diff --git a/tests/misc/iterable_sections/testcase.yaml b/tests/misc/iterable_sections/testcase.yaml index 7e8581946eba..eeba6274530c 100644 --- a/tests/misc/iterable_sections/testcase.yaml +++ b/tests/misc/iterable_sections/testcase.yaml @@ -1,4 +1,4 @@ tests: - misc.iterable_sections: + linker.iterable_sections: tags: iterable_sections arch_exclude: xtensa diff --git a/tests/misc/kconfigoptions/testcase.yaml b/tests/misc/kconfigoptions/testcase.yaml index fd4925761985..d2ee1c06408f 100644 --- a/tests/misc/kconfigoptions/testcase.yaml +++ b/tests/misc/kconfigoptions/testcase.yaml @@ -1,4 +1,4 @@ tests: - misc.kconfigoptions: + kconfig.kconfigoptions: tags: kconfigoptions platform_allow: native_posix From 66969fc9a702fea376c7bcd3fc9db5ca36a5f3e0 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 1 Aug 2023 12:09:43 +0000 Subject: [PATCH 2041/2042] tests: mgmt: fix test identifiers Use mgmt as the component, the same we use in other related tests. Signed-off-by: Anas Nashif --- tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml index 3ecfc5e10898..930ae58cd3de 100644 --- a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml @@ -17,17 +17,17 @@ common: - mips - posix tests: - os.mgmt.info: {} - os.mgmt.info_no_hooks: + mgmt.mcumgr.os.info: {} + mgmt.mcumgr.os.info.no_hooks: extra_configs: - CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=n - CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=n - os.mgmt.info_bt: + mgmt.mcumgr.os.info.bt: depends_on: ble extra_configs: - CONFIG_BT=y - CONFIG_BT_DEVICE_NAME="a_bt_name" - os.mgmt.info_net: + mgmt.mcumgr.os.info.net: depends_on: netif # FIXME: Exclude systems whereby the processor type is not known and emits a warning platform_exclude: @@ -45,10 +45,10 @@ tests: - CONFIG_NET_HOSTNAME_ENABLE=y - CONFIG_NET_HOSTNAME="test_net_name" - CONFIG_TEST_RANDOM_GENERATOR=y - os.mgmt.info_build_date: + mgmt.mcumgr.os.info.build_date: extra_configs: - CONFIG_BUILD_DATE_TIME_TEST=y - os.mgmt.info_limited_size: + mgmt.mcumgr.os.info.limited_size: extra_configs: - CONFIG_LIMITED_TEST=y - CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=64 From af7b3369452161576e3dbad65124896e44b16b6c Mon Sep 17 00:00:00 2001 From: Tristan Honscheid Date: Tue, 1 Aug 2023 15:56:12 -0600 Subject: [PATCH 2042/2042] emul: icm42688: Implement backend sensor emul API Implement the backend emul API for the ICM42688 motion sensor so it can be automatically tested by the generic sensor test (see #60394). Supports all channels (temp, accel XYZ, and gyro XYZ) at each of the programmable full-scale accel and gyro ranges. Also fixes an arithmetic bug in the driver that was causing a minor error in the returned readings. Signed-off-by: Tristan Honscheid --- drivers/sensor/icm42688/icm42688_decoder.c | 10 +- drivers/sensor/icm42688/icm42688_emul.c | 292 ++++++++++++++++++++- 2 files changed, 297 insertions(+), 5 deletions(-) diff --git a/drivers/sensor/icm42688/icm42688_decoder.c b/drivers/sensor/icm42688/icm42688_decoder.c index 42a44496ef70..781e7567ffd5 100644 --- a/drivers/sensor/icm42688/icm42688_decoder.c +++ b/drivers/sensor/icm42688/icm42688_decoder.c @@ -99,8 +99,8 @@ static enum sensor_channel icm42688_get_channel_from_position(int pos) } } -int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel chan, - int32_t reading, q31_t *out) +int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel chan, int32_t reading, + q31_t *out) { int32_t whole; int32_t fraction; @@ -134,9 +134,11 @@ int icm42688_convert_raw_to_q31(struct icm42688_cfg *cfg, enum sensor_channel ch } intermediate = ((int64_t)whole * INT64_C(1000000) + fraction); if (shift < 0) { - intermediate = intermediate * INT32_MAX * (1 << -shift) / INT64_C(1000000); + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) * (1 << -shift) / INT64_C(1000000); } else if (shift > 0) { - intermediate = intermediate * INT32_MAX / (((1 << shift) - 1) * INT64_C(1000000)); + intermediate = + intermediate * ((int64_t)INT32_MAX + 1) / ((1 << shift) * INT64_C(1000000)); } *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); diff --git a/drivers/sensor/icm42688/icm42688_emul.c b/drivers/sensor/icm42688/icm42688_emul.c index 5ac652c29d71..e01b90742e34 100644 --- a/drivers/sensor/icm42688/icm42688_emul.c +++ b/drivers/sensor/icm42688/icm42688_emul.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -117,9 +118,298 @@ static const struct spi_emul_api icm42688_emul_spi_api = { .io = icm42688_emul_io_spi, }; +#define Q31_SCALE ((int64_t)INT32_MAX + 1) + +/** + * @brief Get current full-scale range in g's based on register config, along with corresponding + * sensitivity and shift. See datasheet section 3.2, table 2. + */ +static void icm42688_emul_get_accel_settings(const struct emul *target, int *fs_g, int *sensitivity, + int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_g_out; + int8_t shift_out; + + icm42688_emul_get_reg(target, REG_ACCEL_CONFIG0, ®, 1); + + switch ((reg & MASK_ACCEL_UI_FS_SEL) >> 5) { + case BIT_ACCEL_UI_FS_16: + fs_g_out = 16; + sensitivity_out = 2048; + /* shift is based on `fs_g * 9.8` since the final numbers will be in SI units of + * m/s^2, not g's + */ + shift_out = 8; + break; + case BIT_ACCEL_UI_FS_8: + fs_g_out = 8; + sensitivity_out = 4096; + shift_out = 7; + break; + case BIT_ACCEL_UI_FS_4: + fs_g_out = 4; + sensitivity_out = 8192; + shift_out = 6; + break; + case BIT_ACCEL_UI_FS_2: + fs_g_out = 2; + sensitivity_out = 16384; + shift_out = 5; + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_g) { + *fs_g = fs_g_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Helper function for calculating accelerometer ranges. Considers the current full-scale + * register config (i.e. +/-2g, +/-4g, etc...) + */ +static void icm42688_emul_get_accel_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + int fs_g; + int sensitivity; + + icm42688_emul_get_accel_settings(target, &fs_g, &sensitivity, shift); + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_G * Q31_SCALE / sensitivity / 1000000LL / 2) >> *shift; + *upper = (fs_g * SENSOR_G * Q31_SCALE / 1000000LL) >> *shift; + *lower = -*upper; +} + +/** + * @brief Get current full-scale gyro range in milli-degrees per second based on register config, + * along with corresponding sensitivity and shift. See datasheet section 3.1, table 1. + */ +static void icm42688_emul_get_gyro_settings(const struct emul *target, int *fs_mdps, + int *sensitivity, int8_t *shift) +{ + uint8_t reg; + + int sensitivity_out, fs_mdps_out; + int8_t shift_out; + + icm42688_emul_get_reg(target, REG_GYRO_CONFIG0, ®, 1); + + switch ((reg & MASK_GYRO_UI_FS_SEL) >> 5) { + case BIT_GYRO_UI_FS_2000: + /* Milli-degrees per second */ + fs_mdps_out = 2000000; + /* 10x LSBs/deg/s */ + sensitivity_out = 164; + /* Shifts are based on rad/s: `(fs_mdps * pi / 180 / 1000)` */ + shift_out = 6; /* +/- 34.90659 */ + break; + case BIT_GYRO_UI_FS_1000: + fs_mdps_out = 1000000; + sensitivity_out = 328; + shift_out = 5; /* +/- 17.44444 */ + break; + case BIT_GYRO_UI_FS_500: + fs_mdps_out = 500000; + sensitivity_out = 655; + shift_out = 4; /* +/- 8.72222 */ + break; + case BIT_GYRO_UI_FS_250: + fs_mdps_out = 250000; + sensitivity_out = 1310; + shift_out = 3; /* +/- 4.36111 */ + break; + case BIT_GYRO_UI_FS_125: + fs_mdps_out = 125000; + sensitivity_out = 2620; + shift_out = 2; /* +/- 2.18055 */ + break; + case BIT_GYRO_UI_FS_62_5: + fs_mdps_out = 62500; + sensitivity_out = 5243; + shift_out = 1; /* +/- 1.09027 */ + break; + case BIT_GYRO_UI_FS_31_25: + fs_mdps_out = 31250; + sensitivity_out = 10486; + shift_out = 0; /* +/- 0.54513 */ + break; + case BIT_GYRO_UI_FS_15_625: + fs_mdps_out = 15625; + sensitivity_out = 20972; + shift_out = -1; /* +/- 0.27256 */ + break; + default: + __ASSERT_UNREACHABLE; + } + + if (fs_mdps) { + *fs_mdps = fs_mdps_out; + } + if (sensitivity) { + *sensitivity = sensitivity_out; + } + if (shift) { + *shift = shift_out; + } +} + +/** + * @brief Helper function for calculating gyroscope ranges. Considers the current full-scale + * register config + */ +static void icm42688_emul_get_gyro_ranges(const struct emul *target, q31_t *lower, q31_t *upper, + q31_t *epsilon, int8_t *shift) +{ + /* millidegrees/second */ + int fs_mdps; + /* 10x LSBs per degrees/second*/ + int sensitivity; + + icm42688_emul_get_gyro_settings(target, &fs_mdps, &sensitivity, shift); + + /* Reduce the actual range of gyroscope values. Some full-scale ranges actually exceed the + * size of an int16 by a small margin. For example, FS_SEL=0 has a +/-2000 deg/s range with + * 16.4 bits/deg/s sensitivity (Section 3.1, Table 1). This works out to register values of + * +/-2000 * 16.4 = +/-32800. This will cause the expected value to get clipped when + * setting the register and throw off the actual reading. Therefore, scale down the range + * to 99% to avoid the top and bottom edges. + */ + + fs_mdps *= 0.99; + + /* Epsilon is equal to 1.5 bit-counts worth of error. */ + *epsilon = (3 * SENSOR_PI * Q31_SCALE * 10LL / 1000000LL / 180LL / sensitivity / 2LL) >> + *shift; + *upper = (((fs_mdps * SENSOR_PI / 1000000LL) * Q31_SCALE) / 1000LL / 180LL) >> *shift; + *lower = -*upper; +} + +static int icm42688_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_DIE_TEMP: + /* degrees C = ([16-bit signed temp_data register] / 132.48) + 25 */ + *shift = 9; + *lower = (int64_t)(-222.342995169 * Q31_SCALE) >> *shift; + *upper = (int64_t)(272.33544686 * Q31_SCALE) >> *shift; + *epsilon = (int64_t)(0.0076 * Q31_SCALE) >> *shift; + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + icm42688_emul_get_accel_ranges(target, lower, upper, epsilon, shift); + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + icm42688_emul_get_gyro_ranges(target, lower, upper, epsilon, shift); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int icm42688_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + q31_t value, int8_t shift) +{ + if (!target || !target->data) { + return -EINVAL; + } + + struct icm42688_emul_data *data = target->data; + + int sensitivity; + uint8_t reg_addr; + int32_t reg_val; + int64_t value_unshifted = + shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift); + + switch (ch) { + case SENSOR_CHAN_DIE_TEMP: + reg_addr = REG_TEMP_DATA1; + reg_val = ((value_unshifted - (25 * Q31_SCALE)) * 13248) / (100 * Q31_SCALE); + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + reg_addr = REG_ACCEL_DATA_X1; + break; + case SENSOR_CHAN_ACCEL_Y: + reg_addr = REG_ACCEL_DATA_Y1; + break; + case SENSOR_CHAN_ACCEL_Z: + reg_addr = REG_ACCEL_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42688_emul_get_accel_settings(target, NULL, &sensitivity, NULL); + reg_val = ((value_unshifted * sensitivity / Q31_SCALE) * 1000000LL) / SENSOR_G; + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + switch (ch) { + case SENSOR_CHAN_GYRO_X: + reg_addr = REG_GYRO_DATA_X1; + break; + case SENSOR_CHAN_GYRO_Y: + reg_addr = REG_GYRO_DATA_Y1; + break; + case SENSOR_CHAN_GYRO_Z: + reg_addr = REG_GYRO_DATA_Z1; + break; + default: + __ASSERT_UNREACHABLE; + } + icm42688_emul_get_gyro_settings(target, NULL, &sensitivity, NULL); + reg_val = + CLAMP((((value_unshifted * sensitivity * 180LL) / Q31_SCALE) * 1000000LL) / + SENSOR_PI / 10LL, + INT16_MIN, INT16_MAX); + break; + default: + return -ENOTSUP; + } + + data->reg[reg_addr] = (reg_val >> 8) & 0xFF; + data->reg[reg_addr + 1] = reg_val & 0xFF; + + /* Set data ready flag */ + data->reg[REG_INT_STATUS] |= BIT_INT_STATUS_DATA_RDY; + + return 0; +} + +static const struct emul_sensor_backend_api icm42688_emul_sensor_backend_api = { + .set_channel = icm42688_emul_backend_set_channel, + .get_sample_range = icm42688_emul_backend_get_sample_range, +}; + #define ICM42688_EMUL_DEFINE(n, api) \ EMUL_DT_INST_DEFINE(n, icm42688_emul_init, &icm42688_emul_data_##n, \ - &icm42688_emul_cfg_##n, &api, NULL) + &icm42688_emul_cfg_##n, &api, &icm42688_emul_sensor_backend_api) #define ICM42688_EMUL_SPI(n) \ static struct icm42688_emul_data icm42688_emul_data_##n; \

1 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 CAp(H_ literal 0 HcmV?d00001 diff --git a/boards/xtensa/xiao_esp32s3/doc/index.rst b/boards/xtensa/xiao_esp32s3/doc/index.rst new file mode 100644 index 000000000000..1f12763646b0 --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/doc/index.rst @@ -0,0 +1,239 @@ +.. _xiao_esp32s3: + +XIAO ESP32S3 +############ + +Overview +******** + +Seeed Studio XIAO ESP32S3 is an IoT mini development board based on the +Espressif ESP32-S3 WiFi/Bluetooth dual-mode chip. + +For more details see the `Seeed Studio XIAO ESP32S3`_ wiki page. + +.. figure:: img/xiao_esp32s3.jpg + :align: center + :alt: XIAO ESP32S3 + + XIAO ESP32S3 + +Hardware +******** + +This board is based on the ESP32-S3 with 8MB of flash, WiFi and BLE support. It +has an USB-C port for programming and debugging, integrated battery charging +and an U.FL external antenna connector. It is based on a standard XIAO 14 pin +pinout. + +ESP32-S3 is a low-power MCU-based system on a chip (SoC) with integrated 2.4 GHz Wi-Fi +and Bluetooth® Low Energy (Bluetooth LE). It consists of high-performance dual-core microprocessor +(Xtensa® 32-bit LX7), a low power coprocessor, a Wi-Fi baseband, a Bluetooth LE baseband, +RF module, and numerous peripherals. + +Supported Features +================== + +Current Zephyr's XIAO ESP32S3 board supports the following features: + ++------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++============+============+=====================================+ ++------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++------------+------------+-------------------------------------+ +| USB-JTAG | on-chip | hardware interface | ++------------+------------+-------------------------------------+ +| SPI Master | on-chip | spi | ++------------+------------+-------------------------------------+ +| Timers | on-chip | counter | ++------------+------------+-------------------------------------+ +| Watchdog | on-chip | watchdog | ++------------+------------+-------------------------------------+ +| TRNG | on-chip | entropy | ++------------+------------+-------------------------------------+ +| LEDC | on-chip | pwm | ++------------+------------+-------------------------------------+ +| MCPWM | on-chip | pwm | ++------------+------------+-------------------------------------+ +| PCNT | on-chip | qdec | ++------------+------------+-------------------------------------+ +| GDMA | on-chip | dma | ++------------+------------+-------------------------------------+ + +Connections and IOs +=================== + +The board uses a standard XIAO pinout, the default pin mapping is the following: + +.. figure:: img/xiao_esp32s3_pinout.jpg + :align: center + :alt: XIAO ESP32S3 Pinout + + XIAO ESP32S3 Pinout + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +******************* + +ESP-IDF bootloader +================== + +The board is using the ESP-IDF bootloader as the default 2nd stage bootloader. +It is build as a subproject at each application build. No further attention +is expected from the user. + +MCUboot bootloader +================== + +User may choose to use MCUboot bootloader instead. In that case the bootloader +must be build (and flash) at least once. + +There are two options to be used when building an application: + +1. Sysbuild +2. Manual build + +.. note:: + + User can select the MCUboot bootloader by adding the following line + to the board default configuration file. + ``` + CONFIG_BOOTLOADER_MCUBOOT=y + ``` + +Sysbuild +======== + +The sysbuild makes possible to build and flash all necessary images needed to +bootstrap the board with the EPS32 SoC. + +To build the sample application using sysbuild use the command: + +.. zephyr-app-commands:: + :tool: west + :app: samples/hello_world + :board: xiao_esp32s3 + :goals: build + :west-args: --sysbuild + :compact: + +By default, the ESP32 sysbuild creates bootloader (MCUboot) and application +images. But it can be configured to create other kind of images. + +Build directory structure created by sysbuild is different from traditional +Zephyr build. Output is structured by the domain subdirectories: + +.. code-block:: + + build/ + ├── hello_world + │   └── zephyr + │   ├── zephyr.elf + │   └── zephyr.bin + ├── mcuboot + │ └── zephyr + │ ├── zephyr.elf + │ └── zephyr.bin + └── domains.yaml + +.. note:: + + With ``--sysbuild`` option the bootloader will be re-build and re-flash + every time the pristine build is used. + +For more information about the system build please read the :ref:`sysbuild` documentation. + +Manual build +============ + +During the development cycle, it is intended to build & flash as quickly possible. +For that reason, images can be build one at a time using traditional build. + +The instructions following are relevant for both manual build and sysbuild. +The only difference is the structure of the build directory. + +.. note:: + + Remember that bootloader (MCUboot) needs to be flash at least once. + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: xiao_esp32s3 + :goals: build + +The usual ``flash`` target will work with the ``xiao_esp32s3`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: xiao_esp32s3 + :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! xiao_esp32s3 + +Debugging +********* + +ESP32-S3 support on OpenOCD is available upstream as of version 0.12.0. +Download and install OpenOCD from `OpenOCD`_. + +ESP32-S3 has a built-in JTAG circuitry and can be debugged without any additional chip. Only an USB cable connected to the D+/D- pins is necessary. + +Further documentation can be obtained from the SoC vendor in `JTAG debugging +for ESP32-S3`_. + +Here is an example for building the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: xiao_esp32s3 + :goals: build flash + +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: xiao_esp32s3 + :goals: debug +.. _`JTAG debugging for ESP32-S3`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/jtag-debugging/ +.. _`OpenOCD`: https://github.com/openocd-org/openocd + +References +********** + +.. target-notes:: + +.. _`Seeed Studio XIAO ESP32S3`: https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/ diff --git a/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi b/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi new file mode 100644 index 000000000000..2251ed92015a --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/seeed_xiao_connector.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Seeed Studio inc. + * + * 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 1 0>, /* D0 */ + <1 0 &gpio0 2 0>, /* D1 */ + <2 0 &gpio0 3 0>, /* D2 */ + <3 0 &gpio0 4 0>, /* D3 */ + <4 0 &gpio0 5 0>, /* D4 */ + <5 0 &gpio0 6 0>, /* D5 */ + <6 0 &gpio0 43 0>, /* D6 */ + <7 0 &gpio0 44 0>, /* D7 */ + <8 0 &gpio0 7 0>, /* D8 */ + <9 0 &gpio0 8 0>, /* D9 */ + <10 0 &gpio0 9 0>; /* D10 */ + }; +}; + +xiao_spi: &spi2 {}; +xiao_i2c: &i2c0 {}; +xiao_serial: &uart0 {}; diff --git a/boards/xtensa/xiao_esp32s3/support/openocd.cfg b/boards/xtensa/xiao_esp32s3/support/openocd.cfg new file mode 100644 index 000000000000..2f740b4a36ab --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/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] diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi b/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi new file mode 100644 index 000000000000..3f9343d846ef --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3-pinctrl.dtsi @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; +}; diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts new file mode 100644 index 000000000000..667cabab6ed9 --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2023 Seeed Studio inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "xiao_esp32s3-pinctrl.dtsi" +#include "seeed_xiao_connector.dtsi" + +/ { + model = "Seeed XIAO ESP32S3"; + compatible = "seeed,xiao-esp32s3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + }; + + aliases { + i2c-0 = &i2c0; + watchdog0 = &wdt0; + led0 = &led0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + label = "BUILTIN LED"; + }; + }; + +}; + +&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"; +}; + +&trng0 { + status = "okay"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + 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/xiao_esp32s3/xiao_esp32s3.yaml b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml new file mode 100644 index 000000000000..129b25ed8ded --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.yaml @@ -0,0 +1,20 @@ +identifier: xiao_esp32s3 +name: XIAO ESP32S3 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - counter + - watchdog + - entropy + - pwm + - dma +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig b/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig new file mode 100644 index 000000000000..df75dd7d2836 --- /dev/null +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_XTENSA_RESET_VECTOR=n +CONFIG_BOARD_XIAO_ESP32S3=y +CONFIG_SOC_ESP32S3=y +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_XTENSA_USE_CORE_CRT1=n +CONFIG_GPIO=y +CONFIG_GEN_ISR_TABLES=y +CONFIG_GEN_IRQ_VECTOR_TABLE=n +CONFIG_CLOCK_CONTROL=y diff --git a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay new file mode 100644 index 000000000000..045056613e08 --- /dev/null +++ b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + */ + +#include +#include + +/ { + aliases { + pwm-0 = &ledc0; + pwm-led0 = &pwm_led_blue; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_blue: pwm_led_gpio0_21 { + label = "PWM LED0"; + pwms = <&ledc0 0 1000 PWM_POLARITY_NORMAL>; + }; + }; +}; + +&pinctrl { + ledc0_default: ledc0_default { + group1 { + pinmux = ; + output-enable; + }; + }; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; +}; diff --git a/samples/net/wifi/boards/xiao_esp32s3.conf b/samples/net/wifi/boards/xiao_esp32s3.conf new file mode 100644 index 000000000000..a72fdf39efa2 --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32s3.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_esp32s3.overlay b/samples/net/wifi/boards/xiao_esp32s3.overlay new file mode 100644 index 000000000000..4d69fe294930 --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32s3.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wifi { + status = "okay"; +}; From 6622735ea8f6a95af938561b4c35e1380f9c5537 Mon Sep 17 00:00:00 2001 From: Roberto Medina Date: Fri, 30 Jun 2023 17:51:25 +0200 Subject: [PATCH 0785/2042] arch: arm64: add support for coredump * Add support for coredump on ARM64 architectures. * Add the script used for post-processing coredump output. Signed-off-by: Marcelo Ruaro Signed-off-by: Rodrigo Cataldo Signed-off-by: Roberto Medina --- arch/Kconfig | 1 + arch/arm64/core/CMakeLists.txt | 1 + arch/arm64/core/coredump.c | 105 +++++++++++++++++++ include/zephyr/debug/coredump.h | 1 + scripts/coredump/gdbstubs/__init__.py | 4 + scripts/coredump/gdbstubs/arch/arm64.py | 131 ++++++++++++++++++++++++ 6 files changed, 243 insertions(+) create mode 100644 arch/arm64/core/coredump.c create mode 100644 scripts/coredump/gdbstubs/arch/arm64.py diff --git a/arch/Kconfig b/arch/Kconfig index 24dce5c0c9cd..6179fd7645e2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -43,6 +43,7 @@ config ARM64 select ARCH_IS_SET select 64BIT select HAS_DTS + select ARCH_SUPPORTS_COREDUMP select HAS_ARM_SMCCC select ARCH_HAS_THREAD_LOCAL_STORAGE select USE_SWITCH diff --git a/arch/arm64/core/CMakeLists.txt b/arch/arm64/core/CMakeLists.txt index 2a44e1969c1e..25cd7f8df6b8 100644 --- a/arch/arm64/core/CMakeLists.txt +++ b/arch/arm64/core/CMakeLists.txt @@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_HAS_ARM_SMCCC smccc-call.S) zephyr_library_sources_ifdef(CONFIG_AARCH64_IMAGE_HEADER header.S) zephyr_library_sources_ifdef(CONFIG_SEMIHOST semihost.c) +zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) if ((CONFIG_MP_MAX_NUM_CPUS GREATER 1) OR (CONFIG_SMP)) zephyr_library_sources(smp.c) endif () diff --git a/arch/arm64/core/coredump.c b/arch/arm64/core/coredump.c new file mode 100644 index 000000000000..399cf85e3d0f --- /dev/null +++ b/arch/arm64/core/coredump.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022 Huawei Technologies SASU + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* Identify the version of this block (in case of architecture changes). + * To be interpreted by the target architecture specific block parser. + */ +#define ARCH_HDR_VER 1 + +/* Structure to store the architecture registers passed arch_coredump_info_dump + * As callee saved registers are not provided in z_arch_esf_t structure in Zephyr + * we just need 22 registers. + */ +struct arm64_arch_block { + struct { + uint64_t x0; + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + uint64_t x12; + uint64_t x13; + uint64_t x14; + uint64_t x15; + uint64_t x16; + uint64_t x17; + uint64_t x18; + uint64_t lr; + uint64_t spsr; + uint64_t elr; + } r; +} __packed; + + +/* + * Register block takes up too much stack space + * if defined within function. So define it here. + */ +static struct arm64_arch_block arch_blk; + +void arch_coredump_info_dump(const z_arch_esf_t *esf) +{ + /* Target architecture information header */ + /* Information just relevant to the python parser */ + struct coredump_arch_hdr_t hdr = { + .id = COREDUMP_ARCH_HDR_ID, + .hdr_version = ARCH_HDR_VER, + .num_bytes = sizeof(arch_blk), + }; + + /* Nothing to process */ + if (esf == NULL) { + return; + } + + (void)memset(&arch_blk, 0, sizeof(arch_blk)); + + /* + * Copies the thread registers to a memory block that will be printed out + * The thread registers are already provided by structure z_arch_esf_t + */ + arch_blk.r.x0 = esf->x0; + arch_blk.r.x1 = esf->x1; + arch_blk.r.x2 = esf->x2; + arch_blk.r.x3 = esf->x3; + arch_blk.r.x4 = esf->x4; + arch_blk.r.x5 = esf->x5; + arch_blk.r.x6 = esf->x6; + arch_blk.r.x7 = esf->x7; + arch_blk.r.x8 = esf->x8; + arch_blk.r.x9 = esf->x9; + arch_blk.r.x10 = esf->x10; + arch_blk.r.x11 = esf->x11; + arch_blk.r.x12 = esf->x12; + arch_blk.r.x13 = esf->x13; + arch_blk.r.x14 = esf->x14; + arch_blk.r.x15 = esf->x15; + arch_blk.r.x16 = esf->x16; + arch_blk.r.x17 = esf->x17; + arch_blk.r.x18 = esf->x18; + arch_blk.r.lr = esf->lr; + arch_blk.r.spsr = esf->spsr; + arch_blk.r.elr = esf->elr; + + /* Send for output */ + coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr)); + coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk)); +} + +uint16_t arch_coredump_tgt_code_get(void) +{ + return COREDUMP_TGT_ARM64; +} diff --git a/include/zephyr/debug/coredump.h b/include/zephyr/debug/coredump.h index e3ab8df28d30..12b743e1f605 100644 --- a/include/zephyr/debug/coredump.h +++ b/include/zephyr/debug/coredump.h @@ -123,6 +123,7 @@ enum coredump_tgt_code { COREDUMP_TGT_ARM_CORTEX_M, COREDUMP_TGT_RISC_V, COREDUMP_TGT_XTENSA, + COREDUMP_TGT_ARM64, }; /* Coredump header */ diff --git a/scripts/coredump/gdbstubs/__init__.py b/scripts/coredump/gdbstubs/__init__.py index 72745dc8b872..c6d783206821 100644 --- a/scripts/coredump/gdbstubs/__init__.py +++ b/scripts/coredump/gdbstubs/__init__.py @@ -9,6 +9,7 @@ from gdbstubs.arch.arm_cortex_m import GdbStub_ARM_CortexM from gdbstubs.arch.risc_v import GdbStub_RISC_V from gdbstubs.arch.xtensa import GdbStub_Xtensa +from gdbstubs.arch.arm64 import GdbStub_ARM64 class TgtCode: UNKNOWN = 0 @@ -17,6 +18,7 @@ class TgtCode: ARM_CORTEX_M = 3 RISC_V = 4 XTENSA = 5 + ARM64 = 6 def get_gdbstub(logfile, elffile): stub = None @@ -33,5 +35,7 @@ def get_gdbstub(logfile, elffile): stub = GdbStub_RISC_V(logfile=logfile, elffile=elffile) elif tgt_code == TgtCode.XTENSA: stub = GdbStub_Xtensa(logfile=logfile, elffile=elffile) + elif tgt_code == TgtCode.ARM64: + stub = GdbStub_ARM64(logfile=logfile, elffile=elffile) return stub diff --git a/scripts/coredump/gdbstubs/arch/arm64.py b/scripts/coredump/gdbstubs/arch/arm64.py new file mode 100644 index 000000000000..008fb88c1b96 --- /dev/null +++ b/scripts/coredump/gdbstubs/arch/arm64.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2022 Huawei Technologies SASU +# +# SPDX-License-Identifier: Apache-2.0 + +import binascii +import logging +import struct + +from gdbstubs.gdbstub import GdbStub + + +logger = logging.getLogger("gdbstub") + + +class RegNum(): + X0 = 0 # X0-X29 - 30 GP registers + X1 = 1 + X2 = 2 + X3 = 3 + X4 = 4 + X5 = 5 + X6 = 6 + X7 = 7 + X8 = 8 + X9 = 9 + X10 = 10 + X11 = 11 + X12 = 12 + X13 = 13 + X14 = 14 + X15 = 15 + X16 = 16 + X17 = 17 + X18 = 18 + X19 = 19 + X20 = 20 + X21 = 21 + X22 = 22 + X23 = 23 + X24 = 24 + X25 = 25 + X26 = 26 + X27 = 27 + X28 = 28 + X29 = 29 # Frame pointer register + LR = 30 # X30 Link Register(LR) + SP_EL0 = 31 # Stack pointer EL0 (SP_EL0) + PC = 32 # Program Counter (PC) + + +class GdbStub_ARM64(GdbStub): + ARCH_DATA_BLK_STRUCT = " unknown value + # Send in "xxxxxxxx" + pkt += b'x' * 16 + + idx += 1 + + self.put_gdb_packet(pkt) + + def handle_register_single_read_packet(self, pkt): + # Mark registers as "". + # 'p' packets are usually used for registers + # other than the general ones (e.g. eax, ebx) + # so we can safely reply "xxxxxxxx" here. + self.put_gdb_packet(b'x' * 16) From 41cfe217b2eb5c8746b729ec84f09184881d091b Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:38:39 +0530 Subject: [PATCH 0786/2042] Bluetooth: Controller: Fix coverity issue 318626 [Coverity CID: 318626] Unintended sign extension in subsys/bluetooth/controller/ll_sw/ull_adv_iso.c. Fixes #58984. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_adv_iso.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c index b5f88f25cc20..982689d83001 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_iso.c @@ -1172,8 +1172,8 @@ static void mfy_iso_offset_get(void *param) LL_ASSERT(id != TICKER_NULL); } while (id != ticker_id); - payload_count = lll_iso->payload_count + ((lll_iso->latency_prepare + - lazy) * lll_iso->bn); + payload_count = lll_iso->payload_count + + (((uint64_t)lll_iso->latency_prepare + lazy) * lll_iso->bn); pdu = lll_adv_sync_data_latest_peek(lll_sync); bi = big_info_get(pdu); From 80632b50c758fc45eba33ed5dcc890faa71d18cc Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:38:39 +0530 Subject: [PATCH 0787/2042] Bluetooth: Controller: Fix coverity issue 318644 [Coverity CID: 318644] Unused value in subsys/bluetooth/controller/ll_sw/ull_central_iso.c. Fixes #58999. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_central_iso.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c index 6dc29b9216fe..2293b134e9ff 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central_iso.c @@ -139,7 +139,6 @@ uint8_t ll_cis_parameters_set(uint8_t cis_id, */ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) { - struct ll_conn_iso_stream *cis; struct ll_conn_iso_group *cig; uint32_t iso_interval_us; uint32_t cig_sync_delay; @@ -227,6 +226,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) /* Create all configurable CISes */ for (uint8_t i = 0U; i < ll_iso_setup.cis_count; i++) { + struct ll_conn_iso_stream *cis; memq_link_t *link_tx_free; cis = ll_conn_iso_stream_get_by_id(ll_iso_setup.stream[i].cis_id); @@ -286,6 +286,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) * ISO_Interval |.................|.. |.................|.. */ for (uint8_t i = 0U; i < num_cis; i++) { + struct ll_conn_iso_stream *cis; uint32_t mpt_c; uint32_t mpt_p; bool tx; @@ -368,7 +369,6 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) if (cig->central.packing == BT_ISO_PACKING_SEQUENTIAL) { /* Sequential CISes - add up the total duration */ for (uint8_t i = 0U; i < num_cis; i++) { - cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); total_time += se[i].total_count * se[i].length; } } @@ -387,6 +387,8 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) * 4) Calculate CIG_Sync_Delay */ for (uint8_t i = 0U; i < num_cis; i++) { + struct ll_conn_iso_stream *cis; + cis = ll_conn_iso_stream_get_by_group(cig, &handle_iter); if (!cig->central.test) { @@ -452,6 +454,7 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles) * 2) Lay out CISes by updating CIS_Sync_Delay, distributing according to the packing. */ for (uint8_t i = 0U; i < num_cis; i++) { + struct ll_conn_iso_stream *cis; uint32_t c_latency; uint32_t p_latency; From 7366dfd1cc8181880ff64511cde56bda93b4f987 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:38:39 +0530 Subject: [PATCH 0788/2042] Bluetooth: Controller: Fix coverity issue 318804 [Coverity CID: 318804] Copy-paste error in subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c Fixes #59512. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c index 3e5f688172d8..a7df6968fe85 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_central_iso.c @@ -863,7 +863,7 @@ static void isr_rx(void *param) /* Adjust nesn when flushing Rx */ /* FIXME: When Flush Timeout is implemented */ - if (cis_lll->tx.bn_curr <= cis_lll->rx.bn) { + if (cis_lll->rx.bn_curr <= cis_lll->rx.bn) { lll_flush_rx(cis_lll); } From 20986ec45dbaa68f47184a57043f52c0f6796e73 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0789/2042] doc: Switch to using docleaf for doxygen entities This switches the Sphinx conf.py file over to using the 'docleaf.doxygen' module and the associated docleaf configuration entries, replacing the breathe module and config. Signed-off-by: Michael Jones --- doc/conf.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 79f2f51b9b59..1ce13cf83821 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -67,7 +67,7 @@ # -- General configuration ------------------------------------------------ extensions = [ - "breathe", + "docleaf.doxygen", "sphinx.ext.todo", "sphinx.ext.extlinks", "sphinx.ext.autodoc", @@ -211,16 +211,14 @@ doxyrunner_fmt_vars = {"ZEPHYR_BASE": str(ZEPHYR_BASE), "ZEPHYR_VERSION": version} doxyrunner_outdir_var = "DOXY_OUT" -# -- Options for Breathe plugin ------------------------------------------- +# -- Options for Docleaf plugin ------------------------------------------- -breathe_projects = {"Zephyr": str(doxyrunner_outdir / "xml")} -breathe_default_project = "Zephyr" -breathe_domain_by_extension = { +docleaf_projects = {"Zephyr": str(doxyrunner_outdir / "xml")} +docleaf_default_project = "Zephyr" +docleaf_domain_by_extension = { "h": "c", "c": "c", } -breathe_show_enumvalue_initializer = True -breathe_default_members = ("members", ) cpp_id_attributes = [ "__syscall", From 30c3ce4a92c7ebcd7885ac5a01ddcfc0334fbad4 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0790/2042] doc: Update requirements-doc.txt to use docleaf Instead of breathe. I'm not sure of the best version comparison to use. There is no intention to break the API for docleaf but it is also still young in some ways and there might be adjustments to the configuration values that would need to be reflected in the version number as it is still pre-1.0 that would only be a minor version change. Signed-off-by: Michael Jones --- doc/_extensions/zephyr/doxyrunner.py | 2 +- doc/_static/css/custom.css | 4 ++-- scripts/requirements-doc.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/_extensions/zephyr/doxyrunner.py b/doc/_extensions/zephyr/doxyrunner.py index 8bd10e63a97c..8ab68cc75439 100644 --- a/doc/_extensions/zephyr/doxyrunner.py +++ b/doc/_extensions/zephyr/doxyrunner.py @@ -9,7 +9,7 @@ ============ This Sphinx plugin can be used to run Doxygen build as part of the Sphinx build -process. It is meant to be used with other plugins such as ``breathe`` in order +process. It is meant to be used with other plugins such as ``docleaf`` in order to improve the user experience. The principal features offered by this plugin are: diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css index da9f379d41d6..a357621205aa 100644 --- a/doc/_static/css/custom.css +++ b/doc/_static/css/custom.css @@ -843,13 +843,13 @@ kbd, .kbd, background-color: var(--navbar-scrollbar-active-color); } -/* Breathe tweaks */ +/* Docleaf tweaks */ .rst-content .section > dl > dd { margin-left: 0; } -.rst-content p.breathe-sectiondef-title { +.rst-content p.docleaf-sectiondef-title { font-size: 115%; color: var(--link-color); } diff --git a/scripts/requirements-doc.txt b/scripts/requirements-doc.txt index 691466759d5c..c26c7da69672 100644 --- a/scripts/requirements-doc.txt +++ b/scripts/requirements-doc.txt @@ -1,6 +1,6 @@ # DOC: used to generate docs -breathe>=4.34 +docleaf==0.8.0 sphinx~=5.0,!=5.2.0.post0 sphinx_rtd_theme~=1.0 sphinx-tabs From 10cb87dc2b430ab51b7fc37794a5faf359c0ea27 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0791/2042] doc: Replace instances of 'Breathe' with 'Docleaf' Where valid. Signed-off-by: Michael Jones --- doc/contribute/documentation/generation.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/contribute/documentation/generation.rst b/doc/contribute/documentation/generation.rst index d7c8d6282bf4..7f2b6ef2d05f 100644 --- a/doc/contribute/documentation/generation.rst +++ b/doc/contribute/documentation/generation.rst @@ -52,7 +52,7 @@ The project's documentation contains the following items: header [shape="rectangle" label="c header\ncomments"] xml [shape="rectangle" label="XML"] html [shape="rectangle" label="HTML\nweb site"] - sphinx[shape="ellipse" label="sphinx +\nbreathe,\ndocutils"] + sphinx[shape="ellipse" label="sphinx +\ndocleaf,\ndocutils"] images -> sphinx rst -> sphinx conf -> sphinx @@ -65,7 +65,7 @@ The project's documentation contains the following items: The reStructuredText files are processed by the Sphinx documentation system, -and make use of the breathe extension for including the doxygen-generated API +and make use of the docleaf extension for including the doxygen-generated API material. Additional tools are required to generate the documentation locally, as described in the following sections. @@ -226,7 +226,7 @@ build the documentation directly from there: Filtering expected warnings *************************** -There are some known issues with Sphinx/Breathe that generate Sphinx warnings +There are some known issues with Sphinx/Docleaf that generate Sphinx warnings even though the input is valid C code. While these issues are being considered for fixing we have created a Sphinx extension that allows to filter them out based on a set of regular expressions. The extension is named @@ -234,8 +234,8 @@ based on a set of regular expressions. The extension is named ``doc/_extensions/zephyr/warnings_filter.py``. The warnings to be filtered out can be added to the ``doc/known-warnings.txt`` file. -The most common warning reported by Sphinx/Breathe is related to duplicate C -declarations. This warning may be caused by different Sphinx/Breathe issues: +The most common warning reported by Sphinx/Docleaf is related to duplicate C +declarations. This warning may be caused by different Sphinx/Docleaf issues: - Multiple declarations of the same object are not supported - Different objects (e.g. a struct and a function) can not share the same name From a3b7102273c2bb0d2dc225420956f91833a5133f Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0792/2042] doc: Adjust docleaf configuration as needed We make sure that we have the 'root' and 'xml' defined for the project which is necessary at the moment for docleaf though the 'root' is only really used for the 'linkcode' integration. Signed-off-by: Michael Jones --- doc/conf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 1ce13cf83821..2d5f97a9f1a7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -213,12 +213,15 @@ # -- Options for Docleaf plugin ------------------------------------------- -docleaf_projects = {"Zephyr": str(doxyrunner_outdir / "xml")} +docleaf_projects = {"Zephyr": {"xml": str(doxyrunner_outdir / "xml"), "root": "../"}} docleaf_default_project = "Zephyr" docleaf_domain_by_extension = { "h": "c", "c": "c", } +# Filters out any 'function' or 'variable' members that have 'all caps' names as +# they are likely unprocessed macro calls +docleaf_doxygen_skip = ["members:all_caps"] cpp_id_attributes = [ "__syscall", From 88c1519414aa5b4d8bd2bae767cc2f21295f2833 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0793/2042] doc: Remove :members: on doxygengroup directives As that is not supported by docleaf. We get everything by default. Signed-off-by: Michael Jones --- doc/connectivity/bluetooth/api/mesh/blob.rst | 1 - doc/connectivity/bluetooth/api/mesh/blob_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/blob_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/dfd_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/dfu.rst | 2 -- doc/connectivity/bluetooth/api/mesh/dfu_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/dfu_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/lcd_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/lcd_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/od_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/od_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/op_agg_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/rpr_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/rpr_srv.rst | 1 - doc/connectivity/bluetooth/api/mesh/srpl_cli.rst | 1 - doc/connectivity/bluetooth/api/mesh/srpl_srv.rst | 1 - 19 files changed, 20 deletions(-) diff --git a/doc/connectivity/bluetooth/api/mesh/blob.rst b/doc/connectivity/bluetooth/api/mesh/blob.rst index 069f1ac9c635..d36ba366ed44 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob.rst @@ -127,4 +127,3 @@ This section contains types and defines common to the BLOB Transfer models. .. doxygengroup:: bt_mesh_blob :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst index 6d926be1b5ca..74ee8d43d6f9 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_cli.rst @@ -93,4 +93,3 @@ API reference .. doxygengroup:: bt_mesh_blob_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst index 22c2540a3377..b88cd364724f 100644 --- a/doc/connectivity/bluetooth/api/mesh/blob_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/blob_srv.rst @@ -67,4 +67,3 @@ API reference .. doxygengroup:: bt_mesh_blob_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/dfd_srv.rst b/doc/connectivity/bluetooth/api/mesh/dfd_srv.rst index a1912e3acfb9..7c9c8c77a587 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfd_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfd_srv.rst @@ -23,4 +23,3 @@ API reference .. doxygengroup:: bt_mesh_dfd_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 685aaf3cbd1d..b4dc456178f7 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -221,8 +221,6 @@ This section lists the types common to the Device Firmware Update mesh models. .. doxygengroup:: bt_mesh_dfu :project: Zephyr - :members: .. doxygengroup:: bt_mesh_dfu_metadata :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/dfu_cli.rst b/doc/connectivity/bluetooth/api/mesh/dfu_cli.rst index c4ea98770d93..74a08ac0620e 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu_cli.rst @@ -11,4 +11,3 @@ API reference .. doxygengroup:: bt_mesh_dfu_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst index 0b98b1ec067c..fa35e484f76f 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu_srv.rst @@ -68,4 +68,3 @@ API reference .. doxygengroup:: bt_mesh_dfu_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst index 27df2e493b21..6871b51abed4 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_cli.rst @@ -17,4 +17,3 @@ API reference .. doxygengroup:: bt_mesh_large_comp_data_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst index df724974b86a..cd10e3f84a4c 100644 --- a/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/lcd_srv.rst @@ -27,4 +27,3 @@ API reference .. doxygengroup:: bt_mesh_large_comp_data_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/od_cli.rst b/doc/connectivity/bluetooth/api/mesh/od_cli.rst index ea2deae79b9f..8d49d716b6d4 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_cli.rst @@ -26,4 +26,3 @@ API reference .. doxygengroup:: bt_mesh_od_priv_proxy_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/od_srv.rst b/doc/connectivity/bluetooth/api/mesh/od_srv.rst index 241ce5f155cf..e23d17c9d951 100644 --- a/doc/connectivity/bluetooth/api/mesh/od_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/od_srv.rst @@ -25,4 +25,3 @@ API reference .. doxygengroup:: bt_mesh_od_priv_proxy_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst index 23eb608391f9..80d5f52d13ec 100644 --- a/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/op_agg_cli.rst @@ -27,4 +27,3 @@ API reference .. doxygengroup:: bt_mesh_op_agg_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/op_agg_srv.rst b/doc/connectivity/bluetooth/api/mesh/op_agg_srv.rst index 5d493cb45909..25fbe8bb758a 100644 --- a/doc/connectivity/bluetooth/api/mesh/op_agg_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/op_agg_srv.rst @@ -29,4 +29,3 @@ API reference .. doxygengroup:: bt_mesh_op_agg_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst index 6a6f44b1387e..ce81cfcd76fa 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst @@ -33,4 +33,3 @@ API reference .. doxygengroup:: bt_mesh_priv_beacon_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst index d69fe616e380..7728bede2a73 100644 --- a/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst @@ -36,4 +36,3 @@ API reference .. doxygengroup:: bt_mesh_priv_beacon_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/rpr_cli.rst b/doc/connectivity/bluetooth/api/mesh/rpr_cli.rst index 38cb8849f9e5..aa4909a37b7c 100644 --- a/doc/connectivity/bluetooth/api/mesh/rpr_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/rpr_cli.rst @@ -129,4 +129,3 @@ API reference .. doxygengroup:: bt_mesh_rpr_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst b/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst index f958ef31bd93..9d966179e980 100644 --- a/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/rpr_srv.rst @@ -27,4 +27,3 @@ API reference .. doxygengroup:: bt_mesh_rpr_srv :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/srpl_cli.rst b/doc/connectivity/bluetooth/api/mesh/srpl_cli.rst index e940158dd2ef..5764d223c07b 100644 --- a/doc/connectivity/bluetooth/api/mesh/srpl_cli.rst +++ b/doc/connectivity/bluetooth/api/mesh/srpl_cli.rst @@ -28,4 +28,3 @@ API reference .. doxygengroup:: bt_mesh_sol_pdu_rpl_cli :project: Zephyr - :members: diff --git a/doc/connectivity/bluetooth/api/mesh/srpl_srv.rst b/doc/connectivity/bluetooth/api/mesh/srpl_srv.rst index a8c5379e3052..8c897450bbb5 100644 --- a/doc/connectivity/bluetooth/api/mesh/srpl_srv.rst +++ b/doc/connectivity/bluetooth/api/mesh/srpl_srv.rst @@ -27,4 +27,3 @@ API reference .. doxygengroup:: bt_mesh_sol_pdu_rpl_srv :project: Zephyr - :members: From 56d7afeac9408f216e5e785ee5c90b740293fed0 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Wed, 21 Jun 2023 20:49:08 +0100 Subject: [PATCH 0794/2042] doc: Make sure message is a string before regexing it There are times when the log message is an exception object and that causes the regex to fail with a TypeError. Here we work around that by converting the input to a string. Signed-off-by: Michael Jones --- doc/_extensions/zephyr/warnings_filter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/_extensions/zephyr/warnings_filter.py b/doc/_extensions/zephyr/warnings_filter.py index 650a76134b21..d92db7796e39 100644 --- a/doc/_extensions/zephyr/warnings_filter.py +++ b/doc/_extensions/zephyr/warnings_filter.py @@ -52,7 +52,8 @@ def filter(self, record: logging.LogRecord) -> bool: return True for expression in self._expressions: - if re.match(expression, record.msg): + # The message isn't always a string so we convert it before regexing as we can only regex strings + if re.match(expression, str(record.msg)): if self._silent: return False else: From 343f60c6314689b8942c446708706a5c8ea9fe13 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Thu, 22 Jun 2023 13:27:56 +0100 Subject: [PATCH 0795/2042] doc: Add '--keep-going' flag to sphinx-build So that we see all the potential errors in CI and not just the first and can assess how much work there is to do. This was introduced for debuggin but gmarull has suggested keeping it in. Signed-off-by: Michael Jones --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 8d86b1033591..ec6e11497b93 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -85,7 +85,7 @@ jobs: DOC_TARGET="html" fi - DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -W -t publish" make -C doc ${DOC_TARGET} + DOC_TAG=${DOC_TAG} SPHINXOPTS="-q -W --keep-going -t publish" make -C doc ${DOC_TARGET} - name: compress-docs run: | From 3127d7b54c22449fcc85dd1c59ca294885d5f997 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Thu, 22 Jun 2023 15:07:07 +0100 Subject: [PATCH 0796/2042] doc: Add more known-warnings We should probably clear out the old warnings and see what still applies for docleaf now that we have that instead of breathe. However for this moment, these are new duplication declarations that we're seeing errors for and so we'd like to silence them. Signed-off-by: Michael Jones --- doc/known-warnings.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/known-warnings.txt b/doc/known-warnings.txt index 2ae3f98729c4..20788ea8e54a 100644 --- a/doc/known-warnings.txt +++ b/doc/known-warnings.txt @@ -16,3 +16,6 @@ .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct in6_addr.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct net_if.*'.* .*Duplicate C declaration.*\n.*'\.\. c:struct:: bt_ots_init'.* +.*Duplicate C declaration.*\n.*'\.\. c:member:: enum *bt_mesh_dfd_upload_phase bt_mesh_dfd_srv.phase'.* +.*Duplicate C declaration.*\n.*'\.\. c:member:: struct *bt_mesh_blob_xfer bt_mesh_dfu_cli.blob'.* +.*Duplicate C declaration.*\n.*'\.\. c:member:: struct *net_if *\* net_if_mcast_monitor.iface'. From 34e50037f0d94efce10770da5abcf48f7ba33906 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Sat, 1 Jul 2023 21:16:50 +0100 Subject: [PATCH 0797/2042] doc: Log unused log filter patterns This allows us to identify any patterns that we can remove or that we didn't realise are no longer in use. This might happen if issues within doxygen or docleaf are resolved. This allows us to remove the pattern: .*Duplicate C declaration.*\n.*'\.\. c:.*:: uint16_t id'.* which does not match anything in the current set up. We also split the filter patterns in known-warnings out into different sections depending on their cause. Also extend the pattern parser to ignore empty lines so that we can have some formatting in the known-warnings file. Signed-off-by: Michael Jones --- doc/_extensions/zephyr/warnings_filter.py | 43 ++++++++++++++++++++--- doc/known-warnings.txt | 19 +++++++--- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/doc/_extensions/zephyr/warnings_filter.py b/doc/_extensions/zephyr/warnings_filter.py index d92db7796e39..9239776ff793 100644 --- a/doc/_extensions/zephyr/warnings_filter.py +++ b/doc/_extensions/zephyr/warnings_filter.py @@ -24,7 +24,7 @@ import logging import re -from typing import Dict, Any, List +from typing import Dict, Any, List, Optional from sphinx.application import Sphinx from sphinx.util.logging import NAMESPACE @@ -41,6 +41,7 @@ class WarningsFilter(logging.Filter): silent: If true, warning is hidden, otherwise it is shown as INFO. name: Filter name. """ + def __init__(self, expressions: List[str], silent: bool, name: str = "") -> None: super().__init__(name) @@ -53,7 +54,7 @@ def filter(self, record: logging.LogRecord) -> bool: for expression in self._expressions: # The message isn't always a string so we convert it before regexing as we can only regex strings - if re.match(expression, str(record.msg)): + if expression.match(str(record.msg)): if self._silent: return False else: @@ -64,6 +65,21 @@ def filter(self, record: logging.LogRecord) -> bool: return True +class Expression: + """ + Encapsulate a log filter pattern and track if it ever matches a log line. + """ + + def __init__(self, pattern): + self.pattern = pattern + self.matched = False + + def match(self, str): + matches = bool(re.match(self.pattern, str)) + self.matched = matches or self.matched + return matches + + def configure(app: Sphinx) -> None: """Entry point. @@ -75,8 +91,10 @@ def configure(app: Sphinx) -> None: with open(app.config.warnings_filter_config) as f: expressions = list() for line in f.readlines(): - if not line.startswith("#"): - expressions.append(line.rstrip()) + if line.strip() and not line.startswith("#"): + expressions.append(Expression(line.rstrip())) + + app.env.warnings_filter_expressions = expressions # install warnings filter to all the Sphinx logger handlers filter = WarningsFilter(expressions, app.config.warnings_filter_silent) @@ -85,11 +103,28 @@ def configure(app: Sphinx) -> None: handler.filters.insert(0, filter) +def finished(app: Sphinx, exception: Optional[Exception]): + """ + Prints out any patterns that have not matched a log line to allow us to clean up any that are not used. + """ + if exception: + # Early exit if there has been an exception as matching data is only + # valid for complete builds + return + + expressions = app.env.warnings_filter_expressions + + for expression in expressions: + if not expression.matched: + logging.warning(f"Unused expression: {expression.pattern}") + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("warnings_filter_config", "", "") app.add_config_value("warnings_filter_silent", True, "") app.connect("builder-inited", configure) + app.connect("build-finished", finished) return { "version": __version__, diff --git a/doc/known-warnings.txt b/doc/known-warnings.txt index 20788ea8e54a..623e89e423b4 100644 --- a/doc/known-warnings.txt +++ b/doc/known-warnings.txt @@ -1,21 +1,30 @@ # Each line should contain the regular expression of a known Sphinx warning # that should be filtered out -.*Duplicate C declaration.*\n.*'\.\. c:.*:: dma_config'.* + +# Function and (enum or struct) name .*Duplicate C declaration.*\n.*'\.\. c:.*:: flash_img_check'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: zsock_fd_set'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: net_if_mcast_monitor'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: fs_statvfs'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*dmic_trigger.*'.* -.*Duplicate C declaration.*\n.*'\.\. c:.*:: uint16_t id'.* +.*Duplicate C declaration.*\n.*'\.\. c:.*:: dma_config'.* +.*Duplicate C declaration.*\n.*'\.\. c:.*:: net_if_mcast_monitor'.* +.*Duplicate C declaration.*\n.*'\.\. c:struct:: bt_ots_init'.* + +# Struct and typedef name +.*Duplicate C declaration.*\n.*'\.\. c:.*:: zsock_fd_set'.* + +# Function and extern function .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_addr_mask_cmp.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_is_addr_bcast.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv4_addr_lookup.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv6_addr_lookup.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*net_if_ipv6_maddr_lookup.*'.* + +# Common field names .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct in_addr.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct in6_addr.*'.* .*Duplicate C declaration.*\n.*'\.\. c:.*:: .*struct net_if.*'.* -.*Duplicate C declaration.*\n.*'\.\. c:struct:: bt_ots_init'.* + +# Clash with field of nested anonymous struct .*Duplicate C declaration.*\n.*'\.\. c:member:: enum *bt_mesh_dfd_upload_phase bt_mesh_dfd_srv.phase'.* .*Duplicate C declaration.*\n.*'\.\. c:member:: struct *bt_mesh_blob_xfer bt_mesh_dfu_cli.blob'.* .*Duplicate C declaration.*\n.*'\.\. c:member:: struct *net_if *\* net_if_mcast_monitor.iface'. From 4828c89fa25eed56bc47b803598a121b3c04e8d8 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sat, 18 Jun 2022 10:51:39 -0700 Subject: [PATCH 0798/2042] dts: bindings: clock: Fix fixed-clock binding Remove `clocks` property for fixed-clock binding. A fixed-clock should not have an input clock, since by definition it's an always on fixed-rate clock. Signed-off-by: Moritz Fischer --- dts/bindings/clock/fixed-clock.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dts/bindings/clock/fixed-clock.yaml b/dts/bindings/clock/fixed-clock.yaml index 1bf6bfd4ad41..d3bd9deea5af 100644 --- a/dts/bindings/clock/fixed-clock.yaml +++ b/dts/bindings/clock/fixed-clock.yaml @@ -13,9 +13,5 @@ properties: description: output clock frequency (Hz) required: true - clocks: - type: array - description: input clock source - "#clock-cells": const: 0 From 28ed7f057d60004aa81424543bd50b416b6a755d Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 9 Jun 2022 12:27:44 -0700 Subject: [PATCH 0799/2042] drivers: clock_control: Add clock_fixed_rate driver Add fixed-clock clock control driver. This is a first step towards making fixed-clocks a first-class citizen in the clock control framework. Since the change is hidden behind a Kconfig enable this is opt-in for now. Signed-off-by: Moritz Fischer --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.fixed | 10 +++ .../clock_control/clock_control_fixed_rate.c | 78 +++++++++++++++++++ .../clock_control/fixed_clock/CMakeLists.txt | 9 +++ .../clock_control/fixed_clock/app.overlay | 17 ++++ .../clock_control/fixed_clock/prj.conf | 4 + .../fixed_clock/src/test_clock_control.c | 51 ++++++++++++ .../clock_control/fixed_clock/testcase.yaml | 7 ++ 9 files changed, 179 insertions(+) create mode 100644 drivers/clock_control/Kconfig.fixed create mode 100644 drivers/clock_control/clock_control_fixed_rate.c create mode 100644 tests/drivers/clock_control/fixed_clock/CMakeLists.txt create mode 100644 tests/drivers/clock_control/fixed_clock/app.overlay create mode 100644 tests/drivers/clock_control/fixed_clock/prj.conf create mode 100644 tests/drivers/clock_control/fixed_clock/src/test_clock_control.c create mode 100644 tests/drivers/clock_control/fixed_clock/testcase.yaml diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 5e73ba3da20b..d1bacc0a2013 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BEETLE beetle_clock_control.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ADSP clock_control_adsp.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32 clock_control_esp32.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_control_fixed_rate.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LITEX clock_control_litex.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LPC11U6X clock_control_lpc11u6x.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index c74808e692eb..6c45839d27d4 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -32,6 +32,8 @@ source "drivers/clock_control/Kconfig.stm32" source "drivers/clock_control/Kconfig.beetle" +source "drivers/clock_control/Kconfig.fixed" + source "drivers/clock_control/Kconfig.lpc11u6x" source "drivers/clock_control/Kconfig.mcux_ccm" diff --git a/drivers/clock_control/Kconfig.fixed b/drivers/clock_control/Kconfig.fixed new file mode 100644 index 000000000000..ee4c868f7ed9 --- /dev/null +++ b/drivers/clock_control/Kconfig.fixed @@ -0,0 +1,10 @@ +# Fixed clock control driver config + +# Copyright (c) 2022 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_FIXED_RATE_CLOCK + bool "Fixed Clock Clock Control" + default n + help + Enable driver for devicetree defined fixed clocks. diff --git a/drivers/clock_control/clock_control_fixed_rate.c b/drivers/clock_control/clock_control_fixed_rate.c new file mode 100644 index 000000000000..eaa4b3979f90 --- /dev/null +++ b/drivers/clock_control/clock_control_fixed_rate.c @@ -0,0 +1,78 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2022 Google, LLC + * + */ + +#include + +#define DT_DRV_COMPAT fixed_clock + +struct fixed_rate_clock_config { + uint32_t rate; +}; + +static int fixed_rate_clk_on(const struct device *dev, + clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return 0; +} + +static int fixed_rate_clk_off(const struct device *dev, + clock_control_subsys_t sys) +{ + ARG_UNUSED(dev); + ARG_UNUSED(sys); + + return 0; +} + +static enum clock_control_status fixed_rate_clk_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + return CLOCK_CONTROL_STATUS_ON; +} + +static int fixed_rate_clk_get_rate(const struct device *dev, + clock_control_subsys_t sys, + uint32_t *rate) +{ + const struct fixed_rate_clock_config *config = dev->config; + + ARG_UNUSED(sys); + + *rate = config->rate; + return 0; +} + +static const struct clock_control_driver_api fixed_rate_clk_api = { + .on = fixed_rate_clk_on, + .off = fixed_rate_clk_off, + .get_status = fixed_rate_clk_get_status, + .get_rate = fixed_rate_clk_get_rate +}; + +static int fixed_rate_clk_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 0; +} + +#define FIXED_CLK_INIT(idx) \ + static const struct fixed_rate_clock_config fixed_rate_clock_config_##idx = { \ + .rate = DT_INST_PROP(idx, clock_frequency), \ + }; \ + DEVICE_DT_INST_DEFINE(idx, \ + fixed_rate_clk_init, \ + NULL, NULL, \ + &fixed_rate_clock_config_##idx, \ + PRE_KERNEL_1, \ + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &fixed_rate_clk_api \ + ); +DT_INST_FOREACH_STATUS_OKAY(FIXED_CLK_INIT) diff --git a/tests/drivers/clock_control/fixed_clock/CMakeLists.txt b/tests/drivers/clock_control/fixed_clock/CMakeLists.txt new file mode 100644 index 000000000000..3de4e8c0c1d7 --- /dev/null +++ b/tests/drivers/clock_control/fixed_clock/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(fixed_clock) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/clock_control/fixed_clock/app.overlay b/tests/drivers/clock_control/fixed_clock/app.overlay new file mode 100644 index 000000000000..913b32176f15 --- /dev/null +++ b/tests/drivers/clock_control/fixed_clock/app.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 Google, LLC + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/ { + test { + test_fixed_rate_clk0: clk { + compatible = "fixed-clock"; + clock-frequency = <100>; + #clock-cells = <0>; + }; + + }; +}; diff --git a/tests/drivers/clock_control/fixed_clock/prj.conf b/tests/drivers/clock_control/fixed_clock/prj.conf new file mode 100644 index 000000000000..b60d57cd8466 --- /dev/null +++ b/tests/drivers/clock_control/fixed_clock/prj.conf @@ -0,0 +1,4 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_CLOCK_CONTROL=y +CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK=y diff --git a/tests/drivers/clock_control/fixed_clock/src/test_clock_control.c b/tests/drivers/clock_control/fixed_clock/src/test_clock_control.c new file mode 100644 index 000000000000..cddc846c1e4d --- /dev/null +++ b/tests/drivers/clock_control/fixed_clock/src/test_clock_control.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Google, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#define TEST_FIXED_RATE_CLK0 DT_NODELABEL(test_fixed_rate_clk0) +#define TEST_FIXED_RATE_CLK0_RATE DT_PROP(TEST_FIXED_RATE_CLK0, clock_frequency) + +/* + * Basic test for checking correctness of clock_api implementation + */ +ZTEST(fixed_clk, test_fixed_rate_clk_on_off_status_rate) +{ + const struct device *dev = DEVICE_DT_GET(TEST_FIXED_RATE_CLK0); + enum clock_control_status status; + uint32_t rate; + int err; + + zassert_equal(device_is_ready(dev), true, "%s: Device wasn't ready", + dev->name); + + status = clock_control_get_status(dev, 0); + zassert_equal(status, CLOCK_CONTROL_STATUS_ON, + "%s: Unexpected status (%d)", dev->name, status); + + err = clock_control_on(dev, 0); + zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err); + + status = clock_control_get_status(dev, 0); + zassert_equal(status, CLOCK_CONTROL_STATUS_ON, + "%s: Unexpected status (%d)", dev->name, status); + + err = clock_control_off(dev, 0); + zassert_equal(0, err, "%s: Expected 0, got (%d)", + dev->name, err); + + status = clock_control_get_status(dev, 0); + zassert_equal(status, CLOCK_CONTROL_STATUS_ON, + "%s: Unexpected status (%d)", dev->name, status); + + err = clock_control_get_rate(dev, 0, &rate); + zassert_equal(0, err, "%s: Unexpected err (%d)", dev->name, err); + zassert_equal(TEST_FIXED_RATE_CLK0_RATE, rate, + "%s: Got wrong rate, expected %u, got %u\n", + dev->name, TEST_FIXED_RATE_CLK0_RATE, rate); +} + +ZTEST_SUITE(fixed_clk, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/drivers/clock_control/fixed_clock/testcase.yaml b/tests/drivers/clock_control/fixed_clock/testcase.yaml new file mode 100644 index 000000000000..1f0e6c161264 --- /dev/null +++ b/tests/drivers/clock_control/fixed_clock/testcase.yaml @@ -0,0 +1,7 @@ +tests: + drivers.clock.clock_control_fixed_clock: + tags: + - drivers + - clock + platform_allow: + - native_posix_64 From bc60619b90400ebe37881c5bfa52900f36a0caa0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Sat, 1 Jul 2023 06:27:06 +0530 Subject: [PATCH 0800/2042] Bluetooth: Controller: Fix coverity issue 248393 [Coverity CID: 248393] Explicit null dereferenced in subsys/bluetooth/controller/ll_sw/ull_scan_aux.c Fixes #58942. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_scan_aux.c | 2 +- 1 file changed, 1 insertion(+), 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 d46cfd1dba89..9f0f6b825b8b 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -411,7 +411,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx) * Setup synchronization if address and SID match in the * Periodic Advertiser List or with the explicitly supplied. */ - if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && sync && adi && + if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) && aux && sync && adi && ull_sync_setup_sid_match(scan, PDU_ADV_ADI_SID_GET(adi))) { ull_sync_setup(scan, aux, rx, si); } From 8f73a479d1c345a76e3d47496a7ae430cb8bcbeb Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Mon, 26 Jun 2023 22:04:03 -0400 Subject: [PATCH 0801/2042] drivers: adc: stm32: use correct device in dma callback The device passed to the DMA callback is the DMA device. Instead use the ADC device available in the private data. Signed-off-by: Brett Witherspoon --- drivers/adc/adc_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 1ba3f9cfec38..dd617bf5d2cd 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -707,7 +707,7 @@ static void dma_callback(const struct device *dev, void *user_data, { /* user_data directly holds the adc device */ struct adc_stm32_data *data = user_data; - const struct adc_stm32_cfg *config = dev->config; + const struct adc_stm32_cfg *config = data->dev->config; ADC_TypeDef *adc = (ADC_TypeDef *)config->base; LOG_DBG("dma callback"); From 4368351917f9f1aeb4832ea53cfae6033a729e17 Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Mon, 3 Jul 2023 11:47:19 +0200 Subject: [PATCH 0802/2042] dts: bindings: add Torex Semiconductor Add new vendor to the dts bindings list. Signed-off-by: Jakub Rzeszutko --- 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 f6244d4e3947..c70b9b6e0537 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -613,6 +613,7 @@ topeet Topeet toppoly TPO (deprecated, use tpo) topwise Topwise Communication Co., Ltd. toradex Toradex AG +torex Torex Semiconductor Ltd. toshiba Toshiba Corporation toumaz Toumaz tpk TPK U.S.A. LLC From 1d61ad8bedf2a2a79acd5d50813e2b2603c546c9 Mon Sep 17 00:00:00 2001 From: Caspar Friedrich Date: Sat, 1 Jul 2023 10:43:37 +0200 Subject: [PATCH 0803/2042] dts: bindings: display: st7735r: Remove requirement for reset-gpios The display controller supports software reset and the driver already implements it. Therefore it's not necessary to require a reset gpio in device tree. Signed-off-by: Caspar Friedrich --- dts/bindings/display/sitronix,st7735r.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/dts/bindings/display/sitronix,st7735r.yaml b/dts/bindings/display/sitronix,st7735r.yaml index 008a1959fb10..987ff620ec56 100644 --- a/dts/bindings/display/sitronix,st7735r.yaml +++ b/dts/bindings/display/sitronix,st7735r.yaml @@ -10,7 +10,6 @@ include: [spi-device.yaml, display-controller.yaml] properties: reset-gpios: type: phandle-array - required: true description: RESET pin. The RESET pin of ST7735R is active low. From 0ce47c7a8de0387e4abf2a342e028847a5aa95db Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:07 +0200 Subject: [PATCH 0804/2042] net: l2: ieee802154: readability: buf -> pkt_buf This change renames buf to pkt_buf in one very specific instance to distinguish the packet buffer from the frame buffer which is kept in the same local scope. In all other instances the meaning of "buf" should be obvious from context, not so here, though Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index a498ad25dacf..5a1c64196039 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -477,7 +477,7 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) struct ieee802154_context *ctx = net_if_l2_data(iface); uint8_t ll_hdr_len = 0, authtag_len = 0; static struct net_buf *frame_buf; - static struct net_buf *buf; + static struct net_buf *pkt_buf; bool send_raw = false; int len; #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT @@ -537,8 +537,8 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) net_capture_pkt(iface, pkt); len = 0; - buf = pkt->buffer; - while (buf) { + pkt_buf = pkt->buffer; + while (pkt_buf) { int ret; /* Reinitializing frame_buf */ @@ -547,18 +547,18 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT if (requires_fragmentation) { - buf = ieee802154_6lo_fragment(&f_ctx, frame_buf, true); + pkt_buf = ieee802154_6lo_fragment(&f_ctx, frame_buf, true); } else { - net_buf_add_mem(frame_buf, buf->data, buf->len); - buf = buf->frags; + net_buf_add_mem(frame_buf, pkt_buf->data, pkt_buf->len); + pkt_buf = pkt_buf->frags; } #else - if (ll_hdr_len + buf->len + authtag_len > IEEE802154_MTU) { - NET_ERR("Frame too long: %d", buf->len); + if (ll_hdr_len + pkt_buf->len + authtag_len > IEEE802154_MTU) { + NET_ERR("Frame too long: %d", pkt_buf->len); return -EINVAL; } - net_buf_add_mem(frame_buf, buf->data, buf->len); - buf = buf->frags; + net_buf_add_mem(frame_buf, pkt_buf->data, pkt_buf->len); + pkt_buf = pkt_buf->frags; #endif /* CONFIG_NET_L2_IEEE802154_FRAGMENT */ __ASSERT_NO_MSG(authtag_len <= net_buf_tailroom(frame_buf)); From 48456d32d548817177e3b0adfce9c92e229b7465 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:08 +0200 Subject: [PATCH 0805/2042] net: l2: ieee802154: rename comp to has_pan_id This change is in preparation for the newer frame version's more complex compression algorithm that may compress both, the source and the destination PAN independently. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 23 +++++++-------------- subsys/net/l2/ieee802154/ieee802154_frame.c | 16 +++++++------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 5a1c64196039..7553aca7d03f 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -242,7 +242,7 @@ int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt, struct net_ return -EIO; } -static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool comp, +static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool has_pan_id, enum ieee802154_addressing_mode mode, struct ieee802154_address_field *ll) { @@ -251,22 +251,13 @@ static inline void swap_and_set_pkt_ll_addr(struct net_linkaddr *addr, bool comp switch (mode) { case IEEE802154_ADDR_MODE_EXTENDED: addr->len = IEEE802154_EXT_ADDR_LENGTH; - - if (comp) { - addr->addr = ll->comp.addr.ext_addr; - } else { - addr->addr = ll->plain.addr.ext_addr; - } + addr->addr = has_pan_id ? ll->plain.addr.ext_addr : ll->comp.addr.ext_addr; break; case IEEE802154_ADDR_MODE_SHORT: addr->len = IEEE802154_SHORT_ADDR_LENGTH; - - if (comp) { - addr->addr = (uint8_t *)&ll->comp.addr.short_addr; - } else { - addr->addr = (uint8_t *)&ll->plain.addr.short_addr; - } + addr->addr = (uint8_t *)(has_pan_id ? &ll->plain.addr.short_addr + : &ll->comp.addr.short_addr); break; case IEEE802154_ADDR_MODE_NONE: @@ -442,10 +433,10 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk * packet handling as it will mangle the package header to comply with upper * network layers' (POSIX) requirement to represent network addresses in big endian. */ - swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), fs->fc.pan_id_comp, fs->fc.src_addr_mode, - mpdu.mhr.src_addr); + swap_and_set_pkt_ll_addr(net_pkt_lladdr_src(pkt), !fs->fc.pan_id_comp, + fs->fc.src_addr_mode, mpdu.mhr.src_addr); - swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), false, fs->fc.dst_addr_mode, + swap_and_set_pkt_ll_addr(net_pkt_lladdr_dst(pkt), true, fs->fc.dst_addr_mode, mpdu.mhr.dst_addr); net_pkt_set_ll_proto_type(pkt, ETH_P_IEEE802154); diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index ee1405e7ddcb..081c0d5a24f3 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -235,11 +235,11 @@ static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, u } static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, uint8_t ar, - uint8_t comp, uint8_t src_bf, + bool has_pan_id, uint8_t src_bf, bool src_pan_brdcst_chk, uint8_t dst_bf, bool dst_brdcst_chk) { - if (mhr->fs->fc.ar != ar || mhr->fs->fc.pan_id_comp != comp) { + if (mhr->fs->fc.ar != ar || mhr->fs->fc.pan_id_comp == has_pan_id) { return false; } @@ -248,14 +248,12 @@ static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, u return false; } - /* This should be set only when comp == 0 */ if (src_pan_brdcst_chk) { if (mhr->src_addr->plain.pan_id != IEEE802154_BROADCAST_PAN_ID) { return false; } } - /* This should be set only when comp == 0 */ if (dst_brdcst_chk) { /* broadcast address is symmetric so no need to swap byte order */ if (mhr->dst_addr->plain.addr.short_addr != IEEE802154_BROADCAST_ADDRESS) { @@ -272,7 +270,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b uint8_t len = IEEE802154_CMD_CFI_LENGTH; bool src_pan_brdcst_chk = false; bool dst_brdcst_chk = false; - uint8_t comp = 0U; + bool has_pan_id = true; uint8_t ar = 0U; uint8_t src_bf, dst_bf; @@ -301,7 +299,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b __fallthrough; case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION: ar = 1U; - comp = 1U; + has_pan_id = false; src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); dst_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); @@ -313,14 +311,14 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b if (mpdu->mhr.fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_NONE) { dst_bf = BIT(IEEE802154_ADDR_MODE_NONE); } else { - comp = 1U; + has_pan_id = false; dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT) | BIT(IEEE802154_ADDR_MODE_EXTENDED); } break; case IEEE802154_CFI_ORPHAN_NOTIFICATION: - comp = 1U; + has_pan_id = false; src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT); @@ -358,7 +356,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b return false; } - if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ar, comp, src_bf, + if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ar, has_pan_id, src_bf, src_pan_brdcst_chk, dst_bf, dst_brdcst_chk)) { return false; From a7338b33d57b8726f3c485abf847ba6f2c41d05b Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:08 +0200 Subject: [PATCH 0806/2042] net: l2: ieee802154: readability: LL header length Several distinct naming conventions existed within the IEEE 802.15.4 stack wrt header length. This change converges to a single naming convention, the one that is less ambiguous and already most used. The change also makes the distinction between L2 (link layer/LL) header length and 6LoWPAN fragmentation header length to avoid confusion. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 6 ++--- .../l2/ieee802154/ieee802154_6lo_fragment.c | 22 +++++++++---------- subsys/net/l2/ieee802154/ieee802154_frame.c | 18 +++++++-------- subsys/net/l2/ieee802154/ieee802154_frame.h | 3 ++- .../net/l2/ieee802154/ieee802154_security.c | 20 ++++++++--------- .../net/l2/ieee802154/ieee802154_security.h | 8 +++---- 6 files changed, 39 insertions(+), 38 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 7553aca7d03f..2d005c0ac092 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -359,7 +359,7 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk struct ieee802154_fcf_seq *fs; struct ieee802154_mpdu mpdu; bool is_broadcast; - size_t hdr_len; + size_t ll_hdr_len; /* The IEEE 802.15.4 stack assumes that drivers provide a single-fragment package. */ __ASSERT_NO_MSG(pkt->buffer && pkt->buffer->frags == NULL); @@ -443,8 +443,8 @@ static enum net_verdict ieee802154_recv(struct net_if *iface, struct net_pkt *pk pkt_hexdump(RX_PKT_TITLE " (with ll)", pkt, true); - hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt); - net_buf_pull(pkt->buffer, hdr_len); + ll_hdr_len = (uint8_t *)mpdu.payload - net_pkt_data(pkt); + net_buf_pull(pkt->buffer, ll_hdr_len); #ifdef CONFIG_NET_6LO verdict = ieee802154_6lo_decode_pkt(iface, pkt); diff --git a/subsys/net/l2/ieee802154/ieee802154_6lo_fragment.c b/subsys/net/l2/ieee802154/ieee802154_6lo_fragment.c index 2d3fa7be230a..7ef408a2e478 100644 --- a/subsys/net/l2/ieee802154/ieee802154_6lo_fragment.c +++ b/subsys/net/l2/ieee802154/ieee802154_6lo_fragment.c @@ -359,18 +359,18 @@ static inline size_t fragment_cached_pkt_len(struct net_pkt *pkt) { size_t len = 0U; struct net_buf *frag; - int hdr_len; + int hdr_diff; uint8_t *data; frag = pkt->buffer; while (frag) { - uint16_t hdr_len = NET_6LO_FRAGN_HDR_LEN; + uint16_t frag_hdr_len = NET_6LO_FRAGN_HDR_LEN; if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) { - hdr_len = NET_6LO_FRAG1_HDR_LEN; + frag_hdr_len = NET_6LO_FRAG1_HDR_LEN; } - len += frag->len - hdr_len; + len += frag->len - frag_hdr_len; frag = frag->frags; } @@ -381,15 +381,15 @@ static inline size_t fragment_cached_pkt_len(struct net_pkt *pkt) data = pkt->buffer->data; pkt->buffer->data += NET_6LO_FRAG1_HDR_LEN; - hdr_len = net_6lo_uncompress_hdr_diff(pkt); + hdr_diff = net_6lo_uncompress_hdr_diff(pkt); pkt->buffer->data = data; - if (hdr_len == INT_MAX) { + if (hdr_diff == INT_MAX) { return 0; } - return len + hdr_len; + return len + hdr_diff; } static inline uint16_t fragment_offset(struct net_buf *frag) @@ -429,14 +429,14 @@ static inline void fragment_remove_headers(struct net_pkt *pkt) frag = pkt->buffer; while (frag) { - uint16_t hdr_len = NET_6LO_FRAGN_HDR_LEN; + uint16_t frag_hdr_len = NET_6LO_FRAGN_HDR_LEN; if (get_datagram_type(frag->data) == NET_6LO_DISPATCH_FRAG1) { - hdr_len = NET_6LO_FRAG1_HDR_LEN; + frag_hdr_len = NET_6LO_FRAG1_HDR_LEN; } - memmove(frag->data, frag->data + hdr_len, frag->len - hdr_len); - frag->len -= hdr_len; + memmove(frag->data, frag->data + frag_hdr_len, frag->len - frag_hdr_len); + frag->len -= frag_hdr_len; frag = frag->frags; } diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 081c0d5a24f3..20f84953a594 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -665,7 +665,7 @@ static uint8_t *generate_aux_security_hdr(struct ieee802154_security_ctx *sec_ct #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */ bool ieee802154_create_data_frame(struct ieee802154_context *ctx, struct net_linkaddr *dst, - struct net_linkaddr *src, struct net_buf *buf, uint8_t hdr_len) + struct net_linkaddr *src, struct net_buf *buf, uint8_t ll_hdr_len) { struct ieee802154_frame_params params = {0}; struct ieee802154_fcf_seq *fs; @@ -732,19 +732,19 @@ bool ieee802154_create_data_frame(struct ieee802154_context *ctx, struct net_lin } uint8_t authtag_len = level_2_authtag_len[level]; - uint8_t payload_len = buf->len - hdr_len - authtag_len; + uint8_t payload_len = buf->len - ll_hdr_len - authtag_len; /* Let's encrypt/auth only in the end, if needed */ - if (!ieee802154_encrypt_auth(&ctx->sec_ctx, buf_start, hdr_len, + if (!ieee802154_encrypt_auth(&ctx->sec_ctx, buf_start, ll_hdr_len, payload_len, authtag_len, ctx->ext_addr)) { goto out; }; no_security_hdr: #endif /* CONFIG_NET_L2_IEEE802154_SECURITY */ - if ((p_buf - buf_start) != hdr_len) { - /* hdr_len was too small? We probably overwrote payload bytes */ - NET_ERR("Could not generate data frame %zu vs %u", (p_buf - buf_start), hdr_len); + if ((p_buf - buf_start) != ll_hdr_len) { + /* ll_hdr_len was too small? We probably overwrote payload bytes */ + NET_ERR("Could not generate data frame %zu vs %u", (p_buf - buf_start), ll_hdr_len); goto out; } @@ -955,8 +955,8 @@ bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt, } uint8_t authtag_len = level_2_authtag_len[level]; - uint8_t hdr_len = (uint8_t *)mpdu->payload - net_pkt_data(pkt); - uint8_t payload_len = net_pkt_get_len(pkt) - hdr_len - authtag_len; + uint8_t ll_hdr_len = (uint8_t *)mpdu->payload - net_pkt_data(pkt); + uint8_t payload_len = net_pkt_get_len(pkt) - ll_hdr_len - authtag_len; uint8_t ext_addr_le[IEEE802154_EXT_ADDR_LENGTH]; /* TODO: Handle src short address. @@ -969,7 +969,7 @@ bool ieee802154_decipher_data_frame(struct net_if *iface, struct net_pkt *pkt, } sys_memcpy_swap(ext_addr_le, net_pkt_lladdr_src(pkt)->addr, net_pkt_lladdr_src(pkt)->len); - if (!ieee802154_decrypt_auth(&ctx->sec_ctx, net_pkt_data(pkt), hdr_len, payload_len, + if (!ieee802154_decrypt_auth(&ctx->sec_ctx, net_pkt_data(pkt), ll_hdr_len, payload_len, authtag_len, ext_addr_le, sys_le32_to_cpu(mpdu->mhr.aux_sec->frame_counter))) { NET_ERR("Could not decipher the frame"); diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.h b/subsys/net/l2/ieee802154/ieee802154_frame.h index b69fa60ec78a..c76d8df464a3 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.h +++ b/subsys/net/l2/ieee802154/ieee802154_frame.h @@ -478,7 +478,8 @@ void ieee802154_compute_header_and_authtag_len(struct net_if *iface, struct net_ uint8_t *authtag_len); bool ieee802154_create_data_frame(struct ieee802154_context *ctx, struct net_linkaddr *dst, - struct net_linkaddr *src, struct net_buf *buf, uint8_t hdr_len); + struct net_linkaddr *src, struct net_buf *buf, + uint8_t ll_hdr_len); struct net_pkt *ieee802154_create_mac_cmd_frame(struct net_if *iface, enum ieee802154_cfi type, struct ieee802154_frame_params *params); diff --git a/subsys/net/l2/ieee802154/ieee802154_security.c b/subsys/net/l2/ieee802154/ieee802154_security.c index 15add0a1591d..4f909e2121b2 100644 --- a/subsys/net/l2/ieee802154/ieee802154_security.c +++ b/subsys/net/l2/ieee802154/ieee802154_security.c @@ -99,7 +99,7 @@ void ieee802154_security_teardown_session(struct ieee802154_security_ctx *sec_ct sec_ctx->level = IEEE802154_SECURITY_LEVEL_NONE; } -static void prepare_cipher_aead_pkt(uint8_t *frame, uint8_t level, uint8_t hdr_len, +static void prepare_cipher_aead_pkt(uint8_t *frame, uint8_t level, uint8_t ll_hdr_len, uint8_t payload_len, uint8_t authtag_len, struct cipher_aead_pkt *apkt, struct cipher_pkt *pkt) { @@ -112,11 +112,11 @@ static void prepare_cipher_aead_pkt(uint8_t *frame, uint8_t level, uint8_t hdr_l is_authenticated = level != IEEE802154_SECURITY_LEVEL_NONE; /* See section 9.3.5.3 */ - pkt->in_buf = is_encrypted && payload_len ? frame + hdr_len : NULL; + pkt->in_buf = is_encrypted && payload_len ? frame + ll_hdr_len : NULL; pkt->in_len = is_encrypted ? payload_len : 0; /* See section 9.3.5.4 */ - uint8_t out_buf_offset = is_encrypted ? hdr_len : hdr_len + payload_len; + uint8_t out_buf_offset = is_encrypted ? ll_hdr_len : ll_hdr_len + payload_len; uint8_t auth_len = is_authenticated ? out_buf_offset : 0; pkt->out_buf = frame + out_buf_offset; @@ -124,12 +124,12 @@ static void prepare_cipher_aead_pkt(uint8_t *frame, uint8_t level, uint8_t hdr_l apkt->ad = is_authenticated ? frame : NULL; apkt->ad_len = auth_len; - apkt->tag = is_authenticated ? frame + hdr_len + payload_len : NULL; + apkt->tag = is_authenticated ? frame + ll_hdr_len + payload_len : NULL; apkt->pkt = pkt; } bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *frame, - uint8_t hdr_len, uint8_t payload_len, uint8_t authtag_len, + uint8_t ll_hdr_len, uint8_t payload_len, uint8_t authtag_len, uint8_t *src_ext_addr, uint32_t frame_counter) { struct cipher_aead_pkt apkt; @@ -149,11 +149,11 @@ bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *f sys_put_be32(frame_counter, &nonce[8]); nonce[12] = level; - prepare_cipher_aead_pkt(frame, level, hdr_len, payload_len, authtag_len, &apkt, &pkt); + prepare_cipher_aead_pkt(frame, level, ll_hdr_len, payload_len, authtag_len, &apkt, &pkt); ret = cipher_ccm_op(&sec_ctx->dec, &apkt, nonce); if (ret) { - NET_ERR("Cannot decrypt/auth (%i): %p %u/%u - fc %u", ret, frame, hdr_len, + NET_ERR("Cannot decrypt/auth (%i): %p %u/%u - fc %u", ret, frame, ll_hdr_len, payload_len, frame_counter); return false; } @@ -162,7 +162,7 @@ bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *f } bool ieee802154_encrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *frame, - uint8_t hdr_len, uint8_t payload_len, uint8_t authtag_len, + uint8_t ll_hdr_len, uint8_t payload_len, uint8_t authtag_len, uint8_t *src_ext_addr) { struct cipher_aead_pkt apkt; @@ -192,11 +192,11 @@ bool ieee802154_encrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *f sys_put_be32(sec_ctx->frame_counter, &nonce[8]); nonce[12] = level; - prepare_cipher_aead_pkt(frame, level, hdr_len, payload_len, authtag_len, &apkt, &pkt); + prepare_cipher_aead_pkt(frame, level, ll_hdr_len, payload_len, authtag_len, &apkt, &pkt); ret = cipher_ccm_op(&sec_ctx->enc, &apkt, nonce); if (ret) { - NET_ERR("Cannot encrypt/auth (%i): %p %u/%u - fc %u", ret, frame, hdr_len, + NET_ERR("Cannot encrypt/auth (%i): %p %u/%u - fc %u", ret, frame, ll_hdr_len, payload_len, sec_ctx->frame_counter); return false; } diff --git a/subsys/net/l2/ieee802154/ieee802154_security.h b/subsys/net/l2/ieee802154/ieee802154_security.h index 0e458b9ee202..139ea08ba766 100644 --- a/subsys/net/l2/ieee802154/ieee802154_security.h +++ b/subsys/net/l2/ieee802154/ieee802154_security.h @@ -25,7 +25,7 @@ void ieee802154_security_teardown_session(struct ieee802154_security_ctx *sec_ct * * @param sec_ctx Pointer to an IEEE 802.15.4 security context. * @param frame Pointer to the frame data in original (little endian) byte order. - * @param hdr_len Length of the MHR. + * @param ll_hdr_len Length of the MHR. * @param payload_len Length of the MAC payload. * @param authtag_len Length of the authentication tag. * @param src_ext_addr Pointer to the extended source address of the frame (in little endian byte @@ -33,7 +33,7 @@ void ieee802154_security_teardown_session(struct ieee802154_security_ctx *sec_ct * @param frame_counter Frame counter in CPU byte order. */ bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *frame, - uint8_t hdr_len, uint8_t payload_len, uint8_t authtag_len, + uint8_t ll_hdr_len, uint8_t payload_len, uint8_t authtag_len, uint8_t *src_ext_addr, uint32_t frame_counter); /** @@ -41,14 +41,14 @@ bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *f * * @param sec_ctx Pointer to an IEEE 802.15.4 security context. * @param frame Pointer to the frame data in original (little endian) byte order. - * @param hdr_len Length of the MHR. + * @param ll_hdr_len Length of the MHR. * @param payload_len Length of the MAC payload. * @param authtag_len Length of the authentication tag. * @param src_ext_addr Pointer to the extended source address of the frame (in little endian byte * order). */ bool ieee802154_encrypt_auth(struct ieee802154_security_ctx *sec_ctx, uint8_t *frame, - uint8_t hdr_len, uint8_t payload_len, + uint8_t ll_hdr_len, uint8_t payload_len, uint8_t authtag_len, uint8_t *src_ext_addr); int ieee802154_security_init(struct ieee802154_security_ctx *sec_ctx); From 06df0d4a7db82a5168582ddf1aab0da3cb7015fb Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:08 +0200 Subject: [PATCH 0807/2042] net: l2: ieee802154: readability: af -> address_field The 'af' abbreviation is nowhere standardized in IEEE 802.15.4 and makes the source code unnecessarily hard to read. It is replaced by a readable long name. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 20f84953a594..7556d151a01f 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -592,20 +592,21 @@ static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx, struct ieee802154_fcf_seq *fs, struct ieee802154_frame_params *params, uint8_t *p_buf) { - struct ieee802154_address_field *af; + struct ieee802154_address_field *address_field; /* destination address */ if (fs->fc.dst_addr_mode != IEEE802154_ADDR_MODE_NONE) { - af = (struct ieee802154_address_field *)p_buf; + address_field = (struct ieee802154_address_field *)p_buf; - af->plain.pan_id = params->dst.pan_id; + address_field->plain.pan_id = params->dst.pan_id; p_buf += IEEE802154_PAN_ID_LENGTH; if (fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_SHORT) { - af->plain.addr.short_addr = sys_cpu_to_le16(params->dst.short_addr); + address_field->plain.addr.short_addr = + sys_cpu_to_le16(params->dst.short_addr); p_buf += IEEE802154_SHORT_ADDR_LENGTH; } else { - sys_memcpy_swap(af->plain.addr.ext_addr, params->dst.ext_addr, + sys_memcpy_swap(address_field->plain.addr.ext_addr, params->dst.ext_addr, IEEE802154_EXT_ADDR_LENGTH); p_buf += IEEE802154_EXT_ADDR_LENGTH; } @@ -616,14 +617,14 @@ static uint8_t *generate_addressing_fields(struct ieee802154_context *ctx, return p_buf; } - af = (struct ieee802154_address_field *)p_buf; + address_field = (struct ieee802154_address_field *)p_buf; struct ieee802154_address *src_addr; if (fs->fc.pan_id_comp) { - src_addr = &af->comp.addr; + src_addr = &address_field->comp.addr; } else { - af->plain.pan_id = params->pan_id; - src_addr = &af->plain.addr; + address_field->plain.pan_id = params->pan_id; + src_addr = &address_field->plain.addr; p_buf += IEEE802154_PAN_ID_LENGTH; } From 805ca4dde66c5214da7c9e8010653624613af49a Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:08 +0200 Subject: [PATCH 0808/2042] net: l2: ieee802154: readability: ar -> ack_requested The 'ar' abbreviation has a well defined meaning in IEEE 802.15.4 which is NOT the meaning of the local "ar" variable being renamed in this change (see the comparison to the actual MHR ar field in this change set). To avoid confusion, a non-abbreviated variable name is introduced instead. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.c | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index 7556d151a01f..ad4f1fb2275d 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -234,12 +234,12 @@ static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, u return true; } -static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, uint8_t ar, - bool has_pan_id, uint8_t src_bf, - bool src_pan_brdcst_chk, uint8_t dst_bf, - bool dst_brdcst_chk) +static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, + bool ack_requested, bool has_pan_id, + uint8_t src_bf, bool src_pan_brdcst_chk, + uint8_t dst_bf, bool dst_brdcst_chk) { - if (mhr->fs->fc.ar != ar || mhr->fs->fc.pan_id_comp == has_pan_id) { + if (mhr->fs->fc.ar != ack_requested || mhr->fs->fc.pan_id_comp == has_pan_id) { return false; } @@ -270,8 +270,8 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b uint8_t len = IEEE802154_CMD_CFI_LENGTH; bool src_pan_brdcst_chk = false; bool dst_brdcst_chk = false; + bool ack_requested = false; bool has_pan_id = true; - uint8_t ar = 0U; uint8_t src_bf, dst_bf; if (length < len) { @@ -282,8 +282,8 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b case IEEE802154_CFI_UNKNOWN: return false; case IEEE802154_CFI_ASSOCIATION_REQUEST: - ar = 1U; len += IEEE802154_CMD_ASSOC_REQ_LENGTH; + ack_requested = true; src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); src_pan_brdcst_chk = true; dst_bf = BIT(IEEE802154_ADDR_MODE_SHORT) | BIT(IEEE802154_ADDR_MODE_EXTENDED); @@ -298,14 +298,14 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b } __fallthrough; case IEEE802154_CFI_PAN_ID_CONFLICT_NOTIFICATION: - ar = 1U; + ack_requested = true; has_pan_id = false; src_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); dst_bf = BIT(IEEE802154_ADDR_MODE_EXTENDED); break; case IEEE802154_CFI_DATA_REQUEST: - ar = 1U; + ack_requested = true; src_bf = BIT(IEEE802154_ADDR_MODE_SHORT) | BIT(IEEE802154_ADDR_MODE_EXTENDED); if (mpdu->mhr.fs->fc.dst_addr_mode == IEEE802154_ADDR_MODE_NONE) { @@ -343,7 +343,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b break; case IEEE802154_CFI_GTS_REQUEST: len += IEEE802154_GTS_REQUEST_LENGTH; - ar = 1U; + ack_requested = true; src_bf = BIT(IEEE802154_ADDR_MODE_SHORT); dst_bf = BIT(IEEE802154_ADDR_MODE_NONE); @@ -356,7 +356,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b return false; } - if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ar, has_pan_id, src_bf, + if (!validate_mac_command_cfi_to_mhr(&mpdu->mhr, ack_requested, has_pan_id, src_bf, src_pan_brdcst_chk, dst_bf, dst_brdcst_chk)) { return false; @@ -511,7 +511,7 @@ void ieee802154_compute_header_and_authtag_len(struct net_if *iface, struct net_ *authtag_len = tag_len; } -static inline struct ieee802154_fcf_seq *generate_fcf_grounds(uint8_t **p_buf, bool ack) +static inline struct ieee802154_fcf_seq *generate_fcf_grounds(uint8_t **p_buf, bool ack_requested) { struct ieee802154_fcf_seq *fs; @@ -519,7 +519,7 @@ static inline struct ieee802154_fcf_seq *generate_fcf_grounds(uint8_t **p_buf, b fs->fc.security_enabled = 0U; fs->fc.frame_pending = 0U; - fs->fc.ar = ack; + fs->fc.ar = ack_requested; fs->fc.pan_id_comp = 0U; fs->fc.reserved = 0U; /* We support version 2006 only for now */ @@ -804,7 +804,7 @@ static inline bool cfi_to_fs_settings(enum ieee802154_cfi cfi, struct ieee802154 break; case IEEE802154_CFI_COORDINATOR_REALIGNEMENT: fs->fc.src_addr_mode = IEEE802154_ADDR_MODE_EXTENDED; - /* TODO: ar and dst addr mode: see section 7.5.10 */ + /* TODO: ack_requested and dst addr mode: see section 7.5.10 */ break; case IEEE802154_CFI_GTS_REQUEST: From 0d5eba7900c8f34ee91dbb52effbb5cd4a5312c3 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:09 +0200 Subject: [PATCH 0809/2042] net: l2: ieee802154: readability: f_ctx -> frag_ctx The f_ctx variable renamed in this change has a considerable variable span. This makes the code hard to read as the variable name is neither defined in the IEEE 802.15.4 standard nor can it be deduced from the variable name. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154.c | 6 +++--- subsys/net/l2/ieee802154/ieee802154_6lo.c | 4 ++-- subsys/net/l2/ieee802154/ieee802154_6lo.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154.c b/subsys/net/l2/ieee802154/ieee802154.c index 2d005c0ac092..8f06912b1b85 100644 --- a/subsys/net/l2/ieee802154/ieee802154.c +++ b/subsys/net/l2/ieee802154/ieee802154.c @@ -472,7 +472,7 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) bool send_raw = false; int len; #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT - struct ieee802154_6lo_fragment_ctx f_ctx; + struct ieee802154_6lo_fragment_ctx frag_ctx; int requires_fragmentation = 0; #endif @@ -515,7 +515,7 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) #ifdef CONFIG_NET_6LO #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT requires_fragmentation = - ieee802154_6lo_encode_pkt(iface, pkt, &f_ctx, ll_hdr_len, authtag_len); + ieee802154_6lo_encode_pkt(iface, pkt, &frag_ctx, ll_hdr_len, authtag_len); if (requires_fragmentation < 0) { return requires_fragmentation; } @@ -538,7 +538,7 @@ static int ieee802154_send(struct net_if *iface, struct net_pkt *pkt) #ifdef CONFIG_NET_L2_IEEE802154_FRAGMENT if (requires_fragmentation) { - pkt_buf = ieee802154_6lo_fragment(&f_ctx, frame_buf, true); + pkt_buf = ieee802154_6lo_fragment(&frag_ctx, frame_buf, true); } else { net_buf_add_mem(frame_buf, pkt_buf->data, pkt_buf->len); pkt_buf = pkt_buf->frags; diff --git a/subsys/net/l2/ieee802154/ieee802154_6lo.c b/subsys/net/l2/ieee802154/ieee802154_6lo.c index 78aa0ddcee61..dbbc7a06a206 100644 --- a/subsys/net/l2/ieee802154/ieee802154_6lo.c +++ b/subsys/net/l2/ieee802154/ieee802154_6lo.c @@ -36,7 +36,7 @@ enum net_verdict ieee802154_6lo_decode_pkt(struct net_if *iface, struct net_pkt } int ieee802154_6lo_encode_pkt(struct net_if *iface, struct net_pkt *pkt, - struct ieee802154_6lo_fragment_ctx *f_ctx, uint8_t ll_hdr_len, + struct ieee802154_6lo_fragment_ctx *frag_ctx, uint8_t ll_hdr_len, uint8_t authtag_len) { if (net_pkt_family(pkt) != AF_INET6) { @@ -55,7 +55,7 @@ int ieee802154_6lo_encode_pkt(struct net_if *iface, struct net_pkt *pkt, ieee802154_6lo_requires_fragmentation(pkt, ll_hdr_len, authtag_len); if (requires_fragmentation) { - ieee802154_6lo_fragment_ctx_init(f_ctx, pkt, hdr_diff, true); + ieee802154_6lo_fragment_ctx_init(frag_ctx, pkt, hdr_diff, true); } return requires_fragmentation ? 1 : 0; #else diff --git a/subsys/net/l2/ieee802154/ieee802154_6lo.h b/subsys/net/l2/ieee802154/ieee802154_6lo.h index 65d36e13ca35..48937153d7c3 100644 --- a/subsys/net/l2/ieee802154/ieee802154_6lo.h +++ b/subsys/net/l2/ieee802154/ieee802154_6lo.h @@ -51,7 +51,7 @@ enum net_verdict ieee802154_6lo_decode_pkt(struct net_if *iface, struct net_pkt * @param iface A valid pointer on the network interface the package is * sent to * @param pkt A valid pointer on a non-compressed IPv6 packet - * @param f_ctx A valid pointer on a fragmentation context. + * @param frag_ctx A valid pointer on a fragmentation context. * @param ll_hdr_len required headroom for the LL header (after fragmentation) * @param authtag_len required tailroom for the authentication tag in the frame (after * fragmentation) @@ -60,7 +60,7 @@ enum net_verdict ieee802154_6lo_decode_pkt(struct net_if *iface, struct net_pkt * fragmentation is needed, negative value on error */ int ieee802154_6lo_encode_pkt(struct net_if *iface, struct net_pkt *pkt, - struct ieee802154_6lo_fragment_ctx *f_ctx, uint8_t ll_hdr_len, + struct ieee802154_6lo_fragment_ctx *frag_ctx, uint8_t ll_hdr_len, uint8_t authtag_len); #endif /* __NET_IEEE802154_6LO_H__ */ From 0341d67625578582f60284017096e09f0f035d9e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 19 May 2023 14:27:09 +0200 Subject: [PATCH 0810/2042] net: l2: ieee802154: readability: one-letter names This change replaces one letter variable names with considerable variable spans by much more readable alternatives that ease code maintenance and help human reviewers to catch semantic errors. Signed-off-by: Florian Grandel --- subsys/net/l2/ieee802154/ieee802154_frame.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/subsys/net/l2/ieee802154/ieee802154_frame.c b/subsys/net/l2/ieee802154/ieee802154_frame.c index ad4f1fb2275d..30db890b96d0 100644 --- a/subsys/net/l2/ieee802154/ieee802154_frame.c +++ b/subsys/net/l2/ieee802154/ieee802154_frame.c @@ -196,7 +196,7 @@ ieee802154_validate_aux_security_hdr(uint8_t *buf, uint8_t **p_buf, uint8_t *len static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, uint8_t length) { - struct ieee802154_beacon *b = (struct ieee802154_beacon *)buf; + struct ieee802154_beacon *beacon = (struct ieee802154_beacon *)buf; struct ieee802154_pas_spec *pas; uint8_t len = IEEE802154_BEACON_SF_SIZE + IEEE802154_BEACON_GTS_SPEC_SIZE; @@ -204,9 +204,9 @@ static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, u return false; } - if (b->gts.desc_count) { + if (beacon->gts.desc_count) { len += IEEE802154_BEACON_GTS_DIR_SIZE + - b->gts.desc_count * IEEE802154_BEACON_GTS_SIZE; + beacon->gts.desc_count * IEEE802154_BEACON_GTS_SIZE; } if (length < len) { @@ -229,7 +229,7 @@ static inline bool validate_beacon(struct ieee802154_mpdu *mpdu, uint8_t *buf, u return false; } - mpdu->beacon = b; + mpdu->beacon = beacon; return true; } @@ -266,7 +266,7 @@ static inline bool validate_mac_command_cfi_to_mhr(struct ieee802154_mhr *mhr, static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *buf, uint8_t length) { - struct ieee802154_command *c = (struct ieee802154_command *)buf; + struct ieee802154_command *command = (struct ieee802154_command *)buf; uint8_t len = IEEE802154_CMD_CFI_LENGTH; bool src_pan_brdcst_chk = false; bool dst_brdcst_chk = false; @@ -278,7 +278,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b return false; } - switch (c->cfi) { + switch (command->cfi) { case IEEE802154_CFI_UNKNOWN: return false; case IEEE802154_CFI_ASSOCIATION_REQUEST: @@ -293,7 +293,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b len += IEEE802154_CMD_ASSOC_RES_LENGTH; __fallthrough; case IEEE802154_CFI_DISASSOCIATION_NOTIFICATION: - if (c->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) { + if (command->cfi == IEEE802154_CFI_DISASSOCIATION_NOTIFICATION) { len += IEEE802154_CMD_DISASSOC_NOTE_LENGTH; } __fallthrough; @@ -362,7 +362,7 @@ static inline bool validate_mac_command(struct ieee802154_mpdu *mpdu, uint8_t *b return false; } - mpdu->command = c; + mpdu->command = command; return true; } From 433767543688d2122a5e4acffee53fa1cfc213d9 Mon Sep 17 00:00:00 2001 From: Mateusz Kusiak Date: Thu, 22 Jun 2023 13:32:03 +0200 Subject: [PATCH 0811/2042] Bluetooth: Controller: Ignore ticker_stop() return value Cast ticker_stop() calls to void where return value is not checked. This is to satisfy coverity and indicate that return value is not important. Signed-off-by: Mateusz Kusiak --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c | 2 +- subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_central.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_peripheral.c | 2 +- 4 files changed, 4 insertions(+), 4 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 251b0c3a2a7a..1e5a79871e8f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -1031,7 +1031,7 @@ static void isr_done_cleanup(void *param) * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, TICKER_ID_SCAN_STOP, NULL, NULL); #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index 2f0acebd7030..e6ebe4d7494f 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -579,7 +579,7 @@ static void isr_abort(void *param) * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, TICKER_ID_SCAN_STOP, NULL, NULL); /* Under race conditions, radio could get started while entering ISR */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index 451d38a8ea6d..3e805a5295e2 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -859,7 +859,7 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, TICKER_ID_SCAN_STOP, NULL, NULL); /* Start central */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index c06d9367a2dc..c860f6ce4544 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -441,7 +441,7 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * Deferred attempt to stop can fail as it would have * expired, hence ignore failure. */ - ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, + (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, TICKER_ID_ADV_STOP, NULL, NULL); } From 9e0e2be7651cbabc142e6e9e706c91f638defc75 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 3 Jul 2023 16:39:18 +0200 Subject: [PATCH 0812/2042] Bluetooth: controller: Fix indent in calls to ticker_stop() Follow-up from #59602. Signed-off-by: Carles Cufi --- subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c | 2 +- subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_central.c | 2 +- subsys/bluetooth/controller/ll_sw/ull_peripheral.c | 2 +- 4 files changed, 4 insertions(+), 4 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 1e5a79871e8f..724b878ace39 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -1032,7 +1032,7 @@ static void isr_done_cleanup(void *param) * expired, hence ignore failure. */ (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, NULL, NULL); + TICKER_ID_SCAN_STOP, NULL, NULL); #if defined(CONFIG_BT_CTLR_SCAN_INDICATION) struct node_rx_hdr *node_rx; diff --git a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c index e6ebe4d7494f..ddb74fef6526 100644 --- a/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/openisa/lll/lll_scan.c @@ -580,7 +580,7 @@ static void isr_abort(void *param) * expired, hence ignore failure. */ (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_LLL, - TICKER_ID_SCAN_STOP, NULL, NULL); + TICKER_ID_SCAN_STOP, NULL, NULL); /* Under race conditions, radio could get started while entering ISR */ radio_disable(); diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index 3e805a5295e2..5effe2ae6769 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -860,7 +860,7 @@ void ull_central_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * expired, hence ignore failure. */ (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, - TICKER_ID_SCAN_STOP, NULL, NULL); + TICKER_ID_SCAN_STOP, NULL, NULL); /* Start central */ ticker_id_conn = TICKER_ID_CONN_BASE + ll_conn_handle_get(conn); diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index c860f6ce4544..f1716c065736 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -442,7 +442,7 @@ void ull_periph_setup(struct node_rx_hdr *rx, struct node_rx_ftr *ftr, * expired, hence ignore failure. */ (void)ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH, - TICKER_ID_ADV_STOP, NULL, NULL); + TICKER_ID_ADV_STOP, NULL, NULL); } /* Start Peripheral */ From 95c2dfce94fd38cbc5114f44cf5d3d5d1fc30825 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Fri, 19 May 2023 12:34:23 +0530 Subject: [PATCH 0813/2042] board: MIMXRT1062-FMURT6: Add pinmux support for uart ports used for gps and telemtry. This patch configures the correct pinmux settings for lpuart2, lpuart3, lpuart5 ports used for gps and telemetry modules. It also adds software pull up for the UART console port lpuart7. Signed-off-by: Sumit Batra Co-authored-by: Benjamin Perseghetti Co-authored-by: Iain Galloway --- .../mimxrt1062_fmurt6-pinctrl.dtsi | 72 ++++++++++++++++--- .../mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts | 27 +++++++ 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi index 83899828bdf1..587c66ac2878 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi @@ -313,6 +313,8 @@ pinmux = <&iomuxc_gpio_emc_32_lpuart7_rx>, <&iomuxc_gpio_emc_31_lpuart7_tx>; drive-strength = "r0-6"; + bias-pull-up; + bias-pull-up-value = "100k"; slew-rate = "slow"; nxp,speed = "100-mhz"; }; @@ -330,10 +332,37 @@ }; }; + pinmux_lpuart2: pinmux_lpuart2 { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_lpuart2_tx>, + <&iomuxc_gpio_ad_b1_03_lpuart2_rx>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_lpuart2_sleep: pinmux_lpuart2_sleep { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_03_lpuart2_rx>; + drive-strength = "r0"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_b1_02_lpuart2_tx>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + pinmux_lpuart3: pinmux_lpuart3 { group0 { - pinmux = <&iomuxc_gpio_ad_b1_06_lpuart3_tx>, - <&iomuxc_gpio_ad_b1_07_lpuart3_rx>; + pinmux = <&iomuxc_gpio_b0_08_lpuart3_tx>, + <&iomuxc_gpio_b0_09_lpuart3_rx>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; @@ -343,10 +372,10 @@ /* Flow control for lpuart3 */ pinmux_lpuart3_flow_control: pinmux_lpuart3_flow_control { group0 { - pinmux = <&iomuxc_gpio_ad_b1_06_lpuart3_tx>, - <&iomuxc_gpio_ad_b1_07_lpuart3_rx>, - <&iomuxc_gpio_ad_b1_04_lpuart3_cts_b>, - <&iomuxc_gpio_ad_b1_05_lpuart3_rts_b>; + pinmux = <&iomuxc_gpio_b0_08_lpuart3_tx>, + <&iomuxc_gpio_b0_09_lpuart3_rx>, + <&iomuxc_gpio_sd_b1_04_gpio3_io04>, + <&iomuxc_gpio_emc_24_gpio4_io24>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; @@ -355,7 +384,34 @@ pinmux_lpuart3_sleep: pinmux_lpuart3_sleep { group0 { - pinmux = <&iomuxc_gpio_ad_b1_06_gpio1_io22>; + pinmux = <&iomuxc_gpio_b0_09_lpuart3_rx>; + drive-strength = "r0"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + group1 { + pinmux = <&iomuxc_gpio_b0_08_lpuart3_tx>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_lpuart5: pinmux_lpuart5 { + group0 { + pinmux = <&iomuxc_gpio_emc_23_lpuart5_tx>, + <&iomuxc_gpio_b1_13_lpuart5_rx>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_lpuart5_sleep: pinmux_lpuart5_sleep { + group0 { + pinmux = <&iomuxc_gpio_b1_13_lpuart5_rx>; drive-strength = "r0"; bias-pull-up; bias-pull-up-value = "100k"; @@ -363,7 +419,7 @@ nxp,speed = "100-mhz"; }; group1 { - pinmux = <&iomuxc_gpio_ad_b1_07_lpuart3_rx>; + pinmux = <&iomuxc_gpio_emc_23_lpuart5_tx>; drive-strength = "r0-6"; slew-rate = "slow"; nxp,speed = "100-mhz"; diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index ceebc7e2e499..37bc9c8c127d 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -21,6 +21,9 @@ watchdog0 = &wdog0; sdhc0 = &usdhc1; pwm-0 = &flexpwm2_pwm0; + gps1 = &lpuart2; + telem1 = &lpuart3; + telem4-gps2 = &lpuart5; }; chosen { @@ -284,6 +287,30 @@ pinctrl-names = "default", "sleep"; }; +&lpuart2 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart2>; + pinctrl-1 = <&pinmux_lpuart2_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&lpuart3 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart3>; + pinctrl-1 = <&pinmux_lpuart3_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&lpuart5 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&pinmux_lpuart5>; + pinctrl-1 = <&pinmux_lpuart5_sleep>; + pinctrl-names = "default", "sleep"; +}; + &lpspi1 { status = "okay"; pinctrl-0 = <&pinmux_lpspi1>; From c10b4ef3011c0b50b20de437f4013dd651c9310d Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Fri, 19 May 2023 12:47:28 +0530 Subject: [PATCH 0814/2042] board: MIMXRT1062-FMURT6: Removing the CONFIG_DISPLAY check in CMakeLists This patch removes an unncessary message for presence or absence of DISPLAY Signed-off-by: Sumit Batra --- boards/arm/mimxrt1062_fmurt6/CMakeLists.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/boards/arm/mimxrt1062_fmurt6/CMakeLists.txt b/boards/arm/mimxrt1062_fmurt6/CMakeLists.txt index 7132083c109a..29f92cc83c6e 100644 --- a/boards/arm/mimxrt1062_fmurt6/CMakeLists.txt +++ b/boards/arm/mimxrt1062_fmurt6/CMakeLists.txt @@ -4,12 +4,6 @@ # Copyright 2023 NXP # -if (CONFIG_DISPLAY) -message(WARNING " -CONFIG_DISPLAY: Running this firmware on a board without a display may damage the board -") -endif() - if(CONFIG_NXP_IMX_RT_BOOT_HEADER) zephyr_library() if(CONFIG_BOARD_MIMXRT1062_FMURT6) From 0ae7010946f22755ddee7b4d92bdb6deb460a6e9 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Sun, 4 Jun 2023 23:56:09 +0530 Subject: [PATCH 0815/2042] soc: rt10xx: fix the sequence of Enet2 ref clk enablement This patch sets ENET2 ref clock to be generated by External OSC ENET2 ref clock direction as output ENET2 ref clk frequency to 50MHz Signed-off-by: Sumit Batra --- soc/arm/nxp_imx/rt/soc_rt10xx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 754534e67759..26d00952ffd1 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -66,7 +66,12 @@ const clock_enet_pll_config_t ethPllConfig = { #else .enableClkOutput25M = false, #endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) .loopDivider = 1, +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(enet2), okay) + .loopDivider1 = 1, +#endif }; #endif @@ -199,6 +204,13 @@ static ALWAYS_INLINE void clock_init(void) IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true); #endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(enet2), okay) && CONFIG_NET_L2_ETHERNET + /* Set ENET2 ref clock to be generated by External OSC,*/ + /* direction as output and frequency to 50MHz */ + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET2TxClkOutputDir | + kIOMUXC_GPR_ENET2RefClkMode, true); +#endif + #if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency)); From 176d51555cdbe7da107d757cea9ed8d80e220512 Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Thu, 15 Jun 2023 15:21:57 +0530 Subject: [PATCH 0816/2042] soc: nxp_rt10xx: add unique PWM names. Enable PWM to use unique device names. Signed-off-by: Benjamin Perseghetti --- dts/arm/nxp/nxp_rt10xx.dtsi | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index ca642495df8a..57c4c3c982cc 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -564,7 +564,7 @@ reg = <0x403dc000 0x4000>; interrupts = <106 0>; - flexpwm1_pwm0: pwm0 { + flexpwm1_pwm0: flexpwm1_pwm0 { compatible = "nxp,imx-pwm"; index = <0>; interrupts = <102 0>; @@ -574,7 +574,7 @@ status = "disabled"; }; - flexpwm1_pwm1: pwm1 { + flexpwm1_pwm1: flexpwm1_pwm1 { compatible = "nxp,imx-pwm"; index = <1>; interrupts = <103 0>; @@ -584,7 +584,7 @@ status = "disabled"; }; - flexpwm1_pwm2: pwm2 { + flexpwm1_pwm2: flexpwm1_pwm2 { compatible = "nxp,imx-pwm"; index = <2>; interrupts = <104 0>; @@ -594,7 +594,7 @@ status = "disabled"; }; - flexpwm1_pwm3: pwm3 { + flexpwm1_pwm3: flexpwm1_pwm3 { compatible = "nxp,imx-pwm"; index = <3>; interrupts = <105 0>; @@ -610,7 +610,7 @@ reg = <0x403e0000 0x4000>; interrupts = <141 0>; - flexpwm2_pwm0: pwm0 { + flexpwm2_pwm0: flexpwm2_pwm0 { compatible = "nxp,imx-pwm"; index = <0>; interrupts = <137 0>; @@ -620,7 +620,7 @@ status = "disabled"; }; - flexpwm2_pwm1: pwm1 { + flexpwm2_pwm1: flexpwm2_pwm1 { compatible = "nxp,imx-pwm"; index = <1>; interrupts = <138 0>; @@ -630,7 +630,7 @@ status = "disabled"; }; - flexpwm2_pwm2: pwm2 { + flexpwm2_pwm2: flexpwm2_pwm2 { compatible = "nxp,imx-pwm"; index = <2>; interrupts = <139 0>; @@ -640,7 +640,7 @@ status = "disabled"; }; - flexpwm2_pwm3: pwm3 { + flexpwm2_pwm3: flexpwm2_pwm3 { compatible = "nxp,imx-pwm"; index = <3>; interrupts = <140 0>; @@ -656,7 +656,7 @@ reg = <0x403e4000 0x4000>; interrupts = <146 0>; - flexpwm3_pwm0: pwm0 { + flexpwm3_pwm0: flexpwm3_pwm0 { compatible = "nxp,imx-pwm"; index = <0>; interrupts = <142 0>; @@ -666,7 +666,7 @@ status = "disabled"; }; - flexpwm3_pwm1: pwm1 { + flexpwm3_pwm1: flexpwm3_pwm1 { compatible = "nxp,imx-pwm"; index = <1>; interrupts = <143 0>; @@ -676,7 +676,7 @@ status = "disabled"; }; - flexpwm3_pwm2: pwm2 { + flexpwm3_pwm2: flexpwm3_pwm2 { compatible = "nxp,imx-pwm"; index = <2>; interrupts = <144 0>; @@ -686,7 +686,7 @@ status = "disabled"; }; - flexpwm3_pwm3: pwm3 { + flexpwm3_pwm3: flexpwm3_pwm3 { compatible = "nxp,imx-pwm"; index = <3>; interrupts = <145 0>; @@ -702,7 +702,7 @@ reg = <0x403e8000 0x4000>; interrupts = <151 0>; - flexpwm4_pwm0: pwm0 { + flexpwm4_pwm0: flexpwm4_pwm0 { compatible = "nxp,imx-pwm"; index = <0>; interrupts = <147 0>; @@ -712,7 +712,7 @@ status = "disabled"; }; - flexpwm4_pwm1: pwm1 { + flexpwm4_pwm1: flexpwm4_pwm1 { compatible = "nxp,imx-pwm"; index = <1>; interrupts = <148 0>; @@ -722,7 +722,7 @@ status = "disabled"; }; - flexpwm4_pwm2: pwm2 { + flexpwm4_pwm2: flexpwm4_pwm2 { compatible = "nxp,imx-pwm"; index = <2>; interrupts = <149 0>; @@ -732,7 +732,7 @@ status = "disabled"; }; - flexpwm4_pwm3: pwm3 { + flexpwm4_pwm3: flexpwm4_pwm3 { compatible = "nxp,imx-pwm"; index = <3>; interrupts = <150 0>; From 5315a2e445fd00ed81104895d7e99da5f37eff9f Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Fri, 16 Jun 2023 13:18:20 +0530 Subject: [PATCH 0817/2042] board: MIMXRT1062-FMURT6: Add pinmux support for FMU PPM Input This commit adds the Pinmux and Pad settings for FMU PPM Input Pin Signed-off-by: Sumit Batra --- .../mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi index 587c66ac2878..a376006797dc 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi @@ -184,6 +184,18 @@ }; }; + pinmux_fmu_ppm_rc: pinmux_fmu_ppm_rc { + group0 { + pinmux = <&iomuxc_gpio_b1_06_gpt1_capture2>; + + drive-strength = "disabled"; + bias-pull-up; + bias-pull-up-value = "47k"; + slew-rate = "fast"; + input-enable; + }; + }; + pinmux_flexspi1: pinmux_flexspi1 { group0 { pinmux = <&iomuxc_gpio_sd_b1_05_flexspi_a_dqs>; From 64c4d4dd5dde8acbfc76c0032a4a452813267dc6 Mon Sep 17 00:00:00 2001 From: Sumit Batra Date: Fri, 16 Jun 2023 15:12:18 +0530 Subject: [PATCH 0818/2042] board: MIMXRT1062-FMURT6: Add pinmux support for I2C3 module Pins This patch adds the pinmux and pad settings for I2C3 SDA and SCL pins Signed-off-by: Sumit Batra --- .../mimxrt1062_fmurt6-pinctrl.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi index a376006797dc..9c22377dfe2e 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6-pinctrl.dtsi @@ -243,7 +243,19 @@ group0 { pinmux = <&iomuxc_gpio_b0_05_lpi2c2_sda>, <&iomuxc_gpio_b0_04_lpi2c2_scl>; - drive-strength = "r0-6"; + drive-strength = "r0-7"; + drive-open-drain; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + input-enable; + }; + }; + + pinmux_lpi2c3: pinmux_lpi2c3 { + group0 { + pinmux = <&iomuxc_gpio_emc_21_lpi2c3_sda>, + <&iomuxc_gpio_emc_22_lpi2c3_scl>; + drive-strength = "r0-7"; drive-open-drain; slew-rate = "slow"; nxp,speed = "100-mhz"; From 3529de3349c6f553bd49380bcf2d7a380aeec644 Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Tue, 27 Jun 2023 14:27:25 -0400 Subject: [PATCH 0819/2042] board: MIMXRT1062-FMURT6: correct PWM prescaler Set the PWM clock prescaler values to 64 for controlling standard servo 50Hz carrier frequency. Signed-off-by: Benjamin Perseghetti --- boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index 37bc9c8c127d..1cb246687c1b 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -20,7 +20,6 @@ led1 = &red_led; watchdog0 = &wdog0; sdhc0 = &usdhc1; - pwm-0 = &flexpwm2_pwm0; gps1 = &lpuart2; telem1 = &lpuart3; telem4-gps2 = &lpuart5; @@ -350,48 +349,56 @@ status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch1>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm2_pwm1 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch2>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm2_pwm2 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch3>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm2_pwm3 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch4>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm3_pwm2 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch5>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm3_pwm0 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch6>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm4_pwm2 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch7>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &flexpwm4_pwm0 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm_fmu_ch8>; pinctrl-names = "default"; + nxp,prescaler = <64>; }; &enet2 { From fe0efb4ea0a30e7e32a3589e297642a72aa9f8b0 Mon Sep 17 00:00:00 2001 From: Benjamin Perseghetti Date: Tue, 27 Jun 2023 14:33:06 -0400 Subject: [PATCH 0820/2042] board: MIMXRT1062-FMURT6: Set CANFD bus-speed-data Set the flexcan3 bus-speed-data to allow for correct CANFD data-speed. Signed-off-by: Benjamin Perseghetti --- boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index 1cb246687c1b..17caea7f2b1a 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -142,6 +142,7 @@ pinctrl-0 = <&pinmux_flexcan3>; pinctrl-names = "default"; bus-speed = <125000>; + bus-speed-data = <1000000>; can-transceiver { max-bitrate = <5000000>; }; From ff2d9cfcb615558db2251f669b014b40bc64879c Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Mon, 3 Jul 2023 15:17:53 +0200 Subject: [PATCH 0821/2042] scripts: compliance: Fix handling of integer node items Some node items in Kconfig can be kconfiglib.MENU or kconfiglib.COMMENT. Those are integers and thus do not contain a node.item.name field. Handle those separately to avoid hitting the followig exception: Traceback (most recent call last): File "/home/runner/work/zephyr/zephyr/./scripts/ci/check_compliance.py",\ line 1307, in main n_fails = _main(args) File "/home/runner/work/zephyr/zephyr/./scripts/ci/check_compliance.py",\ line 1242, in _main test.run() File "/home/runner/work/zephyr/zephyr/./scripts/ci/check_compliance.py",\ line 277, in run self.check_no_redefined_in_defconfig(kconf) File "/home/runner/work/zephyr/zephyr/./scripts/ci/check_compliance.py",\ line 445, in check_no_redefined_in_defconfig Kconfig node '{node.item.name}' found with prompt or help in\ {node.filename}. AttributeError: 'int' object has no attribute 'name' Seen in #58454. Signed-off-by: Carles Cufi --- scripts/ci/check_compliance.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 25d7f9df37ee..561874098109 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -440,9 +440,13 @@ def check_no_redefined_in_defconfig(self, kconf): # Checks that no symbols are (re)defined in defconfigs. for node in kconf.node_iter(): + # 'kconfiglib' is global + # pylint: disable=undefined-variable if "defconfig" in node.filename and (node.prompt or node.help): + name = (node.item.name if node.item not in + (kconfiglib.MENU, kconfiglib.COMMENT) else str(node)) self.failure(f""" -Kconfig node '{node.item.name}' found with prompt or help in {node.filename}. +Kconfig node '{name}' found with prompt or help in {node.filename}. Options must not be defined in defconfig files. """) continue From 28b6c36fc531a10eab4d623de3bd8121d49dd652 Mon Sep 17 00:00:00 2001 From: Emilio Benavente Date: Fri, 9 Jun 2023 10:35:54 -0500 Subject: [PATCH 0822/2042] tests: drivers: dma: Added channel chaining support to mimxrt1050 Added test case support for the mimxrt1050_evk Signed-off-by: Emilio Benavente --- .../dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay | 7 +++++++ .../dma/chan_link_transfer/boards/mimxrt1050_evk.overlay | 8 ++++++++ tests/drivers/dma/chan_link_transfer/testcase.yaml | 1 + 3 files changed, 16 insertions(+) create mode 100644 tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay create mode 100644 tests/drivers/dma/chan_link_transfer/boards/mimxrt1050_evk.overlay diff --git a/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay new file mode 100644 index 000000000000..5965bf744f9d --- /dev/null +++ b/tests/drivers/dma/chan_blen_transfer/boards/mimxrt1050_evk.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +test_dma0: &edma0 {}; diff --git a/tests/drivers/dma/chan_link_transfer/boards/mimxrt1050_evk.overlay b/tests/drivers/dma/chan_link_transfer/boards/mimxrt1050_evk.overlay new file mode 100644 index 000000000000..e384c0c391fd --- /dev/null +++ b/tests/drivers/dma/chan_link_transfer/boards/mimxrt1050_evk.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +dma0: &edma0 {}; diff --git a/tests/drivers/dma/chan_link_transfer/testcase.yaml b/tests/drivers/dma/chan_link_transfer/testcase.yaml index ba981b12840d..45027d880979 100644 --- a/tests/drivers/dma/chan_link_transfer/testcase.yaml +++ b/tests/drivers/dma/chan_link_transfer/testcase.yaml @@ -7,6 +7,7 @@ tests: - dma platform_allow: - frdm_k64f + - mimxrt1050_evk - mimxrt1060_evk - mimxrt1064_evk - mimxrt1160_evk_cm7 From b20ef863cddc72b9c3393ba283ef827cefc161e7 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 20 Jun 2023 13:40:41 +0200 Subject: [PATCH 0823/2042] Bluetooth: OTS: Add explicit ignore of ret error when reset dir_list When doing the bt_ots_dir_list_reset_anchor we now explicitly ignore the return value of bt_gatt_ots_obj_manager_first_obj_get to fix a coverity issue. Signed-off-by: Emil Gydesen --- subsys/bluetooth/services/ots/ots_dir_list.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/services/ots/ots_dir_list.c b/subsys/bluetooth/services/ots/ots_dir_list.c index 3ffa4decfde7..78a104b6e142 100644 --- a/subsys/bluetooth/services/ots/ots_dir_list.c +++ b/subsys/bluetooth/services/ots/ots_dir_list.c @@ -126,7 +126,9 @@ static void dir_list_object_encode(const struct bt_gatt_ots_object *obj, static void bt_ots_dir_list_reset_anchor(struct bt_ots_dir_list *dir_list, void *obj_manager) { dir_list->anchor_offset = 0; - bt_gatt_ots_obj_manager_first_obj_get(obj_manager, &dir_list->anchor_object); + + /* Reset the dir_list - Ignore any error as we can't do anything about it anyways */ + (void)bt_gatt_ots_obj_manager_first_obj_get(obj_manager, &dir_list->anchor_object); } static int bt_ots_dir_list_search_forward(struct bt_ots_dir_list *dir_list, void *obj_manager, From 64eecd448861128abaf34d02afb08e3948d35fd9 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 2 Jul 2023 17:15:41 +0200 Subject: [PATCH 0824/2042] MAINTAINERS: native IEEE 802.15.4 L2 maintenance Introduce a new area of maintenance for the IEEE 802.15.4 native stack as distinguished from both, IEEE 802.15.4 drivers and OpenThread and more specialized than generic network subsystem maintainership. Signed-off-by: Florian Grandel --- MAINTAINERS.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index fda0bd0c29f4..ad2e92ddb954 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1899,6 +1899,24 @@ Networking: labels: - "area: Networking" +"Networking: Native IEEE 802.15.4": + status: maintained + maintainers: + - tbursztyka + collaborators: + - rlubos + - fgrandel + files: + - doc/connectivity/networking/api/ieee802154.rst + - include/zephyr/net/ieee802154.h + - include/zephyr/net/ieee802154_pkt.h + - include/zephyr/net/ieee802154_mgmt.h + - subsys/net/l2/ieee802154/ + - subsys/net/lib/config/ieee802154_* + - tests/net/ieee802154/ + labels: + - "area: IEEE 802.15.4" + "Networking: OpenThread": status: maintained maintainers: From 30dab6c4f4ad36d6825f237b69eb1f0654c2b2e0 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Sun, 2 Jul 2023 17:18:29 +0200 Subject: [PATCH 0825/2042] MAINTAINERS: add IEEE 802.15.4 drivers header file The radio API header file was missing from the IEEE 802.15.4 maintenance scope. Signed-off-by: Florian Grandel --- MAINTAINERS.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index ad2e92ddb954..428c391d77a5 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -1019,6 +1019,7 @@ Release Notes: - fgrandel files: - drivers/ieee802154/ + - include/zephyr/net/ieee802154_radio.h labels: - "area: IEEE 802.15.4" From 03c04fd8d7456823ece3b476b999c2f37e34e302 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 3 Jul 2023 10:05:11 +0200 Subject: [PATCH 0826/2042] tests: Bluetooth: ascs: Fix build warning This fixes incompatible pointer type warning. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/mocks/src/pacs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bluetooth/audio/mocks/src/pacs.c b/tests/bluetooth/audio/mocks/src/pacs.c index 11cfd629dbcd..df006dac76f8 100644 --- a/tests/bluetooth/audio/mocks/src/pacs.c +++ b/tests/bluetooth/audio/mocks/src/pacs.c @@ -13,7 +13,7 @@ #define PACS_FFF_FAKES_LIST(FAKE) \ FAKE(bt_pacs_cap_foreach) \ -static struct bt_audio_codec_cfg lc3_codec = +static struct bt_audio_codec_cap lc3_codec = BT_AUDIO_CODEC_LC3(BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_10, BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 120u, 1u, (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); From acde5fe199734099ac05ea7912c4269cfb09458c Mon Sep 17 00:00:00 2001 From: Eric Holmberg Date: Thu, 18 May 2023 23:25:42 +1200 Subject: [PATCH 0827/2042] driver: gpio: fix shell blink command The blink command should blink until the user presses a key, however on some systems a pending keypress is present when entering the loop causing it to immediate exit before getting a chance to blink. Add a dummy read to clear the buffer before starting the blink loop. Signed-off-by: Eric Holmberg --- drivers/gpio/gpio_shell.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpio/gpio_shell.c b/drivers/gpio/gpio_shell.c index ee81326d826b..b444288953b0 100644 --- a/drivers/gpio/gpio_shell.c +++ b/drivers/gpio/gpio_shell.c @@ -157,6 +157,9 @@ static int cmd_gpio_blink(const struct shell *sh, shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s index %d.", argv[1], index); shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit"); + /* dummy read to clear any pending input */ + (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); + while (true) { (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count); if (count != 0) { From 3e385d9adf6837cdd289c1d7106b746034440234 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 4 Jul 2023 07:55:54 +0100 Subject: [PATCH 0828/2042] bluetooth: bt_gatt_subscribe: Fix documentation Fixes a minor issue with the documentation where there are conflicting messages about the required validity of the parameters. Signed-off-by: Jamie McCrae --- include/zephyr/bluetooth/gatt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 8e626e97570e..e4aae4e4d41a 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -1866,12 +1866,12 @@ struct bt_gatt_subscribe_params { * * The Response comes in callback @p params->subscribe. The callback is run from * the context specified by 'config BT_RECV_CONTEXT'. - * @p params must remain valid until start of callback. * The Notification callback @p params->notify is also called from the BT RX * thread. * - * @note Notifications are asynchronous therefore the parameters need to - * remain valid while subscribed. + * @note Notifications are asynchronous therefore the @p params must remain + * valid while subscribed and cannot be reused for additional subscriptions + * whilst active. * * This function will block while the ATT request queue is full, except when * called from the BT RX thread, as this would cause a deadlock. From 42a402abe3321c49550b4d5a33da95533eb46995 Mon Sep 17 00:00:00 2001 From: Szymon Czapracki Date: Wed, 15 Mar 2023 22:36:16 +0100 Subject: [PATCH 0829/2042] bluetooth: audio: Rework PACS notify system This commits eliminates the old way of pacs notifications, replacing k_work with simple bt_gatt_notify. Signed-off-by: Szymon Czapracki --- subsys/bluetooth/audio/pacs.c | 218 +++++++++++++++++++--------------- 1 file changed, 123 insertions(+), 95 deletions(-) diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 8b5c664fa99c..8638ac2949a3 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../host/conn_internal.h" #include @@ -36,25 +37,15 @@ LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL); #define PAC_NOTIFY_TIMEOUT K_MSEC(10) #define READ_BUF_SEM_TIMEOUT K_MSEC(50) -#define PACS(_name, _work_handler) \ - struct pacs _name = { \ - .work = Z_WORK_DELAYABLE_INITIALIZER(_work_handler), \ - }; - -#define PACS_LOCATION(_name, _work_handler) \ - struct pacs_location _name = { \ - .work = Z_WORK_DELAYABLE_INITIALIZER(_work_handler), \ - }; - -struct pacs_location { - struct k_work_delayable work; - uint32_t location; -}; +#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); +#endif /* CONFIG_BT_PAC_SRC */ -struct pacs { - struct k_work_delayable work; - sys_slist_t list; -}; +#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); +#endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK) static uint16_t snk_available_contexts; @@ -231,10 +222,8 @@ static ssize_t supported_context_read(struct bt_conn *conn, sizeof(context)); } -static void available_contexts_notify(struct k_work *work); -static void supported_contexts_notify(struct k_work *work); -static K_WORK_DELAYABLE_DEFINE(available_contexts_work, available_contexts_notify); -static K_WORK_DELAYABLE_DEFINE(supported_contexts_work, supported_contexts_notify); +static int available_contexts_notify(void); +static int supported_contexts_notify(void); static int set_available_contexts(uint16_t contexts, uint16_t *available, uint16_t supported) @@ -249,8 +238,8 @@ static int set_available_contexts(uint16_t contexts, uint16_t *available, return 0; } - err = k_work_reschedule(&available_contexts_work, PAC_NOTIFY_TIMEOUT); - if (err < 0) { + err = available_contexts_notify(); + if (err) { return err; } @@ -263,6 +252,8 @@ static int set_supported_contexts(uint16_t contexts, uint16_t *supported, uint16_t *available) { int err; + uint16_t tmp_supported = *supported; + uint16_t tmp_available = *available; /* Ensure unspecified is always supported */ contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; @@ -271,30 +262,32 @@ static int set_supported_contexts(uint16_t contexts, uint16_t *supported, return 0; } - err = k_work_reschedule(&supported_contexts_work, PAC_NOTIFY_TIMEOUT); - if (err < 0) { - return err; - } - *supported = contexts; /* Update available contexts if needed*/ if ((contexts & *available) != *available) { - *available = *available & contexts; - err = k_work_reschedule(&available_contexts_work, - PAC_NOTIFY_TIMEOUT); - if (err < 0) { - LOG_WRN("Update available contexts notify failed: %d", err); + err = set_available_contexts(contexts & *available, available, contexts); + if (err) { + *available = tmp_available; + *supported = tmp_supported; + + return err; } } + err = supported_contexts_notify(); + if (err) { + *supported = tmp_supported; + *available = tmp_available; + + return err; + } + return 0; } #if defined(CONFIG_BT_PAC_SNK) -static void pac_notify_snk(struct k_work *work); -static PACS(snk_pacs, pac_notify_snk); - +static int pac_notify_snk(void); static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { @@ -310,7 +303,7 @@ static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); } - get_pac_records(&snk_pacs.list, &read_buf); + get_pac_records(&snk_pacs_list, &read_buf); ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data, read_buf.len); @@ -349,14 +342,12 @@ static inline int set_snk_supported_contexts(uint16_t contexts) #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK_LOC) -static void pac_notify_snk_loc(struct k_work *work); -static PACS_LOCATION(snk_location, pac_notify_snk_loc); - +static int pac_notify_snk_loc(void); static ssize_t snk_loc_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint32_t location = sys_cpu_to_le32(snk_location.location); + uint32_t location = sys_cpu_to_le32(pacs_snk_location); LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -371,15 +362,17 @@ static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) static int set_snk_location(enum bt_audio_location audio_location) { - if (audio_location == snk_location.location) { + int err; + + if (audio_location == pacs_snk_location) { return 0; } - snk_location.location = audio_location; + pacs_snk_location = audio_location; - k_work_reschedule(&snk_location.work, PAC_NOTIFY_TIMEOUT); + err = pac_notify_snk_loc(); - return 0; + return err; } #else static int set_snk_location(enum bt_audio_location location) @@ -421,9 +414,7 @@ static ssize_t snk_loc_write(struct bt_conn *conn, #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */ #if defined(CONFIG_BT_PAC_SRC) -static void pac_notify_src(struct k_work *work); -static PACS(src_pacs, pac_notify_src); - +static int pac_notify_src(void); static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { @@ -439,7 +430,7 @@ static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); } - get_pac_records(&src_pacs.list, &read_buf); + get_pac_records(&src_pacs_list, &read_buf); ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data, read_buf.len); @@ -478,14 +469,12 @@ static inline int set_src_supported_contexts(uint16_t contexts) #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SRC_LOC) -static void pac_notify_src_loc(struct k_work *work); -static PACS_LOCATION(src_location, pac_notify_src_loc); - +static int pac_notify_src_loc(void); static ssize_t src_loc_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - uint32_t location = sys_cpu_to_le32(src_location.location); + uint32_t location = sys_cpu_to_le32(pacs_src_location); LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -500,13 +489,23 @@ static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) static int set_src_location(enum bt_audio_location audio_location) { - if (audio_location == src_location.location) { + int err; + enum bt_audio_location tmp_audio_location = audio_location; + + + if (audio_location == pacs_src_location) { return 0; } - src_location.location = audio_location; + pacs_src_location = audio_location; - k_work_reschedule(&src_location.work, PAC_NOTIFY_TIMEOUT); + err = pac_notify_src_loc(); + if (err) { + LOG_DBG("Notify failed, previous audio location restored"); + audio_location = tmp_audio_location; + + return err; + } return 0; } @@ -606,53 +605,52 @@ BT_GATT_SERVICE_DEFINE(pacs_svc, ); #if defined(CONFIG_BT_PAC_SNK_LOC) -static void pac_notify_snk_loc(struct k_work *work) +static int pac_notify_snk_loc(void) { - struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work); - uint32_t location_le = sys_cpu_to_le32(location->location); + uint32_t location_le = sys_cpu_to_le32(pacs_snk_location); int err; err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK_LOC, pacs_svc.attrs, &location_le, sizeof(location_le)); if (err != 0 && err != -ENOTCONN) { LOG_WRN("PACS notify_loc failed: %d", err); + return err; } + + return 0; } #endif /* CONFIG_BT_PAC_SNK_LOC */ #if defined(CONFIG_BT_PAC_SRC_LOC) -static void pac_notify_src_loc(struct k_work *work) +static int pac_notify_src_loc(void) { - struct pacs_location *location = CONTAINER_OF(work, struct pacs_location, work); - uint32_t location_le = sys_cpu_to_le32(location->location); + uint32_t location_le = sys_cpu_to_le32(pacs_src_location); int err; err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC_LOC, pacs_svc.attrs, &location_le, sizeof(location_le)); if (err != 0 && err != -ENOTCONN) { LOG_WRN("PACS notify_loc failed: %d", err); + return err; } + + return 0; } #endif /* CONFIG_BT_PAC_SRC_LOC */ #if defined(CONFIG_BT_PAC_SNK) -static void pac_notify_snk(struct k_work *work) +static int pac_notify_snk(void) { - struct pacs *pac = CONTAINER_OF(work, struct pacs, work); - int err; + int err = 0; err = k_sem_take(&read_buf_sem, K_NO_WAIT); if (err != 0) { LOG_DBG("Failed to take read_buf_sem: %d", err); - /* Try again later */ - k_work_reschedule(k_work_delayable_from_work(work), - PAC_NOTIFY_TIMEOUT); - - return; + return err; } - get_pac_records(&pac->list, &read_buf); + get_pac_records(&snk_pacs_list, &read_buf); err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SNK, pacs_svc.attrs, read_buf.data, read_buf.len); @@ -661,27 +659,28 @@ static void pac_notify_snk(struct k_work *work) } k_sem_give(&read_buf_sem); + + if (err == -ENOTCONN) { + return 0; + } else { + return 0; + } } #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) -static void pac_notify_src(struct k_work *work) +static int pac_notify_src(void) { - struct pacs *pac = CONTAINER_OF(work, struct pacs, work); int err = 0; err = k_sem_take(&read_buf_sem, K_NO_WAIT); if (err != 0) { LOG_DBG("Failed to take read_buf_sem: %d", err); - /* Try again later */ - k_work_reschedule(k_work_delayable_from_work(work), - PAC_NOTIFY_TIMEOUT); - - return; + return err; } - get_pac_records(&pac->list, &read_buf); + get_pac_records(&src_pacs_list, &read_buf); err = bt_gatt_notify_uuid(NULL, BT_UUID_PACS_SRC, pacs_svc.attrs, read_buf.data, read_buf.len); @@ -690,15 +689,33 @@ static void pac_notify_src(struct k_work *work) } k_sem_give(&read_buf_sem); + + if (err == -ENOTCONN) { + return 0; + } else { + return 0; + } } #endif /* CONFIG_BT_PAC_SRC */ -static void pacs_changed(struct pacs *caps) +static int pacs_changed(enum bt_audio_dir dir) { - k_work_reschedule(&caps->work, PAC_NOTIFY_TIMEOUT); + int err = 0; + + if (dir == BT_AUDIO_DIR_SINK) { +#if defined(CONFIG_BT_PAC_SNK) + err = pac_notify_snk(); +#endif /* CONFIG_BT_PAC_SNK */ + } else { +#if defined(CONFIG_BT_PAC_SRC) + err = pac_notify_src(); +#endif /* CONFIG_BT_PAC_SRC */ + } + + return err; } -static void available_contexts_notify(struct k_work *work) +static int available_contexts_notify(void) { struct bt_pacs_context context = { .snk = sys_cpu_to_le16(snk_available_contexts), @@ -710,10 +727,13 @@ static void available_contexts_notify(struct k_work *work) &context, sizeof(context)); if (err != 0 && err != -ENOTCONN) { LOG_WRN("Available Audio Contexts notify failed: %d", err); + return err; } + + return 0; } -static void supported_contexts_notify(struct k_work *work) +static int supported_contexts_notify(void) { struct bt_pacs_context context = { .snk = sys_cpu_to_le16(snk_supported_contexts), @@ -725,7 +745,11 @@ static void supported_contexts_notify(struct k_work *work) &context, sizeof(context)); if (err != 0 && err != -ENOTCONN) { LOG_WRN("Supported Audio Contexts notify failed: %d", err); + + return err; } + + return 0; } bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context) @@ -741,16 +765,16 @@ bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context) return false; } -static struct pacs *pacs_get(enum bt_audio_dir dir) +static sys_slist_t *pacs_get(enum bt_audio_dir dir) { switch (dir) { #if defined(CONFIG_BT_PAC_SNK) case BT_AUDIO_DIR_SINK: - return &snk_pacs; + return &snk_pacs_list; #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SRC) case BT_AUDIO_DIR_SOURCE: - return &src_pacs; + return &src_pacs_list; #endif /* CONFIG_BT_PAC_SRC */ default: return NULL; @@ -759,7 +783,7 @@ static struct pacs *pacs_get(enum bt_audio_dir dir) void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data) { - struct pacs *pac; + sys_slist_t *pac; CHECKIF(func == NULL) { LOG_ERR("func is NULL"); @@ -771,14 +795,15 @@ void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, return; } - foreach_cap(&pac->list, func, user_data); + foreach_cap(pac, func, user_data); } /* Register Audio Capability */ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap) { const struct bt_audio_codec_cap *codec_cap; - struct pacs *pac; + sys_slist_t *pac; + int err; if (!cap || !cap->codec_cap) { return -EINVAL; @@ -794,9 +819,12 @@ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap) LOG_DBG("cap %p dir %s codec_cap id 0x%02x codec_cap cid 0x%04x codec_cap vid 0x%04x", cap, bt_audio_dir_str(dir), codec_cap->id, codec_cap->cid, codec_cap->vid); - sys_slist_append(&pac->list, &cap->_node); + sys_slist_append(pac, &cap->_node); - pacs_changed(pac); + err = pacs_changed(dir); + if (err) { + return -EINVAL; + } return 0; } @@ -804,7 +832,7 @@ int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap) /* Unregister Audio Capability */ int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap) { - struct pacs *pac; + sys_slist_t *pac; if (!cap) { return -EINVAL; @@ -817,11 +845,11 @@ int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap) LOG_DBG("cap %p dir %s", cap, bt_audio_dir_str(dir)); - if (!sys_slist_find_and_remove(&pac->list, &cap->_node)) { + if (!sys_slist_find_and_remove(pac, &cap->_node)) { return -ENOENT; } - pacs_changed(pac); + pacs_changed(dir); return 0; } From 25bfbb1cafd8c2ba609a4d36ada288d1e3e657ce Mon Sep 17 00:00:00 2001 From: Aleksandr Khromykh Date: Wed, 28 Jun 2023 13:50:28 +0200 Subject: [PATCH 0830/2042] Bluetooth: Mesh: instantiate cdb and core keys PR instantiates cdb and core keys to prevent scenario when key is changed over cdb API and gets new ID but core still operates with old ID(potentially invalid). Known issue the keys will be desynchronized during\after key refresh procedure. Signed-off-by: Aleksandr Khromykh --- subsys/bluetooth/mesh/main.c | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 18a52e238ffe..054871b82b98 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -51,6 +51,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, struct bt_mesh_key mesh_net_key; bool is_net_key_valid = false; bool is_dev_key_valid = false; + bool is_cdb_dev_key_valid = false; int err = 0; if (!atomic_test_bit(bt_mesh.flags, BT_MESH_INIT)) { @@ -58,6 +59,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, } struct bt_mesh_cdb_subnet *subnet = NULL; + struct bt_mesh_cdb_node *node; LOG_INF("Primary Element: 0x%04x", addr); LOG_DBG("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", net_idx, flags, iv_index); @@ -70,7 +72,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { const struct bt_mesh_comp *comp; const struct bt_mesh_prov *prov; - struct bt_mesh_cdb_node *node; comp = bt_mesh_comp_get(); if (comp == NULL) { @@ -101,16 +102,16 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, subnet->kr_phase = BT_MESH_KR_NORMAL; } + /* The primary network key has been imported during cdb creation. + * Importing here leaves it 'as is' if the key is the same. + * Otherwise, cdb replaces the old one with the new one. + */ err = bt_mesh_cdb_subnet_key_import(subnet, BT_MESH_KEY_REFRESH(flags) ? 1 : 0, net_key); if (err) { LOG_ERR("Failed to import cdb network key"); goto end; } - memcpy(&mesh_net_key, &subnet->keys[BT_MESH_KEY_REFRESH(flags) ? 1 : 0].net_key, - sizeof(struct bt_mesh_key)); - is_net_key_valid = true; - bt_mesh_cdb_subnet_store(subnet); addr = node->addr; @@ -121,27 +122,26 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, LOG_ERR("Failed to import cdb device key"); goto end; } - memcpy(&mesh_dev_key, &node->dev_key, sizeof(struct bt_mesh_key)); - is_dev_key_valid = true; + is_cdb_dev_key_valid = true; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_cdb_node_store(node); } - } else { - err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, net_key, &mesh_net_key); - if (err) { - LOG_ERR("Failed to import network key"); - goto end; - } - is_net_key_valid = true; + } - err = bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, dev_key, &mesh_dev_key); - if (err) { - LOG_ERR("Failed to import device key"); - goto end; - } - is_dev_key_valid = true; + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_DEV, dev_key, &mesh_dev_key); + if (err) { + LOG_ERR("Failed to import device key"); + goto end; } + is_dev_key_valid = true; + + err = bt_mesh_key_import(BT_MESH_KEY_TYPE_NET, net_key, &mesh_net_key); + if (err) { + LOG_ERR("Failed to import network key"); + goto end; + } + is_net_key_valid = true; err = bt_mesh_net_create(net_idx, flags, &mesh_net_key, iv_index); if (err) { @@ -169,6 +169,10 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_start(); end: + if (err && is_cdb_dev_key_valid && IS_ENABLED(CONFIG_BT_MESH_CDB)) { + bt_mesh_cdb_node_del(node, true); + } + if (err && is_dev_key_valid) { bt_mesh_key_destroy(&mesh_dev_key); } From 9ccf5ae521480b26dee9ea056e9fe9fab75c92fa Mon Sep 17 00:00:00 2001 From: Andrej Valek Date: Mon, 3 Jul 2023 21:23:27 +0200 Subject: [PATCH 0831/2042] boards: arm: nucleo_f756zg: add flash0 partitions Split flash into partitions (4x256KB). There is no way to make partitions smaller, because of block size. This feature enables to switch between 2 applications. Signed-off-by: Andrej Valek --- boards/arm/nucleo_f756zg/nucleo_f756zg.dts | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/boards/arm/nucleo_f756zg/nucleo_f756zg.dts b/boards/arm/nucleo_f756zg/nucleo_f756zg.dts index 01cec2c07659..329182ffcf7b 100644 --- a/boards/arm/nucleo_f756zg/nucleo_f756zg.dts +++ b/boards/arm/nucleo_f756zg/nucleo_f756zg.dts @@ -25,6 +25,7 @@ zephyr,shell-uart = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,dtcm = &dtcm; }; @@ -149,3 +150,40 @@ zephyr_udc0: &usbotg_fs { ð_txd1_pb13>; pinctrl-names = "default"; }; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * 256KB for bootloader. This is too large but + * there is no way to make the part smaller. + */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(256)>; + read-only; + }; + + /* application image slot: 256KB */ + slot0_partition: partition@40000 { + label = "image-0"; + reg = <0x00040000 DT_SIZE_K(256)>; + }; + + /* backup slot: 256KB */ + slot1_partition: partition@80000 { + label = "image-1"; + reg = <0x00080000 DT_SIZE_K(256)>; + }; + + /* scratch slot: 256KB */ + scratch_partition: partition@C0000 { + label = "image-scratch"; + reg = <0x000C0000 DT_SIZE_K(256)>; + }; + + }; +}; From 074fdbb4f70be48f9e44143a68b7de99fc24ab60 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Thu, 22 Jun 2023 11:54:05 -0500 Subject: [PATCH 0832/2042] drivers: mcux_usb: Fix selection of NO_CACHE NO_CACHE cannot be selected for certain cores. Use ARCH_HAS_NOCACHE_MEMORY_SUPPORT as the condtion to select NO_CACHE config Signed-off-by: Mahesh Mahadevan --- drivers/usb/device/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 087fbbe21c74..d5f58317eaf7 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -160,7 +160,7 @@ choice USB_MCUX_CONTROLLER_TYPE config USB_DC_NXP_EHCI bool "MXRT EHCI USB Device Controller" - select NOCACHE_MEMORY if HAS_MCUX_CACHE + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT select USB_DC_HAS_HS_SUPPORT help Kinetis and RT EHCI USB Device Controller Driver. From f3cafe75593596e09893fdb9377b57538d4031ea Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 4 Jul 2023 10:36:00 +0200 Subject: [PATCH 0833/2042] tests: drivers: can: api: do not quote overlay file name Remove quotes from DTC_OVERLAY_FILE as they break the build. Signed-off-by: Henrik Brix Andersen --- tests/drivers/can/api/testcase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/can/api/testcase.yaml b/tests/drivers/can/api/testcase.yaml index dc765579c7df..ee240f81a47d 100644 --- a/tests/drivers/can/api/testcase.yaml +++ b/tests/drivers/can/api/testcase.yaml @@ -9,7 +9,7 @@ tests: tags: - drivers - can - extra_args: DTC_OVERLAY_FILE="twai-enable.overlay" + extra_args: DTC_OVERLAY_FILE=twai-enable.overlay harness: console harness_config: # actual CAN transceiver or shorted CAN RX/TX pins required for board testing From 6e72e401f26c0bd12f37431f2887212d07ee8319 Mon Sep 17 00:00:00 2001 From: Marek Matej Date: Tue, 4 Jul 2023 12:56:17 +0200 Subject: [PATCH 0834/2042] drivers: wifi: Fix esp32 driver Fix compilation issue on esp_wifi_drv. Signed-off-by: Marek Matej --- drivers/wifi/esp32/src/esp_wifi_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index 5272b6df21e4..647f91b28909 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -406,7 +406,7 @@ static int esp32_wifi_scan(const struct device *dev, if (params) { /* The enum values are same, so, no conversion needed */ - scan_config->scan_type = params->scan_type; + scan_config.scan_type = params->scan_type; } ret = esp_wifi_set_mode(ESP32_WIFI_MODE_STA); From 690b21718ae67a972b442dc98c9eccc3f140df0c Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Thu, 29 Jun 2023 10:37:08 +0100 Subject: [PATCH 0835/2042] tfm: Fix the merged hex file name for mps3_an547 This fixes a typo that leads to failure when running `west build` with the `run` target. Signed-off-by: Wilfried Chauveau --- boards/arm/mps3_an547/board.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm/mps3_an547/board.cmake b/boards/arm/mps3_an547/board.cmake index 4b7f8a40b7be..b8035658dd23 100644 --- a/boards/arm/mps3_an547/board.cmake +++ b/boards/arm/mps3_an547/board.cmake @@ -25,7 +25,7 @@ if (CONFIG_BUILD_WITH_TFM) # Override the binary used by qemu, to use the combined # TF-M (Secure) & Zephyr (Non Secure) image (when running # in-tree tests). - set(QEMU_KERNEL_OPTION "-device;loader,file=${CMAKE_BINARY_DIR}/zephyr/merged.hex") + set(QEMU_KERNEL_OPTION "-device;loader,file=${CMAKE_BINARY_DIR}/zephyr/tfm_merged.hex") endif() # FVP settings From 30fa612289e9ec87e751b5ca1858c93295b47e27 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 13 Jun 2023 18:40:16 +0100 Subject: [PATCH 0836/2042] modules: define few undefined but referenced symbols These are referenced by the "x module not available" message in modules/Kconfig, but were only defined in the module, were generating an undefined symbol warning when running CI compliance with no modules. Signed-off-by: Fabio Baltieri --- modules/Kconfig | 2 ++ modules/Kconfig.chre | 5 +++++ modules/Kconfig.picolibc | 5 +++++ modules/liblc3/Kconfig | 3 +++ 4 files changed, 15 insertions(+) create mode 100644 modules/Kconfig.chre create mode 100644 modules/Kconfig.picolibc diff --git a/modules/Kconfig b/modules/Kconfig index a6e14030eb95..f35dfdcbd486 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -16,6 +16,7 @@ comment "Optional modules. Make sure they're installed, via the project manifest source "modules/Kconfig.altera" source "modules/Kconfig.atmel" +source "modules/Kconfig.chre" source "modules/Kconfig.cmsis" source "modules/Kconfig.cypress" source "modules/Kconfig.eos_s3" @@ -28,6 +29,7 @@ source "modules/Kconfig.mcux" source "modules/Kconfig.microchip" source "modules/Kconfig.nuvoton" source "modules/Kconfig.open-amp" +source "modules/Kconfig.picolibc" source "modules/Kconfig.s32" source "modules/Kconfig.silabs" source "modules/Kconfig.simplelink" diff --git a/modules/Kconfig.chre b/modules/Kconfig.chre new file mode 100644 index 000000000000..c9d07f11a440 --- /dev/null +++ b/modules/Kconfig.chre @@ -0,0 +1,5 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_CHRE_MODULE + bool diff --git a/modules/Kconfig.picolibc b/modules/Kconfig.picolibc new file mode 100644 index 000000000000..95382a8adaae --- /dev/null +++ b/modules/Kconfig.picolibc @@ -0,0 +1,5 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_PICOLIBC_MODULE + bool diff --git a/modules/liblc3/Kconfig b/modules/liblc3/Kconfig index 4123d12c6e70..aaca9d95d7bb 100644 --- a/modules/liblc3/Kconfig +++ b/modules/liblc3/Kconfig @@ -1,6 +1,9 @@ # Copyright (c) 2022 Bose Corporation # SPDX-License-Identifier: Apache-2.0 +config ZEPHYR_LIBLC3_MODULE + bool + config LIBLC3 bool "liblc3 Support" depends on FPU From 9de541b9c278cf0d9e42c71abc6f84ebbf0419f2 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Tue, 13 Jun 2023 18:42:49 +0100 Subject: [PATCH 0837/2042] scripts: ci: check_compliance: add a no-modules Kconfig check Add a variation of the basic Kconfig check that runs with no modules, catches symbols that are used in the main repository but are defined only in modules, which are potentially problematic if a downstream project is not using the specific module. Signed-off-by: Fabio Baltieri --- .gitignore | 1 + scripts/ci/check_compliance.py | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 735440b4cac7..16e54c466283 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ Identity.txt ImageSize.txt Kconfig.txt KconfigBasic.txt +KconfigBasicNoModules.txt MaintainersFormat.txt Nits.txt Pylint.txt diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 561874098109..f5e3002fd5ea 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -268,7 +268,9 @@ class KconfigCheck(ComplianceTest): doc = "See https://docs.zephyrproject.org/latest/guides/kconfig/index.html for more details." path_hint = "" - def run(self, full=True): + def run(self, full=True, no_modules=False): + self.no_modules = no_modules + kconf = self.parse_kconfig() self.check_top_menu_not_too_long(kconf) @@ -287,6 +289,11 @@ def get_modules(self, modules_file): This is needed to complete Kconfig sanity tests. """ + if self.no_modules: + with open(modules_file, 'w') as fp_module_file: + fp_module_file.write("# Empty\n") + return + # Invoke the script directly using the Python executable since this is # not a module nor a pip-installed Python utility zephyr_module_path = os.path.join(ZEPHYR_BASE, "scripts", @@ -711,6 +718,18 @@ class KconfigBasicCheck(KconfigCheck): def run(self): super().run(full=False) +class KconfigBasicNoModulesCheck(KconfigCheck): + """ + Checks if we are introducing any new warnings/errors with Kconfig when no + modules are available. Catches symbols used in the main repository but + defined only in a module. + """ + name = "KconfigBasicNoModules" + doc = "See https://docs.zephyrproject.org/latest/guides/kconfig/index.html for more details." + path_hint = "" + def run(self): + super().run(full=False, no_modules=True) + class Nits(ComplianceTest): """ From a459e56cc5349b4bd32515600ec57e573f073870 Mon Sep 17 00:00:00 2001 From: Tomislav Milkovic Date: Tue, 4 Jul 2023 14:25:55 +0200 Subject: [PATCH 0838/2042] drivers: clock_control: Export initialization function for STM32H7 Because they are needed in SoC power.c, clock control init functions for all other STM32 series has been exported as global. This commit exports stm32_clock_control_init function as global for STM32H7 series as well, making custom power management implementations for STM32H7 series possible. Signed-off-by: Tomislav Milkovic --- drivers/clock_control/clock_stm32_ll_h7.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index bf77ce507f5c..8ef3b48c4970 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -818,7 +818,7 @@ static int set_up_plls(void) } #if defined(CONFIG_CPU_CORTEX_M7) -static int stm32_clock_control_init(const struct device *dev) +int stm32_clock_control_init(const struct device *dev) { uint32_t old_hclk_freq = 0; uint32_t new_hclk_freq = 0; @@ -913,7 +913,7 @@ static int stm32_clock_control_init(const struct device *dev) return r; } #else -static int stm32_clock_control_init(const struct device *dev) +int stm32_clock_control_init(const struct device *dev) { ARG_UNUSED(dev); From 12c89edc39a01f8aa374b9f60f935a17e334966f Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 28 Jun 2023 13:22:57 +0200 Subject: [PATCH 0839/2042] Bluetooth: ascs: Fix return without state change nor response This fixes missing control point status and ASE status change, when failed to disconnect the CIS. As the server may, but does not have to disconnect the CIS, the operation should not be considered as failed when it happens. 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 01ea1359f998..0123a1fc232e 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -2482,7 +2482,6 @@ static void ase_stop(struct bt_ascs_ase *ase) err = ascs_disconnect_stream(stream); if (err < 0) { LOG_ERR("Failed to disconnect stream %p: %d", stream, err); - return; } } From 8797e50b6421a9afb5c7a08d1ba3d3c419a29a86 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 28 Jun 2023 11:37:14 +0200 Subject: [PATCH 0840/2042] tests: Bluetooth: ascs: Swap bt_gatt_attr_read mock with real function This refactors the code to use exact copy of bt_gatt_attr_read instead of mock, as the implementation might call the function with stack allocated value. Using mock would require deep copy of the value for further verification. As the buffer where the value is about to placed is one of the attr->read() parameters, the test may call the read() callback with stack allocated buffer of defined size and read the value from the buffer. Signed-off-by: Mariusz Skamra --- tests/bluetooth/audio/ascs/src/main.c | 10 ++-- tests/bluetooth/audio/ascs/src/test_common.c | 13 ++--- tests/bluetooth/audio/mocks/include/gatt.h | 3 -- .../audio/mocks/include/gatt_expects.h | 53 ------------------- tests/bluetooth/audio/mocks/src/gatt.c | 27 ++++++++-- 5 files changed, 30 insertions(+), 76 deletions(-) diff --git a/tests/bluetooth/audio/ascs/src/main.c b/tests/bluetooth/audio/ascs/src/main.c index 5bee5fc955d3..4c13a31420e2 100644 --- a/tests/bluetooth/audio/ascs/src/main.c +++ b/tests/bluetooth/audio/ascs/src/main.c @@ -125,19 +125,15 @@ ZTEST_F(ascs_test_suite, test_sink_ase_read_state_idle) { const struct bt_gatt_attr *ase = fixture->ase_snk.attr; struct bt_conn *conn = &fixture->conn; - struct test_ase_chrc_value_hdr *hdr; + struct test_ase_chrc_value_hdr hdr = { 0xff }; ssize_t ret; Z_TEST_SKIP_IFNDEF(CONFIG_BT_ASCS_ASE_SNK); zexpect_not_null(fixture->ase_snk.attr); - ret = ase->read(conn, ase, NULL, 0, 0); + ret = ase->read(conn, ase, &hdr, sizeof(hdr), 0); zassert_false(ret < 0, "attr->read returned unexpected (err 0x%02x)", BT_GATT_ERR(ret)); - - expect_bt_gatt_attr_read_called_once(conn, ase, EMPTY, EMPTY, 0x0000, EMPTY, sizeof(*hdr)); - - hdr = (void *)bt_gatt_attr_read_fake.arg5_val; - zassert_equal(0x00, hdr->ase_state, "unexpected ASE_State 0x%02x", hdr->ase_state); + zassert_equal(0x00, hdr.ase_state, "unexpected ASE_State 0x%02x", hdr.ase_state); } ZTEST_F(ascs_test_suite, test_release_ase_on_callback_unregister) diff --git a/tests/bluetooth/audio/ascs/src/test_common.c b/tests/bluetooth/audio/ascs/src/test_common.c index bc529097b8f3..e2632fa16a43 100644 --- a/tests/bluetooth/audio/ascs/src/test_common.c +++ b/tests/bluetooth/audio/ascs/src/test_common.c @@ -116,20 +116,13 @@ uint8_t test_ase_get(const struct bt_uuid *uuid, int num_ase, ...) uint8_t test_ase_id_get(const struct bt_gatt_attr *ase) { - const struct test_ase_chrc_value_hdr *hdr; + struct test_ase_chrc_value_hdr hdr = { 0 }; ssize_t ret; - ret = ase->read(NULL, ase, NULL, 0, 0); + ret = ase->read(NULL, ase, &hdr, sizeof(hdr), 0); zassert_false(ret < 0, "ase->read returned unexpected (err 0x%02x)", BT_GATT_ERR(ret)); - expect_bt_gatt_attr_read_called_once(NULL, ase, EMPTY, EMPTY, 0, EMPTY, sizeof(*hdr)); - - hdr = bt_gatt_attr_read_fake.arg5_val; - - /* Reset the mock state */ - bt_gatt_attr_read_reset(); - - return hdr->ase_id; + return hdr.ase_id; } static struct bt_bap_stream *stream_allocated; diff --git a/tests/bluetooth/audio/mocks/include/gatt.h b/tests/bluetooth/audio/mocks/include/gatt.h index f61f7efd5446..f54ad42492e3 100644 --- a/tests/bluetooth/audio/mocks/include/gatt.h +++ b/tests/bluetooth/audio/mocks/include/gatt.h @@ -15,9 +15,6 @@ void mock_bt_gatt_cleanup(void); DECLARE_FAKE_VALUE_FUNC(int, mock_bt_gatt_notify_cb, struct bt_conn *, struct bt_gatt_notify_params *); -DECLARE_FAKE_VALUE_FUNC(ssize_t, bt_gatt_attr_read, struct bt_conn *, - const struct bt_gatt_attr *, void *, uint16_t, uint16_t, const void *, - uint16_t); void bt_gatt_notify_cb_reset(void); uint16_t bt_gatt_get_mtu(struct bt_conn *conn); diff --git a/tests/bluetooth/audio/mocks/include/gatt_expects.h b/tests/bluetooth/audio/mocks/include/gatt_expects.h index 67eebf53bbe3..3e661bfc2a1b 100644 --- a/tests/bluetooth/audio/mocks/include/gatt_expects.h +++ b/tests/bluetooth/audio/mocks/include/gatt_expects.h @@ -12,51 +12,6 @@ #include "gatt.h" #include "expects_util.h" -#define expect_bt_gatt_attr_read_called_once(_conn, _attr, _buf, _buf_len, _offset, _value, \ - _value_len) \ -do { \ - const char *func_name = "bt_gatt_attr_read"; \ - \ - zassert_equal(1, bt_gatt_attr_read_fake.call_count, \ - "'%s()' was called %u times, but expected once", \ - func_name, bt_gatt_attr_read_fake.call_count); \ - \ - IF_NOT_EMPTY(_conn, ( \ - zassert_equal_ptr(_conn, bt_gatt_attr_read_fake.arg0_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "conn");)) \ - \ - IF_NOT_EMPTY(_attr, ( \ - zassert_equal_ptr(_attr, bt_gatt_attr_read_fake.arg1_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "attr");)) \ - \ - IF_NOT_EMPTY(_buf, ( \ - zassert_equal_ptr(_buf, bt_gatt_attr_read_fake.arg2_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "buf");)) \ - \ - IF_NOT_EMPTY(_buf_len, ( \ - zassert_equal(_buf_len, bt_gatt_attr_read_fake.arg3_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "_buf_len");)) \ - \ - IF_NOT_EMPTY(_offset, ( \ - zassert_equal(_offset, bt_gatt_attr_read_fake.arg4_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "offset");)) \ - \ - /* assert if _data is valid, but _len is empty */ \ - IF_EMPTY(_value_len, (IF_NOT_EMPTY(_value, (zassert_unreachable();)))) \ - \ - IF_NOT_EMPTY(_value_len, ( \ - zassert_equal(_value_len, bt_gatt_attr_read_fake.arg6_val, \ - "'%s()' was called with incorrect '%s' value", \ - func_name, "value_len"); \ - expect_data(func_name, "value", _value, bt_gatt_attr_read_fake.arg5_val, \ - _value_len);)) \ -} while (0) - #define expect_bt_gatt_notify_cb_called_once(_conn, _uuid, _attr, _data, _len) \ do { \ const char *func_name = "bt_gatt_notify_cb"; \ @@ -92,14 +47,6 @@ do { expect_data(func_name, "params->data", _data, params->data, _len);)) \ } while (0) -static inline void expect_bt_gatt_attr_read_not_called(void) -{ - const char *func_name = "bt_gatt_attr_read"; - - zassert_equal(0, bt_gatt_attr_read_fake.call_count, - "'%s()' was called unexpectedly", func_name); -} - static inline void expect_bt_gatt_notify_cb_not_called(void) { const char *func_name = "bt_gatt_notify_cb"; diff --git a/tests/bluetooth/audio/mocks/src/gatt.c b/tests/bluetooth/audio/mocks/src/gatt.c index 445098dfc705..be2ca633df88 100644 --- a/tests/bluetooth/audio/mocks/src/gatt.c +++ b/tests/bluetooth/audio/mocks/src/gatt.c @@ -11,15 +11,16 @@ #include "gatt.h" +#define LOG_LEVEL CONFIG_BT_GATT_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_gatt); + /* List of fakes used by this unit tester */ #define FFF_FAKES_LIST(FAKE) \ FAKE(mock_bt_gatt_notify_cb) \ - FAKE(bt_gatt_attr_read) \ DEFINE_FAKE_VALUE_FUNC(int, mock_bt_gatt_notify_cb, struct bt_conn *, struct bt_gatt_notify_params *); -DEFINE_FAKE_VALUE_FUNC(ssize_t, bt_gatt_attr_read, struct bt_conn *, const struct bt_gatt_attr *, - void *, uint16_t, uint16_t, const void *, uint16_t); 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) @@ -221,6 +222,26 @@ void bt_gatt_foreach_attr_type(uint16_t start_handle, uint16_t end_handle, num_matches, func, user_data); } +/* Exact copy of subsys/bluetooth/host/gatt.c:bt_gatt_attr_read() */ +ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t buf_len, uint16_t offset, + const void *value, uint16_t value_len) +{ + uint16_t len; + + if (offset > value_len) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + len = MIN(buf_len, value_len - offset); + + LOG_DBG("handle 0x%04x offset %u length %u", attr->handle, offset, len); + + memcpy(buf, (uint8_t *)value + offset, len); + + return len; +} + uint16_t bt_gatt_get_mtu(struct bt_conn *conn) { return 64; From 7c21a9c18938e7ed2e128a5a563bb504147f4f41 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Mon, 26 Jun 2023 14:08:52 +0200 Subject: [PATCH 0841/2042] Bluetooth: ascs: Make sure idle state can be always read Instead of waiting for ase_buf to be available, the read of an ASE in IDLE state can be handled without using ase_buf. Signed-off-by: Mariusz Skamra --- subsys/bluetooth/audio/ascs.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 0123a1fc232e..e4e010a78247 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -545,23 +545,17 @@ static void ascs_ep_get_status_enable(struct bt_bap_ep *ep, struct net_buf_simpl bt_audio_dir_str(ep->dir), ep->cig_id, ep->cis_id); } -static int ascs_ep_get_status_idle(uint8_t ase_id, struct net_buf_simple *buf) +static ssize_t ascs_ase_read_status_idle(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, uint16_t len, uint16_t offset) { - struct bt_ascs_ase_status *status; - - if (!buf || ase_id > ASE_COUNT) { - return -EINVAL; - } - - net_buf_simple_reset(buf); - - status = net_buf_simple_add(buf, sizeof(*status)); - status->id = ase_id; - status->state = BT_BAP_EP_STATE_IDLE; + struct bt_ascs_ase_status status = { + .id = POINTER_TO_UINT(BT_AUDIO_CHRC_USER_DATA(attr)), + .state = BT_BAP_EP_STATE_IDLE, + }; - LOG_DBG("id 0x%02x state %s", ase_id, bt_bap_ep_state_str(status->state)); + LOG_DBG("conn %p id 0x%02x", (void *)conn, status.id); - return 0; + return bt_gatt_attr_read(conn, attr, buf, len, offset, &status, sizeof(status)); } static int ascs_ep_get_status(struct bt_bap_ep *ep, struct net_buf_simple *buf) @@ -1169,6 +1163,11 @@ static ssize_t ascs_ase_read(struct bt_conn *conn, ase = ase_find(conn, ase_id); } + /* If NULL, we haven't assigned an ASE, this also means that we are currently in IDLE */ + if (ase == NULL) { + return ascs_ase_read_status_idle(conn, attr, buf, len, offset); + } + err = k_sem_take(&ase_buf_sem, ASE_BUF_SEM_TIMEOUT); if (err != 0) { LOG_DBG("Failed to take ase_buf_sem: %d", err); @@ -1176,12 +1175,7 @@ static ssize_t ascs_ase_read(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES); } - /* If NULL, we haven't assigned an ASE, this also means that we are currently in IDLE */ - if (!ase) { - ascs_ep_get_status_idle(ase_id, &ase_buf); - } else { - ascs_ep_get_status(&ase->ep, &ase_buf); - } + ascs_ep_get_status(&ase->ep, &ase_buf); ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, ase_buf.data, ase_buf.len); From 4d3611e95c702bd209355dd03414a73929a753c9 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Mon, 3 Jul 2023 23:31:43 +0200 Subject: [PATCH 0842/2042] include: drivers: uart: remove incorrect comments about CDC ACM UART The CDC ACM implementation provides a virtual UART interface that is used by various samples and subsystems in a way that is compatible with the real UART interface. Commit cc1b2c70cc8b ("uart: doc: Add special case for virtual UART") added a questionable comment to uart_fifo_fill() API description in an attempt to fix issue described in https://github.com/zephyrproject-rtos/zephyr/issues/11455 However, this did not fix the problem because the API is not designed to be used in this way. Finally commit 0e57e4fb78e0 ("samples: usb: cdc_acm: Update CDC ACM echo sample") revised the sample to use the API in the correct way. Remove incorrect comment in uart_fifo_fill(). For compatibility reasons and due to the design of the API, such differences must not exist. Signed-off-by: Johann Fischer --- include/zephyr/drivers/uart.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/zephyr/drivers/uart.h b/include/zephyr/drivers/uart.h index 50d83b76bfa6..01ee29368b01 100644 --- a/include/zephyr/drivers/uart.h +++ b/include/zephyr/drivers/uart.h @@ -775,9 +775,6 @@ static inline int uart_fifo_fill_u16(const struct device *dev, * available data in the FIFO (i.e. until it returns less data * than was requested). * - * Note that the calling context only applies to physical UARTs and - * no to the virtual ones found in USB CDC ACM code. - * * @param dev UART device instance. * @param rx_data Data container. * @param size Container size. @@ -819,9 +816,6 @@ static inline int uart_fifo_read(const struct device *dev, uint8_t *rx_data, * available data in the FIFO (i.e. until it returns less data * than was requested). * - * Note that the calling context only applies to physical UARTs and - * no to the virtual ones found in USB CDC ACM code. - * * @param dev UART device instance. * @param rx_data Wide data container. * @param size Container size. From 85fe3c45fd0a5305bb09f70d37494f3d427729f5 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 3 Jul 2023 16:47:00 +0200 Subject: [PATCH 0843/2042] ipc_service: rename virtio_xxx static functions The "virtio_" prefix is used by the open-amp library API. Rename local functions using "ipc_virtio_" prefix to avoid function redefinition. Signed-off-by: Arnaud Pouliquen --- .../ipc/ipc_service/lib/ipc_static_vrings.c | 20 ++++++++-------- subsys/ipc/rpmsg_service/rpmsg_backend.c | 23 +++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c index 0d1786d84335..6d253b6d071c 100644 --- a/subsys/ipc/ipc_service/lib/ipc_static_vrings.c +++ b/subsys/ipc/ipc_service/lib/ipc_static_vrings.c @@ -12,7 +12,7 @@ #define RPMSG_VQ_0 (0) /* TX virtqueue queue index */ #define RPMSG_VQ_1 (1) /* RX virtqueue queue index */ -static void virtio_notify(struct virtqueue *vq) +static void ipc_virtio_notify(struct virtqueue *vq) { struct ipc_static_vrings *vr; @@ -23,12 +23,12 @@ static void virtio_notify(struct virtqueue *vq) } } -static void virtio_set_features(struct virtio_device *vdev, uint32_t features) +static void ipc_virtio_set_features(struct virtio_device *vdev, uint32_t features) { /* No need for implementation */ } -static void virtio_set_status(struct virtio_device *p_vdev, unsigned char status) +static void ipc_virtio_set_status(struct virtio_device *p_vdev, unsigned char status) { struct ipc_static_vrings *vr; @@ -42,12 +42,12 @@ static void virtio_set_status(struct virtio_device *p_vdev, unsigned char status sys_cache_data_flush_range((void *) vr->status_reg_addr, sizeof(status)); } -static uint32_t virtio_get_features(struct virtio_device *vdev) +static uint32_t ipc_virtio_get_features(struct virtio_device *vdev) { return BIT(VIRTIO_RPMSG_F_NS); } -static unsigned char virtio_get_status(struct virtio_device *p_vdev) +static unsigned char ipc_virtio_get_status(struct virtio_device *p_vdev) { struct ipc_static_vrings *vr; uint8_t ret; @@ -65,11 +65,11 @@ static unsigned char virtio_get_status(struct virtio_device *p_vdev) } const static struct virtio_dispatch dispatch = { - .get_status = virtio_get_status, - .get_features = virtio_get_features, - .set_status = virtio_set_status, - .set_features = virtio_set_features, - .notify = virtio_notify, + .get_status = ipc_virtio_get_status, + .get_features = ipc_virtio_get_features, + .set_status = ipc_virtio_set_status, + .set_features = ipc_virtio_set_features, + .notify = ipc_virtio_notify, }; static int libmetal_setup(struct ipc_static_vrings *vr) diff --git a/subsys/ipc/rpmsg_service/rpmsg_backend.c b/subsys/ipc/rpmsg_service/rpmsg_backend.c index 5ac16ebe50cf..a913d4085ce1 100644 --- a/subsys/ipc/rpmsg_service/rpmsg_backend.c +++ b/subsys/ipc/rpmsg_service/rpmsg_backend.c @@ -92,7 +92,7 @@ static struct virtqueue *vq[2]; static struct k_work ipm_work; -static unsigned char virtio_get_status(struct virtio_device *vdev) +static unsigned char ipc_virtio_get_status(struct virtio_device *vdev) { #if MASTER return VIRTIO_CONFIG_STATUS_DRIVER_OK; @@ -101,22 +101,21 @@ static unsigned char virtio_get_status(struct virtio_device *vdev) #endif } -static void virtio_set_status(struct virtio_device *vdev, unsigned char status) +static void ipc_virtio_set_status(struct virtio_device *vdev, unsigned char status) { sys_write8(status, VDEV_STATUS_ADDR); } -static uint32_t virtio_get_features(struct virtio_device *vdev) +static uint32_t ipc_virtio_get_features(struct virtio_device *vdev) { return BIT(VIRTIO_RPMSG_F_NS); } -static void virtio_set_features(struct virtio_device *vdev, - uint32_t features) +static void ipc_virtio_set_features(struct virtio_device *vdev, uint32_t features) { } -static void virtio_notify(struct virtqueue *vq) +static void ipc_virtio_notify(struct virtqueue *vq) { int status; @@ -143,11 +142,11 @@ static void virtio_notify(struct virtqueue *vq) } const struct virtio_dispatch dispatch = { - .get_status = virtio_get_status, - .set_status = virtio_set_status, - .get_features = virtio_get_features, - .set_features = virtio_set_features, - .notify = virtio_notify, + .get_status = ipc_virtio_get_status, + .set_status = ipc_virtio_set_status, + .get_features = ipc_virtio_get_features, + .set_features = ipc_virtio_set_features, + .notify = ipc_virtio_notify, }; static void ipm_callback_process(struct k_work *work) @@ -285,7 +284,7 @@ int rpmsg_backend_init(struct metal_io_region **io, struct virtio_device *vdev) */ int init_status_flag(void) { - virtio_set_status(NULL, 0); + ipc_virtio_set_status(NULL, 0); return 0; } From b227f89bcd6deb3b0b8e8e215c2de860ad027427 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 3 Jul 2023 16:49:15 +0200 Subject: [PATCH 0844/2042] samples: ipc: rename virtio_xxx static functions The "virtio_" prefix is used by the open-amp library API. Rename local functions using "ipc_virtio_" prefix to avoid function redefinition. Signed-off-by: Arnaud Pouliquen --- samples/subsys/ipc/openamp/src/main.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/samples/subsys/ipc/openamp/src/main.c b/samples/subsys/ipc/openamp/src/main.c index c12023da2f7a..a38418ea1292 100644 --- a/samples/subsys/ipc/openamp/src/main.c +++ b/samples/subsys/ipc/openamp/src/main.c @@ -63,27 +63,26 @@ static struct rpmsg_virtio_device rvdev; static struct metal_io_region *io; static struct virtqueue *vq[2]; -static unsigned char virtio_get_status(struct virtio_device *vdev) +static unsigned char ipc_virtio_get_status(struct virtio_device *vdev) { return VIRTIO_CONFIG_STATUS_DRIVER_OK; } -static void virtio_set_status(struct virtio_device *vdev, unsigned char status) +static void ipc_virtio_set_status(struct virtio_device *vdev, unsigned char status) { sys_write8(status, VDEV_STATUS_ADDR); } -static uint32_t virtio_get_features(struct virtio_device *vdev) +static uint32_t ipc_virtio_get_features(struct virtio_device *vdev) { return 1 << VIRTIO_RPMSG_F_NS; } -static void virtio_set_features(struct virtio_device *vdev, - uint32_t features) +static void ipc_virtio_set_features(struct virtio_device *vdev, uint32_t features) { } -static void virtio_notify(struct virtqueue *vq) +static void ipc_virtio_notify(struct virtqueue *vq) { #if defined(CONFIG_SOC_MPS2_AN521) || \ defined(CONFIG_SOC_V2M_MUSCA_B1) @@ -98,11 +97,11 @@ static void virtio_notify(struct virtqueue *vq) } struct virtio_dispatch dispatch = { - .get_status = virtio_get_status, - .set_status = virtio_set_status, - .get_features = virtio_get_features, - .set_features = virtio_set_features, - .notify = virtio_notify, + .get_status = ipc_virtio_get_status, + .set_status = ipc_virtio_set_status, + .get_features = ipc_virtio_get_features, + .set_features = ipc_virtio_set_features, + .notify = ipc_virtio_notify, }; static K_SEM_DEFINE(data_sem, 0, 1); @@ -301,7 +300,7 @@ int main(void) */ int init_status_flag(void) { - virtio_set_status(NULL, 0); + ipc_virtio_set_status(NULL, 0); return 0; } From 0d4e5bf67f6186ef56bfafc696848c3f804bfdc9 Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 30 Jun 2023 10:23:13 +0200 Subject: [PATCH 0845/2042] arch: arm: nmi: simplify NMI initialization Zephyr provides a default NMI handler (`z_SysNmiOnReset`), which will basically call `wfi` endlessly. It is allowed to override such handler when CONFIG_RUNTIME_NMI=y, via `z_arm_nmi_set_handler`. However, enabling such option also provided `z_arm_nmi_init` (via `NMI_INIT()`), which basically sets the handler to `DefaultHandler` (a new handler that basically printks and reboots). This is strictly not needed, and independent of the runtime NMI option. As a result, most SoCs were blindly calling `NMI_INIT()`, probably because of a copy&paste effect. In the majority of cases, this was a no-op, but most SoCs do IRQ enable/disable, making this even more convoluted. To make things worse, the init call is expected to run after console has been initialized (for printk to work?), but most SoCs just called it in PRE_KERNEL_1+0. This patch just drops this NMI initializer API, and leaves only the handler set call when CONFIG_RUNTIME_NMI=y. NMI_INIT() dummy definition is left in this patch to preserve bisectability, will be dropped later. Signed-off-by: Gerard Marull-Paretas --- arch/arm/core/aarch32/nmi.c | 31 --------------------------- include/zephyr/arch/arm/aarch32/nmi.h | 10 +++------ 2 files changed, 3 insertions(+), 38 deletions(-) diff --git a/arch/arm/core/aarch32/nmi.c b/arch/arm/core/aarch32/nmi.c index a84827d1e38a..371f125eb645 100644 --- a/arch/arm/core/aarch32/nmi.c +++ b/arch/arm/core/aarch32/nmi.c @@ -29,37 +29,6 @@ extern void z_SysNmiOnReset(void); typedef void (*_NmiHandler_t)(void); static _NmiHandler_t handler = z_SysNmiOnReset; -/** - * - * @brief Default NMI handler installed when kernel is up - * - * The default handler outputs a error message and reboots the target. It is - * installed by calling z_arm_nmi_init(); - * - */ - -static void DefaultHandler(void) -{ - printk("NMI received! Rebooting...\n"); - /* In ARM implementation sys_reboot ignores the parameter */ - sys_reboot(0); -} - -/** - * - * @brief Install default runtime NMI handler - * - * Meant to be called by platform code if they want to install a simple NMI - * handler that reboots the target. It should be installed after the console is - * initialized. - * - */ - -void z_arm_nmi_init(void) -{ - handler = DefaultHandler; -} - /** * * @brief Install a custom runtime NMI handler diff --git a/include/zephyr/arch/arm/aarch32/nmi.h b/include/zephyr/arch/arm/aarch32/nmi.h index 6d44499aafcb..e3c65504dc31 100644 --- a/include/zephyr/arch/arm/aarch32/nmi.h +++ b/include/zephyr/arch/arm/aarch32/nmi.h @@ -13,14 +13,10 @@ #ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ #define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ -#ifndef _ASMLANGUAGE -#ifdef CONFIG_RUNTIME_NMI -extern void z_arm_nmi_init(void); +#if !defined(_ASMLANGUAGE) && defined(CONFIG_RUNTIME_NMI) extern void z_arm_nmi_set_handler(void (*pHandler)(void)); -#define NMI_INIT() z_arm_nmi_init() -#else -#define NMI_INIT() -#endif #endif +#define NMI_INIT() + #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ */ From fcaa259e22c2cbc555f242914ad3c8e4579f900a Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 30 Jun 2023 11:15:25 +0200 Subject: [PATCH 0846/2042] soc: arm: remove all unnecessary NMI_INIT() calls NMI_INIT() is now a no-op, so remove it from all SoC code. Also remove the irq lock/unlock pattern as it was likely a cause of copy&paste when NMI_INIT() was called. Signed-off-by: Gerard Marull-Paretas --- soc/arm/arm/beetle/soc.c | 14 ------- soc/arm/arm/designstart/CMakeLists.txt | 4 -- soc/arm/arm/designstart/soc.c | 22 ---------- soc/arm/arm/mps2/soc.c | 21 ---------- soc/arm/arm/mps3/soc.c | 21 ---------- soc/arm/arm/musca_b1/soc.c | 21 ---------- soc/arm/arm/musca_s1/CMakeLists.txt | 4 -- soc/arm/arm/musca_s1/soc.c | 28 ------------- soc/arm/atmel_sam/sam3x/soc.c | 14 ------- soc/arm/atmel_sam/sam4e/soc.c | 15 ------- soc/arm/atmel_sam/sam4l/soc.c | 15 ------- soc/arm/atmel_sam/sam4s/soc.c | 15 ------- soc/arm/atmel_sam/same70/soc.c | 13 ------ soc/arm/atmel_sam/samv71/soc.c | 13 ------ soc/arm/atmel_sam0/common/soc_samc2x.c | 13 ------ soc/arm/atmel_sam0/common/soc_samd2x.c | 13 ------ soc/arm/atmel_sam0/common/soc_samd5x.c | 12 ------ soc/arm/atmel_sam0/common/soc_saml2x.c | 13 ------ soc/arm/bcm_vk/valkyrie/CMakeLists.txt | 3 -- soc/arm/bcm_vk/valkyrie/soc.c | 34 ---------------- soc/arm/bcm_vk/viper/soc.c | 9 ---- soc/arm/gigadevice/gd32a50x/soc.c | 10 +---- soc/arm/gigadevice/gd32e10x/soc.c | 9 ---- soc/arm/gigadevice/gd32e50x/soc.c | 10 +---- soc/arm/gigadevice/gd32f3x0/soc.c | 9 ---- soc/arm/gigadevice/gd32f403/soc.c | 10 +---- soc/arm/gigadevice/gd32f4xx/soc.c | 10 +---- soc/arm/gigadevice/gd32l23x/soc.c | 9 ---- soc/arm/intel_socfpga_std/cyclonev/soc.c | 2 - soc/arm/nordic_nrf/nrf51/soc.c | 21 ---------- soc/arm/nordic_nrf/nrf52/soc.c | 13 ------ soc/arm/nordic_nrf/nrf53/soc.c | 12 ------ soc/arm/nordic_nrf/nrf91/soc.c | 13 ------ soc/arm/nxp_imx/mcimx6x_m4/soc.c | 17 -------- soc/arm/nxp_imx/rt/soc_rt10xx.c | 15 ------- soc/arm/nxp_imx/rt/soc_rt11xx.c | 16 -------- soc/arm/nxp_imx/rt5xx/soc.c | 18 -------- soc/arm/nxp_imx/rt6xx/soc.c | 16 -------- soc/arm/nxp_kinetis/k2x/soc.c | 14 ------- soc/arm/nxp_kinetis/k6x/soc.c | 14 ------- soc/arm/nxp_kinetis/k8x/soc.c | 14 ------- soc/arm/nxp_kinetis/ke1xf/soc.c | 13 ------ soc/arm/nxp_kinetis/kl2x/soc.c | 14 ------- soc/arm/nxp_kinetis/kv5x/soc.c | 15 ------- soc/arm/nxp_kinetis/kwx/soc_kw2xd.c | 15 ------- soc/arm/nxp_kinetis/kwx/soc_kw4xz.c | 15 ------- soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt | 8 ---- soc/arm/nxp_lpc/lpc11u6x/soc.c | 52 ------------------------ soc/arm/nxp_lpc/lpc54xxx/soc.c | 17 -------- soc/arm/nxp_lpc/lpc55xxx/soc.c | 16 -------- soc/arm/nxp_s32/s32ze/soc.c | 6 --- soc/arm/quicklogic_eos_s3/soc.c | 9 ---- soc/arm/renesas_rcar/gen3/soc.c | 20 --------- soc/arm/renesas_smartbond/da1469x/soc.c | 4 -- soc/arm/rpi_pico/rp2/soc.c | 13 ------ soc/arm/silabs_exx32/common/soc.c | 15 ------- soc/arm/st_stm32/stm32c0/soc.c | 15 ------- soc/arm/st_stm32/stm32f0/soc.c | 15 ------- soc/arm/st_stm32/stm32f1/soc.c | 15 ------- soc/arm/st_stm32/stm32f2/soc.c | 15 ------- soc/arm/st_stm32/stm32f3/soc.c | 15 ------- soc/arm/st_stm32/stm32f4/soc.c | 15 ------- soc/arm/st_stm32/stm32f7/soc.c | 15 ------- soc/arm/st_stm32/stm32g0/soc.c | 15 ------- soc/arm/st_stm32/stm32g4/soc.c | 15 ------- soc/arm/st_stm32/stm32h5/soc.c | 15 ------- soc/arm/st_stm32/stm32h7/soc_m4.c | 14 ------- soc/arm/st_stm32/stm32h7/soc_m7.c | 15 ------- soc/arm/st_stm32/stm32l0/soc.c | 15 ------- soc/arm/st_stm32/stm32l1/soc.c | 15 ------- soc/arm/st_stm32/stm32l4/soc.c | 15 ------- soc/arm/st_stm32/stm32l5/soc.c | 15 ------- soc/arm/st_stm32/stm32mp1/soc.c | 15 ------- soc/arm/st_stm32/stm32u5/soc.c | 15 ------- soc/arm/st_stm32/stm32wb/soc.c | 15 ------- soc/arm/st_stm32/stm32wl/soc.c | 15 ------- soc/arm/ti_lm3s6965/CMakeLists.txt | 1 - soc/arm/ti_lm3s6965/soc.c | 43 -------------------- soc/arm/xilinx_zynq7000/xc7zxxx/soc.c | 19 --------- soc/arm/xilinx_zynq7000/xc7zxxxs/soc.c | 19 --------- soc/arm/xilinx_zynqmp/soc.c | 20 --------- 81 files changed, 4 insertions(+), 1198 deletions(-) delete mode 100644 soc/arm/arm/designstart/soc.c delete mode 100644 soc/arm/arm/musca_s1/soc.c delete mode 100644 soc/arm/bcm_vk/valkyrie/soc.c delete mode 100644 soc/arm/nxp_lpc/lpc11u6x/soc.c delete mode 100644 soc/arm/ti_lm3s6965/soc.c diff --git a/soc/arm/arm/beetle/soc.c b/soc/arm/arm/beetle/soc.c index c61e753b7ec2..0cf8668a514b 100644 --- a/soc/arm/arm/beetle/soc.c +++ b/soc/arm/arm/beetle/soc.c @@ -17,8 +17,6 @@ #include #include -#include - /** * @brief Perform basic hardware initialization at boot. * @@ -32,21 +30,9 @@ */ static int arm_beetle_init(void) { - uint32_t key; - - - key = irq_lock(); - /* Setup various clocks and wakeup sources */ soc_power_init(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/arm/designstart/CMakeLists.txt b/soc/arm/arm/designstart/CMakeLists.txt index 332416ba43b0..9881313609aa 100644 --- a/soc/arm/arm/designstart/CMakeLists.txt +++ b/soc/arm/arm/designstart/CMakeLists.txt @@ -1,5 +1 @@ # SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - soc.c - ) diff --git a/soc/arm/arm/designstart/soc.c b/soc/arm/arm/designstart/soc.c deleted file mode 100644 index d914210277ba..000000000000 --- a/soc/arm/arm/designstart/soc.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2020 Henrik Brix Andersen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -static int arm_designstart_init(void) -{ - - /* - * Install default handler that simply resets the CPU if - * configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - return 0; -} - -SYS_INIT(arm_designstart_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/arm/mps2/soc.c b/soc/arm/arm/mps2/soc.c index 4b9659d72a85..76edaa388f5a 100644 --- a/soc/arm/arm/mps2/soc.c +++ b/soc/arm/arm/mps2/soc.c @@ -7,9 +7,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include #include #include @@ -70,22 +68,3 @@ uint32_t sse_200_platform_get_cpu_id(void) return (uint32_t)*p_cpu_id; } - -/** - * @brief Perform basic hardware initialization at boot. - * - * @return 0 - */ -static int arm_mps2_init(void) -{ - - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - return 0; -} - -SYS_INIT(arm_mps2_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/arm/mps3/soc.c b/soc/arm/arm/mps3/soc.c index 86c7c2649bff..e51a9ba5c59a 100644 --- a/soc/arm/arm/mps3/soc.c +++ b/soc/arm/arm/mps3/soc.c @@ -4,9 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include #include #include @@ -24,22 +22,3 @@ FPGAIO_INIT(0); FPGAIO_INIT(1); FPGAIO_INIT(2); - -/** - * @brief Perform basic hardware initialization at boot. - * - * @return 0 - */ -static int arm_mps3_init(void) -{ - - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - return 0; -} - -SYS_INIT(arm_mps3_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/arm/musca_b1/soc.c b/soc/arm/arm/musca_b1/soc.c index 44d8d887d50b..5e9f869c3306 100644 --- a/soc/arm/arm/musca_b1/soc.c +++ b/soc/arm/arm/musca_b1/soc.c @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include #include #include @@ -46,22 +44,3 @@ uint32_t sse_200_platform_get_cpu_id(void) return (uint32_t)*p_cpu_id; } - -/** - * @brief Perform basic hardware initialization at boot. - * - * @return 0 - */ -static int arm_musca_b1_init(void) -{ - - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - return 0; -} - -SYS_INIT(arm_musca_b1_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/arm/musca_s1/CMakeLists.txt b/soc/arm/arm/musca_s1/CMakeLists.txt index ae3f7d6c3be5..2ceba388601b 100644 --- a/soc/arm/arm/musca_s1/CMakeLists.txt +++ b/soc/arm/arm/musca_s1/CMakeLists.txt @@ -3,7 +3,3 @@ # # SPDX-License-Identifier: Apache-2.0 # - -zephyr_sources( - soc.c - ) diff --git a/soc/arm/arm/musca_s1/soc.c b/soc/arm/arm/musca_s1/soc.c deleted file mode 100644 index 7570678d1a3b..000000000000 --- a/soc/arm/arm/musca_s1/soc.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019-2020 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -/** - * @brief Perform basic hardware initialization at boot. - * - * @return 0 - */ -static int arm_musca_s1_init(void) -{ - - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise. - */ - NMI_INIT(); - - return 0; -} - -SYS_INIT(arm_musca_s1_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/atmel_sam/sam3x/soc.c b/soc/arm/atmel_sam/sam3x/soc.c index 891b205e195e..fb4ef6db866c 100644 --- a/soc/arm/atmel_sam/sam3x/soc.c +++ b/soc/arm/atmel_sam/sam3x/soc.c @@ -17,9 +17,7 @@ #include #include #include -#include #include -#include /* * PLL clock = Main * (MULA + 1) / DIVA @@ -204,11 +202,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_sam3x_init(void) { - uint32_t key; - - - key = irq_lock(); - /* * Set FWS (Flash Wait State) value before increasing Master Clock * (MCK) frequency. @@ -221,13 +214,6 @@ static int atmel_sam3x_init(void) /* Setup system clocks */ clock_init(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam/sam4e/soc.c b/soc/arm/atmel_sam/sam4e/soc.c index 4407b2325d38..8c6f4965483e 100644 --- a/soc/arm/atmel_sam/sam4e/soc.c +++ b/soc/arm/atmel_sam/sam4e/soc.c @@ -18,9 +18,7 @@ #include #include #include -#include #include -#include /** * @brief Setup various clock on SoC at boot time. @@ -192,11 +190,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_sam4e_init(void) { - uint32_t key; - - - key = irq_lock(); - /* * Set FWS (Flash Wait State) value before increasing Master Clock * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet. @@ -210,14 +203,6 @@ static int atmel_sam4e_init(void) /* Setup system clocks. */ clock_init(); - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise. - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam/sam4l/soc.c b/soc/arm/atmel_sam/sam4l/soc.c index 88427c990cd2..9c67f99c6b6d 100644 --- a/soc/arm/atmel_sam/sam4l/soc.c +++ b/soc/arm/atmel_sam/sam4l/soc.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include /** Watchdog control register first write keys */ @@ -265,11 +263,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_sam4l_init(void) { - uint32_t key; - - - key = irq_lock(); - #if defined(CONFIG_WDT_DISABLE_AT_BOOT) wdt_set_ctrl(WDT->CTRL & ~WDT_CTRL_EN); while (WDT->CTRL & WDT_CTRL_EN) { @@ -280,14 +273,6 @@ static int atmel_sam4l_init(void) /* Setup system clocks. */ clock_init(); - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise. - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam/sam4s/soc.c b/soc/arm/atmel_sam/sam4s/soc.c index 395972549d73..d89363928e0f 100644 --- a/soc/arm/atmel_sam/sam4s/soc.c +++ b/soc/arm/atmel_sam/sam4s/soc.c @@ -17,9 +17,7 @@ #include #include #include -#include #include -#include /** * @brief Setup various clock on SoC at boot time. @@ -191,11 +189,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_sam4s_init(void) { - uint32_t key; - - - key = irq_lock(); - /* * Set FWS (Flash Wait State) value before increasing Master Clock * (MCK) frequency. Look at table 44.73 in the SAM4S datasheet. @@ -210,14 +203,6 @@ static int atmel_sam4s_init(void) /* Setup system clocks. */ clock_init(); - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise. - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam/same70/soc.c b/soc/arm/atmel_sam/same70/soc.c index 5bded6490db5..35913cb0fa44 100644 --- a/soc/arm/atmel_sam/same70/soc.c +++ b/soc/arm/atmel_sam/same70/soc.c @@ -16,7 +16,6 @@ #include #include #include -#include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); @@ -234,11 +233,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_same70_init(void) { - uint32_t key; - - - key = irq_lock(); - SCB_EnableICache(); if (!(SCB->CCR & SCB_CCR_DC_Msk)) { @@ -256,13 +250,6 @@ static int atmel_same70_init(void) /* Setup system clocks */ clock_init(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Check that the CHIP CIDR matches the HAL one */ if (CHIPID->CHIPID_CIDR != CHIP_CIDR) { LOG_WRN("CIDR mismatch: chip = 0x%08x vs HAL = 0x%08x", diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index 7f04c0bbb3ca..94eeb7b07a8a 100644 --- a/soc/arm/atmel_sam/samv71/soc.c +++ b/soc/arm/atmel_sam/samv71/soc.c @@ -17,7 +17,6 @@ #include #include #include -#include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); @@ -235,11 +234,6 @@ static ALWAYS_INLINE void clock_init(void) */ static int atmel_samv71_init(void) { - uint32_t key; - - - key = irq_lock(); - SCB_EnableICache(); if (!(SCB->CCR & SCB_CCR_DC_Msk)) { @@ -257,13 +251,6 @@ static int atmel_samv71_init(void) /* Setup system clocks */ clock_init(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Check that the CHIP CIDR matches the HAL one */ if (CHIPID->CHIPID_CIDR != CHIP_CIDR) { LOG_WRN("CIDR mismatch: chip = 0x%08x vs HAL = 0x%08x", diff --git a/soc/arm/atmel_sam0/common/soc_samc2x.c b/soc/arm/atmel_sam0/common/soc_samc2x.c index 4eefe27af4dc..6a0528309a56 100644 --- a/soc/arm/atmel_sam0/common/soc_samc2x.c +++ b/soc/arm/atmel_sam0/common/soc_samc2x.c @@ -9,7 +9,6 @@ * @brief Atmel SAMC MCU series initialization code */ -#include #include #include #include @@ -45,23 +44,11 @@ static void gclks_init(void) static int atmel_samc_init(void) { - uint32_t key; - - - key = irq_lock(); - flash_waitstates_init(); osc48m_init(); mclk_init(); gclks_init(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam0/common/soc_samd2x.c b/soc/arm/atmel_sam0/common/soc_samd2x.c index 90c0d1b008d2..33ef01192e59 100644 --- a/soc/arm/atmel_sam0/common/soc_samd2x.c +++ b/soc/arm/atmel_sam0/common/soc_samd2x.c @@ -21,7 +21,6 @@ * GCLK Gen 3 -> ADC @ 8 MHz */ -#include #include #include #include @@ -257,11 +256,6 @@ static inline void osc8m_disable(void) static int atmel_samd_init(void) { - uint32_t key; - - - key = irq_lock(); - osc8m_init(); osc32k_init(); xosc_init(); @@ -272,13 +266,6 @@ static int atmel_samd_init(void) gclk_adc_configure(); osc8m_disable(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam0/common/soc_samd5x.c b/soc/arm/atmel_sam0/common/soc_samd5x.c index 557b4e559990..d50191f3c3f0 100644 --- a/soc/arm/atmel_sam0/common/soc_samd5x.c +++ b/soc/arm/atmel_sam0/common/soc_samd5x.c @@ -9,7 +9,6 @@ * @brief Atmel SAMD MCU series initialization code */ -#include #include #include #include @@ -107,7 +106,6 @@ static void gclk_connect(uint8_t gclk, uint8_t src, uint8_t div) static int atmel_samd_init(void) { - uint32_t key; uint8_t dfll_div; if (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC < SAM0_DFLL_FREQ_HZ) { @@ -118,9 +116,6 @@ static int atmel_samd_init(void) dfll_div = 1; } - - key = irq_lock(); - /* enable the Cortex M Cache Controller */ CMCC->CTRL.bit.CEN = 1; @@ -135,13 +130,6 @@ static int atmel_samd_init(void) /* connect GCLK2 to 48 MHz DFLL for USB */ gclk_connect(2, GCLK_SOURCE_DFLL48M, 0); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/atmel_sam0/common/soc_saml2x.c b/soc/arm/atmel_sam0/common/soc_saml2x.c index 5e8d0a8061c4..1914b221433f 100644 --- a/soc/arm/atmel_sam0/common/soc_saml2x.c +++ b/soc/arm/atmel_sam0/common/soc_saml2x.c @@ -9,7 +9,6 @@ * @brief Atmel SAML MCU series initialization code */ -#include #include #include #include @@ -245,11 +244,6 @@ static inline void pause_for_debug(void) {} static int atmel_saml_init(void) { - uint32_t key; - - - key = irq_lock(); - pause_for_debug(); gclk_reset(); @@ -262,13 +256,6 @@ static int atmel_saml_init(void) gclk_main_configure(); gclk_adc_configure(); - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/bcm_vk/valkyrie/CMakeLists.txt b/soc/arm/bcm_vk/valkyrie/CMakeLists.txt index 3b465dc7da89..f75aec6b3117 100644 --- a/soc/arm/bcm_vk/valkyrie/CMakeLists.txt +++ b/soc/arm/bcm_vk/valkyrie/CMakeLists.txt @@ -1,6 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) -zephyr_sources( - soc.c -) diff --git a/soc/arm/bcm_vk/valkyrie/soc.c b/soc/arm/bcm_vk/valkyrie/soc.c deleted file mode 100644 index bd5e025107cf..000000000000 --- a/soc/arm/bcm_vk/valkyrie/soc.c +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * Copyright 2018 Broadcom. - */ - -#include -#include -#include -#include -#include - -/** - * @brief Perform basic hardware initialization at boot. - * - * This needs to be run from the very beginning. - * So the init priority has to be 0 (zero). - * - * @return 0 - */ -static int valkyrie_init(void) -{ - uint32_t key; - - - key = irq_lock(); - - NMI_INIT(); - - irq_unlock(key); - - return 0; -} - -SYS_INIT(valkyrie_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/bcm_vk/viper/soc.c b/soc/arm/bcm_vk/viper/soc.c index 49ee4a78ebe2..d18d13ce8844 100644 --- a/soc/arm/bcm_vk/viper/soc.c +++ b/soc/arm/bcm_vk/viper/soc.c @@ -8,7 +8,6 @@ #include #include #include -#include /** * @brief Perform basic hardware initialization at boot. @@ -20,14 +19,8 @@ */ static int viper_init(void) { - uint32_t key; uint32_t data; - - key = irq_lock(); - - NMI_INIT(); - /* pcie pmon lite init */ data = sys_read32(LS_ICFG_PMON_LITE_CLK_CTRL); data |= PCIE_PMON_LITE_CLK_ENABLE; @@ -37,8 +30,6 @@ static int viper_init(void) data |= PCIE_PMON_LITE_SW_RESETN; sys_write32(data, LS_ICFG_PMON_LITE_SW_RESETN); - irq_unlock(key); - return 0; } diff --git a/soc/arm/gigadevice/gd32a50x/soc.c b/soc/arm/gigadevice/gd32a50x/soc.c index 0a5033796c6b..5f8024f7fd66 100644 --- a/soc/arm/gigadevice/gd32a50x/soc.c +++ b/soc/arm/gigadevice/gd32a50x/soc.c @@ -5,7 +5,7 @@ #include #include -#include +#include /* initial ecc memory */ void z_arm_platform_init(void) @@ -21,15 +21,7 @@ void z_arm_platform_init(void) static int gd32a50x_soc_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32e10x/soc.c b/soc/arm/gigadevice/gd32e10x/soc.c index 6958f5bb1c13..939af3492c85 100644 --- a/soc/arm/gigadevice/gd32e10x/soc.c +++ b/soc/arm/gigadevice/gd32e10x/soc.c @@ -5,20 +5,11 @@ #include #include -#include #include static int gd32e10x_soc_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32e50x/soc.c b/soc/arm/gigadevice/gd32e50x/soc.c index e8731171d583..0bd63afaff5f 100644 --- a/soc/arm/gigadevice/gd32e50x/soc.c +++ b/soc/arm/gigadevice/gd32e50x/soc.c @@ -4,19 +4,11 @@ */ #include -#include +#include static int gd32e50x_soc_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32f3x0/soc.c b/soc/arm/gigadevice/gd32f3x0/soc.c index 1f160d495954..ebf0e3fea355 100644 --- a/soc/arm/gigadevice/gd32f3x0/soc.c +++ b/soc/arm/gigadevice/gd32f3x0/soc.c @@ -5,20 +5,11 @@ #include #include -#include #include static int gd32f3x0_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32f403/soc.c b/soc/arm/gigadevice/gd32f403/soc.c index 2c5c0c5e0371..2e52dd08508c 100644 --- a/soc/arm/gigadevice/gd32f403/soc.c +++ b/soc/arm/gigadevice/gd32f403/soc.c @@ -13,7 +13,7 @@ #include #include -#include +#include /** * @brief Perform basic hardware initialization at boot. @@ -25,15 +25,7 @@ */ static int gigadevice_gd32_soc_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32f4xx/soc.c b/soc/arm/gigadevice/gd32f4xx/soc.c index d7b189530a98..e096ba64b0b5 100644 --- a/soc/arm/gigadevice/gd32f4xx/soc.c +++ b/soc/arm/gigadevice/gd32f4xx/soc.c @@ -5,19 +5,11 @@ #include #include -#include +#include static int gd32f4xx_soc_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/gigadevice/gd32l23x/soc.c b/soc/arm/gigadevice/gd32l23x/soc.c index 89e8821be5a3..381941337390 100644 --- a/soc/arm/gigadevice/gd32l23x/soc.c +++ b/soc/arm/gigadevice/gd32l23x/soc.c @@ -5,20 +5,11 @@ #include #include -#include #include static int gd32l23x_init(void) { - uint32_t key; - - - key = irq_lock(); - SystemInit(); - NMI_INIT(); - - irq_unlock(key); return 0; } diff --git a/soc/arm/intel_socfpga_std/cyclonev/soc.c b/soc/arm/intel_socfpga_std/cyclonev/soc.c index 3ae336ebe678..c00964600a40 100644 --- a/soc/arm/intel_socfpga_std/cyclonev/soc.c +++ b/soc/arm/intel_socfpga_std/cyclonev/soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "soc.h" void arch_reserved_pages_update(void) @@ -72,7 +71,6 @@ const struct arm_mmu_config mmu_config = { */ static int soc_intel_cyclonev_init(void) { - NMI_INIT(); unsigned int sctlr = __get_SCTLR(); /* modifying some registers prior to initialization */ sctlr &= ~SCTLR_A_Msk; diff --git a/soc/arm/nordic_nrf/nrf51/soc.c b/soc/arm/nordic_nrf/nrf51/soc.c index a3cfe2ededf9..078a422c06b1 100644 --- a/soc/arm/nordic_nrf/nrf51/soc.c +++ b/soc/arm/nordic_nrf/nrf51/soc.c @@ -14,8 +14,6 @@ */ #include -#include -#include #include #include #include @@ -36,23 +34,6 @@ void sys_arch_reboot(int type) } #endif -static int nordicsemi_nrf51_init(void) -{ - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - - return 0; -} - #define DELAY_CALL_OVERHEAD_US 2 void arch_busy_wait(uint32_t time_us) @@ -64,5 +45,3 @@ void arch_busy_wait(uint32_t time_us) time_us -= DELAY_CALL_OVERHEAD_US; nrfx_coredep_delay_us(time_us); } - -SYS_INIT(nordicsemi_nrf51_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nordic_nrf/nrf52/soc.c b/soc/arm/nordic_nrf/nrf52/soc.c index 2c8bd51c657f..fe610a1aa45f 100644 --- a/soc/arm/nordic_nrf/nrf52/soc.c +++ b/soc/arm/nordic_nrf/nrf52/soc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -38,11 +37,6 @@ void sys_arch_reboot(int type) static int nordicsemi_nrf52_init(void) { - uint32_t key; - - - key = irq_lock(); - #ifdef CONFIG_NRF_ENABLE_ICACHE /* Enable the instruction cache */ NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Msk; @@ -55,13 +49,6 @@ static int nordicsemi_nrf52_init(void) nrf_power_dcdcen_vddh_set(NRF_POWER, true); #endif - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/nordic_nrf/nrf53/soc.c b/soc/arm/nordic_nrf/nrf53/soc.c index 7f8e1b5ba818..be2c36c3bbe2 100644 --- a/soc/arm/nordic_nrf/nrf53/soc.c +++ b/soc/arm/nordic_nrf/nrf53/soc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -144,10 +143,6 @@ bool z_arm_on_enter_cpu_idle(void) static int nordicsemi_nrf53_init(void) { - uint32_t key; - - key = irq_lock(); - #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF_ENABLE_CACHE) #if !defined(CONFIG_BUILD_WITH_TFM) /* Enable the instruction & data cache. @@ -237,13 +232,6 @@ static int nordicsemi_nrf53_init(void) enable_ram_retention(); #endif /* CONFIG_PM_S2RAM */ - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/nordic_nrf/nrf91/soc.c b/soc/arm/nordic_nrf/nrf91/soc.c index e1938cbf9ce5..500d26ee76b6 100644 --- a/soc/arm/nordic_nrf/nrf91/soc.c +++ b/soc/arm/nordic_nrf/nrf91/soc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -24,23 +23,11 @@ LOG_MODULE_REGISTER(soc); static int nordicsemi_nrf91_init(void) { - uint32_t key; - - - key = irq_lock(); - #ifdef CONFIG_NRF_ENABLE_ICACHE /* Enable the instruction cache */ NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Msk; #endif - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/nxp_imx/mcimx6x_m4/soc.c b/soc/arm/nxp_imx/mcimx6x_m4/soc.c index 3e664176da7c..e9a3b1d4df61 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/soc.c +++ b/soc/arm/nxp_imx/mcimx6x_m4/soc.c @@ -5,12 +5,10 @@ */ #include -#include #include #include #include #include -#include #include "wdog_imx.h" /* Initialize Resource Domain Controller. */ @@ -288,12 +286,6 @@ static void SOC_ClockInit(void) */ static int mcimx6x_m4_init(void) { - - unsigned int oldLevel; /* Old interrupt lock level */ - - /* Disable interrupts */ - oldLevel = irq_lock(); - /* Configure RDC */ SOC_RdcInit(); @@ -306,15 +298,6 @@ static int mcimx6x_m4_init(void) /* Initialize clock */ SOC_ClockInit(); - /* - * Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* Restore interrupt state */ - irq_unlock(oldLevel); - return 0; } diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 26d00952ffd1..d02046884a16 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER #include @@ -306,12 +305,6 @@ void imxrt_audio_codec_pll_init(uint32_t clock_name, uint32_t clk_src, static int imxrt_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - #ifndef CONFIG_IMXRT1XXX_CODE_CACHE /* SystemInit enables code cache, disable it here */ SCB_DisableICache(); @@ -333,14 +326,6 @@ static int imxrt_init(void) /* Initialize system clock */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index 9a4ec19d9c97..a308c5ac994a 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER #include @@ -630,13 +629,6 @@ void imxrt_post_init_display_interface(void) static int imxrt_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - - #if defined(CONFIG_SECOND_CORE_MCUX) && defined(CONFIG_CPU_CORTEX_M7) /** * Copy CM4 core from flash to memory. Note that depending on where the @@ -684,14 +676,6 @@ static int imxrt_init(void) /* Initialize system clock */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index 5dba2a28481b..2fbb7d609b30 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -12,10 +12,8 @@ * hardware for the RT5XX platforms. */ -#include #include #include -#include #include #include #include "fsl_power.h" @@ -472,29 +470,13 @@ void imxrt_post_init_display_interface(void) */ static int nxp_rt500_init(void) { - - /* old interrupt lock level */ - unsigned int oldLevel; - - /* disable interrupts */ - oldLevel = irq_lock(); - /* Initialize clocks with tool generated code */ clock_init(); - /* - * install default handler that simply resets the CPU if configured in - * the kernel, NOP otherwise - */ - NMI_INIT(); - #ifndef CONFIG_IMXRT5XX_CODE_CACHE CACHE64_DisableCache(CACHE64_CTRL0); #endif - /* restore interrupt state */ - irq_unlock(oldLevel); - return 0; } diff --git a/soc/arm/nxp_imx/rt6xx/soc.c b/soc/arm/nxp_imx/rt6xx/soc.c index 6f07a8a7952c..b691187c865a 100644 --- a/soc/arm/nxp_imx/rt6xx/soc.c +++ b/soc/arm/nxp_imx/rt6xx/soc.c @@ -352,29 +352,13 @@ void imxrt_usdhc_dat3_pull(bool pullup) static int nxp_rt600_init(void) { - - /* old interrupt lock level */ - unsigned int oldLevel; - - /* disable interrupts */ - oldLevel = irq_lock(); - /* Initialize clock */ clock_init(); - /* - * install default handler that simply resets the CPU if configured in - * the kernel, NOP otherwise - */ - NMI_INIT(); - #ifndef CONFIG_IMXRT6XX_CODE_CACHE CACHE64_DisableCache(CACHE64); #endif - /* restore interrupt state */ - irq_unlock(oldLevel); - return 0; } diff --git a/soc/arm/nxp_kinetis/k2x/soc.c b/soc/arm/nxp_kinetis/k2x/soc.c index 657d58a27343..dedb1367060a 100644 --- a/soc/arm/nxp_kinetis/k2x/soc.c +++ b/soc/arm/nxp_kinetis/k2x/soc.c @@ -118,26 +118,12 @@ static ALWAYS_INLINE void clock_init(void) static int fsl_frdm_k22f_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; /* Initialize PLL/system clock to 120 MHz */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_kinetis/k6x/soc.c b/soc/arm/nxp_kinetis/k6x/soc.c index 75a179477ceb..1464df9a3276 100644 --- a/soc/arm/nxp_kinetis/k6x/soc.c +++ b/soc/arm/nxp_kinetis/k6x/soc.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #define LPUART0SRC_OSCERCLK (1) @@ -129,15 +128,10 @@ static ALWAYS_INLINE void clock_init(void) static int k6x_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ #if !defined(CONFIG_ARM_MPU) uint32_t temp_reg; #endif /* !CONFIG_ARM_MPU */ - /* disable interrupts */ - oldLevel = irq_lock(); - /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; @@ -168,14 +162,6 @@ static int k6x_init(void) /* Initialize PLL/system clock up to 180 MHz */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_kinetis/k8x/soc.c b/soc/arm/nxp_kinetis/k8x/soc.c index 4f5c7c8f5254..50fa7c1b1095 100644 --- a/soc/arm/nxp_kinetis/k8x/soc.c +++ b/soc/arm/nxp_kinetis/k8x/soc.c @@ -94,15 +94,10 @@ static ALWAYS_INLINE void clk_init(void) static int k8x_init(void) { - - unsigned int old_level; /* old interrupt lock level */ #if !defined(CONFIG_ARM_MPU) uint32_t temp_reg; #endif /* !CONFIG_ARM_MPU */ - /* Disable interrupts */ - old_level = irq_lock(); - /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; @@ -122,15 +117,6 @@ static int k8x_init(void) /* Initialize system clocks and PLL */ clk_init(); - /* - * Install default handler that simply resets the CPU if - * configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* Restore interrupt state */ - irq_unlock(old_level); - return 0; } diff --git a/soc/arm/nxp_kinetis/ke1xf/soc.c b/soc/arm/nxp_kinetis/ke1xf/soc.c index 40967fb55515..b48ed1a88863 100644 --- a/soc/arm/nxp_kinetis/ke1xf/soc.c +++ b/soc/arm/nxp_kinetis/ke1xf/soc.c @@ -240,15 +240,10 @@ static ALWAYS_INLINE void clk_init(void) static int ke1xf_init(void) { - - unsigned int old_level; /* old interrupt lock level */ #if !defined(CONFIG_ARM_MPU) uint32_t temp_reg; #endif /* !CONFIG_ARM_MPU */ - /* Disable interrupts */ - old_level = irq_lock(); - #if !defined(CONFIG_ARM_MPU) /* * Disable memory protection and clear slave port errors. @@ -265,18 +260,10 @@ static int ke1xf_init(void) /* Initialize system clocks and PLL */ clk_init(); - /* - * Install default handler that simply resets the CPU if - * configured in the kernel, NOP otherwise - */ - NMI_INIT(); - #ifndef CONFIG_KINETIS_KE1XF_ENABLE_CODE_CACHE /* SystemInit will have enabled the code cache. Disable it here */ L1CACHE_DisableCodeCache(); #endif - /* Restore interrupt state */ - irq_unlock(old_level); return 0; } diff --git a/soc/arm/nxp_kinetis/kl2x/soc.c b/soc/arm/nxp_kinetis/kl2x/soc.c index 362242537818..3bb71d03e144 100644 --- a/soc/arm/nxp_kinetis/kl2x/soc.c +++ b/soc/arm/nxp_kinetis/kl2x/soc.c @@ -81,23 +81,9 @@ static ALWAYS_INLINE void clock_init(void) static int kl2x_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - /* Initialize system clock to 48 MHz */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_kinetis/kv5x/soc.c b/soc/arm/nxp_kinetis/kv5x/soc.c index b8339344ad82..4c566dadcd05 100644 --- a/soc/arm/nxp_kinetis/kv5x/soc.c +++ b/soc/arm/nxp_kinetis/kv5x/soc.c @@ -79,12 +79,6 @@ static ALWAYS_INLINE void clk_init(void) static int kv5x_init(void) { - - unsigned int old_level; /* old interrupt lock level */ - - /* Disable interrupts */ - old_level = irq_lock(); - /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; @@ -96,12 +90,6 @@ static int kv5x_init(void) /* Initialize system clocks and PLL */ clk_init(); - /* - * Install default handler that simply resets the CPU if - * configured in the kernel, NOP otherwise - */ - NMI_INIT(); - #ifndef CONFIG_KINETIS_KV5X_ENABLE_CODE_CACHE /* SystemInit will have enabled the code cache. Disable it here */ SCB_DisableICache(); @@ -111,9 +99,6 @@ static int kv5x_init(void) SCB_DisableDCache(); #endif - /* Restore interrupt state */ - irq_unlock(old_level); - return 0; } diff --git a/soc/arm/nxp_kinetis/kwx/soc_kw2xd.c b/soc/arm/nxp_kinetis/kwx/soc_kw2xd.c index c872e95e7fb4..eaecced4ae1b 100644 --- a/soc/arm/nxp_kinetis/kwx/soc_kw2xd.c +++ b/soc/arm/nxp_kinetis/kwx/soc_kw2xd.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #define PLLFLLSEL_MCGFLLCLK (0) @@ -149,26 +148,12 @@ static ALWAYS_INLINE void clock_init(void) */ static int kw2xd_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - /* release I/O power hold to allow normal run state */ PMC->REGSC |= PMC_REGSC_ACKISO_MASK; /* Initialize PLL/system clock to 48 MHz */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_kinetis/kwx/soc_kw4xz.c b/soc/arm/nxp_kinetis/kwx/soc_kw4xz.c index b178a30004b9..f9d4845eb278 100644 --- a/soc/arm/nxp_kinetis/kwx/soc_kw4xz.c +++ b/soc/arm/nxp_kinetis/kwx/soc_kw4xz.c @@ -11,7 +11,6 @@ #include #include #include -#include #define LPUART0SRC_OSCERCLK (1) #define TPMSRC_MCGPLLCLK (1) @@ -82,23 +81,9 @@ static ALWAYS_INLINE void clock_init(void) static int kwx_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - /* Initialize system clock to 40 MHz */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt b/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt index 88cafc9bc72a..84686ad59cd1 100644 --- a/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt +++ b/soc/arm/nxp_lpc/lpc11u6x/CMakeLists.txt @@ -3,11 +3,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/${ARCH}/include - ) diff --git a/soc/arm/nxp_lpc/lpc11u6x/soc.c b/soc/arm/nxp_lpc/lpc11u6x/soc.c deleted file mode 100644 index 8e2b8d3984bd..000000000000 --- a/soc/arm/nxp_lpc/lpc11u6x/soc.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2020, Seagate - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief System/hardware module for nxp_lpc11u6x platform - * - * This module provides routines to initialize and support board-level - * hardware for the nxp_lpc11u6x platform. - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * - * @brief Perform basic hardware initialization - * - * Initialize the interrupt controller device drivers. - * Also initialize the timer device driver, if required. - * - * @return 0 - */ - -static int nxp_lpc11u6x_init(void) -{ - - /* old interrupt lock level */ - unsigned int old_level; - - /* disable interrupts */ - old_level = irq_lock(); - - /* install default handler that simply resets the CPU if configured in - * the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(old_level); - - return 0; -} -SYS_INIT(nxp_lpc11u6x_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nxp_lpc/lpc54xxx/soc.c b/soc/arm/nxp_lpc/lpc54xxx/soc.c index 3625f580d4be..df7e5ac1c06e 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc54xxx/soc.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -109,13 +108,6 @@ static ALWAYS_INLINE void clock_init(void) static int nxp_lpc54114_init(void) { - - /* old interrupt lock level */ - unsigned int oldLevel; - - /* disable interrupts */ - oldLevel = irq_lock(); - /* Initialize FRO/system clock to 48 MHz */ clock_init(); @@ -124,15 +116,6 @@ static int nxp_lpc54114_init(void) PINT_Init(PINT); #endif - /* - * install default handler that simply resets the CPU if configured in - * the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); - return 0; } diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index ba7a55a13351..45c51d18424a 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -297,13 +297,6 @@ DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) static int nxp_lpc55xxx_init(void) { - - /* old interrupt lock level */ - unsigned int oldLevel; - - /* disable interrupts */ - oldLevel = irq_lock(); - z_arm_clear_faults(); /* Initialize FRO/system clock to 96 MHz */ @@ -314,15 +307,6 @@ static int nxp_lpc55xxx_init(void) PINT_Init(PINT); #endif - /* - * install default handler that simply resets the CPU if configured in - * the kernel, NOP otherwise - */ - NMI_INIT(); - - /* restore interrupt state */ - irq_unlock(oldLevel); - return 0; } diff --git a/soc/arm/nxp_s32/s32ze/soc.c b/soc/arm/nxp_s32/s32ze/soc.c index 0c79067ce419..5e242d413ae0 100644 --- a/soc/arm/nxp_s32/s32ze/soc.c +++ b/soc/arm/nxp_s32/s32ze/soc.c @@ -45,12 +45,6 @@ void z_arm_platform_init(void) static int soc_init(void) { - - /* Install default handler that simply resets the CPU if configured in the - * kernel, NOP otherwise - */ - NMI_INIT(); - OsIf_Init(NULL); #ifdef CONFIG_INIT_CLOCK_AT_BOOT_TIME diff --git a/soc/arm/quicklogic_eos_s3/soc.c b/soc/arm/quicklogic_eos_s3/soc.c index 56f7323db994..81d070df427c 100644 --- a/soc/arm/quicklogic_eos_s3/soc.c +++ b/soc/arm/quicklogic_eos_s3/soc.c @@ -66,9 +66,6 @@ static void eos_s3_cru_init(void) static int eos_s3_init(void) { - uint32_t key; - - /* Clocks setup */ eos_s3_lock_enable(); eos_s3_cru_init(); @@ -82,12 +79,6 @@ static int eos_s3_init(void) /* Enable UART interrupt */ INTR_CTRL->OTHER_INTR_EN_M4 = UART_INTR_EN_M4; - key = irq_lock(); - - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/renesas_rcar/gen3/soc.c b/soc/arm/renesas_rcar/gen3/soc.c index 29b7acf0acbb..9dc79e0394d4 100644 --- a/soc/arm/renesas_rcar/gen3/soc.c +++ b/soc/arm/renesas_rcar/gen3/soc.c @@ -7,26 +7,8 @@ #include #include -#include #include -/** - * - * @brief Perform basic hardware initialization - * - * @return 0 - */ - -static int soc_init(void) -{ - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - return 0; -} - void z_arm_platform_init(void) { L1C_DisableCaches(); @@ -40,5 +22,3 @@ void z_arm_platform_init(void) L1C_EnableCaches(); L1C_EnableBTAC(); } - -SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/renesas_smartbond/da1469x/soc.c b/soc/arm/renesas_smartbond/da1469x/soc.c index b353b10ef1cf..7bef1f9fdf2a 100644 --- a/soc/arm/renesas_smartbond/da1469x/soc.c +++ b/soc/arm/renesas_smartbond/da1469x/soc.c @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -110,9 +109,6 @@ void z_arm_platform_init(void) static int renesas_da14699_init(void) { - - NMI_INIT(); - /* Freeze watchdog until configured */ GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk; /* Reset clock dividers to 0 */ diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c index 8af2f884a523..d953436f77e3 100644 --- a/soc/arm/rpi_pico/rp2/soc.c +++ b/soc/arm/rpi_pico/rp2/soc.c @@ -15,7 +15,6 @@ #include -#include #include #include #include @@ -29,8 +28,6 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); static int rp2040_init(void) { - uint32_t key; - reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS | RESETS_RESET_PLL_USB_BITS | RESETS_RESET_PLL_SYS_BITS)); @@ -44,16 +41,6 @@ static int rp2040_init(void) unreset_block_wait(RESETS_RESET_BITS); - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - return 0; } diff --git a/soc/arm/silabs_exx32/common/soc.c b/soc/arm/silabs_exx32/common/soc.c index 9ce5ff859ca1..c2e152aec080 100644 --- a/soc/arm/silabs_exx32/common/soc.c +++ b/soc/arm/silabs_exx32/common/soc.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include @@ -209,12 +208,6 @@ static void swo_init(void) */ static int silabs_exx32_init(void) { - - unsigned int oldLevel; /* old interrupt lock level */ - - /* disable interrupts */ - oldLevel = irq_lock(); - /* handle chip errata */ CHIP_Init(); @@ -242,20 +235,12 @@ static int silabs_exx32_init(void) /* Initialize system clock according to CONFIG_CMU settings */ clock_init(); - /* - * install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - #ifdef CONFIG_LOG_BACKEND_SWO /* Configure SWO debug output */ swo_init(); #endif #endif /* !CONFIG_SOC_GECKO_DEV_INIT */ - /* restore interrupt state */ - irq_unlock(oldLevel); return 0; } diff --git a/soc/arm/st_stm32/stm32c0/soc.c b/soc/arm/st_stm32/stm32c0/soc.c index 4bff4d055e3a..14ad99a278db 100644 --- a/soc/arm/st_stm32/stm32c0/soc.c +++ b/soc/arm/st_stm32/stm32c0/soc.c @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include #include #include @@ -28,18 +25,6 @@ */ static int stm32c0_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 48 MHz from HSI */ SystemCoreClock = 48000000; diff --git a/soc/arm/st_stm32/stm32f0/soc.c b/soc/arm/st_stm32/stm32f0/soc.c index c5bb64ece302..a59e9214203c 100644 --- a/soc/arm/st_stm32/stm32f0/soc.c +++ b/soc/arm/st_stm32/stm32f0/soc.c @@ -12,10 +12,7 @@ #include #include #include -#include #include -#include -#include #include #include @@ -69,18 +66,6 @@ void relocate_vector_table(void) */ static int stm32f0_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 8 MHz from HSI */ SystemCoreClock = 8000000; diff --git a/soc/arm/st_stm32/stm32f1/soc.c b/soc/arm/st_stm32/stm32f1/soc.c index e5f77d472340..b4f034dbc257 100644 --- a/soc/arm/st_stm32/stm32f1/soc.c +++ b/soc/arm/st_stm32/stm32f1/soc.c @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include /** * @brief Perform basic hardware initialization at boot. @@ -26,18 +23,6 @@ */ static int stm32f1_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 8 MHz from HSI */ SystemCoreClock = 8000000; diff --git a/soc/arm/st_stm32/stm32f2/soc.c b/soc/arm/st_stm32/stm32f2/soc.c index 4f6b1a397350..89e711b62c42 100644 --- a/soc/arm/st_stm32/stm32f2/soc.c +++ b/soc/arm/st_stm32/stm32f2/soc.c @@ -13,12 +13,9 @@ #include #include #include -#include #include -#include #include #include -#include #include /** @@ -31,22 +28,10 @@ */ static int stm32f2_init(void) { - uint32_t key; - - /* Enable ART Flash cache accelerator for both Instruction and Data */ LL_FLASH_EnableInstCache(); LL_FLASH_EnableDataCache(); - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/arm/st_stm32/stm32f3/soc.c b/soc/arm/st_stm32/stm32f3/soc.c index dd357e6c1821..97a29e35a8d2 100644 --- a/soc/arm/st_stm32/stm32f3/soc.c +++ b/soc/arm/st_stm32/stm32f3/soc.c @@ -12,10 +12,7 @@ #include #include #include -#include #include -#include -#include /** * @brief Perform basic hardware initialization at boot. @@ -27,18 +24,6 @@ */ static int stm32f3_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 8 MHz from HSI */ SystemCoreClock = 8000000; diff --git a/soc/arm/st_stm32/stm32f4/soc.c b/soc/arm/st_stm32/stm32f4/soc.c index 616a513caee2..66f1bb7e7959 100644 --- a/soc/arm/st_stm32/stm32f4/soc.c +++ b/soc/arm/st_stm32/stm32f4/soc.c @@ -12,10 +12,7 @@ #include #include -#include #include -#include -#include #include @@ -29,22 +26,10 @@ */ static int st_stm32f4_init(void) { - uint32_t key; - - /* Enable ART Flash cache accelerator for both instruction and data */ LL_FLASH_EnableInstCache(); LL_FLASH_EnableDataCache(); - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/arm/st_stm32/stm32f7/soc.c b/soc/arm/st_stm32/stm32f7/soc.c index c1768a884be7..2f42610403c2 100644 --- a/soc/arm/st_stm32/stm32f7/soc.c +++ b/soc/arm/st_stm32/stm32f7/soc.c @@ -13,10 +13,7 @@ #include #include #include -#include #include -#include -#include #include /** @@ -29,14 +26,9 @@ */ static int st_stm32f7_init(void) { - uint32_t key; - - /* Enable ART Flash cache accelerator */ LL_FLASH_EnableART(); - key = irq_lock(); - SCB_EnableICache(); if (IS_ENABLED(CONFIG_DCACHE)) { @@ -45,13 +37,6 @@ static int st_stm32f7_init(void) } } - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/arm/st_stm32/stm32g0/soc.c b/soc/arm/st_stm32/stm32g0/soc.c index 854737cb2d97..15a3f9b27fc7 100644 --- a/soc/arm/st_stm32/stm32g0/soc.c +++ b/soc/arm/st_stm32/stm32g0/soc.c @@ -12,10 +12,7 @@ #include #include -#include #include -#include -#include #include #include #if defined(SYSCFG_CFGR1_UCPD1_STROBE) || defined(SYSCFG_CFGR1_UCPD2_STROBE) @@ -83,18 +80,6 @@ static void stm32g0_disable_dead_battery(void) */ static int stm32g0_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/arm/st_stm32/stm32g4/soc.c b/soc/arm/st_stm32/stm32g4/soc.c index 1ab0e8de3838..ddc48c801f4d 100644 --- a/soc/arm/st_stm32/stm32g4/soc.c +++ b/soc/arm/st_stm32/stm32g4/soc.c @@ -12,10 +12,7 @@ #include #include #include -#include #include -#include -#include #if defined(PWR_CR3_UCPD_DBDIS) #include @@ -32,18 +29,6 @@ */ static int stm32g4_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ SystemCoreClock = 16000000; diff --git a/soc/arm/st_stm32/stm32h5/soc.c b/soc/arm/st_stm32/stm32h5/soc.c index 6b2b72ac73fd..67a5075024e2 100644 --- a/soc/arm/st_stm32/stm32h5/soc.c +++ b/soc/arm/st_stm32/stm32h5/soc.c @@ -14,10 +14,7 @@ #include #include #include -#include #include -#include -#include #include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL @@ -33,18 +30,6 @@ LOG_MODULE_REGISTER(soc); */ static int stm32h5_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); LL_ICACHE_Enable(); diff --git a/soc/arm/st_stm32/stm32h7/soc_m4.c b/soc/arm/st_stm32/stm32h7/soc_m4.c index a7543a131710..7bd4a9ec0ecc 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m4.c +++ b/soc/arm/st_stm32/stm32h7/soc_m4.c @@ -12,16 +12,13 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include -#include #include "stm32_hsem.h" /** @@ -34,22 +31,11 @@ */ static int stm32h7_m4_init(void) { - uint32_t key; - /* Enable ART Flash cache accelerator */ LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ART); LL_ART_SetBaseAddress(DT_REG_ADDR(DT_CHOSEN(zephyr_flash))); LL_ART_Enable(); - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* In case CM4 has not been forced boot by CM7, * CM4 needs to wait until CM7 has setup clock configuration */ diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 2898fb3e1093..46b871dfb907 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m7.c +++ b/soc/arm/st_stm32/stm32h7/soc_m7.c @@ -12,15 +12,12 @@ #include #include #include -#include #include #include #include #include #include -#include #include -#include #include "stm32_hsem.h" #if defined(CONFIG_STM32H7_DUAL_CORE) @@ -56,11 +53,6 @@ static int stm32h7_m4_wakeup(void) */ static int stm32h7_init(void) { - uint32_t key; - - - key = irq_lock(); - SCB_EnableICache(); if (IS_ENABLED(CONFIG_DCACHE)) { @@ -69,13 +61,6 @@ static int stm32h7_init(void) } } - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 64 MHz from HSI */ SystemCoreClock = 64000000; diff --git a/soc/arm/st_stm32/stm32l0/soc.c b/soc/arm/st_stm32/stm32l0/soc.c index e8f2bc81a1e8..247a61d13333 100644 --- a/soc/arm/st_stm32/stm32l0/soc.c +++ b/soc/arm/st_stm32/stm32l0/soc.c @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include #include #include #include @@ -31,18 +28,6 @@ */ static int stm32l0_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 2.1 MHz from MSI */ SystemCoreClock = 2097152; diff --git a/soc/arm/st_stm32/stm32l1/soc.c b/soc/arm/st_stm32/stm32l1/soc.c index 00d9f662ff42..20b3af7f3d7d 100644 --- a/soc/arm/st_stm32/stm32l1/soc.c +++ b/soc/arm/st_stm32/stm32l1/soc.c @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include #include #include #include @@ -30,18 +27,6 @@ */ static int stm32l1_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 2.1 MHz from MSI */ SystemCoreClock = 2097000; diff --git a/soc/arm/st_stm32/stm32l4/soc.c b/soc/arm/st_stm32/stm32l4/soc.c index 7bb37722384f..61cf5e6d36ac 100644 --- a/soc/arm/st_stm32/stm32l4/soc.c +++ b/soc/arm/st_stm32/stm32l4/soc.c @@ -12,10 +12,7 @@ #include #include -#include #include -#include -#include #include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL @@ -32,18 +29,6 @@ LOG_MODULE_REGISTER(soc); */ static int stm32l4_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ SystemCoreClock = 4000000; diff --git a/soc/arm/st_stm32/stm32l5/soc.c b/soc/arm/st_stm32/stm32l5/soc.c index 1db1bf0411a5..fb7b956d72d4 100644 --- a/soc/arm/st_stm32/stm32l5/soc.c +++ b/soc/arm/st_stm32/stm32l5/soc.c @@ -13,10 +13,7 @@ #include #include #include -#include #include -#include -#include #include #include @@ -33,23 +30,11 @@ LOG_MODULE_REGISTER(soc); */ static int stm32l5_init(void) { - uint32_t key; - - /* Enable ICACHE */ while (LL_ICACHE_IsActiveFlag_BUSY()) { } LL_ICACHE_Enable(); - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ SystemCoreClock = 4000000; diff --git a/soc/arm/st_stm32/stm32mp1/soc.c b/soc/arm/st_stm32/stm32mp1/soc.c index 35d8155ab887..fc95eab56ad7 100644 --- a/soc/arm/st_stm32/stm32mp1/soc.c +++ b/soc/arm/st_stm32/stm32mp1/soc.c @@ -14,10 +14,7 @@ #include #include #include -#include #include -#include -#include /** * @brief Perform basic hardware initialization at boot. @@ -29,18 +26,6 @@ */ static int stm32m4_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /*HW semaphore Clock enable*/ LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_HSEM); diff --git a/soc/arm/st_stm32/stm32u5/soc.c b/soc/arm/st_stm32/stm32u5/soc.c index ddd1f304a8fd..a775a1d20003 100644 --- a/soc/arm/st_stm32/stm32u5/soc.c +++ b/soc/arm/st_stm32/stm32u5/soc.c @@ -14,10 +14,7 @@ #include #include #include -#include #include -#include -#include #include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL @@ -33,18 +30,6 @@ LOG_MODULE_REGISTER(soc); */ static int stm32u5_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); LL_ICACHE_Enable(); diff --git a/soc/arm/st_stm32/stm32wb/soc.c b/soc/arm/st_stm32/stm32wb/soc.c index af45930da299..3fd07aefb975 100644 --- a/soc/arm/st_stm32/stm32wb/soc.c +++ b/soc/arm/st_stm32/stm32wb/soc.c @@ -11,11 +11,8 @@ #include #include -#include #include -#include #include -#include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); @@ -30,18 +27,6 @@ LOG_MODULE_REGISTER(soc); */ static int stm32wb_init(void) { - uint32_t key; - - - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ SystemCoreClock = 4000000; diff --git a/soc/arm/st_stm32/stm32wl/soc.c b/soc/arm/st_stm32/stm32wl/soc.c index 4524a726626e..928f97429c55 100644 --- a/soc/arm/st_stm32/stm32wl/soc.c +++ b/soc/arm/st_stm32/stm32wl/soc.c @@ -11,10 +11,7 @@ #include #include -#include #include -#include -#include #include @@ -34,22 +31,10 @@ LOG_MODULE_REGISTER(soc); */ static int stm32wl_init(void) { - uint32_t key; - - /* Enable CPU data and instruction cache */ LL_FLASH_EnableInstCache(); LL_FLASH_EnableDataCache(); - key = irq_lock(); - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - - irq_unlock(key); - /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 4 MHz from MSI */ SystemCoreClock = 4000000; diff --git a/soc/arm/ti_lm3s6965/CMakeLists.txt b/soc/arm/ti_lm3s6965/CMakeLists.txt index 1701f41c83f5..c5f6f41f49ab 100644 --- a/soc/arm/ti_lm3s6965/CMakeLists.txt +++ b/soc/arm/ti_lm3s6965/CMakeLists.txt @@ -3,7 +3,6 @@ zephyr_library() zephyr_library_sources( - soc.c soc_config.c reboot.S sys_arch_reboot.c diff --git a/soc/arm/ti_lm3s6965/soc.c b/soc/arm/ti_lm3s6965/soc.c deleted file mode 100644 index 596dd9d75691..000000000000 --- a/soc/arm/ti_lm3s6965/soc.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013-2015 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief System/hardware module for ti_lm3s6965 platform - * - * This module provides routines to initialize and support board-level hardware - * for the ti_lm3s6965 platform. - */ - -#include -#include -#include -#include - -#include - -/** - * - * @brief Perform basic hardware initialization - * - * Initialize the interrupt controller device drivers and the - * integrated 16550-compatible UART device driver. - * Also initialize the timer device driver, if required. - * - * @return 0 - */ - -static int ti_lm3s6965_init(void) -{ - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - return 0; -} - -SYS_INIT(ti_lm3s6965_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/xilinx_zynq7000/xc7zxxx/soc.c b/soc/arm/xilinx_zynq7000/xc7zxxx/soc.c index ef00fda9c09f..253bd31c83cb 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxx/soc.c +++ b/soc/arm/xilinx_zynq7000/xc7zxxx/soc.c @@ -6,13 +6,11 @@ #include #include #include -#include #include #include #include #include -#include #include "soc.h" /* System Level Control Registers (SLCR) */ @@ -71,23 +69,6 @@ const struct arm_mmu_config mmu_config = { .mmu_regions = mmu_regions, }; -/** - * @brief Basic hardware initialization of the Zynq-7000 SoC - * - * Performs the basic initialization of the Zynq-7000 SoC. - * - * @return 0 - */ -static int soc_xlnx_zynq7000_init(void) -{ - NMI_INIT(); - - return 0; -} - -SYS_INIT(soc_xlnx_zynq7000_init, PRE_KERNEL_1, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - /* Platform-specific early initialization */ void z_arm_platform_init(void) diff --git a/soc/arm/xilinx_zynq7000/xc7zxxxs/soc.c b/soc/arm/xilinx_zynq7000/xc7zxxxs/soc.c index 1d3c24d1e730..f3b1137cb28d 100644 --- a/soc/arm/xilinx_zynq7000/xc7zxxxs/soc.c +++ b/soc/arm/xilinx_zynq7000/xc7zxxxs/soc.c @@ -6,13 +6,11 @@ #include #include #include -#include #include #include #include #include -#include #include "soc.h" /* System Level Configuration Registers */ @@ -71,23 +69,6 @@ const struct arm_mmu_config mmu_config = { .mmu_regions = mmu_regions, }; -/** - * @brief Basic hardware initialization of the Zynq-7000 SoC - * - * Performs the basic initialization of the Zynq-7000 SoC. - * - * @return 0 - */ -static int soc_xlnx_zynq7000s_init(void) -{ - NMI_INIT(); - - return 0; -} - -SYS_INIT(soc_xlnx_zynq7000s_init, PRE_KERNEL_1, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - /* Platform-specific early initialization */ void z_arm_platform_init(void) diff --git a/soc/arm/xilinx_zynqmp/soc.c b/soc/arm/xilinx_zynqmp/soc.c index 3073869e084b..f84dc48f74e5 100644 --- a/soc/arm/xilinx_zynqmp/soc.c +++ b/soc/arm/xilinx_zynqmp/soc.c @@ -7,28 +7,8 @@ #include #include -#include #include -/** - * - * @brief Perform basic hardware initialization - * - * @return 0 - */ - -static int soc_init(void) -{ - - /* Install default handler that simply resets the CPU - * if configured in the kernel, NOP otherwise - */ - NMI_INIT(); - return 0; -} - -SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - void z_arm_platform_init(void) { /* From 7b98cd6404416d774b3366c6ff7804c31cb114ac Mon Sep 17 00:00:00 2001 From: Gerard Marull-Paretas Date: Fri, 30 Jun 2023 11:16:44 +0200 Subject: [PATCH 0847/2042] arch: arm: nmi: remove dummy NMI_INIT() It is no longer used, so it can be dropped now. Signed-off-by: Gerard Marull-Paretas --- include/zephyr/arch/arm/aarch32/nmi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/zephyr/arch/arm/aarch32/nmi.h b/include/zephyr/arch/arm/aarch32/nmi.h index e3c65504dc31..a4bd85802c1a 100644 --- a/include/zephyr/arch/arm/aarch32/nmi.h +++ b/include/zephyr/arch/arm/aarch32/nmi.h @@ -17,6 +17,4 @@ extern void z_arm_nmi_set_handler(void (*pHandler)(void)); #endif -#define NMI_INIT() - #endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ */ From 0885416b602acef926806581626f36803674142f Mon Sep 17 00:00:00 2001 From: Arkadiusz Kozdra Date: Wed, 22 Mar 2023 16:59:16 +0100 Subject: [PATCH 0848/2042] bluetooth: host: add checks for connection types Fail gracefully if an HCI event of one type arrives for a handle of a different connection type. The requested types are currently based on what fields are used, not on the usage context, in order to keep every correct use so far still working. A warning is logged if the connection identified by the handle does not match the requested connection type. Signed-off-by: Arkadiusz Kozdra --- subsys/bluetooth/host/adv.c | 2 +- subsys/bluetooth/host/br.c | 4 ++-- subsys/bluetooth/host/conn.c | 24 +++++++++++++++++------- subsys/bluetooth/host/conn_internal.h | 2 +- subsys/bluetooth/host/direction.c | 6 +++--- subsys/bluetooth/host/hci_core.c | 26 +++++++++++++------------- subsys/bluetooth/host/iso.c | 8 ++++---- subsys/bluetooth/host/scan.c | 3 ++- subsys/bluetooth/host/ssp.c | 2 +- 9 files changed, 44 insertions(+), 33 deletions(-) diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index dc6856ead2d2..613bf62fa146 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -2195,7 +2195,7 @@ void bt_hci_le_adv_set_terminated(struct net_buf *buf) } if (IS_ENABLED(CONFIG_BT_CONN) && !evt->status) { - struct bt_conn *conn = bt_conn_lookup_handle(conn_handle); + struct bt_conn *conn = bt_conn_lookup_handle(conn_handle, BT_CONN_TYPE_LE); if (conn) { if (IS_ENABLED(CONFIG_BT_PRIVACY) && diff --git a/subsys/bluetooth/host/br.c b/subsys/bluetooth/host/br.c index 1d4851686cdd..6a2b16d6aa5c 100644 --- a/subsys/bluetooth/host/br.c +++ b/subsys/bluetooth/host/br.c @@ -625,7 +625,7 @@ void bt_hci_read_remote_features_complete(struct net_buf *buf) LOG_DBG("status 0x%02x handle %u", evt->status, handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_BR); if (!conn) { LOG_ERR("Can't find conn for handle %u", handle); return; @@ -666,7 +666,7 @@ void bt_hci_read_remote_ext_features_complete(struct net_buf *buf) LOG_DBG("status 0x%02x handle %u", evt->status, handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_BR); if (!conn) { LOG_ERR("Can't find conn for handle %u", handle); return; diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index b6d95b83ebd1..782f4fd87bd4 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1079,8 +1079,10 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) conn->role == BT_CONN_ROLE_PERIPHERAL) { #if defined(CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS) - conn->le.conn_param_retry_countdown = - CONFIG_BT_CONN_PARAM_RETRY_COUNT; + if (conn->type == BT_CONN_TYPE_LE) { + conn->le.conn_param_retry_countdown = + CONFIG_BT_CONN_PARAM_RETRY_COUNT; + } #endif /* CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS */ k_work_schedule(&conn->deferred_work, @@ -1205,31 +1207,39 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) } } -struct bt_conn *bt_conn_lookup_handle(uint16_t handle) +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, int type) { struct bt_conn *conn; #if defined(CONFIG_BT_CONN) conn = conn_lookup_handle(acl_conns, ARRAY_SIZE(acl_conns), handle); if (conn) { - return conn; + goto found; } #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_ISO) conn = conn_lookup_handle(iso_conns, ARRAY_SIZE(iso_conns), handle); if (conn) { - return conn; + goto found; } #endif - #if defined(CONFIG_BT_BREDR) +#if defined(CONFIG_BT_BREDR) conn = conn_lookup_handle(sco_conns, ARRAY_SIZE(sco_conns), handle); if (conn) { - return conn; + goto found; } #endif +found: + if (conn) { + if (type & conn->type) { + return conn; + } + LOG_WRN("incompatible handle %u", handle); + bt_conn_unref(conn); + } return NULL; } diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index ce89a65dd45f..eac811260c32 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -308,7 +308,7 @@ void bt_conn_disconnect_all(uint8_t id); struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size); /* Look up an existing connection */ -struct bt_conn *bt_conn_lookup_handle(uint16_t handle); +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, int type); static inline bool bt_conn_is_handle_valid(struct bt_conn *conn) { diff --git a/subsys/bluetooth/host/direction.c b/subsys/bluetooth/host/direction.c index 76c4b190b24e..84ca24126c19 100644 --- a/subsys/bluetooth/host/direction.c +++ b/subsys/bluetooth/host/direction.c @@ -680,7 +680,7 @@ int hci_df_prepare_connection_iq_report(struct net_buf *buf, evt = net_buf_pull_mem(buf, sizeof(*evt)); - conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle)); + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle), BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unknown conn handle 0x%04X for iq samples report", sys_le16_to_cpu(evt->conn_handle)); @@ -732,7 +732,7 @@ int hci_df_vs_prepare_connection_iq_report(struct net_buf *buf, evt = net_buf_pull_mem(buf, sizeof(*evt)); - conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle)); + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle), BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unknown conn handle 0x%04X for iq samples report", sys_le16_to_cpu(evt->conn_handle)); @@ -857,7 +857,7 @@ int hci_df_prepare_conn_cte_req_failed(struct net_buf *buf, evt = net_buf_pull_mem(buf, sizeof(*evt)); - conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle)); + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->conn_handle), BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unknown conn handle 0x%04X for iq samples report", sys_le16_to_cpu(evt->conn_handle)); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 0713fca69c23..994cfe32e101 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -447,7 +447,7 @@ static void hci_num_completed_packets(struct net_buf *buf) LOG_DBG("handle %u count %u", handle, count); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("No connection for handle %u", handle); continue; @@ -520,7 +520,7 @@ static void hci_acl(struct net_buf *buf) return; } - conn = bt_conn_lookup_handle(acl(buf)->handle); + conn = bt_conn_lookup_handle(acl(buf)->handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("Unable to find conn for handle %u", acl(buf)->handle); net_buf_unref(buf); @@ -824,7 +824,7 @@ static void hci_disconn_complete_prio(struct net_buf *buf) return; } - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { /* Priority disconnect complete event received before normal * connection complete event. @@ -849,7 +849,7 @@ static void hci_disconn_complete(struct net_buf *buf) return; } - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("Unable to look up conn with handle %u", handle); return; @@ -1617,7 +1617,7 @@ static void le_remote_feat_complete(struct net_buf *buf) uint16_t handle = sys_le16_to_cpu(evt->handle); struct bt_conn *conn; - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); return; @@ -1645,7 +1645,7 @@ static void le_data_len_change(struct net_buf *buf) uint16_t handle = sys_le16_to_cpu(evt->handle); struct bt_conn *conn; - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); return; @@ -1678,7 +1678,7 @@ static void le_phy_update_complete(struct net_buf *buf) uint16_t handle = sys_le16_to_cpu(evt->handle); struct bt_conn *conn; - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); return; @@ -1774,7 +1774,7 @@ static void le_conn_param_req(struct net_buf *buf) param.latency = sys_le16_to_cpu(evt->latency); param.timeout = sys_le16_to_cpu(evt->timeout); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); le_conn_param_neg_reply(handle, BT_HCI_ERR_UNKNOWN_CONN_ID); @@ -1800,7 +1800,7 @@ static void le_conn_update_complete(struct net_buf *buf) LOG_DBG("status 0x%02x, handle %u", evt->status, handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); return; @@ -2020,7 +2020,7 @@ static void hci_encrypt_change(struct net_buf *buf) LOG_DBG("status 0x%02x handle %u encrypt 0x%02x", evt->status, handle, evt->encrypt); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("Unable to look up conn with handle %u", handle); return; @@ -2095,7 +2095,7 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf) LOG_DBG("status 0x%02x handle %u", evt->status, handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("Unable to look up conn with handle %u", handle); return; @@ -2151,7 +2151,7 @@ static void bt_hci_evt_read_remote_version_complete(struct net_buf *buf) evt = net_buf_pull_mem(buf, sizeof(*evt)); handle = sys_le16_to_cpu(evt->handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ALL); if (!conn) { LOG_ERR("No connection for handle %u", handle); return; @@ -2232,7 +2232,7 @@ static void le_ltk_request(struct net_buf *buf) LOG_DBG("handle %u", handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); if (!conn) { LOG_ERR("Unable to lookup conn for handle %u", handle); return; diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 6e9976fa8154..9becf9ff1e9f 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -124,7 +124,7 @@ void hci_iso(struct net_buf *buf) return; } - iso = bt_conn_lookup_handle(iso(buf)->handle); + iso = bt_conn_lookup_handle(iso(buf)->handle, BT_CONN_TYPE_ISO); if (iso == NULL) { LOG_ERR("Unable to find conn for handle %u", iso(buf)->handle); net_buf_unref(buf); @@ -982,7 +982,7 @@ void hci_le_cis_established(struct net_buf *buf) LOG_DBG("status 0x%02x handle %u", evt->status, handle); /* ISO connection handles are already assigned at this point */ - iso = bt_conn_lookup_handle(handle); + iso = bt_conn_lookup_handle(handle, BT_CONN_TYPE_ISO); if (!iso) { LOG_ERR("No connection found for handle %u", handle); return; @@ -1229,7 +1229,7 @@ void hci_le_cis_req(struct net_buf *buf) } /* Lookup existing connection with same handle */ - iso = bt_conn_lookup_handle(cis_handle); + iso = bt_conn_lookup_handle(cis_handle, BT_CONN_TYPE_ISO); if (iso) { LOG_ERR("Invalid ISO handle %u", cis_handle); hci_le_reject_cis(cis_handle, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); @@ -1238,7 +1238,7 @@ void hci_le_cis_req(struct net_buf *buf) } /* Lookup ACL connection to attach */ - acl = bt_conn_lookup_handle(acl_handle); + acl = bt_conn_lookup_handle(acl_handle, BT_CONN_TYPE_LE); if (!acl) { LOG_ERR("Invalid ACL handle %u", acl_handle); hci_le_reject_cis(cis_handle, BT_HCI_ERR_UNKNOWN_CONN_ID); diff --git a/subsys/bluetooth/host/scan.c b/subsys/bluetooth/host/scan.c index 4aa7ab5b3e41..168d7f6ead38 100644 --- a/subsys/bluetooth/host/scan.c +++ b/subsys/bluetooth/host/scan.c @@ -1201,7 +1201,8 @@ static void bt_hci_le_past_received_common(struct net_buf *buf) } sync_info.conn = bt_conn_lookup_handle( - sys_le16_to_cpu(evt->conn_handle)); + sys_le16_to_cpu(evt->conn_handle), + BT_CONN_TYPE_LE); if (!sync_info.conn) { LOG_ERR("Could not lookup connection handle from PAST"); diff --git a/subsys/bluetooth/host/ssp.c b/subsys/bluetooth/host/ssp.c index 0c8ba58c2182..814a35b32fb5 100644 --- a/subsys/bluetooth/host/ssp.c +++ b/subsys/bluetooth/host/ssp.c @@ -779,7 +779,7 @@ void bt_hci_auth_complete(struct net_buf *buf) LOG_DBG("status 0x%02x, handle %u", evt->status, handle); - conn = bt_conn_lookup_handle(handle); + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_BR); if (!conn) { LOG_ERR("Can't find conn for handle %u", handle); return; From 82d8f09de18708259b85e5bbf5e32541fd807ed4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Kozdra Date: Wed, 28 Jun 2023 17:02:51 +0200 Subject: [PATCH 0849/2042] bluetooth: host: track connection type enum The enum used for connection types gets named bt_conn_type to guard against accidental usage of generic integers with relation to it. The added default case in several switch statements avoids warnings against unhandled enum values. Signed-off-by: Arkadiusz Kozdra --- include/zephyr/bluetooth/conn.h | 35 +++++++++++++------------- subsys/bluetooth/host/conn.c | 7 ++++-- subsys/bluetooth/host/conn_internal.h | 4 +-- subsys/bluetooth/shell/bt.c | 4 +++ tests/bluetooth/host/keys/mocks/conn.c | 2 +- tests/bluetooth/host/keys/mocks/conn.h | 2 +- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index a6c6d3b0366c..81a96937b08e 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -196,6 +196,21 @@ struct bt_conn_le_data_len_param { BT_CONN_LE_DATA_LEN_PARAM(BT_GAP_DATA_LEN_MAX, \ BT_GAP_DATA_TIME_MAX) +/** Connection Type */ +enum __packed bt_conn_type { + /** LE Connection Type */ + BT_CONN_TYPE_LE = BIT(0), + /** BR/EDR Connection Type */ + BT_CONN_TYPE_BR = BIT(1), + /** SCO Connection Type */ + BT_CONN_TYPE_SCO = BIT(2), + /** ISO Connection Type */ + BT_CONN_TYPE_ISO = BIT(3), + /** All Connection Type */ + BT_CONN_TYPE_ALL = BT_CONN_TYPE_LE | BT_CONN_TYPE_BR | + BT_CONN_TYPE_SCO | BT_CONN_TYPE_ISO, +}; + /** @brief Increment a connection's reference count. * * Increment the reference count of a connection object. @@ -233,7 +248,8 @@ void bt_conn_unref(struct bt_conn *conn); * @param func Function to call for each connection. * @param data Data to pass to the callback function. */ -void bt_conn_foreach(int type, void (*func)(struct bt_conn *conn, void *data), +void bt_conn_foreach(enum bt_conn_type type, + void (*func)(struct bt_conn *conn, void *data), void *data); /** @brief Look up an existing connection by address. @@ -270,21 +286,6 @@ const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn); */ uint8_t bt_conn_index(const struct bt_conn *conn); -/** Connection Type */ -enum { - /** LE Connection Type */ - BT_CONN_TYPE_LE = BIT(0), - /** BR/EDR Connection Type */ - BT_CONN_TYPE_BR = BIT(1), - /** SCO Connection Type */ - BT_CONN_TYPE_SCO = BIT(2), - /** ISO Connection Type */ - BT_CONN_TYPE_ISO = BIT(3), - /** All Connection Type */ - BT_CONN_TYPE_ALL = BT_CONN_TYPE_LE | BT_CONN_TYPE_BR | - BT_CONN_TYPE_SCO | BT_CONN_TYPE_ISO, -}; - /** LE Connection Info Structure */ struct bt_conn_le_info { /** Source (Local) Identity Address */ @@ -390,7 +391,7 @@ struct bt_security_info { /** Connection Info Structure */ struct bt_conn_info { /** Connection Type. */ - uint8_t type; + enum bt_conn_type type; /** Connection Role. */ uint8_t role; /** Which local identity the connection was created with */ diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 782f4fd87bd4..66b8a662f3ec 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1207,7 +1207,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state) } } -struct bt_conn *bt_conn_lookup_handle(uint16_t handle, int type) +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type) { struct bt_conn *conn; @@ -1243,7 +1243,8 @@ struct bt_conn *bt_conn_lookup_handle(uint16_t handle, int type) return NULL; } -void bt_conn_foreach(int type, void (*func)(struct bt_conn *conn, void *data), +void bt_conn_foreach(enum bt_conn_type type, + void (*func)(struct bt_conn *conn, void *data), void *data) { int i; @@ -2557,6 +2558,8 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info) } return 0; #endif + default: + break; } return -EINVAL; diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index eac811260c32..7b2ed8dd04a6 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -159,7 +159,7 @@ struct acl_data { struct bt_conn { uint16_t handle; - uint8_t type; + enum bt_conn_type type; uint8_t role; ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS); @@ -308,7 +308,7 @@ void bt_conn_disconnect_all(uint8_t id); struct bt_conn *bt_conn_new(struct bt_conn *conns, size_t size); /* Look up an existing connection */ -struct bt_conn *bt_conn_lookup_handle(uint16_t handle, int type); +struct bt_conn *bt_conn_lookup_handle(uint16_t handle, enum bt_conn_type type); static inline bool bt_conn_is_handle_valid(struct bt_conn *conn) { diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index aea64c923296..37868e444dcb 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -570,6 +570,8 @@ void conn_addr_str(struct bt_conn *conn, char *addr, size_t len) case BT_CONN_TYPE_LE: bt_addr_le_to_str(info.le.dst, addr, len); break; + default: + break; } } @@ -3277,6 +3279,8 @@ static void connection_info(struct bt_conn *conn, void *user_data) shell_print(ctx_shell, " #%u [ISO][%s] %s", info.id, role_str(info.role), addr); break; #endif + default: + break; } (*conn_count)++; diff --git a/tests/bluetooth/host/keys/mocks/conn.c b/tests/bluetooth/host/keys/mocks/conn.c index cf5dd37177bc..0045f3b787fe 100644 --- a/tests/bluetooth/host/keys/mocks/conn.c +++ b/tests/bluetooth/host/keys/mocks/conn.c @@ -7,5 +7,5 @@ #include #include "mocks/conn.h" -DEFINE_FAKE_VOID_FUNC(bt_conn_foreach, int, bt_conn_foreach_cb, void *); +DEFINE_FAKE_VOID_FUNC(bt_conn_foreach, enum bt_conn_type, bt_conn_foreach_cb, void *); DEFINE_FAKE_VALUE_FUNC(const bt_addr_le_t *, bt_conn_get_dst, const struct bt_conn *); diff --git a/tests/bluetooth/host/keys/mocks/conn.h b/tests/bluetooth/host/keys/mocks/conn.h index 506a1757380d..98ef8cc1e3d7 100644 --- a/tests/bluetooth/host/keys/mocks/conn.h +++ b/tests/bluetooth/host/keys/mocks/conn.h @@ -16,5 +16,5 @@ typedef void (*bt_conn_foreach_cb) (struct bt_conn *conn, void *data); FAKE(bt_conn_foreach) \ FAKE(bt_conn_get_dst) \ -DECLARE_FAKE_VOID_FUNC(bt_conn_foreach, int, bt_conn_foreach_cb, void *); +DECLARE_FAKE_VOID_FUNC(bt_conn_foreach, enum bt_conn_type, bt_conn_foreach_cb, void *); DECLARE_FAKE_VALUE_FUNC(const bt_addr_le_t *, bt_conn_get_dst, const struct bt_conn *); From aaa9cedf185e4ba674c8d1131060f1fd0c27e4dd Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Wed, 21 Jun 2023 15:26:19 +0300 Subject: [PATCH 0850/2042] net: lwm2m: Update next event timestamp on PMAX change When PMAX value is changed, it should update all events. I believe there is a bug that caused the code only to update events that are ongoing (to be send). Now if PMAX changes, next event timestamp is recalculated. Fixes #59397 Signed-off-by: Seppo Takalo --- subsys/net/lib/lwm2m/lwm2m_observation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_observation.c b/subsys/net/lib/lwm2m/lwm2m_observation.c index 559e33212d9f..696b5e9210f5 100644 --- a/subsys/net/lib/lwm2m/lwm2m_observation.c +++ b/subsys/net/lib/lwm2m/lwm2m_observation.c @@ -913,7 +913,7 @@ static int lwm2m_engine_observer_timestamp_update(sys_slist_t *observer, /* update observe_node accordingly */ SYS_SLIST_FOR_EACH_CONTAINER(observer, obs, node) { - if (!obs->resource_update) { + if (obs->resource_update) { /* Resource Update on going skip this*/ continue; } From e1964b8a8208e091e0f65085a976fca3082a23f7 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Thu, 22 Jun 2023 15:49:16 +0200 Subject: [PATCH 0851/2042] net: wifi: shell: Fix unsafe pointer casts parse_number() helper function accepts long * pointer or the output, however in several places, an address of a variable of incompatible type was passed to the function (for example an address of a bool variable was cast to (long *) and provided to the function). This could cause memory overwrites or other unexpected behaviour. Fix this, by defining a helper variable of type long, and use it with the parse_number() function. Only after successful parsing, the value is then assigned to the proper destination. Signed-off-by: Robert Lubos --- subsys/net/l2/wifi/wifi_shell.c | 116 ++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 5372f8746d73..299619b1f888 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -734,6 +734,7 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; + long value; context.sh = sh; @@ -754,11 +755,15 @@ static int cmd_wifi_twt_setup_quick(const struct shell *sh, size_t argc, params.setup.trigger = 0; params.setup.announce = 0; - if (!parse_number(sh, (long *)¶ms.setup.twt_wake_interval, argv[idx++], - 1, WIFI_MAX_TWT_WAKE_INTERVAL_US) || - !parse_number(sh, (long *)¶ms.setup.twt_interval, argv[idx++], 1, - WIFI_MAX_TWT_INTERVAL_US)) + if (!parse_number(sh, &value, argv[idx++], 1, WIFI_MAX_TWT_WAKE_INTERVAL_US)) { return -EINVAL; + } + params.setup.twt_wake_interval = (uint32_t)value; + + if (!parse_number(sh, &value, argv[idx++], 1, WIFI_MAX_TWT_INTERVAL_US)) { + return -EINVAL; + } + 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", @@ -783,8 +788,7 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; int idx = 1; - long neg_type; - long setup_cmd; + long value; context.sh = sh; @@ -796,25 +800,57 @@ static int cmd_wifi_twt_setup(const struct shell *sh, size_t argc, params.operation = WIFI_TWT_SETUP; - if (!parse_number(sh, &neg_type, argv[idx++], WIFI_TWT_INDIVIDUAL, - WIFI_TWT_WAKE_TBTT) || - !parse_number(sh, &setup_cmd, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST, - WIFI_TWT_SETUP_CMD_DEMAND) || - !parse_number(sh, (long *)¶ms.dialog_token, argv[idx++], 1, 255) || - !parse_number(sh, (long *)¶ms.flow_id, argv[idx++], 0, - (WIFI_MAX_TWT_FLOWS - 1)) || - !parse_number(sh, (long *)¶ms.setup.responder, argv[idx++], 0, 1) || - !parse_number(sh, (long *)¶ms.setup.trigger, argv[idx++], 0, 1) || - !parse_number(sh, (long *)¶ms.setup.implicit, argv[idx++], 0, 1) || - !parse_number(sh, (long *)¶ms.setup.announce, argv[idx++], 0, 1) || - !parse_number(sh, (long *)¶ms.setup.twt_wake_interval, argv[idx++], 1, - WIFI_MAX_TWT_WAKE_INTERVAL_US) || - !parse_number(sh, (long *)¶ms.setup.twt_interval, argv[idx++], 1, - WIFI_MAX_TWT_INTERVAL_US)) + if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_INDIVIDUAL, + WIFI_TWT_WAKE_TBTT)) { + return -EINVAL; + } + params.negotiation_type = (enum wifi_twt_negotiation_type)value; + + if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST, + WIFI_TWT_SETUP_CMD_DEMAND)) { + return -EINVAL; + } + params.setup_cmd = (enum wifi_twt_setup_cmd)value; + + if (!parse_number(sh, &value, argv[idx++], 1, 255)) { + return -EINVAL; + } + params.dialog_token = (uint8_t)value; + + if (!parse_number(sh, &value, argv[idx++], 0, (WIFI_MAX_TWT_FLOWS - 1))) { + return -EINVAL; + } + params.flow_id = (uint8_t)value; + + if (!parse_number(sh, &value, argv[idx++], 0, 1)) { + return -EINVAL; + } + params.setup.responder = (bool)value; + + if (!parse_number(sh, &value, argv[idx++], 0, 1)) { + return -EINVAL; + } + params.setup.trigger = (bool)value; + + if (!parse_number(sh, &value, argv[idx++], 0, 1)) { return -EINVAL; + } + params.setup.implicit = (bool)value; - params.negotiation_type = neg_type; - params.setup_cmd = setup_cmd; + if (!parse_number(sh, &value, argv[idx++], 0, 1)) { + return -EINVAL; + } + params.setup.announce = (bool)value; + + if (!parse_number(sh, &value, argv[idx++], 1, WIFI_MAX_TWT_WAKE_INTERVAL_US)) { + return -EINVAL; + } + params.setup.twt_wake_interval = (uint32_t)value; + + if (!parse_number(sh, &value, argv[idx++], 1, WIFI_MAX_TWT_INTERVAL_US)) { + return -EINVAL; + } + 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", @@ -837,8 +873,7 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, { struct net_if *iface = net_if_get_first_wifi(); struct wifi_twt_params params = { 0 }; - long neg_type = 0; - long setup_cmd = 0; + long value; context.sh = sh; int idx = 1; @@ -850,17 +885,28 @@ static int cmd_wifi_twt_teardown(const struct shell *sh, size_t argc, } params.operation = WIFI_TWT_TEARDOWN; - neg_type = params.negotiation_type; - setup_cmd = params.setup_cmd; - - if (!parse_number(sh, &neg_type, argv[idx++], WIFI_TWT_INDIVIDUAL, - WIFI_TWT_WAKE_TBTT) || - !parse_number(sh, &setup_cmd, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST, - WIFI_TWT_SETUP_CMD_DEMAND) || - !parse_number(sh, (long *)¶ms.dialog_token, argv[idx++], 1, 255) || - !parse_number(sh, (long *)¶ms.flow_id, argv[idx++], 0, - (WIFI_MAX_TWT_FLOWS - 1))) + + if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_INDIVIDUAL, + WIFI_TWT_WAKE_TBTT)) { return -EINVAL; + } + params.negotiation_type = (enum wifi_twt_negotiation_type)value; + + if (!parse_number(sh, &value, argv[idx++], WIFI_TWT_SETUP_CMD_REQUEST, + WIFI_TWT_SETUP_CMD_DEMAND)) { + return -EINVAL; + } + params.setup_cmd = (enum wifi_twt_setup_cmd)value; + + if (!parse_number(sh, &value, argv[idx++], 1, 255)) { + return -EINVAL; + } + params.dialog_token = (uint8_t)value; + + if (!parse_number(sh, &value, argv[idx++], 0, (WIFI_MAX_TWT_FLOWS - 1))) { + return -EINVAL; + } + 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", From 77c86e8ad3e45644725df1da3a83bfffda516b83 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 4 Jul 2023 15:48:29 +0300 Subject: [PATCH 0852/2042] net: Clarify the documentation of net_if_dev The documentation of net_if_dev was missing information how it should be instantiated. Fixes #59975 Signed-off-by: Jukka Rissanen --- include/zephyr/net/net_if.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index d8042d6601cf..59a5f11b1245 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -465,7 +465,8 @@ typedef int (*net_socket_create_t)(int, int, int); * and the network device. * * Because of the strong relationship between a device driver and such - * network interface, each net_if_dev should be instantiated by + * network interface, each net_if_dev should be instantiated by one of the + * network device init macros found in net_if.h. */ struct net_if_dev { /** The actually device driver instance the net_if is related to */ From f93da64ec858f9a3c56d548da9bc48cc33eafb2c Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Tue, 6 Jun 2023 09:38:32 +0100 Subject: [PATCH 0853/2042] drivers: sensor: npm1300_charger: Startup vbus current limit The vbus current limit is now written to the vbus startup register. It is now applied at all times and does not need to be updated on charger insertion. Signed-off-by: Andy Sinclair --- .../sensor/npm1300_charger/npm1300_charger.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/sensor/npm1300_charger/npm1300_charger.c b/drivers/sensor/npm1300_charger/npm1300_charger.c index b7d52fc5e65c..f72418aa9a0c 100644 --- a/drivers/sensor/npm1300_charger/npm1300_charger.c +++ b/drivers/sensor/npm1300_charger/npm1300_charger.c @@ -58,8 +58,7 @@ struct npm1300_charger_data { #define ADC_OFFSET_IBAT_EN 0x24U /* nPM1300 VBUS register offsets */ -#define VBUS_OFFSET_TASK_UPDATE 0x00U -#define VBUS_OFFSET_ILIM 0x01U +#define VBUS_OFFSET_ILIMSTARTUP 0x02U #define VBUS_OFFSET_STATUS 0x07U /* Ibat status */ @@ -198,7 +197,6 @@ int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel c const struct npm1300_charger_config *const config = dev->config; struct npm1300_charger_data *data = dev->data; struct adc_results_t results; - bool last_vbus; int ret; /* Read charge status and error reason */ @@ -236,21 +234,12 @@ int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel c return ret; } - /* Read vbus status, and set SW current limit on new vbus detection */ - last_vbus = (data->vbus_stat & 1U) != 0U; + /* Read vbus status */ ret = mfd_npm1300_reg_read(config->mfd, VBUS_BASE, VBUS_OFFSET_STATUS, &data->vbus_stat); if (ret != 0) { return ret; } - if (!last_vbus && ((data->vbus_stat & 1U) != 0U)) { - ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_TASK_UPDATE, 1U); - - if (ret != 0) { - return ret; - } - } - return ret; } @@ -329,7 +318,7 @@ int npm1300_charger_init(const struct device *dev) if (ret == -EINVAL) { return ret; } - ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIM, idx); + ret = mfd_npm1300_reg_write(config->mfd, VBUS_BASE, VBUS_OFFSET_ILIMSTARTUP, idx); if (ret != 0) { return ret; } From 725d45e6d42d497793429dcbdaa015edb4fda9b0 Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Mon, 12 Jun 2023 16:17:22 +0100 Subject: [PATCH 0854/2042] drivers: sensor: npm1300_charger: Auto temp measurements Enable automatic temperature measurements during charging. Allows the PMIC to charge when the host is in low power mode. Signed-off-by: Andy Sinclair --- drivers/sensor/npm1300_charger/npm1300_charger.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/sensor/npm1300_charger/npm1300_charger.c b/drivers/sensor/npm1300_charger/npm1300_charger.c index f72418aa9a0c..500df3099f4e 100644 --- a/drivers/sensor/npm1300_charger/npm1300_charger.c +++ b/drivers/sensor/npm1300_charger/npm1300_charger.c @@ -54,6 +54,7 @@ struct npm1300_charger_data { #define ADC_OFFSET_TASK_TEMP 0x01U #define ADC_OFFSET_CONFIG 0x09U #define ADC_OFFSET_NTCR_SEL 0x0AU +#define ADC_OFFSET_TASK_AUTO 0x0CU #define ADC_OFFSET_RESULTS 0x10U #define ADC_OFFSET_IBAT_EN 0x24U @@ -341,6 +342,12 @@ int npm1300_charger_init(const struct device *dev) return ret; } + /* Enable automatic temperature measurements during charging */ + ret = mfd_npm1300_reg_write(config->mfd, ADC_BASE, ADC_OFFSET_TASK_AUTO, 1U); + if (ret != 0) { + return ret; + } + /* Enable charging if configured */ if (config->charging_enable) { ret = mfd_npm1300_reg_write(config->mfd, CHGR_BASE, CHGR_OFFSET_EN_SET, 1U); From 7e3f6f129044e1023bdab6d3ae3664f130bc2f6f Mon Sep 17 00:00:00 2001 From: Andy Sinclair Date: Thu, 8 Jun 2023 17:47:12 +0100 Subject: [PATCH 0855/2042] drivers: sensor: npm1300_charger: Added Ntc threshold config The NTC thresholds (cold, cool, warm, hot) are now configured during initialisation Signed-off-by: Andy Sinclair --- .../sensor/npm1300_charger/npm1300_charger.c | 81 +++++++++++++++---- .../sensor/nordic,npm1300-charger.yaml | 16 ++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/drivers/sensor/npm1300_charger/npm1300_charger.c b/drivers/sensor/npm1300_charger/npm1300_charger.c index 500df3099f4e..5d8a9ae0b959 100644 --- a/drivers/sensor/npm1300_charger/npm1300_charger.c +++ b/drivers/sensor/npm1300_charger/npm1300_charger.c @@ -19,8 +19,10 @@ struct npm1300_charger_config { int32_t current_microamp; int32_t dischg_limit_microamp; int32_t vbus_limit_microamp; - uint8_t thermistor_idx; + int32_t temp_thresholds[4U]; + uint32_t thermistor_ohms; uint16_t thermistor_beta; + uint8_t thermistor_idx; bool charging_enable; }; @@ -40,14 +42,15 @@ struct npm1300_charger_data { #define VBUS_BASE 0x02U /* nPM1300 charger register offsets */ -#define CHGR_OFFSET_EN_SET 0x04U -#define CHGR_OFFSET_EN_CLR 0x05U -#define CHGR_OFFSET_ISET 0x08U +#define CHGR_OFFSET_EN_SET 0x04U +#define CHGR_OFFSET_EN_CLR 0x05U +#define CHGR_OFFSET_ISET 0x08U #define CHGR_OFFSET_ISET_DISCHG 0x0AU -#define CHGR_OFFSET_VTERM 0x0CU -#define CHGR_OFFSET_VTERM_R 0x0DU -#define CHGR_OFFSET_CHG_STAT 0x34U -#define CHGR_OFFSET_ERR_REASON 0x36U +#define CHGR_OFFSET_VTERM 0x0CU +#define CHGR_OFFSET_VTERM_R 0x0DU +#define CHGR_OFFSET_NTC_TEMPS 0x10U +#define CHGR_OFFSET_CHG_STAT 0x34U +#define CHGR_OFFSET_ERR_REASON 0x36U /* nPM1300 ADC register offsets */ #define ADC_OFFSET_TASK_VBAT 0x00U @@ -59,14 +62,14 @@ struct npm1300_charger_data { #define ADC_OFFSET_IBAT_EN 0x24U /* nPM1300 VBUS register offsets */ -#define VBUS_OFFSET_ILIMSTARTUP 0x02U -#define VBUS_OFFSET_STATUS 0x07U +#define VBUS_OFFSET_ILIMSTARTUP 0x02U +#define VBUS_OFFSET_STATUS 0x07U /* Ibat status */ -#define IBAT_STAT_DISCHARGE 0x04U +#define IBAT_STAT_DISCHARGE 0x04U #define IBAT_STAT_CHARGE_TRICKLE 0x0CU -#define IBAT_STAT_CHARGE_COOL 0x0DU -#define IBAT_STAT_CHARGE_NORMAL 0x0FU +#define IBAT_STAT_CHARGE_COOL 0x0DU +#define IBAT_STAT_CHARGE_NORMAL 0x0FU struct adc_results_t { uint8_t ibat_stat; @@ -83,12 +86,16 @@ struct adc_results_t { } __packed; /* ADC result masks */ -#define ADC_MSB_SHIFT 2U -#define ADC_LSB_MASK 0x03U +#define ADC_MSB_SHIFT 2U +#define ADC_LSB_MASK 0x03U #define ADC_LSB_VBAT_SHIFT 0U #define ADC_LSB_NTC_SHIFT 2U #define ADC_LSB_IBAT_SHIFT 4U +/* NTC temp masks */ +#define NTCTEMP_MSB_SHIFT 2U +#define NTCTEMP_LSB_MASK 0x03U + /* Linear range for charger terminal voltage */ static const struct linear_range charger_volt_ranges[] = { LINEAR_RANGE_INIT(3500000, 50000, 0U, 3U), LINEAR_RANGE_INIT(4000000, 50000, 4U, 13U)}; @@ -116,6 +123,17 @@ static void calc_temp(const struct npm1300_charger_config *const config, uint16_ valp->val2 = (int32_t)(fmodf(temp, 1.f) * 1000000.f); } +static uint32_t calc_ntc_res(const struct npm1300_charger_config *const config, int32_t temp_mdegc) +{ + float inv_t0 = 1.f / 298.15f; + float temp = (float)temp_mdegc / 1000000.f; + + float inv_temp_k = 1.f / (temp + 273.15f); + + return config->thermistor_ohms * + exp((float)config->thermistor_beta * (inv_temp_k - inv_t0)); +} + static uint16_t adc_get_res(uint8_t msb, uint8_t lsb, uint16_t lsb_shift) { return ((uint16_t)msb << ADC_MSB_SHIFT) | ((lsb >> lsb_shift) & ADC_LSB_MASK); @@ -244,6 +262,28 @@ int npm1300_charger_sample_fetch(const struct device *dev, enum sensor_channel c return ret; } +static int set_ntc_thresholds(const struct npm1300_charger_config *const config) +{ + for (uint8_t idx = 0U; idx < 4U; idx++) { + if (config->temp_thresholds[idx] < INT32_MAX) { + uint32_t res = calc_ntc_res(config, config->temp_thresholds[idx]); + + /* Ref: Datasheet Figure 14: Equation for battery temperature */ + uint16_t code = (1024 * res) / (res + config->thermistor_ohms); + + int ret = mfd_npm1300_reg_write2( + config->mfd, CHGR_BASE, CHGR_OFFSET_NTC_TEMPS + (idx * 2U), + code >> NTCTEMP_MSB_SHIFT, code & NTCTEMP_LSB_MASK); + + if (ret != 0) { + return ret; + } + } + } + + return 0; +} + int npm1300_charger_init(const struct device *dev) { const struct npm1300_charger_config *const config = dev->config; @@ -261,6 +301,11 @@ int npm1300_charger_init(const struct device *dev) return ret; } + ret = set_ntc_thresholds(config); + if (ret != 0) { + return ret; + } + /* Configure termination voltages */ ret = linear_range_group_get_win_index(charger_volt_ranges, ARRAY_SIZE(charger_volt_ranges), config->term_microvolt, config->term_microvolt, @@ -375,10 +420,14 @@ static const struct sensor_driver_api npm1300_charger_battery_driver_api = { .current_microamp = DT_INST_PROP(n, current_microamp), \ .dischg_limit_microamp = DT_INST_PROP(n, dischg_limit_microamp), \ .vbus_limit_microamp = DT_INST_PROP(n, vbus_limit_microamp), \ + .thermistor_ohms = DT_INST_PROP(n, thermistor_ohms), \ .thermistor_idx = DT_INST_ENUM_IDX(n, thermistor_ohms), \ .thermistor_beta = DT_INST_PROP(n, thermistor_beta), \ .charging_enable = DT_INST_PROP(n, charging_enable), \ - }; \ + .temp_thresholds = {DT_INST_PROP_OR(n, thermistor_cold_millidegrees, INT32_MAX), \ + DT_INST_PROP_OR(n, thermistor_cool_millidegrees, INT32_MAX), \ + DT_INST_PROP_OR(n, thermistor_warm_millidegrees, INT32_MAX), \ + DT_INST_PROP_OR(n, thermistor_hot_millidegrees, INT32_MAX)}}; \ \ SENSOR_DEVICE_DT_INST_DEFINE(n, &npm1300_charger_init, NULL, &npm1300_charger_data_##n, \ &npm1300_charger_config_##n, POST_KERNEL, \ diff --git a/dts/bindings/sensor/nordic,npm1300-charger.yaml b/dts/bindings/sensor/nordic,npm1300-charger.yaml index 86a22b7a3b5d..c6f3915a737f 100644 --- a/dts/bindings/sensor/nordic,npm1300-charger.yaml +++ b/dts/bindings/sensor/nordic,npm1300-charger.yaml @@ -62,6 +62,22 @@ properties: required: true description: Beta value of selected thermistor. + thermistor-cold-millidegrees: + type: int + description: Thermistor cold threshold in milli-degrees + + thermistor-cool-millidegrees: + type: int + description: Thermistor cool threshold in milli-degrees + + thermistor-warm-millidegrees: + type: int + description: Thermistor warm threshold in milli-degrees + + thermistor-hot-millidegrees: + type: int + description: Thermistor hot threshold in milli-degrees + charging-enable: type: boolean description: | From b896ca5771359c2d54ca1dfe8119df4c97fe6689 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 21 Dec 2022 12:56:59 +0100 Subject: [PATCH 0856/2042] drivers: counter: Add Smartbond basic support This adds support for the TIMER1-4 counter. Each counter has 24bits and can run on LP_CLK (15-32KHz) or DIVN clock (32MHz) with prescaler 1-32. Each counter can have one alarm set. Signed-off-by: Jerzy Kasenberg --- boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml | 1 + drivers/counter/CMakeLists.txt | 1 + drivers/counter/Kconfig | 2 + drivers/counter/Kconfig.smartbond_timer | 11 + drivers/counter/counter_smartbond_timer.c | 381 ++++++++++++++++++ dts/arm/renesas/smartbond/da1469x.dtsi | 36 ++ .../timer/renesas,smartbond-timer.yaml | 25 ++ 7 files changed, 457 insertions(+) create mode 100644 drivers/counter/Kconfig.smartbond_timer create mode 100644 drivers/counter/counter_smartbond_timer.c create mode 100644 dts/bindings/timer/renesas,smartbond-timer.yaml diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index 23bc043fc93b..4cf50541c1eb 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -9,6 +9,7 @@ toolchain: - xtools supported: - arduino_gpio + - counter - gpio - watchdog - i2c diff --git a/drivers/counter/CMakeLists.txt b/drivers/counter/CMakeLists.txt index 147f0ca761c8..ffd5068bc93f 100644 --- a/drivers/counter/CMakeLists.txt +++ b/drivers/counter/CMakeLists.txt @@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_PIT counter_mcux_pit zephyr_library_sources_ifdef(CONFIG_COUNTER_XLNX_AXI_TIMER counter_xlnx_axi_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_TMR_ESP32 counter_esp32_tmr.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_RTC_ESP32 counter_esp32_rtc.c) +zephyr_library_sources_ifdef(CONFIG_COUNTER_SMARTBOND_TIMER counter_smartbond_timer.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_MICROCHIP_MCP7940N rtc_mcp7940n.c) zephyr_library_sources_ifdef(CONFIG_COUNTER_ANDES_ATCPIT100 counter_andes_atcpit100.c) zephyr_library_sources_ifdef(CONFIG_ACE_V1X_ART_COUNTER counter_ace_v1x_art.c) diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index ff983fb4f03f..ad29553a7be6 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -68,6 +68,8 @@ source "drivers/counter/Kconfig.esp32_tmr" source "drivers/counter/Kconfig.esp32_rtc" +source "drivers/counter/Kconfig.smartbond_timer" + source "drivers/counter/Kconfig.mcp7940n" source "drivers/counter/Kconfig.mcux_ctimer" diff --git a/drivers/counter/Kconfig.smartbond_timer b/drivers/counter/Kconfig.smartbond_timer new file mode 100644 index 000000000000..f958810d0af2 --- /dev/null +++ b/drivers/counter/Kconfig.smartbond_timer @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config COUNTER_SMARTBOND_TIMER + bool "Renesas SmartBond(tm) counter driver" + default y + depends on DT_HAS_RENESAS_SMARTBOND_TIMER_ENABLED + select CLOCK_CONTROL_SMARTBOND + select CLOCK_CONTROL + help + Enable the counter driver for for Renesas SmartBond(tm) family of processors. diff --git a/drivers/counter/counter_smartbond_timer.c b/drivers/counter/counter_smartbond_timer.c new file mode 100644 index 000000000000..5d1468648fd2 --- /dev/null +++ b/drivers/counter/counter_smartbond_timer.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2022 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_timer + +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(counter_timer, CONFIG_COUNTER_LOG_LEVEL); + +#define LP_CLK_OSC_RC32K 0 +#define LP_CLK_OSC_RCX 1 +#define LP_CLK_OSC_XTAL32K 2 + +#define TIMER_TOP_VALUE 0xFFFFFF + +struct counter_smartbond_data { + counter_alarm_callback_t callback; + void *user_data; + uint32_t guard_period; + uint32_t freq; +}; + +struct counter_smartbond_ch_data { + counter_alarm_callback_t callback; + void *user_data; +}; + +struct counter_smartbond_config { + struct counter_config_info info; + /* Register set for timer */ + TIMER2_Type *timer; + uint8_t prescaler; + /* Timer driven by DIVn if 1 or lp_clk if 0 */ + uint8_t clock_src_divn; + uint8_t irqn; + void (*irq_config_func)(const struct device *dev); + + LOG_INSTANCE_PTR_DECLARE(log); +}; + +static int counter_smartbond_start(const struct device *dev) +{ + const struct counter_smartbond_config *config = dev->config; + TIMER2_Type *timer = config->timer; + + /* enable counter in free running mode */ + timer->TIMER2_CTRL_REG |= TIMER_TIMER_CTRL_REG_TIM_CLK_EN_Msk | + TIMER_TIMER_CTRL_REG_TIM_EN_Msk | + TIMER_TIMER_CTRL_REG_TIM_FREE_RUN_MODE_EN_Msk; + + return 0; +} + +static int counter_smartbond_stop(const struct device *dev) +{ + const struct counter_smartbond_config *config = dev->config; + struct counter_smartbond_data *data = dev->data; + TIMER2_Type *timer = config->timer; + + /* disable counter */ + timer->TIMER2_CTRL_REG &= ~(TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk | + TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk); + data->callback = NULL; + + return 0; +} + +static uint32_t counter_smartbond_get_top_value(const struct device *dev) +{ + ARG_UNUSED(dev); + + return TIMER_TOP_VALUE; +} + +static uint32_t counter_smartbond_read(const struct device *dev) +{ + const struct counter_smartbond_config *config = dev->config; + TIMER2_Type *timer = config->timer; + + return timer->TIMER2_TIMER_VAL_REG; +} + +static int counter_smartbond_get_value(const struct device *dev, uint32_t *ticks) +{ + *ticks = counter_smartbond_read(dev); + + return 0; +} + +static int counter_smartbond_set_alarm(const struct device *dev, uint8_t chan, + const struct counter_alarm_cfg *alarm_cfg) +{ + const struct counter_smartbond_config *config = dev->config; + struct counter_smartbond_data *data = dev->data; + TIMER2_Type *timer = config->timer; + volatile uint32_t *timer_clear_irq_reg = ((TIMER_Type *)timer) == TIMER ? + &((TIMER_Type *)timer)->TIMER_CLEAR_IRQ_REG : + &timer->TIMER2_CLEAR_IRQ_REG; + bool absolute = alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE; + uint32_t flags = alarm_cfg->flags; + uint32_t val = alarm_cfg->ticks; + bool irq_on_late; + int err = 0; + uint32_t max_rel_val; + uint32_t now; + uint32_t diff; + + if (chan != 0 || alarm_cfg->ticks > counter_smartbond_get_top_value(dev)) { + return -EINVAL; + } + + if (data->callback) { + return -EBUSY; + } + + now = counter_smartbond_read(dev); + data->callback = alarm_cfg->callback; + data->user_data = alarm_cfg->user_data; + + __ASSERT_NO_MSG(data->guard_period < TIMER_TOP_VALUE); + + if (absolute) { + max_rel_val = TIMER_TOP_VALUE - data->guard_period; + irq_on_late = flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE; + } else { + /* If relative value is smaller than half of the counter range + * it is assumed that there is a risk of setting value too late + * and late detection algorithm must be applied. When late + * setting is detected, interrupt shall be triggered for + * immediate expiration of the timer. Detection is performed + * by limiting relative distance between CC and counter. + * + * Note that half of counter range is an arbitrary value. + */ + irq_on_late = val < (TIMER_TOP_VALUE / 2U); + /* limit max to detect short relative being set too late. */ + max_rel_val = irq_on_late ? TIMER_TOP_VALUE / 2U : TIMER_TOP_VALUE; + val = (now + val) & TIMER_TOP_VALUE; + } + timer->TIMER2_RELOAD_REG = val; + *timer_clear_irq_reg = 1; + /* decrement value to detect also case when val == counter_smartbond_read(dev). Otherwise, + * condition would need to include comparing diff against 0. + */ + diff = ((val - 1U) - counter_smartbond_read(dev)) & TIMER_TOP_VALUE; + if (diff > max_rel_val) { + if (absolute) { + err = -ETIME; + } + + /* Interrupt is triggered always for relative alarm and + * for absolute depending on the flag. + */ + if (irq_on_late) { + NVIC_SetPendingIRQ(config->irqn); + } else { + data->callback = NULL; + } + } else { + if (diff == 0) { + /* RELOAD value could be set just in time for interrupt + * trigger or too late. In any case time is interrupt + * should be triggered. No need to enable interrupt + * on TIMER just make sure interrupt is pending. + */ + NVIC_SetPendingIRQ(config->irqn); + } else { + timer->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk; + } + } + + return err; +} + +static int counter_smartbond_cancel_alarm(const struct device *dev, uint8_t chan) +{ + const struct counter_smartbond_config *config = dev->config; + TIMER2_Type *timer = config->timer; + struct counter_smartbond_data *data = dev->data; + + ARG_UNUSED(chan); + + timer->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk; + data->callback = NULL; + + return 0; +} + +static int counter_smartbond_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + ARG_UNUSED(dev); + + if (cfg->ticks != 0xFFFFFF) { + return -ENOTSUP; + } + + return 0; +} + +static uint32_t counter_smartbond_get_pending_int(const struct device *dev) +{ + const struct counter_smartbond_config *config = dev->config; + + /* There is no register to check TIMER peripheral to check for interrupt + * pending, check directly in NVIC. + */ + return NVIC_GetPendingIRQ(config->irqn); +} + +static int counter_smartbond_init_timer(const struct device *dev) +{ + const struct counter_smartbond_config *cfg = dev->config; + struct counter_smartbond_data *data = dev->data; + TIMER2_Type *timer = cfg->timer; + TIMER_Type *timer0 = ((TIMER_Type *)cfg->timer) == TIMER ? TIMER : NULL; + const struct device *osc_dev; + uint32_t osc_freq; + uint32_t osc; + + if (cfg->clock_src_divn) { + /* Timer clock source is DIVn 32MHz */ + timer->TIMER2_CTRL_REG = TIMER_TIMER_CTRL_REG_TIM_SYS_CLK_EN_Msk; + data->freq = DT_PROP(DT_NODELABEL(divn_clk), clock_frequency) / + (cfg->prescaler + 1); + } else { + osc_dev = DEVICE_DT_GET(DT_NODELABEL(osc)); + timer->TIMER2_CTRL_REG = 0; + switch ((CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) >> + CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Pos) { + case LP_CLK_OSC_RC32K: + osc = DT_DEP_ORD(DT_NODELABEL(rc32k)); + break; + case LP_CLK_OSC_RCX: + osc = DT_DEP_ORD(DT_NODELABEL(rcx)); + break; + default: + case LP_CLK_OSC_XTAL32K: + osc = DT_DEP_ORD(DT_NODELABEL(xtal32k)); + break; + } + clock_control_get_rate(osc_dev, (clock_control_subsys_t *)&osc, &osc_freq); + data->freq = osc_freq / (cfg->prescaler + 1); + } + timer->TIMER2_PRESCALER_REG = cfg->prescaler; + timer->TIMER2_RELOAD_REG = counter_get_max_top_value(dev); + timer->TIMER2_GPIO1_CONF_REG = 0; + timer->TIMER2_GPIO2_CONF_REG = 0; + timer->TIMER2_SHOTWIDTH_REG = 0; + timer->TIMER2_CAPTURE_GPIO1_REG = 0; + timer->TIMER2_CAPTURE_GPIO2_REG = 0; + timer->TIMER2_PWM_FREQ_REG = 0; + timer->TIMER2_PWM_DC_REG = 0; + if (timer0) { + timer0->TIMER_CAPTURE_GPIO3_REG = 0; + timer0->TIMER_CAPTURE_GPIO4_REG = 0; + } + + /* config/enable IRQ */ + cfg->irq_config_func(dev); + + return 0; +} + +static uint32_t counter_smartbond_get_guard_period(const struct device *dev, uint32_t flags) +{ + struct counter_smartbond_data *data = dev->data; + + ARG_UNUSED(flags); + return data->guard_period; +} + +static int counter_smartbond_set_guard_period(const struct device *dev, uint32_t guard, + uint32_t flags) +{ + struct counter_smartbond_data *data = dev->data; + + ARG_UNUSED(flags); + __ASSERT_NO_MSG(guard < counter_smartbond_get_top_value(dev)); + + data->guard_period = guard; + + return 0; +} + +static uint32_t counter_smartbond_get_freq(const struct device *dev) +{ + struct counter_smartbond_data *data = dev->data; + + return data->freq; +} + +static const struct counter_driver_api counter_smartbond_driver_api = { + .start = counter_smartbond_start, + .stop = counter_smartbond_stop, + .get_value = counter_smartbond_get_value, + .set_alarm = counter_smartbond_set_alarm, + .cancel_alarm = counter_smartbond_cancel_alarm, + .set_top_value = counter_smartbond_set_top_value, + .get_pending_int = counter_smartbond_get_pending_int, + .get_top_value = counter_smartbond_get_top_value, + .get_guard_period = counter_smartbond_get_guard_period, + .set_guard_period = counter_smartbond_set_guard_period, + .get_freq = counter_smartbond_get_freq, +}; + +void counter_smartbond_irq_handler(const struct device *dev) +{ + const struct counter_smartbond_config *cfg = dev->config; + struct counter_smartbond_data *data = dev->data; + counter_alarm_callback_t alarm_callback = data->callback; + TIMER2_Type *timer = cfg->timer; + /* Timer0 has interrupt clear register in other offset */ + __IOM uint32_t *timer_clear_irq_reg = ((TIMER_Type *)timer) == TIMER ? + &((TIMER_Type *)timer)->TIMER_CLEAR_IRQ_REG : + &timer->TIMER2_CLEAR_IRQ_REG; + + timer->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk; + *timer_clear_irq_reg = 1; + + if (alarm_callback != NULL) { + data->callback = NULL; + alarm_callback(dev, 0, timer->TIMER2_TIMER_VAL_REG, + data->user_data); + } +} + +#define TIMERN(idx) DT_DRV_INST(idx) + +/** TIMERn instance from DT */ +#define TIM(idx) ((TIMER2_Type *)DT_REG_ADDR(TIMERN(idx))) + +#define COUNTER_DEVICE_INIT(idx) \ + BUILD_ASSERT(DT_PROP(TIMERN(idx), prescaler) <= 32 && \ + DT_PROP(TIMERN(idx), prescaler) > 0, \ + "TIMER prescaler out of range (1..32)"); \ + \ + static struct counter_smartbond_data counter##idx##_data; \ + \ + static void counter##idx##_smartbond_irq_config(const struct device *dev)\ + { \ + IRQ_CONNECT(DT_IRQN(TIMERN(idx)), \ + DT_IRQ(TIMERN(idx), priority), \ + counter_smartbond_irq_handler, \ + DEVICE_DT_INST_GET(idx), \ + 0); \ + irq_enable(DT_IRQN(TIMERN(idx))); \ + } \ + \ + static const struct counter_smartbond_config counter##idx##_config = { \ + .info = { \ + .max_top_value = 0x00FFFFFF, \ + .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ + .channels = 1, \ + }, \ + .timer = TIM(idx), \ + .prescaler = DT_PROP(TIMERN(idx), prescaler) - 1, \ + .clock_src_divn = DT_SAME_NODE(DT_PROP(TIMERN(idx), clock_src), \ + DT_NODELABEL(divn_clk)) ? 1 : 0, \ + .irq_config_func = counter##idx##_smartbond_irq_config, \ + .irqn = DT_IRQN(TIMERN(idx)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, \ + counter_smartbond_init_timer, \ + NULL, \ + &counter##idx##_data, \ + &counter##idx##_config, \ + PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, \ + &counter_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(COUNTER_DEVICE_INIT) diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index 43208cd19abd..6b2df0d5e915 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -149,6 +149,42 @@ status = "okay"; }; + timer1: timer@50010200 { + compatible = "renesas,smartbond-timer"; + reg = <0x50010200 0x300>; + clock-src = <&lp_clk>; + interrupts = <16 0>; + prescaler = <1>; + status = "disabled"; + }; + + timer2: timer@50010300 { + compatible = "renesas,smartbond-timer"; + reg = <0x50010300 0x300>; + clock-src = <&divn_clk>; + interrupts = <17 0>; + prescaler = <32>; + status = "disabled"; + }; + + timer3: timer@50040a00 { + compatible = "renesas,smartbond-timer"; + reg = <0x50040a00 0x300>; + clock-src = <&lp_clk>; + interrupts = <34 0>; + prescaler = <31>; + status = "disabled"; + }; + + timer4: timer@50040b00 { + compatible = "renesas,smartbond-timer"; + reg = <0x50040b00 0x300>; + clock-src = <&divn_clk>; + interrupts = <35 0>; + prescaler = <32>; + status = "disabled"; + }; + uart: uart@50020000 { compatible = "renesas,smartbond-uart"; reg = <0x50020000 0x100>; diff --git a/dts/bindings/timer/renesas,smartbond-timer.yaml b/dts/bindings/timer/renesas,smartbond-timer.yaml new file mode 100644 index 000000000000..16798f33eeae --- /dev/null +++ b/dts/bindings/timer/renesas,smartbond-timer.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SmartBond(tm) general purpose timers + +compatible: "renesas,smartbond-timer" + +include: base.yaml + +properties: + reg: + required: true + + clock-src: + required: true + type: phandle + description: | + Timer uses divn_clk or lp_clk + + prescaler: + type: int + required: true + description: | + Clock prescaler at the input of the timer + Could be in range [0 .. 31] (CLK/(prescaler+1) ) From cc53f3f021f0143ed168e578f5ca74fc36e3a610 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 21 Dec 2022 13:15:06 +0100 Subject: [PATCH 0857/2042] samples: drivers: counter: alarm: add support for the Smartbond Timer Add support for the Renesas Smartbond Timer IP to the counter alarm sample. Signed-off-by: Jerzy Kasenberg --- samples/drivers/counter/alarm/boards/da1469x_dk_pro.overlay | 5 +++++ samples/drivers/counter/alarm/src/main.c | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 samples/drivers/counter/alarm/boards/da1469x_dk_pro.overlay diff --git a/samples/drivers/counter/alarm/boards/da1469x_dk_pro.overlay b/samples/drivers/counter/alarm/boards/da1469x_dk_pro.overlay new file mode 100644 index 000000000000..a0cf92a2a375 --- /dev/null +++ b/samples/drivers/counter/alarm/boards/da1469x_dk_pro.overlay @@ -0,0 +1,5 @@ +&timer3 { + clock-src = <&lp_clk>; + prescaler = <1>; + status = "okay"; +}; diff --git a/samples/drivers/counter/alarm/src/main.c b/samples/drivers/counter/alarm/src/main.c index f6d22840394a..566cc4eef9dc 100644 --- a/samples/drivers/counter/alarm/src/main.c +++ b/samples/drivers/counter/alarm/src/main.c @@ -27,6 +27,8 @@ struct counter_alarm_cfg alarm_cfg; #define TIMER DT_INST(0, st_stm32_counter) #elif defined(CONFIG_COUNTER_RTC_STM32) #define TIMER DT_INST(0, st_stm32_rtc) +#elif defined(CONFIG_COUNTER_SMARTBOND_TIMER) +#define TIMER DT_NODELABEL(timer3) #elif defined(CONFIG_COUNTER_NATIVE_POSIX) #define TIMER DT_NODELABEL(counter0) #elif defined(CONFIG_COUNTER_XLNX_AXI_TIMER) From d58b3151650c70b4e41a9b48ec8840f41a7fe51e Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 21 Dec 2022 13:49:28 +0100 Subject: [PATCH 0858/2042] tests: drivers: counter: basic_api: add overlay for da1469x_dk_pro Overlay adds 4 timers for testing and selects various frequencies to select high speed (DIVN) and low-speed (LP-CLK) as sources. Different prescalers are applied for different timers to test wider range of conditions. Signed-off-by: Jerzy Kasenberg --- .../boards/da1469x_dk_pro.overlay | 23 +++++++++++++++++++ .../counter_basic_api/src/test_counter.c | 1 + 2 files changed, 24 insertions(+) create mode 100644 tests/drivers/counter/counter_basic_api/boards/da1469x_dk_pro.overlay diff --git a/tests/drivers/counter/counter_basic_api/boards/da1469x_dk_pro.overlay b/tests/drivers/counter/counter_basic_api/boards/da1469x_dk_pro.overlay new file mode 100644 index 000000000000..a0404b411420 --- /dev/null +++ b/tests/drivers/counter/counter_basic_api/boards/da1469x_dk_pro.overlay @@ -0,0 +1,23 @@ +&timer1 { + clock-src = <&lp_clk>; + prescaler = <1>; + status = "okay"; +}; + +&timer2 { + clock-src = <&divn_clk>; + prescaler = <1>; + status = "okay"; +}; + +&timer3 { + clock-src = <&lp_clk>; + prescaler = <2>; + status = "okay"; +}; + +&timer4 { + clock-src = <&divn_clk>; + prescaler = <32>; + 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 9636d9ec2c96..109198d7b5f5 100644 --- a/tests/drivers/counter/counter_basic_api/src/test_counter.c +++ b/tests/drivers/counter/counter_basic_api/src/test_counter.c @@ -53,6 +53,7 @@ static const struct device *const devices[] = { DEVS_FOR_DT_COMPAT(microchip_xec_timer) DEVS_FOR_DT_COMPAT(nxp_imx_epit) DEVS_FOR_DT_COMPAT(nxp_imx_gpt) + DEVS_FOR_DT_COMPAT(renesas_smartbond_timer) #ifdef CONFIG_COUNTER_MCUX_CTIMER DEVS_FOR_DT_COMPAT(nxp_lpc_ctimer) #endif From 2eb14f14691c69edb77d7f5a31512ce5e665ec9b Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 26 May 2023 13:15:09 +0200 Subject: [PATCH 0859/2042] Kconfig: Add new NATIVE_LIBRARY and NATIVE_BUILD options To differentiate builds which will produce a native executable as direct output from the Zephyr build, or a library which can be used later. Signed-off-by: Alberto Escolar Piedras --- Kconfig.zephyr | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 38d86271311e..fffb658b15ac 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -316,14 +316,30 @@ config CODING_GUIDELINE_CHECK Use available compiler flags to check coding guideline rules during the build. -config NATIVE_APPLICATION - bool "Build as a native host application" +config NATIVE_BUILD + bool select FULL_LIBC_SUPPORTED select FULL_LIBCPP_SUPPORTED if CPP + help + Zephyr will be built targeting the host system for debug and + development purposes. + +config NATIVE_APPLICATION + bool + default y if ARCH_POSIX + depends on !NATIVE_LIBRARY + select NATIVE_BUILD help Build as a native application that can run on the host and using resources and libraries provided by the host. +config NATIVE_LIBRARY + bool + select NATIVE_BUILD + help + Build as a prelinked library for the native host target. + This library can later be built into an executable for the host. + config COMPILER_FREESTANDING bool "Build in a freestanding compiler mode" help From 56dc20eb1d1cde8fd7ff9cafaadcfdba964e68f2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 26 May 2023 13:23:43 +0200 Subject: [PATCH 0860/2042] Kconfig: Tidy up dependants of NATIVE_APPLICATION So they depend or select on the right NATIVE_BUILD instead of NATIVE_APPLICATION. Signed-off-by: Alberto Escolar Piedras --- CMakeLists.txt | 2 +- Kconfig.zephyr | 2 +- arch/Kconfig | 2 +- boards/posix/native_posix/Kconfig | 1 + boards/posix/nrf52_bsim/Kconfig.board | 1 + cmake/compiler/gcc/compiler_flags.cmake | 2 +- lib/cpp/Kconfig | 2 +- lib/libc/Kconfig | 2 +- subsys/testsuite/Kconfig | 2 +- 9 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f64f4cf0ff1b..d354d0081798 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,7 +346,7 @@ toolchain_ld_force_undefined_symbols( _ConfigAbsSyms ) -if(NOT CONFIG_NATIVE_APPLICATION) +if(NOT CONFIG_NATIVE_BUILD) # @Intent: Set linker specific flags for bare metal target toolchain_ld_baremetal() endif() diff --git a/Kconfig.zephyr b/Kconfig.zephyr index fffb658b15ac..0fa8ff2db82c 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -414,7 +414,7 @@ config COMPILER_COLOR_DIAGNOSTICS choice COMPILER_SECURITY_FORTIFY prompt "Detect buffer overflows in libc calls" - default FORTIFY_SOURCE_NONE if NO_OPTIMIZATIONS || MINIMAL_LIBC || NATIVE_APPLICATION + default FORTIFY_SOURCE_NONE if NO_OPTIMIZATIONS || MINIMAL_LIBC || NATIVE_BUILD default FORTIFY_SOURCE_COMPILE_TIME help Buffer overflow checking in libc calls. Supported by Clang and diff --git a/arch/Kconfig b/arch/Kconfig index 6179fd7645e2..afa6fb0a7097 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -142,7 +142,7 @@ config ARCH_POSIX select ARCH_HAS_CUSTOM_SWAP_TO_MAIN select ARCH_HAS_CUSTOM_BUSY_WAIT select ARCH_HAS_THREAD_ABORT - select NATIVE_APPLICATION + select NATIVE_BUILD select HAS_COVERAGE_SUPPORT select BARRIER_OPERATIONS_BUILTIN help diff --git a/boards/posix/native_posix/Kconfig b/boards/posix/native_posix/Kconfig index 5b785fd642f5..3d79a87504f8 100644 --- a/boards/posix/native_posix/Kconfig +++ b/boards/posix/native_posix/Kconfig @@ -4,6 +4,7 @@ config BOARD_NATIVE_POSIX bool select NATIVE_POSIX_TIMER select POSIX_ARCH_CONSOLE + select NATIVE_APPLICATION if BOARD_NATIVE_POSIX diff --git a/boards/posix/nrf52_bsim/Kconfig.board b/boards/posix/nrf52_bsim/Kconfig.board index 6dea002f541b..bcf7141c25e4 100644 --- a/boards/posix/nrf52_bsim/Kconfig.board +++ b/boards/posix/nrf52_bsim/Kconfig.board @@ -11,6 +11,7 @@ config BOARD_NRF52_BSIM select CLOCK_CONTROL select HAS_NRFX select HAS_NORDIC_DRIVERS + select NATIVE_APPLICATION 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/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index f2c2845923bf..75c54577cdc2 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -106,7 +106,7 @@ if (NOT CONFIG_NEWLIB_LIBC AND NOT (CONFIG_PICOLIBC AND NOT CONFIG_PICOLIBC_USE_MODULE) AND NOT COMPILER STREQUAL "xcc" AND NOT CONFIG_HAS_ESPRESSIF_HAL AND - NOT CONFIG_NATIVE_APPLICATION) + NOT CONFIG_NATIVE_BUILD) set_compiler_property(PROPERTY nostdinc -nostdinc) set_compiler_property(APPEND PROPERTY nostdinc_include ${NOSTDINC}) endif() diff --git a/lib/cpp/Kconfig b/lib/cpp/Kconfig index 1e032a9e85b6..3cfb8ac57e9d 100644 --- a/lib/cpp/Kconfig +++ b/lib/cpp/Kconfig @@ -73,7 +73,7 @@ config FULL_LIBCPP_SUPPORTED choice LIBCPP_IMPLEMENTATION prompt "C++ Standard Library Implementation" - default EXTERNAL_LIBCPP if REQUIRES_FULL_LIBCPP && NATIVE_APPLICATION + default EXTERNAL_LIBCPP if REQUIRES_FULL_LIBCPP && NATIVE_BUILD default GLIBCXX_LIBCPP if REQUIRES_FULL_LIBCPP default MINIMAL_LIBCPP diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 81d34fcfc68b..0f3f96fa9842 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -54,7 +54,7 @@ menu "C Library" choice LIBC_IMPLEMENTATION prompt "C Library Implementation" - default EXTERNAL_LIBC if NATIVE_APPLICATION + default EXTERNAL_LIBC if NATIVE_BUILD default NEWLIB_LIBC if REQUIRES_FULL_LIBC default PICOLIBC if REQUIRES_FULL_LIBC default MINIMAL_LIBC diff --git a/subsys/testsuite/Kconfig b/subsys/testsuite/Kconfig index 8de5c9d9360a..cd528ec555a0 100644 --- a/subsys/testsuite/Kconfig +++ b/subsys/testsuite/Kconfig @@ -44,7 +44,7 @@ config COVERAGE_GCOV bool "Create Coverage data from hardware platform" default y depends on COVERAGE - depends on !NATIVE_APPLICATION + depends on !NATIVE_BUILD help This option will select the custom gcov library. The reports will be available over serial. This serial dump can be passed to From 2e6396cf2050243478abc05d7085251852d82c09 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 9 Jun 2023 14:28:01 +0200 Subject: [PATCH 0861/2042] libC: STDOUT_CONSOLE narrow filtering by type of native build It is possible to build with STDOUT_CONSOLE with the embedded C libraries with the POSIX arch. Narrow down the filtering accordingly. Signed-off-by: Alberto Escolar Piedras --- lib/libc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index 0f3f96fa9842..7b91feec0409 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -117,7 +117,7 @@ rsource "picolibc/Kconfig" config STDOUT_CONSOLE bool "Send stdout to console" depends on CONSOLE_HAS_DRIVER - depends on !NATIVE_APPLICATION + depends on !(NATIVE_APPLICATION || (NATIVE_LIBRARY && EXTERNAL_LIBC)) default y help This option directs standard output (e.g. printf) to the console From 5abee92a6c21bf1b0b2178d389fdbe720010eaa2 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 16:04:57 +0200 Subject: [PATCH 0862/2042] samples zbus uart_bridge: Add overlay for native_sim Add overlay configuration for native_sim. Signed-off-by: Alberto Escolar Piedras --- samples/subsys/zbus/uart_bridge/boards/native_sim.conf | 1 + samples/subsys/zbus/uart_bridge/boards/native_sim_64.conf | 1 + 2 files changed, 2 insertions(+) create mode 100644 samples/subsys/zbus/uart_bridge/boards/native_sim.conf create mode 100644 samples/subsys/zbus/uart_bridge/boards/native_sim_64.conf diff --git a/samples/subsys/zbus/uart_bridge/boards/native_sim.conf b/samples/subsys/zbus/uart_bridge/boards/native_sim.conf new file mode 100644 index 000000000000..b552360756ca --- /dev/null +++ b/samples/subsys/zbus/uart_bridge/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=y diff --git a/samples/subsys/zbus/uart_bridge/boards/native_sim_64.conf b/samples/subsys/zbus/uart_bridge/boards/native_sim_64.conf new file mode 100644 index 000000000000..b552360756ca --- /dev/null +++ b/samples/subsys/zbus/uart_bridge/boards/native_sim_64.conf @@ -0,0 +1 @@ +CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=y From d3633b58f10a90fc508eeff44fd1c456ccbcba96 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Tue, 6 Jun 2023 16:32:40 +0200 Subject: [PATCH 0863/2042] tests ADC API: Add overlay for native_sim Add DT overlay for native_sim. Signed-off-by: Alberto Escolar Piedras --- tests/drivers/adc/adc_api/boards/native_sim.overlay | 7 +++++++ tests/drivers/adc/adc_api/boards/native_sim_64.overlay | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/drivers/adc/adc_api/boards/native_sim.overlay create mode 100644 tests/drivers/adc/adc_api/boards/native_sim_64.overlay diff --git a/tests/drivers/adc/adc_api/boards/native_sim.overlay b/tests/drivers/adc/adc_api/boards/native_sim.overlay new file mode 100644 index 000000000000..6b622000bdf5 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/native_sim.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" diff --git a/tests/drivers/adc/adc_api/boards/native_sim_64.overlay b/tests/drivers/adc/adc_api/boards/native_sim_64.overlay new file mode 100644 index 000000000000..6b622000bdf5 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/native_sim_64.overlay @@ -0,0 +1,7 @@ +/* + * Copyright 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_posix.overlay" From 41a185a1b53286bd972dab84fde105b92a39a73e Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 10:29:10 +0200 Subject: [PATCH 0864/2042] arch POSIX: Use posix cheats only for native apps native libraries do not need it Signed-off-by: Alberto Escolar Piedras --- arch/posix/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 6f987149c855..2f7a8cec6735 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -16,9 +16,14 @@ endif() zephyr_compile_options( ${ARCH_FLAG} - -include ${ZEPHYR_BASE}/arch/posix/include/posix_cheats.h ) +if (CONFIG_NATIVE_APPLICATION) + zephyr_compile_options( + -include ${ZEPHYR_BASE}/arch/posix/include/posix_cheats.h + ) +endif() + # @Intent: Obtain compiler specific flags for no freestanding compilation zephyr_compile_options($) From 3af65caed0afb9a909620492caeb45fe05811b46 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 13:10:09 +0200 Subject: [PATCH 0865/2042] samples display lvgl: Add overlay for native_sim Add overlays for the native_sim board Signed-off-by: Alberto Escolar Piedras --- samples/subsys/display/lvgl/boards/native_sim.conf | 5 +++++ samples/subsys/display/lvgl/boards/native_sim.overlay | 6 ++++++ samples/subsys/display/lvgl/boards/native_sim_64.conf | 5 +++++ samples/subsys/display/lvgl/boards/native_sim_64.overlay | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 samples/subsys/display/lvgl/boards/native_sim.conf create mode 100644 samples/subsys/display/lvgl/boards/native_sim.overlay create mode 100644 samples/subsys/display/lvgl/boards/native_sim_64.conf create mode 100644 samples/subsys/display/lvgl/boards/native_sim_64.overlay diff --git a/samples/subsys/display/lvgl/boards/native_sim.conf b/samples/subsys/display/lvgl/boards/native_sim.conf new file mode 100644 index 000000000000..93d63c2b2ded --- /dev/null +++ b/samples/subsys/display/lvgl/boards/native_sim.conf @@ -0,0 +1,5 @@ +CONFIG_LV_COLOR_DEPTH_32=y +CONFIG_GPIO=y +CONFIG_KSCAN=y +CONFIG_INPUT=y +CONFIG_LV_Z_POINTER_KSCAN=y diff --git a/samples/subsys/display/lvgl/boards/native_sim.overlay b/samples/subsys/display/lvgl/boards/native_sim.overlay new file mode 100644 index 000000000000..a77c43378bd6 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/native_sim.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_posix.overlay" diff --git a/samples/subsys/display/lvgl/boards/native_sim_64.conf b/samples/subsys/display/lvgl/boards/native_sim_64.conf new file mode 100644 index 000000000000..93d63c2b2ded --- /dev/null +++ b/samples/subsys/display/lvgl/boards/native_sim_64.conf @@ -0,0 +1,5 @@ +CONFIG_LV_COLOR_DEPTH_32=y +CONFIG_GPIO=y +CONFIG_KSCAN=y +CONFIG_INPUT=y +CONFIG_LV_Z_POINTER_KSCAN=y diff --git a/samples/subsys/display/lvgl/boards/native_sim_64.overlay b/samples/subsys/display/lvgl/boards/native_sim_64.overlay new file mode 100644 index 000000000000..5308ee486800 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/native_sim_64.overlay @@ -0,0 +1,6 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "native_sim.overlay" From feaf0ff5761b8f4deb1b8e93d4e760975ac28739 Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Wed, 7 Jun 2023 10:28:22 +0200 Subject: [PATCH 0866/2042] cmake: Treat native libraries differently where needed When building a native library there is a few options we cannot pass to the compiler and linker, including instructing them to genrate non PIE code (as it is still to early to say that), or garbage collect unused sections (as we are not yet doing the final linking). We also need to provide different link options when building the elf for the DTS gen_handles parsing (as that script requires a "final" executable elf) than when we build the native library itself. Signed-off-by: Alberto Escolar Piedras --- CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d354d0081798..390d12fbd90f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,7 +351,7 @@ if(NOT CONFIG_NATIVE_BUILD) toolchain_ld_baremetal() endif() -if(CONFIG_CPP AND NOT CONFIG_MINIMAL_LIBCPP) +if(CONFIG_CPP AND NOT CONFIG_MINIMAL_LIBCPP AND NOT CONFIG_NATIVE_LIBRARY) # @Intent: Set linker specific flags for C++ toolchain_ld_cpp() endif() @@ -394,7 +394,12 @@ zephyr_compile_options($<$:$:$>) zephyr_compile_options($<$:$>) -zephyr_link_libraries($) + +# In case of CONFIG_NATIVE_LIBRARY we also don't want position independent code, +# but we cannot tell that to the linker yet as we are first only doing a +# relocatable link into a static library +zephyr_link_libraries_ifndef(CONFIG_NATIVE_LIBRARY + $) # Allow the user to inject options when calling cmake, e.g. # 'cmake -DEXTRA_CFLAGS="-Werror -Wno-deprecated-declarations" ..' @@ -1209,6 +1214,8 @@ if(CONFIG_USERSPACE OR CONFIG_DEVICE_DEPS) LIBRARIES_POST_SCRIPT "" DEPENDENCIES ${CODE_RELOCATION_DEP} ) + target_link_libraries_ifdef(CONFIG_NATIVE_LIBRARY ${ZEPHYR_LINK_STAGE_EXECUTABLE} + $) target_byproducts(TARGET ${ZEPHYR_LINK_STAGE_EXECUTABLE} BYPRODUCTS ${PROJECT_BINARY_DIR}/${ZEPHYR_LINK_STAGE_EXECUTABLE}.map ) @@ -1426,6 +1433,8 @@ toolchain_ld_link_elf( LINKER_SCRIPT ${PROJECT_BINARY_DIR}/${ZEPHYR_CURRENT_LINKER_CMD} DEPENDENCIES ${CODE_RELOCATION_DEP} ) +target_link_libraries_ifdef(CONFIG_NATIVE_LIBRARY ${ZEPHYR_LINK_STAGE_EXECUTABLE} + $) target_byproducts(TARGET ${ZEPHYR_LINK_STAGE_EXECUTABLE} BYPRODUCTS ${PROJECT_BINARY_DIR}/${ZEPHYR_LINK_STAGE_EXECUTABLE}.map ) From 850fc2f22f058bbf022e999f6d2c4be7ccd4e5de Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Fri, 26 May 2023 18:04:42 +0200 Subject: [PATCH 0867/2042] Native simulator: Add first version in-tree Add the first version of the native simulator. The simultaor is taken as is from https://github.com/BabbleSim/native_simulator/ sha: 74986abfe088a1780e604dae65f87470b4c2a0eb Signed-off-by: Alberto Escolar Piedras --- scripts/native_simulator/.gitignore | 11 + scripts/native_simulator/Makefile | 127 ++++ .../common/other/linker_script.pre.ld | 50 ++ .../common/src/include/nce_if.h | 32 + .../common/src/include/nct_if.h | 33 + .../common/src/include/nsi_cpu_es_if.h | 19 + .../common/src/include/nsi_cpu_if.h | 100 +++ .../common/src/include/nsi_host_trampolines.h | 34 + .../common/src/include/nsi_hw_scheduler.h | 32 + .../common/src/include/nsi_hws_models_if.h | 43 ++ .../common/src/include/nsi_main.h | 27 + .../common/src/include/nsi_tracing.h | 47 ++ scripts/native_simulator/common/src/main.c | 144 ++++ scripts/native_simulator/common/src/nce.c | 292 ++++++++ scripts/native_simulator/common/src/nct.c | 690 ++++++++++++++++++ .../common/src/nsi_host_trampolines.c | 19 + .../common/src/nsi_hw_scheduler.c | 181 +++++ .../common/src/nsi_internal.h | 37 + .../common/src/nsi_safe_call.h | 37 + .../native_simulator/common/src/nsi_tasks.c | 42 ++ .../native_simulator/common/src/nsi_tasks.h | 69 ++ .../common/src/nsi_trace_varg.c | 35 + .../native_simulator/common/src/nsi_utils.h | 26 + .../native_simulator/native/src/hw_counter.c | 104 +++ .../native/src/include/hw_counter.h | 33 + .../native/src/include/irq_ctrl.h | 46 ++ .../native/src/include/native_rtc.h | 75 ++ .../native/src/include/nsi_cmdline.h | 81 ++ .../native/src/include/nsi_cpu0_interrupts.h | 27 + .../native/src/include/nsi_timer_model.h | 38 + .../native_simulator/native/src/irq_ctrl.c | 268 +++++++ .../native_simulator/native/src/native_rtc.c | 69 ++ .../native_simulator/native/src/nsi_cmdline.c | 152 ++++ .../native/src/nsi_cmdline_common.c | 420 +++++++++++ .../native/src/nsi_cmdline_internal.h | 43 ++ .../native_simulator/native/src/nsi_trace.c | 157 ++++ .../native_simulator/native/src/timer_model.c | 540 ++++++++++++++ 37 files changed, 4180 insertions(+) create mode 100644 scripts/native_simulator/.gitignore create mode 100644 scripts/native_simulator/Makefile create mode 100644 scripts/native_simulator/common/other/linker_script.pre.ld create mode 100644 scripts/native_simulator/common/src/include/nce_if.h create mode 100644 scripts/native_simulator/common/src/include/nct_if.h create mode 100644 scripts/native_simulator/common/src/include/nsi_cpu_es_if.h create mode 100644 scripts/native_simulator/common/src/include/nsi_cpu_if.h create mode 100644 scripts/native_simulator/common/src/include/nsi_host_trampolines.h create mode 100644 scripts/native_simulator/common/src/include/nsi_hw_scheduler.h create mode 100644 scripts/native_simulator/common/src/include/nsi_hws_models_if.h create mode 100644 scripts/native_simulator/common/src/include/nsi_main.h create mode 100644 scripts/native_simulator/common/src/include/nsi_tracing.h create mode 100644 scripts/native_simulator/common/src/main.c create mode 100644 scripts/native_simulator/common/src/nce.c create mode 100644 scripts/native_simulator/common/src/nct.c create mode 100644 scripts/native_simulator/common/src/nsi_host_trampolines.c create mode 100644 scripts/native_simulator/common/src/nsi_hw_scheduler.c create mode 100644 scripts/native_simulator/common/src/nsi_internal.h create mode 100644 scripts/native_simulator/common/src/nsi_safe_call.h create mode 100644 scripts/native_simulator/common/src/nsi_tasks.c create mode 100644 scripts/native_simulator/common/src/nsi_tasks.h create mode 100644 scripts/native_simulator/common/src/nsi_trace_varg.c create mode 100644 scripts/native_simulator/common/src/nsi_utils.h create mode 100644 scripts/native_simulator/native/src/hw_counter.c create mode 100644 scripts/native_simulator/native/src/include/hw_counter.h create mode 100644 scripts/native_simulator/native/src/include/irq_ctrl.h create mode 100644 scripts/native_simulator/native/src/include/native_rtc.h create mode 100644 scripts/native_simulator/native/src/include/nsi_cmdline.h create mode 100644 scripts/native_simulator/native/src/include/nsi_cpu0_interrupts.h create mode 100644 scripts/native_simulator/native/src/include/nsi_timer_model.h create mode 100644 scripts/native_simulator/native/src/irq_ctrl.c create mode 100644 scripts/native_simulator/native/src/native_rtc.c create mode 100644 scripts/native_simulator/native/src/nsi_cmdline.c create mode 100644 scripts/native_simulator/native/src/nsi_cmdline_common.c create mode 100644 scripts/native_simulator/native/src/nsi_cmdline_internal.h create mode 100644 scripts/native_simulator/native/src/nsi_trace.c create mode 100644 scripts/native_simulator/native/src/timer_model.c diff --git a/scripts/native_simulator/.gitignore b/scripts/native_simulator/.gitignore new file mode 100644 index 000000000000..fd94d56559d2 --- /dev/null +++ b/scripts/native_simulator/.gitignore @@ -0,0 +1,11 @@ +_build/* +*.o +*.a +*.d +*.elf +*.gcda +*.gcno +*~ +~*.~* +/.*project +.settings/* diff --git a/scripts/native_simulator/Makefile b/scripts/native_simulator/Makefile new file mode 100644 index 000000000000..5dc9b409e1f0 --- /dev/null +++ b/scripts/native_simulator/Makefile @@ -0,0 +1,127 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Native Simulator (NSI) Makefile. +# It builds the simulator runner itself, and produces the final +# Linux executable by linking it to the the embedded cpu library + +# By default all the build output is placed under the _build folder, but the user can override it +# setting the NSI_BUILD_PATH + +NSI_CONFIG_FILE?=nsi_config +-include ${NSI_CONFIG_FILE} + +NSI_PATH?=./ +NSI_BUILD_PATH?=$(abspath _build/) +EXE_NAME?=native_simulator.exe +NSI_EXE?=${NSI_BUILD_PATH}/${EXE_NAME} +NSI_EMBEDDED_CPU_SW?= +NSI_ARCH?=-m32 +NSI_COVERAGE?=--coverage +NSI_BUILD_OPTIONS?=${NSI_ARCH} ${NSI_COVERAGE} +NSI_LINK_OPTIONS?=${NSI_ARCH} ${NSI_COVERAGE} +NSI_EXTRA_SRCS?= +NSI_EXTRA_LIBS?= + +SHELL?=bash +NSI_CC?=gcc +NSI_AR?=ar +NSI_OBJCOPY?=objcopy + +no_default: + @echo "There is no default rule, please specify what you want to build,\ + or run make help for more info" + +NSI_DEBUG?=-g +NSI_OPT?=-O0 +NSI_WARNINGS?=-Wall -Wpedantic +NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED +NO_PIE_CO:=-fno-pie -fno-pic +DEPENDFLAGS:=-MMD -MP +CFLAGS:=${NSI_DEBUG} ${NSI_WARNINGS} ${NSI_OPT} ${NO_PIE_CO} \ + -ffunction-sections -fdata-sections ${DEPENDFLAGS} -std=c11 ${NSI_BUILD_OPTIONS} +FINALLINK_FLAGS:=${NO_PIE_CO} -no-pie ${NSI_WARNINGS} \ + -Wl,--gc-sections -lm -ldl -pthread \ + ${NSI_LINK_OPTIONS} + +RUNNER_LIB:=runner.a + +SRCS:=$(shell ls ${NSI_PATH}common/src/*.c ${NSI_PATH}native/src/*.c ) + +INCLUDES:=-I${NSI_PATH}common/src/include/ \ + -I${NSI_PATH}native/src/include/ \ + -I${NSI_PATH}common/src + +EXTRA_OBJS:=$(abspath $(addprefix $(NSI_BUILD_PATH)/,$(sort ${NSI_EXTRA_SRCS:%.c=%.o}))) +OBJS:=$(abspath $(addprefix $(NSI_BUILD_PATH)/,${SRCS:${NSI_PATH}%.c=%.o})) ${EXTRA_OBJS} + +DEPENDFILES:=$(addsuffix .d,$(basename ${OBJS})) + +-include ${DEPENDFILES} + +${NSI_BUILD_PATH}: + @if [ ! -d ${NSI_BUILD_PATH} ]; then mkdir -p ${NSI_BUILD_PATH}; fi + +#Extra sources build: +${NSI_BUILD_PATH}/%.o: /%.c ${NSI_PATH}Makefile ${NSI_CONFIG_FILE} + @if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi + ${NSI_CC} ${NSI_CPPFLAGS} ${INCLUDES} ${CFLAGS} -c $< -o $@ + +${NSI_BUILD_PATH}/%.o: ${NSI_PATH}/%.c ${NSI_PATH}Makefile ${NSI_CONFIG_FILE} + @if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi + ${NSI_CC} ${NSI_CPPFLAGS} ${INCLUDES} ${CFLAGS} -c $< -o $@ + +${NSI_BUILD_PATH}/linker_script.ld : ${NSI_PATH}/common/other/linker_script.pre.ld | ${NSI_BUILD_PATH} + ${NSI_CC} -x c -E -P $< -o $@ ${DEPENDFLAGS} + +${NSI_BUILD_PATH}/${RUNNER_LIB}: ${OBJS} + if [ -f $@ ]; then rm $@ ; fi + ${NSI_AR} -cr $@ ${OBJS} + +${NSI_EXE}: ${NSI_BUILD_PATH}/${RUNNER_LIB} ${NSI_EMBEDDED_CPU_SW} ${NSI_EXTRA_LIBS} \ + ${NSI_BUILD_PATH}/linker_script.ld + @if [ -z ${NSI_EMBEDDED_CPU_SW} ] || [ ! -f ${NSI_EMBEDDED_CPU_SW} ]; then \ + echo "Error: Input embedded CPU SW not found (NSI_EMBEDDED_CPU_SW=${NSI_EMBEDDED_CPU_SW} )"; \ + false; \ + fi + ${NSI_OBJCOPY} --localize-hidden ${NSI_EMBEDDED_CPU_SW} ${NSI_BUILD_PATH}/cpu_0.sw.o \ + -w --localize-symbol=_* + ${NSI_CC} -Wl,--whole-archive ${NSI_BUILD_PATH}/cpu_0.sw.o ${NSI_BUILD_PATH}/${RUNNER_LIB} \ + ${NSI_EXTRA_LIBS} -Wl,--no-whole-archive \ + -o $@ ${FINALLINK_FLAGS} -T ${NSI_BUILD_PATH}/linker_script.ld + +Makefile: ; + +link_with_esw: ${NSI_EXE}; + +runner_lib: ${NSI_BUILD_PATH}/${RUNNER_LIB} + +all: link_with_esw + +clean: + @echo "Deleting intermediate compilation results + libraries + executables (*.d .o .a .exe)" + find $(NSI_BUILD_PATH) -name "*.o" -or -name "*.exe" -or -name "*.a" -or -name "*.d" | xargs rm -f + +clean_coverage: + find $(NSI_BUILD_PATH) -name "*.gcda" -or -name "*.gcno" | xargs rm -f ; true + +clean_all: clean clean_coverage ; + +.PHONY: clean clean_coverage clean_all link_with_esw runner_lib no_default all ${DEPENDFILES} + +ifndef NSI_BUILD_VERBOSE +.SILENT: +endif + +help: + @echo "*******************************" + @echo "* Native Simulator makefile *" + @echo "*******************************" + @echo "Provided rules:" + @echo " clean : clean all build output" + @echo " clean_coverage : clean all coverage files" + @echo " clean_all : clean + clean_coverage" + @echo " link_with_esw : Link the runner with the CPU embedded sw" + @echo " runner_lib : Build the runner itself (pending the embedded SW)" + @echo " all : link_with_esw" + @echo "Note that you can use TAB to autocomplete rules in the command line in modern OSs" diff --git a/scripts/native_simulator/common/other/linker_script.pre.ld b/scripts/native_simulator/common/other/linker_script.pre.ld new file mode 100644 index 000000000000..408d8a660d0d --- /dev/null +++ b/scripts/native_simulator/common/other/linker_script.pre.ld @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file for the native simulator runner + */ + +#define NSI_INIT_LEVEL(level) \ + __nsi_##level##_tasks_start = .; \ + KEEP(*(SORT(.nsi_##level[0-9]_task))); \ + KEEP(*(SORT(.nsi_##level[1-9][0-9]_task))); \ + KEEP(*(SORT(.nsi_##level[1-9][0-9][0-9]_task))); \ + +SECTIONS + { + nsi_tasks : + { + __nsi_tasks_start = .; + NSI_INIT_LEVEL(PRE_BOOT_1) + NSI_INIT_LEVEL(PRE_BOOT_2) + NSI_INIT_LEVEL(HW_INIT) + NSI_INIT_LEVEL(PRE_BOOT_3) + NSI_INIT_LEVEL(FIRST_SLEEP) + NSI_INIT_LEVEL(ON_EXIT_PRE) + NSI_INIT_LEVEL(ON_EXIT_POST) + __nsi_tasks_end = .; + } + + nsi_hw_events : + { + __nsi_hw_events_callbacks_start = .; + KEEP(*(SORT(.nsi_hw_event[0-9]_callback))); \ + KEEP(*(SORT(.nsi_hw_event[1-9][0-9]_callback))); \ + KEEP(*(SORT(.nsi_hw_event[1-9][0-9][0-9]_callback))); + __nsi_hw_events_callbacks_end = .; + __nsi_hw_events_timers_start = .; + KEEP(*(SORT(.nsi_hw_event[0-9]_timer))); \ + KEEP(*(SORT(.nsi_hw_event[1-9][0-9]_timer))); \ + KEEP(*(SORT(.nsi_hw_event[1-9][0-9][0-9]_timer))); + __nsi_hw_events_timers_end = .; + } + } INSERT AFTER .data; + +/* + * Note this script augments the default host linker script + */ diff --git a/scripts/native_simulator/common/src/include/nce_if.h b/scripts/native_simulator/common/src/include/nce_if.h new file mode 100644 index 000000000000..5ce5d20dc570 --- /dev/null +++ b/scripts/native_simulator/common/src/include/nce_if.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef NSI_COMMON_SRC_INCL_NCE_IF_H +#define NSI_COMMON_SRC_INCL_NCE_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Native simulator CPU start/stop emulation module interface + * + * Check docs/NCE.md for an overview. + * + * A descriptions of each function can be found in the .c file + */ + +void *nce_init(void); +void nce_terminate(void *this); +void nce_boot_cpu(void *this, void (*start_routine)(void)); +void nce_halt_cpu(void *this); +void nce_wake_cpu(void *this); +int nce_is_cpu_running(void *this); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NCE_IF_H */ diff --git a/scripts/native_simulator/common/src/include/nct_if.h b/scripts/native_simulator/common/src/include/nct_if.h new file mode 100644 index 000000000000..6887ab99b6ca --- /dev/null +++ b/scripts/native_simulator/common/src/include/nct_if.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef NSI_COMMON_SRC_INCL_NCT_IF_H +#define NSI_COMMON_SRC_INCL_NCT_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interface provided by the Native simulator CPU threading emulation + * + * A description of each function can be found in the C file + * + * In docs/NCT.md you can find more information + */ + +void *nct_init(void (*fptr)(void *)); +void nct_clean_up(void *this); +void nct_swap_threads(void *this, int next_allowed_thread_nbr); +void nct_first_thread_start(void *this, int next_allowed_thread_nbr); +int nct_new_thread(void *this, void *payload); +void nct_abort_thread(void *this, int thread_idx); +int nct_get_unique_thread_id(void *this, int thread_idx); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NCT_IF_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_cpu_es_if.h b/scripts/native_simulator/common/src/include/nsi_cpu_es_if.h new file mode 100644 index 000000000000..a847820596af --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_cpu_es_if.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Interfaces the Native Simulator provides to + * the embedded CPU SW + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_CPU_ES_IF_H +#define NSI_COMMON_SRC_INCL_NSI_CPU_ES_IF_H + +#include "nsi_tracing.h" +#include "nsi_main.h" +#include "nsi_hw_scheduler.h" + +#endif /* NSI_COMMON_SRC_INCL_NSI_CPU_ES_IF_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_cpu_if.h b/scripts/native_simulator/common/src/include/nsi_cpu_if.h new file mode 100644 index 000000000000..c49374e4a9a5 --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_cpu_if.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_CPU_IF_H +#define NSI_COMMON_SRC_INCL_NSI_CPU_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Any symbol annotated by this macro will be visible outside of the + * embedded SW library, both by the native simulator runner, + * and other possible embedded CPU's SW. + */ +#define NATIVE_SIMULATOR_IF __attribute__((visibility("default"))) \ + __attribute__((__section__(".native_sim_if"))) +/* + * Implementation note: + * The interface between the embedded SW and the native simulator is allocated in its + * own section to allow the embedded software developers to, using a linker script, + * direct the linker to keep those symbols even when doing its linking with garbage collection. + * It is also be possible for the embedded SW to require the linker to keep those + * symbols by requiring each of them to be kept explicitly by name (either by defining them + * as entry points, or as required in the output). + * It is also possible for the embedded SW developers to not use garbage collection + * during their SW linking. + */ + + +/* + * Interfaces the Native Simulator _expects_ from the embedded CPUs: + */ + +/* + * Called during the earliest initialization (before command line parsing) + * + * The embedded SW library may provide this function to perform any + * early initialization, including registering its own command line arguments + * in the runner. + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_pre_cmdline_hooks(void); + +/* + * Called during initialization (before the HW models are initialized) + * + * The embedded SW library may provide this function to perform any + * early initialization, after the command line arguments have been parsed. + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_pre_hw_init_hooks(void); + +/* + * Called by the runner to boot the CPU. + * + * The embedded SW library must provide this function. + * This function is expected to return after the embedded CPU + * has gone to sleep for the first time. + * + * The expectation is that the embedded CPU SW will spawn a + * new pthread while in this call, and run the embedded SW + * initialization in that pthread. + * + * It is recommended for the embedded SW to use the NCE (CPU start/stop emulation) + * component to achieve this. + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_boot(void); + +/* + * Called by the runner when the simulation is ending/exiting + * + * The embedded SW library may provide this function. + * to do any cleanup it needs. + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_cleanup(void); + +/* + * Called by the runner each time an interrupt is raised by the HW + * + * The embedded SW library must provide this function. + * This function is expected to return after the embedded CPU + * has gone back to sleep. + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_irq_raised(void); + +/* + * Called by the runner each time an interrupt is raised in SW context itself. + * That is, when a embedded SW action in the HW models, causes an immediate + * interrupt to be raised (while the execution is still in the + * context of the calling SW thread). + */ +NATIVE_SIMULATOR_IF void nsif_cpu0_irq_raised_from_sw(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_CPU_IF_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h new file mode 100644 index 000000000000..53eff33bc99f --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * The native simulator provides a set of trampolines to some of the simplest + * host C library symbols. + * These are intended to facilitate test embedded code interacting with the host. + * + * We should never include here symbols which require host headers be exposed + * to the embedded side, for example due to non-basic types being used in + * function calls, as that would break the include path isolation + * + * Naming convention: nsi_hots_() where is the name of the equivalent + * C library call we call thru. + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_HOST_TRAMPOLINES_H +#define NSI_COMMON_SRC_INCL_NSI_HOST_TRAMPOLINES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* void nsi_host_exit (int status); Use nsi_exit() instead */ +/* int nsi_host_printf (const char *fmt, ...); Use the nsi_tracing.h equivalents */ +long nsi_host_random(void); +void nsi_host_srandom(unsigned int seed); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_HOST_TRAMPOLINES_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h new file mode 100644 index 000000000000..1f40fc89e783 --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_HW_SCHEDULER_H +#define NSI_COMMON_SRC_INCL_HW_SCHEDULER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NSI_NEVER UINT64_MAX + +/* API intended for the native simulator specific embedded drivers: */ +uint64_t nsi_hws_get_time(void); + +/* Internal APIs to the native_simulator and its HW models: */ +void nsi_hws_init(void); +void nsi_hws_cleanup(void); +void nsi_hws_one_event(void); +void nsi_hws_set_end_of_time(uint64_t new_end_of_time); +void nsi_hws_find_next_event(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_HW_SCHEDULER_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_hws_models_if.h b/scripts/native_simulator/common/src/include/nsi_hws_models_if.h new file mode 100644 index 000000000000..544234d2f482 --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_hws_models_if.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_HWS_MODELS_IF_H +#define NSI_COMMON_SRC_INCL_HWS_MODELS_IF_H + +#include +#include "nsi_utils.h" +#include "nsi_hw_scheduler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Register an event timer and event callback + * + * The HW scheduler will keep track of this event, and call its callback whenever its + * timer is reached. + * The ordering of events in the same microsecond is given by prio (lowest first), + * and if also in the same priority by alphabetical order of the callback. + * (Normally HW models will not care about the event ordering, and will simply set a prio like 100) + * + * Only very particular models will need to execute before or after others. + */ +#define NSI_HW_EVENT(timer, fn, prio) \ + static void (* const NSI_CONCAT(__nsi_hw_event_cb_, fn))(void) \ + __attribute__((__used__)) \ + __attribute__((__section__(".nsi_hw_event" NSI_STRINGIFY(prio) "_callback")))\ + = fn; \ + static uint64_t * const NSI_CONCAT(__nsi_hw_event_ti_, fn) \ + __attribute__((__used__)) \ + __attribute__((__section__(".nsi_hw_event" NSI_STRINGIFY(prio) "_timer")))\ + = &timer + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_HWS_MODELS_IF_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_main.h b/scripts/native_simulator/common/src/include/nsi_main.h new file mode 100644 index 000000000000..84714e90db62 --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_main.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_MAIN_H +#define NSI_COMMON_SRC_INCL_NSI_MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Terminate the execution of the native simulator + * + * exit_code: Requested exit code to the shell + * 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); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_MAIN_H */ diff --git a/scripts/native_simulator/common/src/include/nsi_tracing.h b/scripts/native_simulator/common/src/include/nsi_tracing.h new file mode 100644 index 000000000000..e8ff4fb75d3b --- /dev/null +++ b/scripts/native_simulator/common/src/include/nsi_tracing.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_TRACING_H +#define NSI_COMMON_SRC_INCL_NSI_TRACING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Native simulator tracing API: + * Print a message/warning/error to the tracing backend + * and in case of nsi_print_error_and_exit() also call nsi_exit() + * + * All print()/vprint() APIs take the same arguments as printf()/vprintf(). + */ + +void nsi_print_error_and_exit(const char *format, ...); +void nsi_print_warning(const char *format, ...); +void nsi_print_trace(const char *format, ...); +void nsi_vprint_error_and_exit(const char *format, va_list vargs); +void nsi_vprint_warning(const char *format, va_list vargs); +void nsi_vprint_trace(const char *format, va_list vargs); + +/* + * @brief Is the tracing backend connected to a ptty/terminal or not + * + * @param nbr: Which output. Options are: 0 trace output, 1: warning and error output + * + * @return + * 0 : Not a ptty (i.e. probably a pipe to another program) + * 1 : Connected to a ptty (for ex. stdout/err to the invoking terminal) + * -1: Unknown at this point + */ +int nsi_trace_over_tty(int nbr); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_TRACING_H */ diff --git a/scripts/native_simulator/common/src/main.c b/scripts/native_simulator/common/src/main.c new file mode 100644 index 000000000000..6c341d486c05 --- /dev/null +++ b/scripts/native_simulator/common/src/main.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Native simulator entry point (main) + * + * Documentation can be found starting in docs/README.md + */ + +#include +#include + +#include "nsi_cpu_if.h" +#include "nsi_tasks.h" +#include "nsi_cmdline.h" +#include "nsi_utils.h" +#include "nsi_hw_scheduler.h" + +void nsi_exit(int exit_code) +{ + static int max_exit_code; + + max_exit_code = NSI_MAX(exit_code, max_exit_code); + /* + * nsif_cpu0_cleanup may not return if this is called from a SW thread, + * but instead it would get nsi_exit() recalled again + * ASAP from the HW thread + */ + nsif_cpu0_cleanup(); + nsi_run_tasks(NSITASK_ON_EXIT_PRE_LEVEL); + nsi_hws_cleanup(); + nsi_cleanup_cmd_line(); + nsi_run_tasks(NSITASK_ON_EXIT_POST_LEVEL); + exit(max_exit_code); +} + +/** + * Run all early native_posix initialization steps, including command + * line parsing and CPU start, until we are ready to let the HW models + * run via hwm_one_event() + */ +static void nsi_init(int argc, char *argv[]) +{ + /* + * Let's ensure that even if we are redirecting to a file, we get stdout + * and stderr line buffered (default for console) + * Note that glibc ignores size. But just in case we set a reasonable + * number in case somebody tries to compile against a different library + */ + setvbuf(stdout, NULL, _IOLBF, 512); + setvbuf(stderr, NULL, _IOLBF, 512); + + nsi_run_tasks(NSITASK_PRE_BOOT_1_LEVEL); + nsif_cpu0_pre_cmdline_hooks(); + + nsi_handle_cmd_line(argc, argv); + + nsi_run_tasks(NSITASK_PRE_BOOT_2_LEVEL); + nsif_cpu0_pre_hw_init_hooks(); + + nsi_run_tasks(NSITASK_HW_INIT_LEVEL); + nsi_hws_init(); + + nsi_run_tasks(NSITASK_PRE_BOOT_3_LEVEL); + + nsif_cpu0_boot(); + + nsi_run_tasks(NSITASK_FIRST_SLEEP_LEVEL); +} + +/** + * Execute the simulator for at least the specified timeout, then + * return. Note that this does not affect event timing, so the "next + * event" may be significantly after the request if the hardware has + * not been configured to e.g. send an interrupt when expected. + */ +void nsi_exec_for(uint64_t us) +{ + uint64_t start = nsi_hws_get_time(); + + do { + nsi_hws_one_event(); + } while (nsi_hws_get_time() < (start + us)); +} + +#ifndef NSI_LIBFUZZER + +/** + * + * Note that this main() is not used when building fuzz cases, + * as libfuzzer has its own main(), + * and calls the "OS" through a per-case fuzz test entry point. + */ +int main(int argc, char *argv[]) +{ + nsi_init(argc, argv); + while (true) { + nsi_hws_one_event(); + } + + /* This line should be unreachable */ + return 1; /* LCOV_EXCL_LINE */ +} + +#else /* NSI_LIBFUZZER */ + +/** + * Entry point for fuzzing (when enabled). Works by placing the data + * into two known symbols, triggering an app-visible interrupt, and + * then letting the simulator run for a fixed amount of time (intended to be + * "long enough" to handle the event and reach a quiescent state + * again) + */ +uint8_t *nsi_fuzz_buf, nsi_fuzz_sz; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t sz) +{ + static bool nsi_initialized; + + if (!nsi_initialized) { + nsi_init(0, NULL); + nsi_initialized = true; + } + + /* Provide the fuzz data to the embedded OS as an interrupt, with + * "DMA-like" data placed into nsi_fuzz_buf/sz + */ + nsi_fuzz_buf = (void *)data; + nsi_fuzz_sz = sz; + hw_irq_ctrl_set_irq(NSI_FUZZ_IRQ); + + /* Give the OS time to process whatever happened in that + * interrupt and reach an idle state. + */ + nsi_exec_for(NSI_FUZZ_TIME); + + return 0; +} + +#endif /* NSI_LIBFUZZER */ diff --git a/scripts/native_simulator/common/src/nce.c b/scripts/native_simulator/common/src/nce.c new file mode 100644 index 000000000000..54989dcd32cd --- /dev/null +++ b/scripts/native_simulator/common/src/nce.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Native simulator CPU emulator, + * an *optional* module provided by the native simulator + * the hosted embedded OS / SW can use to emulate the CPU + * being started and stopped. + * + * Its mode of operation is that it step-locks the HW + * and SW operation, so that only one of them executes at + * a time. Check the docs for more info. + */ + +#include +#include +#include +#include +#include "nce_if.h" +#include "nsi_safe_call.h" + +struct nce_status_t { + /* Conditional variable to know if the CPU is running or halted/idling */ + pthread_cond_t cond_cpu; + /* Mutex for the conditional variable cond_cpu */ + pthread_mutex_t mtx_cpu; + /* Variable which tells if the CPU is halted (1) or not (0) */ + bool cpu_halted; + bool terminate; /* Are we terminating the program == cleaning up */ + void (*start_routine)(void); +}; + +#define NCE_DEBUG_PRINTS 0 + +#define PREFIX "NCE: " +#define ERPREFIX PREFIX"error on " +#define NO_MEM_ERR PREFIX"Can't allocate memory\n" + +#if NCE_DEBUG_PRINTS +#define NCE_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__) +#else +#define NCE_DEBUG(...) +#endif + +extern void nsi_exit(int exit_code); + +/* + * Initialize an instance of the native simulator CPU emulator + * and return a pointer to it. + * That pointer should be passed to all subsequent calls to this module. + */ +void *nce_init(void) +{ + struct nce_status_t *this; + + this = calloc(1, sizeof(struct nce_status_t)); + + if (this == NULL) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ + } + this->cpu_halted = true; + this->terminate = false; + + NSI_SAFE_CALL(pthread_cond_init(&this->cond_cpu, NULL)); + NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_cpu, NULL)); + + return (void *)this; +} + +/* + * This function will: + * + * If called from a SW thread, release the HW thread which is blocked in + * a nce_wake_cpu() and never return. + * + * If called from a HW thread, do the necessary clean up of this nce instance + * and return right away. + */ +void nce_terminate(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + /* LCOV_EXCL_START */ /* See Note1 */ + /* + * If we are being called from a HW thread we can cleanup + * + * Otherwise (!cpu_halted) we give back control to the HW thread and + * tell it to terminate ASAP + */ + if (this == NULL || this->cpu_halted) { + /* + * Note: The nce_status structure cannot be safely free'd up + * as the user is allowed to call nce_clean_up() + * repeatedly on the same structure. + * Instead we rely of on the host OS process cleanup. + * If you got here due to valgrind's leak report, please use the + * provided valgrind suppression file valgrind.supp + */ + return; + } else if (this->terminate == false) { + + this->terminate = true; + + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + this->cpu_halted = true; + + NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + + while (1) { + sleep(1); + /* This SW thread will wait until being cancelled from + * the HW thread. sleep() is a cancellation point, so it + * won't really wait 1 second + */ + } + } + /* LCOV_EXCL_STOP */ +} + +/** + * Helper function which changes the status of the CPU (halted or running) + * and waits until somebody else changes it to the opposite + * + * Both HW and SW threads will use this function to transfer control to the + * other side. + * + * This is how the idle thread halts the CPU and gets halted until the HW models + * raise a new interrupt; and how the HW models awake the CPU, and wait for it + * to complete and go to idle. + */ +static void change_cpu_state_and_wait(struct nce_status_t *this, bool halted) +{ + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + NCE_DEBUG("Going to halted = %d\n", halted); + + this->cpu_halted = halted; + + /* We let the other side know the CPU has changed state */ + NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_cpu)); + + /* We wait until the CPU state has been changed. Either: + * we just awoke it, and therefore wait until the CPU has run until + * completion before continuing (before letting the HW models do + * anything else) + * or + * we are just hanging it, and therefore wait until the HW models awake + * it again + */ + while (this->cpu_halted == halted) { + /* Here we unlock the mutex while waiting */ + pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); + } + + NCE_DEBUG("Awaken after halted = %d\n", halted); + + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); +} + +/* + * Helper function that wraps the SW start_routine + */ +static void *sw_wrapper(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + /* Ensure nce_boot_cpu has reached the cond loop */ + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + +#if (NCE_DEBUG_PRINTS) + pthread_t sw_thread = pthread_self(); + + NCE_DEBUG("SW init started (%lu)\n", + sw_thread); +#endif + + this->start_routine(); + return NULL; +} + +/* + * Boot the emulated CPU, that is: + * * Spawn a new pthread which will run the first embedded SW thread + * * Hold the caller until that embedded SW thread (or a child it spawns) + * calls nce_halt_cpu() + * + * Note that during this, an embedded SW thread may call nsi_exit(), which would result + * in this function never returning. + */ +void nce_boot_cpu(void *this_arg, void (*start_routine)(void)) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_cpu)); + + this->cpu_halted = false; + this->start_routine = start_routine; + + /* Create a thread for the embedded SW init: */ + pthread_t sw_thread; + + NSI_SAFE_CALL(pthread_create(&sw_thread, NULL, sw_wrapper, this_arg)); + + /* And we wait until the embedded OS has send the CPU to sleep for the first time */ + while (this->cpu_halted == false) { + pthread_cond_wait(&this->cond_cpu, &this->mtx_cpu); + } + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_cpu)); + + if (this->terminate) { + nsi_exit(0); + } +} + +/* + * Halt the CPU, that is: + * * Hold this embedded SW thread until the CPU is awaken again, + * and release the HW thread which had been held on + * nce_boot_cpu() or nce_wake_cpu(). + * + * Note: Can only be called from embedded SW threads + * Calling it from a HW thread is a programming error. + */ +void nce_halt_cpu(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this->cpu_halted == true) { + nsi_print_error_and_exit("Programming error on: %s ", + "This CPU was already halted\n"); + } + change_cpu_state_and_wait(this, true); +} + +/* + * Awake the CPU, that is: + * * Hold this HW thread until the CPU is set to idle again + * * Release the SW thread which had been held on nce_halt_cpu() + * + * Note: Can only be called from HW threads + * Calling it from a SW thread is a programming error. + */ +void nce_wake_cpu(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this->cpu_halted == false) { + nsi_print_error_and_exit("Programming error on: %s ", + "This CPU was already awake\n"); + } + change_cpu_state_and_wait(this, false); + + /* + * If while the SW was running it was decided to terminate the execution + * we stop immediately. + */ + if (this->terminate) { + nsi_exit(0); + } +} + +/* + * Return 0 if the CPU is sleeping (or terminated) + * and !=0 if the CPU is running + */ +int nce_is_cpu_running(void *this_arg) +{ + struct nce_status_t *this = (struct nce_status_t *)this_arg; + + if (this != NULL) { + return !this->cpu_halted; + } else { + return false; + } +} + +/* + * Notes about coverage: + * + * Note1: When the application is closed due to a SIGTERM, the path in this + * function will depend on when that signal was received. Typically during a + * regression run, both paths will be covered. But in some cases they won't. + * Therefore and to avoid confusing developers with spurious coverage changes + * we exclude this function from the coverage check + */ diff --git a/scripts/native_simulator/common/src/nct.c b/scripts/native_simulator/common/src/nct.c new file mode 100644 index 000000000000..d048f52954f6 --- /dev/null +++ b/scripts/native_simulator/common/src/nct.c @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Native simulator, CPU Thread emulation (nct) + */ + +/** + * Native simulator single CPU threading emulation, + * an *optional* module provided by the Native simulator + * the hosted embedded OS / SW can use to emulate the threading + * context switching which would be handled by a OS CPU AL + * + * Principle of operation: + * + * The embedded OS threads are run as a set of native Linux pthreads. + * The embedded OS only sees one of this thread executing at a time. + * + * The hosted OS shall call nct_init() to initialize the state of an + * instance of this module, and nct_clean_up() once it desires to destroy it. + * + * For SOCs with several micro-controllers (AMP) one instance of this module + * would be instantiated per simulated uC and embedded OS. + * + * To create a new embedded thread, the hosted OS shall call nct_new_thread(). + * To swap to a thread nct_swap_threads(), and to terminate a thread + * nct_abort_thread(). + * The hosted OS can optionally use nct_first_thread_start() to swap + * to the "first thread". + * + * Whenever a thread calls nct_swap_threads(next_thread_idx) it will be blocked, + * and the thread identified by next_thread_idx will continue executing. + * + * + * Internal design: + * + * Which thread is running is controlled using {cond|mtx}_threads and + * currently_allowed_thread. + * + * The main part of the execution of each thread will occur in a fully + * synchronous and deterministic manner, and only when commanded by + * the embedded operating system kernel. + * + * The creation of a thread will spawn a new pthread whose start + * is asynchronous to the rest, until synchronized in nct_wait_until_allowed() + * below. + * Similarly aborting and canceling threads execute a tail in a quite an + * asynchronous manner. + * + * This implementation is meant to be portable in between fully compatible + * POSIX systems. + * A table (threads_table) is used to abstract the native pthreads. + * An index in this table is used to identify threads in the IF to the + * embedded OS. + */ + +#define NCT_DEBUG_PRINTS 0 + +#include +#include +#include +#include +#include +#include "nct_if.h" +#include "nsi_internal.h" +#include "nsi_safe_call.h" + +#if NCT_DEBUG_PRINTS +#define NCT_DEBUG(fmt, ...) nsi_print_trace(PREFIX fmt, __VA_ARGS__) +#else +#define NCT_DEBUG(...) +#endif + +#define PREFIX "Tread Simulator: " +#define ERPREFIX PREFIX"error on " +#define NO_MEM_ERR PREFIX"Can't allocate memory\n" + +#define NCT_ALLOC_CHUNK_SIZE 64 /* In how big chunks we grow the thread table */ +#define NCT_REUSE_ABORTED_ENTRIES 0 +/* For the Zephyr OS, tests/kernel/threads/scheduling/schedule_api fails when setting + * NCT_REUSE_ABORTED_ENTRIES => don't set it by now + */ + +struct te_status_t; + +struct threads_table_el { + /* Pointer to the overall status of the threading emulator instance */ + struct te_status_t *ts_status; + struct threads_table_el *next; /* Pointer to the next element of the table */ + int thread_idx; /* Index of this element in the threads_table*/ + + enum {NOTUSED = 0, USED, ABORTING, ABORTED, FAILED} state; + bool running; /* Is this the currently running thread */ + pthread_t thread; /* Actual pthread_t as returned by the native kernel */ + int thead_cnt; /* For debugging: Unique, consecutive, thread number */ + + /* + * Pointer to data from the hosted OS architecture + * What that is, if anything, is up to that the hosted OS + */ + void *payload; +}; + +struct te_status_t { + struct threads_table_el *threads_table; /* Pointer to the threads table */ + int thread_create_count; /* (For debugging) Thread creation counter */ + int threads_table_size; /* Size of threads_table */ + /* Pointer to the hosted OS function to be called when a thread is started */ + void (*fptr)(void *payload); + /* + * Conditional variable to block/awake all threads during swaps. + * (we only need 1 mutex and 1 cond variable for all threads) + */ + pthread_cond_t cond_threads; + /* Mutex for the conditional variable cond_threads */ + pthread_mutex_t mtx_threads; + /* Token which tells which thread is allowed to run now */ + int currently_allowed_thread; + bool terminate; /* Are we terminating the program == cleaning up */ +}; + +static void nct_exit_and_cleanup(struct te_status_t *this); +static struct threads_table_el *ttable_get_element(struct te_status_t *this, int index); + +/** + * Helper function, run by a thread which is being aborted + */ +static void abort_tail(struct te_status_t *this, int this_th_nbr) +{ + struct threads_table_el *tt_el = ttable_get_element(this, this_th_nbr); + + NCT_DEBUG("Thread [%i] %i: %s: Aborting (exiting) (rel mut)\n", + tt_el->thead_cnt, + this_th_nbr, + __func__); + + tt_el->running = false; + tt_el->state = ABORTED; + nct_exit_and_cleanup(this); +} + +/** + * Helper function to block this thread until it is allowed again + * + * Note that we go out of this function (the while loop below) + * with the mutex locked by this particular thread. + * In normal circumstances, the mutex is only unlocked internally in + * pthread_cond_wait() while waiting for cond_threads to be signaled + */ +static void nct_wait_until_allowed(struct te_status_t *this, int this_th_nbr) +{ + struct threads_table_el *tt_el = ttable_get_element(this, this_th_nbr); + + tt_el->running = false; + + NCT_DEBUG("Thread [%i] %i: %s: Waiting to be allowed to run (rel mut)\n", + tt_el->thead_cnt, + this_th_nbr, + __func__); + + while (this_th_nbr != this->currently_allowed_thread) { + pthread_cond_wait(&this->cond_threads, &this->mtx_threads); + + if (tt_el->state == ABORTING) { + abort_tail(this, this_th_nbr); + } + } + + tt_el->running = true; + + NCT_DEBUG("Thread [%i] %i: %s(): I'm allowed to run! (hav mut)\n", + tt_el->thead_cnt, + this_th_nbr, + __func__); +} + +/** + * Helper function to let the thread run + * + * Note: nct_let_run() can only be called with the mutex locked + */ +static void nct_let_run(struct te_status_t *this, int next_allowed_th) +{ +#if NCT_DEBUG_PRINTS + struct threads_table_el *tt_el = ttable_get_element(this, next_allowed_th); + + NCT_DEBUG("%s: We let thread [%i] %i run\n", + __func__, + tt_el->thead_cnt, + next_allowed_th); +#endif + + this->currently_allowed_thread = next_allowed_th; + + /* + * We let all threads know one is able to run now (it may even be us + * again if fancied) + * Note that as we hold the mutex, they are going to be blocked until + * we reach our own nct_wait_until_allowed() while loop or abort_tail() + * mutex release + */ + NSI_SAFE_CALL(pthread_cond_broadcast(&this->cond_threads)); +} + +/** + * Helper function, run by a thread which is being ended + */ +static void nct_exit_and_cleanup(struct te_status_t *this) +{ + /* + * Release the mutex so the next allowed thread can run + */ + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_threads)); + + /* We detach ourselves so nobody needs to join to us */ + pthread_detach(pthread_self()); + + pthread_exit(NULL); +} + +/** + * Let the ready thread run and block this managed thread until it is allowed again + * + * The hosted OS shall call this when it has decided to swap in/out two of its threads, + * from the thread that is being swapped out. + * + * Note: If called without having ever let another managed thread run / from a thread not + * managed by this nct instance, it will behave like nct_first_thread_start(), + * and terminate the calling thread while letting the managed thread + * continue. + * + * inputs: + * this_arg: Pointer to this thread emulator instance as returned by nct_init() + * next_allowed_thread_nbr: Identifier of the thread the hosted OS wants to swap in + */ +void nct_swap_threads(void *this_arg, int next_allowed_thread_nbr) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + int this_th_nbr = this->currently_allowed_thread; + + nct_let_run(this, next_allowed_thread_nbr); + + if (this_th_nbr == -1) { /* This is the first time a thread was swapped in */ + NCT_DEBUG("%s: called from an unmanaged thread, terminating it\n", + __func__); + nct_exit_and_cleanup(this); + } + + struct threads_table_el *tt_el = ttable_get_element(this, this_th_nbr); + + if (tt_el->state == ABORTING) { + NCT_DEBUG("Thread [%i] %i: %s: Aborting curr.\n", + tt_el->thead_cnt, + this_th_nbr, + __func__); + abort_tail(this, this_th_nbr); + } else { + nct_wait_until_allowed(this, this_th_nbr); + } +} + +/** + * Let the very first hosted thread run, and exit this thread. + * + * The hosted OS shall call this when it has decided to swap in into another + * thread, and wants to terminate the currently executing thread, which is not + * a thread managed by the thread emulator. + * + * This function allows to emulate a hosted OS doing its first swapping into one + * of its hosted threads from the init thread, abandoning/terminating the init + * thread. + */ +void nct_first_thread_start(void *this_arg, int next_allowed_thread_nbr) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + + nct_let_run(this, next_allowed_thread_nbr); + NCT_DEBUG("%s: Init thread dying now (rel mut)\n", + __func__); + nct_exit_and_cleanup(this); +} + +/** + * Handler called when any thread is cancelled or exits + */ +static void nct_cleanup_handler(void *arg) +{ + struct threads_table_el *element = (struct threads_table_el *)arg; + struct te_status_t *this = element->ts_status; + + /* + * If we are not terminating, this is just an aborted thread, + * and the mutex was already released + * Otherwise, release the mutex so other threads which may be + * caught waiting for it could terminate + */ + + if (!this->terminate) { + return; + } + + NCT_DEBUG("Thread %i: %s: Canceling (rel mut)\n", + element->thread_idx, + __func__); + + + NSI_SAFE_CALL(pthread_mutex_unlock(&this->mtx_threads)); + + /* We detach ourselves so nobody needs to join to us */ + pthread_detach(pthread_self()); +} + +/** + * Helper function to start a hosted thread as a POSIX thread: + * It will block the pthread until the embedded OS devices to "swap in" + * this thread. + */ +static void *nct_thread_starter(void *arg_el) +{ + struct threads_table_el *tt_el = (struct threads_table_el *)arg_el; + struct te_status_t *this = tt_el->ts_status; + + int thread_idx = tt_el->thread_idx; + + NCT_DEBUG("Thread [%i] %i: %s: Starting\n", + tt_el->thead_cnt, + thread_idx, + __func__); + + /* + * We block until all other running threads reach the while loop + * in nct_wait_until_allowed() and they release the mutex + */ + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_threads)); + + /* + * The program may have been finished before this thread ever got to run + */ + /* LCOV_EXCL_START */ /* See Note1 */ + if (!this->threads_table || this->terminate) { + nct_cleanup_handler(arg_el); + pthread_exit(NULL); + } + /* LCOV_EXCL_STOP */ + + pthread_cleanup_push(nct_cleanup_handler, arg_el); + + NCT_DEBUG("Thread [%i] %i: %s: After start mutex (hav mut)\n", + tt_el->thead_cnt, + thread_idx, + __func__); + + /* + * The thread would try to execute immediately, so we block it + * until allowed + */ + nct_wait_until_allowed(this, thread_idx); + + this->fptr(tt_el->payload); + + /* + * We only reach this point if the thread actually returns which should + * not happen. But we handle it gracefully just in case + */ + /* LCOV_EXCL_START */ + nsi_print_trace(PREFIX"Thread [%i] %i [%lu] ended!?!\n", + tt_el->thead_cnt, + thread_idx, + pthread_self()); + + tt_el->running = false; + tt_el->state = FAILED; + + pthread_cleanup_pop(1); + + return NULL; + /* LCOV_EXCL_STOP */ +} + +static struct threads_table_el *ttable_get_element(struct te_status_t *this, int index) +{ + struct threads_table_el *threads_table = this->threads_table; + + if (index >= this->threads_table_size) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit("%s: Programming error, attempted out of bound access to " + "thread table (%i>=%i)\n", + index, this->threads_table_size); /* LCOV_EXCL_LINE */ + } + while (index >= NCT_ALLOC_CHUNK_SIZE) { + index -= NCT_ALLOC_CHUNK_SIZE; + threads_table = threads_table[NCT_ALLOC_CHUNK_SIZE - 1].next; + } + return &threads_table[index]; +} + +/** + * Return the first free entry index in the threads table + */ +static int ttable_get_empty_slot(struct te_status_t *this) +{ + struct threads_table_el *tt_el = this->threads_table; + + for (int i = 0; i < this->threads_table_size; i++, tt_el = tt_el->next) { + if ((tt_el->state == NOTUSED) + || (NCT_REUSE_ABORTED_ENTRIES + && (tt_el->state == ABORTED))) { + return i; + } + } + + /* + * else, we run out of table without finding an index + * => we expand the table + */ + + struct threads_table_el *new_chunk; + + new_chunk = calloc(NCT_ALLOC_CHUNK_SIZE, sizeof(struct threads_table_el)); + if (new_chunk == NULL) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ + } + + /* Link new chunk to last element */ + tt_el = ttable_get_element(this, this->threads_table_size-1); + tt_el->next = new_chunk; + + this->threads_table_size += NCT_ALLOC_CHUNK_SIZE; + + /* Link all new elements together */ + for (int i = 0 ; i < NCT_ALLOC_CHUNK_SIZE - 1; i++) { + new_chunk[i].next = &new_chunk[i+1]; + } + new_chunk[NCT_ALLOC_CHUNK_SIZE - 1].next = NULL; + + /* The first newly created entry is good, we return it */ + return this->threads_table_size - NCT_ALLOC_CHUNK_SIZE; +} + +/** + * Create a new pthread for the new hosted OS thread. + * + * Returns a unique integer thread identifier/index, which should be used + * to refer to this thread for future calls to the thread emulator. + * + * It takes as parameter a pointer which will be passed to + * function registered in nct_init when the thread is swapped in. + * + * Note that the thread is created but not swapped in. + * The new thread execution will be held until nct_swap_threads() + * (or nct_first_thread_start()) is called with this newly created + * thread number. + */ +int nct_new_thread(void *this_arg, void *payload) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + struct threads_table_el *tt_el; + int t_slot; + + t_slot = ttable_get_empty_slot(this); + tt_el = ttable_get_element(this, t_slot); + + tt_el->state = USED; + tt_el->running = false; + tt_el->thead_cnt = this->thread_create_count++; + tt_el->payload = payload; + tt_el->ts_status = this; + tt_el->thread_idx = t_slot; + + NSI_SAFE_CALL(pthread_create(&tt_el->thread, + NULL, + nct_thread_starter, + (void *)tt_el)); + + NCT_DEBUG("%s created thread [%i] %i [%lu]\n", + __func__, + tt_el->thead_cnt, + t_slot, + tt_el->thread); + + return t_slot; +} + +/** + * Initialize an instance of the threading emulator. + * + * Returns a pointer to the initialize threading emulator instance. + * This pointer shall be passed to all subsequent calls of the + * threading emulator when interacting with this particular instance. + * + * The input fptr is a pointer to the hosted OS function + * to be called each time a thread which is created on its request + * with nct_new_thread() is swapped in (from that thread context) + */ +void *nct_init(void (*fptr)(void *)) +{ + struct te_status_t *this; + + /* + * Note: This (and the calloc below) won't be free'd by this code + * but left for the OS to clear at process end. + * This is a conscious choice, see nct_clean_up() for more info. + * If you got here due to valgrind's leak report, please use the + * provided valgrind suppression file valgrind.supp + */ + this = calloc(1, sizeof(struct te_status_t)); + if (this == NULL) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ + } + + this->fptr = fptr; + this->thread_create_count = 0; + this->currently_allowed_thread = -1; + + NSI_SAFE_CALL(pthread_cond_init(&this->cond_threads, NULL)); + NSI_SAFE_CALL(pthread_mutex_init(&this->mtx_threads, NULL)); + + this->threads_table = calloc(NCT_ALLOC_CHUNK_SIZE, + sizeof(struct threads_table_el)); + if (this->threads_table == NULL) { /* LCOV_EXCL_BR_LINE */ + nsi_print_error_and_exit(NO_MEM_ERR); /* LCOV_EXCL_LINE */ + } + + this->threads_table_size = NCT_ALLOC_CHUNK_SIZE; + + for (int i = 0 ; i < NCT_ALLOC_CHUNK_SIZE - 1; i++) { + this->threads_table[i].next = &this->threads_table[i+1]; + } + this->threads_table[NCT_ALLOC_CHUNK_SIZE - 1].next = NULL; + + NSI_SAFE_CALL(pthread_mutex_lock(&this->mtx_threads)); + + return (void *)this; +} + +/** + * Free any allocated memory by the threading emulator and clean up. + * Note that this function cannot be called from a SW thread + * (the CPU is assumed halted. Otherwise we would cancel ourselves) + * + * Note: This function cannot guarantee the threads will be cancelled before the HW + * thread exists. The only way to do that, would be to wait for each of them in + * a join without detaching them, but that could lead to locks in some + * convoluted cases; as a call to this function can come due to a hosted OS + * assert or other error termination, we better do not assume things are working fine. + * => we prefer the supposed memory leak report from valgrind, and ensure we + * will not hang. + */ +void nct_clean_up(void *this_arg) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + struct threads_table_el *tt_el; + + if (!this || !this->threads_table) { /* LCOV_EXCL_BR_LINE */ + return; /* LCOV_EXCL_LINE */ + } + + this->terminate = true; + + tt_el = this->threads_table; + + for (int i = 0; i < this->threads_table_size; i++, tt_el = tt_el->next) { + if (tt_el->state != USED) { + continue; + } + + /* LCOV_EXCL_START */ + if (pthread_cancel(tt_el->thread)) { + nsi_print_warning( + PREFIX"cleanup: could not stop thread %i\n", + i); + } + /* LCOV_EXCL_STOP */ + } + + /* + * This is the cleanup we do not do: + * + * free(this->threads_table); + * Including all chunks + * this->threads_table = NULL; + * + * (void)pthread_cond_destroy(&this->cond_threads); + * (void)pthread_mutex_destroy(&this->mtx_threads); + * + * free(this); + */ +} + + +/* + * Mark a thread as being aborted. This will result in the underlying pthread + * being terminated some time later: + * If the thread is marking itself as aborting, as soon as it is swapped out + * by the hosted (embedded) OS + * If it is marking another thread, at some non-specific time in the future + * (But note that no embedded part of the aborted thread will execute anymore) + * + * * thread_idx : The thread identifier as provided during creation (return from nct_new_thread()) + */ +void nct_abort_thread(void *this_arg, int thread_idx) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + struct threads_table_el *tt_el = ttable_get_element(this, thread_idx); + + if (thread_idx == this->currently_allowed_thread) { + NCT_DEBUG("Thread [%i] %i: %s Marked myself " + "as aborting\n", + tt_el->thead_cnt, + thread_idx, + __func__); + } else { + if (tt_el->state != USED) { /* LCOV_EXCL_BR_LINE */ + /* The thread may have been already aborted before */ + return; /* LCOV_EXCL_LINE */ + } + + NCT_DEBUG("Aborting not scheduled thread [%i] %i\n", + tt_el->thead_cnt, + thread_idx); + } + tt_el->state = ABORTING; + /* + * Note: the native thread will linger in RAM until it catches the + * mutex or awakes on the condition. + * Note that even if we would pthread_cancel() the thread here, that + * would be the case, but with a pthread_cancel() the mutex state would + * be uncontrolled + */ +} + +/* + * Return a unique thread identifier for this thread for this + * run. This identifier is only meant for debug purposes + * + * thread_idx is the value returned by nct_new_thread() + */ +int nct_get_unique_thread_id(void *this_arg, int thread_idx) +{ + struct te_status_t *this = (struct te_status_t *)this_arg; + struct threads_table_el *tt_el = ttable_get_element(this, thread_idx); + + return tt_el->thead_cnt; +} + +/* + * Notes about coverage: + * + * Note1: + * + * This condition will only be triggered in very unlikely cases + * (once every few full regression runs). + * It is therefore excluded from the coverage report to avoid confusing + * developers. + * + * Background: A pthread is created as soon as the hosted kernel creates + * a hosted thread. A pthread creation is an asynchronous process handled by the + * host kernel. + * + * This emulator normally keeps only 1 thread executing at a time. + * But part of the pre-initialization during creation of a new thread + * and some cleanup at the tail of the thread termination are executed + * in parallel to other threads. + * That is, the execution of those code paths is a bit indeterministic. + * + * Only when the hosted kernel attempts to swap to a new thread does this + * emulator need to wait until its pthread is ready and initialized + * (has reached nct_wait_until_allowed()) + * + * In some cases (tests) hosted threads are created which are never actually needed + * (typically the idle thread). That means the test may finish before that + * thread's underlying pthread has reached nct_wait_until_allowed(). + * + * In this unlikely cases the initialization or cleanup of the thread follows + * non-typical code paths. + * This code paths are there to ensure things work always, no matter + * the load of the host. Without them, very rare & mysterious segfault crashes + * would occur. + * But as they are very atypical and only triggered with some host loads, + * they will be covered in the coverage reports only rarely. + * + * Note2: + * + * Some other code will never or only very rarely trigger and is therefore + * excluded with LCOV_EXCL_LINE + * + */ diff --git a/scripts/native_simulator/common/src/nsi_host_trampolines.c b/scripts/native_simulator/common/src/nsi_host_trampolines.c new file mode 100644 index 000000000000..d35dce407590 --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_host_trampolines.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * See description in header + */ + +#include + +long nsi_host_random(void) +{ + return random(); +} + +void nsi_host_srandom(unsigned int seed) +{ + srandom(seed); +} diff --git a/scripts/native_simulator/common/src/nsi_hw_scheduler.c b/scripts/native_simulator/common/src/nsi_hw_scheduler.c new file mode 100644 index 000000000000..da5a641ec518 --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_hw_scheduler.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Overall HW models scheduler for the native simulator + * + * Models events are registered with NSI_HW_EVENT(). + */ + +#include +#include +#include +#include +#include "nsi_tracing.h" +#include "nsi_main.h" +#include "nsi_safe_call.h" +#include "nsi_hw_scheduler.h" + +static uint64_t 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 uint64_t *__nsi_hw_events_timers_start[]; +extern uint64_t *__nsi_hw_events_timers_end[]; + +extern void (*__nsi_hw_events_callbacks_start[])(void); +extern void (*__nsi_hw_events_callbacks_end[])(void); + +static unsigned int number_of_timers; +static unsigned int number_of_callbacks; + +static unsigned int next_timer_index; +static uint64_t next_timer_time; + +/* Have we received a SIGTERM or SIGINT */ +static volatile sig_atomic_t signaled_end; + +/** + * Handler for SIGTERM and SIGINT + */ +static void nsi_hws_signal_end_handler(int sig) +{ + signaled_end = 1; +} + +/** + * Set the handler for SIGTERM and SIGINT which will cause the + * program to exit gracefully when they are received the 1st time + * + * Note that our handler only sets a variable indicating the signal was + * received, and in each iteration of the hw main loop this variable is + * evaluated. + * If for some reason (the program is stuck) we never evaluate it, the program + * would never exit. + * 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 + * _XOPEN_SOURCE>=500 + */ +static void nsi_hws_set_sig_handler(void) +{ + struct sigaction act; + + act.sa_handler = nsi_hws_signal_end_handler; + NSI_SAFE_CALL(sigemptyset(&act.sa_mask)); + + act.sa_flags = SA_RESETHAND; + + NSI_SAFE_CALL(sigaction(SIGTERM, &act, NULL)); + NSI_SAFE_CALL(sigaction(SIGINT, &act, NULL)); +} + + +static void nsi_hws_sleep_until_next_event(void) +{ + if (next_timer_time >= simu_time) { /* LCOV_EXCL_BR_LINE */ + 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, + next_timer_index); + /* LCOV_EXCL_STOP */ + } + + if (signaled_end || (simu_time > end_of_time)) { + nsi_print_trace("\nStopped at %.3Lfs\n", + ((long double)simu_time)/1.0e6L); + nsi_exit(0); + } +} + + +/** + * Find in between all events timers which is the next one. + * (and update the internal next_timer_* accordingly) + */ +void nsi_hws_find_next_event(void) +{ + next_timer_index = 0; + next_timer_time = *__nsi_hw_events_timers_start[0]; + + for (unsigned int i = 1; i < number_of_timers ; i++) { + if (next_timer_time > *__nsi_hw_events_timers_start[i]) { + next_timer_index = i; + next_timer_time = *__nsi_hw_events_timers_start[i]; + } + } +} + +/** + * Execute the next scheduled HW event + * (advancing time until that event would trigger) + */ +void nsi_hws_one_event(void) +{ + nsi_hws_sleep_until_next_event(); + + if (next_timer_index < number_of_timers) { /* LCOV_EXCL_BR_LINE */ + __nsi_hw_events_callbacks_start[next_timer_index](); + } else { + nsi_print_error_and_exit("next_timer_index corrupted\n"); /* LCOV_EXCL_LINE */ + } + + nsi_hws_find_next_event(); +} + +/** + * Set the simulated time when the process will stop + */ +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 + * + * Note that the HW models should register their initialization functions + * as NSI_TASKS of HW_INIT level. + */ +void nsi_hws_init(void) +{ + number_of_timers = + (__nsi_hw_events_timers_end - __nsi_hw_events_timers_start); + number_of_callbacks = + (__nsi_hw_events_callbacks_end - __nsi_hw_events_callbacks_start); + + /* LCOV_EXCL_START */ + if (number_of_timers != number_of_callbacks || number_of_timers == 0) { + nsi_print_error_and_exit("number_of_timers corrupted\n"); + } + /* LCOV_EXCL_STOP */ + + nsi_hws_set_sig_handler(); + nsi_hws_find_next_event(); +} + +/** + * Function to free any resources allocated by the HW scheduler + * + * Note that the HW models should register their initialization functions + * as NSI_TASKS of ON_EXIT_PRE/POST levels. + */ +void nsi_hws_cleanup(void) +{ +} diff --git a/scripts/native_simulator/common/src/nsi_internal.h b/scripts/native_simulator/common/src/nsi_internal.h new file mode 100644 index 000000000000..00e638979963 --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_internal.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_NSI_INTERNAL_H +#define NSI_COMMON_SRC_NSI_INTERNAL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * + * @brief find least significant bit set in a 32-bit word + * + * This routine finds the first bit set starting from the least significant bit + * in the argument passed in and returns the index of that bit. Bits are + * numbered starting at 1 from the least significant bit. A return value of + * zero indicates that the value passed is zero. + * + * @return least significant bit set, 0 if @a op is 0 + */ + +static inline unsigned int nsi_find_lsb_set(uint32_t op) +{ + return __builtin_ffs(op); +} + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_NSI_INTERNAL_H */ diff --git a/scripts/native_simulator/common/src/nsi_safe_call.h b/scripts/native_simulator/common/src/nsi_safe_call.h new file mode 100644 index 000000000000..0bfeaadec869 --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_safe_call.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_NSI_SAFE_CALLL_H +#define NSI_COMMON_SRC_NSI_SAFE_CALLL_H + +#include +#include "nsi_tracing.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef nsi_unlikely +#define nsi_unlikely(x) (__builtin_expect((bool)!!(x), false) != 0L) +#endif + +#define NSI_SAFE_CALL(a) nsi_safe_call(a, #a) + +static inline void nsi_safe_call(int test, const char *test_str) +{ + /* LCOV_EXCL_START */ /* See Note1 */ + if (nsi_unlikely(test)) { + nsi_print_error_and_exit("Error on: %s\n", + test_str); + } + /* LCOV_EXCL_STOP */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_NSI_SAFE_CALLL_H */ diff --git a/scripts/native_simulator/common/src/nsi_tasks.c b/scripts/native_simulator/common/src/nsi_tasks.c new file mode 100644 index 000000000000..3a52e4cfcf0b --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_tasks.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Run the set of special NSI tasks corresponding to the given level + * + * @param level One of NSITASK_*_LEVEL as defined in nsi_tasks.h + */ +void nsi_run_tasks(int level) +{ + extern void (*__nsi_PRE_BOOT_1_tasks_start[])(void); + extern void (*__nsi_PRE_BOOT_2_tasks_start[])(void); + extern void (*__nsi_HW_INIT_tasks_start[])(void); + extern void (*__nsi_PRE_BOOT_3_tasks_start[])(void); + extern void (*__nsi_FIRST_SLEEP_tasks_start[])(void); + extern void (*__nsi_ON_EXIT_PRE_tasks_start[])(void); + extern void (*__nsi_ON_EXIT_POST_tasks_start[])(void); + extern void (*__nsi_tasks_end[])(void); + + static void (**nsi_pre_tasks[])(void) = { + __nsi_PRE_BOOT_1_tasks_start, + __nsi_PRE_BOOT_2_tasks_start, + __nsi_HW_INIT_tasks_start, + __nsi_PRE_BOOT_3_tasks_start, + __nsi_FIRST_SLEEP_tasks_start, + __nsi_ON_EXIT_PRE_tasks_start, + __nsi_ON_EXIT_POST_tasks_start, + __nsi_tasks_end + }; + + void (**fptr)(void); + + for (fptr = nsi_pre_tasks[level]; fptr < nsi_pre_tasks[level+1]; + fptr++) { + if (*fptr) { /* LCOV_EXCL_BR_LINE */ + (*fptr)(); + } + } +} diff --git a/scripts/native_simulator/common/src/nsi_tasks.h b/scripts/native_simulator/common/src/nsi_tasks.h new file mode 100644 index 000000000000..ee98ba5ddc10 --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_tasks.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_NSI_TASKS_H +#define NSI_COMMON_SRC_NSI_TASKS_H + +#include "nsi_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * NSI_TASK + * + * Register a function to be called at particular moments + * during the Native Simulator 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, + * or the HW models are initialized + * + * * PRE_BOOT_2: Will be called after the command line parameters are parsed, + * but before the HW models are initialized + * + * * HW_INIT: Will be called during HW models initialization + * + * * PRE_BOOT_3: Will be called after the HW models initialization, right before + * the "CPUs are booted" and embedded SW in them is started. + * + * * FIRST_SLEEP: Will be called after the 1st time all CPUs are sent to sleep + * + * * ON_EXIT_PRE: Will be called during termination of the runner + * execution, as a first set. + * + * * ON_EXIT_POST: Will be called during termination of the runner + * execution, as the very last set before the program returns. + * + * The function must take no parameters and return nothing. + */ +#define NSI_TASK(fn, level, prio) \ + static void (* const NSI_CONCAT(__nsi_task_, fn))() \ + __attribute__((__used__)) \ + __attribute__((__section__(".nsi_" #level NSI_STRINGIFY(prio) "_task")))\ + = fn + +#define NSITASK_PRE_BOOT_1_LEVEL 0 +#define NSITASK_PRE_BOOT_2_LEVEL 1 +#define NSITASK_HW_INIT_LEVEL 2 +#define NSITASK_PRE_BOOT_3_LEVEL 3 +#define NSITASK_FIRST_SLEEP_LEVEL 4 +#define NSITASK_ON_EXIT_PRE_LEVEL 5 +#define NSITASK_ON_EXIT_POST_LEVEL 6 + +/** + * @brief Run the set of special native tasks corresponding to the given level + * + * @param level One of NSITASK_*_LEVEL as defined in soc.h + */ +void nsi_run_tasks(int level); + +#ifdef __cplusplus +} +#endif + +#endif /* NSI_COMMON_SRC_NSI_TASKS_H */ diff --git a/scripts/native_simulator/common/src/nsi_trace_varg.c b/scripts/native_simulator/common/src/nsi_trace_varg.c new file mode 100644 index 000000000000..71f35665599f --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_trace_varg.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "nsi_tracing.h" + +void nsi_print_error_and_exit(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + nsi_vprint_error_and_exit(format, variable_args); + va_end(variable_args); +} + +void nsi_print_warning(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + nsi_vprint_warning(format, variable_args); + va_end(variable_args); +} + +void nsi_print_trace(const char *format, ...) +{ + va_list variable_args; + + va_start(variable_args, format); + nsi_vprint_trace(format, variable_args); + va_end(variable_args); +} diff --git a/scripts/native_simulator/common/src/nsi_utils.h b/scripts/native_simulator/common/src/nsi_utils.h new file mode 100644 index 000000000000..83f2f22943bf --- /dev/null +++ b/scripts/native_simulator/common/src/nsi_utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2014 Wind River Systems, Inc. + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NSI_COMMON_SRC_INCL_NSI_UTILS_H +#define NSI_COMMON_SRC_INCL_NSI_UTILS_H + + +#define _NSI_STRINGIFY(x) #x +#define NSI_STRINGIFY(s) _NSI_STRINGIFY(s) + +/* concatenate the values of the arguments into one */ +#define NSI_DO_CONCAT(x, y) x ## y +#define NSI_CONCAT(x, y) NSI_DO_CONCAT(x, y) + +#define NSI_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define NSI_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#ifndef NSI_ARG_UNUSED +#define NSI_ARG_UNUSED(x) (void)(x) +#endif + +#endif /* NSI_COMMON_SRC_INCL_NSI_UTILS_H */ diff --git a/scripts/native_simulator/native/src/hw_counter.c b/scripts/native_simulator/native/src/hw_counter.c new file mode 100644 index 000000000000..fc0770dc6a24 --- /dev/null +++ b/scripts/native_simulator/native/src/hw_counter.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "nsi_cpu0_interrupts.h" +#include "irq_ctrl.h" +#include "nsi_tasks.h" +#include "nsi_hws_models_if.h" + +static uint64_t hw_counter_timer; + +static bool counter_running; +static uint64_t counter_value; +static uint64_t counter_target; +static uint64_t counter_period; + +/** + * Initialize the counter with prescaler of HW + */ +static void hw_counter_init(void) +{ + hw_counter_timer = NSI_NEVER; + counter_target = NSI_NEVER; + counter_value = 0; + counter_running = false; + counter_period = NSI_NEVER; +} + +NSI_TASK(hw_counter_init, HW_INIT, 10); + +static void hw_counter_triggered(void) +{ + if (!counter_running) { + hw_counter_timer = NSI_NEVER; + return; + } + + hw_counter_timer = nsi_hws_get_time() + counter_period; + counter_value = counter_value + 1; + + if (counter_value == counter_target) { + hw_irq_ctrl_set_irq(COUNTER_EVENT_IRQ); + } +} + +NSI_HW_EVENT(hw_counter_timer, hw_counter_triggered, 20); + +/** + * Configures the counter period. + * The counter will be incremented every 'period' microseconds. + */ +void hw_counter_set_period(uint64_t period) +{ + counter_period = period; +} + +/** + * Starts the counter. It must be previously configured with + * hw_counter_set_period() and hw_counter_set_target(). + */ +void hw_counter_start(void) +{ + if (counter_running) { + return; + } + + counter_running = true; + + hw_counter_timer = nsi_hws_get_time() + counter_period; + nsi_hws_find_next_event(); +} + +/** + * Stops the counter at current value. + * On the next call to hw_counter_start, the counter will + * start from the value at which it was stopped. + */ +void hw_counter_stop(void) +{ + counter_running = false; + hw_counter_timer = NSI_NEVER; + nsi_hws_find_next_event(); +} + +/** + * Returns the current counter value. + */ +uint64_t hw_counter_get_value(void) +{ + return counter_value; +} + +/** + * Configures the counter to generate an interrupt + * when its count value reaches target. + */ +void hw_counter_set_target(uint64_t target) +{ + counter_target = target; +} diff --git a/scripts/native_simulator/native/src/include/hw_counter.h b/scripts/native_simulator/native/src/include/hw_counter.h new file mode 100644 index 000000000000..766aa8e27c34 --- /dev/null +++ b/scripts/native_simulator/native/src/include/hw_counter.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief API to the native simulator - native HW counter + */ + +#ifndef NATIVE_SIMULATOR_NATIVE_SRC_HW_COUNTER_H +#define NATIVE_SIMULATOR_NATIVE_SRC_HW_COUNTER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void hw_counter_triggered(void); + +void hw_counter_set_period(uint64_t period); +void hw_counter_set_target(uint64_t counter_target); +void hw_counter_start(void); +void hw_counter_stop(void); +uint64_t hw_counter_get_value(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NATIVE_SIMULATOR_NATIVE_SRC_HW_COUNTER_H */ diff --git a/scripts/native_simulator/native/src/include/irq_ctrl.h b/scripts/native_simulator/native/src/include/irq_ctrl.h new file mode 100644 index 000000000000..c0d0cb7470fb --- /dev/null +++ b/scripts/native_simulator/native/src/include/irq_ctrl.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief API to the native simulator - native interrupt controller + */ + +#ifndef NATIVE_SIMULATOR_NATIVE_SRC_IRQ_CTRL_H +#define NATIVE_SIMULATOR_NATIVE_SRC_IRQ_CTRL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void hw_irq_ctrl_set_cur_prio(int new); +int hw_irq_ctrl_get_cur_prio(void); + +void hw_irq_ctrl_prio_set(unsigned int irq, unsigned int prio); +uint8_t hw_irq_ctrl_get_prio(unsigned int irq); + +int hw_irq_ctrl_get_highest_prio_irq(void); +uint32_t hw_irq_ctrl_get_current_lock(void); +uint32_t hw_irq_ctrl_change_lock(uint32_t new_lock); +uint64_t hw_irq_ctrl_get_irq_status(void); +void hw_irq_ctrl_disable_irq(unsigned int irq); +int hw_irq_ctrl_is_irq_enabled(unsigned int irq); +void hw_irq_ctrl_clear_irq(unsigned int irq); +void hw_irq_ctrl_enable_irq(unsigned int irq); +void hw_irq_ctrl_set_irq(unsigned int irq); +void hw_irq_ctrl_raise_im(unsigned int irq); +void hw_irq_ctrl_raise_im_from_sw(unsigned int irq); + +#define N_IRQS 32 + +#ifdef __cplusplus +} +#endif + +#endif /* NATIVE_SIMULATOR_NATIVE_SRC_IRQ_CTRL_H */ diff --git a/scripts/native_simulator/native/src/include/native_rtc.h b/scripts/native_simulator/native/src/include/native_rtc.h new file mode 100644 index 000000000000..e8833629263f --- /dev/null +++ b/scripts/native_simulator/native/src/include/native_rtc.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief API to the native simulator - native (Real) Time Clock + */ + + +#ifndef NATIVE_SIMULATOR_NATIVE_SRC_NATIVE_RTC_H +#define NATIVE_SIMULATOR_NATIVE_SRC_NATIVE_RTC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Types of clocks this RTC provides: + */ +/** Time since boot, cannot be offset. Microsecond resolution */ +#define RTC_CLOCK_BOOT 0 +/** Persistent clock, can be offset. Microsecond resolution */ +#define RTC_CLOCK_REALTIME 1 +/** + * Pseudo-host real time clock (Please see documentation). + * Nanosecond resolution + */ +#define RTC_CLOCK_PSEUDOHOSTREALTIME 2 + +/** + * @brief Get the value of a clock in microseconds + * + * @param clock_type Which clock to measure from + * + * @return Number of microseconds + */ +uint64_t native_rtc_gettime_us(int clock_type); + +/** + * @brief Get the value of a clock split in in nsec and seconds + * + * @param clock_type Which clock to measure from + * @param nsec Pointer to store the nanoseconds + * @param nsec Pointer to store the seconds + */ +void native_rtc_gettime(int clock_type, uint32_t *nsec, uint64_t *sec); + +/** + * @brief Offset the real time clock by a number of microseconds. + * Note that this only affects the RTC_CLOCK_REALTIME and + * RTC_CLOCK_PSEUDOHOSTREALTIME clocks. + * + * @param delta_us Number of microseconds to offset. The value is added to all + * offsetable clocks. + */ +void native_rtc_offset(int64_t delta_us); + +/** + * @brief Adjust the speed of the clock source by a multiplicative factor + * + * @param clock_correction Factor by which to correct the clock speed + */ +void native_rtc_adjust_clock(double clock_correction); + +#ifdef __cplusplus +} +#endif + +#endif /* NATIVE_SIMULATOR_NATIVE_SRC_NATIVE_RTC_H */ diff --git a/scripts/native_simulator/native/src/include/nsi_cmdline.h b/scripts/native_simulator/native/src/include/nsi_cmdline.h new file mode 100644 index 000000000000..0319e82c3bd9 --- /dev/null +++ b/scripts/native_simulator/native/src/include/nsi_cmdline.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Oticon A/S + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief API to the native simulator - native command line parsing utilities + * + * Note: The arguments structure definitions is kept fully compatible with Zephyr's native_posix + * and BabbleSim's command line options to enable to reuse components between them. + * And for APIs to be accessible thru a trivial shim. + */ + +#ifndef NATIVE_SIMULATOR_NATIVE_SRC_NSI_CMDLINE_H +#define NATIVE_SIMULATOR_NATIVE_SRC_NSI_CMDLINE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Prototype for a callback function when an option is found: + * inputs: + * argv: Whole argv[i] option as received in main + * offset: Offset to the end of the option string + * (including a possible ':' or '=') + * If the option had a value, it would be placed in &argv[offset] + */ +typedef void (*option_found_callback_f)(char *argv, int offset); + +/* + * Structure defining each command line option + */ +struct args_struct_t { + /* + * if manual is set nsi_cmd_args_parse*() will ignore it except for + * displaying it the help messages and initializing to its + * default + */ + bool manual; + /* For help messages, should it be wrapped in "[]" */ + bool is_mandatory; + /* It is just a switch: it does not have something to store after */ + bool is_switch; + /* Option name we search for: --